@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
|
@@ -16,7 +16,7 @@ import type { TSchema } from "typebox";
|
|
|
16
16
|
import type { ToolDefinition, ToolExposure, ToolNamespace } from "../../core/extensions/types.ts";
|
|
17
17
|
import type { McpExposure } from "./config.ts";
|
|
18
18
|
/**
|
|
19
|
-
* Tool exposure of an MCP exposure.
|
|
19
|
+
* Tool exposure of an MCP exposure. `codemode` and `deferred` both leave tools out of the codemode
|
|
20
20
|
* description; they differ only in which tool the MCP extension activates to reach them.
|
|
21
21
|
*/
|
|
22
22
|
export declare function toToolExposure(exposure: McpExposure): ToolExposure;
|
|
@@ -40,9 +40,10 @@ export interface McpToolCaller {
|
|
|
40
40
|
callTool(name: string, args: Record<string, unknown>, options: McpRequestOptions): Promise<CallToolResult>;
|
|
41
41
|
}
|
|
42
42
|
/**
|
|
43
|
-
* `mcp__<server>__<tool>`, sanitized and shortened with a hash suffix when too long.
|
|
44
|
-
*
|
|
45
|
-
*
|
|
43
|
+
* `mcp__<server>__<tool>`, sanitized and shortened with a hash suffix when too long. Like Codex,
|
|
44
|
+
* everything but `[A-Za-z0-9_]` becomes `_`, so the name is also the identifier codemode scripts
|
|
45
|
+
* call it by. `isTaken` reports names used by a different MCP tool: sanitizing can map two tools to
|
|
46
|
+
* one name (`a-b` and `a_b`), which then get the hash suffix.
|
|
46
47
|
*/
|
|
47
48
|
export declare function createMcpToolName(server: string, tool: string, isTaken?: (name: string) => boolean): string;
|
|
48
49
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/extensions/mcp/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,KAAK,EAAE,YAAY,EAAa,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAClF,OAAO,EACN,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,IAAI,IAAI,OAAO,EAEpB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,KAAK,EAAmB,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/extensions/mcp/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,KAAK,EAAE,YAAY,EAAa,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAClF,OAAO,EACN,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,IAAI,IAAI,OAAO,EAEpB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,KAAK,EAAmB,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAKnH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,WAAW,GAAG,YAAY,CAElE;AAID,2EAA2E;AAC3E,eAAO,MAAM,oBAAoB,QAAY,CAAC;AAG9C,6DAA6D;AAC7D,eAAO,MAAM,sBAAsB,sBAAsB,CAAC;AAE1D,MAAM,WAAW,cAAc;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,qFAAqF;IACrF,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAE/F,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAKlG;AAED,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CAC3G;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAChC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAqB,GAC9C,MAAM,CAKR;AASD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,uBAAuB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,OAAO,CAW3G;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACpC,OAAO,EAAE,CAAC,WAAW,GAAG,YAAY,CAAC,EAAE,EACvC,UAAU,GAAE,cAA+B,GACzC,OAAO,CAAC;IAAE,OAAO,EAAE,CAAC,WAAW,GAAG,YAAY,CAAC,EAAE,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAkB/E;AAED,MAAM,WAAW,uBAAuB;IACvC,uEAAuE;IACvE,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,2GAA2G;IAC3G,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAgDD,kFAAkF;AAClF,wBAAsB,cAAc,CACnC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,SAAS,YAAY,EAAE,EAC/B,OAAO,GAAE,uBAA4B,GACnC,OAAO,CAAC,CAAC,WAAW,GAAG,YAAY,CAAC,EAAE,CAAC,CAEzC;AAED,qGAAqG;AACrG,wBAAsB,gBAAgB,CACrC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,cAAc,EACtB,OAAO,GAAE,uBAA4B,GACnC,OAAO,CAAC,eAAe,CAAC,cAAc,CAAC,CAAC,CAe1C;AA0BD,wBAAgB,uBAAuB,CAAC,OAAO,EAAE;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,WAAW,CAAC;IACtB,SAAS,EAAE,aAAa,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC;IACxC,mEAAmE;IACnE,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC;CAClC,GAAG,cAAc,CAAC,OAAO,EAAE,cAAc,CAAC,CA8D1C"}
|
|
@@ -14,22 +14,23 @@ import { writeFile } from "node:fs/promises";
|
|
|
14
14
|
import { tmpdir } from "node:os";
|
|
15
15
|
import { join } from "node:path";
|
|
16
16
|
import { toLlmContent, } from "@earendil-works/pi-mcp";
|
|
17
|
-
import { Text } from "@earendil-works/pi-tui";
|
|
17
|
+
import { Container, Spacer, Text } from "@earendil-works/pi-tui";
|
|
18
18
|
import { formatToolCallWithArgs, getTextOutput, replaceTabs } from "../../core/tools/render-utils.js";
|
|
19
19
|
import { formatSize, truncateMiddle } from "../../core/tools/truncate.js";
|
|
20
20
|
import { keyHint } from "../../modes/interactive/components/keybinding-hints.js";
|
|
21
|
+
import { VisualLinePreview } from "../../modes/interactive/components/visual-truncate.js";
|
|
21
22
|
/**
|
|
22
|
-
* Tool exposure of an MCP exposure.
|
|
23
|
+
* Tool exposure of an MCP exposure. `codemode` and `deferred` both leave tools out of the codemode
|
|
23
24
|
* description; they differ only in which tool the MCP extension activates to reach them.
|
|
24
25
|
*/
|
|
25
26
|
export function toToolExposure(exposure) {
|
|
26
|
-
return exposure === "codemode
|
|
27
|
+
return exposure === "codemode" ? "deferred" : exposure;
|
|
27
28
|
}
|
|
28
29
|
/** Provider tool names are limited to 64 characters of `[A-Za-z0-9_-]`. */
|
|
29
30
|
const MAX_TOOL_NAME_LENGTH = 64;
|
|
30
31
|
/** Model-facing text of an MCP result beyond this is cut in the middle. */
|
|
31
32
|
export const MCP_OUTPUT_MAX_BYTES = 20 * 1024;
|
|
32
|
-
/**
|
|
33
|
+
/** Visual (wrapped) result lines shown before the output is expanded. */
|
|
33
34
|
const OUTPUT_PREVIEW_LINES = 5;
|
|
34
35
|
/** Tool that reads the resources named by resource links. */
|
|
35
36
|
export const READ_MCP_RESOURCE_TOOL = "read_mcp_resource";
|
|
@@ -40,12 +41,13 @@ export async function saveToTempFile(data, extension) {
|
|
|
40
41
|
return path;
|
|
41
42
|
}
|
|
42
43
|
/**
|
|
43
|
-
* `mcp__<server>__<tool>`, sanitized and shortened with a hash suffix when too long.
|
|
44
|
-
*
|
|
45
|
-
*
|
|
44
|
+
* `mcp__<server>__<tool>`, sanitized and shortened with a hash suffix when too long. Like Codex,
|
|
45
|
+
* everything but `[A-Za-z0-9_]` becomes `_`, so the name is also the identifier codemode scripts
|
|
46
|
+
* call it by. `isTaken` reports names used by a different MCP tool: sanitizing can map two tools to
|
|
47
|
+
* one name (`a-b` and `a_b`), which then get the hash suffix.
|
|
46
48
|
*/
|
|
47
49
|
export function createMcpToolName(server, tool, isTaken = () => false) {
|
|
48
|
-
const name = `mcp__${server}__${tool}`.replace(/[^A-Za-z0-9_
|
|
50
|
+
const name = `mcp__${server}__${tool}`.replace(/[^A-Za-z0-9_]/g, "_");
|
|
49
51
|
if (name.length <= MAX_TOOL_NAME_LENGTH && !isTaken(name))
|
|
50
52
|
return name;
|
|
51
53
|
const hash = createHash("sha256").update(`${server}\0${tool}`).digest("hex").slice(0, 8);
|
|
@@ -203,16 +205,32 @@ export function createMcpToolDefinition(options) {
|
|
|
203
205
|
return component;
|
|
204
206
|
},
|
|
205
207
|
renderResult(result, options, theme, context) {
|
|
208
|
+
const component = context.lastComponent ?? new Container();
|
|
209
|
+
component.clear();
|
|
206
210
|
const output = getTextOutput(result, context.showImages).trim();
|
|
207
|
-
|
|
208
|
-
|
|
211
|
+
if (!output)
|
|
212
|
+
return component;
|
|
209
213
|
const color = context.isError ? "error" : "toolOutput";
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
214
|
+
const styled = replaceTabs(output)
|
|
215
|
+
.split("\n")
|
|
216
|
+
.map((line) => theme.fg(color, line))
|
|
217
|
+
.join("\n");
|
|
218
|
+
component.addChild(new Spacer(1));
|
|
219
|
+
if (options.expanded) {
|
|
220
|
+
component.addChild(new Text(styled, 0, 0));
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
// Limit wrapped lines, not logical ones: MCP results are often one long JSON line.
|
|
224
|
+
component.addChild(new VisualLinePreview({
|
|
225
|
+
text: styled,
|
|
226
|
+
maxVisualLines: OUTPUT_PREVIEW_LINES,
|
|
227
|
+
keep: "start",
|
|
228
|
+
formatHint: (hidden) => `${theme.fg("muted", `... (${hidden} more lines,`)} ${keyHint("app.tools.expand", "to expand")}${theme.fg("muted", ")")}`,
|
|
229
|
+
}));
|
|
230
|
+
const fullOutputPath = result.details?.fullOutputPath;
|
|
231
|
+
if (fullOutputPath)
|
|
232
|
+
component.addChild(new Text(theme.fg("muted", `Full output: ${fullOutputPath}`), 0, 0));
|
|
213
233
|
}
|
|
214
|
-
const component = context.lastComponent ?? new Text("", 0, 0);
|
|
215
|
-
component.setText(text ? `\n${text}` : "");
|
|
216
234
|
return component;
|
|
217
235
|
},
|
|
218
236
|
async execute(_toolCallId, params, signal, onUpdate) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../src/extensions/mcp/tools.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Adapts MCP tools to pi tool definitions.\n *\n * Results map onto pi's model-facing content (text and images). Text over 20KB keeps its start and\n * end with the middle cut out, like Codex does, and the full text is saved to a temp file the model\n * can read. Binary resources other than images are saved to temp files too, and resource links name\n * the `read_mcp_resource` tool. Codemode scripts receive the whole `CallToolResult` without `_meta`\n * (`content` blocks as sent by the server, `structuredContent`, `isError`), never truncated: it is\n * the tool's `structuredContent`, and every MCP tool declares a `CallToolResult` output schema. MCP\n * errors (`isError`) are error results for the model, but scripts still resolve to the result.\n */\n\nimport { createHash, randomBytes } from \"node:crypto\";\nimport { writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { AgentToolResult } from \"@earendil-works/pi-agent-core\";\nimport type { ImageContent, JsonValue, TextContent } from \"@earendil-works/pi-ai\";\nimport {\n\ttype CallToolResult,\n\ttype ContentBlock,\n\ttype McpRequestOptions,\n\ttype Tool as McpTool,\n\ttoLlmContent,\n} from \"@earendil-works/pi-mcp\";\nimport { Text } from \"@earendil-works/pi-tui\";\nimport type { TSchema } from \"typebox\";\nimport type { ToolAnnotations, ToolDefinition, ToolExposure, ToolNamespace } from \"../../core/extensions/types.ts\";\nimport { formatToolCallWithArgs, getTextOutput, replaceTabs } from \"../../core/tools/render-utils.ts\";\nimport { formatSize, truncateMiddle } from \"../../core/tools/truncate.ts\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport type { McpExposure } from \"./config.ts\";\n\n/**\n * Tool exposure of an MCP exposure. Both deferred exposures leave tools out of the codemode\n * description; they differ only in which tool the MCP extension activates to reach them.\n */\nexport function toToolExposure(exposure: McpExposure): ToolExposure {\n\treturn exposure === \"codemode-deferred\" ? \"deferred\" : exposure;\n}\n\n/** Provider tool names are limited to 64 characters of `[A-Za-z0-9_-]`. */\nconst MAX_TOOL_NAME_LENGTH = 64;\n/** Model-facing text of an MCP result beyond this is cut in the middle. */\nexport const MCP_OUTPUT_MAX_BYTES = 20 * 1024;\n/** Result lines shown before the output is expanded. */\nconst OUTPUT_PREVIEW_LINES = 5;\n/** Tool that reads the resources named by resource links. */\nexport const READ_MCP_RESOURCE_TOOL = \"read_mcp_resource\";\n\nexport interface McpToolDetails {\n\tserver: string;\n\ttool: string;\n\t/** Temp file with the full text output, when the model-facing text was truncated. */\n\tfullOutputPath?: string;\n}\n\n/**\n * Saves the full text of a truncated result, or a binary resource, and returns the file path.\n * `extension` includes the dot, for example `.txt`.\n */\nexport type McpOutputSaver = (data: string | Uint8Array, extension: string) => Promise<string>;\n\nexport async function saveToTempFile(data: string | Uint8Array, extension: string): Promise<string> {\n\tconst path = join(tmpdir(), `pi-mcp-${randomBytes(8).toString(\"hex\")}${extension}`);\n\t// Results can carry private data, so only the user may read the file.\n\tawait writeFile(path, data, { mode: 0o600 });\n\treturn path;\n}\n\nexport interface McpToolCaller {\n\tcallTool(name: string, args: Record<string, unknown>, options: McpRequestOptions): Promise<CallToolResult>;\n}\n\n/**\n * `mcp__<server>__<tool>`, sanitized and shortened with a hash suffix when too long. `isTaken`\n * reports names already used by a different MCP tool: sanitizing can map two tools to one name\n * (`a.b` and `a_b`), and the second then gets the hash suffix too.\n */\nexport function createMcpToolName(\n\tserver: string,\n\ttool: string,\n\tisTaken: (name: string) => boolean = () => false,\n): string {\n\tconst name = `mcp__${server}__${tool}`.replace(/[^A-Za-z0-9_-]/g, \"_\");\n\tif (name.length <= MAX_TOOL_NAME_LENGTH && !isTaken(name)) return name;\n\tconst hash = createHash(\"sha256\").update(`${server}\\0${tool}`).digest(\"hex\").slice(0, 8);\n\treturn `${name.slice(0, MAX_TOOL_NAME_LENGTH - hash.length - 1)}_${hash}`;\n}\n\nfunction textOf(content: readonly (TextContent | ImageContent)[]): string {\n\treturn content\n\t\t.filter((block): block is TextContent => block.type === \"text\")\n\t\t.map((block) => block.text)\n\t\t.join(\"\\n\");\n}\n\n/**\n * Output schema of every MCP tool: the `CallToolResult` scripts receive, with the tool's own output\n * schema as `structuredContent`. Codemode detects this shape to render `CallToolResult<T>`\n * declarations.\n */\nexport function createMcpResultSchema(structuredContentSchema: Record<string, unknown> | undefined): TSchema {\n\treturn {\n\t\ttype: \"object\",\n\t\tproperties: {\n\t\t\tcontent: { type: \"array\", items: { type: \"object\" } },\n\t\t\t...(structuredContentSchema ? { structuredContent: structuredContentSchema } : {}),\n\t\t\tisError: { type: \"boolean\" },\n\t\t\t_meta: { type: \"object\" },\n\t\t},\n\t\trequired: [\"content\"],\n\t} as unknown as TSchema;\n}\n\n/**\n * Keep model-facing text within {@link MCP_OUTPUT_MAX_BYTES}. Longer text becomes one text block in\n * Codex's truncation format, followed by the path of the file with the full text; images follow it.\n */\nexport async function limitMcpContent(\n\tcontent: (TextContent | ImageContent)[],\n\tsaveOutput: McpOutputSaver = saveToTempFile,\n): Promise<{ content: (TextContent | ImageContent)[]; fullOutputPath?: string }> {\n\tconst combined = textOf(content);\n\tconst truncation = truncateMiddle(combined, MCP_OUTPUT_MAX_BYTES);\n\tif (!truncation.truncated) return { content };\n\tlet fullOutputPath: string | undefined;\n\tlet where: string;\n\ttry {\n\t\tfullOutputPath = await saveOutput(combined, \".txt\");\n\t\twhere = `[Full output: ${fullOutputPath} (read it with offset/limit)]`;\n\t} catch (error) {\n\t\twhere = `[Could not save the full output: ${error instanceof Error ? error.message : String(error)}]`;\n\t}\n\tconst tokens = Math.ceil(truncation.totalBytes / 4);\n\tconst text = `Warning: truncated output (original token count: ${tokens})\\nTotal output lines: ${truncation.totalLines}\\n\\n${truncation.content}\\n\\n${where}`;\n\treturn {\n\t\tcontent: [{ type: \"text\", text }, ...content.filter((block) => block.type === \"image\")],\n\t\t...(fullOutputPath ? { fullOutputPath } : {}),\n\t};\n}\n\nexport interface ConvertMcpResultOptions {\n\t/** Saves truncated text and binary resources. Default: a temp file. */\n\tsaveOutput?: McpOutputSaver;\n\t/** Whether the server's resources can be read with `read_mcp_resource`, which resource links then name. */\n\treadableResources?: boolean;\n}\n\n/** File extension for a saved binary resource: the one its URI ends in, else `.bin`. */\nfunction extensionOf(uri: string): string {\n\tconst path = URL.canParse(uri) ? new URL(uri).pathname : uri;\n\treturn /\\.[A-Za-z0-9]{1,8}$/.exec(path)?.[0] ?? \".bin\";\n}\n\n/** Blobs of these types are shown as text. */\nfunction isTextMimeType(mimeType: string | undefined): boolean {\n\tif (!mimeType) return false;\n\tconst type = mimeType.split(\";\", 1)[0].trim().toLowerCase();\n\treturn type.startsWith(\"text/\") || type === \"application/json\" || type.endsWith(\"+json\") || type.endsWith(\"+xml\");\n}\n\n/** Model-facing content of one block of `server`'s result. */\nasync function blockToContent(\n\tserver: string,\n\tblock: ContentBlock,\n\toptions: ConvertMcpResultOptions,\n): Promise<(TextContent | ImageContent)[]> {\n\tif (block.type === \"resource_link\") {\n\t\tconst details = [block.mimeType, block.size === undefined ? undefined : formatSize(block.size)].filter(Boolean);\n\t\tconst read = options.readableResources ? `. Read it with ${READ_MCP_RESOURCE_TOOL} (server \"${server}\")` : \"\";\n\t\tconst description = block.description ? `: ${block.description}` : \"\";\n\t\treturn [\n\t\t\t{\n\t\t\t\ttype: \"text\",\n\t\t\t\ttext: `[Resource ${block.uri} \"${block.title ?? block.name}\"${details.length > 0 ? ` (${details.join(\", \")})` : \"\"}${description}${read}]`,\n\t\t\t},\n\t\t];\n\t}\n\tif (block.type === \"resource\" && \"blob\" in block.resource && !block.resource.mimeType?.startsWith(\"image/\")) {\n\t\tconst { uri, mimeType, blob } = block.resource;\n\t\tconst data = Buffer.from(blob, \"base64\");\n\t\tif (isTextMimeType(mimeType)) return [{ type: \"text\", text: data.toString(\"utf8\") }];\n\t\tconst kind = `${mimeType ?? \"unknown type\"}, ${formatSize(data.length)}`;\n\t\ttry {\n\t\t\tconst path = await (options.saveOutput ?? saveToTempFile)(data, extensionOf(uri));\n\t\t\treturn [{ type: \"text\", text: `[Binary resource ${uri} (${kind}) saved to ${path}]` }];\n\t\t} catch (error) {\n\t\t\tconst reason = error instanceof Error ? error.message : String(error);\n\t\t\treturn [{ type: \"text\", text: `[Binary resource ${uri} (${kind}) could not be saved: ${reason}]` }];\n\t\t}\n\t}\n\treturn toLlmContent({ content: [block] });\n}\n\n/** Model-facing content of `server`'s content blocks, before the output limit. */\nexport async function toModelContent(\n\tserver: string,\n\tblocks: readonly ContentBlock[],\n\toptions: ConvertMcpResultOptions = {},\n): Promise<(TextContent | ImageContent)[]> {\n\treturn (await Promise.all(blocks.map((block) => blockToContent(server, block, options)))).flat();\n}\n\n/** Convert an MCP result. `isError` results become error results that keep the structured result. */\nexport async function convertMcpResult(\n\tserver: string,\n\ttool: string,\n\tresult: CallToolResult,\n\toptions: ConvertMcpResultOptions = {},\n): Promise<AgentToolResult<McpToolDetails>> {\n\t// Without content blocks, toLlmContent falls back to the structured content as JSON.\n\tconst converted: (TextContent | ImageContent)[] =\n\t\tresult.content.length > 0 ? await toModelContent(server, result.content, options) : toLlmContent(result);\n\tif (result.isError && textOf(converted) === \"\") {\n\t\tconverted.push({ type: \"text\", text: `MCP tool ${server}/${tool} returned an error` });\n\t}\n\tconst { content, fullOutputPath } = await limitMcpContent(converted, options.saveOutput);\n\tconst { _meta: _ignored, ...scriptResult } = result;\n\treturn {\n\t\tcontent,\n\t\tdetails: { server, tool, ...(fullOutputPath ? { fullOutputPath } : {}) },\n\t\tstructuredContent: scriptResult as unknown as JsonValue,\n\t\t...(result.isError ? { isError: true } : {}),\n\t};\n}\n\n/**\n * Tool input schemas must be objects. MCP servers may omit `type`, and some providers reject object\n * schemas without `properties`.\n */\nfunction toParameters(schema: Record<string, unknown>): TSchema {\n\treturn {\n\t\t...schema,\n\t\ttype: schema.type ?? \"object\",\n\t\t...(schema.properties === undefined ? { properties: {} } : {}),\n\t} as unknown as TSchema;\n}\n\nconst ANNOTATION_HINTS = [\"readOnlyHint\", \"destructiveHint\", \"idempotentHint\", \"openWorldHint\"] as const;\n\n/** The boolean hints of an MCP tool's annotations, or undefined when it has none. */\nfunction toToolAnnotations(tool: McpTool): ToolAnnotations | undefined {\n\tconst annotations: ToolAnnotations = {};\n\tfor (const hint of ANNOTATION_HINTS) {\n\t\tconst value = tool.annotations?.[hint];\n\t\tif (typeof value === \"boolean\") annotations[hint] = value;\n\t}\n\treturn Object.keys(annotations).length > 0 ? annotations : undefined;\n}\n\nexport function createMcpToolDefinition(options: {\n\tserver: string;\n\ttool: McpTool;\n\tname: string;\n\texposure: McpExposure;\n\tnamespace: ToolNamespace;\n\ttimeoutMs: number;\n\tgetClient: () => Promise<McpToolCaller>;\n\t/** Whether `read_mcp_resource` can read the server's resources. */\n\treadableResources?: () => boolean;\n}): ToolDefinition<TSchema, McpToolDetails> {\n\tconst { server, tool } = options;\n\tconst title = tool.title ?? tool.annotations?.title;\n\tconst annotations = toToolAnnotations(tool);\n\tconst label = `${server}/${tool.name}`;\n\treturn {\n\t\tname: options.name,\n\t\tlabel,\n\t\tdescription: tool.description?.trim() || title || `MCP tool ${tool.name} from server ${server}`,\n\t\tparameters: toParameters(tool.inputSchema),\n\t\toutputSchema: createMcpResultSchema(tool.outputSchema),\n\t\texposure: toToolExposure(options.exposure),\n\t\tnamespace: options.namespace,\n\t\t...(annotations ? { annotations } : {}),\n\t\trenderCall(args, theme, context) {\n\t\t\tconst component = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\tcomponent.setText(formatToolCallWithArgs(label, args, theme, context.expanded));\n\t\t\treturn component;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst output = getTextOutput(result, context.showImages).trim();\n\t\t\tconst lines = output ? replaceTabs(output).split(\"\\n\") : [];\n\t\t\tconst shown = options.expanded ? lines : lines.slice(0, OUTPUT_PREVIEW_LINES);\n\t\t\tconst color = context.isError ? \"error\" : \"toolOutput\";\n\t\t\tlet text = shown.map((line) => theme.fg(color, line)).join(\"\\n\");\n\t\t\tif (shown.length < lines.length) {\n\t\t\t\ttext += `\\n${theme.fg(\"muted\", `... (${lines.length - shown.length} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")}${theme.fg(\"muted\", \")\")}`;\n\t\t\t}\n\t\t\tconst component = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\tcomponent.setText(text ? `\\n${text}` : \"\");\n\t\t\treturn component;\n\t\t},\n\t\tasync execute(_toolCallId, params, signal, onUpdate) {\n\t\t\tconst client = await options.getClient();\n\t\t\tconst result = await client.callTool(tool.name, (params ?? {}) as Record<string, unknown>, {\n\t\t\t\tsignal,\n\t\t\t\ttimeoutMs: options.timeoutMs,\n\t\t\t\tonProgress: (progress) => {\n\t\t\t\t\tconst total = progress.total === undefined ? \"\" : `/${progress.total}`;\n\t\t\t\t\tconst text = progress.message ?? `Progress ${progress.progress}${total}`;\n\t\t\t\t\tonUpdate?.({ content: [{ type: \"text\", text }], details: { server, tool: tool.name } });\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn convertMcpResult(server, tool.name, result, { readableResources: options.readableResources?.() });\n\t\t},\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../src/extensions/mcp/tools.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Adapts MCP tools to pi tool definitions.\n *\n * Results map onto pi's model-facing content (text and images). Text over 20KB keeps its start and\n * end with the middle cut out, like Codex does, and the full text is saved to a temp file the model\n * can read. Binary resources other than images are saved to temp files too, and resource links name\n * the `read_mcp_resource` tool. Codemode scripts receive the whole `CallToolResult` without `_meta`\n * (`content` blocks as sent by the server, `structuredContent`, `isError`), never truncated: it is\n * the tool's `structuredContent`, and every MCP tool declares a `CallToolResult` output schema. MCP\n * errors (`isError`) are error results for the model, but scripts still resolve to the result.\n */\n\nimport { createHash, randomBytes } from \"node:crypto\";\nimport { writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { AgentToolResult } from \"@earendil-works/pi-agent-core\";\nimport type { ImageContent, JsonValue, TextContent } from \"@earendil-works/pi-ai\";\nimport {\n\ttype CallToolResult,\n\ttype ContentBlock,\n\ttype McpRequestOptions,\n\ttype Tool as McpTool,\n\ttoLlmContent,\n} from \"@earendil-works/pi-mcp\";\nimport { Container, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { TSchema } from \"typebox\";\nimport type { ToolAnnotations, ToolDefinition, ToolExposure, ToolNamespace } from \"../../core/extensions/types.ts\";\nimport { formatToolCallWithArgs, getTextOutput, replaceTabs } from \"../../core/tools/render-utils.ts\";\nimport { formatSize, truncateMiddle } from \"../../core/tools/truncate.ts\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { VisualLinePreview } from \"../../modes/interactive/components/visual-truncate.ts\";\nimport type { McpExposure } from \"./config.ts\";\n\n/**\n * Tool exposure of an MCP exposure. `codemode` and `deferred` both leave tools out of the codemode\n * description; they differ only in which tool the MCP extension activates to reach them.\n */\nexport function toToolExposure(exposure: McpExposure): ToolExposure {\n\treturn exposure === \"codemode\" ? \"deferred\" : exposure;\n}\n\n/** Provider tool names are limited to 64 characters of `[A-Za-z0-9_-]`. */\nconst MAX_TOOL_NAME_LENGTH = 64;\n/** Model-facing text of an MCP result beyond this is cut in the middle. */\nexport const MCP_OUTPUT_MAX_BYTES = 20 * 1024;\n/** Visual (wrapped) result lines shown before the output is expanded. */\nconst OUTPUT_PREVIEW_LINES = 5;\n/** Tool that reads the resources named by resource links. */\nexport const READ_MCP_RESOURCE_TOOL = \"read_mcp_resource\";\n\nexport interface McpToolDetails {\n\tserver: string;\n\ttool: string;\n\t/** Temp file with the full text output, when the model-facing text was truncated. */\n\tfullOutputPath?: string;\n}\n\n/**\n * Saves the full text of a truncated result, or a binary resource, and returns the file path.\n * `extension` includes the dot, for example `.txt`.\n */\nexport type McpOutputSaver = (data: string | Uint8Array, extension: string) => Promise<string>;\n\nexport async function saveToTempFile(data: string | Uint8Array, extension: string): Promise<string> {\n\tconst path = join(tmpdir(), `pi-mcp-${randomBytes(8).toString(\"hex\")}${extension}`);\n\t// Results can carry private data, so only the user may read the file.\n\tawait writeFile(path, data, { mode: 0o600 });\n\treturn path;\n}\n\nexport interface McpToolCaller {\n\tcallTool(name: string, args: Record<string, unknown>, options: McpRequestOptions): Promise<CallToolResult>;\n}\n\n/**\n * `mcp__<server>__<tool>`, sanitized and shortened with a hash suffix when too long. Like Codex,\n * everything but `[A-Za-z0-9_]` becomes `_`, so the name is also the identifier codemode scripts\n * call it by. `isTaken` reports names used by a different MCP tool: sanitizing can map two tools to\n * one name (`a-b` and `a_b`), which then get the hash suffix.\n */\nexport function createMcpToolName(\n\tserver: string,\n\ttool: string,\n\tisTaken: (name: string) => boolean = () => false,\n): string {\n\tconst name = `mcp__${server}__${tool}`.replace(/[^A-Za-z0-9_]/g, \"_\");\n\tif (name.length <= MAX_TOOL_NAME_LENGTH && !isTaken(name)) return name;\n\tconst hash = createHash(\"sha256\").update(`${server}\\0${tool}`).digest(\"hex\").slice(0, 8);\n\treturn `${name.slice(0, MAX_TOOL_NAME_LENGTH - hash.length - 1)}_${hash}`;\n}\n\nfunction textOf(content: readonly (TextContent | ImageContent)[]): string {\n\treturn content\n\t\t.filter((block): block is TextContent => block.type === \"text\")\n\t\t.map((block) => block.text)\n\t\t.join(\"\\n\");\n}\n\n/**\n * Output schema of every MCP tool: the `CallToolResult` scripts receive, with the tool's own output\n * schema as `structuredContent`. Codemode detects this shape to render `CallToolResult<T>`\n * declarations.\n */\nexport function createMcpResultSchema(structuredContentSchema: Record<string, unknown> | undefined): TSchema {\n\treturn {\n\t\ttype: \"object\",\n\t\tproperties: {\n\t\t\tcontent: { type: \"array\", items: { type: \"object\" } },\n\t\t\t...(structuredContentSchema ? { structuredContent: structuredContentSchema } : {}),\n\t\t\tisError: { type: \"boolean\" },\n\t\t\t_meta: { type: \"object\" },\n\t\t},\n\t\trequired: [\"content\"],\n\t} as unknown as TSchema;\n}\n\n/**\n * Keep model-facing text within {@link MCP_OUTPUT_MAX_BYTES}. Longer text becomes one text block in\n * Codex's truncation format, followed by the path of the file with the full text; images follow it.\n */\nexport async function limitMcpContent(\n\tcontent: (TextContent | ImageContent)[],\n\tsaveOutput: McpOutputSaver = saveToTempFile,\n): Promise<{ content: (TextContent | ImageContent)[]; fullOutputPath?: string }> {\n\tconst combined = textOf(content);\n\tconst truncation = truncateMiddle(combined, MCP_OUTPUT_MAX_BYTES);\n\tif (!truncation.truncated) return { content };\n\tlet fullOutputPath: string | undefined;\n\tlet where: string;\n\ttry {\n\t\tfullOutputPath = await saveOutput(combined, \".txt\");\n\t\twhere = `[Full output: ${fullOutputPath} (read it with offset/limit)]`;\n\t} catch (error) {\n\t\twhere = `[Could not save the full output: ${error instanceof Error ? error.message : String(error)}]`;\n\t}\n\tconst tokens = Math.ceil(truncation.totalBytes / 4);\n\tconst text = `Warning: truncated output (original token count: ${tokens})\\nTotal output lines: ${truncation.totalLines}\\n\\n${truncation.content}\\n\\n${where}`;\n\treturn {\n\t\tcontent: [{ type: \"text\", text }, ...content.filter((block) => block.type === \"image\")],\n\t\t...(fullOutputPath ? { fullOutputPath } : {}),\n\t};\n}\n\nexport interface ConvertMcpResultOptions {\n\t/** Saves truncated text and binary resources. Default: a temp file. */\n\tsaveOutput?: McpOutputSaver;\n\t/** Whether the server's resources can be read with `read_mcp_resource`, which resource links then name. */\n\treadableResources?: boolean;\n}\n\n/** File extension for a saved binary resource: the one its URI ends in, else `.bin`. */\nfunction extensionOf(uri: string): string {\n\tconst path = URL.canParse(uri) ? new URL(uri).pathname : uri;\n\treturn /\\.[A-Za-z0-9]{1,8}$/.exec(path)?.[0] ?? \".bin\";\n}\n\n/** Blobs of these types are shown as text. */\nfunction isTextMimeType(mimeType: string | undefined): boolean {\n\tif (!mimeType) return false;\n\tconst type = mimeType.split(\";\", 1)[0].trim().toLowerCase();\n\treturn type.startsWith(\"text/\") || type === \"application/json\" || type.endsWith(\"+json\") || type.endsWith(\"+xml\");\n}\n\n/** Model-facing content of one block of `server`'s result. */\nasync function blockToContent(\n\tserver: string,\n\tblock: ContentBlock,\n\toptions: ConvertMcpResultOptions,\n): Promise<(TextContent | ImageContent)[]> {\n\tif (block.type === \"resource_link\") {\n\t\tconst details = [block.mimeType, block.size === undefined ? undefined : formatSize(block.size)].filter(Boolean);\n\t\tconst read = options.readableResources ? `. Read it with ${READ_MCP_RESOURCE_TOOL} (server \"${server}\")` : \"\";\n\t\tconst description = block.description ? `: ${block.description}` : \"\";\n\t\treturn [\n\t\t\t{\n\t\t\t\ttype: \"text\",\n\t\t\t\ttext: `[Resource ${block.uri} \"${block.title ?? block.name}\"${details.length > 0 ? ` (${details.join(\", \")})` : \"\"}${description}${read}]`,\n\t\t\t},\n\t\t];\n\t}\n\tif (block.type === \"resource\" && \"blob\" in block.resource && !block.resource.mimeType?.startsWith(\"image/\")) {\n\t\tconst { uri, mimeType, blob } = block.resource;\n\t\tconst data = Buffer.from(blob, \"base64\");\n\t\tif (isTextMimeType(mimeType)) return [{ type: \"text\", text: data.toString(\"utf8\") }];\n\t\tconst kind = `${mimeType ?? \"unknown type\"}, ${formatSize(data.length)}`;\n\t\ttry {\n\t\t\tconst path = await (options.saveOutput ?? saveToTempFile)(data, extensionOf(uri));\n\t\t\treturn [{ type: \"text\", text: `[Binary resource ${uri} (${kind}) saved to ${path}]` }];\n\t\t} catch (error) {\n\t\t\tconst reason = error instanceof Error ? error.message : String(error);\n\t\t\treturn [{ type: \"text\", text: `[Binary resource ${uri} (${kind}) could not be saved: ${reason}]` }];\n\t\t}\n\t}\n\treturn toLlmContent({ content: [block] });\n}\n\n/** Model-facing content of `server`'s content blocks, before the output limit. */\nexport async function toModelContent(\n\tserver: string,\n\tblocks: readonly ContentBlock[],\n\toptions: ConvertMcpResultOptions = {},\n): Promise<(TextContent | ImageContent)[]> {\n\treturn (await Promise.all(blocks.map((block) => blockToContent(server, block, options)))).flat();\n}\n\n/** Convert an MCP result. `isError` results become error results that keep the structured result. */\nexport async function convertMcpResult(\n\tserver: string,\n\ttool: string,\n\tresult: CallToolResult,\n\toptions: ConvertMcpResultOptions = {},\n): Promise<AgentToolResult<McpToolDetails>> {\n\t// Without content blocks, toLlmContent falls back to the structured content as JSON.\n\tconst converted: (TextContent | ImageContent)[] =\n\t\tresult.content.length > 0 ? await toModelContent(server, result.content, options) : toLlmContent(result);\n\tif (result.isError && textOf(converted) === \"\") {\n\t\tconverted.push({ type: \"text\", text: `MCP tool ${server}/${tool} returned an error` });\n\t}\n\tconst { content, fullOutputPath } = await limitMcpContent(converted, options.saveOutput);\n\tconst { _meta: _ignored, ...scriptResult } = result;\n\treturn {\n\t\tcontent,\n\t\tdetails: { server, tool, ...(fullOutputPath ? { fullOutputPath } : {}) },\n\t\tstructuredContent: scriptResult as unknown as JsonValue,\n\t\t...(result.isError ? { isError: true } : {}),\n\t};\n}\n\n/**\n * Tool input schemas must be objects. MCP servers may omit `type`, and some providers reject object\n * schemas without `properties`.\n */\nfunction toParameters(schema: Record<string, unknown>): TSchema {\n\treturn {\n\t\t...schema,\n\t\ttype: schema.type ?? \"object\",\n\t\t...(schema.properties === undefined ? { properties: {} } : {}),\n\t} as unknown as TSchema;\n}\n\nconst ANNOTATION_HINTS = [\"readOnlyHint\", \"destructiveHint\", \"idempotentHint\", \"openWorldHint\"] as const;\n\n/** The boolean hints of an MCP tool's annotations, or undefined when it has none. */\nfunction toToolAnnotations(tool: McpTool): ToolAnnotations | undefined {\n\tconst annotations: ToolAnnotations = {};\n\tfor (const hint of ANNOTATION_HINTS) {\n\t\tconst value = tool.annotations?.[hint];\n\t\tif (typeof value === \"boolean\") annotations[hint] = value;\n\t}\n\treturn Object.keys(annotations).length > 0 ? annotations : undefined;\n}\n\nexport function createMcpToolDefinition(options: {\n\tserver: string;\n\ttool: McpTool;\n\tname: string;\n\texposure: McpExposure;\n\tnamespace: ToolNamespace;\n\ttimeoutMs: number;\n\tgetClient: () => Promise<McpToolCaller>;\n\t/** Whether `read_mcp_resource` can read the server's resources. */\n\treadableResources?: () => boolean;\n}): ToolDefinition<TSchema, McpToolDetails> {\n\tconst { server, tool } = options;\n\tconst title = tool.title ?? tool.annotations?.title;\n\tconst annotations = toToolAnnotations(tool);\n\tconst label = `${server}/${tool.name}`;\n\treturn {\n\t\tname: options.name,\n\t\tlabel,\n\t\tdescription: tool.description?.trim() || title || `MCP tool ${tool.name} from server ${server}`,\n\t\tparameters: toParameters(tool.inputSchema),\n\t\toutputSchema: createMcpResultSchema(tool.outputSchema),\n\t\texposure: toToolExposure(options.exposure),\n\t\tnamespace: options.namespace,\n\t\t...(annotations ? { annotations } : {}),\n\t\trenderCall(args, theme, context) {\n\t\t\tconst component = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\tcomponent.setText(formatToolCallWithArgs(label, args, theme, context.expanded));\n\t\t\treturn component;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst component = (context.lastComponent as Container | undefined) ?? new Container();\n\t\t\tcomponent.clear();\n\t\t\tconst output = getTextOutput(result, context.showImages).trim();\n\t\t\tif (!output) return component;\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: MCP results are 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) =>\n\t\t\t\t\t\t\t`${theme.fg(\"muted\", `... (${hidden} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")}${theme.fg(\"muted\", \")\")}`,\n\t\t\t\t\t}),\n\t\t\t\t);\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\treturn component;\n\t\t},\n\t\tasync execute(_toolCallId, params, signal, onUpdate) {\n\t\t\tconst client = await options.getClient();\n\t\t\tconst result = await client.callTool(tool.name, (params ?? {}) as Record<string, unknown>, {\n\t\t\t\tsignal,\n\t\t\t\ttimeoutMs: options.timeoutMs,\n\t\t\t\tonProgress: (progress) => {\n\t\t\t\t\tconst total = progress.total === undefined ? \"\" : `/${progress.total}`;\n\t\t\t\t\tconst text = progress.message ?? `Progress ${progress.progress}${total}`;\n\t\t\t\t\tonUpdate?.({ content: [{ type: \"text\", text }], details: { server, tool: tool.name } });\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn convertMcpResult(server, tool.name, result, { readableResources: options.readableResources?.() });\n\t\t},\n\t};\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../../src/extensions/mcp/ui.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,KAAK,SAAS,EAEd,KAAK,SAAS,
|
|
1
|
+
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../../src/extensions/mcp/ui.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,KAAK,SAAS,EAEd,KAAK,SAAS,EAGd,KAAK,UAAU,EAIf,KAAK,GAAG,EAGR,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAC9E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAGpE,OAAO,EAAsB,KAAK,KAAK,EAAE,MAAM,wCAAwC,CAAC;AAExF,MAAM,WAAW,OAAO;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,qCAAqC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,YAAY,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,KAAK;IACrB;;;OAGG;IACH,IAAI,CAAC,KAAK,EAAE,MAAM,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC1G,8CAA8C;IAC9C,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C;;;OAGG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CACvG;AAiBD,qBAAa,cAAe,YAAW,KAAK,EAAE,SAAS,EAAE,SAAS;IACjE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAM;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;IACjD,OAAO,CAAC,OAAO,CAAY;IAC3B,OAAO,CAAC,YAAY,CAAuC;IAC3D,OAAO,CAAC,WAAW,CAAwB;IAC3C,OAAO,CAAC,QAAQ,CAAS;IAEzB,YAAY,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAKlE;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAGzB;IAED,OAAO,CAAC,UAAU;IASlB,IAAI,CAAC,KAAK,EAAE,MAAM,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAkDxG;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAE3C;IAED,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAoDrG;IAED,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAG9B;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAI9B;IAED,UAAU,IAAI,IAAI,CAEjB;CACD;AAED,yDAAyD;AACzD,wBAAsB,cAAc,CACnC,GAAG,EAAE,uBAAuB,EAC5B,MAAM,EAAE,CAAC,EAAE,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,GAClC,OAAO,CAAC,IAAI,CAAC,CAYf"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* The `/mcp` manager view: menus that rebuild while servers connect, a read-only status screen, and
|
|
3
3
|
* the sign-in screen that accepts a pasted redirect URL.
|
|
4
4
|
*/
|
|
5
|
-
import { Container, Input, SelectList, Spacer, Text, truncateToWidth, visibleWidth, } from "@earendil-works/pi-tui";
|
|
5
|
+
import { Container, hyperlink, Input, SelectList, Spacer, Text, truncateToWidth, visibleWidth, } from "@earendil-works/pi-tui";
|
|
6
6
|
import { DynamicBorder } from "../../modes/interactive/components/dynamic-border.js";
|
|
7
7
|
import { keyHint } from "../../modes/interactive/components/keybinding-hints.js";
|
|
8
8
|
import { getSelectListTheme } from "../../modes/interactive/theme/theme.js";
|
|
@@ -122,10 +122,12 @@ export class McpManagerView {
|
|
|
122
122
|
}
|
|
123
123
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
124
124
|
const input = new Input();
|
|
125
|
+
const clickHint = process.platform === "darwin" ? "Cmd+click to open" : "Ctrl+click to open";
|
|
125
126
|
const body = [
|
|
126
127
|
new Spacer(1),
|
|
127
128
|
new Text(this.theme.fg("muted", "Approve access in your browser. If it did not open, visit:"), 1, 0),
|
|
128
|
-
new Text(this.theme.fg("accent", authorizationUrl), 1, 0),
|
|
129
|
+
new Text(this.theme.fg("accent", hyperlink(authorizationUrl, authorizationUrl)), 1, 0),
|
|
130
|
+
new Text(this.theme.fg("dim", hyperlink(clickHint, authorizationUrl)), 1, 0),
|
|
129
131
|
new Spacer(1),
|
|
130
132
|
new Text(this.theme.fg("muted", "If the browser runs on another machine, paste the URL it was redirected to:"), 1, 0),
|
|
131
133
|
input,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../../src/extensions/mcp/ui.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The `/mcp` manager view: menus that rebuild while servers connect, a read-only status screen, and\n * the sign-in screen that accepts a pasted redirect URL.\n */\n\nimport {\n\ttype Component,\n\tContainer,\n\ttype Focusable,\n\tInput,\n\ttype SelectItem,\n\tSelectList,\n\tSpacer,\n\tText,\n\ttype TUI,\n\ttruncateToWidth,\n\tvisibleWidth,\n} from \"@earendil-works/pi-tui\";\nimport type { ExtensionCommandContext } from \"../../core/extensions/types.ts\";\nimport type { KeybindingsManager } from \"../../core/keybindings.ts\";\nimport { DynamicBorder } from \"../../modes/interactive/components/dynamic-border.ts\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { getSelectListTheme, type Theme } from \"../../modes/interactive/theme/theme.ts\";\n\nexport interface McpMenu {\n\ttitle: string;\n\t/** Shown below the title. */\n\tdetails?: string;\n\t/** Shown below the details in the error color. */\n\terror?: string;\n\titems: SelectItem[];\n\t/** Shown when there are no items. */\n\tempty?: string;\n\t/** Value of the item selected when the menu opens. */\n\tselected?: string;\n\t/** What the confirm key does, for the key hint. */\n\tconfirmLabel: string;\n\t/** What the cancel key does, for the key hint. */\n\tcancelLabel: string;\n}\n\nexport interface McpUi {\n\t/**\n\t * Show a menu and resolve to the chosen item's value, or undefined when cancelled. `subscribe`\n\t * rebuilds the menu on every change, keeping the selected item.\n\t */\n\tmenu(build: () => McpMenu, subscribe?: (listener: () => void) => () => void): Promise<string | undefined>;\n\t/** Show a message while an operation runs. */\n\tstatus(title: string, message: string): void;\n\t/**\n\t * Show the authorization URL and wait for a pasted redirect URL. Resolves to undefined when\n\t * cancelled or when `signal` aborts (the browser reached the callback).\n\t */\n\tredirectUrl(title: string, authorizationUrl: string, signal: AbortSignal): Promise<string | undefined>;\n}\n\nfunction frame(theme: Theme, title: string, body: Component[], footer?: string): Container {\n\tconst container = new Container();\n\tcontainer.addChild(new DynamicBorder((text: string) => theme.fg(\"accent\", text)));\n\tcontainer.addChild(new Text(theme.fg(\"accent\", theme.bold(title)), 1, 0));\n\tfor (const child of body) container.addChild(child);\n\tif (footer) {\n\t\tcontainer.addChild(new Spacer(1));\n\t\tcontainer.addChild(new Text(theme.fg(\"dim\", footer), 1, 0));\n\t}\n\tcontainer.addChild(new DynamicBorder((text: string) => theme.fg(\"accent\", text)));\n\treturn container;\n}\n\nconst MAX_VISIBLE_ITEMS = 12;\n\nexport class McpManagerView implements McpUi, Component, Focusable {\n\tprivate readonly tui: TUI;\n\tprivate readonly theme: Theme;\n\tprivate readonly keybindings: KeybindingsManager;\n\tprivate content: Container;\n\tprivate inputHandler: ((data: string) => void) | undefined;\n\tprivate inputTarget: Focusable | undefined;\n\tprivate _focused = false;\n\n\tconstructor(tui: TUI, theme: Theme, keybindings: KeybindingsManager) {\n\t\tthis.tui = tui;\n\t\tthis.theme = theme;\n\t\tthis.keybindings = keybindings;\n\t\tthis.content = frame(theme, \"MCP servers\", [new Text(theme.fg(\"muted\", \"Loading…\"), 1, 1)]);\n\t}\n\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tif (this.inputTarget) this.inputTarget.focused = value;\n\t}\n\n\tprivate setContent(content: Container, inputHandler?: (data: string) => void, inputTarget?: Focusable): void {\n\t\tif (this.inputTarget) this.inputTarget.focused = false;\n\t\tthis.content = content;\n\t\tthis.inputHandler = inputHandler;\n\t\tthis.inputTarget = inputTarget;\n\t\tif (this.inputTarget) this.inputTarget.focused = this._focused;\n\t\tthis.tui.requestRender();\n\t}\n\n\tmenu(build: () => McpMenu, subscribe?: (listener: () => void) => () => void): Promise<string | undefined> {\n\t\treturn new Promise((resolve) => {\n\t\t\tlet unsubscribe: (() => void) | undefined;\n\t\t\tlet settled = false;\n\t\t\tconst finish = (value: string | undefined) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tunsubscribe?.();\n\t\t\t\tresolve(value);\n\t\t\t};\n\t\t\tlet selected: string | undefined;\n\t\t\tconst render = () => {\n\t\t\t\tconst menu = build();\n\t\t\t\tconst wanted = selected ?? menu.selected;\n\t\t\t\tconst body: Component[] = [];\n\t\t\t\tif (menu.details) body.push(new Text(this.theme.fg(\"muted\", menu.details), 1, 0));\n\t\t\t\tif (menu.error) body.push(new Text(this.theme.fg(\"error\", menu.error), 1, 0));\n\t\t\t\tbody.push(new Spacer(1));\n\t\t\t\tconst footer = `${keyHint(\"tui.select.confirm\", menu.confirmLabel)} • ${keyHint(\"tui.select.cancel\", menu.cancelLabel)}`;\n\t\t\t\tif (menu.items.length === 0) {\n\t\t\t\t\tbody.push(new Text(this.theme.fg(\"muted\", menu.empty ?? \"Nothing to show.\"), 1, 0));\n\t\t\t\t\tthis.setContent(\n\t\t\t\t\t\tframe(this.theme, menu.title, body, keyHint(\"tui.select.cancel\", menu.cancelLabel)),\n\t\t\t\t\t\t(data) => {\n\t\t\t\t\t\t\tif (this.keybindings.matches(data, \"tui.select.cancel\")) finish(undefined);\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst list = new SelectList(\n\t\t\t\t\tmenu.items,\n\t\t\t\t\tMath.min(menu.items.length, MAX_VISIBLE_ITEMS),\n\t\t\t\t\tgetSelectListTheme(),\n\t\t\t\t);\n\t\t\t\tconst index = menu.items.findIndex((item) => item.value === wanted);\n\t\t\t\tif (index !== -1) list.setSelectedIndex(index);\n\t\t\t\tselected = list.getSelectedItem()?.value;\n\t\t\t\tlist.onSelectionChange = (item) => {\n\t\t\t\t\tselected = item.value;\n\t\t\t\t};\n\t\t\t\tlist.onSelect = (item) => finish(item.value);\n\t\t\t\tlist.onCancel = () => finish(undefined);\n\t\t\t\tbody.push(list);\n\t\t\t\tthis.setContent(frame(this.theme, menu.title, body, footer), (data) => list.handleInput(data));\n\t\t\t};\n\t\t\trender();\n\t\t\tunsubscribe = subscribe?.(() => {\n\t\t\t\tif (!settled) render();\n\t\t\t});\n\t\t});\n\t}\n\n\tstatus(title: string, message: string): void {\n\t\tthis.setContent(frame(this.theme, title, [new Spacer(1), new Text(this.theme.fg(\"muted\", message), 1, 0)]));\n\t}\n\n\tredirectUrl(title: string, authorizationUrl: string, signal: AbortSignal): Promise<string | undefined> {\n\t\treturn new Promise((resolve) => {\n\t\t\tlet settled = false;\n\t\t\tconst finish = (value: string | undefined) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\t\tresolve(value);\n\t\t\t};\n\t\t\tconst onAbort = () => finish(undefined);\n\t\t\tif (signal.aborted) {\n\t\t\t\tfinish(undefined);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\tconst input = new Input();\n\t\t\tconst body: Component[] = [\n\t\t\t\tnew Spacer(1),\n\t\t\t\tnew Text(this.theme.fg(\"muted\", \"Approve access in your browser. If it did not open, visit:\"), 1, 0),\n\t\t\t\tnew Text(this.theme.fg(\"accent\", authorizationUrl), 1, 0),\n\t\t\t\tnew Spacer(1),\n\t\t\t\tnew Text(\n\t\t\t\t\tthis.theme.fg(\"muted\", \"If the browser runs on another machine, paste the URL it was redirected to:\"),\n\t\t\t\t\t1,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t\tinput,\n\t\t\t];\n\t\t\tthis.setContent(\n\t\t\t\tframe(\n\t\t\t\t\tthis.theme,\n\t\t\t\t\ttitle,\n\t\t\t\t\tbody,\n\t\t\t\t\t`${keyHint(\"tui.select.confirm\", \"submit\")} • ${keyHint(\"tui.select.cancel\", \"cancel\")}`,\n\t\t\t\t),\n\t\t\t\t(data) => {\n\t\t\t\t\tif (this.keybindings.matches(data, \"tui.select.confirm\")) {\n\t\t\t\t\t\tconst value = input.getValue().trim();\n\t\t\t\t\t\tif (value) finish(value);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (this.keybindings.matches(data, \"tui.select.cancel\")) {\n\t\t\t\t\t\tfinish(undefined);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tinput.handleInput(data);\n\t\t\t\t},\n\t\t\t\tinput,\n\t\t\t);\n\t\t});\n\t}\n\n\thandleInput(data: string): void {\n\t\tthis.inputHandler?.(data);\n\t\tthis.tui.requestRender();\n\t}\n\n\trender(width: number): string[] {\n\t\treturn this.content\n\t\t\t.render(width)\n\t\t\t.map((line) => (visibleWidth(line) > width ? truncateToWidth(line, width, \"\") : line));\n\t}\n\n\tinvalidate(): void {\n\t\tthis.content.invalidate();\n\t}\n}\n\n/** Run `manage` in the manager view until it returns. */\nexport async function showMcpManager(\n\tctx: ExtensionCommandContext,\n\tmanage: (ui: McpUi) => Promise<void>,\n): Promise<void> {\n\tawait ctx.ui.custom<void>((tui, theme, keybindings, done) => {\n\t\tconst view = new McpManagerView(tui, theme, keybindings);\n\t\tvoid manage(view).then(\n\t\t\t() => done(),\n\t\t\t(error: unknown) => {\n\t\t\t\tctx.ui.notify(error instanceof Error ? error.message : String(error), \"error\");\n\t\t\t\tdone();\n\t\t\t},\n\t\t);\n\t\treturn view;\n\t});\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../../src/extensions/mcp/ui.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The `/mcp` manager view: menus that rebuild while servers connect, a read-only status screen, and\n * the sign-in screen that accepts a pasted redirect URL.\n */\n\nimport {\n\ttype Component,\n\tContainer,\n\ttype Focusable,\n\thyperlink,\n\tInput,\n\ttype SelectItem,\n\tSelectList,\n\tSpacer,\n\tText,\n\ttype TUI,\n\ttruncateToWidth,\n\tvisibleWidth,\n} from \"@earendil-works/pi-tui\";\nimport type { ExtensionCommandContext } from \"../../core/extensions/types.ts\";\nimport type { KeybindingsManager } from \"../../core/keybindings.ts\";\nimport { DynamicBorder } from \"../../modes/interactive/components/dynamic-border.ts\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { getSelectListTheme, type Theme } from \"../../modes/interactive/theme/theme.ts\";\n\nexport interface McpMenu {\n\ttitle: string;\n\t/** Shown below the title. */\n\tdetails?: string;\n\t/** Shown below the details in the error color. */\n\terror?: string;\n\titems: SelectItem[];\n\t/** Shown when there are no items. */\n\tempty?: string;\n\t/** Value of the item selected when the menu opens. */\n\tselected?: string;\n\t/** What the confirm key does, for the key hint. */\n\tconfirmLabel: string;\n\t/** What the cancel key does, for the key hint. */\n\tcancelLabel: string;\n}\n\nexport interface McpUi {\n\t/**\n\t * Show a menu and resolve to the chosen item's value, or undefined when cancelled. `subscribe`\n\t * rebuilds the menu on every change, keeping the selected item.\n\t */\n\tmenu(build: () => McpMenu, subscribe?: (listener: () => void) => () => void): Promise<string | undefined>;\n\t/** Show a message while an operation runs. */\n\tstatus(title: string, message: string): void;\n\t/**\n\t * Show the authorization URL and wait for a pasted redirect URL. Resolves to undefined when\n\t * cancelled or when `signal` aborts (the browser reached the callback).\n\t */\n\tredirectUrl(title: string, authorizationUrl: string, signal: AbortSignal): Promise<string | undefined>;\n}\n\nfunction frame(theme: Theme, title: string, body: Component[], footer?: string): Container {\n\tconst container = new Container();\n\tcontainer.addChild(new DynamicBorder((text: string) => theme.fg(\"accent\", text)));\n\tcontainer.addChild(new Text(theme.fg(\"accent\", theme.bold(title)), 1, 0));\n\tfor (const child of body) container.addChild(child);\n\tif (footer) {\n\t\tcontainer.addChild(new Spacer(1));\n\t\tcontainer.addChild(new Text(theme.fg(\"dim\", footer), 1, 0));\n\t}\n\tcontainer.addChild(new DynamicBorder((text: string) => theme.fg(\"accent\", text)));\n\treturn container;\n}\n\nconst MAX_VISIBLE_ITEMS = 12;\n\nexport class McpManagerView implements McpUi, Component, Focusable {\n\tprivate readonly tui: TUI;\n\tprivate readonly theme: Theme;\n\tprivate readonly keybindings: KeybindingsManager;\n\tprivate content: Container;\n\tprivate inputHandler: ((data: string) => void) | undefined;\n\tprivate inputTarget: Focusable | undefined;\n\tprivate _focused = false;\n\n\tconstructor(tui: TUI, theme: Theme, keybindings: KeybindingsManager) {\n\t\tthis.tui = tui;\n\t\tthis.theme = theme;\n\t\tthis.keybindings = keybindings;\n\t\tthis.content = frame(theme, \"MCP servers\", [new Text(theme.fg(\"muted\", \"Loading…\"), 1, 1)]);\n\t}\n\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tif (this.inputTarget) this.inputTarget.focused = value;\n\t}\n\n\tprivate setContent(content: Container, inputHandler?: (data: string) => void, inputTarget?: Focusable): void {\n\t\tif (this.inputTarget) this.inputTarget.focused = false;\n\t\tthis.content = content;\n\t\tthis.inputHandler = inputHandler;\n\t\tthis.inputTarget = inputTarget;\n\t\tif (this.inputTarget) this.inputTarget.focused = this._focused;\n\t\tthis.tui.requestRender();\n\t}\n\n\tmenu(build: () => McpMenu, subscribe?: (listener: () => void) => () => void): Promise<string | undefined> {\n\t\treturn new Promise((resolve) => {\n\t\t\tlet unsubscribe: (() => void) | undefined;\n\t\t\tlet settled = false;\n\t\t\tconst finish = (value: string | undefined) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tunsubscribe?.();\n\t\t\t\tresolve(value);\n\t\t\t};\n\t\t\tlet selected: string | undefined;\n\t\t\tconst render = () => {\n\t\t\t\tconst menu = build();\n\t\t\t\tconst wanted = selected ?? menu.selected;\n\t\t\t\tconst body: Component[] = [];\n\t\t\t\tif (menu.details) body.push(new Text(this.theme.fg(\"muted\", menu.details), 1, 0));\n\t\t\t\tif (menu.error) body.push(new Text(this.theme.fg(\"error\", menu.error), 1, 0));\n\t\t\t\tbody.push(new Spacer(1));\n\t\t\t\tconst footer = `${keyHint(\"tui.select.confirm\", menu.confirmLabel)} • ${keyHint(\"tui.select.cancel\", menu.cancelLabel)}`;\n\t\t\t\tif (menu.items.length === 0) {\n\t\t\t\t\tbody.push(new Text(this.theme.fg(\"muted\", menu.empty ?? \"Nothing to show.\"), 1, 0));\n\t\t\t\t\tthis.setContent(\n\t\t\t\t\t\tframe(this.theme, menu.title, body, keyHint(\"tui.select.cancel\", menu.cancelLabel)),\n\t\t\t\t\t\t(data) => {\n\t\t\t\t\t\t\tif (this.keybindings.matches(data, \"tui.select.cancel\")) finish(undefined);\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst list = new SelectList(\n\t\t\t\t\tmenu.items,\n\t\t\t\t\tMath.min(menu.items.length, MAX_VISIBLE_ITEMS),\n\t\t\t\t\tgetSelectListTheme(),\n\t\t\t\t);\n\t\t\t\tconst index = menu.items.findIndex((item) => item.value === wanted);\n\t\t\t\tif (index !== -1) list.setSelectedIndex(index);\n\t\t\t\tselected = list.getSelectedItem()?.value;\n\t\t\t\tlist.onSelectionChange = (item) => {\n\t\t\t\t\tselected = item.value;\n\t\t\t\t};\n\t\t\t\tlist.onSelect = (item) => finish(item.value);\n\t\t\t\tlist.onCancel = () => finish(undefined);\n\t\t\t\tbody.push(list);\n\t\t\t\tthis.setContent(frame(this.theme, menu.title, body, footer), (data) => list.handleInput(data));\n\t\t\t};\n\t\t\trender();\n\t\t\tunsubscribe = subscribe?.(() => {\n\t\t\t\tif (!settled) render();\n\t\t\t});\n\t\t});\n\t}\n\n\tstatus(title: string, message: string): void {\n\t\tthis.setContent(frame(this.theme, title, [new Spacer(1), new Text(this.theme.fg(\"muted\", message), 1, 0)]));\n\t}\n\n\tredirectUrl(title: string, authorizationUrl: string, signal: AbortSignal): Promise<string | undefined> {\n\t\treturn new Promise((resolve) => {\n\t\t\tlet settled = false;\n\t\t\tconst finish = (value: string | undefined) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\t\tresolve(value);\n\t\t\t};\n\t\t\tconst onAbort = () => finish(undefined);\n\t\t\tif (signal.aborted) {\n\t\t\t\tfinish(undefined);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\tconst input = new Input();\n\t\t\tconst clickHint = process.platform === \"darwin\" ? \"Cmd+click to open\" : \"Ctrl+click to open\";\n\t\t\tconst body: Component[] = [\n\t\t\t\tnew Spacer(1),\n\t\t\t\tnew Text(this.theme.fg(\"muted\", \"Approve access in your browser. If it did not open, visit:\"), 1, 0),\n\t\t\t\tnew Text(this.theme.fg(\"accent\", hyperlink(authorizationUrl, authorizationUrl)), 1, 0),\n\t\t\t\tnew Text(this.theme.fg(\"dim\", hyperlink(clickHint, authorizationUrl)), 1, 0),\n\t\t\t\tnew Spacer(1),\n\t\t\t\tnew Text(\n\t\t\t\t\tthis.theme.fg(\"muted\", \"If the browser runs on another machine, paste the URL it was redirected to:\"),\n\t\t\t\t\t1,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t\tinput,\n\t\t\t];\n\t\t\tthis.setContent(\n\t\t\t\tframe(\n\t\t\t\t\tthis.theme,\n\t\t\t\t\ttitle,\n\t\t\t\t\tbody,\n\t\t\t\t\t`${keyHint(\"tui.select.confirm\", \"submit\")} • ${keyHint(\"tui.select.cancel\", \"cancel\")}`,\n\t\t\t\t),\n\t\t\t\t(data) => {\n\t\t\t\t\tif (this.keybindings.matches(data, \"tui.select.confirm\")) {\n\t\t\t\t\t\tconst value = input.getValue().trim();\n\t\t\t\t\t\tif (value) finish(value);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (this.keybindings.matches(data, \"tui.select.cancel\")) {\n\t\t\t\t\t\tfinish(undefined);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tinput.handleInput(data);\n\t\t\t\t},\n\t\t\t\tinput,\n\t\t\t);\n\t\t});\n\t}\n\n\thandleInput(data: string): void {\n\t\tthis.inputHandler?.(data);\n\t\tthis.tui.requestRender();\n\t}\n\n\trender(width: number): string[] {\n\t\treturn this.content\n\t\t\t.render(width)\n\t\t\t.map((line) => (visibleWidth(line) > width ? truncateToWidth(line, width, \"\") : line));\n\t}\n\n\tinvalidate(): void {\n\t\tthis.content.invalidate();\n\t}\n}\n\n/** Run `manage` in the manager view until it returns. */\nexport async function showMcpManager(\n\tctx: ExtensionCommandContext,\n\tmanage: (ui: McpUi) => Promise<void>,\n): Promise<void> {\n\tawait ctx.ui.custom<void>((tui, theme, keybindings, done) => {\n\t\tconst view = new McpManagerView(tui, theme, keybindings);\n\t\tvoid manage(view).then(\n\t\t\t() => done(),\n\t\t\t(error: unknown) => {\n\t\t\t\tctx.ui.notify(error instanceof Error ? error.message : String(error), \"error\");\n\t\t\t\tdone();\n\t\t\t},\n\t\t);\n\t\treturn view;\n\t});\n}\n"]}
|
|
@@ -28,7 +28,8 @@ export interface ToolRanker {
|
|
|
28
28
|
export declare function tokenize(text: string): string[];
|
|
29
29
|
/**
|
|
30
30
|
* Search text of a tool: the name, the name with `_`
|
|
31
|
-
* as spaces, the description, schema descriptions and property names, and the namespace
|
|
31
|
+
* as spaces, the description, schema descriptions and property names, and the namespace with its
|
|
32
|
+
* description and instructions.
|
|
32
33
|
*/
|
|
33
34
|
export declare function createToolSearchDocument(tool: Pick<ToolInfo, "name" | "description" | "parameters">, namespace?: ToolNamespace): ToolSearchDocument;
|
|
34
35
|
/** Okapi BM25 with the usual parameters. Ties keep document order. */
|
|
@@ -64,9 +65,9 @@ export interface ToolSearchToolOptions {
|
|
|
64
65
|
tools?: Pick<ExtensionAPI, "getAllTools" | "getActiveTools" | "setActiveTools">;
|
|
65
66
|
}
|
|
66
67
|
/**
|
|
67
|
-
* The `tool_search` description.
|
|
68
|
-
*
|
|
68
|
+
* The `tool_search` description. It does not list the searchable tools or their namespaces, so it
|
|
69
|
+
* stays the same while tools are registered, for example when MCP servers connect.
|
|
69
70
|
*/
|
|
70
|
-
export declare
|
|
71
|
+
export declare const TOOL_SEARCH_DESCRIPTION = "# Tool discovery\n\nSearches over deferred tool metadata with BM25 and exposes matching tools for the next model call.\n\nSome of the tools, such as tools of MCP servers, may not have been provided to you upfront, and you should use this tool (`tool_search`) to search for the required tools. For MCP tool discovery, always use `tool_search`.";
|
|
71
72
|
export declare function createToolSearchToolDefinition(options?: ToolSearchToolOptions): ToolDefinition<typeof toolSearchSchema, ToolSearchToolDetails>;
|
|
72
73
|
//# sourceMappingURL=tool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../../src/extensions/tool-search/tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EACX,YAAY,EACZ,cAAc,EAEd,QAAQ,EACR,aAAa,EACb,MAAM,gCAAgC,CAAC;AAExC,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AACnD,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAE3C,qGAAqG;AACrG,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACd;AAED,2FAA2F;AAC3F,MAAM,WAAW,UAAU;IAC1B,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,kBAAkB,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,EAAE,CAAC;CAChG;AAkCD,gGAAgG;AAChG,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ/C;AAuBD
|
|
1
|
+
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../../src/extensions/tool-search/tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EACX,YAAY,EACZ,cAAc,EAEd,QAAQ,EACR,aAAa,EACb,MAAM,gCAAgC,CAAC;AAExC,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AACnD,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAE3C,qGAAqG;AACrG,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACd;AAED,2FAA2F;AAC3F,MAAM,WAAW,UAAU;IAC1B,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,kBAAkB,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,EAAE,CAAC;CAChG;AAkCD,gGAAgG;AAChG,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ/C;AAuBD;;;;GAIG;AACH,wBAAgB,wBAAwB,CACvC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,GAAG,YAAY,CAAC,EAC3D,SAAS,CAAC,EAAE,aAAa,GACvB,kBAAkB,CAKpB;AAED,sEAAsE;AACtE,qBAAa,UAAW,YAAW,UAAU;IAC5C,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAS;IAE3B,YAAY,OAAO,GAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAA;KAAO,EAGpD;IAED,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,kBAAkB,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,EAAE,CA4B9F;CACD;AAED,eAAO,MAAM,gBAAgB;;;EAK3B,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE9D,6FAA6F;AAC7F,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,CAAC,GAAG,OAAO,CAErF;AAED,MAAM,WAAW,oBAAoB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,qBAAqB;IACrC,iCAAiC;IACjC,MAAM,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,qBAAqB;IACrC;;;OAGG;IACH,KAAK,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,aAAa,GAAG,gBAAgB,GAAG,gBAAgB,CAAC,CAAC;CAChF;AA2BD;;;GAGG;AACH,eAAO,MAAM,uBAAuB,2VAAyX,CAAC;AAE9Z,wBAAgB,8BAA8B,CAC7C,OAAO,GAAE,qBAA0B,GACjC,cAAc,CAAC,OAAO,gBAAgB,EAAE,qBAAqB,CAAC,CAuBhE"}
|
|
@@ -78,13 +78,14 @@ function schemaText(schema, parts) {
|
|
|
78
78
|
}
|
|
79
79
|
/**
|
|
80
80
|
* Search text of a tool: the name, the name with `_`
|
|
81
|
-
* as spaces, the description, schema descriptions and property names, and the namespace
|
|
81
|
+
* as spaces, the description, schema descriptions and property names, and the namespace with its
|
|
82
|
+
* description and instructions.
|
|
82
83
|
*/
|
|
83
84
|
export function createToolSearchDocument(tool, namespace) {
|
|
84
85
|
const parts = [tool.name, tool.name.replaceAll("_", " "), tool.description];
|
|
85
86
|
schemaText(tool.parameters, parts);
|
|
86
87
|
if (namespace)
|
|
87
|
-
parts.push(namespace.name, namespace.description ?? "");
|
|
88
|
+
parts.push(namespace.name, namespace.description ?? "", namespace.instructions ?? "");
|
|
88
89
|
return { name: tool.name, text: parts.filter((part) => part.trim()).join(" ") };
|
|
89
90
|
}
|
|
90
91
|
/** Okapi BM25 with the usual parameters. Ties keep document order. */
|
|
@@ -156,41 +157,19 @@ function searchAndLoad(tools, query, limit) {
|
|
|
156
157
|
}));
|
|
157
158
|
}
|
|
158
159
|
/**
|
|
159
|
-
* The `tool_search` description.
|
|
160
|
-
*
|
|
160
|
+
* The `tool_search` description. It does not list the searchable tools or their namespaces, so it
|
|
161
|
+
* stays the same while tools are registered, for example when MCP servers connect.
|
|
161
162
|
*/
|
|
162
|
-
export
|
|
163
|
-
const listed = sources.length === 0
|
|
164
|
-
? "None currently enabled."
|
|
165
|
-
: sources
|
|
166
|
-
.map((source) => {
|
|
167
|
-
const description = source.description?.trim().split(/\r?\n/)[0];
|
|
168
|
-
return description ? `- ${source.name}: ${description}` : `- ${source.name}`;
|
|
169
|
-
})
|
|
170
|
-
.join("\n");
|
|
171
|
-
return `# Tool discovery\n\nSearches over deferred tool metadata with BM25 and exposes matching tools for the next model call.\n\nYou have access to tools from the following sources:\n${listed}\n\nSome of the tools may not have been provided to you upfront, and you should use this tool (\`${TOOL_SEARCH_TOOL_NAME}\`) to search for the required tools. For MCP tool discovery, always use \`${TOOL_SEARCH_TOOL_NAME}\`.`;
|
|
172
|
-
}
|
|
163
|
+
export const TOOL_SEARCH_DESCRIPTION = `# Tool discovery\n\nSearches over deferred tool metadata with BM25 and exposes matching tools for the next model call.\n\nSome of the tools, such as tools of MCP servers, may not have been provided to you upfront, and you should use this tool (\`${TOOL_SEARCH_TOOL_NAME}\`) to search for the required tools. For MCP tool discovery, always use \`${TOOL_SEARCH_TOOL_NAME}\`.`;
|
|
173
164
|
export function createToolSearchToolDefinition(options = {}) {
|
|
174
165
|
return {
|
|
175
166
|
name: TOOL_SEARCH_TOOL_NAME,
|
|
176
167
|
label: TOOL_SEARCH_TOOL_NAME,
|
|
177
|
-
|
|
178
|
-
description: createToolSearchDescription(),
|
|
168
|
+
description: TOOL_SEARCH_DESCRIPTION,
|
|
179
169
|
promptSnippet: "Search for tools that are not loaded yet and load the matches",
|
|
180
170
|
parameters: toolSearchSchema,
|
|
181
171
|
// Searching is not something scripts need; it changes what the model sees.
|
|
182
172
|
exposure: "model-only",
|
|
183
|
-
// List the namespaces of the searchable tools.
|
|
184
|
-
prepareLoadout: (loadout) => {
|
|
185
|
-
const sources = new Map();
|
|
186
|
-
for (const tool of loadout.registered) {
|
|
187
|
-
const namespace = loadout.getNamespace(tool.name);
|
|
188
|
-
if (isSearchable(loadout.getExposure(tool.name)) && namespace && !sources.has(namespace.name)) {
|
|
189
|
-
sources.set(namespace.name, namespace);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
return { descriptions: { [TOOL_SEARCH_TOOL_NAME]: createToolSearchDescription([...sources.values()]) } };
|
|
193
|
-
},
|
|
194
173
|
async execute(_toolCallId, { query, limit }) {
|
|
195
174
|
if (query.trim() === "")
|
|
196
175
|
throw new Error("query must not be empty");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.js","sourceRoot":"","sources":["../../../src/extensions/tool-search/tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAS5C,MAAM,CAAC,MAAM,qBAAqB,GAAG,aAAa,CAAC;AACnD,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC;AAkB3C,MAAM,UAAU,GAAwB,IAAI,GAAG,CAAC;IAC/C,GAAG;IACH,IAAI;IACJ,KAAK;IACL,KAAK;IACL,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,KAAK;IACL,MAAM;IACN,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,MAAM;IACN,KAAK;IACL,MAAM;IACN,IAAI;IACJ,MAAM;CACN,CAAC,CAAC;AAEH,wFAAwF;AACxF,SAAS,IAAI,CAAC,IAAY;IACzB,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;IAC5E,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,2BAA2B,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACxF,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5F,OAAO,IAAI,CAAC;AACb,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,QAAQ,CAAC,IAAY;IACpC,OAAO,IAAI;SACT,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC;SACtC,OAAO,CAAC,uBAAuB,EAAE,OAAO,CAAC;SACzC,WAAW,EAAE;SACb,KAAK,CAAC,YAAY,CAAC;SACnB,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;SAC1D,GAAG,CAAC,IAAI,CAAC,CAAC;AACb,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC/B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC7E,CAAC;AAED,2DAA2D;AAC3D,SAAS,UAAU,CAAC,MAAe,EAAE,KAAe;IACnD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO;IAC9B,IAAI,OAAO,MAAM,CAAC,WAAW,KAAK,QAAQ;QAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAC3E,IAAI,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;QACjC,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;YAClE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjB,UAAU,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC7B,CAAC;IACF,CAAC;IACD,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAChC,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;QAC/C,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;YAAE,KAAK,MAAM,OAAO,IAAI,QAAQ;gBAAE,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACzF,CAAC;AACF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,wBAAwB,CACvC,IAA2D,EAC3D,SAAyB;IAEzB,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IAC5E,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACnC,IAAI,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;IACvE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;AACjF,CAAC;AAED,sEAAsE;AACtE,MAAM,OAAO,UAAU;IACL,EAAE,CAAS;IACX,CAAC,CAAS;IAE3B,YAAY,OAAO,GAAgC,EAAE;QACpD,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC,EAAE,IAAI,GAAG,CAAC;QAC5B,IAAI,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,IAAI,CAAC;IAC5B,CAAC;IAED,IAAI,CAAC,KAAa,EAAE,SAAwC,EAAE,KAAa;QAC1E,MAAM,UAAU,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACjD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;YAAE,OAAO,EAAE,CAAC;QAC/E,MAAM,UAAU,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE;YAC7C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;YACzC,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAAE,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1F,OAAO,MAAM,CAAC;QACf,CAAC,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;QACxG,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,GAAG,GAAG,MAAM,EAAE,CAAC,CAAC,GAAG,SAAS,CAAC,MAAM,IAAI,CAAC,CAAC;QAC/F,MAAM,GAAG,GAAG,IAAI,GAAG,CAClB,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YACvB,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;YACzE,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,GAAG,SAAS,GAAG,GAAG,CAAC,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,CAAU,CAAC;QAChG,CAAC,CAAC,CACF,CAAC;QACF,MAAM,OAAO,GAAsB,EAAE,CAAC;QACtC,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE;YACrC,IAAI,KAAK,GAAG,CAAC,CAAC;YACd,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;gBAC/B,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAC1C,IAAI,CAAC,KAAK;oBAAE,SAAS;gBACrB,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC;gBAChF,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC;YAC5E,CAAC;YACD,IAAI,KAAK,GAAG,CAAC;gBAAE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC7D,CAAC,CAAC,CAAC;QACH,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAClE,CAAC;CACD;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAAC;IAC3C,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,kCAAkC,EAAE,CAAC;IACvE,KAAK,EAAE,IAAI,CAAC,QAAQ,CACnB,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,kDAAkD,yBAAyB,GAAG,EAAE,CAAC,CAC5G;CACD,CAAC,CAAC;AAIH,6FAA6F;AAC7F,MAAM,UAAU,gBAAgB,CAAC,IAA2C;IAC3E,OAAO,IAAI,CAAC,IAAI,KAAK,qBAAqB,IAAI,IAAI,CAAC,UAAU,KAAK,gBAAgB,CAAC;AACpF,CAAC;AAoBD,gEAAgE;AAChE,SAAS,YAAY,CAAC,QAAsB;IAC3C,OAAO,QAAQ,KAAK,UAAU,IAAI,QAAQ,KAAK,UAAU,CAAC;AAC3D,CAAC;AAED;;;GAGG;AACH,SAAS,aAAa,CACrB,KAAkD,EAClD,KAAa,EACb,KAAa;IAEb,MAAM,MAAM,GAAG,KAAK,CAAC,cAAc,EAAE,CAAC;IACtC,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACpH,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,wBAAwB,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IAC3F,MAAM,OAAO,GAAG,IAAI,UAAU,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;IAC/D,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,KAAK,CAAC,cAAc,CAAC,CAAC,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjG,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC9B,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,WAAW,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,EAAE,WAAW,IAAI,EAAE;KACnF,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,2BAA2B,CAAC,OAAO,GAA6B,EAAE;IACjF,MAAM,MAAM,GACX,OAAO,CAAC,MAAM,KAAK,CAAC;QACnB,CAAC,CAAC,yBAAyB;QAC3B,CAAC,CAAC,OAAO;aACN,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;YACf,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;YACjE,OAAO,WAAW,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC;QAC9E,CAAC,CAAC;aACD,IAAI,CAAC,IAAI,CAAC,CAAC;IAChB,OAAO,mLAAmL,MAAM,oGAAoG,qBAAqB,8EAA8E,qBAAqB,KAAK,CAAC;AACna,CAAC;AAED,MAAM,UAAU,8BAA8B,CAC7C,OAAO,GAA0B,EAAE;IAEnC,OAAO;QACN,IAAI,EAAE,qBAAqB;QAC3B,KAAK,EAAE,qBAAqB;QAC5B,mEAAmE;QACnE,WAAW,EAAE,2BAA2B,EAAE;QAC1C,aAAa,EAAE,+DAA+D;QAC9E,UAAU,EAAE,gBAAgB;QAC5B,2EAA2E;QAC3E,QAAQ,EAAE,YAAY;QACtB,+CAA+C;QAC/C,cAAc,EAAE,CAAC,OAAO,EAAE,EAAE;YAC3B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAyB,CAAC;YACjD,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;gBACvC,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAClD,IAAI,YAAY,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,SAAS,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC/F,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;gBACxC,CAAC;YACF,CAAC;YACD,OAAO,EAAE,YAAY,EAAE,EAAE,CAAC,qBAAqB,CAAC,EAAE,2BAA2B,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;QAC1G,CAAC;QACD,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE;YAC1C,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE;gBAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;YACpE,MAAM,GAAG,GAAG,KAAK,IAAI,yBAAyB,CAAC;YAC/C,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;YAC5F,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5E,MAAM,IAAI,GACT,KAAK,CAAC,MAAM,KAAK,CAAC;gBACjB,CAAC,CAAC,0BAA0B;gBAC5B,CAAC,CAAC,UAAU,KAAK,CAAC,MAAM,QAAQ,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,8CAA8C,KAAK;qBAC7G,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;qBAC7E,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAClB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QACnG,CAAC;KACD,CAAC;AACH,CAAC","sourcesContent":["/**\n * Tool discovery: a BM25 ranker over tool metadata, shared by `searchTools()` in codemode scripts and\n * the optional `tool_search` tool.\n *\n * `tool_search` searches tools that are not declared to\n * the model (`codemode` and `deferred` exposure) and loads the matches, so they are declared for the\n * next model call. Loading goes through the active tool set, so it is recorded in the transcript\n * like any other tool change and survives `/tree`, resume, and fork on that branch.\n */\n\nimport { type Static, Type } from \"typebox\";\nimport type {\n\tExtensionAPI,\n\tToolDefinition,\n\tToolExposure,\n\tToolInfo,\n\tToolNamespace,\n} from \"../../core/extensions/types.ts\";\n\nexport const TOOL_SEARCH_TOOL_NAME = \"tool_search\";\nexport const DEFAULT_TOOL_SEARCH_LIMIT = 8;\n\n/** A tool as the ranker sees it: its name and the text built by {@link createToolSearchDocument}. */\nexport interface ToolSearchDocument {\n\tname: string;\n\ttext: string;\n}\n\nexport interface ToolSearchMatch {\n\tname: string;\n\tscore: number;\n}\n\n/** Ranks tools for a query. BM25 today; a hybrid ranker with embeddings can replace it. */\nexport interface ToolRanker {\n\trank(query: string, documents: readonly ToolSearchDocument[], limit: number): ToolSearchMatch[];\n}\n\nconst STOP_WORDS: ReadonlySet<string> = new Set([\n\t\"a\",\n\t\"an\",\n\t\"and\",\n\t\"are\",\n\t\"as\",\n\t\"at\",\n\t\"be\",\n\t\"by\",\n\t\"for\",\n\t\"from\",\n\t\"in\",\n\t\"is\",\n\t\"it\",\n\t\"of\",\n\t\"on\",\n\t\"or\",\n\t\"that\",\n\t\"the\",\n\t\"this\",\n\t\"to\",\n\t\"with\",\n]);\n\n/** Naive singular form, so `issues` matches `issue` and `searches` matches `search`. */\nfunction stem(term: string): string {\n\tif (term.length > 4 && term.endsWith(\"ies\")) return `${term.slice(0, -3)}y`;\n\tif (term.length > 4 && /(ches|shes|sses|xes|zes)$/.test(term)) return term.slice(0, -2);\n\tif (term.length > 3 && term.endsWith(\"s\") && !term.endsWith(\"ss\")) return term.slice(0, -1);\n\treturn term;\n}\n\n/** Lowercase terms, split at camelCase boundaries and non-alphanumerics, without stop words. */\nexport function tokenize(text: string): string[] {\n\treturn text\n\t\t.replace(/([a-z0-9])([A-Z])/g, \"$1 $2\")\n\t\t.replace(/([A-Z]+)([A-Z][a-z])/g, \"$1 $2\")\n\t\t.toLowerCase()\n\t\t.split(/[^a-z0-9]+/)\n\t\t.filter((term) => term.length > 0 && !STOP_WORDS.has(term))\n\t\t.map(stem);\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Schema descriptions and property names, recursively. */\nfunction schemaText(schema: unknown, parts: string[]): void {\n\tif (!isObject(schema)) return;\n\tif (typeof schema.description === \"string\") parts.push(schema.description);\n\tif (isObject(schema.properties)) {\n\t\tfor (const [name, property] of Object.entries(schema.properties)) {\n\t\t\tparts.push(name);\n\t\t\tschemaText(property, parts);\n\t\t}\n\t}\n\tschemaText(schema.items, parts);\n\tfor (const key of [\"anyOf\", \"oneOf\", \"allOf\"]) {\n\t\tconst variants = schema[key];\n\t\tif (Array.isArray(variants)) for (const variant of variants) schemaText(variant, parts);\n\t}\n}\n\n/**\n * Search text of a tool: the name, the name with `_`\n * as spaces, the description, schema descriptions and property names, and the namespace.\n */\nexport function createToolSearchDocument(\n\ttool: Pick<ToolInfo, \"name\" | \"description\" | \"parameters\">,\n\tnamespace?: ToolNamespace,\n): ToolSearchDocument {\n\tconst parts = [tool.name, tool.name.replaceAll(\"_\", \" \"), tool.description];\n\tschemaText(tool.parameters, parts);\n\tif (namespace) parts.push(namespace.name, namespace.description ?? \"\");\n\treturn { name: tool.name, text: parts.filter((part) => part.trim()).join(\" \") };\n}\n\n/** Okapi BM25 with the usual parameters. Ties keep document order. */\nexport class Bm25Ranker implements ToolRanker {\n\tprivate readonly k1: number;\n\tprivate readonly b: number;\n\n\tconstructor(options: { k1?: number; b?: number } = {}) {\n\t\tthis.k1 = options.k1 ?? 1.2;\n\t\tthis.b = options.b ?? 0.75;\n\t}\n\n\trank(query: string, documents: readonly ToolSearchDocument[], limit: number): ToolSearchMatch[] {\n\t\tconst queryTerms = [...new Set(tokenize(query))];\n\t\tif (queryTerms.length === 0 || documents.length === 0 || limit <= 0) return [];\n\t\tconst termCounts = documents.map((document) => {\n\t\t\tconst counts = new Map<string, number>();\n\t\t\tfor (const term of tokenize(document.text)) counts.set(term, (counts.get(term) ?? 0) + 1);\n\t\t\treturn counts;\n\t\t});\n\t\tconst lengths = termCounts.map((counts) => [...counts.values()].reduce((sum, count) => sum + count, 0));\n\t\tconst averageLength = lengths.reduce((sum, length) => sum + length, 0) / documents.length || 1;\n\t\tconst idf = new Map(\n\t\t\tqueryTerms.map((term) => {\n\t\t\t\tconst frequency = termCounts.filter((counts) => counts.has(term)).length;\n\t\t\t\treturn [term, Math.log(1 + (documents.length - frequency + 0.5) / (frequency + 0.5))] as const;\n\t\t\t}),\n\t\t);\n\t\tconst matches: ToolSearchMatch[] = [];\n\t\tdocuments.forEach((document, index) => {\n\t\t\tlet score = 0;\n\t\t\tfor (const term of queryTerms) {\n\t\t\t\tconst count = termCounts[index].get(term);\n\t\t\t\tif (!count) continue;\n\t\t\t\tconst norm = this.k1 * (1 - this.b + (this.b * lengths[index]) / averageLength);\n\t\t\t\tscore += (idf.get(term) ?? 0) * ((count * (this.k1 + 1)) / (count + norm));\n\t\t\t}\n\t\t\tif (score > 0) matches.push({ name: document.name, score });\n\t\t});\n\t\treturn matches.sort((a, b) => b.score - a.score).slice(0, limit);\n\t}\n}\n\nexport const toolSearchSchema = Type.Object({\n\tquery: Type.String({ description: \"Search query for deferred tools.\" }),\n\tlimit: Type.Optional(\n\t\tType.Number({ description: `Maximum number of tools to return. Defaults to ${DEFAULT_TOOL_SEARCH_LIMIT}.` }),\n\t),\n});\n\nexport type ToolSearchInput = Static<typeof toolSearchSchema>;\n\n/** Whether the tool is this `tool_search`, not another extension's tool of the same name. */\nexport function isToolSearchTool(tool: Pick<ToolInfo, \"name\" | \"parameters\">): boolean {\n\treturn tool.name === TOOL_SEARCH_TOOL_NAME && tool.parameters === toolSearchSchema;\n}\n\nexport interface ToolSearchResultTool {\n\tname: string;\n\tdescription: string;\n}\n\nexport interface ToolSearchToolDetails {\n\t/** Tools loaded by this call. */\n\tloaded: string[];\n}\n\nexport interface ToolSearchToolOptions {\n\t/**\n\t * The session's tools. `tool_search` searches the tools that are not declared to the model and\n\t * activates the matches. Without it, the tool finds nothing. An `ExtensionAPI` fits.\n\t */\n\ttools?: Pick<ExtensionAPI, \"getAllTools\" | \"getActiveTools\" | \"setActiveTools\">;\n}\n\n/** Whether `tool_search` can load a tool with this exposure. */\nfunction isSearchable(exposure: ToolExposure): boolean {\n\treturn exposure === \"codemode\" || exposure === \"deferred\";\n}\n\n/**\n * Rank the searchable tools that are not active yet and activate the matches, so the next model\n * call declares them. Activation is recorded in the transcript like any tool change.\n */\nfunction searchAndLoad(\n\ttools: NonNullable<ToolSearchToolOptions[\"tools\"]>,\n\tquery: string,\n\tlimit: number,\n): ToolSearchResultTool[] {\n\tconst active = tools.getActiveTools();\n\tconst candidates = tools.getAllTools().filter((tool) => isSearchable(tool.exposure) && !active.includes(tool.name));\n\tconst documents = candidates.map((tool) => createToolSearchDocument(tool, tool.namespace));\n\tconst matches = new Bm25Ranker().rank(query, documents, limit);\n\tif (matches.length > 0) tools.setActiveTools([...active, ...matches.map((match) => match.name)]);\n\treturn matches.map((match) => ({\n\t\tname: match.name,\n\t\tdescription: candidates.find((tool) => tool.name === match.name)?.description ?? \"\",\n\t}));\n}\n\n/**\n * The `tool_search` description. `sources` lists the namespaces whose tools can be found, with\n * their descriptions.\n */\nexport function createToolSearchDescription(sources: readonly ToolNamespace[] = []): string {\n\tconst listed =\n\t\tsources.length === 0\n\t\t\t? \"None currently enabled.\"\n\t\t\t: sources\n\t\t\t\t\t.map((source) => {\n\t\t\t\t\t\tconst description = source.description?.trim().split(/\\r?\\n/)[0];\n\t\t\t\t\t\treturn description ? `- ${source.name}: ${description}` : `- ${source.name}`;\n\t\t\t\t\t})\n\t\t\t\t\t.join(\"\\n\");\n\treturn `# Tool discovery\\n\\nSearches over deferred tool metadata with BM25 and exposes matching tools for the next model call.\\n\\nYou have access to tools from the following sources:\\n${listed}\\n\\nSome of the tools may not have been provided to you upfront, and you should use this tool (\\`${TOOL_SEARCH_TOOL_NAME}\\`) to search for the required tools. For MCP tool discovery, always use \\`${TOOL_SEARCH_TOOL_NAME}\\`.`;\n}\n\nexport function createToolSearchToolDefinition(\n\toptions: ToolSearchToolOptions = {},\n): ToolDefinition<typeof toolSearchSchema, ToolSearchToolDetails> {\n\treturn {\n\t\tname: TOOL_SEARCH_TOOL_NAME,\n\t\tlabel: TOOL_SEARCH_TOOL_NAME,\n\t\t// Replaced with the searchable sources when the tool is activated.\n\t\tdescription: createToolSearchDescription(),\n\t\tpromptSnippet: \"Search for tools that are not loaded yet and load the matches\",\n\t\tparameters: toolSearchSchema,\n\t\t// Searching is not something scripts need; it changes what the model sees.\n\t\texposure: \"model-only\",\n\t\t// List the namespaces of the searchable tools.\n\t\tprepareLoadout: (loadout) => {\n\t\t\tconst sources = new Map<string, ToolNamespace>();\n\t\t\tfor (const tool of loadout.registered) {\n\t\t\t\tconst namespace = loadout.getNamespace(tool.name);\n\t\t\t\tif (isSearchable(loadout.getExposure(tool.name)) && namespace && !sources.has(namespace.name)) {\n\t\t\t\t\tsources.set(namespace.name, namespace);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { descriptions: { [TOOL_SEARCH_TOOL_NAME]: createToolSearchDescription([...sources.values()]) } };\n\t\t},\n\t\tasync execute(_toolCallId, { query, limit }) {\n\t\t\tif (query.trim() === \"\") throw new Error(\"query must not be empty\");\n\t\t\tconst max = limit ?? DEFAULT_TOOL_SEARCH_LIMIT;\n\t\t\tif (!Number.isInteger(max) || max <= 0) throw new Error(\"limit must be a positive integer\");\n\t\t\tconst tools = options.tools ? searchAndLoad(options.tools, query, max) : [];\n\t\t\tconst text =\n\t\t\t\ttools.length === 0\n\t\t\t\t\t? \"No matching tools found.\"\n\t\t\t\t\t: `Loaded ${tools.length} tool${tools.length === 1 ? \"\" : \"s\"}. They are available from your next call:\\n${tools\n\t\t\t\t\t\t\t.map((tool) => `- ${tool.name}: ${tool.description.trim().split(/\\r?\\n/)[0]}`)\n\t\t\t\t\t\t\t.join(\"\\n\")}`;\n\t\t\treturn { content: [{ type: \"text\", text }], details: { loaded: tools.map((tool) => tool.name) } };\n\t\t},\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tool.js","sourceRoot":"","sources":["../../../src/extensions/tool-search/tool.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Tool discovery: a BM25 ranker over tool metadata, shared by `searchTools()` in codemode scripts and\n * the optional `tool_search` tool.\n *\n * `tool_search` searches tools that are not declared to\n * the model (`codemode` and `deferred` exposure) and loads the matches, so they are declared for the\n * next model call. Loading goes through the active tool set, so it is recorded in the transcript\n * like any other tool change and survives `/tree`, resume, and fork on that branch.\n */\n\nimport { type Static, Type } from \"typebox\";\nimport type {\n\tExtensionAPI,\n\tToolDefinition,\n\tToolExposure,\n\tToolInfo,\n\tToolNamespace,\n} from \"../../core/extensions/types.ts\";\n\nexport const TOOL_SEARCH_TOOL_NAME = \"tool_search\";\nexport const DEFAULT_TOOL_SEARCH_LIMIT = 8;\n\n/** A tool as the ranker sees it: its name and the text built by {@link createToolSearchDocument}. */\nexport interface ToolSearchDocument {\n\tname: string;\n\ttext: string;\n}\n\nexport interface ToolSearchMatch {\n\tname: string;\n\tscore: number;\n}\n\n/** Ranks tools for a query. BM25 today; a hybrid ranker with embeddings can replace it. */\nexport interface ToolRanker {\n\trank(query: string, documents: readonly ToolSearchDocument[], limit: number): ToolSearchMatch[];\n}\n\nconst STOP_WORDS: ReadonlySet<string> = new Set([\n\t\"a\",\n\t\"an\",\n\t\"and\",\n\t\"are\",\n\t\"as\",\n\t\"at\",\n\t\"be\",\n\t\"by\",\n\t\"for\",\n\t\"from\",\n\t\"in\",\n\t\"is\",\n\t\"it\",\n\t\"of\",\n\t\"on\",\n\t\"or\",\n\t\"that\",\n\t\"the\",\n\t\"this\",\n\t\"to\",\n\t\"with\",\n]);\n\n/** Naive singular form, so `issues` matches `issue` and `searches` matches `search`. */\nfunction stem(term: string): string {\n\tif (term.length > 4 && term.endsWith(\"ies\")) return `${term.slice(0, -3)}y`;\n\tif (term.length > 4 && /(ches|shes|sses|xes|zes)$/.test(term)) return term.slice(0, -2);\n\tif (term.length > 3 && term.endsWith(\"s\") && !term.endsWith(\"ss\")) return term.slice(0, -1);\n\treturn term;\n}\n\n/** Lowercase terms, split at camelCase boundaries and non-alphanumerics, without stop words. */\nexport function tokenize(text: string): string[] {\n\treturn text\n\t\t.replace(/([a-z0-9])([A-Z])/g, \"$1 $2\")\n\t\t.replace(/([A-Z]+)([A-Z][a-z])/g, \"$1 $2\")\n\t\t.toLowerCase()\n\t\t.split(/[^a-z0-9]+/)\n\t\t.filter((term) => term.length > 0 && !STOP_WORDS.has(term))\n\t\t.map(stem);\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Schema descriptions and property names, recursively. */\nfunction schemaText(schema: unknown, parts: string[]): void {\n\tif (!isObject(schema)) return;\n\tif (typeof schema.description === \"string\") parts.push(schema.description);\n\tif (isObject(schema.properties)) {\n\t\tfor (const [name, property] of Object.entries(schema.properties)) {\n\t\t\tparts.push(name);\n\t\t\tschemaText(property, parts);\n\t\t}\n\t}\n\tschemaText(schema.items, parts);\n\tfor (const key of [\"anyOf\", \"oneOf\", \"allOf\"]) {\n\t\tconst variants = schema[key];\n\t\tif (Array.isArray(variants)) for (const variant of variants) schemaText(variant, parts);\n\t}\n}\n\n/**\n * Search text of a tool: the name, the name with `_`\n * as spaces, the description, schema descriptions and property names, and the namespace with its\n * description and instructions.\n */\nexport function createToolSearchDocument(\n\ttool: Pick<ToolInfo, \"name\" | \"description\" | \"parameters\">,\n\tnamespace?: ToolNamespace,\n): ToolSearchDocument {\n\tconst parts = [tool.name, tool.name.replaceAll(\"_\", \" \"), tool.description];\n\tschemaText(tool.parameters, parts);\n\tif (namespace) parts.push(namespace.name, namespace.description ?? \"\", namespace.instructions ?? \"\");\n\treturn { name: tool.name, text: parts.filter((part) => part.trim()).join(\" \") };\n}\n\n/** Okapi BM25 with the usual parameters. Ties keep document order. */\nexport class Bm25Ranker implements ToolRanker {\n\tprivate readonly k1: number;\n\tprivate readonly b: number;\n\n\tconstructor(options: { k1?: number; b?: number } = {}) {\n\t\tthis.k1 = options.k1 ?? 1.2;\n\t\tthis.b = options.b ?? 0.75;\n\t}\n\n\trank(query: string, documents: readonly ToolSearchDocument[], limit: number): ToolSearchMatch[] {\n\t\tconst queryTerms = [...new Set(tokenize(query))];\n\t\tif (queryTerms.length === 0 || documents.length === 0 || limit <= 0) return [];\n\t\tconst termCounts = documents.map((document) => {\n\t\t\tconst counts = new Map<string, number>();\n\t\t\tfor (const term of tokenize(document.text)) counts.set(term, (counts.get(term) ?? 0) + 1);\n\t\t\treturn counts;\n\t\t});\n\t\tconst lengths = termCounts.map((counts) => [...counts.values()].reduce((sum, count) => sum + count, 0));\n\t\tconst averageLength = lengths.reduce((sum, length) => sum + length, 0) / documents.length || 1;\n\t\tconst idf = new Map(\n\t\t\tqueryTerms.map((term) => {\n\t\t\t\tconst frequency = termCounts.filter((counts) => counts.has(term)).length;\n\t\t\t\treturn [term, Math.log(1 + (documents.length - frequency + 0.5) / (frequency + 0.5))] as const;\n\t\t\t}),\n\t\t);\n\t\tconst matches: ToolSearchMatch[] = [];\n\t\tdocuments.forEach((document, index) => {\n\t\t\tlet score = 0;\n\t\t\tfor (const term of queryTerms) {\n\t\t\t\tconst count = termCounts[index].get(term);\n\t\t\t\tif (!count) continue;\n\t\t\t\tconst norm = this.k1 * (1 - this.b + (this.b * lengths[index]) / averageLength);\n\t\t\t\tscore += (idf.get(term) ?? 0) * ((count * (this.k1 + 1)) / (count + norm));\n\t\t\t}\n\t\t\tif (score > 0) matches.push({ name: document.name, score });\n\t\t});\n\t\treturn matches.sort((a, b) => b.score - a.score).slice(0, limit);\n\t}\n}\n\nexport const toolSearchSchema = Type.Object({\n\tquery: Type.String({ description: \"Search query for deferred tools.\" }),\n\tlimit: Type.Optional(\n\t\tType.Number({ description: `Maximum number of tools to return. Defaults to ${DEFAULT_TOOL_SEARCH_LIMIT}.` }),\n\t),\n});\n\nexport type ToolSearchInput = Static<typeof toolSearchSchema>;\n\n/** Whether the tool is this `tool_search`, not another extension's tool of the same name. */\nexport function isToolSearchTool(tool: Pick<ToolInfo, \"name\" | \"parameters\">): boolean {\n\treturn tool.name === TOOL_SEARCH_TOOL_NAME && tool.parameters === toolSearchSchema;\n}\n\nexport interface ToolSearchResultTool {\n\tname: string;\n\tdescription: string;\n}\n\nexport interface ToolSearchToolDetails {\n\t/** Tools loaded by this call. */\n\tloaded: string[];\n}\n\nexport interface ToolSearchToolOptions {\n\t/**\n\t * The session's tools. `tool_search` searches the tools that are not declared to the model and\n\t * activates the matches. Without it, the tool finds nothing. An `ExtensionAPI` fits.\n\t */\n\ttools?: Pick<ExtensionAPI, \"getAllTools\" | \"getActiveTools\" | \"setActiveTools\">;\n}\n\n/** Whether `tool_search` can load a tool with this exposure. */\nfunction isSearchable(exposure: ToolExposure): boolean {\n\treturn exposure === \"codemode\" || exposure === \"deferred\";\n}\n\n/**\n * Rank the searchable tools that are not active yet and activate the matches, so the next model\n * call declares them. Activation is recorded in the transcript like any tool change.\n */\nfunction searchAndLoad(\n\ttools: NonNullable<ToolSearchToolOptions[\"tools\"]>,\n\tquery: string,\n\tlimit: number,\n): ToolSearchResultTool[] {\n\tconst active = tools.getActiveTools();\n\tconst candidates = tools.getAllTools().filter((tool) => isSearchable(tool.exposure) && !active.includes(tool.name));\n\tconst documents = candidates.map((tool) => createToolSearchDocument(tool, tool.namespace));\n\tconst matches = new Bm25Ranker().rank(query, documents, limit);\n\tif (matches.length > 0) tools.setActiveTools([...active, ...matches.map((match) => match.name)]);\n\treturn matches.map((match) => ({\n\t\tname: match.name,\n\t\tdescription: candidates.find((tool) => tool.name === match.name)?.description ?? \"\",\n\t}));\n}\n\n/**\n * The `tool_search` description. It does not list the searchable tools or their namespaces, so it\n * stays the same while tools are registered, for example when MCP servers connect.\n */\nexport const TOOL_SEARCH_DESCRIPTION = `# Tool discovery\\n\\nSearches over deferred tool metadata with BM25 and exposes matching tools for the next model call.\\n\\nSome of the tools, such as tools of MCP servers, may not have been provided to you upfront, and you should use this tool (\\`${TOOL_SEARCH_TOOL_NAME}\\`) to search for the required tools. For MCP tool discovery, always use \\`${TOOL_SEARCH_TOOL_NAME}\\`.`;\n\nexport function createToolSearchToolDefinition(\n\toptions: ToolSearchToolOptions = {},\n): ToolDefinition<typeof toolSearchSchema, ToolSearchToolDetails> {\n\treturn {\n\t\tname: TOOL_SEARCH_TOOL_NAME,\n\t\tlabel: TOOL_SEARCH_TOOL_NAME,\n\t\tdescription: TOOL_SEARCH_DESCRIPTION,\n\t\tpromptSnippet: \"Search for tools that are not loaded yet and load the matches\",\n\t\tparameters: toolSearchSchema,\n\t\t// Searching is not something scripts need; it changes what the model sees.\n\t\texposure: \"model-only\",\n\t\tasync execute(_toolCallId, { query, limit }) {\n\t\t\tif (query.trim() === \"\") throw new Error(\"query must not be empty\");\n\t\t\tconst max = limit ?? DEFAULT_TOOL_SEARCH_LIMIT;\n\t\t\tif (!Number.isInteger(max) || max <= 0) throw new Error(\"limit must be a positive integer\");\n\t\t\tconst tools = options.tools ? searchAndLoad(options.tools, query, max) : [];\n\t\t\tconst text =\n\t\t\t\ttools.length === 0\n\t\t\t\t\t? \"No matching tools found.\"\n\t\t\t\t\t: `Loaded ${tools.length} tool${tools.length === 1 ? \"\" : \"s\"}. They are available from your next call:\\n${tools\n\t\t\t\t\t\t\t.map((tool) => `- ${tool.name}: ${tool.description.trim().split(/\\r?\\n/)[0]}`)\n\t\t\t\t\t\t\t.join(\"\\n\")}`;\n\t\t\treturn { content: [{ type: \"text\", text }], details: { loaded: tools.map((tool) => tool.name) } };\n\t\t},\n\t};\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export type { ResourceCollision, ResourceDiagnostic, ResourceLoader } from "./co
|
|
|
19
19
|
export { DefaultResourceLoader, loadProjectContextFiles } from "./core/resource-loader.ts";
|
|
20
20
|
export { AgentSessionRuntime, type AgentSessionRuntimeDiagnostic, type AgentSessionServices, type CreateAgentSessionFromServicesOptions, type CreateAgentSessionOptions, type CreateAgentSessionResult, type CreateAgentSessionRuntimeFactory, type CreateAgentSessionRuntimeResult, type CreateAgentSessionServicesOptions, createAgentSession, createAgentSessionFromServices, createAgentSessionRuntime, createAgentSessionServices, createBashTool, createCodingTools, createEditTool, createFindTool, createGrepTool, createLsTool, createPowerShellTool, createReadOnlyTools, createReadTool, createWriteTool, type PromptTemplate, } from "./core/sdk.ts";
|
|
21
21
|
export { type BranchSummaryEntry, buildContextEntries, buildSessionContext, buildSessionProjection, type CompactionEntry, type ContextEditableContent, type ContextEditEntry, CURRENT_SESSION_VERSION, type CustomEntry, type CustomMessageEntry, type FileEntry, getLatestCompactionEntry, type ModelChangeEntry, migrateSessionEntries, type NewSessionOptions, type ProjectedSessionEntry, parseSessionEntries, type SessionContext, type SessionEntry, type SessionEntryBase, type SessionHeader, type SessionInfo, type SessionInfoEntry, SessionManager, type SessionMessageEntry, type SessionProjection, type SessionTreeNode, sessionEntryToContextMessages, type ThinkingLevelChangeEntry, } from "./core/session-manager.ts";
|
|
22
|
-
export { type CacheWarmingMode, type CompactionModelOverride, type CompactionSettings, type DefaultProjectTrust, type FullscreenExitOutput, type ImageSettings, type PackageSource, type RetrySettings, SettingsManager, type SettingsManagerCreateOptions, type TuiMode, } from "./core/settings-manager.ts";
|
|
22
|
+
export { type CacheWarmingMode, type CompactionModelOverride, type CompactionSettings, type DefaultProjectTrust, type FullscreenExitOutput, type ImageSettings, type PackageSource, type QuietStartup, type RetrySettings, SettingsManager, type SettingsManagerCreateOptions, type TuiMode, } from "./core/settings-manager.ts";
|
|
23
23
|
export { formatSkillsForPrompt, type LoadSkillsFromDirOptions, type LoadSkillsResult, loadSkills, loadSkillsFromDir, type Skill, type SkillFrontmatter, } from "./core/skills.ts";
|
|
24
24
|
export { createSyntheticSourceInfo } from "./core/source-info.ts";
|
|
25
25
|
export { type EditDiffResult, generateDiffString, generateUnifiedPatch } from "./core/tools/edit-diff.ts";
|