@code-yeongyu/senpi 2026.7.9-2 → 2026.7.9
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 +1 -25
- package/README.md +1 -1
- package/dist/cli/args.js +3 -3
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/config-selector.d.ts +2 -4
- package/dist/cli/config-selector.d.ts.map +1 -1
- package/dist/cli/config-selector.js +1 -1
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/core/agent-session.d.ts +3 -18
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +36 -153
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +2 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +79 -54
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/extensions/builtin/goal/continuation.js +1 -1
- package/dist/core/extensions/builtin/goal/continuation.js.map +1 -1
- package/dist/core/extensions/builtin/goal/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/goal/index.js +0 -1
- package/dist/core/extensions/builtin/goal/index.js.map +1 -1
- package/dist/core/extensions/builtin/import-repro.d.ts.map +1 -1
- package/dist/core/extensions/builtin/import-repro.js +6 -100
- package/dist/core/extensions/builtin/import-repro.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/connection.d.ts +0 -1
- package/dist/core/extensions/builtin/mcp/connection.d.ts.map +1 -1
- package/dist/core/extensions/builtin/mcp/connection.js +0 -15
- package/dist/core/extensions/builtin/mcp/connection.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/service.d.ts.map +1 -1
- package/dist/core/extensions/builtin/mcp/service.js +1 -3
- package/dist/core/extensions/builtin/mcp/service.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/runner.d.ts +3 -4
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +24 -30
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +3 -23
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/model-registry.d.ts +0 -3
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +3 -20
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/package-manager.d.ts +1 -4
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +26 -68
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/resource-loader.d.ts +2 -2
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +7 -6
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +2 -9
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +2 -11
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +0 -5
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +0 -8
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts +0 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +3 -3
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts +2 -2
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +0 -1
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts +3 -34
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +24 -272
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +0 -4
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +2 -5
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts +1 -3
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +6 -16
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +0 -2
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +0 -10
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +0 -10
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +37 -261
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/print-mode.js +1 -1
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +6 -6
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +3 -3
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/package-manager-cli.d.ts +2 -2
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +17 -64
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/utils/clipboard-image.js +1 -1
- package/dist/utils/clipboard-image.js.map +1 -1
- package/docs/extensions.md +9 -33
- package/docs/models.md +4 -4
- package/docs/packages.md +10 -7
- package/docs/rpc.md +3 -13
- package/docs/sdk.md +0 -22
- package/docs/settings.md +0 -1
- package/docs/usage.md +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/reload-runtime.ts +2 -2
- 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/examples/sdk/README.md +1 -1
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +3 -3
- package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js +2 -37
- package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl-repo.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl-repo.js +0 -2
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl-repo.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl-storage.d.ts +0 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl-storage.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl-storage.js +0 -7
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl-storage.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.d.ts +4 -18
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.js +37 -72
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts +0 -2
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/index.d.ts +0 -2
- package/node_modules/@earendil-works/pi-agent-core/dist/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/index.js +0 -2
- package/node_modules/@earendil-works/pi-agent-core/dist/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +1 -2
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/transform-messages.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/transform-messages.js +1 -4
- package/node_modules/@earendil-works/pi-ai/dist/api/transform-messages.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +195 -446
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.models.d.ts +0 -84
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.models.js +0 -72
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.models.js +4 -4
- package/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex.models.d.ts +0 -63
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex.models.js +0 -54
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai.models.d.ts +0 -84
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai.models.js +0 -72
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts +63 -138
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js +76 -136
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.d.ts +0 -77
- package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.js +0 -71
- package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-ams.models.d.ts +44 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-ams.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-ams.models.js +45 -9
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-ams.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-cn.models.d.ts +44 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-cn.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-cn.models.js +45 -9
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-cn.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-sgp.models.d.ts +44 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-sgp.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-sgp.models.js +45 -9
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-sgp.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +0 -3
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +1 -1
- package/node_modules/@earendil-works/pi-pty/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +1 -22
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/npm-shrinkwrap.json +14 -14
- package/package.json +6 -6
- package/dist/core/cache-stats.d.ts +0 -49
- package/dist/core/cache-stats.d.ts.map +0 -1
- package/dist/core/cache-stats.js +0 -101
- package/dist/core/cache-stats.js.map +0 -1
|
@@ -13,7 +13,6 @@ import { APP_NAME, APP_TITLE, CONFIG_DIR_NAME, expandTildePath, getAuthPath, get
|
|
|
13
13
|
import { parseSkillBlock } from "../../core/agent-session.js";
|
|
14
14
|
import { SessionImportFileNotFoundError } from "../../core/agent-session-runtime.js";
|
|
15
15
|
import { isApiKeyLoginProvider } from "../../core/auth-providers.js";
|
|
16
|
-
import { CACHE_TTL_MS, collectCacheMisses, computeCacheWaste, detectCacheMiss, } from "../../core/cache-stats.js";
|
|
17
16
|
import { FooterDataProvider } from "../../core/footer-data-provider.js";
|
|
18
17
|
import { appendHiddenTuiStdout } from "../../core/hidden-stdout-log.js";
|
|
19
18
|
import { configureHttpDispatcher, formatHttpIdleTimeoutMs } from "../../core/http-dispatcher.js";
|
|
@@ -50,12 +49,12 @@ import { ExtensionEditorComponent } from "./components/extension-editor.js";
|
|
|
50
49
|
import { ExtensionInputComponent } from "./components/extension-input.js";
|
|
51
50
|
import { ExtensionSelectorComponent } from "./components/extension-selector.js";
|
|
52
51
|
import { FavoriteModelsSelectorComponent } from "./components/favorite-models-selector.js";
|
|
53
|
-
import { FooterComponent
|
|
52
|
+
import { FooterComponent } from "./components/footer.js";
|
|
54
53
|
import { formatKeyText, keyDisplayText, keyHint, keyText, rawKeyHint } from "./components/keybinding-hints.js";
|
|
55
54
|
import { LoginDialogComponent } from "./components/login-dialog.js";
|
|
56
55
|
import { getModelFullId } from "./components/model-favorites.js";
|
|
57
56
|
import { ModelSelectorComponent } from "./components/model-selector.js";
|
|
58
|
-
import {
|
|
57
|
+
import { OAuthSelectorComponent } from "./components/oauth-selector.js";
|
|
59
58
|
import { SessionSelectorComponent } from "./components/session-selector.js";
|
|
60
59
|
import { SettingsSelectorComponent } from "./components/settings-selector.js";
|
|
61
60
|
import { SkillInvocationMessageComponent } from "./components/skill-invocation-message.js";
|
|
@@ -67,6 +66,7 @@ import { UserMessageComponent } from "./components/user-message.js";
|
|
|
67
66
|
import { UserMessageSelectorComponent } from "./components/user-message-selector.js";
|
|
68
67
|
import { restoreInteractiveStderr, takeOverInteractiveStderr } from "./interactive-stderr-guard.js";
|
|
69
68
|
import { getModelSearchText } from "./model-search.js";
|
|
69
|
+
import { formatSessionInfo } from "./session-info-format.js";
|
|
70
70
|
import { resolveStartupToolPaths } from "./startup-tools.js";
|
|
71
71
|
import { getAvailableThemes, getAvailableThemesWithPaths, getEditorTheme, getMarkdownTheme, getThemeByName, onThemeChange, setRegisteredThemes, stopThemeWatcher, Theme, theme, } from "./theme/theme.js";
|
|
72
72
|
import { InteractiveThemeController } from "./theme/theme-controller.js";
|
|
@@ -179,42 +179,6 @@ const BEDROCK_PROVIDER_ID = "amazon-bedrock";
|
|
|
179
179
|
// keep the existing public import (test/oauth-selector.test.ts) working, and used
|
|
180
180
|
// locally by getLoginProviderOptions below.
|
|
181
181
|
export { isApiKeyLoginProvider };
|
|
182
|
-
const AUTH_TYPE_ORDER = { oauth: 0, api_key: 1 };
|
|
183
|
-
function createFuzzyAutocompleteItems(items, prefix, getSearchText, toAutocompleteItem) {
|
|
184
|
-
const filtered = fuzzyFilter(items, prefix, getSearchText);
|
|
185
|
-
if (filtered.length === 0)
|
|
186
|
-
return null;
|
|
187
|
-
return filtered.map(toAutocompleteItem);
|
|
188
|
-
}
|
|
189
|
-
function getLoginProviderCompletionOptions(providerOptions) {
|
|
190
|
-
const byId = new Map();
|
|
191
|
-
for (const provider of providerOptions) {
|
|
192
|
-
const existing = byId.get(provider.id);
|
|
193
|
-
if (existing) {
|
|
194
|
-
if (!existing.authTypes.includes(provider.authType)) {
|
|
195
|
-
existing.authTypes.push(provider.authType);
|
|
196
|
-
existing.authTypes.sort((a, b) => AUTH_TYPE_ORDER[a] - AUTH_TYPE_ORDER[b]);
|
|
197
|
-
}
|
|
198
|
-
continue;
|
|
199
|
-
}
|
|
200
|
-
byId.set(provider.id, {
|
|
201
|
-
id: provider.id,
|
|
202
|
-
name: provider.name,
|
|
203
|
-
authTypes: [provider.authType],
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
return Array.from(byId.values()).sort((a, b) => a.name.localeCompare(b.name));
|
|
207
|
-
}
|
|
208
|
-
function getLoginProviderSearchText(provider) {
|
|
209
|
-
const authTypes = provider.authTypes
|
|
210
|
-
.map((authType) => `${authType} ${formatAuthSelectorProviderType(authType)}`)
|
|
211
|
-
.join(" ");
|
|
212
|
-
return `${provider.id} ${provider.name} ${authTypes}`;
|
|
213
|
-
}
|
|
214
|
-
function formatLoginProviderCompletionDescription(provider) {
|
|
215
|
-
const authTypes = provider.authTypes.map(formatAuthSelectorProviderType).join("/");
|
|
216
|
-
return provider.name === provider.id ? authTypes : `${provider.name} · ${authTypes}`;
|
|
217
|
-
}
|
|
218
182
|
export class InteractiveMode {
|
|
219
183
|
requestStreamingRender() {
|
|
220
184
|
this.ui.requestRender();
|
|
@@ -386,7 +350,6 @@ export class InteractiveMode {
|
|
|
386
350
|
const slashCommands = BUILTIN_SLASH_COMMANDS.map((command) => ({
|
|
387
351
|
name: command.name,
|
|
388
352
|
description: command.description,
|
|
389
|
-
...(command.argumentHint && { argumentHint: command.argumentHint }),
|
|
390
353
|
}));
|
|
391
354
|
const modelCommand = slashCommands.find((command) => command.name === "model");
|
|
392
355
|
if (modelCommand) {
|
|
@@ -404,24 +367,17 @@ export class InteractiveMode {
|
|
|
404
367
|
name: m.name,
|
|
405
368
|
label: `${m.provider}/${m.id}`,
|
|
406
369
|
}));
|
|
407
|
-
|
|
370
|
+
// Fuzzy filter by model ID + provider in either order.
|
|
371
|
+
const filtered = fuzzyFilter(items, prefix, getModelSearchText);
|
|
372
|
+
if (filtered.length === 0)
|
|
373
|
+
return null;
|
|
374
|
+
return filtered.map((item) => ({
|
|
408
375
|
value: item.label,
|
|
409
376
|
label: item.id,
|
|
410
377
|
description: item.provider,
|
|
411
378
|
}));
|
|
412
379
|
};
|
|
413
380
|
}
|
|
414
|
-
const loginCommand = slashCommands.find((command) => command.name === "login");
|
|
415
|
-
if (loginCommand) {
|
|
416
|
-
loginCommand.getArgumentCompletions = (prefix) => {
|
|
417
|
-
const providers = getLoginProviderCompletionOptions(this.getLoginProviderOptions());
|
|
418
|
-
return createFuzzyAutocompleteItems(providers, prefix, getLoginProviderSearchText, (provider) => ({
|
|
419
|
-
value: provider.id,
|
|
420
|
-
label: provider.id,
|
|
421
|
-
description: formatLoginProviderCompletionDescription(provider),
|
|
422
|
-
}));
|
|
423
|
-
};
|
|
424
|
-
}
|
|
425
381
|
// Convert prompt templates to SlashCommand format for autocomplete
|
|
426
382
|
const templateCommands = this.session.promptTemplates.map((cmd) => ({
|
|
427
383
|
name: cmd.name,
|
|
@@ -1249,7 +1205,7 @@ export class InteractiveMode {
|
|
|
1249
1205
|
this.restoreQueuedMessagesToEditor({ abort: true });
|
|
1250
1206
|
},
|
|
1251
1207
|
commandContextActions: {
|
|
1252
|
-
waitForIdle: () => this.session.waitForIdle(),
|
|
1208
|
+
waitForIdle: () => this.session.agent.waitForIdle(),
|
|
1253
1209
|
newSession: async (options) => {
|
|
1254
1210
|
this.clearStatusIndicator();
|
|
1255
1211
|
try {
|
|
@@ -1300,7 +1256,7 @@ export class InteractiveMode {
|
|
|
1300
1256
|
},
|
|
1301
1257
|
shutdownHandler: () => {
|
|
1302
1258
|
this.shutdownRequested = true;
|
|
1303
|
-
if (this.session.
|
|
1259
|
+
if (!this.session.isStreaming) {
|
|
1304
1260
|
void this.shutdown();
|
|
1305
1261
|
}
|
|
1306
1262
|
},
|
|
@@ -1395,7 +1351,7 @@ export class InteractiveMode {
|
|
|
1395
1351
|
modelRegistry: this.session.modelRegistry,
|
|
1396
1352
|
model: this.session.model,
|
|
1397
1353
|
serviceTier: this.session.serviceTier,
|
|
1398
|
-
isIdle: () => this.session.
|
|
1354
|
+
isIdle: () => !this.session.isStreaming,
|
|
1399
1355
|
isProjectTrusted: () => this.settingsManager.isProjectTrusted(),
|
|
1400
1356
|
signal: this.session.agent.signal,
|
|
1401
1357
|
abort: () => this.session.abort(),
|
|
@@ -2391,10 +2347,9 @@ export class InteractiveMode {
|
|
|
2391
2347
|
this.editor.setText("");
|
|
2392
2348
|
return;
|
|
2393
2349
|
}
|
|
2394
|
-
if (text === "/login"
|
|
2395
|
-
|
|
2350
|
+
if (text === "/login") {
|
|
2351
|
+
this.showOAuthSelector("login");
|
|
2396
2352
|
this.editor.setText("");
|
|
2397
|
-
await this.handleLoginCommand(providerRef);
|
|
2398
2353
|
return;
|
|
2399
2354
|
}
|
|
2400
2355
|
if (text === "/logout") {
|
|
@@ -2627,7 +2582,6 @@ export class InteractiveMode {
|
|
|
2627
2582
|
for (const [, component] of this.pendingTools.entries()) {
|
|
2628
2583
|
component.setArgsComplete();
|
|
2629
2584
|
}
|
|
2630
|
-
this.maybeShowCacheMissNotice(this.streamingMessage);
|
|
2631
2585
|
}
|
|
2632
2586
|
this.streamingComponent = undefined;
|
|
2633
2587
|
this.streamingMessage = undefined;
|
|
@@ -2685,10 +2639,8 @@ export class InteractiveMode {
|
|
|
2685
2639
|
this.streamingMessage = undefined;
|
|
2686
2640
|
}
|
|
2687
2641
|
this.clearPendingTools();
|
|
2688
|
-
this.ui.requestRender();
|
|
2689
|
-
break;
|
|
2690
|
-
case "agent_settled":
|
|
2691
2642
|
await this.checkShutdownRequested();
|
|
2643
|
+
this.ui.requestRender();
|
|
2692
2644
|
break;
|
|
2693
2645
|
case "compaction_start": {
|
|
2694
2646
|
if (this.settingsManager.getShowTerminalProgress()) {
|
|
@@ -2919,11 +2871,6 @@ export class InteractiveMode {
|
|
|
2919
2871
|
renderSessionItems(items, options = {}) {
|
|
2920
2872
|
this.clearPendingTools();
|
|
2921
2873
|
const renderedPendingTools = new Map();
|
|
2922
|
-
// Cache-miss notices are not persisted; re-derive them from the full entry
|
|
2923
|
-
// list and re-inject them after the assistant messages that paid for them.
|
|
2924
|
-
const cacheMisses = this.settingsManager.getShowCacheMissNotices()
|
|
2925
|
-
? collectCacheMisses(this.sessionManager.getEntries(), this.session.modelRegistry)
|
|
2926
|
-
: new Map();
|
|
2927
2874
|
if (options.updateFooter) {
|
|
2928
2875
|
this.footer.invalidate();
|
|
2929
2876
|
this.updateEditorBorderColor();
|
|
@@ -2961,11 +2908,6 @@ export class InteractiveMode {
|
|
|
2961
2908
|
}
|
|
2962
2909
|
}
|
|
2963
2910
|
}
|
|
2964
|
-
if (message.stopReason !== "aborted" && message.stopReason !== "error") {
|
|
2965
|
-
const miss = cacheMisses.get(message);
|
|
2966
|
-
if (miss)
|
|
2967
|
-
this.addCacheMissNotice(miss);
|
|
2968
|
-
}
|
|
2969
2911
|
}
|
|
2970
2912
|
else if (message.role === "toolResult") {
|
|
2971
2913
|
// Match tool results to pending tool components
|
|
@@ -3000,35 +2942,6 @@ export class InteractiveMode {
|
|
|
3000
2942
|
});
|
|
3001
2943
|
this.renderSessionItems(items, options);
|
|
3002
2944
|
}
|
|
3003
|
-
/**
|
|
3004
|
-
* Show a transcript notice when a completed assistant message paid for a
|
|
3005
|
-
* significant cache miss. Only states observable facts: the miss itself,
|
|
3006
|
-
* a model switch, or an idle gap past the cache TTL.
|
|
3007
|
-
*/
|
|
3008
|
-
maybeShowCacheMissNotice(message) {
|
|
3009
|
-
if (!this.settingsManager.getShowCacheMissNotices())
|
|
3010
|
-
return;
|
|
3011
|
-
// Entries don't contain `message` yet: message_end fires before persistence.
|
|
3012
|
-
const miss = detectCacheMiss(this.sessionManager.getEntries(), message, this.session.modelRegistry);
|
|
3013
|
-
if (miss)
|
|
3014
|
-
this.addCacheMissNotice(miss);
|
|
3015
|
-
}
|
|
3016
|
-
addCacheMissNotice(miss) {
|
|
3017
|
-
if (miss.missedTokens < 20_000 && miss.missedCost < 0.1)
|
|
3018
|
-
return;
|
|
3019
|
-
const cost = miss.missedCost >= 0.01 ? ` (~$${miss.missedCost.toFixed(2)})` : "";
|
|
3020
|
-
const reBilled = `${formatTokens(miss.missedTokens)} tokens re-billed${cost}`;
|
|
3021
|
-
let label = "Cache miss";
|
|
3022
|
-
if (miss.modelChanged) {
|
|
3023
|
-
label = "Cache miss after model switch";
|
|
3024
|
-
}
|
|
3025
|
-
else if (miss.idleMs >= CACHE_TTL_MS) {
|
|
3026
|
-
label = `Cache miss after ${Math.round(miss.idleMs / 60_000)}m idle`;
|
|
3027
|
-
}
|
|
3028
|
-
const text = theme.fg("warning", `${label}: ${reBilled}`);
|
|
3029
|
-
this.chatContainer.addChild(new Spacer(1));
|
|
3030
|
-
this.chatContainer.addChild(new Text(text, 1, 0));
|
|
3031
|
-
}
|
|
3032
2945
|
renderInitialMessages() {
|
|
3033
2946
|
const entries = this.sessionManager.buildContextEntries();
|
|
3034
2947
|
this.renderSessionEntries(entries, {
|
|
@@ -3683,7 +3596,6 @@ export class InteractiveMode {
|
|
|
3683
3596
|
doubleEscapeAction: this.settingsManager.getDoubleEscapeAction(),
|
|
3684
3597
|
treeFilterMode: this.settingsManager.getTreeFilterMode(),
|
|
3685
3598
|
showHardwareCursor: this.settingsManager.getShowHardwareCursor(),
|
|
3686
|
-
showCacheMissNotices: this.settingsManager.getShowCacheMissNotices(),
|
|
3687
3599
|
defaultProjectTrust: this.settingsManager.getDefaultProjectTrust(),
|
|
3688
3600
|
editorPaddingX: this.settingsManager.getEditorPaddingX(),
|
|
3689
3601
|
outputPad: this.settingsManager.getOutputPad(),
|
|
@@ -3760,10 +3672,6 @@ export class InteractiveMode {
|
|
|
3760
3672
|
this.chatContainer.clear();
|
|
3761
3673
|
this.rebuildChatFromMessages();
|
|
3762
3674
|
},
|
|
3763
|
-
onShowCacheMissNoticesChange: (shown) => {
|
|
3764
|
-
this.settingsManager.setShowCacheMissNotices(shown);
|
|
3765
|
-
this.rebuildChatFromMessages();
|
|
3766
|
-
},
|
|
3767
3675
|
onCollapseChangelogChange: (collapsed) => {
|
|
3768
3676
|
this.settingsManager.setCollapseChangelog(collapsed);
|
|
3769
3677
|
},
|
|
@@ -4067,17 +3975,19 @@ export class InteractiveMode {
|
|
|
4067
3975
|
const initialSelectedId = userMessages[userMessages.length - 1]?.entryId;
|
|
4068
3976
|
this.showSelector((done) => {
|
|
4069
3977
|
const selector = new UserMessageSelectorComponent(userMessages.map((m) => ({ id: m.entryId, text: m.text })), async (entryId) => {
|
|
4070
|
-
done();
|
|
4071
3978
|
try {
|
|
4072
3979
|
const result = await this.runtimeHost.fork(entryId);
|
|
4073
3980
|
if (result.cancelled) {
|
|
3981
|
+
done();
|
|
4074
3982
|
this.ui.requestRender();
|
|
4075
3983
|
return;
|
|
4076
3984
|
}
|
|
4077
3985
|
this.editor.setText(result.selectedText ?? "");
|
|
3986
|
+
done();
|
|
4078
3987
|
this.showStatus("Forked to new session");
|
|
4079
3988
|
}
|
|
4080
3989
|
catch (error) {
|
|
3990
|
+
done();
|
|
4081
3991
|
this.showError(error instanceof Error ? error.message : String(error));
|
|
4082
3992
|
}
|
|
4083
3993
|
}, () => {
|
|
@@ -4306,82 +4216,13 @@ export class InteractiveMode {
|
|
|
4306
4216
|
}
|
|
4307
4217
|
return options.sort((a, b) => a.name.localeCompare(b.name));
|
|
4308
4218
|
}
|
|
4309
|
-
|
|
4310
|
-
const normalizedProviderRef = providerRef.trim().toLowerCase();
|
|
4311
|
-
if (!normalizedProviderRef) {
|
|
4312
|
-
return [];
|
|
4313
|
-
}
|
|
4314
|
-
return this.getLoginProviderOptions().filter((provider) => provider.id.toLowerCase() === normalizedProviderRef ||
|
|
4315
|
-
provider.name.toLowerCase() === normalizedProviderRef);
|
|
4316
|
-
}
|
|
4317
|
-
async handleLoginCommand(providerRef) {
|
|
4318
|
-
if (!providerRef) {
|
|
4319
|
-
this.showLoginAuthTypeSelector();
|
|
4320
|
-
return;
|
|
4321
|
-
}
|
|
4322
|
-
const providerOptions = this.findLoginProviderOptions(providerRef);
|
|
4323
|
-
if (providerOptions.length === 1) {
|
|
4324
|
-
await this.startProviderLogin(providerOptions[0]);
|
|
4325
|
-
return;
|
|
4326
|
-
}
|
|
4327
|
-
if (providerOptions.length > 1) {
|
|
4328
|
-
const providerIds = new Set(providerOptions.map((provider) => provider.id));
|
|
4329
|
-
if (providerIds.size === 1) {
|
|
4330
|
-
this.showLoginAuthTypeSelector(providerOptions);
|
|
4331
|
-
return;
|
|
4332
|
-
}
|
|
4333
|
-
}
|
|
4334
|
-
this.showLoginProviderSelector(undefined, providerRef);
|
|
4335
|
-
}
|
|
4336
|
-
async startProviderLogin(providerOption) {
|
|
4337
|
-
if (providerOption.authType === "oauth") {
|
|
4338
|
-
await this.showLoginDialog(providerOption.id, providerOption.name);
|
|
4339
|
-
}
|
|
4340
|
-
else if (providerOption.id === BEDROCK_PROVIDER_ID) {
|
|
4341
|
-
this.showBedrockSetupDialog(providerOption.id, providerOption.name);
|
|
4342
|
-
}
|
|
4343
|
-
else {
|
|
4344
|
-
await this.showApiKeyLoginDialog(providerOption.id, providerOption.name);
|
|
4345
|
-
}
|
|
4346
|
-
}
|
|
4347
|
-
showLoginAuthTypeSelector(providerOptions) {
|
|
4219
|
+
showLoginAuthTypeSelector() {
|
|
4348
4220
|
const subscriptionLabel = "Use a subscription";
|
|
4349
4221
|
const apiKeyLabel = "Use an API key";
|
|
4350
|
-
const availableAuthTypes = providerOptions
|
|
4351
|
-
? new Set(providerOptions.map((provider) => provider.authType))
|
|
4352
|
-
: new Set(["oauth", "api_key"]);
|
|
4353
|
-
const options = [];
|
|
4354
|
-
if (availableAuthTypes.has("oauth")) {
|
|
4355
|
-
options.push(subscriptionLabel);
|
|
4356
|
-
}
|
|
4357
|
-
if (availableAuthTypes.has("api_key")) {
|
|
4358
|
-
options.push(apiKeyLabel);
|
|
4359
|
-
}
|
|
4360
|
-
if (options.length === 0) {
|
|
4361
|
-
this.showStatus("No login methods available.");
|
|
4362
|
-
return;
|
|
4363
|
-
}
|
|
4364
|
-
if (providerOptions && options.length === 1) {
|
|
4365
|
-
const providerOption = providerOptions[0];
|
|
4366
|
-
if (providerOption) {
|
|
4367
|
-
void this.startProviderLogin(providerOption);
|
|
4368
|
-
}
|
|
4369
|
-
return;
|
|
4370
|
-
}
|
|
4371
|
-
const title = providerOptions?.[0]
|
|
4372
|
-
? `Select authentication method for ${providerOptions[0].name}:`
|
|
4373
|
-
: "Select authentication method:";
|
|
4374
4222
|
this.showSelector((done) => {
|
|
4375
|
-
const selector = new ExtensionSelectorComponent(
|
|
4223
|
+
const selector = new ExtensionSelectorComponent("Select authentication method:", [subscriptionLabel, apiKeyLabel], (option) => {
|
|
4376
4224
|
done();
|
|
4377
4225
|
const authType = option === subscriptionLabel ? "oauth" : "api_key";
|
|
4378
|
-
if (providerOptions) {
|
|
4379
|
-
const providerOption = providerOptions.find((provider) => provider.authType === authType);
|
|
4380
|
-
if (providerOption) {
|
|
4381
|
-
void this.startProviderLogin(providerOption);
|
|
4382
|
-
}
|
|
4383
|
-
return;
|
|
4384
|
-
}
|
|
4385
4226
|
this.showLoginProviderSelector(authType);
|
|
4386
4227
|
}, () => {
|
|
4387
4228
|
done();
|
|
@@ -4390,34 +4231,32 @@ export class InteractiveMode {
|
|
|
4390
4231
|
return { component: selector, focus: selector };
|
|
4391
4232
|
});
|
|
4392
4233
|
}
|
|
4393
|
-
showLoginProviderSelector(authType
|
|
4234
|
+
showLoginProviderSelector(authType) {
|
|
4394
4235
|
const providerOptions = this.getLoginProviderOptions(authType);
|
|
4395
4236
|
if (providerOptions.length === 0) {
|
|
4396
|
-
|
|
4397
|
-
? "No subscription providers available."
|
|
4398
|
-
: authType === "api_key"
|
|
4399
|
-
? "No API key providers available."
|
|
4400
|
-
: "No login providers available.";
|
|
4401
|
-
this.showStatus(message);
|
|
4237
|
+
this.showStatus(authType === "oauth" ? "No subscription providers available." : "No API key providers available.");
|
|
4402
4238
|
return;
|
|
4403
4239
|
}
|
|
4404
4240
|
this.showSelector((done) => {
|
|
4405
|
-
const selector = new OAuthSelectorComponent("login", this.session.modelRegistry.authStorage, providerOptions, async (providerId
|
|
4241
|
+
const selector = new OAuthSelectorComponent("login", this.session.modelRegistry.authStorage, providerOptions, async (providerId) => {
|
|
4406
4242
|
done();
|
|
4407
|
-
const providerOption = providerOptions.find((provider) => provider.id === providerId
|
|
4243
|
+
const providerOption = providerOptions.find((provider) => provider.id === providerId);
|
|
4408
4244
|
if (!providerOption) {
|
|
4409
4245
|
return;
|
|
4410
4246
|
}
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
if (
|
|
4415
|
-
this.
|
|
4247
|
+
if (providerOption.authType === "oauth") {
|
|
4248
|
+
await this.showLoginDialog(providerOption.id, providerOption.name);
|
|
4249
|
+
}
|
|
4250
|
+
else if (providerOption.id === BEDROCK_PROVIDER_ID) {
|
|
4251
|
+
this.showBedrockSetupDialog(providerOption.id, providerOption.name);
|
|
4416
4252
|
}
|
|
4417
4253
|
else {
|
|
4418
|
-
this.
|
|
4254
|
+
await this.showApiKeyLoginDialog(providerOption.id, providerOption.name);
|
|
4419
4255
|
}
|
|
4420
|
-
}, (
|
|
4256
|
+
}, () => {
|
|
4257
|
+
done();
|
|
4258
|
+
this.showLoginAuthTypeSelector();
|
|
4259
|
+
}, (providerId) => this.session.modelRegistry.getProviderAuthStatus(providerId));
|
|
4421
4260
|
return { component: selector, focus: selector };
|
|
4422
4261
|
});
|
|
4423
4262
|
}
|
|
@@ -4678,7 +4517,7 @@ export class InteractiveMode {
|
|
|
4678
4517
|
const borderColor = (s) => theme.fg("border", s);
|
|
4679
4518
|
reloadBox.addChild(new DynamicBorder(borderColor));
|
|
4680
4519
|
reloadBox.addChild(new Spacer(1));
|
|
4681
|
-
reloadBox.addChild(new Text(theme.fg("muted", "Reloading keybindings, extensions, skills, prompts, themes
|
|
4520
|
+
reloadBox.addChild(new Text(theme.fg("muted", "Reloading keybindings, extensions, skills, prompts, themes..."), 1, 0));
|
|
4682
4521
|
reloadBox.addChild(new Spacer(1));
|
|
4683
4522
|
reloadBox.addChild(new DynamicBorder(borderColor));
|
|
4684
4523
|
const previousEditor = this.editor;
|
|
@@ -4742,8 +4581,8 @@ export class InteractiveMode {
|
|
|
4742
4581
|
this.showError(`models.json error: ${modelsJsonError}`);
|
|
4743
4582
|
}
|
|
4744
4583
|
this.showStatus(savedImplicitProjectTrust
|
|
4745
|
-
? "Reloaded keybindings, extensions, skills, prompts, themes
|
|
4746
|
-
: "Reloaded keybindings, extensions, skills, prompts, themes
|
|
4584
|
+
? "Reloaded keybindings, extensions, skills, prompts, themes; saved project trust"
|
|
4585
|
+
: "Reloaded keybindings, extensions, skills, prompts, themes");
|
|
4747
4586
|
dismissReloadBox(this.editor);
|
|
4748
4587
|
reloadBoxDismissed = true;
|
|
4749
4588
|
}
|
|
@@ -4964,70 +4803,7 @@ export class InteractiveMode {
|
|
|
4964
4803
|
handleSessionCommand() {
|
|
4965
4804
|
const stats = this.session.getSessionStats();
|
|
4966
4805
|
const sessionName = this.sessionManager.getSessionName();
|
|
4967
|
-
const
|
|
4968
|
-
const cacheWaste = computeCacheWaste(entries, this.session.modelRegistry);
|
|
4969
|
-
// Cost/token totals per provider/model actually used (e.g. OpenRouter `auto`
|
|
4970
|
-
// resolves to a concrete responseModel), sorted by cost descending.
|
|
4971
|
-
const perModelMap = new Map();
|
|
4972
|
-
for (const entry of entries) {
|
|
4973
|
-
if (entry.type !== "message" || entry.message.role !== "assistant")
|
|
4974
|
-
continue;
|
|
4975
|
-
const message = entry.message;
|
|
4976
|
-
const usage = message.usage;
|
|
4977
|
-
const key = `${message.provider}/${message.responseModel ?? message.model}`;
|
|
4978
|
-
let bucket = perModelMap.get(key);
|
|
4979
|
-
if (!bucket) {
|
|
4980
|
-
bucket = { key, cost: 0, tokens: 0 };
|
|
4981
|
-
perModelMap.set(key, bucket);
|
|
4982
|
-
}
|
|
4983
|
-
bucket.cost += usage.cost.total;
|
|
4984
|
-
bucket.tokens += usage.input + usage.output + usage.cacheRead + usage.cacheWrite;
|
|
4985
|
-
}
|
|
4986
|
-
const perModel = Array.from(perModelMap.values()).sort((a, b) => b.cost - a.cost);
|
|
4987
|
-
let info = `${theme.bold("Session Info")}\n\n`;
|
|
4988
|
-
if (sessionName) {
|
|
4989
|
-
info += `${theme.fg("dim", "Name:")} ${sessionName}\n`;
|
|
4990
|
-
}
|
|
4991
|
-
info += `${theme.fg("dim", "File:")} ${stats.sessionFile ?? "In-memory"}\n`;
|
|
4992
|
-
info += `${theme.fg("dim", "ID:")} ${stats.sessionId}\n\n`;
|
|
4993
|
-
info += `${theme.bold("Messages")}\n`;
|
|
4994
|
-
info += `${theme.fg("dim", "Total:")} ${stats.totalMessages}\n`;
|
|
4995
|
-
info += `${theme.fg("dim", "User:")} ${stats.userMessages}\n`;
|
|
4996
|
-
info += `${theme.fg("dim", "Assistant:")} ${stats.assistantMessages}\n`;
|
|
4997
|
-
info += `${theme.fg("dim", "Tools:")} ${stats.toolCalls} calls, ${stats.toolResults} results\n\n`;
|
|
4998
|
-
info += `${theme.bold("Tokens")}\n`;
|
|
4999
|
-
// "Input" is the full prompt volume. With cache activity, split it into
|
|
5000
|
-
// cached (served from cache) vs uncached (everything else) - the only
|
|
5001
|
-
// provider-independent split. Cache writes, where reported, are a detail
|
|
5002
|
-
// of the uncached portion.
|
|
5003
|
-
const { input, cacheRead, cacheWrite } = stats.tokens;
|
|
5004
|
-
const promptTokens = input + cacheRead + cacheWrite;
|
|
5005
|
-
info += `${theme.fg("dim", "Input:")} ${promptTokens.toLocaleString()}\n`;
|
|
5006
|
-
if (promptTokens > 0 && (cacheRead > 0 || cacheWrite > 0)) {
|
|
5007
|
-
const hitRate = theme.fg("dim", `(${((cacheRead / promptTokens) * 100).toFixed(1)}%)`);
|
|
5008
|
-
info += ` ${theme.fg("dim", "Cached:")} ${cacheRead.toLocaleString()} ${hitRate}\n`;
|
|
5009
|
-
const written = cacheWrite > 0 ? ` ${theme.fg("dim", `(${cacheWrite.toLocaleString()} written to cache)`)}` : "";
|
|
5010
|
-
info += ` ${theme.fg("dim", "Uncached:")} ${(input + cacheWrite).toLocaleString()}${written}\n`;
|
|
5011
|
-
}
|
|
5012
|
-
info += `${theme.fg("dim", "Output:")} ${stats.tokens.output.toLocaleString()}\n`;
|
|
5013
|
-
info += `${theme.fg("dim", "Total:")} ${stats.tokens.total.toLocaleString()}\n`;
|
|
5014
|
-
if (stats.cost > 0 || cacheWaste.missedTokens > 0) {
|
|
5015
|
-
info += `\n${theme.bold("Cost")}\n`;
|
|
5016
|
-
info += `${theme.fg("dim", "Total:")} $${stats.cost.toFixed(3)}`;
|
|
5017
|
-
if (perModel.length > 1) {
|
|
5018
|
-
for (const entry of perModel) {
|
|
5019
|
-
info += `\n ${theme.fg("dim", `${entry.key}:`)} $${entry.cost.toFixed(3)} ${theme.fg("dim", `(${formatTokens(entry.tokens)} tokens)`)}`;
|
|
5020
|
-
}
|
|
5021
|
-
}
|
|
5022
|
-
if (cacheWaste.missedTokens > 0) {
|
|
5023
|
-
const missLabel = cacheWaste.missCount === 1 ? "1 miss" : `${cacheWaste.missCount} misses`;
|
|
5024
|
-
const detail = `${cacheWaste.missedTokens.toLocaleString()} tokens, ${missLabel}`;
|
|
5025
|
-
info +=
|
|
5026
|
-
cacheWaste.missedCost >= 0.0001
|
|
5027
|
-
? `\n${theme.fg("dim", "Cache Re-billed:")} $${cacheWaste.missedCost.toFixed(3)} ${theme.fg("dim", `(${detail})`)}`
|
|
5028
|
-
: `\n${theme.fg("dim", "Cache Re-billed:")} ${detail}`;
|
|
5029
|
-
}
|
|
5030
|
-
}
|
|
4806
|
+
const info = formatSessionInfo(stats, sessionName);
|
|
5031
4807
|
this.chatContainer.addChild(new Spacer(1));
|
|
5032
4808
|
this.chatContainer.addChild(new Text(info, 1, 0));
|
|
5033
4809
|
this.ui.requestRender();
|