@earendil-works/pi-coding-agent 0.85.1 → 0.86.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +86 -0
- package/README.md +2 -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-7IOYH2SY.js +2 -0
- package/dist/bundle/chunks/chunk-7YM6BE7Y.js +1561 -0
- package/dist/bundle/chunks/chunk-A3JYRWB6.js +2 -0
- package/dist/bundle/chunks/chunk-DTD7JQ7Y.js +42 -0
- package/dist/bundle/chunks/chunk-FUXEF6JQ.js +44 -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/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-KQPOPEVM.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-XW5APVUE.js +2 -0
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +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 +1 -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 +14 -0
- package/dist/modes/interactive/bug-report.d.ts.map +1 -0
- package/dist/modes/interactive/bug-report.js +209 -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-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 +13 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +220 -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 +52 -69
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +61 -125
- package/dist/utils/clipboard.js.map +1 -1
- 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 +2 -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
|
@@ -14,6 +14,8 @@ import { APP_NAME, APP_TITLE, CONFIG_DIR_NAME, getAgentDir, getAuthPath, getDebu
|
|
|
14
14
|
import { parseSkillBlock } from "../../core/agent-session.js";
|
|
15
15
|
import { SessionImportFileNotFoundError } from "../../core/agent-session-runtime.js";
|
|
16
16
|
import { CACHE_TTL_MS, collectCacheMisses, computeCacheWaste, detectCacheMiss, } from "../../core/cache-stats.js";
|
|
17
|
+
import { formatCacheWarmingStatus, formatCacheWarmingUsage } from "../../core/cache-warmer.js";
|
|
18
|
+
import { recordCrash, takeUnnotifiedCrash } from "../../core/crash-log.js";
|
|
17
19
|
import { DEFAULT_THINKING_LEVEL, THINKING_LEVEL_OPTIONS } from "../../core/defaults.js";
|
|
18
20
|
import { FooterDataProvider } from "../../core/footer-data-provider.js";
|
|
19
21
|
import { configureHttpDispatcher, formatHttpIdleTimeoutMs } from "../../core/http-dispatcher.js";
|
|
@@ -23,7 +25,7 @@ import { defaultModelPerProvider, findExactModelReferenceMatch, resolveModelScop
|
|
|
23
25
|
import { CredentialSynchronizationError } from "../../core/model-runtime.js";
|
|
24
26
|
import { DefaultPackageManager } from "../../core/package-manager.js";
|
|
25
27
|
import { formatMissingSessionCwdPrompt, MissingSessionCwdError } from "../../core/session-cwd.js";
|
|
26
|
-
import { SessionManager, sessionEntryToContextMessages } from "../../core/session-manager.js";
|
|
28
|
+
import { SessionManager, sessionEntryToContextMessages, } from "../../core/session-manager.js";
|
|
27
29
|
import { BUILTIN_SLASH_COMMANDS } from "../../core/slash-commands.js";
|
|
28
30
|
import { isInstallTelemetryEnabled } from "../../core/telemetry.js";
|
|
29
31
|
import { withBuiltInRenderers } from "../../core/tools/renderers/index.js";
|
|
@@ -39,6 +41,7 @@ import { killTrackedDetachedChildren } from "../../utils/shell.js";
|
|
|
39
41
|
import { loadAllHighlightLanguages } from "../../utils/syntax-highlight.js";
|
|
40
42
|
import { ensureTool } from "../../utils/tools-manager.js";
|
|
41
43
|
import { checkForNewPiVersion } from "../../utils/version-check.js";
|
|
44
|
+
import { reportBug } from "./bug-report.js";
|
|
42
45
|
import { createChatViewport } from "./chat-viewport.js";
|
|
43
46
|
import { ArminComponent } from "./components/armin.js";
|
|
44
47
|
import { AssistantMessageComponent } from "./components/assistant-message.js";
|
|
@@ -106,6 +109,9 @@ function isCustomSessionEntry(item) {
|
|
|
106
109
|
function isCompactionCostNotice(item) {
|
|
107
110
|
return "type" in item && item.type === "compaction_cost";
|
|
108
111
|
}
|
|
112
|
+
function isUsageSessionEntry(item) {
|
|
113
|
+
return "type" in item && item.type === "usage";
|
|
114
|
+
}
|
|
109
115
|
const DEAD_TERMINAL_ERROR_CODES = new Set(["EIO", "EPIPE", "ENOTCONN"]);
|
|
110
116
|
function isDeadTerminalError(error) {
|
|
111
117
|
if (!error || typeof error !== "object" || !("code" in error)) {
|
|
@@ -267,6 +273,8 @@ export class InteractiveMode {
|
|
|
267
273
|
compactionQueuedMessages = [];
|
|
268
274
|
// Shutdown state
|
|
269
275
|
shutdownRequested = false;
|
|
276
|
+
/** The `/bug` hint is shown at most once per session so error output stays readable. */
|
|
277
|
+
bugReportHintShown = false;
|
|
270
278
|
// Extension UI state
|
|
271
279
|
extensionSelector = undefined;
|
|
272
280
|
extensionInput = undefined;
|
|
@@ -322,6 +330,7 @@ export class InteractiveMode {
|
|
|
322
330
|
tuiMode,
|
|
323
331
|
showHardwareCursor: this.settingsManager.getShowHardwareCursor(),
|
|
324
332
|
logDirectory: getAgentDir(),
|
|
333
|
+
terminal: options.terminal,
|
|
325
334
|
onRightClickPaste: this.onRightClickPaste,
|
|
326
335
|
fullscreenCopyOnSelect: this.settingsManager.getFullscreenCopyOnSelect(),
|
|
327
336
|
});
|
|
@@ -809,6 +818,11 @@ export class InteractiveMode {
|
|
|
809
818
|
if (modelFallbackMessage) {
|
|
810
819
|
this.showWarning(modelFallbackMessage);
|
|
811
820
|
}
|
|
821
|
+
const crash = takeUnnotifiedCrash();
|
|
822
|
+
if (crash) {
|
|
823
|
+
const when = new Date(crash.timestamp).toLocaleString();
|
|
824
|
+
this.showWarning(`${APP_NAME} crashed on ${when} (${crash.message}). Run /bug to report it; the crash details are attached automatically.`);
|
|
825
|
+
}
|
|
812
826
|
void this.maybeWarnAboutAnthropicSubscriptionAuth();
|
|
813
827
|
// Process initial messages
|
|
814
828
|
if (initialMessage) {
|
|
@@ -1525,10 +1539,38 @@ export class InteractiveMode {
|
|
|
1525
1539
|
async handleFatalRuntimeError(prefix, error) {
|
|
1526
1540
|
const message = error instanceof Error ? error.message : String(error);
|
|
1527
1541
|
this.showError(`${prefix}: ${message}`);
|
|
1542
|
+
if (this.recordCrash("fatal_error", error)) {
|
|
1543
|
+
this.chatContainer.addChild(new Text(theme.fg("muted", this.crashReportInstructions()), this.outputPad, 0));
|
|
1544
|
+
}
|
|
1528
1545
|
stopThemeWatcher();
|
|
1529
1546
|
this.stop("transcript");
|
|
1530
1547
|
process.exit(1);
|
|
1531
1548
|
}
|
|
1549
|
+
/** Persist a crash so the next start can point the user at `/bug`. Returns false when nothing was written. */
|
|
1550
|
+
recordCrash(kind, error) {
|
|
1551
|
+
try {
|
|
1552
|
+
return (recordCrash({
|
|
1553
|
+
kind,
|
|
1554
|
+
error,
|
|
1555
|
+
sessionFile: this.session.sessionFile,
|
|
1556
|
+
cwd: this.session.sessionManager.getCwd(),
|
|
1557
|
+
}) !== undefined);
|
|
1558
|
+
}
|
|
1559
|
+
catch {
|
|
1560
|
+
return false;
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
crashReportInstructions() {
|
|
1564
|
+
const resume = this.session.sessionFile ? `run \`${APP_NAME} -r\` to resume the session, then` : "start pi and";
|
|
1565
|
+
return `To report this crash: ${resume} run /bug. The crash details are attached automatically.`;
|
|
1566
|
+
}
|
|
1567
|
+
suggestBugReport() {
|
|
1568
|
+
if (this.bugReportHintShown)
|
|
1569
|
+
return;
|
|
1570
|
+
this.bugReportHintShown = true;
|
|
1571
|
+
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));
|
|
1572
|
+
this.ui.requestRender();
|
|
1573
|
+
}
|
|
1532
1574
|
renderCurrentSessionState() {
|
|
1533
1575
|
this.loadedResourcesContainer.clear();
|
|
1534
1576
|
this.chatContainer.clear();
|
|
@@ -1630,7 +1672,7 @@ export class InteractiveMode {
|
|
|
1630
1672
|
this.activeWorkingIndicatorEmbedded = false;
|
|
1631
1673
|
this.statusContainer.clear();
|
|
1632
1674
|
this.setEditorWorkingStatusIndicator(undefined);
|
|
1633
|
-
if (
|
|
1675
|
+
if (this.setEditorWorkingStatusIndicator(indicator)) {
|
|
1634
1676
|
this.activeWorkingIndicatorEmbedded = true;
|
|
1635
1677
|
return;
|
|
1636
1678
|
}
|
|
@@ -1641,7 +1683,7 @@ export class InteractiveMode {
|
|
|
1641
1683
|
return;
|
|
1642
1684
|
}
|
|
1643
1685
|
const clearedIndicator = this.activeStatusIndicator;
|
|
1644
|
-
const clearedIndicatorWasEmbedded =
|
|
1686
|
+
const clearedIndicatorWasEmbedded = this.activeWorkingIndicatorEmbedded;
|
|
1645
1687
|
clearedIndicator?.dispose();
|
|
1646
1688
|
this.activeStatusIndicator = undefined;
|
|
1647
1689
|
this.activeWorkingIndicatorEmbedded = false;
|
|
@@ -2130,7 +2172,7 @@ export class InteractiveMode {
|
|
|
2130
2172
|
this.editor = this.defaultEditor;
|
|
2131
2173
|
}
|
|
2132
2174
|
this.editorContainer.addChild(this.editor);
|
|
2133
|
-
if (this.activeStatusIndicator
|
|
2175
|
+
if (this.activeStatusIndicator) {
|
|
2134
2176
|
this.statusContainer.clear();
|
|
2135
2177
|
this.activeWorkingIndicatorEmbedded = this.setEditorWorkingStatusIndicator(this.activeStatusIndicator);
|
|
2136
2178
|
if (!this.activeWorkingIndicatorEmbedded) {
|
|
@@ -2401,6 +2443,12 @@ export class InteractiveMode {
|
|
|
2401
2443
|
this.editor.setText("");
|
|
2402
2444
|
return;
|
|
2403
2445
|
}
|
|
2446
|
+
if (text === "/bug" || text.startsWith("/bug ")) {
|
|
2447
|
+
const hint = text.slice("/bug".length).trim();
|
|
2448
|
+
this.editor.setText("");
|
|
2449
|
+
await this.handleBugCommand(hint ? hint : undefined);
|
|
2450
|
+
return;
|
|
2451
|
+
}
|
|
2404
2452
|
if (text === "/copy") {
|
|
2405
2453
|
await this.handleCopyCommand();
|
|
2406
2454
|
this.editor.setText("");
|
|
@@ -2592,6 +2640,10 @@ export class InteractiveMode {
|
|
|
2592
2640
|
this.addCustomEntryToChat(event.entry);
|
|
2593
2641
|
this.ui.requestRender();
|
|
2594
2642
|
}
|
|
2643
|
+
else if (event.entry.type === "usage" && event.entry.kind === "cache_warm") {
|
|
2644
|
+
this.addCacheWarmingUsage(event.entry);
|
|
2645
|
+
this.ui.requestRender();
|
|
2646
|
+
}
|
|
2595
2647
|
break;
|
|
2596
2648
|
case "session_info_changed":
|
|
2597
2649
|
this.updateTerminalTitle();
|
|
@@ -2672,13 +2724,15 @@ export class InteractiveMode {
|
|
|
2672
2724
|
});
|
|
2673
2725
|
}
|
|
2674
2726
|
this.pendingTools.clear();
|
|
2727
|
+
if (this.streamingMessage.stopReason === "error")
|
|
2728
|
+
this.suggestBugReport();
|
|
2675
2729
|
}
|
|
2676
2730
|
else {
|
|
2677
2731
|
// Args are now complete - trigger diff computation for edit tools
|
|
2678
2732
|
for (const [, component] of this.pendingTools.entries()) {
|
|
2679
2733
|
component.setArgsComplete();
|
|
2680
2734
|
}
|
|
2681
|
-
this.
|
|
2735
|
+
this.maybeShowThinkingDropNotice(this.streamingMessage);
|
|
2682
2736
|
this.maybeShowCacheMissNotice(this.streamingMessage);
|
|
2683
2737
|
}
|
|
2684
2738
|
this.streamingComponent = undefined;
|
|
@@ -2819,6 +2873,7 @@ export class InteractiveMode {
|
|
|
2819
2873
|
// Show error only on final failure (success shows normal response)
|
|
2820
2874
|
if (!event.success) {
|
|
2821
2875
|
this.showError(`Retry failed after ${event.attempt} attempts: ${event.finalError || "Unknown error"}`);
|
|
2876
|
+
this.suggestBugReport();
|
|
2822
2877
|
}
|
|
2823
2878
|
this.ui.requestRender();
|
|
2824
2879
|
break;
|
|
@@ -2945,6 +3000,8 @@ export class InteractiveMode {
|
|
|
2945
3000
|
this.chatContainer.addChild(component);
|
|
2946
3001
|
break;
|
|
2947
3002
|
}
|
|
3003
|
+
case "system":
|
|
3004
|
+
break;
|
|
2948
3005
|
case "user": {
|
|
2949
3006
|
const textContent = this.getUserMessageText(message);
|
|
2950
3007
|
if (textContent) {
|
|
@@ -2991,8 +3048,8 @@ export class InteractiveMode {
|
|
|
2991
3048
|
renderSessionItems(items, options = {}) {
|
|
2992
3049
|
this.pendingTools.clear();
|
|
2993
3050
|
const renderedPendingTools = new Map();
|
|
2994
|
-
// Cache
|
|
2995
|
-
//
|
|
3051
|
+
// Cache misses are not persisted, unlike successful cache-warming usage.
|
|
3052
|
+
// Re-derive them and inject them after the assistant messages that paid for them.
|
|
2996
3053
|
const cacheMisses = this.settingsManager.getShowCacheMissNotices()
|
|
2997
3054
|
? collectCacheMisses(this.sessionManager.getEntries(), this.session.modelRuntime)
|
|
2998
3055
|
: new Map();
|
|
@@ -3005,6 +3062,10 @@ export class InteractiveMode {
|
|
|
3005
3062
|
this.addCustomEntryToChat(item);
|
|
3006
3063
|
continue;
|
|
3007
3064
|
}
|
|
3065
|
+
if (isUsageSessionEntry(item)) {
|
|
3066
|
+
this.addCacheWarmingUsage(item);
|
|
3067
|
+
continue;
|
|
3068
|
+
}
|
|
3008
3069
|
if (isCompactionCostNotice(item)) {
|
|
3009
3070
|
this.addCompactionCostNotice(item);
|
|
3010
3071
|
continue;
|
|
@@ -3042,7 +3103,6 @@ export class InteractiveMode {
|
|
|
3042
3103
|
}
|
|
3043
3104
|
}
|
|
3044
3105
|
if (message.stopReason !== "aborted" && message.stopReason !== "error") {
|
|
3045
|
-
this.maybeShowAssistantDiagnostics(message);
|
|
3046
3106
|
const miss = cacheMisses.get(message);
|
|
3047
3107
|
if (miss)
|
|
3048
3108
|
this.addCacheMissNotice(miss);
|
|
@@ -3074,7 +3134,7 @@ export class InteractiveMode {
|
|
|
3074
3134
|
*/
|
|
3075
3135
|
renderSessionEntries(entries, options = {}) {
|
|
3076
3136
|
const items = entries.flatMap((entry) => {
|
|
3077
|
-
if (entry.type === "custom") {
|
|
3137
|
+
if (entry.type === "custom" || (entry.type === "usage" && entry.kind === "cache_warm")) {
|
|
3078
3138
|
return [entry];
|
|
3079
3139
|
}
|
|
3080
3140
|
const messages = sessionEntryToContextMessages(entry);
|
|
@@ -3085,6 +3145,12 @@ export class InteractiveMode {
|
|
|
3085
3145
|
});
|
|
3086
3146
|
this.renderSessionItems(items, options);
|
|
3087
3147
|
}
|
|
3148
|
+
addCacheWarmingUsage(entry) {
|
|
3149
|
+
if (!this.settingsManager.getShowCacheMissNotices())
|
|
3150
|
+
return;
|
|
3151
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
3152
|
+
this.chatContainer.addChild(new Text(theme.fg("dim", formatCacheWarmingUsage(entry)), 1, 0));
|
|
3153
|
+
}
|
|
3088
3154
|
/**
|
|
3089
3155
|
* Render billing usage for a compaction or branch summary. The notice is derived
|
|
3090
3156
|
* from persisted summary usage and is not stored as a separate session entry.
|
|
@@ -3099,31 +3165,42 @@ export class InteractiveMode {
|
|
|
3099
3165
|
this.chatContainer.addChild(new Spacer(1));
|
|
3100
3166
|
this.chatContainer.addChild(new Text(theme.fg("warning", `${label}: ${formatTokens(tokens)} tokens billed${cost}`), 1, 0));
|
|
3101
3167
|
}
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
return;
|
|
3168
|
+
static countDroppedThinkingBlocks(message) {
|
|
3169
|
+
let count = 0;
|
|
3105
3170
|
for (const diagnostic of message.diagnostics ?? []) {
|
|
3106
3171
|
if (diagnostic.type !== "anthropic_input_transformations")
|
|
3107
3172
|
continue;
|
|
3108
3173
|
const transformations = diagnostic.details?.transformations;
|
|
3109
3174
|
if (!Array.isArray(transformations))
|
|
3110
3175
|
continue;
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3176
|
+
count += transformations.filter((transformation) => typeof transformation === "object" &&
|
|
3177
|
+
transformation !== null &&
|
|
3178
|
+
transformation.type === "thinking_dropped").length;
|
|
3179
|
+
}
|
|
3180
|
+
return count;
|
|
3181
|
+
}
|
|
3182
|
+
maybeShowThinkingDropNotice(message) {
|
|
3183
|
+
if (!this.settingsManager.getShowCacheMissNotices())
|
|
3184
|
+
return;
|
|
3185
|
+
const droppedCount = InteractiveMode.countDroppedThinkingBlocks(message);
|
|
3186
|
+
if (droppedCount === 0)
|
|
3187
|
+
return;
|
|
3188
|
+
let previousDroppedCount = 0;
|
|
3189
|
+
// message_end reaches the UI before the current message is persisted,
|
|
3190
|
+
// so the branch's last assistant message is the previous response.
|
|
3191
|
+
const branch = this.sessionManager.getBranch();
|
|
3192
|
+
for (let i = branch.length - 1; i >= 0; i--) {
|
|
3193
|
+
const entry = branch[i];
|
|
3194
|
+
if (entry.type === "message" && entry.message.role === "assistant") {
|
|
3195
|
+
previousDroppedCount = InteractiveMode.countDroppedThinkingBlocks(entry.message);
|
|
3196
|
+
break;
|
|
3197
|
+
}
|
|
3126
3198
|
}
|
|
3199
|
+
if (droppedCount <= previousDroppedCount)
|
|
3200
|
+
return;
|
|
3201
|
+
const noun = droppedCount === 1 ? "thinking block" : "thinking blocks";
|
|
3202
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
3203
|
+
this.chatContainer.addChild(new Text(theme.fg("warning", `Anthropic dropped ${droppedCount} ${noun} (details in session)`), 1, 0));
|
|
3127
3204
|
}
|
|
3128
3205
|
/**
|
|
3129
3206
|
* Show a transcript notice when a completed assistant message paid for a
|
|
@@ -3291,6 +3368,9 @@ export class InteractiveMode {
|
|
|
3291
3368
|
catch { }
|
|
3292
3369
|
console.error(`${APP_NAME} exiting due to uncaughtException:`);
|
|
3293
3370
|
console.error(error);
|
|
3371
|
+
if (this.recordCrash("uncaught_exception", error)) {
|
|
3372
|
+
console.error(`\n${this.crashReportInstructions()}`);
|
|
3373
|
+
}
|
|
3294
3374
|
process.exit(1);
|
|
3295
3375
|
}
|
|
3296
3376
|
/**
|
|
@@ -3422,9 +3502,7 @@ export class InteractiveMode {
|
|
|
3422
3502
|
const level = this.session.thinkingLevel || "off";
|
|
3423
3503
|
this.editor.borderColor = theme.getThinkingBorderColor(level);
|
|
3424
3504
|
}
|
|
3425
|
-
|
|
3426
|
-
this.activeStatusIndicator.invalidate();
|
|
3427
|
-
}
|
|
3505
|
+
this.activeStatusIndicator?.invalidate();
|
|
3428
3506
|
this.ui.requestRender();
|
|
3429
3507
|
}
|
|
3430
3508
|
cycleThinkingLevel() {
|
|
@@ -3618,7 +3696,7 @@ export class InteractiveMode {
|
|
|
3618
3696
|
if (allQueued.length === 0) {
|
|
3619
3697
|
this.updatePendingMessagesDisplay();
|
|
3620
3698
|
if (options?.abort) {
|
|
3621
|
-
this.
|
|
3699
|
+
void this.session.abort();
|
|
3622
3700
|
}
|
|
3623
3701
|
return 0;
|
|
3624
3702
|
}
|
|
@@ -3628,7 +3706,7 @@ export class InteractiveMode {
|
|
|
3628
3706
|
this.editor.setText(combinedText);
|
|
3629
3707
|
this.updatePendingMessagesDisplay();
|
|
3630
3708
|
if (options?.abort) {
|
|
3631
|
-
this.
|
|
3709
|
+
void this.session.abort();
|
|
3632
3710
|
}
|
|
3633
3711
|
return allQueued.length;
|
|
3634
3712
|
}
|
|
@@ -3782,6 +3860,7 @@ export class InteractiveMode {
|
|
|
3782
3860
|
followUpMode: this.session.followUpMode,
|
|
3783
3861
|
transport: this.settingsManager.getTransport(),
|
|
3784
3862
|
httpIdleTimeoutMs: this.settingsManager.getHttpIdleTimeoutMs(),
|
|
3863
|
+
cacheWarmingMode: this.settingsManager.getCacheWarmingMode(),
|
|
3785
3864
|
thinkingLevel: this.settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL,
|
|
3786
3865
|
availableThinkingLevels: [...THINKING_LEVEL_OPTIONS],
|
|
3787
3866
|
modelThinkingLevels: this.settingsManager.getAllModelThinkingLevels(),
|
|
@@ -3854,6 +3933,10 @@ export class InteractiveMode {
|
|
|
3854
3933
|
configureHttpDispatcher(timeoutMs);
|
|
3855
3934
|
this.showStatus(`HTTP idle timeout: ${formatHttpIdleTimeoutMs(timeoutMs)}`);
|
|
3856
3935
|
},
|
|
3936
|
+
onCacheWarmingModeChange: (mode) => {
|
|
3937
|
+
this.session.setCacheWarmingMode(mode);
|
|
3938
|
+
this.showStatus(`Cache warming: ${mode}`);
|
|
3939
|
+
},
|
|
3857
3940
|
onModelThinkingLevelChange: (provider, modelId, level) => {
|
|
3858
3941
|
this.settingsManager.setModelThinkingLevel(provider, modelId, level);
|
|
3859
3942
|
// If the override is for the current model, apply it to the session too
|
|
@@ -4405,6 +4488,11 @@ export class InteractiveMode {
|
|
|
4405
4488
|
this.restoreQueuedMessagesToEditor();
|
|
4406
4489
|
await this.session.abort();
|
|
4407
4490
|
}
|
|
4491
|
+
// Recheck after the dialogs and streaming abort, before replacing another operation's UI.
|
|
4492
|
+
if (this.session.isCompacting) {
|
|
4493
|
+
this.showError("Wait for the current compaction or tree navigation to finish before navigating the session tree.");
|
|
4494
|
+
return;
|
|
4495
|
+
}
|
|
4408
4496
|
// Set up escape handler and status indicator if summarizing
|
|
4409
4497
|
let showingSummaryIndicator = false;
|
|
4410
4498
|
const originalOnEscape = this.defaultEditor.onEscape;
|
|
@@ -4475,9 +4563,9 @@ export class InteractiveMode {
|
|
|
4475
4563
|
}
|
|
4476
4564
|
showSessionSelector() {
|
|
4477
4565
|
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) => {
|
|
4566
|
+
const selector = new SessionSelectorComponent((onProgress, signal) => SessionManager.list(this.sessionManager.getCwd(), this.sessionManager.getSessionDir(), onProgress, signal), (onProgress, signal) => this.sessionManager.usesDefaultSessionDir()
|
|
4567
|
+
? SessionManager.listAll(onProgress, signal)
|
|
4568
|
+
: SessionManager.listAll(this.sessionManager.getSessionDir(), onProgress, signal), async (sessionPath) => {
|
|
4481
4569
|
done();
|
|
4482
4570
|
await this.handleResumeSession(sessionPath);
|
|
4483
4571
|
}, () => {
|
|
@@ -4740,67 +4828,89 @@ export class InteractiveMode {
|
|
|
4740
4828
|
}
|
|
4741
4829
|
async completeProviderAuthentication(providerId, providerName, authType, previousModel) {
|
|
4742
4830
|
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
|
-
|
|
4831
|
+
const session = this.session;
|
|
4832
|
+
// Dynamic catalogs may be empty until the first authenticated network refresh.
|
|
4833
|
+
const deferSelection = isUnknownModel(previousModel) &&
|
|
4834
|
+
hasDefaultModelProvider(providerId) &&
|
|
4835
|
+
!session.modelRuntime
|
|
4836
|
+
.getAvailableSnapshot()
|
|
4837
|
+
.some((model) => model.provider === providerId && model.id === defaultModelPerProvider[providerId]);
|
|
4838
|
+
const finishAuthentication = async () => {
|
|
4839
|
+
let selectedModel;
|
|
4840
|
+
let selectionError;
|
|
4841
|
+
if (isUnknownModel(previousModel)) {
|
|
4842
|
+
const availableModels = this.session.modelRuntime.getAvailableSnapshot();
|
|
4843
|
+
const providerModels = availableModels.filter((model) => model.provider === providerId);
|
|
4844
|
+
// Matches LLAMA_PROVIDER_ID from extensions/llama/provider.ts; kept inline to avoid coupling interactive mode to the built-in extension.
|
|
4845
|
+
if (providerId === "llama.cpp") {
|
|
4846
|
+
selectionError = llamaCppPostLoginGuidance(actionLabel, providerModels.length);
|
|
4847
|
+
}
|
|
4848
|
+
else if (!hasDefaultModelProvider(providerId)) {
|
|
4849
|
+
selectionError = `${actionLabel}, but no default model is configured for provider "${providerId}". Use /model to select a model.`;
|
|
4850
|
+
}
|
|
4851
|
+
else if (providerModels.length === 0) {
|
|
4852
|
+
selectionError = `${actionLabel}, but no models are available for that provider. Use /model to select a model.`;
|
|
4763
4853
|
}
|
|
4764
4854
|
else {
|
|
4765
|
-
|
|
4766
|
-
|
|
4855
|
+
const defaultModelId = defaultModelPerProvider[providerId];
|
|
4856
|
+
// Radius catalogs vary by account; prefer balanced, then use catalog order.
|
|
4857
|
+
selectedModel =
|
|
4858
|
+
providerModels.find((model) => model.id === defaultModelId) ??
|
|
4859
|
+
(providerId === "radius" ? providerModels[0] : undefined);
|
|
4860
|
+
if (!selectedModel) {
|
|
4861
|
+
selectionError = `${actionLabel}, but its default model "${defaultModelId}" is not available. Use /model to select a model.`;
|
|
4767
4862
|
}
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4863
|
+
else {
|
|
4864
|
+
try {
|
|
4865
|
+
await this.session.setModel(selectedModel, { persist: true });
|
|
4866
|
+
}
|
|
4867
|
+
catch (error) {
|
|
4868
|
+
selectedModel = undefined;
|
|
4869
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
4870
|
+
selectionError = `${actionLabel}, but selecting its default model failed: ${errorMessage}. Use /model to select a model.`;
|
|
4871
|
+
}
|
|
4772
4872
|
}
|
|
4773
4873
|
}
|
|
4774
4874
|
}
|
|
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);
|
|
4875
|
+
await this.updateAvailableProviderCount();
|
|
4876
|
+
this.footer.invalidate();
|
|
4877
|
+
this.updateEditorBorderColor();
|
|
4878
|
+
if (selectedModel) {
|
|
4879
|
+
this.showStatus(`${actionLabel}. Selected ${selectedModel.id}. Credentials saved to ${getAuthPath()}`);
|
|
4880
|
+
void this.maybeWarnAboutAnthropicSubscriptionAuth(selectedModel);
|
|
4881
|
+
this.checkDaxnutsEasterEgg(selectedModel);
|
|
4788
4882
|
}
|
|
4789
4883
|
else {
|
|
4790
|
-
|
|
4884
|
+
this.showStatus(`${actionLabel}. Credentials saved to ${getAuthPath()}`);
|
|
4885
|
+
if (selectionError) {
|
|
4886
|
+
this.showError(selectionError);
|
|
4887
|
+
}
|
|
4888
|
+
else {
|
|
4889
|
+
void this.maybeWarnAboutAnthropicSubscriptionAuth();
|
|
4890
|
+
}
|
|
4791
4891
|
}
|
|
4892
|
+
};
|
|
4893
|
+
if (deferSelection) {
|
|
4894
|
+
this.showStatus(`${actionLabel}. Credentials saved to ${getAuthPath()}. Refreshing model catalog…`);
|
|
4895
|
+
}
|
|
4896
|
+
else {
|
|
4897
|
+
await finishAuthentication();
|
|
4792
4898
|
}
|
|
4793
4899
|
const controller = new AbortController();
|
|
4794
4900
|
const timeout = setTimeout(() => controller.abort(), 15_000);
|
|
4795
|
-
void
|
|
4901
|
+
void session.modelRuntime
|
|
4796
4902
|
.refresh({ providers: [providerId], signal: controller.signal })
|
|
4797
|
-
.then((result) => {
|
|
4903
|
+
.then(async (result) => {
|
|
4798
4904
|
if (result.aborted) {
|
|
4799
4905
|
this.showWarning(`${actionLabel}, but its model catalog refresh timed out; using cached models.`);
|
|
4800
4906
|
}
|
|
4801
4907
|
else if (result.errors.size > 0) {
|
|
4802
4908
|
this.showWarning(`${actionLabel}, but its model catalog could not be refreshed; using cached models.`);
|
|
4803
4909
|
}
|
|
4910
|
+
// Do not replace a model or session selected while the refresh was running.
|
|
4911
|
+
if (deferSelection && this.session === session && session.model === previousModel) {
|
|
4912
|
+
await finishAuthentication();
|
|
4913
|
+
}
|
|
4804
4914
|
this.updateAvailableProviderCount();
|
|
4805
4915
|
this.footer.invalidate();
|
|
4806
4916
|
this.ui.requestRender();
|
|
@@ -5142,6 +5252,16 @@ export class InteractiveMode {
|
|
|
5142
5252
|
showError: (message) => this.showError(message),
|
|
5143
5253
|
});
|
|
5144
5254
|
}
|
|
5255
|
+
async handleBugCommand(hint) {
|
|
5256
|
+
await reportBug({
|
|
5257
|
+
session: this.session,
|
|
5258
|
+
ui: this.ui,
|
|
5259
|
+
editorContainer: this.editorContainer,
|
|
5260
|
+
editor: this.editor,
|
|
5261
|
+
showStatus: (message) => this.showStatus(message),
|
|
5262
|
+
showError: (message) => this.showError(message),
|
|
5263
|
+
}, hint);
|
|
5264
|
+
}
|
|
5145
5265
|
async handleCopyCommand(options = {}) {
|
|
5146
5266
|
if (options.preferSelection &&
|
|
5147
5267
|
this.ui instanceof TuiAltScreen &&
|
|
@@ -5227,6 +5347,15 @@ export class InteractiveMode {
|
|
|
5227
5347
|
}
|
|
5228
5348
|
info += `${theme.fg("dim", "Output:")} ${stats.tokens.output.toLocaleString()}\n`;
|
|
5229
5349
|
info += `${theme.fg("dim", "Total:")} ${stats.tokens.total.toLocaleString()}\n`;
|
|
5350
|
+
const cacheWarmingStatus = this.session.cacheWarmingStatus;
|
|
5351
|
+
info += `\n${theme.bold("Cache Warming")}\n`;
|
|
5352
|
+
info += `${theme.fg("dim", "Mode:")} ${this.settingsManager.getCacheWarmingMode()}\n`;
|
|
5353
|
+
info += `${theme.fg("dim", "Status:")} ${cacheWarmingStatus ? formatCacheWarmingStatus(cacheWarmingStatus) : "Inactive (cache warming unavailable)"}\n`;
|
|
5354
|
+
const decision = cacheWarmingStatus?.decision;
|
|
5355
|
+
if (decision?.economicsAvailable) {
|
|
5356
|
+
info += `${theme.fg("dim", "Cache miss penalty:")} $${decision.missCost.toFixed(3)}\n`;
|
|
5357
|
+
info += `${theme.fg("dim", "Refresh cost:")} $${decision.warmCost.toFixed(3)}\n`;
|
|
5358
|
+
}
|
|
5230
5359
|
if (stats.cost > 0 || cacheWaste.missedTokens > 0) {
|
|
5231
5360
|
info += `\n${theme.bold("Cost")}\n`;
|
|
5232
5361
|
info += `${theme.fg("dim", "Total:")} $${stats.cost.toFixed(3)}`;
|
|
@@ -5357,7 +5486,7 @@ export class InteractiveMode {
|
|
|
5357
5486
|
| \`${expandTools}\` | Toggle tool output expansion |
|
|
5358
5487
|
| \`${toggleThinking}\` | Toggle thinking block visibility |
|
|
5359
5488
|
| \`${externalEditor}\` | Edit message in external editor |
|
|
5360
|
-
| \`${copyMessage}\` | Copy last assistant message |
|
|
5489
|
+
| \`${copyMessage}\` | Copy selection or last assistant message |
|
|
5361
5490
|
| \`${followUp}\` | Queue follow-up message |
|
|
5362
5491
|
| \`${dequeue}\` | Restore queued messages |
|
|
5363
5492
|
| \`${pasteImage}\` | Paste image or text from clipboard |
|
|
@@ -5453,12 +5582,19 @@ export class InteractiveMode {
|
|
|
5453
5582
|
async handleBashCommand(command, excludeFromContext = false) {
|
|
5454
5583
|
const extensionRunner = this.session.extensionRunner;
|
|
5455
5584
|
// Emit user_bash event to let extensions intercept
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5585
|
+
let eventResult;
|
|
5586
|
+
try {
|
|
5587
|
+
eventResult = await extensionRunner.emitUserBash({
|
|
5588
|
+
type: "user_bash",
|
|
5589
|
+
command,
|
|
5590
|
+
excludeFromContext,
|
|
5591
|
+
cwd: this.sessionManager.getCwd(),
|
|
5592
|
+
});
|
|
5593
|
+
}
|
|
5594
|
+
catch {
|
|
5595
|
+
// The extension runner already reported the error. Do not fall back to local execution.
|
|
5596
|
+
return;
|
|
5597
|
+
}
|
|
5462
5598
|
// If extension returned a full result, use it directly
|
|
5463
5599
|
if (eventResult?.result) {
|
|
5464
5600
|
const result = eventResult.result;
|