@mariozechner/pi-coding-agent 0.30.0 → 0.30.1
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 +7 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +3 -3
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/model-resolver.d.ts +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +2 -1
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +8 -2
- package/dist/core/sdk.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +4 -3
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/docs/session-tree.md +452 -0
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-session.js","sourceRoot":"","sources":["../../src/core/agent-session.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * AgentSession - Core abstraction for agent lifecycle and session management.\n *\n * This class is shared between all run modes (interactive, print, rpc).\n * It encapsulates:\n * - Agent state access\n * - Event subscription with automatic session persistence\n * - Model and thinking level management\n * - Compaction (manual and auto)\n * - Bash execution\n * - Session switching and branching\n *\n * Modes use this class and add their own I/O layer on top.\n */\n\nimport type { Agent, AgentEvent, AgentState, AppMessage, Attachment, ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport type { AssistantMessage, Message, Model, TextContent } from \"@mariozechner/pi-ai\";\nimport { isContextOverflow, supportsXhigh } from \"@mariozechner/pi-ai\";\nimport { getModelsPath } from \"../config.js\";\nimport { type BashResult, executeBash as executeBashCommand } from \"./bash-executor.js\";\nimport { calculateContextTokens, compact, prepareCompaction, shouldCompact } from \"./compaction.js\";\nimport type { LoadedCustomTool, SessionEvent as ToolSessionEvent } from \"./custom-tools/index.js\";\nimport { exportSessionToHtml } from \"./export-html.js\";\nimport type { HookRunner, SessionEventResult, TurnEndEvent, TurnStartEvent } from \"./hooks/index.js\";\nimport type { BashExecutionMessage } from \"./messages.js\";\nimport type { ModelRegistry } from \"./model-registry.js\";\nimport type { CompactionEntry, SessionManager } from \"./session-manager.js\";\nimport type { SettingsManager, SkillsSettings } from \"./settings-manager.js\";\nimport { expandSlashCommand, type FileSlashCommand } from \"./slash-commands.js\";\n\n/** Session-specific events that extend the core AgentEvent */\nexport type AgentSessionEvent =\n\t| AgentEvent\n\t| { type: \"auto_compaction_start\"; reason: \"threshold\" | \"overflow\" }\n\t| { type: \"auto_compaction_end\"; result: CompactionResult | null; aborted: boolean; willRetry: boolean }\n\t| { type: \"auto_retry_start\"; attempt: number; maxAttempts: number; delayMs: number; errorMessage: string }\n\t| { type: \"auto_retry_end\"; success: boolean; attempt: number; finalError?: string };\n\n/** Listener function for agent session events */\nexport type AgentSessionEventListener = (event: AgentSessionEvent) => void;\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface AgentSessionConfig {\n\tagent: Agent;\n\tsessionManager: SessionManager;\n\tsettingsManager: SettingsManager;\n\t/** Models to cycle through with Ctrl+P (from --models flag) */\n\tscopedModels?: Array<{ model: Model<any>; thinkingLevel: ThinkingLevel }>;\n\t/** File-based slash commands for expansion */\n\tfileCommands?: FileSlashCommand[];\n\t/** Hook runner (created in main.ts with wrapped tools) */\n\thookRunner?: HookRunner | null;\n\t/** Custom tools for session lifecycle events */\n\tcustomTools?: LoadedCustomTool[];\n\tskillsSettings?: Required<SkillsSettings>;\n\t/** Model registry for API key resolution and model discovery */\n\tmodelRegistry: ModelRegistry;\n}\n\n/** Options for AgentSession.prompt() */\nexport interface PromptOptions {\n\t/** Whether to expand file-based slash commands (default: true) */\n\texpandSlashCommands?: boolean;\n\t/** Image/file attachments */\n\tattachments?: Attachment[];\n}\n\n/** Result from cycleModel() */\nexport interface ModelCycleResult {\n\tmodel: Model<any>;\n\tthinkingLevel: ThinkingLevel;\n\t/** Whether cycling through scoped models (--models flag) or all available */\n\tisScoped: boolean;\n}\n\n/** Result from compact() or checkAutoCompaction() */\nexport interface CompactionResult {\n\ttokensBefore: number;\n\tsummary: string;\n}\n\n/** Session statistics for /session command */\nexport interface SessionStats {\n\tsessionFile: string | null;\n\tsessionId: string;\n\tuserMessages: number;\n\tassistantMessages: number;\n\ttoolCalls: number;\n\ttoolResults: number;\n\ttotalMessages: number;\n\ttokens: {\n\t\tinput: number;\n\t\toutput: number;\n\t\tcacheRead: number;\n\t\tcacheWrite: number;\n\t\ttotal: number;\n\t};\n\tcost: number;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** Standard thinking levels */\nconst THINKING_LEVELS: ThinkingLevel[] = [\"off\", \"minimal\", \"low\", \"medium\", \"high\"];\n\n/** Thinking levels including xhigh (for supported models) */\nconst THINKING_LEVELS_WITH_XHIGH: ThinkingLevel[] = [\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\"];\n\n// ============================================================================\n// AgentSession Class\n// ============================================================================\n\nexport class AgentSession {\n\treadonly agent: Agent;\n\treadonly sessionManager: SessionManager;\n\treadonly settingsManager: SettingsManager;\n\n\tprivate _scopedModels: Array<{ model: Model<any>; thinkingLevel: ThinkingLevel }>;\n\tprivate _fileCommands: FileSlashCommand[];\n\n\t// Event subscription state\n\tprivate _unsubscribeAgent?: () => void;\n\tprivate _eventListeners: AgentSessionEventListener[] = [];\n\n\t// Message queue state\n\tprivate _queuedMessages: string[] = [];\n\n\t// Compaction state\n\tprivate _compactionAbortController: AbortController | null = null;\n\tprivate _autoCompactionAbortController: AbortController | null = null;\n\n\t// Retry state\n\tprivate _retryAbortController: AbortController | null = null;\n\tprivate _retryAttempt = 0;\n\tprivate _retryPromise: Promise<void> | null = null;\n\tprivate _retryResolve: (() => void) | null = null;\n\n\t// Bash execution state\n\tprivate _bashAbortController: AbortController | null = null;\n\tprivate _pendingBashMessages: BashExecutionMessage[] = [];\n\n\t// Hook system\n\tprivate _hookRunner: HookRunner | null = null;\n\tprivate _turnIndex = 0;\n\n\t// Custom tools for session lifecycle\n\tprivate _customTools: LoadedCustomTool[] = [];\n\n\tprivate _skillsSettings: Required<SkillsSettings> | undefined;\n\n\t// Model registry for API key resolution\n\tprivate _modelRegistry: ModelRegistry;\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._scopedModels = config.scopedModels ?? [];\n\t\tthis._fileCommands = config.fileCommands ?? [];\n\t\tthis._hookRunner = config.hookRunner ?? null;\n\t\tthis._customTools = config.customTools ?? [];\n\t\tthis._skillsSettings = config.skillsSettings;\n\t\tthis._modelRegistry = config.modelRegistry;\n\t}\n\n\t/** Model registry for API key resolution and model discovery */\n\tget modelRegistry(): ModelRegistry {\n\t\treturn this._modelRegistry;\n\t}\n\n\t// =========================================================================\n\t// Event Subscription\n\t// =========================================================================\n\n\t/** Emit an event to all listeners */\n\tprivate _emit(event: AgentSessionEvent): void {\n\t\tfor (const l of this._eventListeners) {\n\t\t\tl(event);\n\t\t}\n\t}\n\n\t// Track last assistant message for auto-compaction check\n\tprivate _lastAssistantMessage: AssistantMessage | null = null;\n\n\t/** Internal handler for agent events - shared by subscribe and reconnect */\n\tprivate _handleAgentEvent = async (event: AgentEvent): Promise<void> => {\n\t\t// When a user message starts, check if it's from the queue and remove it BEFORE emitting\n\t\t// This ensures the UI sees the updated queue state\n\t\tif (event.type === \"message_start\" && event.message.role === \"user\" && this._queuedMessages.length > 0) {\n\t\t\t// Extract text content from the message\n\t\t\tconst messageText = this._getUserMessageText(event.message);\n\t\t\tif (messageText && this._queuedMessages.includes(messageText)) {\n\t\t\t\t// Remove the first occurrence of this message from the queue\n\t\t\t\tconst index = this._queuedMessages.indexOf(messageText);\n\t\t\t\tif (index !== -1) {\n\t\t\t\t\tthis._queuedMessages.splice(index, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Emit to hooks first\n\t\tawait this._emitHookEvent(event);\n\n\t\t// Notify all listeners\n\t\tthis._emit(event);\n\n\t\t// Handle session persistence\n\t\tif (event.type === \"message_end\") {\n\t\t\tthis.sessionManager.saveMessage(event.message);\n\n\t\t\t// Track assistant message for auto-compaction (checked on agent_end)\n\t\t\tif (event.message.role === \"assistant\") {\n\t\t\t\tthis._lastAssistantMessage = event.message;\n\t\t\t}\n\t\t}\n\n\t\t// Check auto-retry and auto-compaction after agent completes\n\t\tif (event.type === \"agent_end\" && this._lastAssistantMessage) {\n\t\t\tconst msg = this._lastAssistantMessage;\n\t\t\tthis._lastAssistantMessage = null;\n\n\t\t\t// Check for retryable errors first (overloaded, rate limit, server errors)\n\t\t\tif (this._isRetryableError(msg)) {\n\t\t\t\tconst didRetry = await this._handleRetryableError(msg);\n\t\t\t\tif (didRetry) return; // Retry was initiated, don't proceed to compaction\n\t\t\t} else if (this._retryAttempt > 0) {\n\t\t\t\t// Previous retry succeeded - emit success event and reset counter\n\t\t\t\tthis._emit({\n\t\t\t\t\ttype: \"auto_retry_end\",\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\tattempt: this._retryAttempt,\n\t\t\t\t});\n\t\t\t\tthis._retryAttempt = 0;\n\t\t\t\t// Resolve the retry promise so waitForRetry() completes\n\t\t\t\tthis._resolveRetry();\n\t\t\t}\n\n\t\t\tawait this._checkCompaction(msg);\n\t\t}\n\t};\n\n\t/** Resolve the pending retry promise */\n\tprivate _resolveRetry(): void {\n\t\tif (this._retryResolve) {\n\t\t\tthis._retryResolve();\n\t\t\tthis._retryResolve = null;\n\t\t\tthis._retryPromise = null;\n\t\t}\n\t}\n\n\t/** Extract text content from a message */\n\tprivate _getUserMessageText(message: Message): string {\n\t\tif (message.role !== \"user\") return \"\";\n\t\tconst content = message.content;\n\t\tif (typeof content === \"string\") return content;\n\t\tconst textBlocks = content.filter((c) => c.type === \"text\");\n\t\treturn textBlocks.map((c) => (c as TextContent).text).join(\"\");\n\t}\n\n\t/** Find the last assistant message in agent state (including aborted ones) */\n\tprivate _findLastAssistantMessage(): AssistantMessage | null {\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 null;\n\t}\n\n\t/** Emit hook events based on agent events */\n\tprivate async _emitHookEvent(event: AgentEvent): Promise<void> {\n\t\tif (!this._hookRunner) return;\n\n\t\tif (event.type === \"agent_start\") {\n\t\t\tthis._turnIndex = 0;\n\t\t\tawait this._hookRunner.emit({ type: \"agent_start\" });\n\t\t} else if (event.type === \"agent_end\") {\n\t\t\tawait this._hookRunner.emit({ type: \"agent_end\", messages: event.messages });\n\t\t} else if (event.type === \"turn_start\") {\n\t\t\tconst hookEvent: 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._hookRunner.emit(hookEvent);\n\t\t} else if (event.type === \"turn_end\") {\n\t\t\tconst hookEvent: 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._hookRunner.emit(hookEvent);\n\t\t\tthis._turnIndex++;\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\t// Set up agent subscription if not already done\n\t\tif (!this._unsubscribeAgent) {\n\t\t\tthis._unsubscribeAgent = this.agent.subscribe(this._handleAgentEvent);\n\t\t}\n\n\t\t// Return unsubscribe function for this specific listener\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\tdispose(): void {\n\t\tthis._disconnectFromAgent();\n\t\tthis._eventListeners = [];\n\t}\n\n\t// =========================================================================\n\t// Read-only State Access\n\t// =========================================================================\n\n\t/** Full agent state */\n\tget state(): AgentState {\n\t\treturn this.agent.state;\n\t}\n\n\t/** Current model (may be null if not yet selected) */\n\tget model(): Model<any> | null {\n\t\treturn this.agent.state.model;\n\t}\n\n\t/** Current thinking level */\n\tget thinkingLevel(): ThinkingLevel {\n\t\treturn this.agent.state.thinkingLevel;\n\t}\n\n\t/** Whether agent is currently streaming a response */\n\tget isStreaming(): boolean {\n\t\treturn this.agent.state.isStreaming;\n\t}\n\n\t/** Whether auto-compaction is currently running */\n\tget isCompacting(): boolean {\n\t\treturn this._autoCompactionAbortController !== null || this._compactionAbortController !== null;\n\t}\n\n\t/** All messages including custom types like BashExecutionMessage */\n\tget messages(): AppMessage[] {\n\t\treturn this.agent.state.messages;\n\t}\n\n\t/** Current queue mode */\n\tget queueMode(): \"all\" | \"one-at-a-time\" {\n\t\treturn this.agent.getQueueMode();\n\t}\n\n\t/** Current session file path, or null if sessions are disabled */\n\tget sessionFile(): string | null {\n\t\treturn this.sessionManager.isPersisted() ? this.sessionManager.getSessionFile() : null;\n\t}\n\n\t/** Current session ID */\n\tget sessionId(): string {\n\t\treturn this.sessionManager.getSessionId();\n\t}\n\n\t/** Scoped models for cycling (from --models flag) */\n\tget scopedModels(): ReadonlyArray<{ model: Model<any>; thinkingLevel: ThinkingLevel }> {\n\t\treturn this._scopedModels;\n\t}\n\n\t/** File-based slash commands */\n\tget fileCommands(): ReadonlyArray<FileSlashCommand> {\n\t\treturn this._fileCommands;\n\t}\n\n\t// =========================================================================\n\t// Prompting\n\t// =========================================================================\n\n\t/**\n\t * Send a prompt to the agent.\n\t * - Validates model and API key before sending\n\t * - Expands file-based slash commands by default\n\t * @throws Error if no model selected or no API key available\n\t */\n\tasync prompt(text: string, options?: PromptOptions): Promise<void> {\n\t\t// Flush any pending bash messages before the new prompt\n\t\tthis._flushPendingBashMessages();\n\n\t\tconst expandCommands = options?.expandSlashCommands ?? true;\n\n\t\t// Validate model\n\t\tif (!this.model) {\n\t\t\tthrow new Error(\n\t\t\t\t\"No model selected.\\n\\n\" +\n\t\t\t\t\t`Use /login, set an API key environment variable, or create ${getModelsPath()}\\n\\n` +\n\t\t\t\t\t\"Then use /model to select a model.\",\n\t\t\t);\n\t\t}\n\n\t\t// Validate API key\n\t\tconst apiKey = await this._modelRegistry.getApiKey(this.model);\n\t\tif (!apiKey) {\n\t\t\tthrow new Error(\n\t\t\t\t`No API key found for ${this.model.provider}.\\n\\n` +\n\t\t\t\t\t`Use /login, set an API key environment variable, or create ${getModelsPath()}`,\n\t\t\t);\n\t\t}\n\n\t\t// Check if we need to compact before sending (catches aborted responses)\n\t\tconst lastAssistant = this._findLastAssistantMessage();\n\t\tif (lastAssistant) {\n\t\t\tawait this._checkCompaction(lastAssistant, false);\n\t\t}\n\n\t\t// Expand slash commands if requested\n\t\tconst expandedText = expandCommands ? expandSlashCommand(text, [...this._fileCommands]) : text;\n\n\t\tawait this.agent.prompt(expandedText, options?.attachments);\n\t\tawait this.waitForRetry();\n\t}\n\n\t/**\n\t * Queue a message to be sent after the current response completes.\n\t * Use when agent is currently streaming.\n\t */\n\tasync queueMessage(text: string): Promise<void> {\n\t\tthis._queuedMessages.push(text);\n\t\tawait this.agent.queueMessage({\n\t\t\trole: \"user\",\n\t\t\tcontent: [{ type: \"text\", text }],\n\t\t\ttimestamp: Date.now(),\n\t\t});\n\t}\n\n\t/**\n\t * Clear queued messages and return them.\n\t * Useful for restoring to editor when user aborts.\n\t */\n\tclearQueue(): string[] {\n\t\tconst queued = [...this._queuedMessages];\n\t\tthis._queuedMessages = [];\n\t\tthis.agent.clearMessageQueue();\n\t\treturn queued;\n\t}\n\n\t/** Number of messages currently queued */\n\tget queuedMessageCount(): number {\n\t\treturn this._queuedMessages.length;\n\t}\n\n\t/** Get queued messages (read-only) */\n\tgetQueuedMessages(): readonly string[] {\n\t\treturn this._queuedMessages;\n\t}\n\n\tget skillsSettings(): Required<SkillsSettings> | undefined {\n\t\treturn this._skillsSettings;\n\t}\n\n\t/**\n\t * Abort current operation and wait for agent to become idle.\n\t */\n\tasync abort(): Promise<void> {\n\t\tthis.abortRetry();\n\t\tthis.agent.abort();\n\t\tawait this.agent.waitForIdle();\n\t}\n\n\t/**\n\t * Reset agent and session to start fresh.\n\t * Clears all messages and starts a new session.\n\t * Listeners are preserved and will continue receiving events.\n\t * @returns true if reset completed, false if cancelled by hook\n\t */\n\tasync reset(): Promise<boolean> {\n\t\tconst previousSessionFile = this.sessionFile;\n\t\tconst entries = this.sessionManager.getEntries();\n\n\t\t// Emit before_new event (can be cancelled)\n\t\tif (this._hookRunner?.hasHandlers(\"session\")) {\n\t\t\tconst result = (await this._hookRunner.emit({\n\t\t\t\ttype: \"session\",\n\t\t\t\tentries,\n\t\t\t\tsessionFile: this.sessionFile,\n\t\t\t\tpreviousSessionFile: null,\n\t\t\t\treason: \"before_new\",\n\t\t\t})) as SessionEventResult | undefined;\n\n\t\t\tif (result?.cancel) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tthis._disconnectFromAgent();\n\t\tawait this.abort();\n\t\tthis.agent.reset();\n\t\tthis.sessionManager.reset();\n\t\tthis._queuedMessages = [];\n\t\tthis._reconnectToAgent();\n\n\t\t// Emit session event with reason \"new\" to hooks\n\t\tif (this._hookRunner) {\n\t\t\tthis._hookRunner.setSessionFile(this.sessionFile);\n\t\t\tawait this._hookRunner.emit({\n\t\t\t\ttype: \"session\",\n\t\t\t\tentries: [],\n\t\t\t\tsessionFile: this.sessionFile,\n\t\t\t\tpreviousSessionFile,\n\t\t\t\treason: \"new\",\n\t\t\t});\n\t\t}\n\n\t\t// Emit session event to custom tools\n\t\tawait this._emitToolSessionEvent(\"new\", previousSessionFile);\n\t\treturn true;\n\t}\n\n\t// =========================================================================\n\t// Model Management\n\t// =========================================================================\n\n\t/**\n\t * Set model directly.\n\t * Validates API key, saves to session and settings.\n\t * @throws Error if no API key available for the model\n\t */\n\tasync setModel(model: Model<any>): Promise<void> {\n\t\tconst apiKey = await this._modelRegistry.getApiKey(model);\n\t\tif (!apiKey) {\n\t\t\tthrow new Error(`No API key for ${model.provider}/${model.id}`);\n\t\t}\n\n\t\tthis.agent.setModel(model);\n\t\tthis.sessionManager.saveModelChange(model.provider, model.id);\n\t\tthis.settingsManager.setDefaultModelAndProvider(model.provider, model.id);\n\n\t\t// Re-clamp thinking level for new model's capabilities\n\t\tthis.setThinkingLevel(this.thinkingLevel);\n\t}\n\n\t/**\n\t * Cycle to next/previous model.\n\t * Uses scoped models (from --models flag) if available, otherwise all available models.\n\t * @param direction - \"forward\" (default) or \"backward\"\n\t * @returns The new model info, or null if only one model available\n\t */\n\tasync cycleModel(direction: \"forward\" | \"backward\" = \"forward\"): Promise<ModelCycleResult | null> {\n\t\tif (this._scopedModels.length > 0) {\n\t\t\treturn this._cycleScopedModel(direction);\n\t\t}\n\t\treturn this._cycleAvailableModel(direction);\n\t}\n\n\tprivate async _cycleScopedModel(direction: \"forward\" | \"backward\"): Promise<ModelCycleResult | null> {\n\t\tif (this._scopedModels.length <= 1) return null;\n\n\t\tconst currentModel = this.model;\n\t\tlet currentIndex = this._scopedModels.findIndex(\n\t\t\t(sm) => sm.model.id === currentModel?.id && sm.model.provider === currentModel?.provider,\n\t\t);\n\n\t\tif (currentIndex === -1) currentIndex = 0;\n\t\tconst len = this._scopedModels.length;\n\t\tconst nextIndex = direction === \"forward\" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;\n\t\tconst next = this._scopedModels[nextIndex];\n\n\t\t// Validate API key\n\t\tconst apiKey = await this._modelRegistry.getApiKey(next.model);\n\t\tif (!apiKey) {\n\t\t\tthrow new Error(`No API key for ${next.model.provider}/${next.model.id}`);\n\t\t}\n\n\t\t// Apply model\n\t\tthis.agent.setModel(next.model);\n\t\tthis.sessionManager.saveModelChange(next.model.provider, next.model.id);\n\t\tthis.settingsManager.setDefaultModelAndProvider(next.model.provider, next.model.id);\n\n\t\t// Apply thinking level (setThinkingLevel clamps to model capabilities)\n\t\tthis.setThinkingLevel(next.thinkingLevel);\n\n\t\treturn { model: next.model, thinkingLevel: this.thinkingLevel, isScoped: true };\n\t}\n\n\tprivate async _cycleAvailableModel(direction: \"forward\" | \"backward\"): Promise<ModelCycleResult | null> {\n\t\tconst availableModels = await this._modelRegistry.getAvailable();\n\t\tif (availableModels.length <= 1) return null;\n\n\t\tconst currentModel = this.model;\n\t\tlet currentIndex = availableModels.findIndex(\n\t\t\t(m) => m.id === currentModel?.id && m.provider === currentModel?.provider,\n\t\t);\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 apiKey = await this._modelRegistry.getApiKey(nextModel);\n\t\tif (!apiKey) {\n\t\t\tthrow new Error(`No API key for ${nextModel.provider}/${nextModel.id}`);\n\t\t}\n\n\t\tthis.agent.setModel(nextModel);\n\t\tthis.sessionManager.saveModelChange(nextModel.provider, nextModel.id);\n\t\tthis.settingsManager.setDefaultModelAndProvider(nextModel.provider, nextModel.id);\n\n\t\t// Re-clamp thinking level for new model's capabilities\n\t\tthis.setThinkingLevel(this.thinkingLevel);\n\n\t\treturn { model: nextModel, thinkingLevel: this.thinkingLevel, isScoped: false };\n\t}\n\n\t/**\n\t * Get all available models with valid API keys.\n\t */\n\tasync getAvailableModels(): Promise<Model<any>[]> {\n\t\treturn this._modelRegistry.getAvailable();\n\t}\n\n\t// =========================================================================\n\t// Thinking Level Management\n\t// =========================================================================\n\n\t/**\n\t * Set thinking level.\n\t * Clamps to model capabilities: \"off\" if no reasoning, \"high\" if xhigh unsupported.\n\t * Saves to session and settings.\n\t */\n\tsetThinkingLevel(level: ThinkingLevel): void {\n\t\tlet effectiveLevel = level;\n\t\tif (!this.supportsThinking()) {\n\t\t\teffectiveLevel = \"off\";\n\t\t} else if (level === \"xhigh\" && !this.supportsXhighThinking()) {\n\t\t\teffectiveLevel = \"high\";\n\t\t}\n\t\tthis.agent.setThinkingLevel(effectiveLevel);\n\t\tthis.sessionManager.saveThinkingLevelChange(effectiveLevel);\n\t\tthis.settingsManager.setDefaultThinkingLevel(effectiveLevel);\n\t}\n\n\t/**\n\t * Cycle to next thinking level.\n\t * @returns New level, or null if model doesn't support thinking\n\t */\n\tcycleThinkingLevel(): ThinkingLevel | null {\n\t\tif (!this.supportsThinking()) return null;\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\t/**\n\t * Get available thinking levels for current model.\n\t */\n\tgetAvailableThinkingLevels(): ThinkingLevel[] {\n\t\treturn this.supportsXhighThinking() ? THINKING_LEVELS_WITH_XHIGH : THINKING_LEVELS;\n\t}\n\n\t/**\n\t * Check if current model supports xhigh thinking level.\n\t */\n\tsupportsXhighThinking(): boolean {\n\t\treturn this.model ? supportsXhigh(this.model) : false;\n\t}\n\n\t/**\n\t * Check if current model supports thinking/reasoning.\n\t */\n\tsupportsThinking(): boolean {\n\t\treturn !!this.model?.reasoning;\n\t}\n\n\t// =========================================================================\n\t// Queue Mode Management\n\t// =========================================================================\n\n\t/**\n\t * Set message queue mode.\n\t * Saves to settings.\n\t */\n\tsetQueueMode(mode: \"all\" | \"one-at-a-time\"): void {\n\t\tthis.agent.setQueueMode(mode);\n\t\tthis.settingsManager.setQueueMode(mode);\n\t}\n\n\t// =========================================================================\n\t// Compaction\n\t// =========================================================================\n\n\t/**\n\t * Manually compact the session context.\n\t * Aborts current agent operation first.\n\t * @param customInstructions Optional instructions for the compaction summary\n\t */\n\tasync compact(customInstructions?: string): Promise<CompactionResult> {\n\t\tthis._disconnectFromAgent();\n\t\tawait this.abort();\n\t\tthis._compactionAbortController = new AbortController();\n\n\t\ttry {\n\t\t\tif (!this.model) {\n\t\t\t\tthrow new Error(\"No model selected\");\n\t\t\t}\n\n\t\t\tconst apiKey = await this._modelRegistry.getApiKey(this.model);\n\t\t\tif (!apiKey) {\n\t\t\t\tthrow new Error(`No API key for ${this.model.provider}`);\n\t\t\t}\n\n\t\t\tconst entries = this.sessionManager.getEntries();\n\t\t\tconst settings = this.settingsManager.getCompactionSettings();\n\n\t\t\tconst preparation = prepareCompaction(entries, settings);\n\t\t\tif (!preparation) {\n\t\t\t\tthrow new Error(\"Already compacted\");\n\t\t\t}\n\n\t\t\t// Find previous compaction summary if any\n\t\t\tlet previousSummary: string | undefined;\n\t\t\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\t\t\tif (entries[i].type === \"compaction\") {\n\t\t\t\t\tpreviousSummary = (entries[i] as CompactionEntry).summary;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet compactionEntry: CompactionEntry | undefined;\n\t\t\tlet fromHook = false;\n\n\t\t\tif (this._hookRunner?.hasHandlers(\"session\")) {\n\t\t\t\tconst result = (await this._hookRunner.emit({\n\t\t\t\t\ttype: \"session\",\n\t\t\t\t\tentries,\n\t\t\t\t\tsessionFile: this.sessionFile,\n\t\t\t\t\tpreviousSessionFile: null,\n\t\t\t\t\treason: \"before_compact\",\n\t\t\t\t\tcutPoint: preparation.cutPoint,\n\t\t\t\t\tpreviousSummary,\n\t\t\t\t\tmessagesToSummarize: [...preparation.messagesToSummarize],\n\t\t\t\t\tmessagesToKeep: [...preparation.messagesToKeep],\n\t\t\t\t\ttokensBefore: preparation.tokensBefore,\n\t\t\t\t\tcustomInstructions,\n\t\t\t\t\tmodel: this.model,\n\t\t\t\t\tresolveApiKey: async (m: Model<any>) => (await this._modelRegistry.getApiKey(m)) ?? undefined,\n\t\t\t\t\tsignal: this._compactionAbortController.signal,\n\t\t\t\t})) as SessionEventResult | undefined;\n\n\t\t\t\tif (result?.cancel) {\n\t\t\t\t\tthrow new Error(\"Compaction cancelled\");\n\t\t\t\t}\n\n\t\t\t\tif (result?.compactionEntry) {\n\t\t\t\t\tcompactionEntry = result.compactionEntry;\n\t\t\t\t\tfromHook = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!compactionEntry) {\n\t\t\t\tcompactionEntry = await compact(\n\t\t\t\t\tentries,\n\t\t\t\t\tthis.model,\n\t\t\t\t\tsettings,\n\t\t\t\t\tapiKey,\n\t\t\t\t\tthis._compactionAbortController.signal,\n\t\t\t\t\tcustomInstructions,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (this._compactionAbortController.signal.aborted) {\n\t\t\t\tthrow new Error(\"Compaction cancelled\");\n\t\t\t}\n\n\t\t\tthis.sessionManager.saveCompaction(compactionEntry);\n\t\t\tconst newEntries = this.sessionManager.getEntries();\n\t\t\tconst sessionContext = this.sessionManager.buildSessionContext();\n\t\t\tthis.agent.replaceMessages(sessionContext.messages);\n\n\t\t\tif (this._hookRunner) {\n\t\t\t\tawait this._hookRunner.emit({\n\t\t\t\t\ttype: \"session\",\n\t\t\t\t\tentries: newEntries,\n\t\t\t\t\tsessionFile: this.sessionFile,\n\t\t\t\t\tpreviousSessionFile: null,\n\t\t\t\t\treason: \"compact\",\n\t\t\t\t\tcompactionEntry,\n\t\t\t\t\ttokensBefore: compactionEntry.tokensBefore,\n\t\t\t\t\tfromHook,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttokensBefore: compactionEntry.tokensBefore,\n\t\t\t\tsummary: compactionEntry.summary,\n\t\t\t};\n\t\t} finally {\n\t\t\tthis._compactionAbortController = null;\n\t\t\tthis._reconnectToAgent();\n\t\t}\n\t}\n\n\t/**\n\t * Cancel in-progress compaction (manual or auto).\n\t */\n\tabortCompaction(): void {\n\t\tthis._compactionAbortController?.abort();\n\t\tthis._autoCompactionAbortController?.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, NO auto-retry (user continues manually)\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 async _checkCompaction(assistantMessage: AssistantMessage, skipAbortedCheck = true): Promise<void> {\n\t\tconst settings = this.settingsManager.getCompactionSettings();\n\t\tif (!settings.enabled) return;\n\n\t\t// Skip if message was aborted (user cancelled) - unless skipAbortedCheck is false\n\t\tif (skipAbortedCheck && assistantMessage.stopReason === \"aborted\") return;\n\n\t\tconst contextWindow = this.model?.contextWindow ?? 0;\n\n\t\t// Case 1: Overflow - LLM returned context overflow error\n\t\tif (isContextOverflow(assistantMessage, contextWindow)) {\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.replaceMessages(messages.slice(0, -1));\n\t\t\t}\n\t\t\tawait this._runAutoCompaction(\"overflow\", true);\n\t\t\treturn;\n\t\t}\n\n\t\t// Case 2: Threshold - turn succeeded but context is getting large\n\t\t// Skip if this was an error (non-overflow errors don't have usage data)\n\t\tif (assistantMessage.stopReason === \"error\") return;\n\n\t\tconst contextTokens = calculateContextTokens(assistantMessage.usage);\n\t\tif (shouldCompact(contextTokens, contextWindow, settings)) {\n\t\t\tawait this._runAutoCompaction(\"threshold\", false);\n\t\t}\n\t}\n\n\t/**\n\t * Internal: Run auto-compaction with events.\n\t */\n\tprivate async _runAutoCompaction(reason: \"overflow\" | \"threshold\", willRetry: boolean): Promise<void> {\n\t\tconst settings = this.settingsManager.getCompactionSettings();\n\n\t\tthis._emit({ type: \"auto_compaction_start\", reason });\n\t\tthis._autoCompactionAbortController = new AbortController();\n\n\t\ttry {\n\t\t\tif (!this.model) {\n\t\t\t\tthis._emit({ type: \"auto_compaction_end\", result: null, aborted: false, willRetry: false });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst apiKey = await this._modelRegistry.getApiKey(this.model);\n\t\t\tif (!apiKey) {\n\t\t\t\tthis._emit({ type: \"auto_compaction_end\", result: null, aborted: false, willRetry: false });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst entries = this.sessionManager.getEntries();\n\n\t\t\tconst preparation = prepareCompaction(entries, settings);\n\t\t\tif (!preparation) {\n\t\t\t\tthis._emit({ type: \"auto_compaction_end\", result: null, aborted: false, willRetry: false });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Find previous compaction summary if any\n\t\t\tlet previousSummary: string | undefined;\n\t\t\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\t\t\tif (entries[i].type === \"compaction\") {\n\t\t\t\t\tpreviousSummary = (entries[i] as CompactionEntry).summary;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet compactionEntry: CompactionEntry | undefined;\n\t\t\tlet fromHook = false;\n\n\t\t\tif (this._hookRunner?.hasHandlers(\"session\")) {\n\t\t\t\tconst hookResult = (await this._hookRunner.emit({\n\t\t\t\t\ttype: \"session\",\n\t\t\t\t\tentries,\n\t\t\t\t\tsessionFile: this.sessionFile,\n\t\t\t\t\tpreviousSessionFile: null,\n\t\t\t\t\treason: \"before_compact\",\n\t\t\t\t\tcutPoint: preparation.cutPoint,\n\t\t\t\t\tpreviousSummary,\n\t\t\t\t\tmessagesToSummarize: [...preparation.messagesToSummarize],\n\t\t\t\t\tmessagesToKeep: [...preparation.messagesToKeep],\n\t\t\t\t\ttokensBefore: preparation.tokensBefore,\n\t\t\t\t\tcustomInstructions: undefined,\n\t\t\t\t\tmodel: this.model,\n\t\t\t\t\tresolveApiKey: async (m: Model<any>) => (await this._modelRegistry.getApiKey(m)) ?? undefined,\n\t\t\t\t\tsignal: this._autoCompactionAbortController.signal,\n\t\t\t\t})) as SessionEventResult | undefined;\n\n\t\t\t\tif (hookResult?.cancel) {\n\t\t\t\t\tthis._emit({ type: \"auto_compaction_end\", result: null, aborted: true, willRetry: false });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (hookResult?.compactionEntry) {\n\t\t\t\t\tcompactionEntry = hookResult.compactionEntry;\n\t\t\t\t\tfromHook = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!compactionEntry) {\n\t\t\t\tcompactionEntry = await compact(\n\t\t\t\t\tentries,\n\t\t\t\t\tthis.model,\n\t\t\t\t\tsettings,\n\t\t\t\t\tapiKey,\n\t\t\t\t\tthis._autoCompactionAbortController.signal,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (this._autoCompactionAbortController.signal.aborted) {\n\t\t\t\tthis._emit({ type: \"auto_compaction_end\", result: null, aborted: true, willRetry: false });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.sessionManager.saveCompaction(compactionEntry);\n\t\t\tconst newEntries = this.sessionManager.getEntries();\n\t\t\tconst sessionContext = this.sessionManager.buildSessionContext();\n\t\t\tthis.agent.replaceMessages(sessionContext.messages);\n\n\t\t\tif (this._hookRunner) {\n\t\t\t\tawait this._hookRunner.emit({\n\t\t\t\t\ttype: \"session\",\n\t\t\t\t\tentries: newEntries,\n\t\t\t\t\tsessionFile: this.sessionFile,\n\t\t\t\t\tpreviousSessionFile: null,\n\t\t\t\t\treason: \"compact\",\n\t\t\t\t\tcompactionEntry,\n\t\t\t\t\ttokensBefore: compactionEntry.tokensBefore,\n\t\t\t\t\tfromHook,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst result: CompactionResult = {\n\t\t\t\ttokensBefore: compactionEntry.tokensBefore,\n\t\t\t\tsummary: compactionEntry.summary,\n\t\t\t};\n\t\t\tthis._emit({ type: \"auto_compaction_end\", result, aborted: false, willRetry });\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.replaceMessages(messages.slice(0, -1));\n\t\t\t\t}\n\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tthis.agent.continue().catch(() => {});\n\t\t\t\t}, 100);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthis._emit({ type: \"auto_compaction_end\", result: null, aborted: false, willRetry: false });\n\n\t\t\tif (reason === \"overflow\") {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Context overflow: ${error instanceof Error ? error.message : \"compaction failed\"}. Your input may be too large for the context window.`,\n\t\t\t\t);\n\t\t\t}\n\t\t} finally {\n\t\t\tthis._autoCompactionAbortController = null;\n\t\t}\n\t}\n\n\t/**\n\t * Toggle auto-compaction setting.\n\t */\n\tsetAutoCompactionEnabled(enabled: boolean): void {\n\t\tthis.settingsManager.setCompactionEnabled(enabled);\n\t}\n\n\t/** Whether auto-compaction is enabled */\n\tget autoCompactionEnabled(): boolean {\n\t\treturn this.settingsManager.getCompactionEnabled();\n\t}\n\n\t// =========================================================================\n\t// Auto-Retry\n\t// =========================================================================\n\n\t/**\n\t * Check if an error is retryable (overloaded, rate limit, server errors).\n\t * Context overflow errors are NOT retryable (handled by compaction instead).\n\t */\n\tprivate _isRetryableError(message: AssistantMessage): boolean {\n\t\tif (message.stopReason !== \"error\" || !message.errorMessage) return false;\n\n\t\t// Context overflow is handled by compaction, not retry\n\t\tconst contextWindow = this.model?.contextWindow ?? 0;\n\t\tif (isContextOverflow(message, contextWindow)) return false;\n\n\t\tconst err = message.errorMessage;\n\t\t// Match: overloaded_error, rate limit, 429, 500, 502, 503, 504, service unavailable, connection error\n\t\treturn /overloaded|rate.?limit|too many requests|429|500|502|503|504|service.?unavailable|server error|internal error|connection.?error/i.test(\n\t\t\terr,\n\t\t);\n\t}\n\n\t/**\n\t * Handle retryable errors with exponential backoff.\n\t * @returns true if retry was initiated, false if max retries exceeded or disabled\n\t */\n\tprivate async _handleRetryableError(message: AssistantMessage): Promise<boolean> {\n\t\tconst settings = this.settingsManager.getRetrySettings();\n\t\tif (!settings.enabled) return false;\n\n\t\tthis._retryAttempt++;\n\n\t\t// Create retry promise on first attempt so waitForRetry() can await it\n\t\tif (this._retryAttempt === 1 && !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\tif (this._retryAttempt > settings.maxRetries) {\n\t\t\t// Max retries exceeded, emit final failure and reset\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._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\t// Remove error message from agent state (keep in session for history)\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.replaceMessages(messages.slice(0, -1));\n\t\t}\n\n\t\t// Wait with exponential backoff (abortable)\n\t\tthis._retryAbortController = new AbortController();\n\t\ttry {\n\t\t\tawait this._sleep(delayMs, this._retryAbortController.signal);\n\t\t} catch {\n\t\t\t// Aborted during sleep - emit end event so UI can clean up\n\t\t\tconst attempt = this._retryAttempt;\n\t\t\tthis._retryAttempt = 0;\n\t\t\tthis._retryAbortController = null;\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\treturn false;\n\t\t}\n\t\tthis._retryAbortController = null;\n\n\t\t// Retry via continue() - use setTimeout to break out of event handler chain\n\t\tsetTimeout(() => {\n\t\t\tthis.agent.continue().catch(() => {\n\t\t\t\t// Retry failed - will be caught by next agent_end\n\t\t\t});\n\t\t}, 0);\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Sleep helper that respects abort signal.\n\t */\n\tprivate _sleep(ms: number, signal?: AbortSignal): Promise<void> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tif (signal?.aborted) {\n\t\t\t\treject(new Error(\"Aborted\"));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst timeout = setTimeout(resolve, ms);\n\n\t\t\tsignal?.addEventListener(\"abort\", () => {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\treject(new Error(\"Aborted\"));\n\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Cancel in-progress retry.\n\t */\n\tabortRetry(): void {\n\t\tthis._retryAbortController?.abort();\n\t\tthis._retryAttempt = 0;\n\t\tthis._resolveRetry();\n\t}\n\n\t/**\n\t * Wait for any in-progress retry to complete.\n\t * Returns immediately if no retry is in progress.\n\t */\n\tprivate async waitForRetry(): Promise<void> {\n\t\tif (this._retryPromise) {\n\t\t\tawait this._retryPromise;\n\t\t}\n\t}\n\n\t/** Whether auto-retry is currently in progress */\n\tget isRetrying(): boolean {\n\t\treturn this._retryPromise !== null;\n\t}\n\n\t/** Whether auto-retry is enabled */\n\tget autoRetryEnabled(): boolean {\n\t\treturn this.settingsManager.getRetryEnabled();\n\t}\n\n\t/**\n\t * Toggle auto-retry setting.\n\t */\n\tsetAutoRetryEnabled(enabled: boolean): void {\n\t\tthis.settingsManager.setRetryEnabled(enabled);\n\t}\n\n\t// =========================================================================\n\t// Bash Execution\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 */\n\tasync executeBash(command: string, onChunk?: (chunk: string) => void): Promise<BashResult> {\n\t\tthis._bashAbortController = new AbortController();\n\n\t\ttry {\n\t\t\tconst result = await executeBashCommand(command, {\n\t\t\t\tonChunk,\n\t\t\t\tsignal: this._bashAbortController.signal,\n\t\t\t});\n\n\t\t\t// Create and save message\n\t\t\tconst bashMessage: BashExecutionMessage = {\n\t\t\t\trole: \"bashExecution\",\n\t\t\t\tcommand,\n\t\t\t\toutput: result.output,\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\ttimestamp: Date.now(),\n\t\t\t};\n\n\t\t\t// If agent is streaming, defer adding to avoid breaking tool_use/tool_result ordering\n\t\t\tif (this.isStreaming) {\n\t\t\t\t// Queue for later - will be flushed on agent_end\n\t\t\t\tthis._pendingBashMessages.push(bashMessage);\n\t\t\t} else {\n\t\t\t\t// Add to agent state immediately\n\t\t\t\tthis.agent.appendMessage(bashMessage);\n\n\t\t\t\t// Save to session\n\t\t\t\tthis.sessionManager.saveMessage(bashMessage);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t} finally {\n\t\t\tthis._bashAbortController = null;\n\t\t}\n\t}\n\n\t/**\n\t * Cancel running bash command.\n\t */\n\tabortBash(): void {\n\t\tthis._bashAbortController?.abort();\n\t}\n\n\t/** Whether a bash command is currently running */\n\tget isBashRunning(): boolean {\n\t\treturn this._bashAbortController !== null;\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\t// Add to agent state\n\t\t\tthis.agent.appendMessage(bashMessage);\n\n\t\t\t// Save to session\n\t\t\tthis.sessionManager.saveMessage(bashMessage);\n\t\t}\n\n\t\tthis._pendingBashMessages = [];\n\t}\n\n\t// =========================================================================\n\t// Session Management\n\t// =========================================================================\n\n\t/**\n\t * Switch to a different session file.\n\t * Aborts current operation, loads messages, restores model/thinking.\n\t * Listeners are preserved and will continue receiving events.\n\t * @returns true if switch completed, false if cancelled by hook\n\t */\n\tasync switchSession(sessionPath: string): Promise<boolean> {\n\t\tconst previousSessionFile = this.sessionFile;\n\t\tconst oldEntries = this.sessionManager.getEntries();\n\n\t\t// Emit before_switch event (can be cancelled)\n\t\tif (this._hookRunner?.hasHandlers(\"session\")) {\n\t\t\tconst result = (await this._hookRunner.emit({\n\t\t\t\ttype: \"session\",\n\t\t\t\tentries: oldEntries,\n\t\t\t\tsessionFile: this.sessionFile,\n\t\t\t\tpreviousSessionFile: null,\n\t\t\t\treason: \"before_switch\",\n\t\t\t})) as SessionEventResult | undefined;\n\n\t\t\tif (result?.cancel) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tthis._disconnectFromAgent();\n\t\tawait this.abort();\n\t\tthis._queuedMessages = [];\n\n\t\t// Set new session\n\t\tthis.sessionManager.setSessionFile(sessionPath);\n\n\t\t// Reload messages\n\t\tconst entries = this.sessionManager.getEntries();\n\t\tconst sessionContext = this.sessionManager.buildSessionContext();\n\n\t\t// Emit session event to hooks\n\t\tif (this._hookRunner) {\n\t\t\tthis._hookRunner.setSessionFile(sessionPath);\n\t\t\tawait this._hookRunner.emit({\n\t\t\t\ttype: \"session\",\n\t\t\t\tentries,\n\t\t\t\tsessionFile: sessionPath,\n\t\t\t\tpreviousSessionFile,\n\t\t\t\treason: \"switch\",\n\t\t\t});\n\t\t}\n\n\t\t// Emit session event to custom tools\n\t\tawait this._emitToolSessionEvent(\"switch\", previousSessionFile);\n\n\t\tthis.agent.replaceMessages(sessionContext.messages);\n\n\t\t// Restore model if saved\n\t\tif (sessionContext.model) {\n\t\t\tconst availableModels = await this._modelRegistry.getAvailable();\n\t\t\tconst match = availableModels.find(\n\t\t\t\t(m) => m.provider === sessionContext.model!.provider && m.id === sessionContext.model!.modelId,\n\t\t\t);\n\t\t\tif (match) {\n\t\t\t\tthis.agent.setModel(match);\n\t\t\t}\n\t\t}\n\n\t\t// Restore thinking level if saved (setThinkingLevel clamps to model capabilities)\n\t\tif (sessionContext.thinkingLevel) {\n\t\t\tthis.setThinkingLevel(sessionContext.thinkingLevel as ThinkingLevel);\n\t\t}\n\n\t\tthis._reconnectToAgent();\n\t\treturn true;\n\t}\n\n\t/**\n\t * Create a branch from a specific entry index.\n\t * Emits before_branch/branch session events to hooks.\n\t *\n\t * @param entryIndex Index into session entries to branch from\n\t * @returns Object with:\n\t * - selectedText: The text of the selected user message (for editor pre-fill)\n\t * - cancelled: True if a hook cancelled the branch\n\t */\n\tasync branch(entryIndex: number): Promise<{ selectedText: string; cancelled: boolean }> {\n\t\tconst previousSessionFile = this.sessionFile;\n\t\tconst entries = this.sessionManager.getEntries();\n\t\tconst selectedEntry = entries[entryIndex];\n\n\t\tif (!selectedEntry || selectedEntry.type !== \"message\" || selectedEntry.message.role !== \"user\") {\n\t\t\tthrow new Error(\"Invalid entry index for branching\");\n\t\t}\n\n\t\tconst selectedText = this._extractUserMessageText(selectedEntry.message.content);\n\n\t\tlet skipConversationRestore = false;\n\n\t\t// Emit before_branch event (can be cancelled)\n\t\tif (this._hookRunner?.hasHandlers(\"session\")) {\n\t\t\tconst result = (await this._hookRunner.emit({\n\t\t\t\ttype: \"session\",\n\t\t\t\tentries,\n\t\t\t\tsessionFile: this.sessionFile,\n\t\t\t\tpreviousSessionFile: null,\n\t\t\t\treason: \"before_branch\",\n\t\t\t\ttargetTurnIndex: entryIndex,\n\t\t\t})) as SessionEventResult | undefined;\n\n\t\t\tif (result?.cancel) {\n\t\t\t\treturn { selectedText, cancelled: true };\n\t\t\t}\n\t\t\tskipConversationRestore = result?.skipConversationRestore ?? false;\n\t\t}\n\n\t\t// Create branched session (returns null in --no-session mode)\n\t\tconst newSessionFile = this.sessionManager.createBranchedSessionFromEntries(entries, entryIndex);\n\n\t\t// Update session file if we have one (file-based mode)\n\t\tif (newSessionFile !== null) {\n\t\t\tthis.sessionManager.setSessionFile(newSessionFile);\n\t\t}\n\n\t\t// Reload messages from entries (works for both file and in-memory mode)\n\t\tconst newEntries = this.sessionManager.getEntries();\n\t\tconst sessionContext = this.sessionManager.buildSessionContext();\n\n\t\t// Emit branch event to hooks (after branch completes)\n\t\tif (this._hookRunner) {\n\t\t\tthis._hookRunner.setSessionFile(newSessionFile);\n\t\t\tawait this._hookRunner.emit({\n\t\t\t\ttype: \"session\",\n\t\t\t\tentries: newEntries,\n\t\t\t\tsessionFile: newSessionFile,\n\t\t\t\tpreviousSessionFile,\n\t\t\t\treason: \"branch\",\n\t\t\t\ttargetTurnIndex: entryIndex,\n\t\t\t});\n\t\t}\n\n\t\t// Emit session event to custom tools (with reason \"branch\")\n\t\tawait this._emitToolSessionEvent(\"branch\", previousSessionFile);\n\n\t\tif (!skipConversationRestore) {\n\t\t\tthis.agent.replaceMessages(sessionContext.messages);\n\t\t}\n\n\t\treturn { selectedText, cancelled: false };\n\t}\n\n\t/**\n\t * Get all user messages from session for branch selector.\n\t */\n\tgetUserMessagesForBranching(): Array<{ entryIndex: number; text: string }> {\n\t\tconst entries = this.sessionManager.getEntries();\n\t\tconst result: Array<{ entryIndex: number; text: string }> = [];\n\n\t\tfor (let i = 0; i < entries.length; i++) {\n\t\t\tconst entry = entries[i];\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({ entryIndex: i, 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\t/**\n\t * Get session statistics.\n\t */\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};\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\texportToHtml(outputPath?: string): string {\n\t\tconst themeName = this.settingsManager.getTheme();\n\t\treturn exportSessionToHtml(this.sessionManager, this.state, { outputPath, themeName });\n\t}\n\n\t// =========================================================================\n\t// Utilities\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 null if no assistant message exists\n\t */\n\tgetLastAssistantText(): string | null {\n\t\tconst lastAssistant = this.messages\n\t\t\t.slice()\n\t\t\t.reverse()\n\t\t\t.find((m) => m.role === \"assistant\");\n\n\t\tif (!lastAssistant) return null;\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() || null;\n\t}\n\n\t// =========================================================================\n\t// Hook System\n\t// =========================================================================\n\n\t/**\n\t * Check if hooks have handlers for a specific event type.\n\t */\n\thasHookHandlers(eventType: string): boolean {\n\t\treturn this._hookRunner?.hasHandlers(eventType) ?? false;\n\t}\n\n\t/**\n\t * Get the hook runner (for setting UI context and error handlers).\n\t */\n\tget hookRunner(): HookRunner | null {\n\t\treturn this._hookRunner;\n\t}\n\n\t/**\n\t * Get custom tools (for setting UI context in modes).\n\t */\n\tget customTools(): LoadedCustomTool[] {\n\t\treturn this._customTools;\n\t}\n\n\t/**\n\t * Emit session event to all custom tools.\n\t * Called on session switch, branch, and clear.\n\t */\n\tprivate async _emitToolSessionEvent(\n\t\treason: ToolSessionEvent[\"reason\"],\n\t\tpreviousSessionFile: string | null,\n\t): Promise<void> {\n\t\tconst event: ToolSessionEvent = {\n\t\t\tentries: this.sessionManager.getEntries(),\n\t\t\tsessionFile: this.sessionFile,\n\t\t\tpreviousSessionFile,\n\t\t\treason,\n\t\t};\n\t\tfor (const { tool } of this._customTools) {\n\t\t\tif (tool.onSession) {\n\t\t\t\ttry {\n\t\t\t\t\tawait tool.onSession(event);\n\t\t\t\t} catch (_err) {\n\t\t\t\t\t// Silently ignore tool errors during session events\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"agent-session.js","sourceRoot":"","sources":["../../src/core/agent-session.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * AgentSession - Core abstraction for agent lifecycle and session management.\n *\n * This class is shared between all run modes (interactive, print, rpc).\n * It encapsulates:\n * - Agent state access\n * - Event subscription with automatic session persistence\n * - Model and thinking level management\n * - Compaction (manual and auto)\n * - Bash execution\n * - Session switching and branching\n *\n * Modes use this class and add their own I/O layer on top.\n */\n\nimport type { Agent, AgentEvent, AgentState, AppMessage, Attachment, ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport type { AssistantMessage, Message, Model, TextContent } from \"@mariozechner/pi-ai\";\nimport { isContextOverflow, modelsAreEqual, supportsXhigh } from \"@mariozechner/pi-ai\";\nimport { getModelsPath } from \"../config.js\";\nimport { type BashResult, executeBash as executeBashCommand } from \"./bash-executor.js\";\nimport { calculateContextTokens, compact, prepareCompaction, shouldCompact } from \"./compaction.js\";\nimport type { LoadedCustomTool, SessionEvent as ToolSessionEvent } from \"./custom-tools/index.js\";\nimport { exportSessionToHtml } from \"./export-html.js\";\nimport type { HookRunner, SessionEventResult, TurnEndEvent, TurnStartEvent } from \"./hooks/index.js\";\nimport type { BashExecutionMessage } from \"./messages.js\";\nimport type { ModelRegistry } from \"./model-registry.js\";\nimport type { CompactionEntry, SessionManager } from \"./session-manager.js\";\nimport type { SettingsManager, SkillsSettings } from \"./settings-manager.js\";\nimport { expandSlashCommand, type FileSlashCommand } from \"./slash-commands.js\";\n\n/** Session-specific events that extend the core AgentEvent */\nexport type AgentSessionEvent =\n\t| AgentEvent\n\t| { type: \"auto_compaction_start\"; reason: \"threshold\" | \"overflow\" }\n\t| { type: \"auto_compaction_end\"; result: CompactionResult | null; aborted: boolean; willRetry: boolean }\n\t| { type: \"auto_retry_start\"; attempt: number; maxAttempts: number; delayMs: number; errorMessage: string }\n\t| { type: \"auto_retry_end\"; success: boolean; attempt: number; finalError?: string };\n\n/** Listener function for agent session events */\nexport type AgentSessionEventListener = (event: AgentSessionEvent) => void;\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface AgentSessionConfig {\n\tagent: Agent;\n\tsessionManager: SessionManager;\n\tsettingsManager: SettingsManager;\n\t/** Models to cycle through with Ctrl+P (from --models flag) */\n\tscopedModels?: Array<{ model: Model<any>; thinkingLevel: ThinkingLevel }>;\n\t/** File-based slash commands for expansion */\n\tfileCommands?: FileSlashCommand[];\n\t/** Hook runner (created in main.ts with wrapped tools) */\n\thookRunner?: HookRunner | null;\n\t/** Custom tools for session lifecycle events */\n\tcustomTools?: LoadedCustomTool[];\n\tskillsSettings?: Required<SkillsSettings>;\n\t/** Model registry for API key resolution and model discovery */\n\tmodelRegistry: ModelRegistry;\n}\n\n/** Options for AgentSession.prompt() */\nexport interface PromptOptions {\n\t/** Whether to expand file-based slash commands (default: true) */\n\texpandSlashCommands?: boolean;\n\t/** Image/file attachments */\n\tattachments?: Attachment[];\n}\n\n/** Result from cycleModel() */\nexport interface ModelCycleResult {\n\tmodel: Model<any>;\n\tthinkingLevel: ThinkingLevel;\n\t/** Whether cycling through scoped models (--models flag) or all available */\n\tisScoped: boolean;\n}\n\n/** Result from compact() or checkAutoCompaction() */\nexport interface CompactionResult {\n\ttokensBefore: number;\n\tsummary: string;\n}\n\n/** Session statistics for /session command */\nexport interface SessionStats {\n\tsessionFile: string | null;\n\tsessionId: string;\n\tuserMessages: number;\n\tassistantMessages: number;\n\ttoolCalls: number;\n\ttoolResults: number;\n\ttotalMessages: number;\n\ttokens: {\n\t\tinput: number;\n\t\toutput: number;\n\t\tcacheRead: number;\n\t\tcacheWrite: number;\n\t\ttotal: number;\n\t};\n\tcost: number;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** Standard thinking levels */\nconst THINKING_LEVELS: ThinkingLevel[] = [\"off\", \"minimal\", \"low\", \"medium\", \"high\"];\n\n/** Thinking levels including xhigh (for supported models) */\nconst THINKING_LEVELS_WITH_XHIGH: ThinkingLevel[] = [\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\"];\n\n// ============================================================================\n// AgentSession Class\n// ============================================================================\n\nexport class AgentSession {\n\treadonly agent: Agent;\n\treadonly sessionManager: SessionManager;\n\treadonly settingsManager: SettingsManager;\n\n\tprivate _scopedModels: Array<{ model: Model<any>; thinkingLevel: ThinkingLevel }>;\n\tprivate _fileCommands: FileSlashCommand[];\n\n\t// Event subscription state\n\tprivate _unsubscribeAgent?: () => void;\n\tprivate _eventListeners: AgentSessionEventListener[] = [];\n\n\t// Message queue state\n\tprivate _queuedMessages: string[] = [];\n\n\t// Compaction state\n\tprivate _compactionAbortController: AbortController | null = null;\n\tprivate _autoCompactionAbortController: AbortController | null = null;\n\n\t// Retry state\n\tprivate _retryAbortController: AbortController | null = null;\n\tprivate _retryAttempt = 0;\n\tprivate _retryPromise: Promise<void> | null = null;\n\tprivate _retryResolve: (() => void) | null = null;\n\n\t// Bash execution state\n\tprivate _bashAbortController: AbortController | null = null;\n\tprivate _pendingBashMessages: BashExecutionMessage[] = [];\n\n\t// Hook system\n\tprivate _hookRunner: HookRunner | null = null;\n\tprivate _turnIndex = 0;\n\n\t// Custom tools for session lifecycle\n\tprivate _customTools: LoadedCustomTool[] = [];\n\n\tprivate _skillsSettings: Required<SkillsSettings> | undefined;\n\n\t// Model registry for API key resolution\n\tprivate _modelRegistry: ModelRegistry;\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._scopedModels = config.scopedModels ?? [];\n\t\tthis._fileCommands = config.fileCommands ?? [];\n\t\tthis._hookRunner = config.hookRunner ?? null;\n\t\tthis._customTools = config.customTools ?? [];\n\t\tthis._skillsSettings = config.skillsSettings;\n\t\tthis._modelRegistry = config.modelRegistry;\n\t}\n\n\t/** Model registry for API key resolution and model discovery */\n\tget modelRegistry(): ModelRegistry {\n\t\treturn this._modelRegistry;\n\t}\n\n\t// =========================================================================\n\t// Event Subscription\n\t// =========================================================================\n\n\t/** Emit an event to all listeners */\n\tprivate _emit(event: AgentSessionEvent): void {\n\t\tfor (const l of this._eventListeners) {\n\t\t\tl(event);\n\t\t}\n\t}\n\n\t// Track last assistant message for auto-compaction check\n\tprivate _lastAssistantMessage: AssistantMessage | null = null;\n\n\t/** Internal handler for agent events - shared by subscribe and reconnect */\n\tprivate _handleAgentEvent = async (event: AgentEvent): Promise<void> => {\n\t\t// When a user message starts, check if it's from the queue and remove it BEFORE emitting\n\t\t// This ensures the UI sees the updated queue state\n\t\tif (event.type === \"message_start\" && event.message.role === \"user\" && this._queuedMessages.length > 0) {\n\t\t\t// Extract text content from the message\n\t\t\tconst messageText = this._getUserMessageText(event.message);\n\t\t\tif (messageText && this._queuedMessages.includes(messageText)) {\n\t\t\t\t// Remove the first occurrence of this message from the queue\n\t\t\t\tconst index = this._queuedMessages.indexOf(messageText);\n\t\t\t\tif (index !== -1) {\n\t\t\t\t\tthis._queuedMessages.splice(index, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Emit to hooks first\n\t\tawait this._emitHookEvent(event);\n\n\t\t// Notify all listeners\n\t\tthis._emit(event);\n\n\t\t// Handle session persistence\n\t\tif (event.type === \"message_end\") {\n\t\t\tthis.sessionManager.saveMessage(event.message);\n\n\t\t\t// Track assistant message for auto-compaction (checked on agent_end)\n\t\t\tif (event.message.role === \"assistant\") {\n\t\t\t\tthis._lastAssistantMessage = event.message;\n\t\t\t}\n\t\t}\n\n\t\t// Check auto-retry and auto-compaction after agent completes\n\t\tif (event.type === \"agent_end\" && this._lastAssistantMessage) {\n\t\t\tconst msg = this._lastAssistantMessage;\n\t\t\tthis._lastAssistantMessage = null;\n\n\t\t\t// Check for retryable errors first (overloaded, rate limit, server errors)\n\t\t\tif (this._isRetryableError(msg)) {\n\t\t\t\tconst didRetry = await this._handleRetryableError(msg);\n\t\t\t\tif (didRetry) return; // Retry was initiated, don't proceed to compaction\n\t\t\t} else if (this._retryAttempt > 0) {\n\t\t\t\t// Previous retry succeeded - emit success event and reset counter\n\t\t\t\tthis._emit({\n\t\t\t\t\ttype: \"auto_retry_end\",\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\tattempt: this._retryAttempt,\n\t\t\t\t});\n\t\t\t\tthis._retryAttempt = 0;\n\t\t\t\t// Resolve the retry promise so waitForRetry() completes\n\t\t\t\tthis._resolveRetry();\n\t\t\t}\n\n\t\t\tawait this._checkCompaction(msg);\n\t\t}\n\t};\n\n\t/** Resolve the pending retry promise */\n\tprivate _resolveRetry(): void {\n\t\tif (this._retryResolve) {\n\t\t\tthis._retryResolve();\n\t\t\tthis._retryResolve = null;\n\t\t\tthis._retryPromise = null;\n\t\t}\n\t}\n\n\t/** Extract text content from a message */\n\tprivate _getUserMessageText(message: Message): string {\n\t\tif (message.role !== \"user\") return \"\";\n\t\tconst content = message.content;\n\t\tif (typeof content === \"string\") return content;\n\t\tconst textBlocks = content.filter((c) => c.type === \"text\");\n\t\treturn textBlocks.map((c) => (c as TextContent).text).join(\"\");\n\t}\n\n\t/** Find the last assistant message in agent state (including aborted ones) */\n\tprivate _findLastAssistantMessage(): AssistantMessage | null {\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 null;\n\t}\n\n\t/** Emit hook events based on agent events */\n\tprivate async _emitHookEvent(event: AgentEvent): Promise<void> {\n\t\tif (!this._hookRunner) return;\n\n\t\tif (event.type === \"agent_start\") {\n\t\t\tthis._turnIndex = 0;\n\t\t\tawait this._hookRunner.emit({ type: \"agent_start\" });\n\t\t} else if (event.type === \"agent_end\") {\n\t\t\tawait this._hookRunner.emit({ type: \"agent_end\", messages: event.messages });\n\t\t} else if (event.type === \"turn_start\") {\n\t\t\tconst hookEvent: 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._hookRunner.emit(hookEvent);\n\t\t} else if (event.type === \"turn_end\") {\n\t\t\tconst hookEvent: 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._hookRunner.emit(hookEvent);\n\t\t\tthis._turnIndex++;\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\t// Set up agent subscription if not already done\n\t\tif (!this._unsubscribeAgent) {\n\t\t\tthis._unsubscribeAgent = this.agent.subscribe(this._handleAgentEvent);\n\t\t}\n\n\t\t// Return unsubscribe function for this specific listener\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\tdispose(): void {\n\t\tthis._disconnectFromAgent();\n\t\tthis._eventListeners = [];\n\t}\n\n\t// =========================================================================\n\t// Read-only State Access\n\t// =========================================================================\n\n\t/** Full agent state */\n\tget state(): AgentState {\n\t\treturn this.agent.state;\n\t}\n\n\t/** Current model (may be null if not yet selected) */\n\tget model(): Model<any> | null {\n\t\treturn this.agent.state.model;\n\t}\n\n\t/** Current thinking level */\n\tget thinkingLevel(): ThinkingLevel {\n\t\treturn this.agent.state.thinkingLevel;\n\t}\n\n\t/** Whether agent is currently streaming a response */\n\tget isStreaming(): boolean {\n\t\treturn this.agent.state.isStreaming;\n\t}\n\n\t/** Whether auto-compaction is currently running */\n\tget isCompacting(): boolean {\n\t\treturn this._autoCompactionAbortController !== null || this._compactionAbortController !== null;\n\t}\n\n\t/** All messages including custom types like BashExecutionMessage */\n\tget messages(): AppMessage[] {\n\t\treturn this.agent.state.messages;\n\t}\n\n\t/** Current queue mode */\n\tget queueMode(): \"all\" | \"one-at-a-time\" {\n\t\treturn this.agent.getQueueMode();\n\t}\n\n\t/** Current session file path, or null if sessions are disabled */\n\tget sessionFile(): string | null {\n\t\treturn this.sessionManager.isPersisted() ? this.sessionManager.getSessionFile() : null;\n\t}\n\n\t/** Current session ID */\n\tget sessionId(): string {\n\t\treturn this.sessionManager.getSessionId();\n\t}\n\n\t/** Scoped models for cycling (from --models flag) */\n\tget scopedModels(): ReadonlyArray<{ model: Model<any>; thinkingLevel: ThinkingLevel }> {\n\t\treturn this._scopedModels;\n\t}\n\n\t/** File-based slash commands */\n\tget fileCommands(): ReadonlyArray<FileSlashCommand> {\n\t\treturn this._fileCommands;\n\t}\n\n\t// =========================================================================\n\t// Prompting\n\t// =========================================================================\n\n\t/**\n\t * Send a prompt to the agent.\n\t * - Validates model and API key before sending\n\t * - Expands file-based slash commands by default\n\t * @throws Error if no model selected or no API key available\n\t */\n\tasync prompt(text: string, options?: PromptOptions): Promise<void> {\n\t\t// Flush any pending bash messages before the new prompt\n\t\tthis._flushPendingBashMessages();\n\n\t\tconst expandCommands = options?.expandSlashCommands ?? true;\n\n\t\t// Validate model\n\t\tif (!this.model) {\n\t\t\tthrow new Error(\n\t\t\t\t\"No model selected.\\n\\n\" +\n\t\t\t\t\t`Use /login, set an API key environment variable, or create ${getModelsPath()}\\n\\n` +\n\t\t\t\t\t\"Then use /model to select a model.\",\n\t\t\t);\n\t\t}\n\n\t\t// Validate API key\n\t\tconst apiKey = await this._modelRegistry.getApiKey(this.model);\n\t\tif (!apiKey) {\n\t\t\tthrow new Error(\n\t\t\t\t`No API key found for ${this.model.provider}.\\n\\n` +\n\t\t\t\t\t`Use /login, set an API key environment variable, or create ${getModelsPath()}`,\n\t\t\t);\n\t\t}\n\n\t\t// Check if we need to compact before sending (catches aborted responses)\n\t\tconst lastAssistant = this._findLastAssistantMessage();\n\t\tif (lastAssistant) {\n\t\t\tawait this._checkCompaction(lastAssistant, false);\n\t\t}\n\n\t\t// Expand slash commands if requested\n\t\tconst expandedText = expandCommands ? expandSlashCommand(text, [...this._fileCommands]) : text;\n\n\t\tawait this.agent.prompt(expandedText, options?.attachments);\n\t\tawait this.waitForRetry();\n\t}\n\n\t/**\n\t * Queue a message to be sent after the current response completes.\n\t * Use when agent is currently streaming.\n\t */\n\tasync queueMessage(text: string): Promise<void> {\n\t\tthis._queuedMessages.push(text);\n\t\tawait this.agent.queueMessage({\n\t\t\trole: \"user\",\n\t\t\tcontent: [{ type: \"text\", text }],\n\t\t\ttimestamp: Date.now(),\n\t\t});\n\t}\n\n\t/**\n\t * Clear queued messages and return them.\n\t * Useful for restoring to editor when user aborts.\n\t */\n\tclearQueue(): string[] {\n\t\tconst queued = [...this._queuedMessages];\n\t\tthis._queuedMessages = [];\n\t\tthis.agent.clearMessageQueue();\n\t\treturn queued;\n\t}\n\n\t/** Number of messages currently queued */\n\tget queuedMessageCount(): number {\n\t\treturn this._queuedMessages.length;\n\t}\n\n\t/** Get queued messages (read-only) */\n\tgetQueuedMessages(): readonly string[] {\n\t\treturn this._queuedMessages;\n\t}\n\n\tget skillsSettings(): Required<SkillsSettings> | undefined {\n\t\treturn this._skillsSettings;\n\t}\n\n\t/**\n\t * Abort current operation and wait for agent to become idle.\n\t */\n\tasync abort(): Promise<void> {\n\t\tthis.abortRetry();\n\t\tthis.agent.abort();\n\t\tawait this.agent.waitForIdle();\n\t}\n\n\t/**\n\t * Reset agent and session to start fresh.\n\t * Clears all messages and starts a new session.\n\t * Listeners are preserved and will continue receiving events.\n\t * @returns true if reset completed, false if cancelled by hook\n\t */\n\tasync reset(): Promise<boolean> {\n\t\tconst previousSessionFile = this.sessionFile;\n\t\tconst entries = this.sessionManager.getEntries();\n\n\t\t// Emit before_new event (can be cancelled)\n\t\tif (this._hookRunner?.hasHandlers(\"session\")) {\n\t\t\tconst result = (await this._hookRunner.emit({\n\t\t\t\ttype: \"session\",\n\t\t\t\tentries,\n\t\t\t\tsessionFile: this.sessionFile,\n\t\t\t\tpreviousSessionFile: null,\n\t\t\t\treason: \"before_new\",\n\t\t\t})) as SessionEventResult | undefined;\n\n\t\t\tif (result?.cancel) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tthis._disconnectFromAgent();\n\t\tawait this.abort();\n\t\tthis.agent.reset();\n\t\tthis.sessionManager.reset();\n\t\tthis._queuedMessages = [];\n\t\tthis._reconnectToAgent();\n\n\t\t// Emit session event with reason \"new\" to hooks\n\t\tif (this._hookRunner) {\n\t\t\tthis._hookRunner.setSessionFile(this.sessionFile);\n\t\t\tawait this._hookRunner.emit({\n\t\t\t\ttype: \"session\",\n\t\t\t\tentries: [],\n\t\t\t\tsessionFile: this.sessionFile,\n\t\t\t\tpreviousSessionFile,\n\t\t\t\treason: \"new\",\n\t\t\t});\n\t\t}\n\n\t\t// Emit session event to custom tools\n\t\tawait this._emitToolSessionEvent(\"new\", previousSessionFile);\n\t\treturn true;\n\t}\n\n\t// =========================================================================\n\t// Model Management\n\t// =========================================================================\n\n\t/**\n\t * Set model directly.\n\t * Validates API key, saves to session and settings.\n\t * @throws Error if no API key available for the model\n\t */\n\tasync setModel(model: Model<any>): Promise<void> {\n\t\tconst apiKey = await this._modelRegistry.getApiKey(model);\n\t\tif (!apiKey) {\n\t\t\tthrow new Error(`No API key for ${model.provider}/${model.id}`);\n\t\t}\n\n\t\tthis.agent.setModel(model);\n\t\tthis.sessionManager.saveModelChange(model.provider, model.id);\n\t\tthis.settingsManager.setDefaultModelAndProvider(model.provider, model.id);\n\n\t\t// Re-clamp thinking level for new model's capabilities\n\t\tthis.setThinkingLevel(this.thinkingLevel);\n\t}\n\n\t/**\n\t * Cycle to next/previous model.\n\t * Uses scoped models (from --models flag) if available, otherwise all available models.\n\t * @param direction - \"forward\" (default) or \"backward\"\n\t * @returns The new model info, or null if only one model available\n\t */\n\tasync cycleModel(direction: \"forward\" | \"backward\" = \"forward\"): Promise<ModelCycleResult | null> {\n\t\tif (this._scopedModels.length > 0) {\n\t\t\treturn this._cycleScopedModel(direction);\n\t\t}\n\t\treturn this._cycleAvailableModel(direction);\n\t}\n\n\tprivate async _cycleScopedModel(direction: \"forward\" | \"backward\"): Promise<ModelCycleResult | null> {\n\t\tif (this._scopedModels.length <= 1) return null;\n\n\t\tconst currentModel = this.model;\n\t\tlet currentIndex = this._scopedModels.findIndex((sm) => modelsAreEqual(sm.model, currentModel));\n\n\t\tif (currentIndex === -1) currentIndex = 0;\n\t\tconst len = this._scopedModels.length;\n\t\tconst nextIndex = direction === \"forward\" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;\n\t\tconst next = this._scopedModels[nextIndex];\n\n\t\t// Validate API key\n\t\tconst apiKey = await this._modelRegistry.getApiKey(next.model);\n\t\tif (!apiKey) {\n\t\t\tthrow new Error(`No API key for ${next.model.provider}/${next.model.id}`);\n\t\t}\n\n\t\t// Apply model\n\t\tthis.agent.setModel(next.model);\n\t\tthis.sessionManager.saveModelChange(next.model.provider, next.model.id);\n\t\tthis.settingsManager.setDefaultModelAndProvider(next.model.provider, next.model.id);\n\n\t\t// Apply thinking level (setThinkingLevel clamps to model capabilities)\n\t\tthis.setThinkingLevel(next.thinkingLevel);\n\n\t\treturn { model: next.model, thinkingLevel: this.thinkingLevel, isScoped: true };\n\t}\n\n\tprivate async _cycleAvailableModel(direction: \"forward\" | \"backward\"): Promise<ModelCycleResult | null> {\n\t\tconst availableModels = await this._modelRegistry.getAvailable();\n\t\tif (availableModels.length <= 1) return null;\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 apiKey = await this._modelRegistry.getApiKey(nextModel);\n\t\tif (!apiKey) {\n\t\t\tthrow new Error(`No API key for ${nextModel.provider}/${nextModel.id}`);\n\t\t}\n\n\t\tthis.agent.setModel(nextModel);\n\t\tthis.sessionManager.saveModelChange(nextModel.provider, nextModel.id);\n\t\tthis.settingsManager.setDefaultModelAndProvider(nextModel.provider, nextModel.id);\n\n\t\t// Re-clamp thinking level for new model's capabilities\n\t\tthis.setThinkingLevel(this.thinkingLevel);\n\n\t\treturn { model: nextModel, thinkingLevel: this.thinkingLevel, isScoped: false };\n\t}\n\n\t/**\n\t * Get all available models with valid API keys.\n\t */\n\tasync getAvailableModels(): Promise<Model<any>[]> {\n\t\treturn this._modelRegistry.getAvailable();\n\t}\n\n\t// =========================================================================\n\t// Thinking Level Management\n\t// =========================================================================\n\n\t/**\n\t * Set thinking level.\n\t * Clamps to model capabilities: \"off\" if no reasoning, \"high\" if xhigh unsupported.\n\t * Saves to session and settings.\n\t */\n\tsetThinkingLevel(level: ThinkingLevel): void {\n\t\tlet effectiveLevel = level;\n\t\tif (!this.supportsThinking()) {\n\t\t\teffectiveLevel = \"off\";\n\t\t} else if (level === \"xhigh\" && !this.supportsXhighThinking()) {\n\t\t\teffectiveLevel = \"high\";\n\t\t}\n\t\tthis.agent.setThinkingLevel(effectiveLevel);\n\t\tthis.sessionManager.saveThinkingLevelChange(effectiveLevel);\n\t\tthis.settingsManager.setDefaultThinkingLevel(effectiveLevel);\n\t}\n\n\t/**\n\t * Cycle to next thinking level.\n\t * @returns New level, or null if model doesn't support thinking\n\t */\n\tcycleThinkingLevel(): ThinkingLevel | null {\n\t\tif (!this.supportsThinking()) return null;\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\t/**\n\t * Get available thinking levels for current model.\n\t */\n\tgetAvailableThinkingLevels(): ThinkingLevel[] {\n\t\treturn this.supportsXhighThinking() ? THINKING_LEVELS_WITH_XHIGH : THINKING_LEVELS;\n\t}\n\n\t/**\n\t * Check if current model supports xhigh thinking level.\n\t */\n\tsupportsXhighThinking(): boolean {\n\t\treturn this.model ? supportsXhigh(this.model) : false;\n\t}\n\n\t/**\n\t * Check if current model supports thinking/reasoning.\n\t */\n\tsupportsThinking(): boolean {\n\t\treturn !!this.model?.reasoning;\n\t}\n\n\t// =========================================================================\n\t// Queue Mode Management\n\t// =========================================================================\n\n\t/**\n\t * Set message queue mode.\n\t * Saves to settings.\n\t */\n\tsetQueueMode(mode: \"all\" | \"one-at-a-time\"): void {\n\t\tthis.agent.setQueueMode(mode);\n\t\tthis.settingsManager.setQueueMode(mode);\n\t}\n\n\t// =========================================================================\n\t// Compaction\n\t// =========================================================================\n\n\t/**\n\t * Manually compact the session context.\n\t * Aborts current agent operation first.\n\t * @param customInstructions Optional instructions for the compaction summary\n\t */\n\tasync compact(customInstructions?: string): Promise<CompactionResult> {\n\t\tthis._disconnectFromAgent();\n\t\tawait this.abort();\n\t\tthis._compactionAbortController = new AbortController();\n\n\t\ttry {\n\t\t\tif (!this.model) {\n\t\t\t\tthrow new Error(\"No model selected\");\n\t\t\t}\n\n\t\t\tconst apiKey = await this._modelRegistry.getApiKey(this.model);\n\t\t\tif (!apiKey) {\n\t\t\t\tthrow new Error(`No API key for ${this.model.provider}`);\n\t\t\t}\n\n\t\t\tconst entries = this.sessionManager.getEntries();\n\t\t\tconst settings = this.settingsManager.getCompactionSettings();\n\n\t\t\tconst preparation = prepareCompaction(entries, settings);\n\t\t\tif (!preparation) {\n\t\t\t\tthrow new Error(\"Already compacted\");\n\t\t\t}\n\n\t\t\t// Find previous compaction summary if any\n\t\t\tlet previousSummary: string | undefined;\n\t\t\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\t\t\tif (entries[i].type === \"compaction\") {\n\t\t\t\t\tpreviousSummary = (entries[i] as CompactionEntry).summary;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet compactionEntry: CompactionEntry | undefined;\n\t\t\tlet fromHook = false;\n\n\t\t\tif (this._hookRunner?.hasHandlers(\"session\")) {\n\t\t\t\tconst result = (await this._hookRunner.emit({\n\t\t\t\t\ttype: \"session\",\n\t\t\t\t\tentries,\n\t\t\t\t\tsessionFile: this.sessionFile,\n\t\t\t\t\tpreviousSessionFile: null,\n\t\t\t\t\treason: \"before_compact\",\n\t\t\t\t\tcutPoint: preparation.cutPoint,\n\t\t\t\t\tpreviousSummary,\n\t\t\t\t\tmessagesToSummarize: [...preparation.messagesToSummarize],\n\t\t\t\t\tmessagesToKeep: [...preparation.messagesToKeep],\n\t\t\t\t\ttokensBefore: preparation.tokensBefore,\n\t\t\t\t\tcustomInstructions,\n\t\t\t\t\tmodel: this.model,\n\t\t\t\t\tresolveApiKey: async (m: Model<any>) => (await this._modelRegistry.getApiKey(m)) ?? undefined,\n\t\t\t\t\tsignal: this._compactionAbortController.signal,\n\t\t\t\t})) as SessionEventResult | undefined;\n\n\t\t\t\tif (result?.cancel) {\n\t\t\t\t\tthrow new Error(\"Compaction cancelled\");\n\t\t\t\t}\n\n\t\t\t\tif (result?.compactionEntry) {\n\t\t\t\t\tcompactionEntry = result.compactionEntry;\n\t\t\t\t\tfromHook = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!compactionEntry) {\n\t\t\t\tcompactionEntry = await compact(\n\t\t\t\t\tentries,\n\t\t\t\t\tthis.model,\n\t\t\t\t\tsettings,\n\t\t\t\t\tapiKey,\n\t\t\t\t\tthis._compactionAbortController.signal,\n\t\t\t\t\tcustomInstructions,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (this._compactionAbortController.signal.aborted) {\n\t\t\t\tthrow new Error(\"Compaction cancelled\");\n\t\t\t}\n\n\t\t\tthis.sessionManager.saveCompaction(compactionEntry);\n\t\t\tconst newEntries = this.sessionManager.getEntries();\n\t\t\tconst sessionContext = this.sessionManager.buildSessionContext();\n\t\t\tthis.agent.replaceMessages(sessionContext.messages);\n\n\t\t\tif (this._hookRunner) {\n\t\t\t\tawait this._hookRunner.emit({\n\t\t\t\t\ttype: \"session\",\n\t\t\t\t\tentries: newEntries,\n\t\t\t\t\tsessionFile: this.sessionFile,\n\t\t\t\t\tpreviousSessionFile: null,\n\t\t\t\t\treason: \"compact\",\n\t\t\t\t\tcompactionEntry,\n\t\t\t\t\ttokensBefore: compactionEntry.tokensBefore,\n\t\t\t\t\tfromHook,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttokensBefore: compactionEntry.tokensBefore,\n\t\t\t\tsummary: compactionEntry.summary,\n\t\t\t};\n\t\t} finally {\n\t\t\tthis._compactionAbortController = null;\n\t\t\tthis._reconnectToAgent();\n\t\t}\n\t}\n\n\t/**\n\t * Cancel in-progress compaction (manual or auto).\n\t */\n\tabortCompaction(): void {\n\t\tthis._compactionAbortController?.abort();\n\t\tthis._autoCompactionAbortController?.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, NO auto-retry (user continues manually)\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 async _checkCompaction(assistantMessage: AssistantMessage, skipAbortedCheck = true): Promise<void> {\n\t\tconst settings = this.settingsManager.getCompactionSettings();\n\t\tif (!settings.enabled) return;\n\n\t\t// Skip if message was aborted (user cancelled) - unless skipAbortedCheck is false\n\t\tif (skipAbortedCheck && assistantMessage.stopReason === \"aborted\") return;\n\n\t\tconst contextWindow = this.model?.contextWindow ?? 0;\n\n\t\t// Case 1: Overflow - LLM returned context overflow error\n\t\tif (isContextOverflow(assistantMessage, contextWindow)) {\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.replaceMessages(messages.slice(0, -1));\n\t\t\t}\n\t\t\tawait this._runAutoCompaction(\"overflow\", true);\n\t\t\treturn;\n\t\t}\n\n\t\t// Case 2: Threshold - turn succeeded but context is getting large\n\t\t// Skip if this was an error (non-overflow errors don't have usage data)\n\t\tif (assistantMessage.stopReason === \"error\") return;\n\n\t\tconst contextTokens = calculateContextTokens(assistantMessage.usage);\n\t\tif (shouldCompact(contextTokens, contextWindow, settings)) {\n\t\t\tawait this._runAutoCompaction(\"threshold\", false);\n\t\t}\n\t}\n\n\t/**\n\t * Internal: Run auto-compaction with events.\n\t */\n\tprivate async _runAutoCompaction(reason: \"overflow\" | \"threshold\", willRetry: boolean): Promise<void> {\n\t\tconst settings = this.settingsManager.getCompactionSettings();\n\n\t\tthis._emit({ type: \"auto_compaction_start\", reason });\n\t\tthis._autoCompactionAbortController = new AbortController();\n\n\t\ttry {\n\t\t\tif (!this.model) {\n\t\t\t\tthis._emit({ type: \"auto_compaction_end\", result: null, aborted: false, willRetry: false });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst apiKey = await this._modelRegistry.getApiKey(this.model);\n\t\t\tif (!apiKey) {\n\t\t\t\tthis._emit({ type: \"auto_compaction_end\", result: null, aborted: false, willRetry: false });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst entries = this.sessionManager.getEntries();\n\n\t\t\tconst preparation = prepareCompaction(entries, settings);\n\t\t\tif (!preparation) {\n\t\t\t\tthis._emit({ type: \"auto_compaction_end\", result: null, aborted: false, willRetry: false });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Find previous compaction summary if any\n\t\t\tlet previousSummary: string | undefined;\n\t\t\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\t\t\tif (entries[i].type === \"compaction\") {\n\t\t\t\t\tpreviousSummary = (entries[i] as CompactionEntry).summary;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet compactionEntry: CompactionEntry | undefined;\n\t\t\tlet fromHook = false;\n\n\t\t\tif (this._hookRunner?.hasHandlers(\"session\")) {\n\t\t\t\tconst hookResult = (await this._hookRunner.emit({\n\t\t\t\t\ttype: \"session\",\n\t\t\t\t\tentries,\n\t\t\t\t\tsessionFile: this.sessionFile,\n\t\t\t\t\tpreviousSessionFile: null,\n\t\t\t\t\treason: \"before_compact\",\n\t\t\t\t\tcutPoint: preparation.cutPoint,\n\t\t\t\t\tpreviousSummary,\n\t\t\t\t\tmessagesToSummarize: [...preparation.messagesToSummarize],\n\t\t\t\t\tmessagesToKeep: [...preparation.messagesToKeep],\n\t\t\t\t\ttokensBefore: preparation.tokensBefore,\n\t\t\t\t\tcustomInstructions: undefined,\n\t\t\t\t\tmodel: this.model,\n\t\t\t\t\tresolveApiKey: async (m: Model<any>) => (await this._modelRegistry.getApiKey(m)) ?? undefined,\n\t\t\t\t\tsignal: this._autoCompactionAbortController.signal,\n\t\t\t\t})) as SessionEventResult | undefined;\n\n\t\t\t\tif (hookResult?.cancel) {\n\t\t\t\t\tthis._emit({ type: \"auto_compaction_end\", result: null, aborted: true, willRetry: false });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (hookResult?.compactionEntry) {\n\t\t\t\t\tcompactionEntry = hookResult.compactionEntry;\n\t\t\t\t\tfromHook = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!compactionEntry) {\n\t\t\t\tcompactionEntry = await compact(\n\t\t\t\t\tentries,\n\t\t\t\t\tthis.model,\n\t\t\t\t\tsettings,\n\t\t\t\t\tapiKey,\n\t\t\t\t\tthis._autoCompactionAbortController.signal,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (this._autoCompactionAbortController.signal.aborted) {\n\t\t\t\tthis._emit({ type: \"auto_compaction_end\", result: null, aborted: true, willRetry: false });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.sessionManager.saveCompaction(compactionEntry);\n\t\t\tconst newEntries = this.sessionManager.getEntries();\n\t\t\tconst sessionContext = this.sessionManager.buildSessionContext();\n\t\t\tthis.agent.replaceMessages(sessionContext.messages);\n\n\t\t\tif (this._hookRunner) {\n\t\t\t\tawait this._hookRunner.emit({\n\t\t\t\t\ttype: \"session\",\n\t\t\t\t\tentries: newEntries,\n\t\t\t\t\tsessionFile: this.sessionFile,\n\t\t\t\t\tpreviousSessionFile: null,\n\t\t\t\t\treason: \"compact\",\n\t\t\t\t\tcompactionEntry,\n\t\t\t\t\ttokensBefore: compactionEntry.tokensBefore,\n\t\t\t\t\tfromHook,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst result: CompactionResult = {\n\t\t\t\ttokensBefore: compactionEntry.tokensBefore,\n\t\t\t\tsummary: compactionEntry.summary,\n\t\t\t};\n\t\t\tthis._emit({ type: \"auto_compaction_end\", result, aborted: false, willRetry });\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.replaceMessages(messages.slice(0, -1));\n\t\t\t\t}\n\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tthis.agent.continue().catch(() => {});\n\t\t\t\t}, 100);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthis._emit({ type: \"auto_compaction_end\", result: null, aborted: false, willRetry: false });\n\n\t\t\tif (reason === \"overflow\") {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Context overflow: ${error instanceof Error ? error.message : \"compaction failed\"}. Your input may be too large for the context window.`,\n\t\t\t\t);\n\t\t\t}\n\t\t} finally {\n\t\t\tthis._autoCompactionAbortController = null;\n\t\t}\n\t}\n\n\t/**\n\t * Toggle auto-compaction setting.\n\t */\n\tsetAutoCompactionEnabled(enabled: boolean): void {\n\t\tthis.settingsManager.setCompactionEnabled(enabled);\n\t}\n\n\t/** Whether auto-compaction is enabled */\n\tget autoCompactionEnabled(): boolean {\n\t\treturn this.settingsManager.getCompactionEnabled();\n\t}\n\n\t// =========================================================================\n\t// Auto-Retry\n\t// =========================================================================\n\n\t/**\n\t * Check if an error is retryable (overloaded, rate limit, server errors).\n\t * Context overflow errors are NOT retryable (handled by compaction instead).\n\t */\n\tprivate _isRetryableError(message: AssistantMessage): boolean {\n\t\tif (message.stopReason !== \"error\" || !message.errorMessage) return false;\n\n\t\t// Context overflow is handled by compaction, not retry\n\t\tconst contextWindow = this.model?.contextWindow ?? 0;\n\t\tif (isContextOverflow(message, contextWindow)) return false;\n\n\t\tconst err = message.errorMessage;\n\t\t// Match: overloaded_error, rate limit, 429, 500, 502, 503, 504, service unavailable, connection error\n\t\treturn /overloaded|rate.?limit|too many requests|429|500|502|503|504|service.?unavailable|server error|internal error|connection.?error/i.test(\n\t\t\terr,\n\t\t);\n\t}\n\n\t/**\n\t * Handle retryable errors with exponential backoff.\n\t * @returns true if retry was initiated, false if max retries exceeded or disabled\n\t */\n\tprivate async _handleRetryableError(message: AssistantMessage): Promise<boolean> {\n\t\tconst settings = this.settingsManager.getRetrySettings();\n\t\tif (!settings.enabled) return false;\n\n\t\tthis._retryAttempt++;\n\n\t\t// Create retry promise on first attempt so waitForRetry() can await it\n\t\tif (this._retryAttempt === 1 && !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\tif (this._retryAttempt > settings.maxRetries) {\n\t\t\t// Max retries exceeded, emit final failure and reset\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._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\t// Remove error message from agent state (keep in session for history)\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.replaceMessages(messages.slice(0, -1));\n\t\t}\n\n\t\t// Wait with exponential backoff (abortable)\n\t\tthis._retryAbortController = new AbortController();\n\t\ttry {\n\t\t\tawait this._sleep(delayMs, this._retryAbortController.signal);\n\t\t} catch {\n\t\t\t// Aborted during sleep - emit end event so UI can clean up\n\t\t\tconst attempt = this._retryAttempt;\n\t\t\tthis._retryAttempt = 0;\n\t\t\tthis._retryAbortController = null;\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\treturn false;\n\t\t}\n\t\tthis._retryAbortController = null;\n\n\t\t// Retry via continue() - use setTimeout to break out of event handler chain\n\t\tsetTimeout(() => {\n\t\t\tthis.agent.continue().catch(() => {\n\t\t\t\t// Retry failed - will be caught by next agent_end\n\t\t\t});\n\t\t}, 0);\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Sleep helper that respects abort signal.\n\t */\n\tprivate _sleep(ms: number, signal?: AbortSignal): Promise<void> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tif (signal?.aborted) {\n\t\t\t\treject(new Error(\"Aborted\"));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst timeout = setTimeout(resolve, ms);\n\n\t\t\tsignal?.addEventListener(\"abort\", () => {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\treject(new Error(\"Aborted\"));\n\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Cancel in-progress retry.\n\t */\n\tabortRetry(): void {\n\t\tthis._retryAbortController?.abort();\n\t\tthis._retryAttempt = 0;\n\t\tthis._resolveRetry();\n\t}\n\n\t/**\n\t * Wait for any in-progress retry to complete.\n\t * Returns immediately if no retry is in progress.\n\t */\n\tprivate async waitForRetry(): Promise<void> {\n\t\tif (this._retryPromise) {\n\t\t\tawait this._retryPromise;\n\t\t}\n\t}\n\n\t/** Whether auto-retry is currently in progress */\n\tget isRetrying(): boolean {\n\t\treturn this._retryPromise !== null;\n\t}\n\n\t/** Whether auto-retry is enabled */\n\tget autoRetryEnabled(): boolean {\n\t\treturn this.settingsManager.getRetryEnabled();\n\t}\n\n\t/**\n\t * Toggle auto-retry setting.\n\t */\n\tsetAutoRetryEnabled(enabled: boolean): void {\n\t\tthis.settingsManager.setRetryEnabled(enabled);\n\t}\n\n\t// =========================================================================\n\t// Bash Execution\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 */\n\tasync executeBash(command: string, onChunk?: (chunk: string) => void): Promise<BashResult> {\n\t\tthis._bashAbortController = new AbortController();\n\n\t\ttry {\n\t\t\tconst result = await executeBashCommand(command, {\n\t\t\t\tonChunk,\n\t\t\t\tsignal: this._bashAbortController.signal,\n\t\t\t});\n\n\t\t\t// Create and save message\n\t\t\tconst bashMessage: BashExecutionMessage = {\n\t\t\t\trole: \"bashExecution\",\n\t\t\t\tcommand,\n\t\t\t\toutput: result.output,\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\ttimestamp: Date.now(),\n\t\t\t};\n\n\t\t\t// If agent is streaming, defer adding to avoid breaking tool_use/tool_result ordering\n\t\t\tif (this.isStreaming) {\n\t\t\t\t// Queue for later - will be flushed on agent_end\n\t\t\t\tthis._pendingBashMessages.push(bashMessage);\n\t\t\t} else {\n\t\t\t\t// Add to agent state immediately\n\t\t\t\tthis.agent.appendMessage(bashMessage);\n\n\t\t\t\t// Save to session\n\t\t\t\tthis.sessionManager.saveMessage(bashMessage);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t} finally {\n\t\t\tthis._bashAbortController = null;\n\t\t}\n\t}\n\n\t/**\n\t * Cancel running bash command.\n\t */\n\tabortBash(): void {\n\t\tthis._bashAbortController?.abort();\n\t}\n\n\t/** Whether a bash command is currently running */\n\tget isBashRunning(): boolean {\n\t\treturn this._bashAbortController !== null;\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\t// Add to agent state\n\t\t\tthis.agent.appendMessage(bashMessage);\n\n\t\t\t// Save to session\n\t\t\tthis.sessionManager.saveMessage(bashMessage);\n\t\t}\n\n\t\tthis._pendingBashMessages = [];\n\t}\n\n\t// =========================================================================\n\t// Session Management\n\t// =========================================================================\n\n\t/**\n\t * Switch to a different session file.\n\t * Aborts current operation, loads messages, restores model/thinking.\n\t * Listeners are preserved and will continue receiving events.\n\t * @returns true if switch completed, false if cancelled by hook\n\t */\n\tasync switchSession(sessionPath: string): Promise<boolean> {\n\t\tconst previousSessionFile = this.sessionFile;\n\t\tconst oldEntries = this.sessionManager.getEntries();\n\n\t\t// Emit before_switch event (can be cancelled)\n\t\tif (this._hookRunner?.hasHandlers(\"session\")) {\n\t\t\tconst result = (await this._hookRunner.emit({\n\t\t\t\ttype: \"session\",\n\t\t\t\tentries: oldEntries,\n\t\t\t\tsessionFile: this.sessionFile,\n\t\t\t\tpreviousSessionFile: null,\n\t\t\t\treason: \"before_switch\",\n\t\t\t})) as SessionEventResult | undefined;\n\n\t\t\tif (result?.cancel) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tthis._disconnectFromAgent();\n\t\tawait this.abort();\n\t\tthis._queuedMessages = [];\n\n\t\t// Set new session\n\t\tthis.sessionManager.setSessionFile(sessionPath);\n\n\t\t// Reload messages\n\t\tconst entries = this.sessionManager.getEntries();\n\t\tconst sessionContext = this.sessionManager.buildSessionContext();\n\n\t\t// Emit session event to hooks\n\t\tif (this._hookRunner) {\n\t\t\tthis._hookRunner.setSessionFile(sessionPath);\n\t\t\tawait this._hookRunner.emit({\n\t\t\t\ttype: \"session\",\n\t\t\t\tentries,\n\t\t\t\tsessionFile: sessionPath,\n\t\t\t\tpreviousSessionFile,\n\t\t\t\treason: \"switch\",\n\t\t\t});\n\t\t}\n\n\t\t// Emit session event to custom tools\n\t\tawait this._emitToolSessionEvent(\"switch\", previousSessionFile);\n\n\t\tthis.agent.replaceMessages(sessionContext.messages);\n\n\t\t// Restore model if saved\n\t\tif (sessionContext.model) {\n\t\t\tconst availableModels = await this._modelRegistry.getAvailable();\n\t\t\tconst match = availableModels.find(\n\t\t\t\t(m) => m.provider === sessionContext.model!.provider && m.id === sessionContext.model!.modelId,\n\t\t\t);\n\t\t\tif (match) {\n\t\t\t\tthis.agent.setModel(match);\n\t\t\t}\n\t\t}\n\n\t\t// Restore thinking level if saved (setThinkingLevel clamps to model capabilities)\n\t\tif (sessionContext.thinkingLevel) {\n\t\t\tthis.setThinkingLevel(sessionContext.thinkingLevel as ThinkingLevel);\n\t\t}\n\n\t\tthis._reconnectToAgent();\n\t\treturn true;\n\t}\n\n\t/**\n\t * Create a branch from a specific entry index.\n\t * Emits before_branch/branch session events to hooks.\n\t *\n\t * @param entryIndex Index into session entries to branch from\n\t * @returns Object with:\n\t * - selectedText: The text of the selected user message (for editor pre-fill)\n\t * - cancelled: True if a hook cancelled the branch\n\t */\n\tasync branch(entryIndex: number): Promise<{ selectedText: string; cancelled: boolean }> {\n\t\tconst previousSessionFile = this.sessionFile;\n\t\tconst entries = this.sessionManager.getEntries();\n\t\tconst selectedEntry = entries[entryIndex];\n\n\t\tif (!selectedEntry || selectedEntry.type !== \"message\" || selectedEntry.message.role !== \"user\") {\n\t\t\tthrow new Error(\"Invalid entry index for branching\");\n\t\t}\n\n\t\tconst selectedText = this._extractUserMessageText(selectedEntry.message.content);\n\n\t\tlet skipConversationRestore = false;\n\n\t\t// Emit before_branch event (can be cancelled)\n\t\tif (this._hookRunner?.hasHandlers(\"session\")) {\n\t\t\tconst result = (await this._hookRunner.emit({\n\t\t\t\ttype: \"session\",\n\t\t\t\tentries,\n\t\t\t\tsessionFile: this.sessionFile,\n\t\t\t\tpreviousSessionFile: null,\n\t\t\t\treason: \"before_branch\",\n\t\t\t\ttargetTurnIndex: entryIndex,\n\t\t\t})) as SessionEventResult | undefined;\n\n\t\t\tif (result?.cancel) {\n\t\t\t\treturn { selectedText, cancelled: true };\n\t\t\t}\n\t\t\tskipConversationRestore = result?.skipConversationRestore ?? false;\n\t\t}\n\n\t\t// Create branched session (returns null in --no-session mode)\n\t\tconst newSessionFile = this.sessionManager.createBranchedSessionFromEntries(entries, entryIndex);\n\n\t\t// Update session file if we have one (file-based mode)\n\t\tif (newSessionFile !== null) {\n\t\t\tthis.sessionManager.setSessionFile(newSessionFile);\n\t\t}\n\n\t\t// Reload messages from entries (works for both file and in-memory mode)\n\t\tconst newEntries = this.sessionManager.getEntries();\n\t\tconst sessionContext = this.sessionManager.buildSessionContext();\n\n\t\t// Emit branch event to hooks (after branch completes)\n\t\tif (this._hookRunner) {\n\t\t\tthis._hookRunner.setSessionFile(newSessionFile);\n\t\t\tawait this._hookRunner.emit({\n\t\t\t\ttype: \"session\",\n\t\t\t\tentries: newEntries,\n\t\t\t\tsessionFile: newSessionFile,\n\t\t\t\tpreviousSessionFile,\n\t\t\t\treason: \"branch\",\n\t\t\t\ttargetTurnIndex: entryIndex,\n\t\t\t});\n\t\t}\n\n\t\t// Emit session event to custom tools (with reason \"branch\")\n\t\tawait this._emitToolSessionEvent(\"branch\", previousSessionFile);\n\n\t\tif (!skipConversationRestore) {\n\t\t\tthis.agent.replaceMessages(sessionContext.messages);\n\t\t}\n\n\t\treturn { selectedText, cancelled: false };\n\t}\n\n\t/**\n\t * Get all user messages from session for branch selector.\n\t */\n\tgetUserMessagesForBranching(): Array<{ entryIndex: number; text: string }> {\n\t\tconst entries = this.sessionManager.getEntries();\n\t\tconst result: Array<{ entryIndex: number; text: string }> = [];\n\n\t\tfor (let i = 0; i < entries.length; i++) {\n\t\t\tconst entry = entries[i];\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({ entryIndex: i, 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\t/**\n\t * Get session statistics.\n\t */\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};\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\texportToHtml(outputPath?: string): string {\n\t\tconst themeName = this.settingsManager.getTheme();\n\t\treturn exportSessionToHtml(this.sessionManager, this.state, { outputPath, themeName });\n\t}\n\n\t// =========================================================================\n\t// Utilities\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 null if no assistant message exists\n\t */\n\tgetLastAssistantText(): string | null {\n\t\tconst lastAssistant = this.messages\n\t\t\t.slice()\n\t\t\t.reverse()\n\t\t\t.find((m) => m.role === \"assistant\");\n\n\t\tif (!lastAssistant) return null;\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() || null;\n\t}\n\n\t// =========================================================================\n\t// Hook System\n\t// =========================================================================\n\n\t/**\n\t * Check if hooks have handlers for a specific event type.\n\t */\n\thasHookHandlers(eventType: string): boolean {\n\t\treturn this._hookRunner?.hasHandlers(eventType) ?? false;\n\t}\n\n\t/**\n\t * Get the hook runner (for setting UI context and error handlers).\n\t */\n\tget hookRunner(): HookRunner | null {\n\t\treturn this._hookRunner;\n\t}\n\n\t/**\n\t * Get custom tools (for setting UI context in modes).\n\t */\n\tget customTools(): LoadedCustomTool[] {\n\t\treturn this._customTools;\n\t}\n\n\t/**\n\t * Emit session event to all custom tools.\n\t * Called on session switch, branch, and clear.\n\t */\n\tprivate async _emitToolSessionEvent(\n\t\treason: ToolSessionEvent[\"reason\"],\n\t\tpreviousSessionFile: string | null,\n\t): Promise<void> {\n\t\tconst event: ToolSessionEvent = {\n\t\t\tentries: this.sessionManager.getEntries(),\n\t\t\tsessionFile: this.sessionFile,\n\t\t\tpreviousSessionFile,\n\t\t\treason,\n\t\t};\n\t\tfor (const { tool } of this._customTools) {\n\t\t\tif (tool.onSession) {\n\t\t\t\ttry {\n\t\t\t\t\tawait tool.onSession(event);\n\t\t\t\t} catch (_err) {\n\t\t\t\t\t// Silently ignore tool errors during session events\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Model resolution, scoping, and initial selection
|
|
3
3
|
*/
|
|
4
4
|
import type { ThinkingLevel } from "@mariozechner/pi-agent-core";
|
|
5
|
-
import type
|
|
5
|
+
import { type Api, type KnownProvider, type Model } from "@mariozechner/pi-ai";
|
|
6
6
|
import type { ModelRegistry } from "./model-registry.js";
|
|
7
7
|
/** Default model IDs for each known provider */
|
|
8
8
|
export declare const defaultModelPerProvider: Record<KnownProvider, string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-resolver.d.ts","sourceRoot":"","sources":["../../src/core/model-resolver.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,KAAK,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAGrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,gDAAgD;AAChD,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAajE,CAAC;AAEF,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,aAAa,EAAE,aAAa,CAAC;CAC7B;AAkED,MAAM,WAAW,iBAAiB;IACjC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE,aAAa,CAAC;IAC7B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,iBAAiB,CA0CnG;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,aAAa,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAuBhH;AAED,MAAM,WAAW,kBAAkB;IAClC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE,aAAa,CAAC;IAC7B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,aAAa,CAAC;IACrC,aAAa,EAAE,aAAa,CAAC;CAC7B,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAiE9B;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAC5C,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,EAC/B,mBAAmB,EAAE,OAAO,EAC5B,aAAa,EAAE,aAAa,GAC1B,OAAO,CAAC;IAAE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;IAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CA+DvE","sourcesContent":["/**\n * Model resolution, scoping, and initial selection\n */\n\nimport type { ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport type { Api, KnownProvider, Model } from \"@mariozechner/pi-ai\";\nimport chalk from \"chalk\";\nimport { isValidThinkingLevel } from \"../cli/args.js\";\nimport type { ModelRegistry } from \"./model-registry.js\";\n\n/** Default model IDs for each known provider */\nexport const defaultModelPerProvider: Record<KnownProvider, string> = {\n\tanthropic: \"claude-sonnet-4-5\",\n\topenai: \"gpt-5.1-codex\",\n\tgoogle: \"gemini-2.5-pro\",\n\t\"google-gemini-cli\": \"gemini-2.5-pro\",\n\t\"google-antigravity\": \"gemini-3-pro-high\",\n\t\"github-copilot\": \"gpt-4o\",\n\topenrouter: \"openai/gpt-5.1-codex\",\n\txai: \"grok-4-fast-non-reasoning\",\n\tgroq: \"openai/gpt-oss-120b\",\n\tcerebras: \"zai-glm-4.6\",\n\tzai: \"glm-4.6\",\n\tmistral: \"devstral-medium-latest\",\n};\n\nexport interface ScopedModel {\n\tmodel: Model<Api>;\n\tthinkingLevel: ThinkingLevel;\n}\n\n/**\n * Helper to check if a model ID looks like an alias (no date suffix)\n * Dates are typically in format: -20241022 or -20250929\n */\nfunction isAlias(id: string): boolean {\n\t// Check if ID ends with -latest\n\tif (id.endsWith(\"-latest\")) return true;\n\n\t// Check if ID ends with a date pattern (-YYYYMMDD)\n\tconst datePattern = /-\\d{8}$/;\n\treturn !datePattern.test(id);\n}\n\n/**\n * Try to match a pattern to a model from the available models list.\n * Returns the matched model or null if no match found.\n */\nfunction tryMatchModel(modelPattern: string, availableModels: Model<Api>[]): Model<Api> | null {\n\t// Check for provider/modelId format (provider is everything before the first /)\n\tconst slashIndex = modelPattern.indexOf(\"/\");\n\tif (slashIndex !== -1) {\n\t\tconst provider = modelPattern.substring(0, slashIndex);\n\t\tconst modelId = modelPattern.substring(slashIndex + 1);\n\t\tconst providerMatch = availableModels.find(\n\t\t\t(m) => m.provider.toLowerCase() === provider.toLowerCase() && m.id.toLowerCase() === modelId.toLowerCase(),\n\t\t);\n\t\tif (providerMatch) {\n\t\t\treturn providerMatch;\n\t\t}\n\t\t// No exact provider/model match - fall through to other matching\n\t}\n\n\t// Check for exact ID match (case-insensitive)\n\tconst exactMatch = availableModels.find((m) => m.id.toLowerCase() === modelPattern.toLowerCase());\n\tif (exactMatch) {\n\t\treturn exactMatch;\n\t}\n\n\t// No exact match - fall back to partial matching\n\tconst matches = availableModels.filter(\n\t\t(m) =>\n\t\t\tm.id.toLowerCase().includes(modelPattern.toLowerCase()) ||\n\t\t\tm.name?.toLowerCase().includes(modelPattern.toLowerCase()),\n\t);\n\n\tif (matches.length === 0) {\n\t\treturn null;\n\t}\n\n\t// Separate into aliases and dated versions\n\tconst aliases = matches.filter((m) => isAlias(m.id));\n\tconst datedVersions = matches.filter((m) => !isAlias(m.id));\n\n\tif (aliases.length > 0) {\n\t\t// Prefer alias - if multiple aliases, pick the one that sorts highest\n\t\taliases.sort((a, b) => b.id.localeCompare(a.id));\n\t\treturn aliases[0];\n\t} else {\n\t\t// No alias found, pick latest dated version\n\t\tdatedVersions.sort((a, b) => b.id.localeCompare(a.id));\n\t\treturn datedVersions[0];\n\t}\n}\n\nexport interface ParsedModelResult {\n\tmodel: Model<Api> | null;\n\tthinkingLevel: ThinkingLevel;\n\twarning: string | null;\n}\n\n/**\n * Parse a pattern to extract model and thinking level.\n * Handles models with colons in their IDs (e.g., OpenRouter's :exacto suffix).\n *\n * Algorithm:\n * 1. Try to match full pattern as a model\n * 2. If found, return it with \"off\" thinking level\n * 3. If not found and has colons, split on last colon:\n * - If suffix is valid thinking level, use it and recurse on prefix\n * - If suffix is invalid, warn and recurse on prefix with \"off\"\n *\n * @internal Exported for testing\n */\nexport function parseModelPattern(pattern: string, availableModels: Model<Api>[]): ParsedModelResult {\n\t// Try exact match first\n\tconst exactMatch = tryMatchModel(pattern, availableModels);\n\tif (exactMatch) {\n\t\treturn { model: exactMatch, thinkingLevel: \"off\", warning: null };\n\t}\n\n\t// No match - try splitting on last colon if present\n\tconst lastColonIndex = pattern.lastIndexOf(\":\");\n\tif (lastColonIndex === -1) {\n\t\t// No colons, pattern simply doesn't match any model\n\t\treturn { model: null, thinkingLevel: \"off\", warning: null };\n\t}\n\n\tconst prefix = pattern.substring(0, lastColonIndex);\n\tconst suffix = pattern.substring(lastColonIndex + 1);\n\n\tif (isValidThinkingLevel(suffix)) {\n\t\t// Valid thinking level - recurse on prefix and use this level\n\t\tconst result = parseModelPattern(prefix, availableModels);\n\t\tif (result.model) {\n\t\t\t// Only use this thinking level if no warning from inner recursion\n\t\t\t// (if there was an invalid suffix deeper, we already have \"off\")\n\t\t\treturn {\n\t\t\t\tmodel: result.model,\n\t\t\t\tthinkingLevel: result.warning ? \"off\" : suffix,\n\t\t\t\twarning: result.warning,\n\t\t\t};\n\t\t}\n\t\treturn result;\n\t} else {\n\t\t// Invalid suffix - recurse on prefix with \"off\" and warn\n\t\tconst result = parseModelPattern(prefix, availableModels);\n\t\tif (result.model) {\n\t\t\treturn {\n\t\t\t\tmodel: result.model,\n\t\t\t\tthinkingLevel: \"off\",\n\t\t\t\twarning: `Invalid thinking level \"${suffix}\" in pattern \"${pattern}\". Using \"off\" instead.`,\n\t\t\t};\n\t\t}\n\t\treturn result;\n\t}\n}\n\n/**\n * Resolve model patterns to actual Model objects with optional thinking levels\n * Format: \"pattern:level\" where :level is optional\n * For each pattern, finds all matching models and picks the best version:\n * 1. Prefer alias (e.g., claude-sonnet-4-5) over dated versions (claude-sonnet-4-5-20250929)\n * 2. If no alias, pick the latest dated version\n *\n * Supports models with colons in their IDs (e.g., OpenRouter's model:exacto).\n * The algorithm tries to match the full pattern first, then progressively\n * strips colon-suffixes to find a match.\n */\nexport async function resolveModelScope(patterns: string[], modelRegistry: ModelRegistry): Promise<ScopedModel[]> {\n\tconst availableModels = await modelRegistry.getAvailable();\n\tconst scopedModels: ScopedModel[] = [];\n\n\tfor (const pattern of patterns) {\n\t\tconst { model, thinkingLevel, warning } = parseModelPattern(pattern, availableModels);\n\n\t\tif (warning) {\n\t\t\tconsole.warn(chalk.yellow(`Warning: ${warning}`));\n\t\t}\n\n\t\tif (!model) {\n\t\t\tconsole.warn(chalk.yellow(`Warning: No models match pattern \"${pattern}\"`));\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Avoid duplicates\n\t\tif (!scopedModels.find((sm) => sm.model.id === model.id && sm.model.provider === model.provider)) {\n\t\t\tscopedModels.push({ model, thinkingLevel });\n\t\t}\n\t}\n\n\treturn scopedModels;\n}\n\nexport interface InitialModelResult {\n\tmodel: Model<Api> | null;\n\tthinkingLevel: ThinkingLevel;\n\tfallbackMessage: string | null;\n}\n\n/**\n * Find the initial model to use based on priority:\n * 1. CLI args (provider + model)\n * 2. First model from scoped models (if not continuing/resuming)\n * 3. Restored from session (if continuing/resuming)\n * 4. Saved default from settings\n * 5. First available model with valid API key\n */\nexport async function findInitialModel(options: {\n\tcliProvider?: string;\n\tcliModel?: string;\n\tscopedModels: ScopedModel[];\n\tisContinuing: boolean;\n\tdefaultProvider?: string;\n\tdefaultModelId?: string;\n\tdefaultThinkingLevel?: ThinkingLevel;\n\tmodelRegistry: ModelRegistry;\n}): Promise<InitialModelResult> {\n\tconst {\n\t\tcliProvider,\n\t\tcliModel,\n\t\tscopedModels,\n\t\tisContinuing,\n\t\tdefaultProvider,\n\t\tdefaultModelId,\n\t\tdefaultThinkingLevel,\n\t\tmodelRegistry,\n\t} = options;\n\n\tlet model: Model<Api> | null = null;\n\tlet thinkingLevel: ThinkingLevel = \"off\";\n\n\t// 1. CLI args take priority\n\tif (cliProvider && cliModel) {\n\t\tconst found = modelRegistry.find(cliProvider, cliModel);\n\t\tif (!found) {\n\t\t\tconsole.error(chalk.red(`Model ${cliProvider}/${cliModel} not found`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\treturn { model: found, thinkingLevel: \"off\", fallbackMessage: null };\n\t}\n\n\t// 2. Use first model from scoped models (skip if continuing/resuming)\n\tif (scopedModels.length > 0 && !isContinuing) {\n\t\treturn {\n\t\t\tmodel: scopedModels[0].model,\n\t\t\tthinkingLevel: scopedModels[0].thinkingLevel,\n\t\t\tfallbackMessage: null,\n\t\t};\n\t}\n\n\t// 3. Try saved default from settings\n\tif (defaultProvider && defaultModelId) {\n\t\tconst found = modelRegistry.find(defaultProvider, defaultModelId);\n\t\tif (found) {\n\t\t\tmodel = found;\n\t\t\tif (defaultThinkingLevel) {\n\t\t\t\tthinkingLevel = defaultThinkingLevel;\n\t\t\t}\n\t\t\treturn { model, thinkingLevel, fallbackMessage: null };\n\t\t}\n\t}\n\n\t// 4. Try first available model with valid API key\n\tconst availableModels = await modelRegistry.getAvailable();\n\n\tif (availableModels.length > 0) {\n\t\t// Try to find a default model from known providers\n\t\tfor (const provider of Object.keys(defaultModelPerProvider) as KnownProvider[]) {\n\t\t\tconst defaultId = defaultModelPerProvider[provider];\n\t\t\tconst match = availableModels.find((m) => m.provider === provider && m.id === defaultId);\n\t\t\tif (match) {\n\t\t\t\treturn { model: match, thinkingLevel: \"off\", fallbackMessage: null };\n\t\t\t}\n\t\t}\n\n\t\t// If no default found, use first available\n\t\treturn { model: availableModels[0], thinkingLevel: \"off\", fallbackMessage: null };\n\t}\n\n\t// 5. No model found\n\treturn { model: null, thinkingLevel: \"off\", fallbackMessage: null };\n}\n\n/**\n * Restore model from session, with fallback to available models\n */\nexport async function restoreModelFromSession(\n\tsavedProvider: string,\n\tsavedModelId: string,\n\tcurrentModel: Model<Api> | null,\n\tshouldPrintMessages: boolean,\n\tmodelRegistry: ModelRegistry,\n): Promise<{ model: Model<Api> | null; fallbackMessage: string | null }> {\n\tconst restoredModel = modelRegistry.find(savedProvider, savedModelId);\n\n\t// Check if restored model exists and has a valid API key\n\tconst hasApiKey = restoredModel ? !!(await modelRegistry.getApiKey(restoredModel)) : false;\n\n\tif (restoredModel && hasApiKey) {\n\t\tif (shouldPrintMessages) {\n\t\t\tconsole.log(chalk.dim(`Restored model: ${savedProvider}/${savedModelId}`));\n\t\t}\n\t\treturn { model: restoredModel, fallbackMessage: null };\n\t}\n\n\t// Model not found or no API key - fall back\n\tconst reason = !restoredModel ? \"model no longer exists\" : \"no API key available\";\n\n\tif (shouldPrintMessages) {\n\t\tconsole.error(chalk.yellow(`Warning: Could not restore model ${savedProvider}/${savedModelId} (${reason}).`));\n\t}\n\n\t// If we already have a model, use it as fallback\n\tif (currentModel) {\n\t\tif (shouldPrintMessages) {\n\t\t\tconsole.log(chalk.dim(`Falling back to: ${currentModel.provider}/${currentModel.id}`));\n\t\t}\n\t\treturn {\n\t\t\tmodel: currentModel,\n\t\t\tfallbackMessage: `Could not restore model ${savedProvider}/${savedModelId} (${reason}). Using ${currentModel.provider}/${currentModel.id}.`,\n\t\t};\n\t}\n\n\t// Try to find any available model\n\tconst availableModels = await modelRegistry.getAvailable();\n\n\tif (availableModels.length > 0) {\n\t\t// Try to find a default model from known providers\n\t\tlet fallbackModel: Model<Api> | null = null;\n\t\tfor (const provider of Object.keys(defaultModelPerProvider) as KnownProvider[]) {\n\t\t\tconst defaultId = defaultModelPerProvider[provider];\n\t\t\tconst match = availableModels.find((m) => m.provider === provider && m.id === defaultId);\n\t\t\tif (match) {\n\t\t\t\tfallbackModel = match;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// If no default found, use first available\n\t\tif (!fallbackModel) {\n\t\t\tfallbackModel = availableModels[0];\n\t\t}\n\n\t\tif (shouldPrintMessages) {\n\t\t\tconsole.log(chalk.dim(`Falling back to: ${fallbackModel.provider}/${fallbackModel.id}`));\n\t\t}\n\n\t\treturn {\n\t\t\tmodel: fallbackModel,\n\t\t\tfallbackMessage: `Could not restore model ${savedProvider}/${savedModelId} (${reason}). Using ${fallbackModel.provider}/${fallbackModel.id}.`,\n\t\t};\n\t}\n\n\t// No models available\n\treturn { model: null, fallbackMessage: null };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"model-resolver.d.ts","sourceRoot":"","sources":["../../src/core/model-resolver.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK,aAAa,EAAE,KAAK,KAAK,EAAkB,MAAM,qBAAqB,CAAC;AAG/F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,gDAAgD;AAChD,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAajE,CAAC;AAEF,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,aAAa,EAAE,aAAa,CAAC;CAC7B;AAkED,MAAM,WAAW,iBAAiB;IACjC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE,aAAa,CAAC;IAC7B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,iBAAiB,CA0CnG;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,aAAa,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAuBhH;AAED,MAAM,WAAW,kBAAkB;IAClC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE,aAAa,CAAC;IAC7B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,aAAa,CAAC;IACrC,aAAa,EAAE,aAAa,CAAC;CAC7B,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAiE9B;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAC5C,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,EAC/B,mBAAmB,EAAE,OAAO,EAC5B,aAAa,EAAE,aAAa,GAC1B,OAAO,CAAC;IAAE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;IAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CA+DvE","sourcesContent":["/**\n * Model resolution, scoping, and initial selection\n */\n\nimport type { ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport { type Api, type KnownProvider, type Model, modelsAreEqual } from \"@mariozechner/pi-ai\";\nimport chalk from \"chalk\";\nimport { isValidThinkingLevel } from \"../cli/args.js\";\nimport type { ModelRegistry } from \"./model-registry.js\";\n\n/** Default model IDs for each known provider */\nexport const defaultModelPerProvider: Record<KnownProvider, string> = {\n\tanthropic: \"claude-sonnet-4-5\",\n\topenai: \"gpt-5.1-codex\",\n\tgoogle: \"gemini-2.5-pro\",\n\t\"google-gemini-cli\": \"gemini-2.5-pro\",\n\t\"google-antigravity\": \"gemini-3-pro-high\",\n\t\"github-copilot\": \"gpt-4o\",\n\topenrouter: \"openai/gpt-5.1-codex\",\n\txai: \"grok-4-fast-non-reasoning\",\n\tgroq: \"openai/gpt-oss-120b\",\n\tcerebras: \"zai-glm-4.6\",\n\tzai: \"glm-4.6\",\n\tmistral: \"devstral-medium-latest\",\n};\n\nexport interface ScopedModel {\n\tmodel: Model<Api>;\n\tthinkingLevel: ThinkingLevel;\n}\n\n/**\n * Helper to check if a model ID looks like an alias (no date suffix)\n * Dates are typically in format: -20241022 or -20250929\n */\nfunction isAlias(id: string): boolean {\n\t// Check if ID ends with -latest\n\tif (id.endsWith(\"-latest\")) return true;\n\n\t// Check if ID ends with a date pattern (-YYYYMMDD)\n\tconst datePattern = /-\\d{8}$/;\n\treturn !datePattern.test(id);\n}\n\n/**\n * Try to match a pattern to a model from the available models list.\n * Returns the matched model or null if no match found.\n */\nfunction tryMatchModel(modelPattern: string, availableModels: Model<Api>[]): Model<Api> | null {\n\t// Check for provider/modelId format (provider is everything before the first /)\n\tconst slashIndex = modelPattern.indexOf(\"/\");\n\tif (slashIndex !== -1) {\n\t\tconst provider = modelPattern.substring(0, slashIndex);\n\t\tconst modelId = modelPattern.substring(slashIndex + 1);\n\t\tconst providerMatch = availableModels.find(\n\t\t\t(m) => m.provider.toLowerCase() === provider.toLowerCase() && m.id.toLowerCase() === modelId.toLowerCase(),\n\t\t);\n\t\tif (providerMatch) {\n\t\t\treturn providerMatch;\n\t\t}\n\t\t// No exact provider/model match - fall through to other matching\n\t}\n\n\t// Check for exact ID match (case-insensitive)\n\tconst exactMatch = availableModels.find((m) => m.id.toLowerCase() === modelPattern.toLowerCase());\n\tif (exactMatch) {\n\t\treturn exactMatch;\n\t}\n\n\t// No exact match - fall back to partial matching\n\tconst matches = availableModels.filter(\n\t\t(m) =>\n\t\t\tm.id.toLowerCase().includes(modelPattern.toLowerCase()) ||\n\t\t\tm.name?.toLowerCase().includes(modelPattern.toLowerCase()),\n\t);\n\n\tif (matches.length === 0) {\n\t\treturn null;\n\t}\n\n\t// Separate into aliases and dated versions\n\tconst aliases = matches.filter((m) => isAlias(m.id));\n\tconst datedVersions = matches.filter((m) => !isAlias(m.id));\n\n\tif (aliases.length > 0) {\n\t\t// Prefer alias - if multiple aliases, pick the one that sorts highest\n\t\taliases.sort((a, b) => b.id.localeCompare(a.id));\n\t\treturn aliases[0];\n\t} else {\n\t\t// No alias found, pick latest dated version\n\t\tdatedVersions.sort((a, b) => b.id.localeCompare(a.id));\n\t\treturn datedVersions[0];\n\t}\n}\n\nexport interface ParsedModelResult {\n\tmodel: Model<Api> | null;\n\tthinkingLevel: ThinkingLevel;\n\twarning: string | null;\n}\n\n/**\n * Parse a pattern to extract model and thinking level.\n * Handles models with colons in their IDs (e.g., OpenRouter's :exacto suffix).\n *\n * Algorithm:\n * 1. Try to match full pattern as a model\n * 2. If found, return it with \"off\" thinking level\n * 3. If not found and has colons, split on last colon:\n * - If suffix is valid thinking level, use it and recurse on prefix\n * - If suffix is invalid, warn and recurse on prefix with \"off\"\n *\n * @internal Exported for testing\n */\nexport function parseModelPattern(pattern: string, availableModels: Model<Api>[]): ParsedModelResult {\n\t// Try exact match first\n\tconst exactMatch = tryMatchModel(pattern, availableModels);\n\tif (exactMatch) {\n\t\treturn { model: exactMatch, thinkingLevel: \"off\", warning: null };\n\t}\n\n\t// No match - try splitting on last colon if present\n\tconst lastColonIndex = pattern.lastIndexOf(\":\");\n\tif (lastColonIndex === -1) {\n\t\t// No colons, pattern simply doesn't match any model\n\t\treturn { model: null, thinkingLevel: \"off\", warning: null };\n\t}\n\n\tconst prefix = pattern.substring(0, lastColonIndex);\n\tconst suffix = pattern.substring(lastColonIndex + 1);\n\n\tif (isValidThinkingLevel(suffix)) {\n\t\t// Valid thinking level - recurse on prefix and use this level\n\t\tconst result = parseModelPattern(prefix, availableModels);\n\t\tif (result.model) {\n\t\t\t// Only use this thinking level if no warning from inner recursion\n\t\t\t// (if there was an invalid suffix deeper, we already have \"off\")\n\t\t\treturn {\n\t\t\t\tmodel: result.model,\n\t\t\t\tthinkingLevel: result.warning ? \"off\" : suffix,\n\t\t\t\twarning: result.warning,\n\t\t\t};\n\t\t}\n\t\treturn result;\n\t} else {\n\t\t// Invalid suffix - recurse on prefix with \"off\" and warn\n\t\tconst result = parseModelPattern(prefix, availableModels);\n\t\tif (result.model) {\n\t\t\treturn {\n\t\t\t\tmodel: result.model,\n\t\t\t\tthinkingLevel: \"off\",\n\t\t\t\twarning: `Invalid thinking level \"${suffix}\" in pattern \"${pattern}\". Using \"off\" instead.`,\n\t\t\t};\n\t\t}\n\t\treturn result;\n\t}\n}\n\n/**\n * Resolve model patterns to actual Model objects with optional thinking levels\n * Format: \"pattern:level\" where :level is optional\n * For each pattern, finds all matching models and picks the best version:\n * 1. Prefer alias (e.g., claude-sonnet-4-5) over dated versions (claude-sonnet-4-5-20250929)\n * 2. If no alias, pick the latest dated version\n *\n * Supports models with colons in their IDs (e.g., OpenRouter's model:exacto).\n * The algorithm tries to match the full pattern first, then progressively\n * strips colon-suffixes to find a match.\n */\nexport async function resolveModelScope(patterns: string[], modelRegistry: ModelRegistry): Promise<ScopedModel[]> {\n\tconst availableModels = await modelRegistry.getAvailable();\n\tconst scopedModels: ScopedModel[] = [];\n\n\tfor (const pattern of patterns) {\n\t\tconst { model, thinkingLevel, warning } = parseModelPattern(pattern, availableModels);\n\n\t\tif (warning) {\n\t\t\tconsole.warn(chalk.yellow(`Warning: ${warning}`));\n\t\t}\n\n\t\tif (!model) {\n\t\t\tconsole.warn(chalk.yellow(`Warning: No models match pattern \"${pattern}\"`));\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Avoid duplicates\n\t\tif (!scopedModels.find((sm) => modelsAreEqual(sm.model, model))) {\n\t\t\tscopedModels.push({ model, thinkingLevel });\n\t\t}\n\t}\n\n\treturn scopedModels;\n}\n\nexport interface InitialModelResult {\n\tmodel: Model<Api> | null;\n\tthinkingLevel: ThinkingLevel;\n\tfallbackMessage: string | null;\n}\n\n/**\n * Find the initial model to use based on priority:\n * 1. CLI args (provider + model)\n * 2. First model from scoped models (if not continuing/resuming)\n * 3. Restored from session (if continuing/resuming)\n * 4. Saved default from settings\n * 5. First available model with valid API key\n */\nexport async function findInitialModel(options: {\n\tcliProvider?: string;\n\tcliModel?: string;\n\tscopedModels: ScopedModel[];\n\tisContinuing: boolean;\n\tdefaultProvider?: string;\n\tdefaultModelId?: string;\n\tdefaultThinkingLevel?: ThinkingLevel;\n\tmodelRegistry: ModelRegistry;\n}): Promise<InitialModelResult> {\n\tconst {\n\t\tcliProvider,\n\t\tcliModel,\n\t\tscopedModels,\n\t\tisContinuing,\n\t\tdefaultProvider,\n\t\tdefaultModelId,\n\t\tdefaultThinkingLevel,\n\t\tmodelRegistry,\n\t} = options;\n\n\tlet model: Model<Api> | null = null;\n\tlet thinkingLevel: ThinkingLevel = \"off\";\n\n\t// 1. CLI args take priority\n\tif (cliProvider && cliModel) {\n\t\tconst found = modelRegistry.find(cliProvider, cliModel);\n\t\tif (!found) {\n\t\t\tconsole.error(chalk.red(`Model ${cliProvider}/${cliModel} not found`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\treturn { model: found, thinkingLevel: \"off\", fallbackMessage: null };\n\t}\n\n\t// 2. Use first model from scoped models (skip if continuing/resuming)\n\tif (scopedModels.length > 0 && !isContinuing) {\n\t\treturn {\n\t\t\tmodel: scopedModels[0].model,\n\t\t\tthinkingLevel: scopedModels[0].thinkingLevel,\n\t\t\tfallbackMessage: null,\n\t\t};\n\t}\n\n\t// 3. Try saved default from settings\n\tif (defaultProvider && defaultModelId) {\n\t\tconst found = modelRegistry.find(defaultProvider, defaultModelId);\n\t\tif (found) {\n\t\t\tmodel = found;\n\t\t\tif (defaultThinkingLevel) {\n\t\t\t\tthinkingLevel = defaultThinkingLevel;\n\t\t\t}\n\t\t\treturn { model, thinkingLevel, fallbackMessage: null };\n\t\t}\n\t}\n\n\t// 4. Try first available model with valid API key\n\tconst availableModels = await modelRegistry.getAvailable();\n\n\tif (availableModels.length > 0) {\n\t\t// Try to find a default model from known providers\n\t\tfor (const provider of Object.keys(defaultModelPerProvider) as KnownProvider[]) {\n\t\t\tconst defaultId = defaultModelPerProvider[provider];\n\t\t\tconst match = availableModels.find((m) => m.provider === provider && m.id === defaultId);\n\t\t\tif (match) {\n\t\t\t\treturn { model: match, thinkingLevel: \"off\", fallbackMessage: null };\n\t\t\t}\n\t\t}\n\n\t\t// If no default found, use first available\n\t\treturn { model: availableModels[0], thinkingLevel: \"off\", fallbackMessage: null };\n\t}\n\n\t// 5. No model found\n\treturn { model: null, thinkingLevel: \"off\", fallbackMessage: null };\n}\n\n/**\n * Restore model from session, with fallback to available models\n */\nexport async function restoreModelFromSession(\n\tsavedProvider: string,\n\tsavedModelId: string,\n\tcurrentModel: Model<Api> | null,\n\tshouldPrintMessages: boolean,\n\tmodelRegistry: ModelRegistry,\n): Promise<{ model: Model<Api> | null; fallbackMessage: string | null }> {\n\tconst restoredModel = modelRegistry.find(savedProvider, savedModelId);\n\n\t// Check if restored model exists and has a valid API key\n\tconst hasApiKey = restoredModel ? !!(await modelRegistry.getApiKey(restoredModel)) : false;\n\n\tif (restoredModel && hasApiKey) {\n\t\tif (shouldPrintMessages) {\n\t\t\tconsole.log(chalk.dim(`Restored model: ${savedProvider}/${savedModelId}`));\n\t\t}\n\t\treturn { model: restoredModel, fallbackMessage: null };\n\t}\n\n\t// Model not found or no API key - fall back\n\tconst reason = !restoredModel ? \"model no longer exists\" : \"no API key available\";\n\n\tif (shouldPrintMessages) {\n\t\tconsole.error(chalk.yellow(`Warning: Could not restore model ${savedProvider}/${savedModelId} (${reason}).`));\n\t}\n\n\t// If we already have a model, use it as fallback\n\tif (currentModel) {\n\t\tif (shouldPrintMessages) {\n\t\t\tconsole.log(chalk.dim(`Falling back to: ${currentModel.provider}/${currentModel.id}`));\n\t\t}\n\t\treturn {\n\t\t\tmodel: currentModel,\n\t\t\tfallbackMessage: `Could not restore model ${savedProvider}/${savedModelId} (${reason}). Using ${currentModel.provider}/${currentModel.id}.`,\n\t\t};\n\t}\n\n\t// Try to find any available model\n\tconst availableModels = await modelRegistry.getAvailable();\n\n\tif (availableModels.length > 0) {\n\t\t// Try to find a default model from known providers\n\t\tlet fallbackModel: Model<Api> | null = null;\n\t\tfor (const provider of Object.keys(defaultModelPerProvider) as KnownProvider[]) {\n\t\t\tconst defaultId = defaultModelPerProvider[provider];\n\t\t\tconst match = availableModels.find((m) => m.provider === provider && m.id === defaultId);\n\t\t\tif (match) {\n\t\t\t\tfallbackModel = match;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// If no default found, use first available\n\t\tif (!fallbackModel) {\n\t\t\tfallbackModel = availableModels[0];\n\t\t}\n\n\t\tif (shouldPrintMessages) {\n\t\t\tconsole.log(chalk.dim(`Falling back to: ${fallbackModel.provider}/${fallbackModel.id}`));\n\t\t}\n\n\t\treturn {\n\t\t\tmodel: fallbackModel,\n\t\t\tfallbackMessage: `Could not restore model ${savedProvider}/${savedModelId} (${reason}). Using ${fallbackModel.provider}/${fallbackModel.id}.`,\n\t\t};\n\t}\n\n\t// No models available\n\treturn { model: null, fallbackMessage: null };\n}\n"]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Model resolution, scoping, and initial selection
|
|
3
3
|
*/
|
|
4
|
+
import { modelsAreEqual } from "@mariozechner/pi-ai";
|
|
4
5
|
import chalk from "chalk";
|
|
5
6
|
import { isValidThinkingLevel } from "../cli/args.js";
|
|
6
7
|
/** Default model IDs for each known provider */
|
|
@@ -149,7 +150,7 @@ export async function resolveModelScope(patterns, modelRegistry) {
|
|
|
149
150
|
continue;
|
|
150
151
|
}
|
|
151
152
|
// Avoid duplicates
|
|
152
|
-
if (!scopedModels.find((sm) => sm.model
|
|
153
|
+
if (!scopedModels.find((sm) => modelsAreEqual(sm.model, model))) {
|
|
153
154
|
scopedModels.push({ model, thinkingLevel });
|
|
154
155
|
}
|
|
155
156
|
}
|