@astralyn/pi 0.87.5 → 0.87.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/dist/bundle/chunks/{chunk-EWLAVDVN.js → chunk-4W4Q2H6W.js} +55 -54
- package/dist/bundle/chunks/{chunk-APQ4ACY3.js → chunk-IORR2FW4.js} +1 -1
- package/dist/bundle/chunks/{virtual-modules-W3OGMIX7.js → virtual-modules-KUEIEAZN.js} +1 -1
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/core/agent-session.d.ts +8 -24
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +54 -109
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/background/session.d.ts +11 -7
- package/dist/core/background/session.d.ts.map +1 -1
- package/dist/core/background/session.js +42 -16
- package/dist/core/background/session.js.map +1 -1
- package/dist/core/context-snapshot.d.ts +17 -4
- package/dist/core/context-snapshot.d.ts.map +1 -1
- package/dist/core/context-snapshot.js +48 -50
- package/dist/core/context-snapshot.js.map +1 -1
- package/dist/core/extensions/distribution-api.d.ts +0 -7
- package/dist/core/extensions/distribution-api.d.ts.map +1 -1
- package/dist/core/extensions/distribution-api.js +6 -6
- package/dist/core/extensions/distribution-api.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +3 -2
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/types.d.ts +1 -5
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/keybindings.d.ts +10 -0
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +3 -0
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +59 -7
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/tools/bash.d.ts +1 -3
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +0 -1
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +0 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +0 -1
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +0 -1
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts +0 -7
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js +0 -11
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/renderers/bash.d.ts.map +1 -1
- package/dist/core/tools/renderers/bash.js +59 -5
- package/dist/core/tools/renderers/bash.js.map +1 -1
- package/dist/core/tools/renderers/edit.d.ts.map +1 -1
- package/dist/core/tools/renderers/edit.js +4 -22
- package/dist/core/tools/renderers/edit.js.map +1 -1
- package/dist/core/tools/renderers/find.d.ts.map +1 -1
- package/dist/core/tools/renderers/find.js +7 -6
- package/dist/core/tools/renderers/find.js.map +1 -1
- package/dist/core/tools/renderers/grep.d.ts.map +1 -1
- package/dist/core/tools/renderers/grep.js +8 -7
- package/dist/core/tools/renderers/grep.js.map +1 -1
- package/dist/core/tools/renderers/ls.d.ts.map +1 -1
- package/dist/core/tools/renderers/ls.js +3 -2
- package/dist/core/tools/renderers/ls.js.map +1 -1
- package/dist/core/tools/renderers/read.d.ts.map +1 -1
- package/dist/core/tools/renderers/read.js +7 -12
- package/dist/core/tools/renderers/read.js.map +1 -1
- package/dist/core/tools/renderers/write.d.ts.map +1 -1
- package/dist/core/tools/renderers/write.js +3 -2
- package/dist/core/tools/renderers/write.js.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts +2 -6
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js +0 -2
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/extensions/background/completion-render.d.ts.map +1 -1
- package/dist/extensions/background/completion-render.js +3 -4
- package/dist/extensions/background/completion-render.js.map +1 -1
- package/dist/extensions/background/constants.d.ts +2 -0
- package/dist/extensions/background/constants.d.ts.map +1 -1
- package/dist/extensions/background/constants.js +2 -0
- package/dist/extensions/background/constants.js.map +1 -1
- package/dist/extensions/background/index.d.ts.map +1 -1
- package/dist/extensions/background/index.js +31 -5
- package/dist/extensions/background/index.js.map +1 -1
- package/dist/extensions/question/detail-pane.d.ts +12 -0
- package/dist/extensions/question/detail-pane.d.ts.map +1 -0
- package/dist/extensions/question/detail-pane.js +42 -0
- package/dist/extensions/question/detail-pane.js.map +1 -0
- package/dist/extensions/question/dialog.d.ts.map +1 -1
- package/dist/extensions/question/dialog.js +175 -105
- package/dist/extensions/question/dialog.js.map +1 -1
- package/dist/extensions/question/option-window.d.ts +26 -0
- package/dist/extensions/question/option-window.d.ts.map +1 -0
- package/dist/extensions/question/option-window.js +53 -0
- package/dist/extensions/question/option-window.js.map +1 -0
- package/dist/extensions/question/render-cache.d.ts +4 -4
- package/dist/extensions/question/render-cache.d.ts.map +1 -1
- package/dist/extensions/question/render-cache.js +10 -11
- package/dist/extensions/question/render-cache.js.map +1 -1
- package/dist/extensions/todo/index.d.ts.map +1 -1
- package/dist/extensions/todo/index.js +12 -8
- package/dist/extensions/todo/index.js.map +1 -1
- package/dist/extensions/todo/view.d.ts +3 -3
- package/dist/extensions/todo/view.d.ts.map +1 -1
- package/dist/extensions/todo/view.js +7 -6
- package/dist/extensions/todo/view.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +1 -1
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +1 -1
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/status-marker.d.ts +2 -2
- package/dist/modes/interactive/components/status-marker.js +2 -2
- package/dist/modes/interactive/components/status-marker.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +7 -10
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +2 -3
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/interactive/tool-view/chat.d.ts +20 -0
- package/dist/modes/interactive/tool-view/chat.d.ts.map +1 -0
- package/dist/modes/interactive/tool-view/chat.js +46 -0
- package/dist/modes/interactive/tool-view/chat.js.map +1 -0
- package/dist/modes/interactive/tool-view/fallback.d.ts +14 -0
- package/dist/modes/interactive/tool-view/fallback.d.ts.map +1 -0
- package/dist/modes/interactive/tool-view/fallback.js +52 -0
- package/dist/modes/interactive/tool-view/fallback.js.map +1 -0
- package/dist/modes/interactive/tool-view/style.d.ts +63 -0
- package/dist/modes/interactive/tool-view/style.d.ts.map +1 -0
- package/dist/modes/interactive/tool-view/style.js +83 -0
- package/dist/modes/interactive/tool-view/style.js.map +1 -0
- package/dist/modes/interactive/{components → tool-view}/tool-execution.d.ts +17 -24
- package/dist/modes/interactive/tool-view/tool-execution.d.ts.map +1 -0
- package/dist/modes/interactive/{components → tool-view}/tool-execution.js +42 -116
- package/dist/modes/interactive/tool-view/tool-execution.js.map +1 -0
- package/docs/bundled/README.md +1 -1
- package/docs/bundled/extensions/background.md +1 -1
- package/docs/bundled/extensions/question.md +6 -5
- package/docs/bundled/tool-presentation.md +41 -31
- package/docs/extensions.md +1 -4
- package/docs/keybindings.md +11 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/dist/core/model-stream-options.d.ts +0 -6
- package/dist/core/model-stream-options.d.ts.map +0 -1
- package/dist/core/model-stream-options.js +0 -20
- package/dist/core/model-stream-options.js.map +0 -1
- package/dist/modes/interactive/components/tool-chrome.d.ts +0 -28
- package/dist/modes/interactive/components/tool-chrome.d.ts.map +0 -1
- package/dist/modes/interactive/components/tool-chrome.js +0 -84
- package/dist/modes/interactive/components/tool-chrome.js.map +0 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +0 -1
- package/dist/modes/interactive/components/tool-execution.js.map +0 -1
- package/dist/modes/interactive/components/tool-group.d.ts +0 -17
- package/dist/modes/interactive/components/tool-group.d.ts.map +0 -1
- package/dist/modes/interactive/components/tool-group.js +0 -78
- package/dist/modes/interactive/components/tool-group.js.map +0 -1
- package/dist/modes/interactive/tool-chat.d.ts +0 -21
- package/dist/modes/interactive/tool-chat.d.ts.map +0 -1
- package/dist/modes/interactive/tool-chat.js +0 -58
- package/dist/modes/interactive/tool-chat.js.map +0 -1
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The look of a tool block, defined in one place.
|
|
3
|
+
*
|
|
4
|
+
* A tool block is a marker line plus a rail:
|
|
5
|
+
*
|
|
6
|
+
* ● grep /useState/ in src marker: the tool's state
|
|
7
|
+
* │ src/a.tsx:12: useState() rail: everything that belongs to the same tool
|
|
8
|
+
*
|
|
9
|
+
* Consecutive tool blocks sit directly under each other; text keeps a blank line. Change the look
|
|
10
|
+
* by editing `toolStyle` or `FramedComponent`; nothing else in the transcript hard-codes it.
|
|
11
|
+
*/
|
|
12
|
+
import { type Component } from "@earendil-works/pi-tui";
|
|
13
|
+
import { type ThemeColor } from "../theme/theme.ts";
|
|
14
|
+
export type ToolStatus = "pending" | "success" | "error";
|
|
15
|
+
export interface ToolStyle {
|
|
16
|
+
marker: {
|
|
17
|
+
glyph: string;
|
|
18
|
+
color: Record<ToolStatus, ThemeColor>;
|
|
19
|
+
};
|
|
20
|
+
rail: {
|
|
21
|
+
glyph: string;
|
|
22
|
+
color: ThemeColor;
|
|
23
|
+
};
|
|
24
|
+
/** Blank lines above a tool block, by what precedes it. */
|
|
25
|
+
gap: {
|
|
26
|
+
afterTool: number;
|
|
27
|
+
afterOther: number;
|
|
28
|
+
};
|
|
29
|
+
collapsed: {
|
|
30
|
+
/**
|
|
31
|
+
* Tools whose successful result stays hidden until expanded. A failure always shows. The shell
|
|
32
|
+
* folds only the built-in result renderer, matched by identity, so list only tools whose
|
|
33
|
+
* renderers are module-level constants: `bash` and `powershell` build fresh ones and never match.
|
|
34
|
+
*/
|
|
35
|
+
headerOnly: ReadonlySet<string>;
|
|
36
|
+
/** Output tail kept for a tool that has no result renderer. */
|
|
37
|
+
fallbackLines: number;
|
|
38
|
+
};
|
|
39
|
+
/** Width budget for the argument summary a tool without a call renderer shows. */
|
|
40
|
+
fallbackArgsWidth: number;
|
|
41
|
+
}
|
|
42
|
+
export declare const toolStyle: ToolStyle;
|
|
43
|
+
export declare function toolStatus(state: {
|
|
44
|
+
isPartial: boolean;
|
|
45
|
+
isError: boolean;
|
|
46
|
+
}): ToolStatus;
|
|
47
|
+
export declare function toolMarkerColor(status: ToolStatus): ThemeColor;
|
|
48
|
+
/** Columns the marker or rail takes, including the space before the content. */
|
|
49
|
+
export declare function gutterWidth(): number;
|
|
50
|
+
/**
|
|
51
|
+
* Hangs a component's lines off the marker (header) or the rail (body). A header's first line
|
|
52
|
+
* carries the marker; every other line, and every body line, carries the rail, and a blank line
|
|
53
|
+
* keeps a bare rail so the block stays connected.
|
|
54
|
+
*/
|
|
55
|
+
export declare class FramedComponent implements Component {
|
|
56
|
+
private component;
|
|
57
|
+
private kind;
|
|
58
|
+
private markerColor;
|
|
59
|
+
constructor(component: Component, kind: "header" | "body", markerColor: () => ThemeColor);
|
|
60
|
+
render(width: number): string[];
|
|
61
|
+
invalidate(): void;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=style.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/tool-view/style.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,KAAK,SAAS,EAAgB,MAAM,wBAAwB,CAAC;AAEtE,OAAO,EAAE,KAAK,UAAU,EAAS,MAAM,mBAAmB,CAAC;AAE3D,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAEzD,MAAM,WAAW,SAAS;IACzB,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,UAAU,EAAE,UAAU,CAAC,CAAA;KAAE,CAAC;IACjE,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAC;IAC3C,2DAA2D;IAC3D,GAAG,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C,SAAS,EAAE;QACV;;;;WAIG;QACH,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;QAChC,+DAA+D;QAC/D,aAAa,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,kFAAkF;IAClF,iBAAiB,EAAE,MAAM,CAAC;CAC1B;AAED,eAAO,MAAM,SAAS,EAAE,SAMvB,CAAC;AAEF,wBAAgB,UAAU,CAAC,KAAK,EAAE;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG,UAAU,CAEtF;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CAE9D;AAMD,gFAAgF;AAChF,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAiBD;;;;GAIG;AACH,qBAAa,eAAgB,YAAW,SAAS;IAChD,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,IAAI,CAAoB;IAChC,OAAO,CAAC,WAAW,CAAmB;gBAE1B,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,EAAE,WAAW,EAAE,MAAM,UAAU;IAMxF,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAqB/B,UAAU,IAAI,IAAI;CAGlB"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The look of a tool block, defined in one place.
|
|
3
|
+
*
|
|
4
|
+
* A tool block is a marker line plus a rail:
|
|
5
|
+
*
|
|
6
|
+
* ● grep /useState/ in src marker: the tool's state
|
|
7
|
+
* │ src/a.tsx:12: useState() rail: everything that belongs to the same tool
|
|
8
|
+
*
|
|
9
|
+
* Consecutive tool blocks sit directly under each other; text keeps a blank line. Change the look
|
|
10
|
+
* by editing `toolStyle` or `FramedComponent`; nothing else in the transcript hard-codes it.
|
|
11
|
+
*/
|
|
12
|
+
import { visibleWidth } from "@earendil-works/pi-tui";
|
|
13
|
+
import { stripAnsi } from "../../../utils/ansi.js";
|
|
14
|
+
import { theme } from "../theme/theme.js";
|
|
15
|
+
export const toolStyle = {
|
|
16
|
+
marker: { glyph: "●", color: { pending: "warning", success: "success", error: "error" } },
|
|
17
|
+
rail: { glyph: "│", color: "dim" },
|
|
18
|
+
gap: { afterTool: 0, afterOther: 1 },
|
|
19
|
+
collapsed: { headerOnly: new Set(["read", "grep", "find", "ls"]), fallbackLines: 10 },
|
|
20
|
+
fallbackArgsWidth: 120,
|
|
21
|
+
};
|
|
22
|
+
export function toolStatus(state) {
|
|
23
|
+
return state.isPartial ? "pending" : state.isError ? "error" : "success";
|
|
24
|
+
}
|
|
25
|
+
export function toolMarkerColor(status) {
|
|
26
|
+
return toolStyle.marker.color[status];
|
|
27
|
+
}
|
|
28
|
+
function cellWidth() {
|
|
29
|
+
return Math.max(visibleWidth(toolStyle.marker.glyph), visibleWidth(toolStyle.rail.glyph));
|
|
30
|
+
}
|
|
31
|
+
/** Columns the marker or rail takes, including the space before the content. */
|
|
32
|
+
export function gutterWidth() {
|
|
33
|
+
return cellWidth() + 1;
|
|
34
|
+
}
|
|
35
|
+
function gutterCell(glyph, color) {
|
|
36
|
+
return `${theme.fg(color, glyph)}${" ".repeat(cellWidth() - visibleWidth(glyph) + 1)}`;
|
|
37
|
+
}
|
|
38
|
+
/** A line that shows nothing: empty, or only spaces once styling is removed (Text pads its lines). */
|
|
39
|
+
function isBlankLine(line) {
|
|
40
|
+
return line === "" || stripAnsi(line).trim() === "";
|
|
41
|
+
}
|
|
42
|
+
function dropLeadingBlankLines(lines) {
|
|
43
|
+
let start = 0;
|
|
44
|
+
while (start < lines.length && isBlankLine(lines[start]))
|
|
45
|
+
start++;
|
|
46
|
+
return lines.slice(start);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Hangs a component's lines off the marker (header) or the rail (body). A header's first line
|
|
50
|
+
* carries the marker; every other line, and every body line, carries the rail, and a blank line
|
|
51
|
+
* keeps a bare rail so the block stays connected.
|
|
52
|
+
*/
|
|
53
|
+
export class FramedComponent {
|
|
54
|
+
constructor(component, kind, markerColor) {
|
|
55
|
+
this.component = component;
|
|
56
|
+
this.kind = kind;
|
|
57
|
+
this.markerColor = markerColor;
|
|
58
|
+
}
|
|
59
|
+
render(width) {
|
|
60
|
+
const rendered = this.component.render(Math.max(1, width - gutterWidth()));
|
|
61
|
+
// A body starts at its first visible line, and a header keeps its second line snug against the
|
|
62
|
+
// marker line: renderers written for padded cards separate a title from its preview with blanks.
|
|
63
|
+
const lines = this.kind === "body"
|
|
64
|
+
? dropLeadingBlankLines(rendered)
|
|
65
|
+
: rendered.length > 1
|
|
66
|
+
? [rendered[0], ...dropLeadingBlankLines(rendered.slice(1))]
|
|
67
|
+
: rendered;
|
|
68
|
+
if (lines.length === 0)
|
|
69
|
+
return [];
|
|
70
|
+
const rail = gutterCell(toolStyle.rail.glyph, toolStyle.rail.color);
|
|
71
|
+
const bareRail = theme.fg(toolStyle.rail.color, toolStyle.rail.glyph);
|
|
72
|
+
return lines.map((line, index) => {
|
|
73
|
+
if (index === 0 && this.kind === "header") {
|
|
74
|
+
return `${gutterCell(toolStyle.marker.glyph, this.markerColor())}${line}`;
|
|
75
|
+
}
|
|
76
|
+
return isBlankLine(line) ? bareRail : `${rail}${line}`;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
invalidate() {
|
|
80
|
+
this.component.invalidate();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=style.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style.js","sourceRoot":"","sources":["../../../../src/modes/interactive/tool-view/style.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The look of a tool block, defined in one place.\n *\n * A tool block is a marker line plus a rail:\n *\n * ● grep /useState/ in src marker: the tool's state\n * │ src/a.tsx:12: useState() rail: everything that belongs to the same tool\n *\n * Consecutive tool blocks sit directly under each other; text keeps a blank line. Change the look\n * by editing `toolStyle` or `FramedComponent`; nothing else in the transcript hard-codes it.\n */\n\nimport { type Component, visibleWidth } from \"@earendil-works/pi-tui\";\nimport { stripAnsi } from \"../../../utils/ansi.ts\";\nimport { type ThemeColor, theme } from \"../theme/theme.ts\";\n\nexport type ToolStatus = \"pending\" | \"success\" | \"error\";\n\nexport interface ToolStyle {\n\tmarker: { glyph: string; color: Record<ToolStatus, ThemeColor> };\n\trail: { glyph: string; color: ThemeColor };\n\t/** Blank lines above a tool block, by what precedes it. */\n\tgap: { afterTool: number; afterOther: number };\n\tcollapsed: {\n\t\t/**\n\t\t * Tools whose successful result stays hidden until expanded. A failure always shows. The shell\n\t\t * folds only the built-in result renderer, matched by identity, so list only tools whose\n\t\t * renderers are module-level constants: `bash` and `powershell` build fresh ones and never match.\n\t\t */\n\t\theaderOnly: ReadonlySet<string>;\n\t\t/** Output tail kept for a tool that has no result renderer. */\n\t\tfallbackLines: number;\n\t};\n\t/** Width budget for the argument summary a tool without a call renderer shows. */\n\tfallbackArgsWidth: number;\n}\n\nexport const toolStyle: ToolStyle = {\n\tmarker: { glyph: \"●\", color: { pending: \"warning\", success: \"success\", error: \"error\" } },\n\trail: { glyph: \"│\", color: \"dim\" },\n\tgap: { afterTool: 0, afterOther: 1 },\n\tcollapsed: { headerOnly: new Set([\"read\", \"grep\", \"find\", \"ls\"]), fallbackLines: 10 },\n\tfallbackArgsWidth: 120,\n};\n\nexport function toolStatus(state: { isPartial: boolean; isError: boolean }): ToolStatus {\n\treturn state.isPartial ? \"pending\" : state.isError ? \"error\" : \"success\";\n}\n\nexport function toolMarkerColor(status: ToolStatus): ThemeColor {\n\treturn toolStyle.marker.color[status];\n}\n\nfunction cellWidth(): number {\n\treturn Math.max(visibleWidth(toolStyle.marker.glyph), visibleWidth(toolStyle.rail.glyph));\n}\n\n/** Columns the marker or rail takes, including the space before the content. */\nexport function gutterWidth(): number {\n\treturn cellWidth() + 1;\n}\n\nfunction gutterCell(glyph: string, color: ThemeColor): string {\n\treturn `${theme.fg(color, glyph)}${\" \".repeat(cellWidth() - visibleWidth(glyph) + 1)}`;\n}\n\n/** A line that shows nothing: empty, or only spaces once styling is removed (Text pads its lines). */\nfunction isBlankLine(line: string): boolean {\n\treturn line === \"\" || stripAnsi(line).trim() === \"\";\n}\n\nfunction dropLeadingBlankLines(lines: string[]): string[] {\n\tlet start = 0;\n\twhile (start < lines.length && isBlankLine(lines[start]!)) start++;\n\treturn lines.slice(start);\n}\n\n/**\n * Hangs a component's lines off the marker (header) or the rail (body). A header's first line\n * carries the marker; every other line, and every body line, carries the rail, and a blank line\n * keeps a bare rail so the block stays connected.\n */\nexport class FramedComponent implements Component {\n\tprivate component: Component;\n\tprivate kind: \"header\" | \"body\";\n\tprivate markerColor: () => ThemeColor;\n\n\tconstructor(component: Component, kind: \"header\" | \"body\", markerColor: () => ThemeColor) {\n\t\tthis.component = component;\n\t\tthis.kind = kind;\n\t\tthis.markerColor = markerColor;\n\t}\n\n\trender(width: number): string[] {\n\t\tconst rendered = this.component.render(Math.max(1, width - gutterWidth()));\n\t\t// A body starts at its first visible line, and a header keeps its second line snug against the\n\t\t// marker line: renderers written for padded cards separate a title from its preview with blanks.\n\t\tconst lines =\n\t\t\tthis.kind === \"body\"\n\t\t\t\t? dropLeadingBlankLines(rendered)\n\t\t\t\t: rendered.length > 1\n\t\t\t\t\t? [rendered[0]!, ...dropLeadingBlankLines(rendered.slice(1))]\n\t\t\t\t\t: rendered;\n\t\tif (lines.length === 0) return [];\n\t\tconst rail = gutterCell(toolStyle.rail.glyph, toolStyle.rail.color);\n\t\tconst bareRail = theme.fg(toolStyle.rail.color, toolStyle.rail.glyph);\n\t\treturn lines.map((line, index) => {\n\t\t\tif (index === 0 && this.kind === \"header\") {\n\t\t\t\treturn `${gutterCell(toolStyle.marker.glyph, this.markerColor())}${line}`;\n\t\t\t}\n\t\t\treturn isBlankLine(line) ? bareRail : `${rail}${line}`;\n\t\t});\n\t}\n\n\tinvalidate(): void {\n\t\tthis.component.invalidate();\n\t}\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
2
2
|
import { type Component, Container, type TUI, type TuiMouseEvent } from "@earendil-works/pi-tui";
|
|
3
3
|
import type { ToolDefinition, ToolRenderContext, ToolRenderResultOptions } from "../../../core/extensions/types.ts";
|
|
4
|
-
import type
|
|
4
|
+
import { type Theme } from "../theme/theme.ts";
|
|
5
5
|
/**
|
|
6
6
|
* What this component needs from a tool: how to draw it. It neither executes tools nor reads their
|
|
7
7
|
* parameter schemas, so a definition and a bare renderer pair are equally acceptable.
|
|
@@ -11,21 +11,19 @@ import type { Theme } from "../theme/theme.ts";
|
|
|
11
11
|
*/
|
|
12
12
|
export interface ToolRenderers {
|
|
13
13
|
renderShell?: "default" | "self";
|
|
14
|
-
toolGroup?: string;
|
|
15
14
|
renderCall?: (args: any, theme: Theme, context: ToolRenderContext<any, any>) => Component;
|
|
16
15
|
renderResult?: (result: AgentToolResult<any>, options: ToolRenderResultOptions, theme: Theme, context: ToolRenderContext<any, any>) => Component;
|
|
17
16
|
}
|
|
18
17
|
export interface ToolExecutionOptions {
|
|
19
18
|
showImages?: boolean;
|
|
20
19
|
imageWidthCells?: number;
|
|
21
|
-
/** Long-running foreground cards advertise backgrounding. Absent means no hint (e.g. hosts without background execution). */
|
|
22
|
-
detachHint?: {
|
|
23
|
-
isDetachable(toolName: string): boolean;
|
|
24
|
-
/** Current key label; empty string means unbound and hides the hint. */
|
|
25
|
-
keyLabel(): string;
|
|
26
|
-
};
|
|
27
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* One tool call in the transcript: a marker line for the call and a rail for its result.
|
|
23
|
+
* `style.ts` owns how that looks; this class owns the call's lifecycle.
|
|
24
|
+
*/
|
|
28
25
|
export declare class ToolExecutionComponent extends Container {
|
|
26
|
+
private gap;
|
|
29
27
|
private contentContainer;
|
|
30
28
|
private selfRenderContainer;
|
|
31
29
|
private selfRenderHeight;
|
|
@@ -42,7 +40,6 @@ export declare class ToolExecutionComponent extends Container {
|
|
|
42
40
|
private imageWidthCells;
|
|
43
41
|
private isPartial;
|
|
44
42
|
private toolDefinition?;
|
|
45
|
-
readonly toolGroup: string | undefined;
|
|
46
43
|
private ui;
|
|
47
44
|
private cwd;
|
|
48
45
|
private executionStarted;
|
|
@@ -51,28 +48,26 @@ export declare class ToolExecutionComponent extends Container {
|
|
|
51
48
|
private convertedImages;
|
|
52
49
|
private pendingImageConversions;
|
|
53
50
|
private hideComponent;
|
|
54
|
-
private progressStartedAt?;
|
|
55
|
-
private refreshTimer?;
|
|
56
|
-
private readonly detachHint?;
|
|
57
51
|
private disposed;
|
|
58
52
|
constructor(toolName: string, toolCallId: string, args: any, options: ToolExecutionOptions | undefined, toolDefinition: ToolRenderers | ToolDefinition<any, any, any> | undefined, ui: TUI, cwd: string);
|
|
59
53
|
private getCallRenderer;
|
|
60
54
|
private getResultRenderer;
|
|
61
|
-
private
|
|
62
|
-
private
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
/** The hint label, or undefined when the hint is unavailable or the key is unbound. */
|
|
66
|
-
private detachHintText;
|
|
55
|
+
private isSelfRendered;
|
|
56
|
+
private status;
|
|
57
|
+
/** Blank lines above this row; the chat sets it from what precedes the row. */
|
|
58
|
+
setLeadingGap(lines: number): void;
|
|
67
59
|
private getRenderContext;
|
|
68
|
-
private
|
|
69
|
-
private wrapCall;
|
|
70
|
-
private wrapResult;
|
|
60
|
+
private frame;
|
|
71
61
|
private createResultFallback;
|
|
62
|
+
/**
|
|
63
|
+
* A successful result of an explore tool stays hidden until expanded; a failure always shows.
|
|
64
|
+
* Only the built-in result renderer is folded, so an extension that overrides the tool with its
|
|
65
|
+
* own renderResult keeps control of what its row shows.
|
|
66
|
+
*/
|
|
67
|
+
private hidesCollapsedResult;
|
|
72
68
|
private createResultRegion;
|
|
73
69
|
updateArgs(args: any): void;
|
|
74
70
|
markExecutionStarted(): void;
|
|
75
|
-
private clearRefreshTimer;
|
|
76
71
|
setArgsComplete(): void;
|
|
77
72
|
updateResult(result: {
|
|
78
73
|
content: Array<{
|
|
@@ -89,8 +84,6 @@ export declare class ToolExecutionComponent extends Container {
|
|
|
89
84
|
setShowImages(show: boolean): void;
|
|
90
85
|
setImageWidthCells(width: number): void;
|
|
91
86
|
invalidate(): void;
|
|
92
|
-
getFinalErrorSummary(): string | undefined;
|
|
93
|
-
renderCallSummary(width: number): string[];
|
|
94
87
|
render(width: number): string[];
|
|
95
88
|
handleMouse(event: TuiMouseEvent): ReturnType<Container["handleMouse"]>;
|
|
96
89
|
private updateDisplay;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-execution.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/tool-view/tool-execution.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import { Container, getCapabilities, Image, MouseRegion, Spacer,
|
|
1
|
+
import { Container, getCapabilities, Image, MouseRegion, Spacer, } from "@earendil-works/pi-tui";
|
|
2
2
|
import { getTextOutput as getRenderedTextOutput } from "../../../core/tools/render-utils.js";
|
|
3
|
+
import { createAllToolRenderers } from "../../../core/tools/renderers/index.js";
|
|
3
4
|
import { convertToPng } from "../../../utils/image-convert.js";
|
|
4
5
|
import { theme } from "../theme/theme.js";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
|
|
6
|
+
import { createCallFallback, FallbackResultComponent } from "./fallback.js";
|
|
7
|
+
import { FramedComponent, toolMarkerColor, toolStatus, toolStyle } from "./style.js";
|
|
8
|
+
let builtInRenderers;
|
|
9
|
+
/**
|
|
10
|
+
* One tool call in the transcript: a marker line for the call and a rail for its result.
|
|
11
|
+
* `style.ts` owns how that looks; this class owns the call's lifecycle.
|
|
12
|
+
*/
|
|
10
13
|
export class ToolExecutionComponent extends Container {
|
|
11
14
|
constructor(toolName, toolCallId, args, options = {}, toolDefinition, ui, cwd) {
|
|
12
15
|
super();
|
|
@@ -26,16 +29,15 @@ export class ToolExecutionComponent extends Container {
|
|
|
26
29
|
this.toolCallId = toolCallId;
|
|
27
30
|
this.args = args;
|
|
28
31
|
this.toolDefinition = toolDefinition;
|
|
29
|
-
this.toolGroup = this.getRenderShell() === "self" ? undefined : this.toolDefinition?.toolGroup;
|
|
30
32
|
this.showImages = options.showImages ?? true;
|
|
31
33
|
this.imageWidthCells = options.imageWidthCells ?? 60;
|
|
32
|
-
this.detachHint = options.detachHint;
|
|
33
34
|
this.ui = ui;
|
|
34
35
|
this.cwd = cwd;
|
|
35
|
-
this.
|
|
36
|
+
this.gap = new Spacer(toolStyle.gap.afterOther);
|
|
37
|
+
this.addChild(this.gap);
|
|
36
38
|
this.contentContainer = new Container();
|
|
37
39
|
this.selfRenderContainer = new Container();
|
|
38
|
-
this.addChild(this.
|
|
40
|
+
this.addChild(this.isSelfRendered() ? this.selfRenderContainer : this.contentContainer);
|
|
39
41
|
this.updateDisplay();
|
|
40
42
|
}
|
|
41
43
|
getCallRenderer() {
|
|
@@ -44,26 +46,17 @@ export class ToolExecutionComponent extends Container {
|
|
|
44
46
|
getResultRenderer() {
|
|
45
47
|
return this.toolDefinition?.renderResult;
|
|
46
48
|
}
|
|
47
|
-
|
|
48
|
-
return this.toolDefinition
|
|
49
|
+
isSelfRendered() {
|
|
50
|
+
return this.toolDefinition?.renderShell === "self";
|
|
49
51
|
}
|
|
50
|
-
|
|
51
|
-
return this.
|
|
52
|
+
status() {
|
|
53
|
+
return toolStatus({ isPartial: this.isPartial, isError: this.result?.isError ?? false });
|
|
52
54
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
/** Blank lines above this row; the chat sets it from what precedes the row. */
|
|
56
|
+
setLeadingGap(lines) {
|
|
57
|
+
this.gap.setLines(lines);
|
|
55
58
|
}
|
|
56
|
-
|
|
57
|
-
return this.getRenderShell() !== "self" && this.detachHint?.isDetachable(this.toolName) === true;
|
|
58
|
-
}
|
|
59
|
-
/** The hint label, or undefined when the hint is unavailable or the key is unbound. */
|
|
60
|
-
detachHintText() {
|
|
61
|
-
if (!this.shouldRenderDetachHint())
|
|
62
|
-
return undefined;
|
|
63
|
-
const key = this.detachHint?.keyLabel();
|
|
64
|
-
return key ? `Press ${key} to run in background, /bg to manage` : undefined;
|
|
65
|
-
}
|
|
66
|
-
getRenderContext(lastComponent, toolGroupSummary = false) {
|
|
59
|
+
getRenderContext(lastComponent) {
|
|
67
60
|
return {
|
|
68
61
|
args: this.args,
|
|
69
62
|
toolCallId: this.toolCallId,
|
|
@@ -88,31 +81,10 @@ export class ToolExecutionComponent extends Container {
|
|
|
88
81
|
details: this.result.details,
|
|
89
82
|
}
|
|
90
83
|
: undefined,
|
|
91
|
-
toolGroupSummary,
|
|
92
84
|
};
|
|
93
85
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const suffix = args ? theme.fg("dim", `(${args})`) : "";
|
|
97
|
-
return new Text(`${theme.fg("toolTitle", theme.bold(this.toolName))}${suffix}`, 0, 0);
|
|
98
|
-
}
|
|
99
|
-
wrapCall(component) {
|
|
100
|
-
const color = this.isPartial ? "warning" : this.result?.isError ? "error" : "success";
|
|
101
|
-
// Continuation lines share the result rail so the whole block reads as one
|
|
102
|
-
// unit hanging off the dot instead of an indented island above a lone rail.
|
|
103
|
-
const rail = theme.fg("dim", "│ ");
|
|
104
|
-
return new ToolChromeComponent(component, `${theme.fg(color, "●")} `, {
|
|
105
|
-
continuationPrefix: rail,
|
|
106
|
-
blankLinePrefix: theme.fg("dim", "│"),
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
wrapResult(component) {
|
|
110
|
-
const rail = theme.fg("dim", "│ ");
|
|
111
|
-
return new ToolChromeComponent(component, rail, {
|
|
112
|
-
trimLeadingBlankLines: true,
|
|
113
|
-
continuationPrefix: rail,
|
|
114
|
-
blankLinePrefix: theme.fg("dim", "│"),
|
|
115
|
-
});
|
|
86
|
+
frame(component, kind) {
|
|
87
|
+
return new FramedComponent(component, kind, () => toolMarkerColor(this.status()));
|
|
116
88
|
}
|
|
117
89
|
createResultFallback() {
|
|
118
90
|
const output = this.getTextOutput();
|
|
@@ -121,6 +93,18 @@ export class ToolExecutionComponent extends Container {
|
|
|
121
93
|
}
|
|
122
94
|
return new FallbackResultComponent(output, this.expanded);
|
|
123
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* A successful result of an explore tool stays hidden until expanded; a failure always shows.
|
|
98
|
+
* Only the built-in result renderer is folded, so an extension that overrides the tool with its
|
|
99
|
+
* own renderResult keeps control of what its row shows.
|
|
100
|
+
*/
|
|
101
|
+
hidesCollapsedResult() {
|
|
102
|
+
if (this.expanded || this.result?.isError || !toolStyle.collapsed.headerOnly.has(this.toolName))
|
|
103
|
+
return false;
|
|
104
|
+
builtInRenderers ??= createAllToolRenderers();
|
|
105
|
+
const builtIn = builtInRenderers[this.toolName];
|
|
106
|
+
return builtIn?.renderResult !== undefined && builtIn.renderResult === this.getResultRenderer();
|
|
107
|
+
}
|
|
124
108
|
createResultRegion(component) {
|
|
125
109
|
return new MouseRegion(component, (event) => {
|
|
126
110
|
if (!this.result || event.type !== "click" || event.button !== "left")
|
|
@@ -137,31 +121,9 @@ export class ToolExecutionComponent extends Container {
|
|
|
137
121
|
if (this.disposed)
|
|
138
122
|
return;
|
|
139
123
|
this.executionStarted = true;
|
|
140
|
-
if (this.shouldRenderGenericProgress() || this.shouldRenderDetachHint()) {
|
|
141
|
-
if (this.progressStartedAt === undefined) {
|
|
142
|
-
this.progressStartedAt = Date.now();
|
|
143
|
-
}
|
|
144
|
-
if (this.refreshTimer === undefined) {
|
|
145
|
-
this.refreshTimer = setInterval(() => {
|
|
146
|
-
if (this.disposed || !this.isPartial) {
|
|
147
|
-
this.clearRefreshTimer();
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
this.invalidate();
|
|
151
|
-
this.ui.requestRender();
|
|
152
|
-
}, PROGRESS_REFRESH_INTERVAL_MS);
|
|
153
|
-
this.refreshTimer.unref?.();
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
124
|
this.updateDisplay();
|
|
157
125
|
this.ui.requestRender();
|
|
158
126
|
}
|
|
159
|
-
clearRefreshTimer() {
|
|
160
|
-
if (this.refreshTimer) {
|
|
161
|
-
clearInterval(this.refreshTimer);
|
|
162
|
-
this.refreshTimer = undefined;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
127
|
setArgsComplete() {
|
|
166
128
|
this.argsComplete = true;
|
|
167
129
|
this.updateDisplay();
|
|
@@ -170,8 +132,6 @@ export class ToolExecutionComponent extends Container {
|
|
|
170
132
|
updateResult(result, isPartial = false) {
|
|
171
133
|
this.result = result;
|
|
172
134
|
this.isPartial = isPartial;
|
|
173
|
-
if (!isPartial)
|
|
174
|
-
this.clearRefreshTimer();
|
|
175
135
|
this.updateDisplay();
|
|
176
136
|
this.maybeConvertImagesForKitty();
|
|
177
137
|
}
|
|
@@ -244,33 +204,11 @@ export class ToolExecutionComponent extends Container {
|
|
|
244
204
|
super.invalidate();
|
|
245
205
|
this.updateDisplay();
|
|
246
206
|
}
|
|
247
|
-
getFinalErrorSummary() {
|
|
248
|
-
if (this.isPartial || !this.result?.isError)
|
|
249
|
-
return undefined;
|
|
250
|
-
const summary = this.getTextOutput().replace(/\s+/gu, " ").trim();
|
|
251
|
-
return summary || undefined;
|
|
252
|
-
}
|
|
253
|
-
renderCallSummary(width) {
|
|
254
|
-
const callRenderer = this.getCallRenderer();
|
|
255
|
-
let component;
|
|
256
|
-
if (!callRenderer) {
|
|
257
|
-
component = this.createCallFallback();
|
|
258
|
-
}
|
|
259
|
-
else {
|
|
260
|
-
try {
|
|
261
|
-
component = callRenderer(this.args, theme, this.getRenderContext(undefined, true));
|
|
262
|
-
}
|
|
263
|
-
catch {
|
|
264
|
-
component = this.createCallFallback();
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
return this.wrapCall(component).render(width);
|
|
268
|
-
}
|
|
269
207
|
render(width) {
|
|
270
208
|
if (this.hideComponent) {
|
|
271
209
|
return [];
|
|
272
210
|
}
|
|
273
|
-
if (this.
|
|
211
|
+
if (this.isSelfRendered()) {
|
|
274
212
|
const contentLines = this.selfRenderContainer.render(width);
|
|
275
213
|
this.selfRenderHeight = contentLines.length;
|
|
276
214
|
if (contentLines.length === 0 && this.imageComponents.length === 0) {
|
|
@@ -296,7 +234,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
296
234
|
return super.render(width);
|
|
297
235
|
}
|
|
298
236
|
handleMouse(event) {
|
|
299
|
-
if (!this.
|
|
237
|
+
if (!this.isSelfRendered())
|
|
300
238
|
return super.handleMouse(event);
|
|
301
239
|
if (event.y <= 0 || event.y > this.selfRenderHeight)
|
|
302
240
|
return undefined;
|
|
@@ -309,20 +247,20 @@ export class ToolExecutionComponent extends Container {
|
|
|
309
247
|
updateDisplay() {
|
|
310
248
|
let hasContent = false;
|
|
311
249
|
this.hideComponent = false;
|
|
312
|
-
const selfRendered = this.
|
|
250
|
+
const selfRendered = this.isSelfRendered();
|
|
313
251
|
const renderContainer = selfRendered ? this.selfRenderContainer : this.contentContainer;
|
|
314
252
|
renderContainer.clear();
|
|
315
253
|
const addCall = (component) => {
|
|
316
|
-
renderContainer.addChild(selfRendered ? component : this.createResultRegion(this.
|
|
254
|
+
renderContainer.addChild(selfRendered ? component : this.createResultRegion(this.frame(component, "header")));
|
|
317
255
|
hasContent = true;
|
|
318
256
|
};
|
|
319
257
|
const addResult = (component) => {
|
|
320
|
-
renderContainer.addChild(selfRendered ? component : this.createResultRegion(this.
|
|
258
|
+
renderContainer.addChild(selfRendered ? component : this.createResultRegion(this.frame(component, "body")));
|
|
321
259
|
hasContent = true;
|
|
322
260
|
};
|
|
323
261
|
const callRenderer = this.getCallRenderer();
|
|
324
262
|
if (!callRenderer) {
|
|
325
|
-
addCall(this.
|
|
263
|
+
addCall(createCallFallback(this.toolName, this.args));
|
|
326
264
|
}
|
|
327
265
|
else {
|
|
328
266
|
try {
|
|
@@ -332,10 +270,10 @@ export class ToolExecutionComponent extends Container {
|
|
|
332
270
|
}
|
|
333
271
|
catch {
|
|
334
272
|
this.callRendererComponent = undefined;
|
|
335
|
-
addCall(this.
|
|
273
|
+
addCall(createCallFallback(this.toolName, this.args));
|
|
336
274
|
}
|
|
337
275
|
}
|
|
338
|
-
if (this.result) {
|
|
276
|
+
if (this.result && (selfRendered || !this.hidesCollapsedResult())) {
|
|
339
277
|
const resultRenderer = this.getResultRenderer();
|
|
340
278
|
if (!resultRenderer) {
|
|
341
279
|
const component = this.createResultFallback();
|
|
@@ -356,17 +294,6 @@ export class ToolExecutionComponent extends Container {
|
|
|
356
294
|
}
|
|
357
295
|
}
|
|
358
296
|
}
|
|
359
|
-
if (this.executionStarted && this.isPartial && this.progressStartedAt !== undefined) {
|
|
360
|
-
const elapsedMs = Date.now() - this.progressStartedAt;
|
|
361
|
-
if (this.shouldRenderGenericProgress() && elapsedMs >= PROGRESS_THRESHOLD_MS) {
|
|
362
|
-
addResult(new Text(theme.fg("muted", `Running… (${formatElapsed(elapsedMs)})`), 0, 0));
|
|
363
|
-
}
|
|
364
|
-
if (elapsedMs >= DETACH_HINT_DELAY_MS) {
|
|
365
|
-
const hint = this.detachHintText();
|
|
366
|
-
if (hint)
|
|
367
|
-
addResult(new Text(theme.fg("dim", hint), 0, 0));
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
297
|
for (const img of this.imageComponents) {
|
|
371
298
|
this.removeChild(img);
|
|
372
299
|
}
|
|
@@ -407,7 +334,6 @@ export class ToolExecutionComponent extends Container {
|
|
|
407
334
|
if (this.disposed)
|
|
408
335
|
return;
|
|
409
336
|
this.disposed = true;
|
|
410
|
-
this.clearRefreshTimer();
|
|
411
337
|
this.rendererState.dispose?.();
|
|
412
338
|
this.pendingImageConversions.clear();
|
|
413
339
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-execution.js","sourceRoot":"","sources":["../../../../src/modes/interactive/tool-view/tool-execution.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentToolResult } from \"@earendil-works/pi-agent-core\";\nimport {\n\ttype Component,\n\tContainer,\n\tgetCapabilities,\n\tImage,\n\tMouseRegion,\n\tSpacer,\n\ttype TUI,\n\ttype TuiMouseEvent,\n} from \"@earendil-works/pi-tui\";\nimport type { ToolDefinition, ToolRenderContext, ToolRenderResultOptions } from \"../../../core/extensions/types.ts\";\nimport { getTextOutput as getRenderedTextOutput } from \"../../../core/tools/render-utils.ts\";\nimport { createAllToolRenderers } from \"../../../core/tools/renderers/index.ts\";\nimport { convertToPng } from \"../../../utils/image-convert.ts\";\nimport { type Theme, theme } from \"../theme/theme.ts\";\nimport { createCallFallback, FallbackResultComponent } from \"./fallback.ts\";\nimport { FramedComponent, type ToolStatus, toolMarkerColor, toolStatus, toolStyle } from \"./style.ts\";\n\n/**\n * What this component needs from a tool: how to draw it. It neither executes tools nor reads their\n * parameter schemas, so a definition and a bare renderer pair are equally acceptable.\n *\n * The renderer parameters are `any` on purpose: a `ToolDefinition` types them from its schema, and\n * narrowing them here would make those definitions unassignable.\n */\nexport interface ToolRenderers {\n\trenderShell?: \"default\" | \"self\";\n\trenderCall?: (args: any, theme: Theme, context: ToolRenderContext<any, any>) => Component;\n\trenderResult?: (\n\t\tresult: AgentToolResult<any>,\n\t\toptions: ToolRenderResultOptions,\n\t\ttheme: Theme,\n\t\tcontext: ToolRenderContext<any, any>,\n\t) => Component;\n}\n\nexport interface ToolExecutionOptions {\n\tshowImages?: boolean;\n\timageWidthCells?: number;\n}\n\ninterface ConvertedImage {\n\tsourceData: string;\n\tsourceMimeType: string;\n\tdata: string;\n\tmimeType: string;\n}\n\ninterface PendingImageConversion {\n\tsourceData: string;\n\tsourceMimeType: string;\n}\n\nlet builtInRenderers: ReturnType<typeof createAllToolRenderers> | undefined;\n\n/**\n * One tool call in the transcript: a marker line for the call and a rail for its result.\n * `style.ts` owns how that looks; this class owns the call's lifecycle.\n */\nexport class ToolExecutionComponent extends Container {\n\tprivate gap: Spacer;\n\tprivate contentContainer: Container;\n\tprivate selfRenderContainer: Container;\n\tprivate selfRenderHeight = 0;\n\tprivate callRendererComponent?: Component;\n\tprivate resultRendererComponent?: Component;\n\tprivate rendererState: any = {};\n\tprivate imageComponents: Image[] = [];\n\tprivate imageSpacers: Spacer[] = [];\n\tprivate toolName: string;\n\tprivate toolCallId: string;\n\tprivate args: any;\n\tprivate expanded = false;\n\tprivate showImages: boolean;\n\tprivate imageWidthCells: number;\n\tprivate isPartial = true;\n\tprivate toolDefinition?: ToolRenderers;\n\tprivate ui: TUI;\n\tprivate cwd: string;\n\tprivate executionStarted = false;\n\tprivate argsComplete = false;\n\tprivate result?: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tisError: boolean;\n\t\tdetails?: any;\n\t};\n\tprivate convertedImages = new Map<number, ConvertedImage>();\n\tprivate pendingImageConversions = new Map<number, PendingImageConversion>();\n\tprivate hideComponent = false;\n\tprivate disposed = false;\n\n\tconstructor(\n\t\ttoolName: string,\n\t\ttoolCallId: string,\n\t\targs: any,\n\t\toptions: ToolExecutionOptions = {},\n\t\ttoolDefinition: ToolRenderers | ToolDefinition<any, any, any> | undefined,\n\t\tui: TUI,\n\t\tcwd: string,\n\t) {\n\t\tsuper();\n\t\tthis.toolName = toolName;\n\t\tthis.toolCallId = toolCallId;\n\t\tthis.args = args;\n\t\tthis.toolDefinition = toolDefinition;\n\t\tthis.showImages = options.showImages ?? true;\n\t\tthis.imageWidthCells = options.imageWidthCells ?? 60;\n\t\tthis.ui = ui;\n\t\tthis.cwd = cwd;\n\n\t\tthis.gap = new Spacer(toolStyle.gap.afterOther);\n\t\tthis.addChild(this.gap);\n\n\t\tthis.contentContainer = new Container();\n\t\tthis.selfRenderContainer = new Container();\n\t\tthis.addChild(this.isSelfRendered() ? this.selfRenderContainer : this.contentContainer);\n\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate getCallRenderer(): ToolDefinition<any, any>[\"renderCall\"] | undefined {\n\t\treturn this.toolDefinition?.renderCall;\n\t}\n\n\tprivate getResultRenderer(): ToolDefinition<any, any>[\"renderResult\"] | undefined {\n\t\treturn this.toolDefinition?.renderResult;\n\t}\n\n\tprivate isSelfRendered(): boolean {\n\t\treturn this.toolDefinition?.renderShell === \"self\";\n\t}\n\n\tprivate status(): ToolStatus {\n\t\treturn toolStatus({ isPartial: this.isPartial, isError: this.result?.isError ?? false });\n\t}\n\n\t/** Blank lines above this row; the chat sets it from what precedes the row. */\n\tsetLeadingGap(lines: number): void {\n\t\tthis.gap.setLines(lines);\n\t}\n\n\tprivate getRenderContext(lastComponent: Component | undefined): ToolRenderContext {\n\t\treturn {\n\t\t\targs: this.args,\n\t\t\ttoolCallId: this.toolCallId,\n\t\t\tinvalidate: () => {\n\t\t\t\tif (this.disposed) return;\n\t\t\t\tthis.invalidate();\n\t\t\t\tthis.ui.requestRender();\n\t\t\t},\n\t\t\tlastComponent,\n\t\t\tstate: this.rendererState,\n\t\t\tcwd: this.cwd,\n\t\t\texecutionStarted: this.executionStarted,\n\t\t\targsComplete: this.argsComplete,\n\t\t\tisPartial: this.isPartial,\n\t\t\texpanded: this.expanded,\n\t\t\tshowImages: this.showImages,\n\t\t\tisError: this.result?.isError ?? false,\n\t\t\tresult: this.result\n\t\t\t\t? {\n\t\t\t\t\t\tcontent: this.result.content as AgentToolResult<unknown>[\"content\"],\n\t\t\t\t\t\tdetails: this.result.details,\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t};\n\t}\n\n\tprivate frame(component: Component, kind: \"header\" | \"body\"): Component {\n\t\treturn new FramedComponent(component, kind, () => toolMarkerColor(this.status()));\n\t}\n\n\tprivate createResultFallback(): Component | undefined {\n\t\tconst output = this.getTextOutput();\n\t\tif (!output) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn new FallbackResultComponent(output, this.expanded);\n\t}\n\n\t/**\n\t * A successful result of an explore tool stays hidden until expanded; a failure always shows.\n\t * Only the built-in result renderer is folded, so an extension that overrides the tool with its\n\t * own renderResult keeps control of what its row shows.\n\t */\n\tprivate hidesCollapsedResult(): boolean {\n\t\tif (this.expanded || this.result?.isError || !toolStyle.collapsed.headerOnly.has(this.toolName)) return false;\n\t\tbuiltInRenderers ??= createAllToolRenderers();\n\t\tconst builtIn = (builtInRenderers as Record<string, ToolRenderers>)[this.toolName];\n\t\treturn builtIn?.renderResult !== undefined && builtIn.renderResult === this.getResultRenderer();\n\t}\n\n\tprivate createResultRegion(component: Component): MouseRegion {\n\t\treturn new MouseRegion(component, (event) => {\n\t\t\tif (!this.result || event.type !== \"click\" || event.button !== \"left\") return undefined;\n\t\t\tthis.setExpanded(!this.expanded);\n\t\t\treturn { handled: true };\n\t\t});\n\t}\n\n\tupdateArgs(args: any): void {\n\t\tthis.args = args;\n\t\tthis.updateDisplay();\n\t}\n\n\tmarkExecutionStarted(): void {\n\t\tif (this.disposed) return;\n\t\tthis.executionStarted = true;\n\t\tthis.updateDisplay();\n\t\tthis.ui.requestRender();\n\t}\n\n\tsetArgsComplete(): void {\n\t\tthis.argsComplete = true;\n\t\tthis.updateDisplay();\n\t\tthis.ui.requestRender();\n\t}\n\n\tupdateResult(\n\t\tresult: {\n\t\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\t\tdetails?: any;\n\t\t\tisError: boolean;\n\t\t},\n\t\tisPartial = false,\n\t): void {\n\t\tthis.result = result;\n\t\tthis.isPartial = isPartial;\n\t\tthis.updateDisplay();\n\t\tthis.maybeConvertImagesForKitty();\n\t}\n\n\tprivate maybeConvertImagesForKitty(): void {\n\t\tconst caps = getCapabilities();\n\t\tif (caps.images !== \"kitty\") return;\n\t\tif (!this.result) return;\n\n\t\tconst imageBlocks = this.result.content.filter((content) => content.type === \"image\");\n\t\tconst sourceMatches = (\n\t\t\timage: { data?: string; mimeType?: string } | undefined,\n\t\t\tentry: PendingImageConversion | undefined,\n\t\t): boolean => image?.data === entry?.sourceData && image?.mimeType === entry?.sourceMimeType;\n\t\tfor (const [index, converted] of this.convertedImages) {\n\t\t\tif (!sourceMatches(imageBlocks[index], converted)) this.convertedImages.delete(index);\n\t\t}\n\t\tfor (const [index, pending] of this.pendingImageConversions) {\n\t\t\tif (!sourceMatches(imageBlocks[index], pending)) this.pendingImageConversions.delete(index);\n\t\t}\n\n\t\tfor (let i = 0; i < imageBlocks.length; i++) {\n\t\t\tconst image = imageBlocks[i];\n\t\t\tif (!image.data || !image.mimeType || image.mimeType === \"image/png\") continue;\n\t\t\tif (sourceMatches(image, this.convertedImages.get(i))) continue;\n\t\t\tif (sourceMatches(image, this.pendingImageConversions.get(i))) continue;\n\n\t\t\tconst index = i;\n\t\t\tconst sourceData = image.data;\n\t\t\tconst sourceMimeType = image.mimeType;\n\t\t\tthis.pendingImageConversions.set(index, { sourceData, sourceMimeType });\n\t\t\tvoid convertToPng(sourceData, sourceMimeType)\n\t\t\t\t.then((converted) => {\n\t\t\t\t\tconst pending = this.pendingImageConversions.get(index);\n\t\t\t\t\tif (pending?.sourceData !== sourceData || pending.sourceMimeType !== sourceMimeType) return;\n\t\t\t\t\tthis.pendingImageConversions.delete(index);\n\t\t\t\t\tif (this.disposed) return;\n\t\t\t\t\tconst currentImage = this.result?.content.filter((content) => content.type === \"image\")[index];\n\t\t\t\t\tif (currentImage?.data !== sourceData || currentImage.mimeType !== sourceMimeType) return;\n\t\t\t\t\tif (converted) {\n\t\t\t\t\t\tthis.convertedImages.set(index, { sourceData, sourceMimeType, ...converted });\n\t\t\t\t\t\tthis.updateDisplay();\n\t\t\t\t\t\tthis.ui.requestRender();\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.catch(() => {\n\t\t\t\t\tconst pending = this.pendingImageConversions.get(index);\n\t\t\t\t\tif (pending?.sourceData === sourceData && pending.sourceMimeType === sourceMimeType) {\n\t\t\t\t\t\tthis.pendingImageConversions.delete(index);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t}\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetShowImages(show: boolean): void {\n\t\tthis.showImages = show;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetImageWidthCells(width: number): void {\n\t\tthis.imageWidthCells = Math.max(1, Math.floor(width));\n\t\tthis.updateDisplay();\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\toverride render(width: number): string[] {\n\t\tif (this.hideComponent) {\n\t\t\treturn [];\n\t\t}\n\n\t\tif (this.isSelfRendered()) {\n\t\t\tconst contentLines = this.selfRenderContainer.render(width);\n\t\t\tthis.selfRenderHeight = contentLines.length;\n\t\t\tif (contentLines.length === 0 && this.imageComponents.length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst lines: string[] = [];\n\t\t\tif (contentLines.length > 0) {\n\t\t\t\tlines.push(\"\");\n\t\t\t\tlines.push(...contentLines);\n\t\t\t}\n\t\t\tfor (let i = 0; i < this.imageComponents.length; i++) {\n\t\t\t\tconst spacer = this.imageSpacers[i];\n\t\t\t\tif (spacer) {\n\t\t\t\t\tlines.push(...spacer.render(width));\n\t\t\t\t}\n\t\t\t\tconst imageComponent = this.imageComponents[i];\n\t\t\t\tif (imageComponent) {\n\t\t\t\t\tlines.push(...imageComponent.render(width));\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn lines;\n\t\t}\n\n\t\treturn super.render(width);\n\t}\n\n\toverride handleMouse(event: TuiMouseEvent): ReturnType<Container[\"handleMouse\"]> {\n\t\tif (!this.isSelfRendered()) return super.handleMouse(event);\n\t\tif (event.y <= 0 || event.y > this.selfRenderHeight) return undefined;\n\t\treturn this.selfRenderContainer.handleMouse({\n\t\t\t...event,\n\t\t\ty: event.y - 1,\n\t\t\theight: this.selfRenderHeight,\n\t\t});\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tlet hasContent = false;\n\t\tthis.hideComponent = false;\n\t\tconst selfRendered = this.isSelfRendered();\n\t\tconst renderContainer = selfRendered ? this.selfRenderContainer : this.contentContainer;\n\t\trenderContainer.clear();\n\n\t\tconst addCall = (component: Component) => {\n\t\t\trenderContainer.addChild(selfRendered ? component : this.createResultRegion(this.frame(component, \"header\")));\n\t\t\thasContent = true;\n\t\t};\n\t\tconst addResult = (component: Component) => {\n\t\t\trenderContainer.addChild(selfRendered ? component : this.createResultRegion(this.frame(component, \"body\")));\n\t\t\thasContent = true;\n\t\t};\n\n\t\tconst callRenderer = this.getCallRenderer();\n\t\tif (!callRenderer) {\n\t\t\taddCall(createCallFallback(this.toolName, this.args));\n\t\t} else {\n\t\t\ttry {\n\t\t\t\tconst component = callRenderer(this.args, theme, this.getRenderContext(this.callRendererComponent));\n\t\t\t\tthis.callRendererComponent = component;\n\t\t\t\taddCall(component);\n\t\t\t} catch {\n\t\t\t\tthis.callRendererComponent = undefined;\n\t\t\t\taddCall(createCallFallback(this.toolName, this.args));\n\t\t\t}\n\t\t}\n\n\t\tif (this.result && (selfRendered || !this.hidesCollapsedResult())) {\n\t\t\tconst resultRenderer = this.getResultRenderer();\n\t\t\tif (!resultRenderer) {\n\t\t\t\tconst component = this.createResultFallback();\n\t\t\t\tif (component) addResult(component);\n\t\t\t} else {\n\t\t\t\ttry {\n\t\t\t\t\tconst component = resultRenderer(\n\t\t\t\t\t\t{ content: this.result.content as any, details: this.result.details },\n\t\t\t\t\t\t{ expanded: this.expanded, isPartial: this.isPartial },\n\t\t\t\t\t\ttheme,\n\t\t\t\t\t\tthis.getRenderContext(this.resultRendererComponent),\n\t\t\t\t\t);\n\t\t\t\t\tthis.resultRendererComponent = component;\n\t\t\t\t\taddResult(component);\n\t\t\t\t} catch {\n\t\t\t\t\tthis.resultRendererComponent = undefined;\n\t\t\t\t\tconst component = this.createResultFallback();\n\t\t\t\t\tif (component) addResult(component);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (const img of this.imageComponents) {\n\t\t\tthis.removeChild(img);\n\t\t}\n\t\tthis.imageComponents = [];\n\t\tfor (const spacer of this.imageSpacers) {\n\t\t\tthis.removeChild(spacer);\n\t\t}\n\t\tthis.imageSpacers = [];\n\n\t\tif (this.result) {\n\t\t\tconst imageBlocks = this.result.content.filter((c) => c.type === \"image\");\n\t\t\tconst caps = getCapabilities();\n\t\t\tfor (let i = 0; i < imageBlocks.length; i++) {\n\t\t\t\tconst img = imageBlocks[i];\n\t\t\t\tif (caps.images && this.showImages && img.data && img.mimeType) {\n\t\t\t\t\tconst cached = this.convertedImages.get(i);\n\t\t\t\t\tconst converted =\n\t\t\t\t\t\tcached?.sourceData === img.data && cached.sourceMimeType === img.mimeType ? cached : undefined;\n\t\t\t\t\tconst imageData = converted?.data ?? img.data;\n\t\t\t\t\tconst imageMimeType = converted?.mimeType ?? img.mimeType;\n\t\t\t\t\tif (caps.images === \"kitty\" && imageMimeType !== \"image/png\") continue;\n\n\t\t\t\t\tconst spacer = new Spacer(1);\n\t\t\t\t\tthis.addChild(spacer);\n\t\t\t\t\tthis.imageSpacers.push(spacer);\n\t\t\t\t\tconst imageComponent = new Image(\n\t\t\t\t\t\timageData,\n\t\t\t\t\t\timageMimeType,\n\t\t\t\t\t\t{ fallbackColor: (s: string) => theme.fg(\"toolOutput\", s) },\n\t\t\t\t\t\t{ maxWidthCells: this.imageWidthCells },\n\t\t\t\t\t);\n\t\t\t\t\tthis.imageComponents.push(imageComponent);\n\t\t\t\t\tthis.addChild(imageComponent);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (!hasContent && this.imageComponents.length === 0) {\n\t\t\tthis.hideComponent = true;\n\t\t}\n\t}\n\n\tprivate getTextOutput(): string {\n\t\treturn getRenderedTextOutput(this.result, this.showImages);\n\t}\n\n\tdispose(): void {\n\t\tif (this.disposed) return;\n\t\tthis.disposed = true;\n\t\t(this.rendererState as { dispose?: () => void }).dispose?.();\n\t\tthis.pendingImageConversions.clear();\n\t}\n}\n"]}
|
package/docs/bundled/README.md
CHANGED
|
@@ -27,7 +27,7 @@ See [Compaction](../compaction.md).
|
|
|
27
27
|
|
|
28
28
|
## Tool presentation
|
|
29
29
|
|
|
30
|
-
Native tool calls
|
|
30
|
+
Native tool calls are compact blocks: a `●` marker whose color is the tool's state and a `│` rail for everything that belongs to it, with no blank line between consecutive tools. Built-in semantic renderers remain responsible for paths, diffs, syntax highlighting, command output, and images.
|
|
31
31
|
|
|
32
32
|
See [Native tool presentation](tool-presentation.md).
|
|
33
33
|
|
|
@@ -21,7 +21,7 @@ Start a whole Subagent invocation through its native tool:
|
|
|
21
21
|
|
|
22
22
|
Omitting `background` keeps the normal foreground wait. A background submission returns an execution reference, not a successful final outcome. `bg create` has been removed; old stored create results and background notifications still render in transcripts.
|
|
23
23
|
|
|
24
|
-
In interactive mode, **Ctrl+B** moves all eligible foreground shell tasks and Subagent invocations to the background. It works even when `/bg` owns focus. The same execution continues: no cancellation, restart, new worker or timeout reset. It does not detach individual workers, ordinary file tools, or user `!` shell commands.
|
|
24
|
+
In interactive mode, **Ctrl+B** moves all eligible foreground shell tasks and Subagent invocations to the background. Once a foreground execution has run for ten seconds and can still move, the statusline shows `Ctrl+B to background`. It works even when `/bg` owns focus. The same execution continues: no cancellation, restart, new worker or timeout reset. It does not detach individual workers, ordinary file tools, or user `!` shell commands.
|
|
25
25
|
|
|
26
26
|
When nothing is eligible, the key is not consumed: it falls through to other bindings instead of reporting a no-op.
|
|
27
27
|
|