@asm-agent/coding-agent 0.8.7 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/README.md +2 -7
- package/dist/asm-agent-runtime/src/__pycache__/asm_cm_driver.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/__pycache__/phase76_address_head.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__init__.py +1 -1
- package/dist/asm-agent-runtime/src/rlm/__pycache__/__init__.cpython-312.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/_winjob.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/bash.cpython-312.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/bash.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/harness.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/mcp.cpython-312.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/mcp.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/mcp_base.cpython-312.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/mcp_base.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/repl.cpython-312.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/repl.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/skill.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/bash.py +94 -31
- package/dist/asm-agent-runtime/src/rlm/repl.md +3 -3
- package/dist/asm-agent-runtime/src/rlm/repl.py +46 -45
- package/dist/asm-agent-runtime/test/__pycache__/test_agent_message_skill.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/test/__pycache__/test_bash.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/test/__pycache__/test_harness.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/test/__pycache__/test_mcp.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/test/__pycache__/test_mcp_base.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/test/__pycache__/test_repl.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/test/__pycache__/test_subagent_registry.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/test/__pycache__/test_winjob.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/test/test_bash.py +74 -19
- package/dist/asm-agent-runtime/test/test_repl.py +67 -3
- package/dist/asm-agent-runtime/uv.lock +446 -155
- package/dist/bundle/{anthropic-XSMQHGYB.js → anthropic-ZOZNPFXS.js} +2 -2
- package/dist/bundle/{azure-openai-responses-XLQAIKKH.js → azure-openai-responses-TDHCU647.js} +2 -2
- package/dist/bundle/{bundled-modules-5OCN73BM.js → bundled-modules-Q2YODC4B.js} +3 -3
- package/dist/bundle/{chunk-IAQLPSMN.js → chunk-AMKLNEAK.js} +47 -47
- package/dist/bundle/{chunk-2LPSALBF.js → chunk-FPY7FFJS.js} +978 -1821
- package/dist/bundle/{chunk-E3YE2Q7A.js → chunk-G6SC4YYW.js} +4973 -1926
- package/dist/bundle/{chunk-YPNK4MRU.js → chunk-QLHAP3FT.js} +1 -1
- package/dist/bundle/{cli-main-QYX5R3LF.js → cli-main-277AG2BR.js} +3 -3
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/{google-ZXJEPWJA.js → google-Q3AJWUOY.js} +1 -1
- package/dist/bundle/{google-vertex-WAF3RIJ6.js → google-vertex-2CSNOUBS.js} +1 -1
- package/dist/bundle/{main-EOUAQCJH.js → main-TNXWJXIU.js} +3 -3
- package/dist/bundle/{mistral-GDZXSXRS.js → mistral-XRYJGLLG.js} +1 -1
- package/dist/bundle/{openai-codex-responses-7XMPW4LG.js → openai-codex-responses-C6BRO2BN.js} +2 -2
- package/dist/bundle/{openai-completions-LNSVGDMF.js → openai-completions-DNXCK2JW.js} +4 -4
- package/dist/bundle/{openai-responses-MFZOBMIT.js → openai-responses-BEMWVIXE.js} +2 -2
- package/dist/config.d.ts +0 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +0 -3
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-config.d.ts +1 -2
- package/dist/core/agent-session-config.d.ts.map +1 -1
- package/dist/core/agent-session-config.js +0 -3
- package/dist/core/agent-session-config.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +0 -8
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +0 -2
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +0 -22
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +8 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +100 -22
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/kernel/bootstrap.d.ts.map +1 -1
- package/dist/core/kernel/bootstrap.js +1 -1
- package/dist/core/kernel/bootstrap.js.map +1 -1
- package/dist/core/kernel/repl-manager.d.ts +32 -8
- package/dist/core/kernel/repl-manager.d.ts.map +1 -1
- package/dist/core/kernel/repl-manager.js +401 -102
- package/dist/core/kernel/repl-manager.js.map +1 -1
- package/dist/core/kernel/shared.d.ts +11 -7
- package/dist/core/kernel/shared.d.ts.map +1 -1
- package/dist/core/kernel/shared.js +2 -5
- package/dist/core/kernel/shared.js.map +1 -1
- package/dist/core/mcp/mcp-manager.d.ts +4 -2
- package/dist/core/mcp/mcp-manager.d.ts.map +1 -1
- package/dist/core/mcp/mcp-manager.js +9 -7
- package/dist/core/mcp/mcp-manager.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +1 -1
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/ollama-models.d.ts +3 -1
- package/dist/core/ollama-models.d.ts.map +1 -1
- package/dist/core/ollama-models.js +31 -10
- package/dist/core/ollama-models.js.map +1 -1
- package/dist/core/prime-inference-auth.d.ts +0 -9
- package/dist/core/prime-inference-auth.d.ts.map +1 -1
- package/dist/core/prime-inference-auth.js +0 -50
- package/dist/core/prime-inference-auth.js.map +1 -1
- package/dist/core/provider-display-names.d.ts.map +1 -1
- package/dist/core/provider-display-names.js +0 -1
- package/dist/core/provider-display-names.js.map +1 -1
- package/dist/core/session-manager.d.ts +0 -4
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +0 -22
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +4 -16
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +13 -43
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +0 -5
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/tools/acp-mcp.d.ts +6 -0
- package/dist/core/tools/acp-mcp.d.ts.map +1 -0
- package/dist/core/tools/acp-mcp.js +86 -0
- package/dist/core/tools/acp-mcp.js.map +1 -0
- package/dist/core/tools/index.d.ts +1 -0
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +1 -0
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/ipython.d.ts.map +1 -1
- package/dist/core/tools/ipython.js +9 -4
- package/dist/core/tools/ipython.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +2 -11
- package/dist/main.js.map +1 -1
- package/dist/modes/acp/acp-mode.d.ts.map +1 -1
- package/dist/modes/acp/acp-mode.js +1 -1
- package/dist/modes/acp/acp-mode.js.map +1 -1
- package/dist/modes/agent-connection/daemon-agent-connection.d.ts +0 -2
- package/dist/modes/agent-connection/daemon-agent-connection.d.ts.map +1 -1
- package/dist/modes/agent-connection/daemon-agent-connection.js +0 -2
- package/dist/modes/agent-connection/daemon-agent-connection.js.map +1 -1
- package/dist/modes/agents-view/agents-view-mode.d.ts.map +1 -1
- package/dist/modes/agents-view/agents-view-mode.js +0 -19
- package/dist/modes/agents-view/agents-view-mode.js.map +1 -1
- package/dist/modes/daemon/daemon-mode.d.ts +1 -10
- package/dist/modes/daemon/daemon-mode.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-mode.js +134 -274
- package/dist/modes/daemon/daemon-mode.js.map +1 -1
- package/dist/modes/daemon/daemon-protocol.d.ts +11 -5
- package/dist/modes/daemon/daemon-protocol.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-protocol.js +6 -8
- package/dist/modes/daemon/daemon-protocol.js.map +1 -1
- package/dist/modes/daemon/daemon-supervisor.d.ts +0 -3
- package/dist/modes/daemon/daemon-supervisor.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-supervisor.js +18 -52
- package/dist/modes/daemon/daemon-supervisor.js.map +1 -1
- package/dist/modes/daemon/daemon-worker-protocol.d.ts +1 -6
- package/dist/modes/daemon/daemon-worker-protocol.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-worker-protocol.js +0 -2
- package/dist/modes/daemon/daemon-worker-protocol.js.map +1 -1
- package/dist/modes/interactive/auth-flows.d.ts +0 -2
- package/dist/modes/interactive/auth-flows.d.ts.map +1 -1
- package/dist/modes/interactive/auth-flows.js +1 -101
- package/dist/modes/interactive/auth-flows.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +6 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +13 -3
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +2 -2
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/mermaid.d.ts +12 -0
- package/dist/modes/interactive/components/mermaid.d.ts.map +1 -0
- package/dist/modes/interactive/components/mermaid.js +63 -0
- package/dist/modes/interactive/components/mermaid.js.map +1 -0
- package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +10 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/feature-hints.d.ts.map +1 -1
- package/dist/modes/interactive/feature-hints.js +0 -4
- package/dist/modes/interactive/feature-hints.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1 -7
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +23 -279
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +1 -1
- package/dist/utils/version-check.js.map +1 -1
- package/docs/settings.md +1 -31
- package/docs/usage.md +1 -4
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +6 -5
- package/dist/core/agent-traces.d.ts +0 -130
- package/dist/core/agent-traces.d.ts.map +0 -1
- package/dist/core/agent-traces.js +0 -746
- package/dist/core/agent-traces.js.map +0 -1
- package/dist/core/telemetry.d.ts +0 -92
- package/dist/core/telemetry.d.ts.map +0 -1
- package/dist/core/telemetry.js +0 -633
- package/dist/core/telemetry.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-session.d.ts","sourceRoot":"","sources":["../../src/core/agent-session.ts"],"names":[],"mappings":"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","sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { randomUUID } from \"node:crypto\";\nimport { existsSync, mkdirSync, mkdtempSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { basename, dirname, join, resolve } from \"node:path\";\nimport {\n\tAgent,\n\ttype AgentContext,\n\tAgentContinueError,\n\ttype AgentEvent,\n\ttype AgentMessage,\n\ttype AgentState,\n\ttype AgentTool,\n\ttype GetContinuationMessagesContext,\n\ttype ShouldStopAfterTurnContext,\n\ttype ThinkingLevel,\n} from \"@asm-agent/agent\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tImageContent,\n\tModel,\n\tServiceTier,\n\tTextContent,\n\tUsage,\n\tUserMessage,\n} from \"@asm-agent/ai\";\nimport {\n\tclampThinkingLevel,\n\tcleanupSessionResources,\n\tgetSupportedThinkingLevels,\n\tisContextOverflow,\n\tmodelsAreEqual,\n\tresetApiProviders,\n\tsupportsFastMode,\n} from \"@asm-agent/ai\";\nimport { theme } from \"../modes/interactive/theme/theme.js\";\nimport { stripFrontmatter } from \"../utils/frontmatter.js\";\nimport { sleep } from \"../utils/sleep.js\";\nimport {\n\tAGENT_MESSAGE_CUSTOM_TYPE,\n\tAGENT_MESSAGE_RECEIVED_PREVIEW_LABEL,\n\tAGENT_MESSAGE_SKILL_NAME,\n\ttype AgentFamilyCatalogEntry,\n\ttype AgentFamilyRosterResult,\n\ttype AgentSessionMessage,\n\ttype AgentSessionMessageAgentSummary,\n\ttype AgentSessionMessageController,\n\ttype AgentSessionMessageListResult,\n\ttype AgentSessionMessageReceipt,\n\tassertAgentSessionNameAvailable,\n\tassertDirectAgentMessageTarget,\n\tcreateAgentMessageHostHandlers,\n\tformatAgentSessionNameUnavailable,\n\tisAgentSessionMessage,\n\tnormalizeAgentSessionMessage,\n\tparseAgentSessionMessagePromptId,\n\tstartsAgentRun,\n} from \"./agent-messages.js\";\nimport {\n\tAGENT_OBSERVE_SKILL_NAME,\n\ttype AgentObserveAgentSnapshot,\n\ttype AgentObserveController,\n\ttype AgentObserveListResult,\n\ttype AgentObserveRecentMessagesResult,\n\tcreateAgentObserveHostHandlers,\n\tnormalizeObserveLimit,\n\tnormalizeObserveMaxChars,\n\tORCHESTRATION_HEARTBEAT_SKILL_NAME,\n} from \"./agent-observe.js\";\nimport { flushAgentTraceUpload } from \"./agent-traces.js\";\nimport {\n\taddLoginGuidanceToAuthError,\n\tformatAuthenticationFailedMessage,\n\tformatNoApiKeyFoundMessage,\n\tformatNoModelSelectedMessage,\n\tisLikelyAuthenticationError,\n} from \"./auth-guidance.js\";\nimport type { AuthSourceToken } from \"./auth-storage.js\";\nimport {\n\ttype AgentAutonomousConfig,\n\ttype AgentAutonomousStatus,\n\ttype AutonomousRuntimeState,\n\taddAutonomousContinuation,\n\taddAutonomousUsage,\n\tautonomousStatus,\n\tcreateAutonomousRuntimeState,\n\tnextAutonomousContinuation,\n\trefreshAutonomousQualityGates,\n\tsetAutonomousEnabled,\n} from \"./autonomous.js\";\nimport { type BashResult, executeBashWithOperations } from \"./bash-executor.js\";\nimport {\n\tCOMPACT_SKILL_NAME,\n\ttype CompactionResult,\n\tcalculateContextTokens,\n\tcollectEntriesForBranchSummary,\n\tcompact,\n\testimateContextTokens,\n\tgenerateBranchSummary,\n\tprepareCompaction,\n\tserializeConversation,\n\tshouldCompact,\n} from \"./compaction/index.js\";\nimport {\n\ttype ContextTreeNode,\n\ttype ContextWindowResolver,\n\tcomputeOwnAndTotalUsage,\n\tloadContextTreeChildFromDisk,\n\tloadContextTreeChildrenFromDisk,\n} from \"./context-tree.js\";\nimport type { AgentCronJob, AgentRlmHeartbeatController, AgentRlmHeartbeatStatusUpdate } from \"./cron-jobs.js\";\nimport { normalizeHeartbeatDeliveryMode } from \"./cron-jobs.js\";\nimport { DEFAULT_THINKING_LEVEL } from \"./defaults.js\";\nimport { exportSessionToHtml, type ToolHtmlRenderer } from \"./export-html/index.js\";\nimport { createToolHtmlRenderer } from \"./export-html/tool-renderer.js\";\nimport {\n\ttype ContextUsage,\n\ttype ExtensionCommandContextActions,\n\ttype ExtensionErrorListener,\n\tExtensionRunner,\n\ttype ExtensionUIContext,\n\ttype InputSource,\n\ttype MessageEndEvent,\n\ttype MessageStartEvent,\n\ttype MessageUpdateEvent,\n\ttype ReplacedSessionContext,\n\ttype SessionBeforeCompactResult,\n\ttype SessionBeforeRefineResult,\n\ttype SessionBeforeTreeResult,\n\ttype SessionStartEvent,\n\ttype ShutdownHandler,\n\ttype ToolDefinition,\n\ttype ToolExecutionEndEvent,\n\ttype ToolExecutionStartEvent,\n\ttype ToolExecutionUpdateEvent,\n\ttype ToolInfo,\n\ttype TreePreparation,\n\ttype TurnEndEvent,\n\ttype TurnStartEvent,\n\twrapRegisteredTools,\n} from \"./extensions/index.js\";\nimport { emitSessionShutdownEvent } from \"./extensions/runner.js\";\nimport {\n\tcreateGoalContextMessage,\n\temptyGoalState,\n\tGOAL_CONTEXT_CUSTOM_TYPE,\n\tGOAL_CONTEXT_PREVIEW_LABEL,\n\tGOAL_SKILL_NAME,\n\tGOAL_STATE_CUSTOM_TYPE,\n\ttype GoalHostResponse,\n\ttype GoalState,\n\ttype GoalStatus,\n\tgoalHostResponse,\n\tgoalTokenDeltaForUsage,\n\tisPersistedGoalState,\n\tnormalizeGoalState,\n\tvalidateGoalBudget,\n\tvalidateGoalObjective,\n} from \"./goals.js\";\nimport type { HostRequestHandlers, KernelSentAgentMessage } from \"./kernel/index.js\";\nimport { type RestoreResult, snapshotPathIn } from \"./kernel/state-snapshot.js\";\nimport type { AcpMcpServerConfig } from \"./mcp/acp-mcp-types.js\";\nimport type { McpManager } from \"./mcp/mcp-manager.js\";\nimport {\n\tBACKGROUND_PROCESS_COMPLETED_CUSTOM_TYPE,\n\ttype BashExecutionMessage,\n\ttype CompactionOutcome,\n\ttype CompactionOutcomeReason,\n\ttype CustomMessage,\n\tconvertToLlm,\n\tcreateBackgroundProcessCompletedMessage,\n\tcreateCompactionOutcomeMessage,\n\tcreateHeartbeatPromptMessage,\n\tcreateRefinementOutcomeMessage,\n\tcreateRlmChildFailureMessage,\n\tcreateRlmChildTerminalNoticeMessage,\n\tcreateSessionSlashCommandMessage,\n\tcreateSessionSlashCommandResultMessage,\n\tHEARTBEAT_PROMPT_CUSTOM_TYPE,\n\tHEARTBEAT_PROMPT_PREVIEW_LABEL,\n\tIPYTHON_STATE_RESTORED_CUSTOM_TYPE,\n\tisSessionSlashCommandMessage,\n\tRLM_CHILD_FAILURE_CUSTOM_TYPE,\n\tRLM_CHILD_TERMINAL_NOTICE_CUSTOM_TYPE,\n} from \"./messages.js\";\nimport type { ModelRegistry } from \"./model-registry.js\";\nimport { throwIfPromptAdmissionCancelled } from \"./prompt-admission.js\";\nimport { expandPromptTemplate, type PromptTemplate } from \"./prompt-templates.js\";\nimport {\n\ttype AutoRefineReason,\n\ttype AutoRefineReview,\n\tappendGlobalRefinement,\n\tapplyRefinementProposal,\n\tgenerateRefinementId,\n\tgetGlobalHarnessStateDir,\n\tgetLocalHarnessStateDir,\n\tgetRefinementHistory,\n\ttype HarnessState,\n\tinferRefinementResultScope,\n\tloadGlobalRefinementHistory,\n\tloadHarnessState,\n\tmergeHarnessStates,\n\tmergeRefinementHistory,\n\tnormalizeRefinementProposal,\n\tplanRefinement,\n\tREFINE_SKILL_NAME,\n\ttype RefinementPlan,\n\ttype RefinementResult,\n\treviewAutoRefine,\n\tsaveHarnessState,\n} from \"./refinement/index.js\";\nimport { resolveConfigValue } from \"./resolve-config-value.js\";\nimport type { ResourceExtensionPaths, ResourceLoader } from \"./resource-loader.js\";\nimport {\n\ttype CreateRlmSubagentRuntimeOptions,\n\tcreateDefaultRlmSubagentSessionName,\n\tcreateRlmDeleteSubagentHostHandler,\n\tcreateRlmFindModelsHostHandler,\n\tcreateRlmListSubagentsHostHandler,\n\tcreateRlmRunHostHandler,\n\tfindRlmModelMatches,\n\tnormalizeRequestedRlmSubagentModel,\n\tnormalizeRequestedRlmSubagentSessionName,\n\tnormalizeRequestedRlmSubagentThinkingLevel,\n\ttype RlmDeleteSubagentResult,\n\ttype RlmFindModelsResult,\n\ttype RlmListSubagentsResult,\n\ttype RlmSpawnHandle,\n\ttype RlmSubagentRegistryEntry,\n\ttype RlmSubagentRuntime,\n\ttype SubagentRuntimeHost,\n} from \"./rlm-runtime.js\";\nimport {\n\tActionStore,\n\ttype ActionTicket,\n\tcanSelectSessionAction,\n\ttype DeliveryPolicy,\n\ttype DeliveryRecord,\n\ttype QueuedMessageLane,\n\ttype QueuedMessageMutation,\n\ttype QueuedMessageMutationStatus,\n\tqueuedMessageLaneDeliveryPolicy,\n\ttype RuntimeActivity,\n\ttype SessionAction,\n\ttype SessionActionSnapshot,\n\ttype SessionCommandPayload,\n\ttype SessionTurnPayload,\n\ttransitionSessionAction,\n\ttype WakePolicy,\n} from \"./session-action-store.js\";\nimport type { BranchSummaryEntry, CompactionEntry, SessionContext, SessionMessageEntry } from \"./session-manager.js\";\nimport {\n\tCURRENT_SESSION_VERSION,\n\tgetLatestCompactionEntry,\n\ttype SessionHeader,\n\tSessionManager,\n} from \"./session-manager.js\";\nimport type { SessionStats } from \"./session-stats.js\";\nimport type { SettingsManager } from \"./settings-manager.js\";\nimport { getPythonSkillRuntimeInfo, type Skill } from \"./skills.js\";\nimport {\n\tparseRefineCommandOptions,\n\tparseSessionSlashCommand,\n\tparseSlashCommand,\n\ttype SessionSlashCommand,\n\ttype SlashCommandInfo,\n} from \"./slash-commands.js\";\nimport { createSyntheticSourceInfo, type SourceInfo } from \"./source-info.js\";\nimport { type BuildSystemPromptOptions, buildSystemPrompt } from \"./system-prompt.js\";\nimport { THINKING_LEVELS } from \"./thinking-levels.js\";\nimport { type BashOperations, createLocalBashOperations } from \"./tools/bash.js\";\nimport { createAllToolDefinitions } from \"./tools/index.js\";\nimport { IpythonKernelProvisioner } from \"./tools/ipython.js\";\nimport { createToolDefinitionFromAgentTool } from \"./tools/tool-definition-wrapper.js\";\nimport { addAssistantUsage, emptyUsage } from \"./usage.js\";\nimport { SERPER_CREDENTIAL_ID, SERPER_ENV_VAR, WEBSEARCH_SKILL_NAME } from \"./websearch-credential.js\";\n\nexport type { GoalState, GoalStatus } from \"./goals.js\";\nexport type { SessionStats } from \"./session-stats.js\";\nexport { type ParsedSkillBlock, parseSkillBlock } from \"./skill-blocks.js\";\n\nexport type RlmChildAgentStatus = \"queued\" | \"running\" | \"done\" | \"error\" | \"cancelled\";\n\nexport interface RlmChildAgentActivity {\n\tkind: \"waiting\" | \"writing\" | \"executing\";\n\ttoolName?: string;\n}\n\nexport interface RlmChildAgentSnapshot {\n\tid: string;\n\tparentId?: string;\n\tactiveSessionId?: string;\n\tsessionName?: string;\n\tmodel?: string;\n\tlabel: string;\n\tstatus: RlmChildAgentStatus;\n\tdurationMs?: number;\n\tanswerPreview?: string;\n\ttoolUseCount?: number;\n\ttokenCount?: number;\n\trecap?: string;\n\tsessionDir: string;\n\tactivity?: RlmChildAgentActivity;\n\trepliedSinceTask?: boolean;\n\terror?: string;\n}\n\nexport type CompactionReason = \"manual\" | \"threshold\" | \"overflow\" | \"requested\";\n\nexport type AgentSessionEvent =\n\t| AgentEvent\n\t| {\n\t\t\ttype: \"ipython_sent_agent_message\";\n\t\t\ttoolCallId: string;\n\t\t\tmessage: KernelSentAgentMessage;\n\t }\n\t| { type: \"session_action_update\"; actions: SessionActionSnapshot }\n\t| {\n\t\t\ttype: \"compaction_start\";\n\t\t\treason: CompactionReason;\n\t\t\tcustomInstructions?: string;\n\t }\n\t| { type: \"session_info_changed\"; name: string | undefined }\n\t| { type: \"thinking_level_changed\"; level: ThinkingLevel }\n\t| { type: \"service_tier_changed\"; serviceTier: ServiceTier }\n\t| {\n\t\t\ttype: \"compaction_end\";\n\t\t\treason: CompactionReason;\n\t\t\tresult: CompactionResult | undefined;\n\t\t\taborted: boolean;\n\t\t\twillRetry: boolean;\n\t\t\terrorMessage?: string;\n\t\t\terrorSeverity?: \"warning\" | \"error\";\n\t\t\tcustomInstructions?: string;\n\t }\n\t| {\n\t\t\ttype: \"auto_retry_start\";\n\t\t\tattempt: number;\n\t\t\tmaxAttempts: number;\n\t\t\tdelayMs: number;\n\t\t\terrorMessage: string;\n\t }\n\t| {\n\t\t\ttype: \"auto_retry_end\";\n\t\t\tsuccess: boolean;\n\t\t\tattempt: number;\n\t\t\tfinalError?: string;\n\t }\n\t| {\n\t\t\ttype: \"auth_stale\";\n\t\t\tprovider: string;\n\t\t\tsourceTokens?: readonly AuthSourceToken[];\n\t }\n\t| { type: \"rlm_child_update\"; child: RlmChildAgentSnapshot }\n\t| { type: \"recap_update\"; recap: string | undefined }\n\t| { type: \"goal_update\"; goal: GoalState }\n\t| {\n\t\t\ttype: \"bash_start\";\n\t\t\tcommand: string;\n\t\t\texcludeFromContext: boolean;\n\t\t\ttransient?: boolean;\n\t\t\trunId?: string;\n\t }\n\t| { type: \"bash_output\"; chunk: string }\n\t| {\n\t\t\ttype: \"bash_end\";\n\t\t\texitCode: number | undefined;\n\t\t\tcancelled: boolean;\n\t\t\ttruncated: boolean;\n\t\t\tfullOutputPath?: string;\n\t\t\terrorMessage?: string;\n\t\t\ttransient?: boolean;\n\t\t\trunId?: string;\n\t }\n\t| { type: \"refine_complete\"; result: RefinementResult }\n\t| { type: \"refine_failed\"; error: string };\n\nexport type AgentSessionEventListener = (event: AgentSessionEvent) => void;\n\ntype UserBashEndDetails = {\n\texitCode: number | undefined;\n\tcancelled: boolean;\n\ttruncated: boolean;\n\tfullOutputPath?: string;\n\terrorMessage?: string;\n};\n\nexport class CompactionSkippedError extends Error {}\n\n/** Thrown when a session_before_refine extension skips the refinement round. */\nexport class RefineSkippedError extends Error {}\n\nexport interface AgentSessionConfig {\n\tagent: Agent;\n\tsessionManager: SessionManager;\n\tsettingsManager: SettingsManager;\n\tserviceTierPreference?: ServiceTier;\n\tcwd: string;\n\tagentDir?: string;\n\tscopedModels?: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }>;\n\tresourceLoader: ResourceLoader;\n\tcustomTools?: ToolDefinition[];\n\tmodelRegistry: ModelRegistry;\n\tinitialActiveToolNames?: string[];\n\tallowedToolNames?: string[];\n\t/**\n\t * Whether the built-in long-running goals feature is available: the bundled\n\t * goal skill in the Python kernel, its goal.* host handlers, and /goal.\n\t * Default: true.\n\t */\n\tincludeGoals?: boolean;\n\tagentMessageController?: AgentSessionMessageController;\n\tagentObserveController?: AgentObserveController;\n\t/**\n\t * Whether the bundled compact skill and its compact.* host handlers are\n\t * available to the model. Default: the compaction.agentCallable setting.\n\t */\n\tincludeCompactSkill?: boolean;\n\t/**\n\t * Optional host-side controller for the bundled rlm-heartbeat Python skill.\n\t * When omitted, rlm_heartbeat.* host requests are unavailable.\n\t */\n\trlmHeartbeatController?: AgentRlmHeartbeatController;\n\t/**\n\t * Optional MCP integration manager. When present, its mcp.* host requests\n\t * (refresh, begin_login) are exposed to the kernel.\n\t */\n\tmcpManager?: McpManager;\n\t/**\n\t * Override base tools (useful for custom runtimes).\n\t *\n\t * These are synthesized into minimal ToolDefinitions internally so AgentSession can keep\n\t * a definition-first registry even when callers provide plain AgentTool instances.\n\t */\n\tbaseToolsOverride?: Record<string, AgentTool>;\n\textensionRunnerRef?: { current?: ExtensionRunner };\n\tsessionStartEvent?: SessionStartEvent;\n\trlmDepth?: number;\n\trlmMaxDepth?: number;\n\trlmSessionDir?: string;\n\trlmParentNodeId?: string;\n\trlmParentAgent?: string;\n\tsubagentRuntimeHost?: SubagentRuntimeHost;\n\tautonomous?: AgentAutonomousConfig;\n\tprewarmIpythonKernel?: boolean;\n\tautoRefineReviewer?: AutoRefineReviewer;\n\t/**\n\t * When true, auto-refine runs synchronously between turns at the\n\t * shouldStopAfterTurn boundary instead of in the background after\n\t * agent_end. Used for print/headless autonomous runs so refinement\n\t * never overlaps the primary model request. Default: false.\n\t */\n\tserializedRefine?: boolean;\n\t/**\n\t * Initial goal to seed at session creation. Only applied when rlmDepth\n\t * is 0 and no persisted thread_goal_state entry exists in the branch.\n\t */\n\tinitialGoal?: { objective: string; tokenBudget?: number };\n}\n\nexport interface ExtensionBindings {\n\tuiContext?: ExtensionUIContext;\n\tcommandContextActions?: ExtensionCommandContextActions;\n\tshutdownHandler?: ShutdownHandler;\n\tonError?: ExtensionErrorListener;\n}\n\nexport interface AutoRefineReviewRequest {\n\treason: AutoRefineReason;\n\tturnsSinceLastReview: number;\n}\n\n/**\n * Discriminated result from a serialized-mode background planning pass.\n * - \"plan\": review approved and planning succeeded; carry the exact plan,\n * options, and abort controller so the boundary can apply directly\n * without a second planning request.\n * - \"skip\": reviewer declined; no refine needed.\n * - \"failure\": review or planning threw; boundary should not retry.\n */\nexport type SerializedBackgroundPlanResult =\n\t| {\n\t\t\tstatus: \"plan\";\n\t\t\tplan: RefinementPlan;\n\t\t\toptions: { instructions?: string; rollbackId?: string; global?: boolean };\n\t\t\tabort: AbortController;\n\t\t\tbranchVersion: number;\n\t }\n\t| { status: \"skip\"; explicit?: boolean }\n\t| { status: \"invalidated\"; branchVersion: number }\n\t| {\n\t\t\tstatus: \"failure\";\n\t\t\texplicit: boolean;\n\t\t\toptions: { instructions?: string; rollbackId?: string; global?: boolean };\n\t\t\tbranchVersion: number;\n\t };\n\nexport type AutoRefineReviewer = (request: AutoRefineReviewRequest, signal?: AbortSignal) => Promise<AutoRefineReview>;\n\nexport interface PromptOptions {\n\texpandPromptTemplates?: boolean;\n\timages?: ImageContent[];\n\tstreamingBehavior?: \"steer\" | \"followUp\";\n\tfollowUpQueueKey?: string;\n\tsource?: InputSource;\n\tpreflightResult?: (success: boolean, queued?: boolean) => void;\n\tqueueIfBusy?: boolean;\n\tresumeIfIdle?: boolean;\n\tinternalPrompt?: boolean;\n\tsuppressAutonomousContinuation?: boolean;\n\tskipInputHandlers?: boolean;\n\tsignal?: AbortSignal;\n\tadmissionCommitted?: () => void;\n\tagentMessageId?: string;\n\tcontent?: (TextContent | ImageContent)[];\n\tcustomMessage?: CustomMessage;\n}\n\ninterface InternalPromptOptions extends PromptOptions {\n\tskipPrePromptWork?: boolean;\n\treturnAfterAccepted?: boolean;\n\tagentMessageId?: string;\n}\n\ntype SubmissionExtensionCommandPolicy = \"execute\" | \"reject\" | \"ignore\";\n\ninterface SubmissionNormalizationPolicy {\n\tparseSessionCommands: boolean;\n\textensionCommands: SubmissionExtensionCommandPolicy;\n\tinputSource?: InputSource;\n\texpandSkills: boolean;\n\texpandPromptTemplates: boolean;\n}\n\ntype NormalizedSubmission =\n\t| { kind: \"prompt\"; text: string; images?: ImageContent[] }\n\t| {\n\t\t\tkind: \"sessionCommand\";\n\t\t\ttext: string;\n\t\t\timages?: ImageContent[];\n\t\t\tcommand: SessionSlashCommand;\n\t }\n\t| { kind: \"extensionCommand\"; completion: Promise<void> }\n\t| { kind: \"handled\" };\n\ntype PreTurnCompactionTiming = \"beforeModelSelection\" | \"afterModelSelection\" | \"skip\";\ntype RefineBarrierPolicy = \"always\" | \"ifInFlight\" | \"skip\";\n\ninterface CommitPreparationPolicy {\n\tinitialRefineBarrier: RefineBarrierPolicy;\n\tflushPendingBashBeforeValidation: boolean;\n\tvalidateModelAndAuth: boolean;\n\tawaitPendingModelSelection: boolean;\n\tpreTurnCompaction: PreTurnCompactionTiming;\n\tfinalRefineBarrier: RefineBarrierPolicy;\n}\n\ninterface CommitPreparationSteps<TPrepared, TCommitted> {\n\tafterValidation?: () => void;\n\tprepare: () => Promise<TPrepared>;\n\tshouldCommit?: (prepared: TPrepared) => boolean;\n\tbeforeFinalRefineBarrier?: (prepared: TPrepared) => void;\n\tcommit: (prepared: TPrepared, passedFinalRefineBarrier: boolean) => TCommitted;\n}\n\ntype QueuedAgentMessage = UserMessage | CustomMessage;\ntype SessionInputSchedule = \"steer\" | \"followUp\";\n\nexport interface TurnExecutionPolicy {\n\tpreparation: CommitPreparationPolicy;\n\trunBeforeAgentStart: boolean;\n\tnextTurnContextTiming: \"preparation\" | \"commit\" | \"skip\";\n\tpreserveEmptyExtensionPrompt: boolean;\n\tcompletionIncludesRetryChain: boolean;\n}\n\nfunction turnExecutionPoliciesEqual(left: TurnExecutionPolicy, right: TurnExecutionPolicy): boolean {\n\treturn (\n\t\tleft.preparation.initialRefineBarrier === right.preparation.initialRefineBarrier &&\n\t\tleft.preparation.flushPendingBashBeforeValidation === right.preparation.flushPendingBashBeforeValidation &&\n\t\tleft.preparation.validateModelAndAuth === right.preparation.validateModelAndAuth &&\n\t\tleft.preparation.awaitPendingModelSelection === right.preparation.awaitPendingModelSelection &&\n\t\tleft.preparation.preTurnCompaction === right.preparation.preTurnCompaction &&\n\t\tleft.preparation.finalRefineBarrier === right.preparation.finalRefineBarrier &&\n\t\tleft.runBeforeAgentStart === right.runBeforeAgentStart &&\n\t\tleft.nextTurnContextTiming === right.nextTurnContextTiming &&\n\t\tleft.preserveEmptyExtensionPrompt === right.preserveEmptyExtensionPrompt &&\n\t\tleft.completionIncludesRetryChain === right.completionIncludesRetryChain\n\t);\n}\n\ninterface PreparedTurnPayload extends SessionTurnPayload {\n\timages?: ImageContent[];\n\tcontent?: (TextContent | ImageContent)[];\n\tcustomMessage?: CustomMessage;\n\tprepared?: PreparedPromptPreparation;\n\texecutionPolicy: TurnExecutionPolicy;\n\tqueueVisible: boolean;\n\tacceptedAgentMessage: boolean;\n\tacceptedBeforeCompletion: boolean;\n\tcaptureRunMessages?: Set<AgentMessage>;\n\tcancelledDispatchEnded?: boolean;\n}\n\ninterface PreparedCommandPayload extends SessionCommandPayload {\n\timages?: ImageContent[];\n}\n\ntype QueuedSessionAction = SessionAction<PreparedTurnPayload | PreparedCommandPayload>;\n\ninterface PreparedPromptPreparation {\n\tresult: Awaited<ReturnType<ExtensionRunner[\"emitBeforeAgentStart\"]>>;\n\tbasePromptSnapshot: string;\n}\n\nclass DeferredSessionInputError extends Error {}\n\nfunction oncePreflight(\n\tpreflightResult: ((success: boolean, queued?: boolean) => void) | undefined,\n): (success: boolean, queued?: boolean) => void {\n\tlet settled = false;\n\treturn (success, queued = false) => {\n\t\tif (!settled) {\n\t\t\tsettled = true;\n\t\t\tpreflightResult?.(success, queued);\n\t\t}\n\t};\n}\n\ninterface RestoredPromptInput {\n\ttext: string;\n\tcontent?: (TextContent | ImageContent)[];\n\timages?: ImageContent[];\n\tqueueKey?: string;\n\tagentMessageId?: string;\n\tcustomMessage?: CustomMessage;\n\tprefixMessages?: CustomMessage[];\n}\n\nexport const SESSION_ACTION_RECOVERY_FORMAT_VERSION = 1;\n\nexport interface SessionActionRecoveryRecord {\n\tid: string;\n\trole: DeliveryRecord[\"role\"];\n\tmessage: QueuedAgentMessage;\n\townerActionId: string;\n}\n\nexport type SessionActionRecoveryPayload =\n\t| {\n\t\t\tkind: \"turn\";\n\t\t\ttext: string;\n\t\t\tpreview?: string;\n\t\t\trecords: SessionActionRecoveryRecord[];\n\t\t\timages?: ImageContent[];\n\t\t\tcontent?: (TextContent | ImageContent)[];\n\t\t\tcustomMessage?: CustomMessage;\n\t\t\texecutionPolicy: TurnExecutionPolicy;\n\t\t\tqueueVisible: boolean;\n\t\t\tacceptedAgentMessage: boolean;\n\t\t\tacceptedBeforeCompletion: boolean;\n\t }\n\t| {\n\t\t\tkind: \"session_command\";\n\t\t\ttext: string;\n\t\t\tcommand: SessionSlashCommand;\n\t\t\timages?: ImageContent[];\n\t };\n\nexport interface SessionActionRecoveryAction {\n\tid: string;\n\tsource: InputSource | \"internal\";\n\tdelivery: DeliveryPolicy;\n\twake: WakePolicy;\n\tpayload: SessionActionRecoveryPayload;\n\tqueueKey?: string;\n\tagentMessageId?: string;\n\tsuppressAutonomousContinuation?: boolean;\n}\n\nexport interface SessionActionRecoverySnapshot {\n\tformatVersion: typeof SESSION_ACTION_RECOVERY_FORMAT_VERSION;\n\tactions: SessionActionRecoveryAction[];\n}\n\nfunction cloneCustomMessage(message: CustomMessage): CustomMessage {\n\treturn {\n\t\t...message,\n\t\tcontent: Array.isArray(message.content) ? message.content.map((block) => ({ ...block })) : message.content,\n\t};\n}\n\nfunction cloneQueuedAgentMessage(message: QueuedAgentMessage): QueuedAgentMessage {\n\tif (message.role === \"custom\") return cloneCustomMessage(message);\n\treturn {\n\t\t...message,\n\t\tcontent: Array.isArray(message.content) ? message.content.map((block) => ({ ...block })) : message.content,\n\t};\n}\n\nfunction primaryDeliveryRecord(action: QueuedSessionAction): DeliveryRecord {\n\tif (action.payload.kind !== \"turn\") throw new Error(`Session action ${action.id} is not a turn`);\n\tconst record = action.payload.records.find((candidate) => candidate.role === \"primary\");\n\tif (!record) throw new Error(`Turn action ${action.id} has no primary delivery record`);\n\treturn record;\n}\n\nfunction normalizeMessageContent(content: string | (TextContent | ImageContent)[]): {\n\ttext: string;\n\timages?: ImageContent[];\n} {\n\tif (typeof content === \"string\") return { text: content };\n\tconst text = content\n\t\t.filter((part): part is TextContent => part.type === \"text\")\n\t\t.map((part) => part.text)\n\t\t.join(\"\\n\");\n\tconst images = content.filter((part): part is ImageContent => part.type === \"image\");\n\treturn { text, ...(images.length > 0 ? { images } : {}) };\n}\n\nfunction queuedAgentMessagePreview(action: QueuedSessionAction): string {\n\tconst payload = action.payload;\n\tif (payload.kind === \"session_command\") return payload.text;\n\tif (payload.customMessage && isAgentSessionMessage(payload.customMessage)) {\n\t\treturn `${AGENT_MESSAGE_RECEIVED_PREVIEW_LABEL}: ${payload.customMessage.details.message}`;\n\t}\n\treturn payload.preview ?? payload.text;\n}\n\nfunction visibleSessionActionProjection(actions: readonly QueuedSessionAction[]): readonly QueuedSessionAction[] {\n\treturn actions.filter(\n\t\t(action) =>\n\t\t\taction.payload.kind === \"session_command\" ||\n\t\t\taction.payload.queueVisible ||\n\t\t\taction.payload.acceptedAgentMessage,\n\t);\n}\n\nconst IPYTHON_SENT_AGENT_MESSAGE_CUSTOM_ENTRY = \"ipython_sent_agent_message\";\n\ninterface PersistedIpythonSentAgentMessage {\n\ttoolCallId: string;\n\tmessage: KernelSentAgentMessage;\n}\n\nfunction isObjectRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction parsePersistedIpythonSentAgentMessage(value: unknown): PersistedIpythonSentAgentMessage | undefined {\n\tif (!isObjectRecord(value) || typeof value.toolCallId !== \"string\" || !isObjectRecord(value.message)) {\n\t\treturn undefined;\n\t}\n\tconst { id, message, deliveryStatus, target } = value.message;\n\tif (\n\t\ttypeof id !== \"string\" ||\n\t\ttypeof message !== \"string\" ||\n\t\t(deliveryStatus !== \"delivered\" && deliveryStatus !== \"queued\") ||\n\t\t!isObjectRecord(target) ||\n\t\ttypeof target.activeSessionId !== \"string\" ||\n\t\ttypeof target.sessionId !== \"string\"\n\t) {\n\t\treturn undefined;\n\t}\n\treturn {\n\t\ttoolCallId: value.toolCallId,\n\t\tmessage: {\n\t\t\tid,\n\t\t\tmessage,\n\t\t\tdeliveryStatus,\n\t\t\ttarget: {\n\t\t\t\tactiveSessionId: target.activeSessionId,\n\t\t\t\tsessionId: target.sessionId,\n\t\t\t\t...(typeof target.sessionName === \"string\" ? { sessionName: target.sessionName } : {}),\n\t\t\t},\n\t\t},\n\t};\n}\n\nfunction appendSentAgentMessageToToolResult(\n\tmessage: AgentMessage,\n\ttoolCallId: string,\n\tsentMessage: KernelSentAgentMessage,\n): boolean {\n\tif (message.role !== \"toolResult\" || message.toolName !== \"ipython\" || message.toolCallId !== toolCallId) {\n\t\treturn false;\n\t}\n\tconst details = isObjectRecord(message.details) ? message.details : {};\n\tconst current = Array.isArray(details.sentAgentMessages) ? details.sentAgentMessages : [];\n\tif (current.some((entry) => isObjectRecord(entry) && entry.id === sentMessage.id)) {\n\t\treturn true;\n\t}\n\tmessage.details = {\n\t\t...details,\n\t\tsentAgentMessages: [...current, sentMessage],\n\t};\n\treturn true;\n}\n\nfunction injectedMessagePreviewLabel(message: CustomMessage): string | undefined {\n\tswitch (message.customType) {\n\t\tcase HEARTBEAT_PROMPT_CUSTOM_TYPE:\n\t\t\treturn HEARTBEAT_PROMPT_PREVIEW_LABEL;\n\t\tcase GOAL_CONTEXT_CUSTOM_TYPE:\n\t\t\treturn GOAL_CONTEXT_PREVIEW_LABEL;\n\t\tcase BACKGROUND_PROCESS_COMPLETED_CUSTOM_TYPE:\n\t\t\treturn \"Background process completed\";\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\ninterface AgentMessageDeferred {\n\tpromise: Promise<void>;\n\tresolve: () => void;\n\treject: (error: Error) => void;\n}\n\ninterface AgentMessageOutcome {\n\tdelivery?: AgentMessageDeferred;\n\tcompletion?: AgentMessageDeferred;\n}\n\nfunction createAgentMessageDeferred(): AgentMessageDeferred {\n\tconst deferred = {} as AgentMessageDeferred;\n\tdeferred.promise = new Promise<void>((resolve, reject) => {\n\t\tdeferred.resolve = resolve;\n\t\tdeferred.reject = reject;\n\t});\n\tdeferred.promise.catch(() => undefined);\n\treturn deferred;\n}\n\n/** One-shot settlement for a scheduled post-compaction continuation; a settled failure is never re-exposed to later waiters. */\ninterface PostCompactionContinuationSettlement extends AgentMessageDeferred {\n\tsettled: boolean;\n}\n\nfunction createPostCompactionContinuationSettlement(): PostCompactionContinuationSettlement {\n\treturn { ...createAgentMessageDeferred(), settled: false };\n}\n\nexport interface ModelCycleResult {\n\tmodel: Model<any>;\n\tthinkingLevel: ThinkingLevel;\n\tserviceTier: ServiceTier;\n\tisScoped: boolean;\n}\n\ninterface ModelSelectOptions {\n\twaitForExtensions?: boolean;\n}\n\ninterface ToolDefinitionEntry {\n\tdefinition: ToolDefinition;\n\tsourceInfo: SourceInfo;\n}\n\ntype GoalSlashCommand =\n\t| { kind: \"status\" }\n\t| { kind: \"clear\" }\n\t| { kind: \"pause\" }\n\t| { kind: \"resume\" }\n\t| { kind: \"start\"; objective: string; tokenBudget?: number };\n\ntype AutonomousSlashCommand = { kind: \"status\" } | { kind: \"on\" } | { kind: \"off\" };\n\nimport type { RlmMaxDepthSource, RlmMaxDepthStatus, SetRlmMaxDepthResult } from \"./rlm-max-depth.js\";\n\nexport type { RlmMaxDepthSource, RlmMaxDepthStatus, SetRlmMaxDepthResult } from \"./rlm-max-depth.js\";\n\ninterface PersistedRlmMaxDepthState {\n\tmaxDepth: number;\n}\n\ntype AutonomousRuntimeSnapshot = Pick<\n\tAutonomousRuntimeState,\n\t\"continuationsUsed\" | \"gateAttempts\" | \"lastGateFailure\" | \"lastGateFailureSnapshot\"\n>;\n\ninterface RlmChildRun {\n\tid: string;\n\tprompt: string;\n\tsessionName: string;\n\tsessionDir: string;\n\tmodel: Model<Api>;\n\tstatus: RlmChildAgentStatus;\n\terror?: string;\n\tabort: () => void;\n\tpublication: AgentMessageDeferred;\n\t/** Resolves after terminal result publication and detached-run cleanup finish. */\n\tsettlement: AgentMessageDeferred;\n\t/** Child session, once its runtime exists. Used to cancel nested child runs. */\n\tsession?: AgentSession;\n\tsettled: boolean;\n\t/** Do not inject a late terminal notice after the parent session is aborted. */\n\tsuppressTerminalNotice?: boolean;\n\t/** Excluded from future strong barriers after an authoritative cancellation cut. */\n\tabandonedForQuiescence?: boolean;\n\t/** Selector snapshot for an admitted explicit delete. */\n\tdetachedDeletion?: RlmSubagentRegistryEntry;\n\t/** Shared physical runtime cleanup owned by the explicit-delete path. */\n\tdeletionCleanup?: Promise<void>;\n\tdeletionCleanupObserver?: Promise<boolean>;\n\t/** Resolves when a deletion may release its selector reservation. */\n\tdeletionReservation: AgentMessageDeferred;\n\tdeletionCleanupFailed?: boolean;\n\tdeletionRunFinished?: boolean;\n\treportDeletionCleanupFailure?: (error: unknown) => Promise<void>;\n\temitUpdate?: () => void;\n\tunsubscribe?: () => void;\n}\n\ninterface RlmSubagentModelSelection {\n\tmodel: Model<Api>;\n}\n\nconst KERNEL_STATE_LISTING_TIMEOUT_MS = 5000;\nconst RLM_MAX_DEPTH_STATE_CUSTOM_TYPE = \"rlm_max_depth_state\";\n\nfunction noopRlmChildAbort(): void {}\nfunction noopRlmChildEventUnsubscribe(): void {}\n\nfunction autoRefineInstructions(reason: AutoRefineReason, review: AutoRefineReview): string {\n\tconst detail = review.instructions\n\t\t? `\nReviewer instructions: ${review.instructions}`\n\t\t: \"\";\n\treturn `Automatic refine review triggered by ${reason}. Only create/update/delete local harness entries if there is clear evidence that should help this session continue. Prefer an empty edits array over speculative or one-off memories. Do not promote anything global unless explicitly requested. Reviewer rationale: ${review.rationale}${detail}`;\n}\n\nfunction isNonNegativeInteger(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isSafeInteger(value) && value >= 0;\n}\n\nfunction parseDepth(value: string | undefined, fallback: number, name: string): number {\n\tif (value === undefined || value === \"\") {\n\t\treturn fallback;\n\t}\n\tif (!/^\\d+$/.test(value)) {\n\t\tthrow new Error(`${name} must be a non-negative integer`);\n\t}\n\tconst parsed = Number(value);\n\tif (!isNonNegativeInteger(parsed)) {\n\t\tthrow new Error(`${name} must be a non-negative integer`);\n\t}\n\treturn parsed;\n}\n\nfunction isPersistedRlmMaxDepthState(value: unknown): value is PersistedRlmMaxDepthState {\n\treturn (\n\t\ttypeof value === \"object\" && value !== null && isNonNegativeInteger((value as PersistedRlmMaxDepthState).maxDepth)\n\t);\n}\n\nfunction parseGoalBudgetValue(value: string): number {\n\tif (!/^[1-9]\\d*$/.test(value)) {\n\t\tthrow new Error(\"Goal token budget must be a positive integer.\");\n\t}\n\tconst budget = validateGoalBudget(Number(value));\n\tif (budget === undefined) {\n\t\tthrow new Error(\"Goal token budget must be a positive integer.\");\n\t}\n\treturn budget;\n}\n\nexport function compactRlmText(text: string, maxLength = 160): string {\n\tconst compact = text.replace(/\\s+/g, \" \").trim();\n\tif (compact.length <= maxLength) {\n\t\treturn compact;\n\t}\n\treturn `${compact.slice(0, Math.max(0, maxLength - 3)).trimEnd()}...`;\n}\n\n// Child-agent label: collapse to one line but keep the full prompt — the TUI\n// truncates to the visible width and elides shared prefixes, so capping here\n// would only hide the divergence between near-identical sibling prompts.\nexport function rlmChildLabel(prompt: string): string {\n\treturn prompt.replace(/\\s+/g, \" \").trim() || \"child agent\";\n}\n\nfunction readAssistantText(message: AssistantMessage): string {\n\treturn message.content\n\t\t.filter((block) => block.type === \"text\")\n\t\t.map((block) => block.text)\n\t\t.join(\"\");\n}\n\nfunction waitForPromiseOrAbort<T>(\n\tpromise: Promise<T>,\n\tsignal: AbortSignal | undefined,\n\tabortMessage: string,\n): Promise<T> {\n\tif (!signal) return promise;\n\tif (signal.aborted) return Promise.reject(new Error(abortMessage));\n\treturn new Promise<T>((resolve, reject) => {\n\t\tconst onAbort = () => {\n\t\t\tcleanup();\n\t\t\treject(new Error(abortMessage));\n\t\t};\n\t\tconst cleanup = () => signal.removeEventListener(\"abort\", onAbort);\n\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t// Close the listener-registration race before observing the awaited work.\n\t\tif (signal.aborted) return onAbort();\n\t\tpromise.then(\n\t\t\t(value) => {\n\t\t\t\tcleanup();\n\t\t\t\tresolve(value);\n\t\t\t},\n\t\t\t(error: unknown) => {\n\t\t\t\tcleanup();\n\t\t\t\treject(error);\n\t\t\t},\n\t\t);\n\t});\n}\n\nfunction attributeChildUsage(parentUsage: Usage, childUsage: Usage): void {\n\tconst parentContextTokens =\n\t\tparentUsage.totalTokens ||\n\t\tparentUsage.input + parentUsage.output + parentUsage.cacheRead + parentUsage.cacheWrite;\n\t// Recursive children are launched from an assistant tool call, so the parent assistant\n\t// message carries their billable usage for session-level cost totals.\n\taddAssistantUsage(parentUsage, childUsage);\n\t// Child work affects session-level billable totals, not the parent's model-facing context size.\n\tparentUsage.totalTokens = parentContextTokens;\n}\n\nexport class AgentSession {\n\treadonly agent: Agent;\n\treadonly sessionManager: SessionManager;\n\treadonly settingsManager: SettingsManager;\n\tprivate _serviceTierPreference: ServiceTier;\n\n\tprivate _scopedModels: Array<{\n\t\tmodel: Model<any>;\n\t\tthinkingLevel?: ThinkingLevel;\n\t}>;\n\n\tprivate _unsubscribeAgent?: () => void;\n\tprivate _eventListeners: AgentSessionEventListener[] = [];\n\tprivate _lastSessionActionSnapshot: SessionActionSnapshot = {\n\t\tqueuedCount: 0,\n\t\tsteering: [],\n\t\tfollowUps: [],\n\t};\n\tprivate _agentEventQueue: Promise<void> = Promise.resolve();\n\n\t/** Session-owned actions. Items are never fed into Agent.steer/followUp. */\n\tprivate readonly _actionStore = new ActionStore<QueuedSessionAction>();\n\tprivate _sessionInputPump: Promise<void> = Promise.resolve();\n\tprivate _sessionInputPumpRequested = false;\n\t// Invalidates preparation when a branch pause starts and finishes before its next await resumes.\n\tprivate _sessionInputPumpEpoch = 0;\n\tprivate _sessionInputArrivalEpoch = 0;\n\t// Persists abort/restart suspension after the initiating call returns.\n\tprivate _sessionInputPumpSuspended = false;\n\tprivate _sessionInputSuspendedForUpdateRestart = false;\n\t// Branch mutation pause leases can overlap and must all release before dispatch resumes.\n\tprivate readonly _queuedWorkPauses = new Set<symbol>();\n\tprivate readonly _sessionInputAdmissionPauses = new Set<symbol>();\n\tprivate readonly _durableRlmTerminalNoticeActionIds = new Set<string>();\n\tprivate readonly _backgroundProcessCompletionIds = new Set<string>();\n\tprivate _sessionActionCommitTail: Promise<void> = Promise.resolve();\n\tprivate _sessionActionCommitOwner: symbol | undefined;\n\tprivate _pendingSessionActionFenceWaiters = 0;\n\tprivate readonly _sessionActionCommitContext = new AsyncLocalStorage<symbol>();\n\tprivate readonly _sessionActionCommitDisposeAbortController = new AbortController();\n\t// Checkpoint and handoff waiters share lifecycle-edge notifications to avoid polling.\n\tprivate readonly _sessionInputCheckpointWaiters = new Set<() => void>();\n\tprivate _pendingNextTurnMessages: CustomMessage[] = [];\n\n\tprivate _goalState: GoalState = emptyGoalState();\n\tprivate _goalAccountingStartedAt: number | undefined = undefined;\n\tprivate _goalContinuationAwaitsRlmWork = false;\n\tprivate _goalAccountedAssistantMessages = new WeakSet<AssistantMessage>();\n\tprivate _goalAbortInProgress = false;\n\tprivate _autonomousState: AutonomousRuntimeState;\n\tprivate _autonomousContinuationSuppressionDepth = 0;\n\tprivate _autonomousContinuationSuppressedMessages = new WeakSet<AgentMessage>();\n\n\tprivate _compactionAbortController: AbortController | undefined = undefined;\n\tprivate _autoCompactionAbortController: AbortController | undefined = undefined;\n\tprivate _compactionOperation: Promise<void> | undefined = undefined;\n\t/** One recovery attempt per overflow; \"reported\" dedups the failure notice. */\n\tprivate _overflowRecovery: \"idle\" | \"attempted\" | \"reported\" = \"idle\";\n\tprivate _continueAfterThresholdCompaction = false;\n\tprivate _pendingRequestedCompaction: { customInstructions?: string } | undefined;\n\tprivate _pendingRequestedRefine: { instructions?: string; global?: boolean } | undefined;\n\n\tprivate _branchSummaryAbortController: AbortController | undefined = undefined;\n\tprivate _branchSummaryOperation: Promise<void> | undefined = undefined;\n\n\tprivate _retryAbortController: AbortController | undefined = undefined;\n\tprivate _retryAttempt = 0;\n\tprivate _retryPromise: Promise<void> | undefined = undefined;\n\tprivate _retryResolve: (() => void) | undefined = undefined;\n\tprivate _retryAuthFailureSources: AuthSourceToken[] = [];\n\tprivate _agentMessageOutcomes = new Map<string, AgentMessageOutcome>();\n\tprivate _lateIpythonSentAgentMessages = new Map<string, KernelSentAgentMessage[]>();\n\t/** Outcome disclosures whose session-file append failed; retained for context rebuilds. */\n\tprivate readonly _unpersistedOutcomes: CustomMessage[] = [];\n\n\tprivate _bashAbortController: AbortController | undefined = undefined;\n\tprivate _userBashRunning = false;\n\tprivate _userBashAbortRequested = false;\n\tprivate _pendingBashMessages: BashExecutionMessage[] = [];\n\n\tprivate _extensionRunner!: ExtensionRunner;\n\tprivate _execEnvProvider?: () => Record<string, string | undefined> | undefined;\n\tprivate _turnIndex = 0;\n\tprivate _modelSelectEmitQueue: Promise<void> = Promise.resolve();\n\tprivate _modelSelectEmitQueueIdle = true;\n\tprivate _modelSelectEmitContext = new AsyncLocalStorage<boolean>();\n\n\tprivate _resourceLoader: ResourceLoader;\n\tprivate _customTools: ToolDefinition[];\n\tprivate _baseToolDefinitions: Map<string, ToolDefinition> = new Map();\n\tprivate _cwd: string;\n\tprivate _agentDir?: string;\n\tprivate _extensionRunnerRef?: { current?: ExtensionRunner };\n\tprivate _initialActiveToolNames?: string[];\n\tprivate _allowedToolNames?: Set<string>;\n\tprivate _includeGoals: boolean;\n\tprivate _includeCompactSkill: boolean;\n\tprivate _rlmHeartbeatController?: AgentRlmHeartbeatController;\n\tprivate _agentMessageController?: AgentSessionMessageController;\n\tprivate _agentObserveController?: AgentObserveController;\n\tprivate _mcpManager?: McpManager;\n\tprivate _baseToolsOverride?: Record<string, AgentTool>;\n\tprivate _sessionStartEvent: SessionStartEvent;\n\tprivate _extensionUIContext?: ExtensionUIContext;\n\tprivate _extensionCommandContextActions?: ExtensionCommandContextActions;\n\tprivate _extensionShutdownHandler?: ShutdownHandler;\n\tprivate _extensionErrorListener?: ExtensionErrorListener;\n\tprivate _extensionErrorUnsubscriber?: () => void;\n\tprivate _disposed = false;\n\tprivate readonly _disposeCallbacks = new Set<() => void | Promise<void>>();\n\tprivate _disposeCallbacksPromise?: Promise<void>;\n\t// Set at the start of async teardown so a child finishing mid-disposeAsync doesn't\n\t// re-populate the retained map after it's been cleared.\n\tprivate _disposing = false;\n\tprivate _disposeAsyncPromise?: Promise<void>;\n\tprivate _ipythonKernelProvisioner?: IpythonKernelProvisioner;\n\t/** Artifact dir backing the current provisioner's kernel snapshot, if any. */\n\tprivate _ipythonKernelSnapshotDir?: string;\n\t/** True once the runtime has been built once; later builds are in-process rebuilds (/reload). */\n\tprivate _ipythonRuntimeBuilt = false;\n\tprivate readonly _prewarmIpythonKernel: boolean;\n\tprivate _rlmDepth: number;\n\tprivate readonly _configuredRlmMaxDepth: number | undefined;\n\tprivate _rlmMaxDepth: number;\n\tprivate _rlmMaxDepthSource: RlmMaxDepthSource;\n\tprivate _rlmSessionDir?: string;\n\tprivate _rlmParentNodeId?: string;\n\tprivate _rlmParentAgent?: string;\n\tprivate _repliedToParentSinceTask: boolean | undefined;\n\tprivate _parentReplyCount = 0;\n\tprivate _subagentRuntimeHost?: SubagentRuntimeHost;\n\tprivate _activeRlmChildRuns = new Map<string, RlmChildRun>();\n\tprivate _unsettledRlmChildRuns = new Set<RlmChildRun>();\n\tprivate _abandonedRlmQuiescenceChildIds = new Set<string>();\n\tprivate _rlmQuiescenceWaitAborts = new Set<AbortController>();\n\tprivate _pendingRlmSubagentSessionNames = new Set<string>();\n\t// Inline mode keeps finished child sessions so the inspector can still read them;\n\t// the daemon does the same by leaving the child session resident in its registry.\n\tprivate _rlmChildSessions = new Map<string, AgentSession>();\n\tprivate _deletedRlmChildIds = new Set<string>();\n\t// Failed explicit deletes stay hidden from listings but retain their original\n\t// selector so a later delete can retry cleanup without orphaning the runtime.\n\tprivate _rlmChildCleanupFailures = new Map<string, RlmSubagentRegistryEntry>();\n\tprivate _deletingRlmChildren = new Map<\n\t\tstring,\n\t\t{\n\t\t\tsubagent: RlmSubagentRegistryEntry;\n\t\t\tpromise: Promise<RlmDeleteSubagentResult>;\n\t\t}\n\t>();\n\t// Kept alive for retained children so nested updates (e.g. a grandchild cancel)\n\t// still forward to root; torn down when the retained child is disposed.\n\tprivate _rlmChildUnsubscribes = new Map<string, () => void>();\n\t/** Latest recap for this session, written by the daemon summarizer; read by a parent to label its child snapshots. */\n\tprivate _currentRecap?: string;\n\n\tprivate _modelRegistry: ModelRegistry;\n\n\tprivate _toolRegistry: Map<string, AgentTool> = new Map();\n\tprivate _toolDefinitions: Map<string, ToolDefinitionEntry> = new Map();\n\tprivate _toolPromptSnippets: Map<string, string> = new Map();\n\tprivate _toolPromptGuidelines: Map<string, string[]> = new Map();\n\n\tprivate _baseSystemPrompt = \"\";\n\tprivate _baseSystemPromptOptions!: BuildSystemPromptOptions;\n\tprivate _assistantTurnsSinceAutoRefine = 0;\n\tprivate _lastAutoRefineReviewAt = 0;\n\tprivate _autoRefineInProgress = false;\n\tprivate readonly _autoRefineOperations = new Set<Promise<void>>();\n\tprivate readonly _scheduledAutoRefineTimers = new Set<ReturnType<typeof setTimeout>>();\n\tprivate _compactAutoRefinePending = false;\n\tprivate _turnIntervalAutoRefinePending = false;\n\tprivate _postCompactionContinuationScheduled = false;\n\tprivate _postCompactionContinuationTimer: ReturnType<typeof setTimeout> | undefined;\n\tprivate _postCompactionContinuationSettlement: PostCompactionContinuationSettlement | undefined;\n\tprivate _postCompactionContinuationMessages: AgentMessage[] = [];\n\tprivate _scheduledPostCompactionContinuationMessages: AgentMessage[] = [];\n\tprivate _queuedAutonomousThresholdContinuations = new WeakMap<AssistantMessage, AgentMessage>();\n\tprivate _queuedAutonomousContinuationSnapshots = new WeakMap<AgentMessage, AutonomousRuntimeSnapshot>();\n\tprivate _pendingThresholdCompactionAutonomousMessages: AgentMessage[] = [];\n\tprivate _queuedGoalThresholdContinuation: AgentMessage | undefined;\n\tprivate _pendingAutoRefineReview: { reason: AutoRefineReason; review: AutoRefineReview } | undefined;\n\tprivate _autoRefineBranchVersion = 0;\n\tprivate _autoRefineReviewAbort?: AbortController;\n\tprivate _refineAbortController?: AbortController;\n\tprivate readonly _autoRefineReviewer?: AutoRefineReviewer;\n\tprivate readonly _serializedRefine: boolean;\n\tprivate _refineInFlight?: Promise<void>;\n\tprivate _refinePlanInFlight?: Promise<void>;\n\tprivate _serializedPlanInFlight?: Promise<SerializedBackgroundPlanResult | undefined>;\n\tprivate _serializedPlanClaim?: Promise<void>;\n\tprivate _serializedExplicitRefineOptions?: {\n\t\tinstructions?: string;\n\t\tglobal?: boolean;\n\t};\n\n\tconstructor(config: AgentSessionConfig) {\n\t\tthis.agent = config.agent;\n\t\tthis.sessionManager = config.sessionManager;\n\t\tthis.settingsManager = config.settingsManager;\n\t\tthis._serviceTierPreference = config.serviceTierPreference ?? config.agent.state.serviceTier;\n\t\tthis._scopedModels = config.scopedModels ?? [];\n\t\tthis._resourceLoader = config.resourceLoader;\n\t\tthis._customTools = config.customTools ?? [];\n\t\tthis._cwd = config.cwd;\n\t\tthis._agentDir = config.agentDir;\n\t\tthis._modelRegistry = config.modelRegistry;\n\t\tthis._extensionRunnerRef = config.extensionRunnerRef;\n\t\tthis._initialActiveToolNames = config.initialActiveToolNames;\n\t\tthis._allowedToolNames = config.allowedToolNames ? new Set(config.allowedToolNames) : undefined;\n\t\tthis._includeGoals = config.includeGoals ?? true;\n\t\tthis._includeCompactSkill = config.includeCompactSkill ?? this.settingsManager.getCompactionAgentCallable();\n\t\tthis._rlmHeartbeatController = config.rlmHeartbeatController;\n\t\tthis._agentMessageController = config.agentMessageController;\n\t\tthis._agentObserveController = config.agentObserveController;\n\t\tthis._mcpManager = config.mcpManager;\n\t\tthis._baseToolsOverride = config.baseToolsOverride;\n\t\tthis._sessionStartEvent = config.sessionStartEvent ?? { type: \"session_start\", reason: \"startup\" };\n\t\tconst headerRlmDepth = this.sessionManager.getHeader()?.rlmDepth;\n\t\tthis._rlmDepth =\n\t\t\tconfig.rlmDepth ??\n\t\t\t(isNonNegativeInteger(headerRlmDepth) ? headerRlmDepth : parseDepth(process.env.RLM_DEPTH, 0, \"RLM_DEPTH\"));\n\t\tthis._configuredRlmMaxDepth = config.rlmMaxDepth;\n\t\tif (this._configuredRlmMaxDepth !== undefined && !isNonNegativeInteger(this._configuredRlmMaxDepth)) {\n\t\t\tthrow new Error(\"rlmMaxDepth must be a non-negative integer\");\n\t\t}\n\t\tconst resolvedRlmMaxDepth = this._resolveRlmMaxDepth();\n\t\tthis._rlmMaxDepth = resolvedRlmMaxDepth.maxDepth;\n\t\tthis._rlmMaxDepthSource = resolvedRlmMaxDepth.source;\n\t\tthis._prewarmIpythonKernel = (config.prewarmIpythonKernel ?? false) && this._rlmDepth === 0;\n\t\tthis._autoRefineReviewer = config.autoRefineReviewer;\n\t\tthis._serializedRefine = config.serializedRefine ?? false;\n\t\tthis._rlmSessionDir = config.rlmSessionDir;\n\t\tthis._rlmParentNodeId = config.rlmParentNodeId;\n\t\tthis._rlmParentAgent = config.rlmParentAgent;\n\t\t// A resumed child may have replied before this process started; false would\n\t\t// claim knowledge that is not present in the session transcript.\n\t\tthis._repliedToParentSinceTask =\n\t\t\tthis._rlmDepth > 0 && this.sessionManager.getBranch().some((entry) => entry.type === \"message\")\n\t\t\t\t? undefined\n\t\t\t\t: false;\n\t\tthis._subagentRuntimeHost = config.subagentRuntimeHost;\n\t\tthis._autonomousState = createAutonomousRuntimeState(config.autonomous, {\n\t\t\tcwd: this._cwd,\n\t\t});\n\t\tthis._goalState = this._loadPersistedGoalState();\n\t\t// Seed initial goal from CLI --goal flag, but only for top-level sessions\n\t\t// and only when the branch contains only bootstrap entry types (model_change,\n\t\t// thinking_level_change, service_tier_change) and no persisted\n\t\t// thread_goal_state. This prevents reseeding after clear/complete/error\n\t\t// or restart/rehydration of a session that already has messages or a goal.\n\t\tif (this._rlmDepth === 0 && config.initialGoal && this._isBranchSeedable()) {\n\t\t\tthis._goalState = this._startGoal(config.initialGoal.objective, config.initialGoal.tokenBudget);\n\t\t\t// Goal context is the model's only source of goal visibility; action\n\t\t\t// admission is unavailable mid-construction, so ride the next turn.\n\t\t\tthis._pendingNextTurnMessages.push(createGoalContextMessage(this._goalState, \"continuation\"));\n\t\t}\n\t\tthis._restoreLateIpythonSentAgentMessages();\n\t\tif (this._goalState.status === \"active\") {\n\t\t\tthis._goalAccountingStartedAt = Date.now();\n\t\t}\n\n\t\tthis._unsubscribeAgent = this.agent.subscribe(this._handleAgentEvent);\n\t\tthis._installAgentToolHooks();\n\t\tthis._installAgentTurnHook();\n\t\tthis._installAgentContinuationHook();\n\n\t\tthis._buildRuntime({\n\t\t\tactiveToolNames: this._initialActiveToolNames,\n\t\t\tincludeAllExtensionTools: true,\n\t\t});\n\t}\n\n\t/** Refreshes MCP provider registrations without rebuilding the session runtime. */\n\trefreshMcpProviders(): void {\n\t\tthis._mcpManager?.refresh();\n\t}\n\n\t/**\n\t * Set the RLM heartbeat controller after construction. Used by\n\t * print/headless mode to attach an in-process heartbeat scheduler\n\t * when the session is created outside the daemon.\n\t */\n\tsetRlmHeartbeatController(controller: AgentRlmHeartbeatController): void {\n\t\tif (this._rlmHeartbeatController === controller) {\n\t\t\treturn;\n\t\t}\n\t\tthis._rlmHeartbeatController = controller;\n\t\tthis._buildRuntime({\n\t\t\tactiveToolNames: this.getActiveToolNames(),\n\t\t\tincludeAllExtensionTools: true,\n\t\t});\n\t\tthis._baseSystemPrompt = this._rebuildSystemPrompt(this.getActiveToolNames());\n\t\tthis.agent.state.systemPrompt = this._baseSystemPrompt;\n\t}\n\n\treplaceAcpMcpServers(servers: readonly AcpMcpServerConfig[], ownerId: string): void {\n\t\tif (this.isStreaming) throw new Error(\"Cannot replace ACP MCP servers while the agent is running\");\n\t\tif (!this._mcpManager) {\n\t\t\tif (servers.length > 0) throw new Error(\"MCP is unavailable in this session\");\n\t\t\treturn;\n\t\t}\n\t\tif (!this._mcpManager.replaceAcpServers(servers, ownerId)) return;\n\t\tthis._rebuildRuntimeForAcpMcpServers();\n\t}\n\n\tasync releaseAcpMcpServers(ownerId: string, serverNames: readonly string[]): Promise<void> {\n\t\tif (!this._mcpManager?.canReleaseAcpServers(ownerId)) return;\n\t\tif (this._mcpManager.replaceAcpServers([], ownerId)) {\n\t\t\t// Host MCP handlers read this manager dynamically, so credentials disappear\n\t\t\t// before the kernel-side transport is closed.\n\t\t\tthis._baseSystemPrompt = this._rebuildSystemPrompt(this.getActiveToolNames());\n\t\t\tthis.agent.state.systemPrompt = this._baseSystemPrompt;\n\t\t}\n\t\tconst names = [...new Set(serverNames)];\n\t\tif (names.length === 0) return;\n\n\t\tconst inputPause = this.acquireSessionInputPause();\n\t\ttry {\n\t\t\t// Do not rebuild or kill the notebook. Wait for the current turn, then ask\n\t\t\t// the kernel-owned MCP registry to close only these cached transports.\n\t\t\tawait this.agent.waitForIdle();\n\t\t\tawait this._agentEventQueue;\n\t\t\tconst manager = this._ipythonKernelProvisioner?.manager;\n\t\t\tif (!manager?.isRunning) return;\n\t\t\tconst code = [\n\t\t\t\t\"import importlib as _prime_importlib\",\n\t\t\t\t'_prime_mcp = _prime_importlib.import_module(\"rlm.mcp\")',\n\t\t\t\t`_prime_mcp_names = ${JSON.stringify(names)}`,\n\t\t\t\t\"_prime_mcp_errors = []\",\n\t\t\t\t\"for _prime_mcp_name in _prime_mcp_names:\",\n\t\t\t\t\" try:\",\n\t\t\t\t\" await _prime_mcp.reload(_prime_mcp_name)\",\n\t\t\t\t\" except BaseException as _prime_mcp_error:\",\n\t\t\t\t\" _prime_mcp_errors.append(_prime_mcp_error)\",\n\t\t\t\t\"if _prime_mcp_errors:\",\n\t\t\t\t\" raise _prime_mcp_errors[0]\",\n\t\t\t\t\"del _prime_mcp, _prime_importlib, _prime_mcp_names, _prime_mcp_errors, _prime_mcp_name\",\n\t\t\t].join(\"\\n\");\n\t\t\tconst result = await manager.execute(code);\n\t\t\tif (result.status !== \"ok\") {\n\t\t\t\tthrow new Error(`Failed to close ACP MCP kernel transports: ${result.stderr || \"kernel error\"}`);\n\t\t\t}\n\t\t} finally {\n\t\t\tinputPause.release();\n\t\t}\n\t}\n\n\tprivate _rebuildRuntimeForAcpMcpServers(): void {\n\t\tthis._buildRuntime({\n\t\t\tactiveToolNames: this.getActiveToolNames(),\n\t\t\tincludeAllExtensionTools: true,\n\t\t});\n\t\tthis._baseSystemPrompt = this._rebuildSystemPrompt(this.getActiveToolNames());\n\t\tthis.agent.state.systemPrompt = this._baseSystemPrompt;\n\t}\n\n\tget modelRegistry(): ModelRegistry {\n\t\treturn this._modelRegistry;\n\t}\n\n\tsetSubagentRuntimeHost(host?: SubagentRuntimeHost): void {\n\t\tthis._subagentRuntimeHost = host;\n\t}\n\n\tprivate async _getRequiredRequestAuth(model: Model<any>): Promise<{\n\t\tapiKey: string;\n\t\theaders?: Record<string, string>;\n\t}> {\n\t\tconst result = await this._modelRegistry.getApiKeyAndHeaders(model);\n\t\tif (!result.ok) {\n\t\t\tif (result.error.startsWith(\"No API key found\")) {\n\t\t\t\tthrow new Error(formatNoApiKeyFoundMessage(model.provider));\n\t\t\t}\n\t\t\tthrow new Error(result.error);\n\t\t}\n\t\tif (result.apiKey) {\n\t\t\treturn { apiKey: result.apiKey, headers: result.headers };\n\t\t}\n\n\t\tconst isOAuth = this._modelRegistry.isUsingOAuth(model);\n\t\tif (isOAuth) {\n\t\t\tthrow new Error(formatAuthenticationFailedMessage(model.provider));\n\t\t}\n\t\tthrow new Error(formatNoApiKeyFoundMessage(model.provider));\n\t}\n\n\t/**\n\t * Install tool hooks once on the Agent instance.\n\t *\n\t * The callbacks read `this._extensionRunner` at execution time, so extension reload swaps in the\n\t * new runner without reinstalling hooks. Extension-specific tool wrappers are still used to adapt\n\t * registered tool execution to the extension context. Tool call and tool result interception now\n\t * happens here instead of in wrappers.\n\t */\n\tprivate _installAgentToolHooks(): void {\n\t\tthis.agent.beforeToolCall = async ({ toolCall, args }) => {\n\t\t\tconst runner = this._extensionRunner;\n\t\t\tif (!runner.hasHandlers(\"tool_call\")) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tawait this._agentEventQueue;\n\n\t\t\ttry {\n\t\t\t\treturn await runner.emitToolCall({\n\t\t\t\t\ttype: \"tool_call\",\n\t\t\t\t\ttoolName: toolCall.name,\n\t\t\t\t\ttoolCallId: toolCall.id,\n\t\t\t\t\tinput: args as Record<string, unknown>,\n\t\t\t\t});\n\t\t\t} catch (err) {\n\t\t\t\tif (err instanceof Error) {\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\t\t\t\tthrow new Error(`Extension failed, blocking execution: ${String(err)}`);\n\t\t\t}\n\t\t};\n\n\t\tthis.agent.afterToolCall = async ({ toolCall, args, result, isError }) => {\n\t\t\tconst runner = this._extensionRunner;\n\t\t\tif (!runner.hasHandlers(\"tool_result\")) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tconst hookResult = await runner.emitToolResult({\n\t\t\t\ttype: \"tool_result\",\n\t\t\t\ttoolName: toolCall.name,\n\t\t\t\ttoolCallId: toolCall.id,\n\t\t\t\tinput: args as Record<string, unknown>,\n\t\t\t\tcontent: result.content,\n\t\t\t\tdetails: result.details,\n\t\t\t\tisError,\n\t\t\t});\n\n\t\t\tif (!hookResult) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tcontent: hookResult.content,\n\t\t\t\tdetails: hookResult.details,\n\t\t\t\tisError: hookResult.isError ?? isError,\n\t\t\t};\n\t\t};\n\t}\n\n\tprivate _installAgentContinuationHook(): void {\n\t\tthis.agent.getContinuationMessages = (context, signal) => this._getContinuationMessages(context, signal);\n\t}\n\n\tprivate _installAgentTurnHook(): void {\n\t\tthis.agent.shouldStopBeforeTurn = () => this._shouldStopBeforeTurn();\n\t\tthis.agent.shouldStopAfterTurn = (context) => this._shouldStopAfterTurn(context);\n\t}\n\n\tprivate _emit(event: AgentSessionEvent): void {\n\t\tfor (const l of this._eventListeners) {\n\t\t\ttry {\n\t\t\t\tl(event);\n\t\t\t} catch {\n\t\t\t\t// A failing observer must not prevent other subscribers from\n\t\t\t\t// receiving lifecycle and persistence events.\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _emitQueueUpdate(): void {\n\t\tconst actions = this.getSessionActionSnapshot();\n\t\tif (JSON.stringify(actions) === JSON.stringify(this._lastSessionActionSnapshot)) return;\n\t\tthis._lastSessionActionSnapshot = actions;\n\t\tthis._emit({ type: \"session_action_update\", actions });\n\t}\n\n\tprivate _restoreLateIpythonSentAgentMessages(): void {\n\t\tthis._lateIpythonSentAgentMessages.clear();\n\t\tfor (const entry of this.sessionManager.getBranch()) {\n\t\t\tif (entry.type !== \"custom\" || entry.customType !== IPYTHON_SENT_AGENT_MESSAGE_CUSTOM_ENTRY) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst persisted = parsePersistedIpythonSentAgentMessage(entry.data);\n\t\t\tif (persisted) {\n\t\t\t\tthis._rememberLateIpythonSentAgentMessage(persisted.toolCallId, persisted.message);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _rememberLateIpythonSentAgentMessage(toolCallId: string, message: KernelSentAgentMessage): boolean {\n\t\tconst messages = this._lateIpythonSentAgentMessages.get(toolCallId) ?? [];\n\t\tconst isNew = !messages.some((entry) => entry.id === message.id);\n\t\tif (isNew) {\n\t\t\tmessages.push(message);\n\t\t\tthis._lateIpythonSentAgentMessages.set(toolCallId, messages);\n\t\t}\n\t\tfor (let index = this.agent.state.messages.length - 1; index >= 0; index -= 1) {\n\t\t\tif (appendSentAgentMessageToToolResult(this.agent.state.messages[index], toolCallId, message)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn isNew;\n\t}\n\n\tprivate _applyLateIpythonSentAgentMessages(message: AgentMessage): void {\n\t\tif (message.role !== \"toolResult\" || message.toolName !== \"ipython\") {\n\t\t\treturn;\n\t\t}\n\t\tfor (const sentMessage of this._lateIpythonSentAgentMessages.get(message.toolCallId) ?? []) {\n\t\t\tappendSentAgentMessageToToolResult(message, message.toolCallId, sentMessage);\n\t\t}\n\t}\n\n\tprivate _recordLateIpythonSentAgentMessage(toolCallId: string, message: KernelSentAgentMessage): void {\n\t\tconst record = () => {\n\t\t\tif (this._disposed || !this._rememberLateIpythonSentAgentMessage(toolCallId, message)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.sessionManager.appendCustomEntry(IPYTHON_SENT_AGENT_MESSAGE_CUSTOM_ENTRY, { toolCallId, message });\n\t\t\tthis._emit({ type: \"ipython_sent_agent_message\", toolCallId, message });\n\t\t};\n\t\tthis._agentEventQueue = this._agentEventQueue.then(record, record);\n\t\tthis._agentEventQueue.catch(() => {});\n\t}\n\n\tprivate _emitGoalUpdate(): void {\n\t\tthis._emit({ type: \"goal_update\", goal: this.goalState });\n\t}\n\n\tprivate _loadPersistedRlmMaxDepthState(): PersistedRlmMaxDepthState | undefined {\n\t\tconst branch = this.sessionManager.getBranch();\n\t\tfor (let i = branch.length - 1; i >= 0; i--) {\n\t\t\tconst entry = branch[i];\n\t\t\tif (\n\t\t\t\tentry.type === \"custom\" &&\n\t\t\t\tentry.customType === RLM_MAX_DEPTH_STATE_CUSTOM_TYPE &&\n\t\t\t\tisPersistedRlmMaxDepthState(entry.data)\n\t\t\t) {\n\t\t\t\treturn entry.data;\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate _resolveRlmMaxDepth(): {\n\t\tmaxDepth: number;\n\t\tsource: RlmMaxDepthSource;\n\t} {\n\t\tconst persisted = this._loadPersistedRlmMaxDepthState();\n\t\tif (persisted) {\n\t\t\treturn { maxDepth: persisted.maxDepth, source: \"chat\" };\n\t\t}\n\t\tif (this._configuredRlmMaxDepth !== undefined) {\n\t\t\treturn { maxDepth: this._configuredRlmMaxDepth, source: \"inherited\" };\n\t\t}\n\t\tconst global = this.settingsManager.getRlmMaxDepth();\n\t\tif (global !== undefined && isNonNegativeInteger(global)) {\n\t\t\treturn { maxDepth: global, source: \"global\" };\n\t\t}\n\t\tconst env = process.env.RLM_MAX_DEPTH;\n\t\tif (env !== undefined && env !== \"\") {\n\t\t\treturn { maxDepth: parseDepth(env, 1, \"RLM_MAX_DEPTH\"), source: \"env\" };\n\t\t}\n\t\treturn { maxDepth: 2, source: \"default\" };\n\t}\n\n\tprivate _loadPersistedGoalState(): GoalState {\n\t\tconst branch = this.sessionManager.getBranch();\n\t\tfor (let i = branch.length - 1; i >= 0; i--) {\n\t\t\tconst entry = branch[i];\n\t\t\tif (\n\t\t\t\tentry.type === \"custom\" &&\n\t\t\t\tentry.customType === GOAL_STATE_CUSTOM_TYPE &&\n\t\t\t\tisPersistedGoalState(entry.data)\n\t\t\t) {\n\t\t\t\treturn normalizeGoalState(entry.data);\n\t\t\t}\n\t\t}\n\t\treturn emptyGoalState();\n\t}\n\n\t/**\n\t * Whether the session branch is seedable for an initial goal. Returns true\n\t * only when the branch contains exclusively bootstrap entry types\n\t * (model_change, thinking_level_change, service_tier_change) and no\n\t * thread_goal_state custom entry. Any message, custom entry, or persisted\n\t * goal (including cleared/complete/error) means the session has been used\n\t * and should not be reseeded.\n\t */\n\tprivate _isBranchSeedable(): boolean {\n\t\tconst branch = this.sessionManager.getBranch();\n\t\tfor (const entry of branch) {\n\t\t\tswitch (entry.type) {\n\t\t\t\tcase \"model_change\":\n\t\t\t\tcase \"thinking_level_change\":\n\t\t\t\tcase \"service_tier_change\":\n\t\t\t\t\tcontinue;\n\t\t\t\tcase \"custom\":\n\t\t\t\t\tif (entry.customType === GOAL_STATE_CUSTOM_TYPE) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn false;\n\t\t\t\tdefault:\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate _reloadGoalStateFromBranch(): void {\n\t\tthis._goalState = this._loadPersistedGoalState();\n\t\tthis._goalAccountingStartedAt = this._goalState.status === \"active\" ? Date.now() : undefined;\n\t\tthis._emitGoalUpdate();\n\t}\n\n\tprivate _reloadRlmMaxDepthFromBranch(): void {\n\t\tconst previousMaxDepth = this._rlmMaxDepth;\n\t\tconst resolved = this._resolveRlmMaxDepth();\n\t\tthis._rlmMaxDepth = resolved.maxDepth;\n\t\tthis._rlmMaxDepthSource = resolved.source;\n\t\tif (resolved.maxDepth !== previousMaxDepth) {\n\t\t\tthis._baseSystemPrompt = this._rebuildSystemPrompt(this.getActiveToolNames());\n\t\t\tthis.agent.state.systemPrompt = this._baseSystemPrompt;\n\t\t}\n\t}\n\n\tprivate _persistGoalState(goal: GoalState): void {\n\t\tthis.sessionManager.appendCustomEntry(GOAL_STATE_CUSTOM_TYPE, goal);\n\t\t// Force flush so the goal state is durable on disk immediately,\n\t\t// even before the first assistant response. This ensures idempotent\n\t\t// restart/rehydration can detect the persisted goal.\n\t\tthis.sessionManager.flushNow();\n\t}\n\n\tprivate _setGoalState(next: GoalState, options: { persist?: boolean } = {}): void {\n\t\tconst normalized = normalizeGoalState({\n\t\t\t...next,\n\t\t\tupdatedAt: Date.now(),\n\t\t});\n\t\tthis._goalState = normalized;\n\t\tif (normalized.status === \"active\") {\n\t\t\tthis._goalAccountingStartedAt ??= Date.now();\n\t\t} else {\n\t\t\tthis._goalAccountingStartedAt = undefined;\n\t\t}\n\t\tif (options.persist !== false) {\n\t\t\tthis._persistGoalState(normalized);\n\t\t}\n\t\tthis._emitGoalUpdate();\n\t}\n\n\tprivate _goalWithCurrentWallClock(now = Date.now()): GoalState {\n\t\tif (this._goalState.status !== \"active\" || !this._goalAccountingStartedAt) {\n\t\t\treturn this._goalState;\n\t\t}\n\t\tconst elapsedSeconds = Math.floor((now - this._goalAccountingStartedAt) / 1000);\n\t\tif (elapsedSeconds <= 0) {\n\t\t\treturn this._goalState;\n\t\t}\n\t\treturn {\n\t\t\t...this._goalState,\n\t\t\ttimeUsedSeconds: this._goalState.timeUsedSeconds + elapsedSeconds,\n\t\t};\n\t}\n\n\tprivate _goalWithAccountedWallClock(): GoalState {\n\t\tconst now = Date.now();\n\t\tconst goal = this._goalWithCurrentWallClock(now);\n\t\tif (goal !== this._goalState) {\n\t\t\tthis._goalAccountingStartedAt = now;\n\t\t}\n\t\treturn goal;\n\t}\n\n\tprivate _cancelSessionActions(\n\t\tpredicate: (action: QueuedSessionAction) => boolean,\n\t\terror: Error,\n\t\tcandidates = this._actionStore.clearableActions(),\n\t): QueuedSessionAction[] {\n\t\tconst matching = candidates.filter(predicate);\n\t\tconst previousStates = new Map(matching.map((action) => [action.id, action.lifecycle.state]));\n\t\tconst preparing = this._actionStore\n\t\t\t.activeActions()\n\t\t\t.filter(\n\t\t\t\t(action): action is SessionAction<PreparedTurnPayload> =>\n\t\t\t\t\taction.payload.kind === \"turn\" && action.lifecycle.state === \"preparing\",\n\t\t\t);\n\t\tconst previousAnchor = preparing.at(-1);\n\t\tconst actions = this._actionStore.remove(predicate, candidates);\n\t\tconst restorableMessages: CustomMessage[] = [];\n\t\tconst removed = new Set(actions);\n\t\tif (previousAnchor && removed.has(previousAnchor)) {\n\t\t\tfor (const action of preparing) {\n\t\t\t\tif (!removed.has(action)) action.payload.prepared = undefined;\n\t\t\t}\n\t\t}\n\t\tfor (const action of actions) {\n\t\t\tconst ticket = this._actionStore.ticketFor(action);\n\t\t\tif (\n\t\t\t\taction.payload.kind === \"turn\" &&\n\t\t\t\t(action.payload.acceptedAgentMessage ||\n\t\t\t\t\t!action.payload.queueVisible ||\n\t\t\t\t\tpreviousStates.get(action.id) !== \"queued\")\n\t\t\t) {\n\t\t\t\tticket.rejectDelivered(error);\n\t\t\t} else {\n\t\t\t\tticket.settleDelivered({ status: \"not_applicable\" });\n\t\t\t}\n\t\t\tticket.settleCompleted(error);\n\t\t\tconst dispatched = previousStates.get(action.id) === \"committing\" && action.payload.kind === \"turn\";\n\t\t\tif (action.payload.kind === \"turn\") {\n\t\t\t\tconst payload = action.payload;\n\t\t\t\tconst restorable = payload.records\n\t\t\t\t\t.filter(\n\t\t\t\t\t\t(record): record is DeliveryRecord & { message: CustomMessage } =>\n\t\t\t\t\t\t\t(record.role === \"next_turn\" || (payload.acceptedAgentMessage && record.role === \"prefix\")) &&\n\t\t\t\t\t\t\trecord.message.role === \"custom\" &&\n\t\t\t\t\t\t\t!record.durable,\n\t\t\t\t\t)\n\t\t\t\t\t.map((record) => cloneCustomMessage(record.message));\n\t\t\t\trestorableMessages.push(...restorable);\n\t\t\t\tif (dispatched) {\n\t\t\t\t\tpayload.captureRunMessages = new Set(payload.records.map((record) => record.message));\n\t\t\t\t\tthis.agent.state.messages = this.agent.state.messages.filter(\n\t\t\t\t\t\t(message) => !payload.captureRunMessages?.has(message),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!dispatched) {\n\t\t\t\tthis._actionStore.releaseTerminal(action);\n\t\t\t}\n\t\t}\n\t\tthis._pendingNextTurnMessages.unshift(...restorableMessages);\n\t\tif (actions.length > 0) this._notifySessionInputCheckpointChange();\n\t\treturn actions;\n\t}\n\n\tprivate _clearQueuedGoalContexts(): void {\n\t\tthis._goalContinuationAwaitsRlmWork = false;\n\t\tthis._pendingNextTurnMessages = this._pendingNextTurnMessages.filter(\n\t\t\t(message) => message.customType !== GOAL_CONTEXT_CUSTOM_TYPE,\n\t\t);\n\t\tthis.agent.removeQueuedMessages(\n\t\t\t(message) => message.role === \"custom\" && message.customType === GOAL_CONTEXT_CUSTOM_TYPE,\n\t\t);\n\t\tthis._cancelSessionActions(\n\t\t\t(action) =>\n\t\t\t\taction.payload.kind === \"turn\" && action.payload.customMessage?.customType === GOAL_CONTEXT_CUSTOM_TYPE,\n\t\t\tnew Error(\"Queued goal context was cleared before delivery.\"),\n\t\t);\n\t\tthis._emitQueueUpdate();\n\t}\n\n\tprivate _startGoal(objectiveText: string, tokenBudget: number | undefined): GoalState {\n\t\tconst objective = validateGoalObjective(objectiveText);\n\t\tconst budget = validateGoalBudget(tokenBudget);\n\t\tconst now = Date.now();\n\t\tconst goal: GoalState = {\n\t\t\tactive: true,\n\t\t\tstatus: \"active\",\n\t\t\tgoalId: randomUUID(),\n\t\t\tobjective,\n\t\t\ttokenBudget: budget,\n\t\t\ttokensUsed: 0,\n\t\t\ttimeUsedSeconds: 0,\n\t\t\tcontinuationsUsed: 0,\n\t\t\tcreatedAt: now,\n\t\t\tupdatedAt: now,\n\t\t};\n\t\tthis._goalAccountingStartedAt = now;\n\t\tthis._goalContinuationAwaitsRlmWork = false;\n\t\tthis._setGoalState(goal);\n\t\treturn this._goalState;\n\t}\n\n\tprivate _clearGoal(): void {\n\t\tthis._clearQueuedGoalContexts();\n\t\tthis._setGoalState(emptyGoalState());\n\t}\n\n\tprivate _pauseGoal(reason = \"Paused by user\"): void {\n\t\tthis._clearQueuedGoalContexts();\n\t\tif (this._goalState.status !== \"active\") {\n\t\t\tthis._emitGoalUpdate();\n\t\t\treturn;\n\t\t}\n\t\tconst goal = this._goalWithAccountedWallClock();\n\t\tthis._setGoalState({\n\t\t\t...goal,\n\t\t\tactive: false,\n\t\t\tstatus: \"paused\",\n\t\t\tlastReason: reason,\n\t\t\tlastError: undefined,\n\t\t});\n\t}\n\n\tprivate async _resumeGoal(): Promise<void> {\n\t\tif (!this._goalState.objective) {\n\t\t\tthis._emitGoalUpdate();\n\t\t\treturn;\n\t\t}\n\t\tif (this._goalState.status !== \"paused\" && this._goalState.status !== \"budget_limited\") {\n\t\t\tthis._emitGoalUpdate();\n\t\t\treturn;\n\t\t}\n\t\tconst exhausted =\n\t\t\tthis._goalState.tokenBudget !== undefined && this._goalState.tokensUsed >= this._goalState.tokenBudget;\n\t\tconst nextStatus: GoalStatus = exhausted ? \"budget_limited\" : \"active\";\n\t\tthis._setGoalState({\n\t\t\t...this._goalState,\n\t\t\tactive: nextStatus === \"active\",\n\t\t\tstatus: nextStatus,\n\t\t\tlastReason: exhausted ? \"Goal token budget already reached\" : undefined,\n\t\t\tlastError: undefined,\n\t\t});\n\t\tif (nextStatus === \"active\") {\n\t\t\tawait this._runOrQueueGoalContext(\"continuation\");\n\t\t}\n\t}\n\n\tprivate _finishGoalWithError(errorMessage: string): void {\n\t\tif (!this._goalState.objective || this._goalState.status !== \"active\") {\n\t\t\treturn;\n\t\t}\n\t\tconst goal = this._goalWithAccountedWallClock();\n\t\tthis._setGoalState({\n\t\t\t...goal,\n\t\t\tactive: false,\n\t\t\tstatus: \"error\",\n\t\t\tlastReason: errorMessage,\n\t\t\tlastError: errorMessage,\n\t\t});\n\t}\n\n\tprivate _finishGoalForTerminalAssistantMessage(message: AssistantMessage): void {\n\t\tif (this._goalState.status !== \"active\") {\n\t\t\treturn;\n\t\t}\n\n\t\tif (message.stopReason === \"aborted\") {\n\t\t\tthis._goalAbortInProgress = false;\n\t\t\treturn;\n\t\t}\n\n\t\tif (message.stopReason === \"error\") {\n\t\t\tif (this._goalAbortInProgress) {\n\t\t\t\tthis._goalAbortInProgress = false;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._finishGoalWithError(message.errorMessage || \"Assistant response failed\");\n\t\t}\n\t}\n\n\tprivate _stopGoalContinuationForTerminalMessage(message: AssistantMessage): boolean {\n\t\tif (message.stopReason !== \"error\" && message.stopReason !== \"aborted\") {\n\t\t\treturn false;\n\t\t}\n\t\ttry {\n\t\t\tthis._finishGoalForTerminalAssistantMessage(message);\n\t\t} catch {\n\t\t\t// Goal hooks must not reject; listener failures should not crash the agent loop.\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate _parseGoalSlashCommand(text: string): GoalSlashCommand | undefined {\n\t\tconst command = parseSessionSlashCommand(text);\n\t\tif (command?.name !== \"goal\") return undefined;\n\n\t\tconst rest = command.args;\n\t\tconst normalized = rest.toLowerCase();\n\t\tif (!rest || normalized === \"status\") {\n\t\t\treturn { kind: \"status\" };\n\t\t}\n\t\tif (normalized === \"clear\" || normalized === \"stop\") {\n\t\t\treturn { kind: \"clear\" };\n\t\t}\n\t\tif (normalized === \"pause\") {\n\t\t\treturn { kind: \"pause\" };\n\t\t}\n\t\tif (normalized === \"resume\") {\n\t\t\treturn { kind: \"resume\" };\n\t\t}\n\n\t\tlet tokenBudget: number | undefined;\n\t\tlet objective = rest;\n\t\tconst firstToken = rest.split(/\\s+/, 1)[0] ?? \"\";\n\t\tif (\n\t\t\tfirstToken === \"--budget\" ||\n\t\t\tfirstToken === \"--token-budget\" ||\n\t\t\tfirstToken.startsWith(\"--budget=\") ||\n\t\t\tfirstToken.startsWith(\"--token-budget=\")\n\t\t) {\n\t\t\tlet valueText: string;\n\t\t\tif (firstToken === \"--budget\" || firstToken === \"--token-budget\") {\n\t\t\t\tconst withoutFlag = rest.slice(firstToken.length).trimStart();\n\t\t\t\tconst nextSpace = withoutFlag.search(/\\s/);\n\t\t\t\tif (nextSpace < 0) {\n\t\t\t\t\tthrow new Error(\"Usage: /goal [--budget <tokens>] <objective>\");\n\t\t\t\t}\n\t\t\t\tvalueText = withoutFlag.slice(0, nextSpace);\n\t\t\t\tobjective = withoutFlag.slice(nextSpace + 1).trim();\n\t\t\t} else {\n\t\t\t\tconst separator = firstToken.indexOf(\"=\");\n\t\t\t\tvalueText = firstToken.slice(separator + 1);\n\t\t\t\tobjective = rest.slice(firstToken.length).trim();\n\t\t\t}\n\t\t\ttokenBudget = parseGoalBudgetValue(valueText);\n\t\t}\n\n\t\treturn {\n\t\t\tkind: \"start\",\n\t\t\tobjective: validateGoalObjective(objective),\n\t\t\ttokenBudget,\n\t\t};\n\t}\n\n\tprivate _parseAutonomousSlashCommand(text: string): AutonomousSlashCommand | undefined {\n\t\tconst command = parseSessionSlashCommand(text);\n\t\tif (command?.name !== \"autonomous\") return undefined;\n\t\tconst rest = command.args.toLowerCase();\n\t\tif (!rest || rest === \"status\") {\n\t\t\treturn { kind: \"status\" };\n\t\t}\n\t\tif (rest === \"on\" || rest === \"enable\" || rest === \"enabled\") {\n\t\t\treturn { kind: \"on\" };\n\t\t}\n\t\tif (rest === \"off\" || rest === \"disable\" || rest === \"disabled\") {\n\t\t\treturn { kind: \"off\" };\n\t\t}\n\t\tthrow new Error(\"Usage: /autonomous [on|off|status]\");\n\t}\n\n\tprivate _formatAutonomousStatus(): string {\n\t\tconst status = this.getAutonomousStatus();\n\t\tconst state = status.enabled ? \"on\" : \"off\";\n\t\treturn `Autonomous mode: ${state}. Continuations: ${status.continuationsUsed}/${status.limits.maxContinuations}. Turns: ${status.turnsUsed}/${status.limits.maxTurns}. Tokens: ${status.tokensUsed}/${status.limits.maxTokens}.`;\n\t}\n\n\tprivate _emitAutonomousStatus(): void {\n\t\tconst message = {\n\t\t\trole: \"custom\" as const,\n\t\t\tcustomType: \"autonomous_status\",\n\t\t\tcontent: this._formatAutonomousStatus(),\n\t\t\tdisplay: true,\n\t\t\tdetails: this.getAutonomousStatus(),\n\t\t\ttimestamp: Date.now(),\n\t\t} satisfies CustomMessage<AgentAutonomousStatus>;\n\t\tthis.agent.state.messages.push(message);\n\t\tthis.sessionManager.appendCustomMessageEntry(\n\t\t\tmessage.customType,\n\t\t\tmessage.content,\n\t\t\tmessage.display,\n\t\t\tmessage.details,\n\t\t);\n\t\tthis._emit({ type: \"message_start\", message });\n\t\tthis._emit({ type: \"message_end\", message });\n\t}\n\n\tprivate async _handleAutonomousSlashCommand(text: string): Promise<boolean> {\n\t\tconst command = this._parseAutonomousSlashCommand(text);\n\t\tif (!command) {\n\t\t\treturn false;\n\t\t}\n\t\tif (command.kind === \"on\") {\n\t\t\tsetAutonomousEnabled(this._autonomousState, true, { cwd: this._cwd });\n\t\t} else if (command.kind === \"off\") {\n\t\t\tsetAutonomousEnabled(this._autonomousState, false);\n\t\t\tthis._clearQueuedAutonomousContinuations();\n\t\t}\n\t\tthis._emitAutonomousStatus();\n\t\treturn true;\n\t}\n\n\tprivate _appendBeforeAgentStartMessages(\n\t\tmessages: AgentMessage[],\n\t\tresult: Awaited<ReturnType<ExtensionRunner[\"emitBeforeAgentStart\"]>>,\n\t): void {\n\t\tif (!result?.messages) return;\n\t\tfor (const message of result.messages) {\n\t\t\tmessages.push({\n\t\t\t\trole: \"custom\",\n\t\t\t\tcustomType: message.customType,\n\t\t\t\tcontent: message.content,\n\t\t\t\tdisplay: message.display,\n\t\t\t\tdetails: message.details,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate async _validateCanStartAgentRun(): Promise<void> {\n\t\tif (!this.model) {\n\t\t\tthrow new Error(formatNoModelSelectedMessage());\n\t\t}\n\t\tif (!this._modelRegistry.hasConfiguredAuth(this.model)) {\n\t\t\tconst isOAuth = this._modelRegistry.isUsingOAuth(this.model);\n\t\t\tif (isOAuth) {\n\t\t\t\tthrow new Error(formatAuthenticationFailedMessage(this.model.provider));\n\t\t\t}\n\t\t\tthrow new Error(formatNoApiKeyFoundMessage(this.model.provider));\n\t\t}\n\t}\n\n\t/**\n\t * Goals are pursued through the kernel goal skill, so the only tool the\n\t * model needs is ipython. Force-activate it (including into a live\n\t * continuation context) so the model can always reach `goal.complete()`.\n\t */\n\tprivate _ensureGoalRuntimeActive(context?: AgentContext): void {\n\t\tif (!this._includeGoals) {\n\t\t\tthrow new Error(\"Goals are disabled. Enable goals before using /goal.\");\n\t\t}\n\t\tconst ipythonTool = this._toolRegistry.get(\"ipython\");\n\t\tif (!ipythonTool) {\n\t\t\tthrow new Error(\"Goals require the ipython tool, which is not available in this session.\");\n\t\t}\n\t\tconst activeToolNames = new Set(this.getActiveToolNames());\n\t\tif (!activeToolNames.has(\"ipython\")) {\n\t\t\tactiveToolNames.add(\"ipython\");\n\t\t\tthis.setActiveToolsByName([...activeToolNames]);\n\t\t}\n\t\tif (context) {\n\t\t\tconst contextTools = [...(context.tools ?? [])];\n\t\t\tif (!contextTools.some((tool) => tool.name === \"ipython\")) {\n\t\t\t\tcontextTools.push(ipythonTool);\n\t\t\t\tcontext.tools = contextTools;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _maybeResumeGoalContinuationAfterRlmWork(): void {\n\t\tif (!this._goalContinuationAwaitsRlmWork) return;\n\t\tif (this._disposed || this._disposing || this._hasUnsettledRlmQuiescenceWork()) return;\n\t\tif (this._goalState.status !== \"active\" || !this._goalState.objective) {\n\t\t\tthis._goalContinuationAwaitsRlmWork = false;\n\t\t\treturn;\n\t\t}\n\t\t// Keep the deferral while admission is paused or the pump is suspended\n\t\t// (post-abort); the pause release and resumeQueuedWork retry.\n\t\tif (this._sessionInputAdmissionPauses.size > 0 || this._sessionInputPumpSuspended) return;\n\t\tconst goalBeforeResume = this._goalState;\n\t\ttry {\n\t\t\tthis._ensureGoalRuntimeActive();\n\t\t\tthis._setGoalState({\n\t\t\t\t...this._goalState,\n\t\t\t\tcontinuationsUsed: this._goalState.continuationsUsed + 1,\n\t\t\t\tlastReason: undefined,\n\t\t\t\tlastError: undefined,\n\t\t\t});\n\t\t\tconst message = createGoalContextMessage(this._goalState, \"continuation\");\n\t\t\tconst normalized = normalizeMessageContent(message.content);\n\t\t\t// No front: a settling child's terminal notice must be read first.\n\t\t\tthis._admitSessionInput(\n\t\t\t\tthis._createPreparedTurnAction(\"followUp\", normalized.text, normalized.images, {\n\t\t\t\t\tmessage,\n\t\t\t\t\tresumeIfIdle: true,\n\t\t\t\t}),\n\t\t\t);\n\t\t\tthis._goalContinuationAwaitsRlmWork = false;\n\t\t} catch {\n\t\t\t// Admission can race a new pause; roll back so the retry re-counts.\n\t\t\tthis._setGoalState(goalBeforeResume);\n\t\t}\n\t}\n\n\tprivate _runOrQueueGoalContext(kind: \"continuation\" | \"objective_updated\", images?: ImageContent[]): void {\n\t\tif (!this._goalState.objective) return;\n\t\tthis._ensureGoalRuntimeActive();\n\t\tconst message = createGoalContextMessage(this._goalState, kind, images);\n\t\tconst normalized = normalizeMessageContent(message.content);\n\t\tconst action = this._createPreparedTurnAction(\"followUp\", normalized.text, normalized.images, {\n\t\t\tmessage,\n\t\t\tresumeIfIdle: true,\n\t\t});\n\t\tthis._admitSessionInput(action, { front: true, wake: false });\n\t}\n\n\tprivate async _handleGoalSlashCommand(text: string, images: ImageContent[] | undefined): Promise<boolean> {\n\t\tconst command = this._parseGoalSlashCommand(text);\n\t\tif (!command) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (command.kind === \"status\") {\n\t\t\tthis._emitGoalUpdate();\n\t\t\treturn true;\n\t\t}\n\n\t\tif (command.kind === \"clear\") {\n\t\t\tthis._clearGoal();\n\t\t\treturn true;\n\t\t}\n\n\t\tif (command.kind === \"pause\") {\n\t\t\tthis._pauseGoal();\n\t\t\treturn true;\n\t\t}\n\n\t\tif (command.kind === \"resume\") {\n\t\t\tawait this._resumeGoal();\n\t\t\treturn true;\n\t\t}\n\n\t\tconst previousWasActive = this._goalState.status === \"active\";\n\t\tif (!this.isStreaming) {\n\t\t\tawait this._validateCanStartAgentRun();\n\t\t}\n\t\tthis._ensureGoalRuntimeActive();\n\t\tthis._clearQueuedGoalContexts();\n\t\tthis._startGoal(command.objective, command.tokenBudget);\n\t\tawait this._runOrQueueGoalContext(previousWasActive ? \"objective_updated\" : \"continuation\", images);\n\t\treturn true;\n\t}\n\n\tprivate _accountGoalUsageForAssistantMessage(message: AssistantMessage): boolean {\n\t\tif (!this._goalState.objective) {\n\t\t\treturn false;\n\t\t}\n\t\tif (message.stopReason === \"error\" || message.stopReason === \"aborted\") {\n\t\t\treturn false;\n\t\t}\n\t\tif (this._goalAccountedAssistantMessages.has(message)) {\n\t\t\treturn false;\n\t\t}\n\t\t// Usage is attributed at the assistant message's message_end, which fires\n\t\t// before that turn's ipython cell runs. goal.complete() only arrives later\n\t\t// over the kernel host bridge, so the completing turn is always accounted\n\t\t// while the goal is still active. Only count turns spent pursuing the goal;\n\t\t// post-completion turns (e.g. a closing summary) must not be attributed.\n\t\tif (this._goalState.status !== \"active\") {\n\t\t\treturn false;\n\t\t}\n\t\tthis._goalAccountedAssistantMessages.add(message);\n\t\tconst tokenDelta = goalTokenDeltaForUsage(message.usage);\n\t\tconst goal = this._goalWithAccountedWallClock();\n\t\tconst nextGoal: GoalState = {\n\t\t\t...goal,\n\t\t\ttokensUsed: goal.tokensUsed + tokenDelta,\n\t\t};\n\t\tconst budgetReached = nextGoal.tokenBudget !== undefined && nextGoal.tokensUsed >= nextGoal.tokenBudget;\n\t\tif (!budgetReached) {\n\t\t\tthis._setGoalState(nextGoal);\n\t\t\treturn false;\n\t\t}\n\t\tthis._setGoalState({\n\t\t\t...nextGoal,\n\t\t\tactive: false,\n\t\t\tstatus: \"budget_limited\",\n\t\t\tlastReason: `Reached ${nextGoal.tokenBudget} token goal budget`,\n\t\t\tlastError: undefined,\n\t\t});\n\t\treturn true;\n\t}\n\n\tprivate get _steeringStopPending(): boolean {\n\t\treturn (\n\t\t\tthis._actionStore.queuedActions(\"next_turn_boundary\").length > 0 ||\n\t\t\tthis._actionStore\n\t\t\t\t.activeActions(\"next_turn_boundary\")\n\t\t\t\t.some(\n\t\t\t\t\t(action) =>\n\t\t\t\t\t\taction.payload.kind === \"turn\" &&\n\t\t\t\t\t\t(action.lifecycle.state === \"selected\" || action.lifecycle.state === \"preparing\"),\n\t\t\t\t)\n\t\t);\n\t}\n\n\tprivate _shouldStopBeforeTurn(): boolean {\n\t\treturn this._steeringStopPending;\n\t}\n\n\tprivate async _shouldStopAfterTurn(context: ShouldStopAfterTurnContext): Promise<boolean> {\n\t\tif (this._stopGoalContinuationForTerminalMessage(context.message)) {\n\t\t\treturn true;\n\t\t}\n\t\ttry {\n\t\t\tif (this._accountGoalUsageForAssistantMessage(context.message)) {\n\t\t\t\tconst message = createGoalContextMessage(this._goalState, \"budget_limit\");\n\t\t\t\tconst normalized = normalizeMessageContent(message.content);\n\t\t\t\tawait this._queuePreparedPrompt(\"steer\", normalized.text, normalized.images, {\n\t\t\t\t\tmessage,\n\t\t\t\t\tresumeIfIdle: true,\n\t\t\t\t});\n\t\t\t}\n\t\t} catch {\n\t\t\t// Goal accounting must not interrupt the core agent loop.\n\t\t}\n\t\t// Serialized refine checkpoint: in print/headless mode, run refinement\n\t\t// planning+apply synchronously here — the quiescent boundary between\n\t\t// turns — so it never overlaps the primary model request.\n\t\t// This MUST run BEFORE threshold compaction to prevent the\n\t\t// compaction model call from overlapping an in-flight refine\n\t\t// plan/apply that was started at message_end.\n\t\tif (this._serializedRefine) {\n\t\t\t// Ensure the preceding message_end processing (counter increment,\n\t\t\t// background plan kickoff) has completed before the checkpoint.\n\t\t\tawait this._agentEventQueue;\n\t\t\tawait this._runSerializedRefineCheckpoint();\n\t\t}\n\t\tif (await this._shouldStopForThresholdCompaction(context)) {\n\t\t\treturn true;\n\t\t}\n\t\t// Steering stops continuation only after mandatory serialized checkpoints.\n\t\t// Returning true here still prevents the agent loop from starting another turn.\n\t\treturn this._steeringStopPending;\n\t}\n\n\tprivate async _shouldStopForThresholdCompaction(context: ShouldStopAfterTurnContext): Promise<boolean> {\n\t\tthis._continueAfterThresholdCompaction = false;\n\t\tif (this._pendingRequestedCompaction === undefined && !(await this._thresholdCompactionNeeded(context))) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst lastMessage = this.agent.state.messages[this.agent.state.messages.length - 1];\n\t\t// A queued continuation disproves the assistant-last \"task finished\" heuristic, so preserve a true set above.\n\t\tthis._continueAfterThresholdCompaction ||= lastMessage !== undefined && lastMessage.role !== \"assistant\";\n\t\treturn true;\n\t}\n\n\t/**\n\t * Serialized-mode auto-refine checkpoint called from _shouldStopAfterTurn.\n\t * Runs the review, planning, and application phases inline between turns\n\t * at the quiescent shouldStopAfterTurn boundary. This path NEVER calls\n\t * _maybeAutoRefine, _runApprovedRefine, public refine(), agent.abort(),\n\t * or agent.waitForIdle — all of which would deadlock or defer because\n\t * the agent loop still owns activeRun at this point. Instead it calls\n\t * _reviewAutoRefine, _planRefine, and _applyRefine directly with proper\n\t * in-flight guards and counter resets.\n\t */\n\tprivate async _runSerializedRefineCheckpoint(): Promise<void> {\n\t\tif (this._disposed || this._disposing) {\n\t\t\treturn;\n\t\t}\n\n\t\t// 1. Await any background plan that was started at message_end\n\t\t// (either for a pending refine.run or for interval-triggered\n\t\t// auto-refine). This must be checked BEFORE the pending and\n\t\t// interval checks because background planning may have consumed\n\t\t// the pending request at message_end.\n\t\tconst branchVersion = this._autoRefineBranchVersion;\n\t\tconst bgConsumption = await this._consumeSerializedBackgroundPlan(async (bgResult) => {\n\t\t\tif (this._disposed || this._disposing) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (bgResult?.status === \"plan\") {\n\t\t\t\tif (bgResult.branchVersion !== this._autoRefineBranchVersion) {\n\t\t\t\t\tif (!this._pendingRequestedRefine) {\n\t\t\t\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\t\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Apply the EXACT background plan directly via _applyRefine\n\t\t\t\t\t// (no second _planRefine call).\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait this._applySerializedPlan(bgResult);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tthis._emitRefineFailed(error);\n\t\t\t\t\t}\n\t\t\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t\t\t\tif (!this._pendingRequestedRefine) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (bgResult?.status === \"skip\") {\n\t\t\t\t// Reviewer declined or an extension skipped during background planning.\n\t\t\t\t// Reset exactly once. Never retry the interval review; only fall through for a separate pending refine.run.\n\t\t\t\tif (bgResult.explicit) {\n\t\t\t\t\tthis._emitRefineFailed(new RefineSkippedError(\"Refinement skipped by extension\"));\n\t\t\t\t}\n\t\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t\t\tif (!this._pendingRequestedRefine) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (bgResult?.status === \"failure\") {\n\t\t\t\t// Background review or planning failure stamps cooldown without a synchronous retry.\n\t\t\t\t// A separately queued refine.run may still be serviced below.\n\t\t\t\tif (branchVersion === this._autoRefineBranchVersion) {\n\t\t\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\t\t}\n\t\t\t\t// Re-queue an explicit refine.run whose background plan failed,\n\t\t\t\t// but only when branchVersion is still current and no newer\n\t\t\t\t// pending request has arrived since the background plan consumed\n\t\t\t\t// the original one. A newer request retains priority; interval\n\t\t\t\t// failures keep existing no-retry cooldown semantics.\n\t\t\t\tif (\n\t\t\t\t\tbgResult.explicit &&\n\t\t\t\t\tbgResult.branchVersion === this._autoRefineBranchVersion &&\n\t\t\t\t\t!this._pendingRequestedRefine\n\t\t\t\t) {\n\t\t\t\t\tthis._pendingRequestedRefine = bgResult.options;\n\t\t\t\t}\n\t\t\t\tif (!this._pendingRequestedRefine) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (bgResult?.status === \"invalidated\" && !this._pendingRequestedRefine) {\n\t\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tawait this._runSerializedRefineCheckpointAfterBackground(branchVersion);\n\t\t\treturn true;\n\t\t});\n\t\tif (this._disposed || this._disposing || bgConsumption !== \"none\") {\n\t\t\treturn;\n\t\t}\n\t\tawait this._runSerializedRefineCheckpointAfterBackground(branchVersion);\n\t}\n\n\tprivate async _runSerializedRefineCheckpointAfterBackground(branchVersion: number): Promise<void> {\n\t\t// No background result, or a refine.run arrived while the background result was\n\t\t// in flight. Fall through so an explicit pending request is serviced at this boundary.\n\n\t\t// 2. Agent-callable refine.run requests that were NOT consumed by\n\t\t// background planning (e.g. interval not reached at message_end,\n\t\t// or cooldown was active). Service them synchronously.\n\t\tconst pending = this._pendingRequestedRefine;\n\t\tif (pending) {\n\t\t\tthis._pendingRequestedRefine = undefined;\n\t\t\ttry {\n\t\t\t\tawait this._runSerializedRefine(pending);\n\t\t\t} catch (error) {\n\t\t\t\tthis._emitRefineFailed(error);\n\t\t\t}\n\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t\treturn;\n\t\t}\n\n\t\t// 3. Post-compaction auto-refine. Serialized sessions defer the\n\t\t// compaction trigger to this boundary instead of entering the interactive\n\t\t// path, which waits for agent idle and can never run inside a tool loop.\n\t\tif (!this._autoRefineAllowedForSession()) {\n\t\t\tthis._compactAutoRefinePending = false;\n\t\t\treturn;\n\t\t}\n\t\tconst settings = this.settingsManager.getAutoRefineSettings();\n\t\tif (!settings.enabled) {\n\t\t\tthis._compactAutoRefinePending = false;\n\t\t\treturn;\n\t\t}\n\t\tif (this._compactAutoRefinePending) {\n\t\t\tif (!settings.compact) {\n\t\t\t\tthis._compactAutoRefinePending = false;\n\t\t\t} else {\n\t\t\t\tconst nowMs = Date.now();\n\t\t\t\tconst underCooldown =\n\t\t\t\t\tthis._lastAutoRefineReviewAt > 0 && nowMs - this._lastAutoRefineReviewAt < settings.cooldownMs;\n\t\t\t\tif (underCooldown) {\n\t\t\t\t\t// Preserve the compact trigger for a later boundary, matching the\n\t\t\t\t\t// interactive path's pending behavior while the cooldown is active.\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis._compactAutoRefinePending = false;\n\t\t\t\tawait this._runSerializedAutoRefineReview(\"compact\", branchVersion);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// 4. Interval-triggered auto-refine (no background plan was started).\n\t\tif (this._assistantTurnsSinceAutoRefine < settings.turnInterval) {\n\t\t\treturn;\n\t\t}\n\t\tconst nowMs = Date.now();\n\t\tconst underCooldown =\n\t\t\tthis._lastAutoRefineReviewAt > 0 && nowMs - this._lastAutoRefineReviewAt < settings.cooldownMs;\n\t\tif (underCooldown) {\n\t\t\treturn;\n\t\t}\n\t\tawait this._runSerializedAutoRefineReview(\"turn_interval\", branchVersion);\n\t}\n\n\tprivate async _runSerializedAutoRefineReview(\n\t\treason: \"compact\" | \"turn_interval\",\n\t\tbranchVersion: number,\n\t): Promise<void> {\n\t\tconst reviewAbort = new AbortController();\n\t\tthis._autoRefineReviewAbort = reviewAbort;\n\t\tthis._autoRefineInProgress = true;\n\t\ttry {\n\t\t\tconst review = await this._reviewAutoRefine(\n\t\t\t\t{ reason, turnsSinceLastReview: this._assistantTurnsSinceAutoRefine },\n\t\t\t\treviewAbort.signal,\n\t\t\t);\n\t\t\tif (this._disposed || this._disposing || branchVersion !== this._autoRefineBranchVersion) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!review.shouldRefine) {\n\t\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait this._runSerializedRefine({ instructions: autoRefineInstructions(reason, review) }, \"auto\");\n\t\t\tif (this._disposed || this._disposing || branchVersion !== this._autoRefineBranchVersion) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t} catch (error) {\n\t\t\tif (branchVersion === this._autoRefineBranchVersion) {\n\t\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\t\t// An extension skip is an intentional non-round, not a failure.\n\t\t\t\tif (error instanceof RefineSkippedError) {\n\t\t\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t\t\t} else {\n\t\t\t\t\tthis._emitRefineFailed(error);\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\tif (this._autoRefineReviewAbort === reviewAbort) {\n\t\t\t\tthis._autoRefineReviewAbort = undefined;\n\t\t\t}\n\t\t\tthis._autoRefineInProgress = false;\n\t\t}\n\t}\n\n\t/**\n\t * Claim and process the serialized background plan if one is in flight.\n\t * A concurrent caller waits for the claim holder's full processing callback\n\t * instead of resuming as soon as planning settles.\n\t */\n\tprivate async _consumeSerializedBackgroundPlan(\n\t\tconsume: (result: SerializedBackgroundPlanResult | undefined) => Promise<boolean>,\n\t): Promise<\"none\" | \"waited\" | \"continue\" | \"stop\"> {\n\t\tif (this._serializedPlanClaim) {\n\t\t\tawait this._serializedPlanClaim.catch(() => undefined);\n\t\t\treturn \"waited\";\n\t\t}\n\t\tconst planInFlight = this._serializedPlanInFlight;\n\t\tif (!planInFlight) {\n\t\t\treturn \"none\";\n\t\t}\n\n\t\tlet releaseClaim: () => void = () => {};\n\t\tconst claim = new Promise<void>((resolve) => {\n\t\t\treleaseClaim = resolve;\n\t\t});\n\t\tthis._serializedPlanClaim = claim;\n\t\ttry {\n\t\t\tconst result = await planInFlight.catch(() => undefined);\n\t\t\tif (this._serializedPlanInFlight === planInFlight) {\n\t\t\t\tthis._serializedPlanInFlight = undefined;\n\t\t\t\tthis._serializedExplicitRefineOptions = undefined;\n\t\t\t}\n\t\t\treturn (await consume(result)) ? \"stop\" : \"continue\";\n\t\t} finally {\n\t\t\treleaseClaim();\n\t\t\tif (this._serializedPlanClaim === claim) {\n\t\t\t\tthis._serializedPlanClaim = undefined;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Apply an exact background plan directly via _applyRefine without\n\t * calling _planRefine again. Sets _refineInFlight for safety.\n\t */\n\tprivate async _applySerializedPlan(\n\t\tbgResult: Extract<SerializedBackgroundPlanResult, { status: \"plan\" }>,\n\t): Promise<void> {\n\t\tlet resolveApplySettled: () => void = () => {};\n\t\tconst applySettled = new Promise<void>((resolve) => {\n\t\t\tresolveApplySettled = resolve;\n\t\t});\n\t\tthis._refineInFlight = applySettled;\n\t\ttry {\n\t\t\tawait this._applyRefine(bgResult.plan, bgResult.options, bgResult.abort);\n\t\t} finally {\n\t\t\tresolveApplySettled();\n\t\t\tif (this._refineInFlight === applySettled) {\n\t\t\t\tthis._refineInFlight = undefined;\n\t\t\t}\n\t\t\tthis._scheduleSessionInputPump();\n\t\t}\n\t}\n\n\t/**\n\t * Start background refinement planning at assistant message_end, while\n\t * tools are still executing. The plan (if any) is awaited at the\n\t * shouldStopAfterTurn boundary before applying. Planning overlaps tool\n\t * execution only — never another model request.\n\t */\n\tprivate _maybeStartSerializedBackgroundPlan(): void {\n\t\tif (!this._serializedRefine || this._disposed || this._disposing) {\n\t\t\treturn;\n\t\t}\n\t\t// Don't start if a plan is already in flight.\n\t\tif (this._serializedPlanInFlight || this._refineInFlight || this._refinePlanInFlight) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Start background planning for a pending agent-callable\n\t\t// refine.run request, so its plan is ready at the shouldStopAfterTurn\n\t\t// boundary. The pending request is consumed (cleared) here so the\n\t\t// boundary doesn't re-plan it. Explicit refine.run skips the review gate.\n\t\tconst pending = this._pendingRequestedRefine;\n\t\tif (pending) {\n\t\t\tthis._pendingRequestedRefine = undefined;\n\t\t\tthis._serializedExplicitRefineOptions = pending;\n\t\t\tconst refineAbort = new AbortController();\n\t\t\tthis._refineAbortController = refineAbort;\n\t\t\tconst branchVersion = this._autoRefineBranchVersion;\n\t\t\tthis._serializedPlanInFlight = this._runBackgroundPlan(pending, refineAbort, branchVersion, true);\n\t\t\treturn;\n\t\t}\n\n\t\t// Interval-triggered auto-refine background planning.\n\t\tif (!this._autoRefineAllowedForSession()) {\n\t\t\treturn;\n\t\t}\n\t\tconst settings = this.settingsManager.getAutoRefineSettings();\n\t\tif (!settings.enabled) {\n\t\t\treturn;\n\t\t}\n\t\tif (this._assistantTurnsSinceAutoRefine < settings.turnInterval) {\n\t\t\treturn;\n\t\t}\n\t\tconst nowMs = Date.now();\n\t\tconst underCooldown =\n\t\t\tthis._lastAutoRefineReviewAt > 0 && nowMs - this._lastAutoRefineReviewAt < settings.cooldownMs;\n\t\tif (underCooldown) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst refineAbort = new AbortController();\n\t\tthis._refineAbortController = refineAbort;\n\t\tconst branchVersion = this._autoRefineBranchVersion;\n\t\t// Pass empty options — _runBackgroundPlan derives instructions from\n\t\t// the review result for interval-triggered auto-refine.\n\t\tthis._serializedPlanInFlight = this._runBackgroundPlan({}, refineAbort, branchVersion);\n\t}\n\n\t/**\n\t * Shared background planning coroutine. Runs review + planRefine and\n\t * returns a discriminated result so the boundary can distinguish\n\t * reviewer-declined (\"skip\") from failure (\"failure\") from a ready\n\t * plan (\"plan\") and apply that exact plan without re-planning.\n\t */\n\tprivate async _runBackgroundPlan(\n\t\toptions: { instructions?: string; rollbackId?: string; global?: boolean },\n\t\trefineAbort: AbortController,\n\t\tbranchVersion: number,\n\t\tskipReview = false,\n\t): Promise<SerializedBackgroundPlanResult | undefined> {\n\t\ttry {\n\t\t\tlet planOptions = options;\n\t\t\tif (!skipReview) {\n\t\t\t\t// Interval-triggered: run the review gate first, then derive\n\t\t\t\t// instructions from the review result (not prepopulated).\n\t\t\t\tconst review = await this._reviewAutoRefine(\n\t\t\t\t\t{\n\t\t\t\t\t\treason: \"turn_interval\",\n\t\t\t\t\t\tturnsSinceLastReview: this._assistantTurnsSinceAutoRefine,\n\t\t\t\t\t},\n\t\t\t\t\trefineAbort.signal,\n\t\t\t\t);\n\t\t\t\tif (this._disposed || this._disposing || branchVersion !== this._autoRefineBranchVersion) {\n\t\t\t\t\treturn { status: \"invalidated\", branchVersion };\n\t\t\t\t}\n\t\t\t\tif (!review.shouldRefine) {\n\t\t\t\t\treturn { status: \"skip\" };\n\t\t\t\t}\n\t\t\t\tplanOptions = {\n\t\t\t\t\tinstructions: autoRefineInstructions(\"turn_interval\", review),\n\t\t\t\t};\n\t\t\t}\n\t\t\t// For explicit refine.run (skipReview=true), plan directly with\n\t\t\t// the user-provided options — no auto-review gate.\n\t\t\tconst plan = await this._planRefine(planOptions, refineAbort.signal, skipReview ? \"manual\" : \"auto\");\n\t\t\tif (this._disposed || this._disposing || branchVersion !== this._autoRefineBranchVersion) {\n\t\t\t\treturn { status: \"invalidated\", branchVersion };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tstatus: \"plan\",\n\t\t\t\tplan,\n\t\t\t\toptions: planOptions,\n\t\t\t\tabort: refineAbort,\n\t\t\t\tbranchVersion,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tif (this._disposed || this._disposing || branchVersion !== this._autoRefineBranchVersion) {\n\t\t\t\treturn { status: \"invalidated\", branchVersion };\n\t\t\t}\n\t\t\tif (error instanceof RefineSkippedError) {\n\t\t\t\treturn { status: \"skip\", explicit: skipReview };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tstatus: \"failure\",\n\t\t\t\texplicit: skipReview,\n\t\t\t\toptions,\n\t\t\t\tbranchVersion,\n\t\t\t};\n\t\t} finally {\n\t\t\tif (this._refineAbortController === refineAbort) {\n\t\t\t\tthis._refineAbortController = undefined;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Direct serialized plan+apply. Calls _planRefine and _applyRefine with\n\t * proper in-flight guards but NEVER agent.waitForIdle or agent.abort.\n\t * The caller (shouldStopAfterTurn) is already at the quiescent boundary,\n\t * so the agent is between turns and _applyRefine's disconnect/reconnect\n\t * is safe.\n\t */\n\tprivate async _runSerializedRefine(\n\t\toptions: {\n\t\t\tinstructions?: string;\n\t\t\trollbackId?: string;\n\t\t\tglobal?: boolean;\n\t\t},\n\t\ttrigger: \"manual\" | \"auto\" = \"manual\",\n\t): Promise<void> {\n\t\tif (this._disposed || this._disposing) {\n\t\t\treturn;\n\t\t}\n\t\t// Guard: serialize against concurrent _runSerializedRefine calls.\n\t\t// _serializedPlanInFlight covers background planning; _refineInFlight\n\t\t// covers the apply phase. Both must be settled before starting a new\n\t\t// plan+apply cycle.\n\t\twhile (this._serializedPlanInFlight || this._refineInFlight || this._refinePlanInFlight) {\n\t\t\tif (this._serializedPlanInFlight) {\n\t\t\t\tawait this._consumeSerializedBackgroundPlan(async () => false);\n\t\t\t} else if (this._refineInFlight) {\n\t\t\t\tawait this._refineInFlight;\n\t\t\t} else {\n\t\t\t\tawait this._refinePlanInFlight;\n\t\t\t}\n\t\t}\n\t\tif (this._disposed || this._disposing) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst refineAbort = new AbortController();\n\t\tthis._refineAbortController = refineAbort;\n\n\t\tconst planRun = this._planRefine(options, refineAbort.signal, trigger);\n\t\tconst planSettled = planRun.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\tthis._refinePlanInFlight = planSettled;\n\t\tlet plan: RefinementPlan;\n\t\ttry {\n\t\t\tplan = await planRun;\n\t\t} catch (error) {\n\t\t\tif (this._refineAbortController === refineAbort) {\n\t\t\t\tthis._refineAbortController = undefined;\n\t\t\t}\n\t\t\tthis._scheduleSessionInputPump();\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tif (this._refinePlanInFlight === planSettled) {\n\t\t\t\tthis._refinePlanInFlight = undefined;\n\t\t\t}\n\t\t}\n\n\t\tif (this._disposed || refineAbort.signal.aborted) {\n\t\t\tif (this._refineAbortController === refineAbort) {\n\t\t\t\tthis._refineAbortController = undefined;\n\t\t\t}\n\t\t\tthis._scheduleSessionInputPump();\n\t\t\treturn;\n\t\t}\n\n\t\t// Do NOT call agent.waitForIdle() — we are at the quiescent boundary\n\t\t// already (shouldStopAfterTurn). _applyRefine handles disconnect/reconnect internally.\n\t\tlet resolveApplySettled: () => void = () => {};\n\t\tconst applySettled = new Promise<void>((resolve) => {\n\t\t\tresolveApplySettled = resolve;\n\t\t});\n\t\tthis._refineInFlight = applySettled;\n\t\ttry {\n\t\t\tawait this._applyRefine(plan, options, refineAbort);\n\t\t} finally {\n\t\t\tresolveApplySettled();\n\t\t\tif (this._refineInFlight === applySettled) {\n\t\t\t\tthis._refineInFlight = undefined;\n\t\t\t}\n\t\t\tthis._scheduleSessionInputPump();\n\t\t}\n\t}\n\n\tprivate async _thresholdCompactionNeeded(context: ShouldStopAfterTurnContext): Promise<boolean> {\n\t\tconst settings = this.settingsManager.getCompactionSettings();\n\t\tif (!settings.enabled) return false;\n\n\t\tconst contextWindow = this.model?.contextWindow ?? 0;\n\t\tconst compactionEntry = getLatestCompactionEntry(this.sessionManager.getBranch());\n\t\tconst compactionTimestamp = compactionEntry ? new Date(compactionEntry.timestamp).getTime() : undefined;\n\t\tif (compactionTimestamp !== undefined && context.message.timestamp <= compactionTimestamp) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst contextTokens = this._getThresholdContextTokens(context.message, compactionTimestamp);\n\t\tif (contextTokens === undefined || !shouldCompact(contextTokens, contextWindow, settings)) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Goal continuation takes exclusive priority over autonomous continuation, matching _getContinuationMessages.\n\t\tif (this._queueGoalContinuationForThresholdCompaction(context.message)) {\n\t\t\tthis._continueAfterThresholdCompaction = true;\n\t\t} else if (await this._queueAutonomousContinuationForThresholdCompaction(context.message)) {\n\t\t\tthis._continueAfterThresholdCompaction = true;\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate _snapshotAutonomousRuntimeState(): AutonomousRuntimeSnapshot {\n\t\treturn {\n\t\t\tcontinuationsUsed: this._autonomousState.continuationsUsed,\n\t\t\tgateAttempts: { ...this._autonomousState.gateAttempts },\n\t\t\tlastGateFailure: this._autonomousState.lastGateFailure\n\t\t\t\t? { ...this._autonomousState.lastGateFailure }\n\t\t\t\t: undefined,\n\t\t\tlastGateFailureSnapshot: this._autonomousState.lastGateFailureSnapshot\n\t\t\t\t? { ...this._autonomousState.lastGateFailureSnapshot }\n\t\t\t\t: undefined,\n\t\t};\n\t}\n\n\tprivate _restoreAutonomousRuntimeSnapshot(snapshot: AutonomousRuntimeSnapshot): void {\n\t\tthis._autonomousState.continuationsUsed = snapshot.continuationsUsed;\n\t\tthis._autonomousState.gateAttempts = { ...snapshot.gateAttempts };\n\t\tthis._autonomousState.lastGateFailure = snapshot.lastGateFailure ? { ...snapshot.lastGateFailure } : undefined;\n\t\tthis._autonomousState.lastGateFailureSnapshot = snapshot.lastGateFailureSnapshot\n\t\t\t? { ...snapshot.lastGateFailureSnapshot }\n\t\t\t: undefined;\n\t}\n\n\tprivate async _queueAutonomousContinuationForThresholdCompaction(\n\t\tmessage: AssistantMessage,\n\t): Promise<AgentMessage | undefined> {\n\t\tconst queuedMessage = this._queuedAutonomousThresholdContinuations.get(message);\n\t\tif (queuedMessage && this._postCompactionContinuationMessages.includes(queuedMessage)) {\n\t\t\treturn queuedMessage;\n\t\t}\n\t\tconst snapshot = this._snapshotAutonomousRuntimeState();\n\t\tconst arrivalEpoch = this._sessionInputArrivalEpoch;\n\t\tconst autonomousMessage = await nextAutonomousContinuation(this._autonomousState, message, {\n\t\t\tcwd: this._cwd,\n\t\t\tsignal: this.agent.signal,\n\t\t});\n\t\tif (!autonomousMessage) {\n\t\t\treturn undefined;\n\t\t}\n\t\tif (this._sessionInputArrivalEpoch !== arrivalEpoch) {\n\t\t\tthis._restoreAutonomousRuntimeSnapshot(snapshot);\n\t\t\treturn undefined;\n\t\t}\n\t\tthis._queuedAutonomousThresholdContinuations.set(message, autonomousMessage);\n\t\tthis._queuedAutonomousContinuationSnapshots.set(autonomousMessage, snapshot);\n\t\tthis._postCompactionContinuationMessages.push(autonomousMessage);\n\t\tthis._pendingThresholdCompactionAutonomousMessages.push(autonomousMessage);\n\t\tconst text =\n\t\t\ttypeof autonomousMessage.content === \"string\"\n\t\t\t\t? autonomousMessage.content\n\t\t\t\t: autonomousMessage.content.map((block) => (block.type === \"text\" ? block.text : \"\")).join(\"\\n\");\n\t\tthis._admitSessionInput(\n\t\t\tthis._createPreparedTurnAction(\"followUp\", text, undefined, {\n\t\t\t\tmessage: autonomousMessage,\n\t\t\t}),\n\t\t);\n\t\treturn autonomousMessage;\n\t}\n\n\t// The role heuristic reads an assistant-last threshold stop as \"task finished\" and\n\t// agent.continue() cannot resume from it, so the goal continuation is queued as a session input.\n\tprivate _queueGoalContinuationForThresholdCompaction(message: AssistantMessage): boolean {\n\t\tif (message.stopReason === \"error\" || message.stopReason === \"aborted\") {\n\t\t\treturn false;\n\t\t}\n\t\tif (this._goalState.status !== \"active\" || !this._goalState.objective) {\n\t\t\treturn false;\n\t\t}\n\t\tconst alreadyQueued = this._queuedGoalThresholdContinuation;\n\t\tif (\n\t\t\talreadyQueued !== undefined &&\n\t\t\tthis._actionStore.unfinishedActions().some((action) => {\n\t\t\t\tif (action.payload.kind !== \"turn\" || primaryDeliveryRecord(action).message !== alreadyQueued) return false;\n\t\t\t\t// A running continuation may already need a successor; only undelivered actions deduplicate.\n\t\t\t\treturn (\n\t\t\t\t\taction.lifecycle.state === \"queued\" ||\n\t\t\t\t\taction.lifecycle.state === \"selected\" ||\n\t\t\t\t\taction.lifecycle.state === \"preparing\" ||\n\t\t\t\t\taction.lifecycle.state === \"committing\"\n\t\t\t\t);\n\t\t\t})\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t\ttry {\n\t\t\tthis._ensureGoalRuntimeActive();\n\t\t\tthis._setGoalState({\n\t\t\t\t...this._goalState,\n\t\t\t\tcontinuationsUsed: this._goalState.continuationsUsed + 1,\n\t\t\t\tlastReason: undefined,\n\t\t\t\tlastError: undefined,\n\t\t\t});\n\t\t\tconst goalMessage = createGoalContextMessage(this._goalState, \"continuation\");\n\t\t\tconst normalized = normalizeMessageContent(goalMessage.content);\n\t\t\tthis._admitSessionInput(\n\t\t\t\tthis._createPreparedTurnAction(\"followUp\", normalized.text, normalized.images, {\n\t\t\t\t\tmessage: goalMessage,\n\t\t\t\t}),\n\t\t\t);\n\t\t\tthis._queuedGoalThresholdContinuation = goalMessage;\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t// Withdraws a goal continuation queued for a threshold compaction the user cancelled,\n\t// rolling back the continuationsUsed increment so the next natural stop re-queues it.\n\tprivate _clearQueuedGoalContinuationAfterCancelledThresholdCompaction(\n\t\tqueuedGoalContinuation: AgentMessage | undefined,\n\t): void {\n\t\tif (queuedGoalContinuation === undefined) return;\n\t\tconst cancelled = this._cancelSessionActions(\n\t\t\t(action) => action.payload.kind === \"turn\" && primaryDeliveryRecord(action).message === queuedGoalContinuation,\n\t\t\tnew Error(\"Queued goal continuation was cleared before delivery.\"),\n\t\t);\n\t\tthis._queuedGoalThresholdContinuation = undefined;\n\t\t// A stale marker (continuation already consumed) matches no action; only an\n\t\t// actual cancellation may roll back its queue-time continuationsUsed increment.\n\t\tif (cancelled.length === 0) return;\n\t\tthis._setGoalState({ ...this._goalState, continuationsUsed: this._goalState.continuationsUsed - 1 });\n\t\tthis._emitQueueUpdate();\n\t}\n\n\tprivate _clearQueuedAutonomousContinuations(\n\t\toptions: { restoreAutonomousState?: boolean; messages?: AgentMessage[] } = {},\n\t): void {\n\t\tconst requestedMessages = options.messages ?? [...this._postCompactionContinuationMessages];\n\t\tconst requestedMessageSet = new Set(requestedMessages);\n\t\tconst queuedMessages = this._postCompactionContinuationMessages.filter((message) =>\n\t\t\trequestedMessageSet.has(message),\n\t\t);\n\t\tif (queuedMessages.length === 0) {\n\t\t\treturn;\n\t\t}\n\t\tconst queuedMessageSet = new Set(queuedMessages);\n\t\tthis._postCompactionContinuationMessages = this._postCompactionContinuationMessages.filter(\n\t\t\t(message) => !queuedMessageSet.has(message),\n\t\t);\n\t\tthis.agent.removeQueuedMessages((message) => queuedMessageSet.has(message));\n\t\tthis._cancelSessionActions(\n\t\t\t(action) => action.payload.kind === \"turn\" && queuedMessageSet.has(primaryDeliveryRecord(action).message),\n\t\t\tnew Error(\"Queued autonomous continuation was cleared before delivery.\"),\n\t\t);\n\t\tthis._emitQueueUpdate();\n\t\tif (options.restoreAutonomousState) {\n\t\t\tfor (const queuedMessage of queuedMessages) {\n\t\t\t\tconst snapshot = this._queuedAutonomousContinuationSnapshots.get(queuedMessage);\n\t\t\t\tif (snapshot) {\n\t\t\t\t\tthis._restoreAutonomousRuntimeSnapshot(snapshot);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfor (const queuedMessage of queuedMessages) {\n\t\t\tthis._queuedAutonomousContinuationSnapshots.delete(queuedMessage);\n\t\t}\n\t\tthis._pendingThresholdCompactionAutonomousMessages = this._pendingThresholdCompactionAutonomousMessages.filter(\n\t\t\t(message) => !queuedMessageSet.has(message),\n\t\t);\n\t\tif (options.messages === undefined) {\n\t\t\tthis._continueAfterThresholdCompaction = false;\n\t\t}\n\t\tif (!this.agent.hasQueuedMessages() && this.unfinishedActionCount === 0) {\n\t\t\tthis._cancelPostCompactionContinue();\n\t\t}\n\t}\n\n\tprivate _clearQueuedAutonomousContinuationsAfterSkippedThresholdCompaction(\n\t\tshouldContinueAfterThreshold: boolean,\n\t\tqueuedMessages: AgentMessage[],\n\t): void {\n\t\tif (shouldContinueAfterThreshold) {\n\t\t\tthis._clearQueuedAutonomousContinuations({\n\t\t\t\trestoreAutonomousState: true,\n\t\t\t\tmessages: queuedMessages,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Handle a goal.* request from the Python kernel host bridge (the bundled\n\t * goal skill). All goal state stays host-side; the kernel only sees the\n\t * serialized snake_case response.\n\t */\n\thandleGoalHostRequest(type: string, payload: Record<string, unknown> = {}): GoalHostResponse {\n\t\tif (!this._includeGoals) {\n\t\t\tthrow new Error(\"goals are disabled in this session\");\n\t\t}\n\t\tswitch (type) {\n\t\t\tcase \"goal.get\":\n\t\t\t\treturn goalHostResponse(this.goalState, false);\n\t\t\tcase \"goal.create\": {\n\t\t\t\tif (typeof payload.objective !== \"string\") {\n\t\t\t\t\tthrow new Error(\"goal.create objective must be a string\");\n\t\t\t\t}\n\t\t\t\tif (payload.token_budget !== undefined && typeof payload.token_budget !== \"number\") {\n\t\t\t\t\tthrow new Error(\"goal.create token_budget must be an integer when provided\");\n\t\t\t\t}\n\t\t\t\treturn goalHostResponse(this._createGoalFromHost(payload.objective, payload.token_budget), false);\n\t\t\t}\n\t\t\tcase \"goal.complete\":\n\t\t\t\treturn goalHostResponse(this._completeGoalFromHost(), true);\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`unknown goal request type \"${type}\"`);\n\t\t}\n\t}\n\n\t/**\n\t * Handle a compact.* request from the kernel host bridge. Compaction would\n\t * abort the run executing the requesting cell, so compact.run only schedules\n\t * it; _checkCompaction consumes the request at the turn boundary.\n\t */\n\thandleCompactHostRequest(type: string, payload: Record<string, unknown> = {}): Record<string, unknown> {\n\t\tif (!this._includeCompactSkill) {\n\t\t\tthrow new Error(\"the compact skill is disabled in this session\");\n\t\t}\n\t\tswitch (type) {\n\t\t\tcase \"compact.status\": {\n\t\t\t\tconst usage = this.getContextUsage();\n\t\t\t\treturn {\n\t\t\t\t\ttokens: usage?.tokens ?? null,\n\t\t\t\t\tcontext_window: usage?.contextWindow ?? null,\n\t\t\t\t\tpercent: usage?.percent ?? null,\n\t\t\t\t\tscheduled: this._pendingRequestedCompaction !== undefined,\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"compact.run\": {\n\t\t\t\tconst instructions = payload.instructions;\n\t\t\t\tif (instructions !== undefined && typeof instructions !== \"string\") {\n\t\t\t\t\tthrow new Error(\"compact.run instructions must be a string when provided\");\n\t\t\t\t}\n\t\t\t\t// \"status\" is reserved by the host-request reply protocol; don't use it as a key.\n\t\t\t\tif (!this.isStreaming) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tscheduled: false,\n\t\t\t\t\t\treason: \"no active turn; compaction can only be requested while a turn is running\",\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tconst preparation = prepareCompaction(\n\t\t\t\t\tthis.sessionManager.getBranch(),\n\t\t\t\t\tthis.settingsManager.getCompactionSettings(),\n\t\t\t\t);\n\t\t\t\tif (!preparation) {\n\t\t\t\t\tconst lastEntry = this.sessionManager.getBranch().at(-1);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tscheduled: false,\n\t\t\t\t\t\treason: lastEntry?.type === \"compaction\" ? \"already compacted\" : \"session is too short to compact\",\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tthis._pendingRequestedCompaction = { customInstructions: instructions };\n\t\t\t\treturn {\n\t\t\t\t\tscheduled: true,\n\t\t\t\t\tnote: \"Compaction runs when the current turn ends; you resume automatically afterwards. Continue working normally.\",\n\t\t\t\t};\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`unknown compact request type \"${type}\"`);\n\t\t}\n\t}\n\n\t/**\n\t * Handle a refine.* request from the kernel host bridge. Like compact,\n\t * refinement waits for the current turn to become idle before applying\n\t * changes, so refine.run only schedules it; _consumePendingRequestedRefine\n\t * fires it at the turn boundary. This prevents a deadlock that would occur\n\t * if refine() awaited agent idle from within the active tool call.\n\t */\n\thandleRefineHostRequest(type: string, payload: Record<string, unknown> = {}): Record<string, unknown> {\n\t\tswitch (type) {\n\t\t\tcase \"refine.status\": {\n\t\t\t\treturn {\n\t\t\t\t\tpending: this._pendingRequestedRefine !== undefined,\n\t\t\t\t\tin_flight:\n\t\t\t\t\t\tthis._refineInFlight !== undefined ||\n\t\t\t\t\t\tthis._refinePlanInFlight !== undefined ||\n\t\t\t\t\t\tthis._serializedPlanInFlight !== undefined,\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"refine.run\": {\n\t\t\t\tconst instructions = payload.instructions;\n\t\t\t\tif (instructions !== undefined && typeof instructions !== \"string\") {\n\t\t\t\t\tthrow new Error(\"refine.run instructions must be a string when provided\");\n\t\t\t\t}\n\t\t\t\tconst globalFlag = payload.global;\n\t\t\t\tif (globalFlag !== undefined && typeof globalFlag !== \"boolean\") {\n\t\t\t\t\tthrow new Error(\"refine.run global must be a boolean when provided\");\n\t\t\t\t}\n\t\t\t\tif (!this.isStreaming) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tscheduled: false,\n\t\t\t\t\t\treason: \"no active turn; refine can only be requested while a turn is running\",\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tconst previous = this._pendingRequestedRefine ?? this._serializedExplicitRefineOptions;\n\t\t\t\tthis._pendingRequestedRefine = {\n\t\t\t\t\tinstructions: instructions ?? previous?.instructions,\n\t\t\t\t\tglobal: globalFlag ?? previous?.global,\n\t\t\t\t};\n\t\t\t\t// In serialized mode, kick off background planning immediately\n\t\t\t\t// (the primary response ended at message_end, tools are active).\n\t\t\t\t// This lets planning overlap tool execution rather than waiting\n\t\t\t\t// for the shouldStopAfterTurn boundary.\n\t\t\t\tif (this._serializedRefine) {\n\t\t\t\t\tif (this._serializedPlanInFlight) {\n\t\t\t\t\t\tthis._autoRefineBranchVersion++;\n\t\t\t\t\t\tif (this._refineAbortController) {\n\t\t\t\t\t\t\tthis._refineAbortController.abort();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis._serializedPlanInFlight = Promise.resolve({\n\t\t\t\t\t\t\t\tstatus: \"invalidated\",\n\t\t\t\t\t\t\t\tbranchVersion: this._autoRefineBranchVersion,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis._maybeStartSerializedBackgroundPlan();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tscheduled: true,\n\t\t\t\t\tnote: \"Refinement runs when the current turn ends; the harness rebuilds the system prompt and resumes you automatically. Continue working normally.\",\n\t\t\t\t};\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`unknown refine request type \"${type}\"`);\n\t\t}\n\t}\n\n\t/**\n\t * Handle an rlm_heartbeat.* request from the bundled rlm-heartbeat skill.\n\t * These heartbeats are internal to this active session and never read or\n\t * mutate the user-level /heartbeat.\n\t */\n\thandleRlmHeartbeatHostRequest(type: string, payload: Record<string, unknown> = {}): Record<string, unknown> {\n\t\tconst controller = this._rlmHeartbeatController;\n\t\tif (!controller) {\n\t\t\tthrow new Error(\"RLM heartbeat skill is not available in this session\");\n\t\t}\n\t\tswitch (type) {\n\t\t\tcase \"rlm_heartbeat.list\": {\n\t\t\t\tconst includeInactive = payload.include_inactive === true || payload.includeInactive === true;\n\t\t\t\treturn {\n\t\t\t\t\theartbeats: controller\n\t\t\t\t\t\t.listRlmHeartbeats({ includeInactive })\n\t\t\t\t\t\t.map((heartbeat) => rlmHeartbeatHostResponse(heartbeat)),\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"rlm_heartbeat.create\": {\n\t\t\t\tif (typeof payload.instruction !== \"string\") {\n\t\t\t\t\tthrow new Error(\"rlm_heartbeat.create instruction must be a string\");\n\t\t\t\t}\n\t\t\t\tif (payload.interval !== undefined && typeof payload.interval !== \"string\") {\n\t\t\t\t\tthrow new Error(\"rlm_heartbeat.create interval must be a string when provided\");\n\t\t\t\t}\n\t\t\t\tif (payload.label !== undefined && typeof payload.label !== \"string\") {\n\t\t\t\t\tthrow new Error(\"rlm_heartbeat.create label must be a string when provided\");\n\t\t\t\t}\n\t\t\t\tconst deliveryMode = normalizeHeartbeatDeliveryMode(payload.delivery_mode ?? payload.deliveryMode);\n\t\t\t\treturn {\n\t\t\t\t\theartbeat: rlmHeartbeatHostResponse(\n\t\t\t\t\t\tcontroller.createRlmHeartbeat({\n\t\t\t\t\t\t\tinstruction: payload.instruction,\n\t\t\t\t\t\t\tinterval: payload.interval,\n\t\t\t\t\t\t\tlabel: payload.label,\n\t\t\t\t\t\t\tdeliveryMode,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"rlm_heartbeat.update\": {\n\t\t\t\tif (typeof payload.id !== \"string\") {\n\t\t\t\t\tthrow new Error(\"rlm_heartbeat.update id must be a string\");\n\t\t\t\t}\n\t\t\t\tif (payload.instruction !== undefined && typeof payload.instruction !== \"string\") {\n\t\t\t\t\tthrow new Error(\"rlm_heartbeat.update instruction must be a string when provided\");\n\t\t\t\t}\n\t\t\t\tif (payload.interval !== undefined && typeof payload.interval !== \"string\") {\n\t\t\t\t\tthrow new Error(\"rlm_heartbeat.update interval must be a string when provided\");\n\t\t\t\t}\n\t\t\t\tif (payload.label !== undefined && typeof payload.label !== \"string\") {\n\t\t\t\t\tthrow new Error(\"rlm_heartbeat.update label must be a string when provided\");\n\t\t\t\t}\n\t\t\t\tif (payload.status !== undefined && !isRlmHeartbeatStatusUpdate(payload.status)) {\n\t\t\t\t\tthrow new Error('rlm_heartbeat.update status must be \"pause\" or \"resume\" when provided');\n\t\t\t\t}\n\t\t\t\tconst rawDeliveryMode = payload.delivery_mode ?? payload.deliveryMode;\n\t\t\t\tconst deliveryMode = normalizeHeartbeatDeliveryMode(rawDeliveryMode);\n\t\t\t\tif (\n\t\t\t\t\tpayload.instruction === undefined &&\n\t\t\t\t\tpayload.interval === undefined &&\n\t\t\t\t\tpayload.label === undefined &&\n\t\t\t\t\tpayload.status === undefined &&\n\t\t\t\t\trawDeliveryMode === undefined\n\t\t\t\t) {\n\t\t\t\t\tthrow new Error(\"rlm_heartbeat.update requires at least one field to update\");\n\t\t\t\t}\n\t\t\t\tconst heartbeat = controller.updateRlmHeartbeat({\n\t\t\t\t\tid: payload.id,\n\t\t\t\t\tinstruction: payload.instruction,\n\t\t\t\t\tinterval: payload.interval,\n\t\t\t\t\tlabel: payload.label,\n\t\t\t\t\tstatus: payload.status,\n\t\t\t\t\tdeliveryMode,\n\t\t\t\t});\n\t\t\t\treturn {\n\t\t\t\t\theartbeat: heartbeat ? rlmHeartbeatHostResponse(heartbeat) : null,\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"rlm_heartbeat.delete\": {\n\t\t\t\tif (typeof payload.id !== \"string\") {\n\t\t\t\t\tthrow new Error(\"rlm_heartbeat.delete id must be a string\");\n\t\t\t\t}\n\t\t\t\tconst heartbeat = controller.deleteRlmHeartbeat(payload.id);\n\t\t\t\treturn {\n\t\t\t\t\theartbeat: heartbeat ? rlmHeartbeatHostResponse(heartbeat) : null,\n\t\t\t\t};\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`unknown RLM heartbeat request type \"${type}\"`);\n\t\t}\n\t}\n\n\thandleAgentMessageHostRequest(\n\t\ttype: string,\n\t\tpayload: Record<string, unknown> = {},\n\t):\n\t\t| Promise<AgentSessionMessageListResult | AgentSessionMessageReceipt | AgentFamilyRosterResult>\n\t\t| AgentSessionMessageListResult\n\t\t| AgentFamilyRosterResult {\n\t\tif (!this._agentMessageController) {\n\t\t\tthrow new Error(\"agent messaging is not available in this session\");\n\t\t}\n\t\tswitch (type) {\n\t\t\tcase \"agent_message.list_agents\":\n\t\t\t\tif (!this._agentMessageController.roster)\n\t\t\t\t\tthrow new Error(\"agent family roster is not available in this session\");\n\t\t\t\treturn this._agentMessageController.roster();\n\t\t\tcase \"agent_message.send\": {\n\t\t\t\tif (typeof payload.target !== \"string\") {\n\t\t\t\t\tthrow new Error(\"agent_message.send target must be a string\");\n\t\t\t\t}\n\t\t\t\tif (typeof payload.message !== \"string\") {\n\t\t\t\t\tthrow new Error(\"agent_message.send message must be a string\");\n\t\t\t\t}\n\t\t\t\treturn this._agentMessageController.sendAgentMessage({\n\t\t\t\t\ttarget: assertDirectAgentMessageTarget(payload.target),\n\t\t\t\t\tmessage: normalizeAgentSessionMessage(payload.message),\n\t\t\t\t});\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`unknown agent message request type \"${type}\"`);\n\t\t}\n\t}\n\n\thandleAgentObserveHostRequest(\n\t\ttype: string,\n\t\tpayload: Record<string, unknown> = {},\n\t):\n\t\t| AgentObserveListResult\n\t\t| AgentObserveAgentSnapshot\n\t\t| AgentObserveRecentMessagesResult\n\t\t| Promise<AgentObserveListResult | AgentObserveAgentSnapshot | AgentObserveRecentMessagesResult> {\n\t\tconst controller = this._agentObserveController;\n\t\tif (!controller) {\n\t\t\tthrow new Error(\"agent observation is not available in this session\");\n\t\t}\n\t\tswitch (type) {\n\t\t\tcase \"agent_observe.list\":\n\t\t\t\treturn controller.listAgents();\n\t\t\tcase \"agent_observe.get\": {\n\t\t\t\tif (typeof payload.target !== \"string\") {\n\t\t\t\t\tthrow new Error(\"agent_observe.get target must be a string\");\n\t\t\t\t}\n\t\t\t\treturn controller.getAgent(payload.target);\n\t\t\t}\n\t\t\tcase \"agent_observe.recent\": {\n\t\t\t\tif (typeof payload.target !== \"string\") {\n\t\t\t\t\tthrow new Error(\"agent_observe.recent target must be a string\");\n\t\t\t\t}\n\t\t\t\treturn controller.recentMessages({\n\t\t\t\t\ttarget: payload.target,\n\t\t\t\t\tlimit: normalizeObserveLimit(payload.limit as number | undefined),\n\t\t\t\t\tmaxChars: normalizeObserveMaxChars((payload.max_chars ?? payload.maxChars) as number | undefined),\n\t\t\t\t});\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`unknown agent observe request type \"${type}\"`);\n\t\t}\n\t}\n\n\tprivate _createGoalFromHost(objective: string, tokenBudget: number | undefined): GoalState {\n\t\tswitch (this._goalState.status) {\n\t\t\tcase \"active\":\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"cannot create a new goal because this thread already has an active goal; run `await goal.complete()` when it is achieved, or ask the user to clear it with /goal clear\",\n\t\t\t\t);\n\t\t\tcase \"paused\":\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"cannot create a new goal because a paused goal exists; ask the user to resume it with /goal resume or clear it with /goal clear\",\n\t\t\t\t);\n\t\t\tcase \"budget_limited\":\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"cannot create a new goal because a budget-limited goal exists; ask the user to resume it with /goal resume or clear it with /goal clear\",\n\t\t\t\t);\n\t\t\tdefault:\n\t\t\t\t// idle, or a terminal record (complete / error): nothing pending, start fresh.\n\t\t\t\treturn this._startGoal(objective, tokenBudget);\n\t\t}\n\t}\n\n\tprivate _completeGoalFromHost(): GoalState {\n\t\tif (!this._goalState.objective || this._goalState.status === \"idle\") {\n\t\t\tthrow new Error(\"cannot complete goal because this thread has no goal\");\n\t\t}\n\t\tconst goal = this._goalWithAccountedWallClock();\n\t\t// A turn can cross the budget and complete the goal at once: accounting\n\t\t// runs at message_end, before the completing ipython cell executes, so a\n\t\t// budget-limit context may already be steered. It is stale now — drop it.\n\t\tthis._clearQueuedGoalContexts();\n\t\tthis._setGoalState({\n\t\t\t...goal,\n\t\t\tactive: false,\n\t\t\tstatus: \"complete\",\n\t\t\tlastReason: \"Goal achieved\",\n\t\t\tlastError: undefined,\n\t\t});\n\t\treturn this._goalState;\n\t}\n\n\tprivate async _getGoalContinuationMessages(\n\t\tcontext: GetContinuationMessagesContext,\n\t\tsignal?: AbortSignal,\n\t): Promise<AgentMessage[]> {\n\t\tif (this._stopGoalContinuationForTerminalMessage(context.message)) {\n\t\t\treturn [];\n\t\t}\n\t\tif (signal?.aborted || this._goalState.status !== \"active\" || !this._goalState.objective) {\n\t\t\treturn [];\n\t\t}\n\t\t// Delegating and ending the turn is correct behavior; hold the continuation\n\t\t// until descendants settle instead of re-prompting a waiting parent.\n\t\tif (this._hasUnsettledRlmQuiescenceWork()) {\n\t\t\tthis._goalContinuationAwaitsRlmWork = true;\n\t\t\treturn [];\n\t\t}\n\t\tthis._goalContinuationAwaitsRlmWork = false;\n\t\ttry {\n\t\t\tthis._ensureGoalRuntimeActive(context.context);\n\t\t\tconst nextGoal = {\n\t\t\t\t...this._goalState,\n\t\t\t\tcontinuationsUsed: this._goalState.continuationsUsed + 1,\n\t\t\t\tlastReason: undefined,\n\t\t\t\tlastError: undefined,\n\t\t\t};\n\t\t\tthis._setGoalState(nextGoal);\n\t\t\treturn [createGoalContextMessage(this._goalState, \"continuation\")];\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\ttry {\n\t\t\t\tthis._finishGoalWithError(message);\n\t\t\t} catch {\n\t\t\t\t// The continuation hook must not reject; listener failures should not crash the agent loop.\n\t\t\t}\n\t\t\treturn [];\n\t\t}\n\t}\n\n\tprivate async _getContinuationMessages(\n\t\tcontext: GetContinuationMessagesContext,\n\t\tsignal?: AbortSignal,\n\t): Promise<AgentMessage[]> {\n\t\tif (this.queuedActionCount > 0) {\n\t\t\treturn [];\n\t\t}\n\t\tconst arrivalEpoch = this._sessionInputArrivalEpoch;\n\t\tconst goalSnapshot = this._goalState;\n\t\tconst goalAccountingStartedAt = this._goalAccountingStartedAt;\n\t\tconst goalMessages = await this._getGoalContinuationMessages(context, signal);\n\t\tif (goalMessages.length > 0 || signal?.aborted) {\n\t\t\tif (goalMessages.length > 0 && this._sessionInputArrivalEpoch !== arrivalEpoch) {\n\t\t\t\tthis._setGoalState(goalSnapshot);\n\t\t\t\tthis._goalAccountingStartedAt = goalAccountingStartedAt;\n\t\t\t\treturn [];\n\t\t\t}\n\t\t\treturn goalMessages;\n\t\t}\n\t\tif (\n\t\t\tthis._autonomousContinuationSuppressionDepth > 0 ||\n\t\t\tcontext.newMessages.some((message) => this._autonomousContinuationSuppressedMessages.has(message))\n\t\t) {\n\t\t\treturn [];\n\t\t}\n\t\tconst autonomousSnapshot = this._snapshotAutonomousRuntimeState();\n\t\tconst autonomousMessage = await nextAutonomousContinuation(this._autonomousState, context.message, {\n\t\t\tcwd: this._cwd,\n\t\t\tsignal,\n\t\t});\n\t\tif (autonomousMessage && this._sessionInputArrivalEpoch !== arrivalEpoch) {\n\t\t\tthis._restoreAutonomousRuntimeSnapshot(autonomousSnapshot);\n\t\t\treturn [];\n\t\t}\n\t\treturn autonomousMessage ? [autonomousMessage] : [];\n\t}\n\n\tprivate _lastAssistantMessage: AssistantMessage | undefined = undefined;\n\n\tprivate _agentMessageOutcome(agentMessageId: string): AgentMessageOutcome {\n\t\tlet outcome = this._agentMessageOutcomes.get(agentMessageId);\n\t\tif (!outcome) {\n\t\t\toutcome = {};\n\t\t\tthis._agentMessageOutcomes.set(agentMessageId, outcome);\n\t\t}\n\t\treturn outcome;\n\t}\n\n\t/**\n\t * Register a delivery waiter before submitting the prompt. Delivery outcomes are not retained\n\t * for late lookup, so callers that register after admission may wait for a future use of the id.\n\t */\n\twaitForAgentMessagePromptDelivery(agentMessageId: string): Promise<void> {\n\t\tconst outcome = this._agentMessageOutcome(agentMessageId);\n\t\toutcome.delivery ??= createAgentMessageDeferred();\n\t\treturn outcome.delivery.promise;\n\t}\n\n\tprivate _settleAgentMessage(\n\t\tagentMessageId: string | undefined,\n\t\tleg: \"delivery\" | \"completion\",\n\t\terror?: Error,\n\t): void {\n\t\tif (agentMessageId === undefined) return;\n\t\tconst outcome = this._agentMessageOutcomes.get(agentMessageId);\n\t\tif (!outcome) return;\n\t\tconst deferred = outcome[leg];\n\t\tif (!deferred) return;\n\t\toutcome[leg] = undefined;\n\t\tif (!outcome.delivery && !outcome.completion) {\n\t\t\tthis._agentMessageOutcomes.delete(agentMessageId);\n\t\t}\n\t\tif (error) deferred.reject(error);\n\t\telse deferred.resolve();\n\t}\n\n\tprivate _rejectAgentMessage(agentMessageId: string | undefined, error: Error): void {\n\t\tif (agentMessageId === undefined) return;\n\t\tthis._settleAgentMessage(agentMessageId, \"delivery\", error);\n\t\tthis._settleAgentMessage(agentMessageId, \"completion\", error);\n\t}\n\n\tprivate _rejectQueuedAgentMessageDeliveries(deliveryError: Error, completionError = deliveryError): void {\n\t\tfor (const action of this._actionStore.unfinishedActions()) {\n\t\t\tthis._settleAgentMessage(action.agentMessageId, \"delivery\", deliveryError);\n\t\t\tthis._settleAgentMessage(action.agentMessageId, \"completion\", completionError);\n\t\t}\n\t}\n\n\tprivate _capturingCancelledAction(message: AgentMessage): QueuedSessionAction | undefined {\n\t\treturn this._actionStore\n\t\t\t.ownedActions()\n\t\t\t.find(\n\t\t\t\t(action) =>\n\t\t\t\t\taction.lifecycle.state === \"cancelled\" &&\n\t\t\t\t\taction.payload.kind === \"turn\" &&\n\t\t\t\t\taction.payload.captureRunMessages?.has(message) === true,\n\t\t\t);\n\t}\n\n\tprivate _hasCancelledDispatchCapture(): boolean {\n\t\treturn this._actionStore\n\t\t\t.ownedActions()\n\t\t\t.some(\n\t\t\t\t(action) =>\n\t\t\t\t\taction.lifecycle.state === \"cancelled\" &&\n\t\t\t\t\taction.payload.kind === \"turn\" &&\n\t\t\t\t\taction.payload.captureRunMessages !== undefined,\n\t\t\t);\n\t}\n\n\tprivate _handleAgentEvent = (event: AgentEvent): void => {\n\t\tthis._createRetryPromiseForAgentEnd(event);\n\t\tif (event.type === \"message_start\" || event.type === \"message_end\") {\n\t\t\tfor (const action of this._actionStore.ownedActions()) {\n\t\t\t\tif (\n\t\t\t\t\taction.payload.kind !== \"turn\" ||\n\t\t\t\t\t!action.payload.captureRunMessages ||\n\t\t\t\t\taction.payload.cancelledDispatchEnded\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst primary = primaryDeliveryRecord(action);\n\t\t\t\tif (event.message === primary.message || primary.started) {\n\t\t\t\t\taction.payload.captureRunMessages.add(event.message);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (event.type === \"agent_end\") {\n\t\t\tconst captured = new Set<AgentMessage>();\n\t\t\tfor (const action of this._actionStore.ownedActions()) {\n\t\t\t\tif (action.payload.kind === \"turn\" && action.payload.captureRunMessages) {\n\t\t\t\t\tfor (const message of action.payload.captureRunMessages) captured.add(message);\n\t\t\t\t\taction.payload.cancelledDispatchEnded = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (captured.size > 0) {\n\t\t\t\tthis.agent.state.messages = this.agent.state.messages.filter((message) => !captured.has(message));\n\t\t\t}\n\t\t}\n\t\tif (event.type === \"message_start\" && (event.message.role === \"user\" || event.message.role === \"custom\")) {\n\t\t\tfor (const action of this._actionStore.actionsForMessage(event.message)) {\n\t\t\t\tconst record =\n\t\t\t\t\taction.payload.kind === \"turn\"\n\t\t\t\t\t\t? action.payload.records.find((candidate) => candidate.message === event.message)\n\t\t\t\t\t\t: undefined;\n\t\t\t\tif (record) record.started = true;\n\t\t\t\tif (record?.role === \"primary\") {\n\t\t\t\t\tthis._actionStore.ticketFor(action).settleDelivered({ status: \"delivered\" });\n\t\t\t\t\tthis._settleAgentMessage(action.agentMessageId, \"delivery\");\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (event.type === \"message_end\" && (event.message.role === \"user\" || event.message.role === \"custom\")) {\n\t\t\tfor (const action of this._actionStore.actionsForMessage(event.message)) {\n\t\t\t\tconst record =\n\t\t\t\t\taction.payload.kind === \"turn\"\n\t\t\t\t\t\t? action.payload.records.find((candidate) => candidate.message === event.message)\n\t\t\t\t\t\t: undefined;\n\t\t\t\tif (record) record.durable = true;\n\t\t\t\tif (record?.role === \"primary\" && action.lifecycle.state === \"committing\") {\n\t\t\t\t\ttransitionSessionAction(action, {\n\t\t\t\t\t\tstate: \"running\",\n\t\t\t\t\t\texecution: \"agent_turn\",\n\t\t\t\t\t});\n\t\t\t\t\tthis._notifySessionInputCheckpointChange();\n\t\t\t\t\tthis._emitQueueUpdate();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis._agentEventQueue = this._agentEventQueue.then(\n\t\t\t() => this._processAgentEvent(event),\n\t\t\t() => this._processAgentEvent(event),\n\t\t);\n\t\tthis._agentEventQueue.catch(() => {});\n\t};\n\n\tprivate _createRetryPromiseForAgentEnd(event: AgentEvent): void {\n\t\tif (event.type !== \"agent_end\" || this._retryPromise) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst settings = this.settingsManager.getRetrySettings();\n\t\tif (!settings.enabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst lastAssistant = this._findLastAssistantInMessages(event.messages);\n\t\tconst concreteAuthFailure = lastAssistant ? this._isConcreteProviderAuthFailure(lastAssistant) : false;\n\t\tif (!lastAssistant || (!this._isRetryableError(lastAssistant) && !concreteAuthFailure)) {\n\t\t\treturn;\n\t\t}\n\t\tif (concreteAuthFailure) {\n\t\t\tthis._captureRetryAuthFailureSource(lastAssistant);\n\t\t}\n\n\t\tthis._retryPromise = new Promise((resolve) => {\n\t\t\tthis._retryResolve = resolve;\n\t\t});\n\t}\n\n\tprivate _findLastAssistantInMessages(messages: AgentMessage[]): AssistantMessage | undefined {\n\t\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\t\tconst message = messages[i];\n\t\t\tif (message.role === \"assistant\") {\n\t\t\t\treturn message as AssistantMessage;\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate _addLoginGuidanceToAuthError(event: AgentEvent): void {\n\t\tconst message =\n\t\t\tevent.type === \"message_end\" && event.message.role === \"assistant\"\n\t\t\t\t? (event.message as AssistantMessage)\n\t\t\t\t: event.type === \"agent_end\"\n\t\t\t\t\t? this._findLastAssistantInMessages(event.messages)\n\t\t\t\t\t: undefined;\n\t\tif (!message || message.stopReason !== \"error\" || !message.errorMessage) {\n\t\t\treturn;\n\t\t}\n\t\tif (!isLikelyAuthenticationError(message.errorMessage)) {\n\t\t\treturn;\n\t\t}\n\t\tmessage.errorMessage = addLoginGuidanceToAuthError(message.errorMessage);\n\t}\n\n\tprivate async _processAgentEvent(event: AgentEvent): Promise<void> {\n\t\tlet clearedDispatchEnded = false;\n\t\tif ((event.type === \"message_start\" || event.type === \"message_end\") && event.message.role === \"toolResult\") {\n\t\t\tthis._applyLateIpythonSentAgentMessages(event.message);\n\t\t}\n\t\tif (event.type === \"message_start\" || event.type === \"message_end\") {\n\t\t\tconst cleared = this._capturingCancelledAction(event.message);\n\t\t\tif (cleared?.payload.kind === \"turn\" && cleared.payload.captureRunMessages) {\n\t\t\t\tconst captured = cleared.payload.captureRunMessages;\n\t\t\t\tthis.agent.state.messages = this.agent.state.messages.filter((message) => !captured.has(message));\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tif (event.type === \"agent_end\") {\n\t\t\tconst cleared = this._actionStore\n\t\t\t\t.ownedActions()\n\t\t\t\t.filter(\n\t\t\t\t\t(action) =>\n\t\t\t\t\t\taction.lifecycle.state === \"cancelled\" &&\n\t\t\t\t\t\taction.payload.kind === \"turn\" &&\n\t\t\t\t\t\taction.payload.captureRunMessages !== undefined,\n\t\t\t\t);\n\t\t\tif (cleared.length > 0) {\n\t\t\t\tclearedDispatchEnded = true;\n\t\t\t\tconst removed = new Set(\n\t\t\t\t\tcleared.flatMap((action) =>\n\t\t\t\t\t\taction.payload.kind === \"turn\" ? [...(action.payload.captureRunMessages ?? [])] : [],\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\tthis.agent.state.messages = this.agent.state.messages.filter((message) => !removed.has(message));\n\t\t\t\t(this.agent.state as { errorMessage?: string }).errorMessage = undefined;\n\t\t\t\tthis._lastAssistantMessage = undefined;\n\t\t\t\tfor (const action of cleared) this._actionStore.releaseTerminal(action);\n\t\t\t\tthis._notifySessionInputCheckpointChange();\n\t\t\t\tthis._resolveRetry();\n\t\t\t}\n\t\t}\n\n\t\tif (event.type === \"message_start\" && startsAgentRun(event.message)) {\n\t\t\tthis._overflowRecovery = \"idle\";\n\t\t}\n\n\t\tawait this._emitExtensionEvent(event);\n\t\tif (event.type === \"message_start\" || event.type === \"message_end\") {\n\t\t\tconst cleared = this._capturingCancelledAction(event.message);\n\t\t\tif (cleared?.payload.kind === \"turn\" && cleared.payload.captureRunMessages) {\n\t\t\t\tconst captured = cleared.payload.captureRunMessages;\n\t\t\t\tthis.agent.state.messages = this.agent.state.messages.filter((message) => !captured.has(message));\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tthis._addLoginGuidanceToAuthError(event);\n\n\t\tthis._emit(event);\n\n\t\tif (event.type === \"message_end\") {\n\t\t\tif (event.message.role === \"custom\") {\n\t\t\t\tthis.sessionManager.appendCustomMessageEntry(\n\t\t\t\t\tevent.message.customType,\n\t\t\t\t\tevent.message.content,\n\t\t\t\t\tevent.message.display,\n\t\t\t\t\tevent.message.details,\n\t\t\t\t);\n\t\t\t} else if (\n\t\t\t\tevent.message.role === \"user\" ||\n\t\t\t\tevent.message.role === \"assistant\" ||\n\t\t\t\tevent.message.role === \"toolResult\"\n\t\t\t) {\n\t\t\t\tthis.sessionManager.appendMessage(event.message);\n\t\t\t}\n\n\t\t\tif (event.message.role === \"assistant\") {\n\t\t\t\tthis._lastAssistantMessage = event.message;\n\n\t\t\t\tconst assistantMsg = event.message as AssistantMessage;\n\t\t\t\tif (assistantMsg.stopReason !== \"error\") {\n\t\t\t\t\taddAutonomousUsage(this._autonomousState, assistantMsg.usage);\n\t\t\t\t}\n\t\t\t\tif (assistantMsg.stopReason !== \"error\" && assistantMsg.stopReason !== \"aborted\") {\n\t\t\t\t\tthis._assistantTurnsSinceAutoRefine++;\n\t\t\t\t\t// In serialized mode, kick off background refinement planning\n\t\t\t\t\t// immediately after the primary stream finishes, while tools\n\t\t\t\t\t// are still executing. The plan is awaited at shouldStopAfterTurn\n\t\t\t\t\t// before applying, so planning overlaps tools only — never another\n\t\t\t\t\t// model request.\n\t\t\t\t\tthis._maybeStartSerializedBackgroundPlan();\n\t\t\t\t}\n\t\t\t\tif (assistantMsg.stopReason !== \"error\") {\n\t\t\t\t\tthis._overflowRecovery = \"idle\";\n\t\t\t\t}\n\t\t\t\tif (this._isConcreteProviderAuthFailure(assistantMsg)) {\n\t\t\t\t\tthis._captureRetryAuthFailureSource(assistantMsg);\n\t\t\t\t}\n\n\t\t\t\t// Reset retry counter immediately on successful assistant response\n\t\t\t\t// This prevents accumulation across multiple LLM calls within a turn\n\t\t\t\tif (assistantMsg.stopReason !== \"error\" && this._retryAttempt > 0) {\n\t\t\t\t\tthis._emit({\n\t\t\t\t\t\ttype: \"auto_retry_end\",\n\t\t\t\t\t\tsuccess: true,\n\t\t\t\t\t\tattempt: this._retryAttempt,\n\t\t\t\t\t});\n\t\t\t\t\tthis._retryAttempt = 0;\n\t\t\t\t\tthis._retryAuthFailureSources = [];\n\t\t\t\t}\n\t\t\t\tif (this._accountGoalUsageForAssistantMessage(assistantMsg)) {\n\t\t\t\t\tconst message = createGoalContextMessage(this._goalState, \"budget_limit\");\n\t\t\t\t\tconst normalized = normalizeMessageContent(message.content);\n\t\t\t\t\tawait this._queuePreparedPrompt(\"steer\", normalized.text, normalized.images, {\n\t\t\t\t\t\tmessage,\n\t\t\t\t\t\tresumeIfIdle: true,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (clearedDispatchEnded) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (event.type === \"agent_end\") {\n\t\t\tconst msg =\n\t\t\t\tthis._lastAssistantMessage ??\n\t\t\t\t(this._retryPromise ? this._findLastAssistantInMessages(event.messages) : undefined);\n\t\t\tthis._lastAssistantMessage = undefined;\n\t\t\tif (!msg) {\n\t\t\t\tthis._resolveRetry();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst concreteAuthFailure = this._isConcreteProviderAuthFailure(msg);\n\t\t\tconst retryConcreteAuthFailure =\n\t\t\t\tconcreteAuthFailure && !this._isStructuredPermanentProviderRetryExhausted(msg);\n\t\t\tif (this._isRetryableError(msg) || retryConcreteAuthFailure) {\n\t\t\t\tif (retryConcreteAuthFailure) {\n\t\t\t\t\tthis._captureRetryAuthFailureSource(msg);\n\t\t\t\t}\n\t\t\t\tconst didRetry = await this._handleRetryableError(msg, {\n\t\t\t\t\tmarkAuthStaleOnFailure: retryConcreteAuthFailure,\n\t\t\t\t\tauthSourceTokens: retryConcreteAuthFailure ? this._retryAuthFailureSources : undefined,\n\t\t\t\t});\n\t\t\t\tif (didRetry) return; // Retry was initiated, don't proceed to compaction\n\t\t\t}\n\n\t\t\tconst compactionWillRetry = await this._checkCompaction(msg);\n\t\t\tif (compactionWillRetry && this._retryAttempt > 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._finishActiveRetryWithFailure(msg);\n\t\t\tthis._resolveRetry();\n\t\t\tif (!compactionWillRetry) {\n\t\t\t\tthis._finishGoalForTerminalAssistantMessage(msg);\n\t\t\t\t// In serialized mode, agent-callable refine.run is serviced\n\t\t\t\t// at the shouldStopAfterTurn boundary, not here at agent_end.\n\t\t\t\tif (!this._serializedRefine) {\n\t\t\t\t\tconst consumedRequestedRefine = this._consumePendingRequestedRefine();\n\t\t\t\t\tif (!consumedRequestedRefine) {\n\t\t\t\t\t\tthis._scheduleAutoRefineAfterAgentEnd();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _resolveRetry(): void {\n\t\tif (this._retryResolve) {\n\t\t\tthis._retryResolve();\n\t\t\tthis._retryResolve = undefined;\n\t\t\tthis._retryPromise = undefined;\n\t\t\tthis._scheduleSessionInputPump();\n\t\t}\n\t}\n\n\tprivate _findLastAssistantMessage(): AssistantMessage | undefined {\n\t\tconst messages = this.agent.state.messages;\n\t\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\t\tconst msg = messages[i];\n\t\t\tif (msg.role === \"assistant\") {\n\t\t\t\treturn msg as AssistantMessage;\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate _replaceMessageInPlace(target: AgentMessage, replacement: AgentMessage): void {\n\t\t// Agent-core stores the finalized message object in its state before emitting message_end.\n\t\t// SessionManager persistence happens later in _processAgentEvent() with event.message.\n\t\t// Mutating this object in place keeps agent state, later turn/agent events, listeners,\n\t\t// and the eventual SessionManager.appendMessage(event.message) persistence in sync.\n\t\tif (target === replacement) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst targetRecord = target as unknown as Record<string, unknown>;\n\t\tfor (const key of Object.keys(targetRecord)) {\n\t\t\tdelete targetRecord[key];\n\t\t}\n\t\tObject.assign(targetRecord, replacement);\n\t}\n\n\tprivate async _emitExtensionEvent(event: AgentEvent): Promise<void> {\n\t\tif (event.type === \"agent_start\") {\n\t\t\tthis._turnIndex = 0;\n\t\t\tthis.sessionManager.recordGitStateIfChanged();\n\t\t\tawait this._extensionRunner.emit({ type: \"agent_start\" });\n\t\t} else if (event.type === \"agent_end\") {\n\t\t\t// Also capture at end of turn so commits made during the run (e.g. via a bash tool) land.\n\t\t\tthis.sessionManager.recordGitStateIfChanged();\n\t\t\tawait this._extensionRunner.emit({\n\t\t\t\ttype: \"agent_end\",\n\t\t\t\tmessages: event.messages,\n\t\t\t});\n\t\t} else if (event.type === \"turn_start\") {\n\t\t\tconst extensionEvent: TurnStartEvent = {\n\t\t\t\ttype: \"turn_start\",\n\t\t\t\tturnIndex: this._turnIndex,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t};\n\t\t\tawait this._extensionRunner.emit(extensionEvent);\n\t\t} else if (event.type === \"turn_end\") {\n\t\t\tconst extensionEvent: TurnEndEvent = {\n\t\t\t\ttype: \"turn_end\",\n\t\t\t\tturnIndex: this._turnIndex,\n\t\t\t\tmessage: event.message,\n\t\t\t\ttoolResults: event.toolResults,\n\t\t\t};\n\t\t\tawait this._extensionRunner.emit(extensionEvent);\n\t\t\tthis._turnIndex++;\n\t\t} else if (event.type === \"message_start\") {\n\t\t\tconst extensionEvent: MessageStartEvent = {\n\t\t\t\ttype: \"message_start\",\n\t\t\t\tmessage: event.message,\n\t\t\t};\n\t\t\tawait this._extensionRunner.emit(extensionEvent);\n\t\t} else if (event.type === \"message_update\") {\n\t\t\tconst extensionEvent: MessageUpdateEvent = {\n\t\t\t\ttype: \"message_update\",\n\t\t\t\tmessage: event.message,\n\t\t\t\tassistantMessageEvent: event.assistantMessageEvent,\n\t\t\t};\n\t\t\tawait this._extensionRunner.emit(extensionEvent);\n\t\t} else if (event.type === \"message_end\") {\n\t\t\tconst extensionEvent: MessageEndEvent = {\n\t\t\t\ttype: \"message_end\",\n\t\t\t\tmessage: event.message,\n\t\t\t};\n\t\t\tconst replacement = await this._extensionRunner.emitMessageEnd(extensionEvent);\n\t\t\tif (replacement) {\n\t\t\t\tthis._replaceMessageInPlace(event.message, replacement);\n\t\t\t}\n\t\t} else if (event.type === \"tool_execution_start\") {\n\t\t\tconst extensionEvent: ToolExecutionStartEvent = {\n\t\t\t\ttype: \"tool_execution_start\",\n\t\t\t\ttoolCallId: event.toolCallId,\n\t\t\t\ttoolName: event.toolName,\n\t\t\t\targs: event.args,\n\t\t\t};\n\t\t\tawait this._extensionRunner.emit(extensionEvent);\n\t\t} else if (event.type === \"tool_execution_update\") {\n\t\t\tconst extensionEvent: ToolExecutionUpdateEvent = {\n\t\t\t\ttype: \"tool_execution_update\",\n\t\t\t\ttoolCallId: event.toolCallId,\n\t\t\t\ttoolName: event.toolName,\n\t\t\t\targs: event.args,\n\t\t\t\tpartialResult: event.partialResult,\n\t\t\t};\n\t\t\tawait this._extensionRunner.emit(extensionEvent);\n\t\t} else if (event.type === \"tool_execution_end\") {\n\t\t\tconst extensionEvent: ToolExecutionEndEvent = {\n\t\t\t\ttype: \"tool_execution_end\",\n\t\t\t\ttoolCallId: event.toolCallId,\n\t\t\t\ttoolName: event.toolName,\n\t\t\t\tresult: event.result,\n\t\t\t\tisError: event.isError,\n\t\t\t};\n\t\t\tawait this._extensionRunner.emit(extensionEvent);\n\t\t}\n\t}\n\n\t/**\n\t * Subscribe to agent events.\n\t * Session persistence is handled internally (saves messages on message_end).\n\t * Multiple listeners can be added. Returns unsubscribe function for this listener.\n\t */\n\tsubscribe(listener: AgentSessionEventListener): () => void {\n\t\tthis._eventListeners.push(listener);\n\n\t\treturn () => {\n\t\t\tconst index = this._eventListeners.indexOf(listener);\n\t\t\tif (index !== -1) {\n\t\t\t\tthis._eventListeners.splice(index, 1);\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * Temporarily disconnect from agent events.\n\t * User listeners are preserved and will receive events again after resubscribe().\n\t * Used internally during operations that need to pause event processing.\n\t */\n\tprivate _disconnectFromAgent(): void {\n\t\tif (this._unsubscribeAgent) {\n\t\t\tthis._unsubscribeAgent();\n\t\t\tthis._unsubscribeAgent = undefined;\n\t\t}\n\t}\n\n\t/**\n\t * Reconnect to agent events after _disconnectFromAgent().\n\t * Preserves all existing listeners.\n\t */\n\tprivate _reconnectToAgent(): void {\n\t\tif (this._unsubscribeAgent) return; // Already connected\n\t\tthis._unsubscribeAgent = this.agent.subscribe(this._handleAgentEvent);\n\t}\n\n\t/**\n\t * Remove all listeners and disconnect from agent.\n\t * Call this when completely done with the session.\n\t */\n\t/**\n\t * Async teardown for graceful quit/switch: await the Python kernel's dispose\n\t * (which flushes a final namespace snapshot) before the synchronous dispose, so\n\t * the latest state reaches disk instead of racing process exit.\n\t */\n\tasync disposeAsync(): Promise<void> {\n\t\tif (this._disposed) {\n\t\t\treturn this._disposeCallbacksPromise;\n\t\t}\n\t\t// Concurrent callers await the same in-flight teardown so none resolves before\n\t\t// the kernel snapshot flush finishes.\n\t\tif (this._disposeAsyncPromise) {\n\t\t\treturn this._disposeAsyncPromise;\n\t\t}\n\t\tthis._disposeAsyncPromise = (async () => {\n\t\t\t// Drain before marking _disposing so a refine triggered at the final\n\t\t\t// agent_end completes instead of being aborted by dispose().\n\t\t\tawait this._drainPendingRefinementForDisposal();\n\t\t\tif (this._disposed) {\n\t\t\t\treturn this._disposeCallbacksPromise;\n\t\t\t}\n\t\t\tthis._disposing = true;\n\t\t\tthis._sessionActionCommitDisposeAbortController.abort();\n\t\t\tawait this._disposeAsyncOnce();\n\t\t})();\n\t\treturn this._disposeAsyncPromise;\n\t}\n\n\t/**\n\t * Await any in-flight refinement (planning or application) and run a\n\t * pending auto-refine that was scheduled but not yet started. Called\n\t * from disposeAsync before _disposing is set so refinement completes\n\t * before disposal.\n\t */\n\tprivate async _drainPendingRefinementForDisposal(): Promise<void> {\n\t\tfor (const timer of this._scheduledAutoRefineTimers) {\n\t\t\tclearTimeout(timer);\n\t\t}\n\t\tthis._scheduledAutoRefineTimers.clear();\n\t\tawait Promise.allSettled([...this._autoRefineOperations]);\n\t\tfor (const timer of this._scheduledAutoRefineTimers) {\n\t\t\tclearTimeout(timer);\n\t\t}\n\t\tthis._scheduledAutoRefineTimers.clear();\n\t\t// Wait for in-flight refinement (including serialized background plan) to settle.\n\t\twhile (this._refineInFlight || this._refinePlanInFlight || this._serializedPlanInFlight) {\n\t\t\tif (this._refineInFlight) {\n\t\t\t\tawait this._refineInFlight;\n\t\t\t} else if (this._refinePlanInFlight) {\n\t\t\t\tawait this._refinePlanInFlight;\n\t\t\t} else if (this._serializedPlanInFlight) {\n\t\t\t\t// Await the background plan and apply a ready \"plan\" result before teardown.\n\t\t\t\tawait this._consumeSerializedBackgroundPlan(async (bgResult) => {\n\t\t\t\t\tif (bgResult?.status === \"plan\" && bgResult.branchVersion === this._autoRefineBranchVersion) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tawait this._applySerializedPlan(bgResult);\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tthis._emitRefineFailed(error);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Stamp cooldown and reset counter so the interval\n\t\t\t\t\t\t// check below does not trigger a duplicate refine.\n\t\t\t\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\t\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t\t\t\t}\n\t\t\t\t\t// Preserve a consumed explicit request when its background plan failed,\n\t\t\t\t\t// matching the turn-boundary recovery path. The pending drain below\n\t\t\t\t\t// retries it once before disposal.\n\t\t\t\t\tif (\n\t\t\t\t\t\tbgResult?.status === \"failure\" &&\n\t\t\t\t\t\tbgResult.explicit &&\n\t\t\t\t\t\tbgResult.branchVersion === this._autoRefineBranchVersion &&\n\t\t\t\t\t\t!this._pendingRequestedRefine\n\t\t\t\t\t) {\n\t\t\t\t\t\tthis._pendingRequestedRefine = bgResult.options;\n\t\t\t\t\t}\n\t\t\t\t\tif (bgResult?.status === \"skip\" && bgResult.explicit) {\n\t\t\t\t\t\tthis._emitRefineFailed(new RefineSkippedError(\"Refinement skipped by extension\"));\n\t\t\t\t\t}\n\t\t\t\t\t// For \"skip\" or \"failure\", stamp cooldown and reset counter\n\t\t\t\t\t// so the interval check below does not trigger a duplicate\n\t\t\t\t\t// terminal retry.\n\t\t\t\t\tif (\n\t\t\t\t\t\tbgResult?.status === \"skip\" ||\n\t\t\t\t\t\tbgResult?.status === \"failure\" ||\n\t\t\t\t\t\tbgResult?.status === \"invalidated\"\n\t\t\t\t\t) {\n\t\t\t\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\t\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t\t\t\t}\n\t\t\t\t\treturn false;\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tawait new Promise<void>((resolve) => setTimeout(resolve, 0));\n\t\t\t}\n\t\t}\n\t\t// Drain an agent-callable refine.run request that was scheduled but\n\t\t// not yet consumed. Use the direct serialized path (no waitForIdle)\n\t\t// since the agent may still own activeRun at the final agent_end.\n\t\tif (this._pendingRequestedRefine) {\n\t\t\tconst pending = this._pendingRequestedRefine;\n\t\t\tthis._pendingRequestedRefine = undefined;\n\t\t\ttry {\n\t\t\t\tawait this._runSerializedRefine(pending);\n\t\t\t} catch {\n\t\t\t\t// Best-effort drain; refinement errors must not block disposal.\n\t\t\t}\n\t\t\t// Stamp cooldown and reset counter so the interval check below\n\t\t\t// does not trigger a duplicate refine after the explicit drain.\n\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t}\n\t\t// A serialized compaction can finish without another model turn. Drain its\n\t\t// pending review here so disposal does not silently lose the trigger.\n\t\tif (this._serializedRefine && this._compactAutoRefinePending && this._autoRefineAllowedForSession()) {\n\t\t\tconst compactSettings = this.settingsManager.getAutoRefineSettings();\n\t\t\tif (!compactSettings.enabled || !compactSettings.compact) {\n\t\t\t\tthis._compactAutoRefinePending = false;\n\t\t\t} else {\n\t\t\t\tconst nowMs = Date.now();\n\t\t\t\tconst underCooldown =\n\t\t\t\t\tthis._lastAutoRefineReviewAt > 0 && nowMs - this._lastAutoRefineReviewAt < compactSettings.cooldownMs;\n\t\t\t\tthis._compactAutoRefinePending = false;\n\t\t\t\tif (!underCooldown) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait this._runSerializedAutoRefineReview(\"compact\", this._autoRefineBranchVersion);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Best-effort drain; refinement errors must not block disposal.\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// If auto-refine is due but has not started yet, run it now so the\n\t\t// refinement is persisted before disposal. Use the direct serialized\n\t\t// path in serialized mode, or _maybeAutoRefine in interactive mode\n\t\t// (where the agent is idle at this point).\n\t\tif (this._disposed || !this._autoRefineAllowedForSession()) {\n\t\t\treturn;\n\t\t}\n\t\tconst settings = this.settingsManager.getAutoRefineSettings();\n\t\tif (!settings.enabled) {\n\t\t\treturn;\n\t\t}\n\t\tif (this._assistantTurnsSinceAutoRefine < settings.turnInterval) {\n\t\t\treturn;\n\t\t}\n\t\tconst nowMs = Date.now();\n\t\tconst underCooldown =\n\t\t\tthis._lastAutoRefineReviewAt > 0 && nowMs - this._lastAutoRefineReviewAt < settings.cooldownMs;\n\t\tif (underCooldown) {\n\t\t\treturn;\n\t\t}\n\t\tif (this._serializedRefine) {\n\t\t\tawait this._runSerializedRefineCheckpoint();\n\t\t} else {\n\t\t\tawait this._maybeAutoRefine(\"turn_interval\");\n\t\t}\n\t}\n\n\tprivate async _disposeAsyncOnce(): Promise<void> {\n\t\t// Flush kernels/traces for both still-running and retained children; the sync\n\t\t// dispose() below only tears them down synchronously.\n\t\tfor (const run of [...this._activeRlmChildRuns.values()]) {\n\t\t\tconst childSession = run.session;\n\t\t\tif (!childSession) continue;\n\t\t\tif (run.detachedDeletion) {\n\t\t\t\trun.suppressTerminalNotice = true;\n\t\t\t\tif (run.deletionCleanupObserver) {\n\t\t\t\t\tawait run.deletionCleanupObserver.catch(() => false);\n\t\t\t\t} else if (run.deletionCleanup) {\n\t\t\t\t\tawait run.deletionCleanup.catch(() => childSession.disposeAsync().catch(() => undefined));\n\t\t\t\t} else {\n\t\t\t\t\t// Cleanup already failed and was exposed for retry before disposal.\n\t\t\t\t\tawait childSession.disposeAsync().catch(() => undefined);\n\t\t\t\t}\n\t\t\t\tif (!run.settled) await this._finishRlmRunDeletion(run);\n\t\t\t} else {\n\t\t\t\tawait childSession.disposeAsync().catch(() => undefined);\n\t\t\t}\n\t\t}\n\t\tfor (const unsubscribe of this._rlmChildUnsubscribes.values()) {\n\t\t\tunsubscribe();\n\t\t}\n\t\tthis._rlmChildUnsubscribes.clear();\n\t\tfor (const session of this._rlmChildSessions.values()) {\n\t\t\tawait session.disposeAsync().catch(() => undefined);\n\t\t}\n\t\tthis._rlmChildSessions.clear();\n\t\tthis._rlmChildCleanupFailures.clear();\n\t\tthis._deletedRlmChildIds.clear();\n\t\ttry {\n\t\t\tawait this._ipythonKernelProvisioner?.dispose();\n\t\t} catch {\n\t\t\t// a failed kernel startup already cleaned up after itself\n\t\t}\n\t\tthis.dispose();\n\t\tawait this._disposeCallbacksPromise;\n\t}\n\n\tprivate _startDisposeCallbacks(): Promise<void> {\n\t\tif (this._disposeCallbacksPromise) {\n\t\t\treturn this._disposeCallbacksPromise;\n\t\t}\n\t\tconst pending: Promise<void>[] = [];\n\t\tfor (const callback of this._disposeCallbacks) {\n\t\t\ttry {\n\t\t\t\tconst result = callback();\n\t\t\t\tif (result) {\n\t\t\t\t\tpending.push(result.catch(() => undefined));\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Disposal remains best-effort; one owner must not block the rest.\n\t\t\t}\n\t\t}\n\t\tthis._disposeCallbacks.clear();\n\t\tthis._disposeCallbacksPromise = Promise.all(pending).then(() => undefined);\n\t\treturn this._disposeCallbacksPromise;\n\t}\n\n\tdispose(): void {\n\t\tif (this._disposed) {\n\t\t\treturn;\n\t\t}\n\t\tthis._disposed = true;\n\t\tfor (const run of this._unsettledRlmChildRuns) run.suppressTerminalNotice = true;\n\t\tfor (const controller of this._rlmQuiescenceWaitAborts) controller.abort();\n\t\tthis._sessionActionCommitDisposeAbortController.abort();\n\t\ttry {\n\t\t\t// Invalidate scheduled timers and abort any in-flight review so a late\n\t\t\t// resolution cannot write harness state or re-subscribe handlers.\n\t\t\tthis._autoRefineReviewAbort?.abort();\n\t\t\tthis._refineAbortController?.abort();\n\t\t\tfor (const timer of this._scheduledAutoRefineTimers) {\n\t\t\t\tclearTimeout(timer);\n\t\t\t}\n\t\t\tthis._scheduledAutoRefineTimers.clear();\n\t\t\tthis._serializedPlanInFlight = undefined;\n\t\t\tthis._serializedExplicitRefineOptions = undefined;\n\t\t\tthis._pendingRequestedRefine = undefined;\n\t\t\tthis._discardPendingAutoRefine({ cancelPostCompactionContinue: true });\n\t\t\tthis._autoRefineBranchVersion++;\n\t\t\tthis._cancelActiveRlmChildRuns(\"Parent session disposed\");\n\t\t\tfor (const unsubscribe of this._rlmChildUnsubscribes.values()) {\n\t\t\t\tunsubscribe();\n\t\t\t}\n\t\t\tthis._rlmChildUnsubscribes.clear();\n\t\t\tfor (const session of this._rlmChildSessions.values()) {\n\t\t\t\tsession.dispose();\n\t\t\t}\n\t\t\tthis._rlmChildSessions.clear();\n\t\t\tthis._rlmChildCleanupFailures.clear();\n\t\t\tthis._deletedRlmChildIds.clear();\n\t\t\tthis._pendingNextTurnMessages = [];\n\t\t\tconst deliveryError = new Error(\"Session disposed before prompt delivery.\");\n\t\t\tconst completionError = new Error(\"Session disposed before prompt completion.\");\n\t\t\tthis._rejectQueuedAgentMessageDeliveries(deliveryError, completionError);\n\t\t\tfor (const [agentMessageId, outcome] of this._agentMessageOutcomes) {\n\t\t\t\tif (outcome.delivery) this._settleAgentMessage(agentMessageId, \"delivery\", deliveryError);\n\t\t\t\tif (outcome.completion) this._settleAgentMessage(agentMessageId, \"completion\", completionError);\n\t\t\t}\n\t\t\tthis._cancelSessionActions(() => true, deliveryError);\n\t\t\tthis.agent.clearAllQueues();\n\t\t\tthis._extensionRunner.invalidate(\n\t\t\t\t\"This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().\",\n\t\t\t);\n\t\t\tthis._disconnectFromAgent();\n\t\t\tthis._eventListeners = [];\n\t\t\tcleanupSessionResources(this.sessionId);\n\t\t} finally {\n\t\t\tvoid this._startDisposeCallbacks();\n\t\t}\n\t}\n\n\tregisterDisposeCallback(callback: () => void | Promise<void>): void {\n\t\tif (this._disposed) {\n\t\t\ttry {\n\t\t\t\tconst result = callback();\n\t\t\t\tif (result) void result.catch(() => undefined);\n\t\t\t} catch {\n\t\t\t\t// Late registration follows the same best-effort disposal contract.\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tthis._disposeCallbacks.add(callback);\n\t}\n\n\tget state(): AgentState {\n\t\treturn this.agent.state;\n\t}\n\n\tget model(): Model<any> | undefined {\n\t\treturn this.agent.state.model;\n\t}\n\n\tget thinkingLevel(): ThinkingLevel {\n\t\treturn this.agent.state.thinkingLevel;\n\t}\n\n\tget serviceTier(): ServiceTier {\n\t\treturn this.agent.state.serviceTier;\n\t}\n\n\tget isStreaming(): boolean {\n\t\treturn this.agent.state.isStreaming;\n\t}\n\n\tget systemPrompt(): string {\n\t\treturn this.agent.state.systemPrompt;\n\t}\n\n\tget retryAttempt(): number {\n\t\treturn this._retryAttempt;\n\t}\n\n\tgetActiveToolNames(): string[] {\n\t\treturn this.agent.state.tools.map((t) => t.name);\n\t}\n\n\tgetAllTools(): ToolInfo[] {\n\t\treturn Array.from(this._toolDefinitions.values()).map(({ definition, sourceInfo }) => ({\n\t\t\tname: definition.name,\n\t\t\tdescription: definition.description,\n\t\t\tparameters: definition.parameters,\n\t\t\tsourceInfo,\n\t\t}));\n\t}\n\n\tgetToolDefinition(name: string): ToolDefinition | undefined {\n\t\treturn this._toolDefinitions.get(name)?.definition;\n\t}\n\n\tsetActiveToolsByName(toolNames: string[]): void {\n\t\tconst tools: AgentTool[] = [];\n\t\tconst validToolNames: string[] = [];\n\t\tconst seenToolNames = new Set<string>();\n\t\tfor (const name of toolNames) {\n\t\t\tif (seenToolNames.has(name)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst tool = this._toolRegistry.get(name);\n\t\t\tif (tool) {\n\t\t\t\tseenToolNames.add(name);\n\t\t\t\ttools.push(tool);\n\t\t\t\tvalidToolNames.push(name);\n\t\t\t}\n\t\t}\n\t\tthis.agent.state.tools = tools;\n\n\t\tthis._baseSystemPrompt = this._rebuildSystemPrompt(validToolNames);\n\t\tthis.agent.state.systemPrompt = this._baseSystemPrompt;\n\t}\n\n\tget isCompacting(): boolean {\n\t\treturn (\n\t\t\tthis._autoCompactionAbortController !== undefined ||\n\t\t\tthis._compactionAbortController !== undefined ||\n\t\t\tthis._branchSummaryAbortController !== undefined\n\t\t);\n\t}\n\n\tget messages(): AgentMessage[] {\n\t\treturn this.agent.state.messages;\n\t}\n\n\tbuildSessionContext(): SessionContext {\n\t\tconst context = this.sessionManager.buildSessionContext();\n\t\tfor (const message of context.messages) {\n\t\t\tthis._applyLateIpythonSentAgentMessages(message);\n\t\t}\n\t\tthis._mergeUnpersistedOutcomes(context.messages);\n\t\treturn context;\n\t}\n\n\tprivate _mergeUnpersistedOutcomes(messages: AgentMessage[]): void {\n\t\tfor (const outcome of this._unpersistedOutcomes) {\n\t\t\tlet insertAt = messages.length;\n\t\t\twhile (insertAt > 0 && messages[insertAt - 1]!.timestamp > outcome.timestamp) {\n\t\t\t\tinsertAt -= 1;\n\t\t\t}\n\t\t\tmessages.splice(insertAt, 0, outcome);\n\t\t}\n\t}\n\n\tget steeringMode(): \"all\" | \"one-at-a-time\" {\n\t\treturn this.agent.steeringMode;\n\t}\n\n\tget followUpMode(): \"all\" | \"one-at-a-time\" {\n\t\treturn this.agent.followUpMode;\n\t}\n\n\tget sessionFile(): string | undefined {\n\t\treturn this.sessionManager.getSessionFile();\n\t}\n\n\tget sessionId(): string {\n\t\treturn this.sessionManager.getSessionId();\n\t}\n\n\tget rlmDepth(): number {\n\t\treturn this._rlmDepth;\n\t}\n\n\tget rlmMaxDepth(): number {\n\t\treturn this._rlmMaxDepth;\n\t}\n\n\tget sessionName(): string | undefined {\n\t\treturn this.sessionManager.getSessionName();\n\t}\n\n\tget goalState(): GoalState {\n\t\treturn { ...this._goalWithCurrentWallClock() };\n\t}\n\n\tgetAutonomousStatus(): AgentAutonomousStatus {\n\t\treturn autonomousStatus(this._autonomousState);\n\t}\n\n\trecordHostAutonomousContinuation(): void {\n\t\taddAutonomousContinuation(this._autonomousState);\n\t}\n\n\tasync refreshAutonomousGates(): Promise<void> {\n\t\tawait refreshAutonomousQualityGates(this._autonomousState, {\n\t\t\tcwd: this._cwd,\n\t\t});\n\t}\n\n\tprivate async _runWithAutonomousContinuationSuppressed<T>(fn: () => Promise<T>): Promise<T> {\n\t\tthis._autonomousContinuationSuppressionDepth++;\n\t\ttry {\n\t\t\treturn await fn();\n\t\t} finally {\n\t\t\tthis._autonomousContinuationSuppressionDepth--;\n\t\t}\n\t}\n\n\tprivate _markAutonomousContinuationSuppressed(message: AgentMessage): void {\n\t\tthis._autonomousContinuationSuppressedMessages.add(message);\n\t}\n\n\tget scopedModels(): ReadonlyArray<{\n\t\tmodel: Model<any>;\n\t\tthinkingLevel?: ThinkingLevel;\n\t}> {\n\t\treturn this._scopedModels;\n\t}\n\n\tsetScopedModels(scopedModels: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }>): void {\n\t\tthis._scopedModels = scopedModels;\n\t}\n\n\tget promptTemplates(): ReadonlyArray<PromptTemplate> {\n\t\treturn this._resourceLoader.getPrompts().prompts;\n\t}\n\n\tprivate _normalizePromptSnippet(text: string | undefined): string | undefined {\n\t\tif (!text) return undefined;\n\t\tconst oneLine = text\n\t\t\t.replace(/[\\r\\n]+/g, \" \")\n\t\t\t.replace(/\\s+/g, \" \")\n\t\t\t.trim();\n\t\treturn oneLine.length > 0 ? oneLine : undefined;\n\t}\n\n\tprivate _normalizePromptGuidelines(guidelines: string[] | undefined): string[] {\n\t\tif (!guidelines || guidelines.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst unique = new Set<string>();\n\t\tfor (const guideline of guidelines) {\n\t\t\tconst normalized = guideline.trim();\n\t\t\tif (normalized.length > 0) {\n\t\t\t\tunique.add(normalized);\n\t\t\t}\n\t\t}\n\t\treturn Array.from(unique);\n\t}\n\n\tprivate _rebuildSystemPrompt(toolNames: string[]): string {\n\t\tconst validToolNames = toolNames.filter((name) => this._toolRegistry.has(name));\n\t\tconst toolSnippets: Record<string, string> = {};\n\t\tconst promptGuidelines: string[] = [];\n\t\tfor (const name of validToolNames) {\n\t\t\tconst snippet = this._toolPromptSnippets.get(name);\n\t\t\tif (snippet) {\n\t\t\t\ttoolSnippets[name] = snippet;\n\t\t\t}\n\n\t\t\tconst toolGuidelines = this._toolPromptGuidelines.get(name);\n\t\t\tif (toolGuidelines) {\n\t\t\t\tpromptGuidelines.push(...toolGuidelines);\n\t\t\t}\n\t\t}\n\n\t\tconst loaderSystemPrompt = this._resourceLoader.getSystemPrompt();\n\t\tconst loaderAppendSystemPrompt = this._resourceLoader.getAppendSystemPrompt();\n\t\tconst appendSystemPrompt =\n\t\t\tloaderAppendSystemPrompt.length > 0 ? loaderAppendSystemPrompt.join(\"\\n\\n\") : undefined;\n\t\tconst loadedSkills = this._modelVisibleSkills();\n\t\tconst loadedContextFiles = this._resourceLoader.getAgentsFiles().agentsFiles;\n\n\t\tthis._baseSystemPromptOptions = {\n\t\t\tcwd: this._cwd,\n\t\t\tskills: loadedSkills,\n\t\t\tcontextFiles: loadedContextFiles,\n\t\t\tcustomPrompt: loaderSystemPrompt,\n\t\t\tappendSystemPrompt,\n\t\t\tmessagesPath: this.sessionManager.getSessionFile(),\n\t\t\tselectedTools: validToolNames,\n\t\t\ttoolSnippets,\n\t\t\tpromptGuidelines,\n\t\t\tallowRecursion: this._rlmDepth < this._rlmMaxDepth,\n\t\t\trlmDepth: this._rlmDepth,\n\t\t\trlmParentAgent: this._rlmParentAgent,\n\t\t\tharnessState: this._loadMergedHarnessState(),\n\t\t\tgenericMcpServers: this._mcpManager?.getEnabledGenericServers(),\n\t\t};\n\t\treturn buildSystemPrompt(this._baseSystemPromptOptions);\n\t}\n\n\tprivate _refreshExtensionSystemPrompt(extensionPrompt: string, baseSnapshot: string): string {\n\t\tif (this._baseSystemPrompt === baseSnapshot) {\n\t\t\treturn extensionPrompt;\n\t\t}\n\t\tif (!extensionPrompt.includes(baseSnapshot)) {\n\t\t\treturn extensionPrompt;\n\t\t}\n\t\treturn extensionPrompt.replace(baseSnapshot, () => this._baseSystemPrompt);\n\t}\n\n\tprivate _finishSubmissionNormalization(\n\t\ttext: string,\n\t\timages: ImageContent[] | undefined,\n\t\tpolicy: SubmissionNormalizationPolicy,\n\t): NormalizedSubmission {\n\t\tlet expandedText = text;\n\t\tif (policy.expandSkills) expandedText = this._expandSkillCommand(expandedText);\n\t\tif (policy.expandPromptTemplates) {\n\t\t\texpandedText = expandPromptTemplate(expandedText, [...this.promptTemplates]);\n\t\t}\n\t\treturn { kind: \"prompt\", text: expandedText, images };\n\t}\n\n\tprivate _normalizeSubmission(\n\t\ttext: string,\n\t\timages: ImageContent[] | undefined,\n\t\tpolicy: SubmissionNormalizationPolicy,\n\t): NormalizedSubmission | Promise<NormalizedSubmission> {\n\t\tif (policy.parseSessionCommands) {\n\t\t\tconst command = parseSessionSlashCommand(text);\n\t\t\tif (command) return { kind: \"sessionCommand\", text, images, command };\n\t\t}\n\n\t\tif (text.startsWith(\"/\")) {\n\t\t\tif (policy.extensionCommands === \"execute\") {\n\t\t\t\tconst completion = this._executeExtensionCommand(text);\n\t\t\t\tif (completion) return { kind: \"extensionCommand\", completion };\n\t\t\t} else if (policy.extensionCommands === \"reject\") {\n\t\t\t\tthis._throwIfExtensionCommand(text);\n\t\t\t}\n\t\t}\n\n\t\tif (policy.inputSource !== undefined && this._extensionRunner.hasHandlers(\"input\")) {\n\t\t\treturn this._extensionRunner.emitInput(text, images, policy.inputSource).then((result) => {\n\t\t\t\tif (result.action === \"handled\") return { kind: \"handled\" };\n\t\t\t\tif (result.action === \"transform\") {\n\t\t\t\t\treturn this._finishSubmissionNormalization(result.text, result.images ?? images, policy);\n\t\t\t\t}\n\t\t\t\treturn this._finishSubmissionNormalization(text, images, policy);\n\t\t\t});\n\t\t}\n\n\t\treturn this._finishSubmissionNormalization(text, images, policy);\n\t}\n\n\tprivate async _runPreTurnCompaction(): Promise<void> {\n\t\tconst lastAssistant = this._findLastAssistantMessage();\n\t\tif (lastAssistant) await this._checkCompaction(lastAssistant, false, false);\n\t}\n\n\tprivate async _prepareForCommit<TPrepared, TCommitted>(\n\t\tpolicy: CommitPreparationPolicy,\n\t\tsteps: CommitPreparationSteps<TPrepared, TCommitted>,\n\t): Promise<TCommitted | undefined> {\n\t\tif (\n\t\t\tpolicy.initialRefineBarrier === \"always\" ||\n\t\t\t(policy.initialRefineBarrier === \"ifInFlight\" && this._refineInFlight)\n\t\t) {\n\t\t\tawait this._waitForRefineIdle();\n\t\t}\n\t\tif (policy.flushPendingBashBeforeValidation) this._flushPendingBashMessages();\n\t\tif (policy.validateModelAndAuth) await this._validateCanStartAgentRun();\n\t\tsteps.afterValidation?.();\n\t\tif (!policy.flushPendingBashBeforeValidation) this._flushPendingBashMessages();\n\n\t\tif (policy.preTurnCompaction === \"beforeModelSelection\") await this._runPreTurnCompaction();\n\t\tif (policy.awaitPendingModelSelection) {\n\t\t\tconst pendingModelSelectEmit = this._pendingModelSelectEmit();\n\t\t\tif (pendingModelSelectEmit) await pendingModelSelectEmit;\n\t\t}\n\t\tif (policy.preTurnCompaction === \"afterModelSelection\") await this._runPreTurnCompaction();\n\n\t\tconst prepared = await steps.prepare();\n\t\tif (steps.shouldCommit && !steps.shouldCommit(prepared)) return undefined;\n\t\tsteps.beforeFinalRefineBarrier?.(prepared);\n\t\tlet passedFinalRefineBarrier = false;\n\t\tif (\n\t\t\tpolicy.finalRefineBarrier === \"always\" ||\n\t\t\t(policy.finalRefineBarrier === \"ifInFlight\" && this._refineInFlight)\n\t\t) {\n\t\t\tawait this._waitForRefineIdle();\n\t\t\tpassedFinalRefineBarrier = true;\n\t\t}\n\t\treturn steps.commit(prepared, passedFinalRefineBarrier);\n\t}\n\n\tprivate _applyPreparedSystemPrompt(\n\t\tpreparation: PreparedPromptPreparation | undefined,\n\t\tpreserveEmptyExtensionPrompt: boolean,\n\t): void {\n\t\tconst extensionPrompt = preparation?.result?.systemPrompt;\n\t\tconst hasExtensionPrompt = preserveEmptyExtensionPrompt\n\t\t\t? extensionPrompt !== undefined\n\t\t\t: Boolean(extensionPrompt);\n\t\tthis.agent.state.systemPrompt =\n\t\t\thasExtensionPrompt && extensionPrompt !== undefined && preparation !== undefined\n\t\t\t\t? this._refreshExtensionSystemPrompt(extensionPrompt, preparation.basePromptSnapshot)\n\t\t\t\t: this._baseSystemPrompt;\n\t}\n\n\tprivate _canStartSessionActionImmediately(): boolean {\n\t\treturn (\n\t\t\t!this.isStreaming &&\n\t\t\t!this.isCompacting &&\n\t\t\t!this.isRetrying &&\n\t\t\t!this.isBashRunning &&\n\t\t\t!this._sessionInputPumpSuspended &&\n\t\t\tthis._queuedWorkPauses.size === 0 &&\n\t\t\t!this._disposed &&\n\t\t\t!this._disposing\n\t\t);\n\t}\n\n\t/**\n\t * Send a prompt to the agent.\n\t * - Handles extension commands (registered via pi.registerCommand) immediately, even during streaming\n\t * - Expands file-based prompt templates by default\n\t * - During streaming, queues via steer() or followUp() based on streamingBehavior option\n\t * - Validates model and API key before sending (when not streaming)\n\t * @throws Error if streaming and no streamingBehavior specified\n\t * @throws Error if no model selected or no API key available (when not streaming)\n\t */\n\tasync prompt(text: string, options?: PromptOptions): Promise<void> {\n\t\treturn this._prompt(text, options);\n\t}\n\n\tasync promptUntilAccepted(text: string, options?: PromptOptions): Promise<void> {\n\t\treturn this._prompt(text, { ...options, returnAfterAccepted: true });\n\t}\n\n\tasync promptAndWait(text: string, options?: PromptOptions): Promise<void> {\n\t\tconst agentMessageId = options?.agentMessageId ?? `prompt-wait:${randomUUID()}`;\n\t\tif (this._agentMessageOutcomes.get(agentMessageId)?.completion) {\n\t\t\tthrow new Error(`Prompt completion id is already in use: ${agentMessageId}`);\n\t\t}\n\t\tconst outcome = this._agentMessageOutcome(agentMessageId);\n\t\toutcome.completion = createAgentMessageDeferred();\n\t\tconst completion = outcome.completion.promise;\n\t\tconst signal = options?.signal;\n\t\tlet cancelQueuedPrompt: (() => void) | undefined;\n\t\ttry {\n\t\t\tawait this.promptUntilAccepted(text, { ...options, agentMessageId });\n\t\t\tif (signal) {\n\t\t\t\tcancelQueuedPrompt = () => {\n\t\t\t\t\tconst error = new Error(\"Prompt was cancelled before it started.\");\n\t\t\t\t\tconst cancelled = this._cancelSessionActions(\n\t\t\t\t\t\t(action) => action.agentMessageId === agentMessageId && action.payload.kind === \"turn\",\n\t\t\t\t\t\terror,\n\t\t\t\t\t);\n\t\t\t\t\tif (cancelled.length > 0) {\n\t\t\t\t\t\tthis._settleAgentMessage(agentMessageId, \"completion\", error);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tsignal.addEventListener(\"abort\", cancelQueuedPrompt, { once: true });\n\t\t\t\tif (signal.aborted) cancelQueuedPrompt();\n\t\t\t}\n\t\t\tawait completion;\n\t\t} catch (error) {\n\t\t\tthis._settleAgentMessage(agentMessageId, \"completion\", this._asError(error));\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tif (signal && cancelQueuedPrompt) {\n\t\t\t\tsignal.removeEventListener(\"abort\", cancelQueuedPrompt);\n\t\t\t}\n\t\t}\n\t}\n\n\tasync acceptAgentMessagePrompt(text: string, options?: PromptOptions): Promise<void> {\n\t\tconst customMessage =\n\t\t\toptions?.customMessage && isAgentSessionMessage(options.customMessage) ? options.customMessage : undefined;\n\t\tawait this._prompt(text, {\n\t\t\t...options,\n\t\t\tresumeIfIdle: false,\n\t\t\texpandPromptTemplates: false,\n\t\t\tskipInputHandlers: true,\n\t\t\tskipPrePromptWork: true,\n\t\t\treturnAfterAccepted: true,\n\t\t\tagentMessageId: options?.agentMessageId ?? customMessage?.details.id ?? parseAgentSessionMessagePromptId(text),\n\t\t\tcustomMessage,\n\t\t});\n\t\tif (customMessage?.details.fromRelationship === \"parent\") this._repliedToParentSinceTask = false;\n\t}\n\n\tasync queueAgentMessagePrompt(\n\t\ttext: string,\n\t\tstreamingBehavior: \"steer\" | \"followUp\",\n\t\tcustomMessage?: AgentSessionMessage,\n\t): Promise<boolean> {\n\t\tconst agentMessageId = customMessage?.details.id ?? parseAgentSessionMessagePromptId(text);\n\t\tif (streamingBehavior === \"steer\") {\n\t\t\tawait this._queuePreparedPrompt(\"steer\", text, undefined, {\n\t\t\t\tagentMessageId,\n\t\t\t\tmessage: customMessage,\n\t\t\t});\n\t\t\tif (customMessage?.details.fromRelationship === \"parent\") this._repliedToParentSinceTask = false;\n\t\t\treturn true;\n\t\t}\n\t\tconst queued = await this._queuePreparedPrompt(\"followUp\", text, undefined, {\n\t\t\tagentMessageId,\n\t\t\tmessage: customMessage,\n\t\t});\n\t\tif (queued && customMessage?.details.fromRelationship === \"parent\") this._repliedToParentSinceTask = false;\n\t\treturn queued;\n\t}\n\n\tasync promptHeartbeat(job: AgentCronJob, options?: PromptOptions): Promise<void> {\n\t\tconst message = createHeartbeatPromptMessage(job);\n\t\tawait this._promptInjectedMessage(job.prompt, message, {\n\t\t\t...options,\n\t\t\tfollowUpQueueKey: options?.followUpQueueKey ?? `heartbeat:${job.id}`,\n\t\t\tresumeIfIdle: true,\n\t\t});\n\t}\n\n\tprivate _isRlmTerminalNotice(message: CustomMessage): boolean {\n\t\treturn (\n\t\t\tmessage.customType === RLM_CHILD_TERMINAL_NOTICE_CUSTOM_TYPE ||\n\t\t\tmessage.customType === RLM_CHILD_FAILURE_CUSTOM_TYPE\n\t\t);\n\t}\n\n\tprivate _assertRlmTerminalNotice(message: CustomMessage): void {\n\t\tif (!this._isRlmTerminalNotice(message)) {\n\t\t\tthrow new Error(\"Deferred terminal admission only accepts RLM child terminal notices.\");\n\t\t}\n\t}\n\n\tprivate _isRlmTerminalNoticeAction(action: QueuedSessionAction): boolean {\n\t\tif (action.payload.kind !== \"turn\") return false;\n\t\tconst message = primaryDeliveryRecord(action).message;\n\t\treturn message.role === \"custom\" && this._isRlmTerminalNotice(message);\n\t}\n\n\tprivate _hasDeferredRlmTerminalNotices(): boolean {\n\t\treturn this._pendingNextTurnMessages.some((message) => this._isRlmTerminalNotice(message));\n\t}\n\n\tprivate _enqueueRlmTerminalNoticeAction(message: CustomMessage): void {\n\t\tthis._assertRlmTerminalNotice(message);\n\t\tconst action = this._createPreparedTurnAction(\"followUp\", message.content as string, undefined, {\n\t\t\tmessage,\n\t\t\tsuppressAutonomousContinuation: true,\n\t\t\tresumeIfIdle: false,\n\t\t\tsource: \"internal\",\n\t\t\texecutionPolicy: this._turnExecutionPolicy(\"injected\"),\n\t\t\tqueueVisible: false,\n\t\t});\n\t\tthis._durableRlmTerminalNoticeActionIds.add(action.id);\n\t\ttry {\n\t\t\tconst result = this._admitSessionInput(action, { wake: false });\n\t\t\tif (!result.accepted) throw new Error(\"RLM child terminal notice was not admitted.\");\n\t\t} catch (error) {\n\t\t\tthis._durableRlmTerminalNoticeActionIds.delete(action.id);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprivate _flushDeferredRlmTerminalNotices(): void {\n\t\tif (\n\t\t\tthis._sessionInputAdmissionPauses.size > 0 ||\n\t\t\tthis._sessionInputPumpSuspended ||\n\t\t\tthis._queuedWorkPauses.size > 0 ||\n\t\t\tthis._disposed ||\n\t\t\tthis._disposing\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\twhile (true) {\n\t\t\tconst index = this._pendingNextTurnMessages.findIndex((message) => this._isRlmTerminalNotice(message));\n\t\t\tif (index < 0) break;\n\t\t\tconst message = this._pendingNextTurnMessages[index];\n\t\t\ttry {\n\t\t\t\tthis._enqueueRlmTerminalNoticeAction(message);\n\t\t\t} catch {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._pendingNextTurnMessages.splice(index, 1);\n\t\t}\n\t\tthis._scheduleSessionInputPump();\n\t}\n\n\tprivate async _acquireRlmTerminalNoticeRetentionFence(): Promise<{ owner: symbol; release(): void } | undefined> {\n\t\tconst disposeSignal = this._sessionActionCommitDisposeAbortController.signal;\n\t\twhile (!this._disposed && !this._disposing && !disposeSignal.aborted) {\n\t\t\tif (this._queuedWorkPauses.size > 0) {\n\t\t\t\tlet wake = () => {};\n\t\t\t\tconst pauseReleased = new Promise<void>((resolve) => {\n\t\t\t\t\twake = resolve;\n\t\t\t\t\tthis._sessionInputCheckpointWaiters.add(resolve);\n\t\t\t\t});\n\t\t\t\ttry {\n\t\t\t\t\tawait waitForPromiseOrAbort(pauseReleased, disposeSignal, \"Terminal notice retention cancelled\");\n\t\t\t\t} catch {\n\t\t\t\t\treturn undefined;\n\t\t\t\t} finally {\n\t\t\t\t\tthis._sessionInputCheckpointWaiters.delete(wake);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlet fence: { owner: symbol; release(): void };\n\t\t\ttry {\n\t\t\t\tfence = await this._acquireSessionActionCommitFence(disposeSignal);\n\t\t\t} catch {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tif (this._queuedWorkPauses.size === 0 && !this._disposed && !this._disposing) return fence;\n\t\t\tfence.release();\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate async _deferRlmTerminalNotice(message: CustomMessage): Promise<void> {\n\t\tthis._assertRlmTerminalNotice(message);\n\t\tconst fence = await this._acquireRlmTerminalNoticeRetentionFence();\n\t\tif (!fence) return;\n\t\ttry {\n\t\t\tif (this._disposed || this._disposing) return;\n\t\t\tthis._pendingNextTurnMessages.push(cloneCustomMessage(message));\n\t\t\tthis._flushDeferredRlmTerminalNotices();\n\t\t} finally {\n\t\t\tfence.release();\n\t\t}\n\t}\n\n\tprivate _demoteRlmTerminalNoticeActions(): void {\n\t\tconst actions = this._actionStore\n\t\t\t.clearableActions()\n\t\t\t.filter((action) => this._durableRlmTerminalNoticeActionIds.has(action.id));\n\t\tif (actions.length === 0) return;\n\t\tfor (const action of actions) {\n\t\t\tif (!this._isRlmTerminalNoticeAction(action)) continue;\n\t\t\tconst message = primaryDeliveryRecord(action).message;\n\t\t\tif (message.role === \"custom\") this._pendingNextTurnMessages.push(cloneCustomMessage(message));\n\t\t}\n\t\tconst ids = new Set(actions.map((action) => action.id));\n\t\tthis._cancelSessionActions(\n\t\t\t(action) => ids.has(action.id),\n\t\t\tnew Error(\"RLM child terminal notice deferred across session input suspension.\"),\n\t\t\tactions,\n\t\t);\n\t\tfor (const id of ids) this._durableRlmTerminalNoticeActionIds.delete(id);\n\t}\n\n\tprivate async _promptInjectedMessage(\n\t\ttext: string,\n\t\tmessage: CustomMessage,\n\t\toptions?: InternalPromptOptions & { executionPolicy?: TurnExecutionPolicy },\n\t): Promise<void> {\n\t\tif (!this.isStreaming && options?.resumeIfIdle) this._resumeSessionInputAdmission();\n\t\tconst admissionEpoch = this._sessionInputPumpEpoch;\n\t\tconst admissionFence = await this._acquireDirectTurnAdmissionFence(options?.signal).catch((error: unknown) => {\n\t\t\tthrowIfPromptAdmissionCancelled(options?.signal);\n\t\t\tthrow error;\n\t\t});\n\t\tconst reportPreflight = oncePreflight(options?.preflightResult);\n\t\ttry {\n\t\t\tthrowIfPromptAdmissionCancelled(options?.signal);\n\t\t\tif (admissionEpoch !== this._sessionInputPumpEpoch) {\n\t\t\t\tthrow new Error(\"Injected session input was invalidated before admission\");\n\t\t\t}\n\t\t\toptions?.admissionCommitted?.();\n\t\t\tconst queueForStreaming = this.isStreaming;\n\t\t\tconst queueForBusy = options?.queueIfBusy === true && this._isBusyForSessionInput(\"preflight\");\n\t\t\tconst visibleQueued = queueForStreaming || queueForBusy;\n\t\t\tif (visibleQueued && !options?.streamingBehavior) {\n\t\t\t\tconst stateDescription = queueForStreaming ? \"Agent is already processing\" : \"Agent has queued work\";\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`${stateDescription}. Specify streamingBehavior ('steer' or 'followUp') to queue the message.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst schedule = options?.streamingBehavior ?? \"followUp\";\n\t\t\tconst prefixMessages = visibleQueued ? this._takePendingNextTurnMessages() : undefined;\n\t\t\tconst action = this._createPreparedTurnAction(schedule, text, undefined, {\n\t\t\t\tmessage,\n\t\t\t\tprefixMessages,\n\t\t\t\tqueueKey: options?.followUpQueueKey,\n\t\t\t\tpreviewLabel: injectedMessagePreviewLabel(message),\n\t\t\t\tsuppressAutonomousContinuation: options?.suppressAutonomousContinuation,\n\t\t\t\tresumeIfIdle:\n\t\t\t\t\t!visibleQueued ||\n\t\t\t\t\toptions?.resumeIfIdle ||\n\t\t\t\t\t(options?.queueIfBusy === true && canSelectSessionAction(this._runtimeActivity())),\n\t\t\t\tsource: options?.source ?? \"internal\",\n\t\t\t\texecutionPolicy:\n\t\t\t\t\toptions?.executionPolicy ??\n\t\t\t\t\t(visibleQueued ? this._turnExecutionPolicy(\"queued\") : this._turnExecutionPolicy(\"injected\")),\n\t\t\t\tqueueVisible: visibleQueued,\n\t\t\t});\n\t\t\tconst result = this._admitSessionInput(action, {\n\t\t\t\timmediatelyEligible: !visibleQueued,\n\t\t\t});\n\t\t\tadmissionFence.release();\n\t\t\tif (!result.accepted || !result.ticket) {\n\t\t\t\tif (prefixMessages) this._pendingNextTurnMessages.unshift(...prefixMessages);\n\t\t\t\treportPreflight(false, false);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (result.disposition === \"queued\") {\n\t\t\t\treportPreflight(true, true);\n\t\t\t} else {\n\t\t\t\tvoid result.ticket.delivered.then(\n\t\t\t\t\t() => reportPreflight(true),\n\t\t\t\t\t() => reportPreflight(false),\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (options?.returnAfterAccepted) {\n\t\t\t\tif (result.disposition === \"starts_when_admitted\") await result.ticket.delivered;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (visibleQueued) return;\n\t\t\tawait result.ticket.completed;\n\t\t} catch (error) {\n\t\t\treportPreflight(false);\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tadmissionFence.release();\n\t\t}\n\t}\n\n\tprivate async _prompt(text: string, options?: InternalPromptOptions): Promise<void> {\n\t\tconst resumeSuspendedInput = options?.resumeIfIdle !== false;\n\t\tif (!this.isStreaming) {\n\t\t\tif (resumeSuspendedInput) this._resumeSessionInputAdmission();\n\t\t\tthis._assertSessionActionAdmissionAvailable();\n\t\t}\n\t\tconst admissionEpoch = this._sessionInputPumpEpoch;\n\t\tconst commitFence = this.isStreaming\n\t\t\t? undefined\n\t\t\t: await this._acquireDirectTurnAdmissionFence(options?.signal).catch((error: unknown) => {\n\t\t\t\t\tthrowIfPromptAdmissionCancelled(options?.signal);\n\t\t\t\t\tthrow error;\n\t\t\t\t});\n\t\tconst reportPreflight = oncePreflight(options?.preflightResult);\n\t\tconst run = async () => {\n\t\t\ttry {\n\t\t\t\tthrowIfPromptAdmissionCancelled(options?.signal);\n\t\t\t\tif (!resumeSuspendedInput && admissionEpoch !== this._sessionInputPumpEpoch) {\n\t\t\t\t\tthrow new Error(\"Session input was invalidated before admission\");\n\t\t\t\t}\n\t\t\t\toptions?.admissionCommitted?.();\n\t\t\t\tconst isInternalPrompt = options?.internalPrompt === true;\n\t\t\t\tconst expandPromptTemplates = isInternalPrompt ? false : (options?.expandPromptTemplates ?? true);\n\t\t\t\tconst normalizationResult = this._normalizeSubmission(text, options?.images, {\n\t\t\t\t\tparseSessionCommands: !isInternalPrompt && !options?.skipPrePromptWork,\n\t\t\t\t\textensionCommands: expandPromptTemplates ? \"execute\" : \"ignore\",\n\t\t\t\t\tinputSource:\n\t\t\t\t\t\t!isInternalPrompt && !options?.skipInputHandlers ? (options?.source ?? \"interactive\") : undefined,\n\t\t\t\t\texpandSkills: expandPromptTemplates,\n\t\t\t\t\texpandPromptTemplates,\n\t\t\t\t});\n\t\t\t\tconst normalized = normalizationResult instanceof Promise ? await normalizationResult : normalizationResult;\n\t\t\t\tif (normalized.kind === \"extensionCommand\") {\n\t\t\t\t\tcommitFence?.release();\n\t\t\t\t\treportPreflight(true);\n\t\t\t\t\tvoid normalized.completion.then(\n\t\t\t\t\t\t() => this._settleAgentMessage(options?.agentMessageId, \"completion\"),\n\t\t\t\t\t\t(error) => this._settleAgentMessage(options?.agentMessageId, \"completion\", error),\n\t\t\t\t\t);\n\t\t\t\t\tvoid normalized.completion.catch(() => undefined);\n\t\t\t\t\tif (!options?.returnAfterAccepted) await normalized.completion.catch(() => undefined);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (normalized.kind === \"handled\") {\n\t\t\t\t\tcommitFence?.release();\n\t\t\t\t\treportPreflight(true);\n\t\t\t\t\tthis._settleAgentMessage(options?.agentMessageId, \"completion\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst pendingOwnedWork = this._actionStore.unfinishedActions().length > 0;\n\t\t\t\tconst wasRuntimeBusy = this.isStreaming || this.isCompacting || this.isRetrying || this.isBashRunning;\n\t\t\t\tconst wasBusy = wasRuntimeBusy || pendingOwnedWork;\n\t\t\t\tif (normalized.kind === \"sessionCommand\") {\n\t\t\t\t\tconst schedule = options?.streamingBehavior ?? (this.isStreaming ? \"steer\" : \"followUp\");\n\t\t\t\t\tconst action = this._createSessionCommandAction(\n\t\t\t\t\t\tnormalized.text,\n\t\t\t\t\t\tnormalized.command,\n\t\t\t\t\t\tnormalized.images,\n\t\t\t\t\t\tschedule,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tagentMessageId: options?.agentMessageId,\n\t\t\t\t\t\t\tsource: isInternalPrompt ? \"internal\" : (options?.source ?? \"interactive\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t\tconst result = this._admitSessionInput(action, {\n\t\t\t\t\t\timmediatelyEligible: !wasBusy && this._canStartSessionActionImmediately(),\n\t\t\t\t\t});\n\t\t\t\t\tcommitFence?.release();\n\t\t\t\t\treportPreflight(result.accepted, result.disposition === \"queued\");\n\t\t\t\t\tif (!result.accepted || !result.ticket) return;\n\t\t\t\t\tif (options?.returnAfterAccepted) {\n\t\t\t\t\t\tif (result.disposition === \"starts_when_admitted\") await result.ticket.delivered;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (result.disposition === \"queued\") return;\n\t\t\t\t\tawait this.waitForSessionInputIdle();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst queueForStreaming = this.isStreaming;\n\t\t\t\tconst queueForBusy = options?.queueIfBusy === true && this._isBusyForSessionInput(\"preflight\");\n\t\t\t\tconst visibleQueued = queueForStreaming || queueForBusy;\n\t\t\t\tif (visibleQueued && !options?.streamingBehavior) {\n\t\t\t\t\tconst stateDescription = queueForStreaming ? \"Agent is already processing\" : \"Agent has queued work\";\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`${stateDescription}. Specify streamingBehavior ('steer' or 'followUp') to queue the message.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst schedule = options?.streamingBehavior ?? \"followUp\";\n\t\t\t\tconst prefixMessages = visibleQueued ? this._takePendingNextTurnMessages() : undefined;\n\t\t\t\tconst content = options?.content\n\t\t\t\t\t? options.content.map((block) => ({ ...block }))\n\t\t\t\t\t: this._buildPromptContent(normalized.text, normalized.images);\n\t\t\t\tconst suppliedMessage = options?.customMessage;\n\t\t\t\tconst primaryMessage = suppliedMessage\n\t\t\t\t\t? visibleQueued\n\t\t\t\t\t\t? suppliedMessage\n\t\t\t\t\t\t: cloneCustomMessage(suppliedMessage)\n\t\t\t\t\t: ({\n\t\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\t\tcontent: content.map((block) => ({ ...block })),\n\t\t\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t\t\t} satisfies UserMessage);\n\t\t\t\tconst acceptedAgentMessage = options?.skipPrePromptWork === true && options.returnAfterAccepted === true;\n\t\t\t\tconst action = this._createPreparedTurnAction(schedule, normalized.text, normalized.images, {\n\t\t\t\t\tagentMessageId: options?.agentMessageId,\n\t\t\t\t\tqueueKey: options?.followUpQueueKey,\n\t\t\t\t\tcontent,\n\t\t\t\t\tmessage: primaryMessage,\n\t\t\t\t\tprefixMessages,\n\t\t\t\t\tsuppressAutonomousContinuation: options?.suppressAutonomousContinuation,\n\t\t\t\t\tresumeIfIdle:\n\t\t\t\t\t\t!visibleQueued ||\n\t\t\t\t\t\toptions?.resumeIfIdle ||\n\t\t\t\t\t\t(options?.queueIfBusy === true && canSelectSessionAction(this._runtimeActivity())),\n\t\t\t\t\tsource: isInternalPrompt ? \"internal\" : (options?.source ?? \"interactive\"),\n\t\t\t\t\texecutionPolicy: visibleQueued\n\t\t\t\t\t\t? this._turnExecutionPolicy(\"queued\")\n\t\t\t\t\t\t: this._turnExecutionPolicy(\"directPrompt\", {\n\t\t\t\t\t\t\t\treturnAfterAccepted: options?.returnAfterAccepted,\n\t\t\t\t\t\t\t\tskipPrePromptWork: options?.skipPrePromptWork,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\tqueueVisible: visibleQueued,\n\t\t\t\t\tacceptedAgentMessage,\n\t\t\t\t\tacceptedBeforeCompletion: options?.returnAfterAccepted === true,\n\t\t\t\t});\n\t\t\t\tif (action.suppressAutonomousContinuation) {\n\t\t\t\t\tthis._markAutonomousContinuationSuppressed(primaryDeliveryRecord(action).message);\n\t\t\t\t}\n\t\t\t\tconst result = this._admitSessionInput(action, {\n\t\t\t\t\timmediatelyEligible: !visibleQueued && this._canStartSessionActionImmediately(),\n\t\t\t\t});\n\t\t\t\tcommitFence?.release();\n\t\t\t\tif (!result.accepted || !result.ticket) {\n\t\t\t\t\tif (prefixMessages) this._pendingNextTurnMessages.unshift(...prefixMessages);\n\t\t\t\t\treportPreflight(false, false);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (result.disposition === \"queued\") {\n\t\t\t\t\treportPreflight(true, true);\n\t\t\t\t} else {\n\t\t\t\t\tvoid result.ticket.delivered.then(\n\t\t\t\t\t\t() => reportPreflight(true),\n\t\t\t\t\t\t() => reportPreflight(false),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst deferralObserver =\n\t\t\t\t\tacceptedAgentMessage &&\n\t\t\t\t\toptions?.queueIfBusy === true &&\n\t\t\t\t\t!options.streamingBehavior &&\n\t\t\t\t\tresult.disposition === \"starts_when_admitted\"\n\t\t\t\t\t\t? this._observeSessionActionDeferral(action)\n\t\t\t\t\t\t: undefined;\n\t\t\t\tif (acceptedAgentMessage && !queueForStreaming && !queueForBusy && !options?.streamingBehavior) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst outcome = deferralObserver\n\t\t\t\t\t\t\t? await Promise.race([\n\t\t\t\t\t\t\t\t\tresult.ticket.delivered.then(() => \"delivered\" as const),\n\t\t\t\t\t\t\t\t\tdeferralObserver.deferred.then(() => \"deferred\" as const),\n\t\t\t\t\t\t\t\t])\n\t\t\t\t\t\t\t: await result.ticket.delivered.then(() => \"delivered\" as const);\n\t\t\t\t\t\tif (outcome === \"deferred\" && !options?.streamingBehavior) {\n\t\t\t\t\t\t\tconst error = new Error(\n\t\t\t\t\t\t\t\t\"Agent became busy before prompt delivery. Specify streamingBehavior ('steer' or 'followUp') to queue the message.\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tthis._rejectAgentMessage(action.agentMessageId, error);\n\t\t\t\t\t\t\tthis._cancelSessionActions((candidate) => candidate === action, error);\n\t\t\t\t\t\t\tthis._emitQueueUpdate();\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn;\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tdeferralObserver?.stop();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (options?.returnAfterAccepted) {\n\t\t\t\t\tif (result.disposition === \"starts_when_admitted\" || (acceptedAgentMessage && !visibleQueued)) {\n\t\t\t\t\t\tawait result.ticket.delivered;\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (visibleQueued) return;\n\t\t\t\tawait result.ticket.completed;\n\t\t\t\tawait this.waitForSessionInputIdle();\n\t\t\t} catch (error) {\n\t\t\t\treportPreflight(false);\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tcommitFence?.release();\n\t\t\t}\n\t\t};\n\t\treturn commitFence ? this._sessionActionCommitContext.run(commitFence.owner, run) : run();\n\t}\n\n\tprivate _executeExtensionCommand(text: string): Promise<void> | undefined {\n\t\tconst parsed = parseSlashCommand(text);\n\t\tif (!parsed) return undefined;\n\t\tconst commandName = parsed.name;\n\t\tconst args = parsed.args;\n\n\t\tconst command = this._extensionRunner.getCommand(commandName);\n\t\tif (!command) return undefined;\n\t\tconst context = this._extensionRunner.createCommandContext();\n\t\treturn Promise.resolve()\n\t\t\t.then(() => command.handler(args, context))\n\n\t\t\t.catch((error: unknown) => {\n\t\t\t\tconst commandError = error instanceof Error ? error : new Error(String(error));\n\t\t\t\tthis._extensionRunner.emitError({\n\t\t\t\t\textensionPath: `command:${commandName}`,\n\t\t\t\t\tevent: \"command\",\n\t\t\t\t\terror: commandError.message,\n\t\t\t\t});\n\t\t\t\tthrow commandError;\n\t\t\t});\n\t}\n\n\t/**\n\t * Expand skill commands (/skill:name args) to their full content.\n\t * Returns the expanded text, or the original text if not a skill command or skill not found.\n\t * Emits errors via extension runner if file read fails.\n\t */\n\tprivate _expandSkillCommand(text: string): string {\n\t\tif (!text.startsWith(\"/skill:\")) return text;\n\n\t\tconst parsed = parseSlashCommand(text);\n\t\tif (!parsed?.name.startsWith(\"skill:\")) return text;\n\t\tconst skillName = parsed.name.slice(\"skill:\".length);\n\t\tconst args = parsed.args;\n\n\t\tconst skill = this.resourceLoader.getSkills().skills.find((s) => s.name === skillName);\n\t\tif (!skill) return text; // Unknown skill, pass through\n\n\t\ttry {\n\t\t\tconst content = readFileSync(skill.filePath, \"utf-8\");\n\t\t\tconst body = stripFrontmatter(content).trim();\n\t\t\tconst skillBlock = `<skill name=\"${skill.name}\" location=\"${skill.filePath}\">\\nReferences are relative to ${skill.baseDir}.\\n\\n${body}\\n</skill>`;\n\t\t\treturn args ? `${skillBlock}\\n\\n${args}` : skillBlock;\n\t\t} catch (err) {\n\t\t\tthis._extensionRunner.emitError({\n\t\t\t\textensionPath: skill.filePath,\n\t\t\t\tevent: \"skill_expansion\",\n\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t});\n\t\t\treturn text; // Return original on error\n\t\t}\n\t}\n\n\t/**\n\t * Queue a steering message while the agent is running.\n\t * Delivered after the current assistant turn finishes executing its tool calls,\n\t * before the next LLM call.\n\t * Expands skill commands and prompt templates. Errors on extension commands.\n\t * @param images Optional image attachments to include with the message\n\t * @throws Error if text is an extension command\n\t */\n\tasync steer(\n\t\ttext: string,\n\t\timages?: ImageContent[],\n\t\toptions: {\n\t\t\tqueueKey?: string;\n\t\t\tagentMessageId?: string;\n\t\t\tresumeIfIdle?: boolean;\n\t\t} = {},\n\t): Promise<void> {\n\t\tconst normalized = this._normalizeSubmission(text, images, {\n\t\t\tparseSessionCommands: false,\n\t\t\textensionCommands: \"reject\",\n\t\t\texpandSkills: true,\n\t\t\texpandPromptTemplates: true,\n\t\t});\n\t\tif (normalized instanceof Promise || normalized.kind !== \"prompt\") {\n\t\t\tthrow new Error(\"Queued prompt normalization did not produce a prompt\");\n\t\t}\n\n\t\tawait this._queuePreparedPrompt(\"steer\", normalized.text, normalized.images, {\n\t\t\tqueueKey: options.queueKey,\n\t\t\tagentMessageId: options.agentMessageId,\n\t\t\tresumeIfIdle: options.resumeIfIdle,\n\t\t});\n\t}\n\n\t/**\n\t * Queue a follow-up message to be processed after the agent finishes.\n\t * Delivered only when agent has no more tool calls or steering messages.\n\t * Expands skill commands and prompt templates. Errors on extension commands.\n\t * @param images Optional image attachments to include with the message\n\t * @throws Error if text is an extension command\n\t */\n\tasync followUp(\n\t\ttext: string,\n\t\timages?: ImageContent[],\n\t\toptions: {\n\t\t\tqueueKey?: string;\n\t\t\tagentMessageId?: string;\n\t\t\tresumeIfIdle?: boolean;\n\t\t} = {},\n\t): Promise<boolean> {\n\t\tconst normalized = this._normalizeSubmission(text, images, {\n\t\t\tparseSessionCommands: false,\n\t\t\textensionCommands: \"reject\",\n\t\t\texpandSkills: true,\n\t\t\texpandPromptTemplates: true,\n\t\t});\n\t\tif (normalized instanceof Promise || normalized.kind !== \"prompt\") {\n\t\t\tthrow new Error(\"Queued prompt normalization did not produce a prompt\");\n\t\t}\n\n\t\treturn this._queuePreparedPrompt(\"followUp\", normalized.text, normalized.images, {\n\t\t\tqueueKey: options.queueKey,\n\t\t\tagentMessageId: options.agentMessageId,\n\t\t\tresumeIfIdle: options.resumeIfIdle,\n\t\t});\n\t}\n\n\tasync restoreSessionActions(snapshot: SessionActionRecoverySnapshot): Promise<number> {\n\t\tif (snapshot.formatVersion !== SESSION_ACTION_RECOVERY_FORMAT_VERSION) {\n\t\t\tthrow new Error(`Unsupported session action recovery format version: ${snapshot.formatVersion}`);\n\t\t}\n\t\tconst actionIds = new Set(this._actionStore.ownedActions().map((action) => action.id));\n\t\tconst actions = snapshot.actions.map((recovered): QueuedSessionAction => {\n\t\t\tif (actionIds.has(recovered.id)) throw new Error(`Duplicate session action id: ${recovered.id}`);\n\t\t\tactionIds.add(recovered.id);\n\t\t\tif (\n\t\t\t\trecovered.payload.kind === \"turn\" &&\n\t\t\t\trecovered.payload.records.some((record) => record.ownerActionId !== recovered.id)\n\t\t\t) {\n\t\t\t\tthrow new Error(`Session action ${recovered.id} has invalid delivery correlation`);\n\t\t\t}\n\t\t\tconst payload: PreparedTurnPayload | PreparedCommandPayload =\n\t\t\t\trecovered.payload.kind === \"turn\"\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tkind: \"turn\",\n\t\t\t\t\t\t\ttext: recovered.payload.text,\n\t\t\t\t\t\t\t...(recovered.payload.preview ? { preview: recovered.payload.preview } : {}),\n\t\t\t\t\t\t\trecords: recovered.payload.records.map((record) => ({\n\t\t\t\t\t\t\t\tid: record.id,\n\t\t\t\t\t\t\t\trole: record.role,\n\t\t\t\t\t\t\t\tmessage: cloneQueuedAgentMessage(record.message),\n\t\t\t\t\t\t\t\tstarted: false,\n\t\t\t\t\t\t\t\tdurable: false,\n\t\t\t\t\t\t\t\townerActionId: record.ownerActionId,\n\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t...(recovered.payload.images\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\timages: recovered.payload.images.map((image) => ({\n\t\t\t\t\t\t\t\t\t\t\t...image,\n\t\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t...(recovered.payload.content\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\tcontent: recovered.payload.content.map((block) => ({\n\t\t\t\t\t\t\t\t\t\t\t...block,\n\t\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t...(recovered.payload.customMessage\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\tcustomMessage: cloneCustomMessage(recovered.payload.customMessage),\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\texecutionPolicy: {\n\t\t\t\t\t\t\t\t...recovered.payload.executionPolicy,\n\t\t\t\t\t\t\t\tpreparation: {\n\t\t\t\t\t\t\t\t\t...recovered.payload.executionPolicy.preparation,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tqueueVisible: recovered.payload.queueVisible,\n\t\t\t\t\t\t\tacceptedAgentMessage: recovered.payload.acceptedAgentMessage,\n\t\t\t\t\t\t\tacceptedBeforeCompletion: recovered.payload.acceptedBeforeCompletion,\n\t\t\t\t\t\t}\n\t\t\t\t\t: {\n\t\t\t\t\t\t\tkind: \"session_command\",\n\t\t\t\t\t\t\ttext: recovered.payload.text,\n\t\t\t\t\t\t\tcommand: { ...recovered.payload.command },\n\t\t\t\t\t\t\t...(recovered.payload.images\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\timages: recovered.payload.images.map((image) => ({\n\t\t\t\t\t\t\t\t\t\t\t...image,\n\t\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t};\n\t\t\treturn {\n\t\t\t\tid: recovered.id,\n\t\t\t\tsource: recovered.source,\n\t\t\t\tdelivery: recovered.delivery,\n\t\t\t\twake: recovered.wake,\n\t\t\t\tpayload,\n\t\t\t\tlifecycle: { state: \"queued\" },\n\t\t\t\t...(recovered.queueKey ? { queueKey: recovered.queueKey } : {}),\n\t\t\t\t...(recovered.agentMessageId ? { agentMessageId: recovered.agentMessageId } : {}),\n\t\t\t\t...(recovered.suppressAutonomousContinuation ? { suppressAutonomousContinuation: true } : {}),\n\t\t\t};\n\t\t});\n\t\tfor (const action of actions) {\n\t\t\tconst durableTerminalNotice = this._isRlmTerminalNoticeAction(action);\n\t\t\tif (durableTerminalNotice) this._durableRlmTerminalNoticeActionIds.add(action.id);\n\t\t\ttry {\n\t\t\t\tthis._admitSessionInput(action, { restore: true });\n\t\t\t} catch (error) {\n\t\t\t\tif (durableTerminalNotice) this._durableRlmTerminalNoticeActionIds.delete(action.id);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\treturn actions.length;\n\t}\n\n\tprivate _restoreSessionCommand(\n\t\ttext: string,\n\t\tcustomMessage: CustomMessage | undefined,\n\t\timages: ImageContent[] | undefined,\n\t\tschedule: SessionInputSchedule,\n\t\tagentMessageId: string | undefined,\n\t): boolean | undefined {\n\t\tif (!isSessionSlashCommandMessage(customMessage) || text !== customMessage.details.command.text) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn this._admitSessionInput(\n\t\t\tthis._createSessionCommandAction(text, customMessage.details.command, images, schedule, {\n\t\t\t\tagentMessageId,\n\t\t\t\tsource: \"internal\",\n\t\t\t}),\n\t\t\t{ restore: true },\n\t\t).accepted;\n\t}\n\n\tprivate _restorePromptInput(schedule: SessionInputSchedule, snapshot: RestoredPromptInput): Promise<boolean> {\n\t\treturn this._queuePreparedPrompt(schedule, snapshot.text, snapshot.images, {\n\t\t\tqueueKey: snapshot.queueKey,\n\t\t\tagentMessageId: snapshot.agentMessageId,\n\t\t\tcontent: snapshot.content,\n\t\t\tmessage: snapshot.customMessage,\n\t\t\tprefixMessages: snapshot.prefixMessages,\n\t\t\tsource: \"internal\",\n\t\t});\n\t}\n\n\tasync restoreSteeringMessage(\n\t\ttext: string,\n\t\timages?: ImageContent[],\n\t\toptions: {\n\t\t\tqueueKey?: string;\n\t\t\tagentMessageId?: string;\n\t\t\tcontent?: (TextContent | ImageContent)[];\n\t\t\tcustomMessage?: CustomMessage;\n\t\t\tprefixMessages?: CustomMessage[];\n\t\t} = {},\n\t): Promise<void> {\n\t\tif (\n\t\t\tthis._restoreSessionCommand(text, options.customMessage, images, \"steer\", options.agentMessageId) !== undefined\n\t\t)\n\t\t\treturn;\n\n\t\tawait this._restorePromptInput(\"steer\", {\n\t\t\ttext,\n\t\t\timages,\n\t\t\tqueueKey: options.queueKey,\n\t\t\tagentMessageId: options.agentMessageId,\n\t\t\tcontent: options.content,\n\t\t\tcustomMessage: options.customMessage,\n\t\t\tprefixMessages: options.prefixMessages,\n\t\t});\n\t}\n\n\tasync restoreFollowUpMessage(\n\t\ttext: string,\n\t\timages?: ImageContent[],\n\t\toptions: {\n\t\t\tqueueKey?: string;\n\t\t\tagentMessageId?: string;\n\t\t\tcontent?: (TextContent | ImageContent)[];\n\t\t\tcustomMessage?: CustomMessage;\n\t\t\tprefixMessages?: CustomMessage[];\n\t\t} = {},\n\t): Promise<boolean> {\n\t\tconst restoredCommand = this._restoreSessionCommand(\n\t\t\ttext,\n\t\t\toptions.customMessage,\n\t\t\timages,\n\t\t\t\"followUp\",\n\t\t\toptions.agentMessageId,\n\t\t);\n\t\tif (restoredCommand !== undefined) return restoredCommand;\n\n\t\treturn this._restorePromptInput(\"followUp\", {\n\t\t\ttext,\n\t\t\timages,\n\t\t\tqueueKey: options.queueKey,\n\t\t\tagentMessageId: options.agentMessageId,\n\t\t\tcontent: options.content,\n\t\t\tcustomMessage: options.customMessage,\n\t\t\tprefixMessages: options.prefixMessages,\n\t\t});\n\t}\n\n\tprivate _buildPromptContent(text: string, images?: ImageContent[]): (TextContent | ImageContent)[] {\n\t\tconst content: (TextContent | ImageContent)[] = [];\n\t\tcontent.push({ type: \"text\", text });\n\t\tif (images) content.push(...images);\n\t\treturn content;\n\t}\n\n\tprivate _takePendingNextTurnMessages(): CustomMessage[] {\n\t\tconst messages = this._pendingNextTurnMessages;\n\t\tthis._pendingNextTurnMessages = [];\n\t\treturn messages;\n\t}\n\n\tprivate _deliveryPolicy(schedule: SessionInputSchedule): DeliveryPolicy {\n\t\treturn schedule === \"steer\" ? \"next_turn_boundary\" : \"when_run_idle\";\n\t}\n\n\tprivate _createDeliveryRecord(\n\t\tactionId: string,\n\t\trole: DeliveryRecord[\"role\"],\n\t\tmessage: QueuedAgentMessage,\n\t): DeliveryRecord {\n\t\treturn {\n\t\t\tid: randomUUID(),\n\t\t\trole,\n\t\t\tmessage,\n\t\t\tstarted: false,\n\t\t\tdurable: false,\n\t\t\townerActionId: actionId,\n\t\t};\n\t}\n\n\tprivate _turnExecutionPolicy(\n\t\tkind: \"queued\" | \"directPrompt\" | \"injected\" | \"customTrigger\",\n\t\toptions: {\n\t\t\treturnAfterAccepted?: boolean;\n\t\t\tskipPrePromptWork?: boolean;\n\t\t} = {},\n\t): TurnExecutionPolicy {\n\t\tif (kind === \"queued\") {\n\t\t\treturn {\n\t\t\t\tpreparation: {\n\t\t\t\t\tinitialRefineBarrier: \"skip\",\n\t\t\t\t\tflushPendingBashBeforeValidation: false,\n\t\t\t\t\tvalidateModelAndAuth: true,\n\t\t\t\t\tawaitPendingModelSelection: true,\n\t\t\t\t\tpreTurnCompaction: \"beforeModelSelection\",\n\t\t\t\t\tfinalRefineBarrier: \"always\",\n\t\t\t\t},\n\t\t\t\trunBeforeAgentStart: true,\n\t\t\t\tnextTurnContextTiming: \"commit\",\n\t\t\t\tpreserveEmptyExtensionPrompt: true,\n\t\t\t\tcompletionIncludesRetryChain: true,\n\t\t\t};\n\t\t}\n\t\tif (kind === \"directPrompt\") {\n\t\t\treturn {\n\t\t\t\tpreparation: {\n\t\t\t\t\tinitialRefineBarrier: options.returnAfterAccepted ? \"skip\" : \"always\",\n\t\t\t\t\tflushPendingBashBeforeValidation: true,\n\t\t\t\t\tvalidateModelAndAuth: true,\n\t\t\t\t\tawaitPendingModelSelection: true,\n\t\t\t\t\tpreTurnCompaction: options.skipPrePromptWork ? \"skip\" : \"afterModelSelection\",\n\t\t\t\t\tfinalRefineBarrier: \"ifInFlight\",\n\t\t\t\t},\n\t\t\t\trunBeforeAgentStart: !options.skipPrePromptWork,\n\t\t\t\tnextTurnContextTiming: \"preparation\",\n\t\t\t\tpreserveEmptyExtensionPrompt: false,\n\t\t\t\tcompletionIncludesRetryChain: true,\n\t\t\t};\n\t\t}\n\t\tif (kind === \"injected\") {\n\t\t\treturn {\n\t\t\t\tpreparation: {\n\t\t\t\t\tinitialRefineBarrier: \"always\",\n\t\t\t\t\tflushPendingBashBeforeValidation: true,\n\t\t\t\t\tvalidateModelAndAuth: true,\n\t\t\t\t\tawaitPendingModelSelection: true,\n\t\t\t\t\tpreTurnCompaction: \"beforeModelSelection\",\n\t\t\t\t\tfinalRefineBarrier: \"ifInFlight\",\n\t\t\t\t},\n\t\t\t\trunBeforeAgentStart: true,\n\t\t\t\tnextTurnContextTiming: \"preparation\",\n\t\t\t\tpreserveEmptyExtensionPrompt: true,\n\t\t\t\tcompletionIncludesRetryChain: true,\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tpreparation: {\n\t\t\t\tinitialRefineBarrier: \"always\",\n\t\t\t\tflushPendingBashBeforeValidation: false,\n\t\t\t\tvalidateModelAndAuth: false,\n\t\t\t\tawaitPendingModelSelection: false,\n\t\t\t\tpreTurnCompaction: \"skip\",\n\t\t\t\tfinalRefineBarrier: \"skip\",\n\t\t\t},\n\t\t\trunBeforeAgentStart: false,\n\t\t\tnextTurnContextTiming: \"skip\",\n\t\t\tpreserveEmptyExtensionPrompt: false,\n\t\t\tcompletionIncludesRetryChain: false,\n\t\t};\n\t}\n\n\tprivate _createPreparedTurnAction(\n\t\tschedule: SessionInputSchedule,\n\t\ttext: string,\n\t\timages: ImageContent[] | undefined,\n\t\toptions: {\n\t\t\tagentMessageId?: string;\n\t\t\tqueueKey?: string;\n\t\t\tcontent?: (TextContent | ImageContent)[];\n\t\t\tmessage?: QueuedAgentMessage;\n\t\t\tprefixMessages?: CustomMessage[];\n\t\t\tpreviewLabel?: string;\n\t\t\tsuppressAutonomousContinuation?: boolean;\n\t\t\tresumeIfIdle?: boolean;\n\t\t\tsource?: InputSource | \"internal\";\n\t\t\texecutionPolicy?: TurnExecutionPolicy;\n\t\t\tqueueVisible?: boolean;\n\t\t\tacceptedAgentMessage?: boolean;\n\t\t\tacceptedBeforeCompletion?: boolean;\n\t\t},\n\t): QueuedSessionAction {\n\t\tconst id = randomUUID();\n\t\tconst content = options.content ?? this._buildPromptContent(text, images);\n\t\tconst message =\n\t\t\toptions.message ??\n\t\t\t({\n\t\t\t\trole: \"user\",\n\t\t\t\tcontent: content.map((block) => ({ ...block })),\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t} satisfies UserMessage);\n\t\tconst prefixMessages = options.prefixMessages?.map((prefix) => cloneCustomMessage(prefix)) ?? [];\n\t\tconst preview = options.previewLabel ? `${options.previewLabel}: ${text}` : undefined;\n\t\tconst payload: PreparedTurnPayload = {\n\t\t\tkind: \"turn\",\n\t\t\ttext,\n\t\t\trecords: [\n\t\t\t\t...prefixMessages.map((prefix) => this._createDeliveryRecord(id, \"prefix\", prefix)),\n\t\t\t\tthis._createDeliveryRecord(id, \"primary\", message),\n\t\t\t],\n\t\t\tpreview,\n\t\t\timages: images?.map((image) => ({ ...image })),\n\t\t\tcontent: content.map((block) => ({ ...block })),\n\t\t\tcustomMessage: options.message?.role === \"custom\" ? cloneCustomMessage(options.message) : undefined,\n\t\t\texecutionPolicy: options.executionPolicy ?? this._turnExecutionPolicy(\"queued\"),\n\t\t\tqueueVisible: options.queueVisible ?? true,\n\t\t\tacceptedAgentMessage: options.acceptedAgentMessage ?? false,\n\t\t\tacceptedBeforeCompletion: options.acceptedBeforeCompletion ?? false,\n\t\t};\n\t\treturn {\n\t\t\tid,\n\t\t\tsource: options.source ?? \"internal\",\n\t\t\tdelivery: this._deliveryPolicy(schedule),\n\t\t\twake:\n\t\t\t\toptions.resumeIfIdle === true\n\t\t\t\t\t? \"immediate\"\n\t\t\t\t\t: schedule === \"steer\"\n\t\t\t\t\t\t? \"on_lower_boundary\"\n\t\t\t\t\t\t: \"external_resume\",\n\t\t\tpayload,\n\t\t\tlifecycle: { state: \"queued\" },\n\t\t\tqueueKey: options.queueKey,\n\t\t\tagentMessageId: options.agentMessageId,\n\t\t\tsuppressAutonomousContinuation: options.suppressAutonomousContinuation,\n\t\t};\n\t}\n\n\tprivate _createSessionCommandAction(\n\t\ttext: string,\n\t\tcommand: SessionSlashCommand,\n\t\timages: ImageContent[] | undefined,\n\t\tschedule: SessionInputSchedule,\n\t\toptions: {\n\t\t\tagentMessageId?: string;\n\t\t\tsource?: InputSource | \"internal\";\n\t\t} = {},\n\t): QueuedSessionAction {\n\t\treturn {\n\t\t\tid: randomUUID(),\n\t\t\tsource: options.source ?? \"internal\",\n\t\t\tdelivery: this._deliveryPolicy(schedule),\n\t\t\twake: \"immediate\",\n\t\t\tpayload: { kind: \"session_command\", text, command, images },\n\t\t\tlifecycle: { state: \"queued\" },\n\t\t\tagentMessageId: options.agentMessageId,\n\t\t};\n\t}\n\n\tprivate _coalescedFollowUpOwner(action: QueuedSessionAction): QueuedSessionAction | undefined {\n\t\tif (action.delivery !== \"when_run_idle\" || action.payload.kind !== \"turn\" || !action.queueKey) return undefined;\n\t\treturn this._actionStore\n\t\t\t.unfinishedActions()\n\t\t\t.find(\n\t\t\t\t(candidate) =>\n\t\t\t\t\tcandidate.queueKey === action.queueKey &&\n\t\t\t\t\t(candidate.lifecycle.state === \"queued\" ||\n\t\t\t\t\t\tcandidate.lifecycle.state === \"selected\" ||\n\t\t\t\t\t\tcandidate.lifecycle.state === \"preparing\"),\n\t\t\t);\n\t}\n\n\tprivate _assertSessionActionAdmissionAvailable(): void {\n\t\tif (this._disposed || this._disposing) {\n\t\t\tthrow new Error(\"Cannot admit a session action because the session is disposing or disposed.\");\n\t\t}\n\t\tif (this._sessionInputAdmissionPauses.size > 0) {\n\t\t\tthrow new Error(\"Cannot admit a session action while session input admission is paused.\");\n\t\t}\n\t\tif (this._sessionInputPumpSuspended) {\n\t\t\tthrow new Error(\"Cannot admit a session action while queued session input is suspended.\");\n\t\t}\n\t}\n\n\tprivate _admitSessionInput(\n\t\taction: QueuedSessionAction,\n\t\toptions: {\n\t\t\trestore?: boolean;\n\t\t\tfront?: boolean;\n\t\t\twake?: boolean;\n\t\t\timmediatelyEligible?: boolean;\n\t\t} = {},\n\t): {\n\t\taccepted: boolean;\n\t\tdisposition: \"starts_when_admitted\" | \"queued\";\n\t\tticket?: ActionTicket;\n\t} {\n\t\tif (this._disposed || this._disposing) {\n\t\t\tthrow new Error(\"Cannot admit a session action because the session is disposing or disposed.\");\n\t\t}\n\t\tif (this._sessionInputAdmissionPauses.size > 0) {\n\t\t\tthrow new Error(\"Cannot admit a session action while session input admission is paused.\");\n\t\t}\n\t\tconst coalescedOwner = options.restore ? undefined : this._coalescedFollowUpOwner(action);\n\t\tif (coalescedOwner) {\n\t\t\tif (action.agentMessageId !== coalescedOwner.agentMessageId) {\n\t\t\t\tthis._rejectAgentMessage(\n\t\t\t\t\taction.agentMessageId,\n\t\t\t\t\tnew Error(\"Prompt was not queued because an equivalent follow-up is already pending.\"),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn { accepted: false, disposition: \"queued\" };\n\t\t}\n\t\tconst canStartImmediately =\n\t\t\toptions.immediatelyEligible === true &&\n\t\t\t(this._actionStore.unfinishedActions().length === 0 || options.front === true);\n\t\tif (options.front) this._actionStore.enqueueFront(action);\n\t\telse this._actionStore.enqueue(action);\n\t\tlet disposition: \"starts_when_admitted\" | \"queued\" = \"queued\";\n\t\tif (canStartImmediately && this._actionStore.selectFirst() === action) disposition = \"starts_when_admitted\";\n\t\tconst controller = this._actionStore.ticketFor(action);\n\t\tcontroller.settleAccepted({\n\t\t\tstatus: \"accepted\",\n\t\t\tactionId: action.id,\n\t\t\tdisposition,\n\t\t});\n\t\tthis._sessionInputArrivalEpoch++;\n\t\tthis._emitQueueUpdate();\n\t\tif (\n\t\t\t!options.restore &&\n\t\t\toptions.wake !== false &&\n\t\t\t(disposition === \"starts_when_admitted\" ||\n\t\t\t\t(action.delivery === \"next_turn_boundary\" && this.isStreaming) ||\n\t\t\t\taction.payload.kind === \"session_command\" ||\n\t\t\t\taction.wake === \"immediate\")\n\t\t) {\n\t\t\tif (action.payload.kind === \"turn\" && action.wake === \"immediate\") {\n\t\t\t\tthis._resumeSessionInputAdmission();\n\t\t\t}\n\t\t\tthis._scheduleSessionInputPump();\n\t\t}\n\t\treturn { accepted: true, disposition, ticket: controller.ticket };\n\t}\n\n\tprivate async _queuePreparedPrompt(\n\t\tschedule: SessionInputSchedule,\n\t\ttext: string,\n\t\timages?: ImageContent[],\n\t\toptions: {\n\t\t\tagentMessageId?: string;\n\t\t\tqueueKey?: string;\n\t\t\tcontent?: (TextContent | ImageContent)[];\n\t\t\tmessage?: QueuedAgentMessage;\n\t\t\tprefixMessages?: CustomMessage[];\n\t\t\tpreviewLabel?: string;\n\t\t\tsuppressAutonomousContinuation?: boolean;\n\t\t\tresumeIfIdle?: boolean;\n\t\t\tsource?: InputSource | \"internal\";\n\t\t} = {},\n\t): Promise<boolean> {\n\t\tconst action = this._createPreparedTurnAction(schedule, text, images, options);\n\t\tif (action.suppressAutonomousContinuation) {\n\t\t\tthis._markAutonomousContinuationSuppressed(primaryDeliveryRecord(action).message);\n\t\t}\n\t\treturn this._admitSessionInput(action).accepted;\n\t}\n\n\tprivate _runtimeActivity(): RuntimeActivity {\n\t\treturn {\n\t\t\tlowerAgentRun: this.isStreaming,\n\t\t\tcompaction: this.isCompacting,\n\t\t\tretry: this.isRetrying,\n\t\t\tbash: this.isBashRunning,\n\t\t\trefinementApply: this._refineInFlight !== undefined,\n\t\t\tbranchMutation: this._branchSummaryOperation !== undefined,\n\t\t\tschedulerPauseCount: this._queuedWorkPauses.size + (this._sessionInputPumpSuspended ? 1 : 0),\n\t\t\tdisposing: this._disposed || this._disposing,\n\t\t};\n\t}\n\n\tprivate _hasSelectableSessionInput(): boolean {\n\t\treturn (\n\t\t\tthis._actionStore.queuedActions().length > 0 ||\n\t\t\tthis._actionStore.activeActions().some((action) => action.lifecycle.state === \"selected\")\n\t\t);\n\t}\n\n\tget hasPendingSessionWork(): boolean {\n\t\treturn this._actionStore.unfinishedActions().some((action) => {\n\t\t\tconst state = action.lifecycle.state;\n\t\t\treturn (\n\t\t\t\tstate === \"queued\" ||\n\t\t\t\tstate === \"selected\" ||\n\t\t\t\tstate === \"preparing\" ||\n\t\t\t\t(state === \"committing\" && action.payload.kind === \"turn\" && !primaryDeliveryRecord(action).durable)\n\t\t\t);\n\t\t});\n\t}\n\n\tget hasPendingAdmissionWaiters(): boolean {\n\t\treturn (\n\t\t\tthis._sessionActionCommitOwner !== undefined ||\n\t\t\tthis._pendingSessionActionFenceWaiters > 0 ||\n\t\t\tthis._sessionInputCheckpointWaiters.size > 0\n\t\t);\n\t}\n\n\tprivate _scheduleSessionInputPump(): void {\n\t\tif (this._sessionInputPumpSuspended || this._queuedWorkPauses.size > 0) return;\n\t\tif (this._disposed || this._disposing || this._sessionInputPumpRequested || !this._hasSelectableSessionInput()) {\n\t\t\treturn;\n\t\t}\n\t\tthis._sessionInputPumpRequested = true;\n\t\tconst epoch = this._sessionInputPumpEpoch;\n\t\tconst pump = async () => {\n\t\t\tthis._sessionInputPumpRequested = false;\n\t\t\tawait this._pumpSessionInputs(epoch);\n\t\t};\n\t\tthis._sessionInputPump = this._sessionInputPump.then(pump, pump);\n\t\tthis._sessionInputPump.catch(() => {});\n\t}\n\n\tprivate async _pumpSessionInputs(epoch: number): Promise<void> {\n\t\tlet blocked = false;\n\t\ttry {\n\t\t\twhile (!this._disposed && !this._disposing && this._hasSelectableSessionInput()) {\n\t\t\t\tawait this.agent.waitForIdle();\n\t\t\t\tconst preselected = this._actionStore\n\t\t\t\t\t.activeActions()\n\t\t\t\t\t.find((action) => action.lifecycle.state === \"selected\");\n\t\t\t\tif (epoch !== this._sessionInputPumpEpoch) {\n\t\t\t\t\tif (preselected) {\n\t\t\t\t\t\tthis._actionStore.rollback(preselected);\n\t\t\t\t\t\tthis._notifySessionInputCheckpointChange();\n\t\t\t\t\t\tthis._emitQueueUpdate();\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (!this._hasCancelledDispatchCapture()) await this._agentEventQueue;\n\t\t\t\tif (!preselected || preselected.payload.kind === \"session_command\") await this._waitForRefineIdle();\n\t\t\t\tconst activity = this._runtimeActivity();\n\t\t\t\tconst canSelectPreselectedTurn =\n\t\t\t\t\tpreselected?.payload.kind === \"turn\" && canSelectSessionAction({ ...activity, refinementApply: false });\n\t\t\t\tif (\n\t\t\t\t\tthis._isSessionInputHandoffDeferred(epoch) ||\n\t\t\t\t\t(!canSelectPreselectedTurn && !canSelectSessionAction(activity))\n\t\t\t\t) {\n\t\t\t\t\tblocked = true;\n\t\t\t\t\tthis._notifySessionInputCheckpointChange();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst first = preselected ?? this._actionStore.selectFirst();\n\t\t\t\tif (!first) return;\n\t\t\t\tif (first.payload.kind === \"session_command\") {\n\t\t\t\t\tawait this._executeSelectedSessionCommand(first, epoch);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst mode = first.delivery === \"next_turn_boundary\" ? this.steeringMode : this.followUpMode;\n\t\t\t\tconst actions: QueuedSessionAction[] = [first];\n\t\t\t\twhile (!preselected && mode === \"all\") {\n\t\t\t\t\tconst next = this._actionStore.queuedActions(first.delivery)[0];\n\t\t\t\t\tif (\n\t\t\t\t\t\t!next ||\n\t\t\t\t\t\tnext.payload.kind !== \"turn\" ||\n\t\t\t\t\t\t!turnExecutionPoliciesEqual(first.payload.executionPolicy, next.payload.executionPolicy)\n\t\t\t\t\t) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tthis._actionStore.selectFirst();\n\t\t\t\t\tactions.push(next);\n\t\t\t\t}\n\t\t\t\tif (epoch !== this._sessionInputPumpEpoch) {\n\t\t\t\t\tfor (const action of actions) this._actionStore.rollback(action);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tfor (const action of actions) transitionSessionAction(action, { state: \"preparing\" });\n\t\t\t\tthis._notifySessionInputCheckpointChange();\n\t\t\t\tthis._emitQueueUpdate();\n\t\t\t\ttry {\n\t\t\t\t\tawait this._startPreparedTurnActions(actions, epoch);\n\t\t\t\t\tfor (const action of actions) {\n\t\t\t\t\t\tif (action.lifecycle.state === \"committing\") {\n\t\t\t\t\t\t\tconst primary = primaryDeliveryRecord(action);\n\t\t\t\t\t\t\tif (this.agent.state.messages.includes(primary.message)) {\n\t\t\t\t\t\t\t\tprimary.durable = true;\n\t\t\t\t\t\t\t\ttransitionSessionAction(action, {\n\t\t\t\t\t\t\t\t\tstate: \"running\",\n\t\t\t\t\t\t\t\t\texecution: \"agent_turn\",\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (action.lifecycle.state === \"running\") {\n\t\t\t\t\t\t\ttransitionSessionAction(action, { state: \"completed\" });\n\t\t\t\t\t\t\tthis._actionStore.ticketFor(action).settleCompleted();\n\t\t\t\t\t\t\tthis._settleAgentMessage(action.agentMessageId, \"completion\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst transcript = this.agent.state.messages;\n\t\t\t\t\tconst delivered = new Set(transcript);\n\t\t\t\t\tconst undelivered: QueuedSessionAction[] = [];\n\t\t\t\t\tfor (const action of actions) {\n\t\t\t\t\t\tif (action.payload.kind !== \"turn\" || action.lifecycle.state === \"cancelled\") continue;\n\t\t\t\t\t\tfor (const record of action.payload.records) record.durable ||= delivered.has(record.message);\n\t\t\t\t\t\taction.payload.records = action.payload.records.filter((record) => {\n\t\t\t\t\t\t\tif (record.role === \"prefix\") return !record.durable;\n\t\t\t\t\t\t\tif (record.role === \"next_turn\") return record.durable;\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (!primaryDeliveryRecord(action).durable) undelivered.push(action);\n\t\t\t\t\t}\n\t\t\t\t\tif (this._isDeferredSessionInputError(error, epoch)) {\n\t\t\t\t\t\tfor (const action of undelivered) {\n\t\t\t\t\t\t\tif (action.lifecycle.state === \"committing\") {\n\t\t\t\t\t\t\t\tthis._actionStore.rollback(action, {\n\t\t\t\t\t\t\t\t\tdispatchSettled: true,\n\t\t\t\t\t\t\t\t\ttranscript,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t} else if (action.lifecycle.state === \"preparing\" || action.lifecycle.state === \"selected\") {\n\t\t\t\t\t\t\t\tthis._actionStore.rollback(action);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (undelivered.length > 0) this._emitQueueUpdate();\n\t\t\t\t\t\tblocked = epoch !== this._sessionInputPumpEpoch || this._isBusyForSessionInput(\"pump\");\n\t\t\t\t\t\tif (blocked) return;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tconst terminalError = this._asError(error);\n\t\t\t\t\tfor (const action of actions) {\n\t\t\t\t\t\tif (action.lifecycle.state === \"cancelled\") continue;\n\t\t\t\t\t\tif (action.lifecycle.state !== \"completed\" && action.lifecycle.state !== \"failed\") {\n\t\t\t\t\t\t\ttransitionSessionAction(action, {\n\t\t\t\t\t\t\t\tstate: \"failed\",\n\t\t\t\t\t\t\t\terror: terminalError,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst ticket = this._actionStore.ticketFor(action);\n\t\t\t\t\t\tif (undelivered.includes(action)) {\n\t\t\t\t\t\t\tticket.rejectDelivered(terminalError);\n\t\t\t\t\t\t\tthis._settleAgentMessage(action.agentMessageId, \"delivery\", terminalError);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis._settleAgentMessage(action.agentMessageId, \"completion\", terminalError);\n\t\t\t\t\t\tticket.settleCompleted(terminalError);\n\t\t\t\t\t}\n\t\t\t\t\tif (actions.some((action) => action.payload.kind !== \"turn\" || action.payload.queueVisible)) {\n\t\t\t\t\t\tthis._surfaceSessionInputError(error);\n\t\t\t\t\t}\n\t\t\t\t} finally {\n\t\t\t\t\tfor (const action of actions) {\n\t\t\t\t\t\tconst retainedCancelledDispatch =\n\t\t\t\t\t\t\taction.lifecycle.state === \"cancelled\" &&\n\t\t\t\t\t\t\taction.payload.kind === \"turn\" &&\n\t\t\t\t\t\t\taction.payload.captureRunMessages !== undefined;\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t!retainedCancelledDispatch &&\n\t\t\t\t\t\t\t(action.lifecycle.state === \"completed\" ||\n\t\t\t\t\t\t\t\taction.lifecycle.state === \"failed\" ||\n\t\t\t\t\t\t\t\taction.lifecycle.state === \"cancelled\")\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tthis._durableRlmTerminalNoticeActionIds.delete(action.id);\n\t\t\t\t\t\t\tthis._actionStore.releaseTerminal(action);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthis._notifySessionInputCheckpointChange();\n\t\t\t\t\tthis._emitQueueUpdate();\n\t\t\t\t}\n\t\t\t\tif (epoch !== this._sessionInputPumpEpoch || blocked) return;\n\t\t\t}\n\t\t} finally {\n\t\t\tif (!blocked && epoch === this._sessionInputPumpEpoch && this._hasSelectableSessionInput()) {\n\t\t\t\tthis._scheduleSessionInputPump();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async _executeSelectedSessionCommand(action: QueuedSessionAction, epoch: number): Promise<void> {\n\t\tif (action.payload.kind !== \"session_command\") throw new Error(\"Expected a selected session command\");\n\t\tconst input = action.payload;\n\t\tconst commitFence = await this._acquireSessionActionCommitFence();\n\t\ttry {\n\t\t\tawait this._sessionActionCommitContext.run(commitFence.owner, async () => {\n\t\t\t\tconst isCancelled = () => action.lifecycle.state === \"cancelled\";\n\t\t\t\tif (isCancelled()) return;\n\t\t\t\tawait this._waitForRefineIdle();\n\t\t\t\tif (isCancelled()) return;\n\t\t\t\tif (this._isSessionInputHandoffDeferred(epoch) || !canSelectSessionAction(this._runtimeActivity())) {\n\t\t\t\t\tthis._actionStore.rollback(action);\n\t\t\t\t\tthis._notifySessionInputCheckpointChange();\n\t\t\t\t\tthis._emitQueueUpdate();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\ttransitionSessionAction(action, {\n\t\t\t\t\tstate: \"running\",\n\t\t\t\t\texecution: \"session_command\",\n\t\t\t\t});\n\t\t\t\tthis._notifySessionInputCheckpointChange();\n\t\t\t\tthis._emitQueueUpdate();\n\t\t\t\ttry {\n\t\t\t\t\tthis._appendDurableSessionCommandMessage(input.text, input.command, false);\n\t\t\t\t\tthis._actionStore.ticketFor(action).settleDelivered({ status: \"not_applicable\" });\n\t\t\t\t\tthis._settleAgentMessage(action.agentMessageId, \"delivery\");\n\t\t\t\t\tawait this._executeQueuedSessionCommand(action);\n\t\t\t\t\ttransitionSessionAction(action, { state: \"completed\" });\n\t\t\t\t\tthis._actionStore.ticketFor(action).settleCompleted();\n\t\t\t\t\tthis._settleAgentMessage(action.agentMessageId, \"completion\");\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst commandError = this._asError(error);\n\t\t\t\t\ttransitionSessionAction(action, {\n\t\t\t\t\t\tstate: \"failed\",\n\t\t\t\t\t\terror: commandError,\n\t\t\t\t\t});\n\t\t\t\t\tconst ticket = this._actionStore.ticketFor(action);\n\t\t\t\t\tticket.rejectDelivered(commandError);\n\t\t\t\t\tticket.settleCompleted(commandError);\n\t\t\t\t\tthis._rejectAgentMessage(action.agentMessageId, commandError);\n\t\t\t\t} finally {\n\t\t\t\t\tthis._actionStore.releaseTerminal(action);\n\t\t\t\t\tthis._notifySessionInputCheckpointChange();\n\t\t\t\t\tthis._emitQueueUpdate();\n\t\t\t\t}\n\t\t\t});\n\t\t} finally {\n\t\t\tcommitFence.release();\n\t\t}\n\t}\n\n\tprivate _isBusyForSessionInput(point: \"preflight\" | \"pump\"): boolean {\n\t\tconst externalBusy = this.isCompacting || this.isRetrying || this.isBashRunning;\n\t\tif (point === \"pump\") {\n\t\t\treturn (\n\t\t\t\texternalBusy ||\n\t\t\t\tthis._disposed ||\n\t\t\t\tthis._disposing ||\n\t\t\t\tthis._sessionInputPumpSuspended ||\n\t\t\t\tthis._queuedWorkPauses.size > 0 ||\n\t\t\t\tthis._branchSummaryOperation !== undefined\n\t\t\t);\n\t\t}\n\t\treturn externalBusy || this._actionStore.unfinishedActions().length > 0;\n\t}\n\n\tprivate _isSessionInputHandoffDeferred(epoch: number): boolean {\n\t\treturn epoch !== this._sessionInputPumpEpoch || this._isBusyForSessionInput(\"pump\");\n\t}\n\n\tprivate _asError(error: unknown): Error {\n\t\treturn error instanceof Error ? error : new Error(String(error));\n\t}\n\n\tprivate _isDeferredSessionInputError(error: unknown, epoch: number): boolean {\n\t\tif (error instanceof DeferredSessionInputError) return true;\n\t\tif (epoch !== this._sessionInputPumpEpoch) return true;\n\t\tif (this._isBusyForSessionInput(\"pump\")) {\n\t\t\tthis._surfaceSessionInputError(error);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate _surfaceSessionInputError(error: unknown): void {\n\t\tconst normalized = this._asError(error);\n\t\ttry {\n\t\t\tthis._extensionRunner.emitError({\n\t\t\t\textensionPath: \"<session-input>\",\n\t\t\t\tevent: \"session_input\",\n\t\t\t\terror: normalized.message,\n\t\t\t\tstack: normalized.stack,\n\t\t\t});\n\t\t} catch {\n\t\t\t// Best-effort: a throwing error listener must not break the pump's requeue path.\n\t\t}\n\t}\n\n\tprivate async _startPreparedTurnActions(actions: QueuedSessionAction[], epoch: number): Promise<void> {\n\t\tlet nextTurnMessages: CustomMessage[] = [];\n\t\tconst activeTurns = () =>\n\t\t\tactions.filter(\n\t\t\t\t(action): action is SessionAction<PreparedTurnPayload> =>\n\t\t\t\t\taction.payload.kind === \"turn\" && action.lifecycle.state === \"preparing\",\n\t\t\t);\n\t\tconst firstTurn = activeTurns()[0];\n\t\tif (!firstTurn) return;\n\t\tconst executionPolicy = firstTurn.payload.executionPolicy;\n\t\tconst restoreNextTurnContext = () => {\n\t\t\tthis._pendingNextTurnMessages.unshift(...nextTurnMessages);\n\t\t\tnextTurnMessages = [];\n\t\t};\n\t\ttry {\n\t\t\tconst preparedTurn = await this._prepareForCommit(executionPolicy.preparation, {\n\t\t\t\tafterValidation: () => {\n\t\t\t\t\tif (this._isSessionInputHandoffDeferred(epoch)) {\n\t\t\t\t\t\tthrow new DeferredSessionInputError(\"Session input paused before preflight\");\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tprepare: async () => {\n\t\t\t\t\tif (executionPolicy.nextTurnContextTiming === \"preparation\") {\n\t\t\t\t\t\tnextTurnMessages = this._takePendingNextTurnMessages();\n\t\t\t\t\t}\n\t\t\t\t\tif (!executionPolicy.runBeforeAgentStart) return undefined;\n\t\t\t\t\twhile (activeTurns().some((action) => action.payload.prepared === undefined)) {\n\t\t\t\t\t\tif (this._isSessionInputHandoffDeferred(epoch)) {\n\t\t\t\t\t\t\tthrow new DeferredSessionInputError(\"Session input paused before preparation\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst preparationAction = activeTurns().at(-1);\n\t\t\t\t\t\tif (!preparationAction) return undefined;\n\t\t\t\t\t\tconst basePromptSnapshot = this._baseSystemPrompt;\n\t\t\t\t\t\tconst result = await this._extensionRunner.emitBeforeAgentStart(\n\t\t\t\t\t\t\tpreparationAction.payload.text,\n\t\t\t\t\t\t\tpreparationAction.payload.images,\n\t\t\t\t\t\t\tbasePromptSnapshot,\n\t\t\t\t\t\t\tthis._baseSystemPromptOptions,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (activeTurns().at(-1) !== preparationAction) continue;\n\t\t\t\t\t\tconst prepared = { result, basePromptSnapshot };\n\t\t\t\t\t\tfor (const action of activeTurns()) action.payload.prepared = prepared;\n\t\t\t\t\t}\n\t\t\t\t\tif (this._isSessionInputHandoffDeferred(epoch)) {\n\t\t\t\t\t\tthrow new DeferredSessionInputError(\"Session input paused before handoff\");\n\t\t\t\t\t}\n\t\t\t\t\treturn activeTurns()[0]?.payload.prepared;\n\t\t\t\t},\n\t\t\t\tshouldCommit: () => activeTurns().length > 0,\n\t\t\t\tcommit: (prepared) => {\n\t\t\t\t\tif (this._isSessionInputHandoffDeferred(epoch)) {\n\t\t\t\t\t\tthrow new DeferredSessionInputError(\"Session input paused before handoff\");\n\t\t\t\t\t}\n\t\t\t\t\tconst turns = activeTurns();\n\t\t\t\t\tif (turns.length === 0) return undefined;\n\t\t\t\t\treturn { prepared, turns };\n\t\t\t\t},\n\t\t\t});\n\t\t\tif (!preparedTurn) {\n\t\t\t\trestoreNextTurnContext();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst { prepared, turns } = preparedTurn;\n\t\t\tconst commitFence = await this._acquireSessionActionCommitFence();\n\t\t\tlet promptPromise: Promise<void>;\n\t\t\ttry {\n\t\t\t\tpromptPromise = this._sessionActionCommitContext.run(commitFence.owner, () => {\n\t\t\t\t\tif (\n\t\t\t\t\t\tthis._isSessionInputHandoffDeferred(epoch) ||\n\t\t\t\t\t\tthis.isStreaming ||\n\t\t\t\t\t\tturns.some((action) => action.lifecycle.state !== \"preparing\")\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new DeferredSessionInputError(\"Agent became active before session input handoff\");\n\t\t\t\t\t}\n\t\t\t\t\tif (executionPolicy.nextTurnContextTiming === \"commit\") {\n\t\t\t\t\t\tnextTurnMessages = this._takePendingNextTurnMessages();\n\t\t\t\t\t}\n\t\t\t\t\tconst contextRecords = nextTurnMessages.map((message) =>\n\t\t\t\t\t\tthis._createDeliveryRecord(turns[0].id, \"next_turn\", message),\n\t\t\t\t\t);\n\t\t\t\t\tconst firstPrimaryIndex = turns[0].payload.records.indexOf(primaryDeliveryRecord(turns[0]));\n\t\t\t\t\tturns[0].payload.records.splice(firstPrimaryIndex, 0, ...contextRecords);\n\t\t\t\t\tconst preparedMessages: AgentMessage[] = turns.flatMap((action) =>\n\t\t\t\t\t\taction.payload.records.map((record) => record.message),\n\t\t\t\t\t);\n\t\t\t\t\tfor (const action of turns) {\n\t\t\t\t\t\tif (action.suppressAutonomousContinuation) {\n\t\t\t\t\t\t\tthis._markAutonomousContinuationSuppressed(primaryDeliveryRecord(action).message);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (executionPolicy.runBeforeAgentStart) {\n\t\t\t\t\t\tthis._appendBeforeAgentStartMessages(preparedMessages, prepared?.result);\n\t\t\t\t\t\tthis._applyPreparedSystemPrompt(prepared, executionPolicy.preserveEmptyExtensionPrompt);\n\t\t\t\t\t} else if (executionPolicy.nextTurnContextTiming !== \"skip\") {\n\t\t\t\t\t\tthis.agent.state.systemPrompt = this._baseSystemPrompt;\n\t\t\t\t\t}\n\t\t\t\t\tfor (const action of turns) transitionSessionAction(action, { state: \"committing\" });\n\t\t\t\t\tthis._notifySessionInputCheckpointChange();\n\t\t\t\t\tthis._emitQueueUpdate();\n\t\t\t\t\treturn turns.some((action) => action.suppressAutonomousContinuation)\n\t\t\t\t\t\t? this._runWithAutonomousContinuationSuppressed(() => this.agent.prompt(preparedMessages))\n\t\t\t\t\t\t: this.agent.prompt(preparedMessages);\n\t\t\t\t});\n\t\t\t} finally {\n\t\t\t\tcommitFence.release();\n\t\t\t}\n\t\t\tawait promptPromise;\n\t\t\tif (executionPolicy.completionIncludesRetryChain) await this.waitForRetry();\n\t\t\tif (!this._hasCancelledDispatchCapture()) await this._agentEventQueue;\n\t\t\tif (\n\t\t\t\tturns.some(\n\t\t\t\t\t(action) =>\n\t\t\t\t\t\taction.lifecycle.state !== \"cancelled\" &&\n\t\t\t\t\t\t!primaryDeliveryRecord(action).durable &&\n\t\t\t\t\t\t!this.agent.state.messages.includes(primaryDeliveryRecord(action).message),\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tthrow new Error(\"Session input dispatch settled without durable delivery\");\n\t\t\t}\n\t\t\tthis._forgetConsumedPostCompactionContinuations(turns.map((action) => primaryDeliveryRecord(action).message));\n\t\t} catch (error) {\n\t\t\tconst delivered = new Set(this.agent.state.messages);\n\t\t\tthis._pendingNextTurnMessages.unshift(...nextTurnMessages.filter((message) => !delivered.has(message)));\n\t\t\tfor (const action of actions) {\n\t\t\t\tif (action.payload.kind === \"turn\") {\n\t\t\t\t\taction.payload.records = action.payload.records.filter((record) => record.role !== \"next_turn\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprivate async _executeQueuedSessionCommand(action: QueuedSessionAction): Promise<void> {\n\t\tif (action.payload.kind !== \"session_command\") throw new Error(\"Expected a session command action\");\n\t\tconst input = action.payload;\n\t\ttry {\n\t\t\tlet resultText: string | undefined;\n\t\t\tlet displayResult = true;\n\t\t\tswitch (input.command.name) {\n\t\t\t\tcase \"compact\":\n\t\t\t\t\tawait this.compact(input.command.args || undefined, {\n\t\t\t\t\t\tskipAbort: true,\n\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"refine\": {\n\t\t\t\t\tlet result: RefinementResult;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst options = parseRefineCommandOptions(input.command.args);\n\t\t\t\t\t\tresult = await this.refine(options, { skipAbort: true });\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t// Only a failure of the refinement itself is a refine failure; a later\n\t\t\t\t\t\t// result-row persist error must not report a completed refinement as failed.\n\t\t\t\t\t\tthis._emitRefineFailed(this._asError(error));\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\t\t\t\t\tconst applied = result.appliedEdits.filter((edit) => edit.applied).length;\n\t\t\t\t\tresultText = `Refined continual harness state: ${applied} edit${applied === 1 ? \"\" : \"s\"} applied.`;\n\t\t\t\t\tdisplayResult = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase \"goal\":\n\t\t\t\t\tawait this._handleGoalSlashCommand(input.text, input.images);\n\t\t\t\t\tresultText = this._goalState.objective\n\t\t\t\t\t\t? `Goal ${this._goalState.status}: ${this._goalState.objective}`\n\t\t\t\t\t\t: \"No active goal.\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"autonomous\":\n\t\t\t\t\tawait this._handleAutonomousSlashCommand(input.text);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (resultText) {\n\t\t\t\tthis._appendDurableSessionCommandMessage(resultText, input.command, true, false, displayResult);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (error instanceof CompactionSkippedError) return;\n\t\t\tconst commandError = error instanceof Error ? error : new Error(String(error));\n\t\t\ttry {\n\t\t\t\tthis._appendDurableSessionCommandMessage(\n\t\t\t\t\t`Command failed: ${commandError.message}`,\n\t\t\t\t\tinput.command,\n\t\t\t\t\ttrue,\n\t\t\t\t\ttrue,\n\t\t\t\t);\n\t\t\t} catch {\n\t\t\t\t// The result row is also the command-correlated UI settle edge.\n\t\t\t\tconst message = createSessionSlashCommandResultMessage(`Command failed: ${commandError.message}`, {\n\t\t\t\t\tcommand: input.command,\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tseverity: \"error\",\n\t\t\t\t\terror: commandError.message,\n\t\t\t\t});\n\t\t\t\tthis._emit({ type: \"message_start\", message });\n\t\t\t\tthis._emit({ type: \"message_end\", message });\n\t\t\t}\n\t\t\tthrow commandError;\n\t\t}\n\t}\n\n\tprivate _appendDurableSessionCommandMessage(\n\t\tcontent: string,\n\t\tcommand: SessionSlashCommand,\n\t\tisResult: boolean,\n\t\tisError = false,\n\t\tdisplay = true,\n\t): void {\n\t\tconst message: CustomMessage = isResult\n\t\t\t? createSessionSlashCommandResultMessage(\n\t\t\t\t\tcontent,\n\t\t\t\t\t{\n\t\t\t\t\t\tcommand,\n\t\t\t\t\t\tsuccess: !isError,\n\t\t\t\t\t\tseverity: isError ? \"error\" : \"info\",\n\t\t\t\t\t\t...(isError ? { error: content.replace(/^Command failed:\\s*/, \"\") } : {}),\n\t\t\t\t\t},\n\t\t\t\t\tdisplay,\n\t\t\t\t)\n\t\t\t: createSessionSlashCommandMessage(command);\n\t\t// Persist before touching live state so a failed write cannot leave an\n\t\t// unsaved leaf that the next entry would silently parent onto.\n\t\tthis.sessionManager.appendCustomMessageEntryWithRollback(\n\t\t\tmessage.customType,\n\t\t\tmessage.content,\n\t\t\tmessage.display,\n\t\t\tmessage.details,\n\t\t);\n\t\tthis.agent.state.messages.push(message);\n\t\tthis._emit({ type: \"message_start\", message });\n\t\tthis._emit({ type: \"message_end\", message });\n\t}\n\n\tprivate _throwIfExtensionCommand(text: string): void {\n\t\tconst commandName = parseSlashCommand(text)?.name ?? \"\";\n\t\tconst command = this._extensionRunner.getCommand(commandName);\n\n\t\tif (command) {\n\t\t\tthrow new Error(\n\t\t\t\t`Extension command \"/${commandName}\" cannot be queued. Use prompt() or execute the command when not streaming.`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Send a custom message to the session. Creates a CustomMessageEntry.\n\t *\n\t * Handles three cases:\n\t * - Streaming: queues message, processed when loop pulls from queue\n\t * - Not streaming + triggerTurn: appends to state/session, starts new turn\n\t * - Not streaming + no trigger: appends to state/session, no turn\n\t *\n\t * @param message Custom message with customType, content, display, details\n\t * @param options.triggerTurn If true and not streaming, triggers a new LLM turn\n\t * @param options.deliverAs Delivery mode: \"steer\", \"followUp\", or \"nextTurn\"\n\t */\n\tasync sendCustomMessage<T = unknown>(\n\t\tmessage: Pick<CustomMessage<T>, \"customType\" | \"content\" | \"display\" | \"details\">,\n\t\toptions?: {\n\t\t\ttriggerTurn?: boolean;\n\t\t\tdeliverAs?: \"steer\" | \"followUp\" | \"nextTurn\";\n\t\t},\n\t): Promise<void> {\n\t\tconst appMessage = {\n\t\t\trole: \"custom\" as const,\n\t\t\tcustomType: message.customType,\n\t\t\tcontent: message.content,\n\t\t\tdisplay: message.display,\n\t\t\tdetails: message.details,\n\t\t\ttimestamp: Date.now(),\n\t\t} satisfies CustomMessage<T>;\n\t\tif (options?.deliverAs === \"nextTurn\") {\n\t\t\tthis._pendingNextTurnMessages.push(appMessage);\n\t\t} else if (this.isStreaming) {\n\t\t\tconst normalized = normalizeMessageContent(message.content);\n\t\t\tif (options?.deliverAs === \"followUp\") {\n\t\t\t\tawait this._queuePreparedPrompt(\"followUp\", normalized.text, normalized.images, {\n\t\t\t\t\tmessage: appMessage,\n\t\t\t\t\tresumeIfIdle: true,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tawait this._queuePreparedPrompt(\"steer\", normalized.text, normalized.images, {\n\t\t\t\t\tmessage: appMessage,\n\t\t\t\t\tresumeIfIdle: true,\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (options?.triggerTurn) {\n\t\t\tif (!this._sessionInputSuspendedForUpdateRestart) this._resumeSessionInputAdmission();\n\t\t\tconst admissionFence = await this._acquireDirectTurnAdmissionFence();\n\t\t\ttry {\n\t\t\t\tconst normalized = normalizeMessageContent(message.content);\n\t\t\t\tconst immediatelyEligible = this._canStartSessionActionImmediately();\n\t\t\t\tconst action = this._createPreparedTurnAction(\"followUp\", normalized.text, normalized.images, {\n\t\t\t\t\tmessage: appMessage,\n\t\t\t\t\tresumeIfIdle: true,\n\t\t\t\t\texecutionPolicy: this._turnExecutionPolicy(\"customTrigger\"),\n\t\t\t\t\tqueueVisible: false,\n\t\t\t\t});\n\t\t\t\tconst result = this._admitSessionInput(action, { immediatelyEligible });\n\t\t\t\tadmissionFence.release();\n\t\t\t\tif (!result.ticket) return;\n\t\t\t\tawait result.ticket.completed;\n\t\t\t} finally {\n\t\t\t\tadmissionFence.release();\n\t\t\t}\n\t\t} else {\n\t\t\tthis.agent.state.messages.push(appMessage);\n\t\t\tthis.sessionManager.appendCustomMessageEntry(\n\t\t\t\tmessage.customType,\n\t\t\t\tmessage.content,\n\t\t\t\tmessage.display,\n\t\t\t\tmessage.details,\n\t\t\t);\n\t\t\tthis._emit({ type: \"message_start\", message: appMessage });\n\t\t\tthis._emit({ type: \"message_end\", message: appMessage });\n\t\t}\n\t}\n\n\t/**\n\t * Send a user message to the agent. Always triggers a turn.\n\t * When the agent is streaming, use deliverAs to specify how to queue the message.\n\t *\n\t * @param content User message content (string or content array)\n\t * @param options.deliverAs Delivery mode when streaming: \"steer\" or \"followUp\"\n\t */\n\tasync sendUserMessage(\n\t\tcontent: string | (TextContent | ImageContent)[],\n\t\toptions?: { deliverAs?: \"steer\" | \"followUp\" },\n\t): Promise<void> {\n\t\tlet text: string;\n\t\tlet images: ImageContent[] | undefined;\n\n\t\tif (typeof content === \"string\") {\n\t\t\ttext = content;\n\t\t} else {\n\t\t\tconst textParts: string[] = [];\n\t\t\timages = [];\n\t\t\tfor (const part of content) {\n\t\t\t\tif (part.type === \"text\") {\n\t\t\t\t\ttextParts.push(part.text);\n\t\t\t\t} else {\n\t\t\t\t\timages.push(part);\n\t\t\t\t}\n\t\t\t}\n\t\t\ttext = textParts.join(\"\\n\");\n\t\t\tif (images.length === 0) images = undefined;\n\t\t}\n\n\t\tawait this._prompt(text, {\n\t\t\texpandPromptTemplates: false,\n\t\t\tstreamingBehavior: options?.deliverAs,\n\t\t\timages,\n\t\t\tsource: \"extension\",\n\t\t\tresumeIfIdle: true,\n\t\t});\n\t}\n\n\tclearQueue(): { steering: string[]; followUp: string[] } {\n\t\tconst clearable = this._actionStore\n\t\t\t.clearableActions()\n\t\t\t.filter((action) => action.payload.kind === \"session_command\" || action.payload.queueVisible);\n\t\tif (clearable.some((action) => action.payload.kind === \"turn\" && action.lifecycle.state === \"preparing\")) {\n\t\t\tthis._sessionInputPumpEpoch++;\n\t\t}\n\t\tconst steering = clearable\n\t\t\t.filter((action) => action.delivery === \"next_turn_boundary\")\n\t\t\t.map((action) => action.payload.text);\n\t\tconst followUp = clearable\n\t\t\t.filter((action) => action.delivery === \"when_run_idle\")\n\t\t\t.map((action) => action.payload.text);\n\t\tconst promptError = new Error(\"Queued prompt was cleared before delivery.\");\n\t\tconst agentMessageError = new Error(\"Queued agent message was cleared before delivery.\");\n\t\tfor (const action of clearable) {\n\t\t\tconst error =\n\t\t\t\taction.payload.kind === \"turn\" && action.lifecycle.state === \"preparing\" ? promptError : agentMessageError;\n\t\t\tthis._settleAgentMessage(action.agentMessageId, \"delivery\", error);\n\t\t\tthis._settleAgentMessage(action.agentMessageId, \"completion\", error);\n\t\t}\n\t\tconst clearableIds = new Set(clearable.map((action) => action.id));\n\t\tthis._cancelSessionActions((action) => clearableIds.has(action.id), agentMessageError);\n\t\tthis.agent.clearAllQueues();\n\t\tthis._emitQueueUpdate();\n\t\treturn { steering, followUp };\n\t}\n\n\tprivate _invalidateQueuedPromptPreparation(): void {\n\t\tfor (const action of this._actionStore.clearableActions()) {\n\t\t\tif (action.payload.kind === \"turn\") action.payload.prepared = undefined;\n\t\t}\n\t}\n\n\tclearQueuedUserMessagesMatching(predicate: (text: string) => boolean): { steering: string[]; followUp: string[] } {\n\t\tconst ownedActions = this._actionStore.ownedActions();\n\t\tconst dispatchedTurnCount = ownedActions.filter(\n\t\t\t(action) =>\n\t\t\t\taction.payload.kind === \"turn\" &&\n\t\t\t\t(action.lifecycle.state === \"committing\" || action.lifecycle.state === \"running\"),\n\t\t).length;\n\t\tconst matching = ownedActions.filter(\n\t\t\t(action) =>\n\t\t\t\taction.payload.kind === \"turn\" &&\n\t\t\t\taction.agentMessageId !== undefined &&\n\t\t\t\tpredicate(action.payload.text) &&\n\t\t\t\t(action.lifecycle.state === \"queued\" ||\n\t\t\t\t\taction.lifecycle.state === \"selected\" ||\n\t\t\t\t\taction.lifecycle.state === \"preparing\" ||\n\t\t\t\t\t(action.lifecycle.state === \"committing\" &&\n\t\t\t\t\t\tdispatchedTurnCount === 1 &&\n\t\t\t\t\t\t!primaryDeliveryRecord(action).started)),\n\t\t);\n\t\tif (matching.length === 0) return { steering: [], followUp: [] };\n\t\tconst removedTexts = (delivery: DeliveryPolicy) =>\n\t\t\t[\n\t\t\t\t...matching.filter((action) => action.delivery === delivery && action.lifecycle.state === \"queued\"),\n\t\t\t\t...matching.filter((action) => action.delivery === delivery && action.lifecycle.state !== \"queued\"),\n\t\t\t].map((action) => action.payload.text);\n\t\tconst removedSteering = removedTexts(\"next_turn_boundary\");\n\t\tconst removedFollowUp = removedTexts(\"when_run_idle\");\n\t\tconst acceptedError = new Error(\"Accepted agent message was cleared before delivery.\");\n\t\tconst queuedError = new Error(\"Queued agent message was cleared before delivery.\");\n\t\tfor (const action of matching) {\n\t\t\tconst error =\n\t\t\t\taction.payload.kind === \"turn\" && action.payload.acceptedAgentMessage ? acceptedError : queuedError;\n\t\t\tthis._rejectAgentMessage(action.agentMessageId, error);\n\t\t}\n\t\tfor (const [accepted, error] of [\n\t\t\t[true, acceptedError],\n\t\t\t[false, queuedError],\n\t\t] as const) {\n\t\t\tconst ids = new Set(\n\t\t\t\tmatching\n\t\t\t\t\t.filter((action) => action.payload.kind === \"turn\" && action.payload.acceptedAgentMessage === accepted)\n\t\t\t\t\t.map((action) => action.id),\n\t\t\t);\n\t\t\tif (ids.size > 0) this._cancelSessionActions((action) => ids.has(action.id), error, matching);\n\t\t}\n\t\tif (\n\t\t\tmatching.some(\n\t\t\t\t(action) =>\n\t\t\t\t\taction.lifecycle.state === \"cancelled\" &&\n\t\t\t\t\taction.payload.kind === \"turn\" &&\n\t\t\t\t\taction.payload.captureRunMessages,\n\t\t\t)\n\t\t) {\n\t\t\tthis.agent.abort();\n\t\t}\n\t\tthis._emitQueueUpdate();\n\t\treturn { steering: removedSteering, followUp: removedFollowUp };\n\t}\n\n\t/**\n\t * Mutate a single visible queued message, addressed by its position in the same\n\t * projection the session-action snapshot publishes. expectedText must match the\n\t * item's current preview so clients never edit a shifted queue by accident.\n\t */\n\tmutateQueuedMessage(\n\t\tlane: QueuedMessageLane,\n\t\tindex: number,\n\t\texpectedText: string,\n\t\tmutation: QueuedMessageMutation,\n\t): QueuedMessageMutationStatus {\n\t\tconst policy = queuedMessageLaneDeliveryPolicy(lane);\n\t\tconst projection = visibleSessionActionProjection(this._actionStore.queuedActions(policy));\n\t\tconst item = projection[index];\n\t\tif (!item || queuedAgentMessagePreview(item) !== expectedText) return \"rejected\";\n\t\tif (mutation.type === \"delete\") {\n\t\t\tconst error = new Error(\"Queued prompt was deleted before delivery.\");\n\t\t\tthis._rejectAgentMessage(item.agentMessageId, error);\n\t\t\tthis._cancelSessionActions((candidate) => candidate === item, error);\n\t\t\tthis._emitQueueUpdate();\n\t\t\tthis.resumeQueuedWork();\n\t\t\treturn \"applied\";\n\t\t}\n\t\tif (mutation.type === \"move\") {\n\t\t\tconst neighbor = projection[index + mutation.direction];\n\t\t\tif (!neighbor) return \"rejected\";\n\t\t\tthis._actionStore.swapQueued(item, neighbor);\n\t\t\tthis._emitQueueUpdate();\n\t\t\treturn \"applied\";\n\t\t}\n\t\tif (\n\t\t\titem.payload.kind === \"turn\" &&\n\t\t\t(item.payload.acceptedAgentMessage ||\n\t\t\t\titem.payload.records.some((record) => record.role === \"primary\" && record.message.role !== \"user\"))\n\t\t) {\n\t\t\treturn \"rejected\";\n\t\t}\n\t\tconst images = mutation.images?.map((image) => ({ ...image }));\n\t\tif (item.payload.kind === \"session_command\") {\n\t\t\tconst command = parseSessionSlashCommand(mutation.text);\n\t\t\tif (!command) return \"invalid\";\n\t\t\titem.payload.text = mutation.text;\n\t\t\titem.payload.command = command;\n\t\t\tif (mutation.images !== undefined) item.payload.images = images?.length ? images : undefined;\n\t\t} else {\n\t\t\titem.payload.text = mutation.text;\n\t\t\tconst text = { type: \"text\" as const, text: mutation.text };\n\t\t\tif (mutation.images !== undefined) {\n\t\t\t\titem.payload.images = images?.length ? images : undefined;\n\t\t\t\titem.payload.content = [text, ...(images?.map((image) => ({ ...image })) ?? [])];\n\t\t\t} else if (item.payload.content) {\n\t\t\t\titem.payload.content = [text, ...item.payload.content.filter((block) => block.type !== \"text\")];\n\t\t\t}\n\t\t\titem.payload.preview = undefined;\n\t\t\titem.payload.prepared = undefined;\n\t\t\tfor (const record of item.payload.records) {\n\t\t\t\tif (record.role === \"primary\" && record.message.role === \"user\") {\n\t\t\t\t\trecord.message.content = item.payload.content?.map((block) => ({ ...block })) ?? mutation.text;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tconst targetPolicy = queuedMessageLaneDeliveryPolicy(mutation.lane);\n\t\tif (targetPolicy !== policy) {\n\t\t\titem.queueKey = undefined;\n\t\t\titem.wake = mutation.lane === \"steering\" ? \"on_lower_boundary\" : \"external_resume\";\n\t\t\tthis._actionStore.moveQueued(item, targetPolicy, this._actionStore.queuedActions(targetPolicy).length);\n\t\t}\n\t\tthis.resumeQueuedWork();\n\t\tthis._emitQueueUpdate();\n\t\treturn \"applied\";\n\t}\n\n\tget queuedActionCount(): number {\n\t\treturn visibleSessionActionProjection(this._actionStore.queuedActions()).length;\n\t}\n\n\tget unfinishedActionCount(): number {\n\t\treturn this._actionStore.unfinishedActions().length;\n\t}\n\n\tget isQueuedWorkSuspended(): boolean {\n\t\treturn this._sessionInputPumpSuspended;\n\t}\n\n\tget isSessionActive(): boolean {\n\t\treturn (\n\t\t\tthis.isStreaming ||\n\t\t\tthis.isCompacting ||\n\t\t\tthis.isRetrying ||\n\t\t\tthis.isBashRunning ||\n\t\t\tthis._refineInFlight !== undefined ||\n\t\t\tthis._branchSummaryOperation !== undefined ||\n\t\t\tthis._postCompactionContinuationSettlement !== undefined ||\n\t\t\tthis.unfinishedActionCount > 0\n\t\t);\n\t}\n\n\tgetSessionActionSnapshot(): SessionActionSnapshot {\n\t\tconst steering = visibleSessionActionProjection(this._actionStore.queuedActions(\"next_turn_boundary\")).map(\n\t\t\tqueuedAgentMessagePreview,\n\t\t);\n\t\tconst followUps = visibleSessionActionProjection(this._actionStore.queuedActions(\"when_run_idle\")).map(\n\t\t\tqueuedAgentMessagePreview,\n\t\t);\n\t\tconst active = visibleSessionActionProjection(this._actionStore.activeActions())[0];\n\t\tconst activeState = active?.lifecycle.state;\n\t\tconst phase =\n\t\t\tactiveState === \"selected\"\n\t\t\t\t? \"preparing\"\n\t\t\t\t: activeState === \"preparing\" || activeState === \"committing\" || activeState === \"running\"\n\t\t\t\t\t? activeState\n\t\t\t\t\t: undefined;\n\t\treturn {\n\t\t\tqueuedCount: steering.length + followUps.length,\n\t\t\tsteering,\n\t\t\tfollowUps,\n\t\t\t...(active && phase\n\t\t\t\t? {\n\t\t\t\t\t\tactive: {\n\t\t\t\t\t\t\tkind: active.payload.kind,\n\t\t\t\t\t\t\tphase,\n\t\t\t\t\t\t\tlabel: compactRlmText(active.payload.text),\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t};\n\t}\n\n\tgetSteeringMessages(): readonly string[] {\n\t\treturn visibleSessionActionProjection(this._actionStore.queuedActions(\"next_turn_boundary\")).map(\n\t\t\t(action) => action.payload.text,\n\t\t);\n\t}\n\n\tgetSteeringMessagePreviews(): readonly string[] {\n\t\treturn visibleSessionActionProjection(this._actionStore.queuedActions(\"next_turn_boundary\")).map(\n\t\t\tqueuedAgentMessagePreview,\n\t\t);\n\t}\n\n\tgetFollowUpMessages(): readonly string[] {\n\t\treturn visibleSessionActionProjection(this._actionStore.queuedActions(\"when_run_idle\")).map(\n\t\t\t(action) => action.payload.text,\n\t\t);\n\t}\n\n\tgetFollowUpMessagePreviews(): readonly string[] {\n\t\treturn visibleSessionActionProjection(this._actionStore.queuedActions(\"when_run_idle\")).map(\n\t\t\tqueuedAgentMessagePreview,\n\t\t);\n\t}\n\n\tgetSessionActionRecoverySnapshot(): SessionActionRecoverySnapshot {\n\t\treturn {\n\t\t\tformatVersion: SESSION_ACTION_RECOVERY_FORMAT_VERSION,\n\t\t\tactions: this._actionStore.snapshotActions().map((action) => ({\n\t\t\t\tid: action.id,\n\t\t\t\tsource: action.source,\n\t\t\t\tdelivery: action.delivery,\n\t\t\t\twake: action.wake,\n\t\t\t\t...(action.queueKey ? { queueKey: action.queueKey } : {}),\n\t\t\t\t...(action.agentMessageId ? { agentMessageId: action.agentMessageId } : {}),\n\t\t\t\t...(action.suppressAutonomousContinuation ? { suppressAutonomousContinuation: true } : {}),\n\t\t\t\tpayload:\n\t\t\t\t\taction.payload.kind === \"turn\"\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tkind: \"turn\",\n\t\t\t\t\t\t\t\ttext: action.payload.text,\n\t\t\t\t\t\t\t\t...(action.payload.preview ? { preview: action.payload.preview } : {}),\n\t\t\t\t\t\t\t\trecords: action.payload.records.map((record) => ({\n\t\t\t\t\t\t\t\t\tid: record.id,\n\t\t\t\t\t\t\t\t\trole: record.role,\n\t\t\t\t\t\t\t\t\tmessage: cloneQueuedAgentMessage(record.message),\n\t\t\t\t\t\t\t\t\townerActionId: record.ownerActionId,\n\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t...(action.payload.images\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\timages: action.payload.images.map((image) => ({\n\t\t\t\t\t\t\t\t\t\t\t\t...image,\n\t\t\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t\t...(action.payload.content\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\tcontent: action.payload.content.map((block) => ({\n\t\t\t\t\t\t\t\t\t\t\t\t...block,\n\t\t\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t\t...(action.payload.customMessage\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\tcustomMessage: cloneCustomMessage(action.payload.customMessage),\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t\texecutionPolicy: {\n\t\t\t\t\t\t\t\t\t...action.payload.executionPolicy,\n\t\t\t\t\t\t\t\t\tpreparation: {\n\t\t\t\t\t\t\t\t\t\t...action.payload.executionPolicy.preparation,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tqueueVisible: action.payload.queueVisible,\n\t\t\t\t\t\t\t\tacceptedAgentMessage: action.payload.acceptedAgentMessage,\n\t\t\t\t\t\t\t\tacceptedBeforeCompletion: action.payload.acceptedBeforeCompletion,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\tkind: \"session_command\",\n\t\t\t\t\t\t\t\ttext: action.payload.text,\n\t\t\t\t\t\t\t\tcommand: { ...action.payload.command },\n\t\t\t\t\t\t\t\t...(action.payload.images\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\timages: action.payload.images.map((image) => ({\n\t\t\t\t\t\t\t\t\t\t\t\t...image,\n\t\t\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t},\n\t\t\t})),\n\t\t};\n\t}\n\n\tprivate _notifySessionInputCheckpointChange(): void {\n\t\tconst waiters = [...this._sessionInputCheckpointWaiters];\n\t\tthis._sessionInputCheckpointWaiters.clear();\n\t\tfor (const resolve of waiters) resolve();\n\t}\n\n\tprivate _observeSessionActionDeferral(action: QueuedSessionAction): {\n\t\tdeferred: Promise<void>;\n\t\tstop(): void;\n\t} {\n\t\tlet resolveDeferral = () => {};\n\t\tconst deferred = new Promise<void>((resolve) => {\n\t\t\tresolveDeferral = resolve;\n\t\t});\n\t\tconst check = () => {\n\t\t\tif (action.lifecycle.state === \"queued\") resolveDeferral();\n\t\t\telse this._sessionInputCheckpointWaiters.add(check);\n\t\t};\n\t\tthis._sessionInputCheckpointWaiters.add(check);\n\t\treturn {\n\t\t\tdeferred,\n\t\t\tstop: () => this._sessionInputCheckpointWaiters.delete(check),\n\t\t};\n\t}\n\n\tasync waitForSessionInputCheckpoint(signal?: AbortSignal): Promise<void> {\n\t\tconst blocksCheckpoint = () =>\n\t\t\tthis._actionStore.activeActions().some((action) => {\n\t\t\t\tif (action.payload.kind === \"session_command\") {\n\t\t\t\t\treturn action.lifecycle.state === \"selected\" || action.lifecycle.state === \"running\";\n\t\t\t\t}\n\t\t\t\treturn (\n\t\t\t\t\taction.lifecycle.state === \"selected\" ||\n\t\t\t\t\taction.lifecycle.state === \"preparing\" ||\n\t\t\t\t\t(action.lifecycle.state === \"committing\" && !primaryDeliveryRecord(action).durable)\n\t\t\t\t);\n\t\t\t});\n\t\twhile (true) {\n\t\t\twhile (blocksCheckpoint()) {\n\t\t\t\tif (signal?.aborted) throw new Error(\"Update restart preparation cancelled\");\n\t\t\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\t\t\tconst onChange = () => {\n\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t};\n\t\t\t\t\tconst onAbort = () => {\n\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\treject(new Error(\"Update restart preparation cancelled\"));\n\t\t\t\t\t};\n\t\t\t\t\tconst cleanup = () => {\n\t\t\t\t\t\tthis._sessionInputCheckpointWaiters.delete(onChange);\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t};\n\t\t\t\t\tthis._sessionInputCheckpointWaiters.add(onChange);\n\t\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t\tif (signal?.aborted) onAbort();\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst commitFence = await this._acquireSessionActionCommitFence(signal);\n\t\t\ttry {\n\t\t\t\tif (blocksCheckpoint()) continue;\n\t\t\t\tif (signal?.aborted) throw new Error(\"Update restart preparation cancelled\");\n\t\t\t\tawait waitForPromiseOrAbort(this._agentEventQueue, signal, \"Update restart preparation cancelled\");\n\t\t\t\tif (signal?.aborted) throw new Error(\"Update restart preparation cancelled\");\n\t\t\t\tthis.sessionManager.flushNow();\n\t\t\t\treturn;\n\t\t\t} finally {\n\t\t\t\tcommitFence.release();\n\t\t\t}\n\t\t}\n\t}\n\n\tacquireSessionInputPause(): { release(): void } {\n\t\tconst token = Symbol(\"session-input-admission-pause\");\n\t\tthis._sessionInputAdmissionPauses.add(token);\n\t\tthis._sessionInputPumpRequested = false;\n\t\tthis._sessionInputPumpEpoch++;\n\t\tlet released = false;\n\t\treturn {\n\t\t\trelease: () => {\n\t\t\t\tif (released) return;\n\t\t\t\treleased = true;\n\t\t\t\tthis._sessionInputAdmissionPauses.delete(token);\n\t\t\t\tthis._sessionInputPumpEpoch++;\n\t\t\t\tthis._notifySessionInputCheckpointChange();\n\t\t\t\tthis._flushDeferredRlmTerminalNotices();\n\t\t\t\tthis._maybeResumeGoalContinuationAfterRlmWork();\n\t\t\t\tthis._scheduleSessionInputPump();\n\t\t\t},\n\t\t};\n\t}\n\n\tacquireQueuedWorkPause(): { release(): void } {\n\t\tconst token = Symbol(\"queued-work-pause\");\n\t\tthis._queuedWorkPauses.add(token);\n\t\tthis._sessionInputPumpRequested = false;\n\t\tthis._sessionInputPumpEpoch++;\n\t\tlet released = false;\n\t\treturn {\n\t\t\trelease: () => {\n\t\t\t\tif (released) return;\n\t\t\t\treleased = true;\n\t\t\t\tthis._queuedWorkPauses.delete(token);\n\t\t\t\tthis._notifySessionInputCheckpointChange();\n\t\t\t\tthis._flushDeferredRlmTerminalNotices();\n\t\t\t\tthis._scheduleSessionInputPump();\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate async _acquireDirectTurnAdmissionFence(signal?: AbortSignal): Promise<{ owner: symbol; release(): void }> {\n\t\tconst inheritedOwner = this._sessionActionCommitContext.getStore();\n\t\tif (inheritedOwner !== undefined && inheritedOwner === this._sessionActionCommitOwner) {\n\t\t\tthis._assertSessionActionAdmissionAvailable();\n\t\t\treturn this._acquireSessionActionCommitFence(signal);\n\t\t}\n\t\tconst disposeSignal = this._sessionActionCommitDisposeAbortController.signal;\n\t\tconst waitSignal = signal ? AbortSignal.any([signal, disposeSignal]) : disposeSignal;\n\t\twhile (true) {\n\t\t\tthis._assertSessionActionAdmissionAvailable();\n\t\t\tif (this._queuedWorkPauses.size > 0) {\n\t\t\t\tlet wake = () => {};\n\t\t\t\tconst pauseReleased = new Promise<void>((resolve) => {\n\t\t\t\t\twake = resolve;\n\t\t\t\t\tthis._sessionInputCheckpointWaiters.add(resolve);\n\t\t\t\t});\n\t\t\t\ttry {\n\t\t\t\t\tawait waitForPromiseOrAbort(pauseReleased, waitSignal, \"Update restart preparation cancelled\");\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (disposeSignal.aborted) {\n\t\t\t\t\t\tthrow new Error(\"Cannot admit a session action because the session is disposing or disposed.\");\n\t\t\t\t\t}\n\t\t\t\t\tthrow error;\n\t\t\t\t} finally {\n\t\t\t\t\tthis._sessionInputCheckpointWaiters.delete(wake);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst fence = await this._acquireSessionActionCommitFence(signal);\n\t\t\ttry {\n\t\t\t\tif (this._queuedWorkPauses.size === 0) {\n\t\t\t\t\tthis._assertSessionActionAdmissionAvailable();\n\t\t\t\t\treturn fence;\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tfence.release();\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tfence.release();\n\t\t}\n\t}\n\n\tprivate async _acquireSessionActionCommitFence(signal?: AbortSignal): Promise<{ owner: symbol; release(): void }> {\n\t\tconst inheritedOwner = this._sessionActionCommitContext.getStore();\n\t\tif (inheritedOwner !== undefined && inheritedOwner === this._sessionActionCommitOwner) {\n\t\t\treturn { owner: inheritedOwner, release: () => {} };\n\t\t}\n\t\tconst previous = this._sessionActionCommitTail;\n\t\tlet resolve = () => {};\n\t\tthis._sessionActionCommitTail = new Promise<void>((release) => {\n\t\t\tresolve = release;\n\t\t});\n\t\tconst disposeSignal = this._sessionActionCommitDisposeAbortController.signal;\n\t\tconst waitSignal = signal ? AbortSignal.any([signal, disposeSignal]) : disposeSignal;\n\t\tthis._pendingSessionActionFenceWaiters++;\n\t\ttry {\n\t\t\tawait waitForPromiseOrAbort(previous, waitSignal, \"Update restart preparation cancelled\");\n\t\t} catch (error) {\n\t\t\tthis._pendingSessionActionFenceWaiters--;\n\t\t\t// A cancelled waiter remains in the FIFO chain until its predecessor releases.\n\t\t\tvoid previous.then(resolve, resolve);\n\t\t\tif (disposeSignal.aborted) {\n\t\t\t\tthrow new Error(\"Cannot admit a session action because the session is disposing or disposed.\");\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tconst owner = Symbol(\"session-action-commit\");\n\t\tthis._sessionActionCommitOwner = owner;\n\t\tthis._pendingSessionActionFenceWaiters--;\n\t\tlet released = false;\n\t\treturn {\n\t\t\towner,\n\t\t\trelease: () => {\n\t\t\t\tif (released) return;\n\t\t\t\treleased = true;\n\t\t\t\tif (this._sessionActionCommitOwner === owner) this._sessionActionCommitOwner = undefined;\n\t\t\t\tresolve();\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate _resumeSessionInputAdmission(): void {\n\t\tif (!this._sessionInputPumpSuspended) return;\n\t\tthis._sessionInputPumpSuspended = false;\n\t\tthis._sessionInputSuspendedForUpdateRestart = false;\n\t\tthis._sessionInputPumpEpoch++;\n\t\tthis._notifySessionInputCheckpointChange();\n\t\tthis._flushDeferredRlmTerminalNotices();\n\t}\n\n\t/** Resume the scheduler after requestAbort/abortForUpdateRestart suspended it; owned pause leases are unaffected. */\n\tresumeQueuedWork(): boolean {\n\t\tthis._resumeSessionInputAdmission();\n\t\tthis._maybeResumeGoalContinuationAfterRlmWork();\n\t\tthis._scheduleSessionInputPump();\n\t\treturn this._hasSelectableSessionInput();\n\t}\n\n\tasync waitForSessionInputIdle(): Promise<void> {\n\t\twhile (true) {\n\t\t\tconst pump = this._sessionInputPump;\n\t\t\tawait pump;\n\t\t\tif (pump === this._sessionInputPump && !this._sessionInputPumpRequested) return;\n\t\t}\n\t}\n\n\tasync waitForIdle(): Promise<void> {\n\t\twhile (true) {\n\t\t\tif (this._actionStore.queuedActions().length > 0) {\n\t\t\t\tif (this._sessionInputPumpSuspended || this._queuedWorkPauses.size > 0) {\n\t\t\t\t\tawait new Promise<void>((resolve) => this._sessionInputCheckpointWaiters.add(resolve));\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthis._scheduleSessionInputPump();\n\t\t\t}\n\t\t\tconst pump = this._sessionInputPump;\n\t\t\tawait pump;\n\t\t\tawait this.agent.waitForIdle();\n\t\t\tconst agentEventQueue = this._agentEventQueue;\n\t\t\tawait agentEventQueue;\n\t\t\tif (\n\t\t\t\tpump === this._sessionInputPump &&\n\t\t\t\tagentEventQueue === this._agentEventQueue &&\n\t\t\t\t!this._sessionInputPumpRequested &&\n\t\t\t\t!this.agent.state.isStreaming &&\n\t\t\t\tthis.unfinishedActionCount === 0\n\t\t\t) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Waits out any owned post-compaction continuation and rejects when one cannot start; {@link waitForIdle} never rejects. */\n\tasync waitForHeadlessIdle(): Promise<void> {\n\t\twhile (true) {\n\t\t\tawait this.waitForIdle();\n\t\t\tconst postCompactionContinuation = this._postCompactionContinuationSettlement?.promise;\n\t\t\tif (!postCompactionContinuation) return;\n\t\t\tawait postCompactionContinuation;\n\t\t}\n\t}\n\n\tgetPendingNextTurnMessageSnapshots(): readonly CustomMessage[] {\n\t\tconst messages = this._pendingNextTurnMessages.map((message) => cloneCustomMessage(message));\n\t\tfor (const action of this._actionStore.unfinishedActions()) {\n\t\t\tif (\n\t\t\t\taction.payload.kind !== \"turn\" ||\n\t\t\t\t!action.payload.acceptedAgentMessage ||\n\t\t\t\t!primaryDeliveryRecord(action).started\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tmessages.push(\n\t\t\t\t...action.payload.records\n\t\t\t\t\t.filter(\n\t\t\t\t\t\t(record): record is DeliveryRecord & { message: CustomMessage } =>\n\t\t\t\t\t\t\t(record.role === \"next_turn\" || record.role === \"prefix\") &&\n\t\t\t\t\t\t\trecord.message.role === \"custom\" &&\n\t\t\t\t\t\t\t!record.durable,\n\t\t\t\t\t)\n\t\t\t\t\t.map((record) => cloneCustomMessage(record.message)),\n\t\t\t);\n\t\t}\n\t\treturn messages;\n\t}\n\n\trestorePendingNextTurnMessages(messages: readonly CustomMessage[]): void {\n\t\tthis._pendingNextTurnMessages.push(...messages.map((message) => cloneCustomMessage(message)));\n\t\tthis._flushDeferredRlmTerminalNotices();\n\t}\n\n\tremoveQueuedFollowUp(queueKey: string): boolean {\n\t\tconst matching = this._actionStore\n\t\t\t.clearableActions()\n\t\t\t.filter((action) => action.payload.kind === \"turn\" && action.queueKey === queueKey);\n\t\tif (matching.length === 0) return false;\n\t\tconst error = new Error(\"Queued agent message was cleared before delivery.\");\n\t\tfor (const action of matching) this._rejectAgentMessage(action.agentMessageId, error);\n\t\tconst ids = new Set(matching.map((action) => action.id));\n\t\tthis._cancelSessionActions((action) => ids.has(action.id), error);\n\t\tthis._emitQueueUpdate();\n\t\treturn true;\n\t}\n\n\tget resourceLoader(): ResourceLoader {\n\t\treturn this._resourceLoader;\n\t}\n\n\trequestAbort(): void {\n\t\tfor (const run of [...this._unsettledRlmChildRuns]) {\n\t\t\tif (run.status === \"cancelled\") this._abandonRlmRunForQuiescence(run);\n\t\t}\n\t\tfor (const controller of this._rlmQuiescenceWaitAborts) controller.abort();\n\t\tthis._sessionInputPumpRequested = false;\n\t\tthis._sessionInputPumpEpoch++;\n\t\tthis._sessionInputPumpSuspended = true;\n\t\tthis._sessionInputSuspendedForUpdateRestart = false;\n\t\tthis._demoteRlmTerminalNoticeActions();\n\t\tthis._cancelSessionActions(\n\t\t\t(action) =>\n\t\t\t\taction.payload.kind === \"turn\" &&\n\t\t\t\t!action.payload.queueVisible &&\n\t\t\t\t!this._durableRlmTerminalNoticeActionIds.has(action.id),\n\t\t\tnew Error(\"Prompt aborted before delivery.\"),\n\t\t);\n\t\tthis._cancelPostCompactionContinue();\n\t\tthis.abortRetry();\n\t\tthis.abortCompaction();\n\t\tthis.abortBranchSummary();\n\t\tthis.abortBash();\n\t\tthis._pendingRequestedRefine = undefined;\n\t\tthis._autoRefineBranchVersion++;\n\t\tthis._autoRefineReviewAbort?.abort();\n\t\tthis._refineAbortController?.abort();\n\t\tthis.agent.abort();\n\t}\n\n\tasync abort(): Promise<void> {\n\t\tconst compactionOperation = this._compactionOperation;\n\t\tconst branchSummaryOperation = this._branchSummaryOperation;\n\t\tthis.requestAbort();\n\t\tthis._cancelActiveRlmChildRuns(\"Parent session aborted\");\n\t\tthis._goalAbortInProgress = this._goalState.status === \"active\";\n\t\ttry {\n\t\t\tawait Promise.allSettled([\n\t\t\t\tthis.agent.waitForIdle(),\n\t\t\t\tthis._agentEventQueue,\n\t\t\t\t...(compactionOperation ? [compactionOperation] : []),\n\t\t\t\t...(branchSummaryOperation ? [branchSummaryOperation] : []),\n\t\t\t]);\n\t\t} finally {\n\t\t\tthis._goalAbortInProgress = false;\n\t\t}\n\t}\n\n\tabortForUpdateRestart(): void {\n\t\t// Cancel scheduled pumps and suspend new ones: queued inputs must survive\n\t\t// into the restart manifest instead of starting a turn during teardown.\n\t\tthis._sessionInputPumpRequested = false;\n\t\tthis._sessionInputPumpEpoch++;\n\t\tthis._sessionInputPumpSuspended = true;\n\t\tthis._sessionInputSuspendedForUpdateRestart = true;\n\t\tthis._cancelPostCompactionContinue();\n\t\tthis.abortRetry();\n\t\tfor (const controller of this._rlmQuiescenceWaitAborts) controller.abort();\n\t\tthis._cancelActiveRlmChildRuns(\"Parent session aborted for update restart\");\n\t\tthis._goalAbortInProgress = this._goalState.status === \"active\";\n\t\tthis.agent.abort();\n\t\tif (this._goalAbortInProgress) {\n\t\t\tvoid this.agent\n\t\t\t\t.waitForIdle()\n\t\t\t\t.then(() => this._agentEventQueue)\n\t\t\t\t.catch(() => undefined)\n\t\t\t\t.finally(() => {\n\t\t\t\t\tthis._goalAbortInProgress = false;\n\t\t\t\t});\n\t\t}\n\t}\n\n\tprivate async _emitModelSelect(\n\t\tnextModel: Model<any>,\n\t\tpreviousModel: Model<any> | undefined,\n\t\tsource: \"set\" | \"cycle\" | \"restore\",\n\t): Promise<void> {\n\t\tif (modelsAreEqual(previousModel, nextModel)) return;\n\t\tawait this._extensionRunner.emit({\n\t\t\ttype: \"model_select\",\n\t\t\tmodel: nextModel,\n\t\t\tpreviousModel,\n\t\t\tsource,\n\t\t});\n\t}\n\n\tprivate _queueModelSelectEmit(\n\t\tnextModel: Model<any>,\n\t\tpreviousModel: Model<any> | undefined,\n\t\tsource: \"set\" | \"cycle\" | \"restore\",\n\t): Promise<void> {\n\t\tconst emit = () =>\n\t\t\tthis._modelSelectEmitContext.run(true, () => this._emitModelSelect(nextModel, previousModel, source));\n\t\tthis._modelSelectEmitQueueIdle = false;\n\t\tconst promise = this._modelSelectEmitQueue.then(emit, emit);\n\t\tconst queued = promise.catch(() => {});\n\t\tthis._modelSelectEmitQueue = queued;\n\t\tvoid queued.finally(() => {\n\t\t\tif (this._modelSelectEmitQueue === queued) {\n\t\t\t\tthis._modelSelectEmitQueueIdle = true;\n\t\t\t}\n\t\t});\n\t\treturn promise;\n\t}\n\n\tasync setModel(model: Model<any>, options: ModelSelectOptions = {}): Promise<void> {\n\t\tif (!this._modelRegistry.hasConfiguredAuth(model)) {\n\t\t\tthrow new Error(`No API key for ${model.provider}/${model.id}`);\n\t\t}\n\t\tif (!(await this._modelRegistry.canUseModel(model))) {\n\t\t\tthrow new Error(`Model \"${model.provider}/${model.id}\" is not available for the current Prime team.`);\n\t\t}\n\n\t\tconst previousModel = this.model;\n\t\tconst thinkingLevel = this._getThinkingLevelForModelSwitch();\n\t\tconst serviceTier = this._getServiceTierForModelSwitch();\n\t\tthis.agent.state.model = model;\n\t\tthis.sessionManager.appendModelChange(model.provider, model.id);\n\t\tthis.settingsManager.setDefaultModelAndProvider(model.provider, model.id);\n\n\t\tthis.setThinkingLevel(thinkingLevel);\n\t\tthis._clampServiceTierForModel(serviceTier);\n\n\t\tconst emitPromise = this._queueModelSelectEmit(model, previousModel, \"set\");\n\t\tif (this._shouldWaitForModelSelectEmit(options)) {\n\t\t\tawait emitPromise;\n\t\t} else {\n\t\t\tthis._trackModelSelectEmitError(emitPromise);\n\t\t}\n\t}\n\n\tprivate _trackModelSelectEmitError(emitPromise: Promise<void>): void {\n\t\tvoid emitPromise.catch((error) => {\n\t\t\tthis._extensionRunner.emitError({\n\t\t\t\textensionPath: \"<internal>\",\n\t\t\t\tevent: \"model_select\",\n\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate _shouldWaitForModelSelectEmit(options: ModelSelectOptions): boolean {\n\t\treturn options.waitForExtensions !== false && !this._modelSelectEmitContext.getStore();\n\t}\n\n\tprivate _pendingModelSelectEmit(): Promise<void> | undefined {\n\t\tif (!this._modelSelectEmitContext.getStore() && !this._modelSelectEmitQueueIdle) {\n\t\t\treturn this._modelSelectEmitQueue;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tasync cycleModel(\n\t\tdirection: \"forward\" | \"backward\" = \"forward\",\n\t\toptions: ModelSelectOptions = {},\n\t): Promise<ModelCycleResult | undefined> {\n\t\tif (this._scopedModels.length > 0) {\n\t\t\treturn this._cycleScopedModel(direction, options);\n\t\t}\n\t\treturn this._cycleAvailableModel(direction, options);\n\t}\n\n\tprivate async _cycleScopedModel(\n\t\tdirection: \"forward\" | \"backward\",\n\t\toptions: ModelSelectOptions,\n\t): Promise<ModelCycleResult | undefined> {\n\t\tconst availableModels = await this._modelRegistry.refreshAvailableModels();\n\t\tconst scopedModels = this._scopedModels.filter((scoped) =>\n\t\t\tavailableModels.some((model) => modelsAreEqual(model, scoped.model)),\n\t\t);\n\t\tif (scopedModels.length <= 1) return undefined;\n\n\t\tconst currentModel = this.model;\n\t\tlet currentIndex = scopedModels.findIndex((sm) => modelsAreEqual(sm.model, currentModel));\n\n\t\tif (currentIndex === -1) currentIndex = 0;\n\t\tconst len = scopedModels.length;\n\t\tconst nextIndex = direction === \"forward\" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;\n\t\tconst next = scopedModels[nextIndex];\n\t\tconst thinkingLevel = this._getThinkingLevelForModelSwitch(next.thinkingLevel);\n\t\tconst serviceTier = this._getServiceTierForModelSwitch();\n\n\t\tthis.agent.state.model = next.model;\n\t\tthis.sessionManager.appendModelChange(next.model.provider, next.model.id);\n\t\tthis.settingsManager.setDefaultModelAndProvider(next.model.provider, next.model.id);\n\n\t\tthis.setThinkingLevel(thinkingLevel);\n\t\tthis._clampServiceTierForModel(serviceTier);\n\n\t\tconst emitPromise = this._queueModelSelectEmit(next.model, currentModel, \"cycle\");\n\t\tif (this._shouldWaitForModelSelectEmit(options)) {\n\t\t\tawait emitPromise;\n\t\t} else {\n\t\t\tthis._trackModelSelectEmitError(emitPromise);\n\t\t}\n\n\t\treturn {\n\t\t\tmodel: next.model,\n\t\t\tthinkingLevel: this.thinkingLevel,\n\t\t\tserviceTier: this.serviceTier,\n\t\t\tisScoped: true,\n\t\t};\n\t}\n\n\tprivate async _cycleAvailableModel(\n\t\tdirection: \"forward\" | \"backward\",\n\t\toptions: ModelSelectOptions,\n\t): Promise<ModelCycleResult | undefined> {\n\t\tconst availableModels = await this._modelRegistry.refreshAvailableModels();\n\t\tif (availableModels.length <= 1) return undefined;\n\n\t\tconst currentModel = this.model;\n\t\tlet currentIndex = availableModels.findIndex((m) => modelsAreEqual(m, currentModel));\n\n\t\tif (currentIndex === -1) currentIndex = 0;\n\t\tconst len = availableModels.length;\n\t\tconst nextIndex = direction === \"forward\" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;\n\t\tconst nextModel = availableModels[nextIndex];\n\n\t\tconst thinkingLevel = this._getThinkingLevelForModelSwitch();\n\t\tconst serviceTier = this._getServiceTierForModelSwitch();\n\t\tthis.agent.state.model = nextModel;\n\t\tthis.sessionManager.appendModelChange(nextModel.provider, nextModel.id);\n\t\tthis.settingsManager.setDefaultModelAndProvider(nextModel.provider, nextModel.id);\n\n\t\tthis.setThinkingLevel(thinkingLevel);\n\t\tthis._clampServiceTierForModel(serviceTier);\n\n\t\tconst emitPromise = this._queueModelSelectEmit(nextModel, currentModel, \"cycle\");\n\t\tif (this._shouldWaitForModelSelectEmit(options)) {\n\t\t\tawait emitPromise;\n\t\t} else {\n\t\t\tthis._trackModelSelectEmitError(emitPromise);\n\t\t}\n\n\t\treturn {\n\t\t\tmodel: nextModel,\n\t\t\tthinkingLevel: this.thinkingLevel,\n\t\t\tserviceTier: this.serviceTier,\n\t\t\tisScoped: false,\n\t\t};\n\t}\n\n\tsetThinkingLevel(level: ThinkingLevel): void {\n\t\tconst availableLevels = this.getAvailableThinkingLevels();\n\t\tconst effectiveLevel = availableLevels.includes(level) ? level : this._clampThinkingLevel(level, availableLevels);\n\n\t\tconst previousLevel = this.agent.state.thinkingLevel;\n\t\tconst isChanging = effectiveLevel !== previousLevel;\n\n\t\tthis.agent.state.thinkingLevel = effectiveLevel;\n\n\t\tif (isChanging) {\n\t\t\tthis.sessionManager.appendThinkingLevelChange(effectiveLevel);\n\t\t\tif (this.supportsThinking() || effectiveLevel !== \"off\") {\n\t\t\t\tthis.settingsManager.setDefaultThinkingLevel(effectiveLevel);\n\t\t\t}\n\t\t\tthis._emit({ type: \"thinking_level_changed\", level: effectiveLevel });\n\t\t\tvoid this._extensionRunner.emit({\n\t\t\t\ttype: \"thinking_level_select\",\n\t\t\t\tlevel: effectiveLevel,\n\t\t\t\tpreviousLevel,\n\t\t\t});\n\t\t}\n\t}\n\n\tsetServiceTier(serviceTier: ServiceTier): void {\n\t\tconst effectiveServiceTier = this._getEffectiveServiceTier(serviceTier);\n\t\tconst preferenceChanged = effectiveServiceTier !== this._serviceTierPreference;\n\t\tconst effectiveTierChanged = effectiveServiceTier !== this.agent.state.serviceTier;\n\t\tif (!preferenceChanged && !effectiveTierChanged) {\n\t\t\treturn;\n\t\t}\n\t\tthis._serviceTierPreference = effectiveServiceTier;\n\t\tif (preferenceChanged) {\n\t\t\tthis.sessionManager.appendServiceTierChange(effectiveServiceTier);\n\t\t\tif (this.model && supportsFastMode(this.model)) {\n\t\t\t\tthis.settingsManager.setDefaultServiceTier(effectiveServiceTier);\n\t\t\t}\n\t\t}\n\t\tif (effectiveTierChanged) {\n\t\t\tthis.agent.state.serviceTier = effectiveServiceTier;\n\t\t\tthis._emit({\n\t\t\t\ttype: \"service_tier_changed\",\n\t\t\t\tserviceTier: effectiveServiceTier,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate _getEffectiveServiceTier(serviceTier: ServiceTier): ServiceTier {\n\t\treturn serviceTier === \"priority\" && (!this.model || !supportsFastMode(this.model)) ? \"default\" : serviceTier;\n\t}\n\n\tprivate _getServiceTierForModelSwitch(): ServiceTier {\n\t\treturn this._serviceTierPreference;\n\t}\n\n\tprivate _clampServiceTierForModel(serviceTier: ServiceTier = this.serviceTier): void {\n\t\tconst effectiveServiceTier = this._getEffectiveServiceTier(serviceTier);\n\t\tif (effectiveServiceTier === this.agent.state.serviceTier) {\n\t\t\treturn;\n\t\t}\n\t\tthis.agent.state.serviceTier = effectiveServiceTier;\n\t\tthis._emit({\n\t\t\ttype: \"service_tier_changed\",\n\t\t\tserviceTier: effectiveServiceTier,\n\t\t});\n\t}\n\n\tcycleThinkingLevel(): ThinkingLevel | undefined {\n\t\tif (!this.supportsThinking()) return undefined;\n\n\t\tconst levels = this.getAvailableThinkingLevels();\n\t\tconst currentIndex = levels.indexOf(this.thinkingLevel);\n\t\tconst nextIndex = (currentIndex + 1) % levels.length;\n\t\tconst nextLevel = levels[nextIndex];\n\n\t\tthis.setThinkingLevel(nextLevel);\n\t\treturn nextLevel;\n\t}\n\n\tgetAvailableThinkingLevels(): ThinkingLevel[] {\n\t\tif (!this.model) return THINKING_LEVELS;\n\t\treturn getSupportedThinkingLevels(this.model) as ThinkingLevel[];\n\t}\n\n\tsupportsThinking(): boolean {\n\t\treturn !!this.model?.reasoning;\n\t}\n\n\tprivate _getThinkingLevelForModelSwitch(explicitLevel?: ThinkingLevel): ThinkingLevel {\n\t\tif (explicitLevel !== undefined) {\n\t\t\treturn explicitLevel;\n\t\t}\n\t\tif (!this.supportsThinking()) {\n\t\t\treturn this.settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;\n\t\t}\n\t\treturn this.thinkingLevel;\n\t}\n\n\tprivate _clampThinkingLevel(level: ThinkingLevel, _availableLevels: ThinkingLevel[]): ThinkingLevel {\n\t\treturn this.model ? (clampThinkingLevel(this.model, level) as ThinkingLevel) : \"off\";\n\t}\n\n\tprivate async _syncKernelStateAfterCompaction(): Promise<void> {\n\t\tconst provisioner = this._ipythonKernelProvisioner;\n\t\tif (!provisioner?.hasRunningKernel) return;\n\t\tconst pruned = await provisioner.pruneOversizedVariables().catch(() => null);\n\t\tconst abort = new AbortController();\n\t\tconst timer = setTimeout(() => abort.abort(), KERNEL_STATE_LISTING_TIMEOUT_MS);\n\t\tif (typeof timer === \"object\" && \"unref\" in timer) timer.unref();\n\t\tlet names: string[] | null;\n\t\ttry {\n\t\t\tnames = await provisioner.listNamespaceNames(abort.signal).catch(() => null);\n\t\t} finally {\n\t\t\tclearTimeout(timer);\n\t\t}\n\t\tif (names === null && !provisioner.hasRunningKernel) return;\n\t\tconst detail =\n\t\t\tnames === null\n\t\t\t\t? \"\"\n\t\t\t\t: names.length > 0\n\t\t\t\t\t? ` These names are still defined: ${names.join(\", \")}.`\n\t\t\t\t\t: \" You have not defined any names yet.\";\n\t\tconst prunedDetail =\n\t\t\tpruned && pruned.length > 0\n\t\t\t\t? ` Variables above the per-variable snapshot limit were removed: ${pruned.join(\", \")}.`\n\t\t\t\t: \"\";\n\t\tconst content = [\n\t\t\t\"<ipython_state>\",\n\t\t\t`Your Python kernel persisted through compaction; its remaining variables, imports, and helpers are still available.${prunedDetail}${detail}`,\n\t\t\t\"</ipython_state>\",\n\t\t].join(\"\\n\");\n\t\tconst message = {\n\t\t\trole: \"custom\" as const,\n\t\t\tcustomType: \"ipython_state\",\n\t\t\tcontent,\n\t\t\tdisplay: false,\n\t\t\ttimestamp: Date.now(),\n\t\t} satisfies CustomMessage;\n\t\tconst messages = this.agent.state.messages;\n\t\tconst last = messages[messages.length - 1];\n\t\tconst insertBeforeError = last?.role === \"assistant\" && (last as AssistantMessage).stopReason === \"error\";\n\t\tif (insertBeforeError) {\n\t\t\tmessages.splice(messages.length - 1, 0, message);\n\t\t} else {\n\t\t\tmessages.push(message);\n\t\t}\n\t\tthis.sessionManager.appendCustomMessageEntry(message.customType, message.content, message.display, undefined);\n\t\tthis._emit({ type: \"message_start\", message });\n\t\tthis._emit({ type: \"message_end\", message });\n\t}\n\n\tprivate _onIpythonStateRestored(result: RestoreResult): void {\n\t\tconst lines = [\"<ipython_state_restored>\"];\n\t\tif (result.restored.length > 0) {\n\t\t\tlines.push(\n\t\t\t\t`Your Python kernel state was revived from your previous session. These names are available again: ${result.restored.join(\", \")}.`,\n\t\t\t);\n\t\t} else {\n\t\t\tlines.push(\n\t\t\t\t\"Your previous Python kernel state could not be revived; the kernel is starting fresh, so re-create any variables, imports, or loaded data you need.\",\n\t\t\t);\n\t\t}\n\t\tif (result.failed.length > 0) {\n\t\t\tlines.push(\n\t\t\t\t`These could not be restored and must be recreated if needed: ${result.failed.map((f) => f.name).join(\", \")}.`,\n\t\t\t);\n\t\t}\n\t\tlines.push(\"</ipython_state_restored>\");\n\t\tvoid this.sendCustomMessage(\n\t\t\t{\n\t\t\t\tcustomType: IPYTHON_STATE_RESTORED_CUSTOM_TYPE,\n\t\t\t\tcontent: lines.join(\"\\n\"),\n\t\t\t\tdisplay: true,\n\t\t\t\tdetails: { restored: result.restored.length > 0 },\n\t\t\t},\n\t\t\t{ deliverAs: \"nextTurn\" },\n\t\t).catch(() => {});\n\t}\n\n\tsetSteeringMode(mode: \"all\" | \"one-at-a-time\"): void {\n\t\tthis.agent.steeringMode = mode;\n\t\tthis.settingsManager.setSteeringMode(mode);\n\t}\n\n\tsetFollowUpMode(mode: \"all\" | \"one-at-a-time\"): void {\n\t\tthis.agent.followUpMode = mode;\n\t\tthis.settingsManager.setFollowUpMode(mode);\n\t}\n\n\tasync compact(customInstructions?: string, options: { skipAbort?: boolean } = {}): Promise<CompactionResult> {\n\t\tif (options.skipAbort && this.isStreaming) {\n\t\t\tthrow new Error(\"Cannot compact without aborting while the agent is running.\");\n\t\t}\n\t\tconst hadPostCompactionContinue = this._postCompactionContinuationScheduled;\n\t\tthis._disconnectFromAgent();\n\t\tif (!options.skipAbort) await this.abort();\n\t\tlet didCompact = false;\n\t\tthis._compactionAbortController = new AbortController();\n\t\tlet resolveCompactionOperation: () => void = () => {};\n\t\tconst compactionOperation = new Promise<void>((resolve) => {\n\t\t\tresolveCompactionOperation = resolve;\n\t\t});\n\t\tthis._compactionOperation = compactionOperation;\n\t\tthis._emit({\n\t\t\ttype: \"compaction_start\",\n\t\t\treason: \"manual\",\n\t\t\tcustomInstructions,\n\t\t});\n\n\t\ttry {\n\t\t\tif (!this.model) {\n\t\t\t\tthrow new Error(formatNoModelSelectedMessage());\n\t\t\t}\n\n\t\t\tconst { apiKey, headers } = await this._getRequiredRequestAuth(this.model);\n\t\t\tconst result = await this._performCompaction({\n\t\t\t\tmodel: this.model,\n\t\t\t\tapiKey,\n\t\t\t\theaders,\n\t\t\t\tcustomInstructions,\n\t\t\t\tsignal: this._compactionAbortController.signal,\n\t\t\t});\n\n\t\t\tthis._emit({\n\t\t\t\ttype: \"compaction_end\",\n\t\t\t\treason: \"manual\",\n\t\t\t\tresult,\n\t\t\t\taborted: false,\n\t\t\t\twillRetry: false,\n\t\t\t\tcustomInstructions,\n\t\t\t});\n\t\t\tdidCompact = true;\n\t\t\t// A manual compaction satisfies any pending model request; on failure the\n\t\t\t// request stays scheduled for the next turn boundary.\n\t\t\tthis._pendingRequestedCompaction = undefined;\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tconst aborted = message === \"Compaction cancelled\" || (error instanceof Error && error.name === \"AbortError\");\n\t\t\tconst skipped = error instanceof CompactionSkippedError;\n\t\t\tthis._emit({\n\t\t\t\ttype: \"compaction_end\",\n\t\t\t\treason: \"manual\",\n\t\t\t\tresult: undefined,\n\t\t\t\taborted,\n\t\t\t\twillRetry: false,\n\t\t\t\terrorMessage: aborted ? undefined : skipped ? message : `Compaction failed: ${message}`,\n\t\t\t\terrorSeverity: skipped ? \"warning\" : \"error\",\n\t\t\t\tcustomInstructions,\n\t\t\t});\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tthis._compactionAbortController = undefined;\n\t\t\tthis._reconnectToAgent();\n\t\t\tif (this._compactionOperation === compactionOperation) {\n\t\t\t\tthis._compactionOperation = undefined;\n\t\t\t}\n\t\t\tresolveCompactionOperation();\n\t\t\tthis._scheduleSessionInputPump();\n\t\t\tif (didCompact) {\n\t\t\t\tthis._discardPendingAutoRefine({ cancelPostCompactionContinue: true });\n\t\t\t\tif (hadPostCompactionContinue) {\n\t\t\t\t\tthis._schedulePostCompactionContinue();\n\t\t\t\t}\n\t\t\t\t// Queued agent or session-owned inputs resume the loop; defer refine\n\t\t\t\t// behind them instead of interleaving it before their turns.\n\t\t\t\tthis._scheduleAutoRefineAfterCompaction(\n\t\t\t\t\thadPostCompactionContinue || this.agent.hasQueuedMessages() || this.unfinishedActionCount > 0,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Shared compaction core behind /compact, auto-compaction, and the compact\n\t * skill. Throws CompactionSkippedError when there is nothing to compact and\n\t * Error(\"Compaction cancelled\") on abort or extension cancel.\n\t */\n\tprivate async _performCompaction(options: {\n\t\tmodel: Model<any>;\n\t\tapiKey: string;\n\t\theaders?: Record<string, string>;\n\t\tcustomInstructions?: string;\n\t\tsignal: AbortSignal;\n\t}): Promise<CompactionResult> {\n\t\tconst { model, apiKey, headers, customInstructions, signal } = options;\n\t\tconst pathEntries = this.sessionManager.getBranch();\n\t\tconst settings = this.settingsManager.getCompactionSettings();\n\n\t\tconst preparation = prepareCompaction(pathEntries, settings);\n\t\tif (!preparation) {\n\t\t\tconst lastEntry = pathEntries[pathEntries.length - 1];\n\t\t\tif (lastEntry?.type === \"compaction\") {\n\t\t\t\tthrow new CompactionSkippedError(\"Already compacted\");\n\t\t\t}\n\t\t\tthrow new CompactionSkippedError(\"Session is too short to compact — try again once it grows\");\n\t\t}\n\n\t\tlet extensionCompaction: CompactionResult | undefined;\n\t\tlet fromExtension = false;\n\n\t\tif (this._extensionRunner.hasHandlers(\"session_before_compact\")) {\n\t\t\tconst result = (await this._extensionRunner.emit({\n\t\t\t\ttype: \"session_before_compact\",\n\t\t\t\tpreparation,\n\t\t\t\tbranchEntries: pathEntries,\n\t\t\t\tcustomInstructions,\n\t\t\t\tsignal,\n\t\t\t})) as SessionBeforeCompactResult | undefined;\n\n\t\t\tif (result?.cancel) {\n\t\t\t\tthrow new Error(\"Compaction cancelled\");\n\t\t\t}\n\n\t\t\tif (result?.compaction) {\n\t\t\t\textensionCompaction = result.compaction;\n\t\t\t\tfromExtension = true;\n\t\t\t}\n\t\t}\n\n\t\tconst { summary, firstKeptEntryId, tokensBefore, details } =\n\t\t\textensionCompaction ??\n\t\t\t(await compact(preparation, model, apiKey, headers, customInstructions, signal, this.thinkingLevel));\n\n\t\tif (signal.aborted) {\n\t\t\tthrow new Error(\"Compaction cancelled\");\n\t\t}\n\n\t\tthis.sessionManager.appendCompaction(\n\t\t\tsummary,\n\t\t\tfirstKeptEntryId,\n\t\t\ttokensBefore,\n\t\t\tdetails,\n\t\t\tfromExtension,\n\t\t\tcustomInstructions,\n\t\t);\n\t\tconst newEntries = this.sessionManager.getEntries();\n\t\tthis.agent.state.messages = this.sessionManager.buildSessionContext().messages;\n\t\tthis._mergeUnpersistedOutcomes(this.agent.state.messages);\n\t\tthis._restoreLateIpythonSentAgentMessages();\n\n\t\tconst savedCompactionEntry = newEntries.find((e) => e.type === \"compaction\" && e.summary === summary) as\n\t\t\t| CompactionEntry\n\t\t\t| undefined;\n\t\tif (savedCompactionEntry) {\n\t\t\tawait this._extensionRunner.emit({\n\t\t\t\ttype: \"session_compact\",\n\t\t\t\tcompactionEntry: savedCompactionEntry,\n\t\t\t\tfromExtension,\n\t\t\t});\n\t\t}\n\t\tawait this._syncKernelStateAfterCompaction();\n\t\tawait this._reapDeletedRlmSubagentRuntimesAfterCompaction();\n\n\t\treturn { summary, firstKeptEntryId, tokensBefore, details };\n\t}\n\n\tprivate async _reapDeletedRlmSubagentRuntimesAfterCompaction(): Promise<void> {\n\t\tconst childIds = [...this._rlmChildCleanupFailures.keys()].filter(\n\t\t\t(childId) => !this._activeRlmChildRuns.get(childId)?.detachedDeletion,\n\t\t);\n\t\tawait Promise.allSettled(childIds.map((childId) => this.deleteRlmSubagent(childId)));\n\t}\n\n\tabortCompaction(): void {\n\t\tthis._compactionAbortController?.abort();\n\t\tthis._autoCompactionAbortController?.abort();\n\t}\n\n\tprivate _localHarnessStateDir(): string | undefined {\n\t\treturn (\n\t\t\tgetLocalHarnessStateDir(this.sessionManager.getSessionArtifactDir()) ??\n\t\t\t(this._rlmSessionDir ? getLocalHarnessStateDir(this._rlmSessionDir) : undefined)\n\t\t);\n\t}\n\n\tprivate _autoRefineAllowedForSession(): boolean {\n\t\treturn this._rlmDepth === 0 && this._localHarnessStateDir() !== undefined;\n\t}\n\n\tprivate _settlePostCompactionContinue(error?: Error): void {\n\t\tif (!error && (this._postCompactionContinuationScheduled || this._postCompactionContinuationTimer)) return;\n\t\tconst settlement = this._postCompactionContinuationSettlement;\n\t\tif (!settlement || settlement.settled) return;\n\t\tsettlement.settled = true;\n\t\tthis._postCompactionContinuationSettlement = undefined;\n\t\tif (error) settlement.reject(error);\n\t\telse settlement.resolve();\n\t}\n\n\tprivate _cancelPostCompactionContinue(): void {\n\t\tif (this._postCompactionContinuationTimer) {\n\t\t\tclearTimeout(this._postCompactionContinuationTimer);\n\t\t\tthis._postCompactionContinuationTimer = undefined;\n\t\t}\n\t\tthis._postCompactionContinuationScheduled = false;\n\t\tthis._scheduledPostCompactionContinuationMessages = [];\n\t\tthis._settlePostCompactionContinue();\n\t}\n\n\tprivate _discardPendingAutoRefine(options: { cancelPostCompactionContinue?: boolean } = {}): void {\n\t\tthis._compactAutoRefinePending = false;\n\t\tthis._turnIntervalAutoRefinePending = false;\n\t\tthis._pendingAutoRefineReview = undefined;\n\t\tif (options.cancelPostCompactionContinue) {\n\t\t\tthis._cancelPostCompactionContinue();\n\t\t}\n\t}\n\n\tprivate async _invalidatePendingAutoRefineForBranchChange(): Promise<void> {\n\t\tthis._autoRefineReviewAbort?.abort();\n\t\tthis._discardPendingAutoRefine({ cancelPostCompactionContinue: true });\n\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t// Increment branch version BEFORE aborting/awaiting the serialized plan.\n\t\t// This invalidates the plan's branchVersion check at the boundary\n\t\t// so even if the plan completes, the boundary will reject it\n\t\t// (bgResult.branchVersion !== this._autoRefineBranchVersion).\n\t\tthis._autoRefineBranchVersion++;\n\t\t// Abort the in-flight refine/bplan controller so any pending\n\t\t// _planRefine or _reviewAutoRefine call settles via signal abort\n\t\t// rather than hanging forever.\n\t\tthis._refineAbortController?.abort();\n\t\tif (this._serializedPlanInFlight) {\n\t\t\tawait this._consumeSerializedBackgroundPlan(async () => false);\n\t\t}\n\t\twhile (this._refinePlanInFlight) {\n\t\t\tawait this._refinePlanInFlight;\n\t\t}\n\t\tawait this._waitForRefineIdle();\n\t}\n\n\t/**\n\t * Consume a refine request that was scheduled by the agent-callable refine\n\t * skill (refine.run). Fire-and-forget: the refine() method handles its own\n\t * background planning, idle wait, application, and error recovery. Called\n\t * at the turn boundary after compaction checks and before auto-refine\n\t * scheduling so the manual request takes priority.\n\t */\n\tprivate _emitRefineFailed(error: unknown): void {\n\t\tthis._emit({\n\t\t\ttype: \"refine_failed\",\n\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t});\n\t}\n\n\tprivate _consumePendingRequestedRefine(): boolean {\n\t\tconst pending = this._pendingRequestedRefine;\n\t\tif (!pending) return false;\n\t\tthis._pendingRequestedRefine = undefined;\n\t\tvoid this.refine(pending).catch((error) => this._emitRefineFailed(error));\n\t\treturn true;\n\t}\n\n\tprivate _scheduleAutoRefineAfterAgentEnd(): void {\n\t\tif (!this._autoRefineAllowedForSession()) {\n\t\t\treturn;\n\t\t}\n\t\tif (this._pendingAutoRefineReview) {\n\t\t\tthis._scheduleAutoRefine(this._pendingAutoRefineReview.reason);\n\t\t\treturn;\n\t\t}\n\t\tif (this._compactAutoRefinePending) {\n\t\t\tif (this._postCompactionContinuationScheduled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._scheduleAutoRefine(\"compact\");\n\t\t\treturn;\n\t\t}\n\n\t\tthis._scheduleAutoRefine(\"turn_interval\");\n\t}\n\n\tprivate _scheduleAutoRefineAfterCompaction(willContinueAfterCompaction: boolean): void {\n\t\tif (!this._autoRefineAllowedForSession()) {\n\t\t\treturn;\n\t\t}\n\t\tif (this._serializedRefine) {\n\t\t\t// Serialized sessions must service compaction-triggered refinement at\n\t\t\t// shouldStopAfterTurn (or disposal), never through the interactive path.\n\t\t\tthis._compactAutoRefinePending = true;\n\t\t\treturn;\n\t\t}\n\t\tif (willContinueAfterCompaction) {\n\t\t\tthis._compactAutoRefinePending = true;\n\t\t\treturn;\n\t\t}\n\n\t\tthis._scheduleAutoRefine(\"compact\");\n\t}\n\n\tprivate _schedulePostCompactionContinue(): void {\n\t\tif (this._postCompactionContinuationScheduled) {\n\t\t\treturn;\n\t\t}\n\t\tif (!this._postCompactionContinuationSettlement || this._postCompactionContinuationSettlement.settled) {\n\t\t\tthis._postCompactionContinuationSettlement = createPostCompactionContinuationSettlement();\n\t\t}\n\t\tthis._postCompactionContinuationScheduled = true;\n\t\tthis._scheduledPostCompactionContinuationMessages = [...this._postCompactionContinuationMessages];\n\t\tthis._postCompactionContinuationTimer = setTimeout(() => {\n\t\t\tthis._postCompactionContinuationTimer = undefined;\n\t\t\tvoid this._runScheduledPostCompactionContinue()\n\t\t\t\t.catch(() => undefined)\n\t\t\t\t.finally(() => this._settlePostCompactionContinue());\n\t\t}, 100);\n\t}\n\n\tprivate _sessionOwnsScheduledContinuations(continuationMessages: AgentMessage[]): boolean {\n\t\treturn continuationMessages.some((message) => this._postCompactionContinuationMessages.includes(message));\n\t}\n\n\tprivate async _runScheduledPostCompactionContinue(): Promise<void> {\n\t\tawait this._waitForRefineIdle();\n\t\tif (!this._postCompactionContinuationScheduled) {\n\t\t\treturn;\n\t\t}\n\t\tif (this.isStreaming || this.isCompacting || this.isRetrying || this._queuedWorkPauses.size > 0) {\n\t\t\tthis._postCompactionContinuationScheduled = false;\n\t\t\tthis._schedulePostCompactionContinue();\n\t\t\treturn;\n\t\t}\n\n\t\tconst continuationMessages = [...this._scheduledPostCompactionContinuationMessages];\n\t\tif (continuationMessages.length > 0 && !this._sessionOwnsScheduledContinuations(continuationMessages)) {\n\t\t\tthis._cancelPostCompactionContinue();\n\t\t\tthis._scheduleAutoRefineAfterAgentEnd();\n\t\t\treturn;\n\t\t}\n\t\t// An empty queue is not idle while the scheduler still owns active work.\n\t\tif (this.unfinishedActionCount > 0 || this._sessionInputPumpRequested) {\n\t\t\tthis._scheduleSessionInputPump();\n\t\t\tawait this._sessionInputPump;\n\t\t\tif (this._postCompactionContinuationScheduled) {\n\t\t\t\tthis._postCompactionContinuationScheduled = false;\n\t\t\t\tconst shouldReschedule =\n\t\t\t\t\tcontinuationMessages.length === 0\n\t\t\t\t\t\t? this.unfinishedActionCount > 0\n\t\t\t\t\t\t: this._sessionOwnsScheduledContinuations(continuationMessages);\n\t\t\t\tif (shouldReschedule) {\n\t\t\t\t\tthis._schedulePostCompactionContinue();\n\t\t\t\t} else {\n\t\t\t\t\tthis._scheduledPostCompactionContinuationMessages = [];\n\t\t\t\t\tthis._scheduleAutoRefineAfterAgentEnd();\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tthis._postCompactionContinuationScheduled = false;\n\t\ttry {\n\t\t\tawait this.agent.continue();\n\t\t\tthis._forgetConsumedPostCompactionContinuations(continuationMessages);\n\t\t} catch (error) {\n\t\t\tconst code = error instanceof AgentContinueError ? error.code : undefined;\n\t\t\tif (code === \"busy\") {\n\t\t\t\tthis._schedulePostCompactionContinue();\n\t\t\t} else if (code !== \"nothing-to-continue\") {\n\t\t\t\t// \"nothing-to-continue\" means the turn already completed; anything else must reject headless idle waiters.\n\t\t\t\tthis._settlePostCompactionContinue(this._asError(error));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _forgetConsumedPostCompactionContinuations(continuationMessages: AgentMessage[]): void {\n\t\tif (continuationMessages.length === 0) {\n\t\t\treturn;\n\t\t}\n\t\tconst continuationMessageSet = new Set(continuationMessages);\n\t\tconst stillQueued = new Set(this.agent.removeQueuedMessages((message) => continuationMessageSet.has(message)));\n\t\tfor (const message of stillQueued) {\n\t\t\tthis.agent.followUp(message);\n\t\t}\n\t\tfor (const message of continuationMessages) {\n\t\t\tif (!stillQueued.has(message)) {\n\t\t\t\tthis._queuedAutonomousContinuationSnapshots.delete(message);\n\t\t\t}\n\t\t}\n\t\tthis._postCompactionContinuationMessages = this._postCompactionContinuationMessages.filter(\n\t\t\t(message) => !continuationMessageSet.has(message) || stillQueued.has(message),\n\t\t);\n\t}\n\n\tprivate _shouldSkipAutoRefineForActiveAgent(): boolean {\n\t\treturn this.isStreaming || this.isCompacting;\n\t}\n\n\tprivate _scheduleDeferredAutoRefineIfIdle(): void {\n\t\tif (this._autoRefineInProgress || this._shouldSkipAutoRefineForActiveAgent() || this._pendingAutoRefineReview) {\n\t\t\treturn;\n\t\t}\n\t\tif (this._turnIntervalAutoRefinePending) {\n\t\t\tthis._turnIntervalAutoRefinePending = false;\n\t\t\tthis._scheduleAutoRefine(\"turn_interval\");\n\t\t}\n\t}\n\n\tprivate _scheduleAutoRefine(reason: AutoRefineReason, branchVersion = this._autoRefineBranchVersion): void {\n\t\tconst timer = setTimeout(() => {\n\t\t\tthis._scheduledAutoRefineTimers.delete(timer);\n\t\t\tif (branchVersion !== this._autoRefineBranchVersion) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst operation = this._maybeAutoRefine(reason);\n\t\t\tthis._autoRefineOperations.add(operation);\n\t\t\tvoid operation.finally(() => this._autoRefineOperations.delete(operation)).catch(() => undefined);\n\t\t}, 0);\n\t\tthis._scheduledAutoRefineTimers.add(timer);\n\t}\n\n\tprivate async _maybeAutoRefine(reason: AutoRefineReason): Promise<void> {\n\t\tif (this._disposed || this._disposing) {\n\t\t\tthis._discardPendingAutoRefine();\n\t\t\treturn;\n\t\t}\n\t\tif (!this._autoRefineAllowedForSession()) {\n\t\t\tthis._discardPendingAutoRefine();\n\t\t\treturn;\n\t\t}\n\n\t\tconst settings = this.settingsManager.getAutoRefineSettings();\n\t\tif (!settings.enabled) {\n\t\t\tthis._discardPendingAutoRefine();\n\t\t\treturn;\n\t\t}\n\t\tif (this._autoRefineInProgress || this._shouldSkipAutoRefineForActiveAgent()) {\n\t\t\tif (reason === \"compact\") {\n\t\t\t\tthis._compactAutoRefinePending = true;\n\t\t\t} else {\n\t\t\t\tthis._turnIntervalAutoRefinePending = true;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst nowMs = Date.now();\n\t\tconst underCooldown =\n\t\t\tthis._lastAutoRefineReviewAt > 0 && nowMs - this._lastAutoRefineReviewAt < settings.cooldownMs;\n\n\t\tconst pendingReview = this._pendingAutoRefineReview;\n\t\tif (pendingReview) {\n\t\t\t// A failed refine stamps the cooldown; keep the pending review for later.\n\t\t\tif (underCooldown) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait this._runApprovedRefine(pendingReview.reason, pendingReview.review);\n\t\t\treturn;\n\t\t}\n\n\t\tif (reason === \"compact\" && !settings.compact) {\n\t\t\tthis._compactAutoRefinePending = false;\n\t\t\treason = \"turn_interval\";\n\t\t}\n\t\tif (reason === \"turn_interval\" && this._assistantTurnsSinceAutoRefine < settings.turnInterval) {\n\t\t\treturn;\n\t\t}\n\t\tif (underCooldown) {\n\t\t\tif (reason === \"compact\") {\n\t\t\t\tthis._compactAutoRefinePending = true;\n\t\t\t} else {\n\t\t\t\tthis._turnIntervalAutoRefinePending = true;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (reason === \"turn_interval\") {\n\t\t\tthis._turnIntervalAutoRefinePending = false;\n\t\t}\n\t\tif (!this.model) {\n\t\t\tif (reason === \"compact\") {\n\t\t\t\tthis._compactAutoRefinePending = true;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tthis._autoRefineInProgress = true;\n\t\tconst turnsSinceLastReview = this._assistantTurnsSinceAutoRefine;\n\t\tconst branchVersion = this._autoRefineBranchVersion;\n\t\tconst reviewAbort = new AbortController();\n\t\tthis._autoRefineReviewAbort = reviewAbort;\n\t\tlet approvedReview: AutoRefineReview | undefined;\n\t\ttry {\n\t\t\tconst review = await this._reviewAutoRefine({ reason, turnsSinceLastReview }, reviewAbort.signal);\n\t\t\tif (this._disposed || this._disposing || branchVersion !== this._autoRefineBranchVersion) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!review.shouldRefine) {\n\t\t\t\tconst preserveTurnIntervalReview =\n\t\t\t\t\treason === \"compact\" && this._assistantTurnsSinceAutoRefine >= settings.turnInterval;\n\t\t\t\tif (preserveTurnIntervalReview) {\n\t\t\t\t\tthis._turnIntervalAutoRefinePending = true;\n\t\t\t\t} else {\n\t\t\t\t\tthis._lastAutoRefineReviewAt = nowMs;\n\t\t\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t\t\t}\n\t\t\t\tif (reason === \"compact\") {\n\t\t\t\t\tthis._compactAutoRefinePending = false;\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (this._shouldSkipAutoRefineForActiveAgent()) {\n\t\t\t\tthis._pendingAutoRefineReview = { reason, review };\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tapprovedReview = review;\n\t\t} catch {\n\t\t\t// Failed review: stamp the cooldown so a persistent failure (bad auth,\n\t\t\t// unparseable output) doesn't retry a full review on every agent end.\n\t\t\tif (branchVersion === this._autoRefineBranchVersion) {\n\t\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\t}\n\t\t} finally {\n\t\t\tif (this._autoRefineReviewAbort === reviewAbort) {\n\t\t\t\tthis._autoRefineReviewAbort = undefined;\n\t\t\t}\n\t\t\tthis._autoRefineInProgress = false;\n\t\t\t// When a refine follows, _runApprovedRefine schedules the deferred pass.\n\t\t\tif (!approvedReview) {\n\t\t\t\tthis._scheduleDeferredAutoRefineIfIdle();\n\t\t\t}\n\t\t}\n\t\tif (approvedReview) {\n\t\t\tawait this._runApprovedRefine(reason, approvedReview);\n\t\t}\n\t}\n\n\tprivate async _runApprovedRefine(reason: AutoRefineReason, review: AutoRefineReview): Promise<void> {\n\t\tthis._autoRefineInProgress = true;\n\t\ttry {\n\t\t\tawait this.refine({ instructions: autoRefineInstructions(reason, review) }, { trigger: \"auto\" });\n\t\t\tthis._pendingAutoRefineReview = undefined;\n\t\t\tthis._turnIntervalAutoRefinePending = false;\n\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t\tif (reason === \"compact\") {\n\t\t\t\tthis._compactAutoRefinePending = false;\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// Auto-refine is opportunistic; manual /refine remains available.\n\t\t\t// Stamp the cooldown so a persistently failing refine doesn't retry\n\t\t\t// (via a retained pending review) on every agent end.\n\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\tif (error instanceof RefineSkippedError) {\n\t\t\t\t// A skipped round is consumed like a reviewer decline, not retained for retry.\n\t\t\t\tthis._pendingAutoRefineReview = undefined;\n\t\t\t\tthis._turnIntervalAutoRefinePending = false;\n\t\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t\t\tif (reason === \"compact\") this._compactAutoRefinePending = false;\n\t\t\t}\n\t\t} finally {\n\t\t\tthis._autoRefineInProgress = false;\n\t\t\tthis._scheduleDeferredAutoRefineIfIdle();\n\t\t}\n\t}\n\n\tprivate async _reviewAutoRefine(context: AutoRefineReviewRequest, signal?: AbortSignal): Promise<AutoRefineReview> {\n\t\tif (this._autoRefineReviewer) {\n\t\t\treturn this._autoRefineReviewer(context, signal);\n\t\t}\n\t\tconst model = this.model;\n\t\tif (!model) {\n\t\t\treturn { shouldRefine: false, rationale: \"No model selected.\" };\n\t\t}\n\t\tconst { apiKey, headers } = await this._getRequiredRequestAuth(model);\n\t\treturn reviewAutoRefine(\n\t\t\tthis.agent.state.messages,\n\t\t\tthis._loadMergedHarnessState(),\n\t\t\tthis._loadRefinementHistory(),\n\t\t\tmodel,\n\t\t\tapiKey,\n\t\t\tcontext,\n\t\t\theaders,\n\t\t\tsignal,\n\t\t\tthis.thinkingLevel,\n\t\t);\n\t}\n\n\t/** Global harness state overlaid with this session's local state, when persisted. */\n\tprivate _loadMergedHarnessState(): HarnessState {\n\t\tconst localHarnessStateDir = this._localHarnessStateDir();\n\t\treturn mergeHarnessStates(\n\t\t\tloadHarnessState(getGlobalHarnessStateDir(), \"global\"),\n\t\t\tlocalHarnessStateDir ? loadHarnessState(localHarnessStateDir, \"local\") : undefined,\n\t\t);\n\t}\n\n\tprivate _loadRefinementHistory(): RefinementResult[] {\n\t\treturn mergeRefinementHistory(\n\t\t\tloadGlobalRefinementHistory(getGlobalHarnessStateDir()),\n\t\t\tgetRefinementHistory(this.sessionManager.getEntries().filter((entry) => entry.type === \"custom\")),\n\t\t);\n\t}\n\n\t/**\n\t * Refine editable continual harness state: prompt notes, memory, skills, and subagent specs.\n\t * The base system prompt is intentionally not editable through this path.\n\t *\n\t * Planning runs in the background and does NOT block turn entry points\n\t * (`_waitForRefineIdle` only waits for `_refineInFlight`). Only the fast\n\t * application phase (disk I/O + in-memory mutation) blocks turn entry points.\n\t */\n\tasync refine(\n\t\toptions: {\n\t\t\tinstructions?: string;\n\t\t\trollbackId?: string;\n\t\t\tglobal?: boolean;\n\t\t} = {},\n\t\tinternal: { skipAbort?: boolean; trigger?: \"manual\" | \"auto\" } = {},\n\t): Promise<RefinementResult> {\n\t\t// Queued /refine executes from the session-input pump between turns;\n\t\t// refine never aborts the agent (planning is backgrounded and the apply\n\t\t// phase waits for quiescence), so skipAbort only asserts the pump's\n\t\t// idle invariant instead of changing abort behavior.\n\t\tif (internal.skipAbort && this.isStreaming) {\n\t\t\tthrow new Error(\"Cannot refine without aborting while the agent is running.\");\n\t\t}\n\t\t// Wait for any existing refine (both planning and application) before\n\t\t// starting a new run. This serializes concurrent /refine calls so two\n\t\t// planning phases cannot race into concurrent _applyRefine calls that\n\t\t// overwrite harness state.\n\t\twhile (this._refineInFlight || this._refinePlanInFlight || this._serializedPlanInFlight) {\n\t\t\tif (this._refineInFlight) {\n\t\t\t\tawait this._refineInFlight;\n\t\t\t} else if (this._refinePlanInFlight) {\n\t\t\t\tawait this._refinePlanInFlight;\n\t\t\t} else {\n\t\t\t\t// A serialized background plan is in flight (started during an\n\t\t\t\t// active turn at message_end). Wait for planning and for the active\n\t\t\t\t// turn to settle so its normal checkpoint can consume the plan.\n\t\t\t\tconst serializedPlanInFlight = this._serializedPlanInFlight;\n\t\t\t\tawait serializedPlanInFlight;\n\t\t\t\tif (this._refineInFlight || this._refinePlanInFlight) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tawait this.agent.waitForIdle();\n\t\t\t\t// Aborted turns skip shouldStopAfterTurn. Drop their settled plan\n\t\t\t\t// after idle so a later public refine cannot spin on it forever.\n\t\t\t\tif (this._serializedPlanInFlight === serializedPlanInFlight) {\n\t\t\t\t\tthis._serializedPlanInFlight = undefined;\n\t\t\t\t\tthis._serializedExplicitRefineOptions = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst refineAbort = new AbortController();\n\t\tthis._refineAbortController = refineAbort;\n\n\t\tconst planRun = this._planRefine(options, refineAbort.signal, internal.trigger ?? \"manual\");\n\t\tconst planSettled = planRun.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\tthis._refinePlanInFlight = planSettled;\n\t\tlet plan: RefinementPlan;\n\t\ttry {\n\t\t\tplan = await planRun;\n\t\t} catch (e) {\n\t\t\tif (this._refineAbortController === refineAbort) {\n\t\t\t\tthis._refineAbortController = undefined;\n\t\t\t}\n\t\t\tthis._scheduleSessionInputPump();\n\t\t\tthrow e;\n\t\t} finally {\n\t\t\tif (this._refinePlanInFlight === planSettled) {\n\t\t\t\tthis._refinePlanInFlight = undefined;\n\t\t\t}\n\t\t}\n\n\t\t// Block new turns before waiting for the current turn to finish. One shared\n\t\t// settled promise covers the full transition and apply critical section.\n\t\tlet resolveApplySettled: () => void = () => {};\n\t\tconst applySettled = new Promise<void>((resolve) => {\n\t\t\tresolveApplySettled = resolve;\n\t\t});\n\t\tthis._refineInFlight = applySettled;\n\t\ttry {\n\t\t\t// Wait for the session to become quiescent before applying. Planning is\n\t\t\t// allowed to overlap active user work, but application must not disconnect\n\t\t\t// event handling until that work and its queued events have completed.\n\t\t\tawait this.agent.waitForIdle();\n\t\t\twhile (true) {\n\t\t\t\tconst eventQueue = this._agentEventQueue;\n\t\t\t\tconst compactionOp = this._compactionOperation;\n\t\t\t\tconst branchSummaryOp = this._branchSummaryOperation;\n\t\t\t\tawait Promise.allSettled([\n\t\t\t\t\teventQueue,\n\t\t\t\t\t...(compactionOp ? [compactionOp] : []),\n\t\t\t\t\t...(branchSummaryOp ? [branchSummaryOp] : []),\n\t\t\t\t]);\n\t\t\t\tif (\n\t\t\t\t\teventQueue === this._agentEventQueue &&\n\t\t\t\t\tcompactionOp === this._compactionOperation &&\n\t\t\t\t\tbranchSummaryOp === this._branchSummaryOperation\n\t\t\t\t) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this._disposed || refineAbort.signal.aborted) {\n\t\t\t\tthrow new Error(\"Refinement cancelled because the session was disposed.\");\n\t\t\t}\n\t\t\treturn await this._applyRefine(plan, options, refineAbort);\n\t\t} finally {\n\t\t\tresolveApplySettled();\n\t\t\tif (this._refineInFlight === applySettled) {\n\t\t\t\tthis._refineInFlight = undefined;\n\t\t\t}\n\t\t\tthis._scheduleSessionInputPump();\n\t\t}\n\t}\n\n\t/**\n\t * Block a new agent turn until any in-flight refine application phase has\n\t * reattached event handling; otherwise the turn's messages are never\n\t * persisted or rendered.\n\t *\n\t * The idle-wait and application phase (`_refineInFlight`) block here. The\n\t * background planning phase (`_refinePlanInFlight`) does NOT block turns.\n\t * Refine failures surface to the refine caller, not here.\n\t */\n\tprivate async _waitForRefineIdle(): Promise<void> {\n\t\twhile (this._refineInFlight) {\n\t\t\tawait this._refineInFlight;\n\t\t}\n\t}\n\n\t/**\n\t * Background planning phase: runs the LLM planning call via `planRefinement`.\n\t * Does not disconnect from or abort the agent. Returns the plan without\n\t * applying anything.\n\t */\n\tprivate async _planRefine(\n\t\toptions: { instructions?: string; rollbackId?: string; global?: boolean },\n\t\tsignal: AbortSignal,\n\t\ttrigger: \"manual\" | \"auto\" = \"manual\",\n\t): Promise<RefinementPlan> {\n\t\tif (this._disposed) {\n\t\t\tthrow new Error(\"Cannot refine a disposed session.\");\n\t\t}\n\n\t\tif (!this.model) {\n\t\t\tthrow new Error(formatNoModelSelectedMessage());\n\t\t}\n\n\t\tconst model = this.model;\n\t\tconst { apiKey, headers } = await this._getRequiredRequestAuth(model);\n\t\tconst globalHarnessStateDir = getGlobalHarnessStateDir();\n\t\tconst localHarnessStateDir = this._localHarnessStateDir();\n\t\tconst requestedScope = options.global ? \"global\" : \"local\";\n\t\tif (!options.rollbackId && requestedScope === \"local\" && !localHarnessStateDir) {\n\t\t\tthrow new Error(\"Local harness refinement requires a persisted session; use global refinement instead.\");\n\t\t}\n\t\tconst globalPlanningState = loadHarnessState(globalHarnessStateDir, \"global\");\n\t\tconst localPlanningState = localHarnessStateDir ? loadHarnessState(localHarnessStateDir, \"local\") : undefined;\n\t\tconst planningState =\n\t\t\trequestedScope === \"global\"\n\t\t\t\t? globalPlanningState\n\t\t\t\t: mergeHarnessStates(globalPlanningState, localPlanningState);\n\t\tconst history = this._loadRefinementHistory();\n\t\tconst rollbackTarget = options.rollbackId ? history.find((item) => item.id === options.rollbackId) : undefined;\n\t\tlet baselineScope = rollbackTarget\n\t\t\t? (inferRefinementResultScope(rollbackTarget) ?? requestedScope)\n\t\t\t: requestedScope;\n\t\tlet baselineHarnessStateDir = baselineScope === \"global\" ? globalHarnessStateDir : localHarnessStateDir;\n\t\tif (rollbackTarget?.harnessStatePath) {\n\t\t\tbaselineHarnessStateDir = dirname(rollbackTarget.harnessStatePath);\n\t\t\tbaselineScope = resolve(baselineHarnessStateDir) === resolve(globalHarnessStateDir) ? \"global\" : \"local\";\n\t\t}\n\t\tif (!baselineHarnessStateDir) {\n\t\t\tthrow new Error(\"Local harness refinement requires a persisted session; use global refinement instead.\");\n\t\t}\n\t\tconst baselineState = rollbackTarget\n\t\t\t? loadHarnessState(baselineHarnessStateDir, baselineScope)\n\t\t\t: baselineScope === \"global\"\n\t\t\t\t? globalPlanningState\n\t\t\t\t: localPlanningState!;\n\t\tif (!options.rollbackId && this._extensionRunner.hasHandlers(\"session_before_refine\")) {\n\t\t\tconst result = (await this._extensionRunner.emit({\n\t\t\t\ttype: \"session_before_refine\",\n\t\t\t\tpreparation: {\n\t\t\t\t\ttrigger,\n\t\t\t\t\tinstructions: options.instructions,\n\t\t\t\t\tscope: requestedScope,\n\t\t\t\t\tplanningState,\n\t\t\t\t\thistory,\n\t\t\t\t\tconversationText: serializeConversation(convertToLlm(this.agent.state.messages)).slice(-80_000),\n\t\t\t\t},\n\t\t\t\tsignal,\n\t\t\t})) as SessionBeforeRefineResult | undefined;\n\t\t\tif (this._disposed || signal.aborted) {\n\t\t\t\tthrow new Error(\"Refinement cancelled because the session was disposed.\");\n\t\t\t}\n\t\t\tif (result?.skip) {\n\t\t\t\tthrow new RefineSkippedError(\"Refinement skipped by extension\");\n\t\t\t}\n\t\t\tif (result?.proposal !== undefined) {\n\t\t\t\treturn {\n\t\t\t\t\tproposal: normalizeRefinementProposal(result.proposal),\n\t\t\t\t\tid: generateRefinementId(),\n\t\t\t\t\tbaselineState,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\tconst plan = await planRefinement(\n\t\t\tthis.agent.state.messages,\n\t\t\tplanningState,\n\t\t\thistory,\n\t\t\tmodel,\n\t\t\tapiKey,\n\t\t\toptions,\n\t\t\theaders,\n\t\t\tsignal,\n\t\t\tthis.thinkingLevel,\n\t\t);\n\t\tif (this._disposed || signal.aborted) {\n\t\t\tthrow new Error(\"Refinement cancelled because the session was disposed.\");\n\t\t}\n\t\treturn { ...plan, baselineState };\n\t}\n\n\tprivate _recordRefinementOutcome(result: RefinementResult): void {\n\t\tconst message = createRefinementOutcomeMessage(result);\n\t\ttry {\n\t\t\tthis.sessionManager.appendCustomMessageEntryWithRollback(\n\t\t\t\tmessage.customType,\n\t\t\t\tmessage.content,\n\t\t\t\tmessage.display,\n\t\t\t\tmessage.details,\n\t\t\t);\n\t\t} catch {\n\t\t\t// Not in the session file, so context rebuilds would drop the outcome.\n\t\t\tthis._unpersistedOutcomes.push(message);\n\t\t}\n\t\tthis.agent.state.messages.push(message);\n\t\tthis._emit({ type: \"message_start\", message });\n\t\tthis._emit({ type: \"message_end\", message });\n\t}\n\n\t/**\n\t * Synchronous application phase: disconnects from the agent, aborts any\n\t * in-flight agent run, applies the refinement plan to disk and memory, then\n\t * reconnects. This is the only phase that blocks turn entry points.\n\t */\n\tprivate async _applyRefine(\n\t\tplan: RefinementPlan,\n\t\toptions: { instructions?: string; rollbackId?: string; global?: boolean },\n\t\trefineAbort: AbortController,\n\t): Promise<RefinementResult> {\n\t\tif (this._disposed) {\n\t\t\tthrow new Error(\"Cannot refine a disposed session.\");\n\t\t}\n\t\t// The caller has already set _refineInFlight and waited for agent idle.\n\t\t// Disconnect only for the brief apply + save + reconnect critical section.\n\t\tthis._disconnectFromAgent();\n\n\t\ttry {\n\t\t\tconst globalHarnessStateDir = getGlobalHarnessStateDir();\n\t\t\tconst localHarnessStateDir = this._localHarnessStateDir();\n\t\t\tconst requestedScope = options.global ? \"global\" : \"local\";\n\t\t\tconst history = this._loadRefinementHistory();\n\t\t\tconst rollbackTarget = options.rollbackId ? history.find((item) => item.id === options.rollbackId) : undefined;\n\t\t\tlet targetScope = plan.rollbackScope ?? requestedScope;\n\t\t\tlet targetHarnessStateDir = targetScope === \"global\" ? globalHarnessStateDir : localHarnessStateDir;\n\t\t\tif (targetScope === \"local\" && rollbackTarget?.harnessStatePath) {\n\t\t\t\tif (!existsSync(rollbackTarget.harnessStatePath)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Local refinement ${rollbackTarget.id} state file not found: ${rollbackTarget.harnessStatePath}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\ttargetHarnessStateDir = dirname(rollbackTarget.harnessStatePath);\n\t\t\t\t// Legacy records predate scope fields and default to \"local\" but may point\n\t\t\t\t// at the global store; honor the recorded path so its entries stay global.\n\t\t\t\tif (resolve(targetHarnessStateDir) === resolve(globalHarnessStateDir)) {\n\t\t\t\t\ttargetScope = \"global\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!targetHarnessStateDir) {\n\t\t\t\tthrow new Error(\"Local harness refinement requires a persisted session; use global refinement instead.\");\n\t\t\t}\n\t\t\t// Re-read the target state immediately before applying so concurrent kernel\n\t\t\t// (`rlm.harness`) writes during the LLM pass are not clobbered.\n\t\t\tconst state = loadHarnessState(targetHarnessStateDir, targetScope);\n\t\t\tconst proposal = {\n\t\t\t\t...plan.proposal,\n\t\t\t\tedits: plan.proposal.edits.map((edit) => {\n\t\t\t\t\tconst localPrefix = \"local:\";\n\t\t\t\t\tconst globalPrefix = \"global:\";\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...edit,\n\t\t\t\t\t\tid: edit.id?.startsWith(localPrefix)\n\t\t\t\t\t\t\t? edit.id.slice(localPrefix.length)\n\t\t\t\t\t\t\t: edit.id?.startsWith(globalPrefix)\n\t\t\t\t\t\t\t\t? edit.id.slice(globalPrefix.length)\n\t\t\t\t\t\t\t\t: edit.id,\n\t\t\t\t\t};\n\t\t\t\t}),\n\t\t\t};\n\t\t\tif (this._disposed || refineAbort.signal.aborted) {\n\t\t\t\tthrow new Error(\"Refinement cancelled because the session was disposed.\");\n\t\t\t}\n\t\t\tconst result = applyRefinementProposal(state, proposal, {\n\t\t\t\tid: plan.id,\n\t\t\t\trollbackOf: plan.rollbackOf,\n\t\t\t\tscope: targetScope,\n\t\t\t\tbaselineState: plan.baselineState,\n\t\t\t});\n\t\t\tresult.harnessStatePath = saveHarnessState(targetHarnessStateDir, state);\n\t\t\tif (targetScope === \"global\") {\n\t\t\t\tappendGlobalRefinement(globalHarnessStateDir, result);\n\t\t\t}\n\t\t\tlet refinementAuditAppendError: { error: unknown } | undefined;\n\t\t\ttry {\n\t\t\t\tthis.sessionManager.appendCustomEntry(\"asm-agent.refinement\", result);\n\t\t\t} catch (error) {\n\t\t\t\trefinementAuditAppendError = { error };\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tthis._recordRefinementOutcome(result);\n\t\t\t} catch (error) {\n\t\t\t\tif (!refinementAuditAppendError) throw error;\n\t\t\t}\n\t\t\tif (refinementAuditAppendError) throw refinementAuditAppendError.error;\n\t\t\tthis._baseSystemPrompt = this._rebuildSystemPrompt(this.getActiveToolNames());\n\t\t\tthis.agent.state.systemPrompt = this._baseSystemPrompt;\n\t\t\ttry {\n\t\t\t\tthis._emit({ type: \"refine_complete\", result });\n\t\t\t} catch {\n\t\t\t\t// Listener failures must not flip a successful refinement into\n\t\t\t\t// a reported failure — the refinement is already persisted.\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tawait this._extensionRunner.emit({\n\t\t\t\t\ttype: \"refine_complete\",\n\t\t\t\t\tid: result.id,\n\t\t\t\t\tsummary: result.summary,\n\t\t\t\t\tappliedEdits: result.appliedEdits.filter((edit) => edit.applied).length,\n\t\t\t\t\tscope: result.scope ?? \"local\",\n\t\t\t\t});\n\t\t\t} catch {\n\t\t\t\t// Extension emit failures must not flip a successful refinement\n\t\t\t\t// into a reported failure — the refinement is already persisted.\n\t\t\t}\n\t\t\treturn result;\n\t\t} finally {\n\t\t\tif (this._refineAbortController === refineAbort) {\n\t\t\t\tthis._refineAbortController = undefined;\n\t\t\t}\n\t\t\tif (!this._disposed) {\n\t\t\t\tthis._reconnectToAgent();\n\t\t\t}\n\t\t}\n\t}\n\n\tabortBranchSummary(): void {\n\t\tthis._branchSummaryAbortController?.abort();\n\t}\n\n\t/**\n\t * Check if compaction is needed and run it.\n\t * Called after agent_end and before prompt submission.\n\t *\n\t * Two cases:\n\t * 1. Overflow: LLM returned context overflow error, remove error message from agent state, compact, auto-retry\n\t * 2. Threshold: Context over threshold, compact, and continue only for stopped in-progress loops or queued messages\n\t *\n\t * @param assistantMessage The assistant message to check\n\t * @param skipAbortedCheck If false, include aborted messages (for pre-prompt check). Default: true\n\t */\n\tprivate _getThresholdContextTokens(\n\t\tassistantMessage: AssistantMessage,\n\t\tcompactionTimestamp: number | undefined,\n\t): number | undefined {\n\t\tconst messages = this.agent.state.messages;\n\t\tconst estimate = estimateContextTokens(messages);\n\t\tif (estimate.lastUsageIndex !== null) {\n\t\t\t// Verify the usage source is post-compaction. Kept pre-compaction messages\n\t\t\t// have stale usage reflecting the old (larger) context and would falsely\n\t\t\t// trigger compaction right after one just finished.\n\t\t\tconst usageMsg = messages[estimate.lastUsageIndex];\n\t\t\tif (\n\t\t\t\tcompactionTimestamp !== undefined &&\n\t\t\t\tusageMsg.role === \"assistant\" &&\n\t\t\t\t(usageMsg as AssistantMessage).timestamp <= compactionTimestamp\n\t\t\t) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\treturn estimate.tokens;\n\t\t}\n\t\tif (assistantMessage.stopReason === \"error\") return undefined;\n\t\treturn calculateContextTokens(assistantMessage.usage);\n\t}\n\n\tprivate async _checkCompaction(\n\t\tassistantMessage: AssistantMessage,\n\t\tskipAbortedCheck = true,\n\t\tqueueAutonomousContinuation = true,\n\t): Promise<boolean> {\n\t\t// An abort drops any compaction the model requested this turn, even on the\n\t\t// pre-prompt path (skipAbortedCheck=false) which continues to threshold checks.\n\t\tif (assistantMessage.stopReason === \"aborted\") {\n\t\t\tthis._pendingRequestedCompaction = undefined;\n\t\t\t// An abort also drops any pending explicit refine.run request: the\n\t\t\t// turn that would service it (non-serialized: _consumePendingRequestedRefine\n\t\t\t// at agent_end; serialized: the shouldStopAfterTurn checkpoint) never\n\t\t\t// runs for an aborted turn, so a stale request would leak into the\n\t\t\t// next turn or checkpoint.\n\t\t\tthis._pendingRequestedRefine = undefined;\n\t\t\tif (this._serializedPlanInFlight) {\n\t\t\t\tconst serializedPlanInFlight = this._serializedPlanInFlight;\n\t\t\t\tthis._autoRefineBranchVersion++;\n\t\t\t\tthis._refineAbortController?.abort();\n\t\t\t\tawait serializedPlanInFlight.catch(() => undefined);\n\t\t\t\tif (this._serializedPlanInFlight === serializedPlanInFlight) {\n\t\t\t\t\tthis._serializedPlanInFlight = undefined;\n\t\t\t\t\tthis._serializedExplicitRefineOptions = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (skipAbortedCheck) return false;\n\t\t}\n\n\t\tconst settings = this.settingsManager.getCompactionSettings();\n\t\tconst contextWindow = this.model?.contextWindow ?? 0;\n\n\t\t// Skip overflow check if the message came from a different model.\n\t\t// This handles the case where user switched from a smaller-context model (e.g. opus)\n\t\t// to a larger-context model (e.g. codex) - the overflow error from the old model\n\t\t// shouldn't trigger compaction for the new model.\n\t\tconst sameModel =\n\t\t\tthis.model && assistantMessage.provider === this.model.provider && assistantMessage.model === this.model.id;\n\n\t\t// Skip overflow/threshold checks if this assistant message is older than the\n\t\t// latest compaction boundary. This prevents a stale pre-compaction usage/error\n\t\t// from retriggering compaction on the first prompt after compaction.\n\t\tconst compactionEntry = getLatestCompactionEntry(this.sessionManager.getBranch());\n\t\tconst compactionTimestamp = compactionEntry ? new Date(compactionEntry.timestamp).getTime() : undefined;\n\t\tconst assistantIsFromBeforeCompaction =\n\t\t\tcompactionTimestamp !== undefined && assistantMessage.timestamp <= compactionTimestamp;\n\n\t\t// Case 1: Overflow - takes priority over a pending model request so the error\n\t\t// strip + retry still happen; the compaction it runs consumes the request.\n\t\tif (\n\t\t\t!assistantIsFromBeforeCompaction &&\n\t\t\t(settings.enabled || this._pendingRequestedCompaction !== undefined) &&\n\t\t\tsameModel &&\n\t\t\tisContextOverflow(assistantMessage, contextWindow)\n\t\t) {\n\t\t\tif (this._overflowRecovery !== \"idle\") {\n\t\t\t\tif (this._overflowRecovery === \"attempted\") {\n\t\t\t\t\tthis._overflowRecovery = \"reported\";\n\t\t\t\t\tthis._endCompactionUnsuccessfully(\n\t\t\t\t\t\t\"overflow\",\n\t\t\t\t\t\t\"failed\",\n\t\t\t\t\t\t\"Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model.\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis._overflowRecovery = \"attempted\";\n\t\t\t// Remove the error message from agent state (it IS saved to session for history,\n\t\t\t// but we don't want it in context for the retry)\n\t\t\tconst messages = this.agent.state.messages;\n\t\t\tif (messages.length > 0 && messages[messages.length - 1].role === \"assistant\") {\n\t\t\t\tthis.agent.state.messages = messages.slice(0, -1);\n\t\t\t}\n\t\t\treturn await this._runAutoCompaction(\"overflow\", true);\n\t\t}\n\n\t\tif (this._pendingRequestedCompaction !== undefined) {\n\t\t\treturn await this._runAutoCompaction(\"requested\", false);\n\t\t}\n\n\t\tif (!settings.enabled || assistantIsFromBeforeCompaction) return false;\n\n\t\t// Case 3: Threshold - context is getting large.\n\t\t// Use the full-session estimate so messages appended after the last successful\n\t\t// assistant usage are included, matching the /usage context display.\n\t\tconst contextTokens = this._getThresholdContextTokens(assistantMessage, compactionTimestamp);\n\t\tif (contextTokens === undefined) return false;\n\t\tif (shouldCompact(contextTokens, contextWindow, settings)) {\n\t\t\tif (queueAutonomousContinuation && this._queueGoalContinuationForThresholdCompaction(assistantMessage)) {\n\t\t\t\tthis._continueAfterThresholdCompaction = true;\n\t\t\t} else if (\n\t\t\t\tqueueAutonomousContinuation &&\n\t\t\t\t(await this._queueAutonomousContinuationForThresholdCompaction(assistantMessage))\n\t\t\t) {\n\t\t\t\tthis._continueAfterThresholdCompaction = true;\n\t\t\t}\n\t\t\treturn await this._runAutoCompaction(\"threshold\", false);\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Internal: Run automatic (threshold/overflow) or model-requested compaction\n\t * with events.\n\t */\n\tprivate _endCompactionUnsuccessfully(\n\t\treason: CompactionOutcomeReason,\n\t\toutcome: CompactionOutcome,\n\t\tmessage: string,\n\t\toptions: {\n\t\t\taborted?: boolean;\n\t\t\terrorSeverity?: \"warning\" | \"error\";\n\t\t\tcustomInstructions?: string;\n\t\t} = {},\n\t): void {\n\t\tthis._persistCompactionOutcome(reason, outcome, message);\n\t\tthis._emit({\n\t\t\ttype: \"compaction_end\",\n\t\t\treason,\n\t\t\tresult: undefined,\n\t\t\taborted: options.aborted ?? false,\n\t\t\twillRetry: false,\n\t\t\t// Aborts are user-initiated; they carry no error message on the event.\n\t\t\terrorMessage: options.aborted ? undefined : message,\n\t\t\terrorSeverity: options.errorSeverity,\n\t\t\tcustomInstructions: options.customInstructions,\n\t\t});\n\t}\n\n\tprivate _persistCompactionOutcome(\n\t\treason: CompactionOutcomeReason,\n\t\toutcome: CompactionOutcome,\n\t\tmessage: string,\n\t): void {\n\t\tlet outcomeMessage = createCompactionOutcomeMessage(message, {\n\t\t\treason,\n\t\t\toutcome,\n\t\t});\n\t\ttry {\n\t\t\tthis.sessionManager.appendCustomMessageEntryWithRollback(\n\t\t\t\toutcomeMessage.customType,\n\t\t\t\toutcomeMessage.content,\n\t\t\t\toutcomeMessage.display,\n\t\t\t\toutcomeMessage.details,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tconst persistenceError = error instanceof Error ? error.message : String(error);\n\t\t\toutcomeMessage = createCompactionOutcomeMessage(\n\t\t\t\t`${message}\\n\\nThis compaction outcome could not be saved to session history: ${persistenceError}`,\n\t\t\t\t{ reason, outcome },\n\t\t\t);\n\t\t\t// Not in the session file, so context rebuilds would drop the disclosure.\n\t\t\tthis._unpersistedOutcomes.push(outcomeMessage);\n\t\t}\n\t\tthis.agent.state.messages.push(outcomeMessage);\n\t\tthis._emit({ type: \"message_start\", message: outcomeMessage });\n\t\tthis._emit({ type: \"message_end\", message: outcomeMessage });\n\t}\n\n\tprivate async _runAutoCompaction(\n\t\treason: \"overflow\" | \"threshold\" | \"requested\",\n\t\twillRetry: boolean,\n\t): Promise<boolean> {\n\t\t// Any compaction consumes a pending model request and honors its instructions\n\t\t// (overflow recovery can fire first and take the request with it).\n\t\tconst pending = this._pendingRequestedCompaction;\n\t\tthis._pendingRequestedCompaction = undefined;\n\t\tconst customInstructions = pending?.customInstructions;\n\t\tconst shouldContinueAfterCompaction =\n\t\t\t(reason === \"threshold\" || reason === \"requested\") && this._continueAfterThresholdCompaction;\n\t\tconst queuedAutonomousContinuationsForThisCompaction =\n\t\t\treason === \"threshold\" && shouldContinueAfterCompaction\n\t\t\t\t? this._pendingThresholdCompactionAutonomousMessages.splice(0)\n\t\t\t\t: [];\n\t\tconst queuedGoalContinuationForThisCompaction =\n\t\t\treason === \"threshold\" && shouldContinueAfterCompaction ? this._queuedGoalThresholdContinuation : undefined;\n\t\tthis._continueAfterThresholdCompaction = false;\n\n\t\t// Requested/threshold stop the loop on purpose, so a failed or skipped compaction must not stall it.\n\t\t// Overflow stays excluded: a failed overflow recovery must not re-issue the overflowing request.\n\t\tconst resumeAfterFailure = () => {\n\t\t\tif (\n\t\t\t\t(reason === \"requested\" || reason === \"threshold\") &&\n\t\t\t\t(shouldContinueAfterCompaction || this.agent.hasQueuedMessages() || this.hasPendingSessionWork)\n\t\t\t) {\n\t\t\t\tthis._schedulePostCompactionContinue();\n\t\t\t}\n\t\t};\n\n\t\tthis._emit({ type: \"compaction_start\", reason, customInstructions });\n\t\tthis._autoCompactionAbortController = new AbortController();\n\n\t\ttry {\n\t\t\tconst authResult = this.model ? await this._modelRegistry.getApiKeyAndHeaders(this.model) : undefined;\n\t\t\tif (!this.model || !authResult || !authResult.ok || !authResult.apiKey) {\n\t\t\t\tconst detail =\n\t\t\t\t\t!this.model || !authResult\n\t\t\t\t\t\t? \"no model is selected\"\n\t\t\t\t\t\t: authResult.ok\n\t\t\t\t\t\t\t? \"no API key is available\"\n\t\t\t\t\t\t\t: authResult.error;\n\t\t\t\tthis._endCompactionUnsuccessfully(reason, \"failed\", `Compaction failed: ${detail}`);\n\t\t\t\tthis._clearQueuedAutonomousContinuationsAfterSkippedThresholdCompaction(\n\t\t\t\t\treason === \"threshold\" && shouldContinueAfterCompaction,\n\t\t\t\t\tqueuedAutonomousContinuationsForThisCompaction,\n\t\t\t\t);\n\t\t\t\tresumeAfterFailure();\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tconst result = await this._performCompaction({\n\t\t\t\tmodel: this.model,\n\t\t\t\tapiKey: authResult.apiKey,\n\t\t\t\theaders: authResult.headers,\n\t\t\t\tcustomInstructions,\n\t\t\t\tsignal: this._autoCompactionAbortController.signal,\n\t\t\t});\n\n\t\t\tthis._emit({\n\t\t\t\ttype: \"compaction_end\",\n\t\t\t\treason,\n\t\t\t\tresult,\n\t\t\t\taborted: false,\n\t\t\t\twillRetry,\n\t\t\t\tcustomInstructions,\n\t\t\t});\n\t\t\t// Queued work lives in both the agent queues and the session-owned queues.\n\t\t\tconst hasQueuedMessages = this.agent.hasQueuedMessages() || this.hasPendingSessionWork;\n\t\t\tconst willContinueAfterCompaction = willRetry || shouldContinueAfterCompaction || hasQueuedMessages;\n\n\t\t\tif (willRetry) {\n\t\t\t\tconst messages = this.agent.state.messages;\n\t\t\t\tconst lastMsg = messages[messages.length - 1];\n\t\t\t\tif (lastMsg?.role === \"assistant\" && (lastMsg as AssistantMessage).stopReason === \"error\") {\n\t\t\t\t\tthis.agent.state.messages = messages.slice(0, -1);\n\t\t\t\t}\n\n\t\t\t\tthis._schedulePostCompactionContinue();\n\t\t\t\tthis._scheduleAutoRefineAfterCompaction(willContinueAfterCompaction);\n\t\t\t\treturn true;\n\t\t\t} else if (shouldContinueAfterCompaction || hasQueuedMessages) {\n\t\t\t\t// Compaction can intentionally stop a tool loop between turns.\n\t\t\t\t// Queued follow-up/steering/custom messages can also be waiting.\n\t\t\t\tthis._schedulePostCompactionContinue();\n\t\t\t\tthis._scheduleAutoRefineAfterCompaction(willContinueAfterCompaction);\n\t\t\t} else {\n\t\t\t\tthis._scheduleAutoRefineAfterCompaction(willContinueAfterCompaction);\n\t\t\t}\n\t\t\treturn false;\n\t\t} catch (error) {\n\t\t\tthis._clearQueuedAutonomousContinuationsAfterSkippedThresholdCompaction(\n\t\t\t\treason === \"threshold\" && shouldContinueAfterCompaction,\n\t\t\t\tqueuedAutonomousContinuationsForThisCompaction,\n\t\t\t);\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"compaction failed\";\n\t\t\tconst aborted =\n\t\t\t\terrorMessage === \"Compaction cancelled\" || (error instanceof Error && error.name === \"AbortError\");\n\t\t\tif (aborted) {\n\t\t\t\tthis._clearQueuedGoalContinuationAfterCancelledThresholdCompaction(queuedGoalContinuationForThisCompaction);\n\t\t\t\tthis._endCompactionUnsuccessfully(\n\t\t\t\t\treason,\n\t\t\t\t\t\"cancelled\",\n\t\t\t\t\t`${reason === \"requested\" ? \"Requested c\" : \"C\"}ompaction cancelled`,\n\t\t\t\t\t{ aborted: true, customInstructions },\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (error instanceof CompactionSkippedError) {\n\t\t\t\tthis._endCompactionUnsuccessfully(\n\t\t\t\t\treason,\n\t\t\t\t\t\"skipped\",\n\t\t\t\t\treason === \"requested\"\n\t\t\t\t\t\t? `Requested compaction skipped: ${errorMessage}`\n\t\t\t\t\t\t: `Auto-compaction skipped: ${errorMessage}`,\n\t\t\t\t\t{ errorSeverity: \"warning\", customInstructions },\n\t\t\t\t);\n\t\t\t\tresumeAfterFailure();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tthis._endCompactionUnsuccessfully(\n\t\t\t\treason,\n\t\t\t\t\"failed\",\n\t\t\t\treason === \"overflow\"\n\t\t\t\t\t? `Context overflow recovery failed: ${errorMessage}`\n\t\t\t\t\t: reason === \"requested\"\n\t\t\t\t\t\t? `Requested compaction failed: ${errorMessage}`\n\t\t\t\t\t\t: `Auto-compaction failed: ${errorMessage}`,\n\t\t\t\t{ customInstructions },\n\t\t\t);\n\t\t\tresumeAfterFailure();\n\t\t\treturn false;\n\t\t} finally {\n\t\t\tthis._autoCompactionAbortController = undefined;\n\t\t\tthis._scheduleSessionInputPump();\n\t\t}\n\t}\n\n\tsetAutoCompactionEnabled(enabled: boolean): void {\n\t\tthis.settingsManager.setCompactionEnabled(enabled);\n\t}\n\n\tget autoCompactionEnabled(): boolean {\n\t\treturn this.settingsManager.getCompactionEnabled();\n\t}\n\n\t/**\n\t * Set the provider for extra env vars merged over process.env in extension\n\t * pi.exec() subprocesses. The function is read at exec time, so a host (e.g.\n\t * the daemon) can update the underlying value per attach without rebinding.\n\t */\n\tsetExecEnvProvider(provider: (() => Record<string, string | undefined> | undefined) | undefined): void {\n\t\tthis._execEnvProvider = provider;\n\t\tconst extensions = this._resourceLoader.getExtensions();\n\t\textensions.runtime.getExecEnv = provider;\n\t}\n\n\tasync bindExtensions(bindings: ExtensionBindings): Promise<void> {\n\t\tif (bindings.uiContext !== undefined) {\n\t\t\tthis._extensionUIContext = bindings.uiContext;\n\t\t}\n\t\tif (bindings.commandContextActions !== undefined) {\n\t\t\tthis._extensionCommandContextActions = bindings.commandContextActions;\n\t\t}\n\t\tif (bindings.shutdownHandler !== undefined) {\n\t\t\tthis._extensionShutdownHandler = bindings.shutdownHandler;\n\t\t}\n\t\tif (bindings.onError !== undefined) {\n\t\t\tthis._extensionErrorListener = bindings.onError;\n\t\t}\n\n\t\tthis._applyExtensionBindings(this._extensionRunner);\n\t\tawait this._extensionRunner.emit(this._sessionStartEvent);\n\t\tawait this.extendResourcesFromExtensions(this._sessionStartEvent.reason === \"reload\" ? \"reload\" : \"startup\");\n\t}\n\n\tprivate async extendResourcesFromExtensions(reason: \"startup\" | \"reload\"): Promise<void> {\n\t\tif (!this._extensionRunner.hasHandlers(\"resources_discover\")) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst { skillPaths, promptPaths, themePaths } = await this._extensionRunner.emitResourcesDiscover(\n\t\t\tthis._cwd,\n\t\t\treason,\n\t\t);\n\n\t\tif (skillPaths.length === 0 && promptPaths.length === 0 && themePaths.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst extensionPaths: ResourceExtensionPaths = {\n\t\t\tskillPaths: this.buildExtensionResourcePaths(skillPaths),\n\t\t\tpromptPaths: this.buildExtensionResourcePaths(promptPaths),\n\t\t\tthemePaths: this.buildExtensionResourcePaths(themePaths),\n\t\t};\n\n\t\tthis._resourceLoader.extendResources(extensionPaths);\n\t\tthis._baseSystemPrompt = this._rebuildSystemPrompt(this.getActiveToolNames());\n\t\tthis.agent.state.systemPrompt = this._baseSystemPrompt;\n\t}\n\n\tprivate buildExtensionResourcePaths(entries: Array<{ path: string; extensionPath: string }>): Array<{\n\t\tpath: string;\n\t\tmetadata: {\n\t\t\tsource: string;\n\t\t\tscope: \"temporary\";\n\t\t\torigin: \"top-level\";\n\t\t\tbaseDir?: string;\n\t\t};\n\t}> {\n\t\treturn entries.map((entry) => {\n\t\t\tconst source = this.getExtensionSourceLabel(entry.extensionPath);\n\t\t\tconst baseDir = entry.extensionPath.startsWith(\"<\") ? undefined : dirname(entry.extensionPath);\n\t\t\treturn {\n\t\t\t\tpath: entry.path,\n\t\t\t\tmetadata: {\n\t\t\t\t\tsource,\n\t\t\t\t\tscope: \"temporary\",\n\t\t\t\t\torigin: \"top-level\",\n\t\t\t\t\tbaseDir,\n\t\t\t\t},\n\t\t\t};\n\t\t});\n\t}\n\n\tprivate getExtensionSourceLabel(extensionPath: string): string {\n\t\tif (extensionPath.startsWith(\"<\")) {\n\t\t\treturn `extension:${extensionPath.replace(/[<>]/g, \"\")}`;\n\t\t}\n\t\tconst base = basename(extensionPath);\n\t\tconst name = base.replace(/\\.(ts|js)$/, \"\");\n\t\treturn `extension:${name}`;\n\t}\n\n\tprivate _applyExtensionBindings(runner: ExtensionRunner): void {\n\t\trunner.setUIContext(this._extensionUIContext);\n\t\trunner.bindCommandContext(this._extensionCommandContextActions);\n\n\t\tthis._extensionErrorUnsubscriber?.();\n\t\tthis._extensionErrorUnsubscriber = this._extensionErrorListener\n\t\t\t? runner.onError(this._extensionErrorListener)\n\t\t\t: undefined;\n\t}\n\n\tprivate _refreshCurrentModelFromRegistry(): void {\n\t\tconst currentModel = this.model;\n\t\tif (!currentModel) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst refreshedModel = this._modelRegistry.find(currentModel.provider, currentModel.id);\n\t\tif (!refreshedModel || refreshedModel === currentModel) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.agent.state.model = refreshedModel;\n\t}\n\n\tprivate _bindExtensionCore(runner: ExtensionRunner): void {\n\t\tconst getCommands = (): SlashCommandInfo[] => {\n\t\t\tconst extensionCommands: SlashCommandInfo[] = runner.getRegisteredCommands().map((command) => ({\n\t\t\t\tname: command.invocationName,\n\t\t\t\tdescription: command.description,\n\t\t\t\tsource: \"extension\",\n\t\t\t\tsourceInfo: command.sourceInfo,\n\t\t\t}));\n\n\t\t\tconst templates: SlashCommandInfo[] = this.promptTemplates.map((template) => ({\n\t\t\t\tname: template.name,\n\t\t\t\tdescription: template.description,\n\t\t\t\tsource: \"prompt\",\n\t\t\t\tsourceInfo: template.sourceInfo,\n\t\t\t}));\n\n\t\t\tconst skills: SlashCommandInfo[] = this._resourceLoader.getSkills().skills.map((skill) => ({\n\t\t\t\tname: `skill:${skill.name}`,\n\t\t\t\tdescription: skill.description,\n\t\t\t\tsource: \"skill\",\n\t\t\t\tsourceInfo: skill.sourceInfo,\n\t\t\t}));\n\n\t\t\treturn [...extensionCommands, ...templates, ...skills];\n\t\t};\n\n\t\trunner.bindCore(\n\t\t\t{\n\t\t\t\tsendMessage: (message, options) => {\n\t\t\t\t\tthis.sendCustomMessage(message, options).catch((err) => {\n\t\t\t\t\t\trunner.emitError({\n\t\t\t\t\t\t\textensionPath: \"<runtime>\",\n\t\t\t\t\t\t\tevent: \"send_message\",\n\t\t\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tsendUserMessage: (content, options) => {\n\t\t\t\t\tthis.sendUserMessage(content, options).catch((err) => {\n\t\t\t\t\t\trunner.emitError({\n\t\t\t\t\t\t\textensionPath: \"<runtime>\",\n\t\t\t\t\t\t\tevent: \"send_user_message\",\n\t\t\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tappendEntry: (customType, data) => {\n\t\t\t\t\tthis.sessionManager.appendCustomEntry(customType, data);\n\t\t\t\t},\n\t\t\t\tsetSessionName: async (name) => {\n\t\t\t\t\tif (this._agentMessageController?.setSessionName) {\n\t\t\t\t\t\tawait this._agentMessageController.setSessionName(name);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tthis.setSessionName(name);\n\t\t\t\t},\n\t\t\t\tgetSessionName: () => {\n\t\t\t\t\treturn this.sessionManager.getSessionName();\n\t\t\t\t},\n\t\t\t\tsetLabel: (entryId, label) => {\n\t\t\t\t\tthis.sessionManager.appendLabelChange(entryId, label);\n\t\t\t\t},\n\t\t\t\tgetActiveTools: () => this.getActiveToolNames(),\n\t\t\t\tgetAllTools: () => this.getAllTools(),\n\t\t\t\tsetActiveTools: (toolNames) => this.setActiveToolsByName(toolNames),\n\t\t\t\trefreshTools: () => this._refreshToolRegistry(),\n\t\t\t\tgetCommands,\n\t\t\t\tsetModel: async (model) => {\n\t\t\t\t\tif (!this.modelRegistry.hasConfiguredAuth(model)) return false;\n\t\t\t\t\tawait this.setModel(model);\n\t\t\t\t\treturn true;\n\t\t\t\t},\n\t\t\t\tgetThinkingLevel: () => this.thinkingLevel,\n\t\t\t\tsetThinkingLevel: (level) => this.setThinkingLevel(level),\n\t\t\t},\n\t\t\t{\n\t\t\t\tgetModel: () => this.model,\n\t\t\t\tisIdle: () => !this.isStreaming,\n\t\t\t\tgetSignal: () => this.agent.signal,\n\t\t\t\tabort: () => this.abort(),\n\t\t\t\thasPendingMessages: () => this.queuedActionCount > 0,\n\t\t\t\tshutdown: () => {\n\t\t\t\t\tthis._extensionShutdownHandler?.();\n\t\t\t\t},\n\t\t\t\tgetContextUsage: () => this.getContextUsage(),\n\t\t\t\tcompact: (options) => {\n\t\t\t\t\tvoid (async () => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst result = await this.compact(options?.customInstructions);\n\t\t\t\t\t\t\toptions?.onComplete?.(result);\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tconst err = error instanceof Error ? error : new Error(String(error));\n\t\t\t\t\t\t\toptions?.onError?.(err);\n\t\t\t\t\t\t}\n\t\t\t\t\t})();\n\t\t\t\t},\n\t\t\t\tgetSystemPrompt: () => this.systemPrompt,\n\t\t\t},\n\t\t\t{\n\t\t\t\tregisterProvider: (name, config) => {\n\t\t\t\t\tthis._modelRegistry.registerProvider(name, config);\n\t\t\t\t\tthis._refreshCurrentModelFromRegistry();\n\t\t\t\t},\n\t\t\t\tunregisterProvider: (name) => {\n\t\t\t\t\tthis._modelRegistry.unregisterProvider(name);\n\t\t\t\t\tthis._refreshCurrentModelFromRegistry();\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t}\n\n\tprivate _refreshToolRegistry(options?: { activeToolNames?: string[]; includeAllExtensionTools?: boolean }): void {\n\t\tconst previousRegistryNames = new Set(this._toolRegistry.keys());\n\t\tconst previousActiveToolNames = this.getActiveToolNames();\n\t\tconst allowedToolNames = this._allowedToolNames;\n\t\tconst registeredTools = this._extensionRunner.getAllRegisteredTools();\n\t\tconst allCustomTools = [\n\t\t\t...registeredTools,\n\t\t\t...this._customTools.map((definition) => ({\n\t\t\t\tdefinition,\n\t\t\t\tsourceInfo: createSyntheticSourceInfo(`<sdk:${definition.name}>`, {\n\t\t\t\t\tsource: \"sdk\",\n\t\t\t\t}),\n\t\t\t})),\n\t\t];\n\t\tconst isAllowedTool = (name: string): boolean => !allowedToolNames || allowedToolNames.has(name);\n\t\tconst allowedCustomTools = allCustomTools.filter((tool) => isAllowedTool(tool.definition.name));\n\t\tconst definitionRegistry = new Map<string, ToolDefinitionEntry>(\n\t\t\tArray.from(this._baseToolDefinitions.entries())\n\t\t\t\t.filter(([name]) => isAllowedTool(name))\n\t\t\t\t.map(([name, definition]) => [\n\t\t\t\t\tname,\n\t\t\t\t\t{\n\t\t\t\t\t\tdefinition,\n\t\t\t\t\t\tsourceInfo: createSyntheticSourceInfo(`<builtin:${name}>`, {\n\t\t\t\t\t\t\tsource: \"builtin\",\n\t\t\t\t\t\t}),\n\t\t\t\t\t},\n\t\t\t\t]),\n\t\t);\n\t\tfor (const tool of allowedCustomTools) {\n\t\t\tdefinitionRegistry.set(tool.definition.name, {\n\t\t\t\tdefinition: tool.definition,\n\t\t\t\tsourceInfo: tool.sourceInfo,\n\t\t\t});\n\t\t}\n\t\tthis._toolDefinitions = definitionRegistry;\n\t\tthis._toolPromptSnippets = new Map(\n\t\t\tArray.from(definitionRegistry.values())\n\t\t\t\t.map(({ definition }) => {\n\t\t\t\t\tconst snippet = this._normalizePromptSnippet(definition.promptSnippet);\n\t\t\t\t\treturn snippet ? ([definition.name, snippet] as const) : undefined;\n\t\t\t\t})\n\t\t\t\t.filter((entry): entry is readonly [string, string] => entry !== undefined),\n\t\t);\n\t\tthis._toolPromptGuidelines = new Map(\n\t\t\tArray.from(definitionRegistry.values())\n\t\t\t\t.map(({ definition }) => {\n\t\t\t\t\tconst guidelines = this._normalizePromptGuidelines(definition.promptGuidelines);\n\t\t\t\t\treturn guidelines.length > 0 ? ([definition.name, guidelines] as const) : undefined;\n\t\t\t\t})\n\t\t\t\t.filter((entry): entry is readonly [string, string[]] => entry !== undefined),\n\t\t);\n\t\tconst runner = this._extensionRunner;\n\t\tconst wrappedExtensionTools = wrapRegisteredTools(allowedCustomTools, runner);\n\t\t// Resolve the runner at call time so a rebuild/reload rebinds built-in tools to the\n\t\t// live runner instead of wedging them on the invalidated one's stale-ctx guard.\n\t\tconst wrappedBuiltInTools = wrapRegisteredTools(\n\t\t\tArray.from(this._baseToolDefinitions.values())\n\t\t\t\t.filter((definition) => isAllowedTool(definition.name))\n\t\t\t\t.map((definition) => ({\n\t\t\t\t\tdefinition,\n\t\t\t\t\tsourceInfo: createSyntheticSourceInfo(`<builtin:${definition.name}>`, { source: \"builtin\" }),\n\t\t\t\t})),\n\t\t\t() => this._extensionRunner,\n\t\t);\n\n\t\tconst toolRegistry = new Map(wrappedBuiltInTools.map((tool) => [tool.name, tool]));\n\t\tfor (const tool of wrappedExtensionTools as AgentTool[]) {\n\t\t\ttoolRegistry.set(tool.name, tool);\n\t\t}\n\t\tthis._toolRegistry = toolRegistry;\n\n\t\tconst nextActiveToolNames = (\n\t\t\toptions?.activeToolNames ? [...options.activeToolNames] : [...previousActiveToolNames]\n\t\t).filter((name) => isAllowedTool(name));\n\n\t\tif (allowedToolNames) {\n\t\t\tfor (const toolName of this._toolRegistry.keys()) {\n\t\t\t\tif (allowedToolNames.has(toolName)) {\n\t\t\t\t\tnextActiveToolNames.push(toolName);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (options?.includeAllExtensionTools) {\n\t\t\tfor (const tool of wrappedExtensionTools) {\n\t\t\t\tnextActiveToolNames.push(tool.name);\n\t\t\t}\n\t\t} else if (!options?.activeToolNames) {\n\t\t\tfor (const toolName of this._toolRegistry.keys()) {\n\t\t\t\tif (!previousRegistryNames.has(toolName)) {\n\t\t\t\t\tnextActiveToolNames.push(toolName);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.setActiveToolsByName([...new Set(nextActiveToolNames)]);\n\t}\n\n\tprivate _buildRuntime(options: {\n\t\tactiveToolNames?: string[];\n\t\tflagValues?: Map<string, boolean | string>;\n\t\tincludeAllExtensionTools?: boolean;\n\t}): void {\n\t\tconst pythonSkills = getPythonSkillRuntimeInfo(this._modelVisibleSkills());\n\t\tlet configuredBaseToolDefinitions: Record<string, ToolDefinition>;\n\t\tif (this._baseToolsOverride) {\n\t\t\tconfiguredBaseToolDefinitions = Object.fromEntries(\n\t\t\t\tObject.entries(this._baseToolsOverride).map(([name, tool]) => [\n\t\t\t\t\tname,\n\t\t\t\t\tcreateToolDefinitionFromAgentTool(tool),\n\t\t\t\t]),\n\t\t\t);\n\t\t} else {\n\t\t\t// Rebuilding (e.g. /reload) replaces the provisioner; drop the previous\n\t\t\t// kernel so the session never holds two live kernels. Gate the new kernel's\n\t\t\t// startup on the old one's dispose (which flushes a final snapshot), so a\n\t\t\t// reload can't restore from a snapshot the old kernel is still writing.\n\t\t\tconst previousDispose = this._ipythonKernelProvisioner?.dispose();\n\t\t\tthis._ipythonKernelSnapshotDir = this.sessionManager.getSessionArtifactDir();\n\t\t\t// Only surface the \"revived from your previous session\" notice on the first\n\t\t\t// build (a genuine resume). A later rebuild (/reload) restores state silently\n\t\t\t// for continuity — the conversation is unchanged, so there's nothing to flag.\n\t\t\tconst notifyRestore = !this._ipythonRuntimeBuilt;\n\t\t\tthis._ipythonKernelProvisioner = new IpythonKernelProvisioner(this._cwd, {\n\t\t\t\tenv: this._rlmKernelEnv(),\n\t\t\t\tcommandPrefix: this.settingsManager.getShellCommandPrefix(),\n\t\t\t\tshellPath: this.settingsManager.getShellPath(),\n\t\t\t\tsessionId: this.sessionId,\n\t\t\t\thostHandlers: this._createKernelHostHandlers(),\n\t\t\t\tpythonSkills,\n\t\t\t\tsnapshotDir: this._ipythonKernelSnapshotDir,\n\t\t\t\treadyGate: previousDispose,\n\t\t\t\tonRestore: notifyRestore ? (result) => this._onIpythonStateRestored(result) : undefined,\n\t\t\t});\n\t\t\tconfiguredBaseToolDefinitions = createAllToolDefinitions(this._cwd, {\n\t\t\t\tipython: {\n\t\t\t\t\tprovisioner: this._ipythonKernelProvisioner,\n\t\t\t\t\tcommandPrefix: this.settingsManager.getShellCommandPrefix(),\n\t\t\t\t\tshellPath: this.settingsManager.getShellPath(),\n\t\t\t\t\tonLateSentAgentMessage: (toolCallId, message) =>\n\t\t\t\t\t\tthis._recordLateIpythonSentAgentMessage(toolCallId, message),\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\tthis._baseToolDefinitions = new Map(\n\t\t\tObject.entries(configuredBaseToolDefinitions).map(([name, tool]) => [name, tool as ToolDefinition]),\n\t\t);\n\n\t\tconst extensionsResult = this._resourceLoader.getExtensions();\n\t\tif (options.flagValues) {\n\t\t\tfor (const [name, value] of options.flagValues) {\n\t\t\t\textensionsResult.runtime.flagValues.set(name, value);\n\t\t\t}\n\t\t}\n\t\t// Re-apply on (re)build so the provider survives /reload. Guarded: the\n\t\t// runtime object can be shared across sessions from one ResourceLoader\n\t\t// (RLM children), so a provider-less session must not wipe the owner's.\n\t\tif (this._execEnvProvider) {\n\t\t\textensionsResult.runtime.getExecEnv = this._execEnvProvider;\n\t\t}\n\n\t\tthis._extensionRunner = new ExtensionRunner(\n\t\t\textensionsResult.extensions,\n\t\t\textensionsResult.runtime,\n\t\t\tthis._cwd,\n\t\t\tthis.sessionManager,\n\t\t\tthis._modelRegistry,\n\t\t);\n\t\tif (this._extensionRunnerRef) {\n\t\t\tthis._extensionRunnerRef.current = this._extensionRunner;\n\t\t}\n\t\tthis._bindExtensionCore(this._extensionRunner);\n\t\tthis._applyExtensionBindings(this._extensionRunner);\n\n\t\tconst defaultActiveToolNames = this._baseToolsOverride ? Object.keys(this._baseToolsOverride) : [\"ipython\"];\n\t\tconst baseActiveToolNames = [...(options.activeToolNames ?? defaultActiveToolNames)];\n\t\tif (this._goalState.status === \"active\" && this._includeGoals) {\n\t\t\t// An active goal needs ipython so the model can reach the goal skill.\n\t\t\tbaseActiveToolNames.push(\"ipython\");\n\t\t}\n\t\tthis._refreshToolRegistry({\n\t\t\tactiveToolNames: [...new Set(baseActiveToolNames)],\n\t\t\tincludeAllExtensionTools: options.includeAllExtensionTools,\n\t\t});\n\n\t\t// Prewarm when configured, or whenever we're resuming a session that already\n\t\t// has a kernel snapshot — so its state is revived and the model is told what\n\t\t// came back before the first turn, rather than a turn later when the kernel\n\t\t// would otherwise lazily start on first use.\n\t\tconst hasSnapshot =\n\t\t\t!!this._ipythonKernelSnapshotDir && existsSync(snapshotPathIn(this._ipythonKernelSnapshotDir));\n\t\tif ((this._prewarmIpythonKernel || hasSnapshot) && this.getActiveToolNames().includes(\"ipython\")) {\n\t\t\tthis._ipythonKernelProvisioner?.prewarm();\n\t\t}\n\n\t\t// Subsequent builds are in-process rebuilds (/reload), not a fresh resume.\n\t\tthis._ipythonRuntimeBuilt = true;\n\t}\n\n\t/**\n\t * Skills exposed to the model (system prompt + kernel). The bundled goal\n\t * and compact skills are withheld when disabled for this session.\n\t */\n\tprivate _modelVisibleSkills(): Skill[] {\n\t\tlet skills = this._resourceLoader.getSkills().skills;\n\t\tif (!this._includeGoals) {\n\t\t\tskills = skills.filter((skill) => skill.name !== GOAL_SKILL_NAME);\n\t\t}\n\t\tif (!this._includeCompactSkill) {\n\t\t\tskills = skills.filter((skill) => skill.name !== COMPACT_SKILL_NAME);\n\t\t}\n\t\tif (!this._autoRefineAllowedForSession()) {\n\t\t\tskills = skills.filter((skill) => skill.name !== REFINE_SKILL_NAME);\n\t\t}\n\t\tif (!this._agentMessageController) {\n\t\t\tskills = skills.filter((skill) => skill.name !== AGENT_MESSAGE_SKILL_NAME);\n\t\t}\n\t\tif (!this._agentObserveController) {\n\t\t\tskills = skills.filter((skill) => skill.name !== AGENT_OBSERVE_SKILL_NAME);\n\t\t}\n\t\tif (!this._agentObserveController || !this._rlmHeartbeatController) {\n\t\t\tskills = skills.filter((skill) => skill.name !== ORCHESTRATION_HEARTBEAT_SKILL_NAME);\n\t\t}\n\t\treturn skills;\n\t}\n\n\tprivate async _handleBackgroundProcessCompleted(payload: Record<string, unknown>): Promise<Record<string, unknown>> {\n\t\tconst completionId = payload.completion_id;\n\t\tconst pid = payload.pid;\n\t\tconst command = payload.command;\n\t\tconst exitCode = payload.exit_code;\n\t\tconst duration = payload.duration;\n\t\tif (typeof completionId !== \"string\" || !/^[a-f0-9]{32}$/.test(completionId)) {\n\t\t\tthrow new Error(\"bash.completed requires a valid completion_id\");\n\t\t}\n\t\tif (!Number.isSafeInteger(pid) || (pid as number) <= 0) {\n\t\t\tthrow new Error(\"bash.completed requires a positive integer pid\");\n\t\t}\n\t\tif (typeof command !== \"string\" || command.length === 0 || command.length > 100_000) {\n\t\t\tthrow new Error(\"bash.completed requires a non-empty command\");\n\t\t}\n\t\tif (!Number.isSafeInteger(exitCode)) {\n\t\t\tthrow new Error(\"bash.completed requires an integer exit_code\");\n\t\t}\n\t\tif (typeof duration !== \"number\" || !Number.isFinite(duration) || duration < 0) {\n\t\t\tthrow new Error(\"bash.completed requires a non-negative duration\");\n\t\t}\n\t\tif (this._backgroundProcessCompletionIds.has(completionId)) {\n\t\t\treturn { accepted: false, duplicate: true };\n\t\t}\n\t\tthis._backgroundProcessCompletionIds.add(completionId);\n\t\twhile (this._backgroundProcessCompletionIds.size > 1_024) {\n\t\t\tconst oldest = this._backgroundProcessCompletionIds.values().next().value;\n\t\t\tif (oldest === undefined) break;\n\t\t\tthis._backgroundProcessCompletionIds.delete(oldest);\n\t\t}\n\t\ttry {\n\t\t\tconst message = createBackgroundProcessCompletedMessage({\n\t\t\t\tcompletionId,\n\t\t\t\tpid: pid as number,\n\t\t\t\tcommand,\n\t\t\t\texitCode: exitCode as number,\n\t\t\t\tduration,\n\t\t\t});\n\t\t\tawait this._promptInjectedMessage(message.content as string, message, {\n\t\t\t\tstreamingBehavior: \"followUp\",\n\t\t\t\tqueueIfBusy: true,\n\t\t\t\tresumeIfIdle: true,\n\t\t\t\treturnAfterAccepted: true,\n\t\t\t\tsuppressAutonomousContinuation: true,\n\t\t\t\tsource: \"extension\",\n\t\t\t});\n\t\t\treturn { accepted: true };\n\t\t} catch (error) {\n\t\t\tthis._backgroundProcessCompletionIds.delete(completionId);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprivate _createKernelHostHandlers(): HostRequestHandlers {\n\t\tconst handlers: HostRequestHandlers = {\n\t\t\t\"rlm.run\": createRlmRunHostHandler(async ({ prompt, kwargs, cellSourceCode }) => ({\n\t\t\t\t...(await this.runRlmChild(prompt, kwargs, cellSourceCode)),\n\t\t\t})),\n\t\t\t\"rlm.find_models\": createRlmFindModelsHostHandler((query, limit) => this.findRlmModels(query, limit)),\n\t\t\t\"rlm.list_subagents\": createRlmListSubagentsHostHandler(() => this.listRlmSubagents()),\n\t\t\t\"rlm.delete_subagent\": createRlmDeleteSubagentHostHandler((target) => this.deleteRlmSubagent(target)),\n\t\t\t\"model.info\": async () => ({\n\t\t\t\tid: this.model?.id ?? null,\n\t\t\t\tprovider: this.model?.provider ?? null,\n\t\t\t\tinput: this.model?.input ?? [],\n\t\t\t}),\n\t\t\t\"bash.completed\": async (payload) => this._handleBackgroundProcessCompleted(payload),\n\t\t};\n\t\tif (this._includeGoals) {\n\t\t\tfor (const type of [\"goal.get\", \"goal.create\", \"goal.complete\"]) {\n\t\t\t\thandlers[type] = async (payload) => this.handleGoalHostRequest(type, payload);\n\t\t\t}\n\t\t}\n\t\tif (this._includeCompactSkill) {\n\t\t\tfor (const type of [\"compact.run\", \"compact.status\"]) {\n\t\t\t\thandlers[type] = async (payload) => this.handleCompactHostRequest(type, payload);\n\t\t\t}\n\t\t}\n\t\tif (this._autoRefineAllowedForSession()) {\n\t\t\tfor (const type of [\"refine.run\", \"refine.status\"]) {\n\t\t\t\thandlers[type] = async (payload) => this.handleRefineHostRequest(type, payload);\n\t\t\t}\n\t\t}\n\t\tif (this._rlmHeartbeatController) {\n\t\t\tfor (const type of [\n\t\t\t\t\"rlm_heartbeat.list\",\n\t\t\t\t\"rlm_heartbeat.create\",\n\t\t\t\t\"rlm_heartbeat.update\",\n\t\t\t\t\"rlm_heartbeat.delete\",\n\t\t\t]) {\n\t\t\t\thandlers[type] = async (payload) => this.handleRlmHeartbeatHostRequest(type, payload);\n\t\t\t}\n\t\t}\n\t\tconst visibleKernelSkillNames = new Set(\n\t\t\tthis._modelVisibleSkills()\n\t\t\t\t.filter((skill) => !skill.disableModelInvocation)\n\t\t\t\t.map((skill) => skill.name),\n\t\t);\n\t\tif (this._agentMessageController && visibleKernelSkillNames.has(AGENT_MESSAGE_SKILL_NAME)) {\n\t\t\tObject.assign(\n\t\t\t\thandlers,\n\t\t\t\tcreateAgentMessageHostHandlers({\n\t\t\t\t\troster: async () =>\n\t\t\t\t\t\t(await this.handleAgentMessageHostRequest(\"agent_message.list_agents\")) as AgentFamilyRosterResult,\n\t\t\t\t\tawaitPendingChildPublication: (selector) => this._awaitPendingRlmChildPublication(selector),\n\t\t\t\t\tsendAgentMessage: async (input) => {\n\t\t\t\t\t\tconst receipt = (await this.handleAgentMessageHostRequest(\"agent_message.send\", {\n\t\t\t\t\t\t\ttarget: input.target,\n\t\t\t\t\t\t\tmessage: input.message,\n\t\t\t\t\t\t})) as AgentSessionMessageReceipt;\n\t\t\t\t\t\tif (this._rlmDepth > 0) {\n\t\t\t\t\t\t\tlet addressedParent = input.receiverRole === \"parent\";\n\t\t\t\t\t\t\tif (input.receiverRole === undefined && this._agentMessageController?.roster) {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst roster = await this._agentMessageController.roster();\n\t\t\t\t\t\t\t\t\taddressedParent = roster.entries.some(\n\t\t\t\t\t\t\t\t\t\t(entry) =>\n\t\t\t\t\t\t\t\t\t\t\tentry.relationship === \"parent\" &&\n\t\t\t\t\t\t\t\t\t\t\t(entry.id === input.target || entry.name === input.target),\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\taddressedParent = false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (addressedParent) {\n\t\t\t\t\t\t\t\tthis._repliedToParentSinceTask = true;\n\t\t\t\t\t\t\t\tthis._parentReplyCount += 1;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn receipt;\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tif (this._agentObserveController) {\n\t\t\tObject.assign(\n\t\t\t\thandlers,\n\t\t\t\tcreateAgentObserveHostHandlers({\n\t\t\t\t\tlistAgents: () => this.handleAgentObserveHostRequest(\"agent_observe.list\") as AgentObserveListResult,\n\t\t\t\t\tgetAgent: (target) =>\n\t\t\t\t\t\tthis.handleAgentObserveHostRequest(\"agent_observe.get\", {\n\t\t\t\t\t\t\ttarget,\n\t\t\t\t\t\t}) as AgentObserveAgentSnapshot,\n\t\t\t\t\trecentMessages: (input) =>\n\t\t\t\t\t\tthis.handleAgentObserveHostRequest(\"agent_observe.recent\", {\n\t\t\t\t\t\t\ttarget: input.target,\n\t\t\t\t\t\t\tlimit: input.limit,\n\t\t\t\t\t\t\tmax_chars: input.maxChars,\n\t\t\t\t\t\t}) as AgentObserveRecentMessagesResult,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tif (this._mcpManager) {\n\t\t\tObject.assign(handlers, this._mcpManager.hostHandlers());\n\t\t}\n\t\treturn handlers;\n\t}\n\n\tasync reload(): Promise<void> {\n\t\tconst previousFlagValues = this._extensionRunner.getFlagValues();\n\t\tawait emitSessionShutdownEvent(this._extensionRunner, {\n\t\t\ttype: \"session_shutdown\",\n\t\t\treason: \"reload\",\n\t\t});\n\t\tawait this.settingsManager.reload();\n\t\t// Re-read auth.json: a login saved by the client process (daemon mode) must be\n\t\t// visible here so MCP skill gating sees the new credentials.\n\t\tthis._modelRegistry.authStorage.reload();\n\t\tresetApiProviders();\n\t\tthis._mcpManager?.refresh();\n\t\tawait this._resourceLoader.reload();\n\t\tthis._buildRuntime({\n\t\t\tactiveToolNames: this.getActiveToolNames(),\n\t\t\tflagValues: previousFlagValues,\n\t\t\tincludeAllExtensionTools: true,\n\t\t});\n\n\t\tconst hasBindings =\n\t\t\tthis._extensionUIContext ||\n\t\t\tthis._extensionCommandContextActions ||\n\t\t\tthis._extensionShutdownHandler ||\n\t\t\tthis._extensionErrorListener;\n\t\tif (hasBindings) {\n\t\t\tawait this._extensionRunner.emit({\n\t\t\t\ttype: \"session_start\",\n\t\t\t\treason: \"reload\",\n\t\t\t});\n\t\t\tawait this.extendResourcesFromExtensions(\"reload\");\n\t\t}\n\t}\n\n\tprivate _rlmKernelEnv(): Record<string, string> {\n\t\t// Kernel env is provisioning-time only: RLM_MAX_DEPTH may be stale in an already-running kernel;\n\t\t// the TypeScript-side spawn check remains authoritative.\n\t\tconst env: Record<string, string> = {\n\t\t\tRLM_DEPTH: String(this._rlmDepth),\n\t\t\tRLM_MAX_DEPTH: String(this._rlmMaxDepth),\n\t\t\tRLM_GLOBAL_HARNESS_STATE_DIR: getGlobalHarnessStateDir(),\n\t\t};\n\t\tconst rlmSessionDir = this._ensureRlmSessionDir();\n\t\tif (rlmSessionDir) {\n\t\t\tenv.RLM_SESSION_DIR = rlmSessionDir;\n\t\t\t// Keep kernel writes and host reads (system prompt, review, /refine) on\n\t\t\t// the same local harness path. Subagents prefer their own artifact dir;\n\t\t\t// ephemeral sessions fall back to the RLM session dir once it exists.\n\t\t\tenv.RLM_HARNESS_STATE_DIR = this._localHarnessStateDir() ?? getLocalHarnessStateDir(rlmSessionDir)!;\n\t\t}\n\t\tthis._addWebsearchKeyEnv(env);\n\t\treturn env;\n\t}\n\n\tprivate _addWebsearchKeyEnv(env: Record<string, string>): void {\n\t\tif (this._agentDir) {\n\t\t\tenv.ASM_AGENT_CODING_AGENT_DIR = this._agentDir;\n\t\t}\n\n\t\tif (process.env[SERPER_ENV_VAR]?.trim()) {\n\t\t\treturn;\n\t\t}\n\t\t// Inject only when a websearch skill (bundled or custom) is actually loaded,\n\t\t// so the key isn't exposed to kernels that can't use it.\n\t\tif (!this._resourceLoader.getSkills().skills.some((skill) => skill.name === WEBSEARCH_SKILL_NAME)) {\n\t\t\treturn;\n\t\t}\n\t\tconst cred = this._modelRegistry.authStorage.get(SERPER_CREDENTIAL_ID);\n\t\tif (cred?.type !== \"api_key\") {\n\t\t\treturn;\n\t\t}\n\t\tconst resolved = resolveConfigValue(cred.key)?.trim();\n\t\tif (resolved) {\n\t\t\tenv[SERPER_ENV_VAR] = resolved;\n\t\t}\n\t}\n\n\t// Undefined when there's no persistent artifact dir (e.g. the viewer client):\n\t// don't mkdtemp here, since this runs on every kernel build but a viewer never\n\t// does RLM work. The temp dir is created lazily in _createChildRlmSessionDir.\n\tprivate _ensureRlmSessionDir(): string | undefined {\n\t\tif (this._rlmSessionDir) {\n\t\t\tmkdirSync(this._rlmSessionDir, { recursive: true });\n\t\t\treturn this._rlmSessionDir;\n\t\t}\n\n\t\tconst sessionArtifactDir = this.sessionManager.getSessionArtifactDir();\n\t\tif (sessionArtifactDir) {\n\t\t\tmkdirSync(sessionArtifactDir, { recursive: true });\n\t\t\tthis._rlmSessionDir = sessionArtifactDir;\n\t\t\treturn sessionArtifactDir;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tprivate _createChildRlmSessionDir(): string {\n\t\tconst parentDir = this._ensureRlmSessionDir() ?? this._createEphemeralRlmSessionDir();\n\t\tfor (let i = 0; i < 100; i++) {\n\t\t\tconst childDir = join(parentDir, `sub-${randomUUID().slice(0, 8)}`);\n\t\t\ttry {\n\t\t\t\tmkdirSync(childDir);\n\t\t\t\treturn childDir;\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof Error && \"code\" in error && error.code === \"EEXIST\") {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\tthrow new Error(\"Unable to create unique RLM child session directory\");\n\t}\n\n\tprivate _createEphemeralRlmSessionDir(): string {\n\t\tthis._rlmSessionDir = mkdtempSync(join(tmpdir(), \"asm-agent-rlm-\"));\n\t\treturn this._rlmSessionDir;\n\t}\n\n\t_contextTokensForCurrentMessages(): number | undefined {\n\t\tconst last = this._findLastAssistantMessage();\n\t\treturn last ? calculateContextTokens(last.usage) : undefined;\n\t}\n\n\tsetCurrentRecap(recap: string | undefined): void {\n\t\tif (this._currentRecap === recap) return;\n\t\tthis._currentRecap = recap;\n\t\tthis._emit({ type: \"recap_update\", recap });\n\t}\n\n\tget repliedToParentSinceTask(): boolean | undefined {\n\t\treturn this._repliedToParentSinceTask;\n\t}\n\n\tgetCurrentRecap(): string | undefined {\n\t\treturn this._currentRecap;\n\t}\n\n\tprivate _findAssistantEntryForMessage(message: AssistantMessage): SessionMessageEntry | undefined {\n\t\treturn this.sessionManager\n\t\t\t.getEntries()\n\t\t\t.find((entry): entry is SessionMessageEntry => entry.type === \"message\" && entry.message === message);\n\t}\n\n\tprivate _createRlmSubagentRuntimeOptions(options: {\n\t\tid: string;\n\t\tprompt: string;\n\t\tsessionName: string;\n\t\tspawnCode?: string;\n\t\tsessionDir: string;\n\t\tmodel: Model<any>;\n\t\tthinkingLevel?: ThinkingLevel;\n\t}): CreateRlmSubagentRuntimeOptions {\n\t\treturn {\n\t\t\tparentSession: this,\n\t\t\tid: options.id,\n\t\t\tprompt: options.prompt,\n\t\t\tsessionName: options.sessionName,\n\t\t\tspawnCode: options.spawnCode,\n\t\t\tsessionDir: options.sessionDir,\n\t\t\tmodel: options.model,\n\t\t\tthinkingLevel:\n\t\t\t\toptions.thinkingLevel ?? (clampThinkingLevel(options.model, this.thinkingLevel) as ThinkingLevel),\n\t\t\tserviceTier:\n\t\t\t\tthis.serviceTier === \"priority\" && !supportsFastMode(options.model) ? \"default\" : this.serviceTier,\n\t\t\tscopedModels: [...this._scopedModels],\n\t\t\tactiveToolNames: this.getActiveToolNames(),\n\t\t\tallowedToolNames: this._allowedToolNames ? [...this._allowedToolNames] : undefined,\n\t\t\tcustomTools: [...this._customTools],\n\t\t\tincludeGoals: this._includeGoals,\n\t\t\tincludeCompactSkill: this._includeCompactSkill,\n\t\t\trlmDepth: this._rlmDepth + 1,\n\t\t\trlmMaxDepth: this._rlmMaxDepth,\n\t\t\trlmParentNodeId: options.id,\n\t\t};\n\t}\n\n\tprivate async _createRlmSubagentRuntime(options: CreateRlmSubagentRuntimeOptions): Promise<RlmSubagentRuntime> {\n\t\tif (this._subagentRuntimeHost) {\n\t\t\treturn await this._subagentRuntimeHost.createRlmSubagentRuntime(options);\n\t\t}\n\n\t\treturn this._createInlineRlmSubagentRuntime(options);\n\t}\n\n\tprivate _createInlineRlmSubagentRuntime(options: CreateRlmSubagentRuntimeOptions): RlmSubagentRuntime {\n\t\tconst childSessionManager = SessionManager.create(this._cwd, options.sessionDir);\n\t\tif (options.parentSession.sessionFile) {\n\t\t\tchildSessionManager.newSession({\n\t\t\t\tparentSession: options.parentSession.sessionFile,\n\t\t\t\trlmDepth: options.rlmDepth,\n\t\t\t});\n\t\t}\n\t\tchildSessionManager.appendModelChange(options.model.provider, options.model.id);\n\t\tchildSessionManager.appendThinkingLevelChange(options.thinkingLevel);\n\t\tchildSessionManager.appendServiceTierChange(options.serviceTier);\n\n\t\tconst childAgent = new Agent({\n\t\t\tinitialState: {\n\t\t\t\tsystemPrompt: \"\",\n\t\t\t\tmodel: options.model,\n\t\t\t\tthinkingLevel: options.thinkingLevel,\n\t\t\t\tserviceTier: options.serviceTier,\n\t\t\t\ttools: [],\n\t\t\t},\n\t\t\tconvertToLlm: this.agent.convertToLlm,\n\t\t\ttransformContext: this.agent.transformContext,\n\t\t\tstreamFn: this.agent.streamFn,\n\t\t\tgetApiKey: this.agent.getApiKey,\n\t\t\tonPayload: this.agent.onPayload,\n\t\t\tonResponse: this.agent.onResponse,\n\t\t\tsteeringMode: this.settingsManager.getSteeringMode(),\n\t\t\tfollowUpMode: this.settingsManager.getFollowUpMode(),\n\t\t\tsessionId: childSessionManager.getSessionId(),\n\t\t\tthinkingBudgets: this.settingsManager.getThinkingBudgets(),\n\t\t\ttransport: this.settingsManager.getTransport(),\n\t\t\tmaxRetryDelayMs: this.settingsManager.getProviderRetrySettings().maxRetryDelayMs,\n\t\t\ttoolExecution: this.agent.toolExecution,\n\t\t});\n\n\t\tconst child = new AgentSession({\n\t\t\tagent: childAgent,\n\t\t\tsessionManager: childSessionManager,\n\t\t\tsettingsManager: this.settingsManager,\n\t\t\tcwd: this._cwd,\n\t\t\tagentDir: this._agentDir,\n\t\t\tscopedModels: options.scopedModels,\n\t\t\tresourceLoader: this._resourceLoader,\n\t\t\tcustomTools: options.customTools,\n\t\t\tmodelRegistry: this._modelRegistry,\n\t\t\tinitialActiveToolNames: options.activeToolNames,\n\t\t\tallowedToolNames: options.allowedToolNames,\n\t\t\tincludeGoals: options.includeGoals,\n\t\t\tincludeCompactSkill: options.includeCompactSkill,\n\t\t\trlmDepth: options.rlmDepth,\n\t\t\trlmMaxDepth: options.rlmMaxDepth,\n\t\t\trlmSessionDir: options.sessionDir,\n\t\t\trlmParentNodeId: options.rlmParentNodeId,\n\t\t\trlmParentAgent: options.parentSession.sessionName ?? options.parentSession.sessionId,\n\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"startup\" },\n\t\t});\n\t\tif (child.sessionName !== options.sessionName) {\n\t\t\ttry {\n\t\t\t\tchild.setSessionName(options.sessionName);\n\t\t\t} catch (error) {\n\t\t\t\tchild.dispose();\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\toptions.onSessionPublished?.(child);\n\n\t\treturn { session: child };\n\t}\n\n\tprivate _abandonRlmRunForQuiescence(run: RlmChildRun): void {\n\t\trun.suppressTerminalNotice = true;\n\t\trun.abandonedForQuiescence = true;\n\t\tthis._abandonedRlmQuiescenceChildIds.add(run.id);\n\t\tthis._unsettledRlmChildRuns.delete(run);\n\t\trun.settlement.resolve();\n\t\tthis._maybeResumeGoalContinuationAfterRlmWork();\n\t}\n\n\tprivate _cancelActiveRlmChildRuns(reason: string): void {\n\t\tfor (const run of this._activeRlmChildRuns.values()) {\n\t\t\tthis._cancelRlmChildRun(run, reason);\n\t\t}\n\t}\n\n\tprivate _cancelRlmChildRun(run: RlmChildRun, reason: string): boolean {\n\t\tif (run.status !== \"running\" && run.status !== \"queued\") {\n\t\t\treturn false;\n\t\t}\n\t\trun.status = \"cancelled\";\n\t\tif (this._sessionInputPumpSuspended) this._abandonRlmRunForQuiescence(run);\n\t\trun.error = reason;\n\t\trun.publication.reject(new Error(reason));\n\t\trun.abort();\n\t\t// Surface the cancellation immediately; the run's own terminal update is\n\t\t// delayed indefinitely when the child is stuck mid-stream, which is\n\t\t// exactly when users reach for the kill.\n\t\trun.emitUpdate?.();\n\t\treturn true;\n\t}\n\n\tgetRlmChildRunStatus(childId: string): RlmChildAgentStatus | undefined {\n\t\treturn this._activeRlmChildRuns.get(childId)?.status;\n\t}\n\n\tprivate async _currentActiveSessionId(): Promise<string | undefined> {\n\t\ttry {\n\t\t\treturn (await this._agentMessageController?.listAgents())?.current?.activeSessionId;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tprivate async _awaitPendingRlmChildPublication(selector: string): Promise<string | undefined> {\n\t\tconst run = [...this._activeRlmChildRuns.values()].find(\n\t\t\t(candidate) =>\n\t\t\t\t(candidate.status === \"queued\" || candidate.status === \"running\" || candidate.status === \"done\") &&\n\t\t\t\t!candidate.detachedDeletion &&\n\t\t\t\t(candidate.id === selector || candidate.sessionName === selector),\n\t\t);\n\t\tif (!run) return undefined;\n\t\tawait run.publication.promise;\n\t\treturn run.session?.sessionId;\n\t}\n\n\tasync listRlmSubagents(): Promise<RlmListSubagentsResult> {\n\t\treturn this._buildRlmSubagentList(await this._agentMessageController?.listAgents());\n\t}\n\n\tprivate _buildRlmSubagentList(listedAgents?: AgentSessionMessageListResult): RlmListSubagentsResult {\n\t\tconst daemonChildren = new Map<string, AgentSessionMessageAgentSummary>();\n\t\tconst parentActiveSessionId = listedAgents?.current?.activeSessionId;\n\t\tif (parentActiveSessionId) {\n\t\t\tfor (const agent of listedAgents.agents) {\n\t\t\t\tif (\n\t\t\t\t\tagent.runtimeKind === \"subagent\" &&\n\t\t\t\t\tagent.parentActiveSessionId === parentActiveSessionId &&\n\t\t\t\t\tagent.rlmChildId\n\t\t\t\t) {\n\t\t\t\t\tdaemonChildren.set(agent.rlmChildId, agent);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst subagents: RlmListSubagentsResult[\"subagents\"] = [];\n\t\tconst recorded = new Set<string>();\n\t\tfor (const run of this._activeRlmChildRuns.values()) {\n\t\t\tif (this._deletingRlmChildren.has(run.id) || run.detachedDeletion || run.status === \"cancelled\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst daemonChild = daemonChildren.get(run.id);\n\t\t\tsubagents.push({\n\t\t\t\trlm_child_id: run.id,\n\t\t\t\tactive_session_id: daemonChild?.activeSessionId ?? null,\n\t\t\t\tsession_id: daemonChild?.sessionId ?? run.session?.sessionId ?? null,\n\t\t\t\tsession_name: daemonChild?.sessionName ?? run.session?.sessionName ?? run.sessionName,\n\t\t\t\tsession_dir: run.sessionDir,\n\t\t\t\tstatus: run.status === \"done\" ? \"completed\" : run.status === \"error\" ? \"error\" : \"running\",\n\t\t\t});\n\t\t\trecorded.add(run.id);\n\t\t}\n\t\tfor (const [childId, childSession] of this._rlmChildSessions) {\n\t\t\tif (\n\t\t\t\tthis._deletingRlmChildren.has(childId) ||\n\t\t\t\trecorded.has(childId) ||\n\t\t\t\tthis._rlmChildCleanupFailures.has(childId)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst daemonChild = daemonChildren.get(childId);\n\t\t\tconst sessionDir = childSession._rlmSessionDir;\n\t\t\tif (!sessionDir) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tsubagents.push({\n\t\t\t\trlm_child_id: childId,\n\t\t\t\tactive_session_id: daemonChild?.activeSessionId ?? null,\n\t\t\t\tsession_id: daemonChild?.sessionId ?? childSession.sessionId,\n\t\t\t\tsession_name:\n\t\t\t\t\tdaemonChild?.sessionName ?? childSession.sessionName ?? createDefaultRlmSubagentSessionName(\"\", childId),\n\t\t\t\tsession_dir: sessionDir,\n\t\t\t\tstatus: \"completed\",\n\t\t\t});\n\t\t\trecorded.add(childId);\n\t\t}\n\t\tfor (const [childId, daemonChild] of daemonChildren) {\n\t\t\tif (\n\t\t\t\trecorded.has(childId) ||\n\t\t\t\tthis._deletingRlmChildren.has(childId) ||\n\t\t\t\tthis._deletedRlmChildIds.has(childId) ||\n\t\t\t\tthis._rlmChildCleanupFailures.has(childId) ||\n\t\t\t\t!daemonChild.sessionDir\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tsubagents.push({\n\t\t\t\trlm_child_id: childId,\n\t\t\t\tactive_session_id: daemonChild.activeSessionId,\n\t\t\t\tsession_id: daemonChild.sessionId,\n\t\t\t\tsession_name: daemonChild.sessionName ?? createDefaultRlmSubagentSessionName(\"\", childId),\n\t\t\t\tsession_dir: daemonChild.sessionDir,\n\t\t\t\tstatus: daemonChild.rlmChildRegistryStatus === \"completed\" ? \"completed\" : \"error\",\n\t\t\t});\n\t\t}\n\t\treturn { subagents };\n\t}\n\n\tprivate _rlmSubagentMatchesTarget(entry: RlmSubagentRegistryEntry, target: string): boolean {\n\t\treturn (\n\t\t\tentry.rlm_child_id === target ||\n\t\t\tentry.active_session_id === target ||\n\t\t\tentry.session_id === target ||\n\t\t\tentry.session_name === target\n\t\t);\n\t}\n\n\tprivate async _resolveDirectRlmSubagent(target: string): Promise<RlmSubagentRegistryEntry> {\n\t\tconst candidates = [...(await this.listRlmSubagents()).subagents, ...this._rlmChildCleanupFailures.values()];\n\t\tconst matches = candidates.filter((entry) => this._rlmSubagentMatchesTarget(entry, target));\n\t\tif (matches.length === 0) {\n\t\t\tthrow new Error(`No direct RLM subagent matches \"${target}\" in the current parent session`);\n\t\t}\n\t\tif (matches.length > 1) {\n\t\t\tthrow new Error(`RLM subagent selector \"${target}\" is ambiguous in the current parent session`);\n\t\t}\n\t\treturn matches[0]!;\n\t}\n\n\tasync deleteInactiveRlmSubagent(\n\t\tchildId: string,\n\t\tisExternallyRunning: () => boolean = () => false,\n\t): Promise<\"deleted\" | \"not_found\" | \"running\"> {\n\t\tconst isRunning = (): boolean => {\n\t\t\tconst status = this._activeRlmChildRuns.get(childId)?.status;\n\t\t\treturn status === \"queued\" || status === \"running\" || isExternallyRunning();\n\t\t};\n\t\tif (isRunning()) {\n\t\t\treturn \"running\";\n\t\t}\n\t\tconst subagent = [...(await this.listRlmSubagents()).subagents, ...this._rlmChildCleanupFailures.values()].find(\n\t\t\t(entry) => entry.rlm_child_id === childId,\n\t\t);\n\t\tif (!subagent) {\n\t\t\tfor (const run of this._activeRlmChildRuns.values()) {\n\t\t\t\tconst result = await run.session?.deleteInactiveRlmSubagent(childId, isExternallyRunning);\n\t\t\t\tif (result && result !== \"not_found\") {\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const retained of this._rlmChildSessions.values()) {\n\t\t\t\tconst result = await retained.deleteInactiveRlmSubagent(childId, isExternallyRunning);\n\t\t\t\tif (result !== \"not_found\") {\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn \"not_found\";\n\t\t}\n\t\tif (isRunning()) {\n\t\t\treturn \"running\";\n\t\t}\n\t\tconst result = await this._trackRlmSubagentDeletion(subagent, () => {\n\t\t\tif (isRunning()) {\n\t\t\t\treturn Promise.resolve({ subagent, outcome: \"skipped_running\" });\n\t\t\t}\n\t\t\treturn this._deleteResolvedRlmSubagent(subagent);\n\t\t});\n\t\treturn result.outcome === \"skipped_running\" ? \"running\" : \"deleted\";\n\t}\n\n\tasync deleteRlmSubagent(target: string): Promise<RlmDeleteSubagentResult> {\n\t\tconst inFlight = [...this._deletingRlmChildren.values()].filter(({ subagent }) =>\n\t\t\tthis._rlmSubagentMatchesTarget(subagent, target),\n\t\t);\n\t\tif (inFlight.length > 1) {\n\t\t\tthrow new Error(`RLM subagent selector \"${target}\" is ambiguous in the current parent session`);\n\t\t}\n\n\t\t// Running and retained children can be reserved synchronously. This keeps\n\t\t// them hidden immediately while the async daemon listing checks for a\n\t\t// conflicting passive selector.\n\t\tconst localMatches = [\n\t\t\t...this._buildRlmSubagentList().subagents,\n\t\t\t...this._rlmChildCleanupFailures.values(),\n\t\t].filter((entry) => this._rlmSubagentMatchesTarget(entry, target));\n\t\tconst matchingChildIds = new Set([\n\t\t\t...inFlight.map(({ subagent }) => subagent.rlm_child_id),\n\t\t\t...localMatches.map((subagent) => subagent.rlm_child_id),\n\t\t]);\n\t\tif (matchingChildIds.size > 1 || localMatches.length > 1) {\n\t\t\tthrow new Error(`RLM subagent selector \"${target}\" is ambiguous in the current parent session`);\n\t\t}\n\t\tif (inFlight[0]) {\n\t\t\treturn inFlight[0].promise;\n\t\t}\n\t\tif (localMatches[0]) {\n\t\t\tconst subagent = localMatches[0];\n\t\t\treturn this._trackRlmSubagentDeletion(subagent, async () => {\n\t\t\t\tconst listedAgents = await this._agentMessageController?.listAgents();\n\t\t\t\tconst listedSubagents = this._buildRlmSubagentList(listedAgents).subagents;\n\t\t\t\tconst passiveMatches = listedSubagents.filter(\n\t\t\t\t\t(entry) => entry.rlm_child_id !== subagent.rlm_child_id && this._rlmSubagentMatchesTarget(entry, target),\n\t\t\t\t);\n\t\t\t\tif (passiveMatches.length > 0) {\n\t\t\t\t\tthrow new Error(`RLM subagent selector \"${target}\" is ambiguous in the current parent session`);\n\t\t\t\t}\n\t\t\t\tconst parentActiveSessionId = listedAgents?.current?.activeSessionId;\n\t\t\t\tconst daemonChild = listedAgents?.agents.find(\n\t\t\t\t\t(agent) =>\n\t\t\t\t\t\tagent.rlmChildId === subagent.rlm_child_id && agent.parentActiveSessionId === parentActiveSessionId,\n\t\t\t\t);\n\t\t\t\tconst resolvedSubagent = daemonChild\n\t\t\t\t\t? {\n\t\t\t\t\t\t\t...subagent,\n\t\t\t\t\t\t\tactive_session_id: daemonChild.activeSessionId,\n\t\t\t\t\t\t\tsession_id: daemonChild.sessionId,\n\t\t\t\t\t\t\tsession_name: daemonChild.sessionName ?? subagent.session_name,\n\t\t\t\t\t\t}\n\t\t\t\t\t: subagent;\n\t\t\t\treturn this._deleteResolvedRlmSubagent(resolvedSubagent);\n\t\t\t});\n\t\t}\n\n\t\tconst directMatches = [\n\t\t\t...(await this.listRlmSubagents()).subagents,\n\t\t\t...this._rlmChildCleanupFailures.values(),\n\t\t].filter((entry) => this._rlmSubagentMatchesTarget(entry, target));\n\t\tconst directChildIds = new Set(directMatches.map((subagent) => subagent.rlm_child_id));\n\t\tif (directChildIds.size > 1) {\n\t\t\tthrow new Error(`RLM subagent selector \"${target}\" is ambiguous in the current parent session`);\n\t\t}\n\t\tconst subagent = directMatches[0] ?? (await this._resolveDirectRlmSubagent(target));\n\t\treturn this._trackRlmSubagentDeletion(subagent, () => this._deleteResolvedRlmSubagent(subagent));\n\t}\n\n\tprivate async _trackRlmSubagentDeletion(\n\t\tsubagent: RlmSubagentRegistryEntry,\n\t\tstartDeletion: () => Promise<RlmDeleteSubagentResult>,\n\t): Promise<RlmDeleteSubagentResult> {\n\t\tconst existing = this._deletingRlmChildren.get(subagent.rlm_child_id);\n\t\tif (existing) return existing.promise;\n\t\tconst deletion = Promise.resolve().then(startDeletion);\n\t\tthis._deletingRlmChildren.set(subagent.rlm_child_id, {\n\t\t\tsubagent,\n\t\t\tpromise: deletion,\n\t\t});\n\t\ttry {\n\t\t\treturn await deletion;\n\t\t} finally {\n\t\t\tconst clearReservation = () => {\n\t\t\t\tif (this._deletingRlmChildren.get(subagent.rlm_child_id)?.promise === deletion) {\n\t\t\t\t\tthis._deletingRlmChildren.delete(subagent.rlm_child_id);\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst run = this._activeRlmChildRuns.get(subagent.rlm_child_id);\n\t\t\tif (run?.detachedDeletion) {\n\t\t\t\t// Keep every selector reserved until the run settles, or until a failed\n\t\t\t\t// cleanup is exposed for an explicit retry. Repeated deletes before that\n\t\t\t\t// boundary return the same accepted result.\n\t\t\t\tvoid run.deletionReservation.promise.then(clearReservation, clearReservation);\n\t\t\t} else {\n\t\t\t\tclearReservation();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _deleteRlmSubagentSession(childId: string, session?: AgentSession): Promise<void> {\n\t\tif (this._subagentRuntimeHost) {\n\t\t\treturn this._subagentRuntimeHost.deleteRlmSubagentRuntime(childId, session);\n\t\t}\n\t\treturn session?.disposeAsync() ?? Promise.resolve();\n\t}\n\n\tprivate _ensureRlmRunDeletionCleanup(run: RlmChildRun, session: AgentSession): Promise<void> {\n\t\tif (run.deletionCleanup) return run.deletionCleanup;\n\t\tconst cleanup = Promise.resolve().then(() => this._deleteRlmSubagentSession(run.id, session));\n\t\trun.deletionCleanup = cleanup;\n\t\t// Deletion admission is intentionally nonblocking. The detached run owner\n\t\t// joins this exact promise before settlement and records any failure.\n\t\tvoid cleanup.catch(() => undefined);\n\t\treturn cleanup;\n\t}\n\n\tprivate async _recordRlmRunDeletionCleanupFailure(\n\t\trun: RlmChildRun,\n\t\tsubagent: RlmSubagentRegistryEntry,\n\t\tsession: AgentSession,\n\t\terror: unknown,\n\t): Promise<void> {\n\t\tif (this._disposed || this._disposing) {\n\t\t\trun.suppressTerminalNotice = true;\n\t\t\tawait session.disposeAsync().catch(() => undefined);\n\t\t\tif (!run.settled) await this._finishRlmRunDeletion(run);\n\t\t\treturn;\n\t\t}\n\t\trun.deletionCleanup = undefined;\n\t\trun.deletionCleanupObserver = undefined;\n\t\trun.deletionCleanupFailed = true;\n\t\trun.session = session;\n\t\tthis._rlmChildCleanupFailures.set(run.id, subagent);\n\t\t// Make retry admission available before waking the parent model with the\n\t\t// retry-required notice.\n\t\trun.deletionReservation.resolve();\n\t\tawait Promise.resolve();\n\t\tawait run.reportDeletionCleanupFailure?.(error);\n\t}\n\n\tprivate async _finishRlmRunDeletion(run: RlmChildRun): Promise<void> {\n\t\tif (this._activeRlmChildRuns.get(run.id) === run) {\n\t\t\tthis._removeRlmSubagentTracking(run.id, run);\n\t\t}\n\t\trun.settled = true;\n\t\trun.settlement.resolve();\n\t\trun.deletionReservation.resolve();\n\t\tthis._unsettledRlmChildRuns.delete(run);\n\t\tthis._maybeResumeGoalContinuationAfterRlmWork();\n\t}\n\n\tprivate _observeRlmRunDeletionCleanup(\n\t\trun: RlmChildRun,\n\t\tsubagent: RlmSubagentRegistryEntry,\n\t\tsession: AgentSession,\n\t\tcleanup: Promise<void>,\n\t): Promise<boolean> {\n\t\tif (run.deletionCleanupObserver) return run.deletionCleanupObserver;\n\t\tconst observer = cleanup.then(\n\t\t\t() => true,\n\t\t\tasync (error) => {\n\t\t\t\tawait this._recordRlmRunDeletionCleanupFailure(run, subagent, session, error);\n\t\t\t\treturn false;\n\t\t\t},\n\t\t);\n\t\trun.deletionCleanupObserver = observer;\n\t\tvoid observer.catch(() => undefined);\n\t\treturn observer;\n\t}\n\n\tprivate _continueFinishedRlmRunDeletion(\n\t\trun: RlmChildRun,\n\t\tsubagent: RlmSubagentRegistryEntry,\n\t\tsession: AgentSession,\n\t): void {\n\t\tconst cleanup = this._ensureRlmRunDeletionCleanup(run, session);\n\t\tconst observer = this._observeRlmRunDeletionCleanup(run, subagent, session, cleanup);\n\t\tif (!run.deletionRunFinished) return;\n\t\tvoid observer\n\t\t\t.then(async (cleanupSucceeded) => {\n\t\t\t\tif (cleanupSucceeded) await this._finishRlmRunDeletion(run);\n\t\t\t})\n\t\t\t.catch(() => undefined);\n\t}\n\n\tprivate _removeRlmSubagentTracking(childId: string, run?: RlmChildRun): void {\n\t\trun?.unsubscribe?.();\n\t\tthis._rlmChildUnsubscribes.get(childId)?.();\n\t\tthis._rlmChildUnsubscribes.delete(childId);\n\t\tthis._rlmChildSessions.delete(childId);\n\t\tthis._rlmChildCleanupFailures.delete(childId);\n\t\tthis._abandonedRlmQuiescenceChildIds.delete(childId);\n\t\tif (!run || this._activeRlmChildRuns.get(childId) === run) {\n\t\t\tthis._activeRlmChildRuns.delete(childId);\n\t\t}\n\t\tif (run) {\n\t\t\trun.abort = noopRlmChildAbort;\n\t\t\trun.unsubscribe = undefined;\n\t\t\trun.session = undefined;\n\t\t}\n\t}\n\n\tprivate _emitRlmSubagentRemoval(subagent: RlmSubagentRegistryEntry): void {\n\t\tthis._emit({\n\t\t\ttype: \"rlm_child_update\",\n\t\t\tchild: {\n\t\t\t\tid: subagent.rlm_child_id,\n\t\t\t\tparentId: this._rlmParentNodeId,\n\t\t\t\tactiveSessionId: subagent.active_session_id ?? undefined,\n\t\t\t\tsessionName: subagent.session_name,\n\t\t\t\tlabel: subagent.session_name,\n\t\t\t\tstatus: \"cancelled\",\n\t\t\t\tsessionDir: subagent.session_dir,\n\t\t\t\terror: \"Deleted by parent orchestrator\",\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate async _deleteResolvedRlmSubagent(subagent: RlmSubagentRegistryEntry): Promise<RlmDeleteSubagentResult> {\n\t\tconst childId = subagent.rlm_child_id;\n\t\tconst run = this._activeRlmChildRuns.get(childId);\n\t\tif (run) {\n\t\t\tif (run.deletionCleanupFailed) {\n\t\t\t\t// Reset retry coordination only after selector preflight reaches the\n\t\t\t\t// resolved child. A failed preflight must leave the prior retry boundary\n\t\t\t\t// intact so a later call can acquire it.\n\t\t\t\trun.deletionCleanupFailed = false;\n\t\t\t\trun.deletionReservation = createAgentMessageDeferred();\n\t\t\t}\n\t\t\t// The detached task remains the sole lifecycle owner. Mark deletion before\n\t\t\t// cancellation so its catch/finally path cannot race a normal release or\n\t\t\t// terminal notice against the physical delete.\n\t\t\trun.detachedDeletion = subagent;\n\t\t\tif (!this._cancelRlmChildRun(run, \"Deleted by parent orchestrator\")) {\n\t\t\t\tthis._emitRlmSubagentRemoval(subagent);\n\t\t\t}\n\t\t\tconst liveSession = run.session;\n\t\t\tif (run.status === \"error\" && !liveSession && run.settled) {\n\t\t\t\tthis._deletedRlmChildIds.add(childId);\n\t\t\t\tthis._removeRlmSubagentTracking(childId, run);\n\t\t\t\treturn { subagent };\n\t\t\t}\n\t\t\tif (liveSession && run.settled) {\n\t\t\t\trun.deletionRunFinished = true;\n\t\t\t\trun.settlement = createAgentMessageDeferred();\n\t\t\t\trun.settled = false;\n\t\t\t\tthis._unsettledRlmChildRuns.add(run);\n\t\t\t}\n\t\t\tif (liveSession) this._continueFinishedRlmRunDeletion(run, subagent, liveSession);\n\n\t\t\t// Return once deletion is accepted. The run stays hidden but unsettled until\n\t\t\t// abort-insensitive model/tool work unwinds and the shared cleanup finishes.\n\t\t\tthis._deletedRlmChildIds.add(childId);\n\t\t\treturn { subagent };\n\t\t}\n\n\t\tthis._emitRlmSubagentRemoval(subagent);\n\t\tconst retained = this._rlmChildSessions.get(childId);\n\t\ttry {\n\t\t\tawait this._deleteRlmSubagentSession(childId, retained);\n\t\t} catch (error) {\n\t\t\tif (this._disposed || this._disposing) {\n\t\t\t\tthis._removeRlmSubagentTracking(childId);\n\t\t\t\tvoid retained?.disposeAsync().catch(() => undefined);\n\t\t\t} else {\n\t\t\t\tthis._rlmChildCleanupFailures.set(childId, subagent);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tthis._deletedRlmChildIds.add(childId);\n\t\tthis._removeRlmSubagentTracking(childId);\n\t\treturn { subagent };\n\t}\n\n\t/**\n\t * Retain a finished child session for the parent lifetime so inspectors and\n\t * daemon-hosted agent messaging can keep addressing it. Returns false (and disposes\n\t * the child) when the parent is already tearing down, so the caller can drop the\n\t * matching event forwarder too.\n\t */\n\tregisterRlmChildSession(childId: string, session: AgentSession, unsubscribe?: () => void): boolean {\n\t\t// A child can finish concurrently while the parent is (or has) torn down; don't\n\t\t// resurrect the map (it would never be disposed), just drop the child now.\n\t\tif (this._deletingRlmChildren.has(childId) || this._deletedRlmChildIds.has(childId)) {\n\t\t\treturn false;\n\t\t}\n\t\tif (this._subagentRuntimeHost?.completeRlmSubagentRuntime?.(childId, session) === false) {\n\t\t\treturn false;\n\t\t}\n\t\tif (this._disposed || this._disposing) {\n\t\t\tvoid session.disposeAsync().catch(() => undefined);\n\t\t\treturn false;\n\t\t}\n\t\tthis._rlmChildSessions.set(childId, session);\n\t\tif (unsubscribe) {\n\t\t\tthis._rlmChildUnsubscribes.set(childId, unsubscribe);\n\t\t}\n\t\treturn true;\n\t}\n\n\treleaseRlmChildSession(childId: string, session: AgentSession): (() => void) | false {\n\t\tconst run = this._activeRlmChildRuns.get(childId);\n\t\tif (run?.session === session && run.status === \"done\") {\n\t\t\tconst unsubscribe = run.unsubscribe ?? noopRlmChildEventUnsubscribe;\n\t\t\trun.unsubscribe = undefined;\n\t\t\tthis._activeRlmChildRuns.delete(childId);\n\t\t\treturn unsubscribe;\n\t\t}\n\t\tif (this._rlmChildSessions.get(childId) !== session) return false;\n\t\tconst unsubscribe = this._rlmChildUnsubscribes.get(childId) ?? noopRlmChildEventUnsubscribe;\n\t\tthis._rlmChildUnsubscribes.delete(childId);\n\t\tthis._rlmChildSessions.delete(childId);\n\t\treturn unsubscribe;\n\t}\n\n\t/** Live recursive child roster from lifecycle state, including nested work under retained parents. */\n\tgetRlmChildSnapshots(): RlmChildAgentSnapshot[] {\n\t\tconst snapshots: RlmChildAgentSnapshot[] = [];\n\t\tconst recorded = new Set<string>();\n\t\tconst traversed = new Set<string>();\n\t\tfor (const run of this._activeRlmChildRuns.values()) {\n\t\t\tconst hidden =\n\t\t\t\trun.detachedDeletion || this._deletingRlmChildren.has(run.id) || this._deletedRlmChildIds.has(run.id);\n\t\t\tconst child = run.session;\n\t\t\tif (!hidden) {\n\t\t\t\tconst model = child?.model ?? run.model;\n\t\t\t\tsnapshots.push({\n\t\t\t\t\tid: run.id,\n\t\t\t\t\tparentId: this._rlmParentNodeId,\n\t\t\t\t\tsessionName: child?.sessionName ?? run.sessionName,\n\t\t\t\t\tmodel: `${model.provider}/${model.id}`,\n\t\t\t\t\tlabel: rlmChildLabel(run.prompt),\n\t\t\t\t\tstatus: run.status,\n\t\t\t\t\tsessionDir: run.sessionDir,\n\t\t\t\t});\n\t\t\t\trecorded.add(run.id);\n\t\t\t}\n\t\t\tif (child) {\n\t\t\t\ttraversed.add(run.id);\n\t\t\t\tsnapshots.push(...child.getRlmChildSnapshots());\n\t\t\t}\n\t\t}\n\t\tfor (const [childId, child] of this._rlmChildSessions) {\n\t\t\tif (recorded.has(childId) || traversed.has(childId)) continue;\n\t\t\tconst hidden = this._deletingRlmChildren.has(childId) || this._deletedRlmChildIds.has(childId);\n\t\t\tif (!hidden) {\n\t\t\t\tsnapshots.push({\n\t\t\t\t\tid: childId,\n\t\t\t\t\tparentId: this._rlmParentNodeId,\n\t\t\t\t\tsessionName: child.sessionName,\n\t\t\t\t\tmodel: child.model ? `${child.model.provider}/${child.model.id}` : undefined,\n\t\t\t\t\tlabel: child.sessionName ?? \"child agent\",\n\t\t\t\t\t// A failed delete retains the session solely for cleanup retry. Preserve\n\t\t\t\t\t// its cancellation truth in snapshots rather than reviving it as done.\n\t\t\t\t\tstatus: this._rlmChildCleanupFailures.has(childId) ? \"cancelled\" : \"done\",\n\t\t\t\t\tsessionDir: child._rlmSessionDir ?? child.sessionManager.getSessionDir(),\n\t\t\t\t});\n\t\t\t}\n\t\t\tsnapshots.push(...child.getRlmChildSnapshots());\n\t\t}\n\t\treturn snapshots;\n\t}\n\n\t/** True when any direct or nested subagent is still running or queued. */\n\thasRunningRlmChildren(): boolean {\n\t\tfor (const run of this._activeRlmChildRuns.values()) {\n\t\t\tif (run.status === \"running\" || run.status === \"queued\") {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (run.session?.hasRunningRlmChildren()) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\t// A finished direct child can still have a running nested subagent.\n\t\tfor (const session of this._rlmChildSessions.values()) {\n\t\t\tif (session.hasRunningRlmChildren()) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate _rlmChildSessionSnapshot(): AgentSession[] {\n\t\tconst sessions = new Set<AgentSession>();\n\t\tfor (const [childId, session] of this._rlmChildSessions) {\n\t\t\tif (!this._abandonedRlmQuiescenceChildIds.has(childId)) sessions.add(session);\n\t\t}\n\t\tfor (const run of this._activeRlmChildRuns.values()) {\n\t\t\tif (run.session && !run.abandonedForQuiescence) sessions.add(run.session);\n\t\t}\n\t\treturn [...sessions];\n\t}\n\n\tprivate _hasUnsettledRlmQuiescenceWork(): boolean {\n\t\tif (this._hasDeferredRlmTerminalNotices()) return true;\n\t\tif ([...this._unsettledRlmChildRuns].some((run) => !run.settled)) return true;\n\t\treturn this._rlmChildSessionSnapshot().some(\n\t\t\t(child) => child.isSessionActive || child._hasUnsettledRlmQuiescenceWork(),\n\t\t);\n\t}\n\n\t/**\n\t * Wait for every admitted descendant run to publish its terminal parent\n\t * message and for the resulting parent turns to drain. Re-snapshotting after\n\t * each drain includes descendants spawned while earlier results were consumed.\n\t */\n\tasync waitForRlmQuiescence(externalSignal?: AbortSignal): Promise<void> {\n\t\tconst cancellation = new AbortController();\n\t\tconst cancelFromParent = () => cancellation.abort();\n\t\tif (externalSignal?.aborted) cancellation.abort();\n\t\telse externalSignal?.addEventListener(\"abort\", cancelFromParent, { once: true });\n\t\tthis._rlmQuiescenceWaitAborts.add(cancellation);\n\t\tlet rejectCancelled = (_error: Error) => {};\n\t\tconst cancelled = new Promise<never>((_resolve, reject) => {\n\t\t\trejectCancelled = reject;\n\t\t});\n\t\tconst onCancelled = () => rejectCancelled(new Error(\"RLM quiescence wait cancelled\"));\n\t\tcancellation.signal.addEventListener(\"abort\", onCancelled, { once: true });\n\t\tif (cancellation.signal.aborted) onCancelled();\n\t\tconst wait = <T>(operation: Promise<T>): Promise<T> => Promise.race([operation, cancelled]);\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tawait wait(this.waitForHeadlessIdle());\n\t\t\t\t// Strong RLM quiescence also owns session-level work (bash, refine,\n\t\t\t\t// branch mutation, and manual compaction) that interactive waitForIdle\n\t\t\t\t// intentionally ignores. Yield a macrotask while such work is active so\n\t\t\t\t// recursive parent/child barriers cannot form a microtask busy-loop.\n\t\t\t\tif (this.isSessionActive || this._hasDeferredRlmTerminalNotices()) {\n\t\t\t\t\tawait wait(new Promise<void>((resolve) => setTimeout(resolve, 0)));\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst unsettledRuns = [...this._unsettledRlmChildRuns].filter((run) => !run.settled);\n\t\t\t\tconst childSessions = this._rlmChildSessionSnapshot();\n\t\t\t\tif (unsettledRuns.length === 0 && !this._hasUnsettledRlmQuiescenceWork()) return;\n\t\t\t\tawait wait(\n\t\t\t\t\tPromise.all([\n\t\t\t\t\t\t...unsettledRuns.map((run) => run.settlement.promise),\n\t\t\t\t\t\t...childSessions.map((child) => child.waitForRlmQuiescence(cancellation.signal)),\n\t\t\t\t\t]),\n\t\t\t\t);\n\t\t\t\t// Always loop through the self-active/deferred checks again. Work may\n\t\t\t\t// start at the child-settlement boundary.\n\t\t\t}\n\t\t} finally {\n\t\t\t// A local descendant error must cancel sibling recursive waits owned by\n\t\t\t// this barrier before their propagation listeners are removed.\n\t\t\tcancellation.abort();\n\t\t\texternalSignal?.removeEventListener(\"abort\", cancelFromParent);\n\t\t\tcancellation.signal.removeEventListener(\"abort\", onCancelled);\n\t\t\tthis._rlmQuiescenceWaitAborts.delete(cancellation);\n\t\t}\n\t}\n\n\t// Inline (non-daemon) mode only; daemon clients attach to the child session directly.\n\tgetRlmChildSession(childId: string): AgentSession | undefined {\n\t\tconst direct = this._activeRlmChildRuns.get(childId)?.session ?? this._rlmChildSessions.get(childId);\n\t\tif (direct) {\n\t\t\treturn direct;\n\t\t}\n\t\tfor (const candidate of this._activeRlmChildRuns.values()) {\n\t\t\tconst nested = candidate.session?.getRlmChildSession(childId);\n\t\t\tif (nested) {\n\t\t\t\treturn nested;\n\t\t\t}\n\t\t}\n\t\tfor (const retained of this._rlmChildSessions.values()) {\n\t\t\tconst nested = retained.getRlmChildSession(childId);\n\t\t\tif (nested) {\n\t\t\t\treturn nested;\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Cancel a single RLM child run by id, searching nested child sessions.\n\t *\n\t * @returns true when a live run was cancelled or its unsettled terminal notice\n\t * was suppressed; false when the id is unknown or the run already settled.\n\t */\n\tcancelRlmChildRun(childId: string, reason = \"Cancelled by user\"): boolean {\n\t\tconst run = this._activeRlmChildRuns.get(childId);\n\t\tif (run) {\n\t\t\tif (run.status !== \"running\" && run.status !== \"queued\" && !run.settled) {\n\t\t\t\tif (this._sessionInputPumpSuspended) this._abandonRlmRunForQuiescence(run);\n\t\t\t\telse run.suppressTerminalNotice = true;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn this._cancelRlmChildRun(run, reason);\n\t\t}\n\t\tfor (const candidate of this._activeRlmChildRuns.values()) {\n\t\t\tif (candidate.session?.cancelRlmChildRun(childId, reason)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\tfor (const retained of this._rlmChildSessions.values()) {\n\t\t\tif (retained.cancelRlmChildRun(childId, reason)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate async _assertRlmSubagentSessionNameAvailable(name: string, ignorePendingReservation = false): Promise<void> {\n\t\tconst depth = this._rlmDepth + 1;\n\t\tif (!ignorePendingReservation && this._pendingRlmSubagentSessionNames.has(name)) {\n\t\t\tthrow new Error(formatAgentSessionNameUnavailable(name, depth));\n\t\t}\n\t\tconst localConflict =\n\t\t\t[...this._activeRlmChildRuns.values()].some(\n\t\t\t\t(run) => run.session?.sessionName === name || (!run.session && run.sessionName === name),\n\t\t\t) ||\n\t\t\t[...this._rlmChildSessions.values()].some((session) => session.sessionName === name) ||\n\t\t\t[...this._rlmChildCleanupFailures.values()].some((entry) => entry.session_name === name);\n\t\tif (localConflict) {\n\t\t\tthrow new Error(formatAgentSessionNameUnavailable(name, depth));\n\t\t}\n\t\tconst controller = this._agentMessageController;\n\t\tif (!controller) return;\n\t\tconst input = {\n\t\t\tname,\n\t\t\tdepth,\n\t\t\tparentSessionId: this.sessionId,\n\t\t\tparentSessionPath: this.sessionFile,\n\t\t};\n\t\tif (controller.assertSessionNameAvailable) {\n\t\t\tawait controller.assertSessionNameAvailable(input);\n\t\t\treturn;\n\t\t}\n\t\tconst listed = await controller.listAgents();\n\t\tconst catalog = listed.agents.map(\n\t\t\t(agent): AgentFamilyCatalogEntry => ({\n\t\t\t\tid: agent.sessionId,\n\t\t\t\t...(agent.sessionName ? { name: agent.sessionName } : {}),\n\t\t\t\tdepth: agent.rlmDepth ?? 0,\n\t\t\t\tstatus: agent.status ?? \"idle\",\n\t\t\t\t...(agent.parentSessionId ? { parentSessionId: agent.parentSessionId } : {}),\n\t\t\t\t...(agent.parentSessionPath ? { parentSessionPath: agent.parentSessionPath } : {}),\n\t\t\t\t...(agent.sessionPath ? { sessionPath: agent.sessionPath } : {}),\n\t\t\t}),\n\t\t);\n\t\tassertAgentSessionNameAvailable(catalog, input);\n\t}\n\n\tprivate async _authenticatedRlmModels(): Promise<Model<Api>[]> {\n\t\treturn (await this._modelRegistry.getExecutableModels()).filter((model) => {\n\t\t\tconst status = this._modelRegistry.getProviderAuthStatus(model.provider);\n\t\t\treturn status.source !== \"stale\" && status.label !== \"expired\";\n\t\t});\n\t}\n\n\tasync findRlmModels(query: string, limit: number): Promise<RlmFindModelsResult> {\n\t\treturn {\n\t\t\tmodels: findRlmModelMatches(query, await this._authenticatedRlmModels(), limit),\n\t\t};\n\t}\n\n\tprivate async _resolveRlmSubagentModel(reference: string | undefined): Promise<RlmSubagentModelSelection> {\n\t\tconst parentModel = this.model;\n\t\tif (!parentModel) {\n\t\t\tthrow new Error(formatNoModelSelectedMessage());\n\t\t}\n\t\tif (!reference) {\n\t\t\treturn { model: parentModel };\n\t\t}\n\n\t\tconst normalizedReference = reference.toLowerCase();\n\t\tif (`${parentModel.provider}/${parentModel.id}`.toLowerCase() === normalizedReference) {\n\t\t\treturn { model: parentModel };\n\t\t}\n\t\tconst model = (await this._authenticatedRlmModels()).find(\n\t\t\t(candidate) => `${candidate.provider}/${candidate.id}`.toLowerCase() === normalizedReference,\n\t\t);\n\t\tif (!model) {\n\t\t\tthrow new Error(`Requested subagent model \"${reference}\" is unavailable, unauthenticated, or expired`);\n\t\t}\n\n\t\tconst auth = await this._modelRegistry.getApiKeyAndHeaders(model);\n\t\tif (!auth.ok) {\n\t\t\tthrow new Error(`Requested subagent model \"${reference}\" failed authentication preflight`);\n\t\t}\n\t\treturn { model };\n\t}\n\n\tprivate async _startRlmChildRun(\n\t\tprompt: string,\n\t\tkwargs: Record<string, unknown> = {},\n\t\tspawnCode?: string,\n\t): Promise<RlmSpawnHandle> {\n\t\tconst { name: rawName, model: rawModel, thinking: rawThinking, ...unsupported } = kwargs;\n\t\tconst unsupportedKwargs = Object.keys(unsupported);\n\t\tif (unsupportedKwargs.length > 0) {\n\t\t\tthrow new Error(`Unsupported rlm.run kwargs: ${unsupportedKwargs.sort().join(\", \")}`);\n\t\t}\n\t\tconst requestedSessionName = normalizeRequestedRlmSubagentSessionName(rawName);\n\t\tconst requestedModel = normalizeRequestedRlmSubagentModel(rawModel);\n\t\tconst requestedThinkingLevel = normalizeRequestedRlmSubagentThinkingLevel(rawThinking);\n\t\tif (requestedSessionName) assertDirectAgentMessageTarget(requestedSessionName);\n\t\tif (this._rlmDepth >= this._rlmMaxDepth) {\n\t\t\tthrow new Error(\n\t\t\t\t`RLM recursion depth limit reached (RLM_DEPTH=${this._rlmDepth}, RLM_MAX_DEPTH=${this._rlmMaxDepth})`,\n\t\t\t);\n\t\t}\n\t\tif (requestedSessionName) {\n\t\t\tif (this._pendingRlmSubagentSessionNames.has(requestedSessionName)) {\n\t\t\t\tthrow new Error(formatAgentSessionNameUnavailable(requestedSessionName, this._rlmDepth + 1));\n\t\t\t}\n\t\t\tthis._pendingRlmSubagentSessionNames.add(requestedSessionName);\n\t\t}\n\t\tlet modelSelection: RlmSubagentModelSelection;\n\t\ttry {\n\t\t\tif (requestedSessionName) await this._assertRlmSubagentSessionNameAvailable(requestedSessionName, true);\n\t\t\tmodelSelection = await this._resolveRlmSubagentModel(requestedModel);\n\t\t} finally {\n\t\t\tif (requestedSessionName) this._pendingRlmSubagentSessionNames.delete(requestedSessionName);\n\t\t}\n\t\tif (requestedThinkingLevel !== undefined) {\n\t\t\tconst supported = getSupportedThinkingLevels(modelSelection.model) as ThinkingLevel[];\n\t\t\tif (!supported.includes(requestedThinkingLevel)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Requested thinking level \"${requestedThinkingLevel}\" is not supported by model \"${modelSelection.model.provider}/${modelSelection.model.id}\"; supported levels: ${supported.join(\", \")}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (this._disposed || this._disposing) throw new Error(\"Cannot spawn a subagent after its parent was disposed\");\n\n\t\tconst childSessionDir = this._createChildRlmSessionDir();\n\t\tconst childNodeId = basename(childSessionDir);\n\t\tconst sessionName = requestedSessionName ?? createDefaultRlmSubagentSessionName(prompt, childNodeId);\n\t\tif (!requestedSessionName) await this._assertRlmSubagentSessionNameAvailable(sessionName);\n\t\tconst startedAt = Date.now();\n\t\tconst parentAssistantForUsage = this._findLastAssistantMessage();\n\t\tconst label = rlmChildLabel(prompt);\n\t\tlet answerPreview: string | undefined;\n\t\tlet durationMs: number | undefined;\n\t\tlet toolUseCount = 0;\n\t\tlet runningToolCount = 0;\n\t\tlet activity: RlmChildAgentActivity | undefined;\n\t\tlet childSession: AgentSession | undefined;\n\t\tconst run: RlmChildRun = {\n\t\t\tid: childNodeId,\n\t\t\tprompt,\n\t\t\tsessionName,\n\t\t\tsessionDir: childSessionDir,\n\t\t\tmodel: modelSelection.model,\n\t\t\tstatus: \"queued\",\n\t\t\tsettled: false,\n\t\t\tabort: noopRlmChildAbort,\n\t\t\tpublication: createAgentMessageDeferred(),\n\t\t\tsettlement: createAgentMessageDeferred(),\n\t\t\tdeletionReservation: createAgentMessageDeferred(),\n\t\t};\n\t\tconst throwIfCancelled = () => {\n\t\t\tif (run.status === \"cancelled\") throw new Error(run.error ?? \"RLM child cancelled\");\n\t\t};\n\t\tthis._activeRlmChildRuns.set(run.id, run);\n\t\tthis._unsettledRlmChildRuns.add(run);\n\t\tconst emitChildUpdate = () => {\n\t\t\tconst childModel = childSession?.model ?? modelSelection.model;\n\t\t\tthis._emit({\n\t\t\t\ttype: \"rlm_child_update\",\n\t\t\t\tchild: {\n\t\t\t\t\tid: childNodeId,\n\t\t\t\t\tparentId: this._rlmParentNodeId,\n\t\t\t\t\tsessionName: childSession?.sessionName ?? sessionName,\n\t\t\t\t\tmodel: `${childModel.provider}/${childModel.id}`,\n\t\t\t\t\tlabel,\n\t\t\t\t\tstatus: run.status,\n\t\t\t\t\tdurationMs,\n\t\t\t\t\tanswerPreview,\n\t\t\t\t\ttoolUseCount: toolUseCount > 0 ? toolUseCount : undefined,\n\t\t\t\t\ttokenCount: childSession?._contextTokensForCurrentMessages(),\n\t\t\t\t\trecap: childSession?.getCurrentRecap(),\n\t\t\t\t\tsessionDir: childSessionDir,\n\t\t\t\t\tactivity,\n\t\t\t\t\trepliedSinceTask: childSession?._repliedToParentSinceTask,\n\t\t\t\t\terror: run.error,\n\t\t\t\t},\n\t\t\t});\n\t\t};\n\t\trun.emitUpdate = emitChildUpdate;\n\t\temitChildUpdate();\n\n\t\tconst publishChildSession = (child: AgentSession) => {\n\t\t\tchildSession = child;\n\t\t\tif (this._activeRlmChildRuns.get(run.id) !== run) return;\n\t\t\trun.session = child;\n\t\t\trun.abort = () => void child.abort();\n\t\t\trun.publication.resolve();\n\t\t\t// Cancellation may have been admitted while runtime construction was\n\t\t\t// blocked and run.abort was still a no-op.\n\t\t\tif (run.status === \"cancelled\") run.abort();\n\t\t};\n\t\tconst subagentOptions: CreateRlmSubagentRuntimeOptions = {\n\t\t\t...this._createRlmSubagentRuntimeOptions({\n\t\t\t\tid: childNodeId,\n\t\t\t\tprompt,\n\t\t\t\tsessionName,\n\t\t\t\tspawnCode,\n\t\t\t\tsessionDir: childSessionDir,\n\t\t\t\tmodel: modelSelection.model,\n\t\t\t\tthinkingLevel: requestedThinkingLevel,\n\t\t\t}),\n\t\t\tonSessionPublished: publishChildSession,\n\t\t};\n\n\t\tconst deliverTerminalMessageToParent = async (message: CustomMessage): Promise<void> => {\n\t\t\t// Synthesized lifecycle notices always use the parent's private durable\n\t\t\t// path. Explicit child replies continue through agent_message separately.\n\t\t\tawait this._deferRlmTerminalNotice(message);\n\t\t};\n\n\t\trun.reportDeletionCleanupFailure = (error) => {\n\t\t\tif (run.suppressTerminalNotice || this._disposed || this._disposing) return Promise.resolve();\n\t\t\tconst cleanupError = error instanceof Error ? error.message : String(error);\n\t\t\treturn deliverTerminalMessageToParent(\n\t\t\t\tcreateRlmChildFailureMessage({\n\t\t\t\t\tchildId: run.id,\n\t\t\t\t\tsessionName,\n\t\t\t\t\terror: `Deletion cleanup failed; retry rlm.delete_subagent(\"${run.id}\") before completion: ${cleanupError}`,\n\t\t\t\t}),\n\t\t\t);\n\t\t};\n\n\t\t// Runtime startup and the task run are deliberately detached. The public\n\t\t// spawn resolves at admission, while this task owns live tracking, usage,\n\t\t// retention, cancellation, and late-startup cleanup.\n\t\tvoid (async () => {\n\t\t\tlet childRuntime: RlmSubagentRuntime | undefined;\n\t\t\ttry {\n\t\t\t\tchildRuntime = await this._createRlmSubagentRuntime(subagentOptions);\n\t\t\t\tconst child = childRuntime.session;\n\t\t\t\tif (run.status === \"cancelled\") throw new Error(run.error ?? \"RLM child cancelled\");\n\t\t\t\tif (child.sessionName !== sessionName) child.setSessionName(sessionName);\n\t\t\t\tpublishChildSession(child);\n\t\t\t\tthrowIfCancelled();\n\t\t\t\trun.status = \"running\";\n\t\t\t\temitChildUpdate();\n\t\t\t\tconst unsubscribeChildEvents = child.subscribe((event) => {\n\t\t\t\t\tif (event.type === \"rlm_child_update\") {\n\t\t\t\t\t\tthis._emit(event);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (event.type === \"agent_start\") {\n\t\t\t\t\t\tactivity = { kind: \"waiting\" };\n\t\t\t\t\t\temitChildUpdate();\n\t\t\t\t\t} else if (event.type === \"agent_end\") {\n\t\t\t\t\t\tactivity = undefined;\n\t\t\t\t\t\temitChildUpdate();\n\t\t\t\t\t} else if (event.type === \"message_end\" && event.message.role === \"assistant\") {\n\t\t\t\t\t\tconst assistant = event.message as AssistantMessage;\n\t\t\t\t\t\tif (assistant.stopReason !== \"error\" && assistant.stopReason !== \"aborted\") {\n\t\t\t\t\t\t\tattributeChildUsage(parentAssistantForUsage?.usage ?? emptyUsage(), assistant.usage);\n\t\t\t\t\t\t\tif (parentAssistantForUsage) {\n\t\t\t\t\t\t\t\tconst parentEntry = this._findAssistantEntryForMessage(parentAssistantForUsage);\n\t\t\t\t\t\t\t\tif (parentEntry) {\n\t\t\t\t\t\t\t\t\tconst messages = child.messages;\n\t\t\t\t\t\t\t\t\tconst assistantIndex = messages.lastIndexOf(assistant);\n\t\t\t\t\t\t\t\t\tconst precedingPrompt = messages\n\t\t\t\t\t\t\t\t\t\t.slice(0, assistantIndex)\n\t\t\t\t\t\t\t\t\t\t.reverse()\n\t\t\t\t\t\t\t\t\t\t.find((message) => message.role === \"user\" || message.role === \"custom\");\n\t\t\t\t\t\t\t\t\tconst origin =\n\t\t\t\t\t\t\t\t\t\tprecedingPrompt?.role === \"custom\" && isAgentSessionMessage(precedingPrompt)\n\t\t\t\t\t\t\t\t\t\t\t? precedingPrompt.details.id.startsWith(\"spawn:\")\n\t\t\t\t\t\t\t\t\t\t\t\t? \"spawn_task\"\n\t\t\t\t\t\t\t\t\t\t\t\t: \"agent_message\"\n\t\t\t\t\t\t\t\t\t\t\t: \"direct_user\";\n\t\t\t\t\t\t\t\t\tthis.sessionManager.appendChildUsageAttribution(\n\t\t\t\t\t\t\t\t\t\tparentEntry.id,\n\t\t\t\t\t\t\t\t\t\tassistant.usage,\n\t\t\t\t\t\t\t\t\t\tparentAssistantForUsage.usage,\n\t\t\t\t\t\t\t\t\t\torigin,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst text = compactRlmText(readAssistantText(assistant));\n\t\t\t\t\t\tif (text) answerPreview = text;\n\t\t\t\t\t\tvoid flushAgentTraceUpload(child.sessionManager).catch(() => undefined);\n\t\t\t\t\t\temitChildUpdate();\n\t\t\t\t\t} else if (event.type === \"message_start\" || event.type === \"message_update\") {\n\t\t\t\t\t\tif (event.message.role === \"assistant\") {\n\t\t\t\t\t\t\tconst text = compactRlmText(readAssistantText(event.message as AssistantMessage));\n\t\t\t\t\t\t\tif (text) answerPreview = text;\n\t\t\t\t\t\t\tactivity = { kind: \"writing\" };\n\t\t\t\t\t\t\temitChildUpdate();\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (event.type === \"tool_execution_start\") {\n\t\t\t\t\t\ttoolUseCount += 1;\n\t\t\t\t\t\trunningToolCount += 1;\n\t\t\t\t\t\tactivity = { kind: \"executing\", toolName: event.toolName };\n\t\t\t\t\t\temitChildUpdate();\n\t\t\t\t\t} else if (event.type === \"tool_execution_end\") {\n\t\t\t\t\t\trunningToolCount = Math.max(0, runningToolCount - 1);\n\t\t\t\t\t\tif (runningToolCount === 0) activity = { kind: \"waiting\" };\n\t\t\t\t\t\temitChildUpdate();\n\t\t\t\t\t} else if (event.type === \"session_info_changed\" || event.type === \"recap_update\") {\n\t\t\t\t\t\temitChildUpdate();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\trun.unsubscribe = unsubscribeChildEvents;\n\t\t\t\tconst content = `[task from parent]\\n\\n${prompt}`;\n\t\t\t\tconst spawnMessage: AgentSessionMessage = {\n\t\t\t\t\trole: \"custom\",\n\t\t\t\t\tcustomType: AGENT_MESSAGE_CUSTOM_TYPE,\n\t\t\t\t\tcontent,\n\t\t\t\t\tdisplay: true,\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\tid: `spawn:${run.id}`,\n\t\t\t\t\t\tmessage: prompt,\n\t\t\t\t\t\tfrom: {\n\t\t\t\t\t\t\tsessionId: this.sessionId,\n\t\t\t\t\t\t\tsessionName: this.sessionName,\n\t\t\t\t\t\t\tactiveSessionId: await this._currentActiveSessionId(),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfromRelationship: \"parent\",\n\t\t\t\t\t},\n\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t};\n\t\t\t\tthrowIfCancelled();\n\t\t\t\tconst parentReplyCountBeforeRun = child._parentReplyCount;\n\t\t\t\tawait child.promptAndWait(content, {\n\t\t\t\t\texpandPromptTemplates: false,\n\t\t\t\t\tsource: \"extension\",\n\t\t\t\t\tcustomMessage: spawnMessage,\n\t\t\t\t});\n\t\t\t\tawait child.waitForRlmQuiescence();\n\t\t\t\tif (run.error) throw new Error(run.error);\n\t\t\t\trun.status = \"done\";\n\t\t\t\tdurationMs = Date.now() - startedAt;\n\t\t\t\tactivity = undefined;\n\t\t\t\temitChildUpdate();\n\t\t\t\tif (\n\t\t\t\t\t!run.detachedDeletion &&\n\t\t\t\t\t!run.suppressTerminalNotice &&\n\t\t\t\t\tchild._parentReplyCount === parentReplyCountBeforeRun\n\t\t\t\t) {\n\t\t\t\t\tconst lastAssistantText = child.getLastAssistantText();\n\t\t\t\t\tawait deliverTerminalMessageToParent(\n\t\t\t\t\t\tcreateRlmChildTerminalNoticeMessage({\n\t\t\t\t\t\t\tkind: \"completed_without_reply\",\n\t\t\t\t\t\t\tchildId: run.id,\n\t\t\t\t\t\t\tsessionName,\n\t\t\t\t\t\t\tlastAssistantTextPreview: lastAssistantText ? compactRlmText(lastAssistantText) : undefined,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (!this.registerRlmChildSession(run.id, child) && !run.detachedDeletion) {\n\t\t\t\t\tif (childRuntime && this._subagentRuntimeHost?.releaseRlmSubagentRuntime) {\n\t\t\t\t\t\tawait this._subagentRuntimeHost\n\t\t\t\t\t\t\t.releaseRlmSubagentRuntime(childRuntime, subagentOptions, \"error\")\n\t\t\t\t\t\t\t.catch(() => void child.disposeAsync().catch(() => undefined));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tawait child.disposeAsync().catch(() => undefined);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst runError = error instanceof Error ? error : new Error(String(error));\n\t\t\t\trun.publication.reject(runError);\n\t\t\t\tif (run.status !== \"cancelled\") {\n\t\t\t\t\trun.status = \"error\";\n\t\t\t\t\trun.error = runError.message;\n\t\t\t\t}\n\t\t\t\tdurationMs = Date.now() - startedAt;\n\t\t\t\tactivity = undefined;\n\t\t\t\temitChildUpdate();\n\t\t\t\tif (!run.detachedDeletion && !run.suppressTerminalNotice) {\n\t\t\t\t\tif (run.status === \"error\") {\n\t\t\t\t\t\tawait deliverTerminalMessageToParent(\n\t\t\t\t\t\t\tcreateRlmChildFailureMessage({\n\t\t\t\t\t\t\t\tchildId: run.id,\n\t\t\t\t\t\t\t\tsessionName,\n\t\t\t\t\t\t\t\terror: run.error ?? \"unknown error\",\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t} else if (run.status === \"cancelled\") {\n\t\t\t\t\t\tawait deliverTerminalMessageToParent(\n\t\t\t\t\t\t\tcreateRlmChildTerminalNoticeMessage({\n\t\t\t\t\t\t\t\tkind: \"cancelled\",\n\t\t\t\t\t\t\t\tchildId: run.id,\n\t\t\t\t\t\t\t\tsessionName,\n\t\t\t\t\t\t\t\treason: run.error,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!run.detachedDeletion && childSession && this._subagentRuntimeHost?.releaseRlmSubagentRuntime) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait this._subagentRuntimeHost.releaseRlmSubagentRuntime(\n\t\t\t\t\t\t\tchildRuntime ?? { session: childSession },\n\t\t\t\t\t\t\tsubagentOptions,\n\t\t\t\t\t\t\trun.status === \"cancelled\" ? \"cancelled\" : \"error\",\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (run.status === \"cancelled\" && !this._disposed && !this._disposing) {\n\t\t\t\t\t\t\tthis._deletedRlmChildIds.add(run.id);\n\t\t\t\t\t\t\tthis._removeRlmSubagentTracking(run.id);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tawait childSession?.disposeAsync().catch(() => undefined);\n\t\t\t\t\t}\n\t\t\t\t} else if (!run.detachedDeletion) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (childRuntime && this._subagentRuntimeHost) {\n\t\t\t\t\t\t\tawait this._subagentRuntimeHost.deleteRlmSubagentRuntime(run.id, childRuntime.session);\n\t\t\t\t\t\t} else if (childSession) {\n\t\t\t\t\t\t\tawait childSession.disposeAsync();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (run.status === \"cancelled\" && !this._disposed && !this._disposing) {\n\t\t\t\t\t\t\tthis._deletedRlmChildIds.add(run.id);\n\t\t\t\t\t\t\tthis._removeRlmSubagentTracking(run.id);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// A failed best-effort retry remains available through the retained cleanup maps.\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tif (run.detachedDeletion) {\n\t\t\t\t\trun.deletionRunFinished = true;\n\t\t\t\t\tif (!run.settled) {\n\t\t\t\t\t\tlet cleanupSucceeded = !run.deletionCleanupFailed;\n\t\t\t\t\t\tif (childRuntime && cleanupSucceeded) {\n\t\t\t\t\t\t\tconst cleanup =\n\t\t\t\t\t\t\t\trun.deletionCleanup ?? this._ensureRlmRunDeletionCleanup(run, childRuntime.session);\n\t\t\t\t\t\t\tcleanupSucceeded = await this._observeRlmRunDeletionCleanup(\n\t\t\t\t\t\t\t\trun,\n\t\t\t\t\t\t\t\trun.detachedDeletion,\n\t\t\t\t\t\t\t\tchildRuntime.session,\n\t\t\t\t\t\t\t\tcleanup,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (cleanupSucceeded) await this._finishRlmRunDeletion(run);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (this._activeRlmChildRuns.get(run.id) === run) {\n\t\t\t\t\t\tif (this._rlmChildSessions.has(run.id)) {\n\t\t\t\t\t\t\tthis._activeRlmChildRuns.delete(run.id);\n\t\t\t\t\t\t\tif (run.unsubscribe) this._rlmChildUnsubscribes.set(run.id, run.unsubscribe);\n\t\t\t\t\t\t\trun.abort = noopRlmChildAbort;\n\t\t\t\t\t\t\trun.unsubscribe = undefined;\n\t\t\t\t\t\t\trun.session = undefined;\n\t\t\t\t\t\t} else if (run.status !== \"error\") {\n\t\t\t\t\t\t\tthis._removeRlmSubagentTracking(run.id, run);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\trun.unsubscribe?.();\n\t\t\t\t\t\t\trun.abort = noopRlmChildAbort;\n\t\t\t\t\t\t\trun.unsubscribe = undefined;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\trun.settled = true;\n\t\t\t\t\trun.settlement.resolve();\n\t\t\t\t\tthis._unsettledRlmChildRuns.delete(run);\n\t\t\t\t\tthis._maybeResumeGoalContinuationAfterRlmWork();\n\t\t\t\t}\n\t\t\t}\n\t\t})().catch(() => undefined);\n\n\t\treturn {\n\t\t\trlm_child_id: childNodeId,\n\t\t\tname: sessionName,\n\t\t\tsession_dir: childSessionDir,\n\t\t\tmodel: `${modelSelection.model.provider}/${modelSelection.model.id}`,\n\t\t};\n\t}\n\n\tasync runRlmChild(\n\t\tprompt: string,\n\t\tkwargs: Record<string, unknown> = {},\n\t\tspawnCode?: string,\n\t): Promise<RlmSpawnHandle> {\n\t\treturn this._startRlmChildRun(prompt, kwargs, spawnCode);\n\t}\n\n\tprivate _isRetryableError(message: AssistantMessage): boolean {\n\t\tif (message.stopReason !== \"error\" || !message.errorMessage) return false;\n\n\t\tconst contextWindow = this.model?.contextWindow ?? 0;\n\t\tif (isContextOverflow(message, contextWindow)) return false;\n\n\t\tif (this._isFauxProviderQueueExhausted(message)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (this._isAgentLifecycleFailure(message)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (this._isStructuredPermanentProviderRetryExhausted(message)) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tprivate _isFauxProviderQueueExhausted(message: AssistantMessage): boolean {\n\t\treturn message.provider === \"faux\" && message.errorMessage === \"No more faux responses queued\";\n\t}\n\n\tprivate _isAgentLifecycleFailure(message: AssistantMessage): boolean {\n\t\treturn message.diagnostics?.some((diagnostic) => diagnostic.type === \"agent_lifecycle_failure\") ?? false;\n\t}\n\n\tprivate _getProviderStreamFailureDetails(message: AssistantMessage): Record<string, unknown> | undefined {\n\t\tconst failure = message.diagnostics?.find((diagnostic) => diagnostic.type === \"provider_stream_failure\");\n\t\tconst details = failure?.details;\n\t\tif (!details || typeof details !== \"object\") {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn details;\n\t}\n\n\tprivate _getProviderStreamFailureKind(message: AssistantMessage): string | undefined {\n\t\tconst kind = this._getProviderStreamFailureDetails(message)?.kind;\n\t\treturn typeof kind === \"string\" ? kind : undefined;\n\t}\n\n\tprivate _isStructuredPermanentProviderFailure(message: AssistantMessage): boolean {\n\t\tconst kind = this._getProviderStreamFailureKind(message);\n\t\treturn kind === \"auth\" || kind === \"invalid_request\" || kind === \"refusal\";\n\t}\n\n\tprivate _isStructuredPermanentProviderRetryExhausted(message: AssistantMessage): boolean {\n\t\treturn this._retryAttempt > 0 && this._isStructuredPermanentProviderFailure(message);\n\t}\n\n\tprivate _getProviderStreamFailureAuthStatus(message: AssistantMessage): number | undefined {\n\t\tconst details = this._getProviderStreamFailureDetails(message);\n\t\tif (!details) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst kind = details.kind;\n\t\tif (kind !== \"auth\") {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst status = details.status;\n\t\tif (typeof status === \"number\") {\n\t\t\treturn status;\n\t\t}\n\t\tif (typeof status === \"string\") {\n\t\t\tconst parsed = Number(status);\n\t\t\treturn Number.isInteger(parsed) ? parsed : undefined;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate _isConcreteProviderAuthFailure(message: AssistantMessage): boolean {\n\t\tif (message.stopReason !== \"error\" || !message.errorMessage) return false;\n\n\t\tconst structuredStatus = this._getProviderStreamFailureAuthStatus(message);\n\t\tif (structuredStatus === 401 || structuredStatus === 403) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (/\\b(?:401|403)\\b/.test(message.errorMessage) && /\\bstatus code\\b/i.test(message.errorMessage)) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn (\n\t\t\t/\\b(?:401|403)\\b/.test(message.errorMessage) &&\n\t\t\t/auth|unauthori[sz]ed|forbidden|api.?key|token|credential/i.test(message.errorMessage)\n\t\t);\n\t}\n\n\tprivate _captureRetryAuthFailureSource(message: AssistantMessage): AuthSourceToken | undefined {\n\t\tconst token = this._modelRegistry.getCurrentProviderAuthSourceToken(message.provider);\n\t\tif (!token) {\n\t\t\treturn undefined;\n\t\t}\n\t\tif (\n\t\t\t!this._retryAuthFailureSources.some(\n\t\t\t\t(existing) =>\n\t\t\t\t\texisting.provider === token.provider &&\n\t\t\t\t\texisting.source === token.source &&\n\t\t\t\t\texisting.identityFingerprint === token.identityFingerprint &&\n\t\t\t\t\texisting.valueFingerprint === token.valueFingerprint,\n\t\t\t)\n\t\t) {\n\t\t\tthis._retryAuthFailureSources.push(token);\n\t\t}\n\t\treturn token;\n\t}\n\n\tprivate _markProviderAuthStale(message: AssistantMessage, authSourceTokens?: readonly AuthSourceToken[]): boolean {\n\t\tif (authSourceTokens && authSourceTokens.length > 0) {\n\t\t\tlet marked = false;\n\t\t\tfor (const token of authSourceTokens) {\n\t\t\t\tmarked = this._modelRegistry.markProviderAuthSourceStale(token) || marked;\n\t\t\t}\n\t\t\tif (marked) {\n\t\t\t\tthis._emit({\n\t\t\t\t\ttype: \"auth_stale\",\n\t\t\t\t\tprovider: message.provider,\n\t\t\t\t\tsourceTokens: authSourceTokens,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn marked;\n\t\t}\n\t\tconst marked = this._modelRegistry.markProviderAuthStale(message.provider);\n\t\tif (marked) {\n\t\t\tthis._emit({ type: \"auth_stale\", provider: message.provider });\n\t\t}\n\t\treturn marked;\n\t}\n\n\tprivate _markProviderAuthStaleForRetryFailure(\n\t\tmessage: AssistantMessage,\n\t\toptions?: {\n\t\t\tmarkAuthStaleOnFailure?: boolean;\n\t\t\tauthSourceTokens?: readonly AuthSourceToken[];\n\t\t},\n\t): boolean {\n\t\tconst authSourceTokens =\n\t\t\tthis._retryAuthFailureSources.length > 0 ? this._retryAuthFailureSources : options?.authSourceTokens;\n\t\tif ((authSourceTokens?.length ?? 0) > 0 || options?.markAuthStaleOnFailure) {\n\t\t\tconst marked = this._markProviderAuthStale(message, authSourceTokens);\n\t\t\tif (marked && message.errorMessage) {\n\t\t\t\tmessage.errorMessage = addLoginGuidanceToAuthError(message.errorMessage);\n\t\t\t}\n\t\t\treturn marked;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate _finishActiveRetryWithFailure(message: AssistantMessage): void {\n\t\tif (this._retryAttempt === 0) {\n\t\t\treturn;\n\t\t}\n\t\tthis._markProviderAuthStaleForRetryFailure(message);\n\t\tthis._emit({\n\t\t\ttype: \"auto_retry_end\",\n\t\t\tsuccess: false,\n\t\t\tattempt: this._retryAttempt,\n\t\t\tfinalError: message.errorMessage,\n\t\t});\n\t\tthis._retryAttempt = 0;\n\t\tthis._retryAuthFailureSources = [];\n\t}\n\n\tprivate async _handleRetryableError(\n\t\tmessage: AssistantMessage,\n\t\toptions?: {\n\t\t\tmarkAuthStaleOnFailure?: boolean;\n\t\t\tauthSourceTokens?: readonly AuthSourceToken[];\n\t\t},\n\t): Promise<boolean> {\n\t\tconst settings = this.settingsManager.getRetrySettings();\n\t\tif (!settings.enabled) {\n\t\t\tthis._markProviderAuthStaleForRetryFailure(message, options);\n\t\t\tthis._retryAuthFailureSources = [];\n\t\t\tthis._resolveRetry();\n\t\t\treturn false;\n\t\t}\n\n\t\tif (!this._retryPromise) {\n\t\t\tthis._retryPromise = new Promise((resolve) => {\n\t\t\t\tthis._retryResolve = resolve;\n\t\t\t});\n\t\t}\n\n\t\tthis._retryAttempt++;\n\n\t\tif (this._retryAttempt > settings.maxRetries) {\n\t\t\tthis._markProviderAuthStaleForRetryFailure(message, options);\n\t\t\tthis._emit({\n\t\t\t\ttype: \"auto_retry_end\",\n\t\t\t\tsuccess: false,\n\t\t\t\tattempt: this._retryAttempt - 1,\n\t\t\t\tfinalError: message.errorMessage,\n\t\t\t});\n\t\t\tthis._retryAttempt = 0;\n\t\t\tthis._retryAuthFailureSources = [];\n\t\t\tthis._resolveRetry(); // Resolve so waitForRetry() completes\n\t\t\treturn false;\n\t\t}\n\n\t\tconst delayMs = settings.baseDelayMs * 2 ** (this._retryAttempt - 1);\n\n\t\tthis._emit({\n\t\t\ttype: \"auto_retry_start\",\n\t\t\tattempt: this._retryAttempt,\n\t\t\tmaxAttempts: settings.maxRetries,\n\t\t\tdelayMs,\n\t\t\terrorMessage: message.errorMessage || \"Unknown error\",\n\t\t});\n\n\t\tconst messages = this.agent.state.messages;\n\t\tif (messages.length > 0 && messages[messages.length - 1].role === \"assistant\") {\n\t\t\tthis.agent.state.messages = messages.slice(0, -1);\n\t\t}\n\n\t\tthis._retryAbortController = new AbortController();\n\t\ttry {\n\t\t\tawait sleep(delayMs, this._retryAbortController.signal);\n\t\t} catch {\n\t\t\tconst attempt = this._retryAttempt;\n\t\t\tthis._markProviderAuthStaleForRetryFailure(message, options);\n\t\t\tthis._retryAttempt = 0;\n\t\t\tthis._retryAbortController = undefined;\n\t\t\tthis._emit({\n\t\t\t\ttype: \"auto_retry_end\",\n\t\t\t\tsuccess: false,\n\t\t\t\tattempt,\n\t\t\t\tfinalError: \"Retry cancelled\",\n\t\t\t});\n\t\t\tthis._resolveRetry();\n\t\t\tthis._retryAuthFailureSources = [];\n\t\t\treturn false;\n\t\t}\n\t\tthis._retryAbortController = undefined;\n\n\t\tsetTimeout(() => {\n\t\t\tthis.agent.continue().catch(() => {});\n\t\t}, 0);\n\n\t\treturn true;\n\t}\n\n\tabortRetry(): void {\n\t\tif (this._retryAbortController) {\n\t\t\tthis._retryAbortController.abort();\n\t\t\treturn;\n\t\t}\n\t\tif (this._retryAttempt > 0) {\n\t\t\tthis._autoCompactionAbortController?.abort();\n\t\t\tthis._cancelPostCompactionContinue();\n\t\t\tthis._emit({\n\t\t\t\ttype: \"auto_retry_end\",\n\t\t\t\tsuccess: false,\n\t\t\t\tattempt: this._retryAttempt,\n\t\t\t\tfinalError: \"Retry cancelled\",\n\t\t\t});\n\t\t\tthis._retryAttempt = 0;\n\t\t}\n\t\tthis._retryAuthFailureSources = [];\n\t\tthis._resolveRetry();\n\t}\n\n\tprivate async waitForRetry(): Promise<void> {\n\t\tif (!this._retryPromise) {\n\t\t\treturn;\n\t\t}\n\n\t\tawait this._retryPromise;\n\t\tawait this.agent.waitForIdle();\n\t}\n\n\tget isRetrying(): boolean {\n\t\treturn this._retryPromise !== undefined;\n\t}\n\n\tget hasAcceptedPromptInFlight(): boolean {\n\t\treturn this._actionStore\n\t\t\t.unfinishedActions()\n\t\t\t.some(\n\t\t\t\t(action) =>\n\t\t\t\t\taction.payload.kind === \"turn\" &&\n\t\t\t\t\t!action.payload.queueVisible &&\n\t\t\t\t\taction.payload.acceptedBeforeCompletion,\n\t\t\t);\n\t}\n\n\tget autoRetryEnabled(): boolean {\n\t\treturn this.settingsManager.getRetryEnabled();\n\t}\n\n\tsetAutoRetryEnabled(enabled: boolean): void {\n\t\tthis.settingsManager.setRetryEnabled(enabled);\n\t}\n\n\t/**\n\t * Execute a bash command.\n\t * Adds result to agent context and session.\n\t * @param command The bash command to execute\n\t * @param onChunk Optional streaming callback for output\n\t * @param options.excludeFromContext If true, command output won't be sent to LLM (!! prefix)\n\t * @param options.operations Custom BashOperations for remote execution\n\t */\n\tasync executeBash(\n\t\tcommand: string,\n\t\tonChunk?: (chunk: string) => void,\n\t\toptions?: {\n\t\t\texcludeFromContext?: boolean;\n\t\t\toperations?: BashOperations;\n\t\t\ttransient?: boolean;\n\t\t},\n\t): Promise<BashResult> {\n\t\tthis._bashAbortController = new AbortController();\n\n\t\tconst prefix = this.settingsManager.getShellCommandPrefix();\n\t\tconst shellPath = this.settingsManager.getShellPath();\n\t\tconst resolvedCommand = prefix ? `${prefix}\\n${command}` : command;\n\n\t\ttry {\n\t\t\tconst result = await executeBashWithOperations(\n\t\t\t\tresolvedCommand,\n\t\t\t\tthis.sessionManager.getCwd(),\n\t\t\t\toptions?.operations ?? createLocalBashOperations({ shellPath }),\n\t\t\t\t{\n\t\t\t\t\tonChunk,\n\t\t\t\t\tsignal: this._bashAbortController.signal,\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tif (!options?.transient) {\n\t\t\t\tthis.recordBashResult(command, result, options);\n\t\t\t}\n\t\t\treturn result;\n\t\t} finally {\n\t\t\tthis._bashAbortController = undefined;\n\t\t}\n\t}\n\n\t/**\n\t * Run a user-initiated bash command (! / !! prefix), emitting bash_start,\n\t * bash_output, and bash_end session events so any attached client can render\n\t * streaming output. Extensions can intercept execution via the user_bash event.\n\t * Execution failures are reported through bash_end rather than a rejected promise;\n\t * only the already-running guard and extension dispatch errors reject.\n\t * @param command The bash command to execute\n\t * @param options.excludeFromContext If true, command output won't be sent to LLM (!! prefix)\n\t */\n\tasync runUserBash(\n\t\tcommand: string,\n\t\toptions?: {\n\t\t\texcludeFromContext?: boolean;\n\t\t\ttransient?: boolean;\n\t\t\trunId?: string;\n\t\t},\n\t): Promise<void> {\n\t\tif (this.isBashRunning) {\n\t\t\tthrow new Error(\"A bash command is already running\");\n\t\t}\n\t\t// Claim the bash slot synchronously: isBashRunning is otherwise false until\n\t\t// executeBash installs its abort controller, which would let a second command\n\t\t// slip through during the user_bash extension dispatch below.\n\t\tthis._userBashRunning = true;\n\t\tthis._userBashAbortRequested = false;\n\t\t// Echoed on bash_start/bash_end so the requesting client can tell its own\n\t\t// run apart from other clients' runs broadcast on the same session.\n\t\tconst identity = {\n\t\t\t...(options?.transient ? { transient: true } : {}),\n\t\t\t...(options?.runId !== undefined ? { runId: options.runId } : {}),\n\t\t};\n\t\tlet end: UserBashEndDetails;\n\t\ttry {\n\t\t\tend = await this.runUserBashLocked(\n\t\t\t\tcommand,\n\t\t\t\toptions?.excludeFromContext ?? false,\n\t\t\t\toptions?.transient ?? false,\n\t\t\t\tidentity,\n\t\t\t);\n\t\t} finally {\n\t\t\tthis._userBashRunning = false;\n\t\t}\n\t\t// Emitted after the slot is released so clients never observe a bash_end\n\t\t// while the session still rejects new commands as already running.\n\t\tthis._emit({ type: \"bash_end\", ...end, ...identity });\n\t\tvoid this._drainQueuedMessagesAfterBash().catch(() => undefined);\n\t}\n\n\tprivate async _drainQueuedMessagesAfterBash(): Promise<void> {\n\t\tawait this.agent.waitForIdle();\n\t\tthis._scheduleSessionInputPump();\n\t}\n\n\tprivate async runUserBashLocked(\n\t\tcommand: string,\n\t\texcludeFromContext: boolean,\n\t\ttransient: boolean,\n\t\tidentity: { transient?: boolean; runId?: string },\n\t): Promise<UserBashEndDetails> {\n\t\tconst eventResult = await this._extensionRunner.emitUserBash({\n\t\t\ttype: \"user_bash\",\n\t\t\tcommand,\n\t\t\texcludeFromContext,\n\t\t\tcwd: this.sessionManager.getCwd(),\n\t\t});\n\n\t\t// Transient runs (side-conversation bash) live only in their pane: they\n\t\t// are never recorded, so reloads and rebuilds cannot resurface them.\n\t\tconst record = transient\n\t\t\t? () => {}\n\t\t\t: (result: BashResult) => this.recordBashResult(command, result, { excludeFromContext });\n\n\t\tthis._emit({\n\t\t\ttype: \"bash_start\",\n\t\t\tcommand,\n\t\t\texcludeFromContext,\n\t\t\t...identity,\n\t\t});\n\t\ttry {\n\t\t\t// If an extension returned a full result, surface it without executing\n\t\t\tif (eventResult?.result) {\n\t\t\t\tconst result = eventResult.result;\n\t\t\t\tif (result.output) {\n\t\t\t\t\tthis._emit({ type: \"bash_output\", chunk: result.output });\n\t\t\t\t}\n\t\t\t\trecord(result);\n\t\t\t\treturn {\n\t\t\t\t\texitCode: result.exitCode,\n\t\t\t\t\tcancelled: result.cancelled,\n\t\t\t\t\ttruncated: result.truncated,\n\t\t\t\t\tfullOutputPath: result.fullOutputPath,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// An abort that arrived before the process spawned (during extension\n\t\t\t// dispatch) has no abort controller to act on; honor it here instead.\n\t\t\tif (this._userBashAbortRequested) {\n\t\t\t\trecord({\n\t\t\t\t\toutput: \"\",\n\t\t\t\t\texitCode: undefined,\n\t\t\t\t\tcancelled: true,\n\t\t\t\t\ttruncated: false,\n\t\t\t\t});\n\t\t\t\treturn { exitCode: undefined, cancelled: true, truncated: false };\n\t\t\t}\n\n\t\t\tconst result = await this.executeBash(command, (chunk) => this._emit({ type: \"bash_output\", chunk }), {\n\t\t\t\texcludeFromContext,\n\t\t\t\toperations: eventResult?.operations,\n\t\t\t\ttransient,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\texitCode: result.exitCode,\n\t\t\t\tcancelled: result.cancelled,\n\t\t\t\ttruncated: result.truncated,\n\t\t\t\tfullOutputPath: result.fullOutputPath,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : String(error);\n\t\t\t// Persist the failure like every other outcome so replayed transcripts\n\t\t\t// and the LLM context reflect that the command did not run.\n\t\t\trecord({\n\t\t\t\toutput: `bash failed: ${errorMessage}`,\n\t\t\t\texitCode: undefined,\n\t\t\t\tcancelled: false,\n\t\t\t\ttruncated: false,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\texitCode: undefined,\n\t\t\t\tcancelled: false,\n\t\t\t\ttruncated: false,\n\t\t\t\terrorMessage,\n\t\t\t};\n\t\t}\n\t}\n\n\trecordBashResult(command: string, result: BashResult, options?: { excludeFromContext?: boolean }): void {\n\t\tconst bashMessage: BashExecutionMessage = {\n\t\t\trole: \"bashExecution\",\n\t\t\tcommand,\n\t\t\toutput: result.output,\n\t\t\texitCode: result.exitCode,\n\t\t\tcancelled: result.cancelled,\n\t\t\ttruncated: result.truncated,\n\t\t\tfullOutputPath: result.fullOutputPath,\n\t\t\ttimestamp: Date.now(),\n\t\t\texcludeFromContext: options?.excludeFromContext,\n\t\t};\n\n\t\t// If agent is streaming, defer adding to avoid breaking tool_use/tool_result ordering\n\t\tif (this.isStreaming) {\n\t\t\tthis._pendingBashMessages.push(bashMessage);\n\t\t} else {\n\t\t\tthis.agent.state.messages.push(bashMessage);\n\n\t\t\tthis.sessionManager.appendMessage(bashMessage);\n\t\t}\n\t}\n\n\t/**\n\t * Cancel running bash command.\n\t */\n\tabortBash(): void {\n\t\t// A user bash command may not have spawned yet (extension dispatch in\n\t\t// progress); flag the request so runUserBash cancels before executing.\n\t\tif (this._userBashRunning && this._bashAbortController === undefined) {\n\t\t\tthis._userBashAbortRequested = true;\n\t\t}\n\t\tthis._bashAbortController?.abort();\n\t}\n\n\tget isBashRunning(): boolean {\n\t\treturn this._bashAbortController !== undefined || this._userBashRunning;\n\t}\n\n\t/** Whether there are pending bash messages waiting to be flushed */\n\tget hasPendingBashMessages(): boolean {\n\t\treturn this._pendingBashMessages.length > 0;\n\t}\n\n\t/**\n\t * Flush pending bash messages to agent state and session.\n\t * Called after agent turn completes to maintain proper message ordering.\n\t */\n\tprivate _flushPendingBashMessages(): void {\n\t\tif (this._pendingBashMessages.length === 0) return;\n\n\t\tfor (const bashMessage of this._pendingBashMessages) {\n\t\t\tthis.agent.state.messages.push(bashMessage);\n\n\t\t\tthis.sessionManager.appendMessage(bashMessage);\n\t\t}\n\n\t\tthis._pendingBashMessages = [];\n\t}\n\n\tgetRlmMaxDepthStatus(): RlmMaxDepthStatus {\n\t\treturn { maxDepth: this._rlmMaxDepth, source: this._rlmMaxDepthSource };\n\t}\n\n\tasync setRlmMaxDepth(maxDepth: number, options: { global?: boolean } = {}): Promise<SetRlmMaxDepthResult> {\n\t\tif (!isNonNegativeInteger(maxDepth)) {\n\t\t\tthrow new Error(\"RLM max depth must be a non-negative integer.\");\n\t\t}\n\n\t\tthis.sessionManager.appendCustomEntryWithRollback(RLM_MAX_DEPTH_STATE_CUSTOM_TYPE, { maxDepth });\n\t\tthis._rlmMaxDepth = maxDepth;\n\t\tthis._rlmMaxDepthSource = \"chat\";\n\t\tconst oldBase = this._baseSystemPrompt;\n\t\tthis._baseSystemPrompt = this._rebuildSystemPrompt(this.getActiveToolNames());\n\t\tthis.agent.state.systemPrompt = this._refreshExtensionSystemPrompt(this.agent.state.systemPrompt, oldBase);\n\n\t\tlet globalError: string | undefined;\n\t\tif (options.global) {\n\t\t\tawait this.settingsManager.flush();\n\t\t\tconst staleErrors = this.settingsManager.drainErrors(\"global\");\n\t\t\tfor (const { error } of staleErrors) {\n\t\t\t\tconsole.warn(`Warning: Earlier global settings write failed: ${error.message}`);\n\t\t\t}\n\t\t\tthis.settingsManager.setRlmMaxDepth(maxDepth);\n\t\t\tawait this.settingsManager.flush();\n\t\t\tconst errors = this.settingsManager.drainErrors(\"global\");\n\t\t\tglobalError = errors.map(({ error }) => error.message).join(\"; \") || undefined;\n\t\t}\n\n\t\treturn {\n\t\t\t...this.getRlmMaxDepthStatus(),\n\t\t\tglobalSaved: options.global === true && globalError === undefined,\n\t\t\t...(globalError ? { globalError } : {}),\n\t\t};\n\t}\n\n\tsetSessionName(name: string): void {\n\t\tthis.sessionManager.appendSessionInfo(name);\n\t\tthis._emit({\n\t\t\ttype: \"session_info_changed\",\n\t\t\tname: this.sessionManager.getSessionName(),\n\t\t});\n\t}\n\n\t/**\n\t * Navigate to a different node in the session tree.\n\t * Unlike fork() which creates a new session file, this stays in the same file.\n\t *\n\t * @param targetId The entry ID to navigate to\n\t * @param options.summarize Whether user wants to summarize abandoned branch\n\t * @param options.customInstructions Custom instructions for summarizer\n\t * @param options.replaceInstructions If true, customInstructions replaces the default prompt\n\t * @param options.label Label to attach to the branch summary entry\n\t * @returns Result with editorText (if user message) and cancelled status\n\t */\n\tprivate _branchNavigationQueue: Promise<void> = Promise.resolve();\n\n\tasync navigateTree(\n\t\ttargetId: string,\n\t\toptions: {\n\t\t\tsummarize?: boolean;\n\t\t\tcustomInstructions?: string;\n\t\t\treplaceInstructions?: boolean;\n\t\t\tlabel?: string;\n\t\t} = {},\n\t): Promise<{\n\t\teditorText?: string;\n\t\tcancelled: boolean;\n\t\taborted?: boolean;\n\t\tsummaryEntry?: BranchSummaryEntry;\n\t}> {\n\t\tconst previous = this._branchNavigationQueue;\n\t\tlet release = () => {};\n\t\tthis._branchNavigationQueue = new Promise<void>((resolve) => {\n\t\t\trelease = resolve;\n\t\t});\n\t\tawait previous;\n\t\ttry {\n\t\t\treturn await this._navigateTree(targetId, options);\n\t\t} finally {\n\t\t\trelease();\n\t\t}\n\t}\n\n\tprivate async _navigateTree(\n\t\ttargetId: string,\n\t\toptions: {\n\t\t\tsummarize?: boolean;\n\t\t\tcustomInstructions?: string;\n\t\t\treplaceInstructions?: boolean;\n\t\t\tlabel?: string;\n\t\t} = {},\n\t): Promise<{\n\t\teditorText?: string;\n\t\tcancelled: boolean;\n\t\taborted?: boolean;\n\t\tsummaryEntry?: BranchSummaryEntry;\n\t}> {\n\t\tif (options.summarize && !this.model) {\n\t\t\tthrow new Error(\"No model available for summarization\");\n\t\t}\n\n\t\tconst targetEntry = this.sessionManager.getEntry(targetId);\n\t\tif (!targetEntry) {\n\t\t\tthrow new Error(`Entry ${targetId} not found`);\n\t\t}\n\n\t\tconst queuedWorkPause = this.acquireQueuedWorkPause();\n\t\tlet commitFence: { owner: symbol; release(): void } | undefined;\n\t\ttry {\n\t\t\t// Branch navigation and turn dispatch mutate the same transcript leaf.\n\t\t\tcommitFence = await this._acquireSessionActionCommitFence();\n\t\t\treturn await this._sessionActionCommitContext.run(commitFence.owner, async () => {\n\t\t\t\tawait this.agent.waitForIdle();\n\t\t\t\tawait this._agentEventQueue;\n\t\t\t\treturn this._navigateTreeUnderPause(targetId, targetEntry, options);\n\t\t\t});\n\t\t} finally {\n\t\t\tqueuedWorkPause.release();\n\t\t\tcommitFence?.release();\n\t\t}\n\t}\n\n\tprivate async _navigateTreeUnderPause(\n\t\ttargetId: string,\n\t\ttargetEntry: NonNullable<ReturnType<SessionManager[\"getEntry\"]>>,\n\t\toptions: {\n\t\t\tsummarize?: boolean;\n\t\t\tcustomInstructions?: string;\n\t\t\treplaceInstructions?: boolean;\n\t\t\tlabel?: string;\n\t\t},\n\t): Promise<{\n\t\teditorText?: string;\n\t\tcancelled: boolean;\n\t\taborted?: boolean;\n\t\tsummaryEntry?: BranchSummaryEntry;\n\t}> {\n\t\tconst oldLeafId = this.sessionManager.getLeafId();\n\n\t\t// No-op if already at target after admitted work has settled.\n\t\tif (targetId === oldLeafId) {\n\t\t\treturn { cancelled: false };\n\t\t}\n\n\t\t// Do not switch branches while /refine has detached event handling and is\n\t\t// about to persist harness/session entries for the current branch.\n\t\tawait this._invalidatePendingAutoRefineForBranchChange();\n\n\t\tconst { entries: entriesToSummarize, commonAncestorId } = collectEntriesForBranchSummary(\n\t\t\tthis.sessionManager,\n\t\t\toldLeafId,\n\t\t\ttargetId,\n\t\t);\n\n\t\tlet customInstructions = options.customInstructions;\n\t\tlet replaceInstructions = options.replaceInstructions;\n\t\tlet label = options.label;\n\n\t\tconst preparation: TreePreparation = {\n\t\t\ttargetId,\n\t\t\toldLeafId,\n\t\t\tcommonAncestorId,\n\t\t\tentriesToSummarize,\n\t\t\tuserWantsSummary: options.summarize ?? false,\n\t\t\tcustomInstructions,\n\t\t\treplaceInstructions,\n\t\t\tlabel,\n\t\t};\n\n\t\tthis._branchSummaryAbortController = new AbortController();\n\t\tlet resolveBranchSummaryOperation: () => void = () => {};\n\t\tconst branchSummaryOperation = new Promise<void>((resolve) => {\n\t\t\tresolveBranchSummaryOperation = resolve;\n\t\t});\n\t\tthis._branchSummaryOperation = branchSummaryOperation;\n\n\t\ttry {\n\t\t\tlet extensionSummary: { summary: string; details?: unknown } | undefined;\n\t\t\tlet fromExtension = false;\n\n\t\t\tif (this._extensionRunner.hasHandlers(\"session_before_tree\")) {\n\t\t\t\tconst result = (await this._extensionRunner.emit({\n\t\t\t\t\ttype: \"session_before_tree\",\n\t\t\t\t\tpreparation,\n\t\t\t\t\tsignal: this._branchSummaryAbortController.signal,\n\t\t\t\t})) as SessionBeforeTreeResult | undefined;\n\n\t\t\t\tif (result?.cancel) {\n\t\t\t\t\treturn { cancelled: true };\n\t\t\t\t}\n\n\t\t\t\tif (result?.summary && options.summarize) {\n\t\t\t\t\textensionSummary = result.summary;\n\t\t\t\t\tfromExtension = true;\n\t\t\t\t}\n\n\t\t\t\tif (result?.customInstructions !== undefined) {\n\t\t\t\t\tcustomInstructions = result.customInstructions;\n\t\t\t\t}\n\t\t\t\tif (result?.replaceInstructions !== undefined) {\n\t\t\t\t\treplaceInstructions = result.replaceInstructions;\n\t\t\t\t}\n\t\t\t\tif (result?.label !== undefined) {\n\t\t\t\t\tlabel = result.label;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet summaryText: string | undefined;\n\t\t\tlet summaryDetails: unknown;\n\t\t\tif (options.summarize && entriesToSummarize.length > 0 && !extensionSummary) {\n\t\t\t\tconst model = this.model!;\n\t\t\t\tconst { apiKey, headers } = await this._getRequiredRequestAuth(model);\n\t\t\t\tconst branchSummarySettings = this.settingsManager.getBranchSummarySettings();\n\t\t\t\tconst result = await generateBranchSummary(entriesToSummarize, {\n\t\t\t\t\tmodel,\n\t\t\t\t\tapiKey,\n\t\t\t\t\theaders,\n\t\t\t\t\tsignal: this._branchSummaryAbortController.signal,\n\t\t\t\t\tcustomInstructions,\n\t\t\t\t\treplaceInstructions,\n\t\t\t\t\treserveTokens: branchSummarySettings.reserveTokens,\n\t\t\t\t});\n\t\t\t\tif (result.aborted) {\n\t\t\t\t\treturn { cancelled: true, aborted: true };\n\t\t\t\t}\n\t\t\t\tif (result.error) {\n\t\t\t\t\tthrow new Error(result.error);\n\t\t\t\t}\n\t\t\t\tsummaryText = result.summary;\n\t\t\t\tsummaryDetails = {\n\t\t\t\t\treadFiles: result.readFiles || [],\n\t\t\t\t\tmodifiedFiles: result.modifiedFiles || [],\n\t\t\t\t};\n\t\t\t} else if (extensionSummary) {\n\t\t\t\tsummaryText = extensionSummary.summary;\n\t\t\t\tsummaryDetails = extensionSummary.details;\n\t\t\t}\n\n\t\t\tlet newLeafId: string | null;\n\t\t\tlet editorText: string | undefined;\n\n\t\t\tif (targetEntry.type === \"message\" && targetEntry.message.role === \"user\") {\n\t\t\t\tnewLeafId = targetEntry.parentId;\n\t\t\t\teditorText = this._extractUserMessageText(targetEntry.message.content);\n\t\t\t} else if (targetEntry.type === \"custom_message\") {\n\t\t\t\tnewLeafId = targetEntry.parentId;\n\t\t\t\teditorText =\n\t\t\t\t\ttypeof targetEntry.content === \"string\"\n\t\t\t\t\t\t? targetEntry.content\n\t\t\t\t\t\t: targetEntry.content\n\t\t\t\t\t\t\t\t.filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n\t\t\t\t\t\t\t\t.map((c) => c.text)\n\t\t\t\t\t\t\t\t.join(\"\");\n\t\t\t} else {\n\t\t\t\tnewLeafId = targetId;\n\t\t\t}\n\n\t\t\tlet summaryEntry: BranchSummaryEntry | undefined;\n\t\t\tif (summaryText) {\n\t\t\t\tconst summaryId = this.sessionManager.branchWithSummary(\n\t\t\t\t\tnewLeafId,\n\t\t\t\t\tsummaryText,\n\t\t\t\t\tsummaryDetails,\n\t\t\t\t\tfromExtension,\n\t\t\t\t);\n\t\t\t\tsummaryEntry = this.sessionManager.getEntry(summaryId) as BranchSummaryEntry;\n\n\t\t\t\tif (label) {\n\t\t\t\t\tthis.sessionManager.appendLabelChange(summaryId, label);\n\t\t\t\t}\n\t\t\t} else if (newLeafId === null) {\n\t\t\t\tthis.sessionManager.resetLeaf();\n\t\t\t} else {\n\t\t\t\tthis.sessionManager.branch(newLeafId);\n\t\t\t}\n\n\t\t\tif (label && !summaryText) {\n\t\t\t\tthis.sessionManager.appendLabelChange(targetId, label);\n\t\t\t}\n\n\t\t\tconst sessionContext = this.sessionManager.buildSessionContext();\n\t\t\tthis.agent.state.messages = sessionContext.messages;\n\t\t\tthis._mergeUnpersistedOutcomes(this.agent.state.messages);\n\t\t\tthis._restoreLateIpythonSentAgentMessages();\n\t\t\tthis._reloadGoalStateFromBranch();\n\t\t\tthis._reloadRlmMaxDepthFromBranch();\n\t\t\tthis._invalidateQueuedPromptPreparation();\n\n\t\t\tawait this._extensionRunner.emit({\n\t\t\t\ttype: \"session_tree\",\n\t\t\t\tnewLeafId: this.sessionManager.getLeafId(),\n\t\t\t\toldLeafId,\n\t\t\t\tsummaryEntry,\n\t\t\t\tfromExtension: summaryText ? fromExtension : undefined,\n\t\t\t});\n\n\t\t\treturn { editorText, cancelled: false, summaryEntry };\n\t\t} finally {\n\t\t\tthis._branchSummaryAbortController = undefined;\n\t\t\tif (this._branchSummaryOperation === branchSummaryOperation) {\n\t\t\t\tthis._branchSummaryOperation = undefined;\n\t\t\t}\n\t\t\tresolveBranchSummaryOperation();\n\t\t}\n\t}\n\n\tgetUserMessagesForForking(): Array<{ entryId: string; text: string }> {\n\t\tconst entries = this.sessionManager.getEntries();\n\t\tconst result: Array<{ entryId: string; text: string }> = [];\n\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.type !== \"message\") continue;\n\t\t\tif (entry.message.role !== \"user\") continue;\n\n\t\t\tconst text = this._extractUserMessageText(entry.message.content);\n\t\t\tif (text) {\n\t\t\t\tresult.push({ entryId: entry.id, text });\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate _extractUserMessageText(content: string | Array<{ type: string; text?: string }>): string {\n\t\tif (typeof content === \"string\") return content;\n\t\tif (Array.isArray(content)) {\n\t\t\treturn content\n\t\t\t\t.filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n\t\t\t\t.map((c) => c.text)\n\t\t\t\t.join(\"\");\n\t\t}\n\t\treturn \"\";\n\t}\n\n\tgetSessionStats(): SessionStats {\n\t\tconst state = this.state;\n\t\tconst userMessages = state.messages.filter((m) => m.role === \"user\").length;\n\t\tconst assistantMessages = state.messages.filter((m) => m.role === \"assistant\").length;\n\t\tconst toolResults = state.messages.filter((m) => m.role === \"toolResult\").length;\n\n\t\tlet toolCalls = 0;\n\t\tlet totalInput = 0;\n\t\tlet totalOutput = 0;\n\t\tlet totalCacheRead = 0;\n\t\tlet totalCacheWrite = 0;\n\t\tlet totalCost = 0;\n\n\t\tfor (const message of state.messages) {\n\t\t\tif (message.role === \"assistant\") {\n\t\t\t\tconst assistantMsg = message as AssistantMessage;\n\t\t\t\ttoolCalls += assistantMsg.content.filter((c) => c.type === \"toolCall\").length;\n\t\t\t\ttotalInput += assistantMsg.usage.input;\n\t\t\t\ttotalOutput += assistantMsg.usage.output;\n\t\t\t\ttotalCacheRead += assistantMsg.usage.cacheRead;\n\t\t\t\ttotalCacheWrite += assistantMsg.usage.cacheWrite;\n\t\t\t\ttotalCost += assistantMsg.usage.cost.total;\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tsessionFile: this.sessionFile,\n\t\t\tsessionId: this.sessionId,\n\t\t\tuserMessages,\n\t\t\tassistantMessages,\n\t\t\ttoolCalls,\n\t\t\ttoolResults,\n\t\t\ttotalMessages: state.messages.length,\n\t\t\ttokens: {\n\t\t\t\tinput: totalInput,\n\t\t\t\toutput: totalOutput,\n\t\t\t\tcacheRead: totalCacheRead,\n\t\t\t\tcacheWrite: totalCacheWrite,\n\t\t\t\ttotal: totalInput + totalOutput + totalCacheRead + totalCacheWrite,\n\t\t\t},\n\t\t\tcost: totalCost,\n\t\t\tcontextUsage: this.getContextUsage(),\n\t\t};\n\t}\n\n\tgetContextUsage(): ContextUsage | undefined {\n\t\tconst model = this.model;\n\t\tif (!model) return undefined;\n\n\t\tconst contextWindow = model.contextWindow ?? 0;\n\t\tif (contextWindow <= 0) return undefined;\n\n\t\t// After compaction, the last assistant usage reflects pre-compaction context size.\n\t\t// We can only trust usage from an assistant that responded after the latest compaction.\n\t\t// If no such assistant exists, context token count is unknown until the next LLM response.\n\t\tconst branchEntries = this.sessionManager.getBranch();\n\t\tconst latestCompaction = getLatestCompactionEntry(branchEntries);\n\n\t\tif (latestCompaction) {\n\t\t\t// Check if there's a valid assistant usage after the compaction boundary\n\t\t\tconst compactionIndex = branchEntries.lastIndexOf(latestCompaction);\n\t\t\tlet hasPostCompactionUsage = false;\n\t\t\tfor (let i = branchEntries.length - 1; i > compactionIndex; i--) {\n\t\t\t\tconst entry = branchEntries[i];\n\t\t\t\tif (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\t\t\tconst assistant = entry.message;\n\t\t\t\t\tif (assistant.stopReason !== \"aborted\" && assistant.stopReason !== \"error\") {\n\t\t\t\t\t\tconst contextTokens = calculateContextTokens(assistant.usage);\n\t\t\t\t\t\tif (contextTokens > 0) {\n\t\t\t\t\t\t\thasPostCompactionUsage = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!hasPostCompactionUsage) {\n\t\t\t\treturn { tokens: null, contextWindow, percent: null };\n\t\t\t}\n\t\t}\n\n\t\tconst estimate = estimateContextTokens(this.messages);\n\t\tconst percent = (estimate.tokens / contextWindow) * 100;\n\n\t\treturn {\n\t\t\ttokens: estimate.tokens,\n\t\t\tcontextWindow,\n\t\t\tpercent,\n\t\t};\n\t}\n\n\tprivate _rlmSessionDirForReading(): string | undefined {\n\t\treturn this._rlmSessionDir ?? this.sessionManager.getSessionArtifactDir();\n\t}\n\n\tprivate _contextWindowResolver(): ContextWindowResolver {\n\t\treturn (provider, modelId) => this._modelRegistry.find(provider, modelId)?.contextWindow;\n\t}\n\n\t/**\n\t * Build the agent context overview for /context: this session as the root\n\t * plus one node per RLM sub-agent, recursively. Running children are read\n\t * from their live sessions; completed children from their persisted session\n\t * dirs, so the tree survives child disposal and session resume.\n\t */\n\tgetContextTree(): ContextTreeNode {\n\t\tconst resolveContextWindow = this._contextWindowResolver();\n\t\tconst { ownUsage, totalUsage } = computeOwnAndTotalUsage(\n\t\t\tthis.sessionManager.getBranch(),\n\t\t\tthis.sessionManager.getEntries(),\n\t\t);\n\n\t\tconst children: ContextTreeNode[] = [];\n\t\tconst liveIds = new Set<string>();\n\t\tfor (const run of this._activeRlmChildRuns.values()) {\n\t\t\tliveIds.add(run.id);\n\t\t\tconst node =\n\t\t\t\trun.session?.getContextTree() ?? loadContextTreeChildFromDisk(run.sessionDir, resolveContextWindow);\n\t\t\tchildren.push({\n\t\t\t\t...(node ?? {\n\t\t\t\t\townUsage: emptyUsage(),\n\t\t\t\t\ttotalUsage: emptyUsage(),\n\t\t\t\t\tchildren: [],\n\t\t\t\t}),\n\t\t\t\tid: run.id,\n\t\t\t\tlabel: rlmChildLabel(run.prompt),\n\t\t\t\tstatus: run.status,\n\t\t\t});\n\t\t}\n\t\tchildren.push(...loadContextTreeChildrenFromDisk(this._rlmSessionDirForReading(), resolveContextWindow, liveIds));\n\n\t\tconst model = this.model;\n\t\treturn {\n\t\t\tid: \"root\",\n\t\t\tlabel: this.sessionName ?? \"main agent\",\n\t\t\tstatus: \"active\",\n\t\t\tmodel: model ? { provider: model.provider, id: model.id } : undefined,\n\t\t\townUsage,\n\t\t\ttotalUsage,\n\t\t\tcontextUsage: this.getContextUsage(),\n\t\t\tchildren,\n\t\t};\n\t}\n\n\t/**\n\t * Export session to HTML.\n\t * @param outputPath Optional output path (defaults to session directory)\n\t * @returns Path to exported file\n\t */\n\tasync exportToHtml(outputPath?: string): Promise<string> {\n\t\tconst themeName = this.settingsManager.getTheme();\n\n\t\tconst toolRenderer: ToolHtmlRenderer = createToolHtmlRenderer({\n\t\t\tgetToolDefinition: (name) => this.getToolDefinition(name),\n\t\t\ttheme,\n\t\t\tcwd: this.sessionManager.getCwd(),\n\t\t});\n\n\t\treturn await exportSessionToHtml(this.sessionManager, this.state, {\n\t\t\toutputPath,\n\t\t\tthemeName,\n\t\t\ttoolRenderer,\n\t\t});\n\t}\n\n\t/**\n\t * Export the current session branch to a JSONL file.\n\t * Writes the session header followed by all entries on the current branch path.\n\t * @param outputPath Target file path. If omitted, generates a timestamped file in cwd.\n\t * @returns The resolved output file path.\n\t */\n\texportToJsonl(outputPath?: string): string {\n\t\tconst filePath = resolve(outputPath ?? `session-${new Date().toISOString().replace(/[:.]/g, \"-\")}.jsonl`);\n\t\tconst dir = dirname(filePath);\n\t\tif (!existsSync(dir)) {\n\t\t\tmkdirSync(dir, { recursive: true });\n\t\t}\n\n\t\tconst header: SessionHeader = {\n\t\t\ttype: \"session\",\n\t\t\tversion: CURRENT_SESSION_VERSION,\n\t\t\tid: this.sessionManager.getSessionId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tcwd: this.sessionManager.getCwd(),\n\t\t};\n\n\t\tconst branchEntries = this.sessionManager.getBranch();\n\t\tconst lines = [JSON.stringify(header)];\n\n\t\t// Re-chain parentIds to form a linear sequence\n\t\tlet prevId: string | null = null;\n\t\tfor (const entry of branchEntries) {\n\t\t\tconst linear = { ...entry, parentId: prevId };\n\t\t\tlines.push(JSON.stringify(linear));\n\t\t\tprevId = entry.id;\n\t\t}\n\n\t\twriteFileSync(filePath, `${lines.join(\"\\n\")}\\n`);\n\t\treturn filePath;\n\t}\n\n\t/**\n\t * Get text content of last assistant message.\n\t * Useful for /copy command.\n\t * @returns Text content, or undefined if no assistant message exists\n\t */\n\tgetLastAssistantText(): string | undefined {\n\t\tconst lastAssistant = this.messages\n\t\t\t.slice()\n\t\t\t.reverse()\n\t\t\t.find((m) => {\n\t\t\t\tif (m.role !== \"assistant\") return false;\n\t\t\t\tconst msg = m as AssistantMessage;\n\t\t\t\t// Skip aborted messages with no content\n\t\t\t\tif (msg.stopReason === \"aborted\" && msg.content.length === 0) return false;\n\t\t\t\treturn true;\n\t\t\t});\n\n\t\tif (!lastAssistant) return undefined;\n\n\t\tlet text = \"\";\n\t\tfor (const content of (lastAssistant as AssistantMessage).content) {\n\t\t\tif (content.type === \"text\") {\n\t\t\t\ttext += content.text;\n\t\t\t}\n\t\t}\n\n\t\treturn text.trim() || undefined;\n\t}\n\n\t// =========================================================================\n\t// Extension System\n\t// =========================================================================\n\n\tcreateReplacedSessionContext(): ReplacedSessionContext {\n\t\tconst context = Object.defineProperties(\n\t\t\t{},\n\t\t\tObject.getOwnPropertyDescriptors(this._extensionRunner.createCommandContext()),\n\t\t) as ReplacedSessionContext;\n\t\tcontext.sendMessage = (message, options) => this.sendCustomMessage(message, options);\n\t\tcontext.sendUserMessage = (content, options) => this.sendUserMessage(content, options);\n\t\treturn context;\n\t}\n\n\thasExtensionHandlers(eventType: string): boolean {\n\t\treturn this._extensionRunner.hasHandlers(eventType);\n\t}\n\n\tget extensionRunner(): ExtensionRunner {\n\t\treturn this._extensionRunner;\n\t}\n}\n\nfunction isRlmHeartbeatStatusUpdate(value: unknown): value is AgentRlmHeartbeatStatusUpdate {\n\treturn value === \"pause\" || value === \"resume\";\n}\n\nfunction rlmHeartbeatHostResponse(job: AgentCronJob): Record<string, unknown> {\n\treturn {\n\t\tid: job.id,\n\t\tstatus: job.status,\n\t\tlabel: job.label ?? null,\n\t\tdelivery_mode: job.deliveryMode ?? \"steer\",\n\t\tinstruction: job.prompt,\n\t\tschedule: job.schedule,\n\t\tcreated_at: job.createdAt,\n\t\tupdated_at: job.updatedAt,\n\t\tnext_run_at: job.nextRunAt ?? null,\n\t\tlast_run_at: job.lastRunAt ?? null,\n\t\tlast_error: job.lastError ?? null,\n\t\trun_count: job.runCount,\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"agent-session.d.ts","sourceRoot":"","sources":["../../src/core/agent-session.ts"],"names":[],"mappings":"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","sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { randomUUID } from \"node:crypto\";\nimport { existsSync, mkdirSync, mkdtempSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { basename, dirname, join, resolve } from \"node:path\";\nimport {\n\tAgent,\n\ttype AgentContext,\n\tAgentContinueError,\n\ttype AgentEvent,\n\ttype AgentMessage,\n\ttype AgentState,\n\ttype AgentTool,\n\ttype GetContinuationMessagesContext,\n\ttype ShouldStopAfterTurnContext,\n\ttype ThinkingLevel,\n} from \"@asm-agent/agent\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tImageContent,\n\tModel,\n\tServiceTier,\n\tTextContent,\n\tUsage,\n\tUserMessage,\n} from \"@asm-agent/ai\";\nimport {\n\tclampThinkingLevel,\n\tcleanupSessionResources,\n\tgetSupportedThinkingLevels,\n\tisContextOverflow,\n\tmodelsAreEqual,\n\tresetApiProviders,\n\tsupportsFastMode,\n} from \"@asm-agent/ai\";\nimport { theme } from \"../modes/interactive/theme/theme.js\";\nimport { stripFrontmatter } from \"../utils/frontmatter.js\";\nimport { sleep } from \"../utils/sleep.js\";\nimport {\n\tAGENT_MESSAGE_CUSTOM_TYPE,\n\tAGENT_MESSAGE_RECEIVED_PREVIEW_LABEL,\n\tAGENT_MESSAGE_SKILL_NAME,\n\ttype AgentFamilyCatalogEntry,\n\ttype AgentFamilyRosterResult,\n\ttype AgentSessionMessage,\n\ttype AgentSessionMessageAgentSummary,\n\ttype AgentSessionMessageController,\n\ttype AgentSessionMessageListResult,\n\ttype AgentSessionMessageReceipt,\n\tassertAgentMessageQueueCapacity,\n\tassertAgentSessionNameAvailable,\n\tassertDirectAgentMessageTarget,\n\tcreateAgentMessageHostHandlers,\n\tDEFAULT_AGENT_MESSAGE_MAX_PENDING_PER_SESSION,\n\tformatAgentSessionNameUnavailable,\n\tisAgentSessionMessage,\n\tisAgentSessionMessagePrompt,\n\tnormalizeAgentSessionMessage,\n\tparseAgentSessionMessagePromptId,\n\tstartsAgentRun,\n} from \"./agent-messages.js\";\nimport {\n\tAGENT_OBSERVE_SKILL_NAME,\n\ttype AgentObserveAgentSnapshot,\n\ttype AgentObserveController,\n\ttype AgentObserveListResult,\n\ttype AgentObserveRecentMessagesResult,\n\tcreateAgentObserveHostHandlers,\n\tnormalizeObserveLimit,\n\tnormalizeObserveMaxChars,\n\tORCHESTRATION_HEARTBEAT_SKILL_NAME,\n} from \"./agent-observe.js\";\nimport {\n\taddLoginGuidanceToAuthError,\n\tformatAuthenticationFailedMessage,\n\tformatNoApiKeyFoundMessage,\n\tformatNoModelSelectedMessage,\n\tisLikelyAuthenticationError,\n} from \"./auth-guidance.js\";\nimport type { AuthSourceToken } from \"./auth-storage.js\";\nimport {\n\ttype AgentAutonomousConfig,\n\ttype AgentAutonomousStatus,\n\ttype AutonomousRuntimeState,\n\taddAutonomousContinuation,\n\taddAutonomousUsage,\n\tautonomousStatus,\n\tcreateAutonomousRuntimeState,\n\tnextAutonomousContinuation,\n\trefreshAutonomousQualityGates,\n\tsetAutonomousEnabled,\n} from \"./autonomous.js\";\nimport { type BashResult, executeBashWithOperations } from \"./bash-executor.js\";\nimport {\n\tCOMPACT_SKILL_NAME,\n\ttype CompactionResult,\n\tcalculateContextTokens,\n\tcollectEntriesForBranchSummary,\n\tcompact,\n\testimateContextTokens,\n\tgenerateBranchSummary,\n\tprepareCompaction,\n\tserializeConversation,\n\tshouldCompact,\n} from \"./compaction/index.js\";\nimport {\n\ttype ContextTreeNode,\n\ttype ContextWindowResolver,\n\tcomputeOwnAndTotalUsage,\n\tloadContextTreeChildFromDisk,\n\tloadContextTreeChildrenFromDisk,\n} from \"./context-tree.js\";\nimport type { AgentCronJob, AgentRlmHeartbeatController, AgentRlmHeartbeatStatusUpdate } from \"./cron-jobs.js\";\nimport { normalizeHeartbeatDeliveryMode } from \"./cron-jobs.js\";\nimport { DEFAULT_THINKING_LEVEL } from \"./defaults.js\";\nimport { exportSessionToHtml, type ToolHtmlRenderer } from \"./export-html/index.js\";\nimport { createToolHtmlRenderer } from \"./export-html/tool-renderer.js\";\nimport {\n\ttype ContextUsage,\n\ttype ExtensionCommandContextActions,\n\ttype ExtensionErrorListener,\n\tExtensionRunner,\n\ttype ExtensionUIContext,\n\ttype InputSource,\n\ttype MessageEndEvent,\n\ttype MessageStartEvent,\n\ttype MessageUpdateEvent,\n\ttype ReplacedSessionContext,\n\ttype SessionBeforeCompactResult,\n\ttype SessionBeforeRefineResult,\n\ttype SessionBeforeTreeResult,\n\ttype SessionStartEvent,\n\ttype ShutdownHandler,\n\ttype ToolDefinition,\n\ttype ToolExecutionEndEvent,\n\ttype ToolExecutionStartEvent,\n\ttype ToolExecutionUpdateEvent,\n\ttype ToolInfo,\n\ttype TreePreparation,\n\ttype TurnEndEvent,\n\ttype TurnStartEvent,\n\twrapRegisteredTools,\n} from \"./extensions/index.js\";\nimport { emitSessionShutdownEvent } from \"./extensions/runner.js\";\nimport {\n\tcreateGoalContextMessage,\n\temptyGoalState,\n\tGOAL_CONTEXT_CUSTOM_TYPE,\n\tGOAL_CONTEXT_PREVIEW_LABEL,\n\tGOAL_SKILL_NAME,\n\tGOAL_STATE_CUSTOM_TYPE,\n\ttype GoalHostResponse,\n\ttype GoalState,\n\ttype GoalStatus,\n\tgoalHostResponse,\n\tgoalTokenDeltaForUsage,\n\tisPersistedGoalState,\n\tnormalizeGoalState,\n\tvalidateGoalBudget,\n\tvalidateGoalObjective,\n} from \"./goals.js\";\nimport type { HostRequestHandlers, KernelSentAgentMessage } from \"./kernel/index.js\";\nimport { type RestoreResult, snapshotPathIn } from \"./kernel/state-snapshot.js\";\nimport type { AcpMcpServerConfig } from \"./mcp/acp-mcp-types.js\";\nimport type { McpManager } from \"./mcp/mcp-manager.js\";\nimport {\n\tBACKGROUND_PROCESS_COMPLETED_CUSTOM_TYPE,\n\ttype BashExecutionMessage,\n\ttype CompactionOutcome,\n\ttype CompactionOutcomeReason,\n\ttype CustomMessage,\n\tconvertToLlm,\n\tcreateBackgroundProcessCompletedMessage,\n\tcreateCompactionOutcomeMessage,\n\tcreateHeartbeatPromptMessage,\n\tcreateRefinementOutcomeMessage,\n\tcreateRlmChildFailureMessage,\n\tcreateRlmChildTerminalNoticeMessage,\n\tcreateSessionSlashCommandMessage,\n\tcreateSessionSlashCommandResultMessage,\n\tHEARTBEAT_PROMPT_CUSTOM_TYPE,\n\tHEARTBEAT_PROMPT_PREVIEW_LABEL,\n\tIPYTHON_STATE_RESTORED_CUSTOM_TYPE,\n\tisSessionSlashCommandMessage,\n\tRLM_CHILD_FAILURE_CUSTOM_TYPE,\n\tRLM_CHILD_TERMINAL_NOTICE_CUSTOM_TYPE,\n} from \"./messages.js\";\nimport type { ModelRegistry } from \"./model-registry.js\";\nimport { throwIfPromptAdmissionCancelled } from \"./prompt-admission.js\";\nimport { expandPromptTemplate, type PromptTemplate } from \"./prompt-templates.js\";\nimport {\n\ttype AutoRefineReason,\n\ttype AutoRefineReview,\n\tappendGlobalRefinement,\n\tapplyRefinementProposal,\n\tgenerateRefinementId,\n\tgetGlobalHarnessStateDir,\n\tgetLocalHarnessStateDir,\n\tgetRefinementHistory,\n\ttype HarnessState,\n\tinferRefinementResultScope,\n\tloadGlobalRefinementHistory,\n\tloadHarnessState,\n\tmergeHarnessStates,\n\tmergeRefinementHistory,\n\tnormalizeRefinementProposal,\n\tplanRefinement,\n\tREFINE_SKILL_NAME,\n\ttype RefinementPlan,\n\ttype RefinementResult,\n\treviewAutoRefine,\n\tsaveHarnessState,\n} from \"./refinement/index.js\";\nimport { resolveConfigValue } from \"./resolve-config-value.js\";\nimport type { ResourceExtensionPaths, ResourceLoader } from \"./resource-loader.js\";\nimport {\n\ttype CreateRlmSubagentRuntimeOptions,\n\tcreateDefaultRlmSubagentSessionName,\n\tcreateRlmDeleteSubagentHostHandler,\n\tcreateRlmFindModelsHostHandler,\n\tcreateRlmListSubagentsHostHandler,\n\tcreateRlmRunHostHandler,\n\tfindRlmModelMatches,\n\tnormalizeRequestedRlmSubagentModel,\n\tnormalizeRequestedRlmSubagentSessionName,\n\tnormalizeRequestedRlmSubagentThinkingLevel,\n\ttype RlmDeleteSubagentResult,\n\ttype RlmFindModelsResult,\n\ttype RlmListSubagentsResult,\n\ttype RlmSpawnHandle,\n\ttype RlmSubagentRegistryEntry,\n\ttype RlmSubagentRuntime,\n\ttype SubagentRuntimeHost,\n} from \"./rlm-runtime.js\";\nimport {\n\tActionStore,\n\ttype ActionTicket,\n\tcanSelectSessionAction,\n\ttype DeliveryPolicy,\n\ttype DeliveryRecord,\n\ttype QueuedMessageLane,\n\ttype QueuedMessageMutation,\n\ttype QueuedMessageMutationStatus,\n\tqueuedMessageLaneDeliveryPolicy,\n\ttype RuntimeActivity,\n\ttype SessionAction,\n\ttype SessionActionSnapshot,\n\ttype SessionCommandPayload,\n\ttype SessionTurnPayload,\n\ttransitionSessionAction,\n\ttype WakePolicy,\n} from \"./session-action-store.js\";\nimport type { BranchSummaryEntry, CompactionEntry, SessionContext, SessionMessageEntry } from \"./session-manager.js\";\nimport {\n\tCURRENT_SESSION_VERSION,\n\tgetLatestCompactionEntry,\n\ttype SessionHeader,\n\tSessionManager,\n} from \"./session-manager.js\";\nimport type { SessionStats } from \"./session-stats.js\";\nimport type { SettingsManager } from \"./settings-manager.js\";\nimport { getPythonSkillRuntimeInfo, type Skill } from \"./skills.js\";\nimport {\n\tparseRefineCommandOptions,\n\tparseSessionSlashCommand,\n\tparseSlashCommand,\n\ttype SessionSlashCommand,\n\ttype SlashCommandInfo,\n} from \"./slash-commands.js\";\nimport { createSyntheticSourceInfo, type SourceInfo } from \"./source-info.js\";\nimport { type BuildSystemPromptOptions, buildSystemPrompt } from \"./system-prompt.js\";\nimport { THINKING_LEVELS } from \"./thinking-levels.js\";\nimport { acpMcpToolNames, createAcpMcpToolDefinitions } from \"./tools/acp-mcp.js\";\nimport { type BashOperations, createLocalBashOperations } from \"./tools/bash.js\";\nimport { createAllToolDefinitions } from \"./tools/index.js\";\nimport { IpythonKernelProvisioner } from \"./tools/ipython.js\";\nimport { createToolDefinitionFromAgentTool } from \"./tools/tool-definition-wrapper.js\";\nimport { addAssistantUsage, emptyUsage } from \"./usage.js\";\nimport { SERPER_CREDENTIAL_ID, SERPER_ENV_VAR, WEBSEARCH_SKILL_NAME } from \"./websearch-credential.js\";\n\nexport type { GoalState, GoalStatus } from \"./goals.js\";\nexport type { SessionStats } from \"./session-stats.js\";\nexport { type ParsedSkillBlock, parseSkillBlock } from \"./skill-blocks.js\";\n\nexport type RlmChildAgentStatus = \"queued\" | \"running\" | \"done\" | \"error\" | \"cancelled\";\n\nexport interface RlmChildAgentActivity {\n\tkind: \"waiting\" | \"writing\" | \"executing\";\n\ttoolName?: string;\n}\n\nexport interface RlmChildAgentSnapshot {\n\tid: string;\n\tparentId?: string;\n\tactiveSessionId?: string;\n\tsessionName?: string;\n\tmodel?: string;\n\tlabel: string;\n\tstatus: RlmChildAgentStatus;\n\tdurationMs?: number;\n\tanswerPreview?: string;\n\ttoolUseCount?: number;\n\ttokenCount?: number;\n\trecap?: string;\n\tsessionDir: string;\n\tactivity?: RlmChildAgentActivity;\n\trepliedSinceTask?: boolean;\n\terror?: string;\n}\n\nexport type CompactionReason = \"manual\" | \"threshold\" | \"overflow\" | \"requested\";\n\nexport type AgentSessionEvent =\n\t| AgentEvent\n\t| {\n\t\t\ttype: \"ipython_sent_agent_message\";\n\t\t\ttoolCallId: string;\n\t\t\tmessage: KernelSentAgentMessage;\n\t }\n\t| { type: \"session_action_update\"; actions: SessionActionSnapshot }\n\t| {\n\t\t\ttype: \"compaction_start\";\n\t\t\treason: CompactionReason;\n\t\t\tcustomInstructions?: string;\n\t }\n\t| { type: \"session_info_changed\"; name: string | undefined }\n\t| { type: \"thinking_level_changed\"; level: ThinkingLevel }\n\t| { type: \"service_tier_changed\"; serviceTier: ServiceTier }\n\t| {\n\t\t\ttype: \"compaction_end\";\n\t\t\treason: CompactionReason;\n\t\t\tresult: CompactionResult | undefined;\n\t\t\taborted: boolean;\n\t\t\twillRetry: boolean;\n\t\t\terrorMessage?: string;\n\t\t\terrorSeverity?: \"warning\" | \"error\";\n\t\t\tcustomInstructions?: string;\n\t }\n\t| {\n\t\t\ttype: \"auto_retry_start\";\n\t\t\tattempt: number;\n\t\t\tmaxAttempts: number;\n\t\t\tdelayMs: number;\n\t\t\terrorMessage: string;\n\t }\n\t| {\n\t\t\ttype: \"auto_retry_end\";\n\t\t\tsuccess: boolean;\n\t\t\tattempt: number;\n\t\t\tfinalError?: string;\n\t }\n\t| {\n\t\t\ttype: \"auth_stale\";\n\t\t\tprovider: string;\n\t\t\tsourceTokens?: readonly AuthSourceToken[];\n\t }\n\t| { type: \"rlm_child_update\"; child: RlmChildAgentSnapshot }\n\t| { type: \"recap_update\"; recap: string | undefined }\n\t| { type: \"goal_update\"; goal: GoalState }\n\t| {\n\t\t\ttype: \"bash_start\";\n\t\t\tcommand: string;\n\t\t\texcludeFromContext: boolean;\n\t\t\ttransient?: boolean;\n\t\t\trunId?: string;\n\t }\n\t| { type: \"bash_output\"; chunk: string }\n\t| {\n\t\t\ttype: \"bash_end\";\n\t\t\texitCode: number | undefined;\n\t\t\tcancelled: boolean;\n\t\t\ttruncated: boolean;\n\t\t\tfullOutputPath?: string;\n\t\t\terrorMessage?: string;\n\t\t\ttransient?: boolean;\n\t\t\trunId?: string;\n\t }\n\t| { type: \"refine_complete\"; result: RefinementResult }\n\t| { type: \"refine_failed\"; error: string };\n\nexport type AgentSessionEventListener = (event: AgentSessionEvent) => void;\n\ntype UserBashEndDetails = {\n\texitCode: number | undefined;\n\tcancelled: boolean;\n\ttruncated: boolean;\n\tfullOutputPath?: string;\n\terrorMessage?: string;\n};\n\nexport class CompactionSkippedError extends Error {}\n\n/** Thrown when a session_before_refine extension skips the refinement round. */\nexport class RefineSkippedError extends Error {}\n\nexport interface AgentSessionConfig {\n\tagent: Agent;\n\tsessionManager: SessionManager;\n\tsettingsManager: SettingsManager;\n\tserviceTierPreference?: ServiceTier;\n\tcwd: string;\n\tagentDir?: string;\n\tscopedModels?: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }>;\n\tresourceLoader: ResourceLoader;\n\tcustomTools?: ToolDefinition[];\n\tmodelRegistry: ModelRegistry;\n\tinitialActiveToolNames?: string[];\n\tallowedToolNames?: string[];\n\t/**\n\t * Whether the built-in long-running goals feature is available: the bundled\n\t * goal skill in the Python kernel, its goal.* host handlers, and /goal.\n\t * Default: true.\n\t */\n\tincludeGoals?: boolean;\n\tagentMessageController?: AgentSessionMessageController;\n\tagentObserveController?: AgentObserveController;\n\t/**\n\t * Whether the bundled compact skill and its compact.* host handlers are\n\t * available to the model. Default: the compaction.agentCallable setting.\n\t */\n\tincludeCompactSkill?: boolean;\n\t/**\n\t * Optional host-side controller for the bundled rlm-heartbeat Python skill.\n\t * When omitted, rlm_heartbeat.* host requests are unavailable.\n\t */\n\trlmHeartbeatController?: AgentRlmHeartbeatController;\n\t/**\n\t * Optional MCP integration manager. When present, its mcp.* host requests\n\t * (refresh, begin_login) are exposed to the kernel.\n\t */\n\tmcpManager?: McpManager;\n\t/**\n\t * Override base tools (useful for custom runtimes).\n\t *\n\t * These are synthesized into minimal ToolDefinitions internally so AgentSession can keep\n\t * a definition-first registry even when callers provide plain AgentTool instances.\n\t */\n\tbaseToolsOverride?: Record<string, AgentTool>;\n\textensionRunnerRef?: { current?: ExtensionRunner };\n\tsessionStartEvent?: SessionStartEvent;\n\trlmDepth?: number;\n\trlmMaxDepth?: number;\n\trlmSessionDir?: string;\n\trlmParentNodeId?: string;\n\trlmParentAgent?: string;\n\tsubagentRuntimeHost?: SubagentRuntimeHost;\n\tautonomous?: AgentAutonomousConfig;\n\tprewarmIpythonKernel?: boolean;\n\tautoRefineReviewer?: AutoRefineReviewer;\n\t/**\n\t * When true, auto-refine runs synchronously between turns at the\n\t * shouldStopAfterTurn boundary instead of in the background after\n\t * agent_end. Used for print/headless autonomous runs so refinement\n\t * never overlaps the primary model request. Default: false.\n\t */\n\tserializedRefine?: boolean;\n\t/**\n\t * Initial goal to seed at session creation. Only applied when rlmDepth\n\t * is 0 and no persisted thread_goal_state entry exists in the branch.\n\t */\n\tinitialGoal?: { objective: string; tokenBudget?: number };\n}\n\nexport interface ExtensionBindings {\n\tuiContext?: ExtensionUIContext;\n\tcommandContextActions?: ExtensionCommandContextActions;\n\tshutdownHandler?: ShutdownHandler;\n\tonError?: ExtensionErrorListener;\n}\n\nexport interface AutoRefineReviewRequest {\n\treason: AutoRefineReason;\n\tturnsSinceLastReview: number;\n}\n\n/**\n * Discriminated result from a serialized-mode background planning pass.\n * - \"plan\": review approved and planning succeeded; carry the exact plan,\n * options, and abort controller so the boundary can apply directly\n * without a second planning request.\n * - \"skip\": reviewer declined; no refine needed.\n * - \"failure\": review or planning threw; boundary should not retry.\n */\nexport type SerializedBackgroundPlanResult =\n\t| {\n\t\t\tstatus: \"plan\";\n\t\t\tplan: RefinementPlan;\n\t\t\toptions: { instructions?: string; rollbackId?: string; global?: boolean };\n\t\t\tabort: AbortController;\n\t\t\tbranchVersion: number;\n\t }\n\t| { status: \"skip\"; explicit?: boolean }\n\t| { status: \"invalidated\"; branchVersion: number }\n\t| {\n\t\t\tstatus: \"failure\";\n\t\t\texplicit: boolean;\n\t\t\toptions: { instructions?: string; rollbackId?: string; global?: boolean };\n\t\t\tbranchVersion: number;\n\t };\n\nexport type AutoRefineReviewer = (request: AutoRefineReviewRequest, signal?: AbortSignal) => Promise<AutoRefineReview>;\n\nexport interface PromptOptions {\n\texpandPromptTemplates?: boolean;\n\timages?: ImageContent[];\n\tstreamingBehavior?: \"steer\" | \"followUp\";\n\tfollowUpQueueKey?: string;\n\tsource?: InputSource;\n\tpreflightResult?: (success: boolean, queued?: boolean) => void;\n\tqueueIfBusy?: boolean;\n\tresumeIfIdle?: boolean;\n\tinternalPrompt?: boolean;\n\tsuppressAutonomousContinuation?: boolean;\n\tskipInputHandlers?: boolean;\n\tsignal?: AbortSignal;\n\tadmissionCommitted?: () => void;\n\tagentMessageId?: string;\n\tcontent?: (TextContent | ImageContent)[];\n\tcustomMessage?: CustomMessage;\n}\n\ninterface InternalPromptOptions extends PromptOptions {\n\tskipPrePromptWork?: boolean;\n\treturnAfterAccepted?: boolean;\n\tagentMessageId?: string;\n}\n\ntype SubmissionExtensionCommandPolicy = \"execute\" | \"reject\" | \"ignore\";\n\ninterface SubmissionNormalizationPolicy {\n\tparseSessionCommands: boolean;\n\textensionCommands: SubmissionExtensionCommandPolicy;\n\tinputSource?: InputSource;\n\texpandSkills: boolean;\n\texpandPromptTemplates: boolean;\n}\n\ntype NormalizedSubmission =\n\t| { kind: \"prompt\"; text: string; images?: ImageContent[] }\n\t| {\n\t\t\tkind: \"sessionCommand\";\n\t\t\ttext: string;\n\t\t\timages?: ImageContent[];\n\t\t\tcommand: SessionSlashCommand;\n\t }\n\t| { kind: \"extensionCommand\"; completion: Promise<void> }\n\t| { kind: \"handled\" };\n\ntype PreTurnCompactionTiming = \"beforeModelSelection\" | \"afterModelSelection\" | \"skip\";\ntype RefineBarrierPolicy = \"always\" | \"ifInFlight\" | \"skip\";\n\ninterface CommitPreparationPolicy {\n\tinitialRefineBarrier: RefineBarrierPolicy;\n\tflushPendingBashBeforeValidation: boolean;\n\tvalidateModelAndAuth: boolean;\n\tawaitPendingModelSelection: boolean;\n\tpreTurnCompaction: PreTurnCompactionTiming;\n\tfinalRefineBarrier: RefineBarrierPolicy;\n}\n\ninterface CommitPreparationSteps<TPrepared, TCommitted> {\n\tafterValidation?: () => void;\n\tprepare: () => Promise<TPrepared>;\n\tshouldCommit?: (prepared: TPrepared) => boolean;\n\tbeforeFinalRefineBarrier?: (prepared: TPrepared) => void;\n\tcommit: (prepared: TPrepared, passedFinalRefineBarrier: boolean) => TCommitted;\n}\n\ntype QueuedAgentMessage = UserMessage | CustomMessage;\ntype SessionInputSchedule = \"steer\" | \"followUp\";\n\nexport interface TurnExecutionPolicy {\n\tpreparation: CommitPreparationPolicy;\n\trunBeforeAgentStart: boolean;\n\tnextTurnContextTiming: \"preparation\" | \"commit\" | \"skip\";\n\tpreserveEmptyExtensionPrompt: boolean;\n\tcompletionIncludesRetryChain: boolean;\n}\n\nfunction turnExecutionPoliciesEqual(left: TurnExecutionPolicy, right: TurnExecutionPolicy): boolean {\n\treturn (\n\t\tleft.preparation.initialRefineBarrier === right.preparation.initialRefineBarrier &&\n\t\tleft.preparation.flushPendingBashBeforeValidation === right.preparation.flushPendingBashBeforeValidation &&\n\t\tleft.preparation.validateModelAndAuth === right.preparation.validateModelAndAuth &&\n\t\tleft.preparation.awaitPendingModelSelection === right.preparation.awaitPendingModelSelection &&\n\t\tleft.preparation.preTurnCompaction === right.preparation.preTurnCompaction &&\n\t\tleft.preparation.finalRefineBarrier === right.preparation.finalRefineBarrier &&\n\t\tleft.runBeforeAgentStart === right.runBeforeAgentStart &&\n\t\tleft.nextTurnContextTiming === right.nextTurnContextTiming &&\n\t\tleft.preserveEmptyExtensionPrompt === right.preserveEmptyExtensionPrompt &&\n\t\tleft.completionIncludesRetryChain === right.completionIncludesRetryChain\n\t);\n}\n\ninterface PreparedTurnPayload extends SessionTurnPayload {\n\timages?: ImageContent[];\n\tcontent?: (TextContent | ImageContent)[];\n\tcustomMessage?: CustomMessage;\n\tprepared?: PreparedPromptPreparation;\n\texecutionPolicy: TurnExecutionPolicy;\n\tqueueVisible: boolean;\n\tacceptedAgentMessage: boolean;\n\tacceptedBeforeCompletion: boolean;\n\tcaptureRunMessages?: Set<AgentMessage>;\n\tcancelledDispatchEnded?: boolean;\n}\n\ninterface PreparedCommandPayload extends SessionCommandPayload {\n\timages?: ImageContent[];\n}\n\ntype QueuedSessionAction = SessionAction<PreparedTurnPayload | PreparedCommandPayload>;\n\ninterface PreparedPromptPreparation {\n\tresult: Awaited<ReturnType<ExtensionRunner[\"emitBeforeAgentStart\"]>>;\n\tbasePromptSnapshot: string;\n}\n\nclass DeferredSessionInputError extends Error {}\n\nfunction oncePreflight(\n\tpreflightResult: ((success: boolean, queued?: boolean) => void) | undefined,\n): (success: boolean, queued?: boolean) => void {\n\tlet settled = false;\n\treturn (success, queued = false) => {\n\t\tif (!settled) {\n\t\t\tsettled = true;\n\t\t\tpreflightResult?.(success, queued);\n\t\t}\n\t};\n}\n\ninterface RestoredPromptInput {\n\ttext: string;\n\tcontent?: (TextContent | ImageContent)[];\n\timages?: ImageContent[];\n\tqueueKey?: string;\n\tagentMessageId?: string;\n\tcustomMessage?: CustomMessage;\n\tprefixMessages?: CustomMessage[];\n}\n\nexport const SESSION_ACTION_RECOVERY_FORMAT_VERSION = 1;\n\nexport interface SessionActionRecoveryRecord {\n\tid: string;\n\trole: DeliveryRecord[\"role\"];\n\tmessage: QueuedAgentMessage;\n\townerActionId: string;\n}\n\nexport type SessionActionRecoveryPayload =\n\t| {\n\t\t\tkind: \"turn\";\n\t\t\ttext: string;\n\t\t\tpreview?: string;\n\t\t\trecords: SessionActionRecoveryRecord[];\n\t\t\timages?: ImageContent[];\n\t\t\tcontent?: (TextContent | ImageContent)[];\n\t\t\tcustomMessage?: CustomMessage;\n\t\t\texecutionPolicy: TurnExecutionPolicy;\n\t\t\tqueueVisible: boolean;\n\t\t\tacceptedAgentMessage: boolean;\n\t\t\tacceptedBeforeCompletion: boolean;\n\t }\n\t| {\n\t\t\tkind: \"session_command\";\n\t\t\ttext: string;\n\t\t\tcommand: SessionSlashCommand;\n\t\t\timages?: ImageContent[];\n\t };\n\nexport interface SessionActionRecoveryAction {\n\tid: string;\n\tsource: InputSource | \"internal\";\n\tdelivery: DeliveryPolicy;\n\twake: WakePolicy;\n\tpayload: SessionActionRecoveryPayload;\n\tqueueKey?: string;\n\tagentMessageId?: string;\n\tsuppressAutonomousContinuation?: boolean;\n}\n\nexport interface SessionActionRecoverySnapshot {\n\tformatVersion: typeof SESSION_ACTION_RECOVERY_FORMAT_VERSION;\n\tactions: SessionActionRecoveryAction[];\n}\n\nfunction cloneCustomMessage(message: CustomMessage): CustomMessage {\n\treturn {\n\t\t...message,\n\t\tcontent: Array.isArray(message.content) ? message.content.map((block) => ({ ...block })) : message.content,\n\t};\n}\n\nfunction cloneQueuedAgentMessage(message: QueuedAgentMessage): QueuedAgentMessage {\n\tif (message.role === \"custom\") return cloneCustomMessage(message);\n\treturn {\n\t\t...message,\n\t\tcontent: Array.isArray(message.content) ? message.content.map((block) => ({ ...block })) : message.content,\n\t};\n}\n\nfunction primaryDeliveryRecord(action: QueuedSessionAction): DeliveryRecord {\n\tif (action.payload.kind !== \"turn\") throw new Error(`Session action ${action.id} is not a turn`);\n\tconst record = action.payload.records.find((candidate) => candidate.role === \"primary\");\n\tif (!record) throw new Error(`Turn action ${action.id} has no primary delivery record`);\n\treturn record;\n}\n\nfunction normalizeMessageContent(content: string | (TextContent | ImageContent)[]): {\n\ttext: string;\n\timages?: ImageContent[];\n} {\n\tif (typeof content === \"string\") return { text: content };\n\tconst text = content\n\t\t.filter((part): part is TextContent => part.type === \"text\")\n\t\t.map((part) => part.text)\n\t\t.join(\"\\n\");\n\tconst images = content.filter((part): part is ImageContent => part.type === \"image\");\n\treturn { text, ...(images.length > 0 ? { images } : {}) };\n}\n\nfunction queuedAgentMessagePreview(action: QueuedSessionAction): string {\n\tconst payload = action.payload;\n\tif (payload.kind === \"session_command\") return payload.text;\n\tif (payload.customMessage && isAgentSessionMessage(payload.customMessage)) {\n\t\treturn `${AGENT_MESSAGE_RECEIVED_PREVIEW_LABEL}: ${payload.customMessage.details.message}`;\n\t}\n\treturn payload.preview ?? payload.text;\n}\n\nfunction visibleSessionActionProjection(actions: readonly QueuedSessionAction[]): readonly QueuedSessionAction[] {\n\treturn actions.filter(\n\t\t(action) =>\n\t\t\taction.payload.kind === \"session_command\" ||\n\t\t\taction.payload.queueVisible ||\n\t\t\taction.payload.acceptedAgentMessage,\n\t);\n}\n\nconst IPYTHON_SENT_AGENT_MESSAGE_CUSTOM_ENTRY = \"ipython_sent_agent_message\";\n\ninterface PersistedIpythonSentAgentMessage {\n\ttoolCallId: string;\n\tmessage: KernelSentAgentMessage;\n}\n\nfunction isObjectRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction parsePersistedIpythonSentAgentMessage(value: unknown): PersistedIpythonSentAgentMessage | undefined {\n\tif (!isObjectRecord(value) || typeof value.toolCallId !== \"string\" || !isObjectRecord(value.message)) {\n\t\treturn undefined;\n\t}\n\tconst { id, message, deliveryStatus, target } = value.message;\n\tif (\n\t\ttypeof id !== \"string\" ||\n\t\ttypeof message !== \"string\" ||\n\t\t(deliveryStatus !== \"delivered\" && deliveryStatus !== \"queued\") ||\n\t\t!isObjectRecord(target) ||\n\t\ttypeof target.activeSessionId !== \"string\" ||\n\t\ttypeof target.sessionId !== \"string\"\n\t) {\n\t\treturn undefined;\n\t}\n\treturn {\n\t\ttoolCallId: value.toolCallId,\n\t\tmessage: {\n\t\t\tid,\n\t\t\tmessage,\n\t\t\tdeliveryStatus,\n\t\t\ttarget: {\n\t\t\t\tactiveSessionId: target.activeSessionId,\n\t\t\t\tsessionId: target.sessionId,\n\t\t\t\t...(typeof target.sessionName === \"string\" ? { sessionName: target.sessionName } : {}),\n\t\t\t},\n\t\t},\n\t};\n}\n\nfunction appendSentAgentMessageToToolResult(\n\tmessage: AgentMessage,\n\ttoolCallId: string,\n\tsentMessage: KernelSentAgentMessage,\n): boolean {\n\tif (message.role !== \"toolResult\" || message.toolName !== \"ipython\" || message.toolCallId !== toolCallId) {\n\t\treturn false;\n\t}\n\tconst details = isObjectRecord(message.details) ? message.details : {};\n\tconst current = Array.isArray(details.sentAgentMessages) ? details.sentAgentMessages : [];\n\tif (current.some((entry) => isObjectRecord(entry) && entry.id === sentMessage.id)) {\n\t\treturn true;\n\t}\n\tmessage.details = {\n\t\t...details,\n\t\tsentAgentMessages: [...current, sentMessage],\n\t};\n\treturn true;\n}\n\nfunction injectedMessagePreviewLabel(message: CustomMessage): string | undefined {\n\tswitch (message.customType) {\n\t\tcase HEARTBEAT_PROMPT_CUSTOM_TYPE:\n\t\t\treturn HEARTBEAT_PROMPT_PREVIEW_LABEL;\n\t\tcase GOAL_CONTEXT_CUSTOM_TYPE:\n\t\t\treturn GOAL_CONTEXT_PREVIEW_LABEL;\n\t\tcase BACKGROUND_PROCESS_COMPLETED_CUSTOM_TYPE:\n\t\t\treturn \"Background process completed\";\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\ninterface AgentMessageDeferred {\n\tpromise: Promise<void>;\n\tresolve: () => void;\n\treject: (error: Error) => void;\n}\n\ninterface AgentMessageOutcome {\n\tdelivery?: AgentMessageDeferred;\n\tcompletion?: AgentMessageDeferred;\n}\n\nfunction createAgentMessageDeferred(): AgentMessageDeferred {\n\tconst deferred = {} as AgentMessageDeferred;\n\tdeferred.promise = new Promise<void>((resolve, reject) => {\n\t\tdeferred.resolve = resolve;\n\t\tdeferred.reject = reject;\n\t});\n\tdeferred.promise.catch(() => undefined);\n\treturn deferred;\n}\n\n/** One-shot settlement for a scheduled post-compaction continuation; a settled failure is never re-exposed to later waiters. */\ninterface PostCompactionContinuationSettlement extends AgentMessageDeferred {\n\tsettled: boolean;\n}\n\nfunction createPostCompactionContinuationSettlement(): PostCompactionContinuationSettlement {\n\treturn { ...createAgentMessageDeferred(), settled: false };\n}\n\nexport interface ModelCycleResult {\n\tmodel: Model<any>;\n\tthinkingLevel: ThinkingLevel;\n\tserviceTier: ServiceTier;\n\tisScoped: boolean;\n}\n\ninterface ModelSelectOptions {\n\twaitForExtensions?: boolean;\n}\n\ninterface ToolDefinitionEntry {\n\tdefinition: ToolDefinition;\n\tsourceInfo: SourceInfo;\n}\n\ntype GoalSlashCommand =\n\t| { kind: \"status\" }\n\t| { kind: \"clear\" }\n\t| { kind: \"pause\" }\n\t| { kind: \"resume\" }\n\t| { kind: \"start\"; objective: string; tokenBudget?: number };\n\ntype AutonomousSlashCommand = { kind: \"status\" } | { kind: \"on\" } | { kind: \"off\" };\n\nimport type { RlmMaxDepthSource, RlmMaxDepthStatus, SetRlmMaxDepthResult } from \"./rlm-max-depth.js\";\n\nexport type { RlmMaxDepthSource, RlmMaxDepthStatus, SetRlmMaxDepthResult } from \"./rlm-max-depth.js\";\n\ninterface PersistedRlmMaxDepthState {\n\tmaxDepth: number;\n}\n\ntype AutonomousRuntimeSnapshot = Pick<\n\tAutonomousRuntimeState,\n\t\"continuationsUsed\" | \"gateAttempts\" | \"lastGateFailure\" | \"lastGateFailureSnapshot\"\n>;\n\ninterface RlmChildRun {\n\tid: string;\n\tprompt: string;\n\tsessionName: string;\n\tsessionDir: string;\n\tmodel: Model<Api>;\n\tstatus: RlmChildAgentStatus;\n\terror?: string;\n\tabort: () => void;\n\tpublication: AgentMessageDeferred;\n\t/** Resolves after terminal result publication and detached-run cleanup finish. */\n\tsettlement: AgentMessageDeferred;\n\t/** Child session, once its runtime exists. Used to cancel nested child runs. */\n\tsession?: AgentSession;\n\tsettled: boolean;\n\t/** Do not inject a late terminal notice after the parent session is aborted. */\n\tsuppressTerminalNotice?: boolean;\n\t/** Excluded from future strong barriers after an authoritative cancellation cut. */\n\tabandonedForQuiescence?: boolean;\n\t/** Selector snapshot for an admitted explicit delete. */\n\tdetachedDeletion?: RlmSubagentRegistryEntry;\n\t/** Shared physical runtime cleanup owned by the explicit-delete path. */\n\tdeletionCleanup?: Promise<void>;\n\tdeletionCleanupObserver?: Promise<boolean>;\n\t/** Resolves when a deletion may release its selector reservation. */\n\tdeletionReservation: AgentMessageDeferred;\n\tdeletionCleanupFailed?: boolean;\n\tdeletionRunFinished?: boolean;\n\treportDeletionCleanupFailure?: (error: unknown) => Promise<void>;\n\temitUpdate?: () => void;\n\tunsubscribe?: () => void;\n}\n\ninterface RlmSubagentModelSelection {\n\tmodel: Model<Api>;\n}\n\nconst KERNEL_STATE_LISTING_TIMEOUT_MS = 5000;\nconst RLM_MAX_DEPTH_STATE_CUSTOM_TYPE = \"rlm_max_depth_state\";\n\nfunction noopRlmChildAbort(): void {}\nfunction noopRlmChildEventUnsubscribe(): void {}\n\nfunction autoRefineInstructions(reason: AutoRefineReason, review: AutoRefineReview): string {\n\tconst detail = review.instructions\n\t\t? `\nReviewer instructions: ${review.instructions}`\n\t\t: \"\";\n\treturn `Automatic refine review triggered by ${reason}. Only create/update/delete local harness entries if there is clear evidence that should help this session continue. Prefer an empty edits array over speculative or one-off memories. Do not promote anything global unless explicitly requested. Reviewer rationale: ${review.rationale}${detail}`;\n}\n\nfunction isNonNegativeInteger(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isSafeInteger(value) && value >= 0;\n}\n\nfunction parseDepth(value: string | undefined, fallback: number, name: string): number {\n\tif (value === undefined || value === \"\") {\n\t\treturn fallback;\n\t}\n\tif (!/^\\d+$/.test(value)) {\n\t\tthrow new Error(`${name} must be a non-negative integer`);\n\t}\n\tconst parsed = Number(value);\n\tif (!isNonNegativeInteger(parsed)) {\n\t\tthrow new Error(`${name} must be a non-negative integer`);\n\t}\n\treturn parsed;\n}\n\nfunction isPersistedRlmMaxDepthState(value: unknown): value is PersistedRlmMaxDepthState {\n\treturn (\n\t\ttypeof value === \"object\" && value !== null && isNonNegativeInteger((value as PersistedRlmMaxDepthState).maxDepth)\n\t);\n}\n\nfunction parseGoalBudgetValue(value: string): number {\n\tif (!/^[1-9]\\d*$/.test(value)) {\n\t\tthrow new Error(\"Goal token budget must be a positive integer.\");\n\t}\n\tconst budget = validateGoalBudget(Number(value));\n\tif (budget === undefined) {\n\t\tthrow new Error(\"Goal token budget must be a positive integer.\");\n\t}\n\treturn budget;\n}\n\nexport function compactRlmText(text: string, maxLength = 160): string {\n\tconst compact = text.replace(/\\s+/g, \" \").trim();\n\tif (compact.length <= maxLength) {\n\t\treturn compact;\n\t}\n\treturn `${compact.slice(0, Math.max(0, maxLength - 3)).trimEnd()}...`;\n}\n\n// Child-agent label: collapse to one line but keep the full prompt — the TUI\n// truncates to the visible width and elides shared prefixes, so capping here\n// would only hide the divergence between near-identical sibling prompts.\nexport function rlmChildLabel(prompt: string): string {\n\treturn prompt.replace(/\\s+/g, \" \").trim() || \"child agent\";\n}\n\nfunction readAssistantText(message: AssistantMessage): string {\n\treturn message.content\n\t\t.filter((block) => block.type === \"text\")\n\t\t.map((block) => block.text)\n\t\t.join(\"\");\n}\n\nfunction waitForPromiseOrAbort<T>(\n\tpromise: Promise<T>,\n\tsignal: AbortSignal | undefined,\n\tabortMessage: string,\n): Promise<T> {\n\tif (!signal) return promise;\n\tif (signal.aborted) return Promise.reject(new Error(abortMessage));\n\treturn new Promise<T>((resolve, reject) => {\n\t\tconst onAbort = () => {\n\t\t\tcleanup();\n\t\t\treject(new Error(abortMessage));\n\t\t};\n\t\tconst cleanup = () => signal.removeEventListener(\"abort\", onAbort);\n\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t// Close the listener-registration race before observing the awaited work.\n\t\tif (signal.aborted) return onAbort();\n\t\tpromise.then(\n\t\t\t(value) => {\n\t\t\t\tcleanup();\n\t\t\t\tresolve(value);\n\t\t\t},\n\t\t\t(error: unknown) => {\n\t\t\t\tcleanup();\n\t\t\t\treject(error);\n\t\t\t},\n\t\t);\n\t});\n}\n\nfunction attributeChildUsage(parentUsage: Usage, childUsage: Usage): void {\n\tconst parentContextTokens =\n\t\tparentUsage.totalTokens ||\n\t\tparentUsage.input + parentUsage.output + parentUsage.cacheRead + parentUsage.cacheWrite;\n\t// Recursive children are launched from an assistant tool call, so the parent assistant\n\t// message carries their billable usage for session-level cost totals.\n\taddAssistantUsage(parentUsage, childUsage);\n\t// Child work affects session-level billable totals, not the parent's model-facing context size.\n\tparentUsage.totalTokens = parentContextTokens;\n}\n\nexport class AgentSession {\n\treadonly agent: Agent;\n\treadonly sessionManager: SessionManager;\n\treadonly settingsManager: SettingsManager;\n\tprivate _serviceTierPreference: ServiceTier;\n\n\tprivate _scopedModels: Array<{\n\t\tmodel: Model<any>;\n\t\tthinkingLevel?: ThinkingLevel;\n\t}>;\n\n\tprivate _unsubscribeAgent?: () => void;\n\tprivate _eventListeners: AgentSessionEventListener[] = [];\n\tprivate _lastSessionActionSnapshot: SessionActionSnapshot = {\n\t\tqueuedCount: 0,\n\t\tsteering: [],\n\t\tfollowUps: [],\n\t};\n\tprivate _agentEventQueue: Promise<void> = Promise.resolve();\n\n\t/** Session-owned actions. Items are never fed into Agent.steer/followUp. */\n\tprivate readonly _actionStore = new ActionStore<QueuedSessionAction>();\n\tprivate _sessionInputPump: Promise<void> = Promise.resolve();\n\tprivate _sessionInputPumpRequested = false;\n\t// Invalidates preparation when a branch pause starts and finishes before its next await resumes.\n\tprivate _sessionInputPumpEpoch = 0;\n\tprivate _sessionInputArrivalEpoch = 0;\n\t// Persists abort/restart suspension after the initiating call returns.\n\tprivate _sessionInputPumpSuspended = false;\n\tprivate _sessionInputSuspendedForUpdateRestart = false;\n\t// Branch mutation pause leases can overlap and must all release before dispatch resumes.\n\tprivate readonly _queuedWorkPauses = new Set<symbol>();\n\tprivate readonly _sessionInputAdmissionPauses = new Set<symbol>();\n\tprivate readonly _durableRlmTerminalNoticeActionIds = new Set<string>();\n\tprivate readonly _backgroundProcessCompletionIds = new Set<string>();\n\tprivate _sessionActionCommitTail: Promise<void> = Promise.resolve();\n\tprivate _sessionActionCommitOwner: symbol | undefined;\n\tprivate _pendingSessionActionFenceWaiters = 0;\n\tprivate readonly _sessionActionCommitContext = new AsyncLocalStorage<symbol>();\n\tprivate readonly _sessionActionCommitDisposeAbortController = new AbortController();\n\t// Checkpoint and handoff waiters share lifecycle-edge notifications to avoid polling.\n\tprivate readonly _sessionInputCheckpointWaiters = new Set<() => void>();\n\tprivate _pendingNextTurnMessages: CustomMessage[] = [];\n\n\tprivate _goalState: GoalState = emptyGoalState();\n\tprivate _goalAccountingStartedAt: number | undefined = undefined;\n\tprivate _goalContinuationAwaitsRlmWork = false;\n\tprivate _goalAccountedAssistantMessages = new WeakSet<AssistantMessage>();\n\tprivate _goalAbortInProgress = false;\n\tprivate _autonomousState: AutonomousRuntimeState;\n\tprivate _autonomousContinuationSuppressionDepth = 0;\n\tprivate _autonomousContinuationSuppressedMessages = new WeakSet<AgentMessage>();\n\n\tprivate _compactionAbortController: AbortController | undefined = undefined;\n\tprivate _autoCompactionAbortController: AbortController | undefined = undefined;\n\tprivate _compactionOperation: Promise<void> | undefined = undefined;\n\t/** One recovery attempt per overflow; \"reported\" dedups the failure notice. */\n\tprivate _overflowRecovery: \"idle\" | \"attempted\" | \"reported\" = \"idle\";\n\tprivate _continueAfterThresholdCompaction = false;\n\tprivate _pendingRequestedCompaction: { customInstructions?: string } | undefined;\n\tprivate _pendingRequestedRefine: { instructions?: string; global?: boolean } | undefined;\n\n\tprivate _branchSummaryAbortController: AbortController | undefined = undefined;\n\tprivate _branchSummaryOperation: Promise<void> | undefined = undefined;\n\n\tprivate _retryAbortController: AbortController | undefined = undefined;\n\tprivate _retryAttempt = 0;\n\tprivate _retryPromise: Promise<void> | undefined = undefined;\n\tprivate _retryResolve: (() => void) | undefined = undefined;\n\tprivate _retryAuthFailureSources: AuthSourceToken[] = [];\n\tprivate _agentMessageClearEpoch = 0;\n\tprivate _agentMessageOutcomes = new Map<string, AgentMessageOutcome>();\n\tprivate _lateIpythonSentAgentMessages = new Map<string, KernelSentAgentMessage[]>();\n\t/** Outcome disclosures whose session-file append failed; retained for context rebuilds. */\n\tprivate readonly _unpersistedOutcomes: CustomMessage[] = [];\n\n\tprivate _bashAbortControllers = new Set<AbortController>();\n\tprivate _userBashRunning = false;\n\tprivate _userBashAbortRequested = false;\n\tprivate _pendingBashMessages: BashExecutionMessage[] = [];\n\n\tprivate _extensionRunner!: ExtensionRunner;\n\tprivate _execEnvProvider?: () => Record<string, string | undefined> | undefined;\n\tprivate _turnIndex = 0;\n\tprivate _modelSelectEmitQueue: Promise<void> = Promise.resolve();\n\tprivate _modelSelectEmitQueueIdle = true;\n\tprivate _modelSelectEmitContext = new AsyncLocalStorage<boolean>();\n\n\tprivate _resourceLoader: ResourceLoader;\n\tprivate _customTools: ToolDefinition[];\n\tprivate _acpMcpTools: ToolDefinition[] = [];\n\tprivate _baseToolDefinitions: Map<string, ToolDefinition> = new Map();\n\tprivate _cwd: string;\n\tprivate _agentDir?: string;\n\tprivate _extensionRunnerRef?: { current?: ExtensionRunner };\n\tprivate _initialActiveToolNames?: string[];\n\tprivate _allowedToolNames?: Set<string>;\n\tprivate _includeGoals: boolean;\n\tprivate _includeCompactSkill: boolean;\n\tprivate _rlmHeartbeatController?: AgentRlmHeartbeatController;\n\tprivate _agentMessageController?: AgentSessionMessageController;\n\tprivate _agentObserveController?: AgentObserveController;\n\tprivate _mcpManager?: McpManager;\n\tprivate _baseToolsOverride?: Record<string, AgentTool>;\n\tprivate _sessionStartEvent: SessionStartEvent;\n\tprivate _extensionUIContext?: ExtensionUIContext;\n\tprivate _extensionCommandContextActions?: ExtensionCommandContextActions;\n\tprivate _extensionShutdownHandler?: ShutdownHandler;\n\tprivate _extensionErrorListener?: ExtensionErrorListener;\n\tprivate _extensionErrorUnsubscriber?: () => void;\n\tprivate _disposed = false;\n\tprivate readonly _disposeCallbacks = new Set<() => void | Promise<void>>();\n\tprivate _disposeCallbacksPromise?: Promise<void>;\n\t// Set at the start of async teardown so a child finishing mid-disposeAsync doesn't\n\t// re-populate the retained map after it's been cleared.\n\tprivate _disposing = false;\n\tprivate _disposeAsyncPromise?: Promise<void>;\n\tprivate _ipythonKernelProvisioner?: IpythonKernelProvisioner;\n\t/** Artifact dir backing the current provisioner's kernel snapshot, if any. */\n\tprivate _ipythonKernelSnapshotDir?: string;\n\t/** True once the runtime has been built once; later builds are in-process rebuilds (/reload). */\n\tprivate _ipythonRuntimeBuilt = false;\n\tprivate readonly _prewarmIpythonKernel: boolean;\n\tprivate _rlmDepth: number;\n\tprivate readonly _configuredRlmMaxDepth: number | undefined;\n\tprivate _rlmMaxDepth: number;\n\tprivate _rlmMaxDepthSource: RlmMaxDepthSource;\n\tprivate _rlmSessionDir?: string;\n\tprivate _rlmParentNodeId?: string;\n\tprivate _rlmParentAgent?: string;\n\tprivate _repliedToParentSinceTask: boolean | undefined;\n\tprivate _parentReplyCount = 0;\n\tprivate _subagentRuntimeHost?: SubagentRuntimeHost;\n\tprivate _activeRlmChildRuns = new Map<string, RlmChildRun>();\n\tprivate _unsettledRlmChildRuns = new Set<RlmChildRun>();\n\tprivate _abandonedRlmQuiescenceChildIds = new Set<string>();\n\tprivate _rlmQuiescenceWaitAborts = new Set<AbortController>();\n\tprivate _pendingRlmSubagentSessionNames = new Set<string>();\n\t// Inline mode keeps finished child sessions so the inspector can still read them;\n\t// the daemon does the same by leaving the child session resident in its registry.\n\tprivate _rlmChildSessions = new Map<string, AgentSession>();\n\tprivate _deletedRlmChildIds = new Set<string>();\n\t// Failed explicit deletes stay hidden from listings but retain their original\n\t// selector so a later delete can retry cleanup without orphaning the runtime.\n\tprivate _rlmChildCleanupFailures = new Map<string, RlmSubagentRegistryEntry>();\n\tprivate _deletingRlmChildren = new Map<\n\t\tstring,\n\t\t{\n\t\t\tsubagent: RlmSubagentRegistryEntry;\n\t\t\tpromise: Promise<RlmDeleteSubagentResult>;\n\t\t}\n\t>();\n\t// Kept alive for retained children so nested updates (e.g. a grandchild cancel)\n\t// still forward to root; torn down when the retained child is disposed.\n\tprivate _rlmChildUnsubscribes = new Map<string, () => void>();\n\t/** Latest recap for this session, written by the daemon summarizer; read by a parent to label its child snapshots. */\n\tprivate _currentRecap?: string;\n\n\tprivate _modelRegistry: ModelRegistry;\n\n\tprivate _toolRegistry: Map<string, AgentTool> = new Map();\n\tprivate _toolDefinitions: Map<string, ToolDefinitionEntry> = new Map();\n\tprivate _toolPromptSnippets: Map<string, string> = new Map();\n\tprivate _toolPromptGuidelines: Map<string, string[]> = new Map();\n\n\tprivate _baseSystemPrompt = \"\";\n\tprivate _baseSystemPromptOptions!: BuildSystemPromptOptions;\n\tprivate _assistantTurnsSinceAutoRefine = 0;\n\tprivate _lastAutoRefineReviewAt = 0;\n\tprivate _autoRefineInProgress = false;\n\tprivate readonly _autoRefineOperations = new Set<Promise<void>>();\n\tprivate readonly _scheduledAutoRefineTimers = new Set<ReturnType<typeof setTimeout>>();\n\tprivate _compactAutoRefinePending = false;\n\tprivate _turnIntervalAutoRefinePending = false;\n\tprivate _postCompactionContinuationScheduled = false;\n\tprivate _postCompactionContinuationTimer: ReturnType<typeof setTimeout> | undefined;\n\tprivate _postCompactionContinuationSettlement: PostCompactionContinuationSettlement | undefined;\n\tprivate _postCompactionContinuationMessages: AgentMessage[] = [];\n\tprivate _scheduledPostCompactionContinuationMessages: AgentMessage[] = [];\n\tprivate _queuedAutonomousThresholdContinuations = new WeakMap<AssistantMessage, AgentMessage>();\n\tprivate _queuedAutonomousContinuationSnapshots = new WeakMap<AgentMessage, AutonomousRuntimeSnapshot>();\n\tprivate _pendingThresholdCompactionAutonomousMessages: AgentMessage[] = [];\n\tprivate _queuedGoalThresholdContinuation: AgentMessage | undefined;\n\tprivate _pendingAutoRefineReview: { reason: AutoRefineReason; review: AutoRefineReview } | undefined;\n\tprivate _autoRefineBranchVersion = 0;\n\tprivate _autoRefineReviewAbort?: AbortController;\n\tprivate _refineAbortController?: AbortController;\n\tprivate readonly _autoRefineReviewer?: AutoRefineReviewer;\n\tprivate readonly _serializedRefine: boolean;\n\tprivate _refineInFlight?: Promise<void>;\n\tprivate _refinePlanInFlight?: Promise<void>;\n\tprivate _serializedPlanInFlight?: Promise<SerializedBackgroundPlanResult | undefined>;\n\tprivate _serializedPlanClaim?: Promise<void>;\n\tprivate _serializedExplicitRefineOptions?: {\n\t\tinstructions?: string;\n\t\tglobal?: boolean;\n\t};\n\n\tconstructor(config: AgentSessionConfig) {\n\t\tthis.agent = config.agent;\n\t\tthis.sessionManager = config.sessionManager;\n\t\tthis.settingsManager = config.settingsManager;\n\t\tthis._serviceTierPreference = config.serviceTierPreference ?? config.agent.state.serviceTier;\n\t\tthis._scopedModels = config.scopedModels ?? [];\n\t\tthis._resourceLoader = config.resourceLoader;\n\t\tthis._customTools = config.customTools ?? [];\n\t\tthis._cwd = config.cwd;\n\t\tthis._agentDir = config.agentDir;\n\t\tthis._modelRegistry = config.modelRegistry;\n\t\tthis._extensionRunnerRef = config.extensionRunnerRef;\n\t\tthis._initialActiveToolNames = config.initialActiveToolNames;\n\t\tthis._allowedToolNames = config.allowedToolNames ? new Set(config.allowedToolNames) : undefined;\n\t\tthis._includeGoals = config.includeGoals ?? true;\n\t\tthis._includeCompactSkill = config.includeCompactSkill ?? this.settingsManager.getCompactionAgentCallable();\n\t\tthis._rlmHeartbeatController = config.rlmHeartbeatController;\n\t\tthis._agentMessageController = config.agentMessageController;\n\t\tthis._agentObserveController = config.agentObserveController;\n\t\tthis._mcpManager = config.mcpManager;\n\t\tthis._baseToolsOverride = config.baseToolsOverride;\n\t\tthis._sessionStartEvent = config.sessionStartEvent ?? { type: \"session_start\", reason: \"startup\" };\n\t\tconst headerRlmDepth = this.sessionManager.getHeader()?.rlmDepth;\n\t\tthis._rlmDepth =\n\t\t\tconfig.rlmDepth ??\n\t\t\t(isNonNegativeInteger(headerRlmDepth) ? headerRlmDepth : parseDepth(process.env.RLM_DEPTH, 0, \"RLM_DEPTH\"));\n\t\tthis._configuredRlmMaxDepth = config.rlmMaxDepth;\n\t\tif (this._configuredRlmMaxDepth !== undefined && !isNonNegativeInteger(this._configuredRlmMaxDepth)) {\n\t\t\tthrow new Error(\"rlmMaxDepth must be a non-negative integer\");\n\t\t}\n\t\tconst resolvedRlmMaxDepth = this._resolveRlmMaxDepth();\n\t\tthis._rlmMaxDepth = resolvedRlmMaxDepth.maxDepth;\n\t\tthis._rlmMaxDepthSource = resolvedRlmMaxDepth.source;\n\t\tthis._prewarmIpythonKernel = (config.prewarmIpythonKernel ?? false) && this._rlmDepth === 0;\n\t\tthis._autoRefineReviewer = config.autoRefineReviewer;\n\t\tthis._serializedRefine = config.serializedRefine ?? false;\n\t\tthis._rlmSessionDir = config.rlmSessionDir;\n\t\tthis._rlmParentNodeId = config.rlmParentNodeId;\n\t\tthis._rlmParentAgent = config.rlmParentAgent;\n\t\t// A resumed child may have replied before this process started; false would\n\t\t// claim knowledge that is not present in the session transcript.\n\t\tthis._repliedToParentSinceTask =\n\t\t\tthis._rlmDepth > 0 && this.sessionManager.getBranch().some((entry) => entry.type === \"message\")\n\t\t\t\t? undefined\n\t\t\t\t: false;\n\t\tthis._subagentRuntimeHost = config.subagentRuntimeHost;\n\t\tthis._autonomousState = createAutonomousRuntimeState(config.autonomous, {\n\t\t\tcwd: this._cwd,\n\t\t});\n\t\tthis._goalState = this._loadPersistedGoalState();\n\t\t// Seed initial goal from CLI --goal flag, but only for top-level sessions\n\t\t// and only when the branch contains only bootstrap entry types (model_change,\n\t\t// thinking_level_change, service_tier_change) and no persisted\n\t\t// thread_goal_state. This prevents reseeding after clear/complete/error\n\t\t// or restart/rehydration of a session that already has messages or a goal.\n\t\tif (this._rlmDepth === 0 && config.initialGoal && this._isBranchSeedable()) {\n\t\t\tthis._goalState = this._startGoal(config.initialGoal.objective, config.initialGoal.tokenBudget);\n\t\t\t// Goal context is the model's only source of goal visibility; action\n\t\t\t// admission is unavailable mid-construction, so ride the next turn.\n\t\t\tthis._pendingNextTurnMessages.push(createGoalContextMessage(this._goalState, \"continuation\"));\n\t\t}\n\t\tthis._restoreLateIpythonSentAgentMessages();\n\t\tif (this._goalState.status === \"active\") {\n\t\t\tthis._goalAccountingStartedAt = Date.now();\n\t\t}\n\n\t\tthis._unsubscribeAgent = this.agent.subscribe(this._handleAgentEvent);\n\t\tthis._installAgentToolHooks();\n\t\tthis._installAgentTurnHook();\n\t\tthis._installAgentContinuationHook();\n\n\t\tthis._buildRuntime({\n\t\t\tactiveToolNames: this._initialActiveToolNames,\n\t\t\tincludeAllExtensionTools: true,\n\t\t});\n\t}\n\n\t/** Refreshes MCP provider registrations without rebuilding the session runtime. */\n\trefreshMcpProviders(): void {\n\t\tthis._mcpManager?.refresh();\n\t}\n\n\t/**\n\t * Set the RLM heartbeat controller after construction. Used by\n\t * print/headless mode to attach an in-process heartbeat scheduler\n\t * when the session is created outside the daemon.\n\t */\n\tsetRlmHeartbeatController(controller: AgentRlmHeartbeatController): void {\n\t\tif (this._rlmHeartbeatController === controller) {\n\t\t\treturn;\n\t\t}\n\t\tthis._rlmHeartbeatController = controller;\n\t\tthis._buildRuntime({\n\t\t\tactiveToolNames: this.getActiveToolNames(),\n\t\t\tincludeAllExtensionTools: true,\n\t\t});\n\t\tthis._baseSystemPrompt = this._rebuildSystemPrompt(this.getActiveToolNames());\n\t\tthis.agent.state.systemPrompt = this._baseSystemPrompt;\n\t}\n\n\treplaceAcpMcpServers(servers: readonly AcpMcpServerConfig[], ownerId: string): void {\n\t\tif (this.isStreaming) throw new Error(\"Cannot replace ACP MCP servers while the agent is running\");\n\t\tif (!this._mcpManager) {\n\t\t\tif (servers.length > 0) throw new Error(\"MCP is unavailable in this session\");\n\t\t\treturn;\n\t\t}\n\t\tif (servers.length > 0 && !this._ipythonKernelProvisioner) {\n\t\t\tthrow new Error(\"ACP MCP servers require the built-in cpython tool\");\n\t\t}\n\t\tthis._assertAcpMcpToolNamesAvailable(acpMcpToolNames(servers));\n\t\tif (!this._mcpManager.replaceAcpServers(servers, ownerId)) return;\n\t\tthis._rebuildRuntimeForAcpMcpServers();\n\t}\n\n\tasync releaseAcpMcpServers(ownerId: string, serverNames: readonly string[]): Promise<void> {\n\t\tif (!this._mcpManager?.canReleaseAcpServers(ownerId)) return;\n\t\tif (this._mcpManager.replaceAcpServers([], ownerId)) {\n\t\t\tconst removedToolNames = new Set(this._acpMcpTools.map((tool) => tool.name));\n\t\t\tconst activeToolNames = this.getActiveToolNames().filter((name) => !removedToolNames.has(name));\n\t\t\tfor (const name of removedToolNames) this._allowedToolNames?.delete(name);\n\t\t\tthis._acpMcpTools = [];\n\t\t\tthis._refreshToolRegistry({ activeToolNames, includeAllExtensionTools: true });\n\t\t\tthis._baseSystemPrompt = this._rebuildSystemPrompt(this.getActiveToolNames());\n\t\t\tthis.agent.state.systemPrompt = this._baseSystemPrompt;\n\t\t}\n\t\tconst names = [...new Set(serverNames)];\n\t\tif (names.length === 0) return;\n\n\t\tconst inputPause = this.acquireSessionInputPause();\n\t\ttry {\n\t\t\t// Do not rebuild or kill the notebook. Wait for the current turn, then ask\n\t\t\t// the kernel-owned MCP registry to close only these cached transports.\n\t\t\tawait this.agent.waitForIdle();\n\t\t\tawait this._agentEventQueue;\n\t\t\tconst manager = this._ipythonKernelProvisioner?.manager;\n\t\t\tif (!manager?.isRunning) return;\n\t\t\tconst code = [\n\t\t\t\t\"import importlib as _prime_importlib\",\n\t\t\t\t'_prime_mcp = _prime_importlib.import_module(\"rlm.mcp\")',\n\t\t\t\t`_prime_mcp_names = ${JSON.stringify(names)}`,\n\t\t\t\t\"_prime_mcp_errors = []\",\n\t\t\t\t\"for _prime_mcp_name in _prime_mcp_names:\",\n\t\t\t\t\" try:\",\n\t\t\t\t\" await _prime_mcp.reload(_prime_mcp_name)\",\n\t\t\t\t\" except BaseException as _prime_mcp_error:\",\n\t\t\t\t\" _prime_mcp_errors.append(_prime_mcp_error)\",\n\t\t\t\t\"if _prime_mcp_errors:\",\n\t\t\t\t\" raise _prime_mcp_errors[0]\",\n\t\t\t\t\"del _prime_mcp, _prime_importlib, _prime_mcp_names, _prime_mcp_errors, _prime_mcp_name\",\n\t\t\t].join(\"\\n\");\n\t\t\tconst result = await manager.execute(code);\n\t\t\tif (result.status !== \"ok\") {\n\t\t\t\tthrow new Error(`Failed to close ACP MCP kernel transports: ${result.stderr || \"kernel error\"}`);\n\t\t\t}\n\t\t} finally {\n\t\t\tinputPause.release();\n\t\t}\n\t}\n\n\tprivate _assertAcpMcpToolNamesAvailable(names: readonly string[]): void {\n\t\tconst occupiedNames = new Set([\n\t\t\t...this._baseToolDefinitions.keys(),\n\t\t\t...this._customTools.map((tool) => tool.name),\n\t\t\t...this._extensionRunner.getAllRegisteredTools().map((tool) => tool.definition.name),\n\t\t]);\n\t\tfor (const name of names) {\n\t\t\tif (occupiedNames.has(name)) {\n\t\t\t\tthrow new Error(`ACP MCP tool name conflicts with an existing tool: ${name}`);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _rebuildRuntimeForAcpMcpServers(): void {\n\t\tconst previousToolNames = new Set(this._acpMcpTools.map((tool) => tool.name));\n\t\tconst nextToolNames = acpMcpToolNames(this._mcpManager?.getAcpServers() ?? []);\n\t\tthis._assertAcpMcpToolNamesAvailable(nextToolNames);\n\t\tconst activeToolNames = this.getActiveToolNames().filter((name) => !previousToolNames.has(name));\n\t\tactiveToolNames.push(...nextToolNames);\n\t\tthis._buildRuntime({\n\t\t\tactiveToolNames,\n\t\t\tincludeAllExtensionTools: true,\n\t\t});\n\t\tthis._baseSystemPrompt = this._rebuildSystemPrompt(this.getActiveToolNames());\n\t\tthis.agent.state.systemPrompt = this._baseSystemPrompt;\n\t}\n\n\tget modelRegistry(): ModelRegistry {\n\t\treturn this._modelRegistry;\n\t}\n\n\tsetSubagentRuntimeHost(host?: SubagentRuntimeHost): void {\n\t\tthis._subagentRuntimeHost = host;\n\t}\n\n\tprivate async _getRequiredRequestAuth(model: Model<any>): Promise<{\n\t\tapiKey: string;\n\t\theaders?: Record<string, string>;\n\t}> {\n\t\tconst result = await this._modelRegistry.getApiKeyAndHeaders(model);\n\t\tif (!result.ok) {\n\t\t\tif (result.error.startsWith(\"No API key found\")) {\n\t\t\t\tthrow new Error(formatNoApiKeyFoundMessage(model.provider));\n\t\t\t}\n\t\t\tthrow new Error(result.error);\n\t\t}\n\t\tif (result.apiKey) {\n\t\t\treturn { apiKey: result.apiKey, headers: result.headers };\n\t\t}\n\n\t\tconst isOAuth = this._modelRegistry.isUsingOAuth(model);\n\t\tif (isOAuth) {\n\t\t\tthrow new Error(formatAuthenticationFailedMessage(model.provider));\n\t\t}\n\t\tthrow new Error(formatNoApiKeyFoundMessage(model.provider));\n\t}\n\n\t/**\n\t * Install tool hooks once on the Agent instance.\n\t *\n\t * The callbacks read `this._extensionRunner` at execution time, so extension reload swaps in the\n\t * new runner without reinstalling hooks. Extension-specific tool wrappers are still used to adapt\n\t * registered tool execution to the extension context. Tool call and tool result interception now\n\t * happens here instead of in wrappers.\n\t */\n\tprivate _installAgentToolHooks(): void {\n\t\tthis.agent.beforeToolCall = async ({ toolCall, args }) => {\n\t\t\tconst runner = this._extensionRunner;\n\t\t\tif (!runner.hasHandlers(\"tool_call\")) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tawait this._agentEventQueue;\n\n\t\t\ttry {\n\t\t\t\treturn await runner.emitToolCall({\n\t\t\t\t\ttype: \"tool_call\",\n\t\t\t\t\ttoolName: toolCall.name,\n\t\t\t\t\ttoolCallId: toolCall.id,\n\t\t\t\t\tinput: args as Record<string, unknown>,\n\t\t\t\t});\n\t\t\t} catch (err) {\n\t\t\t\tif (err instanceof Error) {\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\t\t\t\tthrow new Error(`Extension failed, blocking execution: ${String(err)}`);\n\t\t\t}\n\t\t};\n\n\t\tthis.agent.afterToolCall = async ({ toolCall, args, result, isError }) => {\n\t\t\tconst runner = this._extensionRunner;\n\t\t\tif (!runner.hasHandlers(\"tool_result\")) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tconst hookResult = await runner.emitToolResult({\n\t\t\t\ttype: \"tool_result\",\n\t\t\t\ttoolName: toolCall.name,\n\t\t\t\ttoolCallId: toolCall.id,\n\t\t\t\tinput: args as Record<string, unknown>,\n\t\t\t\tcontent: result.content,\n\t\t\t\tdetails: result.details,\n\t\t\t\tisError,\n\t\t\t});\n\n\t\t\tif (!hookResult) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tcontent: hookResult.content,\n\t\t\t\tdetails: hookResult.details,\n\t\t\t\tisError: hookResult.isError ?? isError,\n\t\t\t};\n\t\t};\n\t}\n\n\tprivate _installAgentContinuationHook(): void {\n\t\tthis.agent.getContinuationMessages = (context, signal) => this._getContinuationMessages(context, signal);\n\t}\n\n\tprivate _installAgentTurnHook(): void {\n\t\tthis.agent.shouldStopBeforeTurn = () => this._shouldStopBeforeTurn();\n\t\tthis.agent.shouldStopAfterTurn = (context) => this._shouldStopAfterTurn(context);\n\t}\n\n\tprivate _emit(event: AgentSessionEvent): void {\n\t\tfor (const l of this._eventListeners) {\n\t\t\ttry {\n\t\t\t\tl(event);\n\t\t\t} catch {\n\t\t\t\t// A failing observer must not prevent other subscribers from\n\t\t\t\t// receiving lifecycle and persistence events.\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _emitQueueUpdate(): void {\n\t\tconst actions = this.getSessionActionSnapshot();\n\t\tif (JSON.stringify(actions) === JSON.stringify(this._lastSessionActionSnapshot)) return;\n\t\tthis._lastSessionActionSnapshot = actions;\n\t\tthis._emit({ type: \"session_action_update\", actions });\n\t}\n\n\tprivate _restoreLateIpythonSentAgentMessages(): void {\n\t\tthis._lateIpythonSentAgentMessages.clear();\n\t\tfor (const entry of this.sessionManager.getBranch()) {\n\t\t\tif (entry.type !== \"custom\" || entry.customType !== IPYTHON_SENT_AGENT_MESSAGE_CUSTOM_ENTRY) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst persisted = parsePersistedIpythonSentAgentMessage(entry.data);\n\t\t\tif (persisted) {\n\t\t\t\tthis._rememberLateIpythonSentAgentMessage(persisted.toolCallId, persisted.message);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _rememberLateIpythonSentAgentMessage(toolCallId: string, message: KernelSentAgentMessage): boolean {\n\t\tconst messages = this._lateIpythonSentAgentMessages.get(toolCallId) ?? [];\n\t\tconst isNew = !messages.some((entry) => entry.id === message.id);\n\t\tif (isNew) {\n\t\t\tmessages.push(message);\n\t\t\tthis._lateIpythonSentAgentMessages.set(toolCallId, messages);\n\t\t}\n\t\tfor (let index = this.agent.state.messages.length - 1; index >= 0; index -= 1) {\n\t\t\tif (appendSentAgentMessageToToolResult(this.agent.state.messages[index], toolCallId, message)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn isNew;\n\t}\n\n\tprivate _applyLateIpythonSentAgentMessages(message: AgentMessage): void {\n\t\tif (message.role !== \"toolResult\" || message.toolName !== \"ipython\") {\n\t\t\treturn;\n\t\t}\n\t\tfor (const sentMessage of this._lateIpythonSentAgentMessages.get(message.toolCallId) ?? []) {\n\t\t\tappendSentAgentMessageToToolResult(message, message.toolCallId, sentMessage);\n\t\t}\n\t}\n\n\tprivate _recordLateIpythonSentAgentMessage(toolCallId: string, message: KernelSentAgentMessage): void {\n\t\tconst record = () => {\n\t\t\tif (this._disposed || !this._rememberLateIpythonSentAgentMessage(toolCallId, message)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.sessionManager.appendCustomEntry(IPYTHON_SENT_AGENT_MESSAGE_CUSTOM_ENTRY, { toolCallId, message });\n\t\t\tthis._emit({ type: \"ipython_sent_agent_message\", toolCallId, message });\n\t\t};\n\t\tthis._agentEventQueue = this._agentEventQueue.then(record, record);\n\t\tthis._agentEventQueue.catch(() => {});\n\t}\n\n\tprivate _emitGoalUpdate(): void {\n\t\tthis._emit({ type: \"goal_update\", goal: this.goalState });\n\t}\n\n\tprivate _loadPersistedRlmMaxDepthState(): PersistedRlmMaxDepthState | undefined {\n\t\tconst branch = this.sessionManager.getBranch();\n\t\tfor (let i = branch.length - 1; i >= 0; i--) {\n\t\t\tconst entry = branch[i];\n\t\t\tif (\n\t\t\t\tentry.type === \"custom\" &&\n\t\t\t\tentry.customType === RLM_MAX_DEPTH_STATE_CUSTOM_TYPE &&\n\t\t\t\tisPersistedRlmMaxDepthState(entry.data)\n\t\t\t) {\n\t\t\t\treturn entry.data;\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate _resolveRlmMaxDepth(): {\n\t\tmaxDepth: number;\n\t\tsource: RlmMaxDepthSource;\n\t} {\n\t\tconst persisted = this._loadPersistedRlmMaxDepthState();\n\t\tif (persisted) {\n\t\t\treturn { maxDepth: persisted.maxDepth, source: \"chat\" };\n\t\t}\n\t\tif (this._configuredRlmMaxDepth !== undefined) {\n\t\t\treturn { maxDepth: this._configuredRlmMaxDepth, source: \"inherited\" };\n\t\t}\n\t\tconst global = this.settingsManager.getRlmMaxDepth();\n\t\tif (global !== undefined && isNonNegativeInteger(global)) {\n\t\t\treturn { maxDepth: global, source: \"global\" };\n\t\t}\n\t\tconst env = process.env.RLM_MAX_DEPTH;\n\t\tif (env !== undefined && env !== \"\") {\n\t\t\treturn { maxDepth: parseDepth(env, 1, \"RLM_MAX_DEPTH\"), source: \"env\" };\n\t\t}\n\t\treturn { maxDepth: 2, source: \"default\" };\n\t}\n\n\tprivate _loadPersistedGoalState(): GoalState {\n\t\tconst branch = this.sessionManager.getBranch();\n\t\tfor (let i = branch.length - 1; i >= 0; i--) {\n\t\t\tconst entry = branch[i];\n\t\t\tif (\n\t\t\t\tentry.type === \"custom\" &&\n\t\t\t\tentry.customType === GOAL_STATE_CUSTOM_TYPE &&\n\t\t\t\tisPersistedGoalState(entry.data)\n\t\t\t) {\n\t\t\t\treturn normalizeGoalState(entry.data);\n\t\t\t}\n\t\t}\n\t\treturn emptyGoalState();\n\t}\n\n\t/**\n\t * Whether the session branch is seedable for an initial goal. Returns true\n\t * only when the branch contains exclusively bootstrap entry types\n\t * (model_change, thinking_level_change, service_tier_change) and no\n\t * thread_goal_state custom entry. Any message, custom entry, or persisted\n\t * goal (including cleared/complete/error) means the session has been used\n\t * and should not be reseeded.\n\t */\n\tprivate _isBranchSeedable(): boolean {\n\t\tconst branch = this.sessionManager.getBranch();\n\t\tfor (const entry of branch) {\n\t\t\tswitch (entry.type) {\n\t\t\t\tcase \"model_change\":\n\t\t\t\tcase \"thinking_level_change\":\n\t\t\t\tcase \"service_tier_change\":\n\t\t\t\t\tcontinue;\n\t\t\t\tcase \"custom\":\n\t\t\t\t\tif (entry.customType === GOAL_STATE_CUSTOM_TYPE) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn false;\n\t\t\t\tdefault:\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate _reloadGoalStateFromBranch(): void {\n\t\tthis._goalState = this._loadPersistedGoalState();\n\t\tthis._goalAccountingStartedAt = this._goalState.status === \"active\" ? Date.now() : undefined;\n\t\tthis._emitGoalUpdate();\n\t}\n\n\tprivate _reloadRlmMaxDepthFromBranch(): void {\n\t\tconst previousMaxDepth = this._rlmMaxDepth;\n\t\tconst resolved = this._resolveRlmMaxDepth();\n\t\tthis._rlmMaxDepth = resolved.maxDepth;\n\t\tthis._rlmMaxDepthSource = resolved.source;\n\t\tif (resolved.maxDepth !== previousMaxDepth) {\n\t\t\tthis._baseSystemPrompt = this._rebuildSystemPrompt(this.getActiveToolNames());\n\t\t\tthis.agent.state.systemPrompt = this._baseSystemPrompt;\n\t\t}\n\t}\n\n\tprivate _persistGoalState(goal: GoalState): void {\n\t\tthis.sessionManager.appendCustomEntry(GOAL_STATE_CUSTOM_TYPE, goal);\n\t\t// Force flush so the goal state is durable on disk immediately,\n\t\t// even before the first assistant response. This ensures idempotent\n\t\t// restart/rehydration can detect the persisted goal.\n\t\tthis.sessionManager.flushNow();\n\t}\n\n\tprivate _setGoalState(next: GoalState, options: { persist?: boolean } = {}): void {\n\t\tconst normalized = normalizeGoalState({\n\t\t\t...next,\n\t\t\tupdatedAt: Date.now(),\n\t\t});\n\t\tthis._goalState = normalized;\n\t\tif (normalized.status === \"active\") {\n\t\t\tthis._goalAccountingStartedAt ??= Date.now();\n\t\t} else {\n\t\t\tthis._goalAccountingStartedAt = undefined;\n\t\t}\n\t\tif (options.persist !== false) {\n\t\t\tthis._persistGoalState(normalized);\n\t\t}\n\t\tthis._emitGoalUpdate();\n\t}\n\n\tprivate _goalWithCurrentWallClock(now = Date.now()): GoalState {\n\t\tif (this._goalState.status !== \"active\" || !this._goalAccountingStartedAt) {\n\t\t\treturn this._goalState;\n\t\t}\n\t\tconst elapsedSeconds = Math.floor((now - this._goalAccountingStartedAt) / 1000);\n\t\tif (elapsedSeconds <= 0) {\n\t\t\treturn this._goalState;\n\t\t}\n\t\treturn {\n\t\t\t...this._goalState,\n\t\t\ttimeUsedSeconds: this._goalState.timeUsedSeconds + elapsedSeconds,\n\t\t};\n\t}\n\n\tprivate _goalWithAccountedWallClock(): GoalState {\n\t\tconst now = Date.now();\n\t\tconst goal = this._goalWithCurrentWallClock(now);\n\t\tif (goal !== this._goalState) {\n\t\t\tthis._goalAccountingStartedAt = now;\n\t\t}\n\t\treturn goal;\n\t}\n\n\tprivate _cancelSessionActions(\n\t\tpredicate: (action: QueuedSessionAction) => boolean,\n\t\terror: Error,\n\t\tcandidates = this._actionStore.clearableActions(),\n\t): QueuedSessionAction[] {\n\t\tconst matching = candidates.filter(predicate);\n\t\tconst previousStates = new Map(matching.map((action) => [action.id, action.lifecycle.state]));\n\t\tconst preparing = this._actionStore\n\t\t\t.activeActions()\n\t\t\t.filter(\n\t\t\t\t(action): action is SessionAction<PreparedTurnPayload> =>\n\t\t\t\t\taction.payload.kind === \"turn\" && action.lifecycle.state === \"preparing\",\n\t\t\t);\n\t\tconst previousAnchor = preparing.at(-1);\n\t\tconst actions = this._actionStore.remove(predicate, candidates);\n\t\tconst restorableMessages: CustomMessage[] = [];\n\t\tconst removed = new Set(actions);\n\t\tif (previousAnchor && removed.has(previousAnchor)) {\n\t\t\tfor (const action of preparing) {\n\t\t\t\tif (!removed.has(action)) action.payload.prepared = undefined;\n\t\t\t}\n\t\t}\n\t\tfor (const action of actions) {\n\t\t\tconst ticket = this._actionStore.ticketFor(action);\n\t\t\tif (\n\t\t\t\taction.payload.kind === \"turn\" &&\n\t\t\t\t(action.payload.acceptedAgentMessage ||\n\t\t\t\t\t!action.payload.queueVisible ||\n\t\t\t\t\tpreviousStates.get(action.id) !== \"queued\")\n\t\t\t) {\n\t\t\t\tticket.rejectDelivered(error);\n\t\t\t} else {\n\t\t\t\tticket.settleDelivered({ status: \"not_applicable\" });\n\t\t\t}\n\t\t\tticket.settleCompleted(error);\n\t\t\tconst dispatched = previousStates.get(action.id) === \"committing\" && action.payload.kind === \"turn\";\n\t\t\tif (action.payload.kind === \"turn\") {\n\t\t\t\tconst payload = action.payload;\n\t\t\t\tconst restorable = payload.records\n\t\t\t\t\t.filter(\n\t\t\t\t\t\t(record): record is DeliveryRecord & { message: CustomMessage } =>\n\t\t\t\t\t\t\t(record.role === \"next_turn\" || (payload.acceptedAgentMessage && record.role === \"prefix\")) &&\n\t\t\t\t\t\t\trecord.message.role === \"custom\" &&\n\t\t\t\t\t\t\t!record.durable,\n\t\t\t\t\t)\n\t\t\t\t\t.map((record) => cloneCustomMessage(record.message));\n\t\t\t\trestorableMessages.push(...restorable);\n\t\t\t\tif (dispatched) {\n\t\t\t\t\tpayload.captureRunMessages = new Set(payload.records.map((record) => record.message));\n\t\t\t\t\tthis.agent.state.messages = this.agent.state.messages.filter(\n\t\t\t\t\t\t(message) => !payload.captureRunMessages?.has(message),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!dispatched) {\n\t\t\t\tthis._actionStore.releaseTerminal(action);\n\t\t\t}\n\t\t}\n\t\tthis._pendingNextTurnMessages.unshift(...restorableMessages);\n\t\tif (actions.length > 0) this._notifySessionInputCheckpointChange();\n\t\treturn actions;\n\t}\n\n\tprivate _clearQueuedGoalContexts(): void {\n\t\tthis._goalContinuationAwaitsRlmWork = false;\n\t\tthis._pendingNextTurnMessages = this._pendingNextTurnMessages.filter(\n\t\t\t(message) => message.customType !== GOAL_CONTEXT_CUSTOM_TYPE,\n\t\t);\n\t\tthis.agent.removeQueuedMessages(\n\t\t\t(message) => message.role === \"custom\" && message.customType === GOAL_CONTEXT_CUSTOM_TYPE,\n\t\t);\n\t\tthis._cancelSessionActions(\n\t\t\t(action) =>\n\t\t\t\taction.payload.kind === \"turn\" && action.payload.customMessage?.customType === GOAL_CONTEXT_CUSTOM_TYPE,\n\t\t\tnew Error(\"Queued goal context was cleared before delivery.\"),\n\t\t);\n\t\tthis._emitQueueUpdate();\n\t}\n\n\tprivate _startGoal(objectiveText: string, tokenBudget: number | undefined): GoalState {\n\t\tconst objective = validateGoalObjective(objectiveText);\n\t\tconst budget = validateGoalBudget(tokenBudget);\n\t\tconst now = Date.now();\n\t\tconst goal: GoalState = {\n\t\t\tactive: true,\n\t\t\tstatus: \"active\",\n\t\t\tgoalId: randomUUID(),\n\t\t\tobjective,\n\t\t\ttokenBudget: budget,\n\t\t\ttokensUsed: 0,\n\t\t\ttimeUsedSeconds: 0,\n\t\t\tcontinuationsUsed: 0,\n\t\t\tcreatedAt: now,\n\t\t\tupdatedAt: now,\n\t\t};\n\t\tthis._goalAccountingStartedAt = now;\n\t\tthis._goalContinuationAwaitsRlmWork = false;\n\t\tthis._setGoalState(goal);\n\t\treturn this._goalState;\n\t}\n\n\tprivate _clearGoal(): void {\n\t\tthis._clearQueuedGoalContexts();\n\t\tthis._setGoalState(emptyGoalState());\n\t}\n\n\tprivate _pauseGoal(reason = \"Paused by user\"): void {\n\t\tthis._clearQueuedGoalContexts();\n\t\tif (this._goalState.status !== \"active\") {\n\t\t\tthis._emitGoalUpdate();\n\t\t\treturn;\n\t\t}\n\t\tconst goal = this._goalWithAccountedWallClock();\n\t\tthis._setGoalState({\n\t\t\t...goal,\n\t\t\tactive: false,\n\t\t\tstatus: \"paused\",\n\t\t\tlastReason: reason,\n\t\t\tlastError: undefined,\n\t\t});\n\t}\n\n\tprivate async _resumeGoal(): Promise<void> {\n\t\tif (!this._goalState.objective) {\n\t\t\tthis._emitGoalUpdate();\n\t\t\treturn;\n\t\t}\n\t\tif (this._goalState.status !== \"paused\" && this._goalState.status !== \"budget_limited\") {\n\t\t\tthis._emitGoalUpdate();\n\t\t\treturn;\n\t\t}\n\t\tconst exhausted =\n\t\t\tthis._goalState.tokenBudget !== undefined && this._goalState.tokensUsed >= this._goalState.tokenBudget;\n\t\tconst nextStatus: GoalStatus = exhausted ? \"budget_limited\" : \"active\";\n\t\tthis._setGoalState({\n\t\t\t...this._goalState,\n\t\t\tactive: nextStatus === \"active\",\n\t\t\tstatus: nextStatus,\n\t\t\tlastReason: exhausted ? \"Goal token budget already reached\" : undefined,\n\t\t\tlastError: undefined,\n\t\t});\n\t\tif (nextStatus === \"active\") {\n\t\t\tawait this._runOrQueueGoalContext(\"continuation\");\n\t\t}\n\t}\n\n\tprivate _finishGoalWithError(errorMessage: string): void {\n\t\tif (!this._goalState.objective || this._goalState.status !== \"active\") {\n\t\t\treturn;\n\t\t}\n\t\tconst goal = this._goalWithAccountedWallClock();\n\t\tthis._setGoalState({\n\t\t\t...goal,\n\t\t\tactive: false,\n\t\t\tstatus: \"error\",\n\t\t\tlastReason: errorMessage,\n\t\t\tlastError: errorMessage,\n\t\t});\n\t}\n\n\tprivate _finishGoalForTerminalAssistantMessage(message: AssistantMessage): void {\n\t\tif (this._goalState.status !== \"active\") {\n\t\t\treturn;\n\t\t}\n\n\t\tif (message.stopReason === \"aborted\") {\n\t\t\tthis._goalAbortInProgress = false;\n\t\t\treturn;\n\t\t}\n\n\t\tif (message.stopReason === \"error\") {\n\t\t\tif (this._goalAbortInProgress) {\n\t\t\t\tthis._goalAbortInProgress = false;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._finishGoalWithError(message.errorMessage || \"Assistant response failed\");\n\t\t}\n\t}\n\n\tprivate _stopGoalContinuationForTerminalMessage(message: AssistantMessage): boolean {\n\t\tif (message.stopReason !== \"error\" && message.stopReason !== \"aborted\") {\n\t\t\treturn false;\n\t\t}\n\t\ttry {\n\t\t\tthis._finishGoalForTerminalAssistantMessage(message);\n\t\t} catch {\n\t\t\t// Goal hooks must not reject; listener failures should not crash the agent loop.\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate _parseGoalSlashCommand(text: string): GoalSlashCommand | undefined {\n\t\tconst command = parseSessionSlashCommand(text);\n\t\tif (command?.name !== \"goal\") return undefined;\n\n\t\tconst rest = command.args;\n\t\tconst normalized = rest.toLowerCase();\n\t\tif (!rest || normalized === \"status\") {\n\t\t\treturn { kind: \"status\" };\n\t\t}\n\t\tif (normalized === \"clear\" || normalized === \"stop\") {\n\t\t\treturn { kind: \"clear\" };\n\t\t}\n\t\tif (normalized === \"pause\") {\n\t\t\treturn { kind: \"pause\" };\n\t\t}\n\t\tif (normalized === \"resume\") {\n\t\t\treturn { kind: \"resume\" };\n\t\t}\n\n\t\tlet tokenBudget: number | undefined;\n\t\tlet objective = rest;\n\t\tconst firstToken = rest.split(/\\s+/, 1)[0] ?? \"\";\n\t\tif (\n\t\t\tfirstToken === \"--budget\" ||\n\t\t\tfirstToken === \"--token-budget\" ||\n\t\t\tfirstToken.startsWith(\"--budget=\") ||\n\t\t\tfirstToken.startsWith(\"--token-budget=\")\n\t\t) {\n\t\t\tlet valueText: string;\n\t\t\tif (firstToken === \"--budget\" || firstToken === \"--token-budget\") {\n\t\t\t\tconst withoutFlag = rest.slice(firstToken.length).trimStart();\n\t\t\t\tconst nextSpace = withoutFlag.search(/\\s/);\n\t\t\t\tif (nextSpace < 0) {\n\t\t\t\t\tthrow new Error(\"Usage: /goal [--budget <tokens>] <objective>\");\n\t\t\t\t}\n\t\t\t\tvalueText = withoutFlag.slice(0, nextSpace);\n\t\t\t\tobjective = withoutFlag.slice(nextSpace + 1).trim();\n\t\t\t} else {\n\t\t\t\tconst separator = firstToken.indexOf(\"=\");\n\t\t\t\tvalueText = firstToken.slice(separator + 1);\n\t\t\t\tobjective = rest.slice(firstToken.length).trim();\n\t\t\t}\n\t\t\ttokenBudget = parseGoalBudgetValue(valueText);\n\t\t}\n\n\t\treturn {\n\t\t\tkind: \"start\",\n\t\t\tobjective: validateGoalObjective(objective),\n\t\t\ttokenBudget,\n\t\t};\n\t}\n\n\tprivate _parseAutonomousSlashCommand(text: string): AutonomousSlashCommand | undefined {\n\t\tconst command = parseSessionSlashCommand(text);\n\t\tif (command?.name !== \"autonomous\") return undefined;\n\t\tconst rest = command.args.toLowerCase();\n\t\tif (!rest || rest === \"status\") {\n\t\t\treturn { kind: \"status\" };\n\t\t}\n\t\tif (rest === \"on\" || rest === \"enable\" || rest === \"enabled\") {\n\t\t\treturn { kind: \"on\" };\n\t\t}\n\t\tif (rest === \"off\" || rest === \"disable\" || rest === \"disabled\") {\n\t\t\treturn { kind: \"off\" };\n\t\t}\n\t\tthrow new Error(\"Usage: /autonomous [on|off|status]\");\n\t}\n\n\tprivate _formatAutonomousStatus(): string {\n\t\tconst status = this.getAutonomousStatus();\n\t\tconst state = status.enabled ? \"on\" : \"off\";\n\t\treturn `Autonomous mode: ${state}. Continuations: ${status.continuationsUsed}/${status.limits.maxContinuations}. Turns: ${status.turnsUsed}/${status.limits.maxTurns}. Tokens: ${status.tokensUsed}/${status.limits.maxTokens}.`;\n\t}\n\n\tprivate _emitAutonomousStatus(): void {\n\t\tconst message = {\n\t\t\trole: \"custom\" as const,\n\t\t\tcustomType: \"autonomous_status\",\n\t\t\tcontent: this._formatAutonomousStatus(),\n\t\t\tdisplay: true,\n\t\t\tdetails: this.getAutonomousStatus(),\n\t\t\ttimestamp: Date.now(),\n\t\t} satisfies CustomMessage<AgentAutonomousStatus>;\n\t\tthis.agent.state.messages.push(message);\n\t\tthis.sessionManager.appendCustomMessageEntry(\n\t\t\tmessage.customType,\n\t\t\tmessage.content,\n\t\t\tmessage.display,\n\t\t\tmessage.details,\n\t\t);\n\t\tthis._emit({ type: \"message_start\", message });\n\t\tthis._emit({ type: \"message_end\", message });\n\t}\n\n\tprivate async _handleAutonomousSlashCommand(text: string): Promise<boolean> {\n\t\tconst command = this._parseAutonomousSlashCommand(text);\n\t\tif (!command) {\n\t\t\treturn false;\n\t\t}\n\t\tif (command.kind === \"on\") {\n\t\t\tsetAutonomousEnabled(this._autonomousState, true, { cwd: this._cwd });\n\t\t} else if (command.kind === \"off\") {\n\t\t\tsetAutonomousEnabled(this._autonomousState, false);\n\t\t\tthis._clearQueuedAutonomousContinuations();\n\t\t}\n\t\tthis._emitAutonomousStatus();\n\t\treturn true;\n\t}\n\n\tprivate _appendBeforeAgentStartMessages(\n\t\tmessages: AgentMessage[],\n\t\tresult: Awaited<ReturnType<ExtensionRunner[\"emitBeforeAgentStart\"]>>,\n\t): void {\n\t\tif (!result?.messages) return;\n\t\tfor (const message of result.messages) {\n\t\t\tmessages.push({\n\t\t\t\trole: \"custom\",\n\t\t\t\tcustomType: message.customType,\n\t\t\t\tcontent: message.content,\n\t\t\t\tdisplay: message.display,\n\t\t\t\tdetails: message.details,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate async _validateCanStartAgentRun(): Promise<void> {\n\t\tif (!this.model) {\n\t\t\tthrow new Error(formatNoModelSelectedMessage());\n\t\t}\n\t\tif (!this._modelRegistry.hasConfiguredAuth(this.model)) {\n\t\t\tconst isOAuth = this._modelRegistry.isUsingOAuth(this.model);\n\t\t\tif (isOAuth) {\n\t\t\t\tthrow new Error(formatAuthenticationFailedMessage(this.model.provider));\n\t\t\t}\n\t\t\tthrow new Error(formatNoApiKeyFoundMessage(this.model.provider));\n\t\t}\n\t}\n\n\t/**\n\t * Goals are pursued through the kernel goal skill, so the only tool the\n\t * model needs is ipython. Force-activate it (including into a live\n\t * continuation context) so the model can always reach `goal.complete()`.\n\t */\n\tprivate _ensureGoalRuntimeActive(context?: AgentContext): void {\n\t\tif (!this._includeGoals) {\n\t\t\tthrow new Error(\"Goals are disabled. Enable goals before using /goal.\");\n\t\t}\n\t\tconst ipythonTool = this._toolRegistry.get(\"ipython\");\n\t\tif (!ipythonTool) {\n\t\t\tthrow new Error(\"Goals require the ipython tool, which is not available in this session.\");\n\t\t}\n\t\tconst activeToolNames = new Set(this.getActiveToolNames());\n\t\tif (!activeToolNames.has(\"ipython\")) {\n\t\t\tactiveToolNames.add(\"ipython\");\n\t\t\tthis.setActiveToolsByName([...activeToolNames]);\n\t\t}\n\t\tif (context) {\n\t\t\tconst contextTools = [...(context.tools ?? [])];\n\t\t\tif (!contextTools.some((tool) => tool.name === \"ipython\")) {\n\t\t\t\tcontextTools.push(ipythonTool);\n\t\t\t\tcontext.tools = contextTools;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _maybeResumeGoalContinuationAfterRlmWork(): void {\n\t\tif (!this._goalContinuationAwaitsRlmWork) return;\n\t\tif (this._disposed || this._disposing || this._hasUnsettledRlmQuiescenceWork()) return;\n\t\tif (this._goalState.status !== \"active\" || !this._goalState.objective) {\n\t\t\tthis._goalContinuationAwaitsRlmWork = false;\n\t\t\treturn;\n\t\t}\n\t\t// Keep the deferral while admission is paused or the pump is suspended\n\t\t// (post-abort); the pause release and resumeQueuedWork retry.\n\t\tif (this._sessionInputAdmissionPauses.size > 0 || this._sessionInputPumpSuspended) return;\n\t\tconst goalBeforeResume = this._goalState;\n\t\ttry {\n\t\t\tthis._ensureGoalRuntimeActive();\n\t\t\tthis._setGoalState({\n\t\t\t\t...this._goalState,\n\t\t\t\tcontinuationsUsed: this._goalState.continuationsUsed + 1,\n\t\t\t\tlastReason: undefined,\n\t\t\t\tlastError: undefined,\n\t\t\t});\n\t\t\tconst message = createGoalContextMessage(this._goalState, \"continuation\");\n\t\t\tconst normalized = normalizeMessageContent(message.content);\n\t\t\t// No front: a settling child's terminal notice must be read first.\n\t\t\tthis._admitSessionInput(\n\t\t\t\tthis._createPreparedTurnAction(\"followUp\", normalized.text, normalized.images, {\n\t\t\t\t\tmessage,\n\t\t\t\t\tresumeIfIdle: true,\n\t\t\t\t}),\n\t\t\t);\n\t\t\tthis._goalContinuationAwaitsRlmWork = false;\n\t\t} catch {\n\t\t\t// Admission can race a new pause; roll back so the retry re-counts.\n\t\t\tthis._setGoalState(goalBeforeResume);\n\t\t}\n\t}\n\n\tprivate _runOrQueueGoalContext(kind: \"continuation\" | \"objective_updated\", images?: ImageContent[]): void {\n\t\tif (!this._goalState.objective) return;\n\t\tthis._ensureGoalRuntimeActive();\n\t\tconst message = createGoalContextMessage(this._goalState, kind, images);\n\t\tconst normalized = normalizeMessageContent(message.content);\n\t\tconst action = this._createPreparedTurnAction(\"followUp\", normalized.text, normalized.images, {\n\t\t\tmessage,\n\t\t\tresumeIfIdle: true,\n\t\t});\n\t\tthis._admitSessionInput(action, { front: true, wake: false });\n\t}\n\n\tprivate async _handleGoalSlashCommand(text: string, images: ImageContent[] | undefined): Promise<boolean> {\n\t\tconst command = this._parseGoalSlashCommand(text);\n\t\tif (!command) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (command.kind === \"status\") {\n\t\t\tthis._emitGoalUpdate();\n\t\t\treturn true;\n\t\t}\n\n\t\tif (command.kind === \"clear\") {\n\t\t\tthis._clearGoal();\n\t\t\treturn true;\n\t\t}\n\n\t\tif (command.kind === \"pause\") {\n\t\t\tthis._pauseGoal();\n\t\t\treturn true;\n\t\t}\n\n\t\tif (command.kind === \"resume\") {\n\t\t\tawait this._resumeGoal();\n\t\t\treturn true;\n\t\t}\n\n\t\tconst previousWasActive = this._goalState.status === \"active\";\n\t\tif (!this.isStreaming) {\n\t\t\tawait this._validateCanStartAgentRun();\n\t\t}\n\t\tthis._ensureGoalRuntimeActive();\n\t\tthis._clearQueuedGoalContexts();\n\t\tthis._startGoal(command.objective, command.tokenBudget);\n\t\tawait this._runOrQueueGoalContext(previousWasActive ? \"objective_updated\" : \"continuation\", images);\n\t\treturn true;\n\t}\n\n\tprivate _accountGoalUsageForAssistantMessage(message: AssistantMessage): boolean {\n\t\tif (!this._goalState.objective) {\n\t\t\treturn false;\n\t\t}\n\t\tif (message.stopReason === \"error\" || message.stopReason === \"aborted\") {\n\t\t\treturn false;\n\t\t}\n\t\tif (this._goalAccountedAssistantMessages.has(message)) {\n\t\t\treturn false;\n\t\t}\n\t\t// Usage is attributed at the assistant message's message_end, which fires\n\t\t// before that turn's ipython cell runs. goal.complete() only arrives later\n\t\t// over the kernel host bridge, so the completing turn is always accounted\n\t\t// while the goal is still active. Only count turns spent pursuing the goal;\n\t\t// post-completion turns (e.g. a closing summary) must not be attributed.\n\t\tif (this._goalState.status !== \"active\") {\n\t\t\treturn false;\n\t\t}\n\t\tthis._goalAccountedAssistantMessages.add(message);\n\t\tconst tokenDelta = goalTokenDeltaForUsage(message.usage);\n\t\tconst goal = this._goalWithAccountedWallClock();\n\t\tconst nextGoal: GoalState = {\n\t\t\t...goal,\n\t\t\ttokensUsed: goal.tokensUsed + tokenDelta,\n\t\t};\n\t\tconst budgetReached = nextGoal.tokenBudget !== undefined && nextGoal.tokensUsed >= nextGoal.tokenBudget;\n\t\tif (!budgetReached) {\n\t\t\tthis._setGoalState(nextGoal);\n\t\t\treturn false;\n\t\t}\n\t\tthis._setGoalState({\n\t\t\t...nextGoal,\n\t\t\tactive: false,\n\t\t\tstatus: \"budget_limited\",\n\t\t\tlastReason: `Reached ${nextGoal.tokenBudget} token goal budget`,\n\t\t\tlastError: undefined,\n\t\t});\n\t\treturn true;\n\t}\n\n\tprivate get _steeringStopPending(): boolean {\n\t\treturn (\n\t\t\tthis._actionStore.queuedActions(\"next_turn_boundary\").length > 0 ||\n\t\t\tthis._actionStore\n\t\t\t\t.activeActions(\"next_turn_boundary\")\n\t\t\t\t.some(\n\t\t\t\t\t(action) =>\n\t\t\t\t\t\taction.payload.kind === \"turn\" &&\n\t\t\t\t\t\t(action.lifecycle.state === \"selected\" || action.lifecycle.state === \"preparing\"),\n\t\t\t\t)\n\t\t);\n\t}\n\n\tprivate _shouldStopBeforeTurn(): boolean {\n\t\treturn this._steeringStopPending;\n\t}\n\n\tprivate async _shouldStopAfterTurn(context: ShouldStopAfterTurnContext): Promise<boolean> {\n\t\tif (this._stopGoalContinuationForTerminalMessage(context.message)) {\n\t\t\treturn true;\n\t\t}\n\t\ttry {\n\t\t\tif (this._accountGoalUsageForAssistantMessage(context.message)) {\n\t\t\t\tconst message = createGoalContextMessage(this._goalState, \"budget_limit\");\n\t\t\t\tconst normalized = normalizeMessageContent(message.content);\n\t\t\t\tawait this._queuePreparedPrompt(\"steer\", normalized.text, normalized.images, {\n\t\t\t\t\tmessage,\n\t\t\t\t\tresumeIfIdle: true,\n\t\t\t\t});\n\t\t\t}\n\t\t} catch {\n\t\t\t// Goal accounting must not interrupt the core agent loop.\n\t\t}\n\t\t// Serialized refine checkpoint: in print/headless mode, run refinement\n\t\t// planning+apply synchronously here — the quiescent boundary between\n\t\t// turns — so it never overlaps the primary model request.\n\t\t// This MUST run BEFORE threshold compaction to prevent the\n\t\t// compaction model call from overlapping an in-flight refine\n\t\t// plan/apply that was started at message_end.\n\t\tif (this._serializedRefine) {\n\t\t\t// Ensure the preceding message_end processing (counter increment,\n\t\t\t// background plan kickoff) has completed before the checkpoint.\n\t\t\tawait this._agentEventQueue;\n\t\t\tawait this._runSerializedRefineCheckpoint();\n\t\t}\n\t\tif (await this._shouldStopForThresholdCompaction(context)) {\n\t\t\treturn true;\n\t\t}\n\t\t// Steering stops continuation only after mandatory serialized checkpoints.\n\t\t// Returning true here still prevents the agent loop from starting another turn.\n\t\treturn this._steeringStopPending;\n\t}\n\n\tprivate async _shouldStopForThresholdCompaction(context: ShouldStopAfterTurnContext): Promise<boolean> {\n\t\tthis._continueAfterThresholdCompaction = false;\n\t\tif (this._pendingRequestedCompaction === undefined && !(await this._thresholdCompactionNeeded(context))) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst lastMessage = this.agent.state.messages[this.agent.state.messages.length - 1];\n\t\t// A queued continuation disproves the assistant-last \"task finished\" heuristic, so preserve a true set above.\n\t\tthis._continueAfterThresholdCompaction ||= lastMessage !== undefined && lastMessage.role !== \"assistant\";\n\t\treturn true;\n\t}\n\n\t/**\n\t * Serialized-mode auto-refine checkpoint called from _shouldStopAfterTurn.\n\t * Runs the review, planning, and application phases inline between turns\n\t * at the quiescent shouldStopAfterTurn boundary. This path NEVER calls\n\t * _maybeAutoRefine, _runApprovedRefine, public refine(), agent.abort(),\n\t * or agent.waitForIdle — all of which would deadlock or defer because\n\t * the agent loop still owns activeRun at this point. Instead it calls\n\t * _reviewAutoRefine, _planRefine, and _applyRefine directly with proper\n\t * in-flight guards and counter resets.\n\t */\n\tprivate async _runSerializedRefineCheckpoint(): Promise<void> {\n\t\tif (this._disposed || this._disposing) {\n\t\t\treturn;\n\t\t}\n\n\t\t// 1. Await any background plan that was started at message_end\n\t\t// (either for a pending refine.run or for interval-triggered\n\t\t// auto-refine). This must be checked BEFORE the pending and\n\t\t// interval checks because background planning may have consumed\n\t\t// the pending request at message_end.\n\t\tconst branchVersion = this._autoRefineBranchVersion;\n\t\tconst bgConsumption = await this._consumeSerializedBackgroundPlan(async (bgResult) => {\n\t\t\tif (this._disposed || this._disposing) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (bgResult?.status === \"plan\") {\n\t\t\t\tif (bgResult.branchVersion !== this._autoRefineBranchVersion) {\n\t\t\t\t\tif (!this._pendingRequestedRefine) {\n\t\t\t\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\t\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Apply the EXACT background plan directly via _applyRefine\n\t\t\t\t\t// (no second _planRefine call).\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait this._applySerializedPlan(bgResult);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tthis._emitRefineFailed(error);\n\t\t\t\t\t}\n\t\t\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t\t\t\tif (!this._pendingRequestedRefine) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (bgResult?.status === \"skip\") {\n\t\t\t\t// Reviewer declined or an extension skipped during background planning.\n\t\t\t\t// Reset exactly once. Never retry the interval review; only fall through for a separate pending refine.run.\n\t\t\t\tif (bgResult.explicit) {\n\t\t\t\t\tthis._emitRefineFailed(new RefineSkippedError(\"Refinement skipped by extension\"));\n\t\t\t\t}\n\t\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t\t\tif (!this._pendingRequestedRefine) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (bgResult?.status === \"failure\") {\n\t\t\t\t// Background review or planning failure stamps cooldown without a synchronous retry.\n\t\t\t\t// A separately queued refine.run may still be serviced below.\n\t\t\t\tif (branchVersion === this._autoRefineBranchVersion) {\n\t\t\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\t\t}\n\t\t\t\t// Re-queue an explicit refine.run whose background plan failed,\n\t\t\t\t// but only when branchVersion is still current and no newer\n\t\t\t\t// pending request has arrived since the background plan consumed\n\t\t\t\t// the original one. A newer request retains priority; interval\n\t\t\t\t// failures keep existing no-retry cooldown semantics.\n\t\t\t\tif (\n\t\t\t\t\tbgResult.explicit &&\n\t\t\t\t\tbgResult.branchVersion === this._autoRefineBranchVersion &&\n\t\t\t\t\t!this._pendingRequestedRefine\n\t\t\t\t) {\n\t\t\t\t\tthis._pendingRequestedRefine = bgResult.options;\n\t\t\t\t}\n\t\t\t\tif (!this._pendingRequestedRefine) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (bgResult?.status === \"invalidated\" && !this._pendingRequestedRefine) {\n\t\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tawait this._runSerializedRefineCheckpointAfterBackground(branchVersion);\n\t\t\treturn true;\n\t\t});\n\t\tif (this._disposed || this._disposing || bgConsumption !== \"none\") {\n\t\t\treturn;\n\t\t}\n\t\tawait this._runSerializedRefineCheckpointAfterBackground(branchVersion);\n\t}\n\n\tprivate async _runSerializedRefineCheckpointAfterBackground(branchVersion: number): Promise<void> {\n\t\t// No background result, or a refine.run arrived while the background result was\n\t\t// in flight. Fall through so an explicit pending request is serviced at this boundary.\n\n\t\t// 2. Agent-callable refine.run requests that were NOT consumed by\n\t\t// background planning (e.g. interval not reached at message_end,\n\t\t// or cooldown was active). Service them synchronously.\n\t\tconst pending = this._pendingRequestedRefine;\n\t\tif (pending) {\n\t\t\tthis._pendingRequestedRefine = undefined;\n\t\t\ttry {\n\t\t\t\tawait this._runSerializedRefine(pending);\n\t\t\t} catch (error) {\n\t\t\t\tthis._emitRefineFailed(error);\n\t\t\t}\n\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t\treturn;\n\t\t}\n\n\t\t// 3. Post-compaction auto-refine. Serialized sessions defer the\n\t\t// compaction trigger to this boundary instead of entering the interactive\n\t\t// path, which waits for agent idle and can never run inside a tool loop.\n\t\tif (!this._autoRefineAllowedForSession()) {\n\t\t\tthis._compactAutoRefinePending = false;\n\t\t\treturn;\n\t\t}\n\t\tconst settings = this.settingsManager.getAutoRefineSettings();\n\t\tif (!settings.enabled) {\n\t\t\tthis._compactAutoRefinePending = false;\n\t\t\treturn;\n\t\t}\n\t\tif (this._compactAutoRefinePending) {\n\t\t\tif (!settings.compact) {\n\t\t\t\tthis._compactAutoRefinePending = false;\n\t\t\t} else {\n\t\t\t\tconst nowMs = Date.now();\n\t\t\t\tconst underCooldown =\n\t\t\t\t\tthis._lastAutoRefineReviewAt > 0 && nowMs - this._lastAutoRefineReviewAt < settings.cooldownMs;\n\t\t\t\tif (underCooldown) {\n\t\t\t\t\t// Preserve the compact trigger for a later boundary, matching the\n\t\t\t\t\t// interactive path's pending behavior while the cooldown is active.\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis._compactAutoRefinePending = false;\n\t\t\t\tawait this._runSerializedAutoRefineReview(\"compact\", branchVersion);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// 4. Interval-triggered auto-refine (no background plan was started).\n\t\tif (this._assistantTurnsSinceAutoRefine < settings.turnInterval) {\n\t\t\treturn;\n\t\t}\n\t\tconst nowMs = Date.now();\n\t\tconst underCooldown =\n\t\t\tthis._lastAutoRefineReviewAt > 0 && nowMs - this._lastAutoRefineReviewAt < settings.cooldownMs;\n\t\tif (underCooldown) {\n\t\t\treturn;\n\t\t}\n\t\tawait this._runSerializedAutoRefineReview(\"turn_interval\", branchVersion);\n\t}\n\n\tprivate async _runSerializedAutoRefineReview(\n\t\treason: \"compact\" | \"turn_interval\",\n\t\tbranchVersion: number,\n\t): Promise<void> {\n\t\tconst reviewAbort = new AbortController();\n\t\tthis._autoRefineReviewAbort = reviewAbort;\n\t\tthis._autoRefineInProgress = true;\n\t\ttry {\n\t\t\tconst review = await this._reviewAutoRefine(\n\t\t\t\t{ reason, turnsSinceLastReview: this._assistantTurnsSinceAutoRefine },\n\t\t\t\treviewAbort.signal,\n\t\t\t);\n\t\t\tif (this._disposed || this._disposing || branchVersion !== this._autoRefineBranchVersion) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!review.shouldRefine) {\n\t\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait this._runSerializedRefine({ instructions: autoRefineInstructions(reason, review) }, \"auto\");\n\t\t\tif (this._disposed || this._disposing || branchVersion !== this._autoRefineBranchVersion) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t} catch (error) {\n\t\t\tif (branchVersion === this._autoRefineBranchVersion) {\n\t\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\t\t// An extension skip is an intentional non-round, not a failure.\n\t\t\t\tif (error instanceof RefineSkippedError) {\n\t\t\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t\t\t} else {\n\t\t\t\t\tthis._emitRefineFailed(error);\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\tif (this._autoRefineReviewAbort === reviewAbort) {\n\t\t\t\tthis._autoRefineReviewAbort = undefined;\n\t\t\t}\n\t\t\tthis._autoRefineInProgress = false;\n\t\t}\n\t}\n\n\t/**\n\t * Claim and process the serialized background plan if one is in flight.\n\t * A concurrent caller waits for the claim holder's full processing callback\n\t * instead of resuming as soon as planning settles.\n\t */\n\tprivate async _consumeSerializedBackgroundPlan(\n\t\tconsume: (result: SerializedBackgroundPlanResult | undefined) => Promise<boolean>,\n\t): Promise<\"none\" | \"waited\" | \"continue\" | \"stop\"> {\n\t\tif (this._serializedPlanClaim) {\n\t\t\tawait this._serializedPlanClaim.catch(() => undefined);\n\t\t\treturn \"waited\";\n\t\t}\n\t\tconst planInFlight = this._serializedPlanInFlight;\n\t\tif (!planInFlight) {\n\t\t\treturn \"none\";\n\t\t}\n\n\t\tlet releaseClaim: () => void = () => {};\n\t\tconst claim = new Promise<void>((resolve) => {\n\t\t\treleaseClaim = resolve;\n\t\t});\n\t\tthis._serializedPlanClaim = claim;\n\t\ttry {\n\t\t\tconst result = await planInFlight.catch(() => undefined);\n\t\t\tif (this._serializedPlanInFlight === planInFlight) {\n\t\t\t\tthis._serializedPlanInFlight = undefined;\n\t\t\t\tthis._serializedExplicitRefineOptions = undefined;\n\t\t\t}\n\t\t\treturn (await consume(result)) ? \"stop\" : \"continue\";\n\t\t} finally {\n\t\t\treleaseClaim();\n\t\t\tif (this._serializedPlanClaim === claim) {\n\t\t\t\tthis._serializedPlanClaim = undefined;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Apply an exact background plan directly via _applyRefine without\n\t * calling _planRefine again. Sets _refineInFlight for safety.\n\t */\n\tprivate async _applySerializedPlan(\n\t\tbgResult: Extract<SerializedBackgroundPlanResult, { status: \"plan\" }>,\n\t): Promise<void> {\n\t\tlet resolveApplySettled: () => void = () => {};\n\t\tconst applySettled = new Promise<void>((resolve) => {\n\t\t\tresolveApplySettled = resolve;\n\t\t});\n\t\tthis._refineInFlight = applySettled;\n\t\ttry {\n\t\t\tawait this._applyRefine(bgResult.plan, bgResult.options, bgResult.abort);\n\t\t} finally {\n\t\t\tresolveApplySettled();\n\t\t\tif (this._refineInFlight === applySettled) {\n\t\t\t\tthis._refineInFlight = undefined;\n\t\t\t}\n\t\t\tthis._scheduleSessionInputPump();\n\t\t}\n\t}\n\n\t/**\n\t * Start background refinement planning at assistant message_end, while\n\t * tools are still executing. The plan (if any) is awaited at the\n\t * shouldStopAfterTurn boundary before applying. Planning overlaps tool\n\t * execution only — never another model request.\n\t */\n\tprivate _maybeStartSerializedBackgroundPlan(): void {\n\t\tif (!this._serializedRefine || this._disposed || this._disposing) {\n\t\t\treturn;\n\t\t}\n\t\t// Don't start if a plan is already in flight.\n\t\tif (this._serializedPlanInFlight || this._refineInFlight || this._refinePlanInFlight) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Start background planning for a pending agent-callable\n\t\t// refine.run request, so its plan is ready at the shouldStopAfterTurn\n\t\t// boundary. The pending request is consumed (cleared) here so the\n\t\t// boundary doesn't re-plan it. Explicit refine.run skips the review gate.\n\t\tconst pending = this._pendingRequestedRefine;\n\t\tif (pending) {\n\t\t\tthis._pendingRequestedRefine = undefined;\n\t\t\tthis._serializedExplicitRefineOptions = pending;\n\t\t\tconst refineAbort = new AbortController();\n\t\t\tthis._refineAbortController = refineAbort;\n\t\t\tconst branchVersion = this._autoRefineBranchVersion;\n\t\t\tthis._serializedPlanInFlight = this._runBackgroundPlan(pending, refineAbort, branchVersion, true);\n\t\t\treturn;\n\t\t}\n\n\t\t// Interval-triggered auto-refine background planning.\n\t\tif (!this._autoRefineAllowedForSession()) {\n\t\t\treturn;\n\t\t}\n\t\tconst settings = this.settingsManager.getAutoRefineSettings();\n\t\tif (!settings.enabled) {\n\t\t\treturn;\n\t\t}\n\t\tif (this._assistantTurnsSinceAutoRefine < settings.turnInterval) {\n\t\t\treturn;\n\t\t}\n\t\tconst nowMs = Date.now();\n\t\tconst underCooldown =\n\t\t\tthis._lastAutoRefineReviewAt > 0 && nowMs - this._lastAutoRefineReviewAt < settings.cooldownMs;\n\t\tif (underCooldown) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst refineAbort = new AbortController();\n\t\tthis._refineAbortController = refineAbort;\n\t\tconst branchVersion = this._autoRefineBranchVersion;\n\t\t// Pass empty options — _runBackgroundPlan derives instructions from\n\t\t// the review result for interval-triggered auto-refine.\n\t\tthis._serializedPlanInFlight = this._runBackgroundPlan({}, refineAbort, branchVersion);\n\t}\n\n\t/**\n\t * Shared background planning coroutine. Runs review + planRefine and\n\t * returns a discriminated result so the boundary can distinguish\n\t * reviewer-declined (\"skip\") from failure (\"failure\") from a ready\n\t * plan (\"plan\") and apply that exact plan without re-planning.\n\t */\n\tprivate async _runBackgroundPlan(\n\t\toptions: { instructions?: string; rollbackId?: string; global?: boolean },\n\t\trefineAbort: AbortController,\n\t\tbranchVersion: number,\n\t\tskipReview = false,\n\t): Promise<SerializedBackgroundPlanResult | undefined> {\n\t\ttry {\n\t\t\tlet planOptions = options;\n\t\t\tif (!skipReview) {\n\t\t\t\t// Interval-triggered: run the review gate first, then derive\n\t\t\t\t// instructions from the review result (not prepopulated).\n\t\t\t\tconst review = await this._reviewAutoRefine(\n\t\t\t\t\t{\n\t\t\t\t\t\treason: \"turn_interval\",\n\t\t\t\t\t\tturnsSinceLastReview: this._assistantTurnsSinceAutoRefine,\n\t\t\t\t\t},\n\t\t\t\t\trefineAbort.signal,\n\t\t\t\t);\n\t\t\t\tif (this._disposed || this._disposing || branchVersion !== this._autoRefineBranchVersion) {\n\t\t\t\t\treturn { status: \"invalidated\", branchVersion };\n\t\t\t\t}\n\t\t\t\tif (!review.shouldRefine) {\n\t\t\t\t\treturn { status: \"skip\" };\n\t\t\t\t}\n\t\t\t\tplanOptions = {\n\t\t\t\t\tinstructions: autoRefineInstructions(\"turn_interval\", review),\n\t\t\t\t};\n\t\t\t}\n\t\t\t// For explicit refine.run (skipReview=true), plan directly with\n\t\t\t// the user-provided options — no auto-review gate.\n\t\t\tconst plan = await this._planRefine(planOptions, refineAbort.signal, skipReview ? \"manual\" : \"auto\");\n\t\t\tif (this._disposed || this._disposing || branchVersion !== this._autoRefineBranchVersion) {\n\t\t\t\treturn { status: \"invalidated\", branchVersion };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tstatus: \"plan\",\n\t\t\t\tplan,\n\t\t\t\toptions: planOptions,\n\t\t\t\tabort: refineAbort,\n\t\t\t\tbranchVersion,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tif (this._disposed || this._disposing || branchVersion !== this._autoRefineBranchVersion) {\n\t\t\t\treturn { status: \"invalidated\", branchVersion };\n\t\t\t}\n\t\t\tif (error instanceof RefineSkippedError) {\n\t\t\t\treturn { status: \"skip\", explicit: skipReview };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tstatus: \"failure\",\n\t\t\t\texplicit: skipReview,\n\t\t\t\toptions,\n\t\t\t\tbranchVersion,\n\t\t\t};\n\t\t} finally {\n\t\t\tif (this._refineAbortController === refineAbort) {\n\t\t\t\tthis._refineAbortController = undefined;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Direct serialized plan+apply. Calls _planRefine and _applyRefine with\n\t * proper in-flight guards but NEVER agent.waitForIdle or agent.abort.\n\t * The caller (shouldStopAfterTurn) is already at the quiescent boundary,\n\t * so the agent is between turns and _applyRefine's disconnect/reconnect\n\t * is safe.\n\t */\n\tprivate async _runSerializedRefine(\n\t\toptions: {\n\t\t\tinstructions?: string;\n\t\t\trollbackId?: string;\n\t\t\tglobal?: boolean;\n\t\t},\n\t\ttrigger: \"manual\" | \"auto\" = \"manual\",\n\t): Promise<void> {\n\t\tif (this._disposed || this._disposing) {\n\t\t\treturn;\n\t\t}\n\t\t// Guard: serialize against concurrent _runSerializedRefine calls.\n\t\t// _serializedPlanInFlight covers background planning; _refineInFlight\n\t\t// covers the apply phase. Both must be settled before starting a new\n\t\t// plan+apply cycle.\n\t\twhile (this._serializedPlanInFlight || this._refineInFlight || this._refinePlanInFlight) {\n\t\t\tif (this._serializedPlanInFlight) {\n\t\t\t\tawait this._consumeSerializedBackgroundPlan(async () => false);\n\t\t\t} else if (this._refineInFlight) {\n\t\t\t\tawait this._refineInFlight;\n\t\t\t} else {\n\t\t\t\tawait this._refinePlanInFlight;\n\t\t\t}\n\t\t}\n\t\tif (this._disposed || this._disposing) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst refineAbort = new AbortController();\n\t\tthis._refineAbortController = refineAbort;\n\n\t\tconst planRun = this._planRefine(options, refineAbort.signal, trigger);\n\t\tconst planSettled = planRun.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\tthis._refinePlanInFlight = planSettled;\n\t\tlet plan: RefinementPlan;\n\t\ttry {\n\t\t\tplan = await planRun;\n\t\t} catch (error) {\n\t\t\tif (this._refineAbortController === refineAbort) {\n\t\t\t\tthis._refineAbortController = undefined;\n\t\t\t}\n\t\t\tthis._scheduleSessionInputPump();\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tif (this._refinePlanInFlight === planSettled) {\n\t\t\t\tthis._refinePlanInFlight = undefined;\n\t\t\t}\n\t\t}\n\n\t\tif (this._disposed || refineAbort.signal.aborted) {\n\t\t\tif (this._refineAbortController === refineAbort) {\n\t\t\t\tthis._refineAbortController = undefined;\n\t\t\t}\n\t\t\tthis._scheduleSessionInputPump();\n\t\t\treturn;\n\t\t}\n\n\t\t// Do NOT call agent.waitForIdle() — we are at the quiescent boundary\n\t\t// already (shouldStopAfterTurn). _applyRefine handles disconnect/reconnect internally.\n\t\tlet resolveApplySettled: () => void = () => {};\n\t\tconst applySettled = new Promise<void>((resolve) => {\n\t\t\tresolveApplySettled = resolve;\n\t\t});\n\t\tthis._refineInFlight = applySettled;\n\t\ttry {\n\t\t\tawait this._applyRefine(plan, options, refineAbort);\n\t\t} finally {\n\t\t\tresolveApplySettled();\n\t\t\tif (this._refineInFlight === applySettled) {\n\t\t\t\tthis._refineInFlight = undefined;\n\t\t\t}\n\t\t\tthis._scheduleSessionInputPump();\n\t\t}\n\t}\n\n\tprivate async _thresholdCompactionNeeded(context: ShouldStopAfterTurnContext): Promise<boolean> {\n\t\tconst settings = this.settingsManager.getCompactionSettings();\n\t\tif (!settings.enabled) return false;\n\n\t\tconst contextWindow = this.model?.contextWindow ?? 0;\n\t\tconst compactionEntry = getLatestCompactionEntry(this.sessionManager.getBranch());\n\t\tconst compactionTimestamp = compactionEntry ? new Date(compactionEntry.timestamp).getTime() : undefined;\n\t\tif (compactionTimestamp !== undefined && context.message.timestamp <= compactionTimestamp) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst contextTokens = this._getThresholdContextTokens(context.message, compactionTimestamp);\n\t\tif (contextTokens === undefined || !shouldCompact(contextTokens, contextWindow, settings)) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Goal continuation takes exclusive priority over autonomous continuation, matching _getContinuationMessages.\n\t\tif (this._queueGoalContinuationForThresholdCompaction(context.message)) {\n\t\t\tthis._continueAfterThresholdCompaction = true;\n\t\t} else if (await this._queueAutonomousContinuationForThresholdCompaction(context.message)) {\n\t\t\tthis._continueAfterThresholdCompaction = true;\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate _snapshotAutonomousRuntimeState(): AutonomousRuntimeSnapshot {\n\t\treturn {\n\t\t\tcontinuationsUsed: this._autonomousState.continuationsUsed,\n\t\t\tgateAttempts: { ...this._autonomousState.gateAttempts },\n\t\t\tlastGateFailure: this._autonomousState.lastGateFailure\n\t\t\t\t? { ...this._autonomousState.lastGateFailure }\n\t\t\t\t: undefined,\n\t\t\tlastGateFailureSnapshot: this._autonomousState.lastGateFailureSnapshot\n\t\t\t\t? { ...this._autonomousState.lastGateFailureSnapshot }\n\t\t\t\t: undefined,\n\t\t};\n\t}\n\n\tprivate _restoreAutonomousRuntimeSnapshot(snapshot: AutonomousRuntimeSnapshot): void {\n\t\tthis._autonomousState.continuationsUsed = snapshot.continuationsUsed;\n\t\tthis._autonomousState.gateAttempts = { ...snapshot.gateAttempts };\n\t\tthis._autonomousState.lastGateFailure = snapshot.lastGateFailure ? { ...snapshot.lastGateFailure } : undefined;\n\t\tthis._autonomousState.lastGateFailureSnapshot = snapshot.lastGateFailureSnapshot\n\t\t\t? { ...snapshot.lastGateFailureSnapshot }\n\t\t\t: undefined;\n\t}\n\n\tprivate async _queueAutonomousContinuationForThresholdCompaction(\n\t\tmessage: AssistantMessage,\n\t): Promise<AgentMessage | undefined> {\n\t\tconst queuedMessage = this._queuedAutonomousThresholdContinuations.get(message);\n\t\tif (queuedMessage && this._postCompactionContinuationMessages.includes(queuedMessage)) {\n\t\t\treturn queuedMessage;\n\t\t}\n\t\tconst snapshot = this._snapshotAutonomousRuntimeState();\n\t\tconst arrivalEpoch = this._sessionInputArrivalEpoch;\n\t\tconst autonomousMessage = await nextAutonomousContinuation(this._autonomousState, message, {\n\t\t\tcwd: this._cwd,\n\t\t\tsignal: this.agent.signal,\n\t\t});\n\t\tif (!autonomousMessage) {\n\t\t\treturn undefined;\n\t\t}\n\t\tif (this._sessionInputArrivalEpoch !== arrivalEpoch) {\n\t\t\tthis._restoreAutonomousRuntimeSnapshot(snapshot);\n\t\t\treturn undefined;\n\t\t}\n\t\tthis._queuedAutonomousThresholdContinuations.set(message, autonomousMessage);\n\t\tthis._queuedAutonomousContinuationSnapshots.set(autonomousMessage, snapshot);\n\t\tthis._postCompactionContinuationMessages.push(autonomousMessage);\n\t\tthis._pendingThresholdCompactionAutonomousMessages.push(autonomousMessage);\n\t\tconst text =\n\t\t\ttypeof autonomousMessage.content === \"string\"\n\t\t\t\t? autonomousMessage.content\n\t\t\t\t: autonomousMessage.content.map((block) => (block.type === \"text\" ? block.text : \"\")).join(\"\\n\");\n\t\tthis._admitSessionInput(\n\t\t\tthis._createPreparedTurnAction(\"followUp\", text, undefined, {\n\t\t\t\tmessage: autonomousMessage,\n\t\t\t}),\n\t\t);\n\t\treturn autonomousMessage;\n\t}\n\n\t// The role heuristic reads an assistant-last threshold stop as \"task finished\" and\n\t// agent.continue() cannot resume from it, so the goal continuation is queued as a session input.\n\tprivate _queueGoalContinuationForThresholdCompaction(message: AssistantMessage): boolean {\n\t\tif (message.stopReason === \"error\" || message.stopReason === \"aborted\") {\n\t\t\treturn false;\n\t\t}\n\t\tif (this._goalState.status !== \"active\" || !this._goalState.objective) {\n\t\t\treturn false;\n\t\t}\n\t\tconst alreadyQueued = this._queuedGoalThresholdContinuation;\n\t\tif (\n\t\t\talreadyQueued !== undefined &&\n\t\t\tthis._actionStore.unfinishedActions().some((action) => {\n\t\t\t\tif (action.payload.kind !== \"turn\" || primaryDeliveryRecord(action).message !== alreadyQueued) return false;\n\t\t\t\t// A running continuation may already need a successor; only undelivered actions deduplicate.\n\t\t\t\treturn (\n\t\t\t\t\taction.lifecycle.state === \"queued\" ||\n\t\t\t\t\taction.lifecycle.state === \"selected\" ||\n\t\t\t\t\taction.lifecycle.state === \"preparing\" ||\n\t\t\t\t\taction.lifecycle.state === \"committing\"\n\t\t\t\t);\n\t\t\t})\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t\ttry {\n\t\t\tthis._ensureGoalRuntimeActive();\n\t\t\tthis._setGoalState({\n\t\t\t\t...this._goalState,\n\t\t\t\tcontinuationsUsed: this._goalState.continuationsUsed + 1,\n\t\t\t\tlastReason: undefined,\n\t\t\t\tlastError: undefined,\n\t\t\t});\n\t\t\tconst goalMessage = createGoalContextMessage(this._goalState, \"continuation\");\n\t\t\tconst normalized = normalizeMessageContent(goalMessage.content);\n\t\t\tthis._admitSessionInput(\n\t\t\t\tthis._createPreparedTurnAction(\"followUp\", normalized.text, normalized.images, {\n\t\t\t\t\tmessage: goalMessage,\n\t\t\t\t}),\n\t\t\t);\n\t\t\tthis._queuedGoalThresholdContinuation = goalMessage;\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t// Withdraws a goal continuation queued for a threshold compaction the user cancelled,\n\t// rolling back the continuationsUsed increment so the next natural stop re-queues it.\n\tprivate _clearQueuedGoalContinuationAfterCancelledThresholdCompaction(\n\t\tqueuedGoalContinuation: AgentMessage | undefined,\n\t): void {\n\t\tif (queuedGoalContinuation === undefined) return;\n\t\tconst cancelled = this._cancelSessionActions(\n\t\t\t(action) => action.payload.kind === \"turn\" && primaryDeliveryRecord(action).message === queuedGoalContinuation,\n\t\t\tnew Error(\"Queued goal continuation was cleared before delivery.\"),\n\t\t);\n\t\tthis._queuedGoalThresholdContinuation = undefined;\n\t\t// A stale marker (continuation already consumed) matches no action; only an\n\t\t// actual cancellation may roll back its queue-time continuationsUsed increment.\n\t\tif (cancelled.length === 0) return;\n\t\tthis._setGoalState({ ...this._goalState, continuationsUsed: this._goalState.continuationsUsed - 1 });\n\t\tthis._emitQueueUpdate();\n\t}\n\n\tprivate _clearQueuedAutonomousContinuations(\n\t\toptions: { restoreAutonomousState?: boolean; messages?: AgentMessage[] } = {},\n\t): void {\n\t\tconst requestedMessages = options.messages ?? [...this._postCompactionContinuationMessages];\n\t\tconst requestedMessageSet = new Set(requestedMessages);\n\t\tconst queuedMessages = this._postCompactionContinuationMessages.filter((message) =>\n\t\t\trequestedMessageSet.has(message),\n\t\t);\n\t\tif (queuedMessages.length === 0) {\n\t\t\treturn;\n\t\t}\n\t\tconst queuedMessageSet = new Set(queuedMessages);\n\t\tthis._postCompactionContinuationMessages = this._postCompactionContinuationMessages.filter(\n\t\t\t(message) => !queuedMessageSet.has(message),\n\t\t);\n\t\tthis.agent.removeQueuedMessages((message) => queuedMessageSet.has(message));\n\t\tthis._cancelSessionActions(\n\t\t\t(action) => action.payload.kind === \"turn\" && queuedMessageSet.has(primaryDeliveryRecord(action).message),\n\t\t\tnew Error(\"Queued autonomous continuation was cleared before delivery.\"),\n\t\t);\n\t\tthis._emitQueueUpdate();\n\t\tif (options.restoreAutonomousState) {\n\t\t\tfor (const queuedMessage of queuedMessages) {\n\t\t\t\tconst snapshot = this._queuedAutonomousContinuationSnapshots.get(queuedMessage);\n\t\t\t\tif (snapshot) {\n\t\t\t\t\tthis._restoreAutonomousRuntimeSnapshot(snapshot);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfor (const queuedMessage of queuedMessages) {\n\t\t\tthis._queuedAutonomousContinuationSnapshots.delete(queuedMessage);\n\t\t}\n\t\tthis._pendingThresholdCompactionAutonomousMessages = this._pendingThresholdCompactionAutonomousMessages.filter(\n\t\t\t(message) => !queuedMessageSet.has(message),\n\t\t);\n\t\tif (options.messages === undefined) {\n\t\t\tthis._continueAfterThresholdCompaction = false;\n\t\t}\n\t\tif (!this.agent.hasQueuedMessages() && this.unfinishedActionCount === 0) {\n\t\t\tthis._cancelPostCompactionContinue();\n\t\t}\n\t}\n\n\tprivate _clearQueuedAutonomousContinuationsAfterSkippedThresholdCompaction(\n\t\tshouldContinueAfterThreshold: boolean,\n\t\tqueuedMessages: AgentMessage[],\n\t): void {\n\t\tif (shouldContinueAfterThreshold) {\n\t\t\tthis._clearQueuedAutonomousContinuations({\n\t\t\t\trestoreAutonomousState: true,\n\t\t\t\tmessages: queuedMessages,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Handle a goal.* request from the Python kernel host bridge (the bundled\n\t * goal skill). All goal state stays host-side; the kernel only sees the\n\t * serialized snake_case response.\n\t */\n\thandleGoalHostRequest(type: string, payload: Record<string, unknown> = {}): GoalHostResponse {\n\t\tif (!this._includeGoals) {\n\t\t\tthrow new Error(\"goals are disabled in this session\");\n\t\t}\n\t\tswitch (type) {\n\t\t\tcase \"goal.get\":\n\t\t\t\treturn goalHostResponse(this.goalState, false);\n\t\t\tcase \"goal.create\": {\n\t\t\t\tif (typeof payload.objective !== \"string\") {\n\t\t\t\t\tthrow new Error(\"goal.create objective must be a string\");\n\t\t\t\t}\n\t\t\t\tif (payload.token_budget !== undefined && typeof payload.token_budget !== \"number\") {\n\t\t\t\t\tthrow new Error(\"goal.create token_budget must be an integer when provided\");\n\t\t\t\t}\n\t\t\t\treturn goalHostResponse(this._createGoalFromHost(payload.objective, payload.token_budget), false);\n\t\t\t}\n\t\t\tcase \"goal.complete\":\n\t\t\t\treturn goalHostResponse(this._completeGoalFromHost(), true);\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`unknown goal request type \"${type}\"`);\n\t\t}\n\t}\n\n\t/**\n\t * Handle a compact.* request from the kernel host bridge. Compaction would\n\t * abort the run executing the requesting cell, so compact.run only schedules\n\t * it; _checkCompaction consumes the request at the turn boundary.\n\t */\n\thandleCompactHostRequest(type: string, payload: Record<string, unknown> = {}): Record<string, unknown> {\n\t\tif (!this._includeCompactSkill) {\n\t\t\tthrow new Error(\"the compact skill is disabled in this session\");\n\t\t}\n\t\tswitch (type) {\n\t\t\tcase \"compact.status\": {\n\t\t\t\tconst usage = this.getContextUsage();\n\t\t\t\treturn {\n\t\t\t\t\ttokens: usage?.tokens ?? null,\n\t\t\t\t\tcontext_window: usage?.contextWindow ?? null,\n\t\t\t\t\tpercent: usage?.percent ?? null,\n\t\t\t\t\tscheduled: this._pendingRequestedCompaction !== undefined,\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"compact.run\": {\n\t\t\t\tconst instructions = payload.instructions;\n\t\t\t\tif (instructions !== undefined && typeof instructions !== \"string\") {\n\t\t\t\t\tthrow new Error(\"compact.run instructions must be a string when provided\");\n\t\t\t\t}\n\t\t\t\tif (!this.isStreaming) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tscheduled: false,\n\t\t\t\t\t\treason: \"no active turn; compaction can only be requested while a turn is running\",\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tconst preparation = prepareCompaction(\n\t\t\t\t\tthis.sessionManager.getBranch(),\n\t\t\t\t\tthis.settingsManager.getCompactionSettings(),\n\t\t\t\t);\n\t\t\t\tif (!preparation) {\n\t\t\t\t\tconst lastEntry = this.sessionManager.getBranch().at(-1);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tscheduled: false,\n\t\t\t\t\t\treason: lastEntry?.type === \"compaction\" ? \"already compacted\" : \"session is too short to compact\",\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tthis._pendingRequestedCompaction = { customInstructions: instructions };\n\t\t\t\treturn {\n\t\t\t\t\tscheduled: true,\n\t\t\t\t\tnote: \"Compaction runs when the current turn ends; you resume automatically afterwards. Continue working normally.\",\n\t\t\t\t};\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`unknown compact request type \"${type}\"`);\n\t\t}\n\t}\n\n\t/**\n\t * Handle a refine.* request from the kernel host bridge. Like compact,\n\t * refinement waits for the current turn to become idle before applying\n\t * changes, so refine.run only schedules it; _consumePendingRequestedRefine\n\t * fires it at the turn boundary. This prevents a deadlock that would occur\n\t * if refine() awaited agent idle from within the active tool call.\n\t */\n\thandleRefineHostRequest(type: string, payload: Record<string, unknown> = {}): Record<string, unknown> {\n\t\tswitch (type) {\n\t\t\tcase \"refine.status\": {\n\t\t\t\treturn {\n\t\t\t\t\tpending: this._pendingRequestedRefine !== undefined,\n\t\t\t\t\tin_flight:\n\t\t\t\t\t\tthis._refineInFlight !== undefined ||\n\t\t\t\t\t\tthis._refinePlanInFlight !== undefined ||\n\t\t\t\t\t\tthis._serializedPlanInFlight !== undefined,\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"refine.run\": {\n\t\t\t\tconst instructions = payload.instructions;\n\t\t\t\tif (instructions !== undefined && typeof instructions !== \"string\") {\n\t\t\t\t\tthrow new Error(\"refine.run instructions must be a string when provided\");\n\t\t\t\t}\n\t\t\t\tconst globalFlag = payload.global;\n\t\t\t\tif (globalFlag !== undefined && typeof globalFlag !== \"boolean\") {\n\t\t\t\t\tthrow new Error(\"refine.run global must be a boolean when provided\");\n\t\t\t\t}\n\t\t\t\tif (!this.isStreaming) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tscheduled: false,\n\t\t\t\t\t\treason: \"no active turn; refine can only be requested while a turn is running\",\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tconst previous = this._pendingRequestedRefine ?? this._serializedExplicitRefineOptions;\n\t\t\t\tthis._pendingRequestedRefine = {\n\t\t\t\t\tinstructions: instructions ?? previous?.instructions,\n\t\t\t\t\tglobal: globalFlag ?? previous?.global,\n\t\t\t\t};\n\t\t\t\t// In serialized mode, kick off background planning immediately\n\t\t\t\t// (the primary response ended at message_end, tools are active).\n\t\t\t\t// This lets planning overlap tool execution rather than waiting\n\t\t\t\t// for the shouldStopAfterTurn boundary.\n\t\t\t\tif (this._serializedRefine) {\n\t\t\t\t\tif (this._serializedPlanInFlight) {\n\t\t\t\t\t\tthis._autoRefineBranchVersion++;\n\t\t\t\t\t\tif (this._refineAbortController) {\n\t\t\t\t\t\t\tthis._refineAbortController.abort();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis._serializedPlanInFlight = Promise.resolve({\n\t\t\t\t\t\t\t\tstatus: \"invalidated\",\n\t\t\t\t\t\t\t\tbranchVersion: this._autoRefineBranchVersion,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis._maybeStartSerializedBackgroundPlan();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tscheduled: true,\n\t\t\t\t\tnote: \"Refinement runs when the current turn ends; the harness rebuilds the system prompt and resumes you automatically. Continue working normally.\",\n\t\t\t\t};\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`unknown refine request type \"${type}\"`);\n\t\t}\n\t}\n\n\t/**\n\t * Handle an rlm_heartbeat.* request from the bundled rlm-heartbeat skill.\n\t * These heartbeats are internal to this active session and never read or\n\t * mutate the user-level /heartbeat.\n\t */\n\thandleRlmHeartbeatHostRequest(type: string, payload: Record<string, unknown> = {}): Record<string, unknown> {\n\t\tconst controller = this._rlmHeartbeatController;\n\t\tif (!controller) {\n\t\t\tthrow new Error(\"RLM heartbeat skill is not available in this session\");\n\t\t}\n\t\tswitch (type) {\n\t\t\tcase \"rlm_heartbeat.list\": {\n\t\t\t\tconst includeInactive = payload.include_inactive === true || payload.includeInactive === true;\n\t\t\t\treturn {\n\t\t\t\t\theartbeats: controller\n\t\t\t\t\t\t.listRlmHeartbeats({ includeInactive })\n\t\t\t\t\t\t.map((heartbeat) => rlmHeartbeatHostResponse(heartbeat)),\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"rlm_heartbeat.create\": {\n\t\t\t\tif (typeof payload.instruction !== \"string\") {\n\t\t\t\t\tthrow new Error(\"rlm_heartbeat.create instruction must be a string\");\n\t\t\t\t}\n\t\t\t\tif (payload.interval !== undefined && typeof payload.interval !== \"string\") {\n\t\t\t\t\tthrow new Error(\"rlm_heartbeat.create interval must be a string when provided\");\n\t\t\t\t}\n\t\t\t\tif (payload.label !== undefined && typeof payload.label !== \"string\") {\n\t\t\t\t\tthrow new Error(\"rlm_heartbeat.create label must be a string when provided\");\n\t\t\t\t}\n\t\t\t\tconst deliveryMode = normalizeHeartbeatDeliveryMode(payload.delivery_mode ?? payload.deliveryMode);\n\t\t\t\treturn {\n\t\t\t\t\theartbeat: rlmHeartbeatHostResponse(\n\t\t\t\t\t\tcontroller.createRlmHeartbeat({\n\t\t\t\t\t\t\tinstruction: payload.instruction,\n\t\t\t\t\t\t\tinterval: payload.interval,\n\t\t\t\t\t\t\tlabel: payload.label,\n\t\t\t\t\t\t\tdeliveryMode,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"rlm_heartbeat.update\": {\n\t\t\t\tif (typeof payload.id !== \"string\") {\n\t\t\t\t\tthrow new Error(\"rlm_heartbeat.update id must be a string\");\n\t\t\t\t}\n\t\t\t\tif (payload.instruction !== undefined && typeof payload.instruction !== \"string\") {\n\t\t\t\t\tthrow new Error(\"rlm_heartbeat.update instruction must be a string when provided\");\n\t\t\t\t}\n\t\t\t\tif (payload.interval !== undefined && typeof payload.interval !== \"string\") {\n\t\t\t\t\tthrow new Error(\"rlm_heartbeat.update interval must be a string when provided\");\n\t\t\t\t}\n\t\t\t\tif (payload.label !== undefined && typeof payload.label !== \"string\") {\n\t\t\t\t\tthrow new Error(\"rlm_heartbeat.update label must be a string when provided\");\n\t\t\t\t}\n\t\t\t\tif (payload.status !== undefined && !isRlmHeartbeatStatusUpdate(payload.status)) {\n\t\t\t\t\tthrow new Error('rlm_heartbeat.update status must be \"pause\" or \"resume\" when provided');\n\t\t\t\t}\n\t\t\t\tconst rawDeliveryMode = payload.delivery_mode ?? payload.deliveryMode;\n\t\t\t\tconst deliveryMode = normalizeHeartbeatDeliveryMode(rawDeliveryMode);\n\t\t\t\tif (\n\t\t\t\t\tpayload.instruction === undefined &&\n\t\t\t\t\tpayload.interval === undefined &&\n\t\t\t\t\tpayload.label === undefined &&\n\t\t\t\t\tpayload.status === undefined &&\n\t\t\t\t\trawDeliveryMode === undefined\n\t\t\t\t) {\n\t\t\t\t\tthrow new Error(\"rlm_heartbeat.update requires at least one field to update\");\n\t\t\t\t}\n\t\t\t\tconst heartbeat = controller.updateRlmHeartbeat({\n\t\t\t\t\tid: payload.id,\n\t\t\t\t\tinstruction: payload.instruction,\n\t\t\t\t\tinterval: payload.interval,\n\t\t\t\t\tlabel: payload.label,\n\t\t\t\t\tstatus: payload.status,\n\t\t\t\t\tdeliveryMode,\n\t\t\t\t});\n\t\t\t\treturn {\n\t\t\t\t\theartbeat: heartbeat ? rlmHeartbeatHostResponse(heartbeat) : null,\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"rlm_heartbeat.delete\": {\n\t\t\t\tif (typeof payload.id !== \"string\") {\n\t\t\t\t\tthrow new Error(\"rlm_heartbeat.delete id must be a string\");\n\t\t\t\t}\n\t\t\t\tconst heartbeat = controller.deleteRlmHeartbeat(payload.id);\n\t\t\t\treturn {\n\t\t\t\t\theartbeat: heartbeat ? rlmHeartbeatHostResponse(heartbeat) : null,\n\t\t\t\t};\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`unknown RLM heartbeat request type \"${type}\"`);\n\t\t}\n\t}\n\n\thandleAgentMessageHostRequest(\n\t\ttype: string,\n\t\tpayload: Record<string, unknown> = {},\n\t):\n\t\t| Promise<AgentSessionMessageListResult | AgentSessionMessageReceipt | AgentFamilyRosterResult>\n\t\t| AgentSessionMessageListResult\n\t\t| AgentFamilyRosterResult {\n\t\tif (!this._agentMessageController) {\n\t\t\tthrow new Error(\"agent messaging is not available in this session\");\n\t\t}\n\t\tswitch (type) {\n\t\t\tcase \"agent_message.list_agents\":\n\t\t\t\tif (!this._agentMessageController.roster)\n\t\t\t\t\tthrow new Error(\"agent family roster is not available in this session\");\n\t\t\t\treturn this._agentMessageController.roster();\n\t\t\tcase \"agent_message.send\": {\n\t\t\t\tif (typeof payload.target !== \"string\") {\n\t\t\t\t\tthrow new Error(\"agent_message.send target must be a string\");\n\t\t\t\t}\n\t\t\t\tif (typeof payload.message !== \"string\") {\n\t\t\t\t\tthrow new Error(\"agent_message.send message must be a string\");\n\t\t\t\t}\n\t\t\t\treturn this._agentMessageController.sendAgentMessage({\n\t\t\t\t\ttarget: assertDirectAgentMessageTarget(payload.target),\n\t\t\t\t\tmessage: normalizeAgentSessionMessage(payload.message),\n\t\t\t\t});\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`unknown agent message request type \"${type}\"`);\n\t\t}\n\t}\n\n\thandleAgentObserveHostRequest(\n\t\ttype: string,\n\t\tpayload: Record<string, unknown> = {},\n\t):\n\t\t| AgentObserveListResult\n\t\t| AgentObserveAgentSnapshot\n\t\t| AgentObserveRecentMessagesResult\n\t\t| Promise<AgentObserveListResult | AgentObserveAgentSnapshot | AgentObserveRecentMessagesResult> {\n\t\tconst controller = this._agentObserveController;\n\t\tif (!controller) {\n\t\t\tthrow new Error(\"agent observation is not available in this session\");\n\t\t}\n\t\tswitch (type) {\n\t\t\tcase \"agent_observe.list\":\n\t\t\t\treturn controller.listAgents();\n\t\t\tcase \"agent_observe.get\": {\n\t\t\t\tif (typeof payload.target !== \"string\") {\n\t\t\t\t\tthrow new Error(\"agent_observe.get target must be a string\");\n\t\t\t\t}\n\t\t\t\treturn controller.getAgent(payload.target);\n\t\t\t}\n\t\t\tcase \"agent_observe.recent\": {\n\t\t\t\tif (typeof payload.target !== \"string\") {\n\t\t\t\t\tthrow new Error(\"agent_observe.recent target must be a string\");\n\t\t\t\t}\n\t\t\t\treturn controller.recentMessages({\n\t\t\t\t\ttarget: payload.target,\n\t\t\t\t\tlimit: normalizeObserveLimit(payload.limit as number | undefined),\n\t\t\t\t\tmaxChars: normalizeObserveMaxChars((payload.max_chars ?? payload.maxChars) as number | undefined),\n\t\t\t\t});\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`unknown agent observe request type \"${type}\"`);\n\t\t}\n\t}\n\n\tprivate _createGoalFromHost(objective: string, tokenBudget: number | undefined): GoalState {\n\t\tswitch (this._goalState.status) {\n\t\t\tcase \"active\":\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"cannot create a new goal because this thread already has an active goal; run `await goal.complete()` when it is achieved, or ask the user to clear it with /goal clear\",\n\t\t\t\t);\n\t\t\tcase \"paused\":\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"cannot create a new goal because a paused goal exists; ask the user to resume it with /goal resume or clear it with /goal clear\",\n\t\t\t\t);\n\t\t\tcase \"budget_limited\":\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"cannot create a new goal because a budget-limited goal exists; ask the user to resume it with /goal resume or clear it with /goal clear\",\n\t\t\t\t);\n\t\t\tdefault:\n\t\t\t\t// idle, or a terminal record (complete / error): nothing pending, start fresh.\n\t\t\t\treturn this._startGoal(objective, tokenBudget);\n\t\t}\n\t}\n\n\tprivate _completeGoalFromHost(): GoalState {\n\t\tif (!this._goalState.objective || this._goalState.status === \"idle\") {\n\t\t\tthrow new Error(\"cannot complete goal because this thread has no goal\");\n\t\t}\n\t\tconst goal = this._goalWithAccountedWallClock();\n\t\t// A turn can cross the budget and complete the goal at once: accounting\n\t\t// runs at message_end, before the completing ipython cell executes, so a\n\t\t// budget-limit context may already be steered. It is stale now — drop it.\n\t\tthis._clearQueuedGoalContexts();\n\t\tthis._setGoalState({\n\t\t\t...goal,\n\t\t\tactive: false,\n\t\t\tstatus: \"complete\",\n\t\t\tlastReason: \"Goal achieved\",\n\t\t\tlastError: undefined,\n\t\t});\n\t\treturn this._goalState;\n\t}\n\n\tprivate async _getGoalContinuationMessages(\n\t\tcontext: GetContinuationMessagesContext,\n\t\tsignal?: AbortSignal,\n\t): Promise<AgentMessage[]> {\n\t\tif (this._stopGoalContinuationForTerminalMessage(context.message)) {\n\t\t\treturn [];\n\t\t}\n\t\tif (signal?.aborted || this._goalState.status !== \"active\" || !this._goalState.objective) {\n\t\t\treturn [];\n\t\t}\n\t\t// Delegating and ending the turn is correct behavior; hold the continuation\n\t\t// until descendants settle instead of re-prompting a waiting parent.\n\t\tif (this._hasUnsettledRlmQuiescenceWork()) {\n\t\t\tthis._goalContinuationAwaitsRlmWork = true;\n\t\t\treturn [];\n\t\t}\n\t\tthis._goalContinuationAwaitsRlmWork = false;\n\t\ttry {\n\t\t\tthis._ensureGoalRuntimeActive(context.context);\n\t\t\tconst nextGoal = {\n\t\t\t\t...this._goalState,\n\t\t\t\tcontinuationsUsed: this._goalState.continuationsUsed + 1,\n\t\t\t\tlastReason: undefined,\n\t\t\t\tlastError: undefined,\n\t\t\t};\n\t\t\tthis._setGoalState(nextGoal);\n\t\t\treturn [createGoalContextMessage(this._goalState, \"continuation\")];\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\ttry {\n\t\t\t\tthis._finishGoalWithError(message);\n\t\t\t} catch {\n\t\t\t\t// The continuation hook must not reject; listener failures should not crash the agent loop.\n\t\t\t}\n\t\t\treturn [];\n\t\t}\n\t}\n\n\tprivate async _getContinuationMessages(\n\t\tcontext: GetContinuationMessagesContext,\n\t\tsignal?: AbortSignal,\n\t): Promise<AgentMessage[]> {\n\t\tif (this.queuedActionCount > 0) {\n\t\t\treturn [];\n\t\t}\n\t\tconst arrivalEpoch = this._sessionInputArrivalEpoch;\n\t\tconst goalSnapshot = this._goalState;\n\t\tconst goalAccountingStartedAt = this._goalAccountingStartedAt;\n\t\tconst goalMessages = await this._getGoalContinuationMessages(context, signal);\n\t\tif (goalMessages.length > 0 || signal?.aborted) {\n\t\t\tif (goalMessages.length > 0 && this._sessionInputArrivalEpoch !== arrivalEpoch) {\n\t\t\t\tthis._setGoalState(goalSnapshot);\n\t\t\t\tthis._goalAccountingStartedAt = goalAccountingStartedAt;\n\t\t\t\treturn [];\n\t\t\t}\n\t\t\treturn goalMessages;\n\t\t}\n\t\tif (\n\t\t\tthis._autonomousContinuationSuppressionDepth > 0 ||\n\t\t\tcontext.newMessages.some((message) => this._autonomousContinuationSuppressedMessages.has(message))\n\t\t) {\n\t\t\treturn [];\n\t\t}\n\t\tconst autonomousSnapshot = this._snapshotAutonomousRuntimeState();\n\t\tconst autonomousMessage = await nextAutonomousContinuation(this._autonomousState, context.message, {\n\t\t\tcwd: this._cwd,\n\t\t\tsignal,\n\t\t});\n\t\tif (autonomousMessage && this._sessionInputArrivalEpoch !== arrivalEpoch) {\n\t\t\tthis._restoreAutonomousRuntimeSnapshot(autonomousSnapshot);\n\t\t\treturn [];\n\t\t}\n\t\treturn autonomousMessage ? [autonomousMessage] : [];\n\t}\n\n\tprivate _lastAssistantMessage: AssistantMessage | undefined = undefined;\n\n\tprivate _agentMessageOutcome(agentMessageId: string): AgentMessageOutcome {\n\t\tlet outcome = this._agentMessageOutcomes.get(agentMessageId);\n\t\tif (!outcome) {\n\t\t\toutcome = {};\n\t\t\tthis._agentMessageOutcomes.set(agentMessageId, outcome);\n\t\t}\n\t\treturn outcome;\n\t}\n\n\t/**\n\t * Register a delivery waiter before submitting the prompt. Delivery outcomes are not retained\n\t * for late lookup, so callers that register after admission may wait for a future use of the id.\n\t */\n\twaitForAgentMessagePromptDelivery(agentMessageId: string): Promise<void> {\n\t\tconst outcome = this._agentMessageOutcome(agentMessageId);\n\t\toutcome.delivery ??= createAgentMessageDeferred();\n\t\treturn outcome.delivery.promise;\n\t}\n\n\tprivate _settleAgentMessage(\n\t\tagentMessageId: string | undefined,\n\t\tleg: \"delivery\" | \"completion\",\n\t\terror?: Error,\n\t): void {\n\t\tif (agentMessageId === undefined) return;\n\t\tconst outcome = this._agentMessageOutcomes.get(agentMessageId);\n\t\tif (!outcome) return;\n\t\tconst deferred = outcome[leg];\n\t\tif (!deferred) return;\n\t\toutcome[leg] = undefined;\n\t\tif (!outcome.delivery && !outcome.completion) {\n\t\t\tthis._agentMessageOutcomes.delete(agentMessageId);\n\t\t}\n\t\tif (error) deferred.reject(error);\n\t\telse deferred.resolve();\n\t}\n\n\tprivate _rejectAgentMessage(agentMessageId: string | undefined, error: Error): void {\n\t\tif (agentMessageId === undefined) return;\n\t\tthis._settleAgentMessage(agentMessageId, \"delivery\", error);\n\t\tthis._settleAgentMessage(agentMessageId, \"completion\", error);\n\t}\n\n\tprivate _rejectQueuedAgentMessageDeliveries(deliveryError: Error, completionError = deliveryError): void {\n\t\tfor (const action of this._actionStore.unfinishedActions()) {\n\t\t\tthis._settleAgentMessage(action.agentMessageId, \"delivery\", deliveryError);\n\t\t\tthis._settleAgentMessage(action.agentMessageId, \"completion\", completionError);\n\t\t}\n\t}\n\n\tprivate _capturingCancelledAction(message: AgentMessage): QueuedSessionAction | undefined {\n\t\treturn this._actionStore\n\t\t\t.ownedActions()\n\t\t\t.find(\n\t\t\t\t(action) =>\n\t\t\t\t\taction.lifecycle.state === \"cancelled\" &&\n\t\t\t\t\taction.payload.kind === \"turn\" &&\n\t\t\t\t\taction.payload.captureRunMessages?.has(message) === true,\n\t\t\t);\n\t}\n\n\tprivate _hasCancelledDispatchCapture(): boolean {\n\t\treturn this._actionStore\n\t\t\t.ownedActions()\n\t\t\t.some(\n\t\t\t\t(action) =>\n\t\t\t\t\taction.lifecycle.state === \"cancelled\" &&\n\t\t\t\t\taction.payload.kind === \"turn\" &&\n\t\t\t\t\taction.payload.captureRunMessages !== undefined,\n\t\t\t);\n\t}\n\n\tprivate _handleAgentEvent = (event: AgentEvent): void => {\n\t\tthis._createRetryPromiseForAgentEnd(event);\n\t\tif (event.type === \"message_start\" || event.type === \"message_end\") {\n\t\t\tfor (const action of this._actionStore.ownedActions()) {\n\t\t\t\tif (\n\t\t\t\t\taction.payload.kind !== \"turn\" ||\n\t\t\t\t\t!action.payload.captureRunMessages ||\n\t\t\t\t\taction.payload.cancelledDispatchEnded\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst primary = primaryDeliveryRecord(action);\n\t\t\t\tif (event.message === primary.message || primary.started) {\n\t\t\t\t\taction.payload.captureRunMessages.add(event.message);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (event.type === \"agent_end\") {\n\t\t\tconst captured = new Set<AgentMessage>();\n\t\t\tfor (const action of this._actionStore.ownedActions()) {\n\t\t\t\tif (action.payload.kind === \"turn\" && action.payload.captureRunMessages) {\n\t\t\t\t\tfor (const message of action.payload.captureRunMessages) captured.add(message);\n\t\t\t\t\taction.payload.cancelledDispatchEnded = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (captured.size > 0) {\n\t\t\t\tthis.agent.state.messages = this.agent.state.messages.filter((message) => !captured.has(message));\n\t\t\t}\n\t\t}\n\t\tif (event.type === \"message_start\" && (event.message.role === \"user\" || event.message.role === \"custom\")) {\n\t\t\tfor (const action of this._actionStore.actionsForMessage(event.message)) {\n\t\t\t\tconst record =\n\t\t\t\t\taction.payload.kind === \"turn\"\n\t\t\t\t\t\t? action.payload.records.find((candidate) => candidate.message === event.message)\n\t\t\t\t\t\t: undefined;\n\t\t\t\tif (record) record.started = true;\n\t\t\t\tif (record?.role === \"primary\") {\n\t\t\t\t\tthis._actionStore.ticketFor(action).settleDelivered({ status: \"delivered\" });\n\t\t\t\t\tthis._settleAgentMessage(action.agentMessageId, \"delivery\");\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (event.type === \"message_end\" && (event.message.role === \"user\" || event.message.role === \"custom\")) {\n\t\t\tfor (const action of this._actionStore.actionsForMessage(event.message)) {\n\t\t\t\tconst record =\n\t\t\t\t\taction.payload.kind === \"turn\"\n\t\t\t\t\t\t? action.payload.records.find((candidate) => candidate.message === event.message)\n\t\t\t\t\t\t: undefined;\n\t\t\t\tif (record) record.durable = true;\n\t\t\t\tif (record?.role === \"primary\" && action.lifecycle.state === \"committing\") {\n\t\t\t\t\ttransitionSessionAction(action, {\n\t\t\t\t\t\tstate: \"running\",\n\t\t\t\t\t\texecution: \"agent_turn\",\n\t\t\t\t\t});\n\t\t\t\t\tthis._notifySessionInputCheckpointChange();\n\t\t\t\t\tthis._emitQueueUpdate();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis._agentEventQueue = this._agentEventQueue.then(\n\t\t\t() => this._processAgentEvent(event),\n\t\t\t() => this._processAgentEvent(event),\n\t\t);\n\t\tthis._agentEventQueue.catch(() => {});\n\t};\n\n\tprivate _createRetryPromiseForAgentEnd(event: AgentEvent): void {\n\t\tif (event.type !== \"agent_end\" || this._retryPromise) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst settings = this.settingsManager.getRetrySettings();\n\t\tif (!settings.enabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst lastAssistant = this._findLastAssistantInMessages(event.messages);\n\t\tconst concreteAuthFailure = lastAssistant ? this._isConcreteProviderAuthFailure(lastAssistant) : false;\n\t\tif (!lastAssistant || (!this._isRetryableError(lastAssistant) && !concreteAuthFailure)) {\n\t\t\treturn;\n\t\t}\n\t\tif (concreteAuthFailure) {\n\t\t\tthis._captureRetryAuthFailureSource(lastAssistant);\n\t\t}\n\n\t\tthis._retryPromise = new Promise((resolve) => {\n\t\t\tthis._retryResolve = resolve;\n\t\t});\n\t}\n\n\tprivate _findLastAssistantInMessages(messages: AgentMessage[]): AssistantMessage | undefined {\n\t\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\t\tconst message = messages[i];\n\t\t\tif (message.role === \"assistant\") {\n\t\t\t\treturn message as AssistantMessage;\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate _addLoginGuidanceToAuthError(event: AgentEvent): void {\n\t\tconst message =\n\t\t\tevent.type === \"message_end\" && event.message.role === \"assistant\"\n\t\t\t\t? (event.message as AssistantMessage)\n\t\t\t\t: event.type === \"agent_end\"\n\t\t\t\t\t? this._findLastAssistantInMessages(event.messages)\n\t\t\t\t\t: undefined;\n\t\tif (!message || message.stopReason !== \"error\" || !message.errorMessage) {\n\t\t\treturn;\n\t\t}\n\t\tif (!isLikelyAuthenticationError(message.errorMessage)) {\n\t\t\treturn;\n\t\t}\n\t\tmessage.errorMessage = addLoginGuidanceToAuthError(message.errorMessage);\n\t}\n\n\tprivate async _processAgentEvent(event: AgentEvent): Promise<void> {\n\t\tlet clearedDispatchEnded = false;\n\t\tif ((event.type === \"message_start\" || event.type === \"message_end\") && event.message.role === \"toolResult\") {\n\t\t\tthis._applyLateIpythonSentAgentMessages(event.message);\n\t\t}\n\t\tif (event.type === \"message_start\" || event.type === \"message_end\") {\n\t\t\tconst cleared = this._capturingCancelledAction(event.message);\n\t\t\tif (cleared?.payload.kind === \"turn\" && cleared.payload.captureRunMessages) {\n\t\t\t\tconst captured = cleared.payload.captureRunMessages;\n\t\t\t\tthis.agent.state.messages = this.agent.state.messages.filter((message) => !captured.has(message));\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tif (event.type === \"agent_end\") {\n\t\t\tconst cleared = this._actionStore\n\t\t\t\t.ownedActions()\n\t\t\t\t.filter(\n\t\t\t\t\t(action) =>\n\t\t\t\t\t\taction.lifecycle.state === \"cancelled\" &&\n\t\t\t\t\t\taction.payload.kind === \"turn\" &&\n\t\t\t\t\t\taction.payload.captureRunMessages !== undefined,\n\t\t\t\t);\n\t\t\tif (cleared.length > 0) {\n\t\t\t\tclearedDispatchEnded = true;\n\t\t\t\tconst removed = new Set(\n\t\t\t\t\tcleared.flatMap((action) =>\n\t\t\t\t\t\taction.payload.kind === \"turn\" ? [...(action.payload.captureRunMessages ?? [])] : [],\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\tthis.agent.state.messages = this.agent.state.messages.filter((message) => !removed.has(message));\n\t\t\t\t(this.agent.state as { errorMessage?: string }).errorMessage = undefined;\n\t\t\t\tthis._lastAssistantMessage = undefined;\n\t\t\t\tfor (const action of cleared) this._actionStore.releaseTerminal(action);\n\t\t\t\tthis._notifySessionInputCheckpointChange();\n\t\t\t\tthis._resolveRetry();\n\t\t\t}\n\t\t}\n\n\t\tif (event.type === \"message_start\" && startsAgentRun(event.message)) {\n\t\t\tthis._overflowRecovery = \"idle\";\n\t\t}\n\n\t\tawait this._emitExtensionEvent(event);\n\t\tif (event.type === \"message_start\" || event.type === \"message_end\") {\n\t\t\tconst cleared = this._capturingCancelledAction(event.message);\n\t\t\tif (cleared?.payload.kind === \"turn\" && cleared.payload.captureRunMessages) {\n\t\t\t\tconst captured = cleared.payload.captureRunMessages;\n\t\t\t\tthis.agent.state.messages = this.agent.state.messages.filter((message) => !captured.has(message));\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tthis._addLoginGuidanceToAuthError(event);\n\n\t\tthis._emit(event);\n\n\t\tif (event.type === \"message_end\") {\n\t\t\tif (event.message.role === \"custom\") {\n\t\t\t\tthis.sessionManager.appendCustomMessageEntry(\n\t\t\t\t\tevent.message.customType,\n\t\t\t\t\tevent.message.content,\n\t\t\t\t\tevent.message.display,\n\t\t\t\t\tevent.message.details,\n\t\t\t\t);\n\t\t\t} else if (\n\t\t\t\tevent.message.role === \"user\" ||\n\t\t\t\tevent.message.role === \"assistant\" ||\n\t\t\t\tevent.message.role === \"toolResult\"\n\t\t\t) {\n\t\t\t\tthis.sessionManager.appendMessage(event.message);\n\t\t\t}\n\n\t\t\tif (event.message.role === \"assistant\") {\n\t\t\t\tthis._lastAssistantMessage = event.message;\n\n\t\t\t\tconst assistantMsg = event.message as AssistantMessage;\n\t\t\t\tif (assistantMsg.stopReason !== \"error\") {\n\t\t\t\t\taddAutonomousUsage(this._autonomousState, assistantMsg.usage);\n\t\t\t\t}\n\t\t\t\tif (assistantMsg.stopReason !== \"error\" && assistantMsg.stopReason !== \"aborted\") {\n\t\t\t\t\tthis._assistantTurnsSinceAutoRefine++;\n\t\t\t\t\t// In serialized mode, kick off background refinement planning\n\t\t\t\t\t// immediately after the primary stream finishes, while tools\n\t\t\t\t\t// are still executing. The plan is awaited at shouldStopAfterTurn\n\t\t\t\t\t// before applying, so planning overlaps tools only — never another\n\t\t\t\t\t// model request.\n\t\t\t\t\tthis._maybeStartSerializedBackgroundPlan();\n\t\t\t\t}\n\t\t\t\tif (assistantMsg.stopReason !== \"error\") {\n\t\t\t\t\tthis._overflowRecovery = \"idle\";\n\t\t\t\t}\n\t\t\t\tif (this._isConcreteProviderAuthFailure(assistantMsg)) {\n\t\t\t\t\tthis._captureRetryAuthFailureSource(assistantMsg);\n\t\t\t\t}\n\n\t\t\t\t// Reset retry counter immediately on successful assistant response\n\t\t\t\t// This prevents accumulation across multiple LLM calls within a turn\n\t\t\t\tif (assistantMsg.stopReason !== \"error\" && this._retryAttempt > 0) {\n\t\t\t\t\tthis._emit({\n\t\t\t\t\t\ttype: \"auto_retry_end\",\n\t\t\t\t\t\tsuccess: true,\n\t\t\t\t\t\tattempt: this._retryAttempt,\n\t\t\t\t\t});\n\t\t\t\t\tthis._retryAttempt = 0;\n\t\t\t\t\tthis._retryAuthFailureSources = [];\n\t\t\t\t}\n\t\t\t\tif (this._accountGoalUsageForAssistantMessage(assistantMsg)) {\n\t\t\t\t\tconst message = createGoalContextMessage(this._goalState, \"budget_limit\");\n\t\t\t\t\tconst normalized = normalizeMessageContent(message.content);\n\t\t\t\t\tawait this._queuePreparedPrompt(\"steer\", normalized.text, normalized.images, {\n\t\t\t\t\t\tmessage,\n\t\t\t\t\t\tresumeIfIdle: true,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (clearedDispatchEnded) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (event.type === \"agent_end\") {\n\t\t\tconst msg =\n\t\t\t\tthis._lastAssistantMessage ??\n\t\t\t\t(this._retryPromise ? this._findLastAssistantInMessages(event.messages) : undefined);\n\t\t\tthis._lastAssistantMessage = undefined;\n\t\t\tif (!msg) {\n\t\t\t\tthis._resolveRetry();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst concreteAuthFailure = this._isConcreteProviderAuthFailure(msg);\n\t\t\tconst retryConcreteAuthFailure =\n\t\t\t\tconcreteAuthFailure && !this._isStructuredPermanentProviderRetryExhausted(msg);\n\t\t\tif (this._isRetryableError(msg) || retryConcreteAuthFailure) {\n\t\t\t\tif (retryConcreteAuthFailure) {\n\t\t\t\t\tthis._captureRetryAuthFailureSource(msg);\n\t\t\t\t}\n\t\t\t\tconst didRetry = await this._handleRetryableError(msg, {\n\t\t\t\t\tmarkAuthStaleOnFailure: retryConcreteAuthFailure,\n\t\t\t\t\tauthSourceTokens: retryConcreteAuthFailure ? this._retryAuthFailureSources : undefined,\n\t\t\t\t});\n\t\t\t\tif (didRetry) return; // Retry was initiated, don't proceed to compaction\n\t\t\t}\n\n\t\t\tconst compactionWillRetry = await this._checkCompaction(msg);\n\t\t\tif (compactionWillRetry && this._retryAttempt > 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._finishActiveRetryWithFailure(msg);\n\t\t\tthis._resolveRetry();\n\t\t\tif (!compactionWillRetry) {\n\t\t\t\tthis._finishGoalForTerminalAssistantMessage(msg);\n\t\t\t\t// In serialized mode, agent-callable refine.run is serviced\n\t\t\t\t// at the shouldStopAfterTurn boundary, not here at agent_end.\n\t\t\t\tif (!this._serializedRefine) {\n\t\t\t\t\tconst consumedRequestedRefine = this._consumePendingRequestedRefine();\n\t\t\t\t\tif (!consumedRequestedRefine) {\n\t\t\t\t\t\tthis._scheduleAutoRefineAfterAgentEnd();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _resolveRetry(): void {\n\t\tif (this._retryResolve) {\n\t\t\tthis._retryResolve();\n\t\t\tthis._retryResolve = undefined;\n\t\t\tthis._retryPromise = undefined;\n\t\t\tthis._scheduleSessionInputPump();\n\t\t}\n\t}\n\n\tprivate _findLastAssistantMessage(): AssistantMessage | undefined {\n\t\tconst messages = this.agent.state.messages;\n\t\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\t\tconst msg = messages[i];\n\t\t\tif (msg.role === \"assistant\") {\n\t\t\t\treturn msg as AssistantMessage;\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate _replaceMessageInPlace(target: AgentMessage, replacement: AgentMessage): void {\n\t\t// Agent-core stores the finalized message object in its state before emitting message_end.\n\t\t// SessionManager persistence happens later in _processAgentEvent() with event.message.\n\t\t// Mutating this object in place keeps agent state, later turn/agent events, listeners,\n\t\t// and the eventual SessionManager.appendMessage(event.message) persistence in sync.\n\t\tif (target === replacement) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst targetRecord = target as unknown as Record<string, unknown>;\n\t\tfor (const key of Object.keys(targetRecord)) {\n\t\t\tdelete targetRecord[key];\n\t\t}\n\t\tObject.assign(targetRecord, replacement);\n\t}\n\n\tprivate async _emitExtensionEvent(event: AgentEvent): Promise<void> {\n\t\tif (event.type === \"agent_start\") {\n\t\t\tthis._turnIndex = 0;\n\t\t\tthis.sessionManager.recordGitStateIfChanged();\n\t\t\tawait this._extensionRunner.emit({ type: \"agent_start\" });\n\t\t} else if (event.type === \"agent_end\") {\n\t\t\t// Also capture at end of turn so commits made during the run (e.g. via a bash tool) land.\n\t\t\tthis.sessionManager.recordGitStateIfChanged();\n\t\t\tawait this._extensionRunner.emit({\n\t\t\t\ttype: \"agent_end\",\n\t\t\t\tmessages: event.messages,\n\t\t\t});\n\t\t} else if (event.type === \"turn_start\") {\n\t\t\tconst extensionEvent: TurnStartEvent = {\n\t\t\t\ttype: \"turn_start\",\n\t\t\t\tturnIndex: this._turnIndex,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t};\n\t\t\tawait this._extensionRunner.emit(extensionEvent);\n\t\t} else if (event.type === \"turn_end\") {\n\t\t\tconst extensionEvent: TurnEndEvent = {\n\t\t\t\ttype: \"turn_end\",\n\t\t\t\tturnIndex: this._turnIndex,\n\t\t\t\tmessage: event.message,\n\t\t\t\ttoolResults: event.toolResults,\n\t\t\t};\n\t\t\tawait this._extensionRunner.emit(extensionEvent);\n\t\t\tthis._turnIndex++;\n\t\t} else if (event.type === \"message_start\") {\n\t\t\tconst extensionEvent: MessageStartEvent = {\n\t\t\t\ttype: \"message_start\",\n\t\t\t\tmessage: event.message,\n\t\t\t};\n\t\t\tawait this._extensionRunner.emit(extensionEvent);\n\t\t} else if (event.type === \"message_update\") {\n\t\t\tconst extensionEvent: MessageUpdateEvent = {\n\t\t\t\ttype: \"message_update\",\n\t\t\t\tmessage: event.message,\n\t\t\t\tassistantMessageEvent: event.assistantMessageEvent,\n\t\t\t};\n\t\t\tawait this._extensionRunner.emit(extensionEvent);\n\t\t} else if (event.type === \"message_end\") {\n\t\t\tconst extensionEvent: MessageEndEvent = {\n\t\t\t\ttype: \"message_end\",\n\t\t\t\tmessage: event.message,\n\t\t\t};\n\t\t\tconst replacement = await this._extensionRunner.emitMessageEnd(extensionEvent);\n\t\t\tif (replacement) {\n\t\t\t\tthis._replaceMessageInPlace(event.message, replacement);\n\t\t\t}\n\t\t} else if (event.type === \"tool_execution_start\") {\n\t\t\tconst extensionEvent: ToolExecutionStartEvent = {\n\t\t\t\ttype: \"tool_execution_start\",\n\t\t\t\ttoolCallId: event.toolCallId,\n\t\t\t\ttoolName: event.toolName,\n\t\t\t\targs: event.args,\n\t\t\t};\n\t\t\tawait this._extensionRunner.emit(extensionEvent);\n\t\t} else if (event.type === \"tool_execution_update\") {\n\t\t\tconst extensionEvent: ToolExecutionUpdateEvent = {\n\t\t\t\ttype: \"tool_execution_update\",\n\t\t\t\ttoolCallId: event.toolCallId,\n\t\t\t\ttoolName: event.toolName,\n\t\t\t\targs: event.args,\n\t\t\t\tpartialResult: event.partialResult,\n\t\t\t};\n\t\t\tawait this._extensionRunner.emit(extensionEvent);\n\t\t} else if (event.type === \"tool_execution_end\") {\n\t\t\tconst extensionEvent: ToolExecutionEndEvent = {\n\t\t\t\ttype: \"tool_execution_end\",\n\t\t\t\ttoolCallId: event.toolCallId,\n\t\t\t\ttoolName: event.toolName,\n\t\t\t\tresult: event.result,\n\t\t\t\tisError: event.isError,\n\t\t\t};\n\t\t\tawait this._extensionRunner.emit(extensionEvent);\n\t\t}\n\t}\n\n\t/**\n\t * Subscribe to agent events.\n\t * Session persistence is handled internally (saves messages on message_end).\n\t * Multiple listeners can be added. Returns unsubscribe function for this listener.\n\t */\n\tsubscribe(listener: AgentSessionEventListener): () => void {\n\t\tthis._eventListeners.push(listener);\n\n\t\treturn () => {\n\t\t\tconst index = this._eventListeners.indexOf(listener);\n\t\t\tif (index !== -1) {\n\t\t\t\tthis._eventListeners.splice(index, 1);\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * Temporarily disconnect from agent events.\n\t * User listeners are preserved and will receive events again after resubscribe().\n\t * Used internally during operations that need to pause event processing.\n\t */\n\tprivate _disconnectFromAgent(): void {\n\t\tif (this._unsubscribeAgent) {\n\t\t\tthis._unsubscribeAgent();\n\t\t\tthis._unsubscribeAgent = undefined;\n\t\t}\n\t}\n\n\t/**\n\t * Reconnect to agent events after _disconnectFromAgent().\n\t * Preserves all existing listeners.\n\t */\n\tprivate _reconnectToAgent(): void {\n\t\tif (this._unsubscribeAgent) return; // Already connected\n\t\tthis._unsubscribeAgent = this.agent.subscribe(this._handleAgentEvent);\n\t}\n\n\t/**\n\t * Remove all listeners and disconnect from agent.\n\t * Call this when completely done with the session.\n\t */\n\t/**\n\t * Async teardown for graceful quit/switch: await the Python kernel's dispose\n\t * (which flushes a final namespace snapshot) before the synchronous dispose, so\n\t * the latest state reaches disk instead of racing process exit.\n\t */\n\tasync disposeAsync(): Promise<void> {\n\t\tif (this._disposed) {\n\t\t\treturn this._disposeCallbacksPromise;\n\t\t}\n\t\t// Concurrent callers await the same in-flight teardown so none resolves before\n\t\t// the kernel snapshot flush finishes.\n\t\tif (this._disposeAsyncPromise) {\n\t\t\treturn this._disposeAsyncPromise;\n\t\t}\n\t\tthis._disposeAsyncPromise = (async () => {\n\t\t\t// Drain before marking _disposing so a refine triggered at the final\n\t\t\t// agent_end completes instead of being aborted by dispose().\n\t\t\tawait this._drainPendingRefinementForDisposal();\n\t\t\tif (this._disposed) {\n\t\t\t\treturn this._disposeCallbacksPromise;\n\t\t\t}\n\t\t\tthis._disposing = true;\n\t\t\tthis._sessionActionCommitDisposeAbortController.abort();\n\t\t\tawait this._disposeAsyncOnce();\n\t\t})();\n\t\treturn this._disposeAsyncPromise;\n\t}\n\n\t/**\n\t * Await any in-flight refinement (planning or application) and run a\n\t * pending auto-refine that was scheduled but not yet started. Called\n\t * from disposeAsync before _disposing is set so refinement completes\n\t * before disposal.\n\t */\n\tprivate async _drainPendingRefinementForDisposal(): Promise<void> {\n\t\tfor (const timer of this._scheduledAutoRefineTimers) {\n\t\t\tclearTimeout(timer);\n\t\t}\n\t\tthis._scheduledAutoRefineTimers.clear();\n\t\tawait Promise.allSettled([...this._autoRefineOperations]);\n\t\tfor (const timer of this._scheduledAutoRefineTimers) {\n\t\t\tclearTimeout(timer);\n\t\t}\n\t\tthis._scheduledAutoRefineTimers.clear();\n\t\t// Wait for in-flight refinement (including serialized background plan) to settle.\n\t\twhile (this._refineInFlight || this._refinePlanInFlight || this._serializedPlanInFlight) {\n\t\t\tif (this._refineInFlight) {\n\t\t\t\tawait this._refineInFlight;\n\t\t\t} else if (this._refinePlanInFlight) {\n\t\t\t\tawait this._refinePlanInFlight;\n\t\t\t} else if (this._serializedPlanInFlight) {\n\t\t\t\t// Await the background plan and apply a ready \"plan\" result before teardown.\n\t\t\t\tawait this._consumeSerializedBackgroundPlan(async (bgResult) => {\n\t\t\t\t\tif (bgResult?.status === \"plan\" && bgResult.branchVersion === this._autoRefineBranchVersion) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tawait this._applySerializedPlan(bgResult);\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tthis._emitRefineFailed(error);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Stamp cooldown and reset counter so the interval\n\t\t\t\t\t\t// check below does not trigger a duplicate refine.\n\t\t\t\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\t\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t\t\t\t}\n\t\t\t\t\t// Preserve a consumed explicit request when its background plan failed,\n\t\t\t\t\t// matching the turn-boundary recovery path. The pending drain below\n\t\t\t\t\t// retries it once before disposal.\n\t\t\t\t\tif (\n\t\t\t\t\t\tbgResult?.status === \"failure\" &&\n\t\t\t\t\t\tbgResult.explicit &&\n\t\t\t\t\t\tbgResult.branchVersion === this._autoRefineBranchVersion &&\n\t\t\t\t\t\t!this._pendingRequestedRefine\n\t\t\t\t\t) {\n\t\t\t\t\t\tthis._pendingRequestedRefine = bgResult.options;\n\t\t\t\t\t}\n\t\t\t\t\tif (bgResult?.status === \"skip\" && bgResult.explicit) {\n\t\t\t\t\t\tthis._emitRefineFailed(new RefineSkippedError(\"Refinement skipped by extension\"));\n\t\t\t\t\t}\n\t\t\t\t\t// For \"skip\" or \"failure\", stamp cooldown and reset counter\n\t\t\t\t\t// so the interval check below does not trigger a duplicate\n\t\t\t\t\t// terminal retry.\n\t\t\t\t\tif (\n\t\t\t\t\t\tbgResult?.status === \"skip\" ||\n\t\t\t\t\t\tbgResult?.status === \"failure\" ||\n\t\t\t\t\t\tbgResult?.status === \"invalidated\"\n\t\t\t\t\t) {\n\t\t\t\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\t\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t\t\t\t}\n\t\t\t\t\treturn false;\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tawait new Promise<void>((resolve) => setTimeout(resolve, 0));\n\t\t\t}\n\t\t}\n\t\t// Drain an agent-callable refine.run request that was scheduled but\n\t\t// not yet consumed. Use the direct serialized path (no waitForIdle)\n\t\t// since the agent may still own activeRun at the final agent_end.\n\t\tif (this._pendingRequestedRefine) {\n\t\t\tconst pending = this._pendingRequestedRefine;\n\t\t\tthis._pendingRequestedRefine = undefined;\n\t\t\ttry {\n\t\t\t\tawait this._runSerializedRefine(pending);\n\t\t\t} catch {\n\t\t\t\t// Best-effort drain; refinement errors must not block disposal.\n\t\t\t}\n\t\t\t// Stamp cooldown and reset counter so the interval check below\n\t\t\t// does not trigger a duplicate refine after the explicit drain.\n\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t}\n\t\t// A serialized compaction can finish without another model turn. Drain its\n\t\t// pending review here so disposal does not silently lose the trigger.\n\t\tif (this._serializedRefine && this._compactAutoRefinePending && this._autoRefineAllowedForSession()) {\n\t\t\tconst compactSettings = this.settingsManager.getAutoRefineSettings();\n\t\t\tif (!compactSettings.enabled || !compactSettings.compact) {\n\t\t\t\tthis._compactAutoRefinePending = false;\n\t\t\t} else {\n\t\t\t\tconst nowMs = Date.now();\n\t\t\t\tconst underCooldown =\n\t\t\t\t\tthis._lastAutoRefineReviewAt > 0 && nowMs - this._lastAutoRefineReviewAt < compactSettings.cooldownMs;\n\t\t\t\tthis._compactAutoRefinePending = false;\n\t\t\t\tif (!underCooldown) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait this._runSerializedAutoRefineReview(\"compact\", this._autoRefineBranchVersion);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Best-effort drain; refinement errors must not block disposal.\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// If auto-refine is due but has not started yet, run it now so the\n\t\t// refinement is persisted before disposal. Use the direct serialized\n\t\t// path in serialized mode, or _maybeAutoRefine in interactive mode\n\t\t// (where the agent is idle at this point).\n\t\tif (this._disposed || !this._autoRefineAllowedForSession()) {\n\t\t\treturn;\n\t\t}\n\t\tconst settings = this.settingsManager.getAutoRefineSettings();\n\t\tif (!settings.enabled) {\n\t\t\treturn;\n\t\t}\n\t\tif (this._assistantTurnsSinceAutoRefine < settings.turnInterval) {\n\t\t\treturn;\n\t\t}\n\t\tconst nowMs = Date.now();\n\t\tconst underCooldown =\n\t\t\tthis._lastAutoRefineReviewAt > 0 && nowMs - this._lastAutoRefineReviewAt < settings.cooldownMs;\n\t\tif (underCooldown) {\n\t\t\treturn;\n\t\t}\n\t\tif (this._serializedRefine) {\n\t\t\tawait this._runSerializedRefineCheckpoint();\n\t\t} else {\n\t\t\tawait this._maybeAutoRefine(\"turn_interval\");\n\t\t}\n\t}\n\n\tprivate async _disposeAsyncOnce(): Promise<void> {\n\t\t// Flush kernels for both still-running and retained children; the sync\n\t\t// dispose() below only tears them down synchronously.\n\t\tfor (const run of [...this._activeRlmChildRuns.values()]) {\n\t\t\tconst childSession = run.session;\n\t\t\tif (!childSession) continue;\n\t\t\tif (run.detachedDeletion) {\n\t\t\t\trun.suppressTerminalNotice = true;\n\t\t\t\tif (run.deletionCleanupObserver) {\n\t\t\t\t\tawait run.deletionCleanupObserver.catch(() => false);\n\t\t\t\t} else if (run.deletionCleanup) {\n\t\t\t\t\tawait run.deletionCleanup.catch(() => childSession.disposeAsync().catch(() => undefined));\n\t\t\t\t} else {\n\t\t\t\t\t// Cleanup already failed and was exposed for retry before disposal.\n\t\t\t\t\tawait childSession.disposeAsync().catch(() => undefined);\n\t\t\t\t}\n\t\t\t\tif (!run.settled) await this._finishRlmRunDeletion(run);\n\t\t\t} else {\n\t\t\t\tawait childSession.disposeAsync().catch(() => undefined);\n\t\t\t}\n\t\t}\n\t\tfor (const unsubscribe of this._rlmChildUnsubscribes.values()) {\n\t\t\tunsubscribe();\n\t\t}\n\t\tthis._rlmChildUnsubscribes.clear();\n\t\tfor (const session of this._rlmChildSessions.values()) {\n\t\t\tawait session.disposeAsync().catch(() => undefined);\n\t\t}\n\t\tthis._rlmChildSessions.clear();\n\t\tthis._rlmChildCleanupFailures.clear();\n\t\tthis._deletedRlmChildIds.clear();\n\t\ttry {\n\t\t\tawait this._ipythonKernelProvisioner?.dispose();\n\t\t} catch {\n\t\t\t// a failed kernel startup already cleaned up after itself\n\t\t}\n\t\tthis.dispose();\n\t\tawait this._disposeCallbacksPromise;\n\t}\n\n\tprivate _startDisposeCallbacks(): Promise<void> {\n\t\tif (this._disposeCallbacksPromise) {\n\t\t\treturn this._disposeCallbacksPromise;\n\t\t}\n\t\tconst pending: Promise<void>[] = [];\n\t\tfor (const callback of this._disposeCallbacks) {\n\t\t\ttry {\n\t\t\t\tconst result = callback();\n\t\t\t\tif (result) {\n\t\t\t\t\tpending.push(result.catch(() => undefined));\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Disposal remains best-effort; one owner must not block the rest.\n\t\t\t}\n\t\t}\n\t\tthis._disposeCallbacks.clear();\n\t\tthis._disposeCallbacksPromise = Promise.all(pending).then(() => undefined);\n\t\treturn this._disposeCallbacksPromise;\n\t}\n\n\tdispose(): void {\n\t\tif (this._disposed) {\n\t\t\treturn;\n\t\t}\n\t\tthis._disposed = true;\n\t\tfor (const run of this._unsettledRlmChildRuns) run.suppressTerminalNotice = true;\n\t\tfor (const controller of this._rlmQuiescenceWaitAborts) controller.abort();\n\t\tthis._sessionActionCommitDisposeAbortController.abort();\n\t\ttry {\n\t\t\t// Invalidate scheduled timers and abort any in-flight review so a late\n\t\t\t// resolution cannot write harness state or re-subscribe handlers.\n\t\t\tthis._autoRefineReviewAbort?.abort();\n\t\t\tthis._refineAbortController?.abort();\n\t\t\tfor (const timer of this._scheduledAutoRefineTimers) {\n\t\t\t\tclearTimeout(timer);\n\t\t\t}\n\t\t\tthis._scheduledAutoRefineTimers.clear();\n\t\t\tthis._serializedPlanInFlight = undefined;\n\t\t\tthis._serializedExplicitRefineOptions = undefined;\n\t\t\tthis._pendingRequestedRefine = undefined;\n\t\t\tthis._discardPendingAutoRefine({ cancelPostCompactionContinue: true });\n\t\t\tthis._autoRefineBranchVersion++;\n\t\t\tthis._cancelActiveRlmChildRuns(\"Parent session disposed\");\n\t\t\tfor (const unsubscribe of this._rlmChildUnsubscribes.values()) {\n\t\t\t\tunsubscribe();\n\t\t\t}\n\t\t\tthis._rlmChildUnsubscribes.clear();\n\t\t\tfor (const session of this._rlmChildSessions.values()) {\n\t\t\t\tsession.dispose();\n\t\t\t}\n\t\t\tthis._rlmChildSessions.clear();\n\t\t\tthis._rlmChildCleanupFailures.clear();\n\t\t\tthis._deletedRlmChildIds.clear();\n\t\t\tthis._pendingNextTurnMessages = [];\n\t\t\tconst deliveryError = new Error(\"Session disposed before prompt delivery.\");\n\t\t\tconst completionError = new Error(\"Session disposed before prompt completion.\");\n\t\t\tthis._rejectQueuedAgentMessageDeliveries(deliveryError, completionError);\n\t\t\tfor (const [agentMessageId, outcome] of this._agentMessageOutcomes) {\n\t\t\t\tif (outcome.delivery) this._settleAgentMessage(agentMessageId, \"delivery\", deliveryError);\n\t\t\t\tif (outcome.completion) this._settleAgentMessage(agentMessageId, \"completion\", completionError);\n\t\t\t}\n\t\t\tthis._cancelSessionActions(() => true, deliveryError);\n\t\t\tthis.agent.clearAllQueues();\n\t\t\tthis._extensionRunner.invalidate(\n\t\t\t\t\"This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().\",\n\t\t\t);\n\t\t\tthis._disconnectFromAgent();\n\t\t\tthis._eventListeners = [];\n\t\t\tcleanupSessionResources(this.sessionId);\n\t\t} finally {\n\t\t\tvoid this._startDisposeCallbacks();\n\t\t}\n\t}\n\n\tregisterDisposeCallback(callback: () => void | Promise<void>): void {\n\t\tif (this._disposed) {\n\t\t\ttry {\n\t\t\t\tconst result = callback();\n\t\t\t\tif (result) void result.catch(() => undefined);\n\t\t\t} catch {\n\t\t\t\t// Late registration follows the same best-effort disposal contract.\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tthis._disposeCallbacks.add(callback);\n\t}\n\n\tget state(): AgentState {\n\t\treturn this.agent.state;\n\t}\n\n\tget model(): Model<any> | undefined {\n\t\treturn this.agent.state.model;\n\t}\n\n\tget thinkingLevel(): ThinkingLevel {\n\t\treturn this.agent.state.thinkingLevel;\n\t}\n\n\tget serviceTier(): ServiceTier {\n\t\treturn this.agent.state.serviceTier;\n\t}\n\n\tget isStreaming(): boolean {\n\t\treturn this.agent.state.isStreaming;\n\t}\n\n\tget systemPrompt(): string {\n\t\treturn this.agent.state.systemPrompt;\n\t}\n\n\tget retryAttempt(): number {\n\t\treturn this._retryAttempt;\n\t}\n\n\tgetActiveToolNames(): string[] {\n\t\treturn this.agent.state.tools.map((t) => t.name);\n\t}\n\n\tgetAllTools(): ToolInfo[] {\n\t\treturn Array.from(this._toolDefinitions.values()).map(({ definition, sourceInfo }) => ({\n\t\t\tname: definition.name,\n\t\t\tdescription: definition.description,\n\t\t\tparameters: definition.parameters,\n\t\t\tsourceInfo,\n\t\t}));\n\t}\n\n\tgetToolDefinition(name: string): ToolDefinition | undefined {\n\t\treturn this._toolDefinitions.get(name)?.definition;\n\t}\n\n\tsetActiveToolsByName(toolNames: string[]): void {\n\t\tconst tools: AgentTool[] = [];\n\t\tconst validToolNames: string[] = [];\n\t\tconst seenToolNames = new Set<string>();\n\t\tfor (const name of toolNames) {\n\t\t\tif (seenToolNames.has(name)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst tool = this._toolRegistry.get(name);\n\t\t\tif (tool) {\n\t\t\t\tseenToolNames.add(name);\n\t\t\t\ttools.push(tool);\n\t\t\t\tvalidToolNames.push(name);\n\t\t\t}\n\t\t}\n\t\tthis.agent.state.tools = tools;\n\n\t\tthis._baseSystemPrompt = this._rebuildSystemPrompt(validToolNames);\n\t\tthis.agent.state.systemPrompt = this._baseSystemPrompt;\n\t}\n\n\tget isCompacting(): boolean {\n\t\treturn (\n\t\t\tthis._autoCompactionAbortController !== undefined ||\n\t\t\tthis._compactionAbortController !== undefined ||\n\t\t\tthis._branchSummaryAbortController !== undefined\n\t\t);\n\t}\n\n\tget messages(): AgentMessage[] {\n\t\treturn this.agent.state.messages;\n\t}\n\n\tbuildSessionContext(): SessionContext {\n\t\tconst context = this.sessionManager.buildSessionContext();\n\t\tfor (const message of context.messages) {\n\t\t\tthis._applyLateIpythonSentAgentMessages(message);\n\t\t}\n\t\tthis._mergeUnpersistedOutcomes(context.messages);\n\t\treturn context;\n\t}\n\n\tprivate _mergeUnpersistedOutcomes(messages: AgentMessage[]): void {\n\t\tfor (const outcome of this._unpersistedOutcomes) {\n\t\t\tlet insertAt = messages.length;\n\t\t\twhile (insertAt > 0 && messages[insertAt - 1]!.timestamp > outcome.timestamp) {\n\t\t\t\tinsertAt -= 1;\n\t\t\t}\n\t\t\tmessages.splice(insertAt, 0, outcome);\n\t\t}\n\t}\n\n\tget steeringMode(): \"all\" | \"one-at-a-time\" {\n\t\treturn this.agent.steeringMode;\n\t}\n\n\tget followUpMode(): \"all\" | \"one-at-a-time\" {\n\t\treturn this.agent.followUpMode;\n\t}\n\n\tget sessionFile(): string | undefined {\n\t\treturn this.sessionManager.getSessionFile();\n\t}\n\n\tget sessionId(): string {\n\t\treturn this.sessionManager.getSessionId();\n\t}\n\n\tget rlmDepth(): number {\n\t\treturn this._rlmDepth;\n\t}\n\n\tget rlmMaxDepth(): number {\n\t\treturn this._rlmMaxDepth;\n\t}\n\n\tget sessionName(): string | undefined {\n\t\treturn this.sessionManager.getSessionName();\n\t}\n\n\tget goalState(): GoalState {\n\t\treturn { ...this._goalWithCurrentWallClock() };\n\t}\n\n\tgetAutonomousStatus(): AgentAutonomousStatus {\n\t\treturn autonomousStatus(this._autonomousState);\n\t}\n\n\trecordHostAutonomousContinuation(): void {\n\t\taddAutonomousContinuation(this._autonomousState);\n\t}\n\n\tasync refreshAutonomousGates(): Promise<void> {\n\t\tawait refreshAutonomousQualityGates(this._autonomousState, {\n\t\t\tcwd: this._cwd,\n\t\t});\n\t}\n\n\tprivate async _runWithAutonomousContinuationSuppressed<T>(fn: () => Promise<T>): Promise<T> {\n\t\tthis._autonomousContinuationSuppressionDepth++;\n\t\ttry {\n\t\t\treturn await fn();\n\t\t} finally {\n\t\t\tthis._autonomousContinuationSuppressionDepth--;\n\t\t}\n\t}\n\n\tprivate _markAutonomousContinuationSuppressed(message: AgentMessage): void {\n\t\tthis._autonomousContinuationSuppressedMessages.add(message);\n\t}\n\n\tget scopedModels(): ReadonlyArray<{\n\t\tmodel: Model<any>;\n\t\tthinkingLevel?: ThinkingLevel;\n\t}> {\n\t\treturn this._scopedModels;\n\t}\n\n\tsetScopedModels(scopedModels: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }>): void {\n\t\tthis._scopedModels = scopedModels;\n\t}\n\n\tget promptTemplates(): ReadonlyArray<PromptTemplate> {\n\t\treturn this._resourceLoader.getPrompts().prompts;\n\t}\n\n\tprivate _normalizePromptSnippet(text: string | undefined): string | undefined {\n\t\tif (!text) return undefined;\n\t\tconst oneLine = text\n\t\t\t.replace(/[\\r\\n]+/g, \" \")\n\t\t\t.replace(/\\s+/g, \" \")\n\t\t\t.trim();\n\t\treturn oneLine.length > 0 ? oneLine : undefined;\n\t}\n\n\tprivate _normalizePromptGuidelines(guidelines: string[] | undefined): string[] {\n\t\tif (!guidelines || guidelines.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst unique = new Set<string>();\n\t\tfor (const guideline of guidelines) {\n\t\t\tconst normalized = guideline.trim();\n\t\t\tif (normalized.length > 0) {\n\t\t\t\tunique.add(normalized);\n\t\t\t}\n\t\t}\n\t\treturn Array.from(unique);\n\t}\n\n\tprivate _rebuildSystemPrompt(toolNames: string[]): string {\n\t\tconst validToolNames = toolNames.filter((name) => this._toolRegistry.has(name));\n\t\tconst toolSnippets: Record<string, string> = {};\n\t\tconst promptGuidelines: string[] = [];\n\t\tfor (const name of validToolNames) {\n\t\t\tconst snippet = this._toolPromptSnippets.get(name);\n\t\t\tif (snippet) {\n\t\t\t\ttoolSnippets[name] = snippet;\n\t\t\t}\n\n\t\t\tconst toolGuidelines = this._toolPromptGuidelines.get(name);\n\t\t\tif (toolGuidelines) {\n\t\t\t\tpromptGuidelines.push(...toolGuidelines);\n\t\t\t}\n\t\t}\n\n\t\tconst loaderSystemPrompt = this._resourceLoader.getSystemPrompt();\n\t\tconst loaderAppendSystemPrompt = this._resourceLoader.getAppendSystemPrompt();\n\t\tconst appendSystemPrompt =\n\t\t\tloaderAppendSystemPrompt.length > 0 ? loaderAppendSystemPrompt.join(\"\\n\\n\") : undefined;\n\t\tconst loadedSkills = this._modelVisibleSkills();\n\t\tconst loadedContextFiles = this._resourceLoader.getAgentsFiles().agentsFiles;\n\n\t\tthis._baseSystemPromptOptions = {\n\t\t\tcwd: this._cwd,\n\t\t\tskills: loadedSkills,\n\t\t\tcontextFiles: loadedContextFiles,\n\t\t\tcustomPrompt: loaderSystemPrompt,\n\t\t\tappendSystemPrompt,\n\t\t\tmessagesPath: this.sessionManager.getSessionFile(),\n\t\t\tselectedTools: validToolNames,\n\t\t\ttoolSnippets,\n\t\t\tpromptGuidelines,\n\t\t\tallowRecursion: this._rlmDepth < this._rlmMaxDepth,\n\t\t\trlmDepth: this._rlmDepth,\n\t\t\trlmParentAgent: this._rlmParentAgent,\n\t\t\tharnessState: this._loadMergedHarnessState(),\n\t\t\tgenericMcpServers: this._mcpManager?.getEnabledPersistentGenericServers(),\n\t\t};\n\t\treturn buildSystemPrompt(this._baseSystemPromptOptions);\n\t}\n\n\tprivate _refreshExtensionSystemPrompt(extensionPrompt: string, baseSnapshot: string): string {\n\t\tif (this._baseSystemPrompt === baseSnapshot) {\n\t\t\treturn extensionPrompt;\n\t\t}\n\t\tif (!extensionPrompt.includes(baseSnapshot)) {\n\t\t\treturn extensionPrompt;\n\t\t}\n\t\treturn extensionPrompt.replace(baseSnapshot, () => this._baseSystemPrompt);\n\t}\n\n\tprivate _finishSubmissionNormalization(\n\t\ttext: string,\n\t\timages: ImageContent[] | undefined,\n\t\tpolicy: SubmissionNormalizationPolicy,\n\t): NormalizedSubmission {\n\t\tlet expandedText = text;\n\t\tif (policy.expandSkills) expandedText = this._expandSkillCommand(expandedText);\n\t\tif (policy.expandPromptTemplates) {\n\t\t\texpandedText = expandPromptTemplate(expandedText, [...this.promptTemplates]);\n\t\t}\n\t\treturn { kind: \"prompt\", text: expandedText, images };\n\t}\n\n\tprivate _normalizeSubmission(\n\t\ttext: string,\n\t\timages: ImageContent[] | undefined,\n\t\tpolicy: SubmissionNormalizationPolicy,\n\t): NormalizedSubmission | Promise<NormalizedSubmission> {\n\t\tif (policy.parseSessionCommands) {\n\t\t\tconst command = parseSessionSlashCommand(text);\n\t\t\tif (command) return { kind: \"sessionCommand\", text, images, command };\n\t\t}\n\n\t\tif (text.startsWith(\"/\")) {\n\t\t\tif (policy.extensionCommands === \"execute\") {\n\t\t\t\tconst completion = this._executeExtensionCommand(text);\n\t\t\t\tif (completion) return { kind: \"extensionCommand\", completion };\n\t\t\t} else if (policy.extensionCommands === \"reject\") {\n\t\t\t\tthis._throwIfExtensionCommand(text);\n\t\t\t}\n\t\t}\n\n\t\tif (policy.inputSource !== undefined && this._extensionRunner.hasHandlers(\"input\")) {\n\t\t\treturn this._extensionRunner.emitInput(text, images, policy.inputSource).then((result) => {\n\t\t\t\tif (result.action === \"handled\") return { kind: \"handled\" };\n\t\t\t\tif (result.action === \"transform\") {\n\t\t\t\t\treturn this._finishSubmissionNormalization(result.text, result.images ?? images, policy);\n\t\t\t\t}\n\t\t\t\treturn this._finishSubmissionNormalization(text, images, policy);\n\t\t\t});\n\t\t}\n\n\t\treturn this._finishSubmissionNormalization(text, images, policy);\n\t}\n\n\tprivate async _runPreTurnCompaction(): Promise<void> {\n\t\tconst lastAssistant = this._findLastAssistantMessage();\n\t\tif (lastAssistant) await this._checkCompaction(lastAssistant, false, false);\n\t}\n\n\tprivate async _prepareForCommit<TPrepared, TCommitted>(\n\t\tpolicy: CommitPreparationPolicy,\n\t\tsteps: CommitPreparationSteps<TPrepared, TCommitted>,\n\t): Promise<TCommitted | undefined> {\n\t\tif (\n\t\t\tpolicy.initialRefineBarrier === \"always\" ||\n\t\t\t(policy.initialRefineBarrier === \"ifInFlight\" && this._refineInFlight)\n\t\t) {\n\t\t\tawait this._waitForRefineIdle();\n\t\t}\n\t\tif (policy.flushPendingBashBeforeValidation) this._flushPendingBashMessages();\n\t\tif (policy.validateModelAndAuth) await this._validateCanStartAgentRun();\n\t\tsteps.afterValidation?.();\n\t\tif (!policy.flushPendingBashBeforeValidation) this._flushPendingBashMessages();\n\n\t\tif (policy.preTurnCompaction === \"beforeModelSelection\") await this._runPreTurnCompaction();\n\t\tif (policy.awaitPendingModelSelection) {\n\t\t\tconst pendingModelSelectEmit = this._pendingModelSelectEmit();\n\t\t\tif (pendingModelSelectEmit) await pendingModelSelectEmit;\n\t\t}\n\t\tif (policy.preTurnCompaction === \"afterModelSelection\") await this._runPreTurnCompaction();\n\n\t\tconst prepared = await steps.prepare();\n\t\tif (steps.shouldCommit && !steps.shouldCommit(prepared)) return undefined;\n\t\tsteps.beforeFinalRefineBarrier?.(prepared);\n\t\tlet passedFinalRefineBarrier = false;\n\t\tif (\n\t\t\tpolicy.finalRefineBarrier === \"always\" ||\n\t\t\t(policy.finalRefineBarrier === \"ifInFlight\" && this._refineInFlight)\n\t\t) {\n\t\t\tawait this._waitForRefineIdle();\n\t\t\tpassedFinalRefineBarrier = true;\n\t\t}\n\t\treturn steps.commit(prepared, passedFinalRefineBarrier);\n\t}\n\n\tprivate _applyPreparedSystemPrompt(\n\t\tpreparation: PreparedPromptPreparation | undefined,\n\t\tpreserveEmptyExtensionPrompt: boolean,\n\t): void {\n\t\tconst extensionPrompt = preparation?.result?.systemPrompt;\n\t\tconst hasExtensionPrompt = preserveEmptyExtensionPrompt\n\t\t\t? extensionPrompt !== undefined\n\t\t\t: Boolean(extensionPrompt);\n\t\tthis.agent.state.systemPrompt =\n\t\t\thasExtensionPrompt && extensionPrompt !== undefined && preparation !== undefined\n\t\t\t\t? this._refreshExtensionSystemPrompt(extensionPrompt, preparation.basePromptSnapshot)\n\t\t\t\t: this._baseSystemPrompt;\n\t}\n\n\tprivate _canStartSessionActionImmediately(): boolean {\n\t\treturn (\n\t\t\t!this.isStreaming &&\n\t\t\t!this.isCompacting &&\n\t\t\t!this.isRetrying &&\n\t\t\t!this.isBashRunning &&\n\t\t\t!this._sessionInputPumpSuspended &&\n\t\t\tthis._queuedWorkPauses.size === 0 &&\n\t\t\t!this._disposed &&\n\t\t\t!this._disposing\n\t\t);\n\t}\n\n\t/**\n\t * Send a prompt to the agent.\n\t * - Handles extension commands (registered via pi.registerCommand) immediately, even during streaming\n\t * - Expands file-based prompt templates by default\n\t * - During streaming, queues via steer() or followUp() based on streamingBehavior option\n\t * - Validates model and API key before sending (when not streaming)\n\t * @throws Error if streaming and no streamingBehavior specified\n\t * @throws Error if no model selected or no API key available (when not streaming)\n\t */\n\tasync prompt(text: string, options?: PromptOptions): Promise<void> {\n\t\treturn this._prompt(text, options);\n\t}\n\n\tasync promptUntilAccepted(text: string, options?: PromptOptions): Promise<void> {\n\t\treturn this._prompt(text, { ...options, returnAfterAccepted: true });\n\t}\n\n\tasync promptAndWait(text: string, options?: PromptOptions): Promise<void> {\n\t\tconst agentMessageId = options?.agentMessageId ?? `prompt-wait:${randomUUID()}`;\n\t\tif (this._agentMessageOutcomes.get(agentMessageId)?.completion) {\n\t\t\tthrow new Error(`Prompt completion id is already in use: ${agentMessageId}`);\n\t\t}\n\t\tconst outcome = this._agentMessageOutcome(agentMessageId);\n\t\toutcome.completion = createAgentMessageDeferred();\n\t\tconst completion = outcome.completion.promise;\n\t\tconst signal = options?.signal;\n\t\tlet cancelQueuedPrompt: (() => void) | undefined;\n\t\ttry {\n\t\t\tawait this.promptUntilAccepted(text, { ...options, agentMessageId });\n\t\t\tif (signal) {\n\t\t\t\tcancelQueuedPrompt = () => {\n\t\t\t\t\tconst error = new Error(\"Prompt was cancelled before it started.\");\n\t\t\t\t\tconst cancelled = this._cancelSessionActions(\n\t\t\t\t\t\t(action) => action.agentMessageId === agentMessageId && action.payload.kind === \"turn\",\n\t\t\t\t\t\terror,\n\t\t\t\t\t);\n\t\t\t\t\tif (cancelled.length > 0) {\n\t\t\t\t\t\tthis._settleAgentMessage(agentMessageId, \"completion\", error);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tsignal.addEventListener(\"abort\", cancelQueuedPrompt, { once: true });\n\t\t\t\tif (signal.aborted) cancelQueuedPrompt();\n\t\t\t}\n\t\t\tawait completion;\n\t\t} catch (error) {\n\t\t\tthis._settleAgentMessage(agentMessageId, \"completion\", this._asError(error));\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tif (signal && cancelQueuedPrompt) {\n\t\t\t\tsignal.removeEventListener(\"abort\", cancelQueuedPrompt);\n\t\t\t}\n\t\t}\n\t}\n\n\tasync acceptAgentMessagePrompt(text: string, options?: PromptOptions): Promise<void> {\n\t\tconst customMessage =\n\t\t\toptions?.customMessage && isAgentSessionMessage(options.customMessage) ? options.customMessage : undefined;\n\t\tconst clearEpoch = this._agentMessageClearEpoch;\n\t\tconst admissionCommitted = () => {\n\t\t\toptions?.admissionCommitted?.();\n\t\t\tif (clearEpoch !== this._agentMessageClearEpoch) {\n\t\t\t\tthrow new Error(\"Agent message was cleared before admission\");\n\t\t\t}\n\t\t};\n\t\tif (\n\t\t\tthis._sessionInputPumpSuspended &&\n\t\t\tthis._isBusyForSessionInput(\"preflight\") &&\n\t\t\toptions?.queueIfBusy === true &&\n\t\t\toptions.streamingBehavior\n\t\t) {\n\t\t\tadmissionCommitted();\n\t\t\tconst queued = await this.queueAgentMessagePrompt(text, options.streamingBehavior, customMessage);\n\t\t\toptions.preflightResult?.(queued, queued);\n\t\t\treturn;\n\t\t}\n\t\tawait this._prompt(text, {\n\t\t\t...options,\n\t\t\tresumeIfIdle: false,\n\t\t\texpandPromptTemplates: false,\n\t\t\tskipInputHandlers: true,\n\t\t\tskipPrePromptWork: true,\n\t\t\treturnAfterAccepted: true,\n\t\t\tagentMessageId: options?.agentMessageId ?? customMessage?.details.id ?? parseAgentSessionMessagePromptId(text),\n\t\t\tcustomMessage,\n\t\t\tadmissionCommitted,\n\t\t});\n\t\tif (customMessage?.details.fromRelationship === \"parent\") this._repliedToParentSinceTask = false;\n\t}\n\n\tasync queueAgentMessagePrompt(\n\t\ttext: string,\n\t\tstreamingBehavior: \"steer\" | \"followUp\",\n\t\tcustomMessage?: AgentSessionMessage,\n\t): Promise<boolean> {\n\t\tconst agentMessageId = customMessage?.details.id ?? parseAgentSessionMessagePromptId(text);\n\t\tif (streamingBehavior === \"steer\") {\n\t\t\tawait this._queuePreparedPrompt(\"steer\", text, undefined, {\n\t\t\t\tagentMessageId,\n\t\t\t\tmessage: customMessage,\n\t\t\t});\n\t\t\tif (customMessage?.details.fromRelationship === \"parent\") this._repliedToParentSinceTask = false;\n\t\t\treturn true;\n\t\t}\n\t\tconst queued = await this._queuePreparedPrompt(\"followUp\", text, undefined, {\n\t\t\tagentMessageId,\n\t\t\tmessage: customMessage,\n\t\t});\n\t\tif (queued && customMessage?.details.fromRelationship === \"parent\") this._repliedToParentSinceTask = false;\n\t\treturn queued;\n\t}\n\n\tasync promptHeartbeat(job: AgentCronJob, options?: PromptOptions): Promise<void> {\n\t\tconst message = createHeartbeatPromptMessage(job);\n\t\tawait this._promptInjectedMessage(job.prompt, message, {\n\t\t\t...options,\n\t\t\tfollowUpQueueKey: options?.followUpQueueKey ?? `heartbeat:${job.id}`,\n\t\t\tresumeIfIdle: true,\n\t\t});\n\t}\n\n\tprivate _isRlmTerminalNotice(message: CustomMessage): boolean {\n\t\treturn (\n\t\t\tmessage.customType === RLM_CHILD_TERMINAL_NOTICE_CUSTOM_TYPE ||\n\t\t\tmessage.customType === RLM_CHILD_FAILURE_CUSTOM_TYPE\n\t\t);\n\t}\n\n\tprivate _assertRlmTerminalNotice(message: CustomMessage): void {\n\t\tif (!this._isRlmTerminalNotice(message)) {\n\t\t\tthrow new Error(\"Deferred terminal admission only accepts RLM child terminal notices.\");\n\t\t}\n\t}\n\n\tprivate _isRlmTerminalNoticeAction(action: QueuedSessionAction): boolean {\n\t\tif (action.payload.kind !== \"turn\") return false;\n\t\tconst message = primaryDeliveryRecord(action).message;\n\t\treturn message.role === \"custom\" && this._isRlmTerminalNotice(message);\n\t}\n\n\tprivate _hasDeferredRlmTerminalNotices(): boolean {\n\t\treturn this._pendingNextTurnMessages.some((message) => this._isRlmTerminalNotice(message));\n\t}\n\n\tprivate _enqueueRlmTerminalNoticeAction(message: CustomMessage): void {\n\t\tthis._assertRlmTerminalNotice(message);\n\t\tconst action = this._createPreparedTurnAction(\"followUp\", message.content as string, undefined, {\n\t\t\tmessage,\n\t\t\tsuppressAutonomousContinuation: true,\n\t\t\tresumeIfIdle: false,\n\t\t\tsource: \"internal\",\n\t\t\texecutionPolicy: this._turnExecutionPolicy(\"injected\"),\n\t\t\tqueueVisible: false,\n\t\t});\n\t\tthis._durableRlmTerminalNoticeActionIds.add(action.id);\n\t\ttry {\n\t\t\tconst result = this._admitSessionInput(action, { wake: false });\n\t\t\tif (!result.accepted) throw new Error(\"RLM child terminal notice was not admitted.\");\n\t\t} catch (error) {\n\t\t\tthis._durableRlmTerminalNoticeActionIds.delete(action.id);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprivate _flushDeferredRlmTerminalNotices(): void {\n\t\tif (\n\t\t\tthis._sessionInputAdmissionPauses.size > 0 ||\n\t\t\tthis._sessionInputPumpSuspended ||\n\t\t\tthis._queuedWorkPauses.size > 0 ||\n\t\t\tthis._disposed ||\n\t\t\tthis._disposing\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\twhile (true) {\n\t\t\tconst index = this._pendingNextTurnMessages.findIndex((message) => this._isRlmTerminalNotice(message));\n\t\t\tif (index < 0) break;\n\t\t\tconst message = this._pendingNextTurnMessages[index];\n\t\t\ttry {\n\t\t\t\tthis._enqueueRlmTerminalNoticeAction(message);\n\t\t\t} catch {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._pendingNextTurnMessages.splice(index, 1);\n\t\t}\n\t\tthis._scheduleSessionInputPump();\n\t}\n\n\tprivate async _acquireRlmTerminalNoticeRetentionFence(): Promise<{ owner: symbol; release(): void } | undefined> {\n\t\tconst disposeSignal = this._sessionActionCommitDisposeAbortController.signal;\n\t\twhile (!this._disposed && !this._disposing && !disposeSignal.aborted) {\n\t\t\tif (this._queuedWorkPauses.size > 0) {\n\t\t\t\tlet wake = () => {};\n\t\t\t\tconst pauseReleased = new Promise<void>((resolve) => {\n\t\t\t\t\twake = resolve;\n\t\t\t\t\tthis._sessionInputCheckpointWaiters.add(resolve);\n\t\t\t\t});\n\t\t\t\ttry {\n\t\t\t\t\tawait waitForPromiseOrAbort(pauseReleased, disposeSignal, \"Terminal notice retention cancelled\");\n\t\t\t\t} catch {\n\t\t\t\t\treturn undefined;\n\t\t\t\t} finally {\n\t\t\t\t\tthis._sessionInputCheckpointWaiters.delete(wake);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlet fence: { owner: symbol; release(): void };\n\t\t\ttry {\n\t\t\t\tfence = await this._acquireSessionActionCommitFence(disposeSignal);\n\t\t\t} catch {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tif (this._queuedWorkPauses.size === 0 && !this._disposed && !this._disposing) return fence;\n\t\t\tfence.release();\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate async _deferRlmTerminalNotice(message: CustomMessage): Promise<void> {\n\t\tthis._assertRlmTerminalNotice(message);\n\t\tconst fence = await this._acquireRlmTerminalNoticeRetentionFence();\n\t\tif (!fence) return;\n\t\ttry {\n\t\t\tif (this._disposed || this._disposing) return;\n\t\t\tthis._pendingNextTurnMessages.push(cloneCustomMessage(message));\n\t\t\tthis._flushDeferredRlmTerminalNotices();\n\t\t} finally {\n\t\t\tfence.release();\n\t\t}\n\t}\n\n\tprivate _demoteRlmTerminalNoticeActions(): void {\n\t\tconst actions = this._actionStore\n\t\t\t.clearableActions()\n\t\t\t.filter((action) => this._durableRlmTerminalNoticeActionIds.has(action.id));\n\t\tif (actions.length === 0) return;\n\t\tfor (const action of actions) {\n\t\t\tif (!this._isRlmTerminalNoticeAction(action)) continue;\n\t\t\tconst message = primaryDeliveryRecord(action).message;\n\t\t\tif (message.role === \"custom\") this._pendingNextTurnMessages.push(cloneCustomMessage(message));\n\t\t}\n\t\tconst ids = new Set(actions.map((action) => action.id));\n\t\tthis._cancelSessionActions(\n\t\t\t(action) => ids.has(action.id),\n\t\t\tnew Error(\"RLM child terminal notice deferred across session input suspension.\"),\n\t\t\tactions,\n\t\t);\n\t\tfor (const id of ids) this._durableRlmTerminalNoticeActionIds.delete(id);\n\t}\n\n\tprivate async _promptInjectedMessage(\n\t\ttext: string,\n\t\tmessage: CustomMessage,\n\t\toptions?: InternalPromptOptions & { executionPolicy?: TurnExecutionPolicy },\n\t): Promise<void> {\n\t\tif (!this.isStreaming && options?.resumeIfIdle) this._resumeSessionInputAdmission();\n\t\tconst admissionEpoch = this._sessionInputPumpEpoch;\n\t\tconst admissionFence = await this._acquireDirectTurnAdmissionFence(options?.signal).catch((error: unknown) => {\n\t\t\tthrowIfPromptAdmissionCancelled(options?.signal);\n\t\t\tthrow error;\n\t\t});\n\t\tconst reportPreflight = oncePreflight(options?.preflightResult);\n\t\ttry {\n\t\t\tthrowIfPromptAdmissionCancelled(options?.signal);\n\t\t\tif (admissionEpoch !== this._sessionInputPumpEpoch) {\n\t\t\t\tthrow new Error(\"Injected session input was invalidated before admission\");\n\t\t\t}\n\t\t\toptions?.admissionCommitted?.();\n\t\t\tconst queueForStreaming = this.isStreaming;\n\t\t\tconst queueForBusy = options?.queueIfBusy === true && this._isBusyForSessionInput(\"preflight\");\n\t\t\tconst visibleQueued = queueForStreaming || queueForBusy;\n\t\t\tif (visibleQueued && !options?.streamingBehavior) {\n\t\t\t\tconst stateDescription = queueForStreaming ? \"Agent is already processing\" : \"Agent has queued work\";\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`${stateDescription}. Specify streamingBehavior ('steer' or 'followUp') to queue the message.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst schedule = options?.streamingBehavior ?? \"followUp\";\n\t\t\tconst prefixMessages = visibleQueued ? this._takePendingNextTurnMessages() : undefined;\n\t\t\tconst action = this._createPreparedTurnAction(schedule, text, undefined, {\n\t\t\t\tmessage,\n\t\t\t\tprefixMessages,\n\t\t\t\tqueueKey: options?.followUpQueueKey,\n\t\t\t\tpreviewLabel: injectedMessagePreviewLabel(message),\n\t\t\t\tsuppressAutonomousContinuation: options?.suppressAutonomousContinuation,\n\t\t\t\tresumeIfIdle:\n\t\t\t\t\t!visibleQueued ||\n\t\t\t\t\toptions?.resumeIfIdle ||\n\t\t\t\t\t(options?.queueIfBusy === true && canSelectSessionAction(this._runtimeActivity())),\n\t\t\t\tsource: options?.source ?? \"internal\",\n\t\t\t\texecutionPolicy:\n\t\t\t\t\toptions?.executionPolicy ??\n\t\t\t\t\t(visibleQueued ? this._turnExecutionPolicy(\"queued\") : this._turnExecutionPolicy(\"injected\")),\n\t\t\t\tqueueVisible: visibleQueued,\n\t\t\t});\n\t\t\tconst result = this._admitSessionInput(action, {\n\t\t\t\timmediatelyEligible: !visibleQueued,\n\t\t\t});\n\t\t\tadmissionFence.release();\n\t\t\tif (!result.accepted || !result.ticket) {\n\t\t\t\tif (prefixMessages) this._pendingNextTurnMessages.unshift(...prefixMessages);\n\t\t\t\treportPreflight(false, false);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (result.disposition === \"queued\") {\n\t\t\t\treportPreflight(true, true);\n\t\t\t} else {\n\t\t\t\tvoid result.ticket.delivered.then(\n\t\t\t\t\t() => reportPreflight(true),\n\t\t\t\t\t() => reportPreflight(false),\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (options?.returnAfterAccepted) {\n\t\t\t\tif (result.disposition === \"starts_when_admitted\") await result.ticket.delivered;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (visibleQueued) return;\n\t\t\tawait result.ticket.completed;\n\t\t} catch (error) {\n\t\t\treportPreflight(false);\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tadmissionFence.release();\n\t\t}\n\t}\n\n\tprivate async _prompt(text: string, options?: InternalPromptOptions): Promise<void> {\n\t\tconst resumeSuspendedInput = options?.resumeIfIdle !== false;\n\t\tif (!this.isStreaming) {\n\t\t\tif (resumeSuspendedInput) this._resumeSessionInputAdmission();\n\t\t\tthis._assertSessionActionAdmissionAvailable();\n\t\t}\n\t\tconst admissionEpoch = this._sessionInputPumpEpoch;\n\t\tconst commitFence = this.isStreaming\n\t\t\t? undefined\n\t\t\t: await this._acquireDirectTurnAdmissionFence(options?.signal).catch((error: unknown) => {\n\t\t\t\t\tthrowIfPromptAdmissionCancelled(options?.signal);\n\t\t\t\t\tthrow error;\n\t\t\t\t});\n\t\tconst reportPreflight = oncePreflight(options?.preflightResult);\n\t\tconst run = async () => {\n\t\t\ttry {\n\t\t\t\tthrowIfPromptAdmissionCancelled(options?.signal);\n\t\t\t\tif (!resumeSuspendedInput && admissionEpoch !== this._sessionInputPumpEpoch) {\n\t\t\t\t\tthrow new Error(\"Session input was invalidated before admission\");\n\t\t\t\t}\n\t\t\t\toptions?.admissionCommitted?.();\n\t\t\t\tconst isInternalPrompt = options?.internalPrompt === true;\n\t\t\t\tconst expandPromptTemplates = isInternalPrompt ? false : (options?.expandPromptTemplates ?? true);\n\t\t\t\tconst normalizationResult = this._normalizeSubmission(text, options?.images, {\n\t\t\t\t\tparseSessionCommands: !isInternalPrompt && !options?.skipPrePromptWork,\n\t\t\t\t\textensionCommands: expandPromptTemplates ? \"execute\" : \"ignore\",\n\t\t\t\t\tinputSource:\n\t\t\t\t\t\t!isInternalPrompt && !options?.skipInputHandlers ? (options?.source ?? \"interactive\") : undefined,\n\t\t\t\t\texpandSkills: expandPromptTemplates,\n\t\t\t\t\texpandPromptTemplates,\n\t\t\t\t});\n\t\t\t\tconst normalized = normalizationResult instanceof Promise ? await normalizationResult : normalizationResult;\n\t\t\t\t// Async input handlers ran between the admission check above and\n\t\t\t\t// admission itself; re-check so content invalidated during that\n\t\t\t\t// await (e.g. a cron job cancelled or updated) is not admitted.\n\t\t\t\tif (normalizationResult instanceof Promise) options?.admissionCommitted?.();\n\t\t\t\tif (normalized.kind === \"extensionCommand\") {\n\t\t\t\t\tcommitFence?.release();\n\t\t\t\t\treportPreflight(true);\n\t\t\t\t\tvoid normalized.completion.then(\n\t\t\t\t\t\t() => this._settleAgentMessage(options?.agentMessageId, \"completion\"),\n\t\t\t\t\t\t(error) => this._settleAgentMessage(options?.agentMessageId, \"completion\", error),\n\t\t\t\t\t);\n\t\t\t\t\tvoid normalized.completion.catch(() => undefined);\n\t\t\t\t\tif (!options?.returnAfterAccepted) await normalized.completion.catch(() => undefined);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (normalized.kind === \"handled\") {\n\t\t\t\t\tcommitFence?.release();\n\t\t\t\t\treportPreflight(true);\n\t\t\t\t\tthis._settleAgentMessage(options?.agentMessageId, \"completion\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst pendingOwnedWork = this._actionStore.unfinishedActions().length > 0;\n\t\t\t\tconst wasRuntimeBusy = this.isStreaming || this.isCompacting || this.isRetrying || this.isBashRunning;\n\t\t\t\tconst wasBusy = wasRuntimeBusy || pendingOwnedWork;\n\t\t\t\tif (normalized.kind === \"sessionCommand\") {\n\t\t\t\t\tconst schedule = options?.streamingBehavior ?? (this.isStreaming ? \"steer\" : \"followUp\");\n\t\t\t\t\tconst action = this._createSessionCommandAction(\n\t\t\t\t\t\tnormalized.text,\n\t\t\t\t\t\tnormalized.command,\n\t\t\t\t\t\tnormalized.images,\n\t\t\t\t\t\tschedule,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tagentMessageId: options?.agentMessageId,\n\t\t\t\t\t\t\tsource: isInternalPrompt ? \"internal\" : (options?.source ?? \"interactive\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t\tconst result = this._admitSessionInput(action, {\n\t\t\t\t\t\timmediatelyEligible: !wasBusy && this._canStartSessionActionImmediately(),\n\t\t\t\t\t});\n\t\t\t\t\tcommitFence?.release();\n\t\t\t\t\treportPreflight(result.accepted, result.disposition === \"queued\");\n\t\t\t\t\tif (!result.accepted || !result.ticket) return;\n\t\t\t\t\tif (options?.returnAfterAccepted) {\n\t\t\t\t\t\tif (result.disposition === \"starts_when_admitted\") await result.ticket.delivered;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (result.disposition === \"queued\") return;\n\t\t\t\t\tawait this.waitForSessionInputIdle();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst queueForStreaming = this.isStreaming;\n\t\t\t\tconst queueForBusy = options?.queueIfBusy === true && this._isBusyForSessionInput(\"preflight\");\n\t\t\t\tconst visibleQueued = queueForStreaming || queueForBusy;\n\t\t\t\tif (visibleQueued && !options?.streamingBehavior) {\n\t\t\t\t\tconst stateDescription = queueForStreaming ? \"Agent is already processing\" : \"Agent has queued work\";\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`${stateDescription}. Specify streamingBehavior ('steer' or 'followUp') to queue the message.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst schedule = options?.streamingBehavior ?? \"followUp\";\n\t\t\t\tconst prefixMessages = visibleQueued ? this._takePendingNextTurnMessages() : undefined;\n\t\t\t\tconst content = options?.content\n\t\t\t\t\t? options.content.map((block) => ({ ...block }))\n\t\t\t\t\t: this._buildPromptContent(normalized.text, normalized.images);\n\t\t\t\tconst suppliedMessage = options?.customMessage;\n\t\t\t\tconst primaryMessage = suppliedMessage\n\t\t\t\t\t? visibleQueued\n\t\t\t\t\t\t? suppliedMessage\n\t\t\t\t\t\t: cloneCustomMessage(suppliedMessage)\n\t\t\t\t\t: ({\n\t\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\t\tcontent: content.map((block) => ({ ...block })),\n\t\t\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t\t\t} satisfies UserMessage);\n\t\t\t\tconst acceptedAgentMessage = options?.skipPrePromptWork === true && options.returnAfterAccepted === true;\n\t\t\t\tconst action = this._createPreparedTurnAction(schedule, normalized.text, normalized.images, {\n\t\t\t\t\tagentMessageId: options?.agentMessageId,\n\t\t\t\t\tqueueKey: options?.followUpQueueKey,\n\t\t\t\t\tcontent,\n\t\t\t\t\tmessage: primaryMessage,\n\t\t\t\t\tprefixMessages,\n\t\t\t\t\tsuppressAutonomousContinuation: options?.suppressAutonomousContinuation,\n\t\t\t\t\tresumeIfIdle:\n\t\t\t\t\t\t!visibleQueued ||\n\t\t\t\t\t\toptions?.resumeIfIdle ||\n\t\t\t\t\t\t(options?.queueIfBusy === true && canSelectSessionAction(this._runtimeActivity())),\n\t\t\t\t\tsource: isInternalPrompt ? \"internal\" : (options?.source ?? \"interactive\"),\n\t\t\t\t\texecutionPolicy: visibleQueued\n\t\t\t\t\t\t? this._turnExecutionPolicy(\"queued\")\n\t\t\t\t\t\t: this._turnExecutionPolicy(\"directPrompt\", {\n\t\t\t\t\t\t\t\treturnAfterAccepted: options?.returnAfterAccepted,\n\t\t\t\t\t\t\t\tskipPrePromptWork: options?.skipPrePromptWork,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\tqueueVisible: visibleQueued,\n\t\t\t\t\tacceptedAgentMessage,\n\t\t\t\t\tacceptedBeforeCompletion: options?.returnAfterAccepted === true,\n\t\t\t\t});\n\t\t\t\tif (action.suppressAutonomousContinuation) {\n\t\t\t\t\tthis._markAutonomousContinuationSuppressed(primaryDeliveryRecord(action).message);\n\t\t\t\t}\n\t\t\t\tconst result = this._admitSessionInput(action, {\n\t\t\t\t\timmediatelyEligible: !visibleQueued && this._canStartSessionActionImmediately(),\n\t\t\t\t});\n\t\t\t\tcommitFence?.release();\n\t\t\t\tif (!result.accepted || !result.ticket) {\n\t\t\t\t\tif (prefixMessages) this._pendingNextTurnMessages.unshift(...prefixMessages);\n\t\t\t\t\treportPreflight(false, false);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (result.disposition === \"queued\") {\n\t\t\t\t\treportPreflight(true, true);\n\t\t\t\t} else {\n\t\t\t\t\tvoid result.ticket.delivered.then(\n\t\t\t\t\t\t() => reportPreflight(true),\n\t\t\t\t\t\t() => reportPreflight(false),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst deferralObserver =\n\t\t\t\t\tacceptedAgentMessage &&\n\t\t\t\t\toptions?.queueIfBusy === true &&\n\t\t\t\t\t!options.streamingBehavior &&\n\t\t\t\t\tresult.disposition === \"starts_when_admitted\"\n\t\t\t\t\t\t? this._observeSessionActionDeferral(action)\n\t\t\t\t\t\t: undefined;\n\t\t\t\tif (acceptedAgentMessage && !queueForStreaming && !queueForBusy && !options?.streamingBehavior) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst outcome = deferralObserver\n\t\t\t\t\t\t\t? await Promise.race([\n\t\t\t\t\t\t\t\t\tresult.ticket.delivered.then(() => \"delivered\" as const),\n\t\t\t\t\t\t\t\t\tdeferralObserver.deferred.then(() => \"deferred\" as const),\n\t\t\t\t\t\t\t\t])\n\t\t\t\t\t\t\t: await result.ticket.delivered.then(() => \"delivered\" as const);\n\t\t\t\t\t\tif (outcome === \"deferred\" && !options?.streamingBehavior) {\n\t\t\t\t\t\t\tconst error = new Error(\n\t\t\t\t\t\t\t\t\"Agent became busy before prompt delivery. Specify streamingBehavior ('steer' or 'followUp') to queue the message.\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tthis._rejectAgentMessage(action.agentMessageId, error);\n\t\t\t\t\t\t\tthis._cancelSessionActions((candidate) => candidate === action, error);\n\t\t\t\t\t\t\tthis._emitQueueUpdate();\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn;\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tdeferralObserver?.stop();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (options?.returnAfterAccepted) {\n\t\t\t\t\tif (result.disposition === \"starts_when_admitted\" || (acceptedAgentMessage && !visibleQueued)) {\n\t\t\t\t\t\tawait result.ticket.delivered;\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (visibleQueued) return;\n\t\t\t\tawait result.ticket.completed;\n\t\t\t\tawait this.waitForSessionInputIdle();\n\t\t\t} catch (error) {\n\t\t\t\treportPreflight(false);\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tcommitFence?.release();\n\t\t\t}\n\t\t};\n\t\treturn commitFence ? this._sessionActionCommitContext.run(commitFence.owner, run) : run();\n\t}\n\n\tprivate _executeExtensionCommand(text: string): Promise<void> | undefined {\n\t\tconst parsed = parseSlashCommand(text);\n\t\tif (!parsed) return undefined;\n\t\tconst commandName = parsed.name;\n\t\tconst args = parsed.args;\n\n\t\tconst command = this._extensionRunner.getCommand(commandName);\n\t\tif (!command) return undefined;\n\t\tconst context = this._extensionRunner.createCommandContext();\n\t\treturn Promise.resolve()\n\t\t\t.then(() => command.handler(args, context))\n\n\t\t\t.catch((error: unknown) => {\n\t\t\t\tconst commandError = error instanceof Error ? error : new Error(String(error));\n\t\t\t\tthis._extensionRunner.emitError({\n\t\t\t\t\textensionPath: `command:${commandName}`,\n\t\t\t\t\tevent: \"command\",\n\t\t\t\t\terror: commandError.message,\n\t\t\t\t});\n\t\t\t\tthrow commandError;\n\t\t\t});\n\t}\n\n\t/**\n\t * Expand skill commands (/skill:name args) to their full content.\n\t * Returns the expanded text, or the original text if not a skill command or skill not found.\n\t * Emits errors via extension runner if file read fails.\n\t */\n\tprivate _expandSkillCommand(text: string): string {\n\t\tif (!text.startsWith(\"/skill:\")) return text;\n\n\t\tconst parsed = parseSlashCommand(text);\n\t\tif (!parsed?.name.startsWith(\"skill:\")) return text;\n\t\tconst skillName = parsed.name.slice(\"skill:\".length);\n\t\tconst args = parsed.args;\n\n\t\tconst skill = this.resourceLoader.getSkills().skills.find((s) => s.name === skillName);\n\t\tif (!skill) return text; // Unknown skill, pass through\n\n\t\ttry {\n\t\t\tconst content = readFileSync(skill.filePath, \"utf-8\");\n\t\t\tconst body = stripFrontmatter(content).trim();\n\t\t\tconst skillBlock = `<skill name=\"${skill.name}\" location=\"${skill.filePath}\">\\nReferences are relative to ${skill.baseDir}.\\n\\n${body}\\n</skill>`;\n\t\t\treturn args ? `${skillBlock}\\n\\n${args}` : skillBlock;\n\t\t} catch (err) {\n\t\t\tthis._extensionRunner.emitError({\n\t\t\t\textensionPath: skill.filePath,\n\t\t\t\tevent: \"skill_expansion\",\n\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t});\n\t\t\treturn text; // Return original on error\n\t\t}\n\t}\n\n\t/**\n\t * Queue a steering message while the agent is running.\n\t * Delivered after the current assistant turn finishes executing its tool calls,\n\t * before the next LLM call.\n\t * Expands skill commands and prompt templates. Errors on extension commands.\n\t * @param images Optional image attachments to include with the message\n\t * @throws Error if text is an extension command\n\t */\n\tasync steer(\n\t\ttext: string,\n\t\timages?: ImageContent[],\n\t\toptions: {\n\t\t\tqueueKey?: string;\n\t\t\tagentMessageId?: string;\n\t\t\tresumeIfIdle?: boolean;\n\t\t} = {},\n\t): Promise<void> {\n\t\tconst normalized = this._normalizeSubmission(text, images, {\n\t\t\tparseSessionCommands: false,\n\t\t\textensionCommands: \"reject\",\n\t\t\texpandSkills: true,\n\t\t\texpandPromptTemplates: true,\n\t\t});\n\t\tif (normalized instanceof Promise || normalized.kind !== \"prompt\") {\n\t\t\tthrow new Error(\"Queued prompt normalization did not produce a prompt\");\n\t\t}\n\n\t\tawait this._queuePreparedPrompt(\"steer\", normalized.text, normalized.images, {\n\t\t\tqueueKey: options.queueKey,\n\t\t\tagentMessageId: options.agentMessageId,\n\t\t\tresumeIfIdle: options.resumeIfIdle,\n\t\t});\n\t}\n\n\t/**\n\t * Queue a follow-up message to be processed after the agent finishes.\n\t * Delivered only when agent has no more tool calls or steering messages.\n\t * Expands skill commands and prompt templates. Errors on extension commands.\n\t * @param images Optional image attachments to include with the message\n\t * @throws Error if text is an extension command\n\t */\n\tasync followUp(\n\t\ttext: string,\n\t\timages?: ImageContent[],\n\t\toptions: {\n\t\t\tqueueKey?: string;\n\t\t\tagentMessageId?: string;\n\t\t\tresumeIfIdle?: boolean;\n\t\t} = {},\n\t): Promise<boolean> {\n\t\tconst normalized = this._normalizeSubmission(text, images, {\n\t\t\tparseSessionCommands: false,\n\t\t\textensionCommands: \"reject\",\n\t\t\texpandSkills: true,\n\t\t\texpandPromptTemplates: true,\n\t\t});\n\t\tif (normalized instanceof Promise || normalized.kind !== \"prompt\") {\n\t\t\tthrow new Error(\"Queued prompt normalization did not produce a prompt\");\n\t\t}\n\n\t\treturn this._queuePreparedPrompt(\"followUp\", normalized.text, normalized.images, {\n\t\t\tqueueKey: options.queueKey,\n\t\t\tagentMessageId: options.agentMessageId,\n\t\t\tresumeIfIdle: options.resumeIfIdle,\n\t\t});\n\t}\n\n\tasync restoreSessionActions(snapshot: SessionActionRecoverySnapshot): Promise<number> {\n\t\tif (snapshot.formatVersion !== SESSION_ACTION_RECOVERY_FORMAT_VERSION) {\n\t\t\tthrow new Error(`Unsupported session action recovery format version: ${snapshot.formatVersion}`);\n\t\t}\n\t\tconst actionIds = new Set(this._actionStore.ownedActions().map((action) => action.id));\n\t\tconst actions = snapshot.actions.map((recovered): QueuedSessionAction => {\n\t\t\tif (actionIds.has(recovered.id)) throw new Error(`Duplicate session action id: ${recovered.id}`);\n\t\t\tactionIds.add(recovered.id);\n\t\t\tif (\n\t\t\t\trecovered.payload.kind === \"turn\" &&\n\t\t\t\trecovered.payload.records.some((record) => record.ownerActionId !== recovered.id)\n\t\t\t) {\n\t\t\t\tthrow new Error(`Session action ${recovered.id} has invalid delivery correlation`);\n\t\t\t}\n\t\t\tconst payload: PreparedTurnPayload | PreparedCommandPayload =\n\t\t\t\trecovered.payload.kind === \"turn\"\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tkind: \"turn\",\n\t\t\t\t\t\t\ttext: recovered.payload.text,\n\t\t\t\t\t\t\t...(recovered.payload.preview ? { preview: recovered.payload.preview } : {}),\n\t\t\t\t\t\t\trecords: recovered.payload.records.map((record) => ({\n\t\t\t\t\t\t\t\tid: record.id,\n\t\t\t\t\t\t\t\trole: record.role,\n\t\t\t\t\t\t\t\tmessage: cloneQueuedAgentMessage(record.message),\n\t\t\t\t\t\t\t\tstarted: false,\n\t\t\t\t\t\t\t\tdurable: false,\n\t\t\t\t\t\t\t\townerActionId: record.ownerActionId,\n\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t...(recovered.payload.images\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\timages: recovered.payload.images.map((image) => ({\n\t\t\t\t\t\t\t\t\t\t\t...image,\n\t\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t...(recovered.payload.content\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\tcontent: recovered.payload.content.map((block) => ({\n\t\t\t\t\t\t\t\t\t\t\t...block,\n\t\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t...(recovered.payload.customMessage\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\tcustomMessage: cloneCustomMessage(recovered.payload.customMessage),\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\texecutionPolicy: {\n\t\t\t\t\t\t\t\t...recovered.payload.executionPolicy,\n\t\t\t\t\t\t\t\tpreparation: {\n\t\t\t\t\t\t\t\t\t...recovered.payload.executionPolicy.preparation,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tqueueVisible: recovered.payload.queueVisible,\n\t\t\t\t\t\t\tacceptedAgentMessage: recovered.payload.acceptedAgentMessage,\n\t\t\t\t\t\t\tacceptedBeforeCompletion: recovered.payload.acceptedBeforeCompletion,\n\t\t\t\t\t\t}\n\t\t\t\t\t: {\n\t\t\t\t\t\t\tkind: \"session_command\",\n\t\t\t\t\t\t\ttext: recovered.payload.text,\n\t\t\t\t\t\t\tcommand: { ...recovered.payload.command },\n\t\t\t\t\t\t\t...(recovered.payload.images\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\timages: recovered.payload.images.map((image) => ({\n\t\t\t\t\t\t\t\t\t\t\t...image,\n\t\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t};\n\t\t\treturn {\n\t\t\t\tid: recovered.id,\n\t\t\t\tsource: recovered.source,\n\t\t\t\tdelivery: recovered.delivery,\n\t\t\t\twake: recovered.wake,\n\t\t\t\tpayload,\n\t\t\t\tlifecycle: { state: \"queued\" },\n\t\t\t\t...(recovered.queueKey ? { queueKey: recovered.queueKey } : {}),\n\t\t\t\t...(recovered.agentMessageId ? { agentMessageId: recovered.agentMessageId } : {}),\n\t\t\t\t...(recovered.suppressAutonomousContinuation ? { suppressAutonomousContinuation: true } : {}),\n\t\t\t};\n\t\t});\n\t\tfor (const action of actions) {\n\t\t\tconst durableTerminalNotice = this._isRlmTerminalNoticeAction(action);\n\t\t\tif (durableTerminalNotice) this._durableRlmTerminalNoticeActionIds.add(action.id);\n\t\t\ttry {\n\t\t\t\tthis._admitSessionInput(action, { restore: true });\n\t\t\t} catch (error) {\n\t\t\t\tif (durableTerminalNotice) this._durableRlmTerminalNoticeActionIds.delete(action.id);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\treturn actions.length;\n\t}\n\n\tprivate _restoreSessionCommand(\n\t\ttext: string,\n\t\tcustomMessage: CustomMessage | undefined,\n\t\timages: ImageContent[] | undefined,\n\t\tschedule: SessionInputSchedule,\n\t\tagentMessageId: string | undefined,\n\t): boolean | undefined {\n\t\tif (!isSessionSlashCommandMessage(customMessage) || text !== customMessage.details.command.text) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn this._admitSessionInput(\n\t\t\tthis._createSessionCommandAction(text, customMessage.details.command, images, schedule, {\n\t\t\t\tagentMessageId,\n\t\t\t\tsource: \"internal\",\n\t\t\t}),\n\t\t\t{ restore: true },\n\t\t).accepted;\n\t}\n\n\tprivate _restorePromptInput(schedule: SessionInputSchedule, snapshot: RestoredPromptInput): Promise<boolean> {\n\t\treturn this._queuePreparedPrompt(schedule, snapshot.text, snapshot.images, {\n\t\t\tqueueKey: snapshot.queueKey,\n\t\t\tagentMessageId: snapshot.agentMessageId,\n\t\t\tcontent: snapshot.content,\n\t\t\tmessage: snapshot.customMessage,\n\t\t\tprefixMessages: snapshot.prefixMessages,\n\t\t\tsource: \"internal\",\n\t\t});\n\t}\n\n\tasync restoreSteeringMessage(\n\t\ttext: string,\n\t\timages?: ImageContent[],\n\t\toptions: {\n\t\t\tqueueKey?: string;\n\t\t\tagentMessageId?: string;\n\t\t\tcontent?: (TextContent | ImageContent)[];\n\t\t\tcustomMessage?: CustomMessage;\n\t\t\tprefixMessages?: CustomMessage[];\n\t\t} = {},\n\t): Promise<void> {\n\t\tif (\n\t\t\tthis._restoreSessionCommand(text, options.customMessage, images, \"steer\", options.agentMessageId) !== undefined\n\t\t)\n\t\t\treturn;\n\n\t\tawait this._restorePromptInput(\"steer\", {\n\t\t\ttext,\n\t\t\timages,\n\t\t\tqueueKey: options.queueKey,\n\t\t\tagentMessageId: options.agentMessageId,\n\t\t\tcontent: options.content,\n\t\t\tcustomMessage: options.customMessage,\n\t\t\tprefixMessages: options.prefixMessages,\n\t\t});\n\t}\n\n\tasync restoreFollowUpMessage(\n\t\ttext: string,\n\t\timages?: ImageContent[],\n\t\toptions: {\n\t\t\tqueueKey?: string;\n\t\t\tagentMessageId?: string;\n\t\t\tcontent?: (TextContent | ImageContent)[];\n\t\t\tcustomMessage?: CustomMessage;\n\t\t\tprefixMessages?: CustomMessage[];\n\t\t} = {},\n\t): Promise<boolean> {\n\t\tconst restoredCommand = this._restoreSessionCommand(\n\t\t\ttext,\n\t\t\toptions.customMessage,\n\t\t\timages,\n\t\t\t\"followUp\",\n\t\t\toptions.agentMessageId,\n\t\t);\n\t\tif (restoredCommand !== undefined) return restoredCommand;\n\n\t\treturn this._restorePromptInput(\"followUp\", {\n\t\t\ttext,\n\t\t\timages,\n\t\t\tqueueKey: options.queueKey,\n\t\t\tagentMessageId: options.agentMessageId,\n\t\t\tcontent: options.content,\n\t\t\tcustomMessage: options.customMessage,\n\t\t\tprefixMessages: options.prefixMessages,\n\t\t});\n\t}\n\n\tprivate _buildPromptContent(text: string, images?: ImageContent[]): (TextContent | ImageContent)[] {\n\t\tconst content: (TextContent | ImageContent)[] = [];\n\t\tcontent.push({ type: \"text\", text });\n\t\tif (images) content.push(...images);\n\t\treturn content;\n\t}\n\n\tprivate _takePendingNextTurnMessages(): CustomMessage[] {\n\t\tconst messages = this._pendingNextTurnMessages;\n\t\tthis._pendingNextTurnMessages = [];\n\t\treturn messages;\n\t}\n\n\tprivate _deliveryPolicy(schedule: SessionInputSchedule): DeliveryPolicy {\n\t\treturn schedule === \"steer\" ? \"next_turn_boundary\" : \"when_run_idle\";\n\t}\n\n\tprivate _createDeliveryRecord(\n\t\tactionId: string,\n\t\trole: DeliveryRecord[\"role\"],\n\t\tmessage: QueuedAgentMessage,\n\t): DeliveryRecord {\n\t\treturn {\n\t\t\tid: randomUUID(),\n\t\t\trole,\n\t\t\tmessage,\n\t\t\tstarted: false,\n\t\t\tdurable: false,\n\t\t\townerActionId: actionId,\n\t\t};\n\t}\n\n\tprivate _turnExecutionPolicy(\n\t\tkind: \"queued\" | \"directPrompt\" | \"injected\" | \"customTrigger\",\n\t\toptions: {\n\t\t\treturnAfterAccepted?: boolean;\n\t\t\tskipPrePromptWork?: boolean;\n\t\t} = {},\n\t): TurnExecutionPolicy {\n\t\tif (kind === \"queued\") {\n\t\t\treturn {\n\t\t\t\tpreparation: {\n\t\t\t\t\tinitialRefineBarrier: \"skip\",\n\t\t\t\t\tflushPendingBashBeforeValidation: false,\n\t\t\t\t\tvalidateModelAndAuth: true,\n\t\t\t\t\tawaitPendingModelSelection: true,\n\t\t\t\t\tpreTurnCompaction: \"beforeModelSelection\",\n\t\t\t\t\tfinalRefineBarrier: \"always\",\n\t\t\t\t},\n\t\t\t\trunBeforeAgentStart: true,\n\t\t\t\tnextTurnContextTiming: \"commit\",\n\t\t\t\tpreserveEmptyExtensionPrompt: true,\n\t\t\t\tcompletionIncludesRetryChain: true,\n\t\t\t};\n\t\t}\n\t\tif (kind === \"directPrompt\") {\n\t\t\treturn {\n\t\t\t\tpreparation: {\n\t\t\t\t\tinitialRefineBarrier: options.returnAfterAccepted ? \"skip\" : \"always\",\n\t\t\t\t\tflushPendingBashBeforeValidation: true,\n\t\t\t\t\tvalidateModelAndAuth: true,\n\t\t\t\t\tawaitPendingModelSelection: true,\n\t\t\t\t\tpreTurnCompaction: options.skipPrePromptWork ? \"skip\" : \"afterModelSelection\",\n\t\t\t\t\tfinalRefineBarrier: \"ifInFlight\",\n\t\t\t\t},\n\t\t\t\trunBeforeAgentStart: !options.skipPrePromptWork,\n\t\t\t\tnextTurnContextTiming: \"preparation\",\n\t\t\t\tpreserveEmptyExtensionPrompt: false,\n\t\t\t\tcompletionIncludesRetryChain: true,\n\t\t\t};\n\t\t}\n\t\tif (kind === \"injected\") {\n\t\t\treturn {\n\t\t\t\tpreparation: {\n\t\t\t\t\tinitialRefineBarrier: \"always\",\n\t\t\t\t\tflushPendingBashBeforeValidation: true,\n\t\t\t\t\tvalidateModelAndAuth: true,\n\t\t\t\t\tawaitPendingModelSelection: true,\n\t\t\t\t\tpreTurnCompaction: \"beforeModelSelection\",\n\t\t\t\t\tfinalRefineBarrier: \"ifInFlight\",\n\t\t\t\t},\n\t\t\t\trunBeforeAgentStart: true,\n\t\t\t\tnextTurnContextTiming: \"preparation\",\n\t\t\t\tpreserveEmptyExtensionPrompt: true,\n\t\t\t\tcompletionIncludesRetryChain: true,\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tpreparation: {\n\t\t\t\tinitialRefineBarrier: \"always\",\n\t\t\t\tflushPendingBashBeforeValidation: false,\n\t\t\t\tvalidateModelAndAuth: false,\n\t\t\t\tawaitPendingModelSelection: false,\n\t\t\t\tpreTurnCompaction: \"skip\",\n\t\t\t\tfinalRefineBarrier: \"skip\",\n\t\t\t},\n\t\t\trunBeforeAgentStart: false,\n\t\t\tnextTurnContextTiming: \"skip\",\n\t\t\tpreserveEmptyExtensionPrompt: false,\n\t\t\tcompletionIncludesRetryChain: false,\n\t\t};\n\t}\n\n\tprivate _createPreparedTurnAction(\n\t\tschedule: SessionInputSchedule,\n\t\ttext: string,\n\t\timages: ImageContent[] | undefined,\n\t\toptions: {\n\t\t\tagentMessageId?: string;\n\t\t\tqueueKey?: string;\n\t\t\tcontent?: (TextContent | ImageContent)[];\n\t\t\tmessage?: QueuedAgentMessage;\n\t\t\tprefixMessages?: CustomMessage[];\n\t\t\tpreviewLabel?: string;\n\t\t\tsuppressAutonomousContinuation?: boolean;\n\t\t\tresumeIfIdle?: boolean;\n\t\t\tsource?: InputSource | \"internal\";\n\t\t\texecutionPolicy?: TurnExecutionPolicy;\n\t\t\tqueueVisible?: boolean;\n\t\t\tacceptedAgentMessage?: boolean;\n\t\t\tacceptedBeforeCompletion?: boolean;\n\t\t},\n\t): QueuedSessionAction {\n\t\tconst id = randomUUID();\n\t\tconst content = options.content ?? this._buildPromptContent(text, images);\n\t\tconst message =\n\t\t\toptions.message ??\n\t\t\t({\n\t\t\t\trole: \"user\",\n\t\t\t\tcontent: content.map((block) => ({ ...block })),\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t} satisfies UserMessage);\n\t\tconst prefixMessages = options.prefixMessages?.map((prefix) => cloneCustomMessage(prefix)) ?? [];\n\t\tconst preview = options.previewLabel ? `${options.previewLabel}: ${text}` : undefined;\n\t\tconst payload: PreparedTurnPayload = {\n\t\t\tkind: \"turn\",\n\t\t\ttext,\n\t\t\trecords: [\n\t\t\t\t...prefixMessages.map((prefix) => this._createDeliveryRecord(id, \"prefix\", prefix)),\n\t\t\t\tthis._createDeliveryRecord(id, \"primary\", message),\n\t\t\t],\n\t\t\tpreview,\n\t\t\timages: images?.map((image) => ({ ...image })),\n\t\t\tcontent: content.map((block) => ({ ...block })),\n\t\t\tcustomMessage: options.message?.role === \"custom\" ? cloneCustomMessage(options.message) : undefined,\n\t\t\texecutionPolicy: options.executionPolicy ?? this._turnExecutionPolicy(\"queued\"),\n\t\t\tqueueVisible: options.queueVisible ?? true,\n\t\t\tacceptedAgentMessage: options.acceptedAgentMessage ?? false,\n\t\t\tacceptedBeforeCompletion: options.acceptedBeforeCompletion ?? false,\n\t\t};\n\t\treturn {\n\t\t\tid,\n\t\t\tsource: options.source ?? \"internal\",\n\t\t\tdelivery: this._deliveryPolicy(schedule),\n\t\t\twake:\n\t\t\t\toptions.resumeIfIdle === true\n\t\t\t\t\t? \"immediate\"\n\t\t\t\t\t: schedule === \"steer\"\n\t\t\t\t\t\t? \"on_lower_boundary\"\n\t\t\t\t\t\t: \"external_resume\",\n\t\t\tpayload,\n\t\t\tlifecycle: { state: \"queued\" },\n\t\t\tqueueKey: options.queueKey,\n\t\t\tagentMessageId: options.agentMessageId,\n\t\t\tsuppressAutonomousContinuation: options.suppressAutonomousContinuation,\n\t\t};\n\t}\n\n\tprivate _createSessionCommandAction(\n\t\ttext: string,\n\t\tcommand: SessionSlashCommand,\n\t\timages: ImageContent[] | undefined,\n\t\tschedule: SessionInputSchedule,\n\t\toptions: {\n\t\t\tagentMessageId?: string;\n\t\t\tsource?: InputSource | \"internal\";\n\t\t} = {},\n\t): QueuedSessionAction {\n\t\treturn {\n\t\t\tid: randomUUID(),\n\t\t\tsource: options.source ?? \"internal\",\n\t\t\tdelivery: this._deliveryPolicy(schedule),\n\t\t\twake: \"immediate\",\n\t\t\tpayload: { kind: \"session_command\", text, command, images },\n\t\t\tlifecycle: { state: \"queued\" },\n\t\t\tagentMessageId: options.agentMessageId,\n\t\t};\n\t}\n\n\tprivate _coalescedFollowUpOwner(action: QueuedSessionAction): QueuedSessionAction | undefined {\n\t\tif (action.delivery !== \"when_run_idle\" || action.payload.kind !== \"turn\" || !action.queueKey) return undefined;\n\t\treturn this._actionStore\n\t\t\t.unfinishedActions()\n\t\t\t.find(\n\t\t\t\t(candidate) =>\n\t\t\t\t\tcandidate.queueKey === action.queueKey &&\n\t\t\t\t\t(candidate.lifecycle.state === \"queued\" ||\n\t\t\t\t\t\tcandidate.lifecycle.state === \"selected\" ||\n\t\t\t\t\t\tcandidate.lifecycle.state === \"preparing\"),\n\t\t\t);\n\t}\n\n\tprivate _assertSessionActionAdmissionAvailable(): void {\n\t\tif (this._disposed || this._disposing) {\n\t\t\tthrow new Error(\"Cannot admit a session action because the session is disposing or disposed.\");\n\t\t}\n\t\tif (this._sessionInputAdmissionPauses.size > 0) {\n\t\t\tthrow new Error(\"Cannot admit a session action while session input admission is paused.\");\n\t\t}\n\t\tif (this._sessionInputPumpSuspended) {\n\t\t\tthrow new Error(\"Cannot admit a session action while queued session input is suspended.\");\n\t\t}\n\t}\n\n\tprivate _admitSessionInput(\n\t\taction: QueuedSessionAction,\n\t\toptions: {\n\t\t\trestore?: boolean;\n\t\t\tfront?: boolean;\n\t\t\twake?: boolean;\n\t\t\timmediatelyEligible?: boolean;\n\t\t} = {},\n\t): {\n\t\taccepted: boolean;\n\t\tdisposition: \"starts_when_admitted\" | \"queued\";\n\t\tticket?: ActionTicket;\n\t} {\n\t\tif (this._disposed || this._disposing) {\n\t\t\tthrow new Error(\"Cannot admit a session action because the session is disposing or disposed.\");\n\t\t}\n\t\tif (this._sessionInputAdmissionPauses.size > 0) {\n\t\t\tthrow new Error(\"Cannot admit a session action while session input admission is paused.\");\n\t\t}\n\t\tif (\n\t\t\toptions.restore !== true &&\n\t\t\taction.payload.kind === \"turn\" &&\n\t\t\tisAgentSessionMessage(primaryDeliveryRecord(action).message)\n\t\t) {\n\t\t\tassertAgentMessageQueueCapacity(\n\t\t\t\tthis._actionStore.unfinishedActions().length,\n\t\t\t\tDEFAULT_AGENT_MESSAGE_MAX_PENDING_PER_SESSION,\n\t\t\t);\n\t\t}\n\t\tconst coalescedOwner = options.restore ? undefined : this._coalescedFollowUpOwner(action);\n\t\tif (coalescedOwner) {\n\t\t\tif (action.agentMessageId !== coalescedOwner.agentMessageId) {\n\t\t\t\tthis._rejectAgentMessage(\n\t\t\t\t\taction.agentMessageId,\n\t\t\t\t\tnew Error(\"Prompt was not queued because an equivalent follow-up is already pending.\"),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn { accepted: false, disposition: \"queued\" };\n\t\t}\n\t\tconst canStartImmediately =\n\t\t\toptions.immediatelyEligible === true &&\n\t\t\t(this._actionStore.unfinishedActions().length === 0 || options.front === true);\n\t\tif (options.front) this._actionStore.enqueueFront(action);\n\t\telse this._actionStore.enqueue(action);\n\t\tlet disposition: \"starts_when_admitted\" | \"queued\" = \"queued\";\n\t\tif (canStartImmediately && this._actionStore.selectFirst() === action) disposition = \"starts_when_admitted\";\n\t\tconst controller = this._actionStore.ticketFor(action);\n\t\tcontroller.settleAccepted({\n\t\t\tstatus: \"accepted\",\n\t\t\tactionId: action.id,\n\t\t\tdisposition,\n\t\t});\n\t\tthis._sessionInputArrivalEpoch++;\n\t\tthis._emitQueueUpdate();\n\t\tif (\n\t\t\t!options.restore &&\n\t\t\toptions.wake !== false &&\n\t\t\t(disposition === \"starts_when_admitted\" ||\n\t\t\t\t(action.delivery === \"next_turn_boundary\" && this.isStreaming) ||\n\t\t\t\taction.payload.kind === \"session_command\" ||\n\t\t\t\taction.wake === \"immediate\")\n\t\t) {\n\t\t\tif (action.payload.kind === \"turn\" && action.wake === \"immediate\") {\n\t\t\t\tthis._resumeSessionInputAdmission();\n\t\t\t}\n\t\t\tthis._scheduleSessionInputPump();\n\t\t}\n\t\treturn { accepted: true, disposition, ticket: controller.ticket };\n\t}\n\n\tprivate async _queuePreparedPrompt(\n\t\tschedule: SessionInputSchedule,\n\t\ttext: string,\n\t\timages?: ImageContent[],\n\t\toptions: {\n\t\t\tagentMessageId?: string;\n\t\t\tqueueKey?: string;\n\t\t\tcontent?: (TextContent | ImageContent)[];\n\t\t\tmessage?: QueuedAgentMessage;\n\t\t\tprefixMessages?: CustomMessage[];\n\t\t\tpreviewLabel?: string;\n\t\t\tsuppressAutonomousContinuation?: boolean;\n\t\t\tresumeIfIdle?: boolean;\n\t\t\tsource?: InputSource | \"internal\";\n\t\t} = {},\n\t): Promise<boolean> {\n\t\tconst action = this._createPreparedTurnAction(schedule, text, images, options);\n\t\tif (action.suppressAutonomousContinuation) {\n\t\t\tthis._markAutonomousContinuationSuppressed(primaryDeliveryRecord(action).message);\n\t\t}\n\t\treturn this._admitSessionInput(action).accepted;\n\t}\n\n\tprivate _runtimeActivity(): RuntimeActivity {\n\t\treturn {\n\t\t\tlowerAgentRun: this.isStreaming,\n\t\t\tcompaction: this.isCompacting,\n\t\t\tretry: this.isRetrying,\n\t\t\tbash: this.isBashRunning,\n\t\t\trefinementApply: this._refineInFlight !== undefined,\n\t\t\tbranchMutation: this._branchSummaryOperation !== undefined,\n\t\t\tschedulerPauseCount: this._queuedWorkPauses.size + (this._sessionInputPumpSuspended ? 1 : 0),\n\t\t\tdisposing: this._disposed || this._disposing,\n\t\t};\n\t}\n\n\tprivate _hasSelectableSessionInput(): boolean {\n\t\treturn (\n\t\t\tthis._actionStore.queuedActions().length > 0 ||\n\t\t\tthis._actionStore.activeActions().some((action) => action.lifecycle.state === \"selected\")\n\t\t);\n\t}\n\n\tget hasPendingSessionWork(): boolean {\n\t\treturn this._actionStore.unfinishedActions().some((action) => {\n\t\t\tconst state = action.lifecycle.state;\n\t\t\treturn (\n\t\t\t\tstate === \"queued\" ||\n\t\t\t\tstate === \"selected\" ||\n\t\t\t\tstate === \"preparing\" ||\n\t\t\t\t(state === \"committing\" && action.payload.kind === \"turn\" && !primaryDeliveryRecord(action).durable)\n\t\t\t);\n\t\t});\n\t}\n\n\tget hasPendingAdmissionWaiters(): boolean {\n\t\treturn (\n\t\t\tthis._sessionActionCommitOwner !== undefined ||\n\t\t\tthis._pendingSessionActionFenceWaiters > 0 ||\n\t\t\tthis._sessionInputCheckpointWaiters.size > 0\n\t\t);\n\t}\n\n\tprivate _scheduleSessionInputPump(): void {\n\t\tif (this._sessionInputPumpSuspended || this._queuedWorkPauses.size > 0) return;\n\t\tif (this._disposed || this._disposing || this._sessionInputPumpRequested || !this._hasSelectableSessionInput()) {\n\t\t\treturn;\n\t\t}\n\t\tthis._sessionInputPumpRequested = true;\n\t\tconst epoch = this._sessionInputPumpEpoch;\n\t\tconst pump = async () => {\n\t\t\tthis._sessionInputPumpRequested = false;\n\t\t\tawait this._pumpSessionInputs(epoch);\n\t\t};\n\t\tthis._sessionInputPump = this._sessionInputPump.then(pump, pump);\n\t\tthis._sessionInputPump.catch(() => {});\n\t}\n\n\tprivate async _pumpSessionInputs(epoch: number): Promise<void> {\n\t\tlet blocked = false;\n\t\ttry {\n\t\t\twhile (!this._disposed && !this._disposing && this._hasSelectableSessionInput()) {\n\t\t\t\tawait this.agent.waitForIdle();\n\t\t\t\tconst preselected = this._actionStore\n\t\t\t\t\t.activeActions()\n\t\t\t\t\t.find((action) => action.lifecycle.state === \"selected\");\n\t\t\t\tif (epoch !== this._sessionInputPumpEpoch) {\n\t\t\t\t\tif (preselected) {\n\t\t\t\t\t\tthis._actionStore.rollback(preselected);\n\t\t\t\t\t\tthis._notifySessionInputCheckpointChange();\n\t\t\t\t\t\tthis._emitQueueUpdate();\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (!this._hasCancelledDispatchCapture()) await this._agentEventQueue;\n\t\t\t\tif (!preselected || preselected.payload.kind === \"session_command\") await this._waitForRefineIdle();\n\t\t\t\tconst activity = this._runtimeActivity();\n\t\t\t\tconst canSelectPreselectedTurn =\n\t\t\t\t\tpreselected?.payload.kind === \"turn\" && canSelectSessionAction({ ...activity, refinementApply: false });\n\t\t\t\tif (\n\t\t\t\t\tthis._isSessionInputHandoffDeferred(epoch) ||\n\t\t\t\t\t(!canSelectPreselectedTurn && !canSelectSessionAction(activity))\n\t\t\t\t) {\n\t\t\t\t\tblocked = true;\n\t\t\t\t\tthis._notifySessionInputCheckpointChange();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst first = preselected ?? this._actionStore.selectFirst();\n\t\t\t\tif (!first) return;\n\t\t\t\tif (first.payload.kind === \"session_command\") {\n\t\t\t\t\tawait this._executeSelectedSessionCommand(first, epoch);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst mode = first.delivery === \"next_turn_boundary\" ? this.steeringMode : this.followUpMode;\n\t\t\t\tconst actions: QueuedSessionAction[] = [first];\n\t\t\t\twhile (!preselected && mode === \"all\") {\n\t\t\t\t\tconst next = this._actionStore.queuedActions(first.delivery)[0];\n\t\t\t\t\tif (\n\t\t\t\t\t\t!next ||\n\t\t\t\t\t\tnext.payload.kind !== \"turn\" ||\n\t\t\t\t\t\t!turnExecutionPoliciesEqual(first.payload.executionPolicy, next.payload.executionPolicy)\n\t\t\t\t\t) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tthis._actionStore.selectFirst();\n\t\t\t\t\tactions.push(next);\n\t\t\t\t}\n\t\t\t\tif (epoch !== this._sessionInputPumpEpoch) {\n\t\t\t\t\tfor (const action of actions) this._actionStore.rollback(action);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tfor (const action of actions) transitionSessionAction(action, { state: \"preparing\" });\n\t\t\t\tthis._notifySessionInputCheckpointChange();\n\t\t\t\tthis._emitQueueUpdate();\n\t\t\t\ttry {\n\t\t\t\t\tawait this._startPreparedTurnActions(actions, epoch);\n\t\t\t\t\tfor (const action of actions) {\n\t\t\t\t\t\tif (action.lifecycle.state === \"committing\") {\n\t\t\t\t\t\t\tconst primary = primaryDeliveryRecord(action);\n\t\t\t\t\t\t\tif (this.agent.state.messages.includes(primary.message)) {\n\t\t\t\t\t\t\t\tprimary.durable = true;\n\t\t\t\t\t\t\t\ttransitionSessionAction(action, {\n\t\t\t\t\t\t\t\t\tstate: \"running\",\n\t\t\t\t\t\t\t\t\texecution: \"agent_turn\",\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (action.lifecycle.state === \"running\") {\n\t\t\t\t\t\t\ttransitionSessionAction(action, { state: \"completed\" });\n\t\t\t\t\t\t\tthis._actionStore.ticketFor(action).settleCompleted();\n\t\t\t\t\t\t\tthis._settleAgentMessage(action.agentMessageId, \"completion\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst transcript = this.agent.state.messages;\n\t\t\t\t\tconst delivered = new Set(transcript);\n\t\t\t\t\tconst undelivered: QueuedSessionAction[] = [];\n\t\t\t\t\tfor (const action of actions) {\n\t\t\t\t\t\tif (action.payload.kind !== \"turn\" || action.lifecycle.state === \"cancelled\") continue;\n\t\t\t\t\t\tfor (const record of action.payload.records) record.durable ||= delivered.has(record.message);\n\t\t\t\t\t\taction.payload.records = action.payload.records.filter((record) => {\n\t\t\t\t\t\t\tif (record.role === \"prefix\") return !record.durable;\n\t\t\t\t\t\t\tif (record.role === \"next_turn\") return record.durable;\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (!primaryDeliveryRecord(action).durable) undelivered.push(action);\n\t\t\t\t\t}\n\t\t\t\t\tif (this._isDeferredSessionInputError(error, epoch)) {\n\t\t\t\t\t\tfor (const action of undelivered) {\n\t\t\t\t\t\t\tif (action.lifecycle.state === \"committing\") {\n\t\t\t\t\t\t\t\tthis._actionStore.rollback(action, {\n\t\t\t\t\t\t\t\t\tdispatchSettled: true,\n\t\t\t\t\t\t\t\t\ttranscript,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t} else if (action.lifecycle.state === \"preparing\" || action.lifecycle.state === \"selected\") {\n\t\t\t\t\t\t\t\tthis._actionStore.rollback(action);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (undelivered.length > 0) this._emitQueueUpdate();\n\t\t\t\t\t\tblocked = epoch !== this._sessionInputPumpEpoch || this._isBusyForSessionInput(\"pump\");\n\t\t\t\t\t\tif (blocked) return;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tconst terminalError = this._asError(error);\n\t\t\t\t\tfor (const action of actions) {\n\t\t\t\t\t\tif (action.lifecycle.state === \"cancelled\") continue;\n\t\t\t\t\t\tif (action.lifecycle.state !== \"completed\" && action.lifecycle.state !== \"failed\") {\n\t\t\t\t\t\t\ttransitionSessionAction(action, {\n\t\t\t\t\t\t\t\tstate: \"failed\",\n\t\t\t\t\t\t\t\terror: terminalError,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst ticket = this._actionStore.ticketFor(action);\n\t\t\t\t\t\tif (undelivered.includes(action)) {\n\t\t\t\t\t\t\tticket.rejectDelivered(terminalError);\n\t\t\t\t\t\t\tthis._settleAgentMessage(action.agentMessageId, \"delivery\", terminalError);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis._settleAgentMessage(action.agentMessageId, \"completion\", terminalError);\n\t\t\t\t\t\tticket.settleCompleted(terminalError);\n\t\t\t\t\t}\n\t\t\t\t\tif (actions.some((action) => action.payload.kind !== \"turn\" || action.payload.queueVisible)) {\n\t\t\t\t\t\tthis._surfaceSessionInputError(error);\n\t\t\t\t\t}\n\t\t\t\t} finally {\n\t\t\t\t\tfor (const action of actions) {\n\t\t\t\t\t\tconst retainedCancelledDispatch =\n\t\t\t\t\t\t\taction.lifecycle.state === \"cancelled\" &&\n\t\t\t\t\t\t\taction.payload.kind === \"turn\" &&\n\t\t\t\t\t\t\taction.payload.captureRunMessages !== undefined;\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t!retainedCancelledDispatch &&\n\t\t\t\t\t\t\t(action.lifecycle.state === \"completed\" ||\n\t\t\t\t\t\t\t\taction.lifecycle.state === \"failed\" ||\n\t\t\t\t\t\t\t\taction.lifecycle.state === \"cancelled\")\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tthis._durableRlmTerminalNoticeActionIds.delete(action.id);\n\t\t\t\t\t\t\tthis._actionStore.releaseTerminal(action);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthis._notifySessionInputCheckpointChange();\n\t\t\t\t\tthis._emitQueueUpdate();\n\t\t\t\t}\n\t\t\t\tif (epoch !== this._sessionInputPumpEpoch || blocked) return;\n\t\t\t}\n\t\t} finally {\n\t\t\tif (!blocked && epoch === this._sessionInputPumpEpoch && this._hasSelectableSessionInput()) {\n\t\t\t\tthis._scheduleSessionInputPump();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async _executeSelectedSessionCommand(action: QueuedSessionAction, epoch: number): Promise<void> {\n\t\tif (action.payload.kind !== \"session_command\") throw new Error(\"Expected a selected session command\");\n\t\tconst input = action.payload;\n\t\tconst commitFence = await this._acquireSessionActionCommitFence();\n\t\ttry {\n\t\t\tawait this._sessionActionCommitContext.run(commitFence.owner, async () => {\n\t\t\t\tconst isCancelled = () => action.lifecycle.state === \"cancelled\";\n\t\t\t\tif (isCancelled()) return;\n\t\t\t\tawait this._waitForRefineIdle();\n\t\t\t\tif (isCancelled()) return;\n\t\t\t\tif (this._isSessionInputHandoffDeferred(epoch) || !canSelectSessionAction(this._runtimeActivity())) {\n\t\t\t\t\tthis._actionStore.rollback(action);\n\t\t\t\t\tthis._notifySessionInputCheckpointChange();\n\t\t\t\t\tthis._emitQueueUpdate();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\ttransitionSessionAction(action, {\n\t\t\t\t\tstate: \"running\",\n\t\t\t\t\texecution: \"session_command\",\n\t\t\t\t});\n\t\t\t\tthis._notifySessionInputCheckpointChange();\n\t\t\t\tthis._emitQueueUpdate();\n\t\t\t\ttry {\n\t\t\t\t\tthis._appendDurableSessionCommandMessage(input.text, input.command, false);\n\t\t\t\t\tthis._actionStore.ticketFor(action).settleDelivered({ status: \"not_applicable\" });\n\t\t\t\t\tthis._settleAgentMessage(action.agentMessageId, \"delivery\");\n\t\t\t\t\tawait this._executeQueuedSessionCommand(action);\n\t\t\t\t\ttransitionSessionAction(action, { state: \"completed\" });\n\t\t\t\t\tthis._actionStore.ticketFor(action).settleCompleted();\n\t\t\t\t\tthis._settleAgentMessage(action.agentMessageId, \"completion\");\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst commandError = this._asError(error);\n\t\t\t\t\ttransitionSessionAction(action, {\n\t\t\t\t\t\tstate: \"failed\",\n\t\t\t\t\t\terror: commandError,\n\t\t\t\t\t});\n\t\t\t\t\tconst ticket = this._actionStore.ticketFor(action);\n\t\t\t\t\tticket.rejectDelivered(commandError);\n\t\t\t\t\tticket.settleCompleted(commandError);\n\t\t\t\t\tthis._rejectAgentMessage(action.agentMessageId, commandError);\n\t\t\t\t} finally {\n\t\t\t\t\tthis._actionStore.releaseTerminal(action);\n\t\t\t\t\tthis._notifySessionInputCheckpointChange();\n\t\t\t\t\tthis._emitQueueUpdate();\n\t\t\t\t}\n\t\t\t});\n\t\t} finally {\n\t\t\tcommitFence.release();\n\t\t}\n\t}\n\n\tprivate _isBusyForSessionInput(point: \"preflight\" | \"pump\"): boolean {\n\t\tconst externalBusy = this.isCompacting || this.isRetrying || this.isBashRunning;\n\t\tif (point === \"pump\") {\n\t\t\treturn (\n\t\t\t\texternalBusy ||\n\t\t\t\tthis._disposed ||\n\t\t\t\tthis._disposing ||\n\t\t\t\tthis._sessionInputPumpSuspended ||\n\t\t\t\tthis._queuedWorkPauses.size > 0 ||\n\t\t\t\tthis._branchSummaryOperation !== undefined\n\t\t\t);\n\t\t}\n\t\treturn externalBusy || this._actionStore.unfinishedActions().length > 0;\n\t}\n\n\tprivate _isSessionInputHandoffDeferred(epoch: number): boolean {\n\t\treturn epoch !== this._sessionInputPumpEpoch || this._isBusyForSessionInput(\"pump\");\n\t}\n\n\tprivate _asError(error: unknown): Error {\n\t\treturn error instanceof Error ? error : new Error(String(error));\n\t}\n\n\tprivate _isDeferredSessionInputError(error: unknown, epoch: number): boolean {\n\t\tif (error instanceof DeferredSessionInputError) return true;\n\t\tif (epoch !== this._sessionInputPumpEpoch) return true;\n\t\tif (this._isBusyForSessionInput(\"pump\")) {\n\t\t\tthis._surfaceSessionInputError(error);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate _surfaceSessionInputError(error: unknown): void {\n\t\tconst normalized = this._asError(error);\n\t\ttry {\n\t\t\tthis._extensionRunner.emitError({\n\t\t\t\textensionPath: \"<session-input>\",\n\t\t\t\tevent: \"session_input\",\n\t\t\t\terror: normalized.message,\n\t\t\t\tstack: normalized.stack,\n\t\t\t});\n\t\t} catch {\n\t\t\t// Best-effort: a throwing error listener must not break the pump's requeue path.\n\t\t}\n\t}\n\n\tprivate async _startPreparedTurnActions(actions: QueuedSessionAction[], epoch: number): Promise<void> {\n\t\tlet nextTurnMessages: CustomMessage[] = [];\n\t\tconst activeTurns = () =>\n\t\t\tactions.filter(\n\t\t\t\t(action): action is SessionAction<PreparedTurnPayload> =>\n\t\t\t\t\taction.payload.kind === \"turn\" && action.lifecycle.state === \"preparing\",\n\t\t\t);\n\t\tconst firstTurn = activeTurns()[0];\n\t\tif (!firstTurn) return;\n\t\tconst executionPolicy = firstTurn.payload.executionPolicy;\n\t\tconst restoreNextTurnContext = () => {\n\t\t\tthis._pendingNextTurnMessages.unshift(...nextTurnMessages);\n\t\t\tnextTurnMessages = [];\n\t\t};\n\t\ttry {\n\t\t\tconst preparedTurn = await this._prepareForCommit(executionPolicy.preparation, {\n\t\t\t\tafterValidation: () => {\n\t\t\t\t\tif (this._isSessionInputHandoffDeferred(epoch)) {\n\t\t\t\t\t\tthrow new DeferredSessionInputError(\"Session input paused before preflight\");\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tprepare: async () => {\n\t\t\t\t\tif (executionPolicy.nextTurnContextTiming === \"preparation\") {\n\t\t\t\t\t\tnextTurnMessages = this._takePendingNextTurnMessages();\n\t\t\t\t\t}\n\t\t\t\t\tif (!executionPolicy.runBeforeAgentStart) return undefined;\n\t\t\t\t\twhile (activeTurns().some((action) => action.payload.prepared === undefined)) {\n\t\t\t\t\t\tif (this._isSessionInputHandoffDeferred(epoch)) {\n\t\t\t\t\t\t\tthrow new DeferredSessionInputError(\"Session input paused before preparation\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst preparationAction = activeTurns().at(-1);\n\t\t\t\t\t\tif (!preparationAction) return undefined;\n\t\t\t\t\t\tconst basePromptSnapshot = this._baseSystemPrompt;\n\t\t\t\t\t\tconst result = await this._extensionRunner.emitBeforeAgentStart(\n\t\t\t\t\t\t\tpreparationAction.payload.text,\n\t\t\t\t\t\t\tpreparationAction.payload.images,\n\t\t\t\t\t\t\tbasePromptSnapshot,\n\t\t\t\t\t\t\tthis._baseSystemPromptOptions,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (activeTurns().at(-1) !== preparationAction) continue;\n\t\t\t\t\t\tconst prepared = { result, basePromptSnapshot };\n\t\t\t\t\t\tfor (const action of activeTurns()) action.payload.prepared = prepared;\n\t\t\t\t\t}\n\t\t\t\t\tif (this._isSessionInputHandoffDeferred(epoch)) {\n\t\t\t\t\t\tthrow new DeferredSessionInputError(\"Session input paused before handoff\");\n\t\t\t\t\t}\n\t\t\t\t\treturn activeTurns()[0]?.payload.prepared;\n\t\t\t\t},\n\t\t\t\tshouldCommit: () => activeTurns().length > 0,\n\t\t\t\tcommit: (prepared) => {\n\t\t\t\t\tif (this._isSessionInputHandoffDeferred(epoch)) {\n\t\t\t\t\t\tthrow new DeferredSessionInputError(\"Session input paused before handoff\");\n\t\t\t\t\t}\n\t\t\t\t\tconst turns = activeTurns();\n\t\t\t\t\tif (turns.length === 0) return undefined;\n\t\t\t\t\treturn { prepared, turns };\n\t\t\t\t},\n\t\t\t});\n\t\t\tif (!preparedTurn) {\n\t\t\t\trestoreNextTurnContext();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst { prepared, turns } = preparedTurn;\n\t\t\tconst commitFence = await this._acquireSessionActionCommitFence();\n\t\t\tlet promptPromise: Promise<void>;\n\t\t\ttry {\n\t\t\t\tpromptPromise = this._sessionActionCommitContext.run(commitFence.owner, () => {\n\t\t\t\t\tif (\n\t\t\t\t\t\tthis._isSessionInputHandoffDeferred(epoch) ||\n\t\t\t\t\t\tthis.isStreaming ||\n\t\t\t\t\t\tturns.some((action) => action.lifecycle.state !== \"preparing\")\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new DeferredSessionInputError(\"Agent became active before session input handoff\");\n\t\t\t\t\t}\n\t\t\t\t\tif (executionPolicy.nextTurnContextTiming === \"commit\") {\n\t\t\t\t\t\tnextTurnMessages = this._takePendingNextTurnMessages();\n\t\t\t\t\t}\n\t\t\t\t\tconst contextRecords = nextTurnMessages.map((message) =>\n\t\t\t\t\t\tthis._createDeliveryRecord(turns[0].id, \"next_turn\", message),\n\t\t\t\t\t);\n\t\t\t\t\tconst firstPrimaryIndex = turns[0].payload.records.indexOf(primaryDeliveryRecord(turns[0]));\n\t\t\t\t\tturns[0].payload.records.splice(firstPrimaryIndex, 0, ...contextRecords);\n\t\t\t\t\tconst preparedMessages: AgentMessage[] = turns.flatMap((action) =>\n\t\t\t\t\t\taction.payload.records.map((record) => record.message),\n\t\t\t\t\t);\n\t\t\t\t\tfor (const action of turns) {\n\t\t\t\t\t\tif (action.suppressAutonomousContinuation) {\n\t\t\t\t\t\t\tthis._markAutonomousContinuationSuppressed(primaryDeliveryRecord(action).message);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (executionPolicy.runBeforeAgentStart) {\n\t\t\t\t\t\tthis._appendBeforeAgentStartMessages(preparedMessages, prepared?.result);\n\t\t\t\t\t\tthis._applyPreparedSystemPrompt(prepared, executionPolicy.preserveEmptyExtensionPrompt);\n\t\t\t\t\t} else if (executionPolicy.nextTurnContextTiming !== \"skip\") {\n\t\t\t\t\t\tthis.agent.state.systemPrompt = this._baseSystemPrompt;\n\t\t\t\t\t}\n\t\t\t\t\tfor (const action of turns) transitionSessionAction(action, { state: \"committing\" });\n\t\t\t\t\tthis._notifySessionInputCheckpointChange();\n\t\t\t\t\tthis._emitQueueUpdate();\n\t\t\t\t\treturn turns.some((action) => action.suppressAutonomousContinuation)\n\t\t\t\t\t\t? this._runWithAutonomousContinuationSuppressed(() => this.agent.prompt(preparedMessages))\n\t\t\t\t\t\t: this.agent.prompt(preparedMessages);\n\t\t\t\t});\n\t\t\t} finally {\n\t\t\t\tcommitFence.release();\n\t\t\t}\n\t\t\tawait promptPromise;\n\t\t\tif (executionPolicy.completionIncludesRetryChain) await this.waitForRetry();\n\t\t\tif (!this._hasCancelledDispatchCapture()) await this._agentEventQueue;\n\t\t\tif (\n\t\t\t\tturns.some(\n\t\t\t\t\t(action) =>\n\t\t\t\t\t\taction.lifecycle.state !== \"cancelled\" &&\n\t\t\t\t\t\t!primaryDeliveryRecord(action).durable &&\n\t\t\t\t\t\t!this.agent.state.messages.includes(primaryDeliveryRecord(action).message),\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tthrow new Error(\"Session input dispatch settled without durable delivery\");\n\t\t\t}\n\t\t\tthis._forgetConsumedPostCompactionContinuations(turns.map((action) => primaryDeliveryRecord(action).message));\n\t\t} catch (error) {\n\t\t\tconst delivered = new Set(this.agent.state.messages);\n\t\t\tthis._pendingNextTurnMessages.unshift(...nextTurnMessages.filter((message) => !delivered.has(message)));\n\t\t\tfor (const action of actions) {\n\t\t\t\tif (action.payload.kind === \"turn\") {\n\t\t\t\t\taction.payload.records = action.payload.records.filter((record) => record.role !== \"next_turn\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprivate async _executeQueuedSessionCommand(action: QueuedSessionAction): Promise<void> {\n\t\tif (action.payload.kind !== \"session_command\") throw new Error(\"Expected a session command action\");\n\t\tconst input = action.payload;\n\t\ttry {\n\t\t\tlet resultText: string | undefined;\n\t\t\tlet displayResult = true;\n\t\t\tswitch (input.command.name) {\n\t\t\t\tcase \"compact\":\n\t\t\t\t\tawait this.compact(input.command.args || undefined, {\n\t\t\t\t\t\tskipAbort: true,\n\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"refine\": {\n\t\t\t\t\tlet result: RefinementResult;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst options = parseRefineCommandOptions(input.command.args);\n\t\t\t\t\t\tresult = await this.refine(options, { skipAbort: true });\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t// Only a failure of the refinement itself is a refine failure; a later\n\t\t\t\t\t\t// result-row persist error must not report a completed refinement as failed.\n\t\t\t\t\t\tthis._emitRefineFailed(this._asError(error));\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\t\t\t\t\tconst applied = result.appliedEdits.filter((edit) => edit.applied).length;\n\t\t\t\t\tresultText = `Refined continual harness state: ${applied} edit${applied === 1 ? \"\" : \"s\"} applied.`;\n\t\t\t\t\tdisplayResult = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase \"goal\":\n\t\t\t\t\tawait this._handleGoalSlashCommand(input.text, input.images);\n\t\t\t\t\tresultText = this._goalState.objective\n\t\t\t\t\t\t? `Goal ${this._goalState.status}: ${this._goalState.objective}`\n\t\t\t\t\t\t: \"No active goal.\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"autonomous\":\n\t\t\t\t\tawait this._handleAutonomousSlashCommand(input.text);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (resultText) {\n\t\t\t\tthis._appendDurableSessionCommandMessage(resultText, input.command, true, false, displayResult);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (error instanceof CompactionSkippedError) return;\n\t\t\tconst commandError = error instanceof Error ? error : new Error(String(error));\n\t\t\ttry {\n\t\t\t\tthis._appendDurableSessionCommandMessage(\n\t\t\t\t\t`Command failed: ${commandError.message}`,\n\t\t\t\t\tinput.command,\n\t\t\t\t\ttrue,\n\t\t\t\t\ttrue,\n\t\t\t\t);\n\t\t\t} catch {\n\t\t\t\t// The result row is also the command-correlated UI settle edge.\n\t\t\t\tconst message = createSessionSlashCommandResultMessage(`Command failed: ${commandError.message}`, {\n\t\t\t\t\tcommand: input.command,\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tseverity: \"error\",\n\t\t\t\t\terror: commandError.message,\n\t\t\t\t});\n\t\t\t\tthis._emit({ type: \"message_start\", message });\n\t\t\t\tthis._emit({ type: \"message_end\", message });\n\t\t\t}\n\t\t\tthrow commandError;\n\t\t}\n\t}\n\n\tprivate _appendDurableSessionCommandMessage(\n\t\tcontent: string,\n\t\tcommand: SessionSlashCommand,\n\t\tisResult: boolean,\n\t\tisError = false,\n\t\tdisplay = true,\n\t): void {\n\t\tconst message: CustomMessage = isResult\n\t\t\t? createSessionSlashCommandResultMessage(\n\t\t\t\t\tcontent,\n\t\t\t\t\t{\n\t\t\t\t\t\tcommand,\n\t\t\t\t\t\tsuccess: !isError,\n\t\t\t\t\t\tseverity: isError ? \"error\" : \"info\",\n\t\t\t\t\t\t...(isError ? { error: content.replace(/^Command failed:\\s*/, \"\") } : {}),\n\t\t\t\t\t},\n\t\t\t\t\tdisplay,\n\t\t\t\t)\n\t\t\t: createSessionSlashCommandMessage(command);\n\t\t// Persist before touching live state so a failed write cannot leave an\n\t\t// unsaved leaf that the next entry would silently parent onto.\n\t\tthis.sessionManager.appendCustomMessageEntryWithRollback(\n\t\t\tmessage.customType,\n\t\t\tmessage.content,\n\t\t\tmessage.display,\n\t\t\tmessage.details,\n\t\t);\n\t\tthis.agent.state.messages.push(message);\n\t\tthis._emit({ type: \"message_start\", message });\n\t\tthis._emit({ type: \"message_end\", message });\n\t}\n\n\tprivate _throwIfExtensionCommand(text: string): void {\n\t\tconst commandName = parseSlashCommand(text)?.name ?? \"\";\n\t\tconst command = this._extensionRunner.getCommand(commandName);\n\n\t\tif (command) {\n\t\t\tthrow new Error(\n\t\t\t\t`Extension command \"/${commandName}\" cannot be queued. Use prompt() or execute the command when not streaming.`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Send a custom message to the session. Creates a CustomMessageEntry.\n\t *\n\t * Handles three cases:\n\t * - Streaming: queues message, processed when loop pulls from queue\n\t * - Not streaming + triggerTurn: appends to state/session, starts new turn\n\t * - Not streaming + no trigger: appends to state/session, no turn\n\t *\n\t * @param message Custom message with customType, content, display, details\n\t * @param options.triggerTurn If true and not streaming, triggers a new LLM turn\n\t * @param options.deliverAs Delivery mode: \"steer\", \"followUp\", or \"nextTurn\"\n\t */\n\tasync sendCustomMessage<T = unknown>(\n\t\tmessage: Pick<CustomMessage<T>, \"customType\" | \"content\" | \"display\" | \"details\">,\n\t\toptions?: {\n\t\t\ttriggerTurn?: boolean;\n\t\t\tdeliverAs?: \"steer\" | \"followUp\" | \"nextTurn\";\n\t\t},\n\t): Promise<void> {\n\t\tconst appMessage = {\n\t\t\trole: \"custom\" as const,\n\t\t\tcustomType: message.customType,\n\t\t\tcontent: message.content,\n\t\t\tdisplay: message.display,\n\t\t\tdetails: message.details,\n\t\t\ttimestamp: Date.now(),\n\t\t} satisfies CustomMessage<T>;\n\t\tif (options?.deliverAs === \"nextTurn\") {\n\t\t\tthis._pendingNextTurnMessages.push(appMessage);\n\t\t} else if (this.isStreaming) {\n\t\t\tconst normalized = normalizeMessageContent(message.content);\n\t\t\tif (options?.deliverAs === \"followUp\") {\n\t\t\t\tawait this._queuePreparedPrompt(\"followUp\", normalized.text, normalized.images, {\n\t\t\t\t\tmessage: appMessage,\n\t\t\t\t\tresumeIfIdle: true,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tawait this._queuePreparedPrompt(\"steer\", normalized.text, normalized.images, {\n\t\t\t\t\tmessage: appMessage,\n\t\t\t\t\tresumeIfIdle: true,\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (options?.triggerTurn) {\n\t\t\tif (!this._sessionInputSuspendedForUpdateRestart) this._resumeSessionInputAdmission();\n\t\t\tconst admissionFence = await this._acquireDirectTurnAdmissionFence();\n\t\t\ttry {\n\t\t\t\tconst normalized = normalizeMessageContent(message.content);\n\t\t\t\tconst immediatelyEligible = this._canStartSessionActionImmediately();\n\t\t\t\tconst action = this._createPreparedTurnAction(\"followUp\", normalized.text, normalized.images, {\n\t\t\t\t\tmessage: appMessage,\n\t\t\t\t\tresumeIfIdle: true,\n\t\t\t\t\texecutionPolicy: this._turnExecutionPolicy(\"customTrigger\"),\n\t\t\t\t\tqueueVisible: false,\n\t\t\t\t});\n\t\t\t\tconst result = this._admitSessionInput(action, { immediatelyEligible });\n\t\t\t\tadmissionFence.release();\n\t\t\t\tif (!result.ticket) return;\n\t\t\t\tawait result.ticket.completed;\n\t\t\t} finally {\n\t\t\t\tadmissionFence.release();\n\t\t\t}\n\t\t} else {\n\t\t\tthis.agent.state.messages.push(appMessage);\n\t\t\tthis.sessionManager.appendCustomMessageEntry(\n\t\t\t\tmessage.customType,\n\t\t\t\tmessage.content,\n\t\t\t\tmessage.display,\n\t\t\t\tmessage.details,\n\t\t\t);\n\t\t\tthis._emit({ type: \"message_start\", message: appMessage });\n\t\t\tthis._emit({ type: \"message_end\", message: appMessage });\n\t\t}\n\t}\n\n\t/**\n\t * Send a user message to the agent. Always triggers a turn.\n\t * When the agent is streaming, use deliverAs to specify how to queue the message.\n\t *\n\t * @param content User message content (string or content array)\n\t * @param options.deliverAs Delivery mode when streaming: \"steer\" or \"followUp\"\n\t */\n\tasync sendUserMessage(\n\t\tcontent: string | (TextContent | ImageContent)[],\n\t\toptions?: { deliverAs?: \"steer\" | \"followUp\" },\n\t): Promise<void> {\n\t\tlet text: string;\n\t\tlet images: ImageContent[] | undefined;\n\n\t\tif (typeof content === \"string\") {\n\t\t\ttext = content;\n\t\t} else {\n\t\t\tconst textParts: string[] = [];\n\t\t\timages = [];\n\t\t\tfor (const part of content) {\n\t\t\t\tif (part.type === \"text\") {\n\t\t\t\t\ttextParts.push(part.text);\n\t\t\t\t} else {\n\t\t\t\t\timages.push(part);\n\t\t\t\t}\n\t\t\t}\n\t\t\ttext = textParts.join(\"\\n\");\n\t\t\tif (images.length === 0) images = undefined;\n\t\t}\n\n\t\tawait this._prompt(text, {\n\t\t\texpandPromptTemplates: false,\n\t\t\tstreamingBehavior: options?.deliverAs,\n\t\t\timages,\n\t\t\tsource: \"extension\",\n\t\t\tresumeIfIdle: true,\n\t\t});\n\t}\n\n\tclearQueue(): { steering: string[]; followUp: string[] } {\n\t\tconst clearable = this._actionStore\n\t\t\t.clearableActions()\n\t\t\t.filter((action) => action.payload.kind === \"session_command\" || action.payload.queueVisible);\n\t\tif (clearable.some((action) => action.payload.kind === \"turn\" && action.lifecycle.state === \"preparing\")) {\n\t\t\tthis._sessionInputPumpEpoch++;\n\t\t}\n\t\tconst steering = clearable\n\t\t\t.filter((action) => action.delivery === \"next_turn_boundary\")\n\t\t\t.map((action) => action.payload.text);\n\t\tconst followUp = clearable\n\t\t\t.filter((action) => action.delivery === \"when_run_idle\")\n\t\t\t.map((action) => action.payload.text);\n\t\tconst promptError = new Error(\"Queued prompt was cleared before delivery.\");\n\t\tconst agentMessageError = new Error(\"Queued agent message was cleared before delivery.\");\n\t\tfor (const action of clearable) {\n\t\t\tconst error =\n\t\t\t\taction.payload.kind === \"turn\" && action.lifecycle.state === \"preparing\" ? promptError : agentMessageError;\n\t\t\tthis._settleAgentMessage(action.agentMessageId, \"delivery\", error);\n\t\t\tthis._settleAgentMessage(action.agentMessageId, \"completion\", error);\n\t\t}\n\t\tconst clearableIds = new Set(clearable.map((action) => action.id));\n\t\tthis._cancelSessionActions((action) => clearableIds.has(action.id), agentMessageError);\n\t\tthis.agent.clearAllQueues();\n\t\tthis._emitQueueUpdate();\n\t\treturn { steering, followUp };\n\t}\n\n\tprivate _invalidateQueuedPromptPreparation(): void {\n\t\tfor (const action of this._actionStore.clearableActions()) {\n\t\t\tif (action.payload.kind === \"turn\") action.payload.prepared = undefined;\n\t\t}\n\t}\n\n\tclearQueuedAgentMessages(): { steering: string[]; followUp: string[] } {\n\t\tthis._agentMessageClearEpoch++;\n\t\treturn this.clearQueuedUserMessagesMatching(isAgentSessionMessagePrompt);\n\t}\n\n\tclearQueuedUserMessagesMatching(predicate: (text: string) => boolean): { steering: string[]; followUp: string[] } {\n\t\tconst ownedActions = this._actionStore.ownedActions();\n\t\tconst dispatchedTurnCount = ownedActions.filter(\n\t\t\t(action) =>\n\t\t\t\taction.payload.kind === \"turn\" &&\n\t\t\t\t(action.lifecycle.state === \"committing\" || action.lifecycle.state === \"running\"),\n\t\t).length;\n\t\tconst matching = ownedActions.filter(\n\t\t\t(action) =>\n\t\t\t\taction.payload.kind === \"turn\" &&\n\t\t\t\taction.agentMessageId !== undefined &&\n\t\t\t\tpredicate(action.payload.text) &&\n\t\t\t\t(action.lifecycle.state === \"queued\" ||\n\t\t\t\t\taction.lifecycle.state === \"selected\" ||\n\t\t\t\t\taction.lifecycle.state === \"preparing\" ||\n\t\t\t\t\t(action.lifecycle.state === \"committing\" &&\n\t\t\t\t\t\tdispatchedTurnCount === 1 &&\n\t\t\t\t\t\t!primaryDeliveryRecord(action).started)),\n\t\t);\n\t\tif (matching.length === 0) return { steering: [], followUp: [] };\n\t\tconst removedTexts = (delivery: DeliveryPolicy) =>\n\t\t\t[\n\t\t\t\t...matching.filter((action) => action.delivery === delivery && action.lifecycle.state === \"queued\"),\n\t\t\t\t...matching.filter((action) => action.delivery === delivery && action.lifecycle.state !== \"queued\"),\n\t\t\t].map((action) => action.payload.text);\n\t\tconst removedSteering = removedTexts(\"next_turn_boundary\");\n\t\tconst removedFollowUp = removedTexts(\"when_run_idle\");\n\t\tconst acceptedError = new Error(\"Accepted agent message was cleared before delivery.\");\n\t\tconst queuedError = new Error(\"Queued agent message was cleared before delivery.\");\n\t\tfor (const action of matching) {\n\t\t\tconst error =\n\t\t\t\taction.payload.kind === \"turn\" && action.payload.acceptedAgentMessage ? acceptedError : queuedError;\n\t\t\tthis._rejectAgentMessage(action.agentMessageId, error);\n\t\t}\n\t\tfor (const [accepted, error] of [\n\t\t\t[true, acceptedError],\n\t\t\t[false, queuedError],\n\t\t] as const) {\n\t\t\tconst ids = new Set(\n\t\t\t\tmatching\n\t\t\t\t\t.filter((action) => action.payload.kind === \"turn\" && action.payload.acceptedAgentMessage === accepted)\n\t\t\t\t\t.map((action) => action.id),\n\t\t\t);\n\t\t\tif (ids.size > 0) this._cancelSessionActions((action) => ids.has(action.id), error, matching);\n\t\t}\n\t\tif (\n\t\t\tmatching.some(\n\t\t\t\t(action) =>\n\t\t\t\t\taction.lifecycle.state === \"cancelled\" &&\n\t\t\t\t\taction.payload.kind === \"turn\" &&\n\t\t\t\t\taction.payload.captureRunMessages,\n\t\t\t)\n\t\t) {\n\t\t\tthis.agent.abort();\n\t\t}\n\t\tthis._emitQueueUpdate();\n\t\treturn { steering: removedSteering, followUp: removedFollowUp };\n\t}\n\n\t/**\n\t * Mutate a single visible queued message, addressed by its position in the same\n\t * projection the session-action snapshot publishes. expectedText must match the\n\t * item's current preview so clients never edit a shifted queue by accident.\n\t */\n\tmutateQueuedMessage(\n\t\tlane: QueuedMessageLane,\n\t\tindex: number,\n\t\texpectedText: string,\n\t\tmutation: QueuedMessageMutation,\n\t): QueuedMessageMutationStatus {\n\t\tconst policy = queuedMessageLaneDeliveryPolicy(lane);\n\t\tconst projection = visibleSessionActionProjection(this._actionStore.queuedActions(policy));\n\t\tconst item = projection[index];\n\t\tif (!item || queuedAgentMessagePreview(item) !== expectedText) return \"rejected\";\n\t\tif (mutation.type === \"delete\") {\n\t\t\tconst error = new Error(\"Queued prompt was deleted before delivery.\");\n\t\t\tthis._rejectAgentMessage(item.agentMessageId, error);\n\t\t\tthis._cancelSessionActions((candidate) => candidate === item, error);\n\t\t\tthis._emitQueueUpdate();\n\t\t\tthis.resumeQueuedWork();\n\t\t\treturn \"applied\";\n\t\t}\n\t\tif (mutation.type === \"move\") {\n\t\t\tconst neighbor = projection[index + mutation.direction];\n\t\t\tif (!neighbor) return \"rejected\";\n\t\t\tthis._actionStore.swapQueued(item, neighbor);\n\t\t\tthis._emitQueueUpdate();\n\t\t\treturn \"applied\";\n\t\t}\n\t\tif (\n\t\t\titem.payload.kind === \"turn\" &&\n\t\t\t(item.payload.acceptedAgentMessage ||\n\t\t\t\titem.payload.records.some((record) => record.role === \"primary\" && record.message.role !== \"user\"))\n\t\t) {\n\t\t\treturn \"rejected\";\n\t\t}\n\t\tconst images = mutation.images?.map((image) => ({ ...image }));\n\t\tif (item.payload.kind === \"session_command\") {\n\t\t\tconst command = parseSessionSlashCommand(mutation.text);\n\t\t\tif (!command) return \"invalid\";\n\t\t\titem.payload.text = mutation.text;\n\t\t\titem.payload.command = command;\n\t\t\tif (mutation.images !== undefined) item.payload.images = images?.length ? images : undefined;\n\t\t} else {\n\t\t\titem.payload.text = mutation.text;\n\t\t\tconst text = { type: \"text\" as const, text: mutation.text };\n\t\t\tif (mutation.images !== undefined) {\n\t\t\t\titem.payload.images = images?.length ? images : undefined;\n\t\t\t\titem.payload.content = [text, ...(images?.map((image) => ({ ...image })) ?? [])];\n\t\t\t} else if (item.payload.content) {\n\t\t\t\titem.payload.content = [text, ...item.payload.content.filter((block) => block.type !== \"text\")];\n\t\t\t}\n\t\t\titem.payload.preview = undefined;\n\t\t\titem.payload.prepared = undefined;\n\t\t\tfor (const record of item.payload.records) {\n\t\t\t\tif (record.role === \"primary\" && record.message.role === \"user\") {\n\t\t\t\t\trecord.message.content = item.payload.content?.map((block) => ({ ...block })) ?? mutation.text;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tconst targetPolicy = queuedMessageLaneDeliveryPolicy(mutation.lane);\n\t\tif (targetPolicy !== policy) {\n\t\t\titem.queueKey = undefined;\n\t\t\titem.wake = mutation.lane === \"steering\" ? \"on_lower_boundary\" : \"external_resume\";\n\t\t\tthis._actionStore.moveQueued(item, targetPolicy, this._actionStore.queuedActions(targetPolicy).length);\n\t\t}\n\t\tthis.resumeQueuedWork();\n\t\tthis._emitQueueUpdate();\n\t\treturn \"applied\";\n\t}\n\n\tget queuedActionCount(): number {\n\t\treturn visibleSessionActionProjection(this._actionStore.queuedActions()).length;\n\t}\n\n\tget unfinishedActionCount(): number {\n\t\treturn this._actionStore.unfinishedActions().length;\n\t}\n\n\tget isQueuedWorkSuspended(): boolean {\n\t\treturn this._sessionInputPumpSuspended;\n\t}\n\n\tget isSessionActive(): boolean {\n\t\treturn (\n\t\t\tthis.isStreaming ||\n\t\t\tthis.isCompacting ||\n\t\t\tthis.isRetrying ||\n\t\t\tthis.isBashRunning ||\n\t\t\tthis._refineInFlight !== undefined ||\n\t\t\tthis._branchSummaryOperation !== undefined ||\n\t\t\tthis._postCompactionContinuationSettlement !== undefined ||\n\t\t\tthis.unfinishedActionCount > 0\n\t\t);\n\t}\n\n\tgetSessionActionSnapshot(): SessionActionSnapshot {\n\t\tconst steering = visibleSessionActionProjection(this._actionStore.queuedActions(\"next_turn_boundary\")).map(\n\t\t\tqueuedAgentMessagePreview,\n\t\t);\n\t\tconst followUps = visibleSessionActionProjection(this._actionStore.queuedActions(\"when_run_idle\")).map(\n\t\t\tqueuedAgentMessagePreview,\n\t\t);\n\t\tconst active = visibleSessionActionProjection(this._actionStore.activeActions())[0];\n\t\tconst activeState = active?.lifecycle.state;\n\t\tconst phase =\n\t\t\tactiveState === \"selected\"\n\t\t\t\t? \"preparing\"\n\t\t\t\t: activeState === \"preparing\" || activeState === \"committing\" || activeState === \"running\"\n\t\t\t\t\t? activeState\n\t\t\t\t\t: undefined;\n\t\treturn {\n\t\t\tqueuedCount: steering.length + followUps.length,\n\t\t\tsteering,\n\t\t\tfollowUps,\n\t\t\t...(active && phase\n\t\t\t\t? {\n\t\t\t\t\t\tactive: {\n\t\t\t\t\t\t\tkind: active.payload.kind,\n\t\t\t\t\t\t\tphase,\n\t\t\t\t\t\t\tlabel: compactRlmText(active.payload.text),\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t};\n\t}\n\n\tgetSteeringMessages(): readonly string[] {\n\t\treturn visibleSessionActionProjection(this._actionStore.queuedActions(\"next_turn_boundary\")).map(\n\t\t\t(action) => action.payload.text,\n\t\t);\n\t}\n\n\tgetSteeringMessagePreviews(): readonly string[] {\n\t\treturn visibleSessionActionProjection(this._actionStore.queuedActions(\"next_turn_boundary\")).map(\n\t\t\tqueuedAgentMessagePreview,\n\t\t);\n\t}\n\n\tgetFollowUpMessages(): readonly string[] {\n\t\treturn visibleSessionActionProjection(this._actionStore.queuedActions(\"when_run_idle\")).map(\n\t\t\t(action) => action.payload.text,\n\t\t);\n\t}\n\n\tgetFollowUpMessagePreviews(): readonly string[] {\n\t\treturn visibleSessionActionProjection(this._actionStore.queuedActions(\"when_run_idle\")).map(\n\t\t\tqueuedAgentMessagePreview,\n\t\t);\n\t}\n\n\tgetSessionActionRecoverySnapshot(): SessionActionRecoverySnapshot {\n\t\treturn {\n\t\t\tformatVersion: SESSION_ACTION_RECOVERY_FORMAT_VERSION,\n\t\t\tactions: this._actionStore.snapshotActions().map((action) => ({\n\t\t\t\tid: action.id,\n\t\t\t\tsource: action.source,\n\t\t\t\tdelivery: action.delivery,\n\t\t\t\twake: action.wake,\n\t\t\t\t...(action.queueKey ? { queueKey: action.queueKey } : {}),\n\t\t\t\t...(action.agentMessageId ? { agentMessageId: action.agentMessageId } : {}),\n\t\t\t\t...(action.suppressAutonomousContinuation ? { suppressAutonomousContinuation: true } : {}),\n\t\t\t\tpayload:\n\t\t\t\t\taction.payload.kind === \"turn\"\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tkind: \"turn\",\n\t\t\t\t\t\t\t\ttext: action.payload.text,\n\t\t\t\t\t\t\t\t...(action.payload.preview ? { preview: action.payload.preview } : {}),\n\t\t\t\t\t\t\t\trecords: action.payload.records.map((record) => ({\n\t\t\t\t\t\t\t\t\tid: record.id,\n\t\t\t\t\t\t\t\t\trole: record.role,\n\t\t\t\t\t\t\t\t\tmessage: cloneQueuedAgentMessage(record.message),\n\t\t\t\t\t\t\t\t\townerActionId: record.ownerActionId,\n\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t...(action.payload.images\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\timages: action.payload.images.map((image) => ({\n\t\t\t\t\t\t\t\t\t\t\t\t...image,\n\t\t\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t\t...(action.payload.content\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\tcontent: action.payload.content.map((block) => ({\n\t\t\t\t\t\t\t\t\t\t\t\t...block,\n\t\t\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t\t...(action.payload.customMessage\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\tcustomMessage: cloneCustomMessage(action.payload.customMessage),\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t\texecutionPolicy: {\n\t\t\t\t\t\t\t\t\t...action.payload.executionPolicy,\n\t\t\t\t\t\t\t\t\tpreparation: {\n\t\t\t\t\t\t\t\t\t\t...action.payload.executionPolicy.preparation,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tqueueVisible: action.payload.queueVisible,\n\t\t\t\t\t\t\t\tacceptedAgentMessage: action.payload.acceptedAgentMessage,\n\t\t\t\t\t\t\t\tacceptedBeforeCompletion: action.payload.acceptedBeforeCompletion,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\tkind: \"session_command\",\n\t\t\t\t\t\t\t\ttext: action.payload.text,\n\t\t\t\t\t\t\t\tcommand: { ...action.payload.command },\n\t\t\t\t\t\t\t\t...(action.payload.images\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\timages: action.payload.images.map((image) => ({\n\t\t\t\t\t\t\t\t\t\t\t\t...image,\n\t\t\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t},\n\t\t\t})),\n\t\t};\n\t}\n\n\tprivate _notifySessionInputCheckpointChange(): void {\n\t\tconst waiters = [...this._sessionInputCheckpointWaiters];\n\t\tthis._sessionInputCheckpointWaiters.clear();\n\t\tfor (const resolve of waiters) resolve();\n\t}\n\n\tprivate _observeSessionActionDeferral(action: QueuedSessionAction): {\n\t\tdeferred: Promise<void>;\n\t\tstop(): void;\n\t} {\n\t\tlet resolveDeferral = () => {};\n\t\tconst deferred = new Promise<void>((resolve) => {\n\t\t\tresolveDeferral = resolve;\n\t\t});\n\t\tconst check = () => {\n\t\t\tif (action.lifecycle.state === \"queued\") resolveDeferral();\n\t\t\telse this._sessionInputCheckpointWaiters.add(check);\n\t\t};\n\t\tthis._sessionInputCheckpointWaiters.add(check);\n\t\treturn {\n\t\t\tdeferred,\n\t\t\tstop: () => this._sessionInputCheckpointWaiters.delete(check),\n\t\t};\n\t}\n\n\tasync waitForSessionInputCheckpoint(signal?: AbortSignal): Promise<void> {\n\t\tconst blocksCheckpoint = () =>\n\t\t\tthis._actionStore.activeActions().some((action) => {\n\t\t\t\tif (action.payload.kind === \"session_command\") {\n\t\t\t\t\treturn action.lifecycle.state === \"selected\" || action.lifecycle.state === \"running\";\n\t\t\t\t}\n\t\t\t\treturn (\n\t\t\t\t\taction.lifecycle.state === \"selected\" ||\n\t\t\t\t\taction.lifecycle.state === \"preparing\" ||\n\t\t\t\t\t(action.lifecycle.state === \"committing\" && !primaryDeliveryRecord(action).durable)\n\t\t\t\t);\n\t\t\t});\n\t\twhile (true) {\n\t\t\twhile (blocksCheckpoint()) {\n\t\t\t\tif (signal?.aborted) throw new Error(\"Update restart preparation cancelled\");\n\t\t\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\t\t\tconst onChange = () => {\n\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t};\n\t\t\t\t\tconst onAbort = () => {\n\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\treject(new Error(\"Update restart preparation cancelled\"));\n\t\t\t\t\t};\n\t\t\t\t\tconst cleanup = () => {\n\t\t\t\t\t\tthis._sessionInputCheckpointWaiters.delete(onChange);\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t};\n\t\t\t\t\tthis._sessionInputCheckpointWaiters.add(onChange);\n\t\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t\tif (signal?.aborted) onAbort();\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst commitFence = await this._acquireSessionActionCommitFence(signal);\n\t\t\ttry {\n\t\t\t\tif (blocksCheckpoint()) continue;\n\t\t\t\tif (signal?.aborted) throw new Error(\"Update restart preparation cancelled\");\n\t\t\t\tawait waitForPromiseOrAbort(this._agentEventQueue, signal, \"Update restart preparation cancelled\");\n\t\t\t\tif (signal?.aborted) throw new Error(\"Update restart preparation cancelled\");\n\t\t\t\tthis.sessionManager.flushNow();\n\t\t\t\treturn;\n\t\t\t} finally {\n\t\t\t\tcommitFence.release();\n\t\t\t}\n\t\t}\n\t}\n\n\tacquireSessionInputPause(): { release(): void } {\n\t\tconst token = Symbol(\"session-input-admission-pause\");\n\t\tthis._sessionInputAdmissionPauses.add(token);\n\t\tthis._sessionInputPumpRequested = false;\n\t\tthis._sessionInputPumpEpoch++;\n\t\tlet released = false;\n\t\treturn {\n\t\t\trelease: () => {\n\t\t\t\tif (released) return;\n\t\t\t\treleased = true;\n\t\t\t\tthis._sessionInputAdmissionPauses.delete(token);\n\t\t\t\tthis._sessionInputPumpEpoch++;\n\t\t\t\tthis._notifySessionInputCheckpointChange();\n\t\t\t\tthis._flushDeferredRlmTerminalNotices();\n\t\t\t\tthis._maybeResumeGoalContinuationAfterRlmWork();\n\t\t\t\tthis._scheduleSessionInputPump();\n\t\t\t},\n\t\t};\n\t}\n\n\tacquireQueuedWorkPause(): { release(): void } {\n\t\tconst token = Symbol(\"queued-work-pause\");\n\t\tthis._queuedWorkPauses.add(token);\n\t\tthis._sessionInputPumpRequested = false;\n\t\tthis._sessionInputPumpEpoch++;\n\t\tlet released = false;\n\t\treturn {\n\t\t\trelease: () => {\n\t\t\t\tif (released) return;\n\t\t\t\treleased = true;\n\t\t\t\tthis._queuedWorkPauses.delete(token);\n\t\t\t\tthis._notifySessionInputCheckpointChange();\n\t\t\t\tthis._flushDeferredRlmTerminalNotices();\n\t\t\t\tthis._scheduleSessionInputPump();\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate async _acquireDirectTurnAdmissionFence(signal?: AbortSignal): Promise<{ owner: symbol; release(): void }> {\n\t\tconst inheritedOwner = this._sessionActionCommitContext.getStore();\n\t\tif (inheritedOwner !== undefined && inheritedOwner === this._sessionActionCommitOwner) {\n\t\t\tthis._assertSessionActionAdmissionAvailable();\n\t\t\treturn this._acquireSessionActionCommitFence(signal);\n\t\t}\n\t\tconst disposeSignal = this._sessionActionCommitDisposeAbortController.signal;\n\t\tconst waitSignal = signal ? AbortSignal.any([signal, disposeSignal]) : disposeSignal;\n\t\twhile (true) {\n\t\t\tthis._assertSessionActionAdmissionAvailable();\n\t\t\tif (this._queuedWorkPauses.size > 0) {\n\t\t\t\tlet wake = () => {};\n\t\t\t\tconst pauseReleased = new Promise<void>((resolve) => {\n\t\t\t\t\twake = resolve;\n\t\t\t\t\tthis._sessionInputCheckpointWaiters.add(resolve);\n\t\t\t\t});\n\t\t\t\ttry {\n\t\t\t\t\tawait waitForPromiseOrAbort(pauseReleased, waitSignal, \"Update restart preparation cancelled\");\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (disposeSignal.aborted) {\n\t\t\t\t\t\tthrow new Error(\"Cannot admit a session action because the session is disposing or disposed.\");\n\t\t\t\t\t}\n\t\t\t\t\tthrow error;\n\t\t\t\t} finally {\n\t\t\t\t\tthis._sessionInputCheckpointWaiters.delete(wake);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst fence = await this._acquireSessionActionCommitFence(signal);\n\t\t\ttry {\n\t\t\t\tif (this._queuedWorkPauses.size === 0) {\n\t\t\t\t\tthis._assertSessionActionAdmissionAvailable();\n\t\t\t\t\treturn fence;\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tfence.release();\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tfence.release();\n\t\t}\n\t}\n\n\tprivate async _acquireSessionActionCommitFence(signal?: AbortSignal): Promise<{ owner: symbol; release(): void }> {\n\t\tconst inheritedOwner = this._sessionActionCommitContext.getStore();\n\t\tif (inheritedOwner !== undefined && inheritedOwner === this._sessionActionCommitOwner) {\n\t\t\treturn { owner: inheritedOwner, release: () => {} };\n\t\t}\n\t\tconst previous = this._sessionActionCommitTail;\n\t\tlet resolve = () => {};\n\t\tthis._sessionActionCommitTail = new Promise<void>((release) => {\n\t\t\tresolve = release;\n\t\t});\n\t\tconst disposeSignal = this._sessionActionCommitDisposeAbortController.signal;\n\t\tconst waitSignal = signal ? AbortSignal.any([signal, disposeSignal]) : disposeSignal;\n\t\tthis._pendingSessionActionFenceWaiters++;\n\t\ttry {\n\t\t\tawait waitForPromiseOrAbort(previous, waitSignal, \"Update restart preparation cancelled\");\n\t\t} catch (error) {\n\t\t\tthis._pendingSessionActionFenceWaiters--;\n\t\t\t// A cancelled waiter remains in the FIFO chain until its predecessor releases.\n\t\t\tvoid previous.then(resolve, resolve);\n\t\t\tif (disposeSignal.aborted) {\n\t\t\t\tthrow new Error(\"Cannot admit a session action because the session is disposing or disposed.\");\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tconst owner = Symbol(\"session-action-commit\");\n\t\tthis._sessionActionCommitOwner = owner;\n\t\tthis._pendingSessionActionFenceWaiters--;\n\t\tlet released = false;\n\t\treturn {\n\t\t\towner,\n\t\t\trelease: () => {\n\t\t\t\tif (released) return;\n\t\t\t\treleased = true;\n\t\t\t\tif (this._sessionActionCommitOwner === owner) this._sessionActionCommitOwner = undefined;\n\t\t\t\tresolve();\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate _resumeSessionInputAdmission(): void {\n\t\tif (!this._sessionInputPumpSuspended) return;\n\t\tthis._sessionInputPumpSuspended = false;\n\t\tthis._sessionInputSuspendedForUpdateRestart = false;\n\t\tthis._sessionInputPumpEpoch++;\n\t\tthis._notifySessionInputCheckpointChange();\n\t\tthis._flushDeferredRlmTerminalNotices();\n\t}\n\n\t/** Resume the scheduler after requestAbort/abortForUpdateRestart suspended it; owned pause leases are unaffected. */\n\tresumeQueuedWork(): boolean {\n\t\tthis._resumeSessionInputAdmission();\n\t\tthis._maybeResumeGoalContinuationAfterRlmWork();\n\t\tthis._scheduleSessionInputPump();\n\t\treturn this._hasSelectableSessionInput();\n\t}\n\n\tasync waitForSessionInputIdle(): Promise<void> {\n\t\twhile (true) {\n\t\t\tconst pump = this._sessionInputPump;\n\t\t\tawait pump;\n\t\t\tif (pump === this._sessionInputPump && !this._sessionInputPumpRequested) return;\n\t\t}\n\t}\n\n\tasync waitForIdle(): Promise<void> {\n\t\twhile (true) {\n\t\t\tif (this._actionStore.queuedActions().length > 0) {\n\t\t\t\tif (this._sessionInputPumpSuspended || this._queuedWorkPauses.size > 0) {\n\t\t\t\t\tawait new Promise<void>((resolve) => this._sessionInputCheckpointWaiters.add(resolve));\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthis._scheduleSessionInputPump();\n\t\t\t}\n\t\t\tconst pump = this._sessionInputPump;\n\t\t\tawait pump;\n\t\t\tawait this.agent.waitForIdle();\n\t\t\tconst agentEventQueue = this._agentEventQueue;\n\t\t\tawait agentEventQueue;\n\t\t\tif (\n\t\t\t\tpump === this._sessionInputPump &&\n\t\t\t\tagentEventQueue === this._agentEventQueue &&\n\t\t\t\t!this._sessionInputPumpRequested &&\n\t\t\t\t!this.agent.state.isStreaming &&\n\t\t\t\tthis.unfinishedActionCount === 0\n\t\t\t) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Waits out any owned post-compaction continuation and rejects when one cannot start; {@link waitForIdle} never rejects. */\n\tasync waitForHeadlessIdle(): Promise<void> {\n\t\twhile (true) {\n\t\t\tawait this.waitForIdle();\n\t\t\tconst postCompactionContinuation = this._postCompactionContinuationSettlement?.promise;\n\t\t\tif (!postCompactionContinuation) return;\n\t\t\tawait postCompactionContinuation;\n\t\t}\n\t}\n\n\tgetPendingNextTurnMessageSnapshots(): readonly CustomMessage[] {\n\t\tconst messages = this._pendingNextTurnMessages.map((message) => cloneCustomMessage(message));\n\t\tfor (const action of this._actionStore.unfinishedActions()) {\n\t\t\tif (\n\t\t\t\taction.payload.kind !== \"turn\" ||\n\t\t\t\t!action.payload.acceptedAgentMessage ||\n\t\t\t\t!primaryDeliveryRecord(action).started\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tmessages.push(\n\t\t\t\t...action.payload.records\n\t\t\t\t\t.filter(\n\t\t\t\t\t\t(record): record is DeliveryRecord & { message: CustomMessage } =>\n\t\t\t\t\t\t\t(record.role === \"next_turn\" || record.role === \"prefix\") &&\n\t\t\t\t\t\t\trecord.message.role === \"custom\" &&\n\t\t\t\t\t\t\t!record.durable,\n\t\t\t\t\t)\n\t\t\t\t\t.map((record) => cloneCustomMessage(record.message)),\n\t\t\t);\n\t\t}\n\t\treturn messages;\n\t}\n\n\trestorePendingNextTurnMessages(messages: readonly CustomMessage[]): void {\n\t\tthis._pendingNextTurnMessages.push(...messages.map((message) => cloneCustomMessage(message)));\n\t\tthis._flushDeferredRlmTerminalNotices();\n\t}\n\n\tremoveQueuedFollowUp(queueKey: string): boolean {\n\t\tconst matching = this._actionStore\n\t\t\t.clearableActions()\n\t\t\t.filter((action) => action.payload.kind === \"turn\" && action.queueKey === queueKey);\n\t\tif (matching.length === 0) return false;\n\t\tconst error = new Error(\"Queued agent message was cleared before delivery.\");\n\t\tfor (const action of matching) this._rejectAgentMessage(action.agentMessageId, error);\n\t\tconst ids = new Set(matching.map((action) => action.id));\n\t\tthis._cancelSessionActions((action) => ids.has(action.id), error);\n\t\tthis._emitQueueUpdate();\n\t\treturn true;\n\t}\n\n\tget resourceLoader(): ResourceLoader {\n\t\treturn this._resourceLoader;\n\t}\n\n\trequestAbort(): void {\n\t\tfor (const run of [...this._unsettledRlmChildRuns]) {\n\t\t\tif (run.status === \"cancelled\") this._abandonRlmRunForQuiescence(run);\n\t\t}\n\t\tfor (const controller of this._rlmQuiescenceWaitAborts) controller.abort();\n\t\tthis._sessionInputPumpRequested = false;\n\t\tthis._sessionInputPumpEpoch++;\n\t\tthis._sessionInputPumpSuspended = true;\n\t\tthis._sessionInputSuspendedForUpdateRestart = false;\n\t\tthis._demoteRlmTerminalNoticeActions();\n\t\tthis._cancelSessionActions(\n\t\t\t(action) =>\n\t\t\t\taction.payload.kind === \"turn\" &&\n\t\t\t\t!action.payload.queueVisible &&\n\t\t\t\t!this._durableRlmTerminalNoticeActionIds.has(action.id),\n\t\t\tnew Error(\"Prompt aborted before delivery.\"),\n\t\t);\n\t\tthis._cancelPostCompactionContinue();\n\t\tthis.abortRetry();\n\t\tthis.abortCompaction();\n\t\tthis.abortBranchSummary();\n\t\tthis.abortBash();\n\t\tthis._pendingRequestedRefine = undefined;\n\t\tthis._autoRefineBranchVersion++;\n\t\tthis._autoRefineReviewAbort?.abort();\n\t\tthis._refineAbortController?.abort();\n\t\tthis.agent.abort();\n\t}\n\n\tasync abort(): Promise<void> {\n\t\tconst compactionOperation = this._compactionOperation;\n\t\tconst branchSummaryOperation = this._branchSummaryOperation;\n\t\tthis.requestAbort();\n\t\tthis._cancelActiveRlmChildRuns(\"Parent session aborted\");\n\t\tthis._goalAbortInProgress = this._goalState.status === \"active\";\n\t\ttry {\n\t\t\tawait Promise.allSettled([\n\t\t\t\tthis.agent.waitForIdle(),\n\t\t\t\tthis._agentEventQueue,\n\t\t\t\t...(compactionOperation ? [compactionOperation] : []),\n\t\t\t\t...(branchSummaryOperation ? [branchSummaryOperation] : []),\n\t\t\t]);\n\t\t} finally {\n\t\t\tthis._goalAbortInProgress = false;\n\t\t}\n\t}\n\n\tabortForUpdateRestart(): void {\n\t\t// Cancel scheduled pumps and suspend new ones: queued inputs must survive\n\t\t// into the restart manifest instead of starting a turn during teardown.\n\t\tthis._sessionInputPumpRequested = false;\n\t\tthis._sessionInputPumpEpoch++;\n\t\tthis._sessionInputPumpSuspended = true;\n\t\tthis._sessionInputSuspendedForUpdateRestart = true;\n\t\tthis._cancelPostCompactionContinue();\n\t\tthis.abortRetry();\n\t\tfor (const controller of this._rlmQuiescenceWaitAborts) controller.abort();\n\t\tthis._cancelActiveRlmChildRuns(\"Parent session aborted for update restart\");\n\t\tthis._goalAbortInProgress = this._goalState.status === \"active\";\n\t\tthis.agent.abort();\n\t\tif (this._goalAbortInProgress) {\n\t\t\tvoid this.agent\n\t\t\t\t.waitForIdle()\n\t\t\t\t.then(() => this._agentEventQueue)\n\t\t\t\t.catch(() => undefined)\n\t\t\t\t.finally(() => {\n\t\t\t\t\tthis._goalAbortInProgress = false;\n\t\t\t\t});\n\t\t}\n\t}\n\n\tprivate async _emitModelSelect(\n\t\tnextModel: Model<any>,\n\t\tpreviousModel: Model<any> | undefined,\n\t\tsource: \"set\" | \"cycle\" | \"restore\",\n\t): Promise<void> {\n\t\tif (modelsAreEqual(previousModel, nextModel)) return;\n\t\tawait this._extensionRunner.emit({\n\t\t\ttype: \"model_select\",\n\t\t\tmodel: nextModel,\n\t\t\tpreviousModel,\n\t\t\tsource,\n\t\t});\n\t}\n\n\tprivate _queueModelSelectEmit(\n\t\tnextModel: Model<any>,\n\t\tpreviousModel: Model<any> | undefined,\n\t\tsource: \"set\" | \"cycle\" | \"restore\",\n\t): Promise<void> {\n\t\tconst emit = () =>\n\t\t\tthis._modelSelectEmitContext.run(true, () => this._emitModelSelect(nextModel, previousModel, source));\n\t\tthis._modelSelectEmitQueueIdle = false;\n\t\tconst promise = this._modelSelectEmitQueue.then(emit, emit);\n\t\tconst queued = promise.catch(() => {});\n\t\tthis._modelSelectEmitQueue = queued;\n\t\tvoid queued.finally(() => {\n\t\t\tif (this._modelSelectEmitQueue === queued) {\n\t\t\t\tthis._modelSelectEmitQueueIdle = true;\n\t\t\t}\n\t\t});\n\t\treturn promise;\n\t}\n\n\tasync setModel(model: Model<any>, options: ModelSelectOptions = {}): Promise<void> {\n\t\tif (!this._modelRegistry.hasConfiguredAuth(model)) {\n\t\t\tthrow new Error(`No API key for ${model.provider}/${model.id}`);\n\t\t}\n\t\tif (!(await this._modelRegistry.canUseModel(model))) {\n\t\t\tthrow new Error(`Model \"${model.provider}/${model.id}\" is not available for the current Prime team.`);\n\t\t}\n\n\t\tconst previousModel = this.model;\n\t\tconst thinkingLevel = this._getThinkingLevelForModelSwitch();\n\t\tconst serviceTier = this._getServiceTierForModelSwitch();\n\t\tthis.agent.state.model = model;\n\t\tthis.sessionManager.appendModelChange(model.provider, model.id);\n\t\tthis.settingsManager.setDefaultModelAndProvider(model.provider, model.id);\n\n\t\tthis.setThinkingLevel(thinkingLevel);\n\t\tthis._clampServiceTierForModel(serviceTier);\n\n\t\tconst emitPromise = this._queueModelSelectEmit(model, previousModel, \"set\");\n\t\tif (this._shouldWaitForModelSelectEmit(options)) {\n\t\t\tawait emitPromise;\n\t\t} else {\n\t\t\tthis._trackModelSelectEmitError(emitPromise);\n\t\t}\n\t}\n\n\tprivate _trackModelSelectEmitError(emitPromise: Promise<void>): void {\n\t\tvoid emitPromise.catch((error) => {\n\t\t\tthis._extensionRunner.emitError({\n\t\t\t\textensionPath: \"<internal>\",\n\t\t\t\tevent: \"model_select\",\n\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate _shouldWaitForModelSelectEmit(options: ModelSelectOptions): boolean {\n\t\treturn options.waitForExtensions !== false && !this._modelSelectEmitContext.getStore();\n\t}\n\n\tprivate _pendingModelSelectEmit(): Promise<void> | undefined {\n\t\tif (!this._modelSelectEmitContext.getStore() && !this._modelSelectEmitQueueIdle) {\n\t\t\treturn this._modelSelectEmitQueue;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tasync cycleModel(\n\t\tdirection: \"forward\" | \"backward\" = \"forward\",\n\t\toptions: ModelSelectOptions = {},\n\t): Promise<ModelCycleResult | undefined> {\n\t\tif (this._scopedModels.length > 0) {\n\t\t\treturn this._cycleScopedModel(direction, options);\n\t\t}\n\t\treturn this._cycleAvailableModel(direction, options);\n\t}\n\n\tprivate async _cycleScopedModel(\n\t\tdirection: \"forward\" | \"backward\",\n\t\toptions: ModelSelectOptions,\n\t): Promise<ModelCycleResult | undefined> {\n\t\tconst availableModels = await this._modelRegistry.refreshAvailableModels();\n\t\tconst scopedModels = this._scopedModels.filter((scoped) =>\n\t\t\tavailableModels.some((model) => modelsAreEqual(model, scoped.model)),\n\t\t);\n\t\tif (scopedModels.length <= 1) return undefined;\n\n\t\tconst currentModel = this.model;\n\t\tlet currentIndex = scopedModels.findIndex((sm) => modelsAreEqual(sm.model, currentModel));\n\n\t\tif (currentIndex === -1) currentIndex = 0;\n\t\tconst len = scopedModels.length;\n\t\tconst nextIndex = direction === \"forward\" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;\n\t\tconst next = scopedModels[nextIndex];\n\t\tconst thinkingLevel = this._getThinkingLevelForModelSwitch(next.thinkingLevel);\n\t\tconst serviceTier = this._getServiceTierForModelSwitch();\n\n\t\tthis.agent.state.model = next.model;\n\t\tthis.sessionManager.appendModelChange(next.model.provider, next.model.id);\n\t\tthis.settingsManager.setDefaultModelAndProvider(next.model.provider, next.model.id);\n\n\t\tthis.setThinkingLevel(thinkingLevel);\n\t\tthis._clampServiceTierForModel(serviceTier);\n\n\t\tconst emitPromise = this._queueModelSelectEmit(next.model, currentModel, \"cycle\");\n\t\tif (this._shouldWaitForModelSelectEmit(options)) {\n\t\t\tawait emitPromise;\n\t\t} else {\n\t\t\tthis._trackModelSelectEmitError(emitPromise);\n\t\t}\n\n\t\treturn {\n\t\t\tmodel: next.model,\n\t\t\tthinkingLevel: this.thinkingLevel,\n\t\t\tserviceTier: this.serviceTier,\n\t\t\tisScoped: true,\n\t\t};\n\t}\n\n\tprivate async _cycleAvailableModel(\n\t\tdirection: \"forward\" | \"backward\",\n\t\toptions: ModelSelectOptions,\n\t): Promise<ModelCycleResult | undefined> {\n\t\tconst availableModels = await this._modelRegistry.refreshAvailableModels();\n\t\tif (availableModels.length <= 1) return undefined;\n\n\t\tconst currentModel = this.model;\n\t\tlet currentIndex = availableModels.findIndex((m) => modelsAreEqual(m, currentModel));\n\n\t\tif (currentIndex === -1) currentIndex = 0;\n\t\tconst len = availableModels.length;\n\t\tconst nextIndex = direction === \"forward\" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;\n\t\tconst nextModel = availableModels[nextIndex];\n\n\t\tconst thinkingLevel = this._getThinkingLevelForModelSwitch();\n\t\tconst serviceTier = this._getServiceTierForModelSwitch();\n\t\tthis.agent.state.model = nextModel;\n\t\tthis.sessionManager.appendModelChange(nextModel.provider, nextModel.id);\n\t\tthis.settingsManager.setDefaultModelAndProvider(nextModel.provider, nextModel.id);\n\n\t\tthis.setThinkingLevel(thinkingLevel);\n\t\tthis._clampServiceTierForModel(serviceTier);\n\n\t\tconst emitPromise = this._queueModelSelectEmit(nextModel, currentModel, \"cycle\");\n\t\tif (this._shouldWaitForModelSelectEmit(options)) {\n\t\t\tawait emitPromise;\n\t\t} else {\n\t\t\tthis._trackModelSelectEmitError(emitPromise);\n\t\t}\n\n\t\treturn {\n\t\t\tmodel: nextModel,\n\t\t\tthinkingLevel: this.thinkingLevel,\n\t\t\tserviceTier: this.serviceTier,\n\t\t\tisScoped: false,\n\t\t};\n\t}\n\n\tsetThinkingLevel(level: ThinkingLevel): void {\n\t\tconst availableLevels = this.getAvailableThinkingLevels();\n\t\tconst effectiveLevel = availableLevels.includes(level) ? level : this._clampThinkingLevel(level, availableLevels);\n\n\t\tconst previousLevel = this.agent.state.thinkingLevel;\n\t\tconst isChanging = effectiveLevel !== previousLevel;\n\n\t\tthis.agent.state.thinkingLevel = effectiveLevel;\n\n\t\tif (isChanging) {\n\t\t\tthis.sessionManager.appendThinkingLevelChange(effectiveLevel);\n\t\t\tif (this.supportsThinking() || effectiveLevel !== \"off\") {\n\t\t\t\tthis.settingsManager.setDefaultThinkingLevel(effectiveLevel);\n\t\t\t}\n\t\t\tthis._emit({ type: \"thinking_level_changed\", level: effectiveLevel });\n\t\t\tvoid this._extensionRunner.emit({\n\t\t\t\ttype: \"thinking_level_select\",\n\t\t\t\tlevel: effectiveLevel,\n\t\t\t\tpreviousLevel,\n\t\t\t});\n\t\t}\n\t}\n\n\tsetServiceTier(serviceTier: ServiceTier): void {\n\t\tconst effectiveServiceTier = this._getEffectiveServiceTier(serviceTier);\n\t\tconst preferenceChanged = effectiveServiceTier !== this._serviceTierPreference;\n\t\tconst effectiveTierChanged = effectiveServiceTier !== this.agent.state.serviceTier;\n\t\tif (!preferenceChanged && !effectiveTierChanged) {\n\t\t\treturn;\n\t\t}\n\t\tthis._serviceTierPreference = effectiveServiceTier;\n\t\tif (preferenceChanged) {\n\t\t\tthis.sessionManager.appendServiceTierChange(effectiveServiceTier);\n\t\t\tif (this.model && supportsFastMode(this.model)) {\n\t\t\t\tthis.settingsManager.setDefaultServiceTier(effectiveServiceTier);\n\t\t\t}\n\t\t}\n\t\tif (effectiveTierChanged) {\n\t\t\tthis.agent.state.serviceTier = effectiveServiceTier;\n\t\t\tthis._emit({\n\t\t\t\ttype: \"service_tier_changed\",\n\t\t\t\tserviceTier: effectiveServiceTier,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate _getEffectiveServiceTier(serviceTier: ServiceTier): ServiceTier {\n\t\treturn serviceTier === \"priority\" && (!this.model || !supportsFastMode(this.model)) ? \"default\" : serviceTier;\n\t}\n\n\tprivate _getServiceTierForModelSwitch(): ServiceTier {\n\t\treturn this._serviceTierPreference;\n\t}\n\n\tprivate _clampServiceTierForModel(serviceTier: ServiceTier = this.serviceTier): void {\n\t\tconst effectiveServiceTier = this._getEffectiveServiceTier(serviceTier);\n\t\tif (effectiveServiceTier === this.agent.state.serviceTier) {\n\t\t\treturn;\n\t\t}\n\t\tthis.agent.state.serviceTier = effectiveServiceTier;\n\t\tthis._emit({\n\t\t\ttype: \"service_tier_changed\",\n\t\t\tserviceTier: effectiveServiceTier,\n\t\t});\n\t}\n\n\tcycleThinkingLevel(): ThinkingLevel | undefined {\n\t\tif (!this.supportsThinking()) return undefined;\n\n\t\tconst levels = this.getAvailableThinkingLevels();\n\t\tconst currentIndex = levels.indexOf(this.thinkingLevel);\n\t\tconst nextIndex = (currentIndex + 1) % levels.length;\n\t\tconst nextLevel = levels[nextIndex];\n\n\t\tthis.setThinkingLevel(nextLevel);\n\t\treturn nextLevel;\n\t}\n\n\tgetAvailableThinkingLevels(): ThinkingLevel[] {\n\t\tif (!this.model) return THINKING_LEVELS;\n\t\treturn getSupportedThinkingLevels(this.model) as ThinkingLevel[];\n\t}\n\n\tsupportsThinking(): boolean {\n\t\treturn !!this.model?.reasoning;\n\t}\n\n\tprivate _getThinkingLevelForModelSwitch(explicitLevel?: ThinkingLevel): ThinkingLevel {\n\t\tif (explicitLevel !== undefined) {\n\t\t\treturn explicitLevel;\n\t\t}\n\t\tif (!this.supportsThinking()) {\n\t\t\treturn this.settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;\n\t\t}\n\t\treturn this.thinkingLevel;\n\t}\n\n\tprivate _clampThinkingLevel(level: ThinkingLevel, _availableLevels: ThinkingLevel[]): ThinkingLevel {\n\t\treturn this.model ? (clampThinkingLevel(this.model, level) as ThinkingLevel) : \"off\";\n\t}\n\n\tprivate async _syncKernelStateAfterCompaction(): Promise<void> {\n\t\tconst provisioner = this._ipythonKernelProvisioner;\n\t\tif (!provisioner?.hasRunningKernel) return;\n\t\tconst pruned = await provisioner.pruneOversizedVariables().catch(() => null);\n\t\tconst abort = new AbortController();\n\t\tconst timer = setTimeout(() => abort.abort(), KERNEL_STATE_LISTING_TIMEOUT_MS);\n\t\tif (typeof timer === \"object\" && \"unref\" in timer) timer.unref();\n\t\tlet names: string[] | null;\n\t\ttry {\n\t\t\tnames = await provisioner.listNamespaceNames(abort.signal).catch(() => null);\n\t\t} finally {\n\t\t\tclearTimeout(timer);\n\t\t}\n\t\tif (names === null && !provisioner.hasRunningKernel) return;\n\t\tconst detail =\n\t\t\tnames === null\n\t\t\t\t? \"\"\n\t\t\t\t: names.length > 0\n\t\t\t\t\t? ` These names are still defined: ${names.join(\", \")}.`\n\t\t\t\t\t: \" You have not defined any names yet.\";\n\t\tconst prunedDetail =\n\t\t\tpruned && pruned.length > 0\n\t\t\t\t? ` Variables above the per-variable snapshot limit were removed: ${pruned.join(\", \")}.`\n\t\t\t\t: \"\";\n\t\tconst content = [\n\t\t\t\"<ipython_state>\",\n\t\t\t`Your Python kernel persisted through compaction; its remaining variables, imports, and helpers are still available.${prunedDetail}${detail}`,\n\t\t\t\"</ipython_state>\",\n\t\t].join(\"\\n\");\n\t\tconst message = {\n\t\t\trole: \"custom\" as const,\n\t\t\tcustomType: \"ipython_state\",\n\t\t\tcontent,\n\t\t\tdisplay: false,\n\t\t\ttimestamp: Date.now(),\n\t\t} satisfies CustomMessage;\n\t\tconst messages = this.agent.state.messages;\n\t\tconst last = messages[messages.length - 1];\n\t\tconst insertBeforeError = last?.role === \"assistant\" && (last as AssistantMessage).stopReason === \"error\";\n\t\tif (insertBeforeError) {\n\t\t\tmessages.splice(messages.length - 1, 0, message);\n\t\t} else {\n\t\t\tmessages.push(message);\n\t\t}\n\t\tthis.sessionManager.appendCustomMessageEntry(message.customType, message.content, message.display, undefined);\n\t\tthis._emit({ type: \"message_start\", message });\n\t\tthis._emit({ type: \"message_end\", message });\n\t}\n\n\tprivate _onIpythonStateRestored(result: RestoreResult): void {\n\t\tconst lines = [\"<ipython_state_restored>\"];\n\t\tif (result.restored.length > 0) {\n\t\t\tlines.push(\n\t\t\t\t`Your Python kernel state was revived from your previous session. These names are available again: ${result.restored.join(\", \")}.`,\n\t\t\t);\n\t\t} else {\n\t\t\tlines.push(\n\t\t\t\t\"Your previous Python kernel state could not be revived; the kernel is starting fresh, so re-create any variables, imports, or loaded data you need.\",\n\t\t\t);\n\t\t}\n\t\tif (result.failed.length > 0) {\n\t\t\tlines.push(\n\t\t\t\t`These could not be restored and must be recreated if needed: ${result.failed.map((f) => f.name).join(\", \")}.`,\n\t\t\t);\n\t\t}\n\t\tlines.push(\"</ipython_state_restored>\");\n\t\tvoid this.sendCustomMessage(\n\t\t\t{\n\t\t\t\tcustomType: IPYTHON_STATE_RESTORED_CUSTOM_TYPE,\n\t\t\t\tcontent: lines.join(\"\\n\"),\n\t\t\t\tdisplay: true,\n\t\t\t\tdetails: { restored: result.restored.length > 0 },\n\t\t\t},\n\t\t\t{ deliverAs: \"nextTurn\" },\n\t\t).catch(() => {});\n\t}\n\n\tsetSteeringMode(mode: \"all\" | \"one-at-a-time\"): void {\n\t\tthis.agent.steeringMode = mode;\n\t\tthis.settingsManager.setSteeringMode(mode);\n\t}\n\n\tsetFollowUpMode(mode: \"all\" | \"one-at-a-time\"): void {\n\t\tthis.agent.followUpMode = mode;\n\t\tthis.settingsManager.setFollowUpMode(mode);\n\t}\n\n\tasync compact(customInstructions?: string, options: { skipAbort?: boolean } = {}): Promise<CompactionResult> {\n\t\tif (options.skipAbort && this.isStreaming) {\n\t\t\tthrow new Error(\"Cannot compact without aborting while the agent is running.\");\n\t\t}\n\t\tconst hadPostCompactionContinue = this._postCompactionContinuationScheduled;\n\t\tthis._disconnectFromAgent();\n\t\tif (!options.skipAbort) await this.abort();\n\t\tlet didCompact = false;\n\t\tthis._compactionAbortController = new AbortController();\n\t\tlet resolveCompactionOperation: () => void = () => {};\n\t\tconst compactionOperation = new Promise<void>((resolve) => {\n\t\t\tresolveCompactionOperation = resolve;\n\t\t});\n\t\tthis._compactionOperation = compactionOperation;\n\t\tthis._emit({\n\t\t\ttype: \"compaction_start\",\n\t\t\treason: \"manual\",\n\t\t\tcustomInstructions,\n\t\t});\n\n\t\ttry {\n\t\t\tif (!this.model) {\n\t\t\t\tthrow new Error(formatNoModelSelectedMessage());\n\t\t\t}\n\n\t\t\tconst { apiKey, headers } = await this._getRequiredRequestAuth(this.model);\n\t\t\tconst result = await this._performCompaction({\n\t\t\t\tmodel: this.model,\n\t\t\t\tapiKey,\n\t\t\t\theaders,\n\t\t\t\tcustomInstructions,\n\t\t\t\tsignal: this._compactionAbortController.signal,\n\t\t\t});\n\n\t\t\tthis._emit({\n\t\t\t\ttype: \"compaction_end\",\n\t\t\t\treason: \"manual\",\n\t\t\t\tresult,\n\t\t\t\taborted: false,\n\t\t\t\twillRetry: false,\n\t\t\t\tcustomInstructions,\n\t\t\t});\n\t\t\tdidCompact = true;\n\t\t\t// A manual compaction satisfies any pending model request; on failure the\n\t\t\t// request stays scheduled for the next turn boundary.\n\t\t\tthis._pendingRequestedCompaction = undefined;\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tconst aborted = message === \"Compaction cancelled\" || (error instanceof Error && error.name === \"AbortError\");\n\t\t\tconst skipped = error instanceof CompactionSkippedError;\n\t\t\tthis._emit({\n\t\t\t\ttype: \"compaction_end\",\n\t\t\t\treason: \"manual\",\n\t\t\t\tresult: undefined,\n\t\t\t\taborted,\n\t\t\t\twillRetry: false,\n\t\t\t\terrorMessage: aborted ? undefined : skipped ? message : `Compaction failed: ${message}`,\n\t\t\t\terrorSeverity: skipped ? \"warning\" : \"error\",\n\t\t\t\tcustomInstructions,\n\t\t\t});\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tthis._compactionAbortController = undefined;\n\t\t\tthis._reconnectToAgent();\n\t\t\tif (this._compactionOperation === compactionOperation) {\n\t\t\t\tthis._compactionOperation = undefined;\n\t\t\t}\n\t\t\tresolveCompactionOperation();\n\t\t\tthis._scheduleSessionInputPump();\n\t\t\tif (didCompact) {\n\t\t\t\tthis._discardPendingAutoRefine({ cancelPostCompactionContinue: true });\n\t\t\t\tif (hadPostCompactionContinue) {\n\t\t\t\t\tthis._schedulePostCompactionContinue();\n\t\t\t\t}\n\t\t\t\t// Queued agent or session-owned inputs resume the loop; defer refine\n\t\t\t\t// behind them instead of interleaving it before their turns.\n\t\t\t\tthis._scheduleAutoRefineAfterCompaction(\n\t\t\t\t\thadPostCompactionContinue || this.agent.hasQueuedMessages() || this.unfinishedActionCount > 0,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Shared compaction core behind /compact, auto-compaction, and the compact\n\t * skill. Throws CompactionSkippedError when there is nothing to compact and\n\t * Error(\"Compaction cancelled\") on abort or extension cancel.\n\t */\n\tprivate async _performCompaction(options: {\n\t\tmodel: Model<any>;\n\t\tapiKey: string;\n\t\theaders?: Record<string, string>;\n\t\tcustomInstructions?: string;\n\t\tsignal: AbortSignal;\n\t}): Promise<CompactionResult> {\n\t\tconst { model, apiKey, headers, customInstructions, signal } = options;\n\t\tconst pathEntries = this.sessionManager.getBranch();\n\t\tconst settings = this.settingsManager.getCompactionSettings();\n\n\t\tconst preparation = prepareCompaction(pathEntries, settings);\n\t\tif (!preparation) {\n\t\t\tconst lastEntry = pathEntries[pathEntries.length - 1];\n\t\t\tif (lastEntry?.type === \"compaction\") {\n\t\t\t\tthrow new CompactionSkippedError(\"Already compacted\");\n\t\t\t}\n\t\t\tthrow new CompactionSkippedError(\"Session is too short to compact — try again once it grows\");\n\t\t}\n\n\t\tlet extensionCompaction: CompactionResult | undefined;\n\t\tlet fromExtension = false;\n\n\t\tif (this._extensionRunner.hasHandlers(\"session_before_compact\")) {\n\t\t\tconst result = (await this._extensionRunner.emit({\n\t\t\t\ttype: \"session_before_compact\",\n\t\t\t\tpreparation,\n\t\t\t\tbranchEntries: pathEntries,\n\t\t\t\tcustomInstructions,\n\t\t\t\tsignal,\n\t\t\t})) as SessionBeforeCompactResult | undefined;\n\n\t\t\tif (result?.cancel) {\n\t\t\t\tthrow new Error(\"Compaction cancelled\");\n\t\t\t}\n\n\t\t\tif (result?.compaction) {\n\t\t\t\textensionCompaction = result.compaction;\n\t\t\t\tfromExtension = true;\n\t\t\t}\n\t\t}\n\n\t\tconst { summary, firstKeptEntryId, tokensBefore, details } =\n\t\t\textensionCompaction ??\n\t\t\t(await compact(preparation, model, apiKey, headers, customInstructions, signal, this.thinkingLevel));\n\n\t\tif (signal.aborted) {\n\t\t\tthrow new Error(\"Compaction cancelled\");\n\t\t}\n\n\t\tthis.sessionManager.appendCompaction(\n\t\t\tsummary,\n\t\t\tfirstKeptEntryId,\n\t\t\ttokensBefore,\n\t\t\tdetails,\n\t\t\tfromExtension,\n\t\t\tcustomInstructions,\n\t\t);\n\t\tconst newEntries = this.sessionManager.getEntries();\n\t\tthis.agent.state.messages = this.sessionManager.buildSessionContext().messages;\n\t\tthis._mergeUnpersistedOutcomes(this.agent.state.messages);\n\t\tthis._restoreLateIpythonSentAgentMessages();\n\n\t\tconst savedCompactionEntry = newEntries.find((e) => e.type === \"compaction\" && e.summary === summary) as\n\t\t\t| CompactionEntry\n\t\t\t| undefined;\n\t\tif (savedCompactionEntry) {\n\t\t\tawait this._extensionRunner.emit({\n\t\t\t\ttype: \"session_compact\",\n\t\t\t\tcompactionEntry: savedCompactionEntry,\n\t\t\t\tfromExtension,\n\t\t\t});\n\t\t}\n\t\tawait this._syncKernelStateAfterCompaction();\n\t\tawait this._reapDeletedRlmSubagentRuntimesAfterCompaction();\n\n\t\treturn { summary, firstKeptEntryId, tokensBefore, details };\n\t}\n\n\tprivate async _reapDeletedRlmSubagentRuntimesAfterCompaction(): Promise<void> {\n\t\tconst childIds = [...this._rlmChildCleanupFailures.keys()].filter(\n\t\t\t(childId) => !this._activeRlmChildRuns.get(childId)?.detachedDeletion,\n\t\t);\n\t\tawait Promise.allSettled(childIds.map((childId) => this.deleteRlmSubagent(childId)));\n\t}\n\n\tabortCompaction(): void {\n\t\tthis._compactionAbortController?.abort();\n\t\tthis._autoCompactionAbortController?.abort();\n\t}\n\n\tprivate _localHarnessStateDir(): string | undefined {\n\t\treturn (\n\t\t\tgetLocalHarnessStateDir(this.sessionManager.getSessionArtifactDir()) ??\n\t\t\t(this._rlmSessionDir ? getLocalHarnessStateDir(this._rlmSessionDir) : undefined)\n\t\t);\n\t}\n\n\tprivate _autoRefineAllowedForSession(): boolean {\n\t\treturn this._rlmDepth === 0 && this._localHarnessStateDir() !== undefined;\n\t}\n\n\tprivate _settlePostCompactionContinue(error?: Error): void {\n\t\tif (!error && (this._postCompactionContinuationScheduled || this._postCompactionContinuationTimer)) return;\n\t\tconst settlement = this._postCompactionContinuationSettlement;\n\t\tif (!settlement || settlement.settled) return;\n\t\tsettlement.settled = true;\n\t\tthis._postCompactionContinuationSettlement = undefined;\n\t\tif (error) settlement.reject(error);\n\t\telse settlement.resolve();\n\t}\n\n\tprivate _cancelPostCompactionContinue(): void {\n\t\tif (this._postCompactionContinuationTimer) {\n\t\t\tclearTimeout(this._postCompactionContinuationTimer);\n\t\t\tthis._postCompactionContinuationTimer = undefined;\n\t\t}\n\t\tthis._postCompactionContinuationScheduled = false;\n\t\tthis._scheduledPostCompactionContinuationMessages = [];\n\t\tthis._settlePostCompactionContinue();\n\t}\n\n\tprivate _discardPendingAutoRefine(options: { cancelPostCompactionContinue?: boolean } = {}): void {\n\t\tthis._compactAutoRefinePending = false;\n\t\tthis._turnIntervalAutoRefinePending = false;\n\t\tthis._pendingAutoRefineReview = undefined;\n\t\tif (options.cancelPostCompactionContinue) {\n\t\t\tthis._cancelPostCompactionContinue();\n\t\t}\n\t}\n\n\tprivate async _invalidatePendingAutoRefineForBranchChange(): Promise<void> {\n\t\tthis._autoRefineReviewAbort?.abort();\n\t\tthis._discardPendingAutoRefine({ cancelPostCompactionContinue: true });\n\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t// Increment branch version BEFORE aborting/awaiting the serialized plan.\n\t\t// This invalidates the plan's branchVersion check at the boundary\n\t\t// so even if the plan completes, the boundary will reject it\n\t\t// (bgResult.branchVersion !== this._autoRefineBranchVersion).\n\t\tthis._autoRefineBranchVersion++;\n\t\t// Abort the in-flight refine/bplan controller so any pending\n\t\t// _planRefine or _reviewAutoRefine call settles via signal abort\n\t\t// rather than hanging forever.\n\t\tthis._refineAbortController?.abort();\n\t\tif (this._serializedPlanInFlight) {\n\t\t\tawait this._consumeSerializedBackgroundPlan(async () => false);\n\t\t}\n\t\twhile (this._refinePlanInFlight) {\n\t\t\tawait this._refinePlanInFlight;\n\t\t}\n\t\tawait this._waitForRefineIdle();\n\t}\n\n\t/**\n\t * Consume a refine request that was scheduled by the agent-callable refine\n\t * skill (refine.run). Fire-and-forget: the refine() method handles its own\n\t * background planning, idle wait, application, and error recovery. Called\n\t * at the turn boundary after compaction checks and before auto-refine\n\t * scheduling so the manual request takes priority.\n\t */\n\tprivate _emitRefineFailed(error: unknown): void {\n\t\tthis._emit({\n\t\t\ttype: \"refine_failed\",\n\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t});\n\t}\n\n\tprivate _consumePendingRequestedRefine(): boolean {\n\t\tconst pending = this._pendingRequestedRefine;\n\t\tif (!pending) return false;\n\t\tthis._pendingRequestedRefine = undefined;\n\t\tvoid this.refine(pending).catch((error) => this._emitRefineFailed(error));\n\t\treturn true;\n\t}\n\n\tprivate _scheduleAutoRefineAfterAgentEnd(): void {\n\t\tif (!this._autoRefineAllowedForSession()) {\n\t\t\treturn;\n\t\t}\n\t\tif (this._pendingAutoRefineReview) {\n\t\t\tthis._scheduleAutoRefine(this._pendingAutoRefineReview.reason);\n\t\t\treturn;\n\t\t}\n\t\tif (this._compactAutoRefinePending) {\n\t\t\tif (this._postCompactionContinuationScheduled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._scheduleAutoRefine(\"compact\");\n\t\t\treturn;\n\t\t}\n\n\t\tthis._scheduleAutoRefine(\"turn_interval\");\n\t}\n\n\tprivate _scheduleAutoRefineAfterCompaction(willContinueAfterCompaction: boolean): void {\n\t\tif (!this._autoRefineAllowedForSession()) {\n\t\t\treturn;\n\t\t}\n\t\tif (this._serializedRefine) {\n\t\t\t// Serialized sessions must service compaction-triggered refinement at\n\t\t\t// shouldStopAfterTurn (or disposal), never through the interactive path.\n\t\t\tthis._compactAutoRefinePending = true;\n\t\t\treturn;\n\t\t}\n\t\tif (willContinueAfterCompaction) {\n\t\t\tthis._compactAutoRefinePending = true;\n\t\t\treturn;\n\t\t}\n\n\t\tthis._scheduleAutoRefine(\"compact\");\n\t}\n\n\tprivate _schedulePostCompactionContinue(): void {\n\t\tif (this._postCompactionContinuationScheduled) {\n\t\t\treturn;\n\t\t}\n\t\tif (!this._postCompactionContinuationSettlement || this._postCompactionContinuationSettlement.settled) {\n\t\t\tthis._postCompactionContinuationSettlement = createPostCompactionContinuationSettlement();\n\t\t}\n\t\tthis._postCompactionContinuationScheduled = true;\n\t\tthis._scheduledPostCompactionContinuationMessages = [...this._postCompactionContinuationMessages];\n\t\tthis._postCompactionContinuationTimer = setTimeout(() => {\n\t\t\tthis._postCompactionContinuationTimer = undefined;\n\t\t\tvoid this._runScheduledPostCompactionContinue()\n\t\t\t\t.catch(() => undefined)\n\t\t\t\t.finally(() => this._settlePostCompactionContinue());\n\t\t}, 100);\n\t}\n\n\tprivate _sessionOwnsScheduledContinuations(continuationMessages: AgentMessage[]): boolean {\n\t\treturn continuationMessages.some((message) => this._postCompactionContinuationMessages.includes(message));\n\t}\n\n\tprivate async _runScheduledPostCompactionContinue(): Promise<void> {\n\t\tawait this._waitForRefineIdle();\n\t\tif (!this._postCompactionContinuationScheduled) {\n\t\t\treturn;\n\t\t}\n\t\tif (this.isStreaming || this.isCompacting || this.isRetrying || this._queuedWorkPauses.size > 0) {\n\t\t\tthis._postCompactionContinuationScheduled = false;\n\t\t\tthis._schedulePostCompactionContinue();\n\t\t\treturn;\n\t\t}\n\n\t\tconst continuationMessages = [...this._scheduledPostCompactionContinuationMessages];\n\t\tif (continuationMessages.length > 0 && !this._sessionOwnsScheduledContinuations(continuationMessages)) {\n\t\t\tthis._cancelPostCompactionContinue();\n\t\t\tthis._scheduleAutoRefineAfterAgentEnd();\n\t\t\treturn;\n\t\t}\n\t\t// An empty queue is not idle while the scheduler still owns active work.\n\t\tif (this.unfinishedActionCount > 0 || this._sessionInputPumpRequested) {\n\t\t\tthis._scheduleSessionInputPump();\n\t\t\tawait this._sessionInputPump;\n\t\t\tif (this._postCompactionContinuationScheduled) {\n\t\t\t\tthis._postCompactionContinuationScheduled = false;\n\t\t\t\tconst shouldReschedule =\n\t\t\t\t\tcontinuationMessages.length === 0\n\t\t\t\t\t\t? this.unfinishedActionCount > 0\n\t\t\t\t\t\t: this._sessionOwnsScheduledContinuations(continuationMessages);\n\t\t\t\tif (shouldReschedule) {\n\t\t\t\t\tthis._schedulePostCompactionContinue();\n\t\t\t\t} else {\n\t\t\t\t\tthis._scheduledPostCompactionContinuationMessages = [];\n\t\t\t\t\tthis._scheduleAutoRefineAfterAgentEnd();\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tthis._postCompactionContinuationScheduled = false;\n\t\ttry {\n\t\t\tawait this.agent.continue();\n\t\t\tthis._forgetConsumedPostCompactionContinuations(continuationMessages);\n\t\t} catch (error) {\n\t\t\tconst code = error instanceof AgentContinueError ? error.code : undefined;\n\t\t\tif (code === \"busy\") {\n\t\t\t\tthis._schedulePostCompactionContinue();\n\t\t\t} else if (code !== \"nothing-to-continue\") {\n\t\t\t\t// \"nothing-to-continue\" means the turn already completed; anything else must reject headless idle waiters.\n\t\t\t\tthis._settlePostCompactionContinue(this._asError(error));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _forgetConsumedPostCompactionContinuations(continuationMessages: AgentMessage[]): void {\n\t\tif (continuationMessages.length === 0) {\n\t\t\treturn;\n\t\t}\n\t\tconst continuationMessageSet = new Set(continuationMessages);\n\t\tconst stillQueued = new Set(this.agent.removeQueuedMessages((message) => continuationMessageSet.has(message)));\n\t\tfor (const message of stillQueued) {\n\t\t\tthis.agent.followUp(message);\n\t\t}\n\t\tfor (const message of continuationMessages) {\n\t\t\tif (!stillQueued.has(message)) {\n\t\t\t\tthis._queuedAutonomousContinuationSnapshots.delete(message);\n\t\t\t}\n\t\t}\n\t\tthis._postCompactionContinuationMessages = this._postCompactionContinuationMessages.filter(\n\t\t\t(message) => !continuationMessageSet.has(message) || stillQueued.has(message),\n\t\t);\n\t}\n\n\tprivate _shouldSkipAutoRefineForActiveAgent(): boolean {\n\t\treturn this.isStreaming || this.isCompacting;\n\t}\n\n\tprivate _scheduleDeferredAutoRefineIfIdle(): void {\n\t\tif (this._autoRefineInProgress || this._shouldSkipAutoRefineForActiveAgent() || this._pendingAutoRefineReview) {\n\t\t\treturn;\n\t\t}\n\t\tif (this._turnIntervalAutoRefinePending) {\n\t\t\tthis._turnIntervalAutoRefinePending = false;\n\t\t\tthis._scheduleAutoRefine(\"turn_interval\");\n\t\t}\n\t}\n\n\tprivate _scheduleAutoRefine(reason: AutoRefineReason, branchVersion = this._autoRefineBranchVersion): void {\n\t\tconst timer = setTimeout(() => {\n\t\t\tthis._scheduledAutoRefineTimers.delete(timer);\n\t\t\tif (branchVersion !== this._autoRefineBranchVersion) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst operation = this._maybeAutoRefine(reason);\n\t\t\tthis._autoRefineOperations.add(operation);\n\t\t\tvoid operation.finally(() => this._autoRefineOperations.delete(operation)).catch(() => undefined);\n\t\t}, 0);\n\t\tthis._scheduledAutoRefineTimers.add(timer);\n\t}\n\n\tprivate async _maybeAutoRefine(reason: AutoRefineReason): Promise<void> {\n\t\tif (this._disposed || this._disposing) {\n\t\t\tthis._discardPendingAutoRefine();\n\t\t\treturn;\n\t\t}\n\t\tif (!this._autoRefineAllowedForSession()) {\n\t\t\tthis._discardPendingAutoRefine();\n\t\t\treturn;\n\t\t}\n\n\t\tconst settings = this.settingsManager.getAutoRefineSettings();\n\t\tif (!settings.enabled) {\n\t\t\tthis._discardPendingAutoRefine();\n\t\t\treturn;\n\t\t}\n\t\tif (this._autoRefineInProgress || this._shouldSkipAutoRefineForActiveAgent()) {\n\t\t\tif (reason === \"compact\") {\n\t\t\t\tthis._compactAutoRefinePending = true;\n\t\t\t} else {\n\t\t\t\tthis._turnIntervalAutoRefinePending = true;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst nowMs = Date.now();\n\t\tconst underCooldown =\n\t\t\tthis._lastAutoRefineReviewAt > 0 && nowMs - this._lastAutoRefineReviewAt < settings.cooldownMs;\n\n\t\tconst pendingReview = this._pendingAutoRefineReview;\n\t\tif (pendingReview) {\n\t\t\t// A failed refine stamps the cooldown; keep the pending review for later.\n\t\t\tif (underCooldown) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait this._runApprovedRefine(pendingReview.reason, pendingReview.review);\n\t\t\treturn;\n\t\t}\n\n\t\tif (reason === \"compact\" && !settings.compact) {\n\t\t\tthis._compactAutoRefinePending = false;\n\t\t\treason = \"turn_interval\";\n\t\t}\n\t\tif (reason === \"turn_interval\" && this._assistantTurnsSinceAutoRefine < settings.turnInterval) {\n\t\t\treturn;\n\t\t}\n\t\tif (underCooldown) {\n\t\t\tif (reason === \"compact\") {\n\t\t\t\tthis._compactAutoRefinePending = true;\n\t\t\t} else {\n\t\t\t\tthis._turnIntervalAutoRefinePending = true;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (reason === \"turn_interval\") {\n\t\t\tthis._turnIntervalAutoRefinePending = false;\n\t\t}\n\t\tif (!this.model) {\n\t\t\tif (reason === \"compact\") {\n\t\t\t\tthis._compactAutoRefinePending = true;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tthis._autoRefineInProgress = true;\n\t\tconst turnsSinceLastReview = this._assistantTurnsSinceAutoRefine;\n\t\tconst branchVersion = this._autoRefineBranchVersion;\n\t\tconst reviewAbort = new AbortController();\n\t\tthis._autoRefineReviewAbort = reviewAbort;\n\t\tlet approvedReview: AutoRefineReview | undefined;\n\t\ttry {\n\t\t\tconst review = await this._reviewAutoRefine({ reason, turnsSinceLastReview }, reviewAbort.signal);\n\t\t\tif (this._disposed || this._disposing || branchVersion !== this._autoRefineBranchVersion) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!review.shouldRefine) {\n\t\t\t\tconst preserveTurnIntervalReview =\n\t\t\t\t\treason === \"compact\" && this._assistantTurnsSinceAutoRefine >= settings.turnInterval;\n\t\t\t\tif (preserveTurnIntervalReview) {\n\t\t\t\t\tthis._turnIntervalAutoRefinePending = true;\n\t\t\t\t} else {\n\t\t\t\t\tthis._lastAutoRefineReviewAt = nowMs;\n\t\t\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t\t\t}\n\t\t\t\tif (reason === \"compact\") {\n\t\t\t\t\tthis._compactAutoRefinePending = false;\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (this._shouldSkipAutoRefineForActiveAgent()) {\n\t\t\t\tthis._pendingAutoRefineReview = { reason, review };\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tapprovedReview = review;\n\t\t} catch {\n\t\t\t// Failed review: stamp the cooldown so a persistent failure (bad auth,\n\t\t\t// unparseable output) doesn't retry a full review on every agent end.\n\t\t\tif (branchVersion === this._autoRefineBranchVersion) {\n\t\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\t}\n\t\t} finally {\n\t\t\tif (this._autoRefineReviewAbort === reviewAbort) {\n\t\t\t\tthis._autoRefineReviewAbort = undefined;\n\t\t\t}\n\t\t\tthis._autoRefineInProgress = false;\n\t\t\t// When a refine follows, _runApprovedRefine schedules the deferred pass.\n\t\t\tif (!approvedReview) {\n\t\t\t\tthis._scheduleDeferredAutoRefineIfIdle();\n\t\t\t}\n\t\t}\n\t\tif (approvedReview) {\n\t\t\tawait this._runApprovedRefine(reason, approvedReview);\n\t\t}\n\t}\n\n\tprivate async _runApprovedRefine(reason: AutoRefineReason, review: AutoRefineReview): Promise<void> {\n\t\tthis._autoRefineInProgress = true;\n\t\ttry {\n\t\t\tawait this.refine({ instructions: autoRefineInstructions(reason, review) }, { trigger: \"auto\" });\n\t\t\tthis._pendingAutoRefineReview = undefined;\n\t\t\tthis._turnIntervalAutoRefinePending = false;\n\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t\tif (reason === \"compact\") {\n\t\t\t\tthis._compactAutoRefinePending = false;\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// Auto-refine is opportunistic; manual /refine remains available.\n\t\t\t// Stamp the cooldown so a persistently failing refine doesn't retry\n\t\t\t// (via a retained pending review) on every agent end.\n\t\t\tthis._lastAutoRefineReviewAt = Date.now();\n\t\t\tif (error instanceof RefineSkippedError) {\n\t\t\t\t// A skipped round is consumed like a reviewer decline, not retained for retry.\n\t\t\t\tthis._pendingAutoRefineReview = undefined;\n\t\t\t\tthis._turnIntervalAutoRefinePending = false;\n\t\t\t\tthis._assistantTurnsSinceAutoRefine = 0;\n\t\t\t\tif (reason === \"compact\") this._compactAutoRefinePending = false;\n\t\t\t}\n\t\t} finally {\n\t\t\tthis._autoRefineInProgress = false;\n\t\t\tthis._scheduleDeferredAutoRefineIfIdle();\n\t\t}\n\t}\n\n\tprivate async _reviewAutoRefine(context: AutoRefineReviewRequest, signal?: AbortSignal): Promise<AutoRefineReview> {\n\t\tif (this._autoRefineReviewer) {\n\t\t\treturn this._autoRefineReviewer(context, signal);\n\t\t}\n\t\tconst model = this.model;\n\t\tif (!model) {\n\t\t\treturn { shouldRefine: false, rationale: \"No model selected.\" };\n\t\t}\n\t\tconst { apiKey, headers } = await this._getRequiredRequestAuth(model);\n\t\treturn reviewAutoRefine(\n\t\t\tthis.agent.state.messages,\n\t\t\tthis._loadMergedHarnessState(),\n\t\t\tthis._loadRefinementHistory(),\n\t\t\tmodel,\n\t\t\tapiKey,\n\t\t\tcontext,\n\t\t\theaders,\n\t\t\tsignal,\n\t\t\tthis.thinkingLevel,\n\t\t);\n\t}\n\n\t/** Global harness state overlaid with this session's local state, when persisted. */\n\tprivate _loadMergedHarnessState(): HarnessState {\n\t\tconst localHarnessStateDir = this._localHarnessStateDir();\n\t\treturn mergeHarnessStates(\n\t\t\tloadHarnessState(getGlobalHarnessStateDir(), \"global\"),\n\t\t\tlocalHarnessStateDir ? loadHarnessState(localHarnessStateDir, \"local\") : undefined,\n\t\t);\n\t}\n\n\tprivate _loadRefinementHistory(): RefinementResult[] {\n\t\treturn mergeRefinementHistory(\n\t\t\tloadGlobalRefinementHistory(getGlobalHarnessStateDir()),\n\t\t\tgetRefinementHistory(this.sessionManager.getEntries().filter((entry) => entry.type === \"custom\")),\n\t\t);\n\t}\n\n\t/**\n\t * Refine editable continual harness state: prompt notes, memory, skills, and subagent specs.\n\t * The base system prompt is intentionally not editable through this path.\n\t *\n\t * Planning runs in the background and does NOT block turn entry points\n\t * (`_waitForRefineIdle` only waits for `_refineInFlight`). Only the fast\n\t * application phase (disk I/O + in-memory mutation) blocks turn entry points.\n\t */\n\tasync refine(\n\t\toptions: {\n\t\t\tinstructions?: string;\n\t\t\trollbackId?: string;\n\t\t\tglobal?: boolean;\n\t\t} = {},\n\t\tinternal: { skipAbort?: boolean; trigger?: \"manual\" | \"auto\" } = {},\n\t): Promise<RefinementResult> {\n\t\t// Queued /refine executes from the session-input pump between turns;\n\t\t// refine never aborts the agent (planning is backgrounded and the apply\n\t\t// phase waits for quiescence), so skipAbort only asserts the pump's\n\t\t// idle invariant instead of changing abort behavior.\n\t\tif (internal.skipAbort && this.isStreaming) {\n\t\t\tthrow new Error(\"Cannot refine without aborting while the agent is running.\");\n\t\t}\n\t\t// Wait for any existing refine (both planning and application) before\n\t\t// starting a new run. This serializes concurrent /refine calls so two\n\t\t// planning phases cannot race into concurrent _applyRefine calls that\n\t\t// overwrite harness state.\n\t\twhile (this._refineInFlight || this._refinePlanInFlight || this._serializedPlanInFlight) {\n\t\t\tif (this._refineInFlight) {\n\t\t\t\tawait this._refineInFlight;\n\t\t\t} else if (this._refinePlanInFlight) {\n\t\t\t\tawait this._refinePlanInFlight;\n\t\t\t} else {\n\t\t\t\t// A serialized background plan is in flight (started during an\n\t\t\t\t// active turn at message_end). Wait for planning and for the active\n\t\t\t\t// turn to settle so its normal checkpoint can consume the plan.\n\t\t\t\tconst serializedPlanInFlight = this._serializedPlanInFlight;\n\t\t\t\tawait serializedPlanInFlight;\n\t\t\t\tif (this._refineInFlight || this._refinePlanInFlight) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tawait this.agent.waitForIdle();\n\t\t\t\t// Aborted turns skip shouldStopAfterTurn. Drop their settled plan\n\t\t\t\t// after idle so a later public refine cannot spin on it forever.\n\t\t\t\tif (this._serializedPlanInFlight === serializedPlanInFlight) {\n\t\t\t\t\tthis._serializedPlanInFlight = undefined;\n\t\t\t\t\tthis._serializedExplicitRefineOptions = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst refineAbort = new AbortController();\n\t\tthis._refineAbortController = refineAbort;\n\n\t\tconst planRun = this._planRefine(options, refineAbort.signal, internal.trigger ?? \"manual\");\n\t\tconst planSettled = planRun.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\tthis._refinePlanInFlight = planSettled;\n\t\tlet plan: RefinementPlan;\n\t\ttry {\n\t\t\tplan = await planRun;\n\t\t} catch (e) {\n\t\t\tif (this._refineAbortController === refineAbort) {\n\t\t\t\tthis._refineAbortController = undefined;\n\t\t\t}\n\t\t\tthis._scheduleSessionInputPump();\n\t\t\tthrow e;\n\t\t} finally {\n\t\t\tif (this._refinePlanInFlight === planSettled) {\n\t\t\t\tthis._refinePlanInFlight = undefined;\n\t\t\t}\n\t\t}\n\n\t\t// Block new turns before waiting for the current turn to finish. One shared\n\t\t// settled promise covers the full transition and apply critical section.\n\t\tlet resolveApplySettled: () => void = () => {};\n\t\tconst applySettled = new Promise<void>((resolve) => {\n\t\t\tresolveApplySettled = resolve;\n\t\t});\n\t\tthis._refineInFlight = applySettled;\n\t\ttry {\n\t\t\t// Wait for the session to become quiescent before applying. Planning is\n\t\t\t// allowed to overlap active user work, but application must not disconnect\n\t\t\t// event handling until that work and its queued events have completed.\n\t\t\tawait this.agent.waitForIdle();\n\t\t\twhile (true) {\n\t\t\t\tconst eventQueue = this._agentEventQueue;\n\t\t\t\tconst compactionOp = this._compactionOperation;\n\t\t\t\tconst branchSummaryOp = this._branchSummaryOperation;\n\t\t\t\tawait Promise.allSettled([\n\t\t\t\t\teventQueue,\n\t\t\t\t\t...(compactionOp ? [compactionOp] : []),\n\t\t\t\t\t...(branchSummaryOp ? [branchSummaryOp] : []),\n\t\t\t\t]);\n\t\t\t\tif (\n\t\t\t\t\teventQueue === this._agentEventQueue &&\n\t\t\t\t\tcompactionOp === this._compactionOperation &&\n\t\t\t\t\tbranchSummaryOp === this._branchSummaryOperation\n\t\t\t\t) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this._disposed || refineAbort.signal.aborted) {\n\t\t\t\tthrow new Error(\"Refinement cancelled because the session was disposed.\");\n\t\t\t}\n\t\t\treturn await this._applyRefine(plan, options, refineAbort);\n\t\t} finally {\n\t\t\tresolveApplySettled();\n\t\t\tif (this._refineInFlight === applySettled) {\n\t\t\t\tthis._refineInFlight = undefined;\n\t\t\t}\n\t\t\tthis._scheduleSessionInputPump();\n\t\t}\n\t}\n\n\t/**\n\t * Block a new agent turn until any in-flight refine application phase has\n\t * reattached event handling; otherwise the turn's messages are never\n\t * persisted or rendered.\n\t *\n\t * The idle-wait and application phase (`_refineInFlight`) block here. The\n\t * background planning phase (`_refinePlanInFlight`) does NOT block turns.\n\t * Refine failures surface to the refine caller, not here.\n\t */\n\tprivate async _waitForRefineIdle(): Promise<void> {\n\t\twhile (this._refineInFlight) {\n\t\t\tawait this._refineInFlight;\n\t\t}\n\t}\n\n\t/**\n\t * Background planning phase: runs the LLM planning call via `planRefinement`.\n\t * Does not disconnect from or abort the agent. Returns the plan without\n\t * applying anything.\n\t */\n\tprivate async _planRefine(\n\t\toptions: { instructions?: string; rollbackId?: string; global?: boolean },\n\t\tsignal: AbortSignal,\n\t\ttrigger: \"manual\" | \"auto\" = \"manual\",\n\t): Promise<RefinementPlan> {\n\t\tif (this._disposed) {\n\t\t\tthrow new Error(\"Cannot refine a disposed session.\");\n\t\t}\n\n\t\tif (!this.model) {\n\t\t\tthrow new Error(formatNoModelSelectedMessage());\n\t\t}\n\n\t\tconst model = this.model;\n\t\tconst { apiKey, headers } = await this._getRequiredRequestAuth(model);\n\t\tconst globalHarnessStateDir = getGlobalHarnessStateDir();\n\t\tconst localHarnessStateDir = this._localHarnessStateDir();\n\t\tconst requestedScope = options.global ? \"global\" : \"local\";\n\t\tif (!options.rollbackId && requestedScope === \"local\" && !localHarnessStateDir) {\n\t\t\tthrow new Error(\"Local harness refinement requires a persisted session; use global refinement instead.\");\n\t\t}\n\t\tconst globalPlanningState = loadHarnessState(globalHarnessStateDir, \"global\");\n\t\tconst localPlanningState = localHarnessStateDir ? loadHarnessState(localHarnessStateDir, \"local\") : undefined;\n\t\tconst planningState =\n\t\t\trequestedScope === \"global\"\n\t\t\t\t? globalPlanningState\n\t\t\t\t: mergeHarnessStates(globalPlanningState, localPlanningState);\n\t\tconst history = this._loadRefinementHistory();\n\t\tconst rollbackTarget = options.rollbackId ? history.find((item) => item.id === options.rollbackId) : undefined;\n\t\tlet baselineScope = rollbackTarget\n\t\t\t? (inferRefinementResultScope(rollbackTarget) ?? requestedScope)\n\t\t\t: requestedScope;\n\t\tlet baselineHarnessStateDir = baselineScope === \"global\" ? globalHarnessStateDir : localHarnessStateDir;\n\t\tif (rollbackTarget?.harnessStatePath) {\n\t\t\tbaselineHarnessStateDir = dirname(rollbackTarget.harnessStatePath);\n\t\t\tbaselineScope = resolve(baselineHarnessStateDir) === resolve(globalHarnessStateDir) ? \"global\" : \"local\";\n\t\t}\n\t\tif (!baselineHarnessStateDir) {\n\t\t\tthrow new Error(\"Local harness refinement requires a persisted session; use global refinement instead.\");\n\t\t}\n\t\tconst baselineState = rollbackTarget\n\t\t\t? loadHarnessState(baselineHarnessStateDir, baselineScope)\n\t\t\t: baselineScope === \"global\"\n\t\t\t\t? globalPlanningState\n\t\t\t\t: localPlanningState!;\n\t\tif (!options.rollbackId && this._extensionRunner.hasHandlers(\"session_before_refine\")) {\n\t\t\tconst result = (await this._extensionRunner.emit({\n\t\t\t\ttype: \"session_before_refine\",\n\t\t\t\tpreparation: {\n\t\t\t\t\ttrigger,\n\t\t\t\t\tinstructions: options.instructions,\n\t\t\t\t\tscope: requestedScope,\n\t\t\t\t\tplanningState,\n\t\t\t\t\thistory,\n\t\t\t\t\tconversationText: serializeConversation(convertToLlm(this.agent.state.messages)).slice(-80_000),\n\t\t\t\t},\n\t\t\t\tsignal,\n\t\t\t})) as SessionBeforeRefineResult | undefined;\n\t\t\tif (this._disposed || signal.aborted) {\n\t\t\t\tthrow new Error(\"Refinement cancelled because the session was disposed.\");\n\t\t\t}\n\t\t\tif (result?.skip) {\n\t\t\t\tthrow new RefineSkippedError(\"Refinement skipped by extension\");\n\t\t\t}\n\t\t\tif (result?.proposal !== undefined) {\n\t\t\t\treturn {\n\t\t\t\t\tproposal: normalizeRefinementProposal(result.proposal),\n\t\t\t\t\tid: generateRefinementId(),\n\t\t\t\t\tbaselineState,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\tconst plan = await planRefinement(\n\t\t\tthis.agent.state.messages,\n\t\t\tplanningState,\n\t\t\thistory,\n\t\t\tmodel,\n\t\t\tapiKey,\n\t\t\toptions,\n\t\t\theaders,\n\t\t\tsignal,\n\t\t\tthis.thinkingLevel,\n\t\t);\n\t\tif (this._disposed || signal.aborted) {\n\t\t\tthrow new Error(\"Refinement cancelled because the session was disposed.\");\n\t\t}\n\t\treturn { ...plan, baselineState };\n\t}\n\n\tprivate _recordRefinementOutcome(result: RefinementResult): void {\n\t\tconst message = createRefinementOutcomeMessage(result);\n\t\ttry {\n\t\t\tthis.sessionManager.appendCustomMessageEntryWithRollback(\n\t\t\t\tmessage.customType,\n\t\t\t\tmessage.content,\n\t\t\t\tmessage.display,\n\t\t\t\tmessage.details,\n\t\t\t);\n\t\t} catch {\n\t\t\t// Not in the session file, so context rebuilds would drop the outcome.\n\t\t\tthis._unpersistedOutcomes.push(message);\n\t\t}\n\t\tthis.agent.state.messages.push(message);\n\t\tthis._emit({ type: \"message_start\", message });\n\t\tthis._emit({ type: \"message_end\", message });\n\t}\n\n\t/**\n\t * Synchronous application phase: disconnects from the agent, aborts any\n\t * in-flight agent run, applies the refinement plan to disk and memory, then\n\t * reconnects. This is the only phase that blocks turn entry points.\n\t */\n\tprivate async _applyRefine(\n\t\tplan: RefinementPlan,\n\t\toptions: { instructions?: string; rollbackId?: string; global?: boolean },\n\t\trefineAbort: AbortController,\n\t): Promise<RefinementResult> {\n\t\tif (this._disposed) {\n\t\t\tthrow new Error(\"Cannot refine a disposed session.\");\n\t\t}\n\t\t// The caller has already set _refineInFlight and waited for agent idle.\n\t\t// Disconnect only for the brief apply + save + reconnect critical section.\n\t\tthis._disconnectFromAgent();\n\n\t\ttry {\n\t\t\tconst globalHarnessStateDir = getGlobalHarnessStateDir();\n\t\t\tconst localHarnessStateDir = this._localHarnessStateDir();\n\t\t\tconst requestedScope = options.global ? \"global\" : \"local\";\n\t\t\tconst history = this._loadRefinementHistory();\n\t\t\tconst rollbackTarget = options.rollbackId ? history.find((item) => item.id === options.rollbackId) : undefined;\n\t\t\tlet targetScope = plan.rollbackScope ?? requestedScope;\n\t\t\tlet targetHarnessStateDir = targetScope === \"global\" ? globalHarnessStateDir : localHarnessStateDir;\n\t\t\tif (targetScope === \"local\" && rollbackTarget?.harnessStatePath) {\n\t\t\t\tif (!existsSync(rollbackTarget.harnessStatePath)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Local refinement ${rollbackTarget.id} state file not found: ${rollbackTarget.harnessStatePath}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\ttargetHarnessStateDir = dirname(rollbackTarget.harnessStatePath);\n\t\t\t\t// Legacy records predate scope fields and default to \"local\" but may point\n\t\t\t\t// at the global store; honor the recorded path so its entries stay global.\n\t\t\t\tif (resolve(targetHarnessStateDir) === resolve(globalHarnessStateDir)) {\n\t\t\t\t\ttargetScope = \"global\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!targetHarnessStateDir) {\n\t\t\t\tthrow new Error(\"Local harness refinement requires a persisted session; use global refinement instead.\");\n\t\t\t}\n\t\t\t// Re-read the target state immediately before applying so concurrent kernel\n\t\t\t// (`rlm.harness`) writes during the LLM pass are not clobbered.\n\t\t\tconst state = loadHarnessState(targetHarnessStateDir, targetScope);\n\t\t\tconst proposal = {\n\t\t\t\t...plan.proposal,\n\t\t\t\tedits: plan.proposal.edits.map((edit) => {\n\t\t\t\t\tconst localPrefix = \"local:\";\n\t\t\t\t\tconst globalPrefix = \"global:\";\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...edit,\n\t\t\t\t\t\tid: edit.id?.startsWith(localPrefix)\n\t\t\t\t\t\t\t? edit.id.slice(localPrefix.length)\n\t\t\t\t\t\t\t: edit.id?.startsWith(globalPrefix)\n\t\t\t\t\t\t\t\t? edit.id.slice(globalPrefix.length)\n\t\t\t\t\t\t\t\t: edit.id,\n\t\t\t\t\t};\n\t\t\t\t}),\n\t\t\t};\n\t\t\tif (this._disposed || refineAbort.signal.aborted) {\n\t\t\t\tthrow new Error(\"Refinement cancelled because the session was disposed.\");\n\t\t\t}\n\t\t\tconst result = applyRefinementProposal(state, proposal, {\n\t\t\t\tid: plan.id,\n\t\t\t\trollbackOf: plan.rollbackOf,\n\t\t\t\tscope: targetScope,\n\t\t\t\tbaselineState: plan.baselineState,\n\t\t\t});\n\t\t\tresult.harnessStatePath = saveHarnessState(targetHarnessStateDir, state);\n\t\t\tif (targetScope === \"global\") {\n\t\t\t\tappendGlobalRefinement(globalHarnessStateDir, result);\n\t\t\t}\n\t\t\tlet refinementAuditAppendError: { error: unknown } | undefined;\n\t\t\ttry {\n\t\t\t\tthis.sessionManager.appendCustomEntry(\"asm-agent.refinement\", result);\n\t\t\t} catch (error) {\n\t\t\t\trefinementAuditAppendError = { error };\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tthis._recordRefinementOutcome(result);\n\t\t\t} catch (error) {\n\t\t\t\tif (!refinementAuditAppendError) throw error;\n\t\t\t}\n\t\t\tif (refinementAuditAppendError) throw refinementAuditAppendError.error;\n\t\t\tthis._baseSystemPrompt = this._rebuildSystemPrompt(this.getActiveToolNames());\n\t\t\tthis.agent.state.systemPrompt = this._baseSystemPrompt;\n\t\t\ttry {\n\t\t\t\tthis._emit({ type: \"refine_complete\", result });\n\t\t\t} catch {\n\t\t\t\t// Listener failures must not flip a successful refinement into\n\t\t\t\t// a reported failure — the refinement is already persisted.\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tawait this._extensionRunner.emit({\n\t\t\t\t\ttype: \"refine_complete\",\n\t\t\t\t\tid: result.id,\n\t\t\t\t\tsummary: result.summary,\n\t\t\t\t\tappliedEdits: result.appliedEdits.filter((edit) => edit.applied).length,\n\t\t\t\t\tscope: result.scope ?? \"local\",\n\t\t\t\t});\n\t\t\t} catch {\n\t\t\t\t// Extension emit failures must not flip a successful refinement\n\t\t\t\t// into a reported failure — the refinement is already persisted.\n\t\t\t}\n\t\t\treturn result;\n\t\t} finally {\n\t\t\tif (this._refineAbortController === refineAbort) {\n\t\t\t\tthis._refineAbortController = undefined;\n\t\t\t}\n\t\t\tif (!this._disposed) {\n\t\t\t\tthis._reconnectToAgent();\n\t\t\t}\n\t\t}\n\t}\n\n\tabortBranchSummary(): void {\n\t\tthis._branchSummaryAbortController?.abort();\n\t}\n\n\t/**\n\t * Check if compaction is needed and run it.\n\t * Called after agent_end and before prompt submission.\n\t *\n\t * Two cases:\n\t * 1. Overflow: LLM returned context overflow error, remove error message from agent state, compact, auto-retry\n\t * 2. Threshold: Context over threshold, compact, and continue only for stopped in-progress loops or queued messages\n\t *\n\t * @param assistantMessage The assistant message to check\n\t * @param skipAbortedCheck If false, include aborted messages (for pre-prompt check). Default: true\n\t */\n\tprivate _getThresholdContextTokens(\n\t\tassistantMessage: AssistantMessage,\n\t\tcompactionTimestamp: number | undefined,\n\t): number | undefined {\n\t\tconst messages = this.agent.state.messages;\n\t\tconst estimate = estimateContextTokens(messages);\n\t\tif (estimate.lastUsageIndex !== null) {\n\t\t\t// Verify the usage source is post-compaction. Kept pre-compaction messages\n\t\t\t// have stale usage reflecting the old (larger) context and would falsely\n\t\t\t// trigger compaction right after one just finished.\n\t\t\tconst usageMsg = messages[estimate.lastUsageIndex];\n\t\t\tif (\n\t\t\t\tcompactionTimestamp !== undefined &&\n\t\t\t\tusageMsg.role === \"assistant\" &&\n\t\t\t\t(usageMsg as AssistantMessage).timestamp <= compactionTimestamp\n\t\t\t) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\treturn estimate.tokens;\n\t\t}\n\t\tif (assistantMessage.stopReason === \"error\") return undefined;\n\t\treturn calculateContextTokens(assistantMessage.usage);\n\t}\n\n\tprivate async _checkCompaction(\n\t\tassistantMessage: AssistantMessage,\n\t\tskipAbortedCheck = true,\n\t\tqueueAutonomousContinuation = true,\n\t): Promise<boolean> {\n\t\t// An abort drops any compaction the model requested this turn, even on the\n\t\t// pre-prompt path (skipAbortedCheck=false) which continues to threshold checks.\n\t\tif (assistantMessage.stopReason === \"aborted\") {\n\t\t\tthis._pendingRequestedCompaction = undefined;\n\t\t\t// An abort also drops any pending explicit refine.run request: the\n\t\t\t// turn that would service it (non-serialized: _consumePendingRequestedRefine\n\t\t\t// at agent_end; serialized: the shouldStopAfterTurn checkpoint) never\n\t\t\t// runs for an aborted turn, so a stale request would leak into the\n\t\t\t// next turn or checkpoint.\n\t\t\tthis._pendingRequestedRefine = undefined;\n\t\t\tif (this._serializedPlanInFlight) {\n\t\t\t\tconst serializedPlanInFlight = this._serializedPlanInFlight;\n\t\t\t\tthis._autoRefineBranchVersion++;\n\t\t\t\tthis._refineAbortController?.abort();\n\t\t\t\tawait serializedPlanInFlight.catch(() => undefined);\n\t\t\t\tif (this._serializedPlanInFlight === serializedPlanInFlight) {\n\t\t\t\t\tthis._serializedPlanInFlight = undefined;\n\t\t\t\t\tthis._serializedExplicitRefineOptions = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (skipAbortedCheck) return false;\n\t\t}\n\n\t\tconst settings = this.settingsManager.getCompactionSettings();\n\t\tconst contextWindow = this.model?.contextWindow ?? 0;\n\n\t\t// Skip overflow check if the message came from a different model.\n\t\t// This handles the case where user switched from a smaller-context model (e.g. opus)\n\t\t// to a larger-context model (e.g. codex) - the overflow error from the old model\n\t\t// shouldn't trigger compaction for the new model.\n\t\tconst sameModel =\n\t\t\tthis.model && assistantMessage.provider === this.model.provider && assistantMessage.model === this.model.id;\n\n\t\t// Skip overflow/threshold checks if this assistant message is older than the\n\t\t// latest compaction boundary. This prevents a stale pre-compaction usage/error\n\t\t// from retriggering compaction on the first prompt after compaction.\n\t\tconst compactionEntry = getLatestCompactionEntry(this.sessionManager.getBranch());\n\t\tconst compactionTimestamp = compactionEntry ? new Date(compactionEntry.timestamp).getTime() : undefined;\n\t\tconst assistantIsFromBeforeCompaction =\n\t\t\tcompactionTimestamp !== undefined && assistantMessage.timestamp <= compactionTimestamp;\n\n\t\t// Case 1: Overflow - takes priority over a pending model request so the error\n\t\t// strip + retry still happen; the compaction it runs consumes the request.\n\t\tif (\n\t\t\t!assistantIsFromBeforeCompaction &&\n\t\t\t(settings.enabled || this._pendingRequestedCompaction !== undefined) &&\n\t\t\tsameModel &&\n\t\t\tisContextOverflow(assistantMessage, contextWindow)\n\t\t) {\n\t\t\tif (this._overflowRecovery !== \"idle\") {\n\t\t\t\tif (this._overflowRecovery === \"attempted\") {\n\t\t\t\t\tthis._overflowRecovery = \"reported\";\n\t\t\t\t\tthis._endCompactionUnsuccessfully(\n\t\t\t\t\t\t\"overflow\",\n\t\t\t\t\t\t\"failed\",\n\t\t\t\t\t\t\"Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model.\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis._overflowRecovery = \"attempted\";\n\t\t\t// Remove the error message from agent state (it IS saved to session for history,\n\t\t\t// but we don't want it in context for the retry)\n\t\t\tconst messages = this.agent.state.messages;\n\t\t\tif (messages.length > 0 && messages[messages.length - 1].role === \"assistant\") {\n\t\t\t\tthis.agent.state.messages = messages.slice(0, -1);\n\t\t\t}\n\t\t\treturn await this._runAutoCompaction(\"overflow\", true);\n\t\t}\n\n\t\tif (this._pendingRequestedCompaction !== undefined) {\n\t\t\treturn await this._runAutoCompaction(\"requested\", false);\n\t\t}\n\n\t\tif (!settings.enabled || assistantIsFromBeforeCompaction) return false;\n\n\t\t// Case 3: Threshold - context is getting large.\n\t\t// Use the full-session estimate so messages appended after the last successful\n\t\t// assistant usage are included, matching the /usage context display.\n\t\tconst contextTokens = this._getThresholdContextTokens(assistantMessage, compactionTimestamp);\n\t\tif (contextTokens === undefined) return false;\n\t\tif (shouldCompact(contextTokens, contextWindow, settings)) {\n\t\t\tif (queueAutonomousContinuation && this._queueGoalContinuationForThresholdCompaction(assistantMessage)) {\n\t\t\t\tthis._continueAfterThresholdCompaction = true;\n\t\t\t} else if (\n\t\t\t\tqueueAutonomousContinuation &&\n\t\t\t\t(await this._queueAutonomousContinuationForThresholdCompaction(assistantMessage))\n\t\t\t) {\n\t\t\t\tthis._continueAfterThresholdCompaction = true;\n\t\t\t}\n\t\t\treturn await this._runAutoCompaction(\"threshold\", false);\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Internal: Run automatic (threshold/overflow) or model-requested compaction\n\t * with events.\n\t */\n\tprivate _endCompactionUnsuccessfully(\n\t\treason: CompactionOutcomeReason,\n\t\toutcome: CompactionOutcome,\n\t\tmessage: string,\n\t\toptions: {\n\t\t\taborted?: boolean;\n\t\t\terrorSeverity?: \"warning\" | \"error\";\n\t\t\tcustomInstructions?: string;\n\t\t} = {},\n\t): void {\n\t\tthis._persistCompactionOutcome(reason, outcome, message);\n\t\tthis._emit({\n\t\t\ttype: \"compaction_end\",\n\t\t\treason,\n\t\t\tresult: undefined,\n\t\t\taborted: options.aborted ?? false,\n\t\t\twillRetry: false,\n\t\t\t// Aborts are user-initiated; they carry no error message on the event.\n\t\t\terrorMessage: options.aborted ? undefined : message,\n\t\t\terrorSeverity: options.errorSeverity,\n\t\t\tcustomInstructions: options.customInstructions,\n\t\t});\n\t}\n\n\tprivate _persistCompactionOutcome(\n\t\treason: CompactionOutcomeReason,\n\t\toutcome: CompactionOutcome,\n\t\tmessage: string,\n\t): void {\n\t\tlet outcomeMessage = createCompactionOutcomeMessage(message, {\n\t\t\treason,\n\t\t\toutcome,\n\t\t});\n\t\ttry {\n\t\t\tthis.sessionManager.appendCustomMessageEntryWithRollback(\n\t\t\t\toutcomeMessage.customType,\n\t\t\t\toutcomeMessage.content,\n\t\t\t\toutcomeMessage.display,\n\t\t\t\toutcomeMessage.details,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tconst persistenceError = error instanceof Error ? error.message : String(error);\n\t\t\toutcomeMessage = createCompactionOutcomeMessage(\n\t\t\t\t`${message}\\n\\nThis compaction outcome could not be saved to session history: ${persistenceError}`,\n\t\t\t\t{ reason, outcome },\n\t\t\t);\n\t\t\t// Not in the session file, so context rebuilds would drop the disclosure.\n\t\t\tthis._unpersistedOutcomes.push(outcomeMessage);\n\t\t}\n\t\tthis.agent.state.messages.push(outcomeMessage);\n\t\tthis._emit({ type: \"message_start\", message: outcomeMessage });\n\t\tthis._emit({ type: \"message_end\", message: outcomeMessage });\n\t}\n\n\tprivate async _runAutoCompaction(\n\t\treason: \"overflow\" | \"threshold\" | \"requested\",\n\t\twillRetry: boolean,\n\t): Promise<boolean> {\n\t\t// Any compaction consumes a pending model request and honors its instructions\n\t\t// (overflow recovery can fire first and take the request with it).\n\t\tconst pending = this._pendingRequestedCompaction;\n\t\tthis._pendingRequestedCompaction = undefined;\n\t\tconst customInstructions = pending?.customInstructions;\n\t\tconst shouldContinueAfterCompaction =\n\t\t\t(reason === \"threshold\" || reason === \"requested\") && this._continueAfterThresholdCompaction;\n\t\tconst queuedAutonomousContinuationsForThisCompaction =\n\t\t\treason === \"threshold\" && shouldContinueAfterCompaction\n\t\t\t\t? this._pendingThresholdCompactionAutonomousMessages.splice(0)\n\t\t\t\t: [];\n\t\tconst queuedGoalContinuationForThisCompaction =\n\t\t\treason === \"threshold\" && shouldContinueAfterCompaction ? this._queuedGoalThresholdContinuation : undefined;\n\t\tthis._continueAfterThresholdCompaction = false;\n\n\t\t// Requested/threshold stop the loop on purpose, so a failed or skipped compaction must not stall it.\n\t\t// Overflow stays excluded: a failed overflow recovery must not re-issue the overflowing request.\n\t\tconst resumeAfterFailure = () => {\n\t\t\tif (\n\t\t\t\t(reason === \"requested\" || reason === \"threshold\") &&\n\t\t\t\t(shouldContinueAfterCompaction || this.agent.hasQueuedMessages() || this.hasPendingSessionWork)\n\t\t\t) {\n\t\t\t\tthis._schedulePostCompactionContinue();\n\t\t\t}\n\t\t};\n\n\t\tthis._emit({ type: \"compaction_start\", reason, customInstructions });\n\t\tthis._autoCompactionAbortController = new AbortController();\n\n\t\ttry {\n\t\t\tconst authResult = this.model ? await this._modelRegistry.getApiKeyAndHeaders(this.model) : undefined;\n\t\t\tif (!this.model || !authResult || !authResult.ok || !authResult.apiKey) {\n\t\t\t\tconst detail =\n\t\t\t\t\t!this.model || !authResult\n\t\t\t\t\t\t? \"no model is selected\"\n\t\t\t\t\t\t: authResult.ok\n\t\t\t\t\t\t\t? \"no API key is available\"\n\t\t\t\t\t\t\t: authResult.error;\n\t\t\t\tthis._endCompactionUnsuccessfully(reason, \"failed\", `Compaction failed: ${detail}`);\n\t\t\t\tthis._clearQueuedAutonomousContinuationsAfterSkippedThresholdCompaction(\n\t\t\t\t\treason === \"threshold\" && shouldContinueAfterCompaction,\n\t\t\t\t\tqueuedAutonomousContinuationsForThisCompaction,\n\t\t\t\t);\n\t\t\t\tresumeAfterFailure();\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tconst result = await this._performCompaction({\n\t\t\t\tmodel: this.model,\n\t\t\t\tapiKey: authResult.apiKey,\n\t\t\t\theaders: authResult.headers,\n\t\t\t\tcustomInstructions,\n\t\t\t\tsignal: this._autoCompactionAbortController.signal,\n\t\t\t});\n\n\t\t\tthis._emit({\n\t\t\t\ttype: \"compaction_end\",\n\t\t\t\treason,\n\t\t\t\tresult,\n\t\t\t\taborted: false,\n\t\t\t\twillRetry,\n\t\t\t\tcustomInstructions,\n\t\t\t});\n\t\t\t// Queued work lives in both the agent queues and the session-owned queues.\n\t\t\tconst hasQueuedMessages = this.agent.hasQueuedMessages() || this.hasPendingSessionWork;\n\t\t\tconst willContinueAfterCompaction = willRetry || shouldContinueAfterCompaction || hasQueuedMessages;\n\n\t\t\tif (willRetry) {\n\t\t\t\tconst messages = this.agent.state.messages;\n\t\t\t\tconst lastMsg = messages[messages.length - 1];\n\t\t\t\tif (lastMsg?.role === \"assistant\" && (lastMsg as AssistantMessage).stopReason === \"error\") {\n\t\t\t\t\tthis.agent.state.messages = messages.slice(0, -1);\n\t\t\t\t}\n\n\t\t\t\tthis._schedulePostCompactionContinue();\n\t\t\t\tthis._scheduleAutoRefineAfterCompaction(willContinueAfterCompaction);\n\t\t\t\treturn true;\n\t\t\t} else if (shouldContinueAfterCompaction || hasQueuedMessages) {\n\t\t\t\t// Compaction can intentionally stop a tool loop between turns.\n\t\t\t\t// Queued follow-up/steering/custom messages can also be waiting.\n\t\t\t\tthis._schedulePostCompactionContinue();\n\t\t\t\tthis._scheduleAutoRefineAfterCompaction(willContinueAfterCompaction);\n\t\t\t} else {\n\t\t\t\tthis._scheduleAutoRefineAfterCompaction(willContinueAfterCompaction);\n\t\t\t}\n\t\t\treturn false;\n\t\t} catch (error) {\n\t\t\tthis._clearQueuedAutonomousContinuationsAfterSkippedThresholdCompaction(\n\t\t\t\treason === \"threshold\" && shouldContinueAfterCompaction,\n\t\t\t\tqueuedAutonomousContinuationsForThisCompaction,\n\t\t\t);\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"compaction failed\";\n\t\t\tconst aborted =\n\t\t\t\terrorMessage === \"Compaction cancelled\" || (error instanceof Error && error.name === \"AbortError\");\n\t\t\tif (aborted) {\n\t\t\t\tthis._clearQueuedGoalContinuationAfterCancelledThresholdCompaction(queuedGoalContinuationForThisCompaction);\n\t\t\t\tthis._endCompactionUnsuccessfully(\n\t\t\t\t\treason,\n\t\t\t\t\t\"cancelled\",\n\t\t\t\t\t`${reason === \"requested\" ? \"Requested c\" : \"C\"}ompaction cancelled`,\n\t\t\t\t\t{ aborted: true, customInstructions },\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (error instanceof CompactionSkippedError) {\n\t\t\t\tthis._endCompactionUnsuccessfully(\n\t\t\t\t\treason,\n\t\t\t\t\t\"skipped\",\n\t\t\t\t\treason === \"requested\"\n\t\t\t\t\t\t? `Requested compaction skipped: ${errorMessage}`\n\t\t\t\t\t\t: `Auto-compaction skipped: ${errorMessage}`,\n\t\t\t\t\t{ errorSeverity: \"warning\", customInstructions },\n\t\t\t\t);\n\t\t\t\tresumeAfterFailure();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tthis._endCompactionUnsuccessfully(\n\t\t\t\treason,\n\t\t\t\t\"failed\",\n\t\t\t\treason === \"overflow\"\n\t\t\t\t\t? `Context overflow recovery failed: ${errorMessage}`\n\t\t\t\t\t: reason === \"requested\"\n\t\t\t\t\t\t? `Requested compaction failed: ${errorMessage}`\n\t\t\t\t\t\t: `Auto-compaction failed: ${errorMessage}`,\n\t\t\t\t{ customInstructions },\n\t\t\t);\n\t\t\tresumeAfterFailure();\n\t\t\treturn false;\n\t\t} finally {\n\t\t\tthis._autoCompactionAbortController = undefined;\n\t\t\tthis._scheduleSessionInputPump();\n\t\t}\n\t}\n\n\tsetAutoCompactionEnabled(enabled: boolean): void {\n\t\tthis.settingsManager.setCompactionEnabled(enabled);\n\t}\n\n\tget autoCompactionEnabled(): boolean {\n\t\treturn this.settingsManager.getCompactionEnabled();\n\t}\n\n\t/**\n\t * Set the provider for extra env vars merged over process.env in extension\n\t * pi.exec() subprocesses. The function is read at exec time, so a host (e.g.\n\t * the daemon) can update the underlying value per attach without rebinding.\n\t */\n\tsetExecEnvProvider(provider: (() => Record<string, string | undefined> | undefined) | undefined): void {\n\t\tthis._execEnvProvider = provider;\n\t\tconst extensions = this._resourceLoader.getExtensions();\n\t\textensions.runtime.getExecEnv = provider;\n\t}\n\n\tasync bindExtensions(bindings: ExtensionBindings): Promise<void> {\n\t\tif (bindings.uiContext !== undefined) {\n\t\t\tthis._extensionUIContext = bindings.uiContext;\n\t\t}\n\t\tif (bindings.commandContextActions !== undefined) {\n\t\t\tthis._extensionCommandContextActions = bindings.commandContextActions;\n\t\t}\n\t\tif (bindings.shutdownHandler !== undefined) {\n\t\t\tthis._extensionShutdownHandler = bindings.shutdownHandler;\n\t\t}\n\t\tif (bindings.onError !== undefined) {\n\t\t\tthis._extensionErrorListener = bindings.onError;\n\t\t}\n\n\t\tthis._applyExtensionBindings(this._extensionRunner);\n\t\tawait this._extensionRunner.emit(this._sessionStartEvent);\n\t\tawait this.extendResourcesFromExtensions(this._sessionStartEvent.reason === \"reload\" ? \"reload\" : \"startup\");\n\t}\n\n\tprivate async extendResourcesFromExtensions(reason: \"startup\" | \"reload\"): Promise<void> {\n\t\tif (!this._extensionRunner.hasHandlers(\"resources_discover\")) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst { skillPaths, promptPaths, themePaths } = await this._extensionRunner.emitResourcesDiscover(\n\t\t\tthis._cwd,\n\t\t\treason,\n\t\t);\n\n\t\tif (skillPaths.length === 0 && promptPaths.length === 0 && themePaths.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst extensionPaths: ResourceExtensionPaths = {\n\t\t\tskillPaths: this.buildExtensionResourcePaths(skillPaths),\n\t\t\tpromptPaths: this.buildExtensionResourcePaths(promptPaths),\n\t\t\tthemePaths: this.buildExtensionResourcePaths(themePaths),\n\t\t};\n\n\t\tthis._resourceLoader.extendResources(extensionPaths);\n\t\tthis._baseSystemPrompt = this._rebuildSystemPrompt(this.getActiveToolNames());\n\t\tthis.agent.state.systemPrompt = this._baseSystemPrompt;\n\t}\n\n\tprivate buildExtensionResourcePaths(entries: Array<{ path: string; extensionPath: string }>): Array<{\n\t\tpath: string;\n\t\tmetadata: {\n\t\t\tsource: string;\n\t\t\tscope: \"temporary\";\n\t\t\torigin: \"top-level\";\n\t\t\tbaseDir?: string;\n\t\t};\n\t}> {\n\t\treturn entries.map((entry) => {\n\t\t\tconst source = this.getExtensionSourceLabel(entry.extensionPath);\n\t\t\tconst baseDir = entry.extensionPath.startsWith(\"<\") ? undefined : dirname(entry.extensionPath);\n\t\t\treturn {\n\t\t\t\tpath: entry.path,\n\t\t\t\tmetadata: {\n\t\t\t\t\tsource,\n\t\t\t\t\tscope: \"temporary\",\n\t\t\t\t\torigin: \"top-level\",\n\t\t\t\t\tbaseDir,\n\t\t\t\t},\n\t\t\t};\n\t\t});\n\t}\n\n\tprivate getExtensionSourceLabel(extensionPath: string): string {\n\t\tif (extensionPath.startsWith(\"<\")) {\n\t\t\treturn `extension:${extensionPath.replace(/[<>]/g, \"\")}`;\n\t\t}\n\t\tconst base = basename(extensionPath);\n\t\tconst name = base.replace(/\\.(ts|js)$/, \"\");\n\t\treturn `extension:${name}`;\n\t}\n\n\tprivate _applyExtensionBindings(runner: ExtensionRunner): void {\n\t\trunner.setUIContext(this._extensionUIContext);\n\t\trunner.bindCommandContext(this._extensionCommandContextActions);\n\n\t\tthis._extensionErrorUnsubscriber?.();\n\t\tthis._extensionErrorUnsubscriber = this._extensionErrorListener\n\t\t\t? runner.onError(this._extensionErrorListener)\n\t\t\t: undefined;\n\t}\n\n\tprivate _refreshCurrentModelFromRegistry(): void {\n\t\tconst currentModel = this.model;\n\t\tif (!currentModel) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst refreshedModel = this._modelRegistry.find(currentModel.provider, currentModel.id);\n\t\tif (!refreshedModel || refreshedModel === currentModel) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.agent.state.model = refreshedModel;\n\t}\n\n\tprivate _bindExtensionCore(runner: ExtensionRunner): void {\n\t\tconst getCommands = (): SlashCommandInfo[] => {\n\t\t\tconst extensionCommands: SlashCommandInfo[] = runner.getRegisteredCommands().map((command) => ({\n\t\t\t\tname: command.invocationName,\n\t\t\t\tdescription: command.description,\n\t\t\t\tsource: \"extension\",\n\t\t\t\tsourceInfo: command.sourceInfo,\n\t\t\t}));\n\n\t\t\tconst templates: SlashCommandInfo[] = this.promptTemplates.map((template) => ({\n\t\t\t\tname: template.name,\n\t\t\t\tdescription: template.description,\n\t\t\t\tsource: \"prompt\",\n\t\t\t\tsourceInfo: template.sourceInfo,\n\t\t\t}));\n\n\t\t\tconst skills: SlashCommandInfo[] = this._resourceLoader.getSkills().skills.map((skill) => ({\n\t\t\t\tname: `skill:${skill.name}`,\n\t\t\t\tdescription: skill.description,\n\t\t\t\tsource: \"skill\",\n\t\t\t\tsourceInfo: skill.sourceInfo,\n\t\t\t}));\n\n\t\t\treturn [...extensionCommands, ...templates, ...skills];\n\t\t};\n\n\t\trunner.bindCore(\n\t\t\t{\n\t\t\t\tsendMessage: (message, options) => {\n\t\t\t\t\tthis.sendCustomMessage(message, options).catch((err) => {\n\t\t\t\t\t\trunner.emitError({\n\t\t\t\t\t\t\textensionPath: \"<runtime>\",\n\t\t\t\t\t\t\tevent: \"send_message\",\n\t\t\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tsendUserMessage: (content, options) => {\n\t\t\t\t\tthis.sendUserMessage(content, options).catch((err) => {\n\t\t\t\t\t\trunner.emitError({\n\t\t\t\t\t\t\textensionPath: \"<runtime>\",\n\t\t\t\t\t\t\tevent: \"send_user_message\",\n\t\t\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tappendEntry: (customType, data) => {\n\t\t\t\t\tthis.sessionManager.appendCustomEntry(customType, data);\n\t\t\t\t},\n\t\t\t\tsetSessionName: async (name) => {\n\t\t\t\t\tif (this._agentMessageController?.setSessionName) {\n\t\t\t\t\t\tawait this._agentMessageController.setSessionName(name);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tthis.setSessionName(name);\n\t\t\t\t},\n\t\t\t\tgetSessionName: () => {\n\t\t\t\t\treturn this.sessionManager.getSessionName();\n\t\t\t\t},\n\t\t\t\tsetLabel: (entryId, label) => {\n\t\t\t\t\tthis.sessionManager.appendLabelChange(entryId, label);\n\t\t\t\t},\n\t\t\t\tgetActiveTools: () => this.getActiveToolNames(),\n\t\t\t\tgetAllTools: () => this.getAllTools(),\n\t\t\t\tsetActiveTools: (toolNames) => this.setActiveToolsByName(toolNames),\n\t\t\t\trefreshTools: () => this._refreshToolRegistry(),\n\t\t\t\tgetCommands,\n\t\t\t\tsetModel: async (model) => {\n\t\t\t\t\tif (!this.modelRegistry.hasConfiguredAuth(model)) return false;\n\t\t\t\t\tawait this.setModel(model);\n\t\t\t\t\treturn true;\n\t\t\t\t},\n\t\t\t\tgetThinkingLevel: () => this.thinkingLevel,\n\t\t\t\tsetThinkingLevel: (level) => this.setThinkingLevel(level),\n\t\t\t},\n\t\t\t{\n\t\t\t\tgetModel: () => this.model,\n\t\t\t\tisIdle: () => !this.isStreaming,\n\t\t\t\tgetSignal: () => this.agent.signal,\n\t\t\t\tabort: () => this.abort(),\n\t\t\t\thasPendingMessages: () => this.queuedActionCount > 0,\n\t\t\t\tshutdown: () => {\n\t\t\t\t\tthis._extensionShutdownHandler?.();\n\t\t\t\t},\n\t\t\t\tgetContextUsage: () => this.getContextUsage(),\n\t\t\t\tcompact: (options) => {\n\t\t\t\t\tvoid (async () => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst result = await this.compact(options?.customInstructions);\n\t\t\t\t\t\t\toptions?.onComplete?.(result);\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tconst err = error instanceof Error ? error : new Error(String(error));\n\t\t\t\t\t\t\toptions?.onError?.(err);\n\t\t\t\t\t\t}\n\t\t\t\t\t})();\n\t\t\t\t},\n\t\t\t\tgetSystemPrompt: () => this.systemPrompt,\n\t\t\t},\n\t\t\t{\n\t\t\t\tregisterProvider: (name, config) => {\n\t\t\t\t\tthis._modelRegistry.registerProvider(name, config);\n\t\t\t\t\tthis._refreshCurrentModelFromRegistry();\n\t\t\t\t},\n\t\t\t\tunregisterProvider: (name) => {\n\t\t\t\t\tthis._modelRegistry.unregisterProvider(name);\n\t\t\t\t\tthis._refreshCurrentModelFromRegistry();\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t}\n\n\tprivate _refreshToolRegistry(options?: { activeToolNames?: string[]; includeAllExtensionTools?: boolean }): void {\n\t\tconst previousRegistryNames = new Set(this._toolRegistry.keys());\n\t\tconst previousActiveToolNames = this.getActiveToolNames();\n\t\tconst allowedToolNames = this._allowedToolNames;\n\t\tconst registeredTools = this._extensionRunner.getAllRegisteredTools();\n\t\tconst sdkToolEntry = (definition: ToolDefinition) => ({\n\t\t\tdefinition,\n\t\t\tsourceInfo: createSyntheticSourceInfo(`<sdk:${definition.name}>`, {\n\t\t\t\tsource: \"sdk\" as const,\n\t\t\t}),\n\t\t});\n\t\tconst allCustomTools = [\n\t\t\t...registeredTools,\n\t\t\t...this._customTools.map(sdkToolEntry),\n\t\t\t...this._acpMcpTools.map(sdkToolEntry),\n\t\t];\n\t\tconst isAllowedTool = (name: string): boolean => !allowedToolNames || allowedToolNames.has(name);\n\t\tconst allowedCustomTools = allCustomTools.filter((tool) => isAllowedTool(tool.definition.name));\n\t\tconst definitionRegistry = new Map<string, ToolDefinitionEntry>(\n\t\t\tArray.from(this._baseToolDefinitions.entries())\n\t\t\t\t.filter(([name]) => isAllowedTool(name))\n\t\t\t\t.map(([name, definition]) => [\n\t\t\t\t\tname,\n\t\t\t\t\t{\n\t\t\t\t\t\tdefinition,\n\t\t\t\t\t\tsourceInfo: createSyntheticSourceInfo(`<builtin:${name}>`, {\n\t\t\t\t\t\t\tsource: \"builtin\",\n\t\t\t\t\t\t}),\n\t\t\t\t\t},\n\t\t\t\t]),\n\t\t);\n\t\tfor (const tool of allowedCustomTools) {\n\t\t\tdefinitionRegistry.set(tool.definition.name, {\n\t\t\t\tdefinition: tool.definition,\n\t\t\t\tsourceInfo: tool.sourceInfo,\n\t\t\t});\n\t\t}\n\t\tthis._toolDefinitions = definitionRegistry;\n\t\tthis._toolPromptSnippets = new Map(\n\t\t\tArray.from(definitionRegistry.values())\n\t\t\t\t.map(({ definition }) => {\n\t\t\t\t\tconst snippet = this._normalizePromptSnippet(definition.promptSnippet);\n\t\t\t\t\treturn snippet ? ([definition.name, snippet] as const) : undefined;\n\t\t\t\t})\n\t\t\t\t.filter((entry): entry is readonly [string, string] => entry !== undefined),\n\t\t);\n\t\tthis._toolPromptGuidelines = new Map(\n\t\t\tArray.from(definitionRegistry.values())\n\t\t\t\t.map(({ definition }) => {\n\t\t\t\t\tconst guidelines = this._normalizePromptGuidelines(definition.promptGuidelines);\n\t\t\t\t\treturn guidelines.length > 0 ? ([definition.name, guidelines] as const) : undefined;\n\t\t\t\t})\n\t\t\t\t.filter((entry): entry is readonly [string, string[]] => entry !== undefined),\n\t\t);\n\t\tconst runner = this._extensionRunner;\n\t\tconst wrappedExtensionTools = wrapRegisteredTools(allowedCustomTools, runner);\n\t\t// Resolve the runner at call time so a rebuild/reload rebinds built-in tools to the\n\t\t// live runner instead of wedging them on the invalidated one's stale-ctx guard.\n\t\tconst wrappedBuiltInTools = wrapRegisteredTools(\n\t\t\tArray.from(this._baseToolDefinitions.values())\n\t\t\t\t.filter((definition) => isAllowedTool(definition.name))\n\t\t\t\t.map((definition) => ({\n\t\t\t\t\tdefinition,\n\t\t\t\t\tsourceInfo: createSyntheticSourceInfo(`<builtin:${definition.name}>`, { source: \"builtin\" }),\n\t\t\t\t})),\n\t\t\t() => this._extensionRunner,\n\t\t);\n\n\t\tconst toolRegistry = new Map(wrappedBuiltInTools.map((tool) => [tool.name, tool]));\n\t\tfor (const tool of wrappedExtensionTools as AgentTool[]) {\n\t\t\ttoolRegistry.set(tool.name, tool);\n\t\t}\n\t\tthis._toolRegistry = toolRegistry;\n\n\t\tconst nextActiveToolNames = (\n\t\t\toptions?.activeToolNames ? [...options.activeToolNames] : [...previousActiveToolNames]\n\t\t).filter((name) => isAllowedTool(name));\n\n\t\tif (allowedToolNames) {\n\t\t\tfor (const toolName of this._toolRegistry.keys()) {\n\t\t\t\tif (allowedToolNames.has(toolName)) {\n\t\t\t\t\tnextActiveToolNames.push(toolName);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (options?.includeAllExtensionTools) {\n\t\t\tfor (const tool of wrappedExtensionTools) {\n\t\t\t\tnextActiveToolNames.push(tool.name);\n\t\t\t}\n\t\t} else if (!options?.activeToolNames) {\n\t\t\tfor (const toolName of this._toolRegistry.keys()) {\n\t\t\t\tif (!previousRegistryNames.has(toolName)) {\n\t\t\t\t\tnextActiveToolNames.push(toolName);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.setActiveToolsByName([...new Set(nextActiveToolNames)]);\n\t}\n\n\tprivate _buildRuntime(options: {\n\t\tactiveToolNames?: string[];\n\t\tflagValues?: Map<string, boolean | string>;\n\t\tincludeAllExtensionTools?: boolean;\n\t}): void {\n\t\tconst pythonSkills = getPythonSkillRuntimeInfo(this._modelVisibleSkills());\n\t\tlet configuredBaseToolDefinitions: Record<string, ToolDefinition>;\n\t\tif (this._baseToolsOverride) {\n\t\t\tconfiguredBaseToolDefinitions = Object.fromEntries(\n\t\t\t\tObject.entries(this._baseToolsOverride).map(([name, tool]) => [\n\t\t\t\t\tname,\n\t\t\t\t\tcreateToolDefinitionFromAgentTool(tool),\n\t\t\t\t]),\n\t\t\t);\n\t\t} else {\n\t\t\t// Rebuilding (e.g. /reload) replaces the provisioner; drop the previous\n\t\t\t// kernel so the session never holds two live kernels. Gate the new kernel's\n\t\t\t// startup on the old one's dispose (which flushes a final snapshot), so a\n\t\t\t// reload can't restore from a snapshot the old kernel is still writing.\n\t\t\tconst previousDispose = this._ipythonKernelProvisioner?.dispose();\n\t\t\tthis._ipythonKernelSnapshotDir = this.sessionManager.getSessionArtifactDir();\n\t\t\t// Only surface the \"revived from your previous session\" notice on the first\n\t\t\t// build (a genuine resume). A later rebuild (/reload) restores state silently\n\t\t\t// for continuity — the conversation is unchanged, so there's nothing to flag.\n\t\t\tconst notifyRestore = !this._ipythonRuntimeBuilt;\n\t\t\tthis._ipythonKernelProvisioner = new IpythonKernelProvisioner(this._cwd, {\n\t\t\t\tenv: this._rlmKernelEnv(),\n\t\t\t\tcommandPrefix: this.settingsManager.getShellCommandPrefix(),\n\t\t\t\tshellPath: this.settingsManager.getShellPath(),\n\t\t\t\tsessionId: this.sessionId,\n\t\t\t\thostHandlers: this._createKernelHostHandlers(),\n\t\t\t\tpythonSkills,\n\t\t\t\tsnapshotDir: this._ipythonKernelSnapshotDir,\n\t\t\t\treadyGate: previousDispose,\n\t\t\t\tonRestore: notifyRestore ? (result) => this._onIpythonStateRestored(result) : undefined,\n\t\t\t});\n\t\t\tconfiguredBaseToolDefinitions = createAllToolDefinitions(this._cwd, {\n\t\t\t\tipython: {\n\t\t\t\t\tprovisioner: this._ipythonKernelProvisioner,\n\t\t\t\t\tcommandPrefix: this.settingsManager.getShellCommandPrefix(),\n\t\t\t\t\tshellPath: this.settingsManager.getShellPath(),\n\t\t\t\t\tonLateSentAgentMessage: (toolCallId, message) =>\n\t\t\t\t\t\tthis._recordLateIpythonSentAgentMessage(toolCallId, message),\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\tthis._baseToolDefinitions = new Map(\n\t\t\tObject.entries(configuredBaseToolDefinitions).map(([name, tool]) => [name, tool as ToolDefinition]),\n\t\t);\n\n\t\tconst extensionsResult = this._resourceLoader.getExtensions();\n\t\tif (options.flagValues) {\n\t\t\tfor (const [name, value] of options.flagValues) {\n\t\t\t\textensionsResult.runtime.flagValues.set(name, value);\n\t\t\t}\n\t\t}\n\t\t// Re-apply on (re)build so the provider survives /reload. Guarded: the\n\t\t// runtime object can be shared across sessions from one ResourceLoader\n\t\t// (RLM children), so a provider-less session must not wipe the owner's.\n\t\tif (this._execEnvProvider) {\n\t\t\textensionsResult.runtime.getExecEnv = this._execEnvProvider;\n\t\t}\n\n\t\tthis._extensionRunner = new ExtensionRunner(\n\t\t\textensionsResult.extensions,\n\t\t\textensionsResult.runtime,\n\t\t\tthis._cwd,\n\t\t\tthis.sessionManager,\n\t\t\tthis._modelRegistry,\n\t\t);\n\t\tif (this._extensionRunnerRef) {\n\t\t\tthis._extensionRunnerRef.current = this._extensionRunner;\n\t\t}\n\t\tthis._bindExtensionCore(this._extensionRunner);\n\t\tthis._applyExtensionBindings(this._extensionRunner);\n\n\t\tconst previousAcpMcpToolNames = new Set(this._acpMcpTools.map((tool) => tool.name));\n\t\tconst acpServers = this._mcpManager?.getAcpServers() ?? [];\n\t\tif (acpServers.length > 0 && !this._ipythonKernelProvisioner) {\n\t\t\tthrow new Error(\"ACP MCP servers require the built-in cpython tool\");\n\t\t}\n\t\tconst acpMcpTools = this._ipythonKernelProvisioner\n\t\t\t? createAcpMcpToolDefinitions(acpServers, this._ipythonKernelProvisioner)\n\t\t\t: [];\n\t\tthis._assertAcpMcpToolNamesAvailable(acpMcpTools.map((tool) => tool.name));\n\t\tfor (const name of previousAcpMcpToolNames) this._allowedToolNames?.delete(name);\n\t\tfor (const tool of acpMcpTools) this._allowedToolNames?.add(tool.name);\n\t\tthis._acpMcpTools = acpMcpTools;\n\n\t\tconst defaultActiveToolNames = this._baseToolsOverride ? Object.keys(this._baseToolsOverride) : [\"ipython\"];\n\t\tconst baseActiveToolNames = [...(options.activeToolNames ?? defaultActiveToolNames)];\n\t\tif (this._goalState.status === \"active\" && this._includeGoals) {\n\t\t\t// An active goal needs ipython so the model can reach the goal skill.\n\t\t\tbaseActiveToolNames.push(\"ipython\");\n\t\t}\n\t\tthis._refreshToolRegistry({\n\t\t\tactiveToolNames: [...new Set(baseActiveToolNames)],\n\t\t\tincludeAllExtensionTools: options.includeAllExtensionTools,\n\t\t});\n\n\t\t// Prewarm when configured, or whenever we're resuming a session that already\n\t\t// has a kernel snapshot — so its state is revived and the model is told what\n\t\t// came back before the first turn, rather than a turn later when the kernel\n\t\t// would otherwise lazily start on first use.\n\t\tconst hasSnapshot =\n\t\t\t!!this._ipythonKernelSnapshotDir && existsSync(snapshotPathIn(this._ipythonKernelSnapshotDir));\n\t\tif ((this._prewarmIpythonKernel || hasSnapshot) && this.getActiveToolNames().includes(\"ipython\")) {\n\t\t\tthis._ipythonKernelProvisioner?.prewarm();\n\t\t}\n\n\t\t// Subsequent builds are in-process rebuilds (/reload), not a fresh resume.\n\t\tthis._ipythonRuntimeBuilt = true;\n\t}\n\n\t/**\n\t * Skills exposed to the model (system prompt + kernel). The bundled goal\n\t * and compact skills are withheld when disabled for this session.\n\t */\n\tprivate _modelVisibleSkills(): Skill[] {\n\t\tlet skills = this._resourceLoader.getSkills().skills;\n\t\tif (!this._includeGoals) {\n\t\t\tskills = skills.filter((skill) => skill.name !== GOAL_SKILL_NAME);\n\t\t}\n\t\tif (!this._includeCompactSkill) {\n\t\t\tskills = skills.filter((skill) => skill.name !== COMPACT_SKILL_NAME);\n\t\t}\n\t\tif (!this._autoRefineAllowedForSession()) {\n\t\t\tskills = skills.filter((skill) => skill.name !== REFINE_SKILL_NAME);\n\t\t}\n\t\tif (!this._agentMessageController) {\n\t\t\tskills = skills.filter((skill) => skill.name !== AGENT_MESSAGE_SKILL_NAME);\n\t\t}\n\t\tif (!this._agentObserveController) {\n\t\t\tskills = skills.filter((skill) => skill.name !== AGENT_OBSERVE_SKILL_NAME);\n\t\t}\n\t\tif (!this._agentObserveController || !this._rlmHeartbeatController) {\n\t\t\tskills = skills.filter((skill) => skill.name !== ORCHESTRATION_HEARTBEAT_SKILL_NAME);\n\t\t}\n\t\treturn skills;\n\t}\n\n\tprivate async _handleBackgroundProcessCompleted(payload: Record<string, unknown>): Promise<Record<string, unknown>> {\n\t\tconst completionId = payload.completion_id;\n\t\tconst pid = payload.pid;\n\t\tconst command = payload.command;\n\t\tconst exitCode = payload.exit_code;\n\t\tconst duration = payload.duration;\n\t\tif (typeof completionId !== \"string\" || !/^[a-f0-9]{32}$/.test(completionId)) {\n\t\t\tthrow new Error(\"bash.completed requires a valid completion_id\");\n\t\t}\n\t\tif (!Number.isSafeInteger(pid) || (pid as number) <= 0) {\n\t\t\tthrow new Error(\"bash.completed requires a positive integer pid\");\n\t\t}\n\t\tif (typeof command !== \"string\" || command.length === 0 || command.length > 100_000) {\n\t\t\tthrow new Error(\"bash.completed requires a non-empty command\");\n\t\t}\n\t\tif (!Number.isSafeInteger(exitCode)) {\n\t\t\tthrow new Error(\"bash.completed requires an integer exit_code\");\n\t\t}\n\t\tif (typeof duration !== \"number\" || !Number.isFinite(duration) || duration < 0) {\n\t\t\tthrow new Error(\"bash.completed requires a non-negative duration\");\n\t\t}\n\t\tif (this._backgroundProcessCompletionIds.has(completionId)) {\n\t\t\treturn { accepted: false, duplicate: true };\n\t\t}\n\t\tthis._backgroundProcessCompletionIds.add(completionId);\n\t\twhile (this._backgroundProcessCompletionIds.size > 1_024) {\n\t\t\tconst oldest = this._backgroundProcessCompletionIds.values().next().value;\n\t\t\tif (oldest === undefined) break;\n\t\t\tthis._backgroundProcessCompletionIds.delete(oldest);\n\t\t}\n\t\ttry {\n\t\t\tconst message = createBackgroundProcessCompletedMessage({\n\t\t\t\tcompletionId,\n\t\t\t\tpid: pid as number,\n\t\t\t\tcommand,\n\t\t\t\texitCode: exitCode as number,\n\t\t\t\tduration,\n\t\t\t});\n\t\t\tawait this._promptInjectedMessage(message.content as string, message, {\n\t\t\t\tstreamingBehavior: \"followUp\",\n\t\t\t\tqueueIfBusy: true,\n\t\t\t\tresumeIfIdle: true,\n\t\t\t\treturnAfterAccepted: true,\n\t\t\t\tsuppressAutonomousContinuation: true,\n\t\t\t\tsource: \"extension\",\n\t\t\t});\n\t\t\treturn { accepted: true };\n\t\t} catch (error) {\n\t\t\tthis._backgroundProcessCompletionIds.delete(completionId);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprivate _createKernelHostHandlers(): HostRequestHandlers {\n\t\tconst handlers: HostRequestHandlers = {\n\t\t\t\"rlm.run\": createRlmRunHostHandler(async ({ prompt, kwargs, cellSourceCode }) => ({\n\t\t\t\t...(await this.runRlmChild(prompt, kwargs, cellSourceCode)),\n\t\t\t})),\n\t\t\t\"rlm.find_models\": createRlmFindModelsHostHandler((query, limit) => this.findRlmModels(query, limit)),\n\t\t\t\"rlm.list_subagents\": createRlmListSubagentsHostHandler(() => this.listRlmSubagents()),\n\t\t\t\"rlm.delete_subagent\": createRlmDeleteSubagentHostHandler((target) => this.deleteRlmSubagent(target)),\n\t\t\t\"model.info\": async () => ({\n\t\t\t\tid: this.model?.id ?? null,\n\t\t\t\tprovider: this.model?.provider ?? null,\n\t\t\t\tinput: this.model?.input ?? [],\n\t\t\t}),\n\t\t\t\"bash.completed\": async (payload) => this._handleBackgroundProcessCompleted(payload),\n\t\t};\n\t\tif (this._includeGoals) {\n\t\t\tfor (const type of [\"goal.get\", \"goal.create\", \"goal.complete\"]) {\n\t\t\t\thandlers[type] = async (payload) => this.handleGoalHostRequest(type, payload);\n\t\t\t}\n\t\t}\n\t\tif (this._includeCompactSkill) {\n\t\t\tfor (const type of [\"compact.run\", \"compact.status\"]) {\n\t\t\t\thandlers[type] = async (payload) => this.handleCompactHostRequest(type, payload);\n\t\t\t}\n\t\t}\n\t\tif (this._autoRefineAllowedForSession()) {\n\t\t\tfor (const type of [\"refine.run\", \"refine.status\"]) {\n\t\t\t\thandlers[type] = async (payload) => this.handleRefineHostRequest(type, payload);\n\t\t\t}\n\t\t}\n\t\tif (this._rlmHeartbeatController) {\n\t\t\tfor (const type of [\n\t\t\t\t\"rlm_heartbeat.list\",\n\t\t\t\t\"rlm_heartbeat.create\",\n\t\t\t\t\"rlm_heartbeat.update\",\n\t\t\t\t\"rlm_heartbeat.delete\",\n\t\t\t]) {\n\t\t\t\thandlers[type] = async (payload) => this.handleRlmHeartbeatHostRequest(type, payload);\n\t\t\t}\n\t\t}\n\t\tconst visibleKernelSkillNames = new Set(\n\t\t\tthis._modelVisibleSkills()\n\t\t\t\t.filter((skill) => !skill.disableModelInvocation)\n\t\t\t\t.map((skill) => skill.name),\n\t\t);\n\t\tif (this._agentMessageController && visibleKernelSkillNames.has(AGENT_MESSAGE_SKILL_NAME)) {\n\t\t\tObject.assign(\n\t\t\t\thandlers,\n\t\t\t\tcreateAgentMessageHostHandlers({\n\t\t\t\t\troster: async () =>\n\t\t\t\t\t\t(await this.handleAgentMessageHostRequest(\"agent_message.list_agents\")) as AgentFamilyRosterResult,\n\t\t\t\t\tawaitPendingChildPublication: (selector) => this._awaitPendingRlmChildPublication(selector),\n\t\t\t\t\tsendAgentMessage: async (input) => {\n\t\t\t\t\t\tconst receipt = (await this.handleAgentMessageHostRequest(\"agent_message.send\", {\n\t\t\t\t\t\t\ttarget: input.target,\n\t\t\t\t\t\t\tmessage: input.message,\n\t\t\t\t\t\t})) as AgentSessionMessageReceipt;\n\t\t\t\t\t\tif (this._rlmDepth > 0) {\n\t\t\t\t\t\t\tlet addressedParent = input.receiverRole === \"parent\";\n\t\t\t\t\t\t\tif (input.receiverRole === undefined && this._agentMessageController?.roster) {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst roster = await this._agentMessageController.roster();\n\t\t\t\t\t\t\t\t\taddressedParent = roster.entries.some(\n\t\t\t\t\t\t\t\t\t\t(entry) =>\n\t\t\t\t\t\t\t\t\t\t\tentry.relationship === \"parent\" &&\n\t\t\t\t\t\t\t\t\t\t\t(entry.id === input.target || entry.name === input.target),\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\taddressedParent = false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (addressedParent) {\n\t\t\t\t\t\t\t\tthis._repliedToParentSinceTask = true;\n\t\t\t\t\t\t\t\tthis._parentReplyCount += 1;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn receipt;\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tif (this._agentObserveController) {\n\t\t\tObject.assign(\n\t\t\t\thandlers,\n\t\t\t\tcreateAgentObserveHostHandlers({\n\t\t\t\t\tlistAgents: () => this.handleAgentObserveHostRequest(\"agent_observe.list\") as AgentObserveListResult,\n\t\t\t\t\tgetAgent: (target) =>\n\t\t\t\t\t\tthis.handleAgentObserveHostRequest(\"agent_observe.get\", {\n\t\t\t\t\t\t\ttarget,\n\t\t\t\t\t\t}) as AgentObserveAgentSnapshot,\n\t\t\t\t\trecentMessages: (input) =>\n\t\t\t\t\t\tthis.handleAgentObserveHostRequest(\"agent_observe.recent\", {\n\t\t\t\t\t\t\ttarget: input.target,\n\t\t\t\t\t\t\tlimit: input.limit,\n\t\t\t\t\t\t\tmax_chars: input.maxChars,\n\t\t\t\t\t\t}) as AgentObserveRecentMessagesResult,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tif (this._mcpManager) {\n\t\t\tObject.assign(handlers, this._mcpManager.hostHandlers());\n\t\t}\n\t\treturn handlers;\n\t}\n\n\tasync reload(): Promise<void> {\n\t\tconst previousFlagValues = this._extensionRunner.getFlagValues();\n\t\tawait emitSessionShutdownEvent(this._extensionRunner, {\n\t\t\ttype: \"session_shutdown\",\n\t\t\treason: \"reload\",\n\t\t});\n\t\tawait this.settingsManager.reload();\n\t\t// Re-read auth.json: a login saved by the client process (daemon mode) must be\n\t\t// visible here so MCP skill gating sees the new credentials.\n\t\tthis._modelRegistry.authStorage.reload();\n\t\tresetApiProviders();\n\t\tthis._mcpManager?.refresh();\n\t\tawait this._resourceLoader.reload();\n\t\tthis._buildRuntime({\n\t\t\tactiveToolNames: this.getActiveToolNames(),\n\t\t\tflagValues: previousFlagValues,\n\t\t\tincludeAllExtensionTools: true,\n\t\t});\n\n\t\tconst hasBindings =\n\t\t\tthis._extensionUIContext ||\n\t\t\tthis._extensionCommandContextActions ||\n\t\t\tthis._extensionShutdownHandler ||\n\t\t\tthis._extensionErrorListener;\n\t\tif (hasBindings) {\n\t\t\tawait this._extensionRunner.emit({\n\t\t\t\ttype: \"session_start\",\n\t\t\t\treason: \"reload\",\n\t\t\t});\n\t\t\tawait this.extendResourcesFromExtensions(\"reload\");\n\t\t}\n\t}\n\n\tprivate _rlmKernelEnv(): Record<string, string> {\n\t\t// Kernel env is provisioning-time only: RLM_MAX_DEPTH may be stale in an already-running kernel;\n\t\t// the TypeScript-side spawn check remains authoritative.\n\t\tconst env: Record<string, string> = {\n\t\t\tRLM_DEPTH: String(this._rlmDepth),\n\t\t\tRLM_MAX_DEPTH: String(this._rlmMaxDepth),\n\t\t\tRLM_GLOBAL_HARNESS_STATE_DIR: getGlobalHarnessStateDir(),\n\t\t};\n\t\tconst rlmSessionDir = this._ensureRlmSessionDir();\n\t\tif (rlmSessionDir) {\n\t\t\tenv.RLM_SESSION_DIR = rlmSessionDir;\n\t\t\t// Keep kernel writes and host reads (system prompt, review, /refine) on\n\t\t\t// the same local harness path. Subagents prefer their own artifact dir;\n\t\t\t// ephemeral sessions fall back to the RLM session dir once it exists.\n\t\t\tenv.RLM_HARNESS_STATE_DIR = this._localHarnessStateDir() ?? getLocalHarnessStateDir(rlmSessionDir)!;\n\t\t}\n\t\tthis._addWebsearchKeyEnv(env);\n\t\treturn env;\n\t}\n\n\tprivate _addWebsearchKeyEnv(env: Record<string, string>): void {\n\t\tif (this._agentDir) {\n\t\t\tenv.ASM_AGENT_CODING_AGENT_DIR = this._agentDir;\n\t\t}\n\n\t\tif (process.env[SERPER_ENV_VAR]?.trim()) {\n\t\t\treturn;\n\t\t}\n\t\t// Inject only when a websearch skill (bundled or custom) is actually loaded,\n\t\t// so the key isn't exposed to kernels that can't use it.\n\t\tif (!this._resourceLoader.getSkills().skills.some((skill) => skill.name === WEBSEARCH_SKILL_NAME)) {\n\t\t\treturn;\n\t\t}\n\t\tconst cred = this._modelRegistry.authStorage.get(SERPER_CREDENTIAL_ID);\n\t\tif (cred?.type !== \"api_key\") {\n\t\t\treturn;\n\t\t}\n\t\tconst resolved = resolveConfigValue(cred.key)?.trim();\n\t\tif (resolved) {\n\t\t\tenv[SERPER_ENV_VAR] = resolved;\n\t\t}\n\t}\n\n\t// Undefined when there's no persistent artifact dir (e.g. the viewer client):\n\t// don't mkdtemp here, since this runs on every kernel build but a viewer never\n\t// does RLM work. The temp dir is created lazily in _createChildRlmSessionDir.\n\tprivate _ensureRlmSessionDir(): string | undefined {\n\t\tif (this._rlmSessionDir) {\n\t\t\tmkdirSync(this._rlmSessionDir, { recursive: true });\n\t\t\treturn this._rlmSessionDir;\n\t\t}\n\n\t\tconst sessionArtifactDir = this.sessionManager.getSessionArtifactDir();\n\t\tif (sessionArtifactDir) {\n\t\t\tmkdirSync(sessionArtifactDir, { recursive: true });\n\t\t\tthis._rlmSessionDir = sessionArtifactDir;\n\t\t\treturn sessionArtifactDir;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tprivate _createChildRlmSessionDir(): string {\n\t\tconst parentDir = this._ensureRlmSessionDir() ?? this._createEphemeralRlmSessionDir();\n\t\tfor (let i = 0; i < 100; i++) {\n\t\t\tconst childDir = join(parentDir, `sub-${randomUUID().slice(0, 8)}`);\n\t\t\ttry {\n\t\t\t\tmkdirSync(childDir);\n\t\t\t\treturn childDir;\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof Error && \"code\" in error && error.code === \"EEXIST\") {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\tthrow new Error(\"Unable to create unique RLM child session directory\");\n\t}\n\n\tprivate _createEphemeralRlmSessionDir(): string {\n\t\tthis._rlmSessionDir = mkdtempSync(join(tmpdir(), \"asm-agent-rlm-\"));\n\t\treturn this._rlmSessionDir;\n\t}\n\n\t_contextTokensForCurrentMessages(): number | undefined {\n\t\tconst last = this._findLastAssistantMessage();\n\t\treturn last ? calculateContextTokens(last.usage) : undefined;\n\t}\n\n\tsetCurrentRecap(recap: string | undefined): void {\n\t\tif (this._currentRecap === recap) return;\n\t\tthis._currentRecap = recap;\n\t\tthis._emit({ type: \"recap_update\", recap });\n\t}\n\n\tget repliedToParentSinceTask(): boolean | undefined {\n\t\treturn this._repliedToParentSinceTask;\n\t}\n\n\tgetCurrentRecap(): string | undefined {\n\t\treturn this._currentRecap;\n\t}\n\n\tprivate _findAssistantEntryForMessage(message: AssistantMessage): SessionMessageEntry | undefined {\n\t\treturn this.sessionManager\n\t\t\t.getEntries()\n\t\t\t.find((entry): entry is SessionMessageEntry => entry.type === \"message\" && entry.message === message);\n\t}\n\n\tprivate _createRlmSubagentRuntimeOptions(options: {\n\t\tid: string;\n\t\tprompt: string;\n\t\tsessionName: string;\n\t\tspawnCode?: string;\n\t\tsessionDir: string;\n\t\tmodel: Model<any>;\n\t\tthinkingLevel?: ThinkingLevel;\n\t}): CreateRlmSubagentRuntimeOptions {\n\t\treturn {\n\t\t\tparentSession: this,\n\t\t\tid: options.id,\n\t\t\tprompt: options.prompt,\n\t\t\tsessionName: options.sessionName,\n\t\t\tspawnCode: options.spawnCode,\n\t\t\tsessionDir: options.sessionDir,\n\t\t\tmodel: options.model,\n\t\t\tthinkingLevel:\n\t\t\t\toptions.thinkingLevel ?? (clampThinkingLevel(options.model, this.thinkingLevel) as ThinkingLevel),\n\t\t\tserviceTier:\n\t\t\t\tthis.serviceTier === \"priority\" && !supportsFastMode(options.model) ? \"default\" : this.serviceTier,\n\t\t\tscopedModels: [...this._scopedModels],\n\t\t\tactiveToolNames: this.getActiveToolNames(),\n\t\t\tallowedToolNames: this._allowedToolNames ? [...this._allowedToolNames] : undefined,\n\t\t\tcustomTools: [...this._customTools],\n\t\t\tincludeGoals: this._includeGoals,\n\t\t\tincludeCompactSkill: this._includeCompactSkill,\n\t\t\trlmDepth: this._rlmDepth + 1,\n\t\t\trlmMaxDepth: this._rlmMaxDepth,\n\t\t\trlmParentNodeId: options.id,\n\t\t};\n\t}\n\n\tprivate async _createRlmSubagentRuntime(options: CreateRlmSubagentRuntimeOptions): Promise<RlmSubagentRuntime> {\n\t\tif (this._subagentRuntimeHost) {\n\t\t\treturn await this._subagentRuntimeHost.createRlmSubagentRuntime(options);\n\t\t}\n\n\t\treturn this._createInlineRlmSubagentRuntime(options);\n\t}\n\n\tprivate _createInlineRlmSubagentRuntime(options: CreateRlmSubagentRuntimeOptions): RlmSubagentRuntime {\n\t\tconst childSessionManager = SessionManager.create(this._cwd, options.sessionDir);\n\t\tif (options.parentSession.sessionFile) {\n\t\t\tchildSessionManager.newSession({\n\t\t\t\tparentSession: options.parentSession.sessionFile,\n\t\t\t\trlmDepth: options.rlmDepth,\n\t\t\t});\n\t\t}\n\t\tchildSessionManager.appendModelChange(options.model.provider, options.model.id);\n\t\tchildSessionManager.appendThinkingLevelChange(options.thinkingLevel);\n\t\tchildSessionManager.appendServiceTierChange(options.serviceTier);\n\n\t\tconst childAgent = new Agent({\n\t\t\tinitialState: {\n\t\t\t\tsystemPrompt: \"\",\n\t\t\t\tmodel: options.model,\n\t\t\t\tthinkingLevel: options.thinkingLevel,\n\t\t\t\tserviceTier: options.serviceTier,\n\t\t\t\ttools: [],\n\t\t\t},\n\t\t\tconvertToLlm: this.agent.convertToLlm,\n\t\t\ttransformContext: this.agent.transformContext,\n\t\t\tstreamFn: this.agent.streamFn,\n\t\t\tgetApiKey: this.agent.getApiKey,\n\t\t\tonPayload: this.agent.onPayload,\n\t\t\tonResponse: this.agent.onResponse,\n\t\t\tsteeringMode: this.settingsManager.getSteeringMode(),\n\t\t\tfollowUpMode: this.settingsManager.getFollowUpMode(),\n\t\t\tsessionId: childSessionManager.getSessionId(),\n\t\t\tthinkingBudgets: this.settingsManager.getThinkingBudgets(),\n\t\t\ttransport: this.settingsManager.getTransport(),\n\t\t\tmaxRetryDelayMs: this.settingsManager.getProviderRetrySettings().maxRetryDelayMs,\n\t\t\ttoolExecution: this.agent.toolExecution,\n\t\t});\n\n\t\tconst child = new AgentSession({\n\t\t\tagent: childAgent,\n\t\t\tsessionManager: childSessionManager,\n\t\t\tsettingsManager: this.settingsManager,\n\t\t\tcwd: this._cwd,\n\t\t\tagentDir: this._agentDir,\n\t\t\tscopedModels: options.scopedModels,\n\t\t\tresourceLoader: this._resourceLoader,\n\t\t\tcustomTools: options.customTools,\n\t\t\tmodelRegistry: this._modelRegistry,\n\t\t\tinitialActiveToolNames: options.activeToolNames,\n\t\t\tallowedToolNames: options.allowedToolNames,\n\t\t\tincludeGoals: options.includeGoals,\n\t\t\tincludeCompactSkill: options.includeCompactSkill,\n\t\t\trlmDepth: options.rlmDepth,\n\t\t\trlmMaxDepth: options.rlmMaxDepth,\n\t\t\trlmSessionDir: options.sessionDir,\n\t\t\trlmParentNodeId: options.rlmParentNodeId,\n\t\t\trlmParentAgent: options.parentSession.sessionName ?? options.parentSession.sessionId,\n\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"startup\" },\n\t\t});\n\t\tif (child.sessionName !== options.sessionName) {\n\t\t\ttry {\n\t\t\t\tchild.setSessionName(options.sessionName);\n\t\t\t} catch (error) {\n\t\t\t\tchild.dispose();\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\toptions.onSessionPublished?.(child);\n\n\t\treturn { session: child };\n\t}\n\n\tprivate _abandonRlmRunForQuiescence(run: RlmChildRun): void {\n\t\trun.suppressTerminalNotice = true;\n\t\trun.abandonedForQuiescence = true;\n\t\tthis._abandonedRlmQuiescenceChildIds.add(run.id);\n\t\tthis._unsettledRlmChildRuns.delete(run);\n\t\trun.settlement.resolve();\n\t\tthis._maybeResumeGoalContinuationAfterRlmWork();\n\t}\n\n\tprivate _cancelActiveRlmChildRuns(reason: string): void {\n\t\tfor (const run of this._activeRlmChildRuns.values()) {\n\t\t\tthis._cancelRlmChildRun(run, reason);\n\t\t}\n\t}\n\n\tprivate _cancelRlmChildRun(run: RlmChildRun, reason: string): boolean {\n\t\tif (run.status !== \"running\" && run.status !== \"queued\") {\n\t\t\treturn false;\n\t\t}\n\t\trun.status = \"cancelled\";\n\t\tif (this._sessionInputPumpSuspended) this._abandonRlmRunForQuiescence(run);\n\t\trun.error = reason;\n\t\trun.publication.reject(new Error(reason));\n\t\trun.abort();\n\t\t// Surface the cancellation immediately; the run's own terminal update is\n\t\t// delayed indefinitely when the child is stuck mid-stream, which is\n\t\t// exactly when users reach for the kill.\n\t\trun.emitUpdate?.();\n\t\treturn true;\n\t}\n\n\tgetRlmChildRunStatus(childId: string): RlmChildAgentStatus | undefined {\n\t\treturn this._activeRlmChildRuns.get(childId)?.status;\n\t}\n\n\tprivate async _currentActiveSessionId(): Promise<string | undefined> {\n\t\ttry {\n\t\t\treturn (await this._agentMessageController?.listAgents())?.current?.activeSessionId;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tprivate async _awaitPendingRlmChildPublication(selector: string): Promise<string | undefined> {\n\t\tconst run = [...this._activeRlmChildRuns.values()].find(\n\t\t\t(candidate) =>\n\t\t\t\t(candidate.status === \"queued\" || candidate.status === \"running\" || candidate.status === \"done\") &&\n\t\t\t\t!candidate.detachedDeletion &&\n\t\t\t\t(candidate.id === selector || candidate.sessionName === selector),\n\t\t);\n\t\tif (!run) return undefined;\n\t\tawait run.publication.promise;\n\t\treturn run.session?.sessionId;\n\t}\n\n\tasync listRlmSubagents(): Promise<RlmListSubagentsResult> {\n\t\treturn this._buildRlmSubagentList(await this._agentMessageController?.listAgents());\n\t}\n\n\tprivate _buildRlmSubagentList(listedAgents?: AgentSessionMessageListResult): RlmListSubagentsResult {\n\t\tconst daemonChildren = new Map<string, AgentSessionMessageAgentSummary>();\n\t\tconst parentActiveSessionId = listedAgents?.current?.activeSessionId;\n\t\tif (parentActiveSessionId) {\n\t\t\tfor (const agent of listedAgents.agents) {\n\t\t\t\tif (\n\t\t\t\t\tagent.runtimeKind === \"subagent\" &&\n\t\t\t\t\tagent.parentActiveSessionId === parentActiveSessionId &&\n\t\t\t\t\tagent.rlmChildId\n\t\t\t\t) {\n\t\t\t\t\tdaemonChildren.set(agent.rlmChildId, agent);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst subagents: RlmListSubagentsResult[\"subagents\"] = [];\n\t\tconst recorded = new Set<string>();\n\t\tfor (const run of this._activeRlmChildRuns.values()) {\n\t\t\tif (this._deletingRlmChildren.has(run.id) || run.detachedDeletion || run.status === \"cancelled\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst daemonChild = daemonChildren.get(run.id);\n\t\t\tsubagents.push({\n\t\t\t\trlm_child_id: run.id,\n\t\t\t\tactive_session_id: daemonChild?.activeSessionId ?? null,\n\t\t\t\tsession_id: daemonChild?.sessionId ?? run.session?.sessionId ?? null,\n\t\t\t\tsession_name: daemonChild?.sessionName ?? run.session?.sessionName ?? run.sessionName,\n\t\t\t\tsession_dir: run.sessionDir,\n\t\t\t\tstatus: run.status === \"done\" ? \"completed\" : run.status === \"error\" ? \"error\" : \"running\",\n\t\t\t});\n\t\t\trecorded.add(run.id);\n\t\t}\n\t\tfor (const [childId, childSession] of this._rlmChildSessions) {\n\t\t\tif (\n\t\t\t\tthis._deletingRlmChildren.has(childId) ||\n\t\t\t\trecorded.has(childId) ||\n\t\t\t\tthis._rlmChildCleanupFailures.has(childId)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst daemonChild = daemonChildren.get(childId);\n\t\t\tconst sessionDir = childSession._rlmSessionDir;\n\t\t\tif (!sessionDir) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tsubagents.push({\n\t\t\t\trlm_child_id: childId,\n\t\t\t\tactive_session_id: daemonChild?.activeSessionId ?? null,\n\t\t\t\tsession_id: daemonChild?.sessionId ?? childSession.sessionId,\n\t\t\t\tsession_name:\n\t\t\t\t\tdaemonChild?.sessionName ?? childSession.sessionName ?? createDefaultRlmSubagentSessionName(\"\", childId),\n\t\t\t\tsession_dir: sessionDir,\n\t\t\t\tstatus: \"completed\",\n\t\t\t});\n\t\t\trecorded.add(childId);\n\t\t}\n\t\tfor (const [childId, daemonChild] of daemonChildren) {\n\t\t\tif (\n\t\t\t\trecorded.has(childId) ||\n\t\t\t\tthis._deletingRlmChildren.has(childId) ||\n\t\t\t\tthis._deletedRlmChildIds.has(childId) ||\n\t\t\t\tthis._rlmChildCleanupFailures.has(childId) ||\n\t\t\t\t!daemonChild.sessionDir\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tsubagents.push({\n\t\t\t\trlm_child_id: childId,\n\t\t\t\tactive_session_id: daemonChild.activeSessionId,\n\t\t\t\tsession_id: daemonChild.sessionId,\n\t\t\t\tsession_name: daemonChild.sessionName ?? createDefaultRlmSubagentSessionName(\"\", childId),\n\t\t\t\tsession_dir: daemonChild.sessionDir,\n\t\t\t\tstatus: daemonChild.rlmChildRegistryStatus === \"completed\" ? \"completed\" : \"error\",\n\t\t\t});\n\t\t}\n\t\treturn { subagents };\n\t}\n\n\tprivate _rlmSubagentMatchesTarget(entry: RlmSubagentRegistryEntry, target: string): boolean {\n\t\treturn (\n\t\t\tentry.rlm_child_id === target ||\n\t\t\tentry.active_session_id === target ||\n\t\t\tentry.session_id === target ||\n\t\t\tentry.session_name === target\n\t\t);\n\t}\n\n\tprivate async _resolveDirectRlmSubagent(target: string): Promise<RlmSubagentRegistryEntry> {\n\t\tconst candidates = [...(await this.listRlmSubagents()).subagents, ...this._rlmChildCleanupFailures.values()];\n\t\tconst matches = candidates.filter((entry) => this._rlmSubagentMatchesTarget(entry, target));\n\t\tif (matches.length === 0) {\n\t\t\tthrow new Error(`No direct RLM subagent matches \"${target}\" in the current parent session`);\n\t\t}\n\t\tif (matches.length > 1) {\n\t\t\tthrow new Error(`RLM subagent selector \"${target}\" is ambiguous in the current parent session`);\n\t\t}\n\t\treturn matches[0]!;\n\t}\n\n\tasync deleteInactiveRlmSubagent(\n\t\tchildId: string,\n\t\tisExternallyRunning: () => boolean = () => false,\n\t): Promise<\"deleted\" | \"not_found\" | \"running\"> {\n\t\tconst isRunning = (): boolean => {\n\t\t\tconst status = this._activeRlmChildRuns.get(childId)?.status;\n\t\t\treturn status === \"queued\" || status === \"running\" || isExternallyRunning();\n\t\t};\n\t\tif (isRunning()) {\n\t\t\treturn \"running\";\n\t\t}\n\t\tconst subagent = [...(await this.listRlmSubagents()).subagents, ...this._rlmChildCleanupFailures.values()].find(\n\t\t\t(entry) => entry.rlm_child_id === childId,\n\t\t);\n\t\tif (!subagent) {\n\t\t\tfor (const run of this._activeRlmChildRuns.values()) {\n\t\t\t\tconst result = await run.session?.deleteInactiveRlmSubagent(childId, isExternallyRunning);\n\t\t\t\tif (result && result !== \"not_found\") {\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const retained of this._rlmChildSessions.values()) {\n\t\t\t\tconst result = await retained.deleteInactiveRlmSubagent(childId, isExternallyRunning);\n\t\t\t\tif (result !== \"not_found\") {\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn \"not_found\";\n\t\t}\n\t\tif (isRunning()) {\n\t\t\treturn \"running\";\n\t\t}\n\t\tconst result = await this._trackRlmSubagentDeletion(subagent, () => {\n\t\t\tif (isRunning()) {\n\t\t\t\treturn Promise.resolve({ subagent, outcome: \"skipped_running\" });\n\t\t\t}\n\t\t\treturn this._deleteResolvedRlmSubagent(subagent);\n\t\t});\n\t\treturn result.outcome === \"skipped_running\" ? \"running\" : \"deleted\";\n\t}\n\n\tasync deleteRlmSubagent(target: string): Promise<RlmDeleteSubagentResult> {\n\t\tconst inFlight = [...this._deletingRlmChildren.values()].filter(({ subagent }) =>\n\t\t\tthis._rlmSubagentMatchesTarget(subagent, target),\n\t\t);\n\t\tif (inFlight.length > 1) {\n\t\t\tthrow new Error(`RLM subagent selector \"${target}\" is ambiguous in the current parent session`);\n\t\t}\n\n\t\t// Running and retained children can be reserved synchronously. This keeps\n\t\t// them hidden immediately while the async daemon listing checks for a\n\t\t// conflicting passive selector.\n\t\tconst localMatches = [\n\t\t\t...this._buildRlmSubagentList().subagents,\n\t\t\t...this._rlmChildCleanupFailures.values(),\n\t\t].filter((entry) => this._rlmSubagentMatchesTarget(entry, target));\n\t\tconst matchingChildIds = new Set([\n\t\t\t...inFlight.map(({ subagent }) => subagent.rlm_child_id),\n\t\t\t...localMatches.map((subagent) => subagent.rlm_child_id),\n\t\t]);\n\t\tif (matchingChildIds.size > 1 || localMatches.length > 1) {\n\t\t\tthrow new Error(`RLM subagent selector \"${target}\" is ambiguous in the current parent session`);\n\t\t}\n\t\tif (inFlight[0]) {\n\t\t\treturn inFlight[0].promise;\n\t\t}\n\t\tif (localMatches[0]) {\n\t\t\tconst subagent = localMatches[0];\n\t\t\treturn this._trackRlmSubagentDeletion(subagent, async () => {\n\t\t\t\tconst listedAgents = await this._agentMessageController?.listAgents();\n\t\t\t\tconst listedSubagents = this._buildRlmSubagentList(listedAgents).subagents;\n\t\t\t\tconst passiveMatches = listedSubagents.filter(\n\t\t\t\t\t(entry) => entry.rlm_child_id !== subagent.rlm_child_id && this._rlmSubagentMatchesTarget(entry, target),\n\t\t\t\t);\n\t\t\t\tif (passiveMatches.length > 0) {\n\t\t\t\t\tthrow new Error(`RLM subagent selector \"${target}\" is ambiguous in the current parent session`);\n\t\t\t\t}\n\t\t\t\tconst parentActiveSessionId = listedAgents?.current?.activeSessionId;\n\t\t\t\tconst daemonChild = listedAgents?.agents.find(\n\t\t\t\t\t(agent) =>\n\t\t\t\t\t\tagent.rlmChildId === subagent.rlm_child_id && agent.parentActiveSessionId === parentActiveSessionId,\n\t\t\t\t);\n\t\t\t\tconst resolvedSubagent = daemonChild\n\t\t\t\t\t? {\n\t\t\t\t\t\t\t...subagent,\n\t\t\t\t\t\t\tactive_session_id: daemonChild.activeSessionId,\n\t\t\t\t\t\t\tsession_id: daemonChild.sessionId,\n\t\t\t\t\t\t\tsession_name: daemonChild.sessionName ?? subagent.session_name,\n\t\t\t\t\t\t}\n\t\t\t\t\t: subagent;\n\t\t\t\treturn this._deleteResolvedRlmSubagent(resolvedSubagent);\n\t\t\t});\n\t\t}\n\n\t\tconst directMatches = [\n\t\t\t...(await this.listRlmSubagents()).subagents,\n\t\t\t...this._rlmChildCleanupFailures.values(),\n\t\t].filter((entry) => this._rlmSubagentMatchesTarget(entry, target));\n\t\tconst directChildIds = new Set(directMatches.map((subagent) => subagent.rlm_child_id));\n\t\tif (directChildIds.size > 1) {\n\t\t\tthrow new Error(`RLM subagent selector \"${target}\" is ambiguous in the current parent session`);\n\t\t}\n\t\tconst subagent = directMatches[0] ?? (await this._resolveDirectRlmSubagent(target));\n\t\treturn this._trackRlmSubagentDeletion(subagent, () => this._deleteResolvedRlmSubagent(subagent));\n\t}\n\n\tprivate async _trackRlmSubagentDeletion(\n\t\tsubagent: RlmSubagentRegistryEntry,\n\t\tstartDeletion: () => Promise<RlmDeleteSubagentResult>,\n\t): Promise<RlmDeleteSubagentResult> {\n\t\tconst existing = this._deletingRlmChildren.get(subagent.rlm_child_id);\n\t\tif (existing) return existing.promise;\n\t\tconst deletion = Promise.resolve().then(startDeletion);\n\t\tthis._deletingRlmChildren.set(subagent.rlm_child_id, {\n\t\t\tsubagent,\n\t\t\tpromise: deletion,\n\t\t});\n\t\ttry {\n\t\t\treturn await deletion;\n\t\t} finally {\n\t\t\tconst clearReservation = () => {\n\t\t\t\tif (this._deletingRlmChildren.get(subagent.rlm_child_id)?.promise === deletion) {\n\t\t\t\t\tthis._deletingRlmChildren.delete(subagent.rlm_child_id);\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst run = this._activeRlmChildRuns.get(subagent.rlm_child_id);\n\t\t\tif (run?.detachedDeletion) {\n\t\t\t\t// Keep every selector reserved until the run settles, or until a failed\n\t\t\t\t// cleanup is exposed for an explicit retry. Repeated deletes before that\n\t\t\t\t// boundary return the same accepted result.\n\t\t\t\tvoid run.deletionReservation.promise.then(clearReservation, clearReservation);\n\t\t\t} else {\n\t\t\t\tclearReservation();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _deleteRlmSubagentSession(childId: string, session?: AgentSession): Promise<void> {\n\t\tif (this._subagentRuntimeHost) {\n\t\t\treturn this._subagentRuntimeHost.deleteRlmSubagentRuntime(childId, session);\n\t\t}\n\t\treturn session?.disposeAsync() ?? Promise.resolve();\n\t}\n\n\tprivate _ensureRlmRunDeletionCleanup(run: RlmChildRun, session: AgentSession): Promise<void> {\n\t\tif (run.deletionCleanup) return run.deletionCleanup;\n\t\tconst cleanup = Promise.resolve().then(() => this._deleteRlmSubagentSession(run.id, session));\n\t\trun.deletionCleanup = cleanup;\n\t\t// Deletion admission is intentionally nonblocking. The detached run owner\n\t\t// joins this exact promise before settlement and records any failure.\n\t\tvoid cleanup.catch(() => undefined);\n\t\treturn cleanup;\n\t}\n\n\tprivate async _recordRlmRunDeletionCleanupFailure(\n\t\trun: RlmChildRun,\n\t\tsubagent: RlmSubagentRegistryEntry,\n\t\tsession: AgentSession,\n\t\terror: unknown,\n\t): Promise<void> {\n\t\tif (this._disposed || this._disposing) {\n\t\t\trun.suppressTerminalNotice = true;\n\t\t\tawait session.disposeAsync().catch(() => undefined);\n\t\t\tif (!run.settled) await this._finishRlmRunDeletion(run);\n\t\t\treturn;\n\t\t}\n\t\trun.deletionCleanup = undefined;\n\t\trun.deletionCleanupObserver = undefined;\n\t\trun.deletionCleanupFailed = true;\n\t\trun.session = session;\n\t\tthis._rlmChildCleanupFailures.set(run.id, subagent);\n\t\t// Make retry admission available before waking the parent model with the\n\t\t// retry-required notice.\n\t\trun.deletionReservation.resolve();\n\t\tawait Promise.resolve();\n\t\tawait run.reportDeletionCleanupFailure?.(error);\n\t}\n\n\tprivate async _finishRlmRunDeletion(run: RlmChildRun): Promise<void> {\n\t\tif (this._activeRlmChildRuns.get(run.id) === run) {\n\t\t\tthis._removeRlmSubagentTracking(run.id, run);\n\t\t}\n\t\trun.settled = true;\n\t\trun.settlement.resolve();\n\t\trun.deletionReservation.resolve();\n\t\tthis._unsettledRlmChildRuns.delete(run);\n\t\tthis._maybeResumeGoalContinuationAfterRlmWork();\n\t}\n\n\tprivate _observeRlmRunDeletionCleanup(\n\t\trun: RlmChildRun,\n\t\tsubagent: RlmSubagentRegistryEntry,\n\t\tsession: AgentSession,\n\t\tcleanup: Promise<void>,\n\t): Promise<boolean> {\n\t\tif (run.deletionCleanupObserver) return run.deletionCleanupObserver;\n\t\tconst observer = cleanup.then(\n\t\t\t() => true,\n\t\t\tasync (error) => {\n\t\t\t\tawait this._recordRlmRunDeletionCleanupFailure(run, subagent, session, error);\n\t\t\t\treturn false;\n\t\t\t},\n\t\t);\n\t\trun.deletionCleanupObserver = observer;\n\t\tvoid observer.catch(() => undefined);\n\t\treturn observer;\n\t}\n\n\tprivate _continueFinishedRlmRunDeletion(\n\t\trun: RlmChildRun,\n\t\tsubagent: RlmSubagentRegistryEntry,\n\t\tsession: AgentSession,\n\t): void {\n\t\tconst cleanup = this._ensureRlmRunDeletionCleanup(run, session);\n\t\tconst observer = this._observeRlmRunDeletionCleanup(run, subagent, session, cleanup);\n\t\tif (!run.deletionRunFinished) return;\n\t\tvoid observer\n\t\t\t.then(async (cleanupSucceeded) => {\n\t\t\t\tif (cleanupSucceeded) await this._finishRlmRunDeletion(run);\n\t\t\t})\n\t\t\t.catch(() => undefined);\n\t}\n\n\tprivate _removeRlmSubagentTracking(childId: string, run?: RlmChildRun): void {\n\t\trun?.unsubscribe?.();\n\t\tthis._rlmChildUnsubscribes.get(childId)?.();\n\t\tthis._rlmChildUnsubscribes.delete(childId);\n\t\tthis._rlmChildSessions.delete(childId);\n\t\tthis._rlmChildCleanupFailures.delete(childId);\n\t\tthis._abandonedRlmQuiescenceChildIds.delete(childId);\n\t\tif (!run || this._activeRlmChildRuns.get(childId) === run) {\n\t\t\tthis._activeRlmChildRuns.delete(childId);\n\t\t}\n\t\tif (run) {\n\t\t\trun.abort = noopRlmChildAbort;\n\t\t\trun.unsubscribe = undefined;\n\t\t\trun.session = undefined;\n\t\t}\n\t}\n\n\tprivate _emitRlmSubagentRemoval(subagent: RlmSubagentRegistryEntry): void {\n\t\tthis._emit({\n\t\t\ttype: \"rlm_child_update\",\n\t\t\tchild: {\n\t\t\t\tid: subagent.rlm_child_id,\n\t\t\t\tparentId: this._rlmParentNodeId,\n\t\t\t\tactiveSessionId: subagent.active_session_id ?? undefined,\n\t\t\t\tsessionName: subagent.session_name,\n\t\t\t\tlabel: subagent.session_name,\n\t\t\t\tstatus: \"cancelled\",\n\t\t\t\tsessionDir: subagent.session_dir,\n\t\t\t\terror: \"Deleted by parent orchestrator\",\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate async _deleteResolvedRlmSubagent(subagent: RlmSubagentRegistryEntry): Promise<RlmDeleteSubagentResult> {\n\t\tconst childId = subagent.rlm_child_id;\n\t\tconst run = this._activeRlmChildRuns.get(childId);\n\t\tif (run) {\n\t\t\tif (run.deletionCleanupFailed) {\n\t\t\t\t// Reset retry coordination only after selector preflight reaches the\n\t\t\t\t// resolved child. A failed preflight must leave the prior retry boundary\n\t\t\t\t// intact so a later call can acquire it.\n\t\t\t\trun.deletionCleanupFailed = false;\n\t\t\t\trun.deletionReservation = createAgentMessageDeferred();\n\t\t\t}\n\t\t\t// The detached task remains the sole lifecycle owner. Mark deletion before\n\t\t\t// cancellation so its catch/finally path cannot race a normal release or\n\t\t\t// terminal notice against the physical delete.\n\t\t\trun.detachedDeletion = subagent;\n\t\t\tif (!this._cancelRlmChildRun(run, \"Deleted by parent orchestrator\")) {\n\t\t\t\tthis._emitRlmSubagentRemoval(subagent);\n\t\t\t}\n\t\t\tconst liveSession = run.session;\n\t\t\tif (run.status === \"error\" && !liveSession && run.settled) {\n\t\t\t\tthis._deletedRlmChildIds.add(childId);\n\t\t\t\tthis._removeRlmSubagentTracking(childId, run);\n\t\t\t\treturn { subagent };\n\t\t\t}\n\t\t\tif (liveSession && run.settled) {\n\t\t\t\trun.deletionRunFinished = true;\n\t\t\t\trun.settlement = createAgentMessageDeferred();\n\t\t\t\trun.settled = false;\n\t\t\t\tthis._unsettledRlmChildRuns.add(run);\n\t\t\t}\n\t\t\tif (liveSession) this._continueFinishedRlmRunDeletion(run, subagent, liveSession);\n\n\t\t\t// Return once deletion is accepted. The run stays hidden but unsettled until\n\t\t\t// abort-insensitive model/tool work unwinds and the shared cleanup finishes.\n\t\t\tthis._deletedRlmChildIds.add(childId);\n\t\t\treturn { subagent };\n\t\t}\n\n\t\tthis._emitRlmSubagentRemoval(subagent);\n\t\tconst retained = this._rlmChildSessions.get(childId);\n\t\ttry {\n\t\t\tawait this._deleteRlmSubagentSession(childId, retained);\n\t\t} catch (error) {\n\t\t\tif (this._disposed || this._disposing) {\n\t\t\t\tthis._removeRlmSubagentTracking(childId);\n\t\t\t\tvoid retained?.disposeAsync().catch(() => undefined);\n\t\t\t} else {\n\t\t\t\tthis._rlmChildCleanupFailures.set(childId, subagent);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tthis._deletedRlmChildIds.add(childId);\n\t\tthis._removeRlmSubagentTracking(childId);\n\t\treturn { subagent };\n\t}\n\n\t/**\n\t * Retain a finished child session for the parent lifetime so inspectors and\n\t * daemon-hosted agent messaging can keep addressing it. Returns false (and disposes\n\t * the child) when the parent is already tearing down, so the caller can drop the\n\t * matching event forwarder too.\n\t */\n\tregisterRlmChildSession(childId: string, session: AgentSession, unsubscribe?: () => void): boolean {\n\t\t// A child can finish concurrently while the parent is (or has) torn down; don't\n\t\t// resurrect the map (it would never be disposed), just drop the child now.\n\t\tif (this._deletingRlmChildren.has(childId) || this._deletedRlmChildIds.has(childId)) {\n\t\t\treturn false;\n\t\t}\n\t\tif (this._subagentRuntimeHost?.completeRlmSubagentRuntime?.(childId, session) === false) {\n\t\t\treturn false;\n\t\t}\n\t\tif (this._disposed || this._disposing) {\n\t\t\tvoid session.disposeAsync().catch(() => undefined);\n\t\t\treturn false;\n\t\t}\n\t\tthis._rlmChildSessions.set(childId, session);\n\t\tif (unsubscribe) {\n\t\t\tthis._rlmChildUnsubscribes.set(childId, unsubscribe);\n\t\t}\n\t\treturn true;\n\t}\n\n\treleaseRlmChildSession(childId: string, session: AgentSession): (() => void) | false {\n\t\tconst run = this._activeRlmChildRuns.get(childId);\n\t\tif (run?.session === session && run.status === \"done\") {\n\t\t\tconst unsubscribe = run.unsubscribe ?? noopRlmChildEventUnsubscribe;\n\t\t\trun.unsubscribe = undefined;\n\t\t\tthis._activeRlmChildRuns.delete(childId);\n\t\t\treturn unsubscribe;\n\t\t}\n\t\tif (this._rlmChildSessions.get(childId) !== session) return false;\n\t\tconst unsubscribe = this._rlmChildUnsubscribes.get(childId) ?? noopRlmChildEventUnsubscribe;\n\t\tthis._rlmChildUnsubscribes.delete(childId);\n\t\tthis._rlmChildSessions.delete(childId);\n\t\treturn unsubscribe;\n\t}\n\n\t/** Live recursive child roster from lifecycle state, including nested work under retained parents. */\n\tgetRlmChildSnapshots(): RlmChildAgentSnapshot[] {\n\t\tconst snapshots: RlmChildAgentSnapshot[] = [];\n\t\tconst recorded = new Set<string>();\n\t\tconst traversed = new Set<string>();\n\t\tfor (const run of this._activeRlmChildRuns.values()) {\n\t\t\tconst hidden =\n\t\t\t\trun.detachedDeletion || this._deletingRlmChildren.has(run.id) || this._deletedRlmChildIds.has(run.id);\n\t\t\tconst child = run.session;\n\t\t\tif (!hidden) {\n\t\t\t\tconst model = child?.model ?? run.model;\n\t\t\t\tsnapshots.push({\n\t\t\t\t\tid: run.id,\n\t\t\t\t\tparentId: this._rlmParentNodeId,\n\t\t\t\t\tsessionName: child?.sessionName ?? run.sessionName,\n\t\t\t\t\tmodel: `${model.provider}/${model.id}`,\n\t\t\t\t\tlabel: rlmChildLabel(run.prompt),\n\t\t\t\t\tstatus: run.status,\n\t\t\t\t\tsessionDir: run.sessionDir,\n\t\t\t\t});\n\t\t\t\trecorded.add(run.id);\n\t\t\t}\n\t\t\tif (child) {\n\t\t\t\ttraversed.add(run.id);\n\t\t\t\tsnapshots.push(...child.getRlmChildSnapshots());\n\t\t\t}\n\t\t}\n\t\tfor (const [childId, child] of this._rlmChildSessions) {\n\t\t\tif (recorded.has(childId) || traversed.has(childId)) continue;\n\t\t\tconst hidden = this._deletingRlmChildren.has(childId) || this._deletedRlmChildIds.has(childId);\n\t\t\tif (!hidden) {\n\t\t\t\tsnapshots.push({\n\t\t\t\t\tid: childId,\n\t\t\t\t\tparentId: this._rlmParentNodeId,\n\t\t\t\t\tsessionName: child.sessionName,\n\t\t\t\t\tmodel: child.model ? `${child.model.provider}/${child.model.id}` : undefined,\n\t\t\t\t\tlabel: child.sessionName ?? \"child agent\",\n\t\t\t\t\t// A failed delete retains the session solely for cleanup retry. Preserve\n\t\t\t\t\t// its cancellation truth in snapshots rather than reviving it as done.\n\t\t\t\t\tstatus: this._rlmChildCleanupFailures.has(childId) ? \"cancelled\" : \"done\",\n\t\t\t\t\tsessionDir: child._rlmSessionDir ?? child.sessionManager.getSessionDir(),\n\t\t\t\t});\n\t\t\t}\n\t\t\tsnapshots.push(...child.getRlmChildSnapshots());\n\t\t}\n\t\treturn snapshots;\n\t}\n\n\t/** True when any direct or nested subagent is still running or queued. */\n\thasRunningRlmChildren(): boolean {\n\t\tfor (const run of this._activeRlmChildRuns.values()) {\n\t\t\tif (run.status === \"running\" || run.status === \"queued\") {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (run.session?.hasRunningRlmChildren()) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\t// A finished direct child can still have a running nested subagent.\n\t\tfor (const session of this._rlmChildSessions.values()) {\n\t\t\tif (session.hasRunningRlmChildren()) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate _rlmChildSessionSnapshot(): AgentSession[] {\n\t\tconst sessions = new Set<AgentSession>();\n\t\tfor (const [childId, session] of this._rlmChildSessions) {\n\t\t\tif (!this._abandonedRlmQuiescenceChildIds.has(childId)) sessions.add(session);\n\t\t}\n\t\tfor (const run of this._activeRlmChildRuns.values()) {\n\t\t\tif (run.session && !run.abandonedForQuiescence) sessions.add(run.session);\n\t\t}\n\t\treturn [...sessions];\n\t}\n\n\tprivate _hasUnsettledRlmQuiescenceWork(): boolean {\n\t\tif (this._hasDeferredRlmTerminalNotices()) return true;\n\t\tif ([...this._unsettledRlmChildRuns].some((run) => !run.settled)) return true;\n\t\treturn this._rlmChildSessionSnapshot().some(\n\t\t\t(child) => child.isSessionActive || child._hasUnsettledRlmQuiescenceWork(),\n\t\t);\n\t}\n\n\t/**\n\t * Wait for every admitted descendant run to publish its terminal parent\n\t * message and for the resulting parent turns to drain. Re-snapshotting after\n\t * each drain includes descendants spawned while earlier results were consumed.\n\t */\n\tasync waitForRlmQuiescence(externalSignal?: AbortSignal): Promise<void> {\n\t\tconst cancellation = new AbortController();\n\t\tconst cancelFromParent = () => cancellation.abort();\n\t\tif (externalSignal?.aborted) cancellation.abort();\n\t\telse externalSignal?.addEventListener(\"abort\", cancelFromParent, { once: true });\n\t\tthis._rlmQuiescenceWaitAborts.add(cancellation);\n\t\tlet rejectCancelled = (_error: Error) => {};\n\t\tconst cancelled = new Promise<never>((_resolve, reject) => {\n\t\t\trejectCancelled = reject;\n\t\t});\n\t\tconst onCancelled = () => rejectCancelled(new Error(\"RLM quiescence wait cancelled\"));\n\t\tcancellation.signal.addEventListener(\"abort\", onCancelled, { once: true });\n\t\tif (cancellation.signal.aborted) onCancelled();\n\t\tconst wait = <T>(operation: Promise<T>): Promise<T> => Promise.race([operation, cancelled]);\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tawait wait(this.waitForHeadlessIdle());\n\t\t\t\t// Strong RLM quiescence also owns session-level work (bash, refine,\n\t\t\t\t// branch mutation, and manual compaction) that interactive waitForIdle\n\t\t\t\t// intentionally ignores. Yield a macrotask while such work is active so\n\t\t\t\t// recursive parent/child barriers cannot form a microtask busy-loop.\n\t\t\t\tif (this.isSessionActive || this._hasDeferredRlmTerminalNotices()) {\n\t\t\t\t\tawait wait(new Promise<void>((resolve) => setTimeout(resolve, 0)));\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst unsettledRuns = [...this._unsettledRlmChildRuns].filter((run) => !run.settled);\n\t\t\t\tconst childSessions = this._rlmChildSessionSnapshot();\n\t\t\t\tif (unsettledRuns.length === 0 && !this._hasUnsettledRlmQuiescenceWork()) return;\n\t\t\t\tawait wait(\n\t\t\t\t\tPromise.all([\n\t\t\t\t\t\t...unsettledRuns.map((run) => run.settlement.promise),\n\t\t\t\t\t\t...childSessions.map((child) => child.waitForRlmQuiescence(cancellation.signal)),\n\t\t\t\t\t]),\n\t\t\t\t);\n\t\t\t\t// Always loop through the self-active/deferred checks again. Work may\n\t\t\t\t// start at the child-settlement boundary.\n\t\t\t}\n\t\t} finally {\n\t\t\t// A local descendant error must cancel sibling recursive waits owned by\n\t\t\t// this barrier before their propagation listeners are removed.\n\t\t\tcancellation.abort();\n\t\t\texternalSignal?.removeEventListener(\"abort\", cancelFromParent);\n\t\t\tcancellation.signal.removeEventListener(\"abort\", onCancelled);\n\t\t\tthis._rlmQuiescenceWaitAborts.delete(cancellation);\n\t\t}\n\t}\n\n\t// Inline (non-daemon) mode only; daemon clients attach to the child session directly.\n\tgetRlmChildSession(childId: string): AgentSession | undefined {\n\t\tconst direct = this._activeRlmChildRuns.get(childId)?.session ?? this._rlmChildSessions.get(childId);\n\t\tif (direct) {\n\t\t\treturn direct;\n\t\t}\n\t\tfor (const candidate of this._activeRlmChildRuns.values()) {\n\t\t\tconst nested = candidate.session?.getRlmChildSession(childId);\n\t\t\tif (nested) {\n\t\t\t\treturn nested;\n\t\t\t}\n\t\t}\n\t\tfor (const retained of this._rlmChildSessions.values()) {\n\t\t\tconst nested = retained.getRlmChildSession(childId);\n\t\t\tif (nested) {\n\t\t\t\treturn nested;\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Cancel a single RLM child run by id, searching nested child sessions.\n\t *\n\t * @returns true when a live run was cancelled or its unsettled terminal notice\n\t * was suppressed; false when the id is unknown or the run already settled.\n\t */\n\tcancelRlmChildRun(childId: string, reason = \"Cancelled by user\"): boolean {\n\t\tconst run = this._activeRlmChildRuns.get(childId);\n\t\tif (run) {\n\t\t\tif (run.status !== \"running\" && run.status !== \"queued\" && !run.settled) {\n\t\t\t\tif (this._sessionInputPumpSuspended) this._abandonRlmRunForQuiescence(run);\n\t\t\t\telse run.suppressTerminalNotice = true;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn this._cancelRlmChildRun(run, reason);\n\t\t}\n\t\tfor (const candidate of this._activeRlmChildRuns.values()) {\n\t\t\tif (candidate.session?.cancelRlmChildRun(childId, reason)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\tfor (const retained of this._rlmChildSessions.values()) {\n\t\t\tif (retained.cancelRlmChildRun(childId, reason)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate async _assertRlmSubagentSessionNameAvailable(name: string, ignorePendingReservation = false): Promise<void> {\n\t\tconst depth = this._rlmDepth + 1;\n\t\tif (!ignorePendingReservation && this._pendingRlmSubagentSessionNames.has(name)) {\n\t\t\tthrow new Error(formatAgentSessionNameUnavailable(name, depth));\n\t\t}\n\t\tconst localConflict =\n\t\t\t[...this._activeRlmChildRuns.values()].some(\n\t\t\t\t(run) => run.session?.sessionName === name || (!run.session && run.sessionName === name),\n\t\t\t) ||\n\t\t\t[...this._rlmChildSessions.values()].some((session) => session.sessionName === name) ||\n\t\t\t[...this._rlmChildCleanupFailures.values()].some((entry) => entry.session_name === name);\n\t\tif (localConflict) {\n\t\t\tthrow new Error(formatAgentSessionNameUnavailable(name, depth));\n\t\t}\n\t\tconst controller = this._agentMessageController;\n\t\tif (!controller) return;\n\t\tconst input = {\n\t\t\tname,\n\t\t\tdepth,\n\t\t\tparentSessionId: this.sessionId,\n\t\t\tparentSessionPath: this.sessionFile,\n\t\t};\n\t\tif (controller.assertSessionNameAvailable) {\n\t\t\tawait controller.assertSessionNameAvailable(input);\n\t\t\treturn;\n\t\t}\n\t\tconst listed = await controller.listAgents();\n\t\tconst catalog = listed.agents.map(\n\t\t\t(agent): AgentFamilyCatalogEntry => ({\n\t\t\t\tid: agent.sessionId,\n\t\t\t\t...(agent.sessionName ? { name: agent.sessionName } : {}),\n\t\t\t\tdepth: agent.rlmDepth ?? 0,\n\t\t\t\tstatus: agent.status ?? \"idle\",\n\t\t\t\t...(agent.parentSessionId ? { parentSessionId: agent.parentSessionId } : {}),\n\t\t\t\t...(agent.parentSessionPath ? { parentSessionPath: agent.parentSessionPath } : {}),\n\t\t\t\t...(agent.sessionPath ? { sessionPath: agent.sessionPath } : {}),\n\t\t\t}),\n\t\t);\n\t\tassertAgentSessionNameAvailable(catalog, input);\n\t}\n\n\tprivate async _authenticatedRlmModels(): Promise<Model<Api>[]> {\n\t\treturn (await this._modelRegistry.getExecutableModels()).filter((model) => {\n\t\t\tconst status = this._modelRegistry.getProviderAuthStatus(model.provider);\n\t\t\treturn status.source !== \"stale\" && status.label !== \"expired\";\n\t\t});\n\t}\n\n\tasync findRlmModels(query: string, limit: number): Promise<RlmFindModelsResult> {\n\t\treturn {\n\t\t\tmodels: findRlmModelMatches(query, await this._authenticatedRlmModels(), limit),\n\t\t};\n\t}\n\n\tprivate async _resolveRlmSubagentModel(reference: string | undefined): Promise<RlmSubagentModelSelection> {\n\t\tconst parentModel = this.model;\n\t\tif (!parentModel) {\n\t\t\tthrow new Error(formatNoModelSelectedMessage());\n\t\t}\n\t\tif (!reference) {\n\t\t\treturn { model: parentModel };\n\t\t}\n\n\t\tconst normalizedReference = reference.toLowerCase();\n\t\tif (`${parentModel.provider}/${parentModel.id}`.toLowerCase() === normalizedReference) {\n\t\t\treturn { model: parentModel };\n\t\t}\n\t\tconst model = (await this._authenticatedRlmModels()).find(\n\t\t\t(candidate) => `${candidate.provider}/${candidate.id}`.toLowerCase() === normalizedReference,\n\t\t);\n\t\tif (!model) {\n\t\t\tthrow new Error(`Requested subagent model \"${reference}\" is unavailable, unauthenticated, or expired`);\n\t\t}\n\n\t\tconst auth = await this._modelRegistry.getApiKeyAndHeaders(model);\n\t\tif (!auth.ok) {\n\t\t\tthrow new Error(`Requested subagent model \"${reference}\" failed authentication preflight`);\n\t\t}\n\t\treturn { model };\n\t}\n\n\tprivate async _startRlmChildRun(\n\t\tprompt: string,\n\t\tkwargs: Record<string, unknown> = {},\n\t\tspawnCode?: string,\n\t): Promise<RlmSpawnHandle> {\n\t\tconst { name: rawName, model: rawModel, thinking: rawThinking, ...unsupported } = kwargs;\n\t\tconst unsupportedKwargs = Object.keys(unsupported);\n\t\tif (unsupportedKwargs.length > 0) {\n\t\t\tthrow new Error(`Unsupported rlm.run kwargs: ${unsupportedKwargs.sort().join(\", \")}`);\n\t\t}\n\t\tconst requestedSessionName = normalizeRequestedRlmSubagentSessionName(rawName);\n\t\tconst requestedModel = normalizeRequestedRlmSubagentModel(rawModel);\n\t\tconst requestedThinkingLevel = normalizeRequestedRlmSubagentThinkingLevel(rawThinking);\n\t\tif (requestedSessionName) assertDirectAgentMessageTarget(requestedSessionName);\n\t\tif (this._rlmDepth >= this._rlmMaxDepth) {\n\t\t\tthrow new Error(\n\t\t\t\t`RLM recursion depth limit reached (RLM_DEPTH=${this._rlmDepth}, RLM_MAX_DEPTH=${this._rlmMaxDepth})`,\n\t\t\t);\n\t\t}\n\t\tif (requestedSessionName) {\n\t\t\tif (this._pendingRlmSubagentSessionNames.has(requestedSessionName)) {\n\t\t\t\tthrow new Error(formatAgentSessionNameUnavailable(requestedSessionName, this._rlmDepth + 1));\n\t\t\t}\n\t\t\tthis._pendingRlmSubagentSessionNames.add(requestedSessionName);\n\t\t}\n\t\tlet modelSelection: RlmSubagentModelSelection;\n\t\ttry {\n\t\t\tif (requestedSessionName) await this._assertRlmSubagentSessionNameAvailable(requestedSessionName, true);\n\t\t\tmodelSelection = await this._resolveRlmSubagentModel(requestedModel);\n\t\t} finally {\n\t\t\tif (requestedSessionName) this._pendingRlmSubagentSessionNames.delete(requestedSessionName);\n\t\t}\n\t\tif (requestedThinkingLevel !== undefined) {\n\t\t\tconst supported = getSupportedThinkingLevels(modelSelection.model) as ThinkingLevel[];\n\t\t\tif (!supported.includes(requestedThinkingLevel)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Requested thinking level \"${requestedThinkingLevel}\" is not supported by model \"${modelSelection.model.provider}/${modelSelection.model.id}\"; supported levels: ${supported.join(\", \")}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (this._disposed || this._disposing) throw new Error(\"Cannot spawn a subagent after its parent was disposed\");\n\n\t\tconst childSessionDir = this._createChildRlmSessionDir();\n\t\tconst childNodeId = basename(childSessionDir);\n\t\tconst sessionName = requestedSessionName ?? createDefaultRlmSubagentSessionName(prompt, childNodeId);\n\t\tif (!requestedSessionName) await this._assertRlmSubagentSessionNameAvailable(sessionName);\n\t\tconst startedAt = Date.now();\n\t\tconst parentAssistantForUsage = this._findLastAssistantMessage();\n\t\tconst label = rlmChildLabel(prompt);\n\t\tlet answerPreview: string | undefined;\n\t\tlet durationMs: number | undefined;\n\t\tlet toolUseCount = 0;\n\t\tlet runningToolCount = 0;\n\t\tlet activity: RlmChildAgentActivity | undefined;\n\t\tlet childSession: AgentSession | undefined;\n\t\tconst run: RlmChildRun = {\n\t\t\tid: childNodeId,\n\t\t\tprompt,\n\t\t\tsessionName,\n\t\t\tsessionDir: childSessionDir,\n\t\t\tmodel: modelSelection.model,\n\t\t\tstatus: \"queued\",\n\t\t\tsettled: false,\n\t\t\tabort: noopRlmChildAbort,\n\t\t\tpublication: createAgentMessageDeferred(),\n\t\t\tsettlement: createAgentMessageDeferred(),\n\t\t\tdeletionReservation: createAgentMessageDeferred(),\n\t\t};\n\t\tconst throwIfCancelled = () => {\n\t\t\tif (run.status === \"cancelled\") throw new Error(run.error ?? \"RLM child cancelled\");\n\t\t};\n\t\tthis._activeRlmChildRuns.set(run.id, run);\n\t\tthis._unsettledRlmChildRuns.add(run);\n\t\tconst emitChildUpdate = () => {\n\t\t\tconst childModel = childSession?.model ?? modelSelection.model;\n\t\t\tthis._emit({\n\t\t\t\ttype: \"rlm_child_update\",\n\t\t\t\tchild: {\n\t\t\t\t\tid: childNodeId,\n\t\t\t\t\tparentId: this._rlmParentNodeId,\n\t\t\t\t\tsessionName: childSession?.sessionName ?? sessionName,\n\t\t\t\t\tmodel: `${childModel.provider}/${childModel.id}`,\n\t\t\t\t\tlabel,\n\t\t\t\t\tstatus: run.status,\n\t\t\t\t\tdurationMs,\n\t\t\t\t\tanswerPreview,\n\t\t\t\t\ttoolUseCount: toolUseCount > 0 ? toolUseCount : undefined,\n\t\t\t\t\ttokenCount: childSession?._contextTokensForCurrentMessages(),\n\t\t\t\t\trecap: childSession?.getCurrentRecap(),\n\t\t\t\t\tsessionDir: childSessionDir,\n\t\t\t\t\tactivity,\n\t\t\t\t\trepliedSinceTask: childSession?._repliedToParentSinceTask,\n\t\t\t\t\terror: run.error,\n\t\t\t\t},\n\t\t\t});\n\t\t};\n\t\trun.emitUpdate = emitChildUpdate;\n\t\temitChildUpdate();\n\n\t\tconst publishChildSession = (child: AgentSession) => {\n\t\t\tchildSession = child;\n\t\t\tif (this._activeRlmChildRuns.get(run.id) !== run) return;\n\t\t\trun.session = child;\n\t\t\trun.abort = () => void child.abort();\n\t\t\trun.publication.resolve();\n\t\t\t// Cancellation may have been admitted while runtime construction was\n\t\t\t// blocked and run.abort was still a no-op.\n\t\t\tif (run.status === \"cancelled\") run.abort();\n\t\t};\n\t\tconst subagentOptions: CreateRlmSubagentRuntimeOptions = {\n\t\t\t...this._createRlmSubagentRuntimeOptions({\n\t\t\t\tid: childNodeId,\n\t\t\t\tprompt,\n\t\t\t\tsessionName,\n\t\t\t\tspawnCode,\n\t\t\t\tsessionDir: childSessionDir,\n\t\t\t\tmodel: modelSelection.model,\n\t\t\t\tthinkingLevel: requestedThinkingLevel,\n\t\t\t}),\n\t\t\tonSessionPublished: publishChildSession,\n\t\t};\n\n\t\tconst deliverTerminalMessageToParent = async (message: CustomMessage): Promise<void> => {\n\t\t\t// Synthesized lifecycle notices always use the parent's private durable\n\t\t\t// path. Explicit child replies continue through agent_message separately.\n\t\t\tawait this._deferRlmTerminalNotice(message);\n\t\t};\n\n\t\trun.reportDeletionCleanupFailure = (error) => {\n\t\t\tif (run.suppressTerminalNotice || this._disposed || this._disposing) return Promise.resolve();\n\t\t\tconst cleanupError = error instanceof Error ? error.message : String(error);\n\t\t\treturn deliverTerminalMessageToParent(\n\t\t\t\tcreateRlmChildFailureMessage({\n\t\t\t\t\tchildId: run.id,\n\t\t\t\t\tsessionName,\n\t\t\t\t\terror: `Deletion cleanup failed; retry rlm.delete_subagent(\"${run.id}\") before completion: ${cleanupError}`,\n\t\t\t\t}),\n\t\t\t);\n\t\t};\n\n\t\t// Runtime startup and the task run are deliberately detached. The public\n\t\t// spawn resolves at admission, while this task owns live tracking, usage,\n\t\t// retention, cancellation, and late-startup cleanup.\n\t\tvoid (async () => {\n\t\t\tlet childRuntime: RlmSubagentRuntime | undefined;\n\t\t\ttry {\n\t\t\t\tchildRuntime = await this._createRlmSubagentRuntime(subagentOptions);\n\t\t\t\tconst child = childRuntime.session;\n\t\t\t\tif (run.status === \"cancelled\") throw new Error(run.error ?? \"RLM child cancelled\");\n\t\t\t\tif (child.sessionName !== sessionName) child.setSessionName(sessionName);\n\t\t\t\tpublishChildSession(child);\n\t\t\t\tthrowIfCancelled();\n\t\t\t\trun.status = \"running\";\n\t\t\t\temitChildUpdate();\n\t\t\t\tconst unsubscribeChildEvents = child.subscribe((event) => {\n\t\t\t\t\tif (event.type === \"rlm_child_update\") {\n\t\t\t\t\t\tthis._emit(event);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (event.type === \"agent_start\") {\n\t\t\t\t\t\tactivity = { kind: \"waiting\" };\n\t\t\t\t\t\temitChildUpdate();\n\t\t\t\t\t} else if (event.type === \"agent_end\") {\n\t\t\t\t\t\tactivity = undefined;\n\t\t\t\t\t\temitChildUpdate();\n\t\t\t\t\t} else if (event.type === \"message_end\" && event.message.role === \"assistant\") {\n\t\t\t\t\t\tconst assistant = event.message as AssistantMessage;\n\t\t\t\t\t\tif (assistant.stopReason !== \"error\" && assistant.stopReason !== \"aborted\") {\n\t\t\t\t\t\t\tattributeChildUsage(parentAssistantForUsage?.usage ?? emptyUsage(), assistant.usage);\n\t\t\t\t\t\t\tif (parentAssistantForUsage) {\n\t\t\t\t\t\t\t\tconst parentEntry = this._findAssistantEntryForMessage(parentAssistantForUsage);\n\t\t\t\t\t\t\t\tif (parentEntry) {\n\t\t\t\t\t\t\t\t\tconst messages = child.messages;\n\t\t\t\t\t\t\t\t\tconst assistantIndex = messages.lastIndexOf(assistant);\n\t\t\t\t\t\t\t\t\tconst precedingPrompt = messages\n\t\t\t\t\t\t\t\t\t\t.slice(0, assistantIndex)\n\t\t\t\t\t\t\t\t\t\t.reverse()\n\t\t\t\t\t\t\t\t\t\t.find((message) => message.role === \"user\" || message.role === \"custom\");\n\t\t\t\t\t\t\t\t\tconst origin =\n\t\t\t\t\t\t\t\t\t\tprecedingPrompt?.role === \"custom\" && isAgentSessionMessage(precedingPrompt)\n\t\t\t\t\t\t\t\t\t\t\t? precedingPrompt.details.id.startsWith(\"spawn:\")\n\t\t\t\t\t\t\t\t\t\t\t\t? \"spawn_task\"\n\t\t\t\t\t\t\t\t\t\t\t\t: \"agent_message\"\n\t\t\t\t\t\t\t\t\t\t\t: \"direct_user\";\n\t\t\t\t\t\t\t\t\tthis.sessionManager.appendChildUsageAttribution(\n\t\t\t\t\t\t\t\t\t\tparentEntry.id,\n\t\t\t\t\t\t\t\t\t\tassistant.usage,\n\t\t\t\t\t\t\t\t\t\tparentAssistantForUsage.usage,\n\t\t\t\t\t\t\t\t\t\torigin,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst text = compactRlmText(readAssistantText(assistant));\n\t\t\t\t\t\tif (text) answerPreview = text;\n\t\t\t\t\t\temitChildUpdate();\n\t\t\t\t\t} else if (event.type === \"message_start\" || event.type === \"message_update\") {\n\t\t\t\t\t\tif (event.message.role === \"assistant\") {\n\t\t\t\t\t\t\tconst text = compactRlmText(readAssistantText(event.message as AssistantMessage));\n\t\t\t\t\t\t\tif (text) answerPreview = text;\n\t\t\t\t\t\t\tactivity = { kind: \"writing\" };\n\t\t\t\t\t\t\temitChildUpdate();\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (event.type === \"tool_execution_start\") {\n\t\t\t\t\t\ttoolUseCount += 1;\n\t\t\t\t\t\trunningToolCount += 1;\n\t\t\t\t\t\tactivity = { kind: \"executing\", toolName: event.toolName };\n\t\t\t\t\t\temitChildUpdate();\n\t\t\t\t\t} else if (event.type === \"tool_execution_end\") {\n\t\t\t\t\t\trunningToolCount = Math.max(0, runningToolCount - 1);\n\t\t\t\t\t\tif (runningToolCount === 0) activity = { kind: \"waiting\" };\n\t\t\t\t\t\temitChildUpdate();\n\t\t\t\t\t} else if (event.type === \"session_info_changed\" || event.type === \"recap_update\") {\n\t\t\t\t\t\temitChildUpdate();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\trun.unsubscribe = unsubscribeChildEvents;\n\t\t\t\tconst content = `[task from parent]\\n\\n${prompt}`;\n\t\t\t\tconst spawnMessage: AgentSessionMessage = {\n\t\t\t\t\trole: \"custom\",\n\t\t\t\t\tcustomType: AGENT_MESSAGE_CUSTOM_TYPE,\n\t\t\t\t\tcontent,\n\t\t\t\t\tdisplay: true,\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\tid: `spawn:${run.id}`,\n\t\t\t\t\t\tmessage: prompt,\n\t\t\t\t\t\tfrom: {\n\t\t\t\t\t\t\tsessionId: this.sessionId,\n\t\t\t\t\t\t\tsessionName: this.sessionName,\n\t\t\t\t\t\t\tactiveSessionId: await this._currentActiveSessionId(),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfromRelationship: \"parent\",\n\t\t\t\t\t},\n\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t};\n\t\t\t\tthrowIfCancelled();\n\t\t\t\tconst parentReplyCountBeforeRun = child._parentReplyCount;\n\t\t\t\tawait child.promptAndWait(content, {\n\t\t\t\t\texpandPromptTemplates: false,\n\t\t\t\t\tsource: \"extension\",\n\t\t\t\t\tcustomMessage: spawnMessage,\n\t\t\t\t});\n\t\t\t\tawait child.waitForRlmQuiescence();\n\t\t\t\tif (run.error) throw new Error(run.error);\n\t\t\t\trun.status = \"done\";\n\t\t\t\tdurationMs = Date.now() - startedAt;\n\t\t\t\tactivity = undefined;\n\t\t\t\temitChildUpdate();\n\t\t\t\tif (\n\t\t\t\t\t!run.detachedDeletion &&\n\t\t\t\t\t!run.suppressTerminalNotice &&\n\t\t\t\t\tchild._parentReplyCount === parentReplyCountBeforeRun\n\t\t\t\t) {\n\t\t\t\t\tconst lastAssistantText = child.getLastAssistantText();\n\t\t\t\t\tawait deliverTerminalMessageToParent(\n\t\t\t\t\t\tcreateRlmChildTerminalNoticeMessage({\n\t\t\t\t\t\t\tkind: \"completed_without_reply\",\n\t\t\t\t\t\t\tchildId: run.id,\n\t\t\t\t\t\t\tsessionName,\n\t\t\t\t\t\t\tlastAssistantTextPreview: lastAssistantText ? compactRlmText(lastAssistantText) : undefined,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (!this.registerRlmChildSession(run.id, child) && !run.detachedDeletion) {\n\t\t\t\t\tif (childRuntime && this._subagentRuntimeHost?.releaseRlmSubagentRuntime) {\n\t\t\t\t\t\tawait this._subagentRuntimeHost\n\t\t\t\t\t\t\t.releaseRlmSubagentRuntime(childRuntime, subagentOptions, \"error\")\n\t\t\t\t\t\t\t.catch(() => void child.disposeAsync().catch(() => undefined));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tawait child.disposeAsync().catch(() => undefined);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst runError = error instanceof Error ? error : new Error(String(error));\n\t\t\t\trun.publication.reject(runError);\n\t\t\t\tif (run.status !== \"cancelled\") {\n\t\t\t\t\trun.status = \"error\";\n\t\t\t\t\trun.error = runError.message;\n\t\t\t\t}\n\t\t\t\tdurationMs = Date.now() - startedAt;\n\t\t\t\tactivity = undefined;\n\t\t\t\temitChildUpdate();\n\t\t\t\tif (!run.detachedDeletion && !run.suppressTerminalNotice) {\n\t\t\t\t\tif (run.status === \"error\") {\n\t\t\t\t\t\tawait deliverTerminalMessageToParent(\n\t\t\t\t\t\t\tcreateRlmChildFailureMessage({\n\t\t\t\t\t\t\t\tchildId: run.id,\n\t\t\t\t\t\t\t\tsessionName,\n\t\t\t\t\t\t\t\terror: run.error ?? \"unknown error\",\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t} else if (run.status === \"cancelled\") {\n\t\t\t\t\t\tawait deliverTerminalMessageToParent(\n\t\t\t\t\t\t\tcreateRlmChildTerminalNoticeMessage({\n\t\t\t\t\t\t\t\tkind: \"cancelled\",\n\t\t\t\t\t\t\t\tchildId: run.id,\n\t\t\t\t\t\t\t\tsessionName,\n\t\t\t\t\t\t\t\treason: run.error,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!run.detachedDeletion && childSession && this._subagentRuntimeHost?.releaseRlmSubagentRuntime) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait this._subagentRuntimeHost.releaseRlmSubagentRuntime(\n\t\t\t\t\t\t\tchildRuntime ?? { session: childSession },\n\t\t\t\t\t\t\tsubagentOptions,\n\t\t\t\t\t\t\trun.status === \"cancelled\" ? \"cancelled\" : \"error\",\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (run.status === \"cancelled\" && !this._disposed && !this._disposing) {\n\t\t\t\t\t\t\tthis._deletedRlmChildIds.add(run.id);\n\t\t\t\t\t\t\tthis._removeRlmSubagentTracking(run.id);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tawait childSession?.disposeAsync().catch(() => undefined);\n\t\t\t\t\t}\n\t\t\t\t} else if (!run.detachedDeletion) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (childRuntime && this._subagentRuntimeHost) {\n\t\t\t\t\t\t\tawait this._subagentRuntimeHost.deleteRlmSubagentRuntime(run.id, childRuntime.session);\n\t\t\t\t\t\t} else if (childSession) {\n\t\t\t\t\t\t\tawait childSession.disposeAsync();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (run.status === \"cancelled\" && !this._disposed && !this._disposing) {\n\t\t\t\t\t\t\tthis._deletedRlmChildIds.add(run.id);\n\t\t\t\t\t\t\tthis._removeRlmSubagentTracking(run.id);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// A failed best-effort retry remains available through the retained cleanup maps.\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tif (run.detachedDeletion) {\n\t\t\t\t\trun.deletionRunFinished = true;\n\t\t\t\t\tif (!run.settled) {\n\t\t\t\t\t\tlet cleanupSucceeded = !run.deletionCleanupFailed;\n\t\t\t\t\t\tif (childRuntime && cleanupSucceeded) {\n\t\t\t\t\t\t\tconst cleanup =\n\t\t\t\t\t\t\t\trun.deletionCleanup ?? this._ensureRlmRunDeletionCleanup(run, childRuntime.session);\n\t\t\t\t\t\t\tcleanupSucceeded = await this._observeRlmRunDeletionCleanup(\n\t\t\t\t\t\t\t\trun,\n\t\t\t\t\t\t\t\trun.detachedDeletion,\n\t\t\t\t\t\t\t\tchildRuntime.session,\n\t\t\t\t\t\t\t\tcleanup,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (cleanupSucceeded) await this._finishRlmRunDeletion(run);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (this._activeRlmChildRuns.get(run.id) === run) {\n\t\t\t\t\t\tif (this._rlmChildSessions.has(run.id)) {\n\t\t\t\t\t\t\tthis._activeRlmChildRuns.delete(run.id);\n\t\t\t\t\t\t\tif (run.unsubscribe) this._rlmChildUnsubscribes.set(run.id, run.unsubscribe);\n\t\t\t\t\t\t\trun.abort = noopRlmChildAbort;\n\t\t\t\t\t\t\trun.unsubscribe = undefined;\n\t\t\t\t\t\t\trun.session = undefined;\n\t\t\t\t\t\t} else if (run.status !== \"error\") {\n\t\t\t\t\t\t\tthis._removeRlmSubagentTracking(run.id, run);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\trun.unsubscribe?.();\n\t\t\t\t\t\t\trun.abort = noopRlmChildAbort;\n\t\t\t\t\t\t\trun.unsubscribe = undefined;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\trun.settled = true;\n\t\t\t\t\trun.settlement.resolve();\n\t\t\t\t\tthis._unsettledRlmChildRuns.delete(run);\n\t\t\t\t\tthis._maybeResumeGoalContinuationAfterRlmWork();\n\t\t\t\t}\n\t\t\t}\n\t\t})().catch(() => undefined);\n\n\t\treturn {\n\t\t\trlm_child_id: childNodeId,\n\t\t\tname: sessionName,\n\t\t\tsession_dir: childSessionDir,\n\t\t\tmodel: `${modelSelection.model.provider}/${modelSelection.model.id}`,\n\t\t};\n\t}\n\n\tasync runRlmChild(\n\t\tprompt: string,\n\t\tkwargs: Record<string, unknown> = {},\n\t\tspawnCode?: string,\n\t): Promise<RlmSpawnHandle> {\n\t\treturn this._startRlmChildRun(prompt, kwargs, spawnCode);\n\t}\n\n\tprivate _isRetryableError(message: AssistantMessage): boolean {\n\t\tif (message.stopReason !== \"error\" || !message.errorMessage) return false;\n\n\t\tconst contextWindow = this.model?.contextWindow ?? 0;\n\t\tif (isContextOverflow(message, contextWindow)) return false;\n\n\t\tif (this._isFauxProviderQueueExhausted(message)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (this._isAgentLifecycleFailure(message)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (this._isStructuredPermanentProviderRetryExhausted(message)) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tprivate _isFauxProviderQueueExhausted(message: AssistantMessage): boolean {\n\t\treturn message.provider === \"faux\" && message.errorMessage === \"No more faux responses queued\";\n\t}\n\n\tprivate _isAgentLifecycleFailure(message: AssistantMessage): boolean {\n\t\treturn message.diagnostics?.some((diagnostic) => diagnostic.type === \"agent_lifecycle_failure\") ?? false;\n\t}\n\n\tprivate _getProviderStreamFailureDetails(message: AssistantMessage): Record<string, unknown> | undefined {\n\t\tconst failure = message.diagnostics?.find((diagnostic) => diagnostic.type === \"provider_stream_failure\");\n\t\tconst details = failure?.details;\n\t\tif (!details || typeof details !== \"object\") {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn details;\n\t}\n\n\tprivate _getProviderStreamFailureKind(message: AssistantMessage): string | undefined {\n\t\tconst kind = this._getProviderStreamFailureDetails(message)?.kind;\n\t\treturn typeof kind === \"string\" ? kind : undefined;\n\t}\n\n\tprivate _isStructuredPermanentProviderFailure(message: AssistantMessage): boolean {\n\t\tconst kind = this._getProviderStreamFailureKind(message);\n\t\treturn kind === \"auth\" || kind === \"invalid_request\" || kind === \"refusal\";\n\t}\n\n\tprivate _isStructuredPermanentProviderRetryExhausted(message: AssistantMessage): boolean {\n\t\treturn this._retryAttempt > 0 && this._isStructuredPermanentProviderFailure(message);\n\t}\n\n\tprivate _getProviderStreamFailureAuthStatus(message: AssistantMessage): number | undefined {\n\t\tconst details = this._getProviderStreamFailureDetails(message);\n\t\tif (!details) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst kind = details.kind;\n\t\tif (kind !== \"auth\") {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst status = details.status;\n\t\tif (typeof status === \"number\") {\n\t\t\treturn status;\n\t\t}\n\t\tif (typeof status === \"string\") {\n\t\t\tconst parsed = Number(status);\n\t\t\treturn Number.isInteger(parsed) ? parsed : undefined;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate _isConcreteProviderAuthFailure(message: AssistantMessage): boolean {\n\t\tif (message.stopReason !== \"error\" || !message.errorMessage) return false;\n\n\t\tconst structuredStatus = this._getProviderStreamFailureAuthStatus(message);\n\t\tif (structuredStatus === 401 || structuredStatus === 403) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (/\\b(?:401|403)\\b/.test(message.errorMessage) && /\\bstatus code\\b/i.test(message.errorMessage)) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn (\n\t\t\t/\\b(?:401|403)\\b/.test(message.errorMessage) &&\n\t\t\t/auth|unauthori[sz]ed|forbidden|api.?key|token|credential/i.test(message.errorMessage)\n\t\t);\n\t}\n\n\tprivate _captureRetryAuthFailureSource(message: AssistantMessage): AuthSourceToken | undefined {\n\t\tconst token = this._modelRegistry.getCurrentProviderAuthSourceToken(message.provider);\n\t\tif (!token) {\n\t\t\treturn undefined;\n\t\t}\n\t\tif (\n\t\t\t!this._retryAuthFailureSources.some(\n\t\t\t\t(existing) =>\n\t\t\t\t\texisting.provider === token.provider &&\n\t\t\t\t\texisting.source === token.source &&\n\t\t\t\t\texisting.identityFingerprint === token.identityFingerprint &&\n\t\t\t\t\texisting.valueFingerprint === token.valueFingerprint,\n\t\t\t)\n\t\t) {\n\t\t\tthis._retryAuthFailureSources.push(token);\n\t\t}\n\t\treturn token;\n\t}\n\n\tprivate _markProviderAuthStale(message: AssistantMessage, authSourceTokens?: readonly AuthSourceToken[]): boolean {\n\t\tif (authSourceTokens && authSourceTokens.length > 0) {\n\t\t\tlet marked = false;\n\t\t\tfor (const token of authSourceTokens) {\n\t\t\t\tmarked = this._modelRegistry.markProviderAuthSourceStale(token) || marked;\n\t\t\t}\n\t\t\tif (marked) {\n\t\t\t\tthis._emit({\n\t\t\t\t\ttype: \"auth_stale\",\n\t\t\t\t\tprovider: message.provider,\n\t\t\t\t\tsourceTokens: authSourceTokens,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn marked;\n\t\t}\n\t\tconst marked = this._modelRegistry.markProviderAuthStale(message.provider);\n\t\tif (marked) {\n\t\t\tthis._emit({ type: \"auth_stale\", provider: message.provider });\n\t\t}\n\t\treturn marked;\n\t}\n\n\tprivate _markProviderAuthStaleForRetryFailure(\n\t\tmessage: AssistantMessage,\n\t\toptions?: {\n\t\t\tmarkAuthStaleOnFailure?: boolean;\n\t\t\tauthSourceTokens?: readonly AuthSourceToken[];\n\t\t},\n\t): boolean {\n\t\tconst authSourceTokens =\n\t\t\tthis._retryAuthFailureSources.length > 0 ? this._retryAuthFailureSources : options?.authSourceTokens;\n\t\tif ((authSourceTokens?.length ?? 0) > 0 || options?.markAuthStaleOnFailure) {\n\t\t\tconst marked = this._markProviderAuthStale(message, authSourceTokens);\n\t\t\tif (marked && message.errorMessage) {\n\t\t\t\tmessage.errorMessage = addLoginGuidanceToAuthError(message.errorMessage);\n\t\t\t}\n\t\t\treturn marked;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate _finishActiveRetryWithFailure(message: AssistantMessage): void {\n\t\tif (this._retryAttempt === 0) {\n\t\t\treturn;\n\t\t}\n\t\tthis._markProviderAuthStaleForRetryFailure(message);\n\t\tthis._emit({\n\t\t\ttype: \"auto_retry_end\",\n\t\t\tsuccess: false,\n\t\t\tattempt: this._retryAttempt,\n\t\t\tfinalError: message.errorMessage,\n\t\t});\n\t\tthis._retryAttempt = 0;\n\t\tthis._retryAuthFailureSources = [];\n\t}\n\n\tprivate async _handleRetryableError(\n\t\tmessage: AssistantMessage,\n\t\toptions?: {\n\t\t\tmarkAuthStaleOnFailure?: boolean;\n\t\t\tauthSourceTokens?: readonly AuthSourceToken[];\n\t\t},\n\t): Promise<boolean> {\n\t\tconst settings = this.settingsManager.getRetrySettings();\n\t\tif (!settings.enabled) {\n\t\t\tthis._markProviderAuthStaleForRetryFailure(message, options);\n\t\t\tthis._retryAuthFailureSources = [];\n\t\t\tthis._resolveRetry();\n\t\t\treturn false;\n\t\t}\n\n\t\tif (!this._retryPromise) {\n\t\t\tthis._retryPromise = new Promise((resolve) => {\n\t\t\t\tthis._retryResolve = resolve;\n\t\t\t});\n\t\t}\n\n\t\tthis._retryAttempt++;\n\n\t\tif (this._retryAttempt > settings.maxRetries) {\n\t\t\tthis._markProviderAuthStaleForRetryFailure(message, options);\n\t\t\tthis._emit({\n\t\t\t\ttype: \"auto_retry_end\",\n\t\t\t\tsuccess: false,\n\t\t\t\tattempt: this._retryAttempt - 1,\n\t\t\t\tfinalError: message.errorMessage,\n\t\t\t});\n\t\t\tthis._retryAttempt = 0;\n\t\t\tthis._retryAuthFailureSources = [];\n\t\t\tthis._resolveRetry(); // Resolve so waitForRetry() completes\n\t\t\treturn false;\n\t\t}\n\n\t\tconst delayMs = settings.baseDelayMs * 2 ** (this._retryAttempt - 1);\n\n\t\tthis._emit({\n\t\t\ttype: \"auto_retry_start\",\n\t\t\tattempt: this._retryAttempt,\n\t\t\tmaxAttempts: settings.maxRetries,\n\t\t\tdelayMs,\n\t\t\terrorMessage: message.errorMessage || \"Unknown error\",\n\t\t});\n\n\t\tconst messages = this.agent.state.messages;\n\t\tif (messages.length > 0 && messages[messages.length - 1].role === \"assistant\") {\n\t\t\tthis.agent.state.messages = messages.slice(0, -1);\n\t\t}\n\n\t\tthis._retryAbortController = new AbortController();\n\t\ttry {\n\t\t\tawait sleep(delayMs, this._retryAbortController.signal);\n\t\t} catch {\n\t\t\tconst attempt = this._retryAttempt;\n\t\t\tthis._markProviderAuthStaleForRetryFailure(message, options);\n\t\t\tthis._retryAttempt = 0;\n\t\t\tthis._retryAbortController = undefined;\n\t\t\tthis._emit({\n\t\t\t\ttype: \"auto_retry_end\",\n\t\t\t\tsuccess: false,\n\t\t\t\tattempt,\n\t\t\t\tfinalError: \"Retry cancelled\",\n\t\t\t});\n\t\t\tthis._resolveRetry();\n\t\t\tthis._retryAuthFailureSources = [];\n\t\t\treturn false;\n\t\t}\n\t\tthis._retryAbortController = undefined;\n\n\t\tsetTimeout(() => {\n\t\t\tthis.agent.continue().catch(() => {});\n\t\t}, 0);\n\n\t\treturn true;\n\t}\n\n\tabortRetry(): void {\n\t\tif (this._retryAbortController) {\n\t\t\tthis._retryAbortController.abort();\n\t\t\treturn;\n\t\t}\n\t\tif (this._retryAttempt > 0) {\n\t\t\tthis._autoCompactionAbortController?.abort();\n\t\t\tthis._cancelPostCompactionContinue();\n\t\t\tthis._emit({\n\t\t\t\ttype: \"auto_retry_end\",\n\t\t\t\tsuccess: false,\n\t\t\t\tattempt: this._retryAttempt,\n\t\t\t\tfinalError: \"Retry cancelled\",\n\t\t\t});\n\t\t\tthis._retryAttempt = 0;\n\t\t}\n\t\tthis._retryAuthFailureSources = [];\n\t\tthis._resolveRetry();\n\t}\n\n\tprivate async waitForRetry(): Promise<void> {\n\t\tif (!this._retryPromise) {\n\t\t\treturn;\n\t\t}\n\n\t\tawait this._retryPromise;\n\t\tawait this.agent.waitForIdle();\n\t}\n\n\tget isRetrying(): boolean {\n\t\treturn this._retryPromise !== undefined;\n\t}\n\n\tget hasAcceptedPromptInFlight(): boolean {\n\t\treturn this._actionStore\n\t\t\t.unfinishedActions()\n\t\t\t.some(\n\t\t\t\t(action) =>\n\t\t\t\t\taction.payload.kind === \"turn\" &&\n\t\t\t\t\t!action.payload.queueVisible &&\n\t\t\t\t\taction.payload.acceptedBeforeCompletion,\n\t\t\t);\n\t}\n\n\tget autoRetryEnabled(): boolean {\n\t\treturn this.settingsManager.getRetryEnabled();\n\t}\n\n\tsetAutoRetryEnabled(enabled: boolean): void {\n\t\tthis.settingsManager.setRetryEnabled(enabled);\n\t}\n\n\t/**\n\t * Execute a bash command.\n\t * Adds result to agent context and session.\n\t * @param command The bash command to execute\n\t * @param onChunk Optional streaming callback for output\n\t * @param options.excludeFromContext If true, command output won't be sent to LLM (!! prefix)\n\t * @param options.operations Custom BashOperations for remote execution\n\t */\n\tasync executeBash(\n\t\tcommand: string,\n\t\tonChunk?: (chunk: string) => void,\n\t\toptions?: {\n\t\t\texcludeFromContext?: boolean;\n\t\t\toperations?: BashOperations;\n\t\t\ttransient?: boolean;\n\t\t},\n\t): Promise<BashResult> {\n\t\t// Each invocation owns its controller so abortBash reaches every in-flight command.\n\t\tconst abortController = new AbortController();\n\t\tthis._bashAbortControllers.add(abortController);\n\n\t\tconst prefix = this.settingsManager.getShellCommandPrefix();\n\t\tconst shellPath = this.settingsManager.getShellPath();\n\t\tconst resolvedCommand = prefix ? `${prefix}\\n${command}` : command;\n\n\t\ttry {\n\t\t\tconst result = await executeBashWithOperations(\n\t\t\t\tresolvedCommand,\n\t\t\t\tthis.sessionManager.getCwd(),\n\t\t\t\toptions?.operations ?? createLocalBashOperations({ shellPath }),\n\t\t\t\t{\n\t\t\t\t\tonChunk,\n\t\t\t\t\tsignal: abortController.signal,\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tif (!options?.transient) {\n\t\t\t\tthis.recordBashResult(command, result, options);\n\t\t\t}\n\t\t\treturn result;\n\t\t} finally {\n\t\t\tthis._bashAbortControllers.delete(abortController);\n\t\t\tthis._notifySessionInputCheckpointChange();\n\t\t}\n\t}\n\n\t/**\n\t * Run a user-initiated bash command (! / !! prefix), emitting bash_start,\n\t * bash_output, and bash_end session events so any attached client can render\n\t * streaming output. Extensions can intercept execution via the user_bash event.\n\t * Execution failures are reported through bash_end rather than a rejected promise;\n\t * only the already-running guard and extension dispatch errors reject.\n\t * @param command The bash command to execute\n\t * @param options.excludeFromContext If true, command output won't be sent to LLM (!! prefix)\n\t */\n\tasync runUserBash(\n\t\tcommand: string,\n\t\toptions?: {\n\t\t\texcludeFromContext?: boolean;\n\t\t\ttransient?: boolean;\n\t\t\trunId?: string;\n\t\t},\n\t): Promise<void> {\n\t\tif (this.isBashRunning) {\n\t\t\tthrow new Error(\"A bash command is already running\");\n\t\t}\n\t\t// Claim the bash slot synchronously: isBashRunning is otherwise false until\n\t\t// executeBash installs its abort controller, which would let a second command\n\t\t// slip through during the user_bash extension dispatch below.\n\t\tthis._userBashRunning = true;\n\t\tthis._userBashAbortRequested = false;\n\t\t// Echoed on bash_start/bash_end so the requesting client can tell its own\n\t\t// run apart from other clients' runs broadcast on the same session.\n\t\tconst identity = {\n\t\t\t...(options?.transient ? { transient: true } : {}),\n\t\t\t...(options?.runId !== undefined ? { runId: options.runId } : {}),\n\t\t};\n\t\tlet end: UserBashEndDetails;\n\t\ttry {\n\t\t\tend = await this.runUserBashLocked(\n\t\t\t\tcommand,\n\t\t\t\toptions?.excludeFromContext ?? false,\n\t\t\t\toptions?.transient ?? false,\n\t\t\t\tidentity,\n\t\t\t);\n\t\t} finally {\n\t\t\tthis._userBashRunning = false;\n\t\t}\n\t\t// Emitted after the slot is released so clients never observe a bash_end\n\t\t// while the session still rejects new commands as already running.\n\t\tthis._emit({ type: \"bash_end\", ...end, ...identity });\n\t\tvoid this._drainQueuedMessagesAfterBash().catch(() => undefined);\n\t}\n\n\tprivate async _drainQueuedMessagesAfterBash(): Promise<void> {\n\t\tawait this.agent.waitForIdle();\n\t\tthis._scheduleSessionInputPump();\n\t}\n\n\tprivate async runUserBashLocked(\n\t\tcommand: string,\n\t\texcludeFromContext: boolean,\n\t\ttransient: boolean,\n\t\tidentity: { transient?: boolean; runId?: string },\n\t): Promise<UserBashEndDetails> {\n\t\tconst eventResult = await this._extensionRunner.emitUserBash({\n\t\t\ttype: \"user_bash\",\n\t\t\tcommand,\n\t\t\texcludeFromContext,\n\t\t\tcwd: this.sessionManager.getCwd(),\n\t\t});\n\n\t\t// Transient runs (side-conversation bash) live only in their pane: they\n\t\t// are never recorded, so reloads and rebuilds cannot resurface them.\n\t\tconst record = transient\n\t\t\t? () => {}\n\t\t\t: (result: BashResult) => this.recordBashResult(command, result, { excludeFromContext });\n\n\t\tthis._emit({\n\t\t\ttype: \"bash_start\",\n\t\t\tcommand,\n\t\t\texcludeFromContext,\n\t\t\t...identity,\n\t\t});\n\t\ttry {\n\t\t\t// If an extension returned a full result, surface it without executing\n\t\t\tif (eventResult?.result) {\n\t\t\t\tconst result = eventResult.result;\n\t\t\t\tif (result.output) {\n\t\t\t\t\tthis._emit({ type: \"bash_output\", chunk: result.output });\n\t\t\t\t}\n\t\t\t\trecord(result);\n\t\t\t\treturn {\n\t\t\t\t\texitCode: result.exitCode,\n\t\t\t\t\tcancelled: result.cancelled,\n\t\t\t\t\ttruncated: result.truncated,\n\t\t\t\t\tfullOutputPath: result.fullOutputPath,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// An abort that arrived before the process spawned (during extension\n\t\t\t// dispatch) has no abort controller to act on; honor it here instead.\n\t\t\tif (this._userBashAbortRequested) {\n\t\t\t\trecord({\n\t\t\t\t\toutput: \"\",\n\t\t\t\t\texitCode: undefined,\n\t\t\t\t\tcancelled: true,\n\t\t\t\t\ttruncated: false,\n\t\t\t\t});\n\t\t\t\treturn { exitCode: undefined, cancelled: true, truncated: false };\n\t\t\t}\n\n\t\t\tconst result = await this.executeBash(command, (chunk) => this._emit({ type: \"bash_output\", chunk }), {\n\t\t\t\texcludeFromContext,\n\t\t\t\toperations: eventResult?.operations,\n\t\t\t\ttransient,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\texitCode: result.exitCode,\n\t\t\t\tcancelled: result.cancelled,\n\t\t\t\ttruncated: result.truncated,\n\t\t\t\tfullOutputPath: result.fullOutputPath,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : String(error);\n\t\t\t// Persist the failure like every other outcome so replayed transcripts\n\t\t\t// and the LLM context reflect that the command did not run.\n\t\t\trecord({\n\t\t\t\toutput: `bash failed: ${errorMessage}`,\n\t\t\t\texitCode: undefined,\n\t\t\t\tcancelled: false,\n\t\t\t\ttruncated: false,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\texitCode: undefined,\n\t\t\t\tcancelled: false,\n\t\t\t\ttruncated: false,\n\t\t\t\terrorMessage,\n\t\t\t};\n\t\t}\n\t}\n\n\trecordBashResult(command: string, result: BashResult, options?: { excludeFromContext?: boolean }): void {\n\t\tconst bashMessage: BashExecutionMessage = {\n\t\t\trole: \"bashExecution\",\n\t\t\tcommand,\n\t\t\toutput: result.output,\n\t\t\texitCode: result.exitCode,\n\t\t\tcancelled: result.cancelled,\n\t\t\ttruncated: result.truncated,\n\t\t\tfullOutputPath: result.fullOutputPath,\n\t\t\ttimestamp: Date.now(),\n\t\t\texcludeFromContext: options?.excludeFromContext,\n\t\t};\n\n\t\t// If agent is streaming, defer adding to avoid breaking tool_use/tool_result ordering\n\t\tif (this.isStreaming) {\n\t\t\tthis._pendingBashMessages.push(bashMessage);\n\t\t} else {\n\t\t\tthis.agent.state.messages.push(bashMessage);\n\n\t\t\tthis.sessionManager.appendMessage(bashMessage);\n\t\t}\n\t}\n\n\t/**\n\t * Cancel running bash command.\n\t */\n\tabortBash(): void {\n\t\t// A user bash command may not have spawned yet (extension dispatch in\n\t\t// progress); flag the request so runUserBash cancels before executing.\n\t\t// runUserBash clears the flag at each start, so a stale flag is harmless.\n\t\tif (this._userBashRunning) {\n\t\t\tthis._userBashAbortRequested = true;\n\t\t}\n\t\tfor (const controller of this._bashAbortControllers) {\n\t\t\tcontroller.abort();\n\t\t}\n\t}\n\n\tget isBashRunning(): boolean {\n\t\treturn this._bashAbortControllers.size > 0 || this._userBashRunning;\n\t}\n\n\t/** Whether there are pending bash messages waiting to be flushed */\n\tget hasPendingBashMessages(): boolean {\n\t\treturn this._pendingBashMessages.length > 0;\n\t}\n\n\t/**\n\t * Flush pending bash messages to agent state and session.\n\t * Called after agent turn completes to maintain proper message ordering.\n\t */\n\tprivate _flushPendingBashMessages(): void {\n\t\tif (this._pendingBashMessages.length === 0) return;\n\n\t\tfor (const bashMessage of this._pendingBashMessages) {\n\t\t\tthis.agent.state.messages.push(bashMessage);\n\n\t\t\tthis.sessionManager.appendMessage(bashMessage);\n\t\t}\n\n\t\tthis._pendingBashMessages = [];\n\t}\n\n\tgetRlmMaxDepthStatus(): RlmMaxDepthStatus {\n\t\treturn { maxDepth: this._rlmMaxDepth, source: this._rlmMaxDepthSource };\n\t}\n\n\tasync setRlmMaxDepth(maxDepth: number, options: { global?: boolean } = {}): Promise<SetRlmMaxDepthResult> {\n\t\tif (!isNonNegativeInteger(maxDepth)) {\n\t\t\tthrow new Error(\"RLM max depth must be a non-negative integer.\");\n\t\t}\n\n\t\tthis.sessionManager.appendCustomEntryWithRollback(RLM_MAX_DEPTH_STATE_CUSTOM_TYPE, { maxDepth });\n\t\tthis._rlmMaxDepth = maxDepth;\n\t\tthis._rlmMaxDepthSource = \"chat\";\n\t\tconst oldBase = this._baseSystemPrompt;\n\t\tthis._baseSystemPrompt = this._rebuildSystemPrompt(this.getActiveToolNames());\n\t\tthis.agent.state.systemPrompt = this._refreshExtensionSystemPrompt(this.agent.state.systemPrompt, oldBase);\n\n\t\tlet globalError: string | undefined;\n\t\tif (options.global) {\n\t\t\tawait this.settingsManager.flush();\n\t\t\tconst staleErrors = this.settingsManager.drainErrors(\"global\");\n\t\t\tfor (const { error } of staleErrors) {\n\t\t\t\tconsole.warn(`Warning: Earlier global settings write failed: ${error.message}`);\n\t\t\t}\n\t\t\tthis.settingsManager.setRlmMaxDepth(maxDepth);\n\t\t\tawait this.settingsManager.flush();\n\t\t\tconst errors = this.settingsManager.drainErrors(\"global\");\n\t\t\tglobalError = errors.map(({ error }) => error.message).join(\"; \") || undefined;\n\t\t}\n\n\t\treturn {\n\t\t\t...this.getRlmMaxDepthStatus(),\n\t\t\tglobalSaved: options.global === true && globalError === undefined,\n\t\t\t...(globalError ? { globalError } : {}),\n\t\t};\n\t}\n\n\tsetSessionName(name: string): void {\n\t\tthis.sessionManager.appendSessionInfo(name);\n\t\tthis._emit({\n\t\t\ttype: \"session_info_changed\",\n\t\t\tname: this.sessionManager.getSessionName(),\n\t\t});\n\t}\n\n\t/**\n\t * Navigate to a different node in the session tree.\n\t * Unlike fork() which creates a new session file, this stays in the same file.\n\t *\n\t * @param targetId The entry ID to navigate to\n\t * @param options.summarize Whether user wants to summarize abandoned branch\n\t * @param options.customInstructions Custom instructions for summarizer\n\t * @param options.replaceInstructions If true, customInstructions replaces the default prompt\n\t * @param options.label Label to attach to the branch summary entry\n\t * @returns Result with editorText (if user message) and cancelled status\n\t */\n\tprivate _branchNavigationQueue: Promise<void> = Promise.resolve();\n\n\tasync navigateTree(\n\t\ttargetId: string,\n\t\toptions: {\n\t\t\tsummarize?: boolean;\n\t\t\tcustomInstructions?: string;\n\t\t\treplaceInstructions?: boolean;\n\t\t\tlabel?: string;\n\t\t} = {},\n\t): Promise<{\n\t\teditorText?: string;\n\t\tcancelled: boolean;\n\t\taborted?: boolean;\n\t\tsummaryEntry?: BranchSummaryEntry;\n\t}> {\n\t\tconst previous = this._branchNavigationQueue;\n\t\tlet release = () => {};\n\t\tthis._branchNavigationQueue = new Promise<void>((resolve) => {\n\t\t\trelease = resolve;\n\t\t});\n\t\tawait previous;\n\t\ttry {\n\t\t\treturn await this._navigateTree(targetId, options);\n\t\t} finally {\n\t\t\trelease();\n\t\t}\n\t}\n\n\tprivate async _navigateTree(\n\t\ttargetId: string,\n\t\toptions: {\n\t\t\tsummarize?: boolean;\n\t\t\tcustomInstructions?: string;\n\t\t\treplaceInstructions?: boolean;\n\t\t\tlabel?: string;\n\t\t} = {},\n\t): Promise<{\n\t\teditorText?: string;\n\t\tcancelled: boolean;\n\t\taborted?: boolean;\n\t\tsummaryEntry?: BranchSummaryEntry;\n\t}> {\n\t\tif (options.summarize && !this.model) {\n\t\t\tthrow new Error(\"No model available for summarization\");\n\t\t}\n\n\t\tconst targetEntry = this.sessionManager.getEntry(targetId);\n\t\tif (!targetEntry) {\n\t\t\tthrow new Error(`Entry ${targetId} not found`);\n\t\t}\n\n\t\tconst queuedWorkPause = this.acquireQueuedWorkPause();\n\t\tlet commitFence: { owner: symbol; release(): void } | undefined;\n\t\ttry {\n\t\t\t// Branch navigation and turn dispatch mutate the same transcript leaf.\n\t\t\tcommitFence = await this._acquireSessionActionCommitFence();\n\t\t\treturn await this._sessionActionCommitContext.run(commitFence.owner, async () => {\n\t\t\t\tawait this.agent.waitForIdle();\n\t\t\t\tawait this._agentEventQueue;\n\t\t\t\treturn this._navigateTreeUnderPause(targetId, targetEntry, options);\n\t\t\t});\n\t\t} finally {\n\t\t\tqueuedWorkPause.release();\n\t\t\tcommitFence?.release();\n\t\t}\n\t}\n\n\tprivate async _navigateTreeUnderPause(\n\t\ttargetId: string,\n\t\ttargetEntry: NonNullable<ReturnType<SessionManager[\"getEntry\"]>>,\n\t\toptions: {\n\t\t\tsummarize?: boolean;\n\t\t\tcustomInstructions?: string;\n\t\t\treplaceInstructions?: boolean;\n\t\t\tlabel?: string;\n\t\t},\n\t): Promise<{\n\t\teditorText?: string;\n\t\tcancelled: boolean;\n\t\taborted?: boolean;\n\t\tsummaryEntry?: BranchSummaryEntry;\n\t}> {\n\t\tconst oldLeafId = this.sessionManager.getLeafId();\n\n\t\t// No-op if already at target after admitted work has settled.\n\t\tif (targetId === oldLeafId) {\n\t\t\treturn { cancelled: false };\n\t\t}\n\n\t\t// Do not switch branches while /refine has detached event handling and is\n\t\t// about to persist harness/session entries for the current branch.\n\t\tawait this._invalidatePendingAutoRefineForBranchChange();\n\n\t\tconst { entries: entriesToSummarize, commonAncestorId } = collectEntriesForBranchSummary(\n\t\t\tthis.sessionManager,\n\t\t\toldLeafId,\n\t\t\ttargetId,\n\t\t);\n\n\t\tlet customInstructions = options.customInstructions;\n\t\tlet replaceInstructions = options.replaceInstructions;\n\t\tlet label = options.label;\n\n\t\tconst preparation: TreePreparation = {\n\t\t\ttargetId,\n\t\t\toldLeafId,\n\t\t\tcommonAncestorId,\n\t\t\tentriesToSummarize,\n\t\t\tuserWantsSummary: options.summarize ?? false,\n\t\t\tcustomInstructions,\n\t\t\treplaceInstructions,\n\t\t\tlabel,\n\t\t};\n\n\t\tthis._branchSummaryAbortController = new AbortController();\n\t\tlet resolveBranchSummaryOperation: () => void = () => {};\n\t\tconst branchSummaryOperation = new Promise<void>((resolve) => {\n\t\t\tresolveBranchSummaryOperation = resolve;\n\t\t});\n\t\tthis._branchSummaryOperation = branchSummaryOperation;\n\n\t\ttry {\n\t\t\tlet extensionSummary: { summary: string; details?: unknown } | undefined;\n\t\t\tlet fromExtension = false;\n\n\t\t\tif (this._extensionRunner.hasHandlers(\"session_before_tree\")) {\n\t\t\t\tconst result = (await this._extensionRunner.emit({\n\t\t\t\t\ttype: \"session_before_tree\",\n\t\t\t\t\tpreparation,\n\t\t\t\t\tsignal: this._branchSummaryAbortController.signal,\n\t\t\t\t})) as SessionBeforeTreeResult | undefined;\n\n\t\t\t\tif (result?.cancel) {\n\t\t\t\t\treturn { cancelled: true };\n\t\t\t\t}\n\n\t\t\t\tif (result?.summary && options.summarize) {\n\t\t\t\t\textensionSummary = result.summary;\n\t\t\t\t\tfromExtension = true;\n\t\t\t\t}\n\n\t\t\t\tif (result?.customInstructions !== undefined) {\n\t\t\t\t\tcustomInstructions = result.customInstructions;\n\t\t\t\t}\n\t\t\t\tif (result?.replaceInstructions !== undefined) {\n\t\t\t\t\treplaceInstructions = result.replaceInstructions;\n\t\t\t\t}\n\t\t\t\tif (result?.label !== undefined) {\n\t\t\t\t\tlabel = result.label;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet summaryText: string | undefined;\n\t\t\tlet summaryDetails: unknown;\n\t\t\tif (options.summarize && entriesToSummarize.length > 0 && !extensionSummary) {\n\t\t\t\tconst model = this.model!;\n\t\t\t\tconst { apiKey, headers } = await this._getRequiredRequestAuth(model);\n\t\t\t\tconst branchSummarySettings = this.settingsManager.getBranchSummarySettings();\n\t\t\t\tconst result = await generateBranchSummary(entriesToSummarize, {\n\t\t\t\t\tmodel,\n\t\t\t\t\tapiKey,\n\t\t\t\t\theaders,\n\t\t\t\t\tsignal: this._branchSummaryAbortController.signal,\n\t\t\t\t\tcustomInstructions,\n\t\t\t\t\treplaceInstructions,\n\t\t\t\t\treserveTokens: branchSummarySettings.reserveTokens,\n\t\t\t\t});\n\t\t\t\tif (result.aborted) {\n\t\t\t\t\treturn { cancelled: true, aborted: true };\n\t\t\t\t}\n\t\t\t\tif (result.error) {\n\t\t\t\t\tthrow new Error(result.error);\n\t\t\t\t}\n\t\t\t\tsummaryText = result.summary;\n\t\t\t\tsummaryDetails = {\n\t\t\t\t\treadFiles: result.readFiles || [],\n\t\t\t\t\tmodifiedFiles: result.modifiedFiles || [],\n\t\t\t\t};\n\t\t\t} else if (extensionSummary) {\n\t\t\t\tsummaryText = extensionSummary.summary;\n\t\t\t\tsummaryDetails = extensionSummary.details;\n\t\t\t}\n\n\t\t\tlet newLeafId: string | null;\n\t\t\tlet editorText: string | undefined;\n\n\t\t\tif (targetEntry.type === \"message\" && targetEntry.message.role === \"user\") {\n\t\t\t\tnewLeafId = targetEntry.parentId;\n\t\t\t\teditorText = this._extractUserMessageText(targetEntry.message.content);\n\t\t\t} else if (targetEntry.type === \"custom_message\") {\n\t\t\t\tnewLeafId = targetEntry.parentId;\n\t\t\t\teditorText =\n\t\t\t\t\ttypeof targetEntry.content === \"string\"\n\t\t\t\t\t\t? targetEntry.content\n\t\t\t\t\t\t: targetEntry.content\n\t\t\t\t\t\t\t\t.filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n\t\t\t\t\t\t\t\t.map((c) => c.text)\n\t\t\t\t\t\t\t\t.join(\"\");\n\t\t\t} else {\n\t\t\t\tnewLeafId = targetId;\n\t\t\t}\n\n\t\t\tlet summaryEntry: BranchSummaryEntry | undefined;\n\t\t\tif (summaryText) {\n\t\t\t\tconst summaryId = this.sessionManager.branchWithSummary(\n\t\t\t\t\tnewLeafId,\n\t\t\t\t\tsummaryText,\n\t\t\t\t\tsummaryDetails,\n\t\t\t\t\tfromExtension,\n\t\t\t\t);\n\t\t\t\tsummaryEntry = this.sessionManager.getEntry(summaryId) as BranchSummaryEntry;\n\n\t\t\t\tif (label) {\n\t\t\t\t\tthis.sessionManager.appendLabelChange(summaryId, label);\n\t\t\t\t}\n\t\t\t} else if (newLeafId === null) {\n\t\t\t\tthis.sessionManager.resetLeaf();\n\t\t\t} else {\n\t\t\t\tthis.sessionManager.branch(newLeafId);\n\t\t\t}\n\n\t\t\tif (label && !summaryText) {\n\t\t\t\tthis.sessionManager.appendLabelChange(targetId, label);\n\t\t\t}\n\n\t\t\tconst sessionContext = this.sessionManager.buildSessionContext();\n\t\t\tthis.agent.state.messages = sessionContext.messages;\n\t\t\tthis._mergeUnpersistedOutcomes(this.agent.state.messages);\n\t\t\tthis._restoreLateIpythonSentAgentMessages();\n\t\t\tthis._reloadGoalStateFromBranch();\n\t\t\tthis._reloadRlmMaxDepthFromBranch();\n\t\t\tthis._invalidateQueuedPromptPreparation();\n\n\t\t\tawait this._extensionRunner.emit({\n\t\t\t\ttype: \"session_tree\",\n\t\t\t\tnewLeafId: this.sessionManager.getLeafId(),\n\t\t\t\toldLeafId,\n\t\t\t\tsummaryEntry,\n\t\t\t\tfromExtension: summaryText ? fromExtension : undefined,\n\t\t\t});\n\n\t\t\treturn { editorText, cancelled: false, summaryEntry };\n\t\t} finally {\n\t\t\tthis._branchSummaryAbortController = undefined;\n\t\t\tif (this._branchSummaryOperation === branchSummaryOperation) {\n\t\t\t\tthis._branchSummaryOperation = undefined;\n\t\t\t}\n\t\t\tresolveBranchSummaryOperation();\n\t\t}\n\t}\n\n\tgetUserMessagesForForking(): Array<{ entryId: string; text: string }> {\n\t\tconst entries = this.sessionManager.getEntries();\n\t\tconst result: Array<{ entryId: string; text: string }> = [];\n\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.type !== \"message\") continue;\n\t\t\tif (entry.message.role !== \"user\") continue;\n\n\t\t\tconst text = this._extractUserMessageText(entry.message.content);\n\t\t\tif (text) {\n\t\t\t\tresult.push({ entryId: entry.id, text });\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate _extractUserMessageText(content: string | Array<{ type: string; text?: string }>): string {\n\t\tif (typeof content === \"string\") return content;\n\t\tif (Array.isArray(content)) {\n\t\t\treturn content\n\t\t\t\t.filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n\t\t\t\t.map((c) => c.text)\n\t\t\t\t.join(\"\");\n\t\t}\n\t\treturn \"\";\n\t}\n\n\tgetSessionStats(): SessionStats {\n\t\tconst state = this.state;\n\t\tconst userMessages = state.messages.filter((m) => m.role === \"user\").length;\n\t\tconst assistantMessages = state.messages.filter((m) => m.role === \"assistant\").length;\n\t\tconst toolResults = state.messages.filter((m) => m.role === \"toolResult\").length;\n\n\t\tlet toolCalls = 0;\n\t\tlet totalInput = 0;\n\t\tlet totalOutput = 0;\n\t\tlet totalCacheRead = 0;\n\t\tlet totalCacheWrite = 0;\n\t\tlet totalCost = 0;\n\n\t\tfor (const message of state.messages) {\n\t\t\tif (message.role === \"assistant\") {\n\t\t\t\tconst assistantMsg = message as AssistantMessage;\n\t\t\t\ttoolCalls += assistantMsg.content.filter((c) => c.type === \"toolCall\").length;\n\t\t\t\ttotalInput += assistantMsg.usage.input;\n\t\t\t\ttotalOutput += assistantMsg.usage.output;\n\t\t\t\ttotalCacheRead += assistantMsg.usage.cacheRead;\n\t\t\t\ttotalCacheWrite += assistantMsg.usage.cacheWrite;\n\t\t\t\ttotalCost += assistantMsg.usage.cost.total;\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tsessionFile: this.sessionFile,\n\t\t\tsessionId: this.sessionId,\n\t\t\tuserMessages,\n\t\t\tassistantMessages,\n\t\t\ttoolCalls,\n\t\t\ttoolResults,\n\t\t\ttotalMessages: state.messages.length,\n\t\t\ttokens: {\n\t\t\t\tinput: totalInput,\n\t\t\t\toutput: totalOutput,\n\t\t\t\tcacheRead: totalCacheRead,\n\t\t\t\tcacheWrite: totalCacheWrite,\n\t\t\t\ttotal: totalInput + totalOutput + totalCacheRead + totalCacheWrite,\n\t\t\t},\n\t\t\tcost: totalCost,\n\t\t\tcontextUsage: this.getContextUsage(),\n\t\t};\n\t}\n\n\tgetContextUsage(): ContextUsage | undefined {\n\t\tconst model = this.model;\n\t\tif (!model) return undefined;\n\n\t\tconst contextWindow = model.contextWindow ?? 0;\n\t\tif (contextWindow <= 0) return undefined;\n\n\t\t// After compaction, the last assistant usage reflects pre-compaction context size.\n\t\t// We can only trust usage from an assistant that responded after the latest compaction.\n\t\t// If no such assistant exists, context token count is unknown until the next LLM response.\n\t\tconst branchEntries = this.sessionManager.getBranch();\n\t\tconst latestCompaction = getLatestCompactionEntry(branchEntries);\n\n\t\tif (latestCompaction) {\n\t\t\t// Check if there's a valid assistant usage after the compaction boundary\n\t\t\tconst compactionIndex = branchEntries.lastIndexOf(latestCompaction);\n\t\t\tlet hasPostCompactionUsage = false;\n\t\t\tfor (let i = branchEntries.length - 1; i > compactionIndex; i--) {\n\t\t\t\tconst entry = branchEntries[i];\n\t\t\t\tif (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\t\t\tconst assistant = entry.message;\n\t\t\t\t\tif (assistant.stopReason !== \"aborted\" && assistant.stopReason !== \"error\") {\n\t\t\t\t\t\tconst contextTokens = calculateContextTokens(assistant.usage);\n\t\t\t\t\t\tif (contextTokens > 0) {\n\t\t\t\t\t\t\thasPostCompactionUsage = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!hasPostCompactionUsage) {\n\t\t\t\treturn { tokens: null, contextWindow, percent: null };\n\t\t\t}\n\t\t}\n\n\t\tconst estimate = estimateContextTokens(this.messages);\n\t\tconst percent = (estimate.tokens / contextWindow) * 100;\n\n\t\treturn {\n\t\t\ttokens: estimate.tokens,\n\t\t\tcontextWindow,\n\t\t\tpercent,\n\t\t};\n\t}\n\n\tprivate _rlmSessionDirForReading(): string | undefined {\n\t\treturn this._rlmSessionDir ?? this.sessionManager.getSessionArtifactDir();\n\t}\n\n\tprivate _contextWindowResolver(): ContextWindowResolver {\n\t\treturn (provider, modelId) => this._modelRegistry.find(provider, modelId)?.contextWindow;\n\t}\n\n\t/**\n\t * Build the agent context overview for /context: this session as the root\n\t * plus one node per RLM sub-agent, recursively. Running children are read\n\t * from their live sessions; completed children from their persisted session\n\t * dirs, so the tree survives child disposal and session resume.\n\t */\n\tgetContextTree(): ContextTreeNode {\n\t\tconst resolveContextWindow = this._contextWindowResolver();\n\t\tconst { ownUsage, totalUsage } = computeOwnAndTotalUsage(\n\t\t\tthis.sessionManager.getBranch(),\n\t\t\tthis.sessionManager.getEntries(),\n\t\t);\n\n\t\tconst children: ContextTreeNode[] = [];\n\t\tconst liveIds = new Set<string>();\n\t\tfor (const run of this._activeRlmChildRuns.values()) {\n\t\t\tliveIds.add(run.id);\n\t\t\tconst node =\n\t\t\t\trun.session?.getContextTree() ?? loadContextTreeChildFromDisk(run.sessionDir, resolveContextWindow);\n\t\t\tchildren.push({\n\t\t\t\t...(node ?? {\n\t\t\t\t\townUsage: emptyUsage(),\n\t\t\t\t\ttotalUsage: emptyUsage(),\n\t\t\t\t\tchildren: [],\n\t\t\t\t}),\n\t\t\t\tid: run.id,\n\t\t\t\tlabel: rlmChildLabel(run.prompt),\n\t\t\t\tstatus: run.status,\n\t\t\t});\n\t\t}\n\t\tchildren.push(...loadContextTreeChildrenFromDisk(this._rlmSessionDirForReading(), resolveContextWindow, liveIds));\n\n\t\tconst model = this.model;\n\t\treturn {\n\t\t\tid: \"root\",\n\t\t\tlabel: this.sessionName ?? \"main agent\",\n\t\t\tstatus: \"active\",\n\t\t\tmodel: model ? { provider: model.provider, id: model.id } : undefined,\n\t\t\townUsage,\n\t\t\ttotalUsage,\n\t\t\tcontextUsage: this.getContextUsage(),\n\t\t\tchildren,\n\t\t};\n\t}\n\n\t/**\n\t * Export session to HTML.\n\t * @param outputPath Optional output path (defaults to session directory)\n\t * @returns Path to exported file\n\t */\n\tasync exportToHtml(outputPath?: string): Promise<string> {\n\t\tconst themeName = this.settingsManager.getTheme();\n\n\t\tconst toolRenderer: ToolHtmlRenderer = createToolHtmlRenderer({\n\t\t\tgetToolDefinition: (name) => this.getToolDefinition(name),\n\t\t\ttheme,\n\t\t\tcwd: this.sessionManager.getCwd(),\n\t\t});\n\n\t\treturn await exportSessionToHtml(this.sessionManager, this.state, {\n\t\t\toutputPath,\n\t\t\tthemeName,\n\t\t\ttoolRenderer,\n\t\t});\n\t}\n\n\t/**\n\t * Export the current session branch to a JSONL file.\n\t * Writes the session header followed by all entries on the current branch path.\n\t * @param outputPath Target file path. If omitted, generates a timestamped file in cwd.\n\t * @returns The resolved output file path.\n\t */\n\texportToJsonl(outputPath?: string): string {\n\t\tconst filePath = resolve(outputPath ?? `session-${new Date().toISOString().replace(/[:.]/g, \"-\")}.jsonl`);\n\t\tconst dir = dirname(filePath);\n\t\tif (!existsSync(dir)) {\n\t\t\tmkdirSync(dir, { recursive: true });\n\t\t}\n\n\t\tconst header: SessionHeader = {\n\t\t\ttype: \"session\",\n\t\t\tversion: CURRENT_SESSION_VERSION,\n\t\t\tid: this.sessionManager.getSessionId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tcwd: this.sessionManager.getCwd(),\n\t\t};\n\n\t\tconst branchEntries = this.sessionManager.getBranch();\n\t\tconst lines = [JSON.stringify(header)];\n\n\t\t// Re-chain parentIds to form a linear sequence\n\t\tlet prevId: string | null = null;\n\t\tfor (const entry of branchEntries) {\n\t\t\tconst linear = { ...entry, parentId: prevId };\n\t\t\tlines.push(JSON.stringify(linear));\n\t\t\tprevId = entry.id;\n\t\t}\n\n\t\twriteFileSync(filePath, `${lines.join(\"\\n\")}\\n`);\n\t\treturn filePath;\n\t}\n\n\t/**\n\t * Get text content of last assistant message.\n\t * Useful for /copy command.\n\t * @returns Text content, or undefined if no assistant message exists\n\t */\n\tgetLastAssistantText(): string | undefined {\n\t\tconst lastAssistant = this.messages\n\t\t\t.slice()\n\t\t\t.reverse()\n\t\t\t.find((m) => {\n\t\t\t\tif (m.role !== \"assistant\") return false;\n\t\t\t\tconst msg = m as AssistantMessage;\n\t\t\t\t// Skip aborted messages with no content\n\t\t\t\tif (msg.stopReason === \"aborted\" && msg.content.length === 0) return false;\n\t\t\t\treturn true;\n\t\t\t});\n\n\t\tif (!lastAssistant) return undefined;\n\n\t\tlet text = \"\";\n\t\tfor (const content of (lastAssistant as AssistantMessage).content) {\n\t\t\tif (content.type === \"text\") {\n\t\t\t\ttext += content.text;\n\t\t\t}\n\t\t}\n\n\t\treturn text.trim() || undefined;\n\t}\n\n\t// =========================================================================\n\t// Extension System\n\t// =========================================================================\n\n\tcreateReplacedSessionContext(): ReplacedSessionContext {\n\t\tconst context = Object.defineProperties(\n\t\t\t{},\n\t\t\tObject.getOwnPropertyDescriptors(this._extensionRunner.createCommandContext()),\n\t\t) as ReplacedSessionContext;\n\t\tcontext.sendMessage = (message, options) => this.sendCustomMessage(message, options);\n\t\tcontext.sendUserMessage = (content, options) => this.sendUserMessage(content, options);\n\t\treturn context;\n\t}\n\n\thasExtensionHandlers(eventType: string): boolean {\n\t\treturn this._extensionRunner.hasHandlers(eventType);\n\t}\n\n\tget extensionRunner(): ExtensionRunner {\n\t\treturn this._extensionRunner;\n\t}\n}\n\nfunction isRlmHeartbeatStatusUpdate(value: unknown): value is AgentRlmHeartbeatStatusUpdate {\n\treturn value === \"pause\" || value === \"resume\";\n}\n\nfunction rlmHeartbeatHostResponse(job: AgentCronJob): Record<string, unknown> {\n\treturn {\n\t\tid: job.id,\n\t\tstatus: job.status,\n\t\tlabel: job.label ?? null,\n\t\tdelivery_mode: job.deliveryMode ?? \"steer\",\n\t\tinstruction: job.prompt,\n\t\tschedule: job.schedule,\n\t\tcreated_at: job.createdAt,\n\t\tupdated_at: job.updatedAt,\n\t\tnext_run_at: job.nextRunAt ?? null,\n\t\tlast_run_at: job.lastRunAt ?? null,\n\t\tlast_error: job.lastError ?? null,\n\t\trun_count: job.runCount,\n\t};\n}\n"]}
|