@selesai/code 0.13.26 → 0.13.27
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 +74 -0
- package/dist/cli/args.js +1 -0
- package/dist/cli/session-picker.d.ts +1 -1
- package/dist/config.js +1 -1
- package/dist/core/agent-session-auto-handoff.test.js +2 -1
- package/dist/core/agent-session-length-continuation.test.js +2 -1
- package/dist/core/agent-session.d.ts +58 -7
- package/dist/core/agent-session.js +334 -167
- package/dist/core/bug-report-upload.d.ts +11 -0
- package/dist/core/bug-report-upload.js +21 -0
- package/dist/core/bug-report.d.ts +175 -0
- package/dist/core/bug-report.js +291 -0
- package/dist/core/cache-stats.js +12 -1
- package/dist/core/cache-warmer.d.ts +101 -0
- package/dist/core/cache-warmer.js +341 -0
- package/dist/core/compaction/branch-summarization.js +2 -2
- package/dist/core/compaction/compaction.d.ts +6 -5
- package/dist/core/compaction/compaction.js +49 -42
- package/dist/core/crash-log.d.ts +21 -0
- package/dist/core/crash-log.js +70 -0
- package/dist/core/experimental.d.ts +0 -4
- package/dist/core/experimental.js +0 -4
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/jiti-loader.d.ts +1 -0
- package/dist/core/extensions/jiti-loader.js +3 -0
- package/dist/core/extensions/jiti-static-loader.d.ts +1 -0
- package/dist/core/extensions/jiti-static-loader.js +3 -0
- package/dist/core/extensions/loader.js +39 -49
- package/dist/core/extensions/runner.d.ts +10 -7
- package/dist/core/extensions/runner.js +85 -67
- package/dist/core/extensions/types.d.ts +66 -52
- package/dist/core/extensions/virtual-modules.d.ts +2 -0
- package/dist/core/extensions/virtual-modules.js +39 -0
- package/dist/core/extensions/wrapper.js +1 -20
- package/dist/core/index.d.ts +2 -1
- package/dist/core/keybindings.d.ts +1 -1
- package/dist/core/keybindings.js +1 -1
- package/dist/core/messages.js +1 -0
- package/dist/core/model-config.d.ts +101 -20
- package/dist/core/model-config.js +25 -18
- package/dist/core/model-resolver.js +2 -1
- package/dist/core/model-runtime.js +5 -3
- package/dist/core/provider-composer.d.ts +7 -2
- package/dist/core/provider-composer.js +10 -5
- package/dist/core/radius.d.ts +3 -0
- package/dist/core/radius.js +6 -0
- package/dist/core/sdk.js +60 -38
- package/dist/core/session-export.d.ts +6 -2
- package/dist/core/session-export.js +14 -13
- package/dist/core/session-format.test.d.ts +1 -0
- package/dist/core/session-format.test.js +96 -0
- package/dist/core/session-manager.d.ts +29 -6
- package/dist/core/session-manager.js +159 -96
- package/dist/core/settings-manager.d.ts +22 -5
- package/dist/core/settings-manager.js +56 -23
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/system-prompt.d.ts +49 -4
- package/dist/core/system-prompt.js +155 -102
- package/dist/core/system-prompt.test.js +61 -23
- package/dist/core/tools/bash.d.ts +2 -1
- package/dist/core/tools/bash.js +10 -4
- package/dist/core/tools/edit.js +1 -2
- package/dist/core/tools/read.js +1 -2
- package/dist/core/tools/renderers/bash.js +9 -1
- package/dist/core/tools/write.js +1 -2
- package/dist/core/usage-totals.d.ts +1 -1
- package/dist/core/usage-totals.js +5 -1
- package/dist/extensions/pi-web-agent/src/backends/factory.ts +14 -6
- package/dist/extensions/pi-web-agent/src/extension.ts +3 -1
- package/dist/extensions/pi-web-agent/src/orchestration/answer-synthesizer.ts +7 -3
- package/dist/extensions/pi-web-agent/src/orchestration/research-orchestrator.ts +3 -0
- package/dist/extensions/pi-web-agent/src/orchestration/research-types.ts +2 -0
- package/dist/extensions/pi-web-agent/src/presentation/explore-presentation.ts +4 -2
- package/dist/extensions/pi-web-agent/src/search/tokenin.ts +4 -1
- package/dist/extensions/pi-web-agent/src/tools/web-explore.ts +2 -1
- package/dist/extensions/pi-web-agent/src/types.ts +4 -0
- package/dist/index.d.ts +3 -2
- package/dist/main.js +13 -9
- package/dist/migrations.js +2 -2
- package/dist/modes/interactive/bug-report.d.ts +15 -0
- package/dist/modes/interactive/bug-report.js +205 -0
- package/dist/modes/interactive/chat-viewport.js +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +12 -5
- package/dist/modes/interactive/components/compaction-summary-message.js +12 -5
- package/dist/modes/interactive/components/custom-editor.d.ts +3 -3
- package/dist/modes/interactive/components/extension-editor.d.ts +4 -1
- package/dist/modes/interactive/components/extension-editor.js +7 -2
- package/dist/modes/interactive/components/extension-input.d.ts +2 -0
- package/dist/modes/interactive/components/extension-input.js +6 -0
- package/dist/modes/interactive/components/extension-selector.d.ts +1 -0
- package/dist/modes/interactive/components/extension-selector.js +4 -0
- package/dist/modes/interactive/components/footer.js +4 -1
- package/dist/modes/interactive/components/session-selector.d.ts +5 -5
- package/dist/modes/interactive/components/session-selector.js +74 -48
- package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
- package/dist/modes/interactive/components/settings-selector.js +11 -0
- package/dist/modes/interactive/components/skill-invocation-message.js +11 -4
- package/dist/modes/interactive/components/status-indicator.d.ts +2 -2
- package/dist/modes/interactive/components/status-indicator.js +7 -7
- package/dist/modes/interactive/components/tool-execution.js +18 -9
- package/dist/modes/interactive/components/tree-selector.js +2 -0
- package/dist/modes/interactive/interactive-mode.d.ts +15 -2
- package/dist/modes/interactive/interactive-mode.js +257 -81
- package/dist/modes/interactive/session-share.d.ts +2 -0
- package/dist/modes/interactive/session-share.js +8 -4
- package/dist/modes/interactive/tui-renderer.js +2 -2
- package/dist/modes/rpc/rpc-mode.js +2 -2
- package/dist/utils/clipboard-command.d.ts +6 -0
- package/dist/utils/clipboard-command.js +44 -0
- package/dist/utils/clipboard-image.js +55 -89
- package/dist/utils/clipboard.d.ts +1 -1
- package/dist/utils/clipboard.js +118 -108
- package/dist/utils/wsl.d.ts +2 -0
- package/dist/utils/wsl.js +14 -0
- package/dist/utils/zip.d.ts +6 -0
- package/dist/utils/zip.js +59 -0
- package/package.json +9 -9
- package/dist/utils/clipboard-native.d.ts +0 -10
- package/dist/utils/clipboard-native.js +0 -19
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import * as fs from "node:fs";
|
|
6
6
|
import * as os from "node:os";
|
|
7
7
|
import * as path from "node:path";
|
|
8
|
+
import { isRetryableAssistantError, } from "@earendil-works/pi-ai/compat";
|
|
8
9
|
import * as TuiLayouts from "@earendil-works/pi-tui";
|
|
9
10
|
import { CombinedAutocompleteProvider, Container, fuzzyFilter, Markdown, matchesKey, Spacer, setCapabilityOverrides, setKeybindings, Text, TruncatedText, TuiAltScreen, TuiMainScreen, visibleWidth, } from "@earendil-works/pi-tui";
|
|
10
11
|
import chalk from "chalk";
|
|
@@ -13,6 +14,9 @@ import { APP_NAME, APP_TITLE, CONFIG_DIR_NAME, getAgentDir, getAuthPath, getBund
|
|
|
13
14
|
import { parseSkillBlocks } from "../../core/agent-session.js";
|
|
14
15
|
import { SessionImportFileNotFoundError } from "../../core/agent-session-runtime.js";
|
|
15
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";
|
|
19
|
+
import { DEFAULT_THINKING_LEVEL, THINKING_LEVEL_OPTIONS } from "../../core/defaults.js";
|
|
16
20
|
import { FooterDataProvider } from "../../core/footer-data-provider.js";
|
|
17
21
|
import { configureHttpDispatcher, formatHttpIdleTimeoutMs } from "../../core/http-dispatcher.js";
|
|
18
22
|
import { KeybindingsManager } from "../../core/keybindings.js";
|
|
@@ -20,14 +24,13 @@ import { createCompactionSummaryMessage } from "../../core/messages.js";
|
|
|
20
24
|
import { defaultModelPerProvider, findExactModelReferenceMatch, resolveModelScope, resolveModelScopeWithDiagnostics, } from "../../core/model-resolver.js";
|
|
21
25
|
import { DefaultPackageManager } from "../../core/package-manager.js";
|
|
22
26
|
import { formatMissingSessionCwdPrompt, MissingSessionCwdError } from "../../core/session-cwd.js";
|
|
23
|
-
import { SessionManager, sessionEntryToContextMessages } from "../../core/session-manager.js";
|
|
27
|
+
import { SessionManager, sessionEntryToContextMessages, } from "../../core/session-manager.js";
|
|
24
28
|
import { buildGitCommandPrompt, GIT_COMMAND_MODES } from "../../core/git-command.js";
|
|
25
29
|
import { BUILTIN_SLASH_COMMANDS } from "../../core/slash-commands.js";
|
|
26
30
|
import { isInstallTelemetryEnabled } from "../../core/telemetry.js";
|
|
27
31
|
import { withBuiltInRenderers } from "../../core/tools/renderers/index.js";
|
|
28
32
|
import { hasTrustRequiringProjectResources, ProjectTrustStore } from "../../core/trust-manager.js";
|
|
29
33
|
import { formatCost, getUsageCostBreakdown } from "../../core/usage-totals.js";
|
|
30
|
-
import { DEFAULT_THINKING_LEVEL } from "../../core/defaults.js";
|
|
31
34
|
import { getChangelogPath, getNewEntries, normalizeChangelogLinks, parseChangelog } from "../../utils/changelog.js";
|
|
32
35
|
import { copyToClipboard, readClipboardText } from "../../utils/clipboard.js";
|
|
33
36
|
import { extensionForImageMimeType, readClipboardImage } from "../../utils/clipboard-image.js";
|
|
@@ -38,6 +41,7 @@ import { getPiUserAgent } from "../../utils/pi-user-agent.js";
|
|
|
38
41
|
import { killTrackedDetachedChildren } from "../../utils/shell.js";
|
|
39
42
|
import { ensureTool } from "../../utils/tools-manager.js";
|
|
40
43
|
import { checkForNewPiVersion } from "../../utils/version-check.js";
|
|
44
|
+
import { reportBug } from "./bug-report.js";
|
|
41
45
|
import { createChatViewport } from "./chat-viewport.js";
|
|
42
46
|
import { ArminComponent } from "./components/armin.js";
|
|
43
47
|
import { AssistantMessageComponent } from "./components/assistant-message.js";
|
|
@@ -104,6 +108,9 @@ function isCustomSessionEntry(item) {
|
|
|
104
108
|
function isCompactionCostNotice(item) {
|
|
105
109
|
return "type" in item && item.type === "compaction_cost";
|
|
106
110
|
}
|
|
111
|
+
function isUsageSessionEntry(item) {
|
|
112
|
+
return "type" in item && item.type === "usage";
|
|
113
|
+
}
|
|
107
114
|
const DEAD_TERMINAL_ERROR_CODES = new Set(["EIO", "EPIPE", "ENOTCONN"]);
|
|
108
115
|
function isDeadTerminalError(error) {
|
|
109
116
|
if (!error || typeof error !== "object" || !("code" in error)) {
|
|
@@ -166,6 +173,12 @@ export function formatResumeCommand(sessionManager) {
|
|
|
166
173
|
function hasDefaultModelProvider(providerId) {
|
|
167
174
|
return providerId in defaultModelPerProvider;
|
|
168
175
|
}
|
|
176
|
+
/** Fork-specific post-login guidance for the bundled llama.cpp runtime. */
|
|
177
|
+
function llamaCppPostLoginGuidance(actionLabel, loadedModelCount) {
|
|
178
|
+
return loadedModelCount === 0
|
|
179
|
+
? `${actionLabel}. No llama.cpp models are loaded. Use /llama to load a model, then /model to select it.`
|
|
180
|
+
: `${actionLabel}. Use /model to select a loaded llama.cpp model, or /llama to manage models.`;
|
|
181
|
+
}
|
|
169
182
|
const AUTH_TYPE_ORDER = { oauth: 0, api_key: 1 };
|
|
170
183
|
function createFuzzyAutocompleteItems(items, prefix, getSearchText, toAutocompleteItem) {
|
|
171
184
|
const filtered = fuzzyFilter(items, prefix, getSearchText);
|
|
@@ -276,6 +289,8 @@ export class InteractiveMode {
|
|
|
276
289
|
compactionQueuedMessages = [];
|
|
277
290
|
// Shutdown state
|
|
278
291
|
shutdownRequested = false;
|
|
292
|
+
/** The `/bug` hint is shown at most once per session so error output stays readable. */
|
|
293
|
+
bugReportHintShown = false;
|
|
279
294
|
// Extension UI state
|
|
280
295
|
extensionSelector = undefined;
|
|
281
296
|
extensionInput = undefined;
|
|
@@ -334,6 +349,7 @@ export class InteractiveMode {
|
|
|
334
349
|
tuiMode,
|
|
335
350
|
showHardwareCursor: this.settingsManager.getShowHardwareCursor(),
|
|
336
351
|
logDirectory: getAgentDir(),
|
|
352
|
+
terminal: options.terminal,
|
|
337
353
|
onRightClickPaste: this.onRightClickPaste,
|
|
338
354
|
fullscreenCopyOnSelect: this.settingsManager.getFullscreenCopyOnSelect(),
|
|
339
355
|
});
|
|
@@ -775,6 +791,11 @@ export class InteractiveMode {
|
|
|
775
791
|
if (modelFallbackMessage) {
|
|
776
792
|
this.showWarning(modelFallbackMessage);
|
|
777
793
|
}
|
|
794
|
+
const crash = takeUnnotifiedCrash();
|
|
795
|
+
if (crash) {
|
|
796
|
+
const when = new Date(crash.timestamp).toLocaleString();
|
|
797
|
+
this.showWarning(`${APP_NAME} crashed on ${when} (${crash.message}). Run /bug to report it; the crash details are attached automatically.`);
|
|
798
|
+
}
|
|
778
799
|
void this.maybeWarnAboutAnthropicSubscriptionAuth();
|
|
779
800
|
// Process initial messages
|
|
780
801
|
if (initialMessage) {
|
|
@@ -1431,10 +1452,45 @@ export class InteractiveMode {
|
|
|
1431
1452
|
async handleFatalRuntimeError(prefix, error) {
|
|
1432
1453
|
const message = error instanceof Error ? error.message : String(error);
|
|
1433
1454
|
this.showError(`${prefix}: ${message}`);
|
|
1455
|
+
if (this.recordCrash("fatal_error", error)) {
|
|
1456
|
+
this.chatContainer.addChild(new Text(theme.fg("muted", this.crashReportInstructions()), this.outputPad, 0));
|
|
1457
|
+
}
|
|
1434
1458
|
stopThemeWatcher();
|
|
1435
1459
|
this.stop("transcript");
|
|
1436
1460
|
process.exit(1);
|
|
1437
1461
|
}
|
|
1462
|
+
/** Persist a crash so the next start can point the user at `/bug`. Returns false when nothing was written. */
|
|
1463
|
+
recordCrash(kind, error) {
|
|
1464
|
+
try {
|
|
1465
|
+
return (recordCrash({
|
|
1466
|
+
kind,
|
|
1467
|
+
error,
|
|
1468
|
+
sessionFile: this.session.sessionFile,
|
|
1469
|
+
cwd: this.session.sessionManager.getCwd(),
|
|
1470
|
+
}) !== undefined);
|
|
1471
|
+
}
|
|
1472
|
+
catch {
|
|
1473
|
+
return false;
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
crashReportInstructions() {
|
|
1477
|
+
const resume = this.session.sessionFile ? `run \`${APP_NAME} -r\` to resume the session, then` : "start pi and";
|
|
1478
|
+
return `To report this crash: ${resume} run /bug. The crash details are attached automatically.`;
|
|
1479
|
+
}
|
|
1480
|
+
suggestBugReport() {
|
|
1481
|
+
if (this.bugReportHintShown)
|
|
1482
|
+
return;
|
|
1483
|
+
this.bugReportHintShown = true;
|
|
1484
|
+
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));
|
|
1485
|
+
this.ui.requestRender();
|
|
1486
|
+
}
|
|
1487
|
+
maybeSuggestBugReport(message) {
|
|
1488
|
+
if (message.stopReason !== "error" || isRetryableAssistantError(message))
|
|
1489
|
+
return;
|
|
1490
|
+
if (/\b(?:abort(?:ed)?|cancel(?:l?ed)?)\b/i.test(message.errorMessage ?? ""))
|
|
1491
|
+
return;
|
|
1492
|
+
this.suggestBugReport();
|
|
1493
|
+
}
|
|
1438
1494
|
renderCurrentSessionState() {
|
|
1439
1495
|
this.loadedResourcesContainer.clear();
|
|
1440
1496
|
this.chatContainer.clear();
|
|
@@ -1533,7 +1589,7 @@ export class InteractiveMode {
|
|
|
1533
1589
|
this.activeWorkingIndicatorEmbedded = false;
|
|
1534
1590
|
this.statusContainer.clear();
|
|
1535
1591
|
this.setEditorWorkingStatusIndicator(undefined);
|
|
1536
|
-
if (
|
|
1592
|
+
if (this.setEditorWorkingStatusIndicator(indicator)) {
|
|
1537
1593
|
this.activeWorkingIndicatorEmbedded = true;
|
|
1538
1594
|
return;
|
|
1539
1595
|
}
|
|
@@ -1544,7 +1600,7 @@ export class InteractiveMode {
|
|
|
1544
1600
|
return;
|
|
1545
1601
|
}
|
|
1546
1602
|
const clearedIndicator = this.activeStatusIndicator;
|
|
1547
|
-
const clearedIndicatorWasEmbedded =
|
|
1603
|
+
const clearedIndicatorWasEmbedded = this.activeWorkingIndicatorEmbedded;
|
|
1548
1604
|
clearedIndicator?.dispose();
|
|
1549
1605
|
this.activeStatusIndicator = undefined;
|
|
1550
1606
|
this.activeWorkingIndicatorEmbedded = false;
|
|
@@ -2026,7 +2082,7 @@ export class InteractiveMode {
|
|
|
2026
2082
|
this.editor = this.defaultEditor;
|
|
2027
2083
|
}
|
|
2028
2084
|
this.editorContainer.addChild(this.editor);
|
|
2029
|
-
if (this.activeStatusIndicator
|
|
2085
|
+
if (this.activeStatusIndicator) {
|
|
2030
2086
|
this.statusContainer.clear();
|
|
2031
2087
|
this.activeWorkingIndicatorEmbedded = this.setEditorWorkingStatusIndicator(this.activeStatusIndicator);
|
|
2032
2088
|
if (!this.activeWorkingIndicatorEmbedded) {
|
|
@@ -2338,6 +2394,12 @@ export class InteractiveMode {
|
|
|
2338
2394
|
this.editor.setText("");
|
|
2339
2395
|
return;
|
|
2340
2396
|
}
|
|
2397
|
+
if (text === "/bug" || text.startsWith("/bug ")) {
|
|
2398
|
+
const hint = text.slice("/bug".length).trim();
|
|
2399
|
+
this.editor.setText("");
|
|
2400
|
+
await this.handleBugCommand(hint ? hint : undefined);
|
|
2401
|
+
return;
|
|
2402
|
+
}
|
|
2341
2403
|
if (text === "/copy") {
|
|
2342
2404
|
await this.handleCopyCommand();
|
|
2343
2405
|
this.editor.setText("");
|
|
@@ -2539,6 +2601,10 @@ export class InteractiveMode {
|
|
|
2539
2601
|
this.addCustomEntryToChat(event.entry);
|
|
2540
2602
|
this.ui.requestRender();
|
|
2541
2603
|
}
|
|
2604
|
+
else if (event.entry.type === "usage" && event.entry.kind === "cache_warm") {
|
|
2605
|
+
this.addCacheWarmingUsage(event.entry);
|
|
2606
|
+
this.ui.requestRender();
|
|
2607
|
+
}
|
|
2542
2608
|
break;
|
|
2543
2609
|
case "session_info_changed":
|
|
2544
2610
|
this.updateTerminalTitle();
|
|
@@ -2619,13 +2685,14 @@ export class InteractiveMode {
|
|
|
2619
2685
|
});
|
|
2620
2686
|
}
|
|
2621
2687
|
this.pendingTools.clear();
|
|
2688
|
+
this.maybeSuggestBugReport(this.streamingMessage);
|
|
2622
2689
|
}
|
|
2623
2690
|
else {
|
|
2624
2691
|
// Args are now complete - trigger diff computation for edit tools
|
|
2625
2692
|
for (const [, component] of this.pendingTools.entries()) {
|
|
2626
2693
|
component.setArgsComplete();
|
|
2627
2694
|
}
|
|
2628
|
-
this.
|
|
2695
|
+
this.maybeShowThinkingDropNotice(this.streamingMessage);
|
|
2629
2696
|
this.maybeShowCacheMissNotice(this.streamingMessage);
|
|
2630
2697
|
}
|
|
2631
2698
|
this.streamingComponent = undefined;
|
|
@@ -2892,6 +2959,8 @@ export class InteractiveMode {
|
|
|
2892
2959
|
this.chatContainer.addChild(component);
|
|
2893
2960
|
break;
|
|
2894
2961
|
}
|
|
2962
|
+
case "system":
|
|
2963
|
+
break;
|
|
2895
2964
|
case "user": {
|
|
2896
2965
|
const textContent = this.getUserMessageText(message);
|
|
2897
2966
|
if (textContent) {
|
|
@@ -2930,6 +2999,10 @@ export class InteractiveMode {
|
|
|
2930
2999
|
// Tool results are rendered inline with tool calls, handled separately
|
|
2931
3000
|
break;
|
|
2932
3001
|
}
|
|
3002
|
+
case "system": {
|
|
3003
|
+
// System messages carry prompt/tool state, not transcript content.
|
|
3004
|
+
break;
|
|
3005
|
+
}
|
|
2933
3006
|
default: {
|
|
2934
3007
|
const _exhaustive = message;
|
|
2935
3008
|
}
|
|
@@ -2938,8 +3011,8 @@ export class InteractiveMode {
|
|
|
2938
3011
|
renderSessionItems(items, options = {}) {
|
|
2939
3012
|
this.pendingTools.clear();
|
|
2940
3013
|
const renderedPendingTools = new Map();
|
|
2941
|
-
// Cache
|
|
2942
|
-
//
|
|
3014
|
+
// Cache misses are not persisted, unlike successful cache-warming usage.
|
|
3015
|
+
// Re-derive them and inject them after the assistant messages that paid for them.
|
|
2943
3016
|
const cacheMisses = this.settingsManager.getShowCacheMissNotices()
|
|
2944
3017
|
? collectCacheMisses(this.sessionManager.getEntries(), this.session.modelRuntime)
|
|
2945
3018
|
: new Map();
|
|
@@ -2952,6 +3025,10 @@ export class InteractiveMode {
|
|
|
2952
3025
|
this.addCustomEntryToChat(item);
|
|
2953
3026
|
continue;
|
|
2954
3027
|
}
|
|
3028
|
+
if (isUsageSessionEntry(item)) {
|
|
3029
|
+
this.addCacheWarmingUsage(item);
|
|
3030
|
+
continue;
|
|
3031
|
+
}
|
|
2955
3032
|
if (isCompactionCostNotice(item)) {
|
|
2956
3033
|
this.addCompactionCostNotice(item);
|
|
2957
3034
|
continue;
|
|
@@ -2989,7 +3066,6 @@ export class InteractiveMode {
|
|
|
2989
3066
|
}
|
|
2990
3067
|
}
|
|
2991
3068
|
if (message.stopReason !== "aborted" && message.stopReason !== "error") {
|
|
2992
|
-
this.maybeShowAssistantDiagnostics(message);
|
|
2993
3069
|
const miss = cacheMisses.get(message);
|
|
2994
3070
|
if (miss)
|
|
2995
3071
|
this.addCacheMissNotice(miss);
|
|
@@ -3021,13 +3097,19 @@ export class InteractiveMode {
|
|
|
3021
3097
|
*/
|
|
3022
3098
|
renderSessionEntries(entries, options = {}) {
|
|
3023
3099
|
const items = entries.flatMap((entry) => {
|
|
3024
|
-
if (entry.type === "custom") {
|
|
3100
|
+
if (entry.type === "custom" || (entry.type === "usage" && entry.kind === "cache_warm")) {
|
|
3025
3101
|
return [entry];
|
|
3026
3102
|
}
|
|
3027
3103
|
return sessionEntryToContextMessages(entry);
|
|
3028
3104
|
});
|
|
3029
3105
|
this.renderSessionItems(items, options);
|
|
3030
3106
|
}
|
|
3107
|
+
addCacheWarmingUsage(entry) {
|
|
3108
|
+
if (!this.settingsManager.getShowCacheMissNotices())
|
|
3109
|
+
return;
|
|
3110
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
3111
|
+
this.chatContainer.addChild(new Text(theme.fg("dim", formatCacheWarmingUsage(entry)), 1, 0));
|
|
3112
|
+
}
|
|
3031
3113
|
/**
|
|
3032
3114
|
* Render billing usage for a compaction or branch summary. The notice is derived
|
|
3033
3115
|
* from persisted summary usage and is not stored as a separate session entry.
|
|
@@ -3042,31 +3124,42 @@ export class InteractiveMode {
|
|
|
3042
3124
|
this.chatContainer.addChild(new Spacer(1));
|
|
3043
3125
|
this.chatContainer.addChild(new Text(theme.fg("warning", `${label}: ${formatTokens(tokens)} tokens billed${cost}`), 1, 0));
|
|
3044
3126
|
}
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
return;
|
|
3127
|
+
static countDroppedThinkingBlocks(message) {
|
|
3128
|
+
let count = 0;
|
|
3048
3129
|
for (const diagnostic of message.diagnostics ?? []) {
|
|
3049
3130
|
if (diagnostic.type !== "anthropic_input_transformations")
|
|
3050
3131
|
continue;
|
|
3051
3132
|
const transformations = diagnostic.details?.transformations;
|
|
3052
3133
|
if (!Array.isArray(transformations))
|
|
3053
3134
|
continue;
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
const details = transformation;
|
|
3058
|
-
if (details.type !== "thinking_dropped")
|
|
3059
|
-
return [];
|
|
3060
|
-
const reason = typeof details.reason === "string" ? details.reason : "unknown reason";
|
|
3061
|
-
const location = typeof details.path === "string" ? ` at ${details.path}` : "";
|
|
3062
|
-
return [`${reason}${location}`];
|
|
3063
|
-
});
|
|
3064
|
-
if (dropped.length === 0)
|
|
3065
|
-
continue;
|
|
3066
|
-
const noun = dropped.length === 1 ? "thinking block" : `${dropped.length} thinking blocks`;
|
|
3067
|
-
this.chatContainer.addChild(new Spacer(1));
|
|
3068
|
-
this.chatContainer.addChild(new Text(theme.fg("warning", `Anthropic dropped ${noun}: ${dropped.join("; ")}`), 1, 0));
|
|
3135
|
+
count += transformations.filter((transformation) => typeof transformation === "object" &&
|
|
3136
|
+
transformation !== null &&
|
|
3137
|
+
transformation.type === "thinking_dropped").length;
|
|
3069
3138
|
}
|
|
3139
|
+
return count;
|
|
3140
|
+
}
|
|
3141
|
+
maybeShowThinkingDropNotice(message) {
|
|
3142
|
+
if (!this.settingsManager.getShowCacheMissNotices())
|
|
3143
|
+
return;
|
|
3144
|
+
const droppedCount = InteractiveMode.countDroppedThinkingBlocks(message);
|
|
3145
|
+
if (droppedCount === 0)
|
|
3146
|
+
return;
|
|
3147
|
+
let previousDroppedCount = 0;
|
|
3148
|
+
// message_end reaches the UI before the current message is persisted,
|
|
3149
|
+
// so the branch's last assistant message is the previous response.
|
|
3150
|
+
const branch = this.sessionManager.getBranch();
|
|
3151
|
+
for (let i = branch.length - 1; i >= 0; i--) {
|
|
3152
|
+
const entry = branch[i];
|
|
3153
|
+
if (entry.type === "message" && entry.message.role === "assistant") {
|
|
3154
|
+
previousDroppedCount = InteractiveMode.countDroppedThinkingBlocks(entry.message);
|
|
3155
|
+
break;
|
|
3156
|
+
}
|
|
3157
|
+
}
|
|
3158
|
+
if (droppedCount <= previousDroppedCount)
|
|
3159
|
+
return;
|
|
3160
|
+
const noun = droppedCount === 1 ? "thinking block" : "thinking blocks";
|
|
3161
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
3162
|
+
this.chatContainer.addChild(new Text(theme.fg("warning", `Anthropic dropped ${droppedCount} ${noun} (details in session)`), 1, 0));
|
|
3070
3163
|
}
|
|
3071
3164
|
/**
|
|
3072
3165
|
* Show a transcript notice when a completed assistant message paid for a
|
|
@@ -3238,6 +3331,9 @@ export class InteractiveMode {
|
|
|
3238
3331
|
catch { }
|
|
3239
3332
|
console.error(`${APP_NAME} exiting due to uncaughtException:`);
|
|
3240
3333
|
console.error(error);
|
|
3334
|
+
if (this.recordCrash("uncaught_exception", error)) {
|
|
3335
|
+
console.error(`\n${this.crashReportInstructions()}`);
|
|
3336
|
+
}
|
|
3241
3337
|
process.exit(1);
|
|
3242
3338
|
}
|
|
3243
3339
|
/**
|
|
@@ -3371,9 +3467,7 @@ export class InteractiveMode {
|
|
|
3371
3467
|
const level = this.session.thinkingLevel || "off";
|
|
3372
3468
|
this.editor.borderColor = theme.getThinkingBorderColor(level);
|
|
3373
3469
|
}
|
|
3374
|
-
|
|
3375
|
-
this.activeStatusIndicator.invalidate();
|
|
3376
|
-
}
|
|
3470
|
+
this.activeStatusIndicator?.invalidate();
|
|
3377
3471
|
this.ui.requestRender();
|
|
3378
3472
|
}
|
|
3379
3473
|
cycleThinkingLevel() {
|
|
@@ -3558,7 +3652,7 @@ export class InteractiveMode {
|
|
|
3558
3652
|
if (allQueued.length === 0) {
|
|
3559
3653
|
this.updatePendingMessagesDisplay();
|
|
3560
3654
|
if (options?.abort) {
|
|
3561
|
-
this.
|
|
3655
|
+
void this.session.abort();
|
|
3562
3656
|
}
|
|
3563
3657
|
return 0;
|
|
3564
3658
|
}
|
|
@@ -3568,7 +3662,7 @@ export class InteractiveMode {
|
|
|
3568
3662
|
this.editor.setText(combinedText);
|
|
3569
3663
|
this.updatePendingMessagesDisplay();
|
|
3570
3664
|
if (options?.abort) {
|
|
3571
|
-
this.
|
|
3665
|
+
void this.session.abort();
|
|
3572
3666
|
}
|
|
3573
3667
|
return allQueued.length;
|
|
3574
3668
|
}
|
|
@@ -3718,8 +3812,9 @@ export class InteractiveMode {
|
|
|
3718
3812
|
followUpMode: this.session.followUpMode,
|
|
3719
3813
|
transport: this.settingsManager.getTransport(),
|
|
3720
3814
|
httpIdleTimeoutMs: this.settingsManager.getHttpIdleTimeoutMs(),
|
|
3721
|
-
|
|
3722
|
-
|
|
3815
|
+
cacheWarmingMode: this.settingsManager.getCacheWarmingMode(),
|
|
3816
|
+
thinkingLevel: this.settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL,
|
|
3817
|
+
availableThinkingLevels: [...THINKING_LEVEL_OPTIONS],
|
|
3723
3818
|
modelThinkingLevels: this.settingsManager.getAllModelThinkingLevels(),
|
|
3724
3819
|
currentTheme: this.themeController.getThemeSelection() || "dark",
|
|
3725
3820
|
terminalTheme: this.themeController.getTerminalTheme(),
|
|
@@ -3800,6 +3895,10 @@ export class InteractiveMode {
|
|
|
3800
3895
|
configureHttpDispatcher(timeoutMs);
|
|
3801
3896
|
this.showStatus(`HTTP idle timeout: ${formatHttpIdleTimeoutMs(timeoutMs)}`);
|
|
3802
3897
|
},
|
|
3898
|
+
onCacheWarmingModeChange: (mode) => {
|
|
3899
|
+
this.session.setCacheWarmingMode(mode);
|
|
3900
|
+
this.showStatus(`Cache warming: ${mode}`);
|
|
3901
|
+
},
|
|
3803
3902
|
onModelThinkingLevelChange: (provider, modelId, level) => {
|
|
3804
3903
|
this.settingsManager.setModelThinkingLevel(provider, modelId, level);
|
|
3805
3904
|
const current = this.session.model;
|
|
@@ -4332,6 +4431,11 @@ export class InteractiveMode {
|
|
|
4332
4431
|
this.restoreQueuedMessagesToEditor();
|
|
4333
4432
|
await this.session.abort();
|
|
4334
4433
|
}
|
|
4434
|
+
// Recheck after the dialogs and streaming abort, before replacing another operation's UI.
|
|
4435
|
+
if (this.session.isCompacting) {
|
|
4436
|
+
this.showError("Wait for the current compaction or tree navigation to finish before navigating the session tree.");
|
|
4437
|
+
return;
|
|
4438
|
+
}
|
|
4335
4439
|
// Set up escape handler and status indicator if summarizing
|
|
4336
4440
|
let showingSummaryIndicator = false;
|
|
4337
4441
|
const originalOnEscape = this.defaultEditor.onEscape;
|
|
@@ -4402,9 +4506,9 @@ export class InteractiveMode {
|
|
|
4402
4506
|
}
|
|
4403
4507
|
showSessionSelector() {
|
|
4404
4508
|
this.showSelector((done) => {
|
|
4405
|
-
const selector = new SessionSelectorComponent((onProgress) => SessionManager.list(this.sessionManager.getCwd(), this.sessionManager.getSessionDir(), onProgress), (onProgress) => this.sessionManager.usesDefaultSessionDir()
|
|
4406
|
-
? SessionManager.listAll(onProgress)
|
|
4407
|
-
: SessionManager.listAll(this.sessionManager.getSessionDir(), onProgress), async (sessionPath) => {
|
|
4509
|
+
const selector = new SessionSelectorComponent((onProgress, signal) => SessionManager.list(this.sessionManager.getCwd(), this.sessionManager.getSessionDir(), onProgress, signal), (onProgress, signal) => this.sessionManager.usesDefaultSessionDir()
|
|
4510
|
+
? SessionManager.listAll(onProgress, signal)
|
|
4511
|
+
: SessionManager.listAll(this.sessionManager.getSessionDir(), onProgress, signal), async (sessionPath) => {
|
|
4408
4512
|
done();
|
|
4409
4513
|
await this.handleResumeSession(sessionPath);
|
|
4410
4514
|
}, () => {
|
|
@@ -4655,54 +4759,99 @@ export class InteractiveMode {
|
|
|
4655
4759
|
});
|
|
4656
4760
|
}
|
|
4657
4761
|
async completeProviderAuthentication(providerId, providerName, authType, previousModel) {
|
|
4658
|
-
|
|
4762
|
+
const session = this.session;
|
|
4659
4763
|
const actionLabel = authType === "oauth" ? `Logged in to ${providerName}` : `Saved API key for ${providerName}`;
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4764
|
+
// Dynamic catalogs may be empty until the first authenticated network refresh.
|
|
4765
|
+
const deferSelection = isUnknownModel(previousModel) &&
|
|
4766
|
+
hasDefaultModelProvider(providerId) &&
|
|
4767
|
+
!session.modelRuntime
|
|
4768
|
+
.getAvailableSnapshot()
|
|
4769
|
+
.some((model) => model.provider === providerId && model.id === defaultModelPerProvider[providerId]);
|
|
4770
|
+
const finishAuthentication = async () => {
|
|
4771
|
+
let selectedModel;
|
|
4772
|
+
let selectionError;
|
|
4773
|
+
if (isUnknownModel(previousModel)) {
|
|
4774
|
+
const availableModels = await this.session.modelRuntime.getAvailable();
|
|
4775
|
+
const providerModels = availableModels.filter((model) => model.provider === providerId);
|
|
4776
|
+
// Matches LLAMA_PROVIDER_ID from core/llama/provider.ts; kept inline to avoid
|
|
4777
|
+
// coupling interactive mode to the built-in extension.
|
|
4778
|
+
if (providerId === "llama.cpp") {
|
|
4779
|
+
selectionError = llamaCppPostLoginGuidance(actionLabel, providerModels.length);
|
|
4780
|
+
}
|
|
4781
|
+
else if (!hasDefaultModelProvider(providerId)) {
|
|
4782
|
+
selectionError = `${actionLabel}, but no default model is configured for provider "${providerId}". Use /model to select a model.`;
|
|
4783
|
+
}
|
|
4784
|
+
else if (providerModels.length === 0) {
|
|
4785
|
+
selectionError = `${actionLabel}, but no models are available for that provider. Use /model to select a model.`;
|
|
4786
|
+
}
|
|
4787
|
+
else {
|
|
4788
|
+
const defaultModelId = defaultModelPerProvider[providerId];
|
|
4789
|
+
// Radius catalogs vary by account; prefer balanced, then use catalog order.
|
|
4790
|
+
selectedModel =
|
|
4791
|
+
providerModels.find((model) => model.id === defaultModelId) ??
|
|
4792
|
+
(providerId === "radius" ? providerModels[0] : undefined);
|
|
4793
|
+
if (!selectedModel) {
|
|
4794
|
+
selectionError = `${actionLabel}, but its default model "${defaultModelId}" is not available. Use /model to select a model.`;
|
|
4795
|
+
}
|
|
4796
|
+
else {
|
|
4797
|
+
try {
|
|
4798
|
+
await this.session.setModel(selectedModel, { persist: true });
|
|
4799
|
+
}
|
|
4800
|
+
catch (error) {
|
|
4801
|
+
selectedModel = undefined;
|
|
4802
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
4803
|
+
selectionError = `${actionLabel}, but selecting its default model failed: ${errorMessage}. Use /model to select a model.`;
|
|
4804
|
+
}
|
|
4805
|
+
}
|
|
4806
|
+
}
|
|
4667
4807
|
}
|
|
4668
|
-
|
|
4669
|
-
|
|
4808
|
+
await this.updateAvailableProviderCount();
|
|
4809
|
+
this.footer.invalidate();
|
|
4810
|
+
this.updateEditorBorderColor();
|
|
4811
|
+
if (selectedModel) {
|
|
4812
|
+
this.showStatus(`${actionLabel}. Selected ${selectedModel.id}. Credentials saved to ${getAuthPath()}`);
|
|
4813
|
+
void this.maybeWarnAboutAnthropicSubscriptionAuth(selectedModel);
|
|
4814
|
+
this.checkDaxnutsEasterEgg(selectedModel);
|
|
4670
4815
|
}
|
|
4671
4816
|
else {
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
selectionError = `${actionLabel}, but its default model "${defaultModelId}" is not available. Use /model to select a model.`;
|
|
4817
|
+
this.showStatus(`${actionLabel}. Credentials saved to ${getAuthPath()}`);
|
|
4818
|
+
if (selectionError) {
|
|
4819
|
+
this.showError(selectionError);
|
|
4676
4820
|
}
|
|
4677
4821
|
else {
|
|
4678
|
-
|
|
4679
|
-
await this.session.setModel(selectedModel);
|
|
4680
|
-
}
|
|
4681
|
-
catch (error) {
|
|
4682
|
-
selectedModel = undefined;
|
|
4683
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
4684
|
-
selectionError = `${actionLabel}, but selecting its default model failed: ${errorMessage}. Use /model to select a model.`;
|
|
4685
|
-
}
|
|
4822
|
+
void this.maybeWarnAboutAnthropicSubscriptionAuth();
|
|
4686
4823
|
}
|
|
4687
4824
|
}
|
|
4688
|
-
}
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
this.updateEditorBorderColor();
|
|
4692
|
-
if (selectedModel) {
|
|
4693
|
-
this.showStatus(`${actionLabel}. Selected ${selectedModel.id}. Credentials saved to ${getAuthPath()}`);
|
|
4694
|
-
void this.maybeWarnAboutAnthropicSubscriptionAuth(selectedModel);
|
|
4695
|
-
this.checkDaxnutsEasterEgg(selectedModel);
|
|
4825
|
+
};
|
|
4826
|
+
if (deferSelection) {
|
|
4827
|
+
this.showStatus(`${actionLabel}. Credentials saved to ${getAuthPath()}. Refreshing model catalog…`);
|
|
4696
4828
|
}
|
|
4697
4829
|
else {
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4830
|
+
await finishAuthentication();
|
|
4831
|
+
}
|
|
4832
|
+
const controller = new AbortController();
|
|
4833
|
+
const timeout = setTimeout(() => controller.abort(), 15_000);
|
|
4834
|
+
void session.modelRuntime
|
|
4835
|
+
.refresh({ providers: [providerId], signal: controller.signal })
|
|
4836
|
+
.then(async (result) => {
|
|
4837
|
+
if (result.aborted) {
|
|
4838
|
+
this.showWarning(`${actionLabel}, but its model catalog refresh timed out; using cached models.`);
|
|
4701
4839
|
}
|
|
4702
|
-
else {
|
|
4703
|
-
|
|
4840
|
+
else if (result.errors.size > 0) {
|
|
4841
|
+
this.showWarning(`${actionLabel}, but its model catalog could not be refreshed; using cached models.`);
|
|
4704
4842
|
}
|
|
4705
|
-
|
|
4843
|
+
// Do not replace a model or session selected while the refresh was running.
|
|
4844
|
+
if (deferSelection && this.session === session && session.model === previousModel) {
|
|
4845
|
+
await finishAuthentication();
|
|
4846
|
+
}
|
|
4847
|
+
this.updateAvailableProviderCount();
|
|
4848
|
+
this.footer.invalidate();
|
|
4849
|
+
this.ui.requestRender();
|
|
4850
|
+
})
|
|
4851
|
+
.catch((error) => {
|
|
4852
|
+
this.showWarning(`${actionLabel}, but its model catalog could not be refreshed: ${error instanceof Error ? error.message : String(error)}`);
|
|
4853
|
+
})
|
|
4854
|
+
.finally(() => clearTimeout(timeout));
|
|
4706
4855
|
}
|
|
4707
4856
|
showAmbientAuthDialog(providerOption) {
|
|
4708
4857
|
const restoreEditor = () => {
|
|
@@ -5150,6 +5299,17 @@ export class InteractiveMode {
|
|
|
5150
5299
|
}
|
|
5151
5300
|
}
|
|
5152
5301
|
}
|
|
5302
|
+
async handleBugCommand(hint) {
|
|
5303
|
+
await reportBug({
|
|
5304
|
+
session: this.session,
|
|
5305
|
+
ui: this.ui,
|
|
5306
|
+
editorContainer: this.editorContainer,
|
|
5307
|
+
editor: this.editor,
|
|
5308
|
+
keybindings: this.keybindings,
|
|
5309
|
+
showStatus: (message) => this.showStatus(message),
|
|
5310
|
+
showError: (message) => this.showError(message),
|
|
5311
|
+
}, hint);
|
|
5312
|
+
}
|
|
5153
5313
|
async handleCopyCommand(options = {}) {
|
|
5154
5314
|
if (options.preferSelection &&
|
|
5155
5315
|
this.ui instanceof TuiAltScreen &&
|
|
@@ -5235,6 +5395,15 @@ export class InteractiveMode {
|
|
|
5235
5395
|
}
|
|
5236
5396
|
info += `${theme.fg("dim", "Output:")} ${stats.tokens.output.toLocaleString()}\n`;
|
|
5237
5397
|
info += `${theme.fg("dim", "Total:")} ${stats.tokens.total.toLocaleString()}\n`;
|
|
5398
|
+
const cacheWarmingStatus = this.session.cacheWarmingStatus;
|
|
5399
|
+
info += `\n${theme.bold("Cache Warming")}\n`;
|
|
5400
|
+
info += `${theme.fg("dim", "Mode:")} ${this.settingsManager.getCacheWarmingMode()}\n`;
|
|
5401
|
+
info += `${theme.fg("dim", "Status:")} ${cacheWarmingStatus ? formatCacheWarmingStatus(cacheWarmingStatus) : "Inactive (cache warming unavailable)"}\n`;
|
|
5402
|
+
const decision = cacheWarmingStatus?.decision;
|
|
5403
|
+
if (decision?.economicsAvailable) {
|
|
5404
|
+
info += `${theme.fg("dim", "Cache miss penalty:")} $${decision.missCost.toFixed(3)}\n`;
|
|
5405
|
+
info += `${theme.fg("dim", "Refresh cost:")} $${decision.warmCost.toFixed(3)}\n`;
|
|
5406
|
+
}
|
|
5238
5407
|
if (stats.cost > 0 || cacheWaste.missedTokens > 0) {
|
|
5239
5408
|
info += `\n${theme.bold("Cost")}\n`;
|
|
5240
5409
|
info += `${theme.fg("dim", "Total:")} ${formatCost(stats.cost)}`;
|
|
@@ -5365,7 +5534,7 @@ export class InteractiveMode {
|
|
|
5365
5534
|
| \`${expandTools}\` | Toggle tool output expansion |
|
|
5366
5535
|
| \`${toggleThinking}\` | Toggle thinking block visibility |
|
|
5367
5536
|
| \`${externalEditor}\` | Edit message in external editor |
|
|
5368
|
-
| \`${copyMessage}\` | Copy last assistant message |
|
|
5537
|
+
| \`${copyMessage}\` | Copy selection or last assistant message |
|
|
5369
5538
|
| \`${followUp}\` | Queue follow-up message |
|
|
5370
5539
|
| \`${dequeue}\` | Restore queued messages |
|
|
5371
5540
|
| \`${pasteImage}\` | Paste image or text from clipboard |
|
|
@@ -5461,12 +5630,19 @@ export class InteractiveMode {
|
|
|
5461
5630
|
async handleBashCommand(command, excludeFromContext = false) {
|
|
5462
5631
|
const extensionRunner = this.session.extensionRunner;
|
|
5463
5632
|
// Emit user_bash event to let extensions intercept
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5633
|
+
let eventResult;
|
|
5634
|
+
try {
|
|
5635
|
+
eventResult = await extensionRunner.emitUserBash({
|
|
5636
|
+
type: "user_bash",
|
|
5637
|
+
command,
|
|
5638
|
+
excludeFromContext,
|
|
5639
|
+
cwd: this.sessionManager.getCwd(),
|
|
5640
|
+
});
|
|
5641
|
+
}
|
|
5642
|
+
catch {
|
|
5643
|
+
// The extension runner already reported the error. Do not fall back to local execution.
|
|
5644
|
+
return;
|
|
5645
|
+
}
|
|
5470
5646
|
// If extension returned a full result, use it directly
|
|
5471
5647
|
if (eventResult?.result) {
|
|
5472
5648
|
const result = eventResult.result;
|
|
@@ -8,6 +8,8 @@ interface SessionShareContext {
|
|
|
8
8
|
showStatus: (message: string) => void;
|
|
9
9
|
showError: (message: string) => void;
|
|
10
10
|
}
|
|
11
|
+
/** Trailing `pi.share` entry carrying the system prompt and tool schemas for the session viewer. */
|
|
12
|
+
export declare function createShareTrailingEntries(session: AgentSession, parentId: string | null, timestamp: string): object[];
|
|
11
13
|
/** Export the current branch with presentation metadata for Radius. */
|
|
12
14
|
export declare function exportSessionForShare(filePath: string, session: AgentSession): void;
|
|
13
15
|
/** Share the current session through Radius, falling back to a private gist. */
|
|
@@ -10,9 +10,9 @@ import { getShareViewerUrl } from "../../config.js";
|
|
|
10
10
|
import { exportSessionToJsonl } from "../../core/session-export.js";
|
|
11
11
|
import { BorderedLoader } from "./components/bordered-loader.js";
|
|
12
12
|
import { theme } from "./theme/theme.js";
|
|
13
|
-
/**
|
|
14
|
-
export function
|
|
15
|
-
|
|
13
|
+
/** Trailing `pi.share` entry carrying the system prompt and tool schemas for the session viewer. */
|
|
14
|
+
export function createShareTrailingEntries(session, parentId, timestamp) {
|
|
15
|
+
return [
|
|
16
16
|
{
|
|
17
17
|
type: "custom",
|
|
18
18
|
customType: "pi.share",
|
|
@@ -28,7 +28,11 @@ export function exportSessionForShare(filePath, session) {
|
|
|
28
28
|
})),
|
|
29
29
|
},
|
|
30
30
|
},
|
|
31
|
-
]
|
|
31
|
+
];
|
|
32
|
+
}
|
|
33
|
+
/** Export the current branch with presentation metadata for Radius. */
|
|
34
|
+
export function exportSessionForShare(filePath, session) {
|
|
35
|
+
exportSessionToJsonl(session.sessionManager, filePath, (parentId, timestamp) => createShareTrailingEntries(session, parentId, timestamp));
|
|
32
36
|
}
|
|
33
37
|
/** Share the current session through Radius, falling back to a private gist. */
|
|
34
38
|
export async function shareSession(context) {
|