@astralyn/pi 1.0.5 → 1.2.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 +79 -0
- package/dist/bundle/chunks/anthropic-messages-NVP5OPIM.js +6 -0
- package/dist/bundle/chunks/anthropic.js +1 -1
- package/dist/bundle/chunks/{azure-openai-responses-LDW4FGAQ.js → azure-openai-responses-IBTOZ5MH.js} +1 -1
- package/dist/bundle/chunks/bedrock-converse-stream.js +2 -2
- package/dist/bundle/chunks/chunk-4XZYHGVN.js +11 -0
- package/dist/bundle/chunks/{chunk-GIG5IHES.js → chunk-5KJH3GGH.js} +1 -1
- package/dist/bundle/chunks/chunk-6VYRLG5F.js +2 -0
- package/dist/bundle/chunks/{chunk-UCXU7KLO.js → chunk-7HJ6CHUB.js} +1 -1
- package/dist/bundle/chunks/chunk-7UBIBLPN.js +2 -0
- package/dist/bundle/chunks/{chunk-IE3Z7ESB.js → chunk-A5HU4TE6.js} +418 -362
- package/dist/bundle/chunks/{chunk-HDHRZ7GT.js → chunk-B2UOWO4A.js} +1 -1
- package/dist/bundle/chunks/chunk-J75WV3FL.js +2 -0
- package/dist/bundle/chunks/{chunk-A6ALEEY5.js → chunk-LHSPN2IO.js} +1 -1
- package/dist/bundle/chunks/chunk-Q74S7ILH.js +2 -0
- package/dist/bundle/chunks/chunk-QDDSFJ35.js +2 -0
- package/dist/bundle/chunks/{chunk-IFELM7MW.js → chunk-UQECUCUH.js} +1 -1
- package/dist/bundle/chunks/cloudflare-workers-ai-system-one-HGOVFZDC.js +2 -0
- package/dist/bundle/chunks/codemode-worker.js +18 -10
- package/dist/bundle/chunks/github-copilot.js +1 -1
- package/dist/bundle/chunks/{google-generative-ai-S5A5IBU4.js → google-generative-ai-M44TSMAN.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-UBRQFDB4.js → google-vertex-3C4OWLFX.js} +1 -1
- package/dist/bundle/chunks/image-resize-worker.js +1 -1
- package/dist/bundle/chunks/{llama-cpp-classify-R7DQLTQN.js → llama-cpp-classify-H3IZDR5O.js} +2 -2
- package/dist/bundle/chunks/mistral-conversations-I5PL4VCZ.js +5 -0
- package/dist/bundle/chunks/openai-chatgpt.js +1 -1
- package/dist/bundle/chunks/openai-codex-responses-O5EUDL54.js +10 -0
- package/dist/bundle/chunks/openai-codex.js +1 -1
- package/dist/bundle/chunks/{openai-completions-H4VMO7AU.js → openai-completions-X3SSG5BQ.js} +1 -1
- package/dist/bundle/chunks/openai-decisions-TVCDIPZX.js +5 -0
- package/dist/bundle/chunks/{openai-responses-G4PGNM2H.js → openai-responses-NYPNKVDV.js} +1 -1
- package/dist/bundle/chunks/{openrouter-images-YP3YVB54.js → openrouter-images-TDLJV5N4.js} +1 -1
- package/dist/bundle/chunks/{pi-messages-HZZ7GEEW.js → pi-messages-ZXNERWJG.js} +1 -1
- package/dist/bundle/chunks/typesafe-system-one-LWPJYTJP.js +2 -0
- package/dist/bundle/chunks/{virtual-modules-46MSJGKO.js → virtual-modules-OZTPKGU7.js} +1 -1
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/cli/args.d.ts +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +13 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-session.d.ts +26 -7
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +190 -183
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +20 -13
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +40 -45
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/bug-report.d.ts +9 -1
- package/dist/core/bug-report.d.ts.map +1 -1
- package/dist/core/compaction/utils.d.ts +6 -0
- package/dist/core/compaction/utils.d.ts.map +1 -1
- package/dist/core/compaction/utils.js +7 -8
- package/dist/core/compaction/utils.js.map +1 -1
- package/dist/core/context-snapshot.d.ts +4 -1
- package/dist/core/context-snapshot.d.ts.map +1 -1
- package/dist/core/context-snapshot.js +45 -0
- package/dist/core/context-snapshot.js.map +1 -1
- package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
- package/dist/core/export-html/tool-renderer.js +2 -0
- package/dist/core/export-html/tool-renderer.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +4 -2
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +2 -3
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +42 -7
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/key-id-schema.d.ts +6 -0
- package/dist/core/key-id-schema.d.ts.map +1 -0
- package/dist/core/key-id-schema.js +16 -0
- package/dist/core/key-id-schema.js.map +1 -0
- package/dist/core/keybinding-registry.d.ts +4 -3
- package/dist/core/keybinding-registry.d.ts.map +1 -1
- package/dist/core/keybinding-registry.js +4 -3
- package/dist/core/keybinding-registry.js.map +1 -1
- package/dist/core/keybindings-schema.d.ts +4 -0
- package/dist/core/keybindings-schema.d.ts.map +1 -0
- package/dist/core/keybindings-schema.js +16 -0
- package/dist/core/keybindings-schema.js.map +1 -0
- package/dist/core/keybindings.d.ts +258 -81
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +27 -24
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/model-config.d.ts +713 -180
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +18 -179
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +13 -7
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/nested-tool-calls.d.ts +1 -0
- package/dist/core/nested-tool-calls.d.ts.map +1 -1
- package/dist/core/nested-tool-calls.js +1 -0
- package/dist/core/nested-tool-calls.js.map +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +3 -3
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/project-trust.d.ts.map +1 -1
- package/dist/core/project-trust.js +2 -1
- package/dist/core/project-trust.js.map +1 -1
- package/dist/core/remote-catalog-provider.d.ts +12 -1
- package/dist/core/remote-catalog-provider.d.ts.map +1 -1
- package/dist/core/remote-catalog-provider.js +82 -24
- package/dist/core/remote-catalog-provider.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +7 -2
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts +4 -0
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +17 -5
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-defaults.d.ts +65 -0
- package/dist/core/settings-defaults.d.ts.map +1 -0
- package/dist/core/settings-defaults.js +66 -0
- package/dist/core/settings-defaults.js.map +1 -0
- package/dist/core/settings-manager.d.ts +15 -147
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +85 -57
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/settings-schema.d.ts +231 -0
- package/dist/core/settings-schema.d.ts.map +1 -0
- package/dist/core/settings-schema.js +294 -0
- package/dist/core/settings-schema.js.map +1 -0
- package/dist/core/tasks/session.d.ts +9 -0
- package/dist/core/tasks/session.d.ts.map +1 -1
- package/dist/core/tasks/session.js +21 -0
- package/dist/core/tasks/session.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts +18 -0
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js +46 -0
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/renderers/bash.d.ts.map +1 -1
- package/dist/core/tools/renderers/bash.js +21 -45
- package/dist/core/tools/renderers/bash.js.map +1 -1
- package/dist/core/tools/renderers/edit.js +1 -1
- package/dist/core/tools/renderers/edit.js.map +1 -1
- package/dist/extensions/btw/keybindings.d.ts +2 -2
- package/dist/extensions/btw/keybindings.d.ts.map +1 -1
- package/dist/extensions/btw/keybindings.js.map +1 -1
- package/dist/extensions/codemode/execute.d.ts.map +1 -1
- package/dist/extensions/codemode/execute.js +115 -40
- package/dist/extensions/codemode/execute.js.map +1 -1
- package/dist/extensions/codemode/index.d.ts.map +1 -1
- package/dist/extensions/codemode/index.js +3 -7
- package/dist/extensions/codemode/index.js.map +1 -1
- package/dist/extensions/codemode/renderer.d.ts +2 -2
- package/dist/extensions/codemode/renderer.d.ts.map +1 -1
- package/dist/extensions/codemode/renderer.js +9 -3
- package/dist/extensions/codemode/renderer.js.map +1 -1
- package/dist/extensions/codemode/tool.d.ts +6 -12
- package/dist/extensions/codemode/tool.d.ts.map +1 -1
- package/dist/extensions/codemode/tool.js +46 -34
- package/dist/extensions/codemode/tool.js.map +1 -1
- package/dist/extensions/index.js +2 -2
- package/dist/extensions/index.js.map +1 -1
- package/dist/extensions/list-keybindings.d.ts +2 -2
- package/dist/extensions/list-keybindings.d.ts.map +1 -1
- package/dist/extensions/list-keybindings.js.map +1 -1
- package/dist/extensions/llama/provider.d.ts.map +1 -1
- package/dist/extensions/llama/provider.js +34 -11
- package/dist/extensions/llama/provider.js.map +1 -1
- package/dist/extensions/mcp/cli.js +22 -31
- package/dist/extensions/mcp/cli.js.map +1 -1
- package/dist/extensions/mcp/index.d.ts.map +1 -1
- package/dist/extensions/mcp/index.js +187 -95
- package/dist/extensions/mcp/index.js.map +1 -1
- package/dist/extensions/mcp/oauth.d.ts +5 -3
- package/dist/extensions/mcp/oauth.d.ts.map +1 -1
- package/dist/extensions/mcp/oauth.js +36 -10
- package/dist/extensions/mcp/oauth.js.map +1 -1
- package/dist/extensions/mcp/resources.d.ts +0 -6
- package/dist/extensions/mcp/resources.d.ts.map +1 -1
- package/dist/extensions/mcp/resources.js +1 -1
- package/dist/extensions/mcp/resources.js.map +1 -1
- package/dist/extensions/mcp/runtime.d.ts +3 -6
- package/dist/extensions/mcp/runtime.d.ts.map +1 -1
- package/dist/extensions/mcp/runtime.js +4 -39
- package/dist/extensions/mcp/runtime.js.map +1 -1
- package/dist/extensions/mcp/tools.d.ts +2 -3
- package/dist/extensions/mcp/tools.d.ts.map +1 -1
- package/dist/extensions/mcp/tools.js +62 -6
- package/dist/extensions/mcp/tools.js.map +1 -1
- package/dist/extensions/mcp/ui.d.ts +3 -3
- package/dist/extensions/mcp/ui.d.ts.map +1 -1
- package/dist/extensions/mcp/ui.js +10 -2
- package/dist/extensions/mcp/ui.js.map +1 -1
- package/dist/extensions/provider/keybindings.d.ts +2 -2
- package/dist/extensions/provider/keybindings.d.ts.map +1 -1
- package/dist/extensions/provider/keybindings.js.map +1 -1
- package/dist/extensions/search/code-search.d.ts +27 -0
- package/dist/extensions/search/code-search.d.ts.map +1 -0
- package/dist/extensions/search/code-search.js +120 -0
- package/dist/extensions/search/code-search.js.map +1 -0
- package/dist/extensions/search/command.d.ts +5 -0
- package/dist/extensions/search/command.d.ts.map +1 -0
- package/dist/extensions/search/command.js +69 -0
- package/dist/extensions/search/command.js.map +1 -0
- package/dist/extensions/search/credential.d.ts +25 -0
- package/dist/extensions/search/credential.d.ts.map +1 -0
- package/dist/extensions/search/credential.js +117 -0
- package/dist/extensions/search/credential.js.map +1 -0
- package/dist/extensions/search/devin.d.ts +34 -0
- package/dist/extensions/search/devin.d.ts.map +1 -0
- package/dist/extensions/search/devin.js +210 -0
- package/dist/extensions/search/devin.js.map +1 -0
- package/dist/extensions/search/index.d.ts +5 -0
- package/dist/extensions/search/index.d.ts.map +1 -0
- package/dist/extensions/search/index.js +113 -0
- package/dist/extensions/search/index.js.map +1 -0
- package/dist/extensions/search/panel.d.ts +53 -0
- package/dist/extensions/search/panel.d.ts.map +1 -0
- package/dist/extensions/search/panel.js +157 -0
- package/dist/extensions/search/panel.js.map +1 -0
- package/dist/extensions/search/prompt.d.ts +14 -0
- package/dist/extensions/search/prompt.d.ts.map +1 -0
- package/dist/extensions/search/prompt.js +221 -0
- package/dist/extensions/search/prompt.js.map +1 -0
- package/dist/extensions/search/render.d.ts +28 -0
- package/dist/extensions/search/render.d.ts.map +1 -0
- package/dist/extensions/search/render.js +86 -0
- package/dist/extensions/search/render.js.map +1 -0
- package/dist/extensions/search/workspace.d.ts +39 -0
- package/dist/extensions/search/workspace.d.ts.map +1 -0
- package/dist/extensions/search/workspace.js +363 -0
- package/dist/extensions/search/workspace.js.map +1 -0
- package/dist/extensions/tool-search/index.d.ts.map +1 -1
- package/dist/extensions/tool-search/index.js +1 -6
- package/dist/extensions/tool-search/index.js.map +1 -1
- package/dist/extensions/tool-search/tool.d.ts +0 -2
- package/dist/extensions/tool-search/tool.d.ts.map +1 -1
- package/dist/extensions/tool-search/tool.js +2 -4
- 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.js +3 -3
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts +5 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +14 -14
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts +2 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +5 -2
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts +2 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +5 -2
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/custom-entry.d.ts +3 -1
- package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-entry.js +7 -2
- package/dist/modes/interactive/components/custom-entry.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +1 -0
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +4 -3
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts +2 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.js +5 -2
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/dist/modes/interactive/components/status-indicator.d.ts +1 -1
- package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
- package/dist/modes/interactive/components/status-indicator.js +2 -2
- package/dist/modes/interactive/components/status-indicator.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +2 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +63 -64
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/program-status-reporter.d.ts +34 -0
- package/dist/modes/interactive/program-status-reporter.d.ts.map +1 -0
- package/dist/modes/interactive/program-status-reporter.js +107 -0
- package/dist/modes/interactive/program-status-reporter.js.map +1 -0
- package/dist/modes/interactive/tasks/host-hooks.d.ts +14 -0
- package/dist/modes/interactive/tasks/host-hooks.d.ts.map +1 -0
- package/dist/modes/interactive/tasks/host-hooks.js +31 -0
- package/dist/modes/interactive/tasks/host-hooks.js.map +1 -0
- package/dist/modes/interactive/theme/dark.json +1 -1
- package/dist/modes/interactive/theme/light.json +1 -1
- package/dist/modes/interactive/theme/theme-schema.d.ts +28 -0
- package/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -0
- package/dist/modes/interactive/theme/theme-schema.js +105 -0
- package/dist/modes/interactive/theme/theme-schema.js.map +1 -0
- package/dist/modes/interactive/theme/theme-tokens.d.ts +257 -0
- package/dist/modes/interactive/theme/theme-tokens.d.ts.map +1 -0
- package/dist/modes/interactive/theme/theme-tokens.js +94 -0
- package/dist/modes/interactive/theme/theme-tokens.js.map +1 -0
- package/dist/modes/interactive/theme/theme.d.ts +13 -16
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +23 -31
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/interactive/tool-view/tool-execution.d.ts +5 -0
- package/dist/modes/interactive/tool-view/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/tool-view/tool-execution.js +7 -0
- package/dist/modes/interactive/tool-view/tool-execution.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +4 -0
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +24 -0
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/utils/ansi.d.ts +8 -0
- package/dist/utils/ansi.d.ts.map +1 -1
- package/dist/utils/ansi.js +30 -11
- package/dist/utils/ansi.js.map +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +18 -12
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/image-resize-core.d.ts +12 -0
- package/dist/utils/image-resize-core.d.ts.map +1 -1
- package/dist/utils/image-resize-core.js +5 -0
- package/dist/utils/image-resize-core.js.map +1 -1
- package/dist/utils/image-resize-worker.js +3 -2
- package/dist/utils/image-resize-worker.js.map +1 -1
- package/dist/utils/image-resize.d.ts.map +1 -1
- package/dist/utils/image-resize.js +9 -10
- package/dist/utils/image-resize.js.map +1 -1
- package/docs/bundled/README.md +1 -1
- package/docs/bundled/extensions/provider.md +1 -1
- package/docs/bundled/extensions/question.md +1 -1
- package/docs/bundled/extensions/search.md +51 -0
- package/docs/bundled/extensions/statusline.md +15 -41
- package/docs/codemode.md +24 -4
- package/docs/compaction.md +2 -2
- package/docs/docs.json +0 -4
- package/docs/environment-variables.md +3 -1
- package/docs/extensions.md +15 -5
- package/docs/json.md +2 -2
- package/docs/keybindings.md +1 -0
- package/docs/llama-cpp.md +8 -1
- package/docs/mcp.md +1 -1
- package/docs/models.md +5 -1
- package/docs/providers.md +33 -0
- package/docs/rpc.md +6 -3
- package/docs/session-format.md +1 -0
- package/docs/settings.md +5 -5
- package/docs/terminal-setup.md +14 -0
- package/docs/themes.md +4 -2
- package/docs/tui.md +1 -1
- package/docs/usage.md +7 -3
- 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/dynamic-resources/dynamic.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/overlay-test.ts +2 -2
- package/examples/extensions/plan-mode/index.ts +6 -2
- 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/npm-shrinkwrap.json +54 -102
- package/package.json +10 -20
- package/schemas/keybindings.schema.json +453 -0
- package/schemas/models.schema.json +1157 -0
- package/schemas/settings.schema.json +782 -0
- package/schemas/theme.schema.json +365 -0
- package/dist/bundle/chunks/anthropic-messages-YIOJIMVL.js +0 -6
- package/dist/bundle/chunks/chunk-57XI7YJH.js +0 -2
- package/dist/bundle/chunks/chunk-JI4WGISU.js +0 -2
- package/dist/bundle/chunks/chunk-TCQ4HHQD.js +0 -2
- package/dist/bundle/chunks/chunk-TXJO4AJ7.js +0 -11
- package/dist/bundle/chunks/cloudflare-workers-ai-system-one-OWU5SM6J.js +0 -2
- package/dist/bundle/chunks/mistral-conversations-A2N5FSOV.js +0 -5
- package/dist/bundle/chunks/openai-codex-responses-Q6JHCWLE.js +0 -10
- package/dist/bundle/chunks/typesafe-system-one-KYKKNU3E.js +0 -2
- package/dist/extensions/web-search/auth.d.ts +0 -12
- package/dist/extensions/web-search/auth.d.ts.map +0 -1
- package/dist/extensions/web-search/auth.js +0 -90
- package/dist/extensions/web-search/auth.js.map +0 -1
- package/dist/extensions/web-search/constants.d.ts +0 -13
- package/dist/extensions/web-search/constants.d.ts.map +0 -1
- package/dist/extensions/web-search/constants.js +0 -26
- package/dist/extensions/web-search/constants.js.map +0 -1
- package/dist/extensions/web-search/execute.d.ts +0 -9
- package/dist/extensions/web-search/execute.d.ts.map +0 -1
- package/dist/extensions/web-search/execute.js +0 -96
- package/dist/extensions/web-search/execute.js.map +0 -1
- package/dist/extensions/web-search/format.d.ts +0 -21
- package/dist/extensions/web-search/format.d.ts.map +0 -1
- package/dist/extensions/web-search/format.js +0 -117
- package/dist/extensions/web-search/format.js.map +0 -1
- package/dist/extensions/web-search/index.d.ts +0 -6
- package/dist/extensions/web-search/index.d.ts.map +0 -1
- package/dist/extensions/web-search/index.js +0 -50
- package/dist/extensions/web-search/index.js.map +0 -1
- package/dist/extensions/web-search/providers/deepseek.d.ts +0 -13
- package/dist/extensions/web-search/providers/deepseek.d.ts.map +0 -1
- package/dist/extensions/web-search/providers/deepseek.js +0 -110
- package/dist/extensions/web-search/providers/deepseek.js.map +0 -1
- package/dist/extensions/web-search/providers/http.d.ts +0 -4
- package/dist/extensions/web-search/providers/http.d.ts.map +0 -1
- package/dist/extensions/web-search/providers/http.js +0 -42
- package/dist/extensions/web-search/providers/http.js.map +0 -1
- package/dist/extensions/web-search/providers/minimax.d.ts +0 -12
- package/dist/extensions/web-search/providers/minimax.d.ts.map +0 -1
- package/dist/extensions/web-search/providers/minimax.js +0 -61
- package/dist/extensions/web-search/providers/minimax.js.map +0 -1
- package/dist/extensions/web-search/render.d.ts +0 -15
- package/dist/extensions/web-search/render.d.ts.map +0 -1
- package/dist/extensions/web-search/render.js +0 -142
- package/dist/extensions/web-search/render.js.map +0 -1
- package/dist/extensions/web-search/results.d.ts +0 -35
- package/dist/extensions/web-search/results.d.ts.map +0 -1
- package/dist/extensions/web-search/results.js +0 -167
- package/dist/extensions/web-search/results.js.map +0 -1
- package/dist/extensions/web-search/schema.d.ts +0 -10
- package/dist/extensions/web-search/schema.d.ts.map +0 -1
- package/dist/extensions/web-search/schema.js +0 -36
- package/dist/extensions/web-search/schema.js.map +0 -1
- package/dist/extensions/web-search/types.d.ts +0 -51
- package/dist/extensions/web-search/types.d.ts.map +0 -1
- package/dist/extensions/web-search/types.js +0 -5
- package/dist/extensions/web-search/types.js.map +0 -1
- package/dist/modes/interactive/theme/theme-json.d.ts +0 -85
- package/dist/modes/interactive/theme/theme-json.d.ts.map +0 -1
- package/dist/modes/interactive/theme/theme-json.js +0 -132
- package/dist/modes/interactive/theme/theme-json.js.map +0 -1
- package/dist/modes/interactive/theme/theme-schema.json +0 -361
- package/docs/bundled/extensions/web-search.md +0 -46
- package/examples/plugins/pi-example-plugin/README.md +0 -38
- package/examples/plugins/pi-example-plugin/package.json +0 -10
- package/examples/plugins/pi-example-plugin/src/contract.ts +0 -13
- package/examples/plugins/pi-example-plugin/src/session.ts +0 -24
- package/examples/plugins/pi-example-plugin/src/tui.ts +0 -31
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The local side of code_search: the planner runs remotely and names commands against a virtual
|
|
3
|
+
* `/codebase`; this module executes them read-only, confined to one directory.
|
|
4
|
+
*
|
|
5
|
+
* Security boundary: every model-supplied path must resolve inside the root, both lexically and
|
|
6
|
+
* after following symlinks, and must be a file or directory that `rg --files` lists, so ignored
|
|
7
|
+
* files are neither searched, listed, nor read. Only `rg`, `readfile`, and `tree` exist; there is
|
|
8
|
+
* no shell and no write. Model-supplied rg values only ever fill `--regexp` and `--glob`.
|
|
9
|
+
*/
|
|
10
|
+
import { spawn } from "node:child_process";
|
|
11
|
+
import { existsSync, readFileSync, realpathSync } from "node:fs";
|
|
12
|
+
import { basename, dirname, isAbsolute, relative, resolve, sep } from "node:path";
|
|
13
|
+
import { createInterface } from "node:readline";
|
|
14
|
+
import { ensureTool } from "../../utils/tools-manager.js";
|
|
15
|
+
export const VIRTUAL_ROOT = "/codebase";
|
|
16
|
+
/** Per-command result cap. Results are sent back to Devin, whose request limit is ~320KB. */
|
|
17
|
+
const RESULT_MAX_LINES = 40;
|
|
18
|
+
const LINE_MAX_CHARS = 200;
|
|
19
|
+
/** Matches read from rg before it is stopped; enough to count which files an over-broad pattern hits. */
|
|
20
|
+
const RG_MAX_MATCHES = 2000;
|
|
21
|
+
/** The repo map's share of that limit; deeper trees fall back to shallower ones until they fit. */
|
|
22
|
+
const MAP_MAX_BYTES = 64 * 1024;
|
|
23
|
+
const MAP_MAX_DEPTH = 3;
|
|
24
|
+
/**
|
|
25
|
+
* Directories skipped at any depth on top of the ignore files, for a tree that has none: `.git`,
|
|
26
|
+
* which `--hidden` would otherwise add, plus dependency installs and tool caches. Names that are
|
|
27
|
+
* sometimes source or committed code (`build`, `dist`, `vendor`, ...) are left to the ignore files.
|
|
28
|
+
*/
|
|
29
|
+
const SKIPPED_DIRS = [
|
|
30
|
+
".git",
|
|
31
|
+
"node_modules",
|
|
32
|
+
"bower_components",
|
|
33
|
+
".venv",
|
|
34
|
+
"venv",
|
|
35
|
+
"__pycache__",
|
|
36
|
+
".tox",
|
|
37
|
+
".mypy_cache",
|
|
38
|
+
".pytest_cache",
|
|
39
|
+
".ruff_cache",
|
|
40
|
+
".gradle",
|
|
41
|
+
".next",
|
|
42
|
+
".nuxt",
|
|
43
|
+
".svelte-kit",
|
|
44
|
+
".turbo",
|
|
45
|
+
".parcel-cache",
|
|
46
|
+
".cache",
|
|
47
|
+
];
|
|
48
|
+
/**
|
|
49
|
+
* What every rg call sees: hidden files, ignore files (`.gitignore`, `.ignore`, `.rgignore`) even
|
|
50
|
+
* outside a git repository, and none of `SKIPPED_DIRS`.
|
|
51
|
+
*/
|
|
52
|
+
const RG_SCOPE = ["--hidden", "--no-require-git", ...SKIPPED_DIRS.flatMap((dir) => ["--glob", `!${dir}/`])];
|
|
53
|
+
/**
|
|
54
|
+
* Run Pi's ripgrep in `root` on `target`, passing each output line to `onLine` until it returns
|
|
55
|
+
* false. Planner globs in `args` come before `RG_SCOPE`, since rg lets a later glob win. Resolves
|
|
56
|
+
* whether rg ran to the end.
|
|
57
|
+
*/
|
|
58
|
+
async function runRg(root, args, target, onLine, signal) {
|
|
59
|
+
const rg = await ensureTool("rg");
|
|
60
|
+
if (!rg)
|
|
61
|
+
throw new Error("ripgrep (rg) is not available");
|
|
62
|
+
return new Promise((resolvePromise, reject) => {
|
|
63
|
+
const child = spawn(rg, [...args, ...RG_SCOPE, "--", target], { cwd: root, stdio: ["ignore", "pipe", "pipe"] });
|
|
64
|
+
let stderr = "";
|
|
65
|
+
let lines = 0;
|
|
66
|
+
let stopped = false;
|
|
67
|
+
const stop = () => {
|
|
68
|
+
stopped = true;
|
|
69
|
+
child.kill();
|
|
70
|
+
};
|
|
71
|
+
signal?.addEventListener("abort", stop, { once: true });
|
|
72
|
+
child.stderr.on("data", (chunk) => {
|
|
73
|
+
stderr += chunk;
|
|
74
|
+
});
|
|
75
|
+
createInterface({ input: child.stdout }).on("line", (line) => {
|
|
76
|
+
if (stopped)
|
|
77
|
+
return;
|
|
78
|
+
lines++;
|
|
79
|
+
if (!onLine(line))
|
|
80
|
+
stop();
|
|
81
|
+
});
|
|
82
|
+
child.on("error", reject);
|
|
83
|
+
child.on("close", (code) => {
|
|
84
|
+
signal?.removeEventListener("abort", stop);
|
|
85
|
+
if (signal?.aborted)
|
|
86
|
+
return reject(new Error("Operation aborted"));
|
|
87
|
+
// 1 is "no matches"; 2 with output means some files were unreadable, which is not worth failing over.
|
|
88
|
+
if (!stopped && code !== 0 && code !== 1 && !lines) {
|
|
89
|
+
// A regex error spans several lines: the message, the pattern, a caret, and the cause.
|
|
90
|
+
const message = stderr.trim().split(/\r?\n/).slice(0, 6).join("\n");
|
|
91
|
+
return reject(new Error(message || `rg exited with code ${code}`));
|
|
92
|
+
}
|
|
93
|
+
resolvePromise(!stopped);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
/** An rg-reported path relative to the root, with forward slashes. */
|
|
98
|
+
function rgPath(path) {
|
|
99
|
+
return path.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
100
|
+
}
|
|
101
|
+
/** A planner glob as rg takes it: relative to the root, which is where rg runs. */
|
|
102
|
+
function rgGlob(glob) {
|
|
103
|
+
return glob.replace(/\\/g, "/").replace(new RegExp(`^${VIRTUAL_ROOT}/`), "");
|
|
104
|
+
}
|
|
105
|
+
function within(base, path) {
|
|
106
|
+
const rel = relative(base, path);
|
|
107
|
+
return rel === "" || (!rel.startsWith(`..${sep}`) && rel !== ".." && !isAbsolute(rel));
|
|
108
|
+
}
|
|
109
|
+
/** realpath of the longest existing prefix, so a not-yet-existing path still resolves through symlinks. */
|
|
110
|
+
function realpathOf(path) {
|
|
111
|
+
let current = resolve(path);
|
|
112
|
+
const tail = [];
|
|
113
|
+
while (!existsSync(current)) {
|
|
114
|
+
const parent = dirname(current);
|
|
115
|
+
if (parent === current)
|
|
116
|
+
return resolve(path);
|
|
117
|
+
tail.unshift(basename(current));
|
|
118
|
+
current = parent;
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
return resolve(realpathSync(current), ...tail);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return resolve(path);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/** Whether `path` lies inside `root`, both as written and after following symlinks. */
|
|
128
|
+
export function isInside(root, path) {
|
|
129
|
+
const abs = resolve(path);
|
|
130
|
+
return within(resolve(root), abs) && within(realpathOf(root), realpathOf(abs));
|
|
131
|
+
}
|
|
132
|
+
function strings(value) {
|
|
133
|
+
return Array.isArray(value) ? value.filter((v) => typeof v === "string" && v.length > 0) : [];
|
|
134
|
+
}
|
|
135
|
+
function clip(line) {
|
|
136
|
+
return line.length > LINE_MAX_CHARS ? line.slice(0, LINE_MAX_CHARS) : line;
|
|
137
|
+
}
|
|
138
|
+
function capLines(text) {
|
|
139
|
+
const lines = text.split("\n");
|
|
140
|
+
const kept = lines.slice(0, RESULT_MAX_LINES).map(clip);
|
|
141
|
+
if (lines.length > RESULT_MAX_LINES)
|
|
142
|
+
kept.push(`... (${lines.length - RESULT_MAX_LINES} more lines)`);
|
|
143
|
+
return kept.join("\n");
|
|
144
|
+
}
|
|
145
|
+
function virtualOf(rel) {
|
|
146
|
+
return rel ? `${VIRTUAL_ROOT}/${rel}` : VIRTUAL_ROOT;
|
|
147
|
+
}
|
|
148
|
+
export class Workspace {
|
|
149
|
+
constructor(root) {
|
|
150
|
+
this.root = resolve(root);
|
|
151
|
+
}
|
|
152
|
+
contains(path) {
|
|
153
|
+
return isInside(this.root, path);
|
|
154
|
+
}
|
|
155
|
+
/** `/codebase/src/a.ts` or `src/a.ts` → an absolute path inside the root, or null. */
|
|
156
|
+
toReal(virtual) {
|
|
157
|
+
if (typeof virtual !== "string" || !virtual)
|
|
158
|
+
return null;
|
|
159
|
+
const normalized = virtual.replace(/\\/g, "/");
|
|
160
|
+
let rel;
|
|
161
|
+
if (normalized === VIRTUAL_ROOT || normalized.startsWith(`${VIRTUAL_ROOT}/`)) {
|
|
162
|
+
rel = normalized.slice(VIRTUAL_ROOT.length);
|
|
163
|
+
}
|
|
164
|
+
else if (isAbsolute(virtual) || normalized.startsWith("/") || /^[a-zA-Z]:/.test(normalized)) {
|
|
165
|
+
// A drive-letter path is another drive on Windows and a stray filename elsewhere; refuse it everywhere.
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
rel = normalized;
|
|
170
|
+
}
|
|
171
|
+
const candidate = resolve(this.root, rel.replace(/^\/+/, ""));
|
|
172
|
+
return this.contains(candidate) ? candidate : null;
|
|
173
|
+
}
|
|
174
|
+
toVirtual(real) {
|
|
175
|
+
return virtualOf(relative(this.root, real).split(sep).join("/"));
|
|
176
|
+
}
|
|
177
|
+
/** Every file rg would search, listed once per search; tree, readfile, and rg targets all check against it. */
|
|
178
|
+
files(signal) {
|
|
179
|
+
this.index ??= (async () => {
|
|
180
|
+
const files = new Set();
|
|
181
|
+
await runRg(this.root, ["--files"], ".", (line) => {
|
|
182
|
+
files.add(rgPath(line));
|
|
183
|
+
return true;
|
|
184
|
+
}, signal);
|
|
185
|
+
const entries = new Map([["", new Set()]]);
|
|
186
|
+
for (const file of files) {
|
|
187
|
+
const parts = file.split("/");
|
|
188
|
+
for (let i = 0; i < parts.length; i++) {
|
|
189
|
+
const dir = parts.slice(0, i).join("/");
|
|
190
|
+
if (!entries.has(dir))
|
|
191
|
+
entries.set(dir, new Set());
|
|
192
|
+
entries.get(dir).add(i < parts.length - 1 ? `${parts[i]}/` : parts[i]);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return { files, dirs: new Map([...entries].map(([dir, names]) => [dir, [...names].sort()])) };
|
|
196
|
+
})();
|
|
197
|
+
return this.index;
|
|
198
|
+
}
|
|
199
|
+
/** A model-named path that rg would see, or the error string to return in its place. */
|
|
200
|
+
async find(value, signal) {
|
|
201
|
+
const real = this.toReal(value);
|
|
202
|
+
if (!real)
|
|
203
|
+
return { error: `Error: path outside project root: ${String(value)}` };
|
|
204
|
+
const rel = relative(this.root, real).split(sep).join("/");
|
|
205
|
+
const index = await this.files(signal);
|
|
206
|
+
if (index.files.has(rel))
|
|
207
|
+
return { rel, real, kind: "file" };
|
|
208
|
+
if (index.dirs.has(rel))
|
|
209
|
+
return { rel, real, kind: "dir" };
|
|
210
|
+
return {
|
|
211
|
+
error: existsSync(real)
|
|
212
|
+
? `Error: not searchable (ignored, a dependency or cache directory, or empty): ${String(value)}`
|
|
213
|
+
: `Error: path does not exist: ${String(value)}`,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
/** The deepest tree of the root, up to three levels, that fits the map budget. */
|
|
217
|
+
async repoMap(signal) {
|
|
218
|
+
const index = await this.files(signal);
|
|
219
|
+
for (let depth = MAP_MAX_DEPTH; depth > 1; depth--) {
|
|
220
|
+
const tree = renderTree(index, "", depth);
|
|
221
|
+
if (Buffer.byteLength(tree) <= MAP_MAX_BYTES)
|
|
222
|
+
return { depth, tree };
|
|
223
|
+
}
|
|
224
|
+
return { depth: 1, tree: renderTree(index, "", 1).slice(0, MAP_MAX_BYTES / 4) };
|
|
225
|
+
}
|
|
226
|
+
async run(command, signal) {
|
|
227
|
+
try {
|
|
228
|
+
switch (command?.type) {
|
|
229
|
+
case "rg":
|
|
230
|
+
return await this.rg(command, signal);
|
|
231
|
+
case "readfile":
|
|
232
|
+
return await this.readfile(command, signal);
|
|
233
|
+
case "tree":
|
|
234
|
+
return await this.tree(command, signal);
|
|
235
|
+
default:
|
|
236
|
+
return `Error: unknown command type '${String(command?.type)}'; use rg, readfile, or tree`;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
catch (e) {
|
|
240
|
+
return `Error: ${e instanceof Error ? e.message : String(e)}`;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
async rg(command, signal) {
|
|
244
|
+
if (typeof command.pattern !== "string" || !command.pattern)
|
|
245
|
+
return "Error: missing pattern";
|
|
246
|
+
// rg searches a path it is handed even when ignored, so the target must pass the same check as readfile.
|
|
247
|
+
const target = await this.find(command.path ?? VIRTUAL_ROOT, signal);
|
|
248
|
+
if ("error" in target)
|
|
249
|
+
return target.error;
|
|
250
|
+
const args = ["--null", "--line-number", "--with-filename", "--no-heading", "--color=never", "--smart-case"];
|
|
251
|
+
args.push("--max-columns", String(LINE_MAX_CHARS), "--max-columns-preview");
|
|
252
|
+
for (const glob of strings(command.include))
|
|
253
|
+
args.push("--glob", rgGlob(glob));
|
|
254
|
+
for (const glob of strings(command.exclude))
|
|
255
|
+
args.push("--glob", `!${rgGlob(glob).replace(/^!+/, "")}`);
|
|
256
|
+
args.push("--regexp", command.pattern);
|
|
257
|
+
const matches = [];
|
|
258
|
+
const complete = await runRg(this.root, args, target.rel || ".", (line) => {
|
|
259
|
+
const nul = line.indexOf("\0");
|
|
260
|
+
const m = line.slice(nul + 1).match(/^(\d+):(.*)$/);
|
|
261
|
+
if (nul >= 0 && m) {
|
|
262
|
+
matches.push({ path: rgPath(line.slice(0, nul)), line: Number(m[1]), text: m[2].replace(/\r$/, "") });
|
|
263
|
+
}
|
|
264
|
+
return matches.length < RG_MAX_MATCHES;
|
|
265
|
+
}, signal);
|
|
266
|
+
if (!matches.length)
|
|
267
|
+
return "(no matches)";
|
|
268
|
+
matches.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : a.line - b.line));
|
|
269
|
+
const lines = matches.map((m) => `${VIRTUAL_ROOT}/${m.path}:${m.line}:${m.text}`);
|
|
270
|
+
if (lines.length <= RESULT_MAX_LINES)
|
|
271
|
+
return capLines(lines.join("\n"));
|
|
272
|
+
return capLines([...matchSummary(matches, complete), ...lines].join("\n"));
|
|
273
|
+
}
|
|
274
|
+
/** A numbered slice of a text file, headed by its length and ending with where to continue. */
|
|
275
|
+
async readfile(command, signal) {
|
|
276
|
+
const file = await this.find(command.file, signal);
|
|
277
|
+
if ("error" in file)
|
|
278
|
+
return file.error;
|
|
279
|
+
if (file.kind !== "file")
|
|
280
|
+
return `Error: not a file: ${String(command.file)}`;
|
|
281
|
+
const name = virtualOf(file.rel);
|
|
282
|
+
const buffer = readFileSync(file.real);
|
|
283
|
+
if (buffer.subarray(0, 8192).includes(0))
|
|
284
|
+
return `Error: binary file: ${name}`;
|
|
285
|
+
const lines = buffer.toString("utf-8").split(/\r?\n/);
|
|
286
|
+
if (lines.at(-1) === "")
|
|
287
|
+
lines.pop();
|
|
288
|
+
const total = lines.length;
|
|
289
|
+
if (!total)
|
|
290
|
+
return `${name} (empty)`;
|
|
291
|
+
const start = Math.max(1, Number(command.start_line) || 1);
|
|
292
|
+
const end = Math.min(total, Number(command.end_line) || total);
|
|
293
|
+
if (start > total)
|
|
294
|
+
return `Error: start_line ${start} is past the end of ${name} (${total} lines)`;
|
|
295
|
+
if (end < start)
|
|
296
|
+
return `Error: end_line ${end} is before start_line ${start}`;
|
|
297
|
+
const last = Math.min(end, start + RESULT_MAX_LINES - 1);
|
|
298
|
+
const out = [`${name} (${total} lines)`];
|
|
299
|
+
for (let n = start; n <= last; n++)
|
|
300
|
+
out.push(clip(`${n}:${lines[n - 1]}`));
|
|
301
|
+
if (last < end)
|
|
302
|
+
out.push(`... (lines ${last + 1}-${end} not shown; continue with start_line=${last + 1})`);
|
|
303
|
+
return out.join("\n");
|
|
304
|
+
}
|
|
305
|
+
/** The requested depth of a directory, or the deepest one that fits the result cap. */
|
|
306
|
+
async tree(command, signal) {
|
|
307
|
+
const dir = await this.find(command.path ?? VIRTUAL_ROOT, signal);
|
|
308
|
+
if ("error" in dir)
|
|
309
|
+
return dir.error;
|
|
310
|
+
if (dir.kind !== "dir")
|
|
311
|
+
return `Error: not a directory: ${String(command.path)}`;
|
|
312
|
+
const index = await this.files(signal);
|
|
313
|
+
const levels = Math.min(Math.max(Number(command.levels) || 2, 1), 4);
|
|
314
|
+
let depth = levels;
|
|
315
|
+
let tree = renderTree(index, dir.rel, depth);
|
|
316
|
+
while (depth > 1 && tree.split("\n").length > RESULT_MAX_LINES)
|
|
317
|
+
tree = renderTree(index, dir.rel, --depth);
|
|
318
|
+
return depth < levels ? `${capLines(tree)}\n(levels reduced to ${depth} to fit)` : capLines(tree);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* What an over-broad pattern hit, per file, ahead of the first matches; rg's arbitrary first 40
|
|
323
|
+
* lines would say nothing about where to narrow next.
|
|
324
|
+
*/
|
|
325
|
+
function matchSummary(matches, complete) {
|
|
326
|
+
const counts = new Map();
|
|
327
|
+
for (const m of matches)
|
|
328
|
+
counts.set(m.path, (counts.get(m.path) ?? 0) + 1);
|
|
329
|
+
const total = complete ? `${matches.length} matches` : `More than ${RG_MAX_MATCHES} matches`;
|
|
330
|
+
const files = complete ? `${counts.size} files` : `at least ${counts.size} files`;
|
|
331
|
+
// Densest files first: they are where a narrower search most likely belongs.
|
|
332
|
+
const rows = [...counts]
|
|
333
|
+
.sort((a, b) => b[1] - a[1])
|
|
334
|
+
.slice(0, RESULT_MAX_LINES / 2)
|
|
335
|
+
.map(([path, n]) => `${VIRTUAL_ROOT}/${path}: ${n}`);
|
|
336
|
+
if (counts.size > rows.length)
|
|
337
|
+
rows.push(`... (${counts.size - rows.length} more files)`);
|
|
338
|
+
return [
|
|
339
|
+
`${total} in ${files}; narrow with path, include, exclude, or a more specific pattern. Matches per file:`,
|
|
340
|
+
...rows,
|
|
341
|
+
"First matches:",
|
|
342
|
+
];
|
|
343
|
+
}
|
|
344
|
+
/** `dir` and its entries to `maxDepth` levels; a trailing slash marks a directory. */
|
|
345
|
+
function renderTree(index, dir, maxDepth) {
|
|
346
|
+
const lines = [virtualOf(dir)];
|
|
347
|
+
const walk = (current, depth, prefix) => {
|
|
348
|
+
if (depth >= maxDepth)
|
|
349
|
+
return;
|
|
350
|
+
const entries = index.dirs.get(current) ?? [];
|
|
351
|
+
entries.forEach((name, i) => {
|
|
352
|
+
const last = i === entries.length - 1;
|
|
353
|
+
lines.push(`${prefix}${last ? "└── " : "├── "}${name}`);
|
|
354
|
+
if (name.endsWith("/")) {
|
|
355
|
+
const child = current ? `${current}/${name.slice(0, -1)}` : name.slice(0, -1);
|
|
356
|
+
walk(child, depth + 1, `${prefix}${last ? " " : "│ "}`);
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
};
|
|
360
|
+
walk(dir, 0, "");
|
|
361
|
+
return lines.join("\n");
|
|
362
|
+
}
|
|
363
|
+
//# sourceMappingURL=workspace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../../src/extensions/search/workspace.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The local side of code_search: the planner runs remotely and names commands against a virtual\n * `/codebase`; this module executes them read-only, confined to one directory.\n *\n * Security boundary: every model-supplied path must resolve inside the root, both lexically and\n * after following symlinks, and must be a file or directory that `rg --files` lists, so ignored\n * files are neither searched, listed, nor read. Only `rg`, `readfile`, and `tree` exist; there is\n * no shell and no write. Model-supplied rg values only ever fill `--regexp` and `--glob`.\n */\nimport { spawn } from \"node:child_process\";\nimport { existsSync, readFileSync, realpathSync } from \"node:fs\";\nimport { basename, dirname, isAbsolute, relative, resolve, sep } from \"node:path\";\nimport { createInterface } from \"node:readline\";\nimport { ensureTool } from \"../../utils/tools-manager.ts\";\n\nexport const VIRTUAL_ROOT = \"/codebase\";\n\n/** Per-command result cap. Results are sent back to Devin, whose request limit is ~320KB. */\nconst RESULT_MAX_LINES = 40;\nconst LINE_MAX_CHARS = 200;\n/** Matches read from rg before it is stopped; enough to count which files an over-broad pattern hits. */\nconst RG_MAX_MATCHES = 2000;\n/** The repo map's share of that limit; deeper trees fall back to shallower ones until they fit. */\nconst MAP_MAX_BYTES = 64 * 1024;\nconst MAP_MAX_DEPTH = 3;\n\n/**\n * Directories skipped at any depth on top of the ignore files, for a tree that has none: `.git`,\n * which `--hidden` would otherwise add, plus dependency installs and tool caches. Names that are\n * sometimes source or committed code (`build`, `dist`, `vendor`, ...) are left to the ignore files.\n */\nconst SKIPPED_DIRS = [\n\t\".git\",\n\t\"node_modules\",\n\t\"bower_components\",\n\t\".venv\",\n\t\"venv\",\n\t\"__pycache__\",\n\t\".tox\",\n\t\".mypy_cache\",\n\t\".pytest_cache\",\n\t\".ruff_cache\",\n\t\".gradle\",\n\t\".next\",\n\t\".nuxt\",\n\t\".svelte-kit\",\n\t\".turbo\",\n\t\".parcel-cache\",\n\t\".cache\",\n];\n\n/**\n * What every rg call sees: hidden files, ignore files (`.gitignore`, `.ignore`, `.rgignore`) even\n * outside a git repository, and none of `SKIPPED_DIRS`.\n */\nconst RG_SCOPE = [\"--hidden\", \"--no-require-git\", ...SKIPPED_DIRS.flatMap((dir) => [\"--glob\", `!${dir}/`])];\n\ninterface Match {\n\t/** Relative to the root, with forward slashes. */\n\tpath: string;\n\tline: number;\n\ttext: string;\n}\n\n/** The files rg would search, and the directories that hold them. */\ninterface Index {\n\t/** Relative to the root, with forward slashes. */\n\tfiles: Set<string>;\n\t/** Directory (\"\" for the root) → its sorted entries, subdirectories with a trailing slash. */\n\tdirs: Map<string, string[]>;\n}\n\n/**\n * Run Pi's ripgrep in `root` on `target`, passing each output line to `onLine` until it returns\n * false. Planner globs in `args` come before `RG_SCOPE`, since rg lets a later glob win. Resolves\n * whether rg ran to the end.\n */\nasync function runRg(\n\troot: string,\n\targs: string[],\n\ttarget: string,\n\tonLine: (line: string) => boolean,\n\tsignal?: AbortSignal,\n): Promise<boolean> {\n\tconst rg = await ensureTool(\"rg\");\n\tif (!rg) throw new Error(\"ripgrep (rg) is not available\");\n\treturn new Promise((resolvePromise, reject) => {\n\t\tconst child = spawn(rg, [...args, ...RG_SCOPE, \"--\", target], { cwd: root, stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n\t\tlet stderr = \"\";\n\t\tlet lines = 0;\n\t\tlet stopped = false;\n\t\tconst stop = () => {\n\t\t\tstopped = true;\n\t\t\tchild.kill();\n\t\t};\n\t\tsignal?.addEventListener(\"abort\", stop, { once: true });\n\t\tchild.stderr.on(\"data\", (chunk) => {\n\t\t\tstderr += chunk;\n\t\t});\n\t\tcreateInterface({ input: child.stdout }).on(\"line\", (line) => {\n\t\t\tif (stopped) return;\n\t\t\tlines++;\n\t\t\tif (!onLine(line)) stop();\n\t\t});\n\t\tchild.on(\"error\", reject);\n\t\tchild.on(\"close\", (code) => {\n\t\t\tsignal?.removeEventListener(\"abort\", stop);\n\t\t\tif (signal?.aborted) return reject(new Error(\"Operation aborted\"));\n\t\t\t// 1 is \"no matches\"; 2 with output means some files were unreadable, which is not worth failing over.\n\t\t\tif (!stopped && code !== 0 && code !== 1 && !lines) {\n\t\t\t\t// A regex error spans several lines: the message, the pattern, a caret, and the cause.\n\t\t\t\tconst message = stderr.trim().split(/\\r?\\n/).slice(0, 6).join(\"\\n\");\n\t\t\t\treturn reject(new Error(message || `rg exited with code ${code}`));\n\t\t\t}\n\t\t\tresolvePromise(!stopped);\n\t\t});\n\t});\n}\n\n/** An rg-reported path relative to the root, with forward slashes. */\nfunction rgPath(path: string): string {\n\treturn path.replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\");\n}\n\n/** A planner glob as rg takes it: relative to the root, which is where rg runs. */\nfunction rgGlob(glob: string): string {\n\treturn glob.replace(/\\\\/g, \"/\").replace(new RegExp(`^${VIRTUAL_ROOT}/`), \"\");\n}\n\nfunction within(base: string, path: string): boolean {\n\tconst rel = relative(base, path);\n\treturn rel === \"\" || (!rel.startsWith(`..${sep}`) && rel !== \"..\" && !isAbsolute(rel));\n}\n\n/** realpath of the longest existing prefix, so a not-yet-existing path still resolves through symlinks. */\nfunction realpathOf(path: string): string {\n\tlet current = resolve(path);\n\tconst tail: string[] = [];\n\twhile (!existsSync(current)) {\n\t\tconst parent = dirname(current);\n\t\tif (parent === current) return resolve(path);\n\t\ttail.unshift(basename(current));\n\t\tcurrent = parent;\n\t}\n\ttry {\n\t\treturn resolve(realpathSync(current), ...tail);\n\t} catch {\n\t\treturn resolve(path);\n\t}\n}\n\n/** Whether `path` lies inside `root`, both as written and after following symlinks. */\nexport function isInside(root: string, path: string): boolean {\n\tconst abs = resolve(path);\n\treturn within(resolve(root), abs) && within(realpathOf(root), realpathOf(abs));\n}\n\nfunction strings(value: unknown): string[] {\n\treturn Array.isArray(value) ? value.filter((v): v is string => typeof v === \"string\" && v.length > 0) : [];\n}\n\nfunction clip(line: string): string {\n\treturn line.length > LINE_MAX_CHARS ? line.slice(0, LINE_MAX_CHARS) : line;\n}\n\nfunction capLines(text: string): string {\n\tconst lines = text.split(\"\\n\");\n\tconst kept = lines.slice(0, RESULT_MAX_LINES).map(clip);\n\tif (lines.length > RESULT_MAX_LINES) kept.push(`... (${lines.length - RESULT_MAX_LINES} more lines)`);\n\treturn kept.join(\"\\n\");\n}\n\nfunction virtualOf(rel: string): string {\n\treturn rel ? `${VIRTUAL_ROOT}/${rel}` : VIRTUAL_ROOT;\n}\n\nexport interface Command {\n\ttype?: unknown;\n\tpattern?: unknown;\n\tpath?: unknown;\n\tinclude?: unknown;\n\texclude?: unknown;\n\tfile?: unknown;\n\tstart_line?: unknown;\n\tend_line?: unknown;\n\tlevels?: unknown;\n}\n\nexport class Workspace {\n\treadonly root: string;\n\tprivate index?: Promise<Index>;\n\n\tconstructor(root: string) {\n\t\tthis.root = resolve(root);\n\t}\n\n\tcontains(path: string): boolean {\n\t\treturn isInside(this.root, path);\n\t}\n\n\t/** `/codebase/src/a.ts` or `src/a.ts` → an absolute path inside the root, or null. */\n\ttoReal(virtual: unknown): string | null {\n\t\tif (typeof virtual !== \"string\" || !virtual) return null;\n\t\tconst normalized = virtual.replace(/\\\\/g, \"/\");\n\t\tlet rel: string;\n\t\tif (normalized === VIRTUAL_ROOT || normalized.startsWith(`${VIRTUAL_ROOT}/`)) {\n\t\t\trel = normalized.slice(VIRTUAL_ROOT.length);\n\t\t} else if (isAbsolute(virtual) || normalized.startsWith(\"/\") || /^[a-zA-Z]:/.test(normalized)) {\n\t\t\t// A drive-letter path is another drive on Windows and a stray filename elsewhere; refuse it everywhere.\n\t\t\treturn null;\n\t\t} else {\n\t\t\trel = normalized;\n\t\t}\n\t\tconst candidate = resolve(this.root, rel.replace(/^\\/+/, \"\"));\n\t\treturn this.contains(candidate) ? candidate : null;\n\t}\n\n\ttoVirtual(real: string): string {\n\t\treturn virtualOf(relative(this.root, real).split(sep).join(\"/\"));\n\t}\n\n\t/** Every file rg would search, listed once per search; tree, readfile, and rg targets all check against it. */\n\tprivate files(signal?: AbortSignal): Promise<Index> {\n\t\tthis.index ??= (async () => {\n\t\t\tconst files = new Set<string>();\n\t\t\tawait runRg(\n\t\t\t\tthis.root,\n\t\t\t\t[\"--files\"],\n\t\t\t\t\".\",\n\t\t\t\t(line) => {\n\t\t\t\t\tfiles.add(rgPath(line));\n\t\t\t\t\treturn true;\n\t\t\t\t},\n\t\t\t\tsignal,\n\t\t\t);\n\t\t\tconst entries = new Map<string, Set<string>>([[\"\", new Set()]]);\n\t\t\tfor (const file of files) {\n\t\t\t\tconst parts = file.split(\"/\");\n\t\t\t\tfor (let i = 0; i < parts.length; i++) {\n\t\t\t\t\tconst dir = parts.slice(0, i).join(\"/\");\n\t\t\t\t\tif (!entries.has(dir)) entries.set(dir, new Set());\n\t\t\t\t\tentries.get(dir)!.add(i < parts.length - 1 ? `${parts[i]}/` : parts[i]!);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { files, dirs: new Map([...entries].map(([dir, names]) => [dir, [...names].sort()])) };\n\t\t})();\n\t\treturn this.index;\n\t}\n\n\t/** A model-named path that rg would see, or the error string to return in its place. */\n\tprivate async find(\n\t\tvalue: unknown,\n\t\tsignal?: AbortSignal,\n\t): Promise<{ rel: string; real: string; kind: \"file\" | \"dir\" } | { error: string }> {\n\t\tconst real = this.toReal(value);\n\t\tif (!real) return { error: `Error: path outside project root: ${String(value)}` };\n\t\tconst rel = relative(this.root, real).split(sep).join(\"/\");\n\t\tconst index = await this.files(signal);\n\t\tif (index.files.has(rel)) return { rel, real, kind: \"file\" };\n\t\tif (index.dirs.has(rel)) return { rel, real, kind: \"dir\" };\n\t\treturn {\n\t\t\terror: existsSync(real)\n\t\t\t\t? `Error: not searchable (ignored, a dependency or cache directory, or empty): ${String(value)}`\n\t\t\t\t: `Error: path does not exist: ${String(value)}`,\n\t\t};\n\t}\n\n\t/** The deepest tree of the root, up to three levels, that fits the map budget. */\n\tasync repoMap(signal?: AbortSignal): Promise<{ depth: number; tree: string }> {\n\t\tconst index = await this.files(signal);\n\t\tfor (let depth = MAP_MAX_DEPTH; depth > 1; depth--) {\n\t\t\tconst tree = renderTree(index, \"\", depth);\n\t\t\tif (Buffer.byteLength(tree) <= MAP_MAX_BYTES) return { depth, tree };\n\t\t}\n\t\treturn { depth: 1, tree: renderTree(index, \"\", 1).slice(0, MAP_MAX_BYTES / 4) };\n\t}\n\n\tasync run(command: Command, signal?: AbortSignal): Promise<string> {\n\t\ttry {\n\t\t\tswitch (command?.type) {\n\t\t\t\tcase \"rg\":\n\t\t\t\t\treturn await this.rg(command, signal);\n\t\t\t\tcase \"readfile\":\n\t\t\t\t\treturn await this.readfile(command, signal);\n\t\t\t\tcase \"tree\":\n\t\t\t\t\treturn await this.tree(command, signal);\n\t\t\t\tdefault:\n\t\t\t\t\treturn `Error: unknown command type '${String(command?.type)}'; use rg, readfile, or tree`;\n\t\t\t}\n\t\t} catch (e) {\n\t\t\treturn `Error: ${e instanceof Error ? e.message : String(e)}`;\n\t\t}\n\t}\n\n\tprivate async rg(command: Command, signal?: AbortSignal): Promise<string> {\n\t\tif (typeof command.pattern !== \"string\" || !command.pattern) return \"Error: missing pattern\";\n\t\t// rg searches a path it is handed even when ignored, so the target must pass the same check as readfile.\n\t\tconst target = await this.find(command.path ?? VIRTUAL_ROOT, signal);\n\t\tif (\"error\" in target) return target.error;\n\t\tconst args = [\"--null\", \"--line-number\", \"--with-filename\", \"--no-heading\", \"--color=never\", \"--smart-case\"];\n\t\targs.push(\"--max-columns\", String(LINE_MAX_CHARS), \"--max-columns-preview\");\n\t\tfor (const glob of strings(command.include)) args.push(\"--glob\", rgGlob(glob));\n\t\tfor (const glob of strings(command.exclude)) args.push(\"--glob\", `!${rgGlob(glob).replace(/^!+/, \"\")}`);\n\t\targs.push(\"--regexp\", command.pattern);\n\n\t\tconst matches: Match[] = [];\n\t\tconst complete = await runRg(\n\t\t\tthis.root,\n\t\t\targs,\n\t\t\ttarget.rel || \".\",\n\t\t\t(line) => {\n\t\t\t\tconst nul = line.indexOf(\"\\0\");\n\t\t\t\tconst m = line.slice(nul + 1).match(/^(\\d+):(.*)$/);\n\t\t\t\tif (nul >= 0 && m) {\n\t\t\t\t\tmatches.push({ path: rgPath(line.slice(0, nul)), line: Number(m[1]), text: m[2]!.replace(/\\r$/, \"\") });\n\t\t\t\t}\n\t\t\t\treturn matches.length < RG_MAX_MATCHES;\n\t\t\t},\n\t\t\tsignal,\n\t\t);\n\t\tif (!matches.length) return \"(no matches)\";\n\t\tmatches.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : a.line - b.line));\n\t\tconst lines = matches.map((m) => `${VIRTUAL_ROOT}/${m.path}:${m.line}:${m.text}`);\n\t\tif (lines.length <= RESULT_MAX_LINES) return capLines(lines.join(\"\\n\"));\n\t\treturn capLines([...matchSummary(matches, complete), ...lines].join(\"\\n\"));\n\t}\n\n\t/** A numbered slice of a text file, headed by its length and ending with where to continue. */\n\tprivate async readfile(command: Command, signal?: AbortSignal): Promise<string> {\n\t\tconst file = await this.find(command.file, signal);\n\t\tif (\"error\" in file) return file.error;\n\t\tif (file.kind !== \"file\") return `Error: not a file: ${String(command.file)}`;\n\t\tconst name = virtualOf(file.rel);\n\t\tconst buffer = readFileSync(file.real);\n\t\tif (buffer.subarray(0, 8192).includes(0)) return `Error: binary file: ${name}`;\n\t\tconst lines = buffer.toString(\"utf-8\").split(/\\r?\\n/);\n\t\tif (lines.at(-1) === \"\") lines.pop();\n\t\tconst total = lines.length;\n\t\tif (!total) return `${name} (empty)`;\n\n\t\tconst start = Math.max(1, Number(command.start_line) || 1);\n\t\tconst end = Math.min(total, Number(command.end_line) || total);\n\t\tif (start > total) return `Error: start_line ${start} is past the end of ${name} (${total} lines)`;\n\t\tif (end < start) return `Error: end_line ${end} is before start_line ${start}`;\n\t\tconst last = Math.min(end, start + RESULT_MAX_LINES - 1);\n\t\tconst out = [`${name} (${total} lines)`];\n\t\tfor (let n = start; n <= last; n++) out.push(clip(`${n}:${lines[n - 1]}`));\n\t\tif (last < end) out.push(`... (lines ${last + 1}-${end} not shown; continue with start_line=${last + 1})`);\n\t\treturn out.join(\"\\n\");\n\t}\n\n\t/** The requested depth of a directory, or the deepest one that fits the result cap. */\n\tprivate async tree(command: Command, signal?: AbortSignal): Promise<string> {\n\t\tconst dir = await this.find(command.path ?? VIRTUAL_ROOT, signal);\n\t\tif (\"error\" in dir) return dir.error;\n\t\tif (dir.kind !== \"dir\") return `Error: not a directory: ${String(command.path)}`;\n\t\tconst index = await this.files(signal);\n\t\tconst levels = Math.min(Math.max(Number(command.levels) || 2, 1), 4);\n\t\tlet depth = levels;\n\t\tlet tree = renderTree(index, dir.rel, depth);\n\t\twhile (depth > 1 && tree.split(\"\\n\").length > RESULT_MAX_LINES) tree = renderTree(index, dir.rel, --depth);\n\t\treturn depth < levels ? `${capLines(tree)}\\n(levels reduced to ${depth} to fit)` : capLines(tree);\n\t}\n}\n\n/**\n * What an over-broad pattern hit, per file, ahead of the first matches; rg's arbitrary first 40\n * lines would say nothing about where to narrow next.\n */\nfunction matchSummary(matches: Match[], complete: boolean): string[] {\n\tconst counts = new Map<string, number>();\n\tfor (const m of matches) counts.set(m.path, (counts.get(m.path) ?? 0) + 1);\n\tconst total = complete ? `${matches.length} matches` : `More than ${RG_MAX_MATCHES} matches`;\n\tconst files = complete ? `${counts.size} files` : `at least ${counts.size} files`;\n\t// Densest files first: they are where a narrower search most likely belongs.\n\tconst rows = [...counts]\n\t\t.sort((a, b) => b[1] - a[1])\n\t\t.slice(0, RESULT_MAX_LINES / 2)\n\t\t.map(([path, n]) => `${VIRTUAL_ROOT}/${path}: ${n}`);\n\tif (counts.size > rows.length) rows.push(`... (${counts.size - rows.length} more files)`);\n\treturn [\n\t\t`${total} in ${files}; narrow with path, include, exclude, or a more specific pattern. Matches per file:`,\n\t\t...rows,\n\t\t\"First matches:\",\n\t];\n}\n\n/** `dir` and its entries to `maxDepth` levels; a trailing slash marks a directory. */\nfunction renderTree(index: Index, dir: string, maxDepth: number): string {\n\tconst lines = [virtualOf(dir)];\n\tconst walk = (current: string, depth: number, prefix: string): void => {\n\t\tif (depth >= maxDepth) return;\n\t\tconst entries = index.dirs.get(current) ?? [];\n\t\tentries.forEach((name, i) => {\n\t\t\tconst last = i === entries.length - 1;\n\t\t\tlines.push(`${prefix}${last ? \"└── \" : \"├── \"}${name}`);\n\t\t\tif (name.endsWith(\"/\")) {\n\t\t\t\tconst child = current ? `${current}/${name.slice(0, -1)}` : name.slice(0, -1);\n\t\t\t\twalk(child, depth + 1, `${prefix}${last ? \" \" : \"│ \"}`);\n\t\t\t}\n\t\t});\n\t};\n\twalk(dir, 0, \"\");\n\treturn lines.join(\"\\n\");\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/extensions/tool-search/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAGvE,wBAAgB,yBAAyB,IAAI,gBAAgB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/extensions/tool-search/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAGvE,wBAAgB,yBAAyB,IAAI,gBAAgB,CAI5D;;AAED,wBAA2C"}
|
|
@@ -5,14 +5,9 @@
|
|
|
5
5
|
* `tool_search` is registered inactive. Activate it with `--tools`, the `defaultTools` setting, or
|
|
6
6
|
* `setActiveTools()`.
|
|
7
7
|
*/
|
|
8
|
-
import { createToolSearchToolDefinition
|
|
8
|
+
import { createToolSearchToolDefinition } from "./tool.js";
|
|
9
9
|
export function createToolSearchExtension() {
|
|
10
10
|
return (pi) => {
|
|
11
|
-
pi.events.on("pi:discover-tool-orchestrators", (candidates) => {
|
|
12
|
-
if (candidates instanceof Map && candidates.get(TOOL_SEARCH_TOOL_NAME) === toolSearchSchema) {
|
|
13
|
-
candidates.set(TOOL_SEARCH_TOOL_NAME, true);
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
11
|
pi.registerTool({ ...createToolSearchToolDefinition({ tools: pi }), defaultActive: false });
|
|
17
12
|
};
|
|
18
13
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/extensions/tool-search/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,8BAA8B,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/extensions/tool-search/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,8BAA8B,EAAE,MAAM,WAAW,CAAC;AAE3D,MAAM,UAAU,yBAAyB;IACxC,OAAO,CAAC,EAAE,EAAE,EAAE;QACb,EAAE,CAAC,YAAY,CAAC,EAAE,GAAG,8BAA8B,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC,CAAC;IAC7F,CAAC,CAAC;AACH,CAAC;AAED,eAAe,yBAAyB,EAAE,CAAC","sourcesContent":["/**\n * The `tool_search` tool as an extension. The CLI loads it as a built-in extension; SDK users add\n * `createToolSearchExtension()` to their extension factories.\n *\n * `tool_search` is registered inactive. Activate it with `--tools`, the `defaultTools` setting, or\n * `setActiveTools()`.\n */\n\nimport type { ExtensionFactory } from \"../../core/extensions/types.ts\";\nimport { createToolSearchToolDefinition } from \"./tool.ts\";\n\nexport function createToolSearchExtension(): ExtensionFactory {\n\treturn (pi) => {\n\t\tpi.registerTool({ ...createToolSearchToolDefinition({ tools: pi }), defaultActive: false });\n\t};\n}\n\nexport default createToolSearchExtension();\n"]}
|
|
@@ -47,8 +47,6 @@ export declare const toolSearchSchema: Type.TObject<{
|
|
|
47
47
|
limit: Type.TOptional<Type.TNumber>;
|
|
48
48
|
}>;
|
|
49
49
|
export type ToolSearchInput = Static<typeof toolSearchSchema>;
|
|
50
|
-
/** Whether the tool is this `tool_search`, not another extension's tool of the same name. */
|
|
51
|
-
export declare function isToolSearchTool(tool: Pick<ToolInfo, "name" | "parameters">): boolean;
|
|
52
50
|
export interface ToolSearchResultTool {
|
|
53
51
|
name: string;
|
|
54
52
|
description: string;
|
|
@@ -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;;;;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;gBAEf,OAAO,GAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAA;KAAO;IAKrD,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,kBAAkB,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,EAAE;CA6B/F;AAED,eAAO,MAAM,gBAAgB;;;EAK3B,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE9D,
|
|
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;gBAEf,OAAO,GAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAA;KAAO;IAKrD,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,kBAAkB,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,EAAE;CA6B/F;AAED,eAAO,MAAM,gBAAgB;;;EAK3B,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE9D,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,CAyBhE"}
|
|
@@ -130,10 +130,6 @@ export const toolSearchSchema = Type.Object({
|
|
|
130
130
|
query: Type.String({ description: "Search query for deferred tools." }),
|
|
131
131
|
limit: Type.Optional(Type.Number({ description: `Maximum number of tools to return. Defaults to ${DEFAULT_TOOL_SEARCH_LIMIT}.` })),
|
|
132
132
|
});
|
|
133
|
-
/** Whether the tool is this `tool_search`, not another extension's tool of the same name. */
|
|
134
|
-
export function isToolSearchTool(tool) {
|
|
135
|
-
return tool.name === TOOL_SEARCH_TOOL_NAME && tool.parameters === toolSearchSchema;
|
|
136
|
-
}
|
|
137
133
|
/** Whether `tool_search` can load a tool with this exposure. */
|
|
138
134
|
function isSearchable(exposure) {
|
|
139
135
|
return exposure === "codemode" || exposure === "deferred";
|
|
@@ -168,6 +164,8 @@ export function createToolSearchToolDefinition(options = {}) {
|
|
|
168
164
|
parameters: toolSearchSchema,
|
|
169
165
|
// Searching is not something scripts need; it changes what the model sees.
|
|
170
166
|
exposure: "model-only",
|
|
167
|
+
// A query can match any tool that is not declared yet.
|
|
168
|
+
reachesTools: () => "all",
|
|
171
169
|
async execute(_toolCallId, { query, limit }) {
|
|
172
170
|
if (query.trim() === "")
|
|
173
171
|
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":"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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"]}
|
|
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\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\t// A query can match any tool that is not declared yet.\n\t\treachesTools: () => \"all\",\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
|
@@ -5,7 +5,7 @@ export { readStoredCredential } from "./core/auth-storage.ts";
|
|
|
5
5
|
export type { CacheWarmingDecision, CacheWarmingStatus } from "./core/cache-warmer.ts";
|
|
6
6
|
export { type BranchPreparation, type BranchSummaryResult, type CollectEntriesResult, type CompactionResult, type CutPointResult, calculateContextTokens, collectEntriesForBranchSummary, compact, DEFAULT_COMPACTION_SETTINGS, estimateTokens, type FileOperations, findCutPoint, findTurnStartIndex, type GenerateBranchSummaryOptions, generateBranchSummary, generateSummary, generateSummaryWithUsage, getLastAssistantUsage, prepareBranchEntries, serializeConversation, shouldCompact, } from "./core/compaction/index.ts";
|
|
7
7
|
export { createEventBus, type EventBus, type EventBusController } from "./core/event-bus.ts";
|
|
8
|
-
export type { AfterProviderResponseEvent, AgentActivityOutcome, AgentBeforeSettleEvent, AgentBeforeSettleEventResult, AgentEndEvent, AgentSettledEvent, AgentStartEvent, AgentToolResult, AgentToolUpdateCallback, AppKeybinding, AutocompleteProviderFactory, BashToolCallEvent, BeforeAgentStartEvent, BeforeAgentStartEventResult, BeforeProviderHeadersEvent, BeforeProviderRequestEvent, BeforeProviderRequestEventResult, BoundaryContextPreview, BoundaryResult, BoundaryState, BuildSystemPromptOptions, CacheWarmingDecisionEvent, CacheWarmingDecisionEventResult, CompactionEntryDraft, CompactOptions, ContextEditEntryDraft, ContextEvent, ContextEventResult, ContextSnapshot, ContextUsage, ContextWithSystemEvent, CustomEntryDraft, CustomMessageEntryDraft, CustomToolCallEvent, EditorHost, EditorSubmitEvent, EditorSubmitHandler, EditToolCallEvent, EntryRenderer, EntryRenderOptions, ExecOptions, ExecResult, ExecuteToolOptions, Extension, ExtensionActions, ExtensionAPI, ExtensionCommandContext, ExtensionCommandContextActions, ExtensionContext, ExtensionContextActions, ExtensionError, ExtensionEvent, ExtensionFactory, ExtensionFlag, ExtensionHandler, ExtensionRuntime, ExtensionShortcut, ExtensionToolContext, ExtensionUIContext, ExtensionUIDialogOptions, ExtensionVirtualModel, ExtensionWidgetOptions, FindToolCallEvent, GrepToolCallEvent, InlineExtension, InputEvent, InputEventResult, InputSource, KeybindingsManager, LoadExtensionsResult, LsToolCallEvent, MarkdownTransformContext, MarkdownTransformer, McpServersChangeEvent, MessageEndEvent, MessageEndEventResult, MessageRenderer, MessageRenderOptions, MessageStartEvent, MessageUpdateEvent, ModelSelectEvent, ModelSelectSource, NormalizedBuildSystemPromptOptions, PowerShellToolCallEvent, ProjectTrustContext, ProjectTrustEvent, ProjectTrustEventDecision, ProjectTrustEventResult, ProjectTrustHandler, ProviderConfig, ProviderModelConfig, ProviderStreamEvent, ReadToolCallEvent, RegisteredCommand, RegisteredTool, ResolvedCommand, ResourcesDiscoverEvent, ResourcesDiscoverResult, SessionBeforeCompactEvent, SessionBeforeCompactResult, SessionBeforeForkEvent, SessionBeforeForkResult, SessionBeforeSwitchEvent, SessionBeforeSwitchResult, SessionBeforeTreeEvent, SessionBeforeTreeResult, SessionBoundaryDraft, SessionCompactEvent, SessionCompactFailedEvent, SessionInfoChangedEvent, SessionShutdownEvent, SessionStartEvent, SessionTreeEvent, SlashCommandInfo, SlashCommandSource, SourceInfo, TerminalInputHandler, ThinkingLevelSelectEvent, ToolAnnotations, ToolCallEvent, ToolCallEventResult, ToolDefinition, ToolExecutionEndEvent, ToolExecutionMode, ToolExecutionStartEvent, ToolExecutionUpdateEvent, ToolExposure, ToolInfo, ToolLoadout, ToolLoadoutChanges, ToolNamespace, ToolRendererResolver, ToolRenderers, ToolRenderResultOptions, ToolResultEvent, ToolResultEventResult, TurnEndEvent, TurnEndEventResult, TurnStartEvent, UIPromptEndEvent, UIPromptKind, UIPromptStartEvent, UserBashEvent, UserBashEventResult, WidgetPlacement, WorkingIndicatorOptions, WriteToolCallEvent, } from "./core/extensions/index.ts";
|
|
8
|
+
export type { AfterProviderResponseEvent, AgentActivityOutcome, AgentBeforeSettleEvent, AgentBeforeSettleEventResult, AgentEndEvent, AgentSettledEvent, AgentStartEvent, AgentToolResult, AgentToolUpdateCallback, AppKeybinding, AutocompleteProviderFactory, BashToolCallEvent, BeforeAgentStartCustomEvent, BeforeAgentStartEvent, BeforeAgentStartEventResult, BeforeAgentStartUserEvent, BeforeProviderHeadersEvent, BeforeProviderRequestEvent, BeforeProviderRequestEventResult, BoundaryContextPreview, BoundaryResult, BoundaryState, BuildSystemPromptOptions, CacheWarmingDecisionEvent, CacheWarmingDecisionEventResult, CompactionEntryDraft, CompactOptions, ContextEditEntryDraft, ContextEvent, ContextEventResult, ContextSnapshot, ContextUsage, ContextWithSystemEvent, CustomEntryDraft, CustomMessageEntryDraft, CustomToolCallEvent, EditorHost, EditorSubmitEvent, EditorSubmitHandler, EditToolCallEvent, EntryRenderer, EntryRenderOptions, ExecOptions, ExecResult, ExecuteToolOptions, Extension, ExtensionActions, ExtensionAPI, ExtensionCommandContext, ExtensionCommandContextActions, ExtensionContext, ExtensionContextActions, ExtensionError, ExtensionEvent, ExtensionFactory, ExtensionFlag, ExtensionHandler, ExtensionRuntime, ExtensionShortcut, ExtensionToolContext, ExtensionUIContext, ExtensionUIDialogOptions, ExtensionVirtualModel, ExtensionWidgetOptions, FindToolCallEvent, GrepToolCallEvent, InlineExtension, InputEvent, InputEventResult, InputSource, KeybindingsManager, LoadExtensionsResult, LsToolCallEvent, MarkdownTransformContext, MarkdownTransformer, McpServersChangeEvent, MessageEndEvent, MessageEndEventResult, MessageRenderer, MessageRenderOptions, MessageStartEvent, MessageUpdateEvent, ModelSelectEvent, ModelSelectSource, NormalizedBuildSystemPromptOptions, PowerShellToolCallEvent, ProjectTrustContext, ProjectTrustEvent, ProjectTrustEventDecision, ProjectTrustEventResult, ProjectTrustHandler, ProviderConfig, ProviderModelConfig, ProviderStreamEvent, ReadToolCallEvent, RegisteredCommand, RegisteredTool, ResolvedCommand, ResourcesDiscoverEvent, ResourcesDiscoverResult, SessionBeforeCompactEvent, SessionBeforeCompactResult, SessionBeforeForkEvent, SessionBeforeForkResult, SessionBeforeSwitchEvent, SessionBeforeSwitchResult, SessionBeforeTreeEvent, SessionBeforeTreeResult, SessionBoundaryDraft, SessionCompactEvent, SessionCompactFailedEvent, SessionInfoChangedEvent, SessionShutdownEvent, SessionStartEvent, SessionTreeEvent, SlashCommandInfo, SlashCommandSource, SourceInfo, TerminalInputHandler, ThinkingLevelSelectEvent, ToolAnnotations, ToolCallEvent, ToolCallEventResult, ToolDefinition, ToolExecutionEndEvent, ToolExecutionMode, ToolExecutionStartEvent, ToolExecutionUpdateEvent, ToolExposure, ToolInfo, ToolLoadout, ToolLoadoutChanges, ToolNamespace, ToolRendererResolver, ToolRenderers, ToolRenderResultOptions, ToolResultEvent, ToolResultEventResult, TurnEndEvent, TurnEndEventResult, TurnStartEvent, UIPromptEndEvent, UIPromptKind, UIPromptStartEvent, UserBashEvent, UserBashEventResult, WidgetPlacement, WorkingIndicatorOptions, WriteToolCallEvent, } from "./core/extensions/index.ts";
|
|
9
9
|
export { createExtensionRuntime, defineTool, discoverAndLoadExtensions, ExtensionRunner, isBashToolResult, isEditToolResult, isFindToolResult, isGrepToolResult, isLsToolResult, isPowerShellToolResult, isReadToolResult, isToolCallEventType, isWriteToolResult, wrapRegisteredTool, wrapRegisteredTools, } from "./core/extensions/index.ts";
|
|
10
10
|
export type { ReadonlyFooterDataProvider } from "./core/footer-data-provider.ts";
|
|
11
11
|
export type { RegisteredMcpServer } from "./core/mcp-servers.ts";
|