gsd-pi 2.39.0 → 2.40.0-dev.4a93031
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/dist/resource-loader.js +66 -2
- package/dist/resources/extensions/async-jobs/index.js +10 -0
- package/dist/resources/extensions/get-secrets-from-user.js +1 -1
- package/dist/resources/extensions/gsd/auto-dashboard.js +7 -0
- package/dist/resources/extensions/gsd/auto-loop.js +761 -673
- package/dist/resources/extensions/gsd/auto-post-unit.js +10 -2
- package/dist/resources/extensions/gsd/auto-prompts.js +3 -3
- package/dist/resources/extensions/gsd/auto-start.js +6 -1
- package/dist/resources/extensions/gsd/auto.js +6 -4
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +126 -0
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +233 -0
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +59 -0
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +38 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +156 -0
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +46 -0
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +300 -0
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +38 -0
- package/dist/resources/extensions/gsd/commands/catalog.js +278 -0
- package/dist/resources/extensions/gsd/commands/context.js +84 -0
- package/dist/resources/extensions/gsd/commands/dispatcher.js +21 -0
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +72 -0
- package/dist/resources/extensions/gsd/commands/handlers/core.js +246 -0
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +166 -0
- package/dist/resources/extensions/gsd/commands/handlers/parallel.js +94 -0
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +102 -0
- package/dist/resources/extensions/gsd/commands/index.js +11 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +1 -1
- package/dist/resources/extensions/gsd/commands.js +8 -1190
- package/dist/resources/extensions/gsd/dashboard-overlay.js +9 -0
- package/dist/resources/extensions/gsd/doctor-proactive.js +80 -10
- package/dist/resources/extensions/gsd/doctor.js +32 -2
- package/dist/resources/extensions/gsd/export-html.js +46 -0
- package/dist/resources/extensions/gsd/files.js +1 -1
- package/dist/resources/extensions/gsd/health-widget.js +1 -1
- package/dist/resources/extensions/gsd/index.js +4 -1115
- package/dist/resources/extensions/gsd/progress-score.js +20 -1
- package/dist/resources/extensions/gsd/prompts/forensics.md +121 -46
- package/dist/resources/extensions/gsd/visualizer-data.js +26 -1
- package/dist/resources/extensions/gsd/visualizer-views.js +52 -0
- package/dist/welcome-screen.d.ts +3 -2
- package/dist/welcome-screen.js +66 -22
- package/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +12 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +107 -24
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skill-tool.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/skill-tool.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/skill-tool.test.js +70 -0
- package/packages/pi-coding-agent/dist/core/skill-tool.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.js +2 -1
- package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts +17 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +244 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.d.ts +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js +58 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts +12 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +54 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.d.ts +6 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js +63 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +38 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +15 -457
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +122 -23
- package/packages/pi-coding-agent/src/core/skill-tool.test.ts +89 -0
- package/packages/pi-coding-agent/src/core/skills.ts +2 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +302 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/extension-ui-controller.ts +59 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +68 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/model-controller.ts +71 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +37 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +18 -510
- package/pkg/package.json +1 -1
- package/src/resources/extensions/async-jobs/index.ts +11 -0
- package/src/resources/extensions/get-secrets-from-user.ts +1 -1
- package/src/resources/extensions/gsd/auto-dashboard.ts +10 -0
- package/src/resources/extensions/gsd/auto-loop.ts +1075 -921
- package/src/resources/extensions/gsd/auto-post-unit.ts +10 -2
- package/src/resources/extensions/gsd/auto-prompts.ts +3 -3
- package/src/resources/extensions/gsd/auto-start.ts +6 -1
- package/src/resources/extensions/gsd/auto.ts +13 -10
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +142 -0
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +238 -0
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +90 -0
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +46 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +167 -0
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +55 -0
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +340 -0
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +51 -0
- package/src/resources/extensions/gsd/commands/catalog.ts +301 -0
- package/src/resources/extensions/gsd/commands/context.ts +101 -0
- package/src/resources/extensions/gsd/commands/dispatcher.ts +32 -0
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +74 -0
- package/src/resources/extensions/gsd/commands/handlers/core.ts +274 -0
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +169 -0
- package/src/resources/extensions/gsd/commands/handlers/parallel.ts +118 -0
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +109 -0
- package/src/resources/extensions/gsd/commands/index.ts +14 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +1 -1
- package/src/resources/extensions/gsd/commands.ts +10 -1329
- package/src/resources/extensions/gsd/dashboard-overlay.ts +10 -0
- package/src/resources/extensions/gsd/doctor-proactive.ts +106 -10
- package/src/resources/extensions/gsd/doctor.ts +47 -3
- package/src/resources/extensions/gsd/export-html.ts +51 -0
- package/src/resources/extensions/gsd/files.ts +1 -1
- package/src/resources/extensions/gsd/health-widget.ts +2 -1
- package/src/resources/extensions/gsd/index.ts +12 -1314
- package/src/resources/extensions/gsd/progress-score.ts +23 -0
- package/src/resources/extensions/gsd/prompts/forensics.md +121 -46
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +13 -9
- package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +16 -16
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +10 -10
- package/src/resources/extensions/gsd/visualizer-data.ts +51 -1
- package/src/resources/extensions/gsd/visualizer-views.ts +58 -0
- /package/dist/resources/extensions/{env-utils.js → gsd/env-utils.js} +0 -0
- /package/src/resources/extensions/{env-utils.ts → gsd/env-utils.ts} +0 -0
|
@@ -45,8 +45,12 @@ import { ToolExecutionComponent } from "./components/tool-execution.js";
|
|
|
45
45
|
import { TreeSelectorComponent } from "./components/tree-selector.js";
|
|
46
46
|
import { UserMessageComponent } from "./components/user-message.js";
|
|
47
47
|
import { UserMessageSelectorComponent } from "./components/user-message-selector.js";
|
|
48
|
-
import {
|
|
49
|
-
import {
|
|
48
|
+
import { getAppKeyDisplay } from "./slash-command-handlers.js";
|
|
49
|
+
import { handleAgentEvent } from "./controllers/chat-controller.js";
|
|
50
|
+
import { createExtensionUIContext as buildExtensionUIContext } from "./controllers/extension-ui-controller.js";
|
|
51
|
+
import { setupEditorSubmitHandler as setupEditorSubmitHandlerController } from "./controllers/input-controller.js";
|
|
52
|
+
import { findExactModelMatch as findExactModelMatchController, getModelCandidates as getModelCandidatesController, handleModelCommand as handleModelCommandController, updateAvailableProviderCount as updateAvailableProviderCountController, } from "./controllers/model-controller.js";
|
|
53
|
+
import { getAvailableThemes, getEditorTheme, getMarkdownTheme, initTheme, onThemeChange, setRegisteredThemes, setTheme, theme, } from "./theme/theme.js";
|
|
50
54
|
function isExpandable(obj) {
|
|
51
55
|
return typeof obj === "object" && obj !== null && "setExpanded" in obj && typeof obj.setExpanded === "function";
|
|
52
56
|
}
|
|
@@ -896,12 +900,10 @@ export class InteractiveMode {
|
|
|
896
900
|
this.showLoadedResources({ extensionPaths: extensionRunner.getExtensionPaths(), force: false });
|
|
897
901
|
}
|
|
898
902
|
/**
|
|
899
|
-
* Get a
|
|
903
|
+
* Get a tool definition by name (for custom rendering).
|
|
900
904
|
*/
|
|
901
905
|
getRegisteredToolDefinition(toolName) {
|
|
902
|
-
|
|
903
|
-
const registeredTool = tools.find((t) => t.definition.name === toolName);
|
|
904
|
-
return registeredTool?.definition;
|
|
906
|
+
return this.session.getRenderableToolDefinition(toolName);
|
|
905
907
|
}
|
|
906
908
|
/**
|
|
907
909
|
* Format web search result content for display in the TUI.
|
|
@@ -1168,60 +1170,7 @@ export class InteractiveMode {
|
|
|
1168
1170
|
* Create the ExtensionUIContext for extensions.
|
|
1169
1171
|
*/
|
|
1170
1172
|
createExtensionUIContext() {
|
|
1171
|
-
return
|
|
1172
|
-
select: (title, options, opts) => this.showExtensionSelector(title, options, opts),
|
|
1173
|
-
confirm: (title, message, opts) => this.showExtensionConfirm(title, message, opts),
|
|
1174
|
-
input: (title, placeholder, opts) => this.showExtensionInput(title, placeholder, opts),
|
|
1175
|
-
notify: (message, type) => this.showExtensionNotify(message, type),
|
|
1176
|
-
onTerminalInput: (handler) => this.addExtensionTerminalInputListener(handler),
|
|
1177
|
-
setStatus: (key, text) => this.setExtensionStatus(key, text),
|
|
1178
|
-
setWorkingMessage: (message) => {
|
|
1179
|
-
if (this.loadingAnimation) {
|
|
1180
|
-
if (message) {
|
|
1181
|
-
this.loadingAnimation.setMessage(message);
|
|
1182
|
-
}
|
|
1183
|
-
else {
|
|
1184
|
-
this.loadingAnimation.setMessage(`${this.defaultWorkingMessage} (${appKey(this.keybindings, "interrupt")} to interrupt)`);
|
|
1185
|
-
}
|
|
1186
|
-
}
|
|
1187
|
-
else {
|
|
1188
|
-
// Queue message for when loadingAnimation is created (handles agent_start race)
|
|
1189
|
-
this.pendingWorkingMessage = message;
|
|
1190
|
-
}
|
|
1191
|
-
},
|
|
1192
|
-
setWidget: (key, content, options) => this.setExtensionWidget(key, content, options),
|
|
1193
|
-
setFooter: (factory) => this.setExtensionFooter(factory),
|
|
1194
|
-
setHeader: (factory) => this.setExtensionHeader(factory),
|
|
1195
|
-
setTitle: (title) => this.ui.terminal.setTitle(title),
|
|
1196
|
-
custom: (factory, options) => this.showExtensionCustom(factory, options),
|
|
1197
|
-
pasteToEditor: (text) => this.editor.handleInput(`\x1b[200~${text}\x1b[201~`),
|
|
1198
|
-
setEditorText: (text) => this.editor.setText(text),
|
|
1199
|
-
getEditorText: () => this.editor.getText(),
|
|
1200
|
-
editor: (title, prefill) => this.showExtensionEditor(title, prefill),
|
|
1201
|
-
setEditorComponent: (factory) => this.setCustomEditorComponent(factory),
|
|
1202
|
-
get theme() {
|
|
1203
|
-
return theme;
|
|
1204
|
-
},
|
|
1205
|
-
getAllThemes: () => getAvailableThemesWithPaths(),
|
|
1206
|
-
getTheme: (name) => getThemeByName(name),
|
|
1207
|
-
setTheme: (themeOrName) => {
|
|
1208
|
-
if (themeOrName instanceof Theme) {
|
|
1209
|
-
setThemeInstance(themeOrName);
|
|
1210
|
-
this.ui.requestRender();
|
|
1211
|
-
return { success: true };
|
|
1212
|
-
}
|
|
1213
|
-
const result = setTheme(themeOrName, true);
|
|
1214
|
-
if (result.success) {
|
|
1215
|
-
if (this.settingsManager.getTheme() !== themeOrName) {
|
|
1216
|
-
this.settingsManager.setTheme(themeOrName);
|
|
1217
|
-
}
|
|
1218
|
-
this.ui.requestRender();
|
|
1219
|
-
}
|
|
1220
|
-
return result;
|
|
1221
|
-
},
|
|
1222
|
-
getToolsExpanded: () => this.toolOutputExpanded,
|
|
1223
|
-
setToolsExpanded: (expanded) => this.setToolsExpanded(expanded),
|
|
1224
|
-
};
|
|
1173
|
+
return buildExtensionUIContext(this);
|
|
1225
1174
|
}
|
|
1226
1175
|
/**
|
|
1227
1176
|
* Show a selector for extensions.
|
|
@@ -1628,65 +1577,7 @@ export class InteractiveMode {
|
|
|
1628
1577
|
};
|
|
1629
1578
|
}
|
|
1630
1579
|
setupEditorSubmitHandler() {
|
|
1631
|
-
this
|
|
1632
|
-
text = text.trim();
|
|
1633
|
-
if (!text)
|
|
1634
|
-
return;
|
|
1635
|
-
// Handle slash commands
|
|
1636
|
-
if (text.startsWith("/")) {
|
|
1637
|
-
const handled = await dispatchSlashCommand(text, this.getSlashCommandContext());
|
|
1638
|
-
if (handled) {
|
|
1639
|
-
this.editor.setText("");
|
|
1640
|
-
return;
|
|
1641
|
-
}
|
|
1642
|
-
}
|
|
1643
|
-
// Handle bash command (! for normal, !! for excluded from context)
|
|
1644
|
-
if (text.startsWith("!")) {
|
|
1645
|
-
const isExcluded = text.startsWith("!!");
|
|
1646
|
-
const command = isExcluded ? text.slice(2).trim() : text.slice(1).trim();
|
|
1647
|
-
if (command) {
|
|
1648
|
-
if (this.session.isBashRunning) {
|
|
1649
|
-
this.showWarning("A bash command is already running. Press Esc to cancel it first.");
|
|
1650
|
-
this.editor.setText(text);
|
|
1651
|
-
return;
|
|
1652
|
-
}
|
|
1653
|
-
this.editor.addToHistory?.(text);
|
|
1654
|
-
await this.handleBashCommand(command, isExcluded);
|
|
1655
|
-
this.isBashMode = false;
|
|
1656
|
-
this.updateEditorBorderColor();
|
|
1657
|
-
return;
|
|
1658
|
-
}
|
|
1659
|
-
}
|
|
1660
|
-
// Queue input during compaction (extension commands execute immediately)
|
|
1661
|
-
if (this.session.isCompacting) {
|
|
1662
|
-
if (this.isExtensionCommand(text)) {
|
|
1663
|
-
this.editor.addToHistory?.(text);
|
|
1664
|
-
this.editor.setText("");
|
|
1665
|
-
await this.session.prompt(text);
|
|
1666
|
-
}
|
|
1667
|
-
else {
|
|
1668
|
-
this.queueCompactionMessage(text, "steer");
|
|
1669
|
-
}
|
|
1670
|
-
return;
|
|
1671
|
-
}
|
|
1672
|
-
// If streaming, use prompt() with steer behavior
|
|
1673
|
-
// This handles extension commands (execute immediately), prompt template expansion, and queueing
|
|
1674
|
-
if (this.session.isStreaming) {
|
|
1675
|
-
this.editor.addToHistory?.(text);
|
|
1676
|
-
this.editor.setText("");
|
|
1677
|
-
await this.session.prompt(text, { streamingBehavior: "steer" });
|
|
1678
|
-
this.updatePendingMessagesDisplay();
|
|
1679
|
-
this.ui.requestRender();
|
|
1680
|
-
return;
|
|
1681
|
-
}
|
|
1682
|
-
// Normal message submission
|
|
1683
|
-
// First, move any pending bash components to chat
|
|
1684
|
-
this.flushPendingBashComponents();
|
|
1685
|
-
if (this.onInputCallback) {
|
|
1686
|
-
this.onInputCallback(text);
|
|
1687
|
-
}
|
|
1688
|
-
this.editor.addToHistory?.(text);
|
|
1689
|
-
};
|
|
1580
|
+
setupEditorSubmitHandlerController(this);
|
|
1690
1581
|
}
|
|
1691
1582
|
subscribeToAgent() {
|
|
1692
1583
|
this.unsubscribe = this.session.subscribe(async (event) => {
|
|
@@ -1694,290 +1585,7 @@ export class InteractiveMode {
|
|
|
1694
1585
|
});
|
|
1695
1586
|
}
|
|
1696
1587
|
async handleEvent(event) {
|
|
1697
|
-
|
|
1698
|
-
await this.init();
|
|
1699
|
-
}
|
|
1700
|
-
this.footer.invalidate();
|
|
1701
|
-
switch (event.type) {
|
|
1702
|
-
case "agent_start":
|
|
1703
|
-
// Restore main escape handler if retry handler is still active
|
|
1704
|
-
// (retry success event fires later, but we need main handler now)
|
|
1705
|
-
if (this.retryEscapeHandler) {
|
|
1706
|
-
this.defaultEditor.onEscape = this.retryEscapeHandler;
|
|
1707
|
-
this.retryEscapeHandler = undefined;
|
|
1708
|
-
}
|
|
1709
|
-
if (this.retryLoader) {
|
|
1710
|
-
this.retryLoader.stop();
|
|
1711
|
-
this.retryLoader = undefined;
|
|
1712
|
-
}
|
|
1713
|
-
if (this.loadingAnimation) {
|
|
1714
|
-
this.loadingAnimation.stop();
|
|
1715
|
-
}
|
|
1716
|
-
this.statusContainer.clear();
|
|
1717
|
-
this.loadingAnimation = new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), this.defaultWorkingMessage);
|
|
1718
|
-
this.statusContainer.addChild(this.loadingAnimation);
|
|
1719
|
-
// Apply any pending working message queued before loader existed
|
|
1720
|
-
if (this.pendingWorkingMessage !== undefined) {
|
|
1721
|
-
if (this.pendingWorkingMessage) {
|
|
1722
|
-
this.loadingAnimation.setMessage(this.pendingWorkingMessage);
|
|
1723
|
-
}
|
|
1724
|
-
this.pendingWorkingMessage = undefined;
|
|
1725
|
-
}
|
|
1726
|
-
this.ui.requestRender();
|
|
1727
|
-
break;
|
|
1728
|
-
case "message_start":
|
|
1729
|
-
if (event.message.role === "custom") {
|
|
1730
|
-
this.addMessageToChat(event.message);
|
|
1731
|
-
this.ui.requestRender();
|
|
1732
|
-
}
|
|
1733
|
-
else if (event.message.role === "user") {
|
|
1734
|
-
this.addMessageToChat(event.message);
|
|
1735
|
-
this.updatePendingMessagesDisplay();
|
|
1736
|
-
this.ui.requestRender();
|
|
1737
|
-
}
|
|
1738
|
-
else if (event.message.role === "assistant") {
|
|
1739
|
-
this.streamingComponent = new AssistantMessageComponent(undefined, this.hideThinkingBlock, this.getMarkdownThemeWithSettings());
|
|
1740
|
-
this.streamingMessage = event.message;
|
|
1741
|
-
this.chatContainer.addChild(this.streamingComponent);
|
|
1742
|
-
this.streamingComponent.updateContent(this.streamingMessage);
|
|
1743
|
-
this.ui.requestRender();
|
|
1744
|
-
}
|
|
1745
|
-
break;
|
|
1746
|
-
case "message_update":
|
|
1747
|
-
if (this.streamingComponent && event.message.role === "assistant") {
|
|
1748
|
-
this.streamingMessage = event.message;
|
|
1749
|
-
this.streamingComponent.updateContent(this.streamingMessage);
|
|
1750
|
-
for (const content of this.streamingMessage.content) {
|
|
1751
|
-
if (content.type === "toolCall") {
|
|
1752
|
-
if (!this.pendingTools.has(content.id)) {
|
|
1753
|
-
const component = new ToolExecutionComponent(content.name, content.arguments, {
|
|
1754
|
-
showImages: this.settingsManager.getShowImages(),
|
|
1755
|
-
}, this.getRegisteredToolDefinition(content.name), this.ui);
|
|
1756
|
-
component.setExpanded(this.toolOutputExpanded);
|
|
1757
|
-
this.chatContainer.addChild(component);
|
|
1758
|
-
this.pendingTools.set(content.id, component);
|
|
1759
|
-
}
|
|
1760
|
-
else {
|
|
1761
|
-
const component = this.pendingTools.get(content.id);
|
|
1762
|
-
if (component) {
|
|
1763
|
-
component.updateArgs(content.arguments);
|
|
1764
|
-
}
|
|
1765
|
-
}
|
|
1766
|
-
}
|
|
1767
|
-
else if (content.type === "serverToolUse") {
|
|
1768
|
-
// Server-side tool (e.g., native web search) — show as pending tool execution
|
|
1769
|
-
if (!this.pendingTools.has(content.id)) {
|
|
1770
|
-
const component = new ToolExecutionComponent(content.name, content.input ?? {}, {
|
|
1771
|
-
showImages: this.settingsManager.getShowImages(),
|
|
1772
|
-
}, undefined, this.ui);
|
|
1773
|
-
component.setExpanded(this.toolOutputExpanded);
|
|
1774
|
-
this.chatContainer.addChild(component);
|
|
1775
|
-
this.pendingTools.set(content.id, component);
|
|
1776
|
-
}
|
|
1777
|
-
}
|
|
1778
|
-
else if (content.type === "webSearchResult") {
|
|
1779
|
-
// Server-side tool result — resolve the pending server tool execution
|
|
1780
|
-
const component = this.pendingTools.get(content.toolUseId);
|
|
1781
|
-
if (component) {
|
|
1782
|
-
const searchContent = content.content;
|
|
1783
|
-
const isError = searchContent && typeof searchContent === "object" && "type" in searchContent && searchContent.type === "web_search_tool_result_error";
|
|
1784
|
-
const resultText = this.formatWebSearchResult(searchContent);
|
|
1785
|
-
component.updateResult({
|
|
1786
|
-
content: [{ type: "text", text: resultText }],
|
|
1787
|
-
isError: !!isError,
|
|
1788
|
-
});
|
|
1789
|
-
this.pendingTools.delete(content.toolUseId);
|
|
1790
|
-
}
|
|
1791
|
-
}
|
|
1792
|
-
}
|
|
1793
|
-
this.ui.requestRender();
|
|
1794
|
-
}
|
|
1795
|
-
break;
|
|
1796
|
-
case "message_end":
|
|
1797
|
-
if (event.message.role === "user")
|
|
1798
|
-
break;
|
|
1799
|
-
if (this.streamingComponent && event.message.role === "assistant") {
|
|
1800
|
-
this.streamingMessage = event.message;
|
|
1801
|
-
let errorMessage;
|
|
1802
|
-
if (this.streamingMessage.stopReason === "aborted") {
|
|
1803
|
-
const retryAttempt = this.session.retryAttempt;
|
|
1804
|
-
errorMessage =
|
|
1805
|
-
retryAttempt > 0
|
|
1806
|
-
? `Aborted after ${retryAttempt} retry attempt${retryAttempt > 1 ? "s" : ""}`
|
|
1807
|
-
: "Operation aborted";
|
|
1808
|
-
this.streamingMessage.errorMessage = errorMessage;
|
|
1809
|
-
}
|
|
1810
|
-
this.streamingComponent.updateContent(this.streamingMessage);
|
|
1811
|
-
if (this.streamingMessage.stopReason === "aborted" || this.streamingMessage.stopReason === "error") {
|
|
1812
|
-
if (!errorMessage) {
|
|
1813
|
-
errorMessage = this.streamingMessage.errorMessage || "Error";
|
|
1814
|
-
}
|
|
1815
|
-
for (const [, component] of this.pendingTools.entries()) {
|
|
1816
|
-
component.updateResult({
|
|
1817
|
-
content: [{ type: "text", text: errorMessage }],
|
|
1818
|
-
isError: true,
|
|
1819
|
-
});
|
|
1820
|
-
}
|
|
1821
|
-
this.pendingTools.clear();
|
|
1822
|
-
}
|
|
1823
|
-
else {
|
|
1824
|
-
// Args are now complete - trigger diff computation for edit tools
|
|
1825
|
-
for (const [, component] of this.pendingTools.entries()) {
|
|
1826
|
-
component.setArgsComplete();
|
|
1827
|
-
}
|
|
1828
|
-
}
|
|
1829
|
-
this.streamingComponent = undefined;
|
|
1830
|
-
this.streamingMessage = undefined;
|
|
1831
|
-
this.footer.invalidate();
|
|
1832
|
-
}
|
|
1833
|
-
this.ui.requestRender();
|
|
1834
|
-
break;
|
|
1835
|
-
case "tool_execution_start": {
|
|
1836
|
-
if (!this.pendingTools.has(event.toolCallId)) {
|
|
1837
|
-
const component = new ToolExecutionComponent(event.toolName, event.args, {
|
|
1838
|
-
showImages: this.settingsManager.getShowImages(),
|
|
1839
|
-
}, this.getRegisteredToolDefinition(event.toolName), this.ui);
|
|
1840
|
-
component.setExpanded(this.toolOutputExpanded);
|
|
1841
|
-
this.chatContainer.addChild(component);
|
|
1842
|
-
this.pendingTools.set(event.toolCallId, component);
|
|
1843
|
-
this.ui.requestRender();
|
|
1844
|
-
}
|
|
1845
|
-
break;
|
|
1846
|
-
}
|
|
1847
|
-
case "tool_execution_update": {
|
|
1848
|
-
const component = this.pendingTools.get(event.toolCallId);
|
|
1849
|
-
if (component) {
|
|
1850
|
-
component.updateResult({ ...event.partialResult, isError: false }, true);
|
|
1851
|
-
this.ui.requestRender();
|
|
1852
|
-
}
|
|
1853
|
-
break;
|
|
1854
|
-
}
|
|
1855
|
-
case "tool_execution_end": {
|
|
1856
|
-
const component = this.pendingTools.get(event.toolCallId);
|
|
1857
|
-
if (component) {
|
|
1858
|
-
component.updateResult({ ...event.result, isError: event.isError });
|
|
1859
|
-
this.pendingTools.delete(event.toolCallId);
|
|
1860
|
-
this.ui.requestRender();
|
|
1861
|
-
}
|
|
1862
|
-
break;
|
|
1863
|
-
}
|
|
1864
|
-
case "agent_end":
|
|
1865
|
-
if (this.loadingAnimation) {
|
|
1866
|
-
this.loadingAnimation.stop();
|
|
1867
|
-
this.loadingAnimation = undefined;
|
|
1868
|
-
this.statusContainer.clear();
|
|
1869
|
-
}
|
|
1870
|
-
if (this.streamingComponent) {
|
|
1871
|
-
this.chatContainer.removeChild(this.streamingComponent);
|
|
1872
|
-
this.streamingComponent = undefined;
|
|
1873
|
-
this.streamingMessage = undefined;
|
|
1874
|
-
}
|
|
1875
|
-
this.pendingTools.clear();
|
|
1876
|
-
await this.checkShutdownRequested();
|
|
1877
|
-
this.ui.requestRender();
|
|
1878
|
-
break;
|
|
1879
|
-
case "auto_compaction_start": {
|
|
1880
|
-
// Keep editor active; submissions are queued during compaction.
|
|
1881
|
-
// Set up escape to abort auto-compaction
|
|
1882
|
-
this.autoCompactionEscapeHandler = this.defaultEditor.onEscape;
|
|
1883
|
-
this.defaultEditor.onEscape = () => {
|
|
1884
|
-
this.session.abortCompaction();
|
|
1885
|
-
};
|
|
1886
|
-
// Show compacting indicator with reason
|
|
1887
|
-
this.statusContainer.clear();
|
|
1888
|
-
const reasonText = event.reason === "overflow" ? "Context overflow detected, " : "";
|
|
1889
|
-
this.autoCompactionLoader = new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), `${reasonText}Auto-compacting... (${appKey(this.keybindings, "interrupt")} to cancel)`);
|
|
1890
|
-
this.statusContainer.addChild(this.autoCompactionLoader);
|
|
1891
|
-
this.ui.requestRender();
|
|
1892
|
-
break;
|
|
1893
|
-
}
|
|
1894
|
-
case "auto_compaction_end": {
|
|
1895
|
-
// Restore escape handler
|
|
1896
|
-
if (this.autoCompactionEscapeHandler) {
|
|
1897
|
-
this.defaultEditor.onEscape = this.autoCompactionEscapeHandler;
|
|
1898
|
-
this.autoCompactionEscapeHandler = undefined;
|
|
1899
|
-
}
|
|
1900
|
-
// Stop loader
|
|
1901
|
-
if (this.autoCompactionLoader) {
|
|
1902
|
-
this.autoCompactionLoader.stop();
|
|
1903
|
-
this.autoCompactionLoader = undefined;
|
|
1904
|
-
this.statusContainer.clear();
|
|
1905
|
-
}
|
|
1906
|
-
// Handle result
|
|
1907
|
-
if (event.aborted) {
|
|
1908
|
-
this.showStatus("Auto-compaction cancelled");
|
|
1909
|
-
}
|
|
1910
|
-
else if (event.result) {
|
|
1911
|
-
// Rebuild chat to show compacted state
|
|
1912
|
-
this.chatContainer.clear();
|
|
1913
|
-
this.rebuildChatFromMessages();
|
|
1914
|
-
// Add compaction component at bottom so user sees it without scrolling
|
|
1915
|
-
this.addMessageToChat({
|
|
1916
|
-
role: "compactionSummary",
|
|
1917
|
-
tokensBefore: event.result.tokensBefore,
|
|
1918
|
-
summary: event.result.summary,
|
|
1919
|
-
timestamp: Date.now(),
|
|
1920
|
-
});
|
|
1921
|
-
this.footer.invalidate();
|
|
1922
|
-
}
|
|
1923
|
-
else if (event.errorMessage) {
|
|
1924
|
-
// Compaction failed (e.g., quota exceeded, API error)
|
|
1925
|
-
this.chatContainer.addChild(new Spacer(1));
|
|
1926
|
-
this.chatContainer.addChild(new Text(theme.fg("error", event.errorMessage), 1, 0));
|
|
1927
|
-
}
|
|
1928
|
-
void this.flushCompactionQueue({ willRetry: event.willRetry });
|
|
1929
|
-
this.ui.requestRender();
|
|
1930
|
-
break;
|
|
1931
|
-
}
|
|
1932
|
-
case "auto_retry_start": {
|
|
1933
|
-
// Set up escape to abort retry
|
|
1934
|
-
this.retryEscapeHandler = this.defaultEditor.onEscape;
|
|
1935
|
-
this.defaultEditor.onEscape = () => {
|
|
1936
|
-
this.session.abortRetry();
|
|
1937
|
-
};
|
|
1938
|
-
// Show retry indicator
|
|
1939
|
-
this.statusContainer.clear();
|
|
1940
|
-
const delaySeconds = Math.round(event.delayMs / 1000);
|
|
1941
|
-
this.retryLoader = new Loader(this.ui, (spinner) => theme.fg("warning", spinner), (text) => theme.fg("muted", text), `Retrying (${event.attempt}/${event.maxAttempts}) in ${delaySeconds}s... (${appKey(this.keybindings, "interrupt")} to cancel)`);
|
|
1942
|
-
this.statusContainer.addChild(this.retryLoader);
|
|
1943
|
-
this.ui.requestRender();
|
|
1944
|
-
break;
|
|
1945
|
-
}
|
|
1946
|
-
case "auto_retry_end": {
|
|
1947
|
-
// Restore escape handler
|
|
1948
|
-
if (this.retryEscapeHandler) {
|
|
1949
|
-
this.defaultEditor.onEscape = this.retryEscapeHandler;
|
|
1950
|
-
this.retryEscapeHandler = undefined;
|
|
1951
|
-
}
|
|
1952
|
-
// Stop loader
|
|
1953
|
-
if (this.retryLoader) {
|
|
1954
|
-
this.retryLoader.stop();
|
|
1955
|
-
this.retryLoader = undefined;
|
|
1956
|
-
this.statusContainer.clear();
|
|
1957
|
-
}
|
|
1958
|
-
// Show error only on final failure (success shows normal response)
|
|
1959
|
-
if (!event.success) {
|
|
1960
|
-
this.showError(`Retry failed after ${event.attempt} attempts: ${event.finalError || "Unknown error"}`);
|
|
1961
|
-
}
|
|
1962
|
-
this.ui.requestRender();
|
|
1963
|
-
break;
|
|
1964
|
-
}
|
|
1965
|
-
case "fallback_provider_switch": {
|
|
1966
|
-
this.showStatus(`Switched from ${event.from} → ${event.to} (${event.reason})`);
|
|
1967
|
-
this.ui.requestRender();
|
|
1968
|
-
break;
|
|
1969
|
-
}
|
|
1970
|
-
case "fallback_provider_restored": {
|
|
1971
|
-
this.showStatus(`Restored to ${event.provider}`);
|
|
1972
|
-
this.ui.requestRender();
|
|
1973
|
-
break;
|
|
1974
|
-
}
|
|
1975
|
-
case "fallback_chain_exhausted": {
|
|
1976
|
-
this.showError(event.reason);
|
|
1977
|
-
this.ui.requestRender();
|
|
1978
|
-
break;
|
|
1979
|
-
}
|
|
1980
|
-
}
|
|
1588
|
+
await handleAgentEvent(this, event);
|
|
1981
1589
|
}
|
|
1982
1590
|
/** Extract text content from a user message */
|
|
1983
1591
|
getUserMessageText(message) {
|
|
@@ -2750,67 +2358,17 @@ export class InteractiveMode {
|
|
|
2750
2358
|
});
|
|
2751
2359
|
}
|
|
2752
2360
|
async handleModelCommand(searchTerm) {
|
|
2753
|
-
|
|
2754
|
-
this.showModelSelector();
|
|
2755
|
-
return;
|
|
2756
|
-
}
|
|
2757
|
-
const model = await this.findExactModelMatch(searchTerm);
|
|
2758
|
-
if (model) {
|
|
2759
|
-
try {
|
|
2760
|
-
await this.session.setModel(model);
|
|
2761
|
-
this.footer.invalidate();
|
|
2762
|
-
this.updateEditorBorderColor();
|
|
2763
|
-
this.showStatus(`Model: ${model.id}`);
|
|
2764
|
-
this.checkDaxnutsEasterEgg(model);
|
|
2765
|
-
}
|
|
2766
|
-
catch (error) {
|
|
2767
|
-
this.showError(error instanceof Error ? error.message : String(error));
|
|
2768
|
-
}
|
|
2769
|
-
return;
|
|
2770
|
-
}
|
|
2771
|
-
this.showModelSelector(searchTerm);
|
|
2361
|
+
await handleModelCommandController(this, searchTerm);
|
|
2772
2362
|
}
|
|
2773
2363
|
async findExactModelMatch(searchTerm) {
|
|
2774
|
-
|
|
2775
|
-
if (!term)
|
|
2776
|
-
return undefined;
|
|
2777
|
-
let targetProvider;
|
|
2778
|
-
let targetModelId = "";
|
|
2779
|
-
if (term.includes("/")) {
|
|
2780
|
-
const parts = term.split("/", 2);
|
|
2781
|
-
targetProvider = parts[0]?.trim().toLowerCase();
|
|
2782
|
-
targetModelId = parts[1]?.trim().toLowerCase() ?? "";
|
|
2783
|
-
}
|
|
2784
|
-
else {
|
|
2785
|
-
targetModelId = term.toLowerCase();
|
|
2786
|
-
}
|
|
2787
|
-
if (!targetModelId)
|
|
2788
|
-
return undefined;
|
|
2789
|
-
const models = await this.getModelCandidates();
|
|
2790
|
-
const exactMatches = models.filter((item) => {
|
|
2791
|
-
const idMatch = item.id.toLowerCase() === targetModelId;
|
|
2792
|
-
const providerMatch = !targetProvider || item.provider.toLowerCase() === targetProvider;
|
|
2793
|
-
return idMatch && providerMatch;
|
|
2794
|
-
});
|
|
2795
|
-
return exactMatches.length === 1 ? exactMatches[0] : undefined;
|
|
2364
|
+
return findExactModelMatchController(this, searchTerm);
|
|
2796
2365
|
}
|
|
2797
2366
|
async getModelCandidates() {
|
|
2798
|
-
|
|
2799
|
-
return this.session.scopedModels.map((scoped) => scoped.model);
|
|
2800
|
-
}
|
|
2801
|
-
this.session.modelRegistry.refresh();
|
|
2802
|
-
try {
|
|
2803
|
-
return await this.session.modelRegistry.getAvailable();
|
|
2804
|
-
}
|
|
2805
|
-
catch {
|
|
2806
|
-
return [];
|
|
2807
|
-
}
|
|
2367
|
+
return getModelCandidatesController(this);
|
|
2808
2368
|
}
|
|
2809
2369
|
/** Update the footer's available provider count from current model candidates */
|
|
2810
2370
|
async updateAvailableProviderCount() {
|
|
2811
|
-
|
|
2812
|
-
const uniqueProviders = new Set(models.map((m) => m.provider));
|
|
2813
|
-
this.footerDataProvider.setAvailableProviderCount(uniqueProviders.size);
|
|
2371
|
+
await updateAvailableProviderCountController(this);
|
|
2814
2372
|
}
|
|
2815
2373
|
showModelSelector(initialSearchInput) {
|
|
2816
2374
|
this.showSelector((done) => {
|