@earendil-works/pi-coding-agent 0.85.1 → 0.86.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 +110 -0
- package/README.md +3 -1
- package/dist/bundle/chunks/anthropic-messages-MYU5ZMRF.js +6 -0
- package/dist/bundle/chunks/azure-openai-responses-HUSQ3GP2.js +2 -0
- package/dist/bundle/chunks/bedrock-converse-stream.js +47 -38
- package/dist/bundle/chunks/chunk-A3JYRWB6.js +2 -0
- package/dist/bundle/chunks/chunk-CMRUVXTE.js +1562 -0
- package/dist/bundle/chunks/chunk-DTD7JQ7Y.js +42 -0
- package/dist/bundle/chunks/chunk-FUXEF6JQ.js +44 -0
- package/dist/bundle/chunks/chunk-HTEQD2HM.js +2 -0
- package/dist/bundle/chunks/{chunk-IDDQWTHI.js → chunk-RCZIEVGO.js} +10 -1
- package/dist/bundle/chunks/chunk-S7SZN6Z3.js +2 -0
- package/dist/bundle/chunks/chunk-WIUZI2CJ.js +11 -0
- package/dist/bundle/chunks/github-copilot.js +1 -1
- package/dist/bundle/chunks/google-generative-ai-IMS5EK2Y.js +2 -0
- package/dist/bundle/chunks/google-vertex-O4YJEQUW.js +2 -0
- package/dist/bundle/chunks/jiti-loader-C3NU2SDH.js +21 -0
- package/dist/bundle/chunks/jiti-static-loader-E6ANQD5T.js +2 -0
- package/dist/bundle/chunks/meta.js +2 -0
- package/dist/bundle/chunks/mistral-conversations-NOSQHBEY.js +5 -0
- package/dist/bundle/chunks/{node-KG362ECQ.js → node-O3RIBJRH.js} +1 -1
- package/dist/bundle/chunks/openai-codex-responses-QDSOTBBO.js +10 -0
- package/dist/bundle/chunks/openai-completions-CYGM3XXP.js +7 -0
- package/dist/bundle/chunks/openai-responses-HWEUZ6WZ.js +2 -0
- package/dist/bundle/chunks/{pi-messages-PML4SPVJ.js → pi-messages-GFKBWJHZ.js} +1 -1
- package/dist/bundle/chunks/virtual-modules-MGTKWDID.js +2 -0
- package/dist/bundle/cli-runtime.js +3 -0
- package/dist/bundle/cli.js +4 -2
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +1 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/session-picker.d.ts +1 -1
- package/dist/cli/session-picker.d.ts.map +1 -1
- package/dist/cli/session-picker.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +56 -6
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +293 -155
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/bug-report-upload.d.ts +12 -0
- package/dist/core/bug-report-upload.d.ts.map +1 -0
- package/dist/core/bug-report-upload.js +22 -0
- package/dist/core/bug-report-upload.js.map +1 -0
- package/dist/core/bug-report.d.ts +176 -0
- package/dist/core/bug-report.d.ts.map +1 -0
- package/dist/core/bug-report.js +292 -0
- package/dist/core/bug-report.js.map +1 -0
- package/dist/core/cache-stats.d.ts.map +1 -1
- package/dist/core/cache-stats.js +12 -1
- package/dist/core/cache-stats.js.map +1 -1
- package/dist/core/cache-warmer.d.ts +102 -0
- package/dist/core/cache-warmer.d.ts.map +1 -0
- package/dist/core/cache-warmer.js +342 -0
- package/dist/core/cache-warmer.js.map +1 -0
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +2 -2
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +2 -2
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +11 -12
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/crash-log.d.ts +22 -0
- package/dist/core/crash-log.d.ts.map +1 -0
- package/dist/core/crash-log.js +71 -0
- package/dist/core/crash-log.js.map +1 -0
- package/dist/core/experimental.d.ts +0 -4
- package/dist/core/experimental.d.ts.map +1 -1
- package/dist/core/experimental.js +0 -4
- package/dist/core/experimental.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/jiti-loader.d.ts +2 -0
- package/dist/core/extensions/jiti-loader.d.ts.map +1 -0
- package/dist/core/extensions/jiti-loader.js +4 -0
- package/dist/core/extensions/jiti-loader.js.map +1 -0
- package/dist/core/extensions/jiti-static-loader.d.ts +2 -0
- package/dist/core/extensions/jiti-static-loader.d.ts.map +1 -0
- package/dist/core/extensions/jiti-static-loader.js +4 -0
- package/dist/core/extensions/jiti-static-loader.js.map +1 -0
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +38 -51
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +10 -7
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +85 -67
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +60 -50
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/extensions/virtual-modules.d.ts +3 -0
- package/dist/core/extensions/virtual-modules.d.ts.map +1 -0
- package/dist/core/extensions/virtual-modules.js +38 -0
- package/dist/core/extensions/virtual-modules.js.map +1 -0
- package/dist/core/extensions/wrapper.d.ts.map +1 -1
- package/dist/core/extensions/wrapper.js +1 -20
- package/dist/core/extensions/wrapper.js.map +1 -1
- package/dist/core/index.d.ts +2 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/keybindings.d.ts +1 -1
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +1 -1
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +1 -0
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-config.d.ts +101 -20
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +25 -18
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-registry.d.ts +5 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +8 -0
- package/dist/core/model-registry.js.map +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/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +5 -3
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/provider-composer.d.ts +3 -2
- package/dist/core/provider-composer.d.ts.map +1 -1
- package/dist/core/provider-composer.js +2 -0
- package/dist/core/provider-composer.js.map +1 -1
- package/dist/core/radius.d.ts +3 -0
- package/dist/core/radius.d.ts.map +1 -1
- package/dist/core/radius.js +6 -0
- package/dist/core/radius.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +60 -38
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-export.d.ts +6 -2
- package/dist/core/session-export.d.ts.map +1 -1
- package/dist/core/session-export.js +14 -13
- package/dist/core/session-export.js.map +1 -1
- package/dist/core/session-manager.d.ts +29 -6
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +159 -96
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +20 -4
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +43 -7
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts +49 -6
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +121 -92
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +2 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +10 -4
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +1 -2
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +1 -2
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/renderers/bash.d.ts.map +1 -1
- package/dist/core/tools/renderers/bash.js +9 -1
- package/dist/core/tools/renderers/bash.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +1 -2
- package/dist/core/tools/write.js.map +1 -1
- package/dist/core/usage-totals.d.ts +1 -1
- package/dist/core/usage-totals.d.ts.map +1 -1
- package/dist/core/usage-totals.js +5 -1
- package/dist/core/usage-totals.js.map +1 -1
- package/dist/extensions/llama/client.d.ts +2 -0
- package/dist/extensions/llama/client.d.ts.map +1 -1
- package/dist/extensions/llama/client.js +7 -3
- package/dist/extensions/llama/client.js.map +1 -1
- package/dist/extensions/llama/provider.d.ts.map +1 -1
- package/dist/extensions/llama/provider.js +20 -5
- package/dist/extensions/llama/provider.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +13 -9
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +2 -2
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/bug-report.d.ts +16 -0
- package/dist/modes/interactive/bug-report.d.ts.map +1 -0
- package/dist/modes/interactive/bug-report.js +206 -0
- package/dist/modes/interactive/bug-report.js.map +1 -0
- package/dist/modes/interactive/chat-viewport.d.ts.map +1 -1
- package/dist/modes/interactive/chat-viewport.js +1 -1
- package/dist/modes/interactive/chat-viewport.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +12 -5
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +12 -5
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +3 -3
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts +4 -1
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +7 -2
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/extension-input.d.ts +2 -0
- package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-input.js +6 -0
- package/dist/modes/interactive/components/extension-input.js.map +1 -1
- package/dist/modes/interactive/components/extension-selector.d.ts +1 -0
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-selector.js +4 -0
- package/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +4 -1
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts +5 -5
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +74 -48
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +11 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.js +11 -4
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/dist/modes/interactive/components/status-indicator.d.ts +2 -2
- package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
- package/dist/modes/interactive/components/status-indicator.js +7 -7
- package/dist/modes/interactive/components/status-indicator.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +18 -9
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +2 -0
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +15 -2
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +227 -84
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/session-share.d.ts +2 -0
- package/dist/modes/interactive/session-share.d.ts.map +1 -1
- package/dist/modes/interactive/session-share.js +8 -4
- package/dist/modes/interactive/session-share.js.map +1 -1
- package/dist/modes/interactive/tui-renderer.d.ts.map +1 -1
- package/dist/modes/interactive/tui-renderer.js +2 -2
- package/dist/modes/interactive/tui-renderer.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +2 -2
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/utils/clipboard-command.d.ts +7 -0
- package/dist/utils/clipboard-command.d.ts.map +1 -0
- package/dist/utils/clipboard-command.js +45 -0
- package/dist/utils/clipboard-command.js.map +1 -0
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +53 -81
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +111 -121
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/wsl.d.ts +3 -0
- package/dist/utils/wsl.d.ts.map +1 -0
- package/dist/utils/wsl.js +15 -0
- package/dist/utils/wsl.js.map +1 -0
- package/dist/utils/zip.d.ts +7 -0
- package/dist/utils/zip.d.ts.map +1 -0
- package/dist/utils/zip.js +60 -0
- package/dist/utils/zip.js.map +1 -0
- package/docs/compaction.md +39 -13
- package/docs/custom-provider.md +22 -13
- package/docs/development.md +4 -4
- package/docs/docs.json +4 -0
- package/docs/environment-variables.md +1 -0
- package/docs/extensions.md +57 -43
- package/docs/json.md +4 -4
- package/docs/models.md +33 -2
- package/docs/providers.md +10 -2
- package/docs/sdk.md +4 -2
- package/docs/security.md +1 -1
- package/docs/session-format.md +82 -40
- package/docs/sessions.md +27 -0
- package/docs/settings.md +60 -1
- package/docs/termux.md +0 -1
- package/docs/tui.md +2 -2
- package/docs/usage.md +1 -0
- package/examples/extensions/README.md +0 -1
- package/examples/extensions/custom-provider-anthropic/index.ts +18 -12
- 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/index.ts +2 -2
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/prompt-customizer.ts +19 -67
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +435 -762
- package/package.json +17 -23
- package/dist/bundle/chunks/anthropic-messages-VWZZOSJQ.js +0 -6
- package/dist/bundle/chunks/azure-openai-responses-BJLAM6CD.js +0 -2
- package/dist/bundle/chunks/chunk-AXIIZGTV.js +0 -2
- package/dist/bundle/chunks/chunk-CLNPYIDP.js +0 -42
- package/dist/bundle/chunks/chunk-GMWCTUPB.js +0 -2
- package/dist/bundle/chunks/chunk-JVUZSMYM.js +0 -1547
- package/dist/bundle/chunks/chunk-OUXLLA64.js +0 -11
- package/dist/bundle/chunks/chunk-U6ZMQKGD.js +0 -50
- package/dist/bundle/chunks/chunk-UAQELI3K.js +0 -2
- package/dist/bundle/chunks/google-generative-ai-Q2K7FBDI.js +0 -2
- package/dist/bundle/chunks/google-vertex-7UJBF4S7.js +0 -2
- package/dist/bundle/chunks/mistral-conversations-4M6BZBX6.js +0 -5
- package/dist/bundle/chunks/openai-codex-responses-R6VYZTVY.js +0 -10
- package/dist/bundle/chunks/openai-completions-EKZT2IH2.js +0 -7
- package/dist/bundle/chunks/openai-responses-TFDINO6W.js +0 -2
- package/dist/utils/clipboard-native.d.ts +0 -11
- package/dist/utils/clipboard-native.d.ts.map +0 -1
- package/dist/utils/clipboard-native.js +0 -20
- package/dist/utils/clipboard-native.js.map +0 -1
- package/examples/extensions/kimi-deferred-tools.ts +0 -61
|
@@ -6,6 +6,7 @@ import * as crypto from "node:crypto";
|
|
|
6
6
|
import * as fs from "node:fs";
|
|
7
7
|
import * as os from "node:os";
|
|
8
8
|
import * as path from "node:path";
|
|
9
|
+
import { isRetryableAssistantError, } from "@earendil-works/pi-ai/compat";
|
|
9
10
|
import * as TuiLayouts from "@earendil-works/pi-tui";
|
|
10
11
|
import { CombinedAutocompleteProvider, Container, fuzzyFilter, getCapabilities, hyperlink, Markdown, matchesKey, Spacer, setCapabilityOverrides, setKeybindings, Text, TruncatedText, TuiAltScreen, TuiMainScreen, visibleWidth, } from "@earendil-works/pi-tui";
|
|
11
12
|
import chalk from "chalk";
|
|
@@ -14,6 +15,8 @@ import { APP_NAME, APP_TITLE, CONFIG_DIR_NAME, getAgentDir, getAuthPath, getDebu
|
|
|
14
15
|
import { parseSkillBlock } from "../../core/agent-session.js";
|
|
15
16
|
import { SessionImportFileNotFoundError } from "../../core/agent-session-runtime.js";
|
|
16
17
|
import { CACHE_TTL_MS, collectCacheMisses, computeCacheWaste, detectCacheMiss, } from "../../core/cache-stats.js";
|
|
18
|
+
import { formatCacheWarmingStatus, formatCacheWarmingUsage } from "../../core/cache-warmer.js";
|
|
19
|
+
import { recordCrash, takeUnnotifiedCrash } from "../../core/crash-log.js";
|
|
17
20
|
import { DEFAULT_THINKING_LEVEL, THINKING_LEVEL_OPTIONS } from "../../core/defaults.js";
|
|
18
21
|
import { FooterDataProvider } from "../../core/footer-data-provider.js";
|
|
19
22
|
import { configureHttpDispatcher, formatHttpIdleTimeoutMs } from "../../core/http-dispatcher.js";
|
|
@@ -23,7 +26,7 @@ import { defaultModelPerProvider, findExactModelReferenceMatch, resolveModelScop
|
|
|
23
26
|
import { CredentialSynchronizationError } from "../../core/model-runtime.js";
|
|
24
27
|
import { DefaultPackageManager } from "../../core/package-manager.js";
|
|
25
28
|
import { formatMissingSessionCwdPrompt, MissingSessionCwdError } from "../../core/session-cwd.js";
|
|
26
|
-
import { SessionManager, sessionEntryToContextMessages } from "../../core/session-manager.js";
|
|
29
|
+
import { SessionManager, sessionEntryToContextMessages, } from "../../core/session-manager.js";
|
|
27
30
|
import { BUILTIN_SLASH_COMMANDS } from "../../core/slash-commands.js";
|
|
28
31
|
import { isInstallTelemetryEnabled } from "../../core/telemetry.js";
|
|
29
32
|
import { withBuiltInRenderers } from "../../core/tools/renderers/index.js";
|
|
@@ -39,6 +42,7 @@ import { killTrackedDetachedChildren } from "../../utils/shell.js";
|
|
|
39
42
|
import { loadAllHighlightLanguages } from "../../utils/syntax-highlight.js";
|
|
40
43
|
import { ensureTool } from "../../utils/tools-manager.js";
|
|
41
44
|
import { checkForNewPiVersion } from "../../utils/version-check.js";
|
|
45
|
+
import { reportBug } from "./bug-report.js";
|
|
42
46
|
import { createChatViewport } from "./chat-viewport.js";
|
|
43
47
|
import { ArminComponent } from "./components/armin.js";
|
|
44
48
|
import { AssistantMessageComponent } from "./components/assistant-message.js";
|
|
@@ -106,6 +110,9 @@ function isCustomSessionEntry(item) {
|
|
|
106
110
|
function isCompactionCostNotice(item) {
|
|
107
111
|
return "type" in item && item.type === "compaction_cost";
|
|
108
112
|
}
|
|
113
|
+
function isUsageSessionEntry(item) {
|
|
114
|
+
return "type" in item && item.type === "usage";
|
|
115
|
+
}
|
|
109
116
|
const DEAD_TERMINAL_ERROR_CODES = new Set(["EIO", "EPIPE", "ENOTCONN"]);
|
|
110
117
|
function isDeadTerminalError(error) {
|
|
111
118
|
if (!error || typeof error !== "object" || !("code" in error)) {
|
|
@@ -267,6 +274,8 @@ export class InteractiveMode {
|
|
|
267
274
|
compactionQueuedMessages = [];
|
|
268
275
|
// Shutdown state
|
|
269
276
|
shutdownRequested = false;
|
|
277
|
+
/** The `/bug` hint is shown at most once per session so error output stays readable. */
|
|
278
|
+
bugReportHintShown = false;
|
|
270
279
|
// Extension UI state
|
|
271
280
|
extensionSelector = undefined;
|
|
272
281
|
extensionInput = undefined;
|
|
@@ -322,6 +331,7 @@ export class InteractiveMode {
|
|
|
322
331
|
tuiMode,
|
|
323
332
|
showHardwareCursor: this.settingsManager.getShowHardwareCursor(),
|
|
324
333
|
logDirectory: getAgentDir(),
|
|
334
|
+
terminal: options.terminal,
|
|
325
335
|
onRightClickPaste: this.onRightClickPaste,
|
|
326
336
|
fullscreenCopyOnSelect: this.settingsManager.getFullscreenCopyOnSelect(),
|
|
327
337
|
});
|
|
@@ -809,6 +819,11 @@ export class InteractiveMode {
|
|
|
809
819
|
if (modelFallbackMessage) {
|
|
810
820
|
this.showWarning(modelFallbackMessage);
|
|
811
821
|
}
|
|
822
|
+
const crash = takeUnnotifiedCrash();
|
|
823
|
+
if (crash) {
|
|
824
|
+
const when = new Date(crash.timestamp).toLocaleString();
|
|
825
|
+
this.showWarning(`${APP_NAME} crashed on ${when} (${crash.message}). Run /bug to report it; the crash details are attached automatically.`);
|
|
826
|
+
}
|
|
812
827
|
void this.maybeWarnAboutAnthropicSubscriptionAuth();
|
|
813
828
|
// Process initial messages
|
|
814
829
|
if (initialMessage) {
|
|
@@ -1525,10 +1540,45 @@ export class InteractiveMode {
|
|
|
1525
1540
|
async handleFatalRuntimeError(prefix, error) {
|
|
1526
1541
|
const message = error instanceof Error ? error.message : String(error);
|
|
1527
1542
|
this.showError(`${prefix}: ${message}`);
|
|
1543
|
+
if (this.recordCrash("fatal_error", error)) {
|
|
1544
|
+
this.chatContainer.addChild(new Text(theme.fg("muted", this.crashReportInstructions()), this.outputPad, 0));
|
|
1545
|
+
}
|
|
1528
1546
|
stopThemeWatcher();
|
|
1529
1547
|
this.stop("transcript");
|
|
1530
1548
|
process.exit(1);
|
|
1531
1549
|
}
|
|
1550
|
+
/** Persist a crash so the next start can point the user at `/bug`. Returns false when nothing was written. */
|
|
1551
|
+
recordCrash(kind, error) {
|
|
1552
|
+
try {
|
|
1553
|
+
return (recordCrash({
|
|
1554
|
+
kind,
|
|
1555
|
+
error,
|
|
1556
|
+
sessionFile: this.session.sessionFile,
|
|
1557
|
+
cwd: this.session.sessionManager.getCwd(),
|
|
1558
|
+
}) !== undefined);
|
|
1559
|
+
}
|
|
1560
|
+
catch {
|
|
1561
|
+
return false;
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
crashReportInstructions() {
|
|
1565
|
+
const resume = this.session.sessionFile ? `run \`${APP_NAME} -r\` to resume the session, then` : "start pi and";
|
|
1566
|
+
return `To report this crash: ${resume} run /bug. The crash details are attached automatically.`;
|
|
1567
|
+
}
|
|
1568
|
+
suggestBugReport() {
|
|
1569
|
+
if (this.bugReportHintShown)
|
|
1570
|
+
return;
|
|
1571
|
+
this.bugReportHintShown = true;
|
|
1572
|
+
this.chatContainer.addChild(new Text(theme.fg("muted", `If this looks like a ${APP_NAME} bug, /bug sends a report to the developers.`), this.outputPad, 0));
|
|
1573
|
+
this.ui.requestRender();
|
|
1574
|
+
}
|
|
1575
|
+
maybeSuggestBugReport(message) {
|
|
1576
|
+
if (message.stopReason !== "error" || isRetryableAssistantError(message))
|
|
1577
|
+
return;
|
|
1578
|
+
if (/\b(?:abort(?:ed)?|cancel(?:l?ed)?)\b/i.test(message.errorMessage ?? ""))
|
|
1579
|
+
return;
|
|
1580
|
+
this.suggestBugReport();
|
|
1581
|
+
}
|
|
1532
1582
|
renderCurrentSessionState() {
|
|
1533
1583
|
this.loadedResourcesContainer.clear();
|
|
1534
1584
|
this.chatContainer.clear();
|
|
@@ -1630,7 +1680,7 @@ export class InteractiveMode {
|
|
|
1630
1680
|
this.activeWorkingIndicatorEmbedded = false;
|
|
1631
1681
|
this.statusContainer.clear();
|
|
1632
1682
|
this.setEditorWorkingStatusIndicator(undefined);
|
|
1633
|
-
if (
|
|
1683
|
+
if (this.setEditorWorkingStatusIndicator(indicator)) {
|
|
1634
1684
|
this.activeWorkingIndicatorEmbedded = true;
|
|
1635
1685
|
return;
|
|
1636
1686
|
}
|
|
@@ -1641,7 +1691,7 @@ export class InteractiveMode {
|
|
|
1641
1691
|
return;
|
|
1642
1692
|
}
|
|
1643
1693
|
const clearedIndicator = this.activeStatusIndicator;
|
|
1644
|
-
const clearedIndicatorWasEmbedded =
|
|
1694
|
+
const clearedIndicatorWasEmbedded = this.activeWorkingIndicatorEmbedded;
|
|
1645
1695
|
clearedIndicator?.dispose();
|
|
1646
1696
|
this.activeStatusIndicator = undefined;
|
|
1647
1697
|
this.activeWorkingIndicatorEmbedded = false;
|
|
@@ -2130,7 +2180,7 @@ export class InteractiveMode {
|
|
|
2130
2180
|
this.editor = this.defaultEditor;
|
|
2131
2181
|
}
|
|
2132
2182
|
this.editorContainer.addChild(this.editor);
|
|
2133
|
-
if (this.activeStatusIndicator
|
|
2183
|
+
if (this.activeStatusIndicator) {
|
|
2134
2184
|
this.statusContainer.clear();
|
|
2135
2185
|
this.activeWorkingIndicatorEmbedded = this.setEditorWorkingStatusIndicator(this.activeStatusIndicator);
|
|
2136
2186
|
if (!this.activeWorkingIndicatorEmbedded) {
|
|
@@ -2401,6 +2451,12 @@ export class InteractiveMode {
|
|
|
2401
2451
|
this.editor.setText("");
|
|
2402
2452
|
return;
|
|
2403
2453
|
}
|
|
2454
|
+
if (text === "/bug" || text.startsWith("/bug ")) {
|
|
2455
|
+
const hint = text.slice("/bug".length).trim();
|
|
2456
|
+
this.editor.setText("");
|
|
2457
|
+
await this.handleBugCommand(hint ? hint : undefined);
|
|
2458
|
+
return;
|
|
2459
|
+
}
|
|
2404
2460
|
if (text === "/copy") {
|
|
2405
2461
|
await this.handleCopyCommand();
|
|
2406
2462
|
this.editor.setText("");
|
|
@@ -2592,6 +2648,10 @@ export class InteractiveMode {
|
|
|
2592
2648
|
this.addCustomEntryToChat(event.entry);
|
|
2593
2649
|
this.ui.requestRender();
|
|
2594
2650
|
}
|
|
2651
|
+
else if (event.entry.type === "usage" && event.entry.kind === "cache_warm") {
|
|
2652
|
+
this.addCacheWarmingUsage(event.entry);
|
|
2653
|
+
this.ui.requestRender();
|
|
2654
|
+
}
|
|
2595
2655
|
break;
|
|
2596
2656
|
case "session_info_changed":
|
|
2597
2657
|
this.updateTerminalTitle();
|
|
@@ -2672,13 +2732,14 @@ export class InteractiveMode {
|
|
|
2672
2732
|
});
|
|
2673
2733
|
}
|
|
2674
2734
|
this.pendingTools.clear();
|
|
2735
|
+
this.maybeSuggestBugReport(this.streamingMessage);
|
|
2675
2736
|
}
|
|
2676
2737
|
else {
|
|
2677
2738
|
// Args are now complete - trigger diff computation for edit tools
|
|
2678
2739
|
for (const [, component] of this.pendingTools.entries()) {
|
|
2679
2740
|
component.setArgsComplete();
|
|
2680
2741
|
}
|
|
2681
|
-
this.
|
|
2742
|
+
this.maybeShowThinkingDropNotice(this.streamingMessage);
|
|
2682
2743
|
this.maybeShowCacheMissNotice(this.streamingMessage);
|
|
2683
2744
|
}
|
|
2684
2745
|
this.streamingComponent = undefined;
|
|
@@ -2945,6 +3006,8 @@ export class InteractiveMode {
|
|
|
2945
3006
|
this.chatContainer.addChild(component);
|
|
2946
3007
|
break;
|
|
2947
3008
|
}
|
|
3009
|
+
case "system":
|
|
3010
|
+
break;
|
|
2948
3011
|
case "user": {
|
|
2949
3012
|
const textContent = this.getUserMessageText(message);
|
|
2950
3013
|
if (textContent) {
|
|
@@ -2991,8 +3054,8 @@ export class InteractiveMode {
|
|
|
2991
3054
|
renderSessionItems(items, options = {}) {
|
|
2992
3055
|
this.pendingTools.clear();
|
|
2993
3056
|
const renderedPendingTools = new Map();
|
|
2994
|
-
// Cache
|
|
2995
|
-
//
|
|
3057
|
+
// Cache misses are not persisted, unlike successful cache-warming usage.
|
|
3058
|
+
// Re-derive them and inject them after the assistant messages that paid for them.
|
|
2996
3059
|
const cacheMisses = this.settingsManager.getShowCacheMissNotices()
|
|
2997
3060
|
? collectCacheMisses(this.sessionManager.getEntries(), this.session.modelRuntime)
|
|
2998
3061
|
: new Map();
|
|
@@ -3005,6 +3068,10 @@ export class InteractiveMode {
|
|
|
3005
3068
|
this.addCustomEntryToChat(item);
|
|
3006
3069
|
continue;
|
|
3007
3070
|
}
|
|
3071
|
+
if (isUsageSessionEntry(item)) {
|
|
3072
|
+
this.addCacheWarmingUsage(item);
|
|
3073
|
+
continue;
|
|
3074
|
+
}
|
|
3008
3075
|
if (isCompactionCostNotice(item)) {
|
|
3009
3076
|
this.addCompactionCostNotice(item);
|
|
3010
3077
|
continue;
|
|
@@ -3042,7 +3109,6 @@ export class InteractiveMode {
|
|
|
3042
3109
|
}
|
|
3043
3110
|
}
|
|
3044
3111
|
if (message.stopReason !== "aborted" && message.stopReason !== "error") {
|
|
3045
|
-
this.maybeShowAssistantDiagnostics(message);
|
|
3046
3112
|
const miss = cacheMisses.get(message);
|
|
3047
3113
|
if (miss)
|
|
3048
3114
|
this.addCacheMissNotice(miss);
|
|
@@ -3074,7 +3140,7 @@ export class InteractiveMode {
|
|
|
3074
3140
|
*/
|
|
3075
3141
|
renderSessionEntries(entries, options = {}) {
|
|
3076
3142
|
const items = entries.flatMap((entry) => {
|
|
3077
|
-
if (entry.type === "custom") {
|
|
3143
|
+
if (entry.type === "custom" || (entry.type === "usage" && entry.kind === "cache_warm")) {
|
|
3078
3144
|
return [entry];
|
|
3079
3145
|
}
|
|
3080
3146
|
const messages = sessionEntryToContextMessages(entry);
|
|
@@ -3085,6 +3151,12 @@ export class InteractiveMode {
|
|
|
3085
3151
|
});
|
|
3086
3152
|
this.renderSessionItems(items, options);
|
|
3087
3153
|
}
|
|
3154
|
+
addCacheWarmingUsage(entry) {
|
|
3155
|
+
if (!this.settingsManager.getShowCacheMissNotices())
|
|
3156
|
+
return;
|
|
3157
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
3158
|
+
this.chatContainer.addChild(new Text(theme.fg("dim", formatCacheWarmingUsage(entry)), 1, 0));
|
|
3159
|
+
}
|
|
3088
3160
|
/**
|
|
3089
3161
|
* Render billing usage for a compaction or branch summary. The notice is derived
|
|
3090
3162
|
* from persisted summary usage and is not stored as a separate session entry.
|
|
@@ -3099,31 +3171,42 @@ export class InteractiveMode {
|
|
|
3099
3171
|
this.chatContainer.addChild(new Spacer(1));
|
|
3100
3172
|
this.chatContainer.addChild(new Text(theme.fg("warning", `${label}: ${formatTokens(tokens)} tokens billed${cost}`), 1, 0));
|
|
3101
3173
|
}
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
return;
|
|
3174
|
+
static countDroppedThinkingBlocks(message) {
|
|
3175
|
+
let count = 0;
|
|
3105
3176
|
for (const diagnostic of message.diagnostics ?? []) {
|
|
3106
3177
|
if (diagnostic.type !== "anthropic_input_transformations")
|
|
3107
3178
|
continue;
|
|
3108
3179
|
const transformations = diagnostic.details?.transformations;
|
|
3109
3180
|
if (!Array.isArray(transformations))
|
|
3110
3181
|
continue;
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
const details = transformation;
|
|
3115
|
-
if (details.type !== "thinking_dropped")
|
|
3116
|
-
return [];
|
|
3117
|
-
const reason = typeof details.reason === "string" ? details.reason : "unknown reason";
|
|
3118
|
-
const location = typeof details.path === "string" ? ` at ${details.path}` : "";
|
|
3119
|
-
return [`${reason}${location}`];
|
|
3120
|
-
});
|
|
3121
|
-
if (dropped.length === 0)
|
|
3122
|
-
continue;
|
|
3123
|
-
const noun = dropped.length === 1 ? "thinking block" : `${dropped.length} thinking blocks`;
|
|
3124
|
-
this.chatContainer.addChild(new Spacer(1));
|
|
3125
|
-
this.chatContainer.addChild(new Text(theme.fg("warning", `Anthropic dropped ${noun}: ${dropped.join("; ")}`), 1, 0));
|
|
3182
|
+
count += transformations.filter((transformation) => typeof transformation === "object" &&
|
|
3183
|
+
transformation !== null &&
|
|
3184
|
+
transformation.type === "thinking_dropped").length;
|
|
3126
3185
|
}
|
|
3186
|
+
return count;
|
|
3187
|
+
}
|
|
3188
|
+
maybeShowThinkingDropNotice(message) {
|
|
3189
|
+
if (!this.settingsManager.getShowCacheMissNotices())
|
|
3190
|
+
return;
|
|
3191
|
+
const droppedCount = InteractiveMode.countDroppedThinkingBlocks(message);
|
|
3192
|
+
if (droppedCount === 0)
|
|
3193
|
+
return;
|
|
3194
|
+
let previousDroppedCount = 0;
|
|
3195
|
+
// message_end reaches the UI before the current message is persisted,
|
|
3196
|
+
// so the branch's last assistant message is the previous response.
|
|
3197
|
+
const branch = this.sessionManager.getBranch();
|
|
3198
|
+
for (let i = branch.length - 1; i >= 0; i--) {
|
|
3199
|
+
const entry = branch[i];
|
|
3200
|
+
if (entry.type === "message" && entry.message.role === "assistant") {
|
|
3201
|
+
previousDroppedCount = InteractiveMode.countDroppedThinkingBlocks(entry.message);
|
|
3202
|
+
break;
|
|
3203
|
+
}
|
|
3204
|
+
}
|
|
3205
|
+
if (droppedCount <= previousDroppedCount)
|
|
3206
|
+
return;
|
|
3207
|
+
const noun = droppedCount === 1 ? "thinking block" : "thinking blocks";
|
|
3208
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
3209
|
+
this.chatContainer.addChild(new Text(theme.fg("warning", `Anthropic dropped ${droppedCount} ${noun} (details in session)`), 1, 0));
|
|
3127
3210
|
}
|
|
3128
3211
|
/**
|
|
3129
3212
|
* Show a transcript notice when a completed assistant message paid for a
|
|
@@ -3291,6 +3374,9 @@ export class InteractiveMode {
|
|
|
3291
3374
|
catch { }
|
|
3292
3375
|
console.error(`${APP_NAME} exiting due to uncaughtException:`);
|
|
3293
3376
|
console.error(error);
|
|
3377
|
+
if (this.recordCrash("uncaught_exception", error)) {
|
|
3378
|
+
console.error(`\n${this.crashReportInstructions()}`);
|
|
3379
|
+
}
|
|
3294
3380
|
process.exit(1);
|
|
3295
3381
|
}
|
|
3296
3382
|
/**
|
|
@@ -3422,9 +3508,7 @@ export class InteractiveMode {
|
|
|
3422
3508
|
const level = this.session.thinkingLevel || "off";
|
|
3423
3509
|
this.editor.borderColor = theme.getThinkingBorderColor(level);
|
|
3424
3510
|
}
|
|
3425
|
-
|
|
3426
|
-
this.activeStatusIndicator.invalidate();
|
|
3427
|
-
}
|
|
3511
|
+
this.activeStatusIndicator?.invalidate();
|
|
3428
3512
|
this.ui.requestRender();
|
|
3429
3513
|
}
|
|
3430
3514
|
cycleThinkingLevel() {
|
|
@@ -3618,7 +3702,7 @@ export class InteractiveMode {
|
|
|
3618
3702
|
if (allQueued.length === 0) {
|
|
3619
3703
|
this.updatePendingMessagesDisplay();
|
|
3620
3704
|
if (options?.abort) {
|
|
3621
|
-
this.
|
|
3705
|
+
void this.session.abort();
|
|
3622
3706
|
}
|
|
3623
3707
|
return 0;
|
|
3624
3708
|
}
|
|
@@ -3628,7 +3712,7 @@ export class InteractiveMode {
|
|
|
3628
3712
|
this.editor.setText(combinedText);
|
|
3629
3713
|
this.updatePendingMessagesDisplay();
|
|
3630
3714
|
if (options?.abort) {
|
|
3631
|
-
this.
|
|
3715
|
+
void this.session.abort();
|
|
3632
3716
|
}
|
|
3633
3717
|
return allQueued.length;
|
|
3634
3718
|
}
|
|
@@ -3782,6 +3866,7 @@ export class InteractiveMode {
|
|
|
3782
3866
|
followUpMode: this.session.followUpMode,
|
|
3783
3867
|
transport: this.settingsManager.getTransport(),
|
|
3784
3868
|
httpIdleTimeoutMs: this.settingsManager.getHttpIdleTimeoutMs(),
|
|
3869
|
+
cacheWarmingMode: this.settingsManager.getCacheWarmingMode(),
|
|
3785
3870
|
thinkingLevel: this.settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL,
|
|
3786
3871
|
availableThinkingLevels: [...THINKING_LEVEL_OPTIONS],
|
|
3787
3872
|
modelThinkingLevels: this.settingsManager.getAllModelThinkingLevels(),
|
|
@@ -3854,6 +3939,10 @@ export class InteractiveMode {
|
|
|
3854
3939
|
configureHttpDispatcher(timeoutMs);
|
|
3855
3940
|
this.showStatus(`HTTP idle timeout: ${formatHttpIdleTimeoutMs(timeoutMs)}`);
|
|
3856
3941
|
},
|
|
3942
|
+
onCacheWarmingModeChange: (mode) => {
|
|
3943
|
+
this.session.setCacheWarmingMode(mode);
|
|
3944
|
+
this.showStatus(`Cache warming: ${mode}`);
|
|
3945
|
+
},
|
|
3857
3946
|
onModelThinkingLevelChange: (provider, modelId, level) => {
|
|
3858
3947
|
this.settingsManager.setModelThinkingLevel(provider, modelId, level);
|
|
3859
3948
|
// If the override is for the current model, apply it to the session too
|
|
@@ -4405,6 +4494,11 @@ export class InteractiveMode {
|
|
|
4405
4494
|
this.restoreQueuedMessagesToEditor();
|
|
4406
4495
|
await this.session.abort();
|
|
4407
4496
|
}
|
|
4497
|
+
// Recheck after the dialogs and streaming abort, before replacing another operation's UI.
|
|
4498
|
+
if (this.session.isCompacting) {
|
|
4499
|
+
this.showError("Wait for the current compaction or tree navigation to finish before navigating the session tree.");
|
|
4500
|
+
return;
|
|
4501
|
+
}
|
|
4408
4502
|
// Set up escape handler and status indicator if summarizing
|
|
4409
4503
|
let showingSummaryIndicator = false;
|
|
4410
4504
|
const originalOnEscape = this.defaultEditor.onEscape;
|
|
@@ -4475,9 +4569,9 @@ export class InteractiveMode {
|
|
|
4475
4569
|
}
|
|
4476
4570
|
showSessionSelector() {
|
|
4477
4571
|
this.showSelector((done) => {
|
|
4478
|
-
const selector = new SessionSelectorComponent((onProgress) => SessionManager.list(this.sessionManager.getCwd(), this.sessionManager.getSessionDir(), onProgress), (onProgress) => this.sessionManager.usesDefaultSessionDir()
|
|
4479
|
-
? SessionManager.listAll(onProgress)
|
|
4480
|
-
: SessionManager.listAll(this.sessionManager.getSessionDir(), onProgress), async (sessionPath) => {
|
|
4572
|
+
const selector = new SessionSelectorComponent((onProgress, signal) => SessionManager.list(this.sessionManager.getCwd(), this.sessionManager.getSessionDir(), onProgress, signal), (onProgress, signal) => this.sessionManager.usesDefaultSessionDir()
|
|
4573
|
+
? SessionManager.listAll(onProgress, signal)
|
|
4574
|
+
: SessionManager.listAll(this.sessionManager.getSessionDir(), onProgress, signal), async (sessionPath) => {
|
|
4481
4575
|
done();
|
|
4482
4576
|
await this.handleResumeSession(sessionPath);
|
|
4483
4577
|
}, () => {
|
|
@@ -4740,67 +4834,89 @@ export class InteractiveMode {
|
|
|
4740
4834
|
}
|
|
4741
4835
|
async completeProviderAuthentication(providerId, providerName, authType, previousModel) {
|
|
4742
4836
|
const actionLabel = authType === "oauth" ? `Logged in to ${providerName}` : `Saved API key for ${providerName}`;
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4837
|
+
const session = this.session;
|
|
4838
|
+
// Dynamic catalogs may be empty until the first authenticated network refresh.
|
|
4839
|
+
const deferSelection = isUnknownModel(previousModel) &&
|
|
4840
|
+
hasDefaultModelProvider(providerId) &&
|
|
4841
|
+
!session.modelRuntime
|
|
4842
|
+
.getAvailableSnapshot()
|
|
4843
|
+
.some((model) => model.provider === providerId && model.id === defaultModelPerProvider[providerId]);
|
|
4844
|
+
const finishAuthentication = async () => {
|
|
4845
|
+
let selectedModel;
|
|
4846
|
+
let selectionError;
|
|
4847
|
+
if (isUnknownModel(previousModel)) {
|
|
4848
|
+
const availableModels = this.session.modelRuntime.getAvailableSnapshot();
|
|
4849
|
+
const providerModels = availableModels.filter((model) => model.provider === providerId);
|
|
4850
|
+
// Matches LLAMA_PROVIDER_ID from extensions/llama/provider.ts; kept inline to avoid coupling interactive mode to the built-in extension.
|
|
4851
|
+
if (providerId === "llama.cpp") {
|
|
4852
|
+
selectionError = llamaCppPostLoginGuidance(actionLabel, providerModels.length);
|
|
4853
|
+
}
|
|
4854
|
+
else if (!hasDefaultModelProvider(providerId)) {
|
|
4855
|
+
selectionError = `${actionLabel}, but no default model is configured for provider "${providerId}". Use /model to select a model.`;
|
|
4856
|
+
}
|
|
4857
|
+
else if (providerModels.length === 0) {
|
|
4858
|
+
selectionError = `${actionLabel}, but no models are available for that provider. Use /model to select a model.`;
|
|
4763
4859
|
}
|
|
4764
4860
|
else {
|
|
4765
|
-
|
|
4766
|
-
|
|
4861
|
+
const defaultModelId = defaultModelPerProvider[providerId];
|
|
4862
|
+
// Radius catalogs vary by account; prefer balanced, then use catalog order.
|
|
4863
|
+
selectedModel =
|
|
4864
|
+
providerModels.find((model) => model.id === defaultModelId) ??
|
|
4865
|
+
(providerId === "radius" ? providerModels[0] : undefined);
|
|
4866
|
+
if (!selectedModel) {
|
|
4867
|
+
selectionError = `${actionLabel}, but its default model "${defaultModelId}" is not available. Use /model to select a model.`;
|
|
4767
4868
|
}
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4869
|
+
else {
|
|
4870
|
+
try {
|
|
4871
|
+
await this.session.setModel(selectedModel, { persist: true });
|
|
4872
|
+
}
|
|
4873
|
+
catch (error) {
|
|
4874
|
+
selectedModel = undefined;
|
|
4875
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
4876
|
+
selectionError = `${actionLabel}, but selecting its default model failed: ${errorMessage}. Use /model to select a model.`;
|
|
4877
|
+
}
|
|
4772
4878
|
}
|
|
4773
4879
|
}
|
|
4774
4880
|
}
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
this.checkDaxnutsEasterEgg(selectedModel);
|
|
4783
|
-
}
|
|
4784
|
-
else {
|
|
4785
|
-
this.showStatus(`${actionLabel}. Credentials saved to ${getAuthPath()}`);
|
|
4786
|
-
if (selectionError) {
|
|
4787
|
-
this.showError(selectionError);
|
|
4881
|
+
await this.updateAvailableProviderCount();
|
|
4882
|
+
this.footer.invalidate();
|
|
4883
|
+
this.updateEditorBorderColor();
|
|
4884
|
+
if (selectedModel) {
|
|
4885
|
+
this.showStatus(`${actionLabel}. Selected ${selectedModel.id}. Credentials saved to ${getAuthPath()}`);
|
|
4886
|
+
void this.maybeWarnAboutAnthropicSubscriptionAuth(selectedModel);
|
|
4887
|
+
this.checkDaxnutsEasterEgg(selectedModel);
|
|
4788
4888
|
}
|
|
4789
4889
|
else {
|
|
4790
|
-
|
|
4890
|
+
this.showStatus(`${actionLabel}. Credentials saved to ${getAuthPath()}`);
|
|
4891
|
+
if (selectionError) {
|
|
4892
|
+
this.showError(selectionError);
|
|
4893
|
+
}
|
|
4894
|
+
else {
|
|
4895
|
+
void this.maybeWarnAboutAnthropicSubscriptionAuth();
|
|
4896
|
+
}
|
|
4791
4897
|
}
|
|
4898
|
+
};
|
|
4899
|
+
if (deferSelection) {
|
|
4900
|
+
this.showStatus(`${actionLabel}. Credentials saved to ${getAuthPath()}. Refreshing model catalog…`);
|
|
4901
|
+
}
|
|
4902
|
+
else {
|
|
4903
|
+
await finishAuthentication();
|
|
4792
4904
|
}
|
|
4793
4905
|
const controller = new AbortController();
|
|
4794
4906
|
const timeout = setTimeout(() => controller.abort(), 15_000);
|
|
4795
|
-
void
|
|
4907
|
+
void session.modelRuntime
|
|
4796
4908
|
.refresh({ providers: [providerId], signal: controller.signal })
|
|
4797
|
-
.then((result) => {
|
|
4909
|
+
.then(async (result) => {
|
|
4798
4910
|
if (result.aborted) {
|
|
4799
4911
|
this.showWarning(`${actionLabel}, but its model catalog refresh timed out; using cached models.`);
|
|
4800
4912
|
}
|
|
4801
4913
|
else if (result.errors.size > 0) {
|
|
4802
4914
|
this.showWarning(`${actionLabel}, but its model catalog could not be refreshed; using cached models.`);
|
|
4803
4915
|
}
|
|
4916
|
+
// Do not replace a model or session selected while the refresh was running.
|
|
4917
|
+
if (deferSelection && this.session === session && session.model === previousModel) {
|
|
4918
|
+
await finishAuthentication();
|
|
4919
|
+
}
|
|
4804
4920
|
this.updateAvailableProviderCount();
|
|
4805
4921
|
this.footer.invalidate();
|
|
4806
4922
|
this.ui.requestRender();
|
|
@@ -5142,6 +5258,17 @@ export class InteractiveMode {
|
|
|
5142
5258
|
showError: (message) => this.showError(message),
|
|
5143
5259
|
});
|
|
5144
5260
|
}
|
|
5261
|
+
async handleBugCommand(hint) {
|
|
5262
|
+
await reportBug({
|
|
5263
|
+
session: this.session,
|
|
5264
|
+
ui: this.ui,
|
|
5265
|
+
editorContainer: this.editorContainer,
|
|
5266
|
+
editor: this.editor,
|
|
5267
|
+
keybindings: this.keybindings,
|
|
5268
|
+
showStatus: (message) => this.showStatus(message),
|
|
5269
|
+
showError: (message) => this.showError(message),
|
|
5270
|
+
}, hint);
|
|
5271
|
+
}
|
|
5145
5272
|
async handleCopyCommand(options = {}) {
|
|
5146
5273
|
if (options.preferSelection &&
|
|
5147
5274
|
this.ui instanceof TuiAltScreen &&
|
|
@@ -5227,6 +5354,15 @@ export class InteractiveMode {
|
|
|
5227
5354
|
}
|
|
5228
5355
|
info += `${theme.fg("dim", "Output:")} ${stats.tokens.output.toLocaleString()}\n`;
|
|
5229
5356
|
info += `${theme.fg("dim", "Total:")} ${stats.tokens.total.toLocaleString()}\n`;
|
|
5357
|
+
const cacheWarmingStatus = this.session.cacheWarmingStatus;
|
|
5358
|
+
info += `\n${theme.bold("Cache Warming")}\n`;
|
|
5359
|
+
info += `${theme.fg("dim", "Mode:")} ${this.settingsManager.getCacheWarmingMode()}\n`;
|
|
5360
|
+
info += `${theme.fg("dim", "Status:")} ${cacheWarmingStatus ? formatCacheWarmingStatus(cacheWarmingStatus) : "Inactive (cache warming unavailable)"}\n`;
|
|
5361
|
+
const decision = cacheWarmingStatus?.decision;
|
|
5362
|
+
if (decision?.economicsAvailable) {
|
|
5363
|
+
info += `${theme.fg("dim", "Cache miss penalty:")} $${decision.missCost.toFixed(3)}\n`;
|
|
5364
|
+
info += `${theme.fg("dim", "Refresh cost:")} $${decision.warmCost.toFixed(3)}\n`;
|
|
5365
|
+
}
|
|
5230
5366
|
if (stats.cost > 0 || cacheWaste.missedTokens > 0) {
|
|
5231
5367
|
info += `\n${theme.bold("Cost")}\n`;
|
|
5232
5368
|
info += `${theme.fg("dim", "Total:")} $${stats.cost.toFixed(3)}`;
|
|
@@ -5357,7 +5493,7 @@ export class InteractiveMode {
|
|
|
5357
5493
|
| \`${expandTools}\` | Toggle tool output expansion |
|
|
5358
5494
|
| \`${toggleThinking}\` | Toggle thinking block visibility |
|
|
5359
5495
|
| \`${externalEditor}\` | Edit message in external editor |
|
|
5360
|
-
| \`${copyMessage}\` | Copy last assistant message |
|
|
5496
|
+
| \`${copyMessage}\` | Copy selection or last assistant message |
|
|
5361
5497
|
| \`${followUp}\` | Queue follow-up message |
|
|
5362
5498
|
| \`${dequeue}\` | Restore queued messages |
|
|
5363
5499
|
| \`${pasteImage}\` | Paste image or text from clipboard |
|
|
@@ -5453,12 +5589,19 @@ export class InteractiveMode {
|
|
|
5453
5589
|
async handleBashCommand(command, excludeFromContext = false) {
|
|
5454
5590
|
const extensionRunner = this.session.extensionRunner;
|
|
5455
5591
|
// Emit user_bash event to let extensions intercept
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5592
|
+
let eventResult;
|
|
5593
|
+
try {
|
|
5594
|
+
eventResult = await extensionRunner.emitUserBash({
|
|
5595
|
+
type: "user_bash",
|
|
5596
|
+
command,
|
|
5597
|
+
excludeFromContext,
|
|
5598
|
+
cwd: this.sessionManager.getCwd(),
|
|
5599
|
+
});
|
|
5600
|
+
}
|
|
5601
|
+
catch {
|
|
5602
|
+
// The extension runner already reported the error. Do not fall back to local execution.
|
|
5603
|
+
return;
|
|
5604
|
+
}
|
|
5462
5605
|
// If extension returned a full result, use it directly
|
|
5463
5606
|
if (eventResult?.result) {
|
|
5464
5607
|
const result = eventResult.result;
|