@earendil-works/pi-coding-agent 0.99.1 → 1.0.0
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 +86 -0
- package/dist/bundle/chunks/anthropic-messages-UID2PALB.js +6 -0
- package/dist/bundle/chunks/anthropic.js +2 -2
- package/dist/bundle/chunks/{azure-openai-responses-EN5WOBET.js → azure-openai-responses-AFMVM6NP.js} +1 -1
- package/dist/bundle/chunks/bedrock-converse-stream.js +1 -1
- package/dist/bundle/chunks/{chunk-AXPY26X7.js → chunk-2KTBZM5G.js} +14 -28
- package/dist/bundle/chunks/{chunk-LRS5S6EK.js → chunk-2VNGUWBO.js} +2 -2
- package/dist/bundle/chunks/chunk-33XOIQ5N.js +1204 -0
- package/dist/bundle/chunks/{chunk-W2DOMZSC.js → chunk-3LH3ZQKY.js} +1 -1
- package/dist/bundle/chunks/chunk-4KU537KD.js +2 -0
- package/dist/bundle/chunks/chunk-6D7LHLKG.js +2 -0
- package/dist/bundle/chunks/chunk-7FH3BDRG.js +82 -0
- package/dist/bundle/chunks/{chunk-LLMKQWZS.js → chunk-IBCPYVFK.js} +7 -9
- package/dist/bundle/chunks/chunk-KDN6RCEQ.js +4 -0
- package/dist/bundle/chunks/chunk-LD2P6SFZ.js +2 -0
- package/dist/bundle/chunks/{chunk-PEHWOV5U.js → chunk-LTXEMVMA.js} +18 -78
- package/dist/bundle/chunks/{chunk-J4CWPC4N.js → chunk-OSKPX3Z5.js} +1 -1
- package/dist/bundle/chunks/chunk-PRD6WYBT.js +16 -0
- package/dist/bundle/chunks/chunk-VIV3CWXG.js +2 -0
- package/dist/bundle/chunks/{cli-AZXNGIZH.js → cli-QOMC26IJ.js} +8 -6
- package/dist/bundle/chunks/{cloudflare-workers-ai-system-one-XJQQYGGU.js → cloudflare-workers-ai-system-one-NPQN263E.js} +1 -1
- package/dist/bundle/chunks/codemode-worker.js +67 -8
- package/dist/bundle/chunks/execute-GVRSEGHL.js +367 -0
- package/dist/bundle/chunks/github-copilot.js +1 -1
- package/dist/bundle/chunks/{google-generative-ai-CQAKKJTA.js → google-generative-ai-APTPZOQL.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-AE36YXJU.js → google-vertex-MXCOSOY3.js} +1 -1
- package/dist/bundle/chunks/{llama-cpp-classify-PJJYKPLD.js → llama-cpp-classify-XT44PI3C.js} +1 -1
- package/dist/bundle/chunks/{mistral-conversations-KEYTXJM7.js → mistral-conversations-DKVFNQL6.js} +1 -1
- package/dist/bundle/chunks/openai-chatgpt.js +1 -1
- package/dist/bundle/chunks/{openai-codex-responses-JQTCOVEG.js → openai-codex-responses-GK67DQQJ.js} +1 -1
- package/dist/bundle/chunks/openai-codex.js +1 -1
- package/dist/bundle/chunks/{openai-completions-XW2Q5HVC.js → openai-completions-JXDDPZ23.js} +1 -1
- package/dist/bundle/chunks/{openai-responses-6AXWFL75.js → openai-responses-CQDDLDQF.js} +1 -1
- package/dist/bundle/chunks/{openrouter-images-TPQ4V6OR.js → openrouter-images-ZVXWCSIM.js} +1 -1
- package/dist/bundle/chunks/openrouter.js +1 -1
- package/dist/bundle/chunks/pi-logo-animation-MPKZE4EK.js +2 -0
- package/dist/bundle/chunks/radius.js +1 -1
- package/dist/bundle/chunks/runtime-2SO2JDWM.js +2 -0
- package/dist/bundle/chunks/{typesafe-system-one-E7A4HNJI.js → typesafe-system-one-A4CZTQWZ.js} +1 -1
- package/dist/bundle/chunks/virtual-modules-6ZMK7GDO.js +2 -0
- package/dist/bundle/cli-runtime.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/cli/args.js +2 -2
- package/dist/cli/args.js.map +1 -1
- package/dist/config.d.ts +5 -8
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +16 -13
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +15 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +51 -10
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +13 -1
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/types.d.ts +6 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/mcp-servers.d.ts +34 -7
- package/dist/core/mcp-servers.d.ts.map +1 -1
- package/dist/core/mcp-servers.js +52 -11
- package/dist/core/mcp-servers.js.map +1 -1
- package/dist/core/model-registry.d.ts +3 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +4 -0
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-runtime.d.ts +6 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +22 -18
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/radius.d.ts +2 -0
- package/dist/core/radius.d.ts.map +1 -1
- package/dist/core/radius.js +2 -0
- package/dist/core/radius.js.map +1 -1
- package/dist/core/remote-catalog-provider.d.ts.map +1 -1
- package/dist/core/remote-catalog-provider.js +4 -9
- package/dist/core/remote-catalog-provider.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +1 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager.d.ts +7 -5
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +3 -2
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.js +1 -1
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +3 -5
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/renderers/bash.d.ts.map +1 -1
- package/dist/core/tools/renderers/bash.js +11 -31
- package/dist/core/tools/renderers/bash.js.map +1 -1
- package/dist/core/virtual-models.d.ts +2 -0
- package/dist/core/virtual-models.d.ts.map +1 -1
- package/dist/core/virtual-models.js +19 -12
- package/dist/core/virtual-models.js.map +1 -1
- package/dist/extensions/codemode/execute.d.ts.map +1 -1
- package/dist/extensions/codemode/execute.js +197 -51
- package/dist/extensions/codemode/execute.js.map +1 -1
- package/dist/extensions/codemode/renderer.d.ts.map +1 -1
- package/dist/extensions/codemode/renderer.js +43 -25
- package/dist/extensions/codemode/renderer.js.map +1 -1
- package/dist/extensions/codemode/tool.d.ts +12 -11
- package/dist/extensions/codemode/tool.d.ts.map +1 -1
- package/dist/extensions/codemode/tool.js +73 -129
- package/dist/extensions/codemode/tool.js.map +1 -1
- package/dist/extensions/codemode/worker.d.ts +1 -1
- package/dist/extensions/codemode/worker.js +1 -1
- package/dist/extensions/codemode/worker.js.map +1 -1
- package/dist/extensions/mcp/cli.d.ts.map +1 -1
- package/dist/extensions/mcp/cli.js +20 -5
- package/dist/extensions/mcp/cli.js.map +1 -1
- package/dist/extensions/mcp/config.d.ts +4 -2
- package/dist/extensions/mcp/config.d.ts.map +1 -1
- package/dist/extensions/mcp/config.js +14 -2
- package/dist/extensions/mcp/config.js.map +1 -1
- package/dist/extensions/mcp/index.d.ts +32 -8
- package/dist/extensions/mcp/index.d.ts.map +1 -1
- package/dist/extensions/mcp/index.js +220 -56
- package/dist/extensions/mcp/index.js.map +1 -1
- package/dist/extensions/mcp/oauth.d.ts +10 -7
- package/dist/extensions/mcp/oauth.d.ts.map +1 -1
- package/dist/extensions/mcp/oauth.js +56 -31
- package/dist/extensions/mcp/oauth.js.map +1 -1
- package/dist/extensions/mcp/runtime.d.ts +2 -0
- package/dist/extensions/mcp/runtime.d.ts.map +1 -1
- package/dist/extensions/mcp/runtime.js +16 -9
- package/dist/extensions/mcp/runtime.js.map +1 -1
- package/dist/extensions/mcp/tools.d.ts +5 -4
- package/dist/extensions/mcp/tools.d.ts.map +1 -1
- package/dist/extensions/mcp/tools.js +33 -15
- package/dist/extensions/mcp/tools.js.map +1 -1
- package/dist/extensions/mcp/ui.d.ts.map +1 -1
- package/dist/extensions/mcp/ui.js +4 -2
- package/dist/extensions/mcp/ui.js.map +1 -1
- package/dist/extensions/tool-search/tool.d.ts +5 -4
- package/dist/extensions/tool-search/tool.d.ts.map +1 -1
- package/dist/extensions/tool-search/tool.js +7 -28
- package/dist/extensions/tool-search/tool.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +6 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts +8 -2
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +24 -21
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/components/pi-logo-animation.d.ts +68 -0
- package/dist/modes/interactive/components/pi-logo-animation.d.ts.map +1 -0
- package/dist/modes/interactive/components/pi-logo-animation.js +1086 -0
- package/dist/modes/interactive/components/pi-logo-animation.js.map +1 -0
- package/dist/modes/interactive/components/pi-logo-animation.lazy.d.ts +7 -0
- package/dist/modes/interactive/components/pi-logo-animation.lazy.d.ts.map +1 -0
- package/dist/modes/interactive/components/pi-logo-animation.lazy.js +12 -0
- package/dist/modes/interactive/components/pi-logo-animation.lazy.js.map +1 -0
- package/dist/modes/interactive/components/pi-logo.d.ts +7 -0
- package/dist/modes/interactive/components/pi-logo.d.ts.map +1 -1
- package/dist/modes/interactive/components/pi-logo.js +13 -1
- package/dist/modes/interactive/components/pi-logo.js.map +1 -1
- package/dist/modes/interactive/components/radius-login-selector.d.ts +15 -0
- package/dist/modes/interactive/components/radius-login-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/radius-login-selector.js +85 -0
- package/dist/modes/interactive/components/radius-login-selector.js.map +1 -0
- package/dist/modes/interactive/components/settings-selector.d.ts +3 -3
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +5 -5
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +5 -4
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/components/visual-truncate.d.ts +27 -3
- package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
- package/dist/modes/interactive/components/visual-truncate.js +39 -6
- package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +10 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +153 -40
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/system-theme.d.ts +2 -1
- package/dist/modes/interactive/theme/system-theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/system-theme.js +16 -5
- package/dist/modes/interactive/theme/system-theme.js.map +1 -1
- package/docs/cli.md +8 -18
- package/docs/codemode.md +207 -0
- package/docs/docs.json +5 -1
- package/docs/environment-variables.md +2 -2
- package/docs/extensions.md +3 -3
- package/docs/index.md +1 -1
- package/docs/mcp.md +142 -82
- package/docs/models.md +22 -1
- package/docs/providers.md +18 -6
- package/docs/sdk.md +2 -2
- package/docs/settings.md +5 -3
- package/docs/usage.md +1 -1
- package/examples/extensions/built-in-tool-renderer.ts +16 -40
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/minimal-mode.ts +24 -96
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/sdk/14-codemode-mcp.ts +2 -2
- package/npm-shrinkwrap.json +25 -30
- package/package.json +10 -10
- package/dist/bundle/chunks/anthropic-messages-A6EXUBG6.js +0 -6
- package/dist/bundle/chunks/chunk-GOPCREV2.js +0 -4
- package/dist/bundle/chunks/chunk-GUORCHFS.js +0 -1435
- package/dist/bundle/chunks/chunk-HSPCVFST.js +0 -2
- package/dist/bundle/chunks/chunk-IMTXZUO7.js +0 -82
- package/dist/bundle/chunks/chunk-SLDA2X2H.js +0 -2
- package/dist/bundle/chunks/chunk-XNGRGP62.js +0 -2
- package/dist/bundle/chunks/execute-7XXPZAWW.js +0 -308
- package/dist/bundle/chunks/runtime-G5WJPRBM.js +0 -2
- package/dist/bundle/chunks/virtual-modules-CSWRO37N.js +0 -2
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
* header. Nested calls are not
|
|
7
7
|
* separate tool rows because they never reach the model as tool calls.
|
|
8
8
|
*/
|
|
9
|
-
import { Text } from "@earendil-works/pi-tui";
|
|
9
|
+
import { Container, Spacer, Text } from "@earendil-works/pi-tui";
|
|
10
10
|
import { getTextOutput, replaceTabs, str } from "../../core/tools/render-utils.js";
|
|
11
11
|
import { keyHint } from "../../modes/interactive/components/keybinding-hints.js";
|
|
12
|
+
import { VisualLinePreview } from "../../modes/interactive/components/visual-truncate.js";
|
|
12
13
|
import { highlightCode } from "../../modes/interactive/theme/theme.js";
|
|
13
14
|
const CODE_PREVIEW_LINES = 10;
|
|
14
15
|
const CALL_PREVIEW_COUNT = 8;
|
|
@@ -59,23 +60,30 @@ export const codemodeRenderers = {
|
|
|
59
60
|
renderCall(args, theme, context) {
|
|
60
61
|
// The code includes the `// @options:` line, so options show as part of the script.
|
|
61
62
|
const code = str(args?.code);
|
|
62
|
-
|
|
63
|
+
const title = theme.fg("toolTitle", theme.bold("codemode"));
|
|
64
|
+
const component = context.lastComponent ?? new Container();
|
|
65
|
+
component.clear();
|
|
63
66
|
if (code === null) {
|
|
64
|
-
|
|
67
|
+
component.addChild(new Text(`${title} ${theme.fg("error", "[invalid arg]")}`, 0, 0));
|
|
68
|
+
return component;
|
|
65
69
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
component.addChild(new Text(title, 0, 0));
|
|
71
|
+
if (code) {
|
|
72
|
+
const highlighted = highlightCode(replaceTabs(code.replace(/\r/g, "").trimEnd()), "javascript").join("\n");
|
|
73
|
+
component.addChild(context.expanded
|
|
74
|
+
? new Text(highlighted, 0, 0)
|
|
75
|
+
: new VisualLinePreview({
|
|
76
|
+
text: highlighted,
|
|
77
|
+
maxVisualLines: CODE_PREVIEW_LINES,
|
|
78
|
+
keep: "start",
|
|
79
|
+
formatHint: (hidden) => expandHint(theme, hidden, "lines"),
|
|
80
|
+
}));
|
|
72
81
|
}
|
|
73
|
-
const component = context.lastComponent ?? new Text("", 0, 0);
|
|
74
|
-
component.setText(text);
|
|
75
82
|
return component;
|
|
76
83
|
},
|
|
77
84
|
renderResult(result, options, theme, context) {
|
|
78
|
-
const
|
|
85
|
+
const component = context.lastComponent ?? new Container();
|
|
86
|
+
component.clear();
|
|
79
87
|
const calls = result.details?.calls ?? [];
|
|
80
88
|
if (calls.length > 0) {
|
|
81
89
|
const shown = options.expanded ? calls : calls.slice(-CALL_PREVIEW_COUNT);
|
|
@@ -89,7 +97,8 @@ export const codemodeRenderers = {
|
|
|
89
97
|
const total = priced.reduce((sum, call) => sum + (call.cost ?? 0), 0);
|
|
90
98
|
lines.push(theme.fg("muted", `Model calls: ${formatCost(total)}`));
|
|
91
99
|
}
|
|
92
|
-
|
|
100
|
+
component.addChild(new Spacer(1));
|
|
101
|
+
component.addChild(new Text(lines.join("\n"), 0, 0));
|
|
93
102
|
}
|
|
94
103
|
// Drop the "Script completed\nWall time ...\nOutput:\n" header. Rejected input (invalid options)
|
|
95
104
|
// has no header.
|
|
@@ -100,19 +109,28 @@ export const codemodeRenderers = {
|
|
|
100
109
|
: getTextOutput({ ...result, content: hasHeader ? rest : result.content }, context.showImages).trim();
|
|
101
110
|
if (output) {
|
|
102
111
|
const color = context.isError ? "error" : "toolOutput";
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
112
|
+
const styled = replaceTabs(output)
|
|
113
|
+
.split("\n")
|
|
114
|
+
.map((line) => theme.fg(color, line))
|
|
115
|
+
.join("\n");
|
|
116
|
+
component.addChild(new Spacer(1));
|
|
117
|
+
if (options.expanded) {
|
|
118
|
+
component.addChild(new Text(styled, 0, 0));
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
// Limit wrapped lines, not logical ones: script output is often one long JSON line.
|
|
122
|
+
component.addChild(new VisualLinePreview({
|
|
123
|
+
text: styled,
|
|
124
|
+
maxVisualLines: OUTPUT_PREVIEW_LINES,
|
|
125
|
+
keep: "start",
|
|
126
|
+
formatHint: (hidden) => expandHint(theme, hidden, "lines"),
|
|
127
|
+
}));
|
|
128
|
+
// The collapsed preview hides the truncation notice at the end, so name the file here.
|
|
129
|
+
const fullOutputPath = result.details?.fullOutputPath;
|
|
130
|
+
if (fullOutputPath)
|
|
131
|
+
component.addChild(new Text(theme.fg("muted", `Full output: ${fullOutputPath}`), 0, 0));
|
|
132
|
+
}
|
|
113
133
|
}
|
|
114
|
-
const component = context.lastComponent ?? new Text("", 0, 0);
|
|
115
|
-
component.setText(sections.length > 0 ? `\n${sections.join("\n\n")}` : "");
|
|
116
134
|
return component;
|
|
117
135
|
},
|
|
118
136
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderer.js","sourceRoot":"","sources":["../../../src/extensions/codemode/renderer.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Presentation for the codemode tool.\n *\n * The call shows the script; the result lists the nested tool calls with their status as they\n * run and the cost of its model calls, followed by the script output without the \"Script completed\"\n * header. Nested calls are not\n * separate tool rows because they never reach the model as tool calls.\n */\n\nimport { Text } from \"@earendil-works/pi-tui\";\nimport type { ToolDefinition } from \"../../core/extensions/types.ts\";\nimport { getTextOutput, replaceTabs, str } from \"../../core/tools/render-utils.ts\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { highlightCode, type Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport type { CodemodeNestedCall, CodemodeToolDetails } from \"./tool.ts\";\n\nconst CODE_PREVIEW_LINES = 10;\nconst CALL_PREVIEW_COUNT = 8;\nconst OUTPUT_PREVIEW_LINES = 5;\nconst COLLAPSED_ARGS_CHARS = 80;\nconst SCRIPT_HEADER = /^Script (completed|failed)\\nWall time [\\d.]+ seconds\\nOutput:\\n$/;\n\nfunction expandHint(theme: Theme, hidden: number, noun: string): string {\n\treturn `${theme.fg(\"muted\", `... (${hidden} more ${noun},`)} ${keyHint(\"app.tools.expand\", \"to expand\")}${theme.fg(\"muted\", \")\")}`;\n}\n\nfunction formatDuration(ms: number | undefined): string {\n\tif (ms === undefined) return \"\";\n\treturn ms < 1000 ? `${Math.round(ms)}ms` : `${(ms / 1000).toFixed(1)}s`;\n}\n\n/** Cents for larger amounts, two significant digits for the fractions of a cent classifier calls cost. */\nfunction formatCost(cost: number): string {\n\treturn `$${cost >= 0.01 ? cost.toFixed(2) : cost.toPrecision(2)}`;\n}\n\nfunction statusIcon(call: CodemodeNestedCall, theme: Theme): string {\n\tswitch (call.status) {\n\t\tcase \"running\":\n\t\t\treturn theme.fg(\"warning\", \"…\");\n\t\tcase \"ok\":\n\t\t\treturn theme.fg(\"success\", \"✓\");\n\t\tcase \"error\":\n\t\t\treturn theme.fg(\"error\", \"✗\");\n\t\tcase \"cancelled\":\n\t\t\treturn theme.fg(\"muted\", \"⊘\");\n\t}\n}\n\nfunction formatCall(call: CodemodeNestedCall, theme: Theme, expanded: boolean): string {\n\tconst args =\n\t\t!expanded && call.args.length > COLLAPSED_ARGS_CHARS\n\t\t\t? `${call.args.slice(0, COLLAPSED_ARGS_CHARS - 3)}...`\n\t\t\t: call.args;\n\tconst duration = formatDuration(call.durationMs);\n\tlet line = `${statusIcon(call, theme)} ${theme.fg(\"toolTitle\", call.name)}`;\n\tif (args) line += ` ${theme.fg(\"muted\", args)}`;\n\tif (duration) line += ` ${theme.fg(\"dim\", duration)}`;\n\tif (call.cost) line += ` ${theme.fg(\"dim\", formatCost(call.cost))}`;\n\tif (expanded && call.error) line += `\\n ${theme.fg(\"error\", call.error.split(\"\\n\").join(\"\\n \"))}`;\n\treturn line;\n}\n\nexport const codemodeRenderers: Pick<\n\tToolDefinition<any, CodemodeToolDetails | undefined>,\n\t\"renderCall\" | \"renderResult\"\n> = {\n\trenderCall(args, theme, context) {\n\t\t// The code includes the `// @options:` line, so options show as part of the script.\n\t\tconst code = str((args as { code?: unknown } | undefined)?.code);\n\t\tlet text = theme.fg(\"toolTitle\", theme.bold(\"codemode\"));\n\t\tif (code === null) {\n\t\t\ttext += ` ${theme.fg(\"error\", \"[invalid arg]\")}`;\n\t\t} else if (code) {\n\t\t\tconst lines = highlightCode(replaceTabs(code.replace(/\\r/g, \"\").trimEnd()), \"javascript\");\n\t\t\tconst shown = context.expanded ? lines : lines.slice(0, CODE_PREVIEW_LINES);\n\t\t\ttext += `\\n${shown.join(\"\\n\")}`;\n\t\t\tif (shown.length < lines.length) text += `\\n${expandHint(theme, lines.length - shown.length, \"lines\")}`;\n\t\t}\n\t\tconst component = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\tcomponent.setText(text);\n\t\treturn component;\n\t},\n\trenderResult(result, options, theme, context) {\n\t\tconst sections: string[] = [];\n\t\tconst calls = result.details?.calls ?? [];\n\t\tif (calls.length > 0) {\n\t\t\tconst shown = options.expanded ? calls : calls.slice(-CALL_PREVIEW_COUNT);\n\t\t\tconst lines = shown.map((call) => formatCall(call, theme, options.expanded));\n\t\t\tif (shown.length < calls.length) {\n\t\t\t\tlines.unshift(\n\t\t\t\t\t`${theme.fg(\"muted\", `... (${calls.length - shown.length} earlier calls,`)} ${keyHint(\"app.tools.expand\", \"to expand\")}${theme.fg(\"muted\", \")\")}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\t// Collapsed rows hide earlier calls, so the total covers every call.\n\t\t\tconst priced = calls.filter((call) => call.cost);\n\t\t\tif (priced.length > 1) {\n\t\t\t\tconst total = priced.reduce((sum, call) => sum + (call.cost ?? 0), 0);\n\t\t\t\tlines.push(theme.fg(\"muted\", `Model calls: ${formatCost(total)}`));\n\t\t\t}\n\t\t\tsections.push(lines.join(\"\\n\"));\n\t\t}\n\n\t\t// Drop the \"Script completed\\nWall time ...\\nOutput:\\n\" header. Rejected input (invalid options)\n\t\t// has no header.\n\t\tconst [first, ...rest] = result.content;\n\t\tconst hasHeader = first?.type === \"text\" && SCRIPT_HEADER.test(first.text);\n\t\tconst output = options.isPartial\n\t\t\t? \"\"\n\t\t\t: getTextOutput({ ...result, content: hasHeader ? rest : result.content }, context.showImages).trim();\n\t\tif (output) {\n\t\t\tconst color = context.isError ? \"error\" : \"toolOutput\";\n\t\t\tconst lines = replaceTabs(output).split(\"\\n\");\n\t\t\tconst shown = options.expanded ? lines : lines.slice(0, OUTPUT_PREVIEW_LINES);\n\t\t\tlet text = shown.map((line) => theme.fg(color, line)).join(\"\\n\");\n\t\t\tif (shown.length < lines.length) text += `\\n${expandHint(theme, lines.length - shown.length, \"lines\")}`;\n\t\t\t// The collapsed preview hides the truncation notice at the end, so name the file here.\n\t\t\tconst fullOutputPath = result.details?.fullOutputPath;\n\t\t\tif (fullOutputPath && !options.expanded) text += `\\n${theme.fg(\"muted\", `Full output: ${fullOutputPath}`)}`;\n\t\t\tsections.push(text);\n\t\t}\n\n\t\tconst component = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\tcomponent.setText(sections.length > 0 ? `\\n${sections.join(\"\\n\\n\")}` : \"\");\n\t\treturn component;\n\t},\n};\n"]}
|
|
1
|
+
{"version":3,"file":"renderer.js","sourceRoot":"","sources":["../../../src/extensions/codemode/renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAEjE,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,OAAO,EAAE,MAAM,wDAAwD,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,uDAAuD,CAAC;AAC1F,OAAO,EAAE,aAAa,EAAc,MAAM,wCAAwC,CAAC;AAGnF,MAAM,kBAAkB,GAAG,EAAE,CAAC;AAC9B,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAC7B,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAC/B,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAChC,MAAM,aAAa,GAAG,kEAAkE,CAAC;AAEzF,SAAS,UAAU,CAAC,KAAY,EAAE,MAAc,EAAE,IAAY;IAC7D,OAAO,GAAG,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,MAAM,SAAS,IAAI,GAAG,CAAC,IAAI,OAAO,CAAC,kBAAkB,EAAE,WAAW,CAAC,GAAG,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,CAAC;AACpI,CAAC;AAED,SAAS,cAAc,CAAC,EAAsB;IAC7C,IAAI,EAAE,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IAChC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;AACzE,CAAC;AAED,0GAA0G;AAC1G,SAAS,UAAU,CAAC,IAAY;IAC/B,OAAO,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;AACnE,CAAC;AAED,SAAS,UAAU,CAAC,IAAwB,EAAE,KAAY;IACzD,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;QACrB,KAAK,SAAS;YACb,OAAO,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QACjC,KAAK,IAAI;YACR,OAAO,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QACjC,KAAK,OAAO;YACX,OAAO,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAC/B,KAAK,WAAW;YACf,OAAO,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAChC,CAAC;AACF,CAAC;AAED,SAAS,UAAU,CAAC,IAAwB,EAAE,KAAY,EAAE,QAAiB;IAC5E,MAAM,IAAI,GACT,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,oBAAoB;QACnD,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,oBAAoB,GAAG,CAAC,CAAC,KAAK;QACtD,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;IACd,MAAM,QAAQ,GAAG,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACjD,IAAI,IAAI,GAAG,GAAG,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IAC5E,IAAI,IAAI;QAAE,IAAI,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC;IAChD,IAAI,QAAQ;QAAE,IAAI,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,CAAC;IACtD,IAAI,IAAI,CAAC,IAAI;QAAE,IAAI,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;IACpE,IAAI,QAAQ,IAAI,IAAI,CAAC,KAAK;QAAE,IAAI,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;IACxG,OAAO,IAAI,CAAC;AACb,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAG1B;IACH,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO;QAC9B,oFAAoF;QACpF,MAAM,IAAI,GAAG,GAAG,CAAE,IAAuC,EAAE,IAAI,CAAC,CAAC;QACjE,MAAM,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QAC5D,MAAM,SAAS,GAAI,OAAO,CAAC,aAAuC,IAAI,IAAI,SAAS,EAAE,CAAC;QACtF,SAAS,CAAC,KAAK,EAAE,CAAC;QAClB,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YACnB,SAAS,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,GAAG,KAAK,IAAI,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACrF,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,SAAS,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC1C,IAAI,IAAI,EAAE,CAAC;YACV,MAAM,WAAW,GAAG,aAAa,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC3G,SAAS,CAAC,QAAQ,CACjB,OAAO,CAAC,QAAQ;gBACf,CAAC,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC;gBAC7B,CAAC,CAAC,IAAI,iBAAiB,CAAC;oBACtB,IAAI,EAAE,WAAW;oBACjB,cAAc,EAAE,kBAAkB;oBAClC,IAAI,EAAE,OAAO;oBACb,UAAU,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC;iBAC1D,CAAC,CACJ,CAAC;QACH,CAAC;QACD,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO;QAC3C,MAAM,SAAS,GAAI,OAAO,CAAC,aAAuC,IAAI,IAAI,SAAS,EAAE,CAAC;QACtF,SAAS,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC;QAC1C,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,kBAAkB,CAAC,CAAC;YAC1E,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC7E,IAAI,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;gBACjC,KAAK,CAAC,OAAO,CACZ,GAAG,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,iBAAiB,CAAC,IAAI,OAAO,CAAC,kBAAkB,EAAE,WAAW,CAAC,GAAG,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,CACjJ,CAAC;YACH,CAAC;YACD,qEAAqE;YACrE,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBACtE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,gBAAgB,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;YACpE,CAAC;YACD,SAAS,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YAClC,SAAS,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACtD,CAAC;QAED,iGAAiG;QACjG,iBAAiB;QACjB,MAAM,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC;QACxC,MAAM,SAAS,GAAG,KAAK,EAAE,IAAI,KAAK,MAAM,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3E,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS;YAC/B,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,aAAa,CAAC,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC;QACvG,IAAI,MAAM,EAAE,CAAC;YACZ,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC;YACvD,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC;iBAChC,KAAK,CAAC,IAAI,CAAC;iBACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;iBACpC,IAAI,CAAC,IAAI,CAAC,CAAC;YACb,SAAS,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YAClC,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;gBACtB,SAAS,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAC5C,CAAC;iBAAM,CAAC;gBACP,oFAAoF;gBACpF,SAAS,CAAC,QAAQ,CACjB,IAAI,iBAAiB,CAAC;oBACrB,IAAI,EAAE,MAAM;oBACZ,cAAc,EAAE,oBAAoB;oBACpC,IAAI,EAAE,OAAO;oBACb,UAAU,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC;iBAC1D,CAAC,CACF,CAAC;gBACF,uFAAuF;gBACvF,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,EAAE,cAAc,CAAC;gBACtD,IAAI,cAAc;oBAAE,SAAS,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,gBAAgB,cAAc,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAC7G,CAAC;QACF,CAAC;QACD,OAAO,SAAS,CAAC;IAClB,CAAC;CACD,CAAC","sourcesContent":["/**\n * Presentation for the codemode tool.\n *\n * The call shows the script; the result lists the nested tool calls with their status as they\n * run and the cost of its model calls, followed by the script output without the \"Script completed\"\n * header. Nested calls are not\n * separate tool rows because they never reach the model as tool calls.\n */\n\nimport { Container, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { ToolDefinition } from \"../../core/extensions/types.ts\";\nimport { getTextOutput, replaceTabs, str } from \"../../core/tools/render-utils.ts\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { VisualLinePreview } from \"../../modes/interactive/components/visual-truncate.ts\";\nimport { highlightCode, type Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport type { CodemodeNestedCall, CodemodeToolDetails } from \"./tool.ts\";\n\nconst CODE_PREVIEW_LINES = 10;\nconst CALL_PREVIEW_COUNT = 8;\nconst OUTPUT_PREVIEW_LINES = 5;\nconst COLLAPSED_ARGS_CHARS = 80;\nconst SCRIPT_HEADER = /^Script (completed|failed)\\nWall time [\\d.]+ seconds\\nOutput:\\n$/;\n\nfunction expandHint(theme: Theme, hidden: number, noun: string): string {\n\treturn `${theme.fg(\"muted\", `... (${hidden} more ${noun},`)} ${keyHint(\"app.tools.expand\", \"to expand\")}${theme.fg(\"muted\", \")\")}`;\n}\n\nfunction formatDuration(ms: number | undefined): string {\n\tif (ms === undefined) return \"\";\n\treturn ms < 1000 ? `${Math.round(ms)}ms` : `${(ms / 1000).toFixed(1)}s`;\n}\n\n/** Cents for larger amounts, two significant digits for the fractions of a cent classifier calls cost. */\nfunction formatCost(cost: number): string {\n\treturn `$${cost >= 0.01 ? cost.toFixed(2) : cost.toPrecision(2)}`;\n}\n\nfunction statusIcon(call: CodemodeNestedCall, theme: Theme): string {\n\tswitch (call.status) {\n\t\tcase \"running\":\n\t\t\treturn theme.fg(\"warning\", \"…\");\n\t\tcase \"ok\":\n\t\t\treturn theme.fg(\"success\", \"✓\");\n\t\tcase \"error\":\n\t\t\treturn theme.fg(\"error\", \"✗\");\n\t\tcase \"cancelled\":\n\t\t\treturn theme.fg(\"muted\", \"⊘\");\n\t}\n}\n\nfunction formatCall(call: CodemodeNestedCall, theme: Theme, expanded: boolean): string {\n\tconst args =\n\t\t!expanded && call.args.length > COLLAPSED_ARGS_CHARS\n\t\t\t? `${call.args.slice(0, COLLAPSED_ARGS_CHARS - 3)}...`\n\t\t\t: call.args;\n\tconst duration = formatDuration(call.durationMs);\n\tlet line = `${statusIcon(call, theme)} ${theme.fg(\"toolTitle\", call.name)}`;\n\tif (args) line += ` ${theme.fg(\"muted\", args)}`;\n\tif (duration) line += ` ${theme.fg(\"dim\", duration)}`;\n\tif (call.cost) line += ` ${theme.fg(\"dim\", formatCost(call.cost))}`;\n\tif (expanded && call.error) line += `\\n ${theme.fg(\"error\", call.error.split(\"\\n\").join(\"\\n \"))}`;\n\treturn line;\n}\n\nexport const codemodeRenderers: Pick<\n\tToolDefinition<any, CodemodeToolDetails | undefined>,\n\t\"renderCall\" | \"renderResult\"\n> = {\n\trenderCall(args, theme, context) {\n\t\t// The code includes the `// @options:` line, so options show as part of the script.\n\t\tconst code = str((args as { code?: unknown } | undefined)?.code);\n\t\tconst title = theme.fg(\"toolTitle\", theme.bold(\"codemode\"));\n\t\tconst component = (context.lastComponent as Container | undefined) ?? new Container();\n\t\tcomponent.clear();\n\t\tif (code === null) {\n\t\t\tcomponent.addChild(new Text(`${title} ${theme.fg(\"error\", \"[invalid arg]\")}`, 0, 0));\n\t\t\treturn component;\n\t\t}\n\t\tcomponent.addChild(new Text(title, 0, 0));\n\t\tif (code) {\n\t\t\tconst highlighted = highlightCode(replaceTabs(code.replace(/\\r/g, \"\").trimEnd()), \"javascript\").join(\"\\n\");\n\t\t\tcomponent.addChild(\n\t\t\t\tcontext.expanded\n\t\t\t\t\t? new Text(highlighted, 0, 0)\n\t\t\t\t\t: new VisualLinePreview({\n\t\t\t\t\t\t\ttext: highlighted,\n\t\t\t\t\t\t\tmaxVisualLines: CODE_PREVIEW_LINES,\n\t\t\t\t\t\t\tkeep: \"start\",\n\t\t\t\t\t\t\tformatHint: (hidden) => expandHint(theme, hidden, \"lines\"),\n\t\t\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\treturn component;\n\t},\n\trenderResult(result, options, theme, context) {\n\t\tconst component = (context.lastComponent as Container | undefined) ?? new Container();\n\t\tcomponent.clear();\n\t\tconst calls = result.details?.calls ?? [];\n\t\tif (calls.length > 0) {\n\t\t\tconst shown = options.expanded ? calls : calls.slice(-CALL_PREVIEW_COUNT);\n\t\t\tconst lines = shown.map((call) => formatCall(call, theme, options.expanded));\n\t\t\tif (shown.length < calls.length) {\n\t\t\t\tlines.unshift(\n\t\t\t\t\t`${theme.fg(\"muted\", `... (${calls.length - shown.length} earlier calls,`)} ${keyHint(\"app.tools.expand\", \"to expand\")}${theme.fg(\"muted\", \")\")}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\t// Collapsed rows hide earlier calls, so the total covers every call.\n\t\t\tconst priced = calls.filter((call) => call.cost);\n\t\t\tif (priced.length > 1) {\n\t\t\t\tconst total = priced.reduce((sum, call) => sum + (call.cost ?? 0), 0);\n\t\t\t\tlines.push(theme.fg(\"muted\", `Model calls: ${formatCost(total)}`));\n\t\t\t}\n\t\t\tcomponent.addChild(new Spacer(1));\n\t\t\tcomponent.addChild(new Text(lines.join(\"\\n\"), 0, 0));\n\t\t}\n\n\t\t// Drop the \"Script completed\\nWall time ...\\nOutput:\\n\" header. Rejected input (invalid options)\n\t\t// has no header.\n\t\tconst [first, ...rest] = result.content;\n\t\tconst hasHeader = first?.type === \"text\" && SCRIPT_HEADER.test(first.text);\n\t\tconst output = options.isPartial\n\t\t\t? \"\"\n\t\t\t: getTextOutput({ ...result, content: hasHeader ? rest : result.content }, context.showImages).trim();\n\t\tif (output) {\n\t\t\tconst color = context.isError ? \"error\" : \"toolOutput\";\n\t\t\tconst styled = replaceTabs(output)\n\t\t\t\t.split(\"\\n\")\n\t\t\t\t.map((line) => theme.fg(color, line))\n\t\t\t\t.join(\"\\n\");\n\t\t\tcomponent.addChild(new Spacer(1));\n\t\t\tif (options.expanded) {\n\t\t\t\tcomponent.addChild(new Text(styled, 0, 0));\n\t\t\t} else {\n\t\t\t\t// Limit wrapped lines, not logical ones: script output is often one long JSON line.\n\t\t\t\tcomponent.addChild(\n\t\t\t\t\tnew VisualLinePreview({\n\t\t\t\t\t\ttext: styled,\n\t\t\t\t\t\tmaxVisualLines: OUTPUT_PREVIEW_LINES,\n\t\t\t\t\t\tkeep: \"start\",\n\t\t\t\t\t\tformatHint: (hidden) => expandHint(theme, hidden, \"lines\"),\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\t// The collapsed preview hides the truncation notice at the end, so name the file here.\n\t\t\t\tconst fullOutputPath = result.details?.fullOutputPath;\n\t\t\t\tif (fullOutputPath) component.addChild(new Text(theme.fg(\"muted\", `Full output: ${fullOutputPath}`), 0, 0));\n\t\t\t}\n\t\t}\n\t\treturn component;\n\t},\n};\n"]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The `codemode` tool: the model writes JavaScript that calls other tools. Scripts use `tools`,
|
|
3
3
|
* `ALL_TOOLS`, `text()`, `image()`, `exit()`, `store()`/`load()`, `console.*`, and `return <value>`,
|
|
4
|
-
* may start with a `// @options:` line, and reach the model catalog and
|
|
5
|
-
* `models.*`. Results start with a "Script completed" or "Script failed" header.
|
|
4
|
+
* may start with a `// @options:` line, and reach the model catalog, classifiers, and image models
|
|
5
|
+
* through `models.*`. Results start with a "Script completed" or "Script failed" header.
|
|
6
6
|
*
|
|
7
7
|
* Scripts can call the agent loop's nested tools: active `direct` tools and every `codemode` or
|
|
8
8
|
* `deferred` tool. Nested calls run through the agent loop's tool pipeline (`ctx.executeTool`), so
|
|
@@ -34,7 +34,7 @@ export interface CodemodeStoreEntryData {
|
|
|
34
34
|
delete: string[];
|
|
35
35
|
}
|
|
36
36
|
/** The part of the model registry that scripts reach through `models`. */
|
|
37
|
-
export type CodemodeModelRuntime = Pick<ModelRegistry, "getModelsOfType" | "getAvailableOfType" | "getModelOfType" | "classify">;
|
|
37
|
+
export type CodemodeModelRuntime = Pick<ModelRegistry, "getModelsOfType" | "getAvailableOfType" | "getModelOfType" | "classify" | "generateImages">;
|
|
38
38
|
export interface CodemodeToolOptions {
|
|
39
39
|
/** Namespace of a tool, for `searchTools()` ranking and its `namespace` filter. */
|
|
40
40
|
getToolNamespace?: (toolName: string) => ToolNamespace | undefined;
|
|
@@ -82,11 +82,11 @@ export interface CodemodeToolDetails {
|
|
|
82
82
|
fullOutputPath?: string;
|
|
83
83
|
}
|
|
84
84
|
export declare const codemodeToolSystemPromptContribution: {
|
|
85
|
-
readonly snippet: "Run JavaScript that calls other tools
|
|
86
|
-
readonly guidelines: readonly ["Use codemode to batch
|
|
85
|
+
readonly snippet: "Run JavaScript that calls other tools";
|
|
86
|
+
readonly guidelines: readonly ["Use codemode to batch independent tool calls (Promise.allSettled), chain them, or filter large output, instead of many separate calls."];
|
|
87
87
|
};
|
|
88
|
-
/**
|
|
89
|
-
export declare const
|
|
88
|
+
/** The reference for scripts: globals, tool results, `store()`, the `models` API, and limits. */
|
|
89
|
+
export declare const CODEMODE_DOCS_PATH: string;
|
|
90
90
|
/** Default for {@link CodemodeDescriptionOptions.inlineBudget}, in estimated tokens. */
|
|
91
91
|
export declare const DEFAULT_CODEMODE_INLINE_BUDGET = 3000;
|
|
92
92
|
/** What a script sees of a tool. Tools without an output schema resolve to their text output. */
|
|
@@ -107,10 +107,11 @@ export interface CodemodeDescriptionOptions {
|
|
|
107
107
|
inlineBudget?: number;
|
|
108
108
|
}
|
|
109
109
|
/**
|
|
110
|
-
* Model-facing description: the helper list, guidance for
|
|
111
|
-
* MCP tools
|
|
112
|
-
*
|
|
113
|
-
*
|
|
110
|
+
* Model-facing description: the helper list, guidance for finding tools that are not listed, the
|
|
111
|
+
* shared MCP types when listed tools need them, the `models` API, and one section per listed tool,
|
|
112
|
+
* grouped by namespace. Deferred tools are never listed and do not affect the description at all, so
|
|
113
|
+
* it stays the same while MCP servers connect or change their tools. Tool sections are limited to
|
|
114
|
+
* `inlineBudget`.
|
|
114
115
|
*/
|
|
115
116
|
export declare function createCodemodeDescription(tools: readonly AgentTool<any>[], options?: CodemodeDescriptionOptions): string;
|
|
116
117
|
export declare function createCodemodeToolDefinition(options?: CodemodeToolOptions): ToolDefinition<typeof codemodeSchema, CodemodeToolDetails | undefined>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../../src/extensions/codemode/tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;
|
|
1
|
+
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../../src/extensions/codemode/tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The `codemode` tool: the model writes JavaScript that calls other tools. Scripts use `tools`,
|
|
3
3
|
* `ALL_TOOLS`, `text()`, `image()`, `exit()`, `store()`/`load()`, `console.*`, and `return <value>`,
|
|
4
|
-
* may start with a `// @options:` line, and reach the model catalog and
|
|
5
|
-
* `models.*`. Results start with a "Script completed" or "Script failed" header.
|
|
4
|
+
* may start with a `// @options:` line, and reach the model catalog, classifiers, and image models
|
|
5
|
+
* through `models.*`. Results start with a "Script completed" or "Script failed" header.
|
|
6
6
|
*
|
|
7
7
|
* Scripts can call the agent loop's nested tools: active `direct` tools and every `codemode` or
|
|
8
8
|
* `deferred` tool. Nested calls run through the agent loop's tool pipeline (`ctx.executeTool`), so
|
|
@@ -20,9 +20,11 @@
|
|
|
20
20
|
* calls; successful scripts append their writes to the session as `codemode-store` custom entries,
|
|
21
21
|
* so each branch sees the values written on its own path.
|
|
22
22
|
*/
|
|
23
|
-
import {
|
|
23
|
+
import { join } from "node:path";
|
|
24
|
+
import { MCP_TYPESCRIPT_PREAMBLE, mcpStructuredContentSchema, renderToolOutputType, renderToolSample, toCodemodeIdentifier, } from "@earendil-works/pi-codemode/declarations";
|
|
24
25
|
import { CODEMODE_SOURCE_GRAMMAR } from "@earendil-works/pi-codemode/source";
|
|
25
26
|
import { Type } from "typebox";
|
|
27
|
+
import { getDocsPath } from "../../config.js";
|
|
26
28
|
import { wrapToolDefinition } from "../../core/tools/tool-definition-wrapper.js";
|
|
27
29
|
import { loadCodemodeExecutor } from "./execute.lazy.js";
|
|
28
30
|
import { codemodeRenderers } from "./renderer.js";
|
|
@@ -32,7 +34,7 @@ export const CODEMODE_STORE_ENTRY_TYPE = "codemode-store";
|
|
|
32
34
|
const TEXT_OUTPUT_SCHEMA = { type: "string" };
|
|
33
35
|
export const codemodeSchema = Type.Object({
|
|
34
36
|
code: Type.String({
|
|
35
|
-
description:
|
|
37
|
+
description: "Raw JavaScript source.",
|
|
36
38
|
}),
|
|
37
39
|
});
|
|
38
40
|
/**
|
|
@@ -43,97 +45,29 @@ export function isCodemodeTool(tool) {
|
|
|
43
45
|
return tool.name === CODEMODE_TOOL_NAME && tool.parameters === codemodeSchema;
|
|
44
46
|
}
|
|
45
47
|
export const codemodeToolSystemPromptContribution = {
|
|
46
|
-
snippet: "Run JavaScript that calls other tools
|
|
48
|
+
snippet: "Run JavaScript that calls other tools",
|
|
47
49
|
guidelines: [
|
|
48
|
-
"Use codemode to batch
|
|
50
|
+
"Use codemode to batch independent tool calls (Promise.allSettled), chain them, or filter large output, instead of many separate calls.",
|
|
49
51
|
],
|
|
50
52
|
};
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
62
|
-
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
- \`text(value: string | number | boolean | undefined | null)\`: Appends a text item. Non-string values are stringified with \`JSON.stringify(...)\` when possible.
|
|
69
|
-
- \`image(imageUrlOrItem: string | { image_url: string } | ImageContent)\`: Appends an image item. \`image_url\` should be a base64-encoded \`data:\` URL. To forward an MCP tool image, pass an individual \`ImageContent\` block from \`result.content\`, for example \`image(result.content[0])\`.
|
|
70
|
-
- \`store(key: string, value: any)\`: stores a serializable value under a string key for later \`codemode\` calls in the same session. Storing \`undefined\` deletes the key. Writes are kept only if the script succeeds.
|
|
71
|
-
- \`load(key: string)\`: returns the stored value for a string key, or \`undefined\` if it is missing.
|
|
72
|
-
- \`ALL_TOOLS\`: metadata for the enabled nested tools as \`{ name, description }\` entries.
|
|
73
|
-
- \`searchTools(query: string, options?: { limit?: number; namespace?: string })\`: resolves to the nested tools that best match the query (BM25, default limit 8), as \`{ name, description }\` entries like \`ALL_TOOLS\`.
|
|
74
|
-
- \`describeTool(name: string)\`: resolves to the description and declaration of a nested tool, or \`undefined\`.
|
|
75
|
-
- \`console.log(...)\` and the other \`console\` methods append a text item like \`text()\`.
|
|
76
|
-
- \`return value\` at the top level appends the value like \`text()\`.`;
|
|
77
|
-
const MODEL_TYPES = `type ModelType = "chat" | "image" | "classifier";
|
|
78
|
-
/** A model catalog entry. \`provider\` and \`id\` identify it; the other fields depend on the type. */
|
|
79
|
-
interface ModelInfo {
|
|
80
|
-
type?: ModelType;
|
|
81
|
-
provider: string;
|
|
82
|
-
id: string;
|
|
83
|
-
name: string;
|
|
84
|
-
api: string;
|
|
85
|
-
input: ("text" | "image")[];
|
|
86
|
-
contextWindow?: number;
|
|
87
|
-
[key: string]: unknown;
|
|
88
|
-
}
|
|
89
|
-
type ClassifierQuestion =
|
|
90
|
-
| { type: "choice"; instructions: string; criteria: Record<string, string> }
|
|
91
|
-
| { type: "score"; instructions: string; criteria: string[] }
|
|
92
|
-
| { type: "bool"; instructions: string; criteria: { true: string; false: string } };
|
|
93
|
-
type ClassifierAnswer =
|
|
94
|
-
| { type: "choice"; choice: string; probabilities: Record<string, number>; confidence: number }
|
|
95
|
-
| { type: "score"; score: number; confidence: number }
|
|
96
|
-
| { type: "bool"; probability: number };
|
|
97
|
-
interface ClassifierContext {
|
|
98
|
-
state: Record<string, unknown>;
|
|
99
|
-
questions: Record<string, ClassifierQuestion>;
|
|
53
|
+
/** The reference for scripts: globals, tool results, `store()`, the `models` API, and limits. */
|
|
54
|
+
export const CODEMODE_DOCS_PATH = join(getDocsPath(), "codemode.md");
|
|
55
|
+
const DESCRIPTION_INTRO = `Run JavaScript that calls other tools. The input is raw JavaScript (not JSON, no code fence), run as an async function body in a QuickJS sandbox: top-level \`await\` and \`return\` work. No Node, file system, network, or timers.
|
|
56
|
+
- \`await tools.<name>({ ...args })\` resolves to a string, or an object if the tool's declaration says so, and rejects with an Error on failure. Calls still running when the script ends are cancelled.
|
|
57
|
+
- Optional first line: \`// @options: {"max_output_tokens": 10000, "timeout_ms": 60000}\``;
|
|
58
|
+
/** One line per global. The details live in {@link CODEMODE_DOCS_PATH}. */
|
|
59
|
+
function describeGlobals(models) {
|
|
60
|
+
const lines = [
|
|
61
|
+
"Globals:",
|
|
62
|
+
"- `text(value)`, `image(dataUrlOrImageBlock)`, `console.log(...)`, and top-level `return` add output; `exit()` ends the script.",
|
|
63
|
+
"- `store(key, value)` and `load(key)` keep JSON values across codemode calls.",
|
|
64
|
+
"- `ALL_TOOLS`, `searchTools(query, { limit?, namespace? })`, `describeTool(name)`, `describeNamespace(name)`: find unlisted tools, such as MCP tools.",
|
|
65
|
+
];
|
|
66
|
+
if (models) {
|
|
67
|
+
lines.push(`- \`models\`: classifiers and image generation. Read ${CODEMODE_DOCS_PATH} first.`);
|
|
68
|
+
}
|
|
69
|
+
return lines.join("\n");
|
|
100
70
|
}
|
|
101
|
-
interface ClassifierResult {
|
|
102
|
-
api: string;
|
|
103
|
-
provider: string;
|
|
104
|
-
model: string;
|
|
105
|
-
answers: Record<string, ClassifierAnswer>;
|
|
106
|
-
/** Set when the service reports token counts. Cost is in USD. */
|
|
107
|
-
usage?: { input: number; output: number; totalTokens: number; cost: { total: number } };
|
|
108
|
-
stopReason: "stop" | "error" | "aborted";
|
|
109
|
-
errorMessage?: string;
|
|
110
|
-
timestamp: number;
|
|
111
|
-
}`;
|
|
112
|
-
/** Declarations of the `models` globals; codemode-execute.ts implements them. */
|
|
113
|
-
export const MODEL_GLOBAL_DECLARATIONS = [
|
|
114
|
-
{
|
|
115
|
-
name: "models.getModelsOfType",
|
|
116
|
-
description: "Every known model of a type, optionally for one provider.",
|
|
117
|
-
signature: "(type: ModelType, provider?: string): Promise<ModelInfo[]>",
|
|
118
|
-
},
|
|
119
|
-
{
|
|
120
|
-
name: "models.getAvailableOfType",
|
|
121
|
-
description: "Models of a type whose provider has working credentials.",
|
|
122
|
-
signature: "(type: ModelType, provider?: string): Promise<ModelInfo[]>",
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
name: "models.getModelOfType",
|
|
126
|
-
description: "One catalog entry, or undefined.",
|
|
127
|
-
signature: "(type: ModelType, provider: string, id: string): Promise<ModelInfo | undefined>",
|
|
128
|
-
},
|
|
129
|
-
{
|
|
130
|
-
name: "models.classify",
|
|
131
|
-
description: "Run a classifier model on one state. Only `provider` and `id` of `model` are used. Provider errors do not throw: check `stopReason` and `errorMessage`.",
|
|
132
|
-
signature: "(model: ModelInfo, context: ClassifierContext): Promise<ClassifierResult>",
|
|
133
|
-
},
|
|
134
|
-
];
|
|
135
|
-
const DEFERRED_TOOLS_GUIDANCE = `Some deferred nested tools may be omitted from this description. They are still available on the global \`tools\` object and listed in \`ALL_TOOLS\`.
|
|
136
|
-
To find one, call \`await searchTools(query)\`, or filter \`ALL_TOOLS\` by \`name\` and \`description\`.`;
|
|
137
71
|
/** Default for {@link CodemodeDescriptionOptions.inlineBudget}, in estimated tokens. */
|
|
138
72
|
export const DEFAULT_CODEMODE_INLINE_BUDGET = 3000;
|
|
139
73
|
/** Characters per token when estimating the cost of a tool section. */
|
|
@@ -164,10 +98,9 @@ function renderToolSection(declaration) {
|
|
|
164
98
|
* represented before any namespace is complete.
|
|
165
99
|
*/
|
|
166
100
|
function selectCatalog(groups, budget) {
|
|
167
|
-
const listable = groups.map((group) => group.entries.filter((entry) => !entry.deferred));
|
|
168
101
|
if (budget === undefined)
|
|
169
|
-
return new Set(
|
|
170
|
-
const queues =
|
|
102
|
+
return new Set(groups.flatMap((group) => group.entries.map((entry) => entry.name)));
|
|
103
|
+
const queues = groups.map((group) => [...group.entries].sort((a, b) => a.cost - b.cost));
|
|
171
104
|
const shown = new Set();
|
|
172
105
|
let remaining = budget;
|
|
173
106
|
let active = queues.filter((queue) => queue.length > 0);
|
|
@@ -185,13 +118,16 @@ function selectCatalog(groups, budget) {
|
|
|
185
118
|
return shown;
|
|
186
119
|
}
|
|
187
120
|
/**
|
|
188
|
-
* Model-facing description: the helper list, guidance for
|
|
189
|
-
* MCP tools
|
|
190
|
-
*
|
|
191
|
-
*
|
|
121
|
+
* Model-facing description: the helper list, guidance for finding tools that are not listed, the
|
|
122
|
+
* shared MCP types when listed tools need them, the `models` API, and one section per listed tool,
|
|
123
|
+
* grouped by namespace. Deferred tools are never listed and do not affect the description at all, so
|
|
124
|
+
* it stays the same while MCP servers connect or change their tools. Tool sections are limited to
|
|
125
|
+
* `inlineBudget`.
|
|
192
126
|
*/
|
|
193
127
|
export function createCodemodeDescription(tools, options = {}) {
|
|
194
|
-
const declarations = getCodemodeCallableTools(tools)
|
|
128
|
+
const declarations = getCodemodeCallableTools(tools)
|
|
129
|
+
.filter((tool) => !options.deferred?.has(tool.name))
|
|
130
|
+
.map(toCodemodeDeclaration);
|
|
195
131
|
const groups = new Map([["", { namespace: undefined, entries: [] }]]);
|
|
196
132
|
for (const declaration of declarations) {
|
|
197
133
|
const namespace = options.namespaces?.get(declaration.name);
|
|
@@ -199,47 +135,28 @@ export function createCodemodeDescription(tools, options = {}) {
|
|
|
199
135
|
const group = groups.get(key) ?? { namespace, entries: [] };
|
|
200
136
|
groups.set(key, group);
|
|
201
137
|
const section = renderToolSection(declaration);
|
|
202
|
-
group.entries.push({
|
|
203
|
-
name: declaration.name,
|
|
204
|
-
section,
|
|
205
|
-
cost: Math.ceil(section.length / CHARS_PER_TOKEN),
|
|
206
|
-
deferred: options.deferred?.has(declaration.name) === true,
|
|
207
|
-
});
|
|
138
|
+
group.entries.push({ name: declaration.name, section, cost: Math.ceil(section.length / CHARS_PER_TOKEN) });
|
|
208
139
|
}
|
|
209
140
|
const ordered = [...groups.values()].sort((a, b) => a.namespace === undefined ? -1 : b.namespace === undefined ? 1 : a.namespace.name.localeCompare(b.namespace.name));
|
|
210
141
|
const shown = selectCatalog(ordered, options.inlineBudget);
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
if (!complete)
|
|
214
|
-
sections.push(DEFERRED_TOOLS_GUIDANCE);
|
|
215
|
-
if (declarations.some((declaration) => mcpStructuredContentSchema(declaration.outputSchema) !== undefined)) {
|
|
142
|
+
const sections = [DESCRIPTION_INTRO, describeGlobals(options.models === true)];
|
|
143
|
+
if (declarations.some((declaration) => shown.has(declaration.name) && mcpStructuredContentSchema(declaration.outputSchema) !== undefined)) {
|
|
216
144
|
sections.push(`Shared MCP Types:\n\`\`\`ts\n${MCP_TYPESCRIPT_PREAMBLE}\n\`\`\``);
|
|
217
145
|
}
|
|
218
|
-
if (options.models) {
|
|
219
|
-
const noop = () => undefined;
|
|
220
|
-
const models = renderDeclarations({
|
|
221
|
-
globals: MODEL_GLOBAL_DECLARATIONS.map((global) => ({ ...global, execute: noop })),
|
|
222
|
-
});
|
|
223
|
-
sections.push(`Model API:\n\`\`\`ts\n${MODEL_TYPES}\n\n${models}\n\`\`\``);
|
|
224
|
-
}
|
|
225
146
|
if (declarations.length === 0)
|
|
226
147
|
return sections.join("\n\n");
|
|
227
|
-
const toolSections = [
|
|
228
|
-
complete
|
|
229
|
-
? `Nested tools: COMPLETE list (${declarations.length} tool${declarations.length === 1 ? "" : "s"}).`
|
|
230
|
-
: `Nested tools: PARTIAL - ${shown.size} of ${declarations.length} shown.`,
|
|
231
|
-
];
|
|
148
|
+
const toolSections = ["Nested tools:"];
|
|
232
149
|
for (const { namespace, entries } of ordered) {
|
|
233
150
|
const visible = entries.filter((entry) => shown.has(entry.name));
|
|
234
151
|
if (namespace) {
|
|
235
|
-
|
|
236
|
-
const
|
|
152
|
+
// Only tools that did not fit the budget are counted as not listed here.
|
|
153
|
+
const listing = visible.length === entries.length
|
|
237
154
|
? ""
|
|
238
155
|
: visible.length === 0
|
|
239
|
-
? "
|
|
240
|
-
:
|
|
156
|
+
? " (tools not listed)"
|
|
157
|
+
: " (some tools not listed)";
|
|
241
158
|
const description = namespace.description?.trim();
|
|
242
|
-
toolSections.push(`## ${namespace.name}
|
|
159
|
+
toolSections.push(`## ${namespace.name}${listing}${description ? `\n${description}` : ""}`);
|
|
243
160
|
}
|
|
244
161
|
for (const entry of visible)
|
|
245
162
|
toolSections.push(entry.section);
|
|
@@ -247,9 +164,36 @@ export function createCodemodeDescription(tools, options = {}) {
|
|
|
247
164
|
sections.push(toolSections.join("\n\n"));
|
|
248
165
|
return sections.join("\n\n");
|
|
249
166
|
}
|
|
167
|
+
/**
|
|
168
|
+
* What a script call resolves to, in one line: `a string`, the field names of an object
|
|
169
|
+
* (`{ output, exit_code, full_output_path? }`), or the rendered type for anything else.
|
|
170
|
+
*/
|
|
171
|
+
function describeOutput(schema) {
|
|
172
|
+
const type = renderToolOutputType(schema);
|
|
173
|
+
if (type === "string")
|
|
174
|
+
return "a string";
|
|
175
|
+
const object = typeof schema === "object" ? schema : undefined;
|
|
176
|
+
const properties = object?.properties;
|
|
177
|
+
if (object?.type === "object" &&
|
|
178
|
+
typeof properties === "object" &&
|
|
179
|
+
properties !== null &&
|
|
180
|
+
mcpStructuredContentSchema(schema) === undefined) {
|
|
181
|
+
const required = new Set(Array.isArray(object.required) ? object.required : []);
|
|
182
|
+
const fields = Object.keys(properties).map((name) => (required.has(name) ? name : `${name}?`));
|
|
183
|
+
return `\`{ ${fields.join(", ")} }\``;
|
|
184
|
+
}
|
|
185
|
+
return `\`${type.replace(/\s+/g, " ")}\``;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* A declared tool's description followed by how scripts call it and what the call resolves to. The
|
|
189
|
+
* arguments are the tool's declared parameters, so they are not repeated.
|
|
190
|
+
*/
|
|
191
|
+
function describeScriptCall(tool) {
|
|
192
|
+
return `${tool.description.trim()}\n\nCodemode: \`tools.${toCodemodeIdentifier(tool.name)}(args)\` resolves to ${describeOutput(toCodemodeDeclaration(tool).outputSchema)}.`;
|
|
193
|
+
}
|
|
250
194
|
/**
|
|
251
195
|
* How the codemode tool presents tools that are both declared and callable from scripts:
|
|
252
|
-
* - `on`: their descriptions
|
|
196
|
+
* - `on`: their descriptions say how scripts call them, and the codemode description
|
|
253
197
|
* lists only the callable tools without `direct` exposure.
|
|
254
198
|
* - `only`: the codemode description lists every callable tool, and requests leave out the
|
|
255
199
|
* declarations of active `direct` tools.
|
|
@@ -266,7 +210,7 @@ function prepareCodemodeLoadout(loadout, options) {
|
|
|
266
210
|
if (mode === "on") {
|
|
267
211
|
for (const tool of loadout.declared) {
|
|
268
212
|
if (callableNames.has(tool.name))
|
|
269
|
-
descriptions[tool.name] =
|
|
213
|
+
descriptions[tool.name] = describeScriptCall(tool);
|
|
270
214
|
}
|
|
271
215
|
}
|
|
272
216
|
const listed = mode === "only" ? callable : callable.filter((tool) => !isDirect(tool));
|