@humain/terminal 0.0.5 → 0.0.7
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 +62 -0
- package/README.md +10 -4
- package/dist/bundle/chunks/anthropic-messages-GDMGYAZB.js +6 -0
- package/dist/bundle/chunks/anthropic.js +75 -0
- package/dist/bundle/chunks/azure-openai-responses-ZN52D6YC.js +2 -0
- package/dist/bundle/chunks/bedrock-converse-stream.js +77 -0
- package/dist/bundle/chunks/chunk-3D3G2X5U.js +6 -0
- package/dist/bundle/chunks/chunk-3VI4HD7D.js +31 -0
- package/dist/bundle/chunks/chunk-6R7UI4IY.js +2 -0
- package/dist/bundle/chunks/chunk-72KO4OMP.js +2 -0
- package/dist/bundle/chunks/chunk-7DDKXS2Q.js +2 -0
- package/dist/bundle/chunks/chunk-ARF4OE6X.js +105 -0
- package/dist/bundle/chunks/chunk-BOW22LW6.js +42 -0
- package/dist/bundle/chunks/chunk-BZQ53VGE.js +70 -0
- package/dist/bundle/chunks/chunk-CBHC6EL7.js +133 -0
- package/dist/bundle/chunks/chunk-D7XAASZM.js +4 -0
- package/dist/bundle/chunks/chunk-ECWELYBH.js +17 -0
- package/dist/bundle/chunks/chunk-GMWCTUPB.js +2 -0
- package/dist/bundle/chunks/chunk-H2O6VOXT.js +11 -0
- package/dist/bundle/chunks/chunk-HNVPY4LZ.js +5995 -0
- package/dist/bundle/chunks/chunk-JUUC5AZY.js +2 -0
- package/dist/bundle/chunks/chunk-JXWJOIH4.js +2 -0
- package/dist/bundle/chunks/chunk-L2ZPNLYD.js +2 -0
- package/dist/bundle/chunks/chunk-LVVZS2NO.js +12 -0
- package/dist/bundle/chunks/chunk-M2GYSCCG.js +44 -0
- package/dist/bundle/chunks/chunk-MA4UUCYX.js +18 -0
- package/dist/bundle/chunks/chunk-PGXDEOVV.js +2 -0
- package/dist/bundle/chunks/chunk-PJACZCIR.js +2 -0
- package/dist/bundle/chunks/chunk-PRRNXB7S.js +2 -0
- package/dist/bundle/chunks/chunk-SGTGQNNP.js +4 -0
- package/dist/bundle/chunks/chunk-TEPMHNKQ.js +2 -0
- package/dist/bundle/chunks/chunk-TXBQIIIO.js +2 -0
- package/dist/bundle/chunks/chunk-WJZ4KLGL.js +2 -0
- package/dist/bundle/chunks/chunk-XNGRGP62.js +2 -0
- package/dist/bundle/chunks/dist-7DSXV2TY.js +9 -0
- package/dist/bundle/chunks/dist-BXEVYJIO.js +7 -0
- package/dist/bundle/chunks/es-P2KNSZYR.js +9 -0
- package/dist/bundle/chunks/es5-FGTJ7ZFW.js +2 -0
- package/dist/bundle/chunks/event-streams-JOSQQSII.js +2 -0
- package/dist/bundle/chunks/extract-2L7ZVN7F.js +106 -0
- package/dist/bundle/chunks/github-copilot.js +2 -0
- package/dist/bundle/chunks/google-generative-ai-XT7NQJ2E.js +2 -0
- package/dist/bundle/chunks/google-vertex-IDQ6Z53W.js +2 -0
- package/dist/bundle/chunks/image-resize-worker.js +2 -0
- package/dist/bundle/chunks/kimi-coding.js +2 -0
- package/dist/bundle/chunks/mistral-conversations-HHDZ4FHR.js +5 -0
- package/dist/bundle/chunks/multipart-parser-FMGQ7342.js +3 -0
- package/dist/bundle/chunks/node-XY3CBY3C.js +294 -0
- package/dist/bundle/chunks/node-ZHY4LHC7.js +15 -0
- package/dist/bundle/chunks/openai-codex-responses-HRVCDY54.js +8 -0
- package/dist/bundle/chunks/openai-codex.js +75 -0
- package/dist/bundle/chunks/openai-completions-6QBYTBXY.js +7 -0
- package/dist/bundle/chunks/openai-responses-4MWLJHIK.js +2 -0
- package/dist/bundle/chunks/openrouter-images-Y2PCWAQH.js +2 -0
- package/dist/bundle/chunks/openrouter.js +75 -0
- package/dist/bundle/chunks/pdfjs-UKQT3OWY.js +107 -0
- package/dist/bundle/chunks/pi-messages-57K43J6J.js +8 -0
- package/dist/bundle/chunks/promise-J5TGSM32.js +2 -0
- package/dist/bundle/chunks/radius.js +75 -0
- package/dist/bundle/chunks/src-QKGKDFSU.js +4 -0
- package/dist/bundle/chunks/undici-D6ABF53Q.js +2 -0
- package/dist/bundle/chunks/webapi-AFS5FDJJ.js +5 -0
- package/dist/bundle/chunks/xai.js +2 -0
- package/dist/bundle/cli.js +3 -0
- package/dist/bundle/client.js +2 -0
- package/dist/bundle/index.js +2 -0
- package/dist/bundle/rpc-entry.js +3 -0
- package/dist/cli/args.d.ts +1 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +29 -9
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/file-processor.d.ts.map +1 -1
- package/dist/cli/file-processor.js +2 -1
- package/dist/cli/file-processor.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +19 -11
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +50 -14
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +163 -95
- 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 +6 -7
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +3 -0
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +4 -3
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +41 -32
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/defaults.d.ts +1 -0
- package/dist/core/defaults.d.ts.map +1 -1
- package/dist/core/defaults.js +9 -0
- package/dist/core/defaults.js.map +1 -1
- package/dist/core/extensions/index.d.ts +2 -2
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +115 -48
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/types.d.ts +38 -9
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js +3 -0
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +1 -1
- package/dist/core/footer-data-provider.js +1 -1
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/keybindings.d.ts +20 -19
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +26 -5
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/model-config.d.ts +5 -0
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +3 -1
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-resolver.d.ts +1 -0
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +18 -8
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/models-store.d.ts.map +1 -1
- package/dist/core/models-store.js +2 -1
- package/dist/core/models-store.js.map +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +22 -14
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/pi-manifest.d.ts.map +1 -1
- package/dist/core/pi-manifest.js +2 -1
- package/dist/core/pi-manifest.js.map +1 -1
- package/dist/core/remote-catalog-provider.d.ts.map +1 -1
- package/dist/core/remote-catalog-provider.js +2 -1
- 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 +3 -2
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts +2 -2
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +10 -3
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-export.d.ts +4 -0
- package/dist/core/session-export.d.ts.map +1 -0
- package/dist/core/session-export.js +32 -0
- package/dist/core/session-export.js.map +1 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +2 -1
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-diagnostics.d.ts +9 -0
- package/dist/core/settings-diagnostics.d.ts.map +1 -0
- package/dist/core/settings-diagnostics.js +21 -0
- package/dist/core/settings-diagnostics.js.map +1 -0
- package/dist/core/settings-manager.d.ts +9 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +51 -10
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +51 -33
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +2 -1
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +11 -2
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +16 -3
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +62 -29
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit-diff.d.ts +0 -5
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.js +2 -5
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +20 -4
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/index.d.ts +4 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +19 -1
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/powershell.d.ts +16 -0
- package/dist/core/tools/powershell.d.ts.map +1 -0
- package/dist/core/tools/powershell.js +39 -0
- package/dist/core/tools/powershell.js.map +1 -0
- package/dist/core/tools/subagent.d.ts.map +1 -1
- package/dist/core/tools/subagent.js +21 -28
- package/dist/core/tools/subagent.js.map +1 -1
- package/dist/core/trust-manager.d.ts.map +1 -1
- package/dist/core/trust-manager.js +2 -1
- package/dist/core/trust-manager.js.map +1 -1
- package/dist/extensions/llama/index.d.ts.map +1 -1
- package/dist/extensions/llama/index.js +2 -0
- package/dist/extensions/llama/index.js.map +1 -1
- package/dist/extensions/llama/provider.d.ts.map +1 -1
- package/dist/extensions/llama/provider.js +6 -2
- package/dist/extensions/llama/provider.js.map +1 -1
- package/dist/humain/agent-execution-protocol.d.ts +1 -217
- package/dist/humain/agent-execution-protocol.d.ts.map +1 -1
- package/dist/humain/agent-execution-protocol.js +1 -203
- package/dist/humain/agent-execution-protocol.js.map +1 -1
- package/dist/humain/bedrock-provider/vendor/index.bundle.mjs +107 -16
- package/dist/humain/mcp-adapter/vendor/CHANGELOG.md +82 -0
- package/dist/humain/mcp-adapter/vendor/README.md +47 -15
- package/dist/humain/mcp-adapter/vendor/cli.js +4 -4
- package/dist/humain/mcp-adapter/vendor/commands.ts +5 -3
- package/dist/humain/mcp-adapter/vendor/config.ts +46 -5
- package/dist/humain/mcp-adapter/vendor/direct-tools.ts +103 -92
- package/dist/humain/mcp-adapter/vendor/dist/agent-dir.d.ts +10 -0
- package/dist/humain/mcp-adapter/vendor/dist/agent-dir.js +63 -0
- package/dist/humain/mcp-adapter/vendor/dist/agent-dir.js.map +1 -0
- package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-loader.d.ts +8 -0
- package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-loader.js +356 -0
- package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-loader.js.map +1 -0
- package/dist/humain/mcp-adapter/vendor/dist/config.d.ts +123 -0
- package/dist/humain/mcp-adapter/vendor/dist/config.js +1088 -0
- package/dist/humain/mcp-adapter/vendor/dist/config.js.map +1 -0
- package/dist/humain/mcp-adapter/vendor/dist/mcp-bearer-store.d.ts +24 -0
- package/dist/humain/mcp-adapter/vendor/dist/mcp-bearer-store.js +336 -0
- package/dist/humain/mcp-adapter/vendor/dist/mcp-bearer-store.js.map +1 -0
- package/dist/humain/mcp-adapter/vendor/dist/metadata-cache.d.ts +19 -0
- package/dist/humain/mcp-adapter/vendor/dist/metadata-cache.js +319 -0
- package/dist/humain/mcp-adapter/vendor/dist/metadata-cache.js.map +1 -0
- package/dist/humain/mcp-adapter/vendor/dist/package-mcp-loader.d.ts +2 -0
- package/dist/humain/mcp-adapter/vendor/dist/package-mcp-loader.js +156 -0
- package/dist/humain/mcp-adapter/vendor/dist/package-mcp-loader.js.map +1 -0
- package/dist/humain/mcp-adapter/vendor/dist/resource-tools.d.ts +1 -0
- package/dist/humain/mcp-adapter/vendor/dist/resource-tools.js +15 -0
- package/dist/humain/mcp-adapter/vendor/dist/resource-tools.js.map +1 -0
- package/dist/humain/mcp-adapter/vendor/dist/types.d.ts +566 -0
- package/dist/humain/mcp-adapter/vendor/dist/types.js +287 -0
- package/dist/humain/mcp-adapter/vendor/dist/types.js.map +1 -0
- package/dist/humain/mcp-adapter/vendor/dist/ui-app-bridge-helpers.d.ts +6 -0
- package/dist/humain/mcp-adapter/vendor/dist/ui-app-bridge-helpers.js +37 -0
- package/dist/humain/mcp-adapter/vendor/dist/ui-app-bridge-helpers.js.map +1 -0
- package/dist/humain/mcp-adapter/vendor/dist/ui-stream-types.d.ts +104 -0
- package/dist/humain/mcp-adapter/vendor/dist/ui-stream-types.js +59 -0
- package/dist/humain/mcp-adapter/vendor/dist/ui-stream-types.js.map +1 -0
- package/dist/humain/mcp-adapter/vendor/dist/ui-tool-visibility.d.ts +4 -0
- package/dist/humain/mcp-adapter/vendor/dist/ui-tool-visibility.js +27 -0
- package/dist/humain/mcp-adapter/vendor/dist/ui-tool-visibility.js.map +1 -0
- package/dist/humain/mcp-adapter/vendor/dist/utils.d.ts +32 -0
- package/dist/humain/mcp-adapter/vendor/dist/utils.js +338 -0
- package/dist/humain/mcp-adapter/vendor/dist/utils.js.map +1 -0
- package/dist/humain/mcp-adapter/vendor/failure-backoff.ts +23 -0
- package/dist/humain/mcp-adapter/vendor/index.bundle.mjs +4870 -3878
- package/dist/humain/mcp-adapter/vendor/index.ts +294 -88
- package/dist/humain/mcp-adapter/vendor/init.ts +41 -30
- package/dist/humain/mcp-adapter/vendor/lifecycle.ts +16 -8
- package/dist/humain/mcp-adapter/vendor/mcp-auth-flow.ts +124 -32
- package/dist/humain/mcp-adapter/vendor/mcp-bearer-store.ts +0 -2
- package/dist/humain/mcp-adapter/vendor/mcp-code.ts +2 -0
- package/dist/humain/mcp-adapter/vendor/mcp-oauth-provider.ts +155 -16
- package/dist/humain/mcp-adapter/vendor/mcp-output-guard.ts +95 -7
- package/dist/humain/mcp-adapter/vendor/mcp-probe.ts +18 -4
- package/dist/humain/mcp-adapter/vendor/mcp-references.ts +376 -0
- package/dist/humain/mcp-adapter/vendor/mcp-status.ts +8 -19
- package/dist/humain/mcp-adapter/vendor/metadata-cache.ts +20 -12
- package/dist/humain/mcp-adapter/vendor/namespace-tools.ts +276 -0
- package/dist/humain/mcp-adapter/vendor/package.json +26 -8
- package/dist/humain/mcp-adapter/vendor/proxy-modes.ts +128 -32
- package/dist/humain/mcp-adapter/vendor/request-headers-command.ts +1 -1
- package/dist/humain/mcp-adapter/vendor/search-ranking.ts +2 -0
- package/dist/humain/mcp-adapter/vendor/server-manager.ts +69 -12
- package/dist/humain/mcp-adapter/vendor/state.ts +1 -3
- package/dist/humain/mcp-adapter/vendor/tool-result-renderer.ts +16 -2
- package/dist/humain/mcp-adapter/vendor/types.ts +51 -2
- package/dist/humain/mcp-adapter/vendor/ui-server.ts +3 -19
- package/dist/humain/mcp-adapter/vendor/ui-session.ts +2 -1
- package/dist/humain/mcp-adapter/vendor/utils.ts +21 -19
- package/dist/humain/mcp-adapter.d.ts.map +1 -1
- package/dist/humain/mcp-adapter.js +4 -0
- package/dist/humain/mcp-adapter.js.map +1 -1
- package/dist/humain/web-access/vendor/chrome-cookies.d.ts +14 -0
- package/dist/humain/web-access/vendor/chrome-cookies.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/chrome-cookies.js +85 -33
- package/dist/humain/web-access/vendor/chrome-cookies.js.map +1 -1
- package/dist/humain/web-access/vendor/credential-source.d.ts +1 -1
- package/dist/humain/web-access/vendor/credential-source.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/credential-source.js +3 -1
- package/dist/humain/web-access/vendor/credential-source.js.map +1 -1
- package/dist/humain/web-access/vendor/curator-page.d.ts +2 -29
- package/dist/humain/web-access/vendor/curator-page.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/curator-page.js +10 -1
- package/dist/humain/web-access/vendor/curator-page.js.map +1 -1
- package/dist/humain/web-access/vendor/curator-server.d.ts +2 -29
- package/dist/humain/web-access/vendor/curator-server.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/curator-server.js +4 -0
- package/dist/humain/web-access/vendor/curator-server.js.map +1 -1
- package/dist/humain/web-access/vendor/extract.d.ts +11 -0
- package/dist/humain/web-access/vendor/extract.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/extract.js +163 -20
- package/dist/humain/web-access/vendor/extract.js.map +1 -1
- package/dist/humain/web-access/vendor/fetch-params.d.ts +2 -0
- package/dist/humain/web-access/vendor/fetch-params.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/fetch-params.js +11 -0
- package/dist/humain/web-access/vendor/fetch-params.js.map +1 -1
- package/dist/humain/web-access/vendor/gemini-adc.d.ts +10 -0
- package/dist/humain/web-access/vendor/gemini-adc.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/gemini-adc.js +268 -0
- package/dist/humain/web-access/vendor/gemini-adc.js.map +1 -0
- package/dist/humain/web-access/vendor/gemini-api.d.ts +7 -1
- package/dist/humain/web-access/vendor/gemini-api.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/gemini-api.js +51 -15
- package/dist/humain/web-access/vendor/gemini-api.js.map +1 -1
- package/dist/humain/web-access/vendor/gemini-search.d.ts +9 -4
- package/dist/humain/web-access/vendor/gemini-search.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/gemini-search.js +63 -21
- package/dist/humain/web-access/vendor/gemini-search.js.map +1 -1
- package/dist/humain/web-access/vendor/gemini-url-context.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/gemini-url-context.js +3 -2
- package/dist/humain/web-access/vendor/gemini-url-context.js.map +1 -1
- package/dist/humain/web-access/vendor/gemini-web-config.d.ts +8 -1
- package/dist/humain/web-access/vendor/gemini-web-config.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/gemini-web-config.js +49 -4
- package/dist/humain/web-access/vendor/gemini-web-config.js.map +1 -1
- package/dist/humain/web-access/vendor/gemini-web.d.ts +2 -1
- package/dist/humain/web-access/vendor/gemini-web.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/gemini-web.js +8 -3
- package/dist/humain/web-access/vendor/gemini-web.js.map +1 -1
- package/dist/humain/web-access/vendor/github-api.d.ts +1 -1
- package/dist/humain/web-access/vendor/github-api.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/github-api.js +6 -4
- package/dist/humain/web-access/vendor/github-api.js.map +1 -1
- package/dist/humain/web-access/vendor/github-extract.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/github-extract.js +50 -3
- package/dist/humain/web-access/vendor/github-extract.js.map +1 -1
- package/dist/humain/web-access/vendor/github-issue-pr.d.ts +27 -0
- package/dist/humain/web-access/vendor/github-issue-pr.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/github-issue-pr.js +701 -0
- package/dist/humain/web-access/vendor/github-issue-pr.js.map +1 -0
- package/dist/humain/web-access/vendor/index.d.ts +3 -31
- package/dist/humain/web-access/vendor/index.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/index.js +643 -530
- package/dist/humain/web-access/vendor/index.js.map +1 -1
- package/dist/humain/web-access/vendor/kimi-search.d.ts +5 -0
- package/dist/humain/web-access/vendor/kimi-search.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/kimi-search.js +228 -0
- package/dist/humain/web-access/vendor/kimi-search.js.map +1 -0
- package/dist/humain/web-access/vendor/openai-search.d.ts +3 -0
- package/dist/humain/web-access/vendor/openai-search.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/openai-search.js +89 -16
- package/dist/humain/web-access/vendor/openai-search.js.map +1 -1
- package/dist/humain/web-access/vendor/page-query.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/page-query.js +56 -8
- package/dist/humain/web-access/vendor/page-query.js.map +1 -1
- package/dist/humain/web-access/vendor/ssrf-protection.js +6 -1
- package/dist/humain/web-access/vendor/ssrf-protection.js.map +1 -1
- package/dist/humain/web-access/vendor/utils.d.ts +12 -0
- package/dist/humain/web-access/vendor/utils.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/utils.js +343 -1
- package/dist/humain/web-access/vendor/utils.js.map +1 -1
- package/dist/humain/web-access/vendor/xcrawl.d.ts +4 -0
- package/dist/humain/web-access/vendor/xcrawl.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/xcrawl.js +251 -0
- package/dist/humain/web-access/vendor/xcrawl.js.map +1 -0
- package/dist/humain/web-access/vendor/youtube-extract.js +2 -2
- package/dist/humain/web-access/vendor/youtube-extract.js.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts +3 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +17 -14
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +4 -3
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts +9 -3
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +53 -10
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +7 -2
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +118 -55
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-submenu.d.ts +72 -0
- package/dist/modes/interactive/components/settings-submenu.d.ts.map +1 -0
- package/dist/modes/interactive/components/settings-submenu.js +151 -0
- package/dist/modes/interactive/components/settings-submenu.js.map +1 -0
- package/dist/modes/interactive/components/thinking-selector.d.ts +15 -3
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +68 -17
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/external-editor.d.ts.map +1 -1
- package/dist/modes/interactive/external-editor.js +2 -1
- package/dist/modes/interactive/external-editor.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +11 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +176 -106
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/session-share.d.ts +16 -0
- package/dist/modes/interactive/session-share.d.ts.map +1 -0
- package/dist/modes/interactive/session-share.js +188 -0
- package/dist/modes/interactive/session-share.js.map +1 -0
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +6 -5
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/json-event.d.ts +16 -13
- package/dist/modes/json-event.d.ts.map +1 -1
- package/dist/modes/json-event.js +20 -6
- package/dist/modes/json-event.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +3 -2
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +2 -7
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/package-manager-cli.d.ts +1 -0
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +189 -3
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/utils/changelog.d.ts +1 -1
- package/dist/utils/changelog.d.ts.map +1 -1
- package/dist/utils/changelog.js +12 -2
- package/dist/utils/changelog.js.map +1 -1
- package/dist/utils/frontmatter.d.ts.map +1 -1
- package/dist/utils/frontmatter.js +2 -1
- package/dist/utils/frontmatter.js.map +1 -1
- package/dist/utils/management-http.d.ts +5 -3
- package/dist/utils/management-http.d.ts.map +1 -1
- package/dist/utils/management-http.js +14 -10
- package/dist/utils/management-http.js.map +1 -1
- package/dist/utils/shell.d.ts +3 -0
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +17 -5
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/syntax-highlight.d.ts +1 -0
- package/dist/utils/syntax-highlight.d.ts.map +1 -1
- package/dist/utils/syntax-highlight.js +64 -1
- package/dist/utils/syntax-highlight.js.map +1 -1
- package/dist/utils/text.d.ts +8 -0
- package/dist/utils/text.d.ts.map +1 -0
- package/dist/utils/text.js +9 -0
- package/dist/utils/text.js.map +1 -0
- package/dist/utils/version-check.js +4 -4
- package/dist/utils/version-check.js.map +1 -1
- package/docs/compaction.md +15 -0
- package/docs/custom-provider.md +5 -2
- package/docs/environment-variables.md +7 -7
- package/docs/extensions.md +17 -7
- package/docs/json.md +7 -2
- package/docs/keybindings.md +8 -8
- package/docs/llama-cpp.md +2 -0
- package/docs/models.md +8 -2
- package/docs/packages.md +2 -2
- package/docs/rpc.md +9 -3
- package/docs/sdk.md +7 -2
- package/docs/settings.md +11 -3
- package/docs/skills.md +3 -2
- package/docs/terminal-setup.md +8 -0
- package/docs/usage.md +10 -7
- package/docs/windows.md +15 -1
- package/examples/extensions/border-status-editor.ts +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +70 -8
- package/examples/extensions/custom-provider-anthropic/package.json +2 -2
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/git-checkpoint.ts +2 -2
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/notify.ts +3 -1
- package/examples/extensions/sandbox/package-lock.json +14 -40
- package/examples/extensions/sandbox/package.json +2 -2
- package/examples/extensions/titlebar-spinner.ts +1 -1
- package/examples/extensions/with-deps/package-lock.json +4 -4
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/rpc-extension-ui.ts +1 -1
- package/examples/sdk/06-extensions.ts +1 -1
- package/examples/sdk/README.md +1 -1
- package/npm-shrinkwrap.json +293 -221
- package/package.json +21 -18
- package/src/humain/mcp-adapter/UPSTREAM.md +15 -5
- package/src/humain/mcp-adapter/upstream.json +4 -3
- package/src/humain/mcp-adapter/vendor/CHANGELOG.md +82 -0
- package/src/humain/web-access/UPSTREAM.md +1 -1
- package/src/humain/web-access/upstream.json +6 -4
|
@@ -15,8 +15,8 @@ import { findContent } from "./content-find.js";
|
|
|
15
15
|
import { answerFromPage } from "./page-query.js";
|
|
16
16
|
import { rewriteSearchQuery } from "./query-rewrite.js";
|
|
17
17
|
import { clearCloneCache } from "./github-extract.js";
|
|
18
|
-
import { getConfiguredSearchRouting, normalizeSearchProviderSelection, RESOLVED_SEARCH_PROVIDERS, SEARCH_PROVIDERS, search } from "./gemini-search.js";
|
|
19
|
-
import { formatSeconds, getWebSearchConfigDir, getWebSearchConfigPath, resolveCuratorNetworkConfig } from "./utils.js";
|
|
18
|
+
import { ALL_SEARCH_PROVIDERS, getConfiguredSearchRouting, normalizeSearchProviderSelection, RESOLVED_SEARCH_PROVIDERS, SEARCH_PROVIDERS, search } from "./gemini-search.js";
|
|
19
|
+
import { formatSeconds, getWebSearchConfigDir, getWebSearchConfigPath, installGlobalProxyFetch, resolveCuratorNetworkConfig, runWithProxy } from "./utils.js";
|
|
20
20
|
import { clearResults, deleteResult, generateId, getAllResults, getResult, restoreFromSession, storeFetchedContentResult, storeResult, } from "./storage.js";
|
|
21
21
|
import { activityMonitor } from "./activity.js";
|
|
22
22
|
import { startCuratorServer } from "./curator-server.js";
|
|
@@ -30,10 +30,10 @@ import { join } from "node:path";
|
|
|
30
30
|
import { isPerplexityAvailable } from "./perplexity.js";
|
|
31
31
|
import { isExaAvailable } from "./exa.js";
|
|
32
32
|
import { isGeminiApiAvailable } from "./gemini-api.js";
|
|
33
|
-
import { getActiveGoogleEmail, getGeminiWebAvailabilityDiagnostic, isGeminiWebAvailable } from "./gemini-web.js";
|
|
33
|
+
import { getActiveGoogleEmail, getGeminiWebAvailabilityDiagnostic, getGeminiWebAvailabilityDiagnosticDetails, isGeminiWebAvailable } from "./gemini-web.js";
|
|
34
34
|
import { isBrowserCookieAccessAllowed } from "./gemini-web-config.js";
|
|
35
35
|
import { isBraveAvailable } from "./brave.js";
|
|
36
|
-
import { isOpenAISearchAvailable } from "./openai-search.js";
|
|
36
|
+
import { isCurrentModelHostedSearchEligible, isOpenAISearchAvailable } from "./openai-search.js";
|
|
37
37
|
import { isParallelAvailable } from "./parallel.js";
|
|
38
38
|
import { isParallelMcpAvailable } from "./parallel-mcp.js";
|
|
39
39
|
import { isTinyFishAvailable } from "./tinyfish.js";
|
|
@@ -51,10 +51,12 @@ import { isSearXNGAvailable } from "./searxng.js";
|
|
|
51
51
|
import { isDuckDuckGoAvailable } from "./duckduckgo.js";
|
|
52
52
|
import { isAnySearchAvailable } from "./anysearch.js";
|
|
53
53
|
import { isXaiSearchAvailable } from "./xai-search.js";
|
|
54
|
+
import { isKimiSearchAvailable } from "./kimi-search.js";
|
|
54
55
|
import { isBrightDataAvailable } from "./brightdata.js";
|
|
55
56
|
import { isSerpBaseAvailable } from "./serpbase.js";
|
|
56
57
|
import { isSerperAvailable } from "./serper.js";
|
|
57
58
|
import { isValyuAvailable } from "./valyu.js";
|
|
59
|
+
import { isXcrawlAvailable } from "./xcrawl.js";
|
|
58
60
|
import { buildSearchErrorPlan } from "./render-search-error.js";
|
|
59
61
|
import { findModelWithProviderRouting, loadEnabledModelPatterns, modelMatchesEnabledPatterns, splitThinkingSuffix } from "./summary-model-scope.js";
|
|
60
62
|
import { buildResearchArtifact, withClaimAssessment, storeResearchArtifact, getResearchArtifact, } from "./source-check.js";
|
|
@@ -64,6 +66,13 @@ async function fetchAllContent(urls, signal, options) {
|
|
|
64
66
|
const extractModule = await (extractModulePromise ??= import("./extract.js"));
|
|
65
67
|
return extractModule.fetchAllContent(urls, signal, options);
|
|
66
68
|
}
|
|
69
|
+
function withRegisteredFetchOptions(options, toolNames, proxy) {
|
|
70
|
+
return {
|
|
71
|
+
...(options ?? {}),
|
|
72
|
+
toolNames,
|
|
73
|
+
...(proxy !== undefined ? { proxy } : {}),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
67
76
|
function isAbortError(err) {
|
|
68
77
|
return (err instanceof Error ? err.message : String(err)).toLowerCase().includes("abort");
|
|
69
78
|
}
|
|
@@ -248,6 +257,34 @@ function normalizeQueryList(queryList) {
|
|
|
248
257
|
}
|
|
249
258
|
return normalized;
|
|
250
259
|
}
|
|
260
|
+
// Some local models serialize a multi-query list into the single-string `query`
|
|
261
|
+
// field as a JSON array (query: "[\"a\", \"b\"]") instead of using the
|
|
262
|
+
// `queries` parameter. Forwarding that raw string verbatim makes every backend
|
|
263
|
+
// search for the literal array text and return zero results, with no signal to
|
|
264
|
+
// the model that its argument shape was wrong. Expand a string that parses as a
|
|
265
|
+
// JSON array of strings so each element is searched independently.
|
|
266
|
+
function expandQueryString(query) {
|
|
267
|
+
if (typeof query !== "string")
|
|
268
|
+
return [];
|
|
269
|
+
const trimmed = query.trim();
|
|
270
|
+
if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
|
|
271
|
+
try {
|
|
272
|
+
const parsed = JSON.parse(trimmed);
|
|
273
|
+
// Only expand an unambiguously string-only array. Mixed or non-string
|
|
274
|
+
// arrays are kept as the literal query so we never silently drop
|
|
275
|
+
// members or collapse them into an empty search.
|
|
276
|
+
if (Array.isArray(parsed) && parsed.every((entry) => typeof entry === "string")) {
|
|
277
|
+
return parsed
|
|
278
|
+
.map((entry) => entry.trim())
|
|
279
|
+
.filter((entry) => entry.length > 0);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
catch {
|
|
283
|
+
// Not JSON — treat as a literal query string.
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return [query];
|
|
287
|
+
}
|
|
251
288
|
function getCuratorTimeoutSeconds() {
|
|
252
289
|
const source = loadConfig();
|
|
253
290
|
const explicit = normalizeCuratorTimeoutSeconds(source.curatorTimeoutSeconds);
|
|
@@ -271,7 +308,7 @@ function shouldAutoOpenCuratorBrowser(config) {
|
|
|
271
308
|
return true;
|
|
272
309
|
}
|
|
273
310
|
async function getProviderAvailability(ctx) {
|
|
274
|
-
const geminiWebAvail = await
|
|
311
|
+
const geminiWebAvail = await getOptionalGeminiWebAvailability();
|
|
275
312
|
const geminiApiAvail = isGeminiApiAvailable();
|
|
276
313
|
const providers = {
|
|
277
314
|
openai: await isOpenAISearchAvailable(ctx),
|
|
@@ -294,19 +331,29 @@ async function getProviderAvailability(ctx) {
|
|
|
294
331
|
perplexity: isPerplexityAvailable(),
|
|
295
332
|
exa: isExaAvailable(),
|
|
296
333
|
gemini: geminiApiAvail || !!geminiWebAvail,
|
|
334
|
+
kimi: await isKimiSearchAvailable(ctx),
|
|
297
335
|
anysearch: isAnySearchAvailable(),
|
|
336
|
+
xcrawl: isXcrawlAvailable(),
|
|
298
337
|
xai: await isXaiSearchAvailable(ctx),
|
|
299
338
|
brightdata: isBrightDataAvailable(),
|
|
300
339
|
serpbase: isSerpBaseAvailable(),
|
|
301
340
|
serper: isSerperAvailable(),
|
|
302
341
|
valyu: isValyuAvailable(),
|
|
303
342
|
};
|
|
343
|
+
const allSearchProviders = new Set(ALL_SEARCH_PROVIDERS);
|
|
304
344
|
return {
|
|
305
|
-
|
|
306
|
-
all: Object.entries(providers).some(([provider, available]) => provider !== "parallel-mcp" && provider !== "duckduckgo" && provider !== "anysearch" && provider !== "xai" && provider !== "brightdata" && provider !== "serpbase" && provider !== "serper" && provider !== "valyu" && provider !== "gemini" && available) || geminiApiAvail,
|
|
345
|
+
all: Object.entries(providers).some(([provider, available]) => provider !== "gemini" && allSearchProviders.has(provider) && available) || geminiApiAvail,
|
|
307
346
|
...providers,
|
|
308
347
|
};
|
|
309
348
|
}
|
|
349
|
+
async function getOptionalGeminiWebAvailability() {
|
|
350
|
+
try {
|
|
351
|
+
return await isGeminiWebAvailable();
|
|
352
|
+
}
|
|
353
|
+
catch {
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
310
357
|
function shouldUseOpenAICodexDefault(ctx) {
|
|
311
358
|
return ctx?.model?.provider === "openai-codex";
|
|
312
359
|
}
|
|
@@ -330,7 +377,7 @@ async function loadCuratorBootstrap(requestedProvider, ctx, options) {
|
|
|
330
377
|
};
|
|
331
378
|
}
|
|
332
379
|
export function resolveCuratorDefaultProvider(provider, available, ctx, options) {
|
|
333
|
-
return resolveProvider(provider, available, options, shouldUseOpenAICodexDefault(ctx));
|
|
380
|
+
return resolveProvider(provider, available, options, shouldUseOpenAICodexDefault(ctx), ctx);
|
|
334
381
|
}
|
|
335
382
|
function firstAvailableProvider(available, preferOpenAI, fallback) {
|
|
336
383
|
if (available.searxng)
|
|
@@ -373,7 +420,7 @@ function firstAvailableProvider(available, preferOpenAI, fallback) {
|
|
|
373
420
|
return "gemini";
|
|
374
421
|
return fallback;
|
|
375
422
|
}
|
|
376
|
-
function resolveProvider(provider, available, options, preferOpenAICodexDefault = false) {
|
|
423
|
+
function resolveProvider(provider, available, options, preferOpenAICodexDefault = false, ctx) {
|
|
377
424
|
if (Array.isArray(provider))
|
|
378
425
|
return "all";
|
|
379
426
|
const preferOpenAI = shouldPreferOpenAI(options, preferOpenAICodexDefault);
|
|
@@ -381,10 +428,12 @@ function resolveProvider(provider, available, options, preferOpenAICodexDefault
|
|
|
381
428
|
const routing = getConfiguredSearchRouting();
|
|
382
429
|
if (routing) {
|
|
383
430
|
for (const candidate of routing.providers) {
|
|
431
|
+
if (candidate === "openai" && routing.useCurrentModel === true && !isCurrentModelHostedSearchEligible(ctx))
|
|
432
|
+
continue;
|
|
384
433
|
if (available[candidate])
|
|
385
434
|
return candidate;
|
|
386
435
|
}
|
|
387
|
-
return routing.providers[0];
|
|
436
|
+
return routing.providers.find(candidate => candidate !== "openai" || routing.useCurrentModel !== true || isCurrentModelHostedSearchEligible(ctx)) ?? routing.providers[0];
|
|
388
437
|
}
|
|
389
438
|
return firstAvailableProvider(available, preferOpenAI, "exa");
|
|
390
439
|
}
|
|
@@ -495,6 +544,25 @@ function normalizeFindQueries(value) {
|
|
|
495
544
|
throw new Error("findText must contain at least one non-empty string");
|
|
496
545
|
return queries;
|
|
497
546
|
}
|
|
547
|
+
function normalizeFindMode(value) {
|
|
548
|
+
if (value === undefined)
|
|
549
|
+
return undefined;
|
|
550
|
+
if (value === "exact" || value === "case-insensitive" || value === "fuzzy")
|
|
551
|
+
return value;
|
|
552
|
+
throw new Error('findMode must be "exact", "case-insensitive", or "fuzzy"');
|
|
553
|
+
}
|
|
554
|
+
function normalizeGetSearchContentParams(params) {
|
|
555
|
+
const normalized = { ...params, findMode: normalizeFindMode(params.findMode) };
|
|
556
|
+
if (normalized.query?.trim() === "")
|
|
557
|
+
delete normalized.query;
|
|
558
|
+
if (normalized.url?.trim() === "")
|
|
559
|
+
delete normalized.url;
|
|
560
|
+
if (normalized.findText !== undefined) {
|
|
561
|
+
delete normalized.offset;
|
|
562
|
+
delete normalized.limit;
|
|
563
|
+
}
|
|
564
|
+
return normalized;
|
|
565
|
+
}
|
|
498
566
|
function formatInputValue(value) {
|
|
499
567
|
if (typeof value === "string")
|
|
500
568
|
return JSON.stringify(value);
|
|
@@ -819,11 +887,18 @@ function handleSessionChange(ctx) {
|
|
|
819
887
|
}
|
|
820
888
|
export default function (pi) {
|
|
821
889
|
const initConfig = loadConfigForExtensionInit();
|
|
890
|
+
installGlobalProxyFetch();
|
|
822
891
|
const toolNames = resolveToolNames(initConfig);
|
|
823
892
|
const webSearchEnabled = isToolEnabled(initConfig, "webSearch");
|
|
824
893
|
const sourceCheckEnabled = isToolEnabled(initConfig, "sourceCheck");
|
|
825
894
|
const fetchContentEnabled = isToolEnabled(initConfig, "fetchContent");
|
|
826
895
|
const getSearchContentEnabled = isToolEnabled(initConfig, "getSearchContent");
|
|
896
|
+
// Names as registered this session, so fetch failure guidance never points
|
|
897
|
+
// at tools that are disabled or were renamed after init.
|
|
898
|
+
const registeredToolNames = {
|
|
899
|
+
...(webSearchEnabled ? { webSearch: toolNames.webSearch } : {}),
|
|
900
|
+
...(fetchContentEnabled ? { fetchContent: toolNames.fetchContent } : {}),
|
|
901
|
+
};
|
|
827
902
|
const storedContentSources = joinToolNames([
|
|
828
903
|
...(webSearchEnabled ? [toolNames.webSearch] : []),
|
|
829
904
|
...(sourceCheckEnabled ? [toolNames.sourceCheck] : []),
|
|
@@ -837,13 +912,13 @@ export default function (pi) {
|
|
|
837
912
|
: "Full original content is stored internally, but the retrieval tool is not registered.";
|
|
838
913
|
const curateKey = initConfig.shortcuts?.curate || DEFAULT_SHORTCUTS.curate;
|
|
839
914
|
const activityKey = initConfig.shortcuts?.activity || DEFAULT_SHORTCUTS.activity;
|
|
840
|
-
function startBackgroundFetch(urls) {
|
|
915
|
+
function startBackgroundFetch(urls, proxy) {
|
|
841
916
|
if (urls.length === 0)
|
|
842
917
|
return null;
|
|
843
918
|
const fetchId = generateId();
|
|
844
919
|
const controller = new AbortController();
|
|
845
920
|
pendingFetches.set(fetchId, controller);
|
|
846
|
-
fetchAllContent(urls, controller.signal)
|
|
921
|
+
runWithProxy(proxy, () => fetchAllContent(urls, controller.signal, withRegisteredFetchOptions(undefined, registeredToolNames, proxy)))
|
|
847
922
|
.then((fetched) => {
|
|
848
923
|
if (!sessionActive || !pendingFetches.has(fetchId))
|
|
849
924
|
return;
|
|
@@ -1107,7 +1182,7 @@ export default function (pi) {
|
|
|
1107
1182
|
}
|
|
1108
1183
|
}
|
|
1109
1184
|
else if (opts.includeContent) {
|
|
1110
|
-
fetchId = startBackgroundFetch(opts.urls);
|
|
1185
|
+
fetchId = startBackgroundFetch(opts.urls, opts.proxy);
|
|
1111
1186
|
if (fetchId && !hasApprovedSummary) {
|
|
1112
1187
|
output += `---\nContent fetching in background [${fetchId}]. Will notify when ready.`;
|
|
1113
1188
|
}
|
|
@@ -1217,20 +1292,22 @@ export default function (pi) {
|
|
|
1217
1292
|
defaultSummaryModel: pc.defaultSummaryModel,
|
|
1218
1293
|
}, {
|
|
1219
1294
|
async onSummarize(selectedQueryIndices, summarizeSignal, model, feedback) {
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1295
|
+
return runWithProxy(pc.proxy, async () => {
|
|
1296
|
+
if (pendingCurates.get(callId) !== pc)
|
|
1297
|
+
throw new Error("Curator session is no longer active.");
|
|
1298
|
+
pc.onUpdate?.({
|
|
1299
|
+
content: [{ type: "text", text: "Generating summary draft..." }],
|
|
1300
|
+
details: { phase: "generating-summary", progress: 0.9, curatorUrl: pc.curatorUrl, timeoutSeconds: pc.timeoutSeconds, shortcut: curateKey },
|
|
1301
|
+
});
|
|
1302
|
+
const draft = await generateSummaryForSelectedIndices(selectedQueryIndices, pc.searchResults, pc.summaryContext, summarizeSignal, model, feedback);
|
|
1303
|
+
if (pendingCurates.get(callId) !== pc)
|
|
1304
|
+
throw new Error("Curator session is no longer active.");
|
|
1305
|
+
pc.onUpdate?.({
|
|
1306
|
+
content: [{ type: "text", text: "Summary draft ready — waiting for approval..." }],
|
|
1307
|
+
details: { phase: "waiting-for-approval", progress: 1, curatorUrl: pc.curatorUrl, timeoutSeconds: pc.timeoutSeconds, shortcut: curateKey },
|
|
1308
|
+
});
|
|
1309
|
+
return draft;
|
|
1232
1310
|
});
|
|
1233
|
-
return draft;
|
|
1234
1311
|
},
|
|
1235
1312
|
onSubmit(payload) {
|
|
1236
1313
|
if (pendingCurates.get(callId) !== pc)
|
|
@@ -1248,6 +1325,7 @@ export default function (pi) {
|
|
|
1248
1325
|
inlineContent: filteredInline.length > 0 ? filteredInline : undefined,
|
|
1249
1326
|
curated: true,
|
|
1250
1327
|
curatedFrom: pc.searchResults.size,
|
|
1328
|
+
proxy: pc.proxy,
|
|
1251
1329
|
};
|
|
1252
1330
|
if (!payload.rawResults) {
|
|
1253
1331
|
const resolvedSummary = resolveSummaryForSubmit(payload, pc.searchResults);
|
|
@@ -1277,6 +1355,7 @@ export default function (pi) {
|
|
|
1277
1355
|
workflow: pc.workflow,
|
|
1278
1356
|
approvedSummary: resolvedSummary.approvedSummary,
|
|
1279
1357
|
summaryMeta: resolvedSummary.summaryMeta,
|
|
1358
|
+
proxy: pc.proxy,
|
|
1280
1359
|
}));
|
|
1281
1360
|
}
|
|
1282
1361
|
else {
|
|
@@ -1309,23 +1388,25 @@ export default function (pi) {
|
|
|
1309
1388
|
}
|
|
1310
1389
|
},
|
|
1311
1390
|
async onAddSearch(query, provider) {
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1391
|
+
return runWithProxy(pc.proxy, async () => {
|
|
1392
|
+
if (pendingCurates.get(callId) !== pc)
|
|
1393
|
+
throw new Error("Curator session is no longer active.");
|
|
1394
|
+
const requestedProvider = resolveCuratorSearchProvider(provider, pc.searchProvider);
|
|
1395
|
+
const response = await search(query, {
|
|
1396
|
+
provider: requestedProvider,
|
|
1397
|
+
numResults: pc.numResults,
|
|
1398
|
+
recencyFilter: pc.recencyFilter,
|
|
1399
|
+
domainFilter: pc.domainFilter,
|
|
1400
|
+
includeContent: pc.includeContent,
|
|
1401
|
+
signal: addSearchSignal,
|
|
1402
|
+
extensionContext: ctx,
|
|
1403
|
+
});
|
|
1404
|
+
if (pendingCurates.get(callId) !== pc)
|
|
1405
|
+
throw new Error("Curator session is no longer active.");
|
|
1406
|
+
if (response.inlineContent)
|
|
1407
|
+
pc.allInlineContent.push(...response.inlineContent);
|
|
1408
|
+
return toCuratorSearchEntries(response);
|
|
1323
1409
|
});
|
|
1324
|
-
if (pendingCurates.get(callId) !== pc)
|
|
1325
|
-
throw new Error("Curator session is no longer active.");
|
|
1326
|
-
if (response.inlineContent)
|
|
1327
|
-
pc.allInlineContent.push(...response.inlineContent);
|
|
1328
|
-
return toCuratorSearchEntries(response);
|
|
1329
1410
|
},
|
|
1330
1411
|
onAddSearchResults(entries) {
|
|
1331
1412
|
if (pendingCurates.get(callId) !== pc)
|
|
@@ -1335,9 +1416,11 @@ export default function (pi) {
|
|
|
1335
1416
|
}
|
|
1336
1417
|
},
|
|
1337
1418
|
async onRewriteQuery(query, rewriteSignal) {
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1419
|
+
return runWithProxy(pc.proxy, async () => {
|
|
1420
|
+
if (pendingCurates.get(callId) !== pc)
|
|
1421
|
+
throw new Error("Curator session is no longer active.");
|
|
1422
|
+
return rewriteSearchQuery(query, pc.summaryContext, rewriteSignal);
|
|
1423
|
+
});
|
|
1341
1424
|
},
|
|
1342
1425
|
});
|
|
1343
1426
|
if (pendingCurates.get(callId) !== pc) {
|
|
@@ -1457,7 +1540,7 @@ export default function (pi) {
|
|
|
1457
1540
|
pi.registerTool({
|
|
1458
1541
|
name: toolNames.webSearch,
|
|
1459
1542
|
label: "Web Search",
|
|
1460
|
-
description: `Search the web using OpenAI, Brave, Parallel, Parallel MCP, TinyFish, Search1API, Searchinfinity, Querit, Tavily, Firecrawl, Jina, SERPdive, Kagi, Bocha, Ollama, SearXNG, DuckDuckGo, Exa, Perplexity, Gemini, AnySearch, Valyu, xAI, Bright Data, SerpBase, or Serper. Pass a provider array to search only those providers simultaneously, or use provider "all" to search every eligible provider except Parallel MCP, DuckDuckGo, AnySearch, Valyu, xAI, Bright Data, SerpBase, and Serper. Returns an AI-synthesized answer with source citations. OpenAI search uses a Codex subscription or OpenAI API key; xAI search uses a SuperGrok/X Premium subscription or xAI API key. Parallel MCP, DuckDuckGo, AnySearch, Valyu, xAI, Bright Data, SerpBase, and Serper are available only when explicitly selected. For comprehensive research, prefer queries (plural) with 2-4 varied angles over a single query — each query gets its own synthesized answer, so varying phrasing and scope gives much broader coverage. When includeContent is true, full page content is fetched in the background. Searches auto-open the interactive browser curator and stream results live; set workflow to "none" to skip curation or "auto-summary" for a model-generated summary without the browser curator. The configured provider is used when provider is omitted or set to auto; omit provider unless explicitly overriding it. Without a configured provider, SearXNG is preferred first for local/private search. When the active Pi model is openai-codex, Codex-backed OpenAI search is preferred next. Otherwise Exa is preferred before OpenAI, then Brave, Parallel, TinyFish, Search1API, Searchinfinity, Querit, Tavily, Firecrawl, Jina, SERPdive, Kagi, Bocha, Ollama, Perplexity, Gemini API, or Gemini Web.`,
|
|
1543
|
+
description: `Search the web using OpenAI, Brave, Parallel, Parallel MCP, TinyFish, Search1API, Searchinfinity, Querit, Tavily, Firecrawl, Jina, SERPdive, Kagi, Bocha, Ollama, SearXNG, DuckDuckGo, Exa, Perplexity, Gemini, Kimi, AnySearch, XCrawl, Valyu, xAI, Bright Data, SerpBase, or Serper. Pass a provider array to search only those providers simultaneously, or use provider "all" to search every eligible provider except Parallel MCP, DuckDuckGo, Kimi, AnySearch, XCrawl, Valyu, xAI, Bright Data, SerpBase, and Serper. Returns an AI-synthesized answer with source citations. OpenAI search uses a Codex subscription or OpenAI API key; Kimi search uses a Kimi Code Plan authenticated through /login kimi-coding; xAI search uses a SuperGrok/X Premium subscription or xAI API key. Parallel MCP, DuckDuckGo, Kimi, AnySearch, XCrawl, Valyu, xAI, Bright Data, SerpBase, and Serper are available only when explicitly selected. For comprehensive research, prefer queries (plural) with 2-4 varied angles over a single query — each query gets its own synthesized answer, so varying phrasing and scope gives much broader coverage. When includeContent is true, full page content is fetched in the background. Searches auto-open the interactive browser curator and stream results live; set workflow to "none" to skip curation or "auto-summary" for a model-generated summary without the browser curator. The configured provider is used when provider is omitted or set to auto; omit provider unless explicitly overriding it. Without a configured provider, SearXNG is preferred first for local/private search. When the active Pi model is openai-codex, Codex-backed OpenAI search is preferred next. Otherwise Exa is preferred before OpenAI, then Brave, Parallel, TinyFish, Search1API, Searchinfinity, Querit, Tavily, Firecrawl, Jina, SERPdive, Kagi, Bocha, Ollama, Perplexity, Gemini API, or Gemini Web.`,
|
|
1461
1544
|
promptSnippet: "Use for web research questions. Prefer {queries:[...]} with 2-4 varied angles over a single query for broader coverage. Omit provider unless explicitly overriding the configured default.",
|
|
1462
1545
|
parameters: Type.Object({
|
|
1463
1546
|
query: Type.Optional(Type.String({ description: "Single search query. For research tasks, prefer 'queries' with multiple varied angles instead." })),
|
|
@@ -1466,290 +1549,297 @@ export default function (pi) {
|
|
|
1466
1549
|
includeContent: Type.Optional(Type.Boolean({ description: "Fetch full page content (async)" })),
|
|
1467
1550
|
recencyFilter: Type.Optional(StringEnum(["day", "week", "month", "year"], { description: "Filter by recency" })),
|
|
1468
1551
|
domainFilter: Type.Optional(Type.Array(Type.String(), { description: "Limit to domains (prefix with - to exclude)" })),
|
|
1469
|
-
provider: Type.Optional(searchProviderSchema("Search provider or non-empty list of providers to search simultaneously; use all to search every eligible provider except Parallel MCP, DuckDuckGo, AnySearch, xAI, Bright Data, SerpBase,
|
|
1552
|
+
provider: Type.Optional(searchProviderSchema("Search provider or non-empty list of providers to search simultaneously; use all to search every eligible provider except Parallel MCP, DuckDuckGo, Kimi, AnySearch, XCrawl, Valyu, xAI, Bright Data, SerpBase, and Serper, omit this field to use the configured provider, or use auto when none is configured")),
|
|
1470
1553
|
workflow: Type.Optional(StringEnum(["none", "summary-review", "auto-summary"], {
|
|
1471
1554
|
description: "Search workflow mode: none = no curator, summary-review = open curator with auto summary draft (default), auto-summary = generate summary without opening curator",
|
|
1472
1555
|
})),
|
|
1556
|
+
proxy: Type.Optional(Type.String({
|
|
1557
|
+
description: "http(s) proxy URL (e.g. http://host:port) used for every outbound request in this call (search APIs and content fetches). Node fetch ignores HTTP(S)_PROXY env vars, so set this (or `proxy` in web-search.json) when direct access is blocked; empty string forces direct access.",
|
|
1558
|
+
})),
|
|
1473
1559
|
}),
|
|
1474
1560
|
async execute(callId, params, signal, onUpdate, ctx) {
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1561
|
+
return runWithProxy(typeof params.proxy === "string" ? params.proxy : undefined, async () => {
|
|
1562
|
+
const rawQueryList = Array.isArray(params.queries)
|
|
1563
|
+
? params.queries
|
|
1564
|
+
: (params.query !== undefined ? expandQueryString(params.query) : []);
|
|
1565
|
+
const queryList = normalizeQueryList(rawQueryList);
|
|
1566
|
+
const configWorkflow = loadConfigForExtensionInit().workflow;
|
|
1567
|
+
const workflow = resolveWorkflow(params.workflow ?? configWorkflow, ctx?.hasUI !== false);
|
|
1568
|
+
const shouldCurate = workflow === "summary-review";
|
|
1569
|
+
const recencyFilter = normalizeRecencyFilter(params.recencyFilter);
|
|
1570
|
+
if (queryList.length === 0) {
|
|
1571
|
+
return {
|
|
1572
|
+
content: [{ type: "text", text: "Error: No query provided. Use 'query' or 'queries' parameter." }],
|
|
1573
|
+
details: { error: "No query provided" },
|
|
1574
|
+
};
|
|
1575
|
+
}
|
|
1576
|
+
if (shouldCurate && !ctx) {
|
|
1577
|
+
return {
|
|
1578
|
+
content: [{ type: "text", text: "Error: Curation requires an active extension context." }],
|
|
1579
|
+
details: { error: "Missing extension context" },
|
|
1580
|
+
};
|
|
1581
|
+
}
|
|
1582
|
+
if (shouldCurate) {
|
|
1583
|
+
closeCurator(callId);
|
|
1584
|
+
let resolvePromise = () => { };
|
|
1585
|
+
const promise = new Promise((resolve) => {
|
|
1586
|
+
resolvePromise = resolve;
|
|
1587
|
+
});
|
|
1588
|
+
const includeContent = params.includeContent ?? false;
|
|
1589
|
+
const searchResults = new Map();
|
|
1590
|
+
const resultSlots = new Map();
|
|
1591
|
+
const allInlineContent = [];
|
|
1592
|
+
let nextResultIndex = queryList.length;
|
|
1593
|
+
const searchAbort = new AbortController();
|
|
1594
|
+
const searchSignal = signal
|
|
1595
|
+
? AbortSignal.any([signal, searchAbort.signal])
|
|
1596
|
+
: searchAbort.signal;
|
|
1597
|
+
let cancelled = false;
|
|
1598
|
+
const requestedProvider = resolveRequestedProvider(params.provider);
|
|
1599
|
+
const bootstrap = await loadCuratorBootstrap(requestedProvider, ctx, {
|
|
1600
|
+
numResults: params.numResults,
|
|
1601
|
+
recencyFilter,
|
|
1602
|
+
});
|
|
1603
|
+
const availableProviders = bootstrap.availableProviders;
|
|
1604
|
+
const defaultProvider = bootstrap.defaultProvider;
|
|
1605
|
+
const searchProvider = requestedProvider;
|
|
1606
|
+
const curatorTimeoutSeconds = bootstrap.timeoutSeconds;
|
|
1607
|
+
const curatorWorkflow = "summary-review";
|
|
1608
|
+
const summaryContext = {
|
|
1609
|
+
model: ctx.model,
|
|
1610
|
+
modelRegistry: ctx.modelRegistry,
|
|
1611
|
+
cwd: ctx.cwd,
|
|
1612
|
+
isProjectTrusted: () => ctx.isProjectTrusted(),
|
|
1613
|
+
};
|
|
1614
|
+
const summaryModelChoices = await loadSummaryModelChoices(summaryContext);
|
|
1615
|
+
const pc = {
|
|
1616
|
+
phase: "searching",
|
|
1617
|
+
workflow: curatorWorkflow,
|
|
1618
|
+
summaryContext,
|
|
1619
|
+
searchResults,
|
|
1620
|
+
resultSlots,
|
|
1621
|
+
allInlineContent,
|
|
1622
|
+
queryList,
|
|
1623
|
+
includeContent,
|
|
1624
|
+
numResults: params.numResults,
|
|
1625
|
+
recencyFilter,
|
|
1626
|
+
domainFilter: params.domainFilter,
|
|
1627
|
+
availableProviders,
|
|
1628
|
+
defaultProvider,
|
|
1629
|
+
searchProvider,
|
|
1630
|
+
summaryModels: summaryModelChoices.summaryModels,
|
|
1631
|
+
defaultSummaryModel: summaryModelChoices.defaultSummaryModel,
|
|
1632
|
+
timeoutSeconds: curatorTimeoutSeconds,
|
|
1633
|
+
proxy: typeof params.proxy === "string" ? params.proxy : undefined,
|
|
1634
|
+
onUpdate: onUpdate,
|
|
1635
|
+
signal,
|
|
1636
|
+
abortSearches: () => {
|
|
1637
|
+
if (!searchAbort.signal.aborted)
|
|
1638
|
+
searchAbort.abort();
|
|
1639
|
+
},
|
|
1640
|
+
finish: () => { },
|
|
1641
|
+
cancel: () => { },
|
|
1642
|
+
};
|
|
1643
|
+
const finish = (value) => {
|
|
1644
|
+
if (cancelled)
|
|
1645
|
+
return;
|
|
1646
|
+
cancelled = true;
|
|
1647
|
+
pc.abortSearches();
|
|
1648
|
+
signal?.removeEventListener("abort", onAbort);
|
|
1649
|
+
pendingCurates.delete(callId);
|
|
1650
|
+
resolvePromise(value);
|
|
1651
|
+
};
|
|
1652
|
+
const cancel = (reason = "stale") => {
|
|
1653
|
+
if (cancelled)
|
|
1654
|
+
return;
|
|
1655
|
+
const conn = activeCurators.get(callId)?.getConnectionState();
|
|
1656
|
+
finish(buildCurationCancelledReturn(reason, {
|
|
1657
|
+
queries: Array.from(searchResults.values()),
|
|
1658
|
+
queryCount: queryList.length,
|
|
1659
|
+
browserConnected: conn?.browserConnected,
|
|
1660
|
+
lastHeartbeatAgeMs: conn?.lastHeartbeatAgeMs,
|
|
1661
|
+
curatorUrl: pc.curatorUrl,
|
|
1662
|
+
browserOpenError: pc.browserOpenError,
|
|
1663
|
+
}));
|
|
1664
|
+
};
|
|
1665
|
+
pc.finish = finish;
|
|
1666
|
+
pc.cancel = cancel;
|
|
1667
|
+
const onAbort = () => closeCurator(callId);
|
|
1668
|
+
pendingCurates.set(callId, pc);
|
|
1669
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
1670
|
+
pc.browserPromise = openCuratorBrowser(callId, pc, ctx, false);
|
|
1671
|
+
for (let qi = 0; qi < queryList.length; qi++) {
|
|
1672
|
+
if (signal?.aborted || cancelled || searchAbort.signal.aborted)
|
|
1673
|
+
break;
|
|
1674
|
+
onUpdate?.({
|
|
1675
|
+
content: [{ type: "text", text: `Searching ${qi + 1}/${queryList.length}: "${queryList[qi]}"...` }],
|
|
1676
|
+
details: { phase: "searching", progress: qi / queryList.length, currentQuery: queryList[qi] },
|
|
1677
|
+
});
|
|
1678
|
+
const requestedProvider = pc.searchProvider;
|
|
1679
|
+
try {
|
|
1680
|
+
const response = await search(queryList[qi], {
|
|
1681
|
+
provider: requestedProvider,
|
|
1682
|
+
numResults: params.numResults,
|
|
1683
|
+
recencyFilter,
|
|
1684
|
+
domainFilter: params.domainFilter,
|
|
1685
|
+
includeContent: params.includeContent,
|
|
1686
|
+
signal: searchSignal,
|
|
1687
|
+
extensionContext: ctx,
|
|
1688
|
+
});
|
|
1689
|
+
if (signal?.aborted || cancelled || searchAbort.signal.aborted)
|
|
1690
|
+
break;
|
|
1691
|
+
if (response.inlineContent)
|
|
1692
|
+
allInlineContent.push(...response.inlineContent);
|
|
1693
|
+
const entries = toCuratorSearchEntries(response);
|
|
1694
|
+
const curator = activeCurators.get(callId);
|
|
1695
|
+
for (let entryIndex = 0; entryIndex < entries.length; entryIndex++) {
|
|
1696
|
+
const entry = entries[entryIndex];
|
|
1697
|
+
const resultIndex = entryIndex === 0 ? qi : nextResultIndex++;
|
|
1698
|
+
const indexedEntry = {
|
|
1699
|
+
...entry,
|
|
1700
|
+
queryIndex: resultIndex,
|
|
1701
|
+
query: queryList[qi],
|
|
1702
|
+
};
|
|
1703
|
+
searchResults.set(resultIndex, indexedCuratorEntryToQueryResult(indexedEntry));
|
|
1704
|
+
resultSlots.set(resultIndex, qi);
|
|
1705
|
+
if (curator) {
|
|
1706
|
+
if (entry.error) {
|
|
1707
|
+
curator.pushError(resultIndex, entry.error, entry.provider, { query: queryList[qi], slotIndex: qi });
|
|
1708
|
+
}
|
|
1709
|
+
else {
|
|
1710
|
+
curator.pushResult(resultIndex, { ...entry, query: queryList[qi], slotIndex: qi });
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
catch (err) {
|
|
1716
|
+
if (signal?.aborted || cancelled || searchAbort.signal.aborted)
|
|
1717
|
+
break;
|
|
1718
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1719
|
+
const failedProvider = toCuratorProvider(requestedProvider);
|
|
1720
|
+
searchResults.set(qi, { query: queryList[qi], answer: "", results: [], error: message, provider: failedProvider });
|
|
1721
|
+
resultSlots.set(qi, qi);
|
|
1722
|
+
const curator = activeCurators.get(callId);
|
|
1723
|
+
if (curator) {
|
|
1724
|
+
curator.pushError(qi, message, failedProvider, { query: queryList[qi], slotIndex: qi });
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
if (signal?.aborted || cancelled || searchAbort.signal.aborted) {
|
|
1729
|
+
cancel();
|
|
1730
|
+
return promise;
|
|
1731
|
+
}
|
|
1732
|
+
await pc.browserPromise;
|
|
1733
|
+
const curator = activeCurators.get(callId);
|
|
1734
|
+
if (curator && !cancelled) {
|
|
1735
|
+
curator.searchesDone();
|
|
1736
|
+
if (pc.browserOpenError) {
|
|
1737
|
+
pc.onUpdate?.({
|
|
1738
|
+
content: [{ type: "text", text: `All searches complete. Open the curator manually: ${pc.curatorUrl}` }],
|
|
1739
|
+
details: {
|
|
1740
|
+
phase: "curator-fallback",
|
|
1741
|
+
progress: 1,
|
|
1742
|
+
curatorUrl: pc.curatorUrl,
|
|
1743
|
+
timeoutSeconds: pc.timeoutSeconds,
|
|
1744
|
+
shortcut: curateKey,
|
|
1745
|
+
browserOpenError: pc.browserOpenError,
|
|
1746
|
+
},
|
|
1747
|
+
});
|
|
1748
|
+
}
|
|
1749
|
+
else {
|
|
1750
|
+
pc.onUpdate?.({
|
|
1751
|
+
content: [{ type: "text", text: "All searches complete — waiting for summary approval in browser..." }],
|
|
1752
|
+
details: {
|
|
1753
|
+
phase: "curating",
|
|
1754
|
+
progress: 1,
|
|
1755
|
+
curatorUrl: pc.curatorUrl,
|
|
1756
|
+
timeoutSeconds: pc.timeoutSeconds,
|
|
1757
|
+
shortcut: curateKey,
|
|
1758
|
+
},
|
|
1759
|
+
});
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
return promise;
|
|
1763
|
+
}
|
|
1764
|
+
const searchResults = [];
|
|
1765
|
+
const allUrls = [];
|
|
1504
1766
|
const allInlineContent = [];
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
? AbortSignal.any([signal, searchAbort.signal])
|
|
1509
|
-
: searchAbort.signal;
|
|
1510
|
-
let cancelled = false;
|
|
1511
|
-
const requestedProvider = resolveRequestedProvider(params.provider);
|
|
1512
|
-
const bootstrap = await loadCuratorBootstrap(requestedProvider, ctx, {
|
|
1513
|
-
numResults: params.numResults,
|
|
1514
|
-
recencyFilter,
|
|
1515
|
-
});
|
|
1516
|
-
const availableProviders = bootstrap.availableProviders;
|
|
1517
|
-
const defaultProvider = bootstrap.defaultProvider;
|
|
1518
|
-
const searchProvider = requestedProvider;
|
|
1519
|
-
const curatorTimeoutSeconds = bootstrap.timeoutSeconds;
|
|
1520
|
-
const curatorWorkflow = "summary-review";
|
|
1521
|
-
const summaryContext = {
|
|
1522
|
-
model: ctx.model,
|
|
1523
|
-
modelRegistry: ctx.modelRegistry,
|
|
1524
|
-
cwd: ctx.cwd,
|
|
1525
|
-
isProjectTrusted: () => ctx.isProjectTrusted(),
|
|
1526
|
-
};
|
|
1527
|
-
const summaryModelChoices = await loadSummaryModelChoices(summaryContext);
|
|
1528
|
-
const pc = {
|
|
1529
|
-
phase: "searching",
|
|
1530
|
-
workflow: curatorWorkflow,
|
|
1531
|
-
summaryContext,
|
|
1532
|
-
searchResults,
|
|
1533
|
-
resultSlots,
|
|
1534
|
-
allInlineContent,
|
|
1535
|
-
queryList,
|
|
1536
|
-
includeContent,
|
|
1537
|
-
numResults: params.numResults,
|
|
1538
|
-
recencyFilter,
|
|
1539
|
-
domainFilter: params.domainFilter,
|
|
1540
|
-
availableProviders,
|
|
1541
|
-
defaultProvider,
|
|
1542
|
-
searchProvider,
|
|
1543
|
-
summaryModels: summaryModelChoices.summaryModels,
|
|
1544
|
-
defaultSummaryModel: summaryModelChoices.defaultSummaryModel,
|
|
1545
|
-
timeoutSeconds: curatorTimeoutSeconds,
|
|
1546
|
-
onUpdate: onUpdate,
|
|
1547
|
-
signal,
|
|
1548
|
-
abortSearches: () => {
|
|
1549
|
-
if (!searchAbort.signal.aborted)
|
|
1550
|
-
searchAbort.abort();
|
|
1551
|
-
},
|
|
1552
|
-
finish: () => { },
|
|
1553
|
-
cancel: () => { },
|
|
1554
|
-
};
|
|
1555
|
-
const finish = (value) => {
|
|
1556
|
-
if (cancelled)
|
|
1557
|
-
return;
|
|
1558
|
-
cancelled = true;
|
|
1559
|
-
pc.abortSearches();
|
|
1560
|
-
signal?.removeEventListener("abort", onAbort);
|
|
1561
|
-
pendingCurates.delete(callId);
|
|
1562
|
-
resolvePromise(value);
|
|
1563
|
-
};
|
|
1564
|
-
const cancel = (reason = "stale") => {
|
|
1565
|
-
if (cancelled)
|
|
1566
|
-
return;
|
|
1567
|
-
const conn = activeCurators.get(callId)?.getConnectionState();
|
|
1568
|
-
finish(buildCurationCancelledReturn(reason, {
|
|
1569
|
-
queries: Array.from(searchResults.values()),
|
|
1570
|
-
queryCount: queryList.length,
|
|
1571
|
-
browserConnected: conn?.browserConnected,
|
|
1572
|
-
lastHeartbeatAgeMs: conn?.lastHeartbeatAgeMs,
|
|
1573
|
-
curatorUrl: pc.curatorUrl,
|
|
1574
|
-
browserOpenError: pc.browserOpenError,
|
|
1575
|
-
}));
|
|
1576
|
-
};
|
|
1577
|
-
pc.finish = finish;
|
|
1578
|
-
pc.cancel = cancel;
|
|
1579
|
-
const onAbort = () => closeCurator(callId);
|
|
1580
|
-
pendingCurates.set(callId, pc);
|
|
1581
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
1582
|
-
pc.browserPromise = openCuratorBrowser(callId, pc, ctx, false);
|
|
1583
|
-
for (let qi = 0; qi < queryList.length; qi++) {
|
|
1584
|
-
if (signal?.aborted || cancelled || searchAbort.signal.aborted)
|
|
1585
|
-
break;
|
|
1767
|
+
const resolvedProvider = resolveRequestedProvider(params.provider);
|
|
1768
|
+
for (let i = 0; i < queryList.length; i++) {
|
|
1769
|
+
const query = queryList[i];
|
|
1586
1770
|
onUpdate?.({
|
|
1587
|
-
content: [{ type: "text", text: `Searching ${
|
|
1588
|
-
details: { phase: "
|
|
1771
|
+
content: [{ type: "text", text: `Searching ${i + 1}/${queryList.length}: "${query}"...` }],
|
|
1772
|
+
details: { phase: "search", progress: i / queryList.length, currentQuery: query },
|
|
1589
1773
|
});
|
|
1590
|
-
const requestedProvider = pc.searchProvider;
|
|
1591
1774
|
try {
|
|
1592
|
-
const
|
|
1593
|
-
provider:
|
|
1775
|
+
const { answer, results, inlineContent, provider } = await search(query, {
|
|
1776
|
+
provider: resolvedProvider,
|
|
1594
1777
|
numResults: params.numResults,
|
|
1595
1778
|
recencyFilter,
|
|
1596
1779
|
domainFilter: params.domainFilter,
|
|
1597
1780
|
includeContent: params.includeContent,
|
|
1598
|
-
signal
|
|
1781
|
+
signal,
|
|
1599
1782
|
extensionContext: ctx,
|
|
1600
1783
|
});
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
const entries = toCuratorSearchEntries(response);
|
|
1606
|
-
const curator = activeCurators.get(callId);
|
|
1607
|
-
for (let entryIndex = 0; entryIndex < entries.length; entryIndex++) {
|
|
1608
|
-
const entry = entries[entryIndex];
|
|
1609
|
-
const resultIndex = entryIndex === 0 ? qi : nextResultIndex++;
|
|
1610
|
-
const indexedEntry = {
|
|
1611
|
-
...entry,
|
|
1612
|
-
queryIndex: resultIndex,
|
|
1613
|
-
query: queryList[qi],
|
|
1614
|
-
};
|
|
1615
|
-
searchResults.set(resultIndex, indexedCuratorEntryToQueryResult(indexedEntry));
|
|
1616
|
-
resultSlots.set(resultIndex, qi);
|
|
1617
|
-
if (curator) {
|
|
1618
|
-
if (entry.error) {
|
|
1619
|
-
curator.pushError(resultIndex, entry.error, entry.provider, { query: queryList[qi], slotIndex: qi });
|
|
1620
|
-
}
|
|
1621
|
-
else {
|
|
1622
|
-
curator.pushResult(resultIndex, { ...entry, query: queryList[qi], slotIndex: qi });
|
|
1623
|
-
}
|
|
1784
|
+
searchResults.push({ query, answer, results, error: null, provider });
|
|
1785
|
+
for (const r of results) {
|
|
1786
|
+
if (!allUrls.includes(r.url)) {
|
|
1787
|
+
allUrls.push(r.url);
|
|
1624
1788
|
}
|
|
1625
1789
|
}
|
|
1790
|
+
if (inlineContent)
|
|
1791
|
+
allInlineContent.push(...inlineContent);
|
|
1626
1792
|
}
|
|
1627
1793
|
catch (err) {
|
|
1628
|
-
if (signal?.aborted ||
|
|
1629
|
-
|
|
1794
|
+
if (signal?.aborted || isAbortError(err))
|
|
1795
|
+
throw err;
|
|
1630
1796
|
const message = err instanceof Error ? err.message : String(err);
|
|
1631
|
-
const
|
|
1632
|
-
searchResults.
|
|
1633
|
-
resultSlots.set(qi, qi);
|
|
1634
|
-
const curator = activeCurators.get(callId);
|
|
1635
|
-
if (curator) {
|
|
1636
|
-
curator.pushError(qi, message, failedProvider, { query: queryList[qi], slotIndex: qi });
|
|
1637
|
-
}
|
|
1797
|
+
const requestedProvider = toCuratorProvider(resolvedProvider);
|
|
1798
|
+
searchResults.push({ query, answer: "", results: [], error: message, provider: requestedProvider });
|
|
1638
1799
|
}
|
|
1639
1800
|
}
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
if (pc.browserOpenError) {
|
|
1649
|
-
pc.onUpdate?.({
|
|
1650
|
-
content: [{ type: "text", text: `All searches complete. Open the curator manually: ${pc.curatorUrl}` }],
|
|
1651
|
-
details: {
|
|
1652
|
-
phase: "curator-fallback",
|
|
1653
|
-
progress: 1,
|
|
1654
|
-
curatorUrl: pc.curatorUrl,
|
|
1655
|
-
timeoutSeconds: pc.timeoutSeconds,
|
|
1656
|
-
shortcut: curateKey,
|
|
1657
|
-
browserOpenError: pc.browserOpenError,
|
|
1658
|
-
},
|
|
1659
|
-
});
|
|
1660
|
-
}
|
|
1661
|
-
else {
|
|
1662
|
-
pc.onUpdate?.({
|
|
1663
|
-
content: [{ type: "text", text: "All searches complete — waiting for summary approval in browser..." }],
|
|
1664
|
-
details: {
|
|
1665
|
-
phase: "curating",
|
|
1666
|
-
progress: 1,
|
|
1667
|
-
curatorUrl: pc.curatorUrl,
|
|
1668
|
-
timeoutSeconds: pc.timeoutSeconds,
|
|
1669
|
-
shortcut: curateKey,
|
|
1670
|
-
},
|
|
1671
|
-
});
|
|
1801
|
+
let approvedSummary;
|
|
1802
|
+
let summaryMeta;
|
|
1803
|
+
if (workflow === "auto-summary") {
|
|
1804
|
+
if (!ctx) {
|
|
1805
|
+
return {
|
|
1806
|
+
content: [{ type: "text", text: "Error: Auto-summary requires an active extension context." }],
|
|
1807
|
+
details: { error: "Missing extension context" },
|
|
1808
|
+
};
|
|
1672
1809
|
}
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
const searchResults = [];
|
|
1677
|
-
const allUrls = [];
|
|
1678
|
-
const allInlineContent = [];
|
|
1679
|
-
const resolvedProvider = resolveRequestedProvider(params.provider);
|
|
1680
|
-
for (let i = 0; i < queryList.length; i++) {
|
|
1681
|
-
const query = queryList[i];
|
|
1682
|
-
onUpdate?.({
|
|
1683
|
-
content: [{ type: "text", text: `Searching ${i + 1}/${queryList.length}: "${query}"...` }],
|
|
1684
|
-
details: { phase: "search", progress: i / queryList.length, currentQuery: query },
|
|
1685
|
-
});
|
|
1686
|
-
try {
|
|
1687
|
-
const { answer, results, inlineContent, provider } = await search(query, {
|
|
1688
|
-
provider: resolvedProvider,
|
|
1689
|
-
numResults: params.numResults,
|
|
1690
|
-
recencyFilter,
|
|
1691
|
-
domainFilter: params.domainFilter,
|
|
1692
|
-
includeContent: params.includeContent,
|
|
1693
|
-
signal,
|
|
1694
|
-
extensionContext: ctx,
|
|
1810
|
+
onUpdate?.({
|
|
1811
|
+
content: [{ type: "text", text: "Generating summary..." }],
|
|
1812
|
+
details: { phase: "generating-summary", progress: 1 },
|
|
1695
1813
|
});
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
}
|
|
1702
|
-
if (inlineContent)
|
|
1703
|
-
allInlineContent.push(...inlineContent);
|
|
1704
|
-
}
|
|
1705
|
-
catch (err) {
|
|
1706
|
-
if (signal?.aborted || isAbortError(err))
|
|
1707
|
-
throw err;
|
|
1708
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
1709
|
-
const requestedProvider = toCuratorProvider(resolvedProvider);
|
|
1710
|
-
searchResults.push({ query, answer: "", results: [], error: message, provider: requestedProvider });
|
|
1711
|
-
}
|
|
1712
|
-
}
|
|
1713
|
-
let approvedSummary;
|
|
1714
|
-
let summaryMeta;
|
|
1715
|
-
if (workflow === "auto-summary") {
|
|
1716
|
-
if (!ctx) {
|
|
1717
|
-
return {
|
|
1718
|
-
content: [{ type: "text", text: "Error: Auto-summary requires an active extension context." }],
|
|
1719
|
-
details: { error: "Missing extension context" },
|
|
1814
|
+
const summaryContext = {
|
|
1815
|
+
model: ctx.model,
|
|
1816
|
+
modelRegistry: ctx.modelRegistry,
|
|
1817
|
+
cwd: ctx.cwd,
|
|
1818
|
+
isProjectTrusted: () => ctx.isProjectTrusted(),
|
|
1720
1819
|
};
|
|
1820
|
+
const summaryModelChoices = await loadSummaryModelChoices(summaryContext);
|
|
1821
|
+
const generated = await generateSummaryDraft(searchResults, summaryContext, signal, summaryModelChoices.defaultSummaryModel ?? undefined, undefined, undefined, getSummaryGenerationDeadlineMs());
|
|
1822
|
+
approvedSummary = generated.summary;
|
|
1823
|
+
summaryMeta = generated.meta;
|
|
1721
1824
|
}
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1825
|
+
return buildSearchReturn({
|
|
1826
|
+
queryList,
|
|
1827
|
+
results: searchResults,
|
|
1828
|
+
urls: allUrls,
|
|
1829
|
+
includeContent: params.includeContent ?? false,
|
|
1830
|
+
inlineContent: allInlineContent.length > 0 ? allInlineContent : undefined,
|
|
1831
|
+
workflow: workflow === "auto-summary" ? "auto-summary" : undefined,
|
|
1832
|
+
approvedSummary,
|
|
1833
|
+
summaryMeta,
|
|
1834
|
+
proxy: typeof params.proxy === "string" ? params.proxy : undefined,
|
|
1725
1835
|
});
|
|
1726
|
-
const summaryContext = {
|
|
1727
|
-
model: ctx.model,
|
|
1728
|
-
modelRegistry: ctx.modelRegistry,
|
|
1729
|
-
cwd: ctx.cwd,
|
|
1730
|
-
isProjectTrusted: () => ctx.isProjectTrusted(),
|
|
1731
|
-
};
|
|
1732
|
-
const summaryModelChoices = await loadSummaryModelChoices(summaryContext);
|
|
1733
|
-
const generated = await generateSummaryDraft(searchResults, summaryContext, signal, summaryModelChoices.defaultSummaryModel ?? undefined, undefined, undefined, getSummaryGenerationDeadlineMs());
|
|
1734
|
-
approvedSummary = generated.summary;
|
|
1735
|
-
summaryMeta = generated.meta;
|
|
1736
|
-
}
|
|
1737
|
-
return buildSearchReturn({
|
|
1738
|
-
queryList,
|
|
1739
|
-
results: searchResults,
|
|
1740
|
-
urls: allUrls,
|
|
1741
|
-
includeContent: params.includeContent ?? false,
|
|
1742
|
-
inlineContent: allInlineContent.length > 0 ? allInlineContent : undefined,
|
|
1743
|
-
workflow: workflow === "auto-summary" ? "auto-summary" : undefined,
|
|
1744
|
-
approvedSummary,
|
|
1745
|
-
summaryMeta,
|
|
1746
1836
|
});
|
|
1747
1837
|
},
|
|
1748
1838
|
renderCall(args, theme) {
|
|
1749
1839
|
const input = args;
|
|
1750
1840
|
const rawQueryList = Array.isArray(input.queries)
|
|
1751
1841
|
? input.queries
|
|
1752
|
-
: (input.query !== undefined ?
|
|
1842
|
+
: (input.query !== undefined ? expandQueryString(input.query) : []);
|
|
1753
1843
|
const queryList = normalizeQueryList(rawQueryList);
|
|
1754
1844
|
if (queryList.length === 0) {
|
|
1755
1845
|
return new Text(theme.fg("toolTitle", theme.bold("search ")) + theme.fg("error", "(no query)"), 0, 0);
|
|
@@ -1969,91 +2059,96 @@ export default function (pi) {
|
|
|
1969
2059
|
fetchContent: Type.Optional(Type.Boolean({ description: "Fetch up to 5 result pages for exact passage extraction." })),
|
|
1970
2060
|
recencyFilter: Type.Optional(StringEnum(["day", "week", "month", "year"], { description: "Filter by recency." })),
|
|
1971
2061
|
domainFilter: Type.Optional(Type.Array(Type.String(), { description: "Limit to domains; prefix with - to exclude." })),
|
|
1972
|
-
provider: Type.Optional(searchProviderSchema("Search provider or non-empty list of providers to search simultaneously; all searches every eligible provider except DuckDuckGo, AnySearch, xAI, Bright Data, SerpBase,
|
|
2062
|
+
provider: Type.Optional(searchProviderSchema("Search provider or non-empty list of providers to search simultaneously; all searches every eligible provider except Parallel MCP, DuckDuckGo, Kimi, AnySearch, XCrawl, Valyu, xAI, Bright Data, SerpBase, and Serper")),
|
|
2063
|
+
proxy: Type.Optional(Type.String({
|
|
2064
|
+
description: "http(s) proxy URL (e.g. http://host:port) used for every outbound request in this call (search APIs and result-page fetches). Empty string forces direct access.",
|
|
2065
|
+
})),
|
|
1973
2066
|
}),
|
|
1974
2067
|
async execute(_callId, params, signal, _onUpdate, ctx) {
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
break;
|
|
1997
|
-
try {
|
|
1998
|
-
const response = await search(query, {
|
|
1999
|
-
provider: resolveRequestedProvider(params.provider),
|
|
2000
|
-
numResults,
|
|
2001
|
-
recencyFilter,
|
|
2002
|
-
domainFilter,
|
|
2003
|
-
signal,
|
|
2004
|
-
extensionContext: ctx,
|
|
2005
|
-
});
|
|
2068
|
+
return runWithProxy(typeof params.proxy === "string" ? params.proxy : undefined, async () => {
|
|
2069
|
+
const claim = typeof params.claim === "string" ? params.claim.trim() : "";
|
|
2070
|
+
if (!claim) {
|
|
2071
|
+
return { content: [{ type: "text", text: "Error: 'claim' is required." }], details: { error: "Missing claim" } };
|
|
2072
|
+
}
|
|
2073
|
+
const requestedQueries = Array.isArray(params.queries)
|
|
2074
|
+
? params.queries.filter((query) => typeof query === "string").map((query) => query.trim()).filter(Boolean)
|
|
2075
|
+
: [];
|
|
2076
|
+
const queries = (requestedQueries.length > 0 ? requestedQueries : [claim]).slice(0, 8);
|
|
2077
|
+
const numResults = typeof params.numResults === "number" && Number.isFinite(params.numResults)
|
|
2078
|
+
? Math.min(20, Math.max(1, Math.floor(params.numResults)))
|
|
2079
|
+
: 5;
|
|
2080
|
+
const domainFilter = Array.isArray(params.domainFilter)
|
|
2081
|
+
? params.domainFilter.filter((domain) => typeof domain === "string")
|
|
2082
|
+
: undefined;
|
|
2083
|
+
const recencyFilter = normalizeRecencyFilter(params.recencyFilter);
|
|
2084
|
+
const resultsByUrl = new Map();
|
|
2085
|
+
const summaries = [];
|
|
2086
|
+
const errors = [];
|
|
2087
|
+
let provider;
|
|
2088
|
+
for (const query of queries) {
|
|
2006
2089
|
if (signal?.aborted)
|
|
2007
2090
|
break;
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2091
|
+
try {
|
|
2092
|
+
const response = await search(query, {
|
|
2093
|
+
provider: resolveRequestedProvider(params.provider),
|
|
2094
|
+
numResults,
|
|
2095
|
+
recencyFilter,
|
|
2096
|
+
domainFilter,
|
|
2097
|
+
signal,
|
|
2098
|
+
extensionContext: ctx,
|
|
2099
|
+
});
|
|
2100
|
+
if (signal?.aborted)
|
|
2101
|
+
break;
|
|
2102
|
+
provider ??= response.provider;
|
|
2103
|
+
if (response.answer)
|
|
2104
|
+
summaries.push(`${query}: ${response.answer}`);
|
|
2105
|
+
for (const result of response.results) {
|
|
2106
|
+
if (!resultsByUrl.has(result.url))
|
|
2107
|
+
resultsByUrl.set(result.url, result);
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
catch (err) {
|
|
2111
|
+
if (signal?.aborted || isAbortError(err))
|
|
2112
|
+
break;
|
|
2113
|
+
errors.push({ query, error: err instanceof Error ? err.message : String(err) });
|
|
2014
2114
|
}
|
|
2015
2115
|
}
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2116
|
+
const results = [...resultsByUrl.values()].slice(0, 20).map((result, index) => ({ ...result, rank: index + 1 }));
|
|
2117
|
+
let fetched = [];
|
|
2118
|
+
if (params.fetchContent && results.length > 0) {
|
|
2119
|
+
const urls = results.slice(0, 5).map((result) => result.url);
|
|
2120
|
+
try {
|
|
2121
|
+
fetched = await fetchAllContent(urls, signal, withRegisteredFetchOptions(undefined, registeredToolNames, typeof params.proxy === "string" ? params.proxy : undefined));
|
|
2122
|
+
}
|
|
2123
|
+
catch (err) {
|
|
2124
|
+
if (signal?.aborted || isAbortError(err))
|
|
2125
|
+
throw err;
|
|
2126
|
+
fetched = urls.map((url) => ({ url, title: "", content: "", error: err instanceof Error ? err.message : String(err) }));
|
|
2127
|
+
}
|
|
2028
2128
|
}
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
artifact,
|
|
2129
|
+
const artifact = withClaimAssessment(buildResearchArtifact({
|
|
2130
|
+
query: claim,
|
|
2131
|
+
provider,
|
|
2132
|
+
summary: summaries.length > 0 ? summaries.join("\n\n") : undefined,
|
|
2133
|
+
results,
|
|
2134
|
+
fetched,
|
|
2135
|
+
recency: recencyFilter,
|
|
2136
|
+
domainFilter,
|
|
2137
|
+
}), [claim]);
|
|
2138
|
+
if (errors.length > 0)
|
|
2139
|
+
artifact.errors = errors;
|
|
2140
|
+
storeResearchArtifact(artifact);
|
|
2141
|
+
pi.appendEntry("web-search-results", {
|
|
2142
|
+
id: artifact.id,
|
|
2143
|
+
type: "research",
|
|
2144
|
+
timestamp: artifact.timestamp,
|
|
2145
|
+
artifact,
|
|
2146
|
+
});
|
|
2147
|
+
return {
|
|
2148
|
+
content: [{ type: "text", text: formatSourceCheckResult(artifact, getSearchContentEnabled ? toolNames.getSearchContent : null) }],
|
|
2149
|
+
details: { responseId: artifact.id, artifact, sourceCount: artifact.sources.length, passageCount: artifact.passages.length },
|
|
2150
|
+
};
|
|
2052
2151
|
});
|
|
2053
|
-
return {
|
|
2054
|
-
content: [{ type: "text", text: formatSourceCheckResult(artifact, getSearchContentEnabled ? toolNames.getSearchContent : null) }],
|
|
2055
|
-
details: { responseId: artifact.id, artifact, sourceCount: artifact.sources.length, passageCount: artifact.passages.length },
|
|
2056
|
-
};
|
|
2057
2152
|
},
|
|
2058
2153
|
});
|
|
2059
2154
|
if (fetchContentEnabled)
|
|
@@ -2075,7 +2170,7 @@ export default function (pi) {
|
|
|
2075
2170
|
description: "Fetch mode: readable (default extraction), raw (exact textual HTTP body), or answer (answer prompt using only fetched content).",
|
|
2076
2171
|
})),
|
|
2077
2172
|
answerModel: Type.Optional(Type.String({
|
|
2078
|
-
description: "Optional provider/model-id override for mode answer. Defaults to the current Pi model.",
|
|
2173
|
+
description: "Optional provider/model-id override for mode answer. Defaults to fetch.answerProvider + fetch.answerModel when configured, otherwise the current Pi model.",
|
|
2079
2174
|
})),
|
|
2080
2175
|
timestamp: Type.Optional(Type.String({
|
|
2081
2176
|
description: "Extract video frame(s) at a timestamp or time range. Single: '1:23:45', '23:45', or '85' (seconds). Range: '23:41-25:00' extracts evenly-spaced frames across that span (default 6). Use frames with ranges to control density; single+frames uses a fixed 5s interval. YouTube requires yt-dlp + ffmpeg; local videos require ffmpeg. Use a range when you know the approximate area but not the exact moment — you'll get a contact sheet to visually identify the right frame.",
|
|
@@ -2091,6 +2186,9 @@ export default function (pi) {
|
|
|
2091
2186
|
auth: Type.Optional(Type.Union([Type.String(), Type.Boolean()], {
|
|
2092
2187
|
description: "Opt into an authFetch profile for local browser-cookie fetching. Use a profile name, or true only when exactly one profile exists.",
|
|
2093
2188
|
})),
|
|
2189
|
+
proxy: Type.Optional(Type.String({
|
|
2190
|
+
description: "http(s) proxy URL (e.g. http://host:port) used for this fetch. Needed when the target is unreachable directly; localhost and NO_PROXY hosts always bypass the proxy. Empty string forces direct access.",
|
|
2191
|
+
})),
|
|
2094
2192
|
}),
|
|
2095
2193
|
async execute(_toolCallId, params, signal, onUpdate, ctx) {
|
|
2096
2194
|
let normalized;
|
|
@@ -2102,159 +2200,159 @@ export default function (pi) {
|
|
|
2102
2200
|
return { content: [{ type: "text", text: `Error: ${error}` }], details: { error } };
|
|
2103
2201
|
}
|
|
2104
2202
|
const { urlList, options } = normalized;
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
if (mode === "raw" && (options.forceClone === true || options.timestamp || options.frames || options.prompt || options.model || options.answerModel)) {
|
|
2110
|
-
return { content: [{ type: "text", text: "Error: mode raw cannot be combined with forceClone, prompt, timestamp, frames, model, or answerModel." }], details: { error: "Incompatible raw mode options" } };
|
|
2111
|
-
}
|
|
2112
|
-
if (mode !== "answer" && options.answerModel) {
|
|
2113
|
-
return { content: [{ type: "text", text: "Error: answerModel requires mode answer." }], details: { error: "answerModel requires mode answer" } };
|
|
2114
|
-
}
|
|
2115
|
-
if (mode === "answer" && options.model) {
|
|
2116
|
-
return { content: [{ type: "text", text: "Error: use answerModel, not model, with mode answer." }], details: { error: "model is incompatible with mode answer" } };
|
|
2117
|
-
}
|
|
2118
|
-
if (mode === "answer" && options.auth !== undefined) {
|
|
2119
|
-
return { content: [{ type: "text", text: "Error: auth cannot be combined with mode answer." }], details: { error: "auth cannot be combined with mode answer" } };
|
|
2120
|
-
}
|
|
2121
|
-
let authFetchProfile;
|
|
2122
|
-
if (options.auth !== undefined) {
|
|
2123
|
-
try {
|
|
2124
|
-
authFetchProfile = resolveAuthFetchProfile(options.auth);
|
|
2203
|
+
return runWithProxy(options.proxy, async () => {
|
|
2204
|
+
const mode = options.mode ?? "readable";
|
|
2205
|
+
if (mode === "answer" && !options.prompt) {
|
|
2206
|
+
return { content: [{ type: "text", text: "Error: mode answer requires prompt." }], details: { error: "mode answer requires prompt" } };
|
|
2125
2207
|
}
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
return { content: [{ type: "text", text: `Error: ${error}` }], details: { error } };
|
|
2208
|
+
if (mode === "raw" && (options.forceClone === true || options.timestamp || options.frames || options.prompt || options.model || options.answerModel)) {
|
|
2209
|
+
return { content: [{ type: "text", text: "Error: mode raw cannot be combined with forceClone, prompt, timestamp, frames, model, or answerModel." }], details: { error: "Incompatible raw mode options" } };
|
|
2129
2210
|
}
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
details: { error: "
|
|
2135
|
-
}
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
const { answerModel: _answerModel, auth: _auth, ...extractionOptions } = options;
|
|
2142
|
-
const fetchOptions = mode === "answer"
|
|
2143
|
-
? (() => {
|
|
2144
|
-
const { prompt: _prompt, ...rest } = extractionOptions;
|
|
2145
|
-
return { ...rest, ...(authFetchProfile ? { authFetchProfile } : {}) };
|
|
2146
|
-
})()
|
|
2147
|
-
: { ...extractionOptions, ...(authFetchProfile ? { authFetchProfile } : {}) };
|
|
2148
|
-
const fetchResults = await fetchAllContent(urlList, signal, fetchOptions);
|
|
2149
|
-
const presentedResults = mode === "answer"
|
|
2150
|
-
? await Promise.all(fetchResults.map(async (result) => {
|
|
2151
|
-
if (result.error)
|
|
2152
|
-
return result;
|
|
2153
|
-
if (result.thumbnail || result.mimeType?.startsWith("image/")) {
|
|
2154
|
-
return { ...result, error: "Page answer requires textual fetched content" };
|
|
2155
|
-
}
|
|
2211
|
+
if (mode !== "answer" && options.answerModel) {
|
|
2212
|
+
return { content: [{ type: "text", text: "Error: answerModel requires mode answer." }], details: { error: "answerModel requires mode answer" } };
|
|
2213
|
+
}
|
|
2214
|
+
if (mode === "answer" && options.model) {
|
|
2215
|
+
return { content: [{ type: "text", text: "Error: use answerModel, not model, with mode answer." }], details: { error: "model is incompatible with mode answer" } };
|
|
2216
|
+
}
|
|
2217
|
+
if (mode === "answer" && options.auth !== undefined) {
|
|
2218
|
+
return { content: [{ type: "text", text: "Error: auth cannot be combined with mode answer." }], details: { error: "auth cannot be combined with mode answer" } };
|
|
2219
|
+
}
|
|
2220
|
+
let authFetchProfile;
|
|
2221
|
+
if (options.auth !== undefined) {
|
|
2156
2222
|
try {
|
|
2157
|
-
|
|
2158
|
-
question: options.prompt,
|
|
2159
|
-
pageText: result.content,
|
|
2160
|
-
sourceUrl: result.url,
|
|
2161
|
-
...(options.answerModel ? { model: options.answerModel } : {}),
|
|
2162
|
-
}, ctx, signal);
|
|
2163
|
-
return { ...result, content: answer.text };
|
|
2223
|
+
authFetchProfile = resolveAuthFetchProfile(options.auth);
|
|
2164
2224
|
}
|
|
2165
2225
|
catch (err) {
|
|
2166
|
-
|
|
2226
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
2227
|
+
return { content: [{ type: "text", text: `Error: ${error}` }], details: { error } };
|
|
2167
2228
|
}
|
|
2168
|
-
}
|
|
2169
|
-
|
|
2170
|
-
const successful = presentedResults.filter((r) => !r.error).length;
|
|
2171
|
-
const totalChars = presentedResults.reduce((sum, r) => sum + r.content.length, 0);
|
|
2172
|
-
const responseId = generateId();
|
|
2173
|
-
const data = {
|
|
2174
|
-
id: responseId,
|
|
2175
|
-
type: "fetch",
|
|
2176
|
-
timestamp: Date.now(),
|
|
2177
|
-
urls: stripThumbnails(fetchResults),
|
|
2178
|
-
};
|
|
2179
|
-
const storedContent = storeFetchResult(pi, responseId, data, authFetchProfile);
|
|
2180
|
-
// Single URL: return content directly (possibly truncated) with responseId
|
|
2181
|
-
if (urlList.length === 1) {
|
|
2182
|
-
const result = presentedResults[0];
|
|
2183
|
-
if (result.error) {
|
|
2229
|
+
}
|
|
2230
|
+
if (urlList.length === 0) {
|
|
2184
2231
|
return {
|
|
2185
|
-
content: [{ type: "text", text:
|
|
2186
|
-
details: {
|
|
2232
|
+
content: [{ type: "text", text: "Error: No URL provided." }],
|
|
2233
|
+
details: { error: "No URL provided" },
|
|
2187
2234
|
};
|
|
2188
2235
|
}
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
const
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2236
|
+
onUpdate?.({
|
|
2237
|
+
content: [{ type: "text", text: `Fetching ${urlList.length} URL(s)...` }],
|
|
2238
|
+
details: { phase: "fetch", progress: 0 },
|
|
2239
|
+
});
|
|
2240
|
+
const { answerModel: _answerModel, auth: _auth, ...extractionOptions } = options;
|
|
2241
|
+
const fetchOptions = mode === "answer"
|
|
2242
|
+
? (() => {
|
|
2243
|
+
const { prompt: _prompt, ...rest } = extractionOptions;
|
|
2244
|
+
return { ...rest, ...(authFetchProfile ? { authFetchProfile } : {}) };
|
|
2245
|
+
})()
|
|
2246
|
+
: { ...extractionOptions, ...(authFetchProfile ? { authFetchProfile } : {}) };
|
|
2247
|
+
const fetchResults = await fetchAllContent(urlList, signal, withRegisteredFetchOptions(fetchOptions, registeredToolNames, options.proxy));
|
|
2248
|
+
const presentedResults = mode === "answer"
|
|
2249
|
+
? await Promise.all(fetchResults.map(async (result) => {
|
|
2250
|
+
if (result.error)
|
|
2251
|
+
return result;
|
|
2252
|
+
if (result.thumbnail || result.mimeType?.startsWith("image/")) {
|
|
2253
|
+
return { ...result, error: "Page answer requires textual fetched content" };
|
|
2254
|
+
}
|
|
2255
|
+
try {
|
|
2256
|
+
const answer = await answerFromPage({
|
|
2257
|
+
question: options.prompt,
|
|
2258
|
+
pageText: result.content,
|
|
2259
|
+
sourceUrl: result.url,
|
|
2260
|
+
...(options.answerModel ? { model: options.answerModel } : {}),
|
|
2261
|
+
}, ctx, signal);
|
|
2262
|
+
return { ...result, content: answer.text };
|
|
2263
|
+
}
|
|
2264
|
+
catch (err) {
|
|
2265
|
+
return { ...result, error: `Page answer failed: ${err instanceof Error ? err.message : String(err)}` };
|
|
2266
|
+
}
|
|
2267
|
+
}))
|
|
2268
|
+
: fetchResults;
|
|
2269
|
+
const successful = presentedResults.filter((r) => !r.error).length;
|
|
2270
|
+
const totalChars = presentedResults.reduce((sum, r) => sum + r.content.length, 0);
|
|
2271
|
+
const responseId = generateId();
|
|
2272
|
+
const data = {
|
|
2273
|
+
id: responseId,
|
|
2274
|
+
type: "fetch",
|
|
2275
|
+
timestamp: Date.now(),
|
|
2276
|
+
urls: stripThumbnails(fetchResults),
|
|
2277
|
+
};
|
|
2278
|
+
const storedContent = storeFetchResult(pi, responseId, data, authFetchProfile);
|
|
2279
|
+
if (urlList.length === 1) {
|
|
2280
|
+
const result = presentedResults[0];
|
|
2281
|
+
if (result.error) {
|
|
2282
|
+
return {
|
|
2283
|
+
content: [{ type: "text", text: `Error: ${result.error}` }],
|
|
2284
|
+
details: { urls: urlList, urlCount: 1, successful: 0, error: result.error, ...(storedContent ? { responseId } : {}), prompt: params.prompt, timestamp: params.timestamp, frames: params.frames },
|
|
2285
|
+
};
|
|
2286
|
+
}
|
|
2287
|
+
const fullLength = result.content.length;
|
|
2288
|
+
const slice = initialContentSlice(result.content, getMaxInlineContentChars());
|
|
2289
|
+
const truncated = slice.endOffset < fullLength;
|
|
2290
|
+
let output = slice.text;
|
|
2291
|
+
if (truncated) {
|
|
2292
|
+
output += `\n\n---\nShowing ${slice.endOffset} of ${fullLength} chars, ${slice.shownBytes} of ${slice.totalBytes} bytes, and ${slice.shownLines} of ${slice.totalLines} lines. `;
|
|
2293
|
+
output += storedContent
|
|
2294
|
+
? getSearchContentEnabled
|
|
2295
|
+
? `Use ${toolNames.getSearchContent}({ responseId: "${responseId}", urlIndex: 0, offset: ${slice.endOffset} }) for the next slice.`
|
|
2296
|
+
: "Content retrieval is not registered."
|
|
2297
|
+
: "Authenticated fetch cache is off; repeat the fetch to read more.";
|
|
2206
2298
|
}
|
|
2299
|
+
const content = [];
|
|
2300
|
+
if (result.frames?.length) {
|
|
2301
|
+
for (const frame of result.frames) {
|
|
2302
|
+
content.push({ type: "image", data: frame.data, mimeType: frame.mimeType });
|
|
2303
|
+
content.push({ type: "text", text: `Frame at ${frame.timestamp}` });
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2306
|
+
else if (result.thumbnail) {
|
|
2307
|
+
content.push({ type: "image", data: result.thumbnail.data, mimeType: result.thumbnail.mimeType });
|
|
2308
|
+
}
|
|
2309
|
+
content.push({ type: "text", text: output });
|
|
2310
|
+
const imageCount = (result.frames?.length ?? 0) + (result.thumbnail ? 1 : 0);
|
|
2311
|
+
return {
|
|
2312
|
+
content,
|
|
2313
|
+
details: {
|
|
2314
|
+
urls: urlList,
|
|
2315
|
+
urlCount: 1,
|
|
2316
|
+
successful: 1,
|
|
2317
|
+
totalChars: fullLength,
|
|
2318
|
+
title: result.title,
|
|
2319
|
+
...(storedContent ? { responseId } : {}),
|
|
2320
|
+
truncated,
|
|
2321
|
+
hasImage: imageCount > 0,
|
|
2322
|
+
imageCount,
|
|
2323
|
+
prompt: params.prompt,
|
|
2324
|
+
timestamp: params.timestamp,
|
|
2325
|
+
frames: params.frames,
|
|
2326
|
+
duration: result.duration,
|
|
2327
|
+
mode,
|
|
2328
|
+
mimeType: result.mimeType,
|
|
2329
|
+
status: result.status,
|
|
2330
|
+
totalBytes: slice.totalBytes,
|
|
2331
|
+
totalLines: slice.totalLines,
|
|
2332
|
+
shownBytes: slice.shownBytes,
|
|
2333
|
+
shownLines: slice.shownLines,
|
|
2334
|
+
},
|
|
2335
|
+
};
|
|
2207
2336
|
}
|
|
2208
|
-
|
|
2209
|
-
|
|
2337
|
+
let output = "## Fetched URLs\n\n";
|
|
2338
|
+
for (const { url, title, content, error } of presentedResults) {
|
|
2339
|
+
if (error) {
|
|
2340
|
+
output += `- ${url}: Error - ${error}\n`;
|
|
2341
|
+
}
|
|
2342
|
+
else {
|
|
2343
|
+
output += `- ${title || url} (${content.length} chars)\n`;
|
|
2344
|
+
}
|
|
2210
2345
|
}
|
|
2211
|
-
|
|
2212
|
-
|
|
2346
|
+
output += storedContent
|
|
2347
|
+
? getSearchContentEnabled
|
|
2348
|
+
? `\n---\nUse ${toolNames.getSearchContent}({ responseId: "${responseId}", urlIndex: 0 }) to retrieve bounded content slices.`
|
|
2349
|
+
: "\n---\nContent retrieval is not registered."
|
|
2350
|
+
: "\n---\nAuthenticated fetch cache is off; repeat the fetch to read content.";
|
|
2213
2351
|
return {
|
|
2214
|
-
content,
|
|
2215
|
-
details: {
|
|
2216
|
-
urls: urlList,
|
|
2217
|
-
urlCount: 1,
|
|
2218
|
-
successful: 1,
|
|
2219
|
-
totalChars: fullLength,
|
|
2220
|
-
title: result.title,
|
|
2221
|
-
...(storedContent ? { responseId } : {}),
|
|
2222
|
-
truncated,
|
|
2223
|
-
hasImage: imageCount > 0,
|
|
2224
|
-
imageCount,
|
|
2225
|
-
prompt: params.prompt,
|
|
2226
|
-
timestamp: params.timestamp,
|
|
2227
|
-
frames: params.frames,
|
|
2228
|
-
duration: result.duration,
|
|
2229
|
-
mode,
|
|
2230
|
-
mimeType: result.mimeType,
|
|
2231
|
-
status: result.status,
|
|
2232
|
-
totalBytes: slice.totalBytes,
|
|
2233
|
-
totalLines: slice.totalLines,
|
|
2234
|
-
shownBytes: slice.shownBytes,
|
|
2235
|
-
shownLines: slice.shownLines,
|
|
2236
|
-
},
|
|
2352
|
+
content: [{ type: "text", text: output }],
|
|
2353
|
+
details: { urls: urlList, urlCount: urlList.length, successful, totalChars, ...(storedContent ? { responseId } : {}) },
|
|
2237
2354
|
};
|
|
2238
|
-
}
|
|
2239
|
-
// Multi-URL: existing behavior (summary + responseId)
|
|
2240
|
-
let output = "## Fetched URLs\n\n";
|
|
2241
|
-
for (const { url, title, content, error } of presentedResults) {
|
|
2242
|
-
if (error) {
|
|
2243
|
-
output += `- ${url}: Error - ${error}\n`;
|
|
2244
|
-
}
|
|
2245
|
-
else {
|
|
2246
|
-
output += `- ${title || url} (${content.length} chars)\n`;
|
|
2247
|
-
}
|
|
2248
|
-
}
|
|
2249
|
-
output += storedContent
|
|
2250
|
-
? getSearchContentEnabled
|
|
2251
|
-
? `\n---\nUse ${toolNames.getSearchContent}({ responseId: "${responseId}", urlIndex: 0 }) to retrieve bounded content slices.`
|
|
2252
|
-
: "\n---\nContent retrieval is not registered."
|
|
2253
|
-
: "\n---\nAuthenticated fetch cache is off; repeat the fetch to read content.";
|
|
2254
|
-
return {
|
|
2255
|
-
content: [{ type: "text", text: output }],
|
|
2256
|
-
details: { urls: urlList, urlCount: urlList.length, successful, totalChars, ...(storedContent ? { responseId } : {}) },
|
|
2257
|
-
};
|
|
2355
|
+
});
|
|
2258
2356
|
},
|
|
2259
2357
|
renderCall(args, theme) {
|
|
2260
2358
|
const { urlList, options } = normalizeFetchContentParams(args);
|
|
@@ -2385,23 +2483,16 @@ export default function (pi) {
|
|
|
2385
2483
|
queryIndex: Type.Optional(Type.Integer({ minimum: 0, description: "Get content for query at index" })),
|
|
2386
2484
|
url: Type.Optional(Type.String({ description: "Get content for this URL" })),
|
|
2387
2485
|
urlIndex: Type.Optional(Type.Integer({ minimum: 0, description: "Get content for URL at index" })),
|
|
2388
|
-
offset: Type.Optional(Type.Integer({ minimum: 0, description: "Character offset for fetched URL content slices (default 0).
|
|
2389
|
-
limit: Type.Optional(Type.Integer({ minimum: 1, maximum: maxInlineContentChars, description: "Maximum characters to return for fetched URL content slices (default and max are set by maxInlineContentChars).
|
|
2486
|
+
offset: Type.Optional(Type.Integer({ minimum: 0, description: "Character offset for fetched URL content slices (default 0). Ignored when findText is supplied." })),
|
|
2487
|
+
limit: Type.Optional(Type.Integer({ minimum: 1, maximum: maxInlineContentChars, description: "Maximum characters to return for fetched URL content slices (default and max are set by maxInlineContentChars). Ignored when findText is supplied." })),
|
|
2390
2488
|
findText: Type.Optional(Type.Union([
|
|
2391
2489
|
Type.String({ minLength: 1, maxLength: 500 }),
|
|
2392
2490
|
Type.Array(Type.String({ minLength: 1, maxLength: 500 }), { minItems: 1, maxItems: 10 }),
|
|
2393
|
-
], { description: "Text or texts to find in the selected stored content.
|
|
2491
|
+
], { description: "Text or texts to find in the selected stored content. When supplied, offset and limit are ignored." })),
|
|
2394
2492
|
findMode: Type.Optional(StringEnum(["exact", "case-insensitive", "fuzzy"], { description: "Matching mode for findText (default: case-insensitive). Requires findText." })),
|
|
2395
2493
|
}),
|
|
2396
|
-
async execute(_toolCallId,
|
|
2397
|
-
|
|
2398
|
-
const offset = formatInputValue(params.offset);
|
|
2399
|
-
const limit = formatInputValue(params.limit);
|
|
2400
|
-
return {
|
|
2401
|
-
content: [{ type: "text", text: `findText cannot be combined with offset or limit. Received offset=${offset}, limit=${limit}; omit offset and limit when using findText.` }],
|
|
2402
|
-
details: { error: "Incompatible find options" },
|
|
2403
|
-
};
|
|
2404
|
-
}
|
|
2494
|
+
async execute(_toolCallId, rawParams) {
|
|
2495
|
+
const params = normalizeGetSearchContentParams(rawParams);
|
|
2405
2496
|
if (params.findMode !== undefined && params.findText === undefined) {
|
|
2406
2497
|
return {
|
|
2407
2498
|
content: [{ type: "text", text: `findMode ${formatInputValue(params.findMode)} requires findText; provide findText or omit findMode.` }],
|
|
@@ -2424,6 +2515,23 @@ export default function (pi) {
|
|
|
2424
2515
|
};
|
|
2425
2516
|
}
|
|
2426
2517
|
const serialized = JSON.stringify(artifact, null, 2);
|
|
2518
|
+
if (params.findText !== undefined) {
|
|
2519
|
+
try {
|
|
2520
|
+
const found = findContent(serialized, normalizeFindQueries(params.findText), params.findMode ?? "case-insensitive");
|
|
2521
|
+
const { text, ...findDetails } = found;
|
|
2522
|
+
return {
|
|
2523
|
+
content: [{ type: "text", text }],
|
|
2524
|
+
details: { responseId: artifact.id, type: "research", contentLength: serialized.length, findMode: params.findMode ?? "case-insensitive", ...findDetails },
|
|
2525
|
+
};
|
|
2526
|
+
}
|
|
2527
|
+
catch (err) {
|
|
2528
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
2529
|
+
return {
|
|
2530
|
+
content: [{ type: "text", text: `Unable to find ${formatInputValue(params.findText)} in research artifact for responseId ${formatInputValue(params.responseId)}: ${error}. Check findText and use a supported findMode.` }],
|
|
2531
|
+
details: { error, responseId: params.responseId, type: "research" },
|
|
2532
|
+
};
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2427
2535
|
const offset = params.offset ?? 0;
|
|
2428
2536
|
const limit = params.limit ?? maxInlineContentChars;
|
|
2429
2537
|
if (!Number.isInteger(offset) || offset < 0) {
|
|
@@ -2490,7 +2598,7 @@ export default function (pi) {
|
|
|
2490
2598
|
const fullResults = formatFullResults(queryData);
|
|
2491
2599
|
if (params.findText !== undefined) {
|
|
2492
2600
|
try {
|
|
2493
|
-
const found = findContent(fullResults, normalizeFindQueries(params.findText),
|
|
2601
|
+
const found = findContent(fullResults, normalizeFindQueries(params.findText), params.findMode ?? "case-insensitive");
|
|
2494
2602
|
const { text, ...findDetails } = found;
|
|
2495
2603
|
return {
|
|
2496
2604
|
content: [{ type: "text", text }],
|
|
@@ -2550,7 +2658,7 @@ export default function (pi) {
|
|
|
2550
2658
|
}
|
|
2551
2659
|
if (params.findText !== undefined) {
|
|
2552
2660
|
try {
|
|
2553
|
-
const found = findContent(urlData.content, normalizeFindQueries(params.findText),
|
|
2661
|
+
const found = findContent(urlData.content, normalizeFindQueries(params.findText), params.findMode ?? "case-insensitive");
|
|
2554
2662
|
const { text, ...findDetails } = found;
|
|
2555
2663
|
return {
|
|
2556
2664
|
content: [{ type: "text", text: `# ${urlData.title || urlData.url}\n\n${text}` }],
|
|
@@ -2994,14 +3102,16 @@ export default function (pi) {
|
|
|
2994
3102
|
const cookies = await isGeminiWebAvailable();
|
|
2995
3103
|
if (!cookies) {
|
|
2996
3104
|
const diagnostic = getGeminiWebAvailabilityDiagnostic();
|
|
3105
|
+
const diagnosticDetails = getGeminiWebAvailabilityDiagnosticDetails();
|
|
3106
|
+
const attempted = formatCookieAttempts(diagnosticDetails?.attempts ?? []);
|
|
2997
3107
|
const text = diagnostic
|
|
2998
|
-
? `Gemini Web is unavailable: ${diagnostic}`
|
|
3108
|
+
? `Gemini Web is unavailable: ${diagnostic}${attempted ? ` Attempted browser profiles: ${attempted}.` : ""}`
|
|
2999
3109
|
: "Gemini Web is unavailable. Sign into gemini.google.com in a supported Chromium-based browser.";
|
|
3000
3110
|
pi.sendMessage({
|
|
3001
3111
|
customType: "google-account",
|
|
3002
3112
|
content: [{ type: "text", text }],
|
|
3003
3113
|
display: true,
|
|
3004
|
-
details: { available: false, cookieAccessAllowed: true, diagnostic },
|
|
3114
|
+
details: { available: false, cookieAccessAllowed: true, diagnostic, cookieDiagnostic: diagnosticDetails },
|
|
3005
3115
|
}, { triggerTurn: true, deliverAs: "followUp" });
|
|
3006
3116
|
return;
|
|
3007
3117
|
}
|
|
@@ -3017,6 +3127,9 @@ export default function (pi) {
|
|
|
3017
3127
|
}, { triggerTurn: true, deliverAs: "followUp" });
|
|
3018
3128
|
},
|
|
3019
3129
|
});
|
|
3130
|
+
function formatCookieAttempts(attempts) {
|
|
3131
|
+
return attempts.map(({ browser, profile, status }) => `${browser}/${profile} (${status})`).join(", ");
|
|
3132
|
+
}
|
|
3020
3133
|
if (isCommandEnabled(initConfig, "search"))
|
|
3021
3134
|
pi.registerCommand("search", {
|
|
3022
3135
|
description: "Browse stored web search results",
|