@codex-infinity/pi-infinity 0.52.2 → 0.60.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 +386 -0
- package/README.md +97 -66
- package/dist/bun/cli.d.ts +3 -0
- package/dist/bun/cli.d.ts.map +1 -0
- package/dist/bun/cli.js +6 -0
- package/dist/bun/cli.js.map +1 -0
- package/dist/bun/register-bedrock.d.ts +2 -0
- package/dist/bun/register-bedrock.d.ts.map +1 -0
- package/dist/bun/register-bedrock.js +4 -0
- package/dist/bun/register-bedrock.js.map +1 -0
- package/dist/cli/args.d.ts +2 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +17 -6
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/initial-message.d.ts +18 -0
- package/dist/cli/initial-message.d.ts.map +1 -0
- package/dist/cli/initial-message.js +22 -0
- package/dist/cli/initial-message.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/core/agent-session.d.ts +28 -6
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +289 -69
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +1 -0
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +27 -2
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/bash-executor.d.ts +6 -7
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +8 -107
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +1 -0
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +6 -1
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/utils.d.ts +3 -0
- package/dist/core/compaction/utils.d.ts.map +1 -1
- package/dist/core/compaction/utils.js +16 -1
- package/dist/core/compaction/utils.js.map +1 -1
- package/dist/core/export-html/index.d.ts +5 -2
- package/dist/core/export-html/index.d.ts.map +1 -1
- package/dist/core/export-html/index.js +4 -3
- package/dist/core/export-html/index.js.map +1 -1
- package/dist/core/export-html/template.js +11 -14
- package/dist/core/export-html/tool-renderer.d.ts +5 -2
- package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
- package/dist/core/export-html/tool-renderer.js +17 -4
- package/dist/core/export-html/tool-renderer.js.map +1 -1
- package/dist/core/extensions/index.d.ts +2 -2
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +37 -11
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +8 -4
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +77 -8
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +56 -4
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/extensions/wrapper.d.ts +4 -11
- package/dist/core/extensions/wrapper.d.ts.map +1 -1
- package/dist/core/extensions/wrapper.js +4 -78
- package/dist/core/extensions/wrapper.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +6 -1
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +83 -37
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/keybindings.d.ts +3 -0
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +22 -12
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/model-registry.d.ts +11 -0
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +56 -16
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts +6 -0
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +126 -43
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/package-manager.d.ts +19 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +290 -57
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/resolve-config-value.d.ts.map +1 -1
- package/dist/core/resolve-config-value.js +43 -8
- package/dist/core/resolve-config-value.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +4 -7
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +7 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +1 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +21 -15
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +10 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +59 -5
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts +3 -2
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +29 -8
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -1
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts +4 -0
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +43 -29
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +8 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +75 -69
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.js +1 -0
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +6 -3
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/index.d.ts +1 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +1 -1
- package/dist/core/tools/index.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +116 -36
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts +5 -2
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +9 -0
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +8 -23
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +1 -1
- package/dist/modes/interactive/components/login-dialog.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 +1 -1
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +1 -1
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +1 -1
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +15 -1
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.js +5 -1
- package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
- package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/theme-selector.js +5 -1
- package/dist/modes/interactive/components/theme-selector.js.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +5 -1
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +7 -0
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +158 -7
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts +21 -2
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +127 -10
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts +1 -0
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +12 -0
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +4 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +160 -66
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +5 -0
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/rpc/jsonl.d.ts +17 -0
- package/dist/modes/rpc/jsonl.d.ts.map +1 -0
- package/dist/modes/rpc/jsonl.js +49 -0
- package/dist/modes/rpc/jsonl.js.map +1 -0
- package/dist/modes/rpc/rpc-client.d.ts +1 -1
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +7 -11
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +9 -11
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +94 -11
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +16 -15
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/exif-orientation.d.ts +5 -0
- package/dist/utils/exif-orientation.d.ts.map +1 -0
- package/dist/utils/exif-orientation.js +158 -0
- package/dist/utils/exif-orientation.js.map +1 -0
- package/dist/utils/image-convert.d.ts.map +1 -1
- package/dist/utils/image-convert.js +5 -1
- package/dist/utils/image-convert.js.map +1 -1
- package/dist/utils/image-resize.d.ts.map +1 -1
- package/dist/utils/image-resize.js +6 -1
- package/dist/utils/image-resize.js.map +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +66 -21
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/compaction.md +2 -0
- package/docs/custom-provider.md +57 -9
- package/docs/extensions.md +125 -12
- package/docs/keybindings.md +11 -1
- package/docs/models.md +44 -2
- package/docs/packages.md +9 -0
- package/docs/providers.md +10 -1
- package/docs/rpc.md +44 -7
- package/docs/sdk.md +2 -2
- package/docs/settings.md +11 -0
- package/docs/terminal-setup.md +39 -3
- package/docs/tmux.md +61 -0
- package/docs/tree.md +9 -0
- package/examples/extensions/README.md +2 -0
- package/examples/extensions/antigravity-image-gen.ts +8 -5
- package/examples/extensions/built-in-tool-renderer.ts +246 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/test.ts +2 -2
- package/examples/extensions/custom-provider-qwen-cli/package.json +1 -1
- package/examples/extensions/dynamic-tools.ts +74 -0
- package/examples/extensions/overlay-qa-tests.ts +468 -1
- package/examples/extensions/preset.ts +2 -3
- package/examples/extensions/provider-payload.ts +14 -0
- package/examples/extensions/sandbox/index.ts +2 -3
- package/examples/extensions/subagent/agents.ts +2 -3
- package/examples/extensions/tool-override.ts +2 -3
- package/examples/extensions/with-deps/index.ts +1 -5
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +10 -7
|
@@ -24,7 +24,7 @@ import { calculateContextTokens, collectEntriesForBranchSummary, compact, estima
|
|
|
24
24
|
import { DEFAULT_THINKING_LEVEL } from "./defaults.js";
|
|
25
25
|
import { exportSessionToHtml } from "./export-html/index.js";
|
|
26
26
|
import { createToolHtmlRenderer } from "./export-html/tool-renderer.js";
|
|
27
|
-
import { ExtensionRunner, wrapRegisteredTools,
|
|
27
|
+
import { ExtensionRunner, wrapRegisteredTools, } from "./extensions/index.js";
|
|
28
28
|
import { expandPromptTemplate } from "./prompt-templates.js";
|
|
29
29
|
import { getLatestCompactionEntry } from "./session-manager.js";
|
|
30
30
|
import { BUILTIN_SLASH_COMMANDS } from "./slash-commands.js";
|
|
@@ -63,6 +63,7 @@ export class AgentSession {
|
|
|
63
63
|
// Event subscription state
|
|
64
64
|
_unsubscribeAgent;
|
|
65
65
|
_eventListeners = [];
|
|
66
|
+
_agentEventQueue = Promise.resolve();
|
|
66
67
|
/** Tracks pending steering messages for UI display. Removed when delivered. */
|
|
67
68
|
_steeringMessages = [];
|
|
68
69
|
/** Tracks pending follow-up messages for UI display. Removed when delivered. */
|
|
@@ -72,6 +73,7 @@ export class AgentSession {
|
|
|
72
73
|
// Compaction state
|
|
73
74
|
_compactionAbortController = undefined;
|
|
74
75
|
_autoCompactionAbortController = undefined;
|
|
76
|
+
_overflowRecoveryAttempted = false;
|
|
75
77
|
// Branch summarization state
|
|
76
78
|
_branchSummaryAbortController = undefined;
|
|
77
79
|
// Retry state
|
|
@@ -104,6 +106,8 @@ export class AgentSession {
|
|
|
104
106
|
_modelRegistry;
|
|
105
107
|
// Tool registry for extension getTools/setTools
|
|
106
108
|
_toolRegistry = new Map();
|
|
109
|
+
_toolPromptSnippets = new Map();
|
|
110
|
+
_toolPromptGuidelines = new Map();
|
|
107
111
|
// Base system prompt (without extension appends) - used to apply fresh appends each turn
|
|
108
112
|
_baseSystemPrompt = "";
|
|
109
113
|
constructor(config) {
|
|
@@ -123,6 +127,7 @@ export class AgentSession {
|
|
|
123
127
|
// Always subscribe to agent events for internal handling
|
|
124
128
|
// (session persistence, extensions, auto-compaction, retry logic)
|
|
125
129
|
this._unsubscribeAgent = this.agent.subscribe(this._handleAgentEvent);
|
|
130
|
+
this._installAgentToolHooks();
|
|
126
131
|
this._buildRuntime({
|
|
127
132
|
activeToolNames: this._initialActiveToolNames,
|
|
128
133
|
includeAllExtensionTools: true,
|
|
@@ -132,6 +137,59 @@ export class AgentSession {
|
|
|
132
137
|
get modelRegistry() {
|
|
133
138
|
return this._modelRegistry;
|
|
134
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* Install tool hooks once on the Agent instance.
|
|
142
|
+
*
|
|
143
|
+
* The callbacks read `this._extensionRunner` at execution time, so extension reload swaps in the
|
|
144
|
+
* new runner without reinstalling hooks. Extension-specific tool wrappers are still used to adapt
|
|
145
|
+
* registered tool execution to the extension context. Tool call and tool result interception now
|
|
146
|
+
* happens here instead of in wrappers.
|
|
147
|
+
*/
|
|
148
|
+
_installAgentToolHooks() {
|
|
149
|
+
this.agent.setBeforeToolCall(async ({ toolCall, args }) => {
|
|
150
|
+
const runner = this._extensionRunner;
|
|
151
|
+
if (!runner?.hasHandlers("tool_call")) {
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
await this._agentEventQueue;
|
|
155
|
+
try {
|
|
156
|
+
return await runner.emitToolCall({
|
|
157
|
+
type: "tool_call",
|
|
158
|
+
toolName: toolCall.name,
|
|
159
|
+
toolCallId: toolCall.id,
|
|
160
|
+
input: args,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
if (err instanceof Error) {
|
|
165
|
+
throw err;
|
|
166
|
+
}
|
|
167
|
+
throw new Error(`Extension failed, blocking execution: ${String(err)}`);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
this.agent.setAfterToolCall(async ({ toolCall, args, result, isError }) => {
|
|
171
|
+
const runner = this._extensionRunner;
|
|
172
|
+
if (!runner?.hasHandlers("tool_result")) {
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
175
|
+
const hookResult = await runner.emitToolResult({
|
|
176
|
+
type: "tool_result",
|
|
177
|
+
toolName: toolCall.name,
|
|
178
|
+
toolCallId: toolCall.id,
|
|
179
|
+
input: args,
|
|
180
|
+
content: result.content,
|
|
181
|
+
details: isError ? undefined : result.details,
|
|
182
|
+
isError,
|
|
183
|
+
});
|
|
184
|
+
if (!hookResult || isError) {
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
content: hookResult.content,
|
|
189
|
+
details: hookResult.details,
|
|
190
|
+
};
|
|
191
|
+
});
|
|
192
|
+
}
|
|
135
193
|
// =========================================================================
|
|
136
194
|
// Event Subscription
|
|
137
195
|
// =========================================================================
|
|
@@ -144,10 +202,47 @@ export class AgentSession {
|
|
|
144
202
|
// Track last assistant message for auto-compaction check
|
|
145
203
|
_lastAssistantMessage = undefined;
|
|
146
204
|
/** Internal handler for agent events - shared by subscribe and reconnect */
|
|
147
|
-
_handleAgentEvent =
|
|
205
|
+
_handleAgentEvent = (event) => {
|
|
206
|
+
// Create retry promise synchronously before queueing async processing.
|
|
207
|
+
// Agent.emit() calls this handler synchronously, and prompt() calls waitForRetry()
|
|
208
|
+
// as soon as agent.prompt() resolves. If _retryPromise is created only inside
|
|
209
|
+
// _processAgentEvent, slow earlier queued events can delay agent_end processing
|
|
210
|
+
// and waitForRetry() can miss the in-flight retry.
|
|
211
|
+
this._createRetryPromiseForAgentEnd(event);
|
|
212
|
+
this._agentEventQueue = this._agentEventQueue.then(() => this._processAgentEvent(event), () => this._processAgentEvent(event));
|
|
213
|
+
// Keep queue alive if an event handler fails
|
|
214
|
+
this._agentEventQueue.catch(() => { });
|
|
215
|
+
};
|
|
216
|
+
_createRetryPromiseForAgentEnd(event) {
|
|
217
|
+
if (event.type !== "agent_end" || this._retryPromise) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
const settings = this.settingsManager.getRetrySettings();
|
|
221
|
+
if (!settings.enabled) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
const lastAssistant = this._findLastAssistantInMessages(event.messages);
|
|
225
|
+
if (!lastAssistant || !this._isRetryableError(lastAssistant)) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
this._retryPromise = new Promise((resolve) => {
|
|
229
|
+
this._retryResolve = resolve;
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
_findLastAssistantInMessages(messages) {
|
|
233
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
234
|
+
const message = messages[i];
|
|
235
|
+
if (message.role === "assistant") {
|
|
236
|
+
return message;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return undefined;
|
|
240
|
+
}
|
|
241
|
+
async _processAgentEvent(event) {
|
|
148
242
|
// When a user message starts, check if it's from either queue and remove it BEFORE emitting
|
|
149
243
|
// This ensures the UI sees the updated queue state
|
|
150
244
|
if (event.type === "message_start" && event.message.role === "user") {
|
|
245
|
+
this._overflowRecoveryAttempted = false;
|
|
151
246
|
const messageText = this._getUserMessageText(event.message);
|
|
152
247
|
if (messageText) {
|
|
153
248
|
// Check steering queue first
|
|
@@ -185,9 +280,12 @@ export class AgentSession {
|
|
|
185
280
|
// Track assistant message for auto-compaction (checked on agent_end)
|
|
186
281
|
if (event.message.role === "assistant") {
|
|
187
282
|
this._lastAssistantMessage = event.message;
|
|
283
|
+
const assistantMsg = event.message;
|
|
284
|
+
if (assistantMsg.stopReason !== "error") {
|
|
285
|
+
this._overflowRecoveryAttempted = false;
|
|
286
|
+
}
|
|
188
287
|
// Reset retry counter immediately on successful assistant response
|
|
189
288
|
// This prevents accumulation across multiple LLM calls within a turn
|
|
190
|
-
const assistantMsg = event.message;
|
|
191
289
|
if (assistantMsg.stopReason !== "error" && this._retryAttempt > 0) {
|
|
192
290
|
this._emit({
|
|
193
291
|
type: "auto_retry_end",
|
|
@@ -213,7 +311,7 @@ export class AgentSession {
|
|
|
213
311
|
// Queue autonomous follow-up if enabled (after compaction, so it has full context)
|
|
214
312
|
this._maybeQueueAutonomousFollowUp(msg);
|
|
215
313
|
}
|
|
216
|
-
}
|
|
314
|
+
}
|
|
217
315
|
/** Resolve the pending retry promise */
|
|
218
316
|
_resolveRetry() {
|
|
219
317
|
if (this._retryResolve) {
|
|
@@ -432,9 +530,11 @@ export class AgentSession {
|
|
|
432
530
|
this._baseSystemPrompt = this._rebuildSystemPrompt(validToolNames);
|
|
433
531
|
this.agent.setSystemPrompt(this._baseSystemPrompt);
|
|
434
532
|
}
|
|
435
|
-
/** Whether
|
|
533
|
+
/** Whether compaction or branch summarization is currently running */
|
|
436
534
|
get isCompacting() {
|
|
437
|
-
return this._autoCompactionAbortController !== undefined ||
|
|
535
|
+
return (this._autoCompactionAbortController !== undefined ||
|
|
536
|
+
this._compactionAbortController !== undefined ||
|
|
537
|
+
this._branchSummaryAbortController !== undefined);
|
|
438
538
|
}
|
|
439
539
|
/** All messages including custom types like BashExecutionMessage */
|
|
440
540
|
get messages() {
|
|
@@ -472,8 +572,42 @@ export class AgentSession {
|
|
|
472
572
|
get promptTemplates() {
|
|
473
573
|
return this._resourceLoader.getPrompts().prompts;
|
|
474
574
|
}
|
|
575
|
+
_normalizePromptSnippet(text) {
|
|
576
|
+
if (!text)
|
|
577
|
+
return undefined;
|
|
578
|
+
const oneLine = text
|
|
579
|
+
.replace(/[\r\n]+/g, " ")
|
|
580
|
+
.replace(/\s+/g, " ")
|
|
581
|
+
.trim();
|
|
582
|
+
return oneLine.length > 0 ? oneLine : undefined;
|
|
583
|
+
}
|
|
584
|
+
_normalizePromptGuidelines(guidelines) {
|
|
585
|
+
if (!guidelines || guidelines.length === 0) {
|
|
586
|
+
return [];
|
|
587
|
+
}
|
|
588
|
+
const unique = new Set();
|
|
589
|
+
for (const guideline of guidelines) {
|
|
590
|
+
const normalized = guideline.trim();
|
|
591
|
+
if (normalized.length > 0) {
|
|
592
|
+
unique.add(normalized);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
return Array.from(unique);
|
|
596
|
+
}
|
|
475
597
|
_rebuildSystemPrompt(toolNames) {
|
|
476
|
-
const validToolNames = toolNames.filter((name) => this.
|
|
598
|
+
const validToolNames = toolNames.filter((name) => this._toolRegistry.has(name));
|
|
599
|
+
const toolSnippets = {};
|
|
600
|
+
const promptGuidelines = [];
|
|
601
|
+
for (const name of validToolNames) {
|
|
602
|
+
const snippet = this._toolPromptSnippets.get(name);
|
|
603
|
+
if (snippet) {
|
|
604
|
+
toolSnippets[name] = snippet;
|
|
605
|
+
}
|
|
606
|
+
const toolGuidelines = this._toolPromptGuidelines.get(name);
|
|
607
|
+
if (toolGuidelines) {
|
|
608
|
+
promptGuidelines.push(...toolGuidelines);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
477
611
|
const loaderSystemPrompt = this._resourceLoader.getSystemPrompt();
|
|
478
612
|
const loaderAppendSystemPrompt = this._resourceLoader.getAppendSystemPrompt();
|
|
479
613
|
const appendSystemPrompt = loaderAppendSystemPrompt.length > 0 ? loaderAppendSystemPrompt.join("\n\n") : undefined;
|
|
@@ -486,6 +620,8 @@ export class AgentSession {
|
|
|
486
620
|
customPrompt: loaderSystemPrompt,
|
|
487
621
|
appendSystemPrompt,
|
|
488
622
|
selectedTools: validToolNames,
|
|
623
|
+
toolSnippets,
|
|
624
|
+
promptGuidelines,
|
|
489
625
|
});
|
|
490
626
|
}
|
|
491
627
|
// =========================================================================
|
|
@@ -673,8 +809,9 @@ export class AgentSession {
|
|
|
673
809
|
}
|
|
674
810
|
}
|
|
675
811
|
/**
|
|
676
|
-
* Queue a steering message
|
|
677
|
-
* Delivered after current
|
|
812
|
+
* Queue a steering message while the agent is running.
|
|
813
|
+
* Delivered after the current assistant turn finishes executing its tool calls,
|
|
814
|
+
* before the next LLM call.
|
|
678
815
|
* Expands skill commands and prompt templates. Errors on extension commands.
|
|
679
816
|
* @param images Optional image attachments to include with the message
|
|
680
817
|
* @throws Error if text is an extension command
|
|
@@ -938,11 +1075,12 @@ export class AgentSession {
|
|
|
938
1075
|
throw new Error(`No API key for ${model.provider}/${model.id}`);
|
|
939
1076
|
}
|
|
940
1077
|
const previousModel = this.model;
|
|
1078
|
+
const thinkingLevel = this._getThinkingLevelForModelSwitch();
|
|
941
1079
|
this.agent.setModel(model);
|
|
942
1080
|
this.sessionManager.appendModelChange(model.provider, model.id);
|
|
943
1081
|
this.settingsManager.setDefaultModelAndProvider(model.provider, model.id);
|
|
944
1082
|
// Re-clamp thinking level for new model's capabilities
|
|
945
|
-
this.setThinkingLevel(
|
|
1083
|
+
this.setThinkingLevel(thinkingLevel);
|
|
946
1084
|
await this._emitModelSelect(model, previousModel, "set");
|
|
947
1085
|
}
|
|
948
1086
|
/**
|
|
@@ -987,12 +1125,16 @@ export class AgentSession {
|
|
|
987
1125
|
const len = scopedModels.length;
|
|
988
1126
|
const nextIndex = direction === "forward" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;
|
|
989
1127
|
const next = scopedModels[nextIndex];
|
|
1128
|
+
const thinkingLevel = this._getThinkingLevelForModelSwitch(next.thinkingLevel);
|
|
990
1129
|
// Apply model
|
|
991
1130
|
this.agent.setModel(next.model);
|
|
992
1131
|
this.sessionManager.appendModelChange(next.model.provider, next.model.id);
|
|
993
1132
|
this.settingsManager.setDefaultModelAndProvider(next.model.provider, next.model.id);
|
|
994
|
-
// Apply thinking level
|
|
995
|
-
|
|
1133
|
+
// Apply thinking level.
|
|
1134
|
+
// - Explicit scoped model thinking level overrides current session level
|
|
1135
|
+
// - Undefined scoped model thinking level inherits the current session preference
|
|
1136
|
+
// setThinkingLevel clamps to model capabilities.
|
|
1137
|
+
this.setThinkingLevel(thinkingLevel);
|
|
996
1138
|
await this._emitModelSelect(next.model, currentModel, "cycle");
|
|
997
1139
|
return { model: next.model, thinkingLevel: this.thinkingLevel, isScoped: true };
|
|
998
1140
|
}
|
|
@@ -1011,11 +1153,12 @@ export class AgentSession {
|
|
|
1011
1153
|
if (!apiKey) {
|
|
1012
1154
|
throw new Error(`No API key for ${nextModel.provider}/${nextModel.id}`);
|
|
1013
1155
|
}
|
|
1156
|
+
const thinkingLevel = this._getThinkingLevelForModelSwitch();
|
|
1014
1157
|
this.agent.setModel(nextModel);
|
|
1015
1158
|
this.sessionManager.appendModelChange(nextModel.provider, nextModel.id);
|
|
1016
1159
|
this.settingsManager.setDefaultModelAndProvider(nextModel.provider, nextModel.id);
|
|
1017
1160
|
// Re-clamp thinking level for new model's capabilities
|
|
1018
|
-
this.setThinkingLevel(
|
|
1161
|
+
this.setThinkingLevel(thinkingLevel);
|
|
1019
1162
|
await this._emitModelSelect(nextModel, currentModel, "cycle");
|
|
1020
1163
|
return { model: nextModel, thinkingLevel: this.thinkingLevel, isScoped: false };
|
|
1021
1164
|
}
|
|
@@ -1035,7 +1178,9 @@ export class AgentSession {
|
|
|
1035
1178
|
this.agent.setThinkingLevel(effectiveLevel);
|
|
1036
1179
|
if (isChanging) {
|
|
1037
1180
|
this.sessionManager.appendThinkingLevelChange(effectiveLevel);
|
|
1038
|
-
this.
|
|
1181
|
+
if (this.supportsThinking() || effectiveLevel !== "off") {
|
|
1182
|
+
this.settingsManager.setDefaultThinkingLevel(effectiveLevel);
|
|
1183
|
+
}
|
|
1039
1184
|
}
|
|
1040
1185
|
}
|
|
1041
1186
|
/**
|
|
@@ -1073,6 +1218,15 @@ export class AgentSession {
|
|
|
1073
1218
|
supportsThinking() {
|
|
1074
1219
|
return !!this.model?.reasoning;
|
|
1075
1220
|
}
|
|
1221
|
+
_getThinkingLevelForModelSwitch(explicitLevel) {
|
|
1222
|
+
if (explicitLevel !== undefined) {
|
|
1223
|
+
return explicitLevel;
|
|
1224
|
+
}
|
|
1225
|
+
if (!this.supportsThinking()) {
|
|
1226
|
+
return this.settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;
|
|
1227
|
+
}
|
|
1228
|
+
return this.thinkingLevel;
|
|
1229
|
+
}
|
|
1076
1230
|
_clampThinkingLevel(level, availableLevels) {
|
|
1077
1231
|
const ordered = THINKING_LEVELS_WITH_XHIGH;
|
|
1078
1232
|
const available = new Set(availableLevels);
|
|
@@ -1244,15 +1398,27 @@ export class AgentSession {
|
|
|
1244
1398
|
// to a larger-context model (e.g. codex) - the overflow error from the old model
|
|
1245
1399
|
// shouldn't trigger compaction for the new model.
|
|
1246
1400
|
const sameModel = this.model && assistantMessage.provider === this.model.provider && assistantMessage.model === this.model.id;
|
|
1247
|
-
// Skip
|
|
1248
|
-
//
|
|
1249
|
-
//
|
|
1250
|
-
// Example: opus fails → switch to codex → compact → switch back to opus → opus error
|
|
1251
|
-
// is still in context but shouldn't trigger compaction again.
|
|
1401
|
+
// Skip compaction checks if this assistant message is older than the latest
|
|
1402
|
+
// compaction boundary. This prevents a stale pre-compaction usage/error
|
|
1403
|
+
// from retriggering compaction on the first prompt after compaction.
|
|
1252
1404
|
const compactionEntry = getLatestCompactionEntry(this.sessionManager.getBranch());
|
|
1253
|
-
const
|
|
1405
|
+
const assistantIsFromBeforeCompaction = compactionEntry !== null && assistantMessage.timestamp <= new Date(compactionEntry.timestamp).getTime();
|
|
1406
|
+
if (assistantIsFromBeforeCompaction) {
|
|
1407
|
+
return;
|
|
1408
|
+
}
|
|
1254
1409
|
// Case 1: Overflow - LLM returned context overflow error
|
|
1255
|
-
if (sameModel &&
|
|
1410
|
+
if (sameModel && isContextOverflow(assistantMessage, contextWindow)) {
|
|
1411
|
+
if (this._overflowRecoveryAttempted) {
|
|
1412
|
+
this._emit({
|
|
1413
|
+
type: "auto_compaction_end",
|
|
1414
|
+
result: undefined,
|
|
1415
|
+
aborted: false,
|
|
1416
|
+
willRetry: false,
|
|
1417
|
+
errorMessage: "Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model.",
|
|
1418
|
+
});
|
|
1419
|
+
return;
|
|
1420
|
+
}
|
|
1421
|
+
this._overflowRecoveryAttempted = true;
|
|
1256
1422
|
// Remove the error message from agent state (it IS saved to session for history,
|
|
1257
1423
|
// but we don't want it in context for the retry)
|
|
1258
1424
|
const messages = this.agent.state.messages;
|
|
@@ -1262,11 +1428,29 @@ export class AgentSession {
|
|
|
1262
1428
|
await this._runAutoCompaction("overflow", true);
|
|
1263
1429
|
return;
|
|
1264
1430
|
}
|
|
1265
|
-
// Case 2: Threshold -
|
|
1266
|
-
//
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1431
|
+
// Case 2: Threshold - context is getting large
|
|
1432
|
+
// For error messages (no usage data), estimate from last successful response.
|
|
1433
|
+
// This ensures sessions that hit persistent API errors (e.g. 529) can still compact.
|
|
1434
|
+
let contextTokens;
|
|
1435
|
+
if (assistantMessage.stopReason === "error") {
|
|
1436
|
+
const messages = this.agent.state.messages;
|
|
1437
|
+
const estimate = estimateContextTokens(messages);
|
|
1438
|
+
if (estimate.lastUsageIndex === null)
|
|
1439
|
+
return; // No usage data at all
|
|
1440
|
+
// Verify the usage source is post-compaction. Kept pre-compaction messages
|
|
1441
|
+
// have stale usage reflecting the old (larger) context and would falsely
|
|
1442
|
+
// trigger compaction right after one just finished.
|
|
1443
|
+
const usageMsg = messages[estimate.lastUsageIndex];
|
|
1444
|
+
if (compactionEntry &&
|
|
1445
|
+
usageMsg.role === "assistant" &&
|
|
1446
|
+
usageMsg.timestamp <= new Date(compactionEntry.timestamp).getTime()) {
|
|
1447
|
+
return;
|
|
1448
|
+
}
|
|
1449
|
+
contextTokens = estimate.tokens;
|
|
1450
|
+
}
|
|
1451
|
+
else {
|
|
1452
|
+
contextTokens = calculateContextTokens(assistantMessage.usage);
|
|
1453
|
+
}
|
|
1270
1454
|
if (shouldCompact(contextTokens, contextWindow, settings)) {
|
|
1271
1455
|
await this._runAutoCompaction("threshold", false);
|
|
1272
1456
|
}
|
|
@@ -1467,6 +1651,17 @@ export class AgentSession {
|
|
|
1467
1651
|
? runner.onError(this._extensionErrorListener)
|
|
1468
1652
|
: undefined;
|
|
1469
1653
|
}
|
|
1654
|
+
_refreshCurrentModelFromRegistry() {
|
|
1655
|
+
const currentModel = this.model;
|
|
1656
|
+
if (!currentModel) {
|
|
1657
|
+
return;
|
|
1658
|
+
}
|
|
1659
|
+
const refreshedModel = this._modelRegistry.find(currentModel.provider, currentModel.id);
|
|
1660
|
+
if (!refreshedModel || refreshedModel === currentModel) {
|
|
1661
|
+
return;
|
|
1662
|
+
}
|
|
1663
|
+
this.agent.setModel(refreshedModel);
|
|
1664
|
+
}
|
|
1470
1665
|
_bindExtensionCore(runner) {
|
|
1471
1666
|
const normalizeLocation = (source) => {
|
|
1472
1667
|
if (source === "user" || source === "project" || source === "path") {
|
|
@@ -1535,6 +1730,7 @@ export class AgentSession {
|
|
|
1535
1730
|
getActiveTools: () => this.getActiveToolNames(),
|
|
1536
1731
|
getAllTools: () => this.getAllTools(),
|
|
1537
1732
|
setActiveTools: (toolNames) => this.setActiveToolsByName(toolNames),
|
|
1733
|
+
refreshTools: () => this._refreshToolRegistry(),
|
|
1538
1734
|
getCommands,
|
|
1539
1735
|
setModel: async (model) => {
|
|
1540
1736
|
const key = await this.modelRegistry.getApiKey(model);
|
|
@@ -1567,8 +1763,62 @@ export class AgentSession {
|
|
|
1567
1763
|
})();
|
|
1568
1764
|
},
|
|
1569
1765
|
getSystemPrompt: () => this.systemPrompt,
|
|
1766
|
+
}, {
|
|
1767
|
+
registerProvider: (name, config) => {
|
|
1768
|
+
this._modelRegistry.registerProvider(name, config);
|
|
1769
|
+
this._refreshCurrentModelFromRegistry();
|
|
1770
|
+
},
|
|
1771
|
+
unregisterProvider: (name) => {
|
|
1772
|
+
this._modelRegistry.unregisterProvider(name);
|
|
1773
|
+
this._refreshCurrentModelFromRegistry();
|
|
1774
|
+
},
|
|
1570
1775
|
});
|
|
1571
1776
|
}
|
|
1777
|
+
_refreshToolRegistry(options) {
|
|
1778
|
+
const previousRegistryNames = new Set(this._toolRegistry.keys());
|
|
1779
|
+
const previousActiveToolNames = this.getActiveToolNames();
|
|
1780
|
+
const registeredTools = this._extensionRunner?.getAllRegisteredTools() ?? [];
|
|
1781
|
+
const allCustomTools = [
|
|
1782
|
+
...registeredTools,
|
|
1783
|
+
...this._customTools.map((def) => ({ definition: def, extensionPath: "<sdk>" })),
|
|
1784
|
+
];
|
|
1785
|
+
this._toolPromptSnippets = new Map(allCustomTools
|
|
1786
|
+
.map((registeredTool) => {
|
|
1787
|
+
const snippet = this._normalizePromptSnippet(registeredTool.definition.promptSnippet);
|
|
1788
|
+
return snippet ? [registeredTool.definition.name, snippet] : undefined;
|
|
1789
|
+
})
|
|
1790
|
+
.filter((entry) => entry !== undefined));
|
|
1791
|
+
this._toolPromptGuidelines = new Map(allCustomTools
|
|
1792
|
+
.map((registeredTool) => {
|
|
1793
|
+
const guidelines = this._normalizePromptGuidelines(registeredTool.definition.promptGuidelines);
|
|
1794
|
+
return guidelines.length > 0 ? [registeredTool.definition.name, guidelines] : undefined;
|
|
1795
|
+
})
|
|
1796
|
+
.filter((entry) => entry !== undefined));
|
|
1797
|
+
const wrappedExtensionTools = this._extensionRunner
|
|
1798
|
+
? wrapRegisteredTools(allCustomTools, this._extensionRunner)
|
|
1799
|
+
: [];
|
|
1800
|
+
const toolRegistry = new Map(this._baseToolRegistry);
|
|
1801
|
+
for (const tool of wrappedExtensionTools) {
|
|
1802
|
+
toolRegistry.set(tool.name, tool);
|
|
1803
|
+
}
|
|
1804
|
+
this._toolRegistry = toolRegistry;
|
|
1805
|
+
const nextActiveToolNames = options?.activeToolNames
|
|
1806
|
+
? [...options.activeToolNames]
|
|
1807
|
+
: [...previousActiveToolNames];
|
|
1808
|
+
if (options?.includeAllExtensionTools) {
|
|
1809
|
+
for (const tool of wrappedExtensionTools) {
|
|
1810
|
+
nextActiveToolNames.push(tool.name);
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
else if (!options?.activeToolNames) {
|
|
1814
|
+
for (const toolName of this._toolRegistry.keys()) {
|
|
1815
|
+
if (!previousRegistryNames.has(toolName)) {
|
|
1816
|
+
nextActiveToolNames.push(toolName);
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
this.setActiveToolsByName([...new Set(nextActiveToolNames)]);
|
|
1821
|
+
}
|
|
1572
1822
|
_buildRuntime(options) {
|
|
1573
1823
|
const autoResizeImages = this.settingsManager.getImageAutoResize();
|
|
1574
1824
|
const shellCommandPrefix = this.settingsManager.getShellCommandPrefix();
|
|
@@ -1598,47 +1848,14 @@ export class AgentSession {
|
|
|
1598
1848
|
this._bindExtensionCore(this._extensionRunner);
|
|
1599
1849
|
this._applyExtensionBindings(this._extensionRunner);
|
|
1600
1850
|
}
|
|
1601
|
-
const registeredTools = this._extensionRunner?.getAllRegisteredTools() ?? [];
|
|
1602
|
-
const allCustomTools = [
|
|
1603
|
-
...registeredTools,
|
|
1604
|
-
...this._customTools.map((def) => ({ definition: def, extensionPath: "<sdk>" })),
|
|
1605
|
-
];
|
|
1606
|
-
const wrappedExtensionTools = this._extensionRunner
|
|
1607
|
-
? wrapRegisteredTools(allCustomTools, this._extensionRunner)
|
|
1608
|
-
: [];
|
|
1609
|
-
const toolRegistry = new Map(this._baseToolRegistry);
|
|
1610
|
-
for (const tool of wrappedExtensionTools) {
|
|
1611
|
-
toolRegistry.set(tool.name, tool);
|
|
1612
|
-
}
|
|
1613
1851
|
const defaultActiveToolNames = this._baseToolsOverride
|
|
1614
1852
|
? Object.keys(this._baseToolsOverride)
|
|
1615
1853
|
: ["read", "bash", "edit", "write"];
|
|
1616
1854
|
const baseActiveToolNames = options.activeToolNames ?? defaultActiveToolNames;
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
}
|
|
1622
|
-
}
|
|
1623
|
-
const extensionToolNames = new Set(wrappedExtensionTools.map((tool) => tool.name));
|
|
1624
|
-
const activeBaseTools = Array.from(activeToolNameSet)
|
|
1625
|
-
.filter((name) => this._baseToolRegistry.has(name) && !extensionToolNames.has(name))
|
|
1626
|
-
.map((name) => this._baseToolRegistry.get(name));
|
|
1627
|
-
const activeExtensionTools = wrappedExtensionTools.filter((tool) => activeToolNameSet.has(tool.name));
|
|
1628
|
-
const activeToolsArray = [...activeBaseTools, ...activeExtensionTools];
|
|
1629
|
-
if (this._extensionRunner) {
|
|
1630
|
-
const wrappedActiveTools = wrapToolsWithExtensions(activeToolsArray, this._extensionRunner);
|
|
1631
|
-
this.agent.setTools(wrappedActiveTools);
|
|
1632
|
-
const wrappedAllTools = wrapToolsWithExtensions(Array.from(toolRegistry.values()), this._extensionRunner);
|
|
1633
|
-
this._toolRegistry = new Map(wrappedAllTools.map((tool) => [tool.name, tool]));
|
|
1634
|
-
}
|
|
1635
|
-
else {
|
|
1636
|
-
this.agent.setTools(activeToolsArray);
|
|
1637
|
-
this._toolRegistry = toolRegistry;
|
|
1638
|
-
}
|
|
1639
|
-
const systemPromptToolNames = Array.from(activeToolNameSet).filter((name) => this._baseToolRegistry.has(name));
|
|
1640
|
-
this._baseSystemPrompt = this._rebuildSystemPrompt(systemPromptToolNames);
|
|
1641
|
-
this.agent.setSystemPrompt(this._baseSystemPrompt);
|
|
1855
|
+
this._refreshToolRegistry({
|
|
1856
|
+
activeToolNames: baseActiveToolNames,
|
|
1857
|
+
includeAllExtensionTools: options.includeAllExtensionTools,
|
|
1858
|
+
});
|
|
1642
1859
|
}
|
|
1643
1860
|
async reload() {
|
|
1644
1861
|
const previousFlagValues = this._extensionRunner?.getFlagValues();
|
|
@@ -1675,8 +1892,8 @@ export class AgentSession {
|
|
|
1675
1892
|
if (isContextOverflow(message, contextWindow))
|
|
1676
1893
|
return false;
|
|
1677
1894
|
const err = message.errorMessage;
|
|
1678
|
-
// Match: overloaded_error, rate limit, 429, 500, 502, 503, 504, service unavailable, connection errors, fetch failed, terminated, retry delay exceeded
|
|
1679
|
-
return /overloaded|rate.?limit|too many requests|429|500|502|503|504|service.?unavailable|server
|
|
1895
|
+
// Match: overloaded_error, provider returned error, rate limit, 429, 500, 502, 503, 504, service unavailable, network/connection errors, fetch failed, terminated, retry delay exceeded
|
|
1896
|
+
return /overloaded|provider.?returned.?error|rate.?limit|too many requests|429|500|502|503|504|service.?unavailable|server.?error|internal.?error|network.?error|connection.?error|connection.?refused|other side closed|fetch failed|upstream.?connect|reset before headers|socket hang up|timed? out|timeout|terminated|retry delay/i.test(err);
|
|
1680
1897
|
}
|
|
1681
1898
|
/**
|
|
1682
1899
|
* Check if autonomous mode is enabled and queue follow-up prompts.
|
|
@@ -1722,15 +1939,18 @@ export class AgentSession {
|
|
|
1722
1939
|
*/
|
|
1723
1940
|
async _handleRetryableError(message) {
|
|
1724
1941
|
const settings = this.settingsManager.getRetrySettings();
|
|
1725
|
-
if (!settings.enabled)
|
|
1942
|
+
if (!settings.enabled) {
|
|
1943
|
+
this._resolveRetry();
|
|
1726
1944
|
return false;
|
|
1727
|
-
|
|
1728
|
-
//
|
|
1729
|
-
|
|
1945
|
+
}
|
|
1946
|
+
// Retry promise is created synchronously in _handleAgentEvent for agent_end.
|
|
1947
|
+
// Keep a defensive fallback here in case a future refactor bypasses that path.
|
|
1948
|
+
if (!this._retryPromise) {
|
|
1730
1949
|
this._retryPromise = new Promise((resolve) => {
|
|
1731
1950
|
this._retryResolve = resolve;
|
|
1732
1951
|
});
|
|
1733
1952
|
}
|
|
1953
|
+
this._retryAttempt++;
|
|
1734
1954
|
if (this._retryAttempt > settings.maxRetries) {
|
|
1735
1955
|
// Max retries exceeded, emit final failure and reset
|
|
1736
1956
|
this._emit({
|