@earendil-works/pi-coding-agent 0.84.1 → 0.84.3
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 +139 -0
- package/README.md +9 -4
- package/dist/bundle/chunks/anthropic-messages-JWX2WP65.js +45 -0
- package/dist/bundle/chunks/anthropic.js +75 -0
- package/dist/bundle/chunks/azure-openai-responses-5ENVCQ7U.js +2 -0
- package/dist/bundle/chunks/bedrock-converse-stream.js +74 -0
- package/dist/bundle/chunks/chunk-4L3WN2XY.js +2 -0
- package/dist/bundle/chunks/chunk-6CYCI3EJ.js +12 -0
- package/dist/bundle/chunks/chunk-6R7UI4IY.js +2 -0
- package/dist/bundle/chunks/chunk-AXIIZGTV.js +2 -0
- package/dist/bundle/chunks/chunk-DRQDKNXA.js +2 -0
- package/dist/bundle/chunks/chunk-E5KXRMZK.js +1547 -0
- package/dist/bundle/chunks/chunk-GMWCTUPB.js +2 -0
- package/dist/bundle/chunks/chunk-GPPBJGBU.js +50 -0
- package/dist/bundle/chunks/chunk-JUUC5AZY.js +2 -0
- package/dist/bundle/chunks/chunk-L2ZPNLYD.js +2 -0
- package/dist/bundle/chunks/chunk-MNAIPA3J.js +2 -0
- package/dist/bundle/chunks/chunk-NBBFIJUL.js +11 -0
- package/dist/bundle/chunks/chunk-NUHFSC37.js +25 -0
- package/dist/bundle/chunks/chunk-PGXDEOVV.js +2 -0
- package/dist/bundle/chunks/chunk-PJACZCIR.js +2 -0
- package/dist/bundle/chunks/chunk-PRRNXB7S.js +2 -0
- package/dist/bundle/chunks/chunk-TEPMHNKQ.js +2 -0
- package/dist/bundle/chunks/chunk-TRDNDS6A.js +4 -0
- package/dist/bundle/chunks/chunk-UAQELI3K.js +2 -0
- package/dist/bundle/chunks/chunk-XDUWOHPL.js +6 -0
- package/dist/bundle/chunks/chunk-XNGRGP62.js +2 -0
- package/dist/bundle/chunks/dist-RDWOYWHR.js +13 -0
- package/dist/bundle/chunks/github-copilot.js +2 -0
- package/dist/bundle/chunks/google-generative-ai-XDKMGBCJ.js +2 -0
- package/dist/bundle/chunks/google-vertex-D5FGEO3Y.js +2 -0
- package/dist/bundle/chunks/image-resize-worker.js +2 -0
- package/dist/bundle/chunks/kimi-coding.js +2 -0
- package/dist/bundle/chunks/lib-HGQMNYVT.js +9 -0
- package/dist/bundle/chunks/mistral-conversations-YK73UAOZ.js +5 -0
- package/dist/bundle/chunks/multipart-parser-SQ6GDJL7.js +3 -0
- package/dist/bundle/chunks/openai-codex-responses-GJVBJXLB.js +8 -0
- package/dist/bundle/chunks/openai-codex.js +75 -0
- package/dist/bundle/chunks/openai-completions-JD4WAC3R.js +7 -0
- package/dist/bundle/chunks/openai-responses-BSOJMSEV.js +2 -0
- package/dist/bundle/chunks/openrouter-images-N4XVVFSD.js +2 -0
- package/dist/bundle/chunks/openrouter.js +75 -0
- package/dist/bundle/chunks/pi-messages-TPFH44NP.js +8 -0
- package/dist/bundle/chunks/radius.js +75 -0
- package/dist/bundle/chunks/src-UK77SYZE.js +4 -0
- package/dist/bundle/chunks/xai.js +2 -0
- package/dist/bundle/cli.js +3 -0
- package/dist/bundle/client.js +2 -0
- package/dist/bundle/index.js +2 -0
- package/dist/bundle/rpc-entry.js +3 -0
- package/dist/cli/args.d.ts +2 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +40 -9
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/auth-command.d.ts.map +1 -1
- package/dist/cli/auth-command.js +5 -4
- package/dist/cli/auth-command.js.map +1 -1
- package/dist/cli/file-processor.d.ts.map +1 -1
- package/dist/cli/file-processor.js +2 -1
- package/dist/cli/file-processor.js.map +1 -1
- package/dist/config.d.ts +4 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +22 -14
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +33 -9
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +169 -101
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +6 -7
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +3 -0
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +4 -3
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +41 -32
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/defaults.d.ts +1 -0
- package/dist/core/defaults.d.ts.map +1 -1
- package/dist/core/defaults.js +9 -0
- package/dist/core/defaults.js.map +1 -1
- package/dist/core/experimental.d.ts +4 -0
- package/dist/core/experimental.d.ts.map +1 -1
- package/dist/core/experimental.js +4 -0
- package/dist/core/experimental.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 +115 -48
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/types.d.ts +42 -9
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js +3 -0
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +1 -1
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +1 -1
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/keybindings.d.ts +38 -13
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +26 -5
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/model-config.d.ts +10 -0
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +4 -1
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-resolver.d.ts +1 -0
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +14 -8
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/models-store.d.ts.map +1 -1
- package/dist/core/models-store.js +2 -1
- package/dist/core/models-store.js.map +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +22 -14
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/pi-manifest.d.ts.map +1 -1
- package/dist/core/pi-manifest.js +2 -1
- package/dist/core/pi-manifest.js.map +1 -1
- package/dist/core/project-trust.d.ts.map +1 -1
- package/dist/core/project-trust.js +2 -2
- package/dist/core/project-trust.js.map +1 -1
- package/dist/core/remote-catalog-provider.d.ts.map +1 -1
- package/dist/core/remote-catalog-provider.js +2 -1
- package/dist/core/remote-catalog-provider.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +3 -2
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts +7 -5
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +12 -4
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-export.d.ts +4 -0
- package/dist/core/session-export.d.ts.map +1 -0
- package/dist/core/session-export.js +32 -0
- package/dist/core/session-export.js.map +1 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +4 -3
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-diagnostics.d.ts +9 -0
- package/dist/core/settings-diagnostics.d.ts.map +1 -0
- package/dist/core/settings-diagnostics.js +21 -0
- package/dist/core/settings-diagnostics.js.map +1 -0
- package/dist/core/settings-manager.d.ts +15 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +64 -10
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +51 -33
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +2 -1
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +12 -3
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +14 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +38 -20
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit-diff.d.ts +0 -5
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.js +2 -5
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +22 -4
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +1 -1
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +1 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +4 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +18 -1
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/powershell.d.ts +16 -0
- package/dist/core/tools/powershell.d.ts.map +1 -0
- package/dist/core/tools/powershell.js +39 -0
- package/dist/core/tools/powershell.js.map +1 -0
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +2 -0
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +2 -0
- package/dist/core/tools/write.js.map +1 -1
- package/dist/core/trust-manager.d.ts.map +1 -1
- package/dist/core/trust-manager.js +2 -1
- package/dist/core/trust-manager.js.map +1 -1
- package/dist/extensions/llama/index.d.ts.map +1 -1
- package/dist/extensions/llama/index.js +2 -0
- package/dist/extensions/llama/index.js.map +1 -1
- package/dist/extensions/llama/provider.d.ts.map +1 -1
- package/dist/extensions/llama/provider.js +6 -2
- package/dist/extensions/llama/provider.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts +4 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +23 -16
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +4 -3
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts +9 -3
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +58 -13
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +10 -3
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +128 -56
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-submenu.d.ts +72 -0
- package/dist/modes/interactive/components/settings-submenu.d.ts.map +1 -0
- package/dist/modes/interactive/components/settings-submenu.js +165 -0
- package/dist/modes/interactive/components/settings-submenu.js.map +1 -0
- package/dist/modes/interactive/components/thinking-selector.d.ts +15 -3
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +74 -17
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +10 -1
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/external-editor.d.ts.map +1 -1
- package/dist/modes/interactive/external-editor.js +2 -1
- package/dist/modes/interactive/external-editor.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +19 -2
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +250 -129
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/model-catalog-refresh.d.ts +7 -0
- package/dist/modes/interactive/model-catalog-refresh.d.ts.map +1 -0
- package/dist/modes/interactive/model-catalog-refresh.js +34 -0
- package/dist/modes/interactive/model-catalog-refresh.js.map +1 -0
- package/dist/modes/interactive/session-share.d.ts +16 -0
- package/dist/modes/interactive/session-share.d.ts.map +1 -0
- package/dist/modes/interactive/session-share.js +188 -0
- package/dist/modes/interactive/session-share.js.map +1 -0
- package/dist/modes/interactive/theme/dark.json +2 -0
- package/dist/modes/interactive/theme/light.json +2 -0
- package/dist/modes/interactive/theme/theme-controller.d.ts +10 -2
- package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-controller.js +25 -11
- package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
- package/dist/modes/interactive/theme/theme-schema.json +9 -1
- package/dist/modes/interactive/theme/theme.d.ts +5 -3
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +16 -5
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/json-event.d.ts +18 -12
- package/dist/modes/json-event.d.ts.map +1 -1
- package/dist/modes/json-event.js +22 -5
- package/dist/modes/json-event.js.map +1 -1
- package/dist/package-manager-cli.d.ts +1 -0
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +187 -3
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/server/create-harness.d.ts.map +1 -1
- package/dist/server/create-harness.js +2 -0
- package/dist/server/create-harness.js.map +1 -1
- package/dist/utils/frontmatter.d.ts.map +1 -1
- package/dist/utils/frontmatter.js +2 -1
- package/dist/utils/frontmatter.js.map +1 -1
- package/dist/utils/management-http.d.ts +5 -3
- package/dist/utils/management-http.d.ts.map +1 -1
- package/dist/utils/management-http.js +14 -10
- package/dist/utils/management-http.js.map +1 -1
- package/dist/utils/shell.d.ts +3 -0
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +17 -5
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/syntax-highlight.d.ts +1 -0
- package/dist/utils/syntax-highlight.d.ts.map +1 -1
- package/dist/utils/syntax-highlight.js +60 -1
- package/dist/utils/syntax-highlight.js.map +1 -1
- package/dist/utils/text.d.ts +8 -0
- package/dist/utils/text.d.ts.map +1 -0
- package/dist/utils/text.js +9 -0
- package/dist/utils/text.js.map +1 -0
- package/dist/utils/tools-manager.d.ts +10 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +14 -19
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/compaction.md +21 -6
- package/docs/custom-provider.md +6 -3
- package/docs/environment-variables.md +16 -10
- package/docs/extensions.md +21 -7
- package/docs/json.md +12 -5
- package/docs/keybindings.md +15 -9
- package/docs/llama-cpp.md +2 -0
- package/docs/models.md +8 -2
- package/docs/packages.md +2 -2
- package/docs/rpc.md +24 -7
- package/docs/sdk.md +16 -2
- package/docs/settings.md +41 -2
- package/docs/skills.md +4 -3
- package/docs/terminal-setup.md +34 -11
- package/docs/themes.md +24 -3
- package/docs/tui.md +2 -2
- package/docs/usage.md +9 -4
- package/docs/windows.md +24 -2
- package/examples/extensions/border-status-editor.ts +1 -1
- 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/git-checkpoint.ts +2 -2
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/notify.ts +3 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/subagent/README.md +3 -1
- package/examples/extensions/subagent/agents.ts +40 -9
- package/examples/extensions/subagent/index.ts +27 -4
- package/examples/extensions/titlebar-spinner.ts +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/rpc-extension-ui.ts +1 -1
- package/examples/sdk/06-extensions.ts +1 -1
- package/examples/sdk/README.md +1 -1
- package/npm-shrinkwrap.json +28 -132
- package/package.json +12 -14
|
@@ -12,26 +12,26 @@
|
|
|
12
12
|
*
|
|
13
13
|
* Modes use this class and add their own I/O layer on top.
|
|
14
14
|
*/
|
|
15
|
-
import {
|
|
15
|
+
import { readFileSync } from "node:fs";
|
|
16
16
|
import { basename, dirname } from "node:path";
|
|
17
17
|
import { contentText } from "@earendil-works/pi-ai";
|
|
18
18
|
import { clampThinkingLevel, cleanupSessionResources, getSupportedThinkingLevels, isContextOverflow, isRecoverableLength, isRetryableAssistantError, modelsAreEqual, resetApiProviders, streamSimple, } from "@earendil-works/pi-ai/compat";
|
|
19
19
|
import { getThemeByName, theme } from "../modes/interactive/theme/theme.js";
|
|
20
20
|
import { stripFrontmatter } from "../utils/frontmatter.js";
|
|
21
|
-
import { resolvePath } from "../utils/paths.js";
|
|
22
21
|
import { sleep } from "../utils/sleep.js";
|
|
23
22
|
import { normalizeToolResultImages } from "../utils/tool-result-images.js";
|
|
24
23
|
import { formatNoApiKeyFoundMessage, formatNoModelSelectedMessage } from "./auth-guidance.js";
|
|
25
24
|
import { executeBashWithOperations } from "./bash-executor.js";
|
|
26
25
|
import { calculateContextTokens, collectEntriesForBranchSummary, compact, estimateContextTokens, estimateTokens, generateBranchSummary, prepareCompaction, shouldCompact, } from "./compaction/index.js";
|
|
27
|
-
import { DEFAULT_THINKING_LEVEL } from "./defaults.js";
|
|
26
|
+
import { DEFAULT_THINKING_LEVEL, THINKING_LEVEL_OPTIONS } from "./defaults.js";
|
|
28
27
|
import { exportSessionToHtml } from "./export-html/index.js";
|
|
29
28
|
import { createToolHtmlRenderer } from "./export-html/tool-renderer.js";
|
|
30
29
|
import { ExtensionRunner, wrapRegisteredTools, } from "./extensions/index.js";
|
|
31
30
|
import { emitSessionShutdownEvent } from "./extensions/runner.js";
|
|
32
31
|
import { ModelRegistry } from "./model-registry.js";
|
|
33
32
|
import { expandPromptTemplate } from "./prompt-templates.js";
|
|
34
|
-
import {
|
|
33
|
+
import { exportSessionToJsonl } from "./session-export.js";
|
|
34
|
+
import { getLatestCompactionEntry } from "./session-manager.js";
|
|
35
35
|
import { createSyntheticSourceInfo } from "./source-info.js";
|
|
36
36
|
import { buildSystemPrompt } from "./system-prompt.js";
|
|
37
37
|
import { createLocalBashOperations } from "./tools/bash.js";
|
|
@@ -71,8 +71,6 @@ function estimateMessagesTokens(messages) {
|
|
|
71
71
|
// ============================================================================
|
|
72
72
|
// Constants
|
|
73
73
|
// ============================================================================
|
|
74
|
-
/** Standard thinking levels */
|
|
75
|
-
const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high"];
|
|
76
74
|
// ============================================================================
|
|
77
75
|
// AgentSession Class
|
|
78
76
|
// ============================================================================
|
|
@@ -307,6 +305,11 @@ export class AgentSession {
|
|
|
307
305
|
followUp: [...this._followUpMessages],
|
|
308
306
|
});
|
|
309
307
|
}
|
|
308
|
+
async _emitSessionCompactFailed(event) {
|
|
309
|
+
if (this._extensionRunner.hasHandlers("session_compact_failed")) {
|
|
310
|
+
await this._extensionRunner.emit({ type: "session_compact_failed", ...event });
|
|
311
|
+
}
|
|
312
|
+
}
|
|
310
313
|
_getIdleWaitPromise() {
|
|
311
314
|
if (!this._idleWaitPromise) {
|
|
312
315
|
this._idleWaitPromise = new Promise((resolve) => {
|
|
@@ -1078,7 +1081,7 @@ export class AgentSession {
|
|
|
1078
1081
|
if (options?.deliverAs === "nextTurn") {
|
|
1079
1082
|
this._pendingNextTurnMessages.push(appMessage);
|
|
1080
1083
|
}
|
|
1081
|
-
else if (this.isStreaming) {
|
|
1084
|
+
else if (this.isStreaming && options?.triggerTurn !== false) {
|
|
1082
1085
|
if (options?.deliverAs === "followUp") {
|
|
1083
1086
|
this.agent.followUp(appMessage);
|
|
1084
1087
|
}
|
|
@@ -1102,6 +1105,7 @@ export class AgentSession {
|
|
|
1102
1105
|
*
|
|
1103
1106
|
* @param content User message content (string or content array)
|
|
1104
1107
|
* @param options.deliverAs Delivery mode when streaming: "steer" or "followUp"
|
|
1108
|
+
* @param options.expandPromptTemplates Whether to dispatch extension commands and expand skill commands and prompt templates. Default: false.
|
|
1105
1109
|
*/
|
|
1106
1110
|
async sendUserMessage(content, options) {
|
|
1107
1111
|
// Normalize content to text string + optional images
|
|
@@ -1125,9 +1129,8 @@ export class AgentSession {
|
|
|
1125
1129
|
if (images.length === 0)
|
|
1126
1130
|
images = undefined;
|
|
1127
1131
|
}
|
|
1128
|
-
// Use prompt() with expandPromptTemplates: false to skip command handling and template expansion
|
|
1129
1132
|
await this.prompt(text, {
|
|
1130
|
-
expandPromptTemplates: false,
|
|
1133
|
+
expandPromptTemplates: options?.expandPromptTemplates ?? false,
|
|
1131
1134
|
streamingBehavior: options?.deliverAs,
|
|
1132
1135
|
images,
|
|
1133
1136
|
source: "extension",
|
|
@@ -1191,19 +1194,24 @@ export class AgentSession {
|
|
|
1191
1194
|
}
|
|
1192
1195
|
/**
|
|
1193
1196
|
* Set model directly.
|
|
1194
|
-
* Validates that auth is configured
|
|
1197
|
+
* Validates that auth is configured and saves to the session transcript.
|
|
1198
|
+
* Persists to global defaults only when options.persist is true.
|
|
1195
1199
|
* @throws Error if no auth is configured for the model
|
|
1196
1200
|
*/
|
|
1197
|
-
async setModel(model) {
|
|
1201
|
+
async setModel(model, options = {}) {
|
|
1198
1202
|
if (!(await this._modelRuntime.checkAuth(model.provider))) {
|
|
1199
1203
|
throw new Error(`No API key for ${model.provider}/${model.id}`);
|
|
1200
1204
|
}
|
|
1201
1205
|
const previousModel = this.model;
|
|
1202
|
-
const thinkingLevel = this._getThinkingLevelForModelSwitch();
|
|
1206
|
+
const thinkingLevel = this._getThinkingLevelForModelSwitch(model);
|
|
1203
1207
|
this.agent.state.model = model;
|
|
1204
1208
|
this.sessionManager.appendModelChange(model.provider, model.id);
|
|
1205
|
-
|
|
1206
|
-
|
|
1209
|
+
if (options.persist) {
|
|
1210
|
+
this.settingsManager.setDefaultModelAndProvider(model.provider, model.id);
|
|
1211
|
+
}
|
|
1212
|
+
// Apply thinking level for the new model.
|
|
1213
|
+
// Per-model thinking level overrides take priority over the global default.
|
|
1214
|
+
// Model persistence does not implicitly rewrite the global thinking default.
|
|
1207
1215
|
this.setThinkingLevel(thinkingLevel);
|
|
1208
1216
|
await this._emitModelSelect(model, previousModel, "set");
|
|
1209
1217
|
}
|
|
@@ -1213,13 +1221,13 @@ export class AgentSession {
|
|
|
1213
1221
|
* @param direction - "forward" (default) or "backward"
|
|
1214
1222
|
* @returns The new model info, or undefined if only one model available
|
|
1215
1223
|
*/
|
|
1216
|
-
async cycleModel(direction = "forward") {
|
|
1224
|
+
async cycleModel(direction = "forward", options = {}) {
|
|
1217
1225
|
if (this._scopedModels.length > 0) {
|
|
1218
|
-
return this._cycleScopedModel(direction);
|
|
1226
|
+
return this._cycleScopedModel(direction, options);
|
|
1219
1227
|
}
|
|
1220
|
-
return this._cycleAvailableModel(direction);
|
|
1228
|
+
return this._cycleAvailableModel(direction, options);
|
|
1221
1229
|
}
|
|
1222
|
-
async _cycleScopedModel(direction) {
|
|
1230
|
+
async _cycleScopedModel(direction, options) {
|
|
1223
1231
|
const availableIds = new Set(this._modelRuntime.getAvailableSnapshot().map((model) => `${model.provider}\0${model.id}`));
|
|
1224
1232
|
const scopedModels = this._scopedModels.filter((scoped) => availableIds.has(`${scoped.model.provider}\0${scoped.model.id}`));
|
|
1225
1233
|
if (scopedModels.length <= 1)
|
|
@@ -1231,20 +1239,23 @@ export class AgentSession {
|
|
|
1231
1239
|
const len = scopedModels.length;
|
|
1232
1240
|
const nextIndex = direction === "forward" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;
|
|
1233
1241
|
const next = scopedModels[nextIndex];
|
|
1234
|
-
const thinkingLevel = this._getThinkingLevelForModelSwitch(next.thinkingLevel);
|
|
1242
|
+
const thinkingLevel = this._getThinkingLevelForModelSwitch(next.model, next.thinkingLevel);
|
|
1235
1243
|
// Apply model
|
|
1236
1244
|
this.agent.state.model = next.model;
|
|
1237
1245
|
this.sessionManager.appendModelChange(next.model.provider, next.model.id);
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
//
|
|
1246
|
+
if (options.persist) {
|
|
1247
|
+
this.settingsManager.setDefaultModelAndProvider(next.model.provider, next.model.id);
|
|
1248
|
+
}
|
|
1249
|
+
// Apply thinking level for the new model.
|
|
1250
|
+
// - Explicit scoped model thinking level overrides defaults
|
|
1251
|
+
// - Per-model thinking level overrides take priority over the global default
|
|
1242
1252
|
// setThinkingLevel clamps to model capabilities.
|
|
1253
|
+
// Model persistence does not implicitly rewrite the global thinking default.
|
|
1243
1254
|
this.setThinkingLevel(thinkingLevel);
|
|
1244
1255
|
await this._emitModelSelect(next.model, currentModel, "cycle");
|
|
1245
1256
|
return { model: next.model, thinkingLevel: this.thinkingLevel, isScoped: true };
|
|
1246
1257
|
}
|
|
1247
|
-
async _cycleAvailableModel(direction) {
|
|
1258
|
+
async _cycleAvailableModel(direction, options) {
|
|
1248
1259
|
const availableModels = this._modelRuntime.getAvailableSnapshot();
|
|
1249
1260
|
if (availableModels.length <= 1)
|
|
1250
1261
|
return undefined;
|
|
@@ -1255,11 +1266,14 @@ export class AgentSession {
|
|
|
1255
1266
|
const len = availableModels.length;
|
|
1256
1267
|
const nextIndex = direction === "forward" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;
|
|
1257
1268
|
const nextModel = availableModels[nextIndex];
|
|
1258
|
-
const thinkingLevel = this._getThinkingLevelForModelSwitch();
|
|
1269
|
+
const thinkingLevel = this._getThinkingLevelForModelSwitch(nextModel);
|
|
1259
1270
|
this.agent.state.model = nextModel;
|
|
1260
1271
|
this.sessionManager.appendModelChange(nextModel.provider, nextModel.id);
|
|
1261
|
-
|
|
1262
|
-
|
|
1272
|
+
if (options.persist) {
|
|
1273
|
+
this.settingsManager.setDefaultModelAndProvider(nextModel.provider, nextModel.id);
|
|
1274
|
+
}
|
|
1275
|
+
// Apply thinking level for the new model.
|
|
1276
|
+
// Model persistence does not implicitly rewrite the global thinking default.
|
|
1263
1277
|
this.setThinkingLevel(thinkingLevel);
|
|
1264
1278
|
await this._emitModelSelect(nextModel, currentModel, "cycle");
|
|
1265
1279
|
return { model: nextModel, thinkingLevel: this.thinkingLevel, isScoped: false };
|
|
@@ -1270,20 +1284,21 @@ export class AgentSession {
|
|
|
1270
1284
|
/**
|
|
1271
1285
|
* Set thinking level.
|
|
1272
1286
|
* Clamps to model capabilities based on available thinking levels.
|
|
1273
|
-
* Saves to session
|
|
1287
|
+
* Saves the clamped level to the session transcript only if the level actually changes.
|
|
1288
|
+
* Persists the requested level to global defaults only when options.persist is true.
|
|
1274
1289
|
*/
|
|
1275
|
-
setThinkingLevel(level) {
|
|
1290
|
+
setThinkingLevel(level, options = {}) {
|
|
1276
1291
|
const availableLevels = this.getAvailableThinkingLevels();
|
|
1277
1292
|
const effectiveLevel = availableLevels.includes(level) ? level : this._clampThinkingLevel(level, availableLevels);
|
|
1278
1293
|
// Only persist if actually changing
|
|
1279
1294
|
const previousLevel = this.agent.state.thinkingLevel;
|
|
1280
1295
|
const isChanging = effectiveLevel !== previousLevel;
|
|
1281
1296
|
this.agent.state.thinkingLevel = effectiveLevel;
|
|
1297
|
+
if (options.persist) {
|
|
1298
|
+
this.settingsManager.setDefaultThinkingLevel(level);
|
|
1299
|
+
}
|
|
1282
1300
|
if (isChanging) {
|
|
1283
1301
|
this.sessionManager.appendThinkingLevelChange(effectiveLevel);
|
|
1284
|
-
if (this.supportsThinking() || effectiveLevel !== "off") {
|
|
1285
|
-
this.settingsManager.setDefaultThinkingLevel(effectiveLevel);
|
|
1286
|
-
}
|
|
1287
1302
|
this._emit({ type: "thinking_level_changed", level: effectiveLevel });
|
|
1288
1303
|
void this._extensionRunner.emit({
|
|
1289
1304
|
type: "thinking_level_select",
|
|
@@ -1296,14 +1311,14 @@ export class AgentSession {
|
|
|
1296
1311
|
* Cycle to next thinking level.
|
|
1297
1312
|
* @returns New level, or undefined if model doesn't support thinking
|
|
1298
1313
|
*/
|
|
1299
|
-
cycleThinkingLevel() {
|
|
1314
|
+
cycleThinkingLevel(options = {}) {
|
|
1300
1315
|
if (!this.supportsThinking())
|
|
1301
1316
|
return undefined;
|
|
1302
1317
|
const levels = this.getAvailableThinkingLevels();
|
|
1303
1318
|
const currentIndex = levels.indexOf(this.thinkingLevel);
|
|
1304
1319
|
const nextIndex = (currentIndex + 1) % levels.length;
|
|
1305
1320
|
const nextLevel = levels[nextIndex];
|
|
1306
|
-
this.setThinkingLevel(nextLevel);
|
|
1321
|
+
this.setThinkingLevel(nextLevel, options);
|
|
1307
1322
|
return nextLevel;
|
|
1308
1323
|
}
|
|
1309
1324
|
/**
|
|
@@ -1312,7 +1327,7 @@ export class AgentSession {
|
|
|
1312
1327
|
*/
|
|
1313
1328
|
getAvailableThinkingLevels() {
|
|
1314
1329
|
if (!this.model)
|
|
1315
|
-
return
|
|
1330
|
+
return [...THINKING_LEVEL_OPTIONS];
|
|
1316
1331
|
return getSupportedThinkingLevels(this.model);
|
|
1317
1332
|
}
|
|
1318
1333
|
/**
|
|
@@ -1321,14 +1336,18 @@ export class AgentSession {
|
|
|
1321
1336
|
supportsThinking() {
|
|
1322
1337
|
return !!this.model?.reasoning;
|
|
1323
1338
|
}
|
|
1324
|
-
_getThinkingLevelForModelSwitch(explicitLevel) {
|
|
1339
|
+
_getThinkingLevelForModelSwitch(targetModel, explicitLevel) {
|
|
1325
1340
|
if (explicitLevel !== undefined) {
|
|
1326
1341
|
return explicitLevel;
|
|
1327
1342
|
}
|
|
1328
|
-
|
|
1329
|
-
|
|
1343
|
+
// Per-model default takes priority when switching to a model that has one
|
|
1344
|
+
if (targetModel) {
|
|
1345
|
+
const perModel = this.settingsManager.getModelThinkingLevel(targetModel.provider, targetModel.id);
|
|
1346
|
+
if (perModel !== undefined) {
|
|
1347
|
+
return perModel;
|
|
1348
|
+
}
|
|
1330
1349
|
}
|
|
1331
|
-
return this.thinkingLevel;
|
|
1350
|
+
return this.settingsManager.getDefaultThinkingLevel() ?? this.thinkingLevel ?? DEFAULT_THINKING_LEVEL;
|
|
1332
1351
|
}
|
|
1333
1352
|
_clampThinkingLevel(level, _availableLevels) {
|
|
1334
1353
|
return this.model ? clampThinkingLevel(this.model, level) : "off";
|
|
@@ -1359,15 +1378,30 @@ export class AgentSession {
|
|
|
1359
1378
|
// =========================================================================
|
|
1360
1379
|
// Compaction
|
|
1361
1380
|
// =========================================================================
|
|
1381
|
+
/** Generate Pi's built-in compaction summary for manual and automatic compaction. */
|
|
1382
|
+
async _runDefaultCompaction(preparation, requestModel, apiKey, headers, customInstructions, signal, env, reason) {
|
|
1383
|
+
return compact(preparation, requestModel, apiKey, headers, customInstructions, signal, this.thinkingLevel, this.agent.streamFunction, env, this.settingsManager.getRetrySettings(), this._summarizationRetryCallbacks({ source: "compaction", reason }), undefined);
|
|
1384
|
+
}
|
|
1362
1385
|
/**
|
|
1363
1386
|
* Manually compact the session context.
|
|
1364
|
-
*
|
|
1387
|
+
*
|
|
1388
|
+
* This is the manual entry point used by `/compact`, RPC, and extensions. It is
|
|
1389
|
+
* separate from automatic threshold/overflow compaction, which enters through
|
|
1390
|
+
* `_checkCompaction()` and `_runAutoCompaction()`. After preparation and the
|
|
1391
|
+
* `session_before_compact` hook, both paths call the lower-level `compact()`
|
|
1392
|
+
* function imported from `./compaction/index.ts`, unless the hook cancels or
|
|
1393
|
+
* supplies a custom result.
|
|
1394
|
+
*
|
|
1395
|
+
* Aborts the current agent operation first. Manual compaction never retries or
|
|
1396
|
+
* continues the interrupted agent turn.
|
|
1397
|
+
*
|
|
1365
1398
|
* @param customInstructions Optional instructions for the compaction summary
|
|
1366
1399
|
*/
|
|
1367
1400
|
async compact(customInstructions) {
|
|
1368
1401
|
await this.abort();
|
|
1369
1402
|
this._compactionAbortController = new AbortController();
|
|
1370
1403
|
this._emit({ type: "compaction_start", reason: "manual" });
|
|
1404
|
+
let fromExtension = false;
|
|
1371
1405
|
try {
|
|
1372
1406
|
if (!this.model) {
|
|
1373
1407
|
throw new Error(formatNoModelSelectedMessage());
|
|
@@ -1385,7 +1419,6 @@ export class AgentSession {
|
|
|
1385
1419
|
throw new Error("Nothing to compact (session too small)");
|
|
1386
1420
|
}
|
|
1387
1421
|
let extensionCompaction;
|
|
1388
|
-
let fromExtension = false;
|
|
1389
1422
|
if (this._extensionRunner.hasHandlers("session_before_compact")) {
|
|
1390
1423
|
const result = (await this._extensionRunner.emit({
|
|
1391
1424
|
type: "session_before_compact",
|
|
@@ -1418,8 +1451,8 @@ export class AgentSession {
|
|
|
1418
1451
|
details = extensionCompaction.details;
|
|
1419
1452
|
}
|
|
1420
1453
|
else {
|
|
1421
|
-
//
|
|
1422
|
-
const result = await
|
|
1454
|
+
// Shared default summary generator, also used by automatic compaction.
|
|
1455
|
+
const result = await this._runDefaultCompaction(preparation, requestModel, apiKey, headers, customInstructions, this._compactionAbortController.signal, env, "manual");
|
|
1423
1456
|
summary = result.summary;
|
|
1424
1457
|
firstKeptEntryId = result.firstKeptEntryId;
|
|
1425
1458
|
tokensBefore = result.tokensBefore;
|
|
@@ -1467,6 +1500,7 @@ export class AgentSession {
|
|
|
1467
1500
|
catch (error) {
|
|
1468
1501
|
const message = error instanceof Error ? error.message : String(error);
|
|
1469
1502
|
const aborted = message === "Compaction cancelled" || (error instanceof Error && error.name === "AbortError");
|
|
1503
|
+
const errorMessage = aborted ? undefined : `Compaction failed: ${message}`;
|
|
1470
1504
|
this._compactionAbortController = undefined;
|
|
1471
1505
|
this._emit({
|
|
1472
1506
|
type: "compaction_end",
|
|
@@ -1474,7 +1508,14 @@ export class AgentSession {
|
|
|
1474
1508
|
result: undefined,
|
|
1475
1509
|
aborted,
|
|
1476
1510
|
willRetry: false,
|
|
1477
|
-
errorMessage
|
|
1511
|
+
errorMessage,
|
|
1512
|
+
});
|
|
1513
|
+
await this._emitSessionCompactFailed({
|
|
1514
|
+
reason: "manual",
|
|
1515
|
+
errorMessage,
|
|
1516
|
+
aborted,
|
|
1517
|
+
willRetry: false,
|
|
1518
|
+
fromExtension,
|
|
1478
1519
|
});
|
|
1479
1520
|
throw error;
|
|
1480
1521
|
}
|
|
@@ -1496,16 +1537,25 @@ export class AgentSession {
|
|
|
1496
1537
|
this._branchSummaryAbortController?.abort();
|
|
1497
1538
|
}
|
|
1498
1539
|
/**
|
|
1499
|
-
*
|
|
1500
|
-
*
|
|
1540
|
+
* Dispatch automatic compaction after `agent_end` or before prompt submission.
|
|
1541
|
+
* Manual compaction does not call this method; it enters through `compact()`.
|
|
1542
|
+
*
|
|
1543
|
+
* Automatic cases:
|
|
1544
|
+
* 1. Overflow with retry: a context-overflow error or recoverable length stop;
|
|
1545
|
+
* remove the failed assistant message, compact, and retry the turn once.
|
|
1546
|
+
* 2. Overflow without retry: a successful response exceeded the configured
|
|
1547
|
+
* context window; compact but preserve the completed response.
|
|
1548
|
+
* 3. Threshold without retry: valid or estimated context usage crossed the
|
|
1549
|
+
* configured threshold; compact without retrying the completed response.
|
|
1501
1550
|
*
|
|
1502
|
-
*
|
|
1503
|
-
*
|
|
1504
|
-
*
|
|
1505
|
-
*
|
|
1551
|
+
* Each case calls `_runAutoCompaction()`. After preparation and the
|
|
1552
|
+
* `session_before_compact` hook, that method calls the lower-level `compact()`
|
|
1553
|
+
* function imported from `./compaction/index.ts`, unless the hook cancels or
|
|
1554
|
+
* supplies a custom result.
|
|
1506
1555
|
*
|
|
1507
1556
|
* @param assistantMessage The assistant message to check
|
|
1508
1557
|
* @param skipAbortedCheck If false, include aborted messages (for pre-prompt check). Default: true
|
|
1558
|
+
* @returns Whether the post-run loop should call `agent.continue()` for overflow recovery or queued messages
|
|
1509
1559
|
*/
|
|
1510
1560
|
async _checkCompaction(assistantMessage, skipAbortedCheck = true) {
|
|
1511
1561
|
const settings = this.settingsManager.getCompactionSettings();
|
|
@@ -1528,38 +1578,49 @@ export class AgentSession {
|
|
|
1528
1578
|
if (assistantIsFromBeforeCompaction) {
|
|
1529
1579
|
return false;
|
|
1530
1580
|
}
|
|
1531
|
-
//
|
|
1581
|
+
// Automatic cases 1 and 2: context overflow.
|
|
1532
1582
|
// A length stop is recoverable when output ended below the model's original desired limit,
|
|
1533
1583
|
// independent of the configured context size or any context-clamped provider request limit.
|
|
1534
|
-
|
|
1535
|
-
// assistant answer already completed and agent.continue() cannot continue from an assistant.
|
|
1584
|
+
const contextOverflow = sameModel && isContextOverflow(assistantMessage, contextWindow);
|
|
1536
1585
|
const recoverableLength = sameModel && isRecoverableLength(assistantMessage, this.model?.maxTokens ?? 0);
|
|
1537
|
-
if (
|
|
1586
|
+
if (contextOverflow || recoverableLength) {
|
|
1538
1587
|
const willRetry = assistantMessage.stopReason !== "stop";
|
|
1588
|
+
// Case 2: the response completed successfully. Compact, but do not retry because
|
|
1589
|
+
// agent.continue() cannot continue from a completed assistant response.
|
|
1539
1590
|
if (!willRetry) {
|
|
1540
1591
|
return await this._runAutoCompaction("overflow", false);
|
|
1541
1592
|
}
|
|
1542
1593
|
if (this._overflowRecoveryAttempted) {
|
|
1594
|
+
const errorMessage = contextOverflow
|
|
1595
|
+
? "Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model."
|
|
1596
|
+
: "Truncated response recovery failed after one compact-and-retry attempt.";
|
|
1543
1597
|
this._emit({
|
|
1544
1598
|
type: "compaction_end",
|
|
1545
1599
|
reason: "overflow",
|
|
1546
1600
|
result: undefined,
|
|
1547
1601
|
aborted: false,
|
|
1548
1602
|
willRetry: false,
|
|
1549
|
-
errorMessage
|
|
1603
|
+
errorMessage,
|
|
1604
|
+
});
|
|
1605
|
+
await this._emitSessionCompactFailed({
|
|
1606
|
+
reason: "overflow",
|
|
1607
|
+
errorMessage,
|
|
1608
|
+
aborted: false,
|
|
1609
|
+
willRetry: false,
|
|
1610
|
+
fromExtension: false,
|
|
1550
1611
|
});
|
|
1551
1612
|
return false;
|
|
1552
1613
|
}
|
|
1614
|
+
// Case 1: remove the failed or truncated message from agent state, compact, and
|
|
1615
|
+
// retry once. The message remains in session history but is excluded from retry context.
|
|
1553
1616
|
this._overflowRecoveryAttempted = true;
|
|
1554
|
-
// Remove the failed or truncated message from agent state. It remains in session history,
|
|
1555
|
-
// but must not be included in the compact-and-retry context.
|
|
1556
1617
|
const messages = this.agent.state.messages;
|
|
1557
1618
|
if (messages.length > 0 && messages[messages.length - 1].role === "assistant") {
|
|
1558
1619
|
this.agent.state.messages = messages.slice(0, -1);
|
|
1559
1620
|
}
|
|
1560
1621
|
return await this._runAutoCompaction("overflow", willRetry);
|
|
1561
1622
|
}
|
|
1562
|
-
// Case
|
|
1623
|
+
// Case 3: threshold compaction without retry.
|
|
1563
1624
|
// For error messages or all-zero usage messages, estimate from the last valid response.
|
|
1564
1625
|
// This ensures sessions that hit persistent API errors (e.g. 529) or malformed zero-usage
|
|
1565
1626
|
// responses can still compact and do not reset context accounting.
|
|
@@ -1568,16 +1629,18 @@ export class AgentSession {
|
|
|
1568
1629
|
if (assistantMessage.stopReason === "error" || directContextTokens === 0) {
|
|
1569
1630
|
const messages = this.agent.state.messages;
|
|
1570
1631
|
const estimate = estimateContextTokens(messages);
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1632
|
+
// Without provider usage, estimate.tokens is the pure message-size estimate.
|
|
1633
|
+
// Only usage-backed estimates need the stale pre-compaction check.
|
|
1634
|
+
if (estimate.lastUsageIndex !== null) {
|
|
1635
|
+
// Verify the usage source is post-compaction. Kept pre-compaction messages
|
|
1636
|
+
// have stale usage reflecting the old (larger) context and would falsely
|
|
1637
|
+
// trigger compaction right after one just finished.
|
|
1638
|
+
const usageMsg = messages[estimate.lastUsageIndex];
|
|
1639
|
+
if (compactionEntry &&
|
|
1640
|
+
usageMsg.role === "assistant" &&
|
|
1641
|
+
usageMsg.timestamp <= new Date(compactionEntry.timestamp).getTime()) {
|
|
1642
|
+
return false;
|
|
1643
|
+
}
|
|
1581
1644
|
}
|
|
1582
1645
|
contextTokens = estimate.tokens;
|
|
1583
1646
|
}
|
|
@@ -1590,11 +1653,19 @@ export class AgentSession {
|
|
|
1590
1653
|
return false;
|
|
1591
1654
|
}
|
|
1592
1655
|
/**
|
|
1593
|
-
*
|
|
1656
|
+
* Execute threshold or overflow compaction. Manual compaction uses
|
|
1657
|
+
* `AgentSession.compact()` instead. Both paths call the lower-level `compact()`
|
|
1658
|
+
* function imported from `./compaction/index.ts` after preparation and extension
|
|
1659
|
+
* interception.
|
|
1660
|
+
*
|
|
1661
|
+
* @param reason Automatic trigger selected by `_checkCompaction()`
|
|
1662
|
+
* @param willRetry Whether to continue the interrupted turn after overflow compaction
|
|
1663
|
+
* @returns Whether the post-run loop should call `agent.continue()`
|
|
1594
1664
|
*/
|
|
1595
1665
|
async _runAutoCompaction(reason, willRetry) {
|
|
1596
1666
|
const settings = this.settingsManager.getCompactionSettings();
|
|
1597
1667
|
let started = false;
|
|
1668
|
+
let fromExtension = false;
|
|
1598
1669
|
try {
|
|
1599
1670
|
if (!this.model) {
|
|
1600
1671
|
return false;
|
|
@@ -1609,7 +1680,6 @@ export class AgentSession {
|
|
|
1609
1680
|
this._autoCompactionAbortController = new AbortController();
|
|
1610
1681
|
started = true;
|
|
1611
1682
|
let extensionCompaction;
|
|
1612
|
-
let fromExtension = false;
|
|
1613
1683
|
if (this._extensionRunner.hasHandlers("session_before_compact")) {
|
|
1614
1684
|
const extensionResult = (await this._extensionRunner.emit({
|
|
1615
1685
|
type: "session_before_compact",
|
|
@@ -1628,6 +1698,12 @@ export class AgentSession {
|
|
|
1628
1698
|
aborted: true,
|
|
1629
1699
|
willRetry: false,
|
|
1630
1700
|
});
|
|
1701
|
+
await this._emitSessionCompactFailed({
|
|
1702
|
+
reason,
|
|
1703
|
+
aborted: true,
|
|
1704
|
+
willRetry: false,
|
|
1705
|
+
fromExtension: false,
|
|
1706
|
+
});
|
|
1631
1707
|
return false;
|
|
1632
1708
|
}
|
|
1633
1709
|
if (extensionResult?.compaction) {
|
|
@@ -1649,8 +1725,8 @@ export class AgentSession {
|
|
|
1649
1725
|
details = extensionCompaction.details;
|
|
1650
1726
|
}
|
|
1651
1727
|
else {
|
|
1652
|
-
//
|
|
1653
|
-
const compactResult = await
|
|
1728
|
+
// Shared default summary generator, also used by manual compaction.
|
|
1729
|
+
const compactResult = await this._runDefaultCompaction(preparation, requestModel, apiKey, headers, undefined, this._autoCompactionAbortController.signal, env, reason);
|
|
1654
1730
|
summary = compactResult.summary;
|
|
1655
1731
|
firstKeptEntryId = compactResult.firstKeptEntryId;
|
|
1656
1732
|
tokensBefore = compactResult.tokensBefore;
|
|
@@ -1665,6 +1741,12 @@ export class AgentSession {
|
|
|
1665
1741
|
aborted: true,
|
|
1666
1742
|
willRetry: false,
|
|
1667
1743
|
});
|
|
1744
|
+
await this._emitSessionCompactFailed({
|
|
1745
|
+
reason,
|
|
1746
|
+
aborted: true,
|
|
1747
|
+
willRetry: false,
|
|
1748
|
+
fromExtension,
|
|
1749
|
+
});
|
|
1668
1750
|
return false;
|
|
1669
1751
|
}
|
|
1670
1752
|
this.sessionManager.appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromExtension, usage);
|
|
@@ -1711,15 +1793,23 @@ export class AgentSession {
|
|
|
1711
1793
|
catch (error) {
|
|
1712
1794
|
const errorMessage = error instanceof Error ? error.message : "compaction failed";
|
|
1713
1795
|
if (started) {
|
|
1796
|
+
const formattedErrorMessage = reason === "overflow"
|
|
1797
|
+
? `Context overflow recovery failed: ${errorMessage}`
|
|
1798
|
+
: `Auto-compaction failed: ${errorMessage}`;
|
|
1714
1799
|
this._emit({
|
|
1715
1800
|
type: "compaction_end",
|
|
1716
1801
|
reason,
|
|
1717
1802
|
result: undefined,
|
|
1718
1803
|
aborted: false,
|
|
1719
1804
|
willRetry: false,
|
|
1720
|
-
errorMessage:
|
|
1721
|
-
|
|
1722
|
-
|
|
1805
|
+
errorMessage: formattedErrorMessage,
|
|
1806
|
+
});
|
|
1807
|
+
await this._emitSessionCompactFailed({
|
|
1808
|
+
reason,
|
|
1809
|
+
errorMessage: formattedErrorMessage,
|
|
1810
|
+
aborted: false,
|
|
1811
|
+
willRetry: false,
|
|
1812
|
+
fromExtension,
|
|
1723
1813
|
});
|
|
1724
1814
|
}
|
|
1725
1815
|
return false;
|
|
@@ -2583,11 +2673,11 @@ export class AgentSession {
|
|
|
2583
2673
|
/**
|
|
2584
2674
|
* Export session to HTML.
|
|
2585
2675
|
* @param outputPath Optional output path (defaults to session directory)
|
|
2676
|
+
* @param options Optional export presentation settings
|
|
2586
2677
|
* @returns Path to exported file
|
|
2587
2678
|
*/
|
|
2588
|
-
async exportToHtml(outputPath) {
|
|
2589
|
-
const
|
|
2590
|
-
const themeName = configuredThemeName && getThemeByName(configuredThemeName) ? configuredThemeName : undefined;
|
|
2679
|
+
async exportToHtml(outputPath, options = {}) {
|
|
2680
|
+
const themeName = [options.themeName, this.settingsManager.getTheme()].find((candidate) => candidate !== undefined && getThemeByName(candidate) !== undefined);
|
|
2591
2681
|
// Create tool renderer if we have an extension runner (for custom tool HTML rendering)
|
|
2592
2682
|
const toolRenderer = createToolHtmlRenderer({
|
|
2593
2683
|
getToolDefinition: (name) => this.getToolDefinition(name),
|
|
@@ -2607,29 +2697,7 @@ export class AgentSession {
|
|
|
2607
2697
|
* @returns The resolved output file path.
|
|
2608
2698
|
*/
|
|
2609
2699
|
exportToJsonl(outputPath) {
|
|
2610
|
-
|
|
2611
|
-
const dir = dirname(filePath);
|
|
2612
|
-
if (!existsSync(dir)) {
|
|
2613
|
-
mkdirSync(dir, { recursive: true });
|
|
2614
|
-
}
|
|
2615
|
-
const header = {
|
|
2616
|
-
type: "session",
|
|
2617
|
-
version: CURRENT_SESSION_VERSION,
|
|
2618
|
-
id: this.sessionManager.getSessionId(),
|
|
2619
|
-
timestamp: new Date().toISOString(),
|
|
2620
|
-
cwd: this.sessionManager.getCwd(),
|
|
2621
|
-
};
|
|
2622
|
-
const branchEntries = this.sessionManager.getBranch();
|
|
2623
|
-
const lines = [JSON.stringify(header)];
|
|
2624
|
-
// Re-chain parentIds to form a linear sequence
|
|
2625
|
-
let prevId = null;
|
|
2626
|
-
for (const entry of branchEntries) {
|
|
2627
|
-
const linear = { ...entry, parentId: prevId };
|
|
2628
|
-
lines.push(JSON.stringify(linear));
|
|
2629
|
-
prevId = entry.id;
|
|
2630
|
-
}
|
|
2631
|
-
writeFileSync(filePath, `${lines.join("\n")}\n`);
|
|
2632
|
-
return filePath;
|
|
2700
|
+
return exportSessionToJsonl(this.sessionManager, outputPath);
|
|
2633
2701
|
}
|
|
2634
2702
|
// =========================================================================
|
|
2635
2703
|
// Utilities
|