@humain/terminal 0.0.18 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/dist/bun/cli.d.ts +3 -1
- package/dist/bun/cli.d.ts.map +1 -1
- package/dist/bun/cli.js +3 -8
- package/dist/bun/cli.js.map +1 -1
- package/dist/bun/runtime-setup.d.ts +2 -0
- package/dist/bun/runtime-setup.d.ts.map +1 -0
- package/dist/bun/runtime-setup.js +9 -0
- package/dist/bun/runtime-setup.js.map +1 -0
- package/dist/bun/sandbox-env-setup.d.ts +2 -0
- package/dist/bun/sandbox-env-setup.d.ts.map +1 -0
- package/dist/bun/sandbox-env-setup.js +4 -0
- package/dist/bun/sandbox-env-setup.js.map +1 -0
- package/dist/bundle/chunks/anthropic-messages-XULXUBIG.js +6 -0
- package/dist/bundle/chunks/{azure-openai-responses-ZN52D6YC.js → azure-openai-responses-JEG2XOYC.js} +1 -1
- package/dist/bundle/chunks/bedrock-converse-stream.js +6 -6
- package/dist/bundle/chunks/{chunk-ARF4OE6X.js → chunk-2LC3S3VV.js} +8 -8
- package/dist/bundle/chunks/chunk-43O5DDAH.js +31 -0
- package/dist/bundle/chunks/{chunk-H2O6VOXT.js → chunk-46DC2JD6.js} +2 -2
- package/dist/bundle/chunks/chunk-7ZC4UXSL.js +2 -0
- package/dist/bundle/chunks/{chunk-WJZ4KLGL.js → chunk-E6KP6V7F.js} +1 -1
- package/dist/bundle/chunks/{chunk-PSKDLDLZ.js → chunk-HPPQHK3J.js} +3 -3
- package/dist/bundle/chunks/chunk-JUPSJTFQ.js +42 -0
- package/dist/bundle/chunks/chunk-PL7O7J4J.js +133 -0
- package/dist/bundle/chunks/{chunk-QLVZGOBY.js → chunk-RM336IEI.js} +360 -352
- package/dist/bundle/chunks/chunk-USJZMAIR.js +2 -0
- package/dist/bundle/chunks/{extract-2L7ZVN7F.js → extract-TRW5FBY6.js} +2 -2
- package/dist/bundle/chunks/github-copilot.js +1 -1
- package/dist/bundle/chunks/{google-generative-ai-FF7M7XHT.js → google-generative-ai-OX6VSCA6.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-YMUBFRBA.js → google-vertex-GW76GSS2.js} +1 -1
- package/dist/bundle/chunks/image-resize-worker.js +1 -1
- package/dist/bundle/chunks/{mistral-conversations-O4M7IQML.js → mistral-conversations-WXGXZOFJ.js} +1 -1
- package/dist/bundle/chunks/node-AUOGOBCN.js +2 -0
- package/dist/bundle/chunks/node-KOIP55YZ.js +16 -0
- package/dist/bundle/chunks/openai-codex-responses-NPLWP6ZC.js +10 -0
- package/dist/bundle/chunks/{openai-completions-L4AHDQ5D.js → openai-completions-OT2GTJKC.js} +3 -3
- package/dist/bundle/chunks/openai-responses-5A6CR7GI.js +2 -0
- package/dist/bundle/chunks/{openrouter-images-Y2PCWAQH.js → openrouter-images-YLQ4RJ2F.js} +1 -1
- package/dist/bundle/chunks/{pi-messages-57K43J6J.js → pi-messages-OJF77SY3.js} +1 -1
- package/dist/bundle/chunks/{undici-D6ABF53Q.js → undici-KA2LJNVT.js} +1 -1
- package/dist/bundle/chunks/webapi-RFAXLI2D.js +5 -0
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/cli/config-selector.d.ts.map +1 -1
- package/dist/cli/config-selector.js +2 -1
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/cli/setup.d.ts +2 -0
- package/dist/cli/setup.d.ts.map +1 -0
- package/dist/cli/setup.js +13 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/cli.js +2 -14
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +15 -7
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session.d.ts +2 -6
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +14 -6
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +2 -1
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +1 -2
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/types.d.ts +8 -2
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/http-dispatcher.d.ts.map +1 -1
- package/dist/core/http-dispatcher.js +2 -0
- package/dist/core/http-dispatcher.js.map +1 -1
- package/dist/core/keybindings.d.ts +5 -0
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +4 -0
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/messages.d.ts +1 -1
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-config.d.ts +15 -0
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +3 -0
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-runtime.d.ts +1 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +5 -2
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/provider-composer.d.ts.map +1 -1
- package/dist/core/provider-composer.js +8 -2
- package/dist/core/provider-composer.js.map +1 -1
- package/dist/core/session-manager.d.ts +3 -2
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +40 -13
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +4 -2
- package/dist/core/skills.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +8 -9
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +3 -120
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit.d.ts +1 -12
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +5 -163
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +4 -55
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +4 -60
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +4 -49
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +4 -120
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/renderers/bash.d.ts +12 -0
- package/dist/core/tools/renderers/bash.d.ts.map +1 -0
- package/dist/core/tools/renderers/bash.js +133 -0
- package/dist/core/tools/renderers/bash.js.map +1 -0
- package/dist/core/tools/renderers/edit.d.ts +23 -0
- package/dist/core/tools/renderers/edit.d.ts.map +1 -0
- package/dist/core/tools/renderers/edit.js +167 -0
- package/dist/core/tools/renderers/edit.js.map +1 -0
- package/dist/core/tools/renderers/find.d.ts +10 -0
- package/dist/core/tools/renderers/find.d.ts.map +1 -0
- package/dist/core/tools/renderers/find.js +64 -0
- package/dist/core/tools/renderers/find.js.map +1 -0
- package/dist/core/tools/renderers/grep.d.ts +10 -0
- package/dist/core/tools/renderers/grep.d.ts.map +1 -0
- package/dist/core/tools/renderers/grep.js +69 -0
- package/dist/core/tools/renderers/grep.js.map +1 -0
- package/dist/core/tools/renderers/index.d.ts +22 -0
- package/dist/core/tools/renderers/index.d.ts.map +1 -0
- package/dist/core/tools/renderers/index.js +48 -0
- package/dist/core/tools/renderers/index.js.map +1 -0
- package/dist/core/tools/renderers/ls.d.ts +10 -0
- package/dist/core/tools/renderers/ls.d.ts.map +1 -0
- package/dist/core/tools/renderers/ls.js +58 -0
- package/dist/core/tools/renderers/ls.js.map +1 -0
- package/dist/core/tools/renderers/read.d.ts +11 -0
- package/dist/core/tools/renderers/read.d.ts.map +1 -0
- package/dist/core/tools/renderers/read.js +129 -0
- package/dist/core/tools/renderers/read.js.map +1 -0
- package/dist/core/tools/renderers/write.d.ts +10 -0
- package/dist/core/tools/renderers/write.d.ts.map +1 -0
- package/dist/core/tools/renderers/write.js +152 -0
- package/dist/core/tools/renderers/write.js.map +1 -0
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +5 -145
- package/dist/core/tools/write.js.map +1 -1
- package/dist/humain/bedrock-provider/vendor/index.bundle.mjs +51 -12
- package/dist/humain/mcp-adapter/vendor/package.json +2 -2
- package/dist/humain/web-access/vendor/curator-page.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/curator-page.js +3 -1
- package/dist/humain/web-access/vendor/curator-page.js.map +1 -1
- package/dist/humain/web-access/vendor/curator-server.d.ts +2 -0
- package/dist/humain/web-access/vendor/curator-server.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/curator-server.js +4 -2
- package/dist/humain/web-access/vendor/curator-server.js.map +1 -1
- package/dist/humain/web-access/vendor/gemini-search.d.ts +2 -2
- package/dist/humain/web-access/vendor/gemini-search.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/gemini-search.js +11 -4
- package/dist/humain/web-access/vendor/gemini-search.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 +238 -1
- package/dist/humain/web-access/vendor/github-extract.js.map +1 -1
- package/dist/humain/web-access/vendor/index.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/index.js +118 -64
- package/dist/humain/web-access/vendor/index.js.map +1 -1
- package/dist/humain/web-access/vendor/mistral-search.d.ts +4 -0
- package/dist/humain/web-access/vendor/mistral-search.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/mistral-search.js +274 -0
- package/dist/humain/web-access/vendor/mistral-search.js.map +1 -0
- package/dist/humain/web-access/vendor/perplexity.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/perplexity.js +12 -1
- package/dist/humain/web-access/vendor/perplexity.js.map +1 -1
- package/dist/humain/web-access/vendor/utils.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/utils.js +1 -2
- package/dist/humain/web-access/vendor/utils.js.map +1 -1
- package/dist/humain/web-access/vendor/xai-search.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/xai-search.js +92 -35
- package/dist/humain/web-access/vendor/xai-search.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +4 -1
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/chat-viewport.d.ts +20 -0
- package/dist/modes/interactive/chat-viewport.d.ts.map +1 -0
- package/dist/modes/interactive/chat-viewport.js +28 -0
- package/dist/modes/interactive/chat-viewport.js.map +1 -0
- package/dist/modes/interactive/components/assistant-message.d.ts +1 -0
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +18 -10
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +10 -1
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +37 -1
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +1 -1
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +8 -17
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +21 -23
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +14 -10
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/status-indicator.d.ts +3 -1
- package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
- package/dist/modes/interactive/components/status-indicator.js +10 -3
- package/dist/modes/interactive/components/status-indicator.js.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +4 -4
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +21 -4
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +34 -32
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/trust-selector.js +2 -2
- package/dist/modes/interactive/components/trust-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +8 -15
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +96 -81
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/session-share.d.ts.map +1 -1
- package/dist/modes/interactive/session-share.js +8 -12
- package/dist/modes/interactive/session-share.js.map +1 -1
- package/dist/modes/interactive/theme/dark.json +2 -1
- package/dist/modes/interactive/theme/light.json +2 -1
- package/dist/modes/interactive/theme/theme-controller.d.ts +1 -0
- package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-controller.js +5 -0
- package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
- package/dist/modes/interactive/theme/theme-json.d.ts +84 -0
- package/dist/modes/interactive/theme/theme-json.d.ts.map +1 -0
- package/dist/modes/interactive/theme/theme-json.js +130 -0
- package/dist/modes/interactive/theme/theme-json.js.map +1 -0
- package/dist/modes/interactive/theme/theme-schema.json +6 -2
- package/dist/modes/interactive/theme/theme.d.ts +14 -5
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +18 -119
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/interactive/tui-renderer.d.ts +21 -0
- package/dist/modes/interactive/tui-renderer.d.ts.map +1 -0
- package/dist/modes/interactive/tui-renderer.js +66 -0
- package/dist/modes/interactive/tui-renderer.js.map +1 -0
- package/dist/utils/exif-orientation.d.ts.map +1 -1
- package/dist/utils/exif-orientation.js +2 -3
- package/dist/utils/exif-orientation.js.map +1 -1
- package/dist/utils/tools-manager.d.ts +1 -0
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +41 -19
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/containerization.md +45 -0
- package/docs/development.md +19 -0
- package/docs/environment-variables.md +2 -0
- package/docs/extensions.md +5 -2
- package/docs/keybindings.md +5 -2
- package/docs/models.md +4 -1
- package/docs/rpc.md +1 -1
- package/docs/sdk.md +5 -0
- package/docs/settings.md +3 -3
- package/docs/skills.md +1 -1
- package/docs/terminal-setup.md +15 -0
- package/docs/themes.md +8 -6
- package/docs/tui.md +19 -0
- package/examples/README.md +3 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +84 -84
- package/examples/extensions/custom-provider-anthropic/package.json +17 -17
- package/examples/extensions/custom-provider-gitlab-duo/package.json +14 -14
- package/examples/extensions/dynamic-resources/dynamic.json +2 -0
- package/examples/extensions/gondolin/package-lock.json +8 -8
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +6 -6
- package/examples/extensions/sandbox/package.json +2 -2
- package/examples/extensions/with-deps/package-lock.json +29 -29
- package/examples/extensions/with-deps/package.json +20 -20
- package/examples/plugins/pi-example-plugin/README.md +38 -0
- package/examples/plugins/pi-example-plugin/package.json +10 -0
- package/examples/plugins/pi-example-plugin/src/contract.ts +13 -0
- package/examples/plugins/pi-example-plugin/src/session.ts +23 -0
- package/examples/plugins/pi-example-plugin/src/tui.ts +31 -0
- package/npm-shrinkwrap.json +772 -205
- package/package.json +31 -24
- package/src/humain/web-access/UPSTREAM.md +12 -1
- package/src/humain/web-access/upstream.json +4 -4
- package/dist/bundle/chunks/anthropic-messages-M4LCS3KH.js +0 -6
- package/dist/bundle/chunks/chunk-3VI4HD7D.js +0 -31
- package/dist/bundle/chunks/chunk-BOW22LW6.js +0 -42
- package/dist/bundle/chunks/chunk-CBHC6EL7.js +0 -133
- package/dist/bundle/chunks/chunk-JUUC5AZY.js +0 -2
- package/dist/bundle/chunks/node-ZHY4LHC7.js +0 -15
- package/dist/bundle/chunks/openai-codex-responses-HRVCDY54.js +0 -8
- package/dist/bundle/chunks/openai-responses-4MWLJHIK.js +0 -2
- package/dist/bundle/chunks/webapi-AFS5FDJJ.js +0 -5
- package/dist/bundle/client.js +0 -2
- package/dist/cli/experimental/auth.d.ts +0 -16
- package/dist/cli/experimental/auth.d.ts.map +0 -1
- package/dist/cli/experimental/auth.js +0 -13
- package/dist/cli/experimental/auth.js.map +0 -1
- package/dist/cli/experimental/cli.d.ts +0 -6
- package/dist/cli/experimental/cli.d.ts.map +0 -1
- package/dist/cli/experimental/cli.js +0 -5
- package/dist/cli/experimental/cli.js.map +0 -1
- package/dist/cli/experimental/command-options.d.ts +0 -17
- package/dist/cli/experimental/command-options.d.ts.map +0 -1
- package/dist/cli/experimental/command-options.js +0 -35
- package/dist/cli/experimental/command-options.js.map +0 -1
- package/dist/cli/experimental/command.d.ts +0 -63
- package/dist/cli/experimental/command.d.ts.map +0 -1
- package/dist/cli/experimental/command.js +0 -127
- package/dist/cli/experimental/command.js.map +0 -1
- package/dist/cli/experimental/commands/client.d.ts +0 -13
- package/dist/cli/experimental/commands/client.d.ts.map +0 -1
- package/dist/cli/experimental/commands/client.js +0 -25
- package/dist/cli/experimental/commands/client.js.map +0 -1
- package/dist/cli/experimental/commands/pi.d.ts +0 -15
- package/dist/cli/experimental/commands/pi.d.ts.map +0 -1
- package/dist/cli/experimental/commands/pi.js +0 -28
- package/dist/cli/experimental/commands/pi.js.map +0 -1
- package/dist/cli/experimental/commands/server.d.ts +0 -13
- package/dist/cli/experimental/commands/server.d.ts.map +0 -1
- package/dist/cli/experimental/commands/server.js +0 -25
- package/dist/cli/experimental/commands/server.js.map +0 -1
- package/dist/cli/experimental/transport-address.d.ts +0 -10
- package/dist/cli/experimental/transport-address.d.ts.map +0 -1
- package/dist/cli/experimental/transport-address.js +0 -38
- package/dist/cli/experimental/transport-address.js.map +0 -1
- package/dist/client/index.d.ts +0 -3
- package/dist/client/index.d.ts.map +0 -1
- package/dist/client/index.js +0 -3
- package/dist/client/index.js.map +0 -1
- package/dist/client/remote-session.d.ts +0 -53
- package/dist/client/remote-session.d.ts.map +0 -1
- package/dist/client/remote-session.js +0 -340
- package/dist/client/remote-session.js.map +0 -1
- package/dist/client/transcript.d.ts +0 -12
- package/dist/client/transcript.d.ts.map +0 -1
- package/dist/client/transcript.js +0 -98
- package/dist/client/transcript.js.map +0 -1
- package/dist/server/create-harness.d.ts +0 -26
- package/dist/server/create-harness.d.ts.map +0 -1
- package/dist/server/create-harness.js +0 -106
- package/dist/server/create-harness.js.map +0 -1
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { SearchOptions, SearchResponse } from "./perplexity.ts";
|
|
2
|
+
export declare function isMistralAvailable(): boolean;
|
|
3
|
+
export declare function searchWithMistral(query: string, options?: SearchOptions): Promise<SearchResponse>;
|
|
4
|
+
//# sourceMappingURL=mistral-search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mistral-search.d.ts","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/mistral-search.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAgB,MAAM,iBAAiB,CAAC;AAiNnF,wBAAgB,kBAAkB,IAAI,OAAO,CAa5C;AAED,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,cAAc,CAAC,CAsD3G"}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { activityMonitor } from "./activity.js";
|
|
3
|
+
import { hasCredentialSource, redactCredential, resolveCredential } from "./credential-source.js";
|
|
4
|
+
import { getWebSearchConfigPath } from "./utils.js";
|
|
5
|
+
const MISTRAL_CONVERSATIONS_URL = "https://api.mistral.ai/v1/conversations";
|
|
6
|
+
const CONFIG_PATH = getWebSearchConfigPath();
|
|
7
|
+
const SEARCH_TIMEOUT_MS = 60_000;
|
|
8
|
+
const DEFAULT_SEARCH_MODEL = "mistral-small-latest";
|
|
9
|
+
const DEFAULT_SEARCH_TOOL = "web_search";
|
|
10
|
+
const MAX_RESULTS = 20;
|
|
11
|
+
let cachedConfig = null;
|
|
12
|
+
function loadConfig() {
|
|
13
|
+
if (cachedConfig)
|
|
14
|
+
return cachedConfig;
|
|
15
|
+
if (!existsSync(CONFIG_PATH)) {
|
|
16
|
+
cachedConfig = {};
|
|
17
|
+
return cachedConfig;
|
|
18
|
+
}
|
|
19
|
+
const raw = readFileSync(CONFIG_PATH, "utf-8");
|
|
20
|
+
let parsed;
|
|
21
|
+
try {
|
|
22
|
+
parsed = JSON.parse(raw);
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
26
|
+
throw new Error(`Failed to parse ${CONFIG_PATH}: ${message}`);
|
|
27
|
+
}
|
|
28
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
29
|
+
throw new Error(`Invalid config in ${CONFIG_PATH}: expected a JSON object`);
|
|
30
|
+
}
|
|
31
|
+
cachedConfig = parsed;
|
|
32
|
+
return cachedConfig;
|
|
33
|
+
}
|
|
34
|
+
function resolveSearchModel(value) {
|
|
35
|
+
if (value === undefined)
|
|
36
|
+
return DEFAULT_SEARCH_MODEL;
|
|
37
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
38
|
+
throw new Error(`mistralSearchModel in ${CONFIG_PATH} must be a non-empty string`);
|
|
39
|
+
}
|
|
40
|
+
return value.trim();
|
|
41
|
+
}
|
|
42
|
+
function resolveSearchTool(value) {
|
|
43
|
+
if (value === undefined)
|
|
44
|
+
return DEFAULT_SEARCH_TOOL;
|
|
45
|
+
if (value !== "web_search" && value !== "web_search_premium") {
|
|
46
|
+
throw new Error(`mistralSearchTool in ${CONFIG_PATH} must be either web_search or web_search_premium`);
|
|
47
|
+
}
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
50
|
+
function normalizeCount(value) {
|
|
51
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
52
|
+
return 5;
|
|
53
|
+
return Math.max(1, Math.min(Math.floor(value), MAX_RESULTS));
|
|
54
|
+
}
|
|
55
|
+
function normalizeDomain(value) {
|
|
56
|
+
let input = value.trim().toLowerCase();
|
|
57
|
+
if (!input)
|
|
58
|
+
return null;
|
|
59
|
+
if (input.startsWith("-"))
|
|
60
|
+
input = input.slice(1).trim();
|
|
61
|
+
if (!input)
|
|
62
|
+
return null;
|
|
63
|
+
try {
|
|
64
|
+
const parsed = input.includes("://") ? new URL(input) : new URL(`https://${input}`);
|
|
65
|
+
input = parsed.hostname;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
input = input.split("/")[0]?.split(":")[0] ?? "";
|
|
69
|
+
}
|
|
70
|
+
input = input.replace(/^\.+|\.+$/g, "");
|
|
71
|
+
return /^[a-z0-9][a-z0-9.-]*\.[a-z]{2,}$/i.test(input) ? input : null;
|
|
72
|
+
}
|
|
73
|
+
function parseDomainFilters(domainFilter) {
|
|
74
|
+
const filters = { include: [], exclude: [] };
|
|
75
|
+
for (const raw of domainFilter ?? []) {
|
|
76
|
+
const domain = normalizeDomain(raw);
|
|
77
|
+
if (!domain)
|
|
78
|
+
continue;
|
|
79
|
+
const target = raw.trim().startsWith("-") ? filters.exclude : filters.include;
|
|
80
|
+
if (!target.includes(domain))
|
|
81
|
+
target.push(domain);
|
|
82
|
+
}
|
|
83
|
+
return filters;
|
|
84
|
+
}
|
|
85
|
+
function passesDomainFilters(url, filters) {
|
|
86
|
+
if (filters.include.length === 0 && filters.exclude.length === 0)
|
|
87
|
+
return true;
|
|
88
|
+
const hostname = new URL(url).hostname.toLowerCase();
|
|
89
|
+
const matches = (domain) => hostname === domain || hostname.endsWith(`.${domain}`);
|
|
90
|
+
if (filters.exclude.some(matches))
|
|
91
|
+
return false;
|
|
92
|
+
return filters.include.length === 0 || filters.include.some(matches);
|
|
93
|
+
}
|
|
94
|
+
function normalizeResultUrl(value) {
|
|
95
|
+
if (typeof value !== "string")
|
|
96
|
+
return null;
|
|
97
|
+
const url = value.trim();
|
|
98
|
+
if (!url)
|
|
99
|
+
return null;
|
|
100
|
+
try {
|
|
101
|
+
const parsed = new URL(url);
|
|
102
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:")
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
return url;
|
|
109
|
+
}
|
|
110
|
+
function buildSearchPrompt(query, options, numResults) {
|
|
111
|
+
const lines = [];
|
|
112
|
+
if (options.recencyFilter) {
|
|
113
|
+
const labels = {
|
|
114
|
+
day: "past 24 hours",
|
|
115
|
+
week: "past week",
|
|
116
|
+
month: "past month",
|
|
117
|
+
year: "past year",
|
|
118
|
+
};
|
|
119
|
+
lines.push(`Prefer sources from the ${labels[options.recencyFilter] ?? options.recencyFilter}.`);
|
|
120
|
+
}
|
|
121
|
+
if (typeof options.numResults === "number" && Number.isFinite(options.numResults) && options.numResults > 0) {
|
|
122
|
+
lines.push(`Prefer up to ${numResults} distinct sources.`);
|
|
123
|
+
}
|
|
124
|
+
const filters = parseDomainFilters(options.domainFilter);
|
|
125
|
+
if (filters.include.length > 0)
|
|
126
|
+
lines.push(`Only use sources from: ${filters.include.slice(0, 100).join(", ")}.`);
|
|
127
|
+
if (filters.exclude.length > 0)
|
|
128
|
+
lines.push(`Do not use sources from: ${filters.exclude.slice(0, 100).join(", ")}.`);
|
|
129
|
+
return lines.length > 0 ? `${lines.join(" ")}\n\n${query}` : query;
|
|
130
|
+
}
|
|
131
|
+
function errorMessage(err) {
|
|
132
|
+
return err instanceof Error ? err.message : String(err);
|
|
133
|
+
}
|
|
134
|
+
function invalidResponse(message) {
|
|
135
|
+
return new Error(`Mistral API returned invalid response: ${message}`);
|
|
136
|
+
}
|
|
137
|
+
function parseConversationResponse(value, options, numResults) {
|
|
138
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
139
|
+
throw invalidResponse("expected an object envelope");
|
|
140
|
+
}
|
|
141
|
+
const outputs = value.outputs;
|
|
142
|
+
if (!Array.isArray(outputs))
|
|
143
|
+
throw invalidResponse("outputs must be an array");
|
|
144
|
+
const answerParts = [];
|
|
145
|
+
const results = [];
|
|
146
|
+
const seenUrls = new Set();
|
|
147
|
+
const domainFilters = parseDomainFilters(options.domainFilter);
|
|
148
|
+
for (const output of outputs) {
|
|
149
|
+
if (!output || typeof output !== "object" || Array.isArray(output))
|
|
150
|
+
continue;
|
|
151
|
+
const entry = output;
|
|
152
|
+
if (entry.type !== "message.output")
|
|
153
|
+
continue;
|
|
154
|
+
const content = entry.content;
|
|
155
|
+
if (typeof content === "string") {
|
|
156
|
+
if (content.trim())
|
|
157
|
+
answerParts.push(content.trim());
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (!Array.isArray(content))
|
|
161
|
+
continue;
|
|
162
|
+
for (const chunk of content) {
|
|
163
|
+
if (!chunk || typeof chunk !== "object" || Array.isArray(chunk))
|
|
164
|
+
continue;
|
|
165
|
+
const part = chunk;
|
|
166
|
+
if (part.type === "text") {
|
|
167
|
+
if (typeof part.text === "string" && part.text.trim())
|
|
168
|
+
answerParts.push(part.text.trim());
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
if (part.type !== "tool_reference" || results.length >= numResults)
|
|
172
|
+
continue;
|
|
173
|
+
const url = normalizeResultUrl(part.url);
|
|
174
|
+
if (!url || !passesDomainFilters(url, domainFilters) || seenUrls.has(url))
|
|
175
|
+
continue;
|
|
176
|
+
seenUrls.add(url);
|
|
177
|
+
const title = typeof part.title === "string" && part.title.trim() ? part.title.trim() : url;
|
|
178
|
+
const snippet = typeof part.description === "string" ? part.description : "";
|
|
179
|
+
results.push({ title, url, snippet });
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const answer = answerParts.join("\n").trim();
|
|
183
|
+
if (!answer && results.length === 0)
|
|
184
|
+
throw invalidResponse("no answer or sources");
|
|
185
|
+
return { answer, results };
|
|
186
|
+
}
|
|
187
|
+
async function getApiKey(signal) {
|
|
188
|
+
const apiKey = await resolveCredential({
|
|
189
|
+
provider: "Mistral",
|
|
190
|
+
configuredValue: loadConfig().mistralApiKey,
|
|
191
|
+
environmentValue: process.env.MISTRAL_API_KEY,
|
|
192
|
+
signal,
|
|
193
|
+
});
|
|
194
|
+
if (!apiKey) {
|
|
195
|
+
throw new Error("Mistral API key not found. Either:\n" +
|
|
196
|
+
` 1. Create ${CONFIG_PATH} with { "mistralApiKey": "your-key" }\n` +
|
|
197
|
+
" 2. Set MISTRAL_API_KEY environment variable\n" +
|
|
198
|
+
"Get a key at https://console.mistral.ai/api-keys");
|
|
199
|
+
}
|
|
200
|
+
return apiKey;
|
|
201
|
+
}
|
|
202
|
+
export function isMistralAvailable() {
|
|
203
|
+
try {
|
|
204
|
+
const config = loadConfig();
|
|
205
|
+
resolveSearchModel(config.mistralSearchModel);
|
|
206
|
+
resolveSearchTool(config.mistralSearchTool);
|
|
207
|
+
return hasCredentialSource({
|
|
208
|
+
provider: "Mistral",
|
|
209
|
+
configuredValue: config.mistralApiKey,
|
|
210
|
+
environmentValue: process.env.MISTRAL_API_KEY,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
export async function searchWithMistral(query, options = {}) {
|
|
218
|
+
const config = loadConfig();
|
|
219
|
+
const model = resolveSearchModel(config.mistralSearchModel);
|
|
220
|
+
const tool = resolveSearchTool(config.mistralSearchTool);
|
|
221
|
+
const numResults = normalizeCount(options.numResults);
|
|
222
|
+
const apiKey = await getApiKey(options.signal);
|
|
223
|
+
const requestSignal = options.signal
|
|
224
|
+
? AbortSignal.any([AbortSignal.timeout(SEARCH_TIMEOUT_MS), options.signal])
|
|
225
|
+
: AbortSignal.timeout(SEARCH_TIMEOUT_MS);
|
|
226
|
+
const activityId = activityMonitor.logStart({ type: "api", query });
|
|
227
|
+
try {
|
|
228
|
+
const response = await fetch(MISTRAL_CONVERSATIONS_URL, {
|
|
229
|
+
method: "POST",
|
|
230
|
+
headers: {
|
|
231
|
+
Authorization: `Bearer ${apiKey}`,
|
|
232
|
+
"Content-Type": "application/json",
|
|
233
|
+
},
|
|
234
|
+
body: JSON.stringify({
|
|
235
|
+
inputs: [{ role: "user", content: buildSearchPrompt(query, options, numResults) }],
|
|
236
|
+
stream: false,
|
|
237
|
+
model,
|
|
238
|
+
tools: [{ type: tool }],
|
|
239
|
+
}),
|
|
240
|
+
signal: requestSignal,
|
|
241
|
+
});
|
|
242
|
+
if (!response.ok) {
|
|
243
|
+
const errorText = redactCredential(await response.text(), apiKey);
|
|
244
|
+
throw new Error(`Mistral API error ${response.status}: ${errorText.slice(0, 300)}`);
|
|
245
|
+
}
|
|
246
|
+
let parsed;
|
|
247
|
+
try {
|
|
248
|
+
parsed = await response.json();
|
|
249
|
+
}
|
|
250
|
+
catch (err) {
|
|
251
|
+
throw new Error(`Mistral API returned invalid JSON: ${errorMessage(err)}`);
|
|
252
|
+
}
|
|
253
|
+
const result = parseConversationResponse(parsed, options, numResults);
|
|
254
|
+
activityMonitor.logComplete(activityId, response.status);
|
|
255
|
+
return result;
|
|
256
|
+
}
|
|
257
|
+
catch (err) {
|
|
258
|
+
const message = errorMessage(err);
|
|
259
|
+
const redactedMessage = redactCredential(message, apiKey);
|
|
260
|
+
if (redactedMessage.toLowerCase().includes("abort")) {
|
|
261
|
+
activityMonitor.logComplete(activityId, 0);
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
activityMonitor.logError(activityId, redactedMessage);
|
|
265
|
+
}
|
|
266
|
+
if (redactedMessage === message)
|
|
267
|
+
throw err;
|
|
268
|
+
const redactedError = new Error(redactedMessage);
|
|
269
|
+
if (err instanceof Error)
|
|
270
|
+
redactedError.name = err.name;
|
|
271
|
+
throw redactedError;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
//# sourceMappingURL=mistral-search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mistral-search.js","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/mistral-search.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { activityMonitor } from \"./activity.ts\";\nimport type { SearchOptions, SearchResponse, SearchResult } from \"./perplexity.ts\";\nimport { hasCredentialSource, redactCredential, resolveCredential } from \"./credential-source.ts\";\nimport { getWebSearchConfigPath } from \"./utils.ts\";\n\nconst MISTRAL_CONVERSATIONS_URL = \"https://api.mistral.ai/v1/conversations\";\nconst CONFIG_PATH = getWebSearchConfigPath();\nconst SEARCH_TIMEOUT_MS = 60_000;\nconst DEFAULT_SEARCH_MODEL = \"mistral-small-latest\";\nconst DEFAULT_SEARCH_TOOL = \"web_search\";\nconst MAX_RESULTS = 20;\n\ntype MistralSearchTool = \"web_search\" | \"web_search_premium\";\n\ninterface WebSearchConfig {\n\tmistralApiKey?: unknown;\n\tmistralSearchModel?: unknown;\n\tmistralSearchTool?: unknown;\n}\n\ninterface DomainFilters {\n\tinclude: string[];\n\texclude: string[];\n}\n\nlet cachedConfig: WebSearchConfig | null = null;\n\nfunction loadConfig(): WebSearchConfig {\n\tif (cachedConfig) return cachedConfig;\n\tif (!existsSync(CONFIG_PATH)) {\n\t\tcachedConfig = {};\n\t\treturn cachedConfig;\n\t}\n\n\tconst raw = readFileSync(CONFIG_PATH, \"utf-8\");\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tthrow new Error(`Failed to parse ${CONFIG_PATH}: ${message}`);\n\t}\n\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\tthrow new Error(`Invalid config in ${CONFIG_PATH}: expected a JSON object`);\n\t}\n\tcachedConfig = parsed as WebSearchConfig;\n\treturn cachedConfig;\n}\n\nfunction resolveSearchModel(value: unknown): string {\n\tif (value === undefined) return DEFAULT_SEARCH_MODEL;\n\tif (typeof value !== \"string\" || value.trim().length === 0) {\n\t\tthrow new Error(`mistralSearchModel in ${CONFIG_PATH} must be a non-empty string`);\n\t}\n\treturn value.trim();\n}\n\nfunction resolveSearchTool(value: unknown): MistralSearchTool {\n\tif (value === undefined) return DEFAULT_SEARCH_TOOL;\n\tif (value !== \"web_search\" && value !== \"web_search_premium\") {\n\t\tthrow new Error(`mistralSearchTool in ${CONFIG_PATH} must be either web_search or web_search_premium`);\n\t}\n\treturn value;\n}\n\nfunction normalizeCount(value: number | undefined): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) return 5;\n\treturn Math.max(1, Math.min(Math.floor(value), MAX_RESULTS));\n}\n\nfunction normalizeDomain(value: string): string | null {\n\tlet input = value.trim().toLowerCase();\n\tif (!input) return null;\n\tif (input.startsWith(\"-\")) input = input.slice(1).trim();\n\tif (!input) return null;\n\ttry {\n\t\tconst parsed = input.includes(\"://\") ? new URL(input) : new URL(`https://${input}`);\n\t\tinput = parsed.hostname;\n\t} catch {\n\t\tinput = input.split(\"/\")[0]?.split(\":\")[0] ?? \"\";\n\t}\n\tinput = input.replace(/^\\.+|\\.+$/g, \"\");\n\treturn /^[a-z0-9][a-z0-9.-]*\\.[a-z]{2,}$/i.test(input) ? input : null;\n}\n\nfunction parseDomainFilters(domainFilter: string[] | undefined): DomainFilters {\n\tconst filters: DomainFilters = { include: [], exclude: [] };\n\tfor (const raw of domainFilter ?? []) {\n\t\tconst domain = normalizeDomain(raw);\n\t\tif (!domain) continue;\n\t\tconst target = raw.trim().startsWith(\"-\") ? filters.exclude : filters.include;\n\t\tif (!target.includes(domain)) target.push(domain);\n\t}\n\treturn filters;\n}\n\nfunction passesDomainFilters(url: string, filters: DomainFilters): boolean {\n\tif (filters.include.length === 0 && filters.exclude.length === 0) return true;\n\tconst hostname = new URL(url).hostname.toLowerCase();\n\tconst matches = (domain: string) => hostname === domain || hostname.endsWith(`.${domain}`);\n\tif (filters.exclude.some(matches)) return false;\n\treturn filters.include.length === 0 || filters.include.some(matches);\n}\n\nfunction normalizeResultUrl(value: unknown): string | null {\n\tif (typeof value !== \"string\") return null;\n\tconst url = value.trim();\n\tif (!url) return null;\n\ttry {\n\t\tconst parsed = new URL(url);\n\t\tif (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") return null;\n\t} catch {\n\t\treturn null;\n\t}\n\treturn url;\n}\n\nfunction buildSearchPrompt(query: string, options: SearchOptions, numResults: number): string {\n\tconst lines: string[] = [];\n\tif (options.recencyFilter) {\n\t\tconst labels: Record<string, string> = {\n\t\t\tday: \"past 24 hours\",\n\t\t\tweek: \"past week\",\n\t\t\tmonth: \"past month\",\n\t\t\tyear: \"past year\",\n\t\t};\n\t\tlines.push(`Prefer sources from the ${labels[options.recencyFilter] ?? options.recencyFilter}.`);\n\t}\n\tif (typeof options.numResults === \"number\" && Number.isFinite(options.numResults) && options.numResults > 0) {\n\t\tlines.push(`Prefer up to ${numResults} distinct sources.`);\n\t}\n\n\tconst filters = parseDomainFilters(options.domainFilter);\n\tif (filters.include.length > 0) lines.push(`Only use sources from: ${filters.include.slice(0, 100).join(\", \")}.`);\n\tif (filters.exclude.length > 0) lines.push(`Do not use sources from: ${filters.exclude.slice(0, 100).join(\", \")}.`);\n\treturn lines.length > 0 ? `${lines.join(\" \")}\\n\\n${query}` : query;\n}\n\nfunction errorMessage(err: unknown): string {\n\treturn err instanceof Error ? err.message : String(err);\n}\n\nfunction invalidResponse(message: string): Error {\n\treturn new Error(`Mistral API returned invalid response: ${message}`);\n}\n\nfunction parseConversationResponse(value: unknown, options: SearchOptions, numResults: number): SearchResponse {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow invalidResponse(\"expected an object envelope\");\n\t}\n\tconst outputs = (value as Record<string, unknown>).outputs;\n\tif (!Array.isArray(outputs)) throw invalidResponse(\"outputs must be an array\");\n\n\tconst answerParts: string[] = [];\n\tconst results: SearchResult[] = [];\n\tconst seenUrls = new Set<string>();\n\tconst domainFilters = parseDomainFilters(options.domainFilter);\n\n\tfor (const output of outputs) {\n\t\tif (!output || typeof output !== \"object\" || Array.isArray(output)) continue;\n\t\tconst entry = output as Record<string, unknown>;\n\t\tif (entry.type !== \"message.output\") continue;\n\t\tconst content = entry.content;\n\t\tif (typeof content === \"string\") {\n\t\t\tif (content.trim()) answerParts.push(content.trim());\n\t\t\tcontinue;\n\t\t}\n\t\tif (!Array.isArray(content)) continue;\n\n\t\tfor (const chunk of content) {\n\t\t\tif (!chunk || typeof chunk !== \"object\" || Array.isArray(chunk)) continue;\n\t\t\tconst part = chunk as Record<string, unknown>;\n\t\t\tif (part.type === \"text\") {\n\t\t\t\tif (typeof part.text === \"string\" && part.text.trim()) answerParts.push(part.text.trim());\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (part.type !== \"tool_reference\" || results.length >= numResults) continue;\n\n\t\t\tconst url = normalizeResultUrl(part.url);\n\t\t\tif (!url || !passesDomainFilters(url, domainFilters) || seenUrls.has(url)) continue;\n\t\t\tseenUrls.add(url);\n\t\t\tconst title = typeof part.title === \"string\" && part.title.trim() ? part.title.trim() : url;\n\t\t\tconst snippet = typeof part.description === \"string\" ? part.description : \"\";\n\t\t\tresults.push({ title, url, snippet });\n\t\t}\n\t}\n\n\tconst answer = answerParts.join(\"\\n\").trim();\n\tif (!answer && results.length === 0) throw invalidResponse(\"no answer or sources\");\n\treturn { answer, results };\n}\n\nasync function getApiKey(signal?: AbortSignal): Promise<string> {\n\tconst apiKey = await resolveCredential({\n\t\tprovider: \"Mistral\",\n\t\tconfiguredValue: loadConfig().mistralApiKey,\n\t\tenvironmentValue: process.env.MISTRAL_API_KEY,\n\t\tsignal,\n\t});\n\tif (!apiKey) {\n\t\tthrow new Error(\n\t\t\t\"Mistral API key not found. Either:\\n\" +\n\t\t\t` 1. Create ${CONFIG_PATH} with { \"mistralApiKey\": \"your-key\" }\\n` +\n\t\t\t\" 2. Set MISTRAL_API_KEY environment variable\\n\" +\n\t\t\t\"Get a key at https://console.mistral.ai/api-keys\",\n\t\t);\n\t}\n\treturn apiKey;\n}\n\nexport function isMistralAvailable(): boolean {\n\ttry {\n\t\tconst config = loadConfig();\n\t\tresolveSearchModel(config.mistralSearchModel);\n\t\tresolveSearchTool(config.mistralSearchTool);\n\t\treturn hasCredentialSource({\n\t\t\tprovider: \"Mistral\",\n\t\t\tconfiguredValue: config.mistralApiKey,\n\t\t\tenvironmentValue: process.env.MISTRAL_API_KEY,\n\t\t});\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport async function searchWithMistral(query: string, options: SearchOptions = {}): Promise<SearchResponse> {\n\tconst config = loadConfig();\n\tconst model = resolveSearchModel(config.mistralSearchModel);\n\tconst tool = resolveSearchTool(config.mistralSearchTool);\n\tconst numResults = normalizeCount(options.numResults);\n\tconst apiKey = await getApiKey(options.signal);\n\tconst requestSignal = options.signal\n\t\t? AbortSignal.any([AbortSignal.timeout(SEARCH_TIMEOUT_MS), options.signal])\n\t\t: AbortSignal.timeout(SEARCH_TIMEOUT_MS);\n\tconst activityId = activityMonitor.logStart({ type: \"api\", query });\n\n\ttry {\n\t\tconst response = await fetch(MISTRAL_CONVERSATIONS_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${apiKey}`,\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t},\n\t\t\tbody: JSON.stringify({\n\t\t\t\tinputs: [{ role: \"user\", content: buildSearchPrompt(query, options, numResults) }],\n\t\t\t\tstream: false,\n\t\t\t\tmodel,\n\t\t\t\ttools: [{ type: tool }],\n\t\t\t}),\n\t\t\tsignal: requestSignal,\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst errorText = redactCredential(await response.text(), apiKey);\n\t\t\tthrow new Error(`Mistral API error ${response.status}: ${errorText.slice(0, 300)}`);\n\t\t}\n\n\t\tlet parsed: unknown;\n\t\ttry {\n\t\t\tparsed = await response.json();\n\t\t} catch (err) {\n\t\t\tthrow new Error(`Mistral API returned invalid JSON: ${errorMessage(err)}`);\n\t\t}\n\t\tconst result = parseConversationResponse(parsed, options, numResults);\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\treturn result;\n\t} catch (err) {\n\t\tconst message = errorMessage(err);\n\t\tconst redactedMessage = redactCredential(message, apiKey);\n\t\tif (redactedMessage.toLowerCase().includes(\"abort\")) {\n\t\t\tactivityMonitor.logComplete(activityId, 0);\n\t\t} else {\n\t\t\tactivityMonitor.logError(activityId, redactedMessage);\n\t\t}\n\t\tif (redactedMessage === message) throw err;\n\t\tconst redactedError = new Error(redactedMessage);\n\t\tif (err instanceof Error) redactedError.name = err.name;\n\t\tthrow redactedError;\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"perplexity.d.ts","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/perplexity.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAcrD,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,aAAa,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,aAAa;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IAClD,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAkED,wBAAgB,qBAAqB,IAAI,OAAO,CAM/C;
|
|
1
|
+
{"version":3,"file":"perplexity.d.ts","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/perplexity.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAcrD,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,aAAa,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,aAAa;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IAClD,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAkED,wBAAgB,qBAAqB,IAAI,OAAO,CAM/C;AAcD,wBAAsB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,cAAc,CAAC,CA+F9G"}
|
|
@@ -67,6 +67,16 @@ export function isPerplexityAvailable() {
|
|
|
67
67
|
environmentValue: process.env.PERPLEXITY_API_KEY,
|
|
68
68
|
});
|
|
69
69
|
}
|
|
70
|
+
/** Hard ceiling on kept citations, matching the `numResults` clamp. */
|
|
71
|
+
const MAX_CITATIONS = 20;
|
|
72
|
+
// Preserve citation numbering by keeping the prefix through the highest cited index, capped at 20.
|
|
73
|
+
function citationsToKeep(answer, available, numResults) {
|
|
74
|
+
let highestCited = 0;
|
|
75
|
+
for (const match of answer.matchAll(/\[(\d{1,3})\]/g)) {
|
|
76
|
+
highestCited = Math.max(highestCited, Number(match[1]));
|
|
77
|
+
}
|
|
78
|
+
return Math.min(available, MAX_CITATIONS, Math.max(numResults, highestCited));
|
|
79
|
+
}
|
|
70
80
|
export async function searchWithPerplexity(query, options = {}) {
|
|
71
81
|
checkRateLimit();
|
|
72
82
|
const activityId = activityMonitor.logStart({ type: "api", query });
|
|
@@ -140,7 +150,8 @@ export async function searchWithPerplexity(query, options = {}) {
|
|
|
140
150
|
const answer = data.choices?.[0]?.message?.content || "";
|
|
141
151
|
const citations = Array.isArray(data.citations) ? data.citations : [];
|
|
142
152
|
const results = [];
|
|
143
|
-
|
|
153
|
+
const citationCount = citationsToKeep(answer, citations.length, numResults);
|
|
154
|
+
for (let i = 0; i < citationCount; i++) {
|
|
144
155
|
const citation = citations[i];
|
|
145
156
|
if (typeof citation === "string") {
|
|
146
157
|
results.push({ title: `Source ${i + 1}`, url: citation, snippet: "" });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"perplexity.js","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/perplexity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAClG,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEpD,MAAM,kBAAkB,GAAG,4CAA4C,CAAC;AACxE,MAAM,WAAW,GAAG,sBAAsB,EAAE,CAAC;AAE7C,MAAM,UAAU,GAAG;IAClB,WAAW,EAAE,EAAE;IACf,QAAQ,EAAE,EAAE,GAAG,IAAI;CACnB,CAAC;AAEF,MAAM,iBAAiB,GAAa,EAAE,CAAC;AAyBvC,IAAI,YAAY,GAA2B,IAAI,CAAC;AAEhD,SAAS,UAAU;IAClB,IAAI,YAAY;QAAE,OAAO,YAAY,CAAC;IACtC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC9B,YAAY,GAAG,EAAE,CAAC;QAClB,OAAO,YAAY,CAAC;IACrB,CAAC;IAED,MAAM,OAAO,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IACnD,IAAI,CAAC;QACJ,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAoB,CAAC;QACtD,OAAO,YAAY,CAAC;IACrB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,MAAM,IAAI,KAAK,CAAC,mBAAmB,WAAW,KAAK,OAAO,EAAE,CAAC,CAAC;IAC/D,CAAC;AACF,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,MAAoB;IAC5C,MAAM,GAAG,GAAG,MAAM,iBAAiB,CAAC;QACnC,QAAQ,EAAE,YAAY;QACtB,eAAe,EAAE,UAAU,EAAE,CAAC,gBAAgB;QAC9C,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB;QAChD,MAAM;KACN,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CACd,yCAAyC;YACzC,eAAe,WAAW,4CAA4C;YACtE,oDAAoD;YACpD,iDAAiD,CACjD,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC;AAED,SAAS,cAAc;IACtB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,WAAW,GAAG,GAAG,GAAG,UAAU,CAAC,QAAQ,CAAC;IAE9C,OAAO,iBAAiB,CAAC,MAAM,GAAG,CAAC,IAAI,iBAAiB,CAAC,CAAC,CAAC,GAAG,WAAW,EAAE,CAAC;QAC3E,iBAAiB,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;IAED,IAAI,iBAAiB,CAAC,MAAM,IAAI,UAAU,CAAC,WAAW,EAAE,CAAC;QACxD,MAAM,MAAM,GAAG,iBAAiB,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,QAAQ,GAAG,GAAG,CAAC;QAChE,MAAM,IAAI,KAAK,CAAC,8BAA8B,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;IAC5E,CAAC;IAED,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC;AAED,SAAS,oBAAoB,CAAC,OAAiB;IAC9C,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QAC3B,MAAM,MAAM,GAAG,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAClD,OAAO,4CAA4C,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB;IACpC,OAAO,mBAAmB,CAAC;QAC1B,QAAQ,EAAE,YAAY;QACtB,eAAe,EAAE,UAAU,EAAE,CAAC,gBAAgB;QAC9C,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB;KAChD,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,KAAa,EAAE,OAAO,GAAkB,EAAE;IACpF,cAAc,EAAE,CAAC;IAEjB,MAAM,UAAU,GAAG,eAAe,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IAEpE,eAAe,CAAC,eAAe,CAAC;QAC/B,IAAI,EAAE,iBAAiB,CAAC,MAAM;QAC9B,GAAG,EAAE,UAAU,CAAC,WAAW;QAC3B,eAAe,EAAE,iBAAiB,CAAC,CAAC,CAAC,IAAI,IAAI;QAC7C,QAAQ,EAAE,UAAU,CAAC,QAAQ;KAC7B,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/C,MAAM,UAAU,GAAG,OAAO,OAAO,CAAC,UAAU,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC;QAC/F,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;QAC3D,CAAC,CAAC,CAAC,CAAC;IAEL,MAAM,WAAW,GAA4B;QAC5C,KAAK,EAAE,OAAO;QACd,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QAC5C,UAAU,EAAE,IAAI;QAChB,wBAAwB,EAAE,KAAK;KAC/B,CAAC;IAEF,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;QAC3B,WAAW,CAAC,qBAAqB,GAAG,OAAO,CAAC,aAAa,CAAC;IAC3D,CAAC;IAED,IAAI,OAAO,CAAC,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7D,MAAM,SAAS,GAAG,oBAAoB,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QAC7D,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,WAAW,CAAC,oBAAoB,GAAG,SAAS,CAAC;QAC9C,CAAC;IACF,CAAC;IAED,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACJ,QAAQ,GAAG,MAAM,KAAK,CAAC,kBAAkB,EAAE;YAC1C,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACR,aAAa,EAAE,UAAU,MAAM,EAAE;gBACjC,cAAc,EAAE,kBAAkB;aAClC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;YACjC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACrD,CAAC,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,MAAM,eAAe,GAAG,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC1D,IAAI,eAAe,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YACrD,eAAe,CAAC,WAAW,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;QAC5C,CAAC;aAAM,CAAC;YACP,eAAe,CAAC,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;QACvD,CAAC;QACD,IAAI,eAAe,KAAK,OAAO;YAAE,MAAM,GAAG,CAAC;QAC3C,MAAM,aAAa,GAAG,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;QACjD,IAAI,GAAG,YAAY,KAAK;YAAE,aAAa,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;QACxD,MAAM,aAAa,CAAC;IACrB,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QAClB,eAAe,CAAC,WAAW,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;QACzD,MAAM,SAAS,GAAG,gBAAgB,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,CAAC,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,wBAAwB,QAAQ,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC,CAAC;IAC1E,CAAC;IAED,IAAI,IAA6B,CAAC;IAClC,IAAI,CAAC;QACJ,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA4B,CAAC;IAC3D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,eAAe,CAAC,WAAW,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;QACzD,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,MAAM,IAAI,KAAK,CAAC,yCAAyC,OAAO,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,MAAM,MAAM,GAAI,IAAI,CAAC,OAAqD,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;IACxG,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;IAEtE,MAAM,OAAO,GAAmB,EAAE,CAAC;IACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACjE,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAC9B,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAClC,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;QACxE,CAAC;aAAM,IAAI,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,OAAO,QAAQ,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;YACzF,OAAO,CAAC,IAAI,CAAC;gBACZ,KAAK,EAAE,QAAQ,CAAC,KAAK,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE;gBAC1C,GAAG,EAAE,QAAQ,CAAC,GAAG;gBACjB,OAAO,EAAE,EAAE;aACX,CAAC,CAAC;QACJ,CAAC;IACF,CAAC;IAED,eAAe,CAAC,WAAW,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACzD,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AAC5B,CAAC","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { activityMonitor } from \"./activity.ts\";\nimport type { ExtractedContent } from \"./extract.ts\";\nimport { hasCredentialSource, redactCredential, resolveCredential } from \"./credential-source.ts\";\nimport { getWebSearchConfigPath } from \"./utils.ts\";\n\nconst PERPLEXITY_API_URL = \"https://api.perplexity.ai/chat/completions\";\nconst CONFIG_PATH = getWebSearchConfigPath();\n\nconst RATE_LIMIT = {\n\tmaxRequests: 10,\n\twindowMs: 60 * 1000,\n};\n\nconst requestTimestamps: number[] = [];\n\nexport interface SearchResult {\n\ttitle: string;\n\turl: string;\n\tsnippet: string;\n}\n\nexport interface SearchResponse {\n\tanswer: string;\n\tresults: SearchResult[];\n\tinlineContent?: ExtractedContent[];\n}\n\nexport interface SearchOptions {\n\tnumResults?: number;\n\trecencyFilter?: \"day\" | \"week\" | \"month\" | \"year\";\n\tdomainFilter?: string[];\n\tsignal?: AbortSignal;\n}\n\ninterface WebSearchConfig {\n\tperplexityApiKey?: unknown;\n}\n\nlet cachedConfig: WebSearchConfig | null = null;\n\nfunction loadConfig(): WebSearchConfig {\n\tif (cachedConfig) return cachedConfig;\n\tif (!existsSync(CONFIG_PATH)) {\n\t\tcachedConfig = {};\n\t\treturn cachedConfig;\n\t}\n\n\tconst content = readFileSync(CONFIG_PATH, \"utf-8\");\n\ttry {\n\t\tcachedConfig = JSON.parse(content) as WebSearchConfig;\n\t\treturn cachedConfig;\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tthrow new Error(`Failed to parse ${CONFIG_PATH}: ${message}`);\n\t}\n}\n\nasync function getApiKey(signal?: AbortSignal): Promise<string> {\n\tconst key = await resolveCredential({\n\t\tprovider: \"Perplexity\",\n\t\tconfiguredValue: loadConfig().perplexityApiKey,\n\t\tenvironmentValue: process.env.PERPLEXITY_API_KEY,\n\t\tsignal,\n\t});\n\tif (!key) {\n\t\tthrow new Error(\n\t\t\t\"Perplexity API key not found. Either:\\n\" +\n\t\t\t` 1. Create ${CONFIG_PATH} with { \"perplexityApiKey\": \"your-key\" }\\n` +\n\t\t\t\" 2. Set PERPLEXITY_API_KEY environment variable\\n\" +\n\t\t\t\"Get a key at https://perplexity.ai/settings/api\"\n\t\t);\n\t}\n\treturn key;\n}\n\nfunction checkRateLimit(): void {\n\tconst now = Date.now();\n\tconst windowStart = now - RATE_LIMIT.windowMs;\n\n\twhile (requestTimestamps.length > 0 && requestTimestamps[0] < windowStart) {\n\t\trequestTimestamps.shift();\n\t}\n\n\tif (requestTimestamps.length >= RATE_LIMIT.maxRequests) {\n\t\tconst waitMs = requestTimestamps[0] + RATE_LIMIT.windowMs - now;\n\t\tthrow new Error(`Rate limited. Try again in ${Math.ceil(waitMs / 1000)}s`);\n\t}\n\n\trequestTimestamps.push(now);\n}\n\nfunction validateDomainFilter(domains: string[]): string[] {\n\treturn domains.filter((d) => {\n\t\tconst domain = d.startsWith(\"-\") ? d.slice(1) : d;\n\t\treturn /^[a-zA-Z0-9][a-zA-Z0-9-_.]*\\.[a-zA-Z]{2,}$/.test(domain);\n\t});\n}\n\nexport function isPerplexityAvailable(): boolean {\n\treturn hasCredentialSource({\n\t\tprovider: \"Perplexity\",\n\t\tconfiguredValue: loadConfig().perplexityApiKey,\n\t\tenvironmentValue: process.env.PERPLEXITY_API_KEY,\n\t});\n}\n\nexport async function searchWithPerplexity(query: string, options: SearchOptions = {}): Promise<SearchResponse> {\n\tcheckRateLimit();\n\n\tconst activityId = activityMonitor.logStart({ type: \"api\", query });\n\n\tactivityMonitor.updateRateLimit({\n\t\tused: requestTimestamps.length,\n\t\tmax: RATE_LIMIT.maxRequests,\n\t\toldestTimestamp: requestTimestamps[0] ?? null,\n\t\twindowMs: RATE_LIMIT.windowMs,\n\t});\n\n\tconst apiKey = await getApiKey(options.signal);\n\tconst numResults = typeof options.numResults === \"number\" && Number.isFinite(options.numResults)\n\t\t? Math.max(1, Math.min(Math.floor(options.numResults), 20))\n\t\t: 5;\n\n\tconst requestBody: Record<string, unknown> = {\n\t\tmodel: \"sonar\",\n\t\tmessages: [{ role: \"user\", content: query }],\n\t\tmax_tokens: 1024,\n\t\treturn_related_questions: false,\n\t};\n\n\tif (options.recencyFilter) {\n\t\trequestBody.search_recency_filter = options.recencyFilter;\n\t}\n\n\tif (options.domainFilter && options.domainFilter.length > 0) {\n\t\tconst validated = validateDomainFilter(options.domainFilter);\n\t\tif (validated.length > 0) {\n\t\t\trequestBody.search_domain_filter = validated;\n\t\t}\n\t}\n\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(PERPLEXITY_API_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${apiKey}`,\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t},\n\t\t\tbody: JSON.stringify(requestBody),\n\t\t\t...(options.signal ? { signal: options.signal } : {}),\n\t\t});\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tconst redactedMessage = redactCredential(message, apiKey);\n\t\tif (redactedMessage.toLowerCase().includes(\"abort\")) {\n\t\t\tactivityMonitor.logComplete(activityId, 0);\n\t\t} else {\n\t\t\tactivityMonitor.logError(activityId, redactedMessage);\n\t\t}\n\t\tif (redactedMessage === message) throw err;\n\t\tconst redactedError = new Error(redactedMessage);\n\t\tif (err instanceof Error) redactedError.name = err.name;\n\t\tthrow redactedError;\n\t}\n\n\tif (!response.ok) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tconst errorText = redactCredential(await response.text(), apiKey);\n\t\tthrow new Error(`Perplexity API error ${response.status}: ${errorText}`);\n\t}\n\n\tlet data: Record<string, unknown>;\n\ttry {\n\t\tdata = (await response.json()) as Record<string, unknown>;\n\t} catch (err) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tthrow new Error(`Perplexity API returned invalid JSON: ${message}`);\n\t}\n\n\tconst answer = (data.choices as Array<{ message?: { content?: string } }>)?.[0]?.message?.content || \"\";\n\tconst citations = Array.isArray(data.citations) ? data.citations : [];\n\n\tconst results: SearchResult[] = [];\n\tfor (let i = 0; i < Math.min(citations.length, numResults); i++) {\n\t\tconst citation = citations[i];\n\t\tif (typeof citation === \"string\") {\n\t\t\tresults.push({ title: `Source ${i + 1}`, url: citation, snippet: \"\" });\n\t\t} else if (citation && typeof citation === \"object\" && typeof citation.url === \"string\") {\n\t\t\tresults.push({\n\t\t\t\ttitle: citation.title || `Source ${i + 1}`,\n\t\t\t\turl: citation.url,\n\t\t\t\tsnippet: \"\",\n\t\t\t});\n\t\t}\n\t}\n\n\tactivityMonitor.logComplete(activityId, response.status);\n\treturn { answer, results };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"perplexity.js","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/perplexity.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { activityMonitor } from \"./activity.ts\";\nimport type { ExtractedContent } from \"./extract.ts\";\nimport { hasCredentialSource, redactCredential, resolveCredential } from \"./credential-source.ts\";\nimport { getWebSearchConfigPath } from \"./utils.ts\";\n\nconst PERPLEXITY_API_URL = \"https://api.perplexity.ai/chat/completions\";\nconst CONFIG_PATH = getWebSearchConfigPath();\n\nconst RATE_LIMIT = {\n\tmaxRequests: 10,\n\twindowMs: 60 * 1000,\n};\n\nconst requestTimestamps: number[] = [];\n\nexport interface SearchResult {\n\ttitle: string;\n\turl: string;\n\tsnippet: string;\n}\n\nexport interface SearchResponse {\n\tanswer: string;\n\tresults: SearchResult[];\n\tinlineContent?: ExtractedContent[];\n}\n\nexport interface SearchOptions {\n\tnumResults?: number;\n\trecencyFilter?: \"day\" | \"week\" | \"month\" | \"year\";\n\tdomainFilter?: string[];\n\tsignal?: AbortSignal;\n}\n\ninterface WebSearchConfig {\n\tperplexityApiKey?: unknown;\n}\n\nlet cachedConfig: WebSearchConfig | null = null;\n\nfunction loadConfig(): WebSearchConfig {\n\tif (cachedConfig) return cachedConfig;\n\tif (!existsSync(CONFIG_PATH)) {\n\t\tcachedConfig = {};\n\t\treturn cachedConfig;\n\t}\n\n\tconst content = readFileSync(CONFIG_PATH, \"utf-8\");\n\ttry {\n\t\tcachedConfig = JSON.parse(content) as WebSearchConfig;\n\t\treturn cachedConfig;\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tthrow new Error(`Failed to parse ${CONFIG_PATH}: ${message}`);\n\t}\n}\n\nasync function getApiKey(signal?: AbortSignal): Promise<string> {\n\tconst key = await resolveCredential({\n\t\tprovider: \"Perplexity\",\n\t\tconfiguredValue: loadConfig().perplexityApiKey,\n\t\tenvironmentValue: process.env.PERPLEXITY_API_KEY,\n\t\tsignal,\n\t});\n\tif (!key) {\n\t\tthrow new Error(\n\t\t\t\"Perplexity API key not found. Either:\\n\" +\n\t\t\t` 1. Create ${CONFIG_PATH} with { \"perplexityApiKey\": \"your-key\" }\\n` +\n\t\t\t\" 2. Set PERPLEXITY_API_KEY environment variable\\n\" +\n\t\t\t\"Get a key at https://perplexity.ai/settings/api\"\n\t\t);\n\t}\n\treturn key;\n}\n\nfunction checkRateLimit(): void {\n\tconst now = Date.now();\n\tconst windowStart = now - RATE_LIMIT.windowMs;\n\n\twhile (requestTimestamps.length > 0 && requestTimestamps[0] < windowStart) {\n\t\trequestTimestamps.shift();\n\t}\n\n\tif (requestTimestamps.length >= RATE_LIMIT.maxRequests) {\n\t\tconst waitMs = requestTimestamps[0] + RATE_LIMIT.windowMs - now;\n\t\tthrow new Error(`Rate limited. Try again in ${Math.ceil(waitMs / 1000)}s`);\n\t}\n\n\trequestTimestamps.push(now);\n}\n\nfunction validateDomainFilter(domains: string[]): string[] {\n\treturn domains.filter((d) => {\n\t\tconst domain = d.startsWith(\"-\") ? d.slice(1) : d;\n\t\treturn /^[a-zA-Z0-9][a-zA-Z0-9-_.]*\\.[a-zA-Z]{2,}$/.test(domain);\n\t});\n}\n\nexport function isPerplexityAvailable(): boolean {\n\treturn hasCredentialSource({\n\t\tprovider: \"Perplexity\",\n\t\tconfiguredValue: loadConfig().perplexityApiKey,\n\t\tenvironmentValue: process.env.PERPLEXITY_API_KEY,\n\t});\n}\n\n/** Hard ceiling on kept citations, matching the `numResults` clamp. */\nconst MAX_CITATIONS = 20;\n\n// Preserve citation numbering by keeping the prefix through the highest cited index, capped at 20.\nfunction citationsToKeep(answer: string, available: number, numResults: number): number {\n\tlet highestCited = 0;\n\tfor (const match of answer.matchAll(/\\[(\\d{1,3})\\]/g)) {\n\t\thighestCited = Math.max(highestCited, Number(match[1]));\n\t}\n\treturn Math.min(available, MAX_CITATIONS, Math.max(numResults, highestCited));\n}\n\nexport async function searchWithPerplexity(query: string, options: SearchOptions = {}): Promise<SearchResponse> {\n\tcheckRateLimit();\n\n\tconst activityId = activityMonitor.logStart({ type: \"api\", query });\n\n\tactivityMonitor.updateRateLimit({\n\t\tused: requestTimestamps.length,\n\t\tmax: RATE_LIMIT.maxRequests,\n\t\toldestTimestamp: requestTimestamps[0] ?? null,\n\t\twindowMs: RATE_LIMIT.windowMs,\n\t});\n\n\tconst apiKey = await getApiKey(options.signal);\n\tconst numResults = typeof options.numResults === \"number\" && Number.isFinite(options.numResults)\n\t\t? Math.max(1, Math.min(Math.floor(options.numResults), 20))\n\t\t: 5;\n\n\tconst requestBody: Record<string, unknown> = {\n\t\tmodel: \"sonar\",\n\t\tmessages: [{ role: \"user\", content: query }],\n\t\tmax_tokens: 1024,\n\t\treturn_related_questions: false,\n\t};\n\n\tif (options.recencyFilter) {\n\t\trequestBody.search_recency_filter = options.recencyFilter;\n\t}\n\n\tif (options.domainFilter && options.domainFilter.length > 0) {\n\t\tconst validated = validateDomainFilter(options.domainFilter);\n\t\tif (validated.length > 0) {\n\t\t\trequestBody.search_domain_filter = validated;\n\t\t}\n\t}\n\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(PERPLEXITY_API_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${apiKey}`,\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t},\n\t\t\tbody: JSON.stringify(requestBody),\n\t\t\t...(options.signal ? { signal: options.signal } : {}),\n\t\t});\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tconst redactedMessage = redactCredential(message, apiKey);\n\t\tif (redactedMessage.toLowerCase().includes(\"abort\")) {\n\t\t\tactivityMonitor.logComplete(activityId, 0);\n\t\t} else {\n\t\t\tactivityMonitor.logError(activityId, redactedMessage);\n\t\t}\n\t\tif (redactedMessage === message) throw err;\n\t\tconst redactedError = new Error(redactedMessage);\n\t\tif (err instanceof Error) redactedError.name = err.name;\n\t\tthrow redactedError;\n\t}\n\n\tif (!response.ok) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tconst errorText = redactCredential(await response.text(), apiKey);\n\t\tthrow new Error(`Perplexity API error ${response.status}: ${errorText}`);\n\t}\n\n\tlet data: Record<string, unknown>;\n\ttry {\n\t\tdata = (await response.json()) as Record<string, unknown>;\n\t} catch (err) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tthrow new Error(`Perplexity API returned invalid JSON: ${message}`);\n\t}\n\n\tconst answer = (data.choices as Array<{ message?: { content?: string } }>)?.[0]?.message?.content || \"\";\n\tconst citations = Array.isArray(data.citations) ? data.citations : [];\n\n\tconst results: SearchResult[] = [];\n\tconst citationCount = citationsToKeep(answer, citations.length, numResults);\n\tfor (let i = 0; i < citationCount; i++) {\n\t\tconst citation = citations[i];\n\t\tif (typeof citation === \"string\") {\n\t\t\tresults.push({ title: `Source ${i + 1}`, url: citation, snippet: \"\" });\n\t\t} else if (citation && typeof citation === \"object\" && typeof citation.url === \"string\") {\n\t\t\tresults.push({\n\t\t\t\ttitle: citation.title || `Source ${i + 1}`,\n\t\t\t\turl: citation.url,\n\t\t\t\tsnippet: \"\",\n\t\t\t});\n\t\t}\n\t}\n\n\tactivityMonitor.logComplete(activityId, response.status);\n\treturn { answer, results };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/utils.ts"],"names":[],"mappings":"AAQA,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAED,UAAU,iBAAiB;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,OAAO,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAgCpE;AAMD,wBAAsB,4BAA4B,CACjD,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,EACjB,iBAAiB,EAAE,SAAS,MAAM,EAAE,GAClC,OAAO,CAAC,QAAQ,CAAC,CAmCnB;AAED,MAAM,WAAW,oBAAoB;IACpC,8DAA8D;IAC9D,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACb;AAUD,kFAAkF;AAClF,wBAAgB,2BAA2B,IAAI,oBAAoB,CAyBlE;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAM/C;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAa9F;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAOpD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAOnD;AAID,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkB/E;AA0BD,wBAAgB,YAAY,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAKzE;AAED,wBAAgB,cAAc,IAAI,MAAM,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/utils.ts"],"names":[],"mappings":"AAQA,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAED,UAAU,iBAAiB;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,OAAO,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAgCpE;AAMD,wBAAsB,4BAA4B,CACjD,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,EACjB,iBAAiB,EAAE,SAAS,MAAM,EAAE,GAClC,OAAO,CAAC,QAAQ,CAAC,CAmCnB;AAED,MAAM,WAAW,oBAAoB;IACpC,8DAA8D;IAC9D,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACb;AAUD,kFAAkF;AAClF,wBAAgB,2BAA2B,IAAI,oBAAoB,CAyBlE;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAM/C;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAa9F;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAOpD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAOnD;AAID,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkB/E;AA0BD,wBAAgB,YAAY,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAKzE;AAED,wBAAgB,cAAc,IAAI,MAAM,GAAG,IAAI,CAE9C;AAED,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAkBD,iEAAiE;AACjE,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAMpD;AAED,MAAM,WAAW,kBAAmB,SAAQ,WAAW;IACtD,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAOD,4GAA4G;AAC5G,wBAAgB,uBAAuB,IAAI,IAAI,CAsB9C"}
|
|
@@ -220,8 +220,7 @@ export function runWithProxy(proxy, fn) {
|
|
|
220
220
|
return proxyStorage.run(normalized, fn);
|
|
221
221
|
}
|
|
222
222
|
export function getActiveProxy() {
|
|
223
|
-
|
|
224
|
-
return scoped !== undefined ? scoped : loadConfiguredProxy();
|
|
223
|
+
return proxyStorage.getStore() ?? null;
|
|
225
224
|
}
|
|
226
225
|
export function hasScopedProxyDecision() {
|
|
227
226
|
return proxyStorage.getStore() !== undefined;
|