lsd-pi 1.3.7 → 1.3.10
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/README.md +82 -0
- package/dist/resources/extensions/mcp-client/index.js +230 -54
- package/dist/resources/extensions/mcp-client/mcp-manager-component.js +220 -0
- package/dist/resources/extensions/slash-commands/plan.js +72 -18
- package/dist/resources/extensions/subagent/agents.js +7 -0
- package/dist/resources/extensions/subagent/index.js +25 -8
- package/dist/resources/extensions/subagent/model-resolution.js +1 -0
- package/dist/resources/extensions/usage/index.js +34 -2
- package/dist/resources/extensions/voice/index.js +1 -0
- package/dist/resources/extensions/voice/push-to-talk.js +2 -0
- package/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.context-usage.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/agent-session.context-usage.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.context-usage.test.js +72 -0
- package/packages/pi-coding-agent/dist/core/agent-session.context-usage.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +4 -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 +29 -2
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tool-priority.js +1 -1
- package/packages/pi-coding-agent/dist/core/tool-priority.js.map +1 -1
- package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/main.js +1 -0
- package/packages/pi-coding-agent/dist/main.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-summary-line.test.js +104 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-summary-line.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +39 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +135 -18
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +17 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.d.ts +21 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.js +147 -9
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.js +51 -13
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +112 -18
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -0
- 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 +34 -4
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +3 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.context-usage.test.ts +87 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +40 -2
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +1 -0
- package/packages/pi-coding-agent/src/core/extensions/types.ts +3 -0
- package/packages/pi-coding-agent/src/core/tool-priority.ts +1 -1
- package/packages/pi-coding-agent/src/main.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-summary-line.test.ts +129 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +158 -18
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +18 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-summary-line.ts +164 -10
- package/packages/pi-coding-agent/src/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.ts +60 -13
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +123 -20
- package/packages/pi-coding-agent/src/modes/interactive/controllers/extension-ui-controller.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +34 -4
- package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +4 -0
- package/pkg/package.json +1 -1
- package/src/resources/extensions/mcp-client/index.ts +259 -58
- package/src/resources/extensions/mcp-client/mcp-manager-component.ts +256 -0
- package/src/resources/extensions/mcp-client/tests/mcp-manager-component.test.ts +141 -0
- package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +32 -0
- package/src/resources/extensions/slash-commands/plan.ts +76 -19
- package/src/resources/extensions/subagent/agents.ts +9 -0
- package/src/resources/extensions/subagent/index.ts +30 -8
- package/src/resources/extensions/subagent/model-resolution.ts +1 -0
- package/src/resources/extensions/usage/index.ts +40 -2
- package/src/resources/extensions/voice/index.ts +1 -0
- package/src/resources/extensions/voice/push-to-talk.ts +3 -0
- package/src/resources/extensions/voice/tests/push-to-talk.test.ts +6 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, it } from "node:test";
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
3
|
import stripAnsi from "strip-ansi";
|
|
4
|
-
import { ToolSummaryLine } from "../tool-summary-line.js";
|
|
4
|
+
import { ToolSummaryLine, extractToolLabel } from "../tool-summary-line.js";
|
|
5
5
|
import { initTheme } from "../../theme/theme.js";
|
|
6
6
|
initTheme("dark");
|
|
7
7
|
describe("ToolSummaryLine", () => {
|
|
@@ -13,7 +13,8 @@ describe("ToolSummaryLine", () => {
|
|
|
13
13
|
assert.match(rendered, /^ ● /);
|
|
14
14
|
assert.ok(rendered.includes("reading 2 files · 0.8s"));
|
|
15
15
|
assert.equal(summary.canGroupWith("read"), true);
|
|
16
|
-
assert.equal(summary.canGroupWith("find"),
|
|
16
|
+
assert.equal(summary.canGroupWith("find"), true);
|
|
17
|
+
assert.equal(summary.canGroupWith("bash"), false);
|
|
17
18
|
assert.equal(rendered.includes("collapsed tools"), false);
|
|
18
19
|
assert.equal(rendered.includes("⎯"), false);
|
|
19
20
|
});
|
|
@@ -30,5 +31,106 @@ describe("ToolSummaryLine", () => {
|
|
|
30
31
|
summary.setHidden(true);
|
|
31
32
|
assert.deepEqual(summary.render(80), []);
|
|
32
33
|
});
|
|
34
|
+
it("renders spinner and label line when pending tools exist", () => {
|
|
35
|
+
const summary = new ToolSummaryLine();
|
|
36
|
+
summary.addPendingTool("t1", "read", { path: "src/foo/bar.ts" });
|
|
37
|
+
const rendered = stripAnsi(summary.render(160).join("\n"));
|
|
38
|
+
assert.ok(!rendered.startsWith(" ●"));
|
|
39
|
+
assert.ok(rendered.includes(" └ bar.ts"));
|
|
40
|
+
assert.ok(rendered.includes("bar.ts"));
|
|
41
|
+
});
|
|
42
|
+
it("keeps last tool label after pending tool completes", () => {
|
|
43
|
+
const summary = new ToolSummaryLine();
|
|
44
|
+
summary.addPendingTool("t1", "read", { path: "file.ts" });
|
|
45
|
+
assert.equal(summary.hasPendingTools(), true);
|
|
46
|
+
summary.removePendingTool("t1");
|
|
47
|
+
summary.addTool("read", 500);
|
|
48
|
+
assert.equal(summary.hasPendingTools(), false);
|
|
49
|
+
const rendered = stripAnsi(summary.render(160).join("\n"));
|
|
50
|
+
assert.ok(rendered.includes("●"));
|
|
51
|
+
assert.ok(rendered.includes("0.5s"));
|
|
52
|
+
assert.ok(rendered.includes("└ file.ts"));
|
|
53
|
+
});
|
|
54
|
+
it("aggregates completed and pending tools in summary text", () => {
|
|
55
|
+
const summary = new ToolSummaryLine();
|
|
56
|
+
summary.addTool("read", 300);
|
|
57
|
+
summary.addPendingTool("t1", "grep", { pattern: "TODO" });
|
|
58
|
+
const rendered = stripAnsi(summary.render(160).join("\n"));
|
|
59
|
+
assert.ok(rendered.includes("1 file"));
|
|
60
|
+
assert.ok(rendered.includes("1 pattern"));
|
|
61
|
+
assert.ok(rendered.includes("…"));
|
|
62
|
+
assert.ok(rendered.includes("TODO"));
|
|
63
|
+
});
|
|
64
|
+
it("shows expand hint when set and tools are pending", () => {
|
|
65
|
+
const summary = new ToolSummaryLine();
|
|
66
|
+
summary.setExpandHint("(ctrl+o to expand)");
|
|
67
|
+
summary.addPendingTool("t1", "read", { path: "test.ts" });
|
|
68
|
+
const rendered = stripAnsi(summary.render(160).join("\n"));
|
|
69
|
+
assert.ok(rendered.includes("ctrl+o to expand"));
|
|
70
|
+
});
|
|
71
|
+
it("does not show expand hint when no pending tools", () => {
|
|
72
|
+
const summary = new ToolSummaryLine();
|
|
73
|
+
summary.setExpandHint("(ctrl+o to expand)");
|
|
74
|
+
summary.addTool("read", 300);
|
|
75
|
+
const rendered = stripAnsi(summary.render(160).join("\n"));
|
|
76
|
+
assert.ok(!rendered.includes("ctrl+o to expand"));
|
|
77
|
+
});
|
|
78
|
+
it("updates label when pending tool args change", () => {
|
|
79
|
+
const summary = new ToolSummaryLine();
|
|
80
|
+
summary.addPendingTool("t1", "read", { path: "old.ts" });
|
|
81
|
+
let rendered = stripAnsi(summary.render(160).join("\n"));
|
|
82
|
+
assert.ok(rendered.includes("old.ts"));
|
|
83
|
+
summary.updatePendingToolArgs("t1", { path: "new.ts" });
|
|
84
|
+
rendered = stripAnsi(summary.render(160).join("\n"));
|
|
85
|
+
assert.ok(rendered.includes("new.ts"));
|
|
86
|
+
});
|
|
87
|
+
it("clears pending spinner without removing last label", () => {
|
|
88
|
+
const summary = new ToolSummaryLine();
|
|
89
|
+
summary.addPendingTool("t1", "read", { path: "file.ts" });
|
|
90
|
+
summary.clearPendingTools();
|
|
91
|
+
const rendered = stripAnsi(summary.render(160).join("\n"));
|
|
92
|
+
assert.ok(!rendered.includes("◯"));
|
|
93
|
+
assert.ok(!rendered.includes("◔"));
|
|
94
|
+
assert.ok(!rendered.includes("◑"));
|
|
95
|
+
assert.ok(!rendered.includes("◕"));
|
|
96
|
+
assert.ok(!rendered.includes("● Listing"));
|
|
97
|
+
assert.ok(!rendered.includes("…"));
|
|
98
|
+
assert.ok(rendered === "" || rendered.includes("file.ts"));
|
|
99
|
+
});
|
|
100
|
+
it("canGroupWith considers pending tools", () => {
|
|
101
|
+
const summary = new ToolSummaryLine();
|
|
102
|
+
summary.addPendingTool("t1", "read", { path: "a.ts" });
|
|
103
|
+
assert.equal(summary.canGroupWith("read"), true);
|
|
104
|
+
assert.equal(summary.canGroupWith("grep"), true);
|
|
105
|
+
assert.equal(summary.canGroupWith("bash"), false);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
describe("extractToolLabel", () => {
|
|
109
|
+
it("extracts basename for read tool", () => {
|
|
110
|
+
assert.equal(extractToolLabel("read", { path: "src/foo/bar.ts" }), "bar.ts");
|
|
111
|
+
assert.equal(extractToolLabel("read", { file_path: "/abs/path/file.json" }), "file.json");
|
|
112
|
+
assert.equal(extractToolLabel("read", {}), "read");
|
|
113
|
+
});
|
|
114
|
+
it("extracts pattern for grep tool", () => {
|
|
115
|
+
assert.equal(extractToolLabel("grep", { pattern: "TODO" }), "TODO");
|
|
116
|
+
assert.equal(extractToolLabel("grep", {}), "grep");
|
|
117
|
+
});
|
|
118
|
+
it("extracts pattern for find tool", () => {
|
|
119
|
+
assert.equal(extractToolLabel("find", { pattern: "*.ts" }), "*.ts");
|
|
120
|
+
assert.equal(extractToolLabel("find", {}), "find");
|
|
121
|
+
});
|
|
122
|
+
it("extracts path for ls tool", () => {
|
|
123
|
+
assert.equal(extractToolLabel("ls", { path: "src/components" }), "components");
|
|
124
|
+
assert.equal(extractToolLabel("ls", {}), ".");
|
|
125
|
+
});
|
|
126
|
+
it("extracts symbol or file for lsp tool", () => {
|
|
127
|
+
assert.equal(extractToolLabel("lsp", { symbol: "MyClass" }), "MyClass");
|
|
128
|
+
assert.equal(extractToolLabel("lsp", { file: "src/index.ts" }), "index.ts");
|
|
129
|
+
assert.equal(extractToolLabel("lsp", { symbol: "foo", file: "bar.ts" }), "foo");
|
|
130
|
+
assert.equal(extractToolLabel("lsp", {}), "lsp");
|
|
131
|
+
});
|
|
132
|
+
it("returns tool name for unknown tools", () => {
|
|
133
|
+
assert.equal(extractToolLabel("custom_tool", { whatever: "value" }), "custom_tool");
|
|
134
|
+
});
|
|
33
135
|
});
|
|
34
136
|
//# sourceMappingURL=tool-summary-line.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-summary-line.test.js","sourceRoot":"","sources":["../../../../../src/modes/interactive/components/__tests__/tool-summary-line.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,SAAS,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,SAAS,CAAC,MAAM,CAAC,CAAC;AAElB,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACrE,MAAM,OAAO,GAAG,IAAI,eAAe,EAAE,CAAC;QACtC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC7B,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAE7B,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAC3D,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC/B,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,wBAAwB,CAAC,CAAC,CAAC;QACvD,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC;QACjD,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,CAAC;QAClD,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,KAAK,CAAC,CAAC;QAC1D,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QAClD,MAAM,OAAO,GAAG,IAAI,eAAe,EAAE,CAAC;QACtC,OAAO,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;QAEpC,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAC3D,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC/C,MAAM,OAAO,GAAG,IAAI,eAAe,EAAE,CAAC;QACtC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QAEzC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC7B,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACxB,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC","sourcesContent":["import { describe, it } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport stripAnsi from \"strip-ansi\";\n\nimport { ToolSummaryLine } from \"../tool-summary-line.js\";\nimport { initTheme } from \"../../theme/theme.js\";\n\ninitTheme(\"dark\");\n\ndescribe(\"ToolSummaryLine\", () => {\n\tit(\"renders action-based summaries for grouped identical tools\", () => {\n\t\tconst summary = new ToolSummaryLine();\n\t\tsummary.addTool(\"read\", 600);\n\t\tsummary.addTool(\"read\", 150);\n\n\t\tconst rendered = stripAnsi(summary.render(160).join(\"\\n\"));\n\t\tassert.match(rendered, /^ ● /);\n\t\tassert.ok(rendered.includes(\"reading 2 files · 0.8s\"));\n\t\tassert.equal(summary.canGroupWith(\"read\"), true);\n\t\tassert.equal(summary.canGroupWith(\"find\"), false);\n\t\tassert.equal(rendered.includes(\"collapsed tools\"), false);\n\t\tassert.equal(rendered.includes(\"⎯\"), false);\n\t});\n\n\tit(\"keeps fallback format for unknown tools\", () => {\n\t\tconst summary = new ToolSummaryLine();\n\t\tsummary.addTool(\"custom_tool\", 100);\n\n\t\tconst rendered = stripAnsi(summary.render(160).join(\"\\n\"));\n\t\tassert.ok(rendered.includes(\"custom_tool · 0.1s\"));\n\t});\n\n\tit(\"renders nothing when empty or hidden\", () => {\n\t\tconst summary = new ToolSummaryLine();\n\t\tassert.deepEqual(summary.render(80), []);\n\n\t\tsummary.addTool(\"grep\", 100);\n\t\tsummary.setHidden(true);\n\t\tassert.deepEqual(summary.render(80), []);\n\t});\n});\n"]}
|
|
1
|
+
{"version":3,"file":"tool-summary-line.test.js","sourceRoot":"","sources":["../../../../../src/modes/interactive/components/__tests__/tool-summary-line.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport stripAnsi from \"strip-ansi\";\n\nimport { ToolSummaryLine, extractToolLabel } from \"../tool-summary-line.js\";\nimport { initTheme } from \"../../theme/theme.js\";\n\ninitTheme(\"dark\");\n\ndescribe(\"ToolSummaryLine\", () => {\n\tit(\"renders action-based summaries for grouped identical tools\", () => {\n\t\tconst summary = new ToolSummaryLine();\n\t\tsummary.addTool(\"read\", 600);\n\t\tsummary.addTool(\"read\", 150);\n\n\t\tconst rendered = stripAnsi(summary.render(160).join(\"\\n\"));\n\t\tassert.match(rendered, /^ ● /);\n\t\tassert.ok(rendered.includes(\"reading 2 files · 0.8s\"));\n\t\tassert.equal(summary.canGroupWith(\"read\"), true);\n\t\tassert.equal(summary.canGroupWith(\"find\"), true);\n\t\tassert.equal(summary.canGroupWith(\"bash\"), false);\n\t\tassert.equal(rendered.includes(\"collapsed tools\"), false);\n\t\tassert.equal(rendered.includes(\"⎯\"), false);\n\t});\n\n\tit(\"keeps fallback format for unknown tools\", () => {\n\t\tconst summary = new ToolSummaryLine();\n\t\tsummary.addTool(\"custom_tool\", 100);\n\n\t\tconst rendered = stripAnsi(summary.render(160).join(\"\\n\"));\n\t\tassert.ok(rendered.includes(\"custom_tool · 0.1s\"));\n\t});\n\n\tit(\"renders nothing when empty or hidden\", () => {\n\t\tconst summary = new ToolSummaryLine();\n\t\tassert.deepEqual(summary.render(80), []);\n\n\t\tsummary.addTool(\"grep\", 100);\n\t\tsummary.setHidden(true);\n\t\tassert.deepEqual(summary.render(80), []);\n\t});\n\n\tit(\"renders spinner and label line when pending tools exist\", () => {\n\t\tconst summary = new ToolSummaryLine();\n\t\tsummary.addPendingTool(\"t1\", \"read\", { path: \"src/foo/bar.ts\" });\n\n\t\tconst rendered = stripAnsi(summary.render(160).join(\"\\n\"));\n\t\tassert.ok(!rendered.startsWith(\" ●\"));\n\t\tassert.ok(rendered.includes(\" └ bar.ts\"));\n\t\tassert.ok(rendered.includes(\"bar.ts\"));\n\t});\n\n\tit(\"keeps last tool label after pending tool completes\", () => {\n\t\tconst summary = new ToolSummaryLine();\n\t\tsummary.addPendingTool(\"t1\", \"read\", { path: \"file.ts\" });\n\t\tassert.equal(summary.hasPendingTools(), true);\n\n\t\tsummary.removePendingTool(\"t1\");\n\t\tsummary.addTool(\"read\", 500);\n\t\tassert.equal(summary.hasPendingTools(), false);\n\n\t\tconst rendered = stripAnsi(summary.render(160).join(\"\\n\"));\n\t\tassert.ok(rendered.includes(\"●\"));\n\t\tassert.ok(rendered.includes(\"0.5s\"));\n\t\tassert.ok(rendered.includes(\"└ file.ts\"));\n\t});\n\n\tit(\"aggregates completed and pending tools in summary text\", () => {\n\t\tconst summary = new ToolSummaryLine();\n\t\tsummary.addTool(\"read\", 300);\n\t\tsummary.addPendingTool(\"t1\", \"grep\", { pattern: \"TODO\" });\n\n\t\tconst rendered = stripAnsi(summary.render(160).join(\"\\n\"));\n\t\tassert.ok(rendered.includes(\"1 file\"));\n\t\tassert.ok(rendered.includes(\"1 pattern\"));\n\t\tassert.ok(rendered.includes(\"…\"));\n\t\tassert.ok(rendered.includes(\"TODO\"));\n\t});\n\n\tit(\"shows expand hint when set and tools are pending\", () => {\n\t\tconst summary = new ToolSummaryLine();\n\t\tsummary.setExpandHint(\"(ctrl+o to expand)\");\n\t\tsummary.addPendingTool(\"t1\", \"read\", { path: \"test.ts\" });\n\n\t\tconst rendered = stripAnsi(summary.render(160).join(\"\\n\"));\n\t\tassert.ok(rendered.includes(\"ctrl+o to expand\"));\n\t});\n\n\tit(\"does not show expand hint when no pending tools\", () => {\n\t\tconst summary = new ToolSummaryLine();\n\t\tsummary.setExpandHint(\"(ctrl+o to expand)\");\n\t\tsummary.addTool(\"read\", 300);\n\n\t\tconst rendered = stripAnsi(summary.render(160).join(\"\\n\"));\n\t\tassert.ok(!rendered.includes(\"ctrl+o to expand\"));\n\t});\n\n\tit(\"updates label when pending tool args change\", () => {\n\t\tconst summary = new ToolSummaryLine();\n\t\tsummary.addPendingTool(\"t1\", \"read\", { path: \"old.ts\" });\n\n\t\tlet rendered = stripAnsi(summary.render(160).join(\"\\n\"));\n\t\tassert.ok(rendered.includes(\"old.ts\"));\n\n\t\tsummary.updatePendingToolArgs(\"t1\", { path: \"new.ts\" });\n\t\trendered = stripAnsi(summary.render(160).join(\"\\n\"));\n\t\tassert.ok(rendered.includes(\"new.ts\"));\n\t});\n\n\tit(\"clears pending spinner without removing last label\", () => {\n\t\tconst summary = new ToolSummaryLine();\n\t\tsummary.addPendingTool(\"t1\", \"read\", { path: \"file.ts\" });\n\n\t\tsummary.clearPendingTools();\n\n\t\tconst rendered = stripAnsi(summary.render(160).join(\"\\n\"));\n\t\tassert.ok(!rendered.includes(\"◯\"));\n\t\tassert.ok(!rendered.includes(\"◔\"));\n\t\tassert.ok(!rendered.includes(\"◑\"));\n\t\tassert.ok(!rendered.includes(\"◕\"));\n\t\tassert.ok(!rendered.includes(\"● Listing\"));\n\t\tassert.ok(!rendered.includes(\"…\"));\n\t\tassert.ok(rendered === \"\" || rendered.includes(\"file.ts\"));\n\t});\n\n\tit(\"canGroupWith considers pending tools\", () => {\n\t\tconst summary = new ToolSummaryLine();\n\t\tsummary.addPendingTool(\"t1\", \"read\", { path: \"a.ts\" });\n\n\t\tassert.equal(summary.canGroupWith(\"read\"), true);\n\t\tassert.equal(summary.canGroupWith(\"grep\"), true);\n\t\tassert.equal(summary.canGroupWith(\"bash\"), false);\n\t});\n});\n\ndescribe(\"extractToolLabel\", () => {\n\tit(\"extracts basename for read tool\", () => {\n\t\tassert.equal(extractToolLabel(\"read\", { path: \"src/foo/bar.ts\" }), \"bar.ts\");\n\t\tassert.equal(extractToolLabel(\"read\", { file_path: \"/abs/path/file.json\" }), \"file.json\");\n\t\tassert.equal(extractToolLabel(\"read\", {}), \"read\");\n\t});\n\n\tit(\"extracts pattern for grep tool\", () => {\n\t\tassert.equal(extractToolLabel(\"grep\", { pattern: \"TODO\" }), \"TODO\");\n\t\tassert.equal(extractToolLabel(\"grep\", {}), \"grep\");\n\t});\n\n\tit(\"extracts pattern for find tool\", () => {\n\t\tassert.equal(extractToolLabel(\"find\", { pattern: \"*.ts\" }), \"*.ts\");\n\t\tassert.equal(extractToolLabel(\"find\", {}), \"find\");\n\t});\n\n\tit(\"extracts path for ls tool\", () => {\n\t\tassert.equal(extractToolLabel(\"ls\", { path: \"src/components\" }), \"components\");\n\t\tassert.equal(extractToolLabel(\"ls\", {}), \".\");\n\t});\n\n\tit(\"extracts symbol or file for lsp tool\", () => {\n\t\tassert.equal(extractToolLabel(\"lsp\", { symbol: \"MyClass\" }), \"MyClass\");\n\t\tassert.equal(extractToolLabel(\"lsp\", { file: \"src/index.ts\" }), \"index.ts\");\n\t\tassert.equal(extractToolLabel(\"lsp\", { symbol: \"foo\", file: \"bar.ts\" }), \"foo\");\n\t\tassert.equal(extractToolLabel(\"lsp\", {}), \"lsp\");\n\t});\n\n\tit(\"returns tool name for unknown tools\", () => {\n\t\tassert.equal(extractToolLabel(\"custom_tool\", { whatever: \"value\" }), \"custom_tool\");\n\t});\n});\n"]}
|
|
@@ -1,8 +1,30 @@
|
|
|
1
1
|
import type { AssistantMessage } from "@gsd/pi-ai";
|
|
2
|
-
import {
|
|
2
|
+
import type { Component } from "@gsd/pi-tui";
|
|
3
|
+
import { Container, Markdown, type MarkdownTheme, Text } from "@gsd/pi-tui";
|
|
3
4
|
import { type TimestampFormat } from "./timestamp.js";
|
|
4
5
|
/**
|
|
5
|
-
*
|
|
6
|
+
* Create a Markdown component for an assistant text block.
|
|
7
|
+
* @param text - Text content (should be trimmed by caller)
|
|
8
|
+
* @param withMarker - Whether to prefix with the response marker
|
|
9
|
+
* @param markdownTheme - Markdown theme
|
|
10
|
+
*/
|
|
11
|
+
export declare function createTextMarkdown(text: string, withMarker: boolean, markdownTheme: MarkdownTheme): Markdown;
|
|
12
|
+
/**
|
|
13
|
+
* Create a Markdown component for a thinking block.
|
|
14
|
+
*/
|
|
15
|
+
export declare function createThinkingMarkdown(thinking: string, markdownTheme: MarkdownTheme): Markdown;
|
|
16
|
+
/**
|
|
17
|
+
* Create an error/abort Text component.
|
|
18
|
+
*/
|
|
19
|
+
export declare function createErrorText(message: string): Text;
|
|
20
|
+
/**
|
|
21
|
+
* Component that renders a complete assistant message.
|
|
22
|
+
*
|
|
23
|
+
* Supports two rendering modes:
|
|
24
|
+
* 1. Legacy: `updateContent(message)` renders all text/thinking into a contentContainer.
|
|
25
|
+
* Tool rows are expected to be added as siblings in the parent container.
|
|
26
|
+
* 2. Interleaved: `updateContentOrdered(message, toolComponents)` renders text/thinking
|
|
27
|
+
* AND tool components in content order. Tool components become children of this container.
|
|
6
28
|
*/
|
|
7
29
|
export declare class AssistantMessageComponent extends Container {
|
|
8
30
|
private contentContainer;
|
|
@@ -15,6 +37,21 @@ export declare class AssistantMessageComponent extends Container {
|
|
|
15
37
|
invalidate(): void;
|
|
16
38
|
setHideThinkingBlock(hide: boolean): void;
|
|
17
39
|
setThinkingLevel(level: string): void;
|
|
40
|
+
/**
|
|
41
|
+
* Legacy rendering: renders text/thinking blocks into contentContainer.
|
|
42
|
+
* Stops rendering at the first tool-type block (toolCall/serverToolUse).
|
|
43
|
+
* Post-tool text blocks are handled by the chat-controller to preserve
|
|
44
|
+
* content ordering relative to tool rows.
|
|
45
|
+
*/
|
|
18
46
|
updateContent(message: AssistantMessage): void;
|
|
47
|
+
/**
|
|
48
|
+
* Interleaved rendering: renders text/thinking AND tool components in content order.
|
|
49
|
+
* Tool components become children of this container, preserving visual ordering.
|
|
50
|
+
*
|
|
51
|
+
* @param message - The assistant message
|
|
52
|
+
* @param toolComponents - Map of content block ID → pre-created Component (ToolExecutionComponent etc.)
|
|
53
|
+
* @returns Map of content block ID → the tool Component that was placed (for pending tool tracking)
|
|
54
|
+
*/
|
|
55
|
+
updateContentOrdered(message: AssistantMessage, toolComponents?: Map<string, Component>): Map<string, Component>;
|
|
19
56
|
}
|
|
20
57
|
//# sourceMappingURL=assistant-message.d.ts.map
|
package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assistant-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"assistant-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAU,IAAI,EAAE,MAAM,aAAa,CAAC;AAEpF,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAUvE;;;;;GAKG;AACH,wBAAgB,kBAAkB,CACjC,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,OAAO,EACnB,aAAa,EAAE,aAAa,GAC1B,QAAQ,CAGV;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACrC,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,aAAa,GAC1B,QAAQ,CAKV;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAErD;AAED;;;;;;;;GAQG;AACH,qBAAa,yBAA0B,SAAQ,SAAS;IACvD,OAAO,CAAC,gBAAgB,CAAY;IACpC,OAAO,CAAC,iBAAiB,CAAU;IACnC,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,WAAW,CAAC,CAAmB;IACvC,OAAO,CAAC,eAAe,CAAkB;gBAGxC,OAAO,CAAC,EAAE,gBAAgB,EAC1B,iBAAiB,UAAQ,EACzB,aAAa,GAAE,aAAkC,EACjD,eAAe,GAAE,eAAiC,EAClD,aAAa,SAAQ;IAkBb,UAAU,IAAI,IAAI;IAO3B,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAIzC,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIrC;;;;;OAKG;IACH,aAAa,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;IA8E9C;;;;;;;OAOG;IACH,oBAAoB,CACnB,OAAO,EAAE,gBAAgB,EACzB,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,GACrC,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC;CA+EzB"}
|
|
@@ -1,7 +1,45 @@
|
|
|
1
1
|
import { Container, Markdown, Spacer, Text } from "@gsd/pi-tui";
|
|
2
2
|
import { getMarkdownTheme, theme } from "../theme/theme.js";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Create the response marker prefixed to the first visible text block.
|
|
5
|
+
* Lazy to avoid calling theme.fg() at module load time (fails in tests).
|
|
6
|
+
*/
|
|
7
|
+
function getResponseMarker() {
|
|
8
|
+
return `${theme.fg("accent", "●")} `;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Create a Markdown component for an assistant text block.
|
|
12
|
+
* @param text - Text content (should be trimmed by caller)
|
|
13
|
+
* @param withMarker - Whether to prefix with the response marker
|
|
14
|
+
* @param markdownTheme - Markdown theme
|
|
15
|
+
*/
|
|
16
|
+
export function createTextMarkdown(text, withMarker, markdownTheme) {
|
|
17
|
+
const withMarker_ = withMarker ? `${getResponseMarker()}${text}` : text;
|
|
18
|
+
return new Markdown(withMarker_, 1, 0, markdownTheme);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Create a Markdown component for a thinking block.
|
|
22
|
+
*/
|
|
23
|
+
export function createThinkingMarkdown(thinking, markdownTheme) {
|
|
24
|
+
return new Markdown(thinking.trim(), 1, 0, markdownTheme, {
|
|
25
|
+
color: (text) => theme.fg("thinkingText", text),
|
|
26
|
+
italic: true,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Create an error/abort Text component.
|
|
31
|
+
*/
|
|
32
|
+
export function createErrorText(message) {
|
|
33
|
+
return new Text(theme.fg("error", message), 1, 0);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Component that renders a complete assistant message.
|
|
37
|
+
*
|
|
38
|
+
* Supports two rendering modes:
|
|
39
|
+
* 1. Legacy: `updateContent(message)` renders all text/thinking into a contentContainer.
|
|
40
|
+
* Tool rows are expected to be added as siblings in the parent container.
|
|
41
|
+
* 2. Interleaved: `updateContentOrdered(message, toolComponents)` renders text/thinking
|
|
42
|
+
* AND tool components in content order. Tool components become children of this container.
|
|
5
43
|
*/
|
|
6
44
|
export class AssistantMessageComponent extends Container {
|
|
7
45
|
constructor(message, hideThinkingBlock = false, markdownTheme = getMarkdownTheme(), timestampFormat = "date-time-iso", thinkingLevel = "off") {
|
|
@@ -29,6 +67,12 @@ export class AssistantMessageComponent extends Container {
|
|
|
29
67
|
setThinkingLevel(level) {
|
|
30
68
|
this.thinkingLevel = level;
|
|
31
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Legacy rendering: renders text/thinking blocks into contentContainer.
|
|
72
|
+
* Stops rendering at the first tool-type block (toolCall/serverToolUse).
|
|
73
|
+
* Post-tool text blocks are handled by the chat-controller to preserve
|
|
74
|
+
* content ordering relative to tool rows.
|
|
75
|
+
*/
|
|
32
76
|
updateContent(message) {
|
|
33
77
|
this.lastMessage = message;
|
|
34
78
|
// Clear content container
|
|
@@ -43,26 +87,26 @@ export class AssistantMessageComponent extends Container {
|
|
|
43
87
|
if (hasVisibleContent) {
|
|
44
88
|
this.contentContainer.addChild(new Spacer(1));
|
|
45
89
|
}
|
|
46
|
-
// Render content
|
|
90
|
+
// Render content blocks up to (but not including) the first tool block.
|
|
91
|
+
// Text blocks after tools are rendered by the chat-controller as separate
|
|
92
|
+
// components to maintain correct visual ordering with tool rows.
|
|
47
93
|
let markerAdded = false;
|
|
48
|
-
const responseMarker = `${theme.fg("accent", "●")} `;
|
|
49
94
|
for (let i = 0; i < message.content.length; i++) {
|
|
50
95
|
const content = message.content[i];
|
|
96
|
+
// Stop at the first tool-type block — post-tool content is handled externally
|
|
97
|
+
if (content.type === "toolCall" || content.type === "serverToolUse") {
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
51
100
|
if (content.type === "text" && content.text.trim()) {
|
|
52
|
-
// Assistant text messages with no background - trim the text
|
|
53
|
-
// Set paddingY=0 to avoid extra spacing before tool executions
|
|
54
101
|
const text = content.text.trim();
|
|
55
|
-
const withMarker = markerAdded ? text : `${
|
|
102
|
+
const withMarker = markerAdded ? text : `${getResponseMarker()}${text}`;
|
|
56
103
|
this.contentContainer.addChild(new Markdown(withMarker, 1, 0, this.markdownTheme));
|
|
57
104
|
markerAdded = true;
|
|
58
105
|
}
|
|
59
106
|
else if (content.type === "thinking" && content.thinking.trim()) {
|
|
60
107
|
if (this.hideThinkingBlock) {
|
|
61
|
-
// Hide thinking content entirely when hide-thinking is enabled.
|
|
62
108
|
continue;
|
|
63
109
|
}
|
|
64
|
-
// Add spacing only when another visible assistant content block follows.
|
|
65
|
-
// This avoids a superfluous blank line before separately-rendered tool execution blocks.
|
|
66
110
|
const hasVisibleContentAfter = message.content.slice(i + 1).some((c) => {
|
|
67
111
|
if (c.type === "text")
|
|
68
112
|
return Boolean(c.text.trim());
|
|
@@ -70,7 +114,6 @@ export class AssistantMessageComponent extends Container {
|
|
|
70
114
|
return !this.hideThinkingBlock && Boolean(c.thinking.trim());
|
|
71
115
|
return false;
|
|
72
116
|
});
|
|
73
|
-
// Thinking traces in thinkingText color, italic
|
|
74
117
|
this.contentContainer.addChild(new Markdown(content.thinking.trim(), 1, 0, this.markdownTheme, {
|
|
75
118
|
color: (text) => theme.fg("thinkingText", text),
|
|
76
119
|
italic: true,
|
|
@@ -81,8 +124,7 @@ export class AssistantMessageComponent extends Container {
|
|
|
81
124
|
}
|
|
82
125
|
}
|
|
83
126
|
// Check if aborted - show after partial content
|
|
84
|
-
|
|
85
|
-
const hasToolCalls = message.content.some((c) => c.type === "toolCall");
|
|
127
|
+
const hasToolCalls = message.content.some((c) => c.type === "toolCall" || c.type === "serverToolUse");
|
|
86
128
|
if (!hasToolCalls) {
|
|
87
129
|
if (message.stopReason === "aborted") {
|
|
88
130
|
const abortMessage = message.errorMessage && message.errorMessage !== "Request was aborted"
|
|
@@ -102,12 +144,87 @@ export class AssistantMessageComponent extends Container {
|
|
|
102
144
|
this.contentContainer.addChild(new Text(theme.fg("error", `Error: ${errorMsg}`), 1, 0));
|
|
103
145
|
}
|
|
104
146
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Interleaved rendering: renders text/thinking AND tool components in content order.
|
|
150
|
+
* Tool components become children of this container, preserving visual ordering.
|
|
151
|
+
*
|
|
152
|
+
* @param message - The assistant message
|
|
153
|
+
* @param toolComponents - Map of content block ID → pre-created Component (ToolExecutionComponent etc.)
|
|
154
|
+
* @returns Map of content block ID → the tool Component that was placed (for pending tool tracking)
|
|
155
|
+
*/
|
|
156
|
+
updateContentOrdered(message, toolComponents) {
|
|
157
|
+
this.lastMessage = message;
|
|
158
|
+
// Clear contentContainer so we can re-render all blocks in order
|
|
159
|
+
this.contentContainer.clear();
|
|
160
|
+
const placedTools = new Map();
|
|
161
|
+
// Check if there's any visible content at all
|
|
162
|
+
const hasVisibleContent = message.content.some((c) => {
|
|
163
|
+
if (c.type === "text")
|
|
164
|
+
return Boolean(c.text.trim());
|
|
165
|
+
if (c.type === "thinking")
|
|
166
|
+
return !this.hideThinkingBlock && Boolean(c.thinking.trim());
|
|
167
|
+
return false;
|
|
168
|
+
});
|
|
169
|
+
if (hasVisibleContent) {
|
|
170
|
+
this.contentContainer.addChild(new Spacer(1));
|
|
171
|
+
}
|
|
172
|
+
// Render all content blocks in order
|
|
173
|
+
let markerAdded = false;
|
|
174
|
+
for (let i = 0; i < message.content.length; i++) {
|
|
175
|
+
const block = message.content[i];
|
|
176
|
+
if (block.type === "text" && block.text.trim()) {
|
|
177
|
+
const text = block.text.trim();
|
|
178
|
+
const withMarker = markerAdded ? text : `${getResponseMarker()}${text}`;
|
|
179
|
+
this.contentContainer.addChild(new Markdown(withMarker, 1, 0, this.markdownTheme));
|
|
180
|
+
markerAdded = true;
|
|
181
|
+
}
|
|
182
|
+
else if (block.type === "thinking" && block.thinking.trim()) {
|
|
183
|
+
if (this.hideThinkingBlock) {
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
// Add spacing only when another visible assistant content block follows.
|
|
187
|
+
const hasVisibleContentAfter = message.content.slice(i + 1).some((c) => {
|
|
188
|
+
if (c.type === "text")
|
|
189
|
+
return Boolean(c.text.trim());
|
|
190
|
+
if (c.type === "thinking")
|
|
191
|
+
return !this.hideThinkingBlock && Boolean(c.thinking.trim());
|
|
192
|
+
return false;
|
|
193
|
+
});
|
|
194
|
+
this.contentContainer.addChild(new Markdown(block.thinking.trim(), 1, 0, this.markdownTheme, {
|
|
195
|
+
color: (text) => theme.fg("thinkingText", text),
|
|
196
|
+
italic: true,
|
|
197
|
+
}));
|
|
198
|
+
if (hasVisibleContentAfter) {
|
|
199
|
+
this.contentContainer.addChild(new Spacer(1));
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
else if ((block.type === "toolCall" || block.type === "serverToolUse") && toolComponents?.has(block.id)) {
|
|
203
|
+
// Place the pre-created tool component in content order
|
|
204
|
+
const toolComponent = toolComponents.get(block.id);
|
|
205
|
+
this.contentContainer.addChild(toolComponent);
|
|
206
|
+
placedTools.set(block.id, toolComponent);
|
|
207
|
+
}
|
|
208
|
+
// webSearchResult blocks don't produce their own component;
|
|
209
|
+
// they update the matching serverToolUse component via updateResult()
|
|
210
|
+
}
|
|
211
|
+
// Handle abort/error after content (only if no tool calls)
|
|
212
|
+
const hasToolCalls = message.content.some((c) => c.type === "toolCall" || c.type === "serverToolUse");
|
|
213
|
+
if (!hasToolCalls) {
|
|
214
|
+
if (message.stopReason === "aborted") {
|
|
215
|
+
const abortMessage = message.errorMessage && message.errorMessage !== "Request was aborted"
|
|
216
|
+
? message.errorMessage
|
|
217
|
+
: "Operation aborted";
|
|
218
|
+
this.contentContainer.addChild(new Spacer(1));
|
|
219
|
+
this.contentContainer.addChild(new Text(theme.fg("error", abortMessage), 1, 0));
|
|
220
|
+
}
|
|
221
|
+
else if (message.stopReason === "error") {
|
|
222
|
+
const errorMsg = message.errorMessage || "Unknown error";
|
|
223
|
+
this.contentContainer.addChild(new Spacer(1));
|
|
224
|
+
this.contentContainer.addChild(new Text(theme.fg("error", `Error: ${errorMsg}`), 1, 0));
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return placedTools;
|
|
111
228
|
}
|
|
112
229
|
}
|
|
113
230
|
//# sourceMappingURL=assistant-message.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assistant-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-message.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AssistantMessage } from \"@gsd/pi-ai\";\nimport { Container, Markdown, type MarkdownTheme, Spacer, Text } from \"@gsd/pi-tui\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.js\";\nimport { formatTimestamp, type TimestampFormat } from \"./timestamp.js\";\n\n/**\n * Component that renders a complete assistant message\n */\nexport class AssistantMessageComponent extends Container {\n\tprivate contentContainer: Container;\n\tprivate hideThinkingBlock: boolean;\n\tprivate thinkingLevel: string;\n\tprivate markdownTheme: MarkdownTheme;\n\tprivate lastMessage?: AssistantMessage;\n\tprivate timestampFormat: TimestampFormat;\n\n\tconstructor(\n\t\tmessage?: AssistantMessage,\n\t\thideThinkingBlock = false,\n\t\tmarkdownTheme: MarkdownTheme = getMarkdownTheme(),\n\t\ttimestampFormat: TimestampFormat = \"date-time-iso\",\n\t\tthinkingLevel = \"off\",\n\t) {\n\t\tsuper();\n\n\t\tthis.hideThinkingBlock = hideThinkingBlock;\n\t\tthis.thinkingLevel = thinkingLevel;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.timestampFormat = timestampFormat;\n\n\t\t// Container for text/thinking content\n\t\tthis.contentContainer = new Container();\n\t\tthis.addChild(this.contentContainer);\n\n\t\tif (message) {\n\t\t\tthis.updateContent(message);\n\t\t}\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tthis.hideThinkingBlock = hide;\n\t}\n\n\tsetThinkingLevel(level: string): void {\n\t\tthis.thinkingLevel = level;\n\t}\n\n\tupdateContent(message: AssistantMessage): void {\n\t\tthis.lastMessage = message;\n\n\t\t// Clear content container\n\t\tthis.contentContainer.clear();\n\n\t\tconst hasVisibleContent = message.content.some((c) => {\n\t\t\tif (c.type === \"text\") return Boolean(c.text.trim());\n\t\t\tif (c.type === \"thinking\") return !this.hideThinkingBlock && Boolean(c.thinking.trim());\n\t\t\treturn false;\n\t\t});\n\n\t\tif (hasVisibleContent) {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t}\n\n\t\t// Render content in order\n\t\tlet markerAdded = false;\n\t\tconst responseMarker = `${theme.fg(\"accent\", \"●\")} `;\n\t\tfor (let i = 0; i < message.content.length; i++) {\n\t\t\tconst content = message.content[i];\n\t\t\tif (content.type === \"text\" && content.text.trim()) {\n\t\t\t\t// Assistant text messages with no background - trim the text\n\t\t\t\t// Set paddingY=0 to avoid extra spacing before tool executions\n\t\t\t\tconst text = content.text.trim();\n\t\t\t\tconst withMarker = markerAdded ? text : `${responseMarker}${text}`;\n\t\t\t\tthis.contentContainer.addChild(new Markdown(withMarker, 1, 0, this.markdownTheme));\n\t\t\t\tmarkerAdded = true;\n\t\t\t} else if (content.type === \"thinking\" && content.thinking.trim()) {\n\t\t\t\tif (this.hideThinkingBlock) {\n\t\t\t\t\t// Hide thinking content entirely when hide-thinking is enabled.\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Add spacing only when another visible assistant content block follows.\n\t\t\t\t// This avoids a superfluous blank line before separately-rendered tool execution blocks.\n\t\t\t\tconst hasVisibleContentAfter = message.content.slice(i + 1).some((c) => {\n\t\t\t\t\tif (c.type === \"text\") return Boolean(c.text.trim());\n\t\t\t\t\tif (c.type === \"thinking\") return !this.hideThinkingBlock && Boolean(c.thinking.trim());\n\t\t\t\t\treturn false;\n\t\t\t\t});\n\n\t\t\t\t// Thinking traces in thinkingText color, italic\n\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\tnew Markdown(content.thinking.trim(), 1, 0, this.markdownTheme, {\n\t\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\t\titalic: true,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check if aborted - show after partial content\n\t\t// But only if there are no tool calls (tool execution components will show the error)\n\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t\tif (!hasToolCalls) {\n\t\t\tif (message.stopReason === \"aborted\") {\n\t\t\t\tconst abortMessage =\n\t\t\t\t\tmessage.errorMessage && message.errorMessage !== \"Request was aborted\"\n\t\t\t\t\t\t? message.errorMessage\n\t\t\t\t\t\t: \"Operation aborted\";\n\t\t\t\tif (hasVisibleContent) {\n\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t} else {\n\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t}\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", abortMessage), 1, 0));\n\t\t\t} else if (message.stopReason === \"error\") {\n\t\t\t\tconst errorMsg = message.errorMessage || \"Unknown error\";\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", `Error: ${errorMsg}`), 1, 0));\n\t\t\t}\n\t\t}\n\n\t\t// Timestamp display removed\n\t\t// Show timestamp when the message is complete (has a stop reason)\n\t\t// if (message.stopReason && message.timestamp) {\n\t\t// \tconst timeStr = formatTimestamp(message.timestamp, this.timestampFormat);\n\t\t// \tthis.contentContainer.addChild(new Text(theme.fg(\"dim\", timeStr), 1, 0));\n\t\t// }\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"assistant-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-message.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AssistantMessage } from \"@gsd/pi-ai\";\nimport type { Component } from \"@gsd/pi-tui\";\nimport { Container, Markdown, type MarkdownTheme, Spacer, Text } from \"@gsd/pi-tui\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.js\";\nimport { formatTimestamp, type TimestampFormat } from \"./timestamp.js\";\n\n/**\n * Create the response marker prefixed to the first visible text block.\n * Lazy to avoid calling theme.fg() at module load time (fails in tests).\n */\nfunction getResponseMarker(): string {\n\treturn `${theme.fg(\"accent\", \"●\")} `;\n}\n\n/**\n * Create a Markdown component for an assistant text block.\n * @param text - Text content (should be trimmed by caller)\n * @param withMarker - Whether to prefix with the response marker\n * @param markdownTheme - Markdown theme\n */\nexport function createTextMarkdown(\n\ttext: string,\n\twithMarker: boolean,\n\tmarkdownTheme: MarkdownTheme,\n): Markdown {\n\tconst withMarker_ = withMarker ? `${getResponseMarker()}${text}` : text;\n\treturn new Markdown(withMarker_, 1, 0, markdownTheme);\n}\n\n/**\n * Create a Markdown component for a thinking block.\n */\nexport function createThinkingMarkdown(\n\tthinking: string,\n\tmarkdownTheme: MarkdownTheme,\n): Markdown {\n\treturn new Markdown(thinking.trim(), 1, 0, markdownTheme, {\n\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\titalic: true,\n\t});\n}\n\n/**\n * Create an error/abort Text component.\n */\nexport function createErrorText(message: string): Text {\n\treturn new Text(theme.fg(\"error\", message), 1, 0);\n}\n\n/**\n * Component that renders a complete assistant message.\n *\n * Supports two rendering modes:\n * 1. Legacy: `updateContent(message)` renders all text/thinking into a contentContainer.\n * Tool rows are expected to be added as siblings in the parent container.\n * 2. Interleaved: `updateContentOrdered(message, toolComponents)` renders text/thinking\n * AND tool components in content order. Tool components become children of this container.\n */\nexport class AssistantMessageComponent extends Container {\n\tprivate contentContainer: Container;\n\tprivate hideThinkingBlock: boolean;\n\tprivate thinkingLevel: string;\n\tprivate markdownTheme: MarkdownTheme;\n\tprivate lastMessage?: AssistantMessage;\n\tprivate timestampFormat: TimestampFormat;\n\n\tconstructor(\n\t\tmessage?: AssistantMessage,\n\t\thideThinkingBlock = false,\n\t\tmarkdownTheme: MarkdownTheme = getMarkdownTheme(),\n\t\ttimestampFormat: TimestampFormat = \"date-time-iso\",\n\t\tthinkingLevel = \"off\",\n\t) {\n\t\tsuper();\n\n\t\tthis.hideThinkingBlock = hideThinkingBlock;\n\t\tthis.thinkingLevel = thinkingLevel;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.timestampFormat = timestampFormat;\n\n\t\t// Container for text/thinking content\n\t\tthis.contentContainer = new Container();\n\t\tthis.addChild(this.contentContainer);\n\n\t\tif (message) {\n\t\t\tthis.updateContent(message);\n\t\t}\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tthis.hideThinkingBlock = hide;\n\t}\n\n\tsetThinkingLevel(level: string): void {\n\t\tthis.thinkingLevel = level;\n\t}\n\n\t/**\n\t * Legacy rendering: renders text/thinking blocks into contentContainer.\n\t * Stops rendering at the first tool-type block (toolCall/serverToolUse).\n\t * Post-tool text blocks are handled by the chat-controller to preserve\n\t * content ordering relative to tool rows.\n\t */\n\tupdateContent(message: AssistantMessage): void {\n\t\tthis.lastMessage = message;\n\n\t\t// Clear content container\n\t\tthis.contentContainer.clear();\n\n\t\tconst hasVisibleContent = message.content.some((c) => {\n\t\t\tif (c.type === \"text\") return Boolean(c.text.trim());\n\t\t\tif (c.type === \"thinking\") return !this.hideThinkingBlock && Boolean(c.thinking.trim());\n\t\t\treturn false;\n\t\t});\n\n\t\tif (hasVisibleContent) {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t}\n\n\t\t// Render content blocks up to (but not including) the first tool block.\n\t\t// Text blocks after tools are rendered by the chat-controller as separate\n\t\t// components to maintain correct visual ordering with tool rows.\n\t\tlet markerAdded = false;\n\t\tfor (let i = 0; i < message.content.length; i++) {\n\t\t\tconst content = message.content[i];\n\n\t\t\t// Stop at the first tool-type block — post-tool content is handled externally\n\t\t\tif (content.type === \"toolCall\" || content.type === \"serverToolUse\") {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (content.type === \"text\" && content.text.trim()) {\n\t\t\t\tconst text = content.text.trim();\n\t\t\t\tconst withMarker = markerAdded ? text : `${getResponseMarker()}${text}`;\n\t\t\t\tthis.contentContainer.addChild(new Markdown(withMarker, 1, 0, this.markdownTheme));\n\t\t\t\tmarkerAdded = true;\n\t\t\t} else if (content.type === \"thinking\" && content.thinking.trim()) {\n\t\t\t\tif (this.hideThinkingBlock) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst hasVisibleContentAfter = message.content.slice(i + 1).some((c) => {\n\t\t\t\t\tif (c.type === \"text\") return Boolean(c.text.trim());\n\t\t\t\t\tif (c.type === \"thinking\") return !this.hideThinkingBlock && Boolean(c.thinking.trim());\n\t\t\t\t\treturn false;\n\t\t\t\t});\n\n\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\tnew Markdown(content.thinking.trim(), 1, 0, this.markdownTheme, {\n\t\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\t\titalic: true,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check if aborted - show after partial content\n\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\" || c.type === \"serverToolUse\");\n\t\tif (!hasToolCalls) {\n\t\t\tif (message.stopReason === \"aborted\") {\n\t\t\t\tconst abortMessage =\n\t\t\t\t\tmessage.errorMessage && message.errorMessage !== \"Request was aborted\"\n\t\t\t\t\t\t? message.errorMessage\n\t\t\t\t\t\t: \"Operation aborted\";\n\t\t\t\tif (hasVisibleContent) {\n\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t} else {\n\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t}\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", abortMessage), 1, 0));\n\t\t\t} else if (message.stopReason === \"error\") {\n\t\t\t\tconst errorMsg = message.errorMessage || \"Unknown error\";\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", `Error: ${errorMsg}`), 1, 0));\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Interleaved rendering: renders text/thinking AND tool components in content order.\n\t * Tool components become children of this container, preserving visual ordering.\n\t *\n\t * @param message - The assistant message\n\t * @param toolComponents - Map of content block ID → pre-created Component (ToolExecutionComponent etc.)\n\t * @returns Map of content block ID → the tool Component that was placed (for pending tool tracking)\n\t */\n\tupdateContentOrdered(\n\t\tmessage: AssistantMessage,\n\t\ttoolComponents?: Map<string, Component>,\n\t): Map<string, Component> {\n\t\tthis.lastMessage = message;\n\n\t\t// Clear contentContainer so we can re-render all blocks in order\n\t\tthis.contentContainer.clear();\n\n\t\tconst placedTools = new Map<string, Component>();\n\n\t\t// Check if there's any visible content at all\n\t\tconst hasVisibleContent = message.content.some((c) => {\n\t\t\tif (c.type === \"text\") return Boolean(c.text.trim());\n\t\t\tif (c.type === \"thinking\") return !this.hideThinkingBlock && Boolean(c.thinking.trim());\n\t\t\treturn false;\n\t\t});\n\n\t\tif (hasVisibleContent) {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t}\n\n\t\t// Render all content blocks in order\n\t\tlet markerAdded = false;\n\t\tfor (let i = 0; i < message.content.length; i++) {\n\t\t\tconst block = message.content[i];\n\n\t\t\tif (block.type === \"text\" && block.text.trim()) {\n\t\t\t\tconst text = block.text.trim();\n\t\t\t\tconst withMarker = markerAdded ? text : `${getResponseMarker()}${text}`;\n\t\t\t\tthis.contentContainer.addChild(new Markdown(withMarker, 1, 0, this.markdownTheme));\n\t\t\t\tmarkerAdded = true;\n\t\t\t} else if (block.type === \"thinking\" && block.thinking.trim()) {\n\t\t\t\tif (this.hideThinkingBlock) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Add spacing only when another visible assistant content block follows.\n\t\t\t\tconst hasVisibleContentAfter = message.content.slice(i + 1).some((c) => {\n\t\t\t\t\tif (c.type === \"text\") return Boolean(c.text.trim());\n\t\t\t\t\tif (c.type === \"thinking\") return !this.hideThinkingBlock && Boolean(c.thinking.trim());\n\t\t\t\t\treturn false;\n\t\t\t\t});\n\n\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\tnew Markdown(block.thinking.trim(), 1, 0, this.markdownTheme, {\n\t\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\t\titalic: true,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t}\n\t\t\t} else if ((block.type === \"toolCall\" || block.type === \"serverToolUse\") && toolComponents?.has(block.id)) {\n\t\t\t\t// Place the pre-created tool component in content order\n\t\t\t\tconst toolComponent = toolComponents.get(block.id)!;\n\t\t\t\tthis.contentContainer.addChild(toolComponent);\n\t\t\t\tplacedTools.set(block.id, toolComponent);\n\t\t\t}\n\t\t\t// webSearchResult blocks don't produce their own component;\n\t\t\t// they update the matching serverToolUse component via updateResult()\n\t\t}\n\n\t\t// Handle abort/error after content (only if no tool calls)\n\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\" || c.type === \"serverToolUse\");\n\t\tif (!hasToolCalls) {\n\t\t\tif (message.stopReason === \"aborted\") {\n\t\t\t\tconst abortMessage =\n\t\t\t\t\tmessage.errorMessage && message.errorMessage !== \"Request was aborted\"\n\t\t\t\t\t\t? message.errorMessage\n\t\t\t\t\t\t: \"Operation aborted\";\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", abortMessage), 1, 0));\n\t\t\t} else if (message.stopReason === \"error\") {\n\t\t\t\tconst errorMsg = message.errorMessage || \"Unknown error\";\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", `Error: ${errorMsg}`), 1, 0));\n\t\t\t}\n\t\t}\n\n\t\treturn placedTools;\n\t}\n}\n"]}
|
|
@@ -33,6 +33,7 @@ export declare class ToolExecutionComponent extends Container {
|
|
|
33
33
|
private writeHighlightCache?;
|
|
34
34
|
private hideComponent;
|
|
35
35
|
private manuallyHidden;
|
|
36
|
+
private indented;
|
|
36
37
|
private startTime;
|
|
37
38
|
private spinnerTimer;
|
|
38
39
|
private spinnerFrame;
|
|
@@ -82,6 +83,7 @@ export declare class ToolExecutionComponent extends Container {
|
|
|
82
83
|
private maybeConvertImagesForKitty;
|
|
83
84
|
setExpanded(expanded: boolean): void;
|
|
84
85
|
setHidden(hidden: boolean): void;
|
|
86
|
+
setIndented(indented: boolean): void;
|
|
85
87
|
isHidden(): boolean;
|
|
86
88
|
getElapsed(): number;
|
|
87
89
|
shouldHideWhenCollapsed(collapseToolCalls?: boolean): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-execution.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tool-execution.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"tool-execution.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tool-execution.ts"],"names":[],"mappings":"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"}
|
|
@@ -82,6 +82,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
82
82
|
// When true, this component intentionally renders no lines
|
|
83
83
|
this.hideComponent = false;
|
|
84
84
|
this.manuallyHidden = false;
|
|
85
|
+
this.indented = false;
|
|
85
86
|
this.startTime = Date.now();
|
|
86
87
|
// Tool status spinner state
|
|
87
88
|
this.spinnerTimer = null;
|
|
@@ -356,6 +357,10 @@ export class ToolExecutionComponent extends Container {
|
|
|
356
357
|
this.manuallyHidden = hidden;
|
|
357
358
|
this.updateDisplay();
|
|
358
359
|
}
|
|
360
|
+
setIndented(indented) {
|
|
361
|
+
this.indented = indented;
|
|
362
|
+
this.updateDisplay();
|
|
363
|
+
}
|
|
359
364
|
isHidden() {
|
|
360
365
|
return this.hideComponent;
|
|
361
366
|
}
|
|
@@ -393,7 +398,18 @@ export class ToolExecutionComponent extends Container {
|
|
|
393
398
|
if (this.hideComponent) {
|
|
394
399
|
return [];
|
|
395
400
|
}
|
|
396
|
-
|
|
401
|
+
const lines = super.render(width);
|
|
402
|
+
if (this.indented) {
|
|
403
|
+
const gutter = theme.fg("dim", "│");
|
|
404
|
+
return lines.map((line, i) => {
|
|
405
|
+
if (i === lines.length - 1 && line === "") {
|
|
406
|
+
// Trailing empty spacer line → gutter only
|
|
407
|
+
return gutter;
|
|
408
|
+
}
|
|
409
|
+
return gutter + " " + theme.fg("dim", line);
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
return [...lines, ""];
|
|
397
413
|
}
|
|
398
414
|
updateDisplay() {
|
|
399
415
|
// Status indicator with circle
|