@vellumai/assistant 0.12.3-staging.1 → 0.12.3-staging.2
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/ARCHITECTURE.md +43 -29
- package/Dockerfile +63 -0
- package/docs/architecture/security.md +10 -5
- package/docs/architecture/turn-actor.md +2 -0
- package/docs/desktop-browser-cli.md +45 -4
- package/docs/live-voice-task-outcomes.md +100 -0
- package/docs/mode-sessions.md +183 -0
- package/docs/voice-input-diagnostics.md +58 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +2 -1
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +2 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +20 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +4 -1
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +38 -7
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +5 -6
- package/node_modules/@vellumai/service-contracts/package.json +2 -1
- package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +4 -8
- package/openapi.yaml +665 -14
- package/package.json +1 -1
- package/scripts/smoke-desktop-browser-cli.ts +10 -26
- package/scripts/smoke-desktop-window-theme.ts +2 -3
- package/src/__tests__/agent-loop-output-hooks.test.ts +150 -1
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +87 -19
- package/src/__tests__/annotate-activity-metadata.test.ts +3 -1
- package/src/__tests__/annotate-risk-options.test.ts +2 -0
- package/src/__tests__/answered-question-persistence.test.ts +2 -0
- package/src/__tests__/anthropic-gateway-shared.test.ts +22 -0
- package/src/__tests__/approval-message-composer.test.ts +1 -118
- package/src/__tests__/approval-routes-http.test.ts +3 -0
- package/src/__tests__/assistant-event-hub-connection-history.test.ts +111 -0
- package/src/__tests__/assistant-event-hub-targeted.test.ts +50 -0
- package/src/__tests__/assistant-event-targeting.test.ts +186 -0
- package/src/__tests__/assistant-stream-state.test.ts +29 -9
- package/src/__tests__/browser-fill-credential.test.ts +11 -22
- package/src/__tests__/btw-routes.test.ts +4 -1
- package/src/__tests__/build-persisted-content.test.ts +1 -1
- package/src/__tests__/call-conversation-messages.test.ts +5 -0
- package/src/__tests__/call-recovery.test.ts +7 -2
- package/src/__tests__/call-routes-http.test.ts +12 -0
- package/src/__tests__/call-store.test.ts +7 -2
- package/src/__tests__/channel-retry-sweep.test.ts +9 -0
- package/src/__tests__/chat-reveal-guard-priming.test.ts +2 -0
- package/src/__tests__/checker.test.ts +11 -3
- package/src/__tests__/client-os-metadata-persistence.test.ts +35 -1
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +0 -25
- package/src/__tests__/computer-use-tools.test.ts +1 -233
- package/src/__tests__/config-model-image-provider.test.ts +39 -0
- package/src/__tests__/config-schema.test.ts +16 -0
- package/src/__tests__/config-watcher.test.ts +24 -0
- package/src/__tests__/context-search-agent-runner.test.ts +260 -1
- package/src/__tests__/context-search-fanout.test.ts +1 -1
- package/src/__tests__/context-search-types.test.ts +7 -7
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +8 -2
- package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop.test.ts +546 -16
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +53 -1
- package/src/__tests__/conversation-evictor.test.ts +62 -37
- package/src/__tests__/conversation-history-boundary-repair-failure.test.ts +174 -0
- package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +2 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +2 -0
- package/src/__tests__/conversation-retry-route.test.ts +22 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +2 -0
- package/src/__tests__/conversation-routes-enabled-plugins.test.ts +2 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +10 -0
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +2 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +29 -0
- package/src/__tests__/conversation-surface-snapshots.test.ts +543 -0
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +151 -0
- package/src/__tests__/conversation-surfaces-point-at-budget.test.ts +63 -1
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +23 -0
- package/src/__tests__/conversation-undo.test.ts +61 -0
- package/src/__tests__/credential-execution-client.test.ts +6 -6
- package/src/__tests__/credential-prompt-route.test.ts +35 -3
- package/src/__tests__/cu-unified-flow.test.ts +82 -1
- package/src/__tests__/db-mode-sessions-migration.test.ts +175 -0
- package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -0
- package/src/__tests__/dm-backfill.test.ts +91 -1
- package/src/__tests__/document-create-route.test.ts +88 -0
- package/src/__tests__/document-sync-tags.test.ts +27 -0
- package/src/__tests__/emit-signal-routing-intent.test.ts +142 -2
- package/src/__tests__/events-tail-route.test.ts +25 -0
- package/src/__tests__/evict-conversations-for-reload.test.ts +57 -8
- package/src/__tests__/guardian-action-sweep.test.ts +16 -0
- package/src/__tests__/guardian-dispatch.test.ts +13 -0
- package/src/__tests__/headless-browser-interactions.test.ts +64 -20
- package/src/__tests__/heartbeat-service.test.ts +2 -59
- package/src/__tests__/helpers/mock-conversation.ts +21 -0
- package/src/__tests__/helpers/native-web-search-harness.ts +2 -0
- package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +5 -0
- package/src/__tests__/host-cu-proxy.test.ts +46 -2
- package/src/__tests__/http-user-message-parity.test.ts +2 -0
- package/src/__tests__/image-credentials.test.ts +49 -0
- package/src/__tests__/image-service-dispatcher.test.ts +45 -0
- package/src/__tests__/inference-profile-session-handler.test.ts +1 -1
- package/src/__tests__/interrupt-on-send.test.ts +57 -43
- package/src/__tests__/interrupt-turn-note.test.ts +5 -6
- package/src/__tests__/llm-catalog-parity.test.ts +2 -2
- package/src/__tests__/media-generate-image.test.ts +49 -1
- package/src/__tests__/message-provenance-contact-id.test.ts +69 -0
- package/src/__tests__/migration-export-to-gcs.test.ts +142 -0
- package/src/__tests__/mode-session-history.test.ts +245 -0
- package/src/__tests__/mode-session-recovery.test.ts +222 -0
- package/src/__tests__/mode-session-wire.test.ts +141 -0
- package/src/__tests__/notification-guardian-path.test.ts +7 -0
- package/src/__tests__/notification-telegram-adapter.test.ts +2 -2
- package/src/__tests__/notification-vellum-adapter.test.ts +34 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +12 -0
- package/src/__tests__/oauth-providers-routes.test.ts +1 -0
- package/src/__tests__/outbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/persistence-secret-redaction.test.ts +2 -0
- package/src/__tests__/plugin-api-provider.test.ts +5 -0
- package/src/__tests__/plugin-api-resolve-credential.test.ts +97 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +9 -0
- package/src/__tests__/process-message-display-content.test.ts +56 -0
- package/src/__tests__/reaction-persistence.test.ts +5 -0
- package/src/__tests__/request-secret-standalone-channel-gate.test.ts +25 -9
- package/src/__tests__/runtime-events-sse-reconnect.test.ts +1 -1
- package/src/__tests__/scripted-turn-metadata-persistence.test.ts +73 -0
- package/src/__tests__/secret-ingress-http.test.ts +2 -0
- package/src/__tests__/secure-keys.test.ts +43 -1
- package/src/__tests__/send-endpoint-busy.test.ts +163 -1
- package/src/__tests__/server-history-render.test.ts +91 -1
- package/src/__tests__/settings-routes.test.ts +50 -1
- package/src/__tests__/skill-script-runner-sandbox.test.ts +32 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +1 -2
- package/src/__tests__/subagent-manager-notify.test.ts +1 -2
- package/src/__tests__/subagent-notify-parent.test.ts +146 -39
- package/src/__tests__/subagent-notify-stale-rebuild.test.ts +2 -4
- package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +2 -0
- package/src/__tests__/thread-backfill.test.ts +53 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +2 -0
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +3 -1
- package/src/__tests__/tool-start-timestamp.test.ts +2 -0
- package/src/__tests__/twilio-routes.test.ts +1 -0
- package/src/__tests__/web-search-backend-failure.test.ts +1 -1
- package/src/activation/progress-store.test.ts +12 -7
- package/src/agent/loop.ts +99 -41
- package/src/api/events/assistant-turn-start.ts +3 -0
- package/src/api/events/generation-handoff.ts +2 -0
- package/src/api/events/message-complete.ts +2 -0
- package/src/api/events/notification-conversation-created.ts +14 -16
- package/src/api/events/notification-intent.ts +4 -2
- package/src/api/events/tool-result.ts +85 -0
- package/src/api/events/tool-use-start.ts +3 -0
- package/src/api/events/user-message-echo.ts +3 -0
- package/src/api/index.ts +31 -6
- package/src/api/mode-session.test.ts +131 -0
- package/src/api/mode-session.ts +148 -0
- package/src/api/remember-tool.ts +15 -0
- package/src/api/responses/conversation-message.ts +6 -0
- package/src/approvals/AGENTS.md +4 -2
- package/src/browser/__tests__/operations.test.ts +29 -0
- package/src/browser/operation-meta.ts +2 -1
- package/src/browser/operations.ts +29 -0
- package/src/browser/virtual-desktop-target.ts +2 -8
- package/src/bundler/bundle-signer.ts +1 -3
- package/src/calls/__tests__/barge-in-guard.test.ts +3 -0
- package/src/calls/__tests__/call-controller.test.ts +94 -0
- package/src/calls/__tests__/call-funnel-telemetry.test.ts +204 -0
- package/src/calls/__tests__/voice-control-protocol.test.ts +15 -0
- package/src/calls/__tests__/voice-escalation-judge.test.ts +209 -0
- package/src/calls/__tests__/voice-leg-coordinator.test.ts +168 -0
- package/src/{live-voice/__tests__/live-voice-metrics.test.ts → calls/__tests__/voice-metrics.test.ts} +32 -38
- package/src/calls/__tests__/voice-session-bridge.test.ts +576 -122
- package/src/calls/barge-in-guard.ts +5 -0
- package/src/calls/call-controller.ts +196 -1
- package/src/calls/call-domain.ts +4 -0
- package/src/calls/call-store.ts +87 -2
- package/src/calls/guardian-action-sweep.ts +22 -8
- package/src/calls/media-stream-audio-transcode.ts +1 -3
- package/src/calls/typesafe-noul.ts +156 -0
- package/src/calls/voice-control-protocol.ts +6 -0
- package/src/calls/voice-escalation-judge.ts +145 -0
- package/src/calls/voice-escalation-target.ts +10 -0
- package/src/calls/voice-leg-coordinator.ts +121 -3
- package/src/{live-voice/live-voice-metrics.ts → calls/voice-metrics.ts} +94 -87
- package/src/calls/voice-session-bridge.ts +256 -112
- package/src/calls/voice-triage-escalate.ts +7 -0
- package/src/cli/__tests__/roadmap-cli.test.ts +4 -41
- package/src/cli/commands/__tests__/notifications.test.ts +35 -10
- package/src/cli/commands/browser.help.ts +4 -5
- package/src/cli/commands/browser.ts +0 -1
- package/src/cli/commands/clients.help.ts +46 -0
- package/src/cli/commands/clients.ts +116 -0
- package/src/cli/commands/credentials.help.ts +6 -1
- package/src/cli/commands/notifications.help.ts +16 -2
- package/src/cli/commands/notifications.ts +30 -8
- package/src/cli/commands/roadmap.help.ts +18 -21
- package/src/cli/commands/roadmap.ts +4 -21
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +5 -2
- package/src/cli/lib/bundled-marketplace.json +84 -34
- package/src/cli/lib/plugin-marketplace.ts +8 -0
- package/src/cli/lib/publish-plugin.ts +1 -2
- package/src/config/__tests__/default-provider.test.ts +3 -1
- package/src/config/__tests__/memory-retrospective-schema.test.ts +14 -1
- package/src/config/bundled-skills/computer-use/SKILL.md +1 -1
- package/src/config/bundled-skills/computer-use/TOOLS.json +89 -1
- package/src/config/bundled-skills/image-studio/SKILL.md +17 -2
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +7 -11
- package/src/config/bundled-skills/sequences/TOOLS.json +1 -5
- package/src/config/call-site-defaults.ts +9 -0
- package/src/config/feature-flag-registry.json +16 -0
- package/src/config/profile-text-generation.test.ts +2 -2
- package/src/config/schemas/__tests__/tools.test.ts +31 -0
- package/src/config/schemas/call-site-catalog.ts +14 -0
- package/src/config/schemas/channels.ts +0 -18
- package/src/config/schemas/llm.ts +3 -1
- package/src/config/schemas/mcp.ts +2 -1
- package/src/config/schemas/memory-retrospective.ts +11 -2
- package/src/config/schemas/services.ts +15 -6
- package/src/config/schemas/tools.ts +10 -0
- package/src/config/session-groups-gate.ts +21 -0
- package/src/config/skills.ts +2 -6
- package/src/conversations/__tests__/message-consolidation.test.ts +149 -0
- package/src/conversations/message-consolidation.ts +102 -5
- package/src/credential-execution/ces-connect.test.ts +69 -0
- package/src/credential-execution/ces-connect.ts +115 -0
- package/src/credential-execution/ces-runtime.ts +55 -93
- package/src/credential-execution/executable-discovery.ts +1 -11
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +10 -1
- package/src/daemon/__tests__/inference-profile-notification.test.ts +2 -0
- package/src/daemon/browser-mode-session.test.ts +402 -0
- package/src/daemon/browser-mode-session.ts +186 -0
- package/src/daemon/computer-use-mode-session.test.ts +210 -0
- package/src/daemon/computer-use-mode-session.ts +105 -0
- package/src/daemon/config-watcher.ts +10 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +58 -10
- package/src/daemon/conversation-agent-loop.ts +219 -25
- package/src/daemon/conversation-evictor.ts +5 -24
- package/src/daemon/conversation-history.ts +10 -0
- package/src/daemon/conversation-interrupt-repair.ts +4 -43
- package/src/daemon/conversation-interrupt.ts +7 -11
- package/src/daemon/conversation-messaging.ts +58 -5
- package/src/daemon/conversation-mode-session.test.ts +1667 -0
- package/src/daemon/conversation-mode-session.ts +1008 -0
- package/src/daemon/conversation-process.ts +5 -0
- package/src/daemon/conversation-runtime-assembly.ts +10 -20
- package/src/daemon/conversation-skill-tools.ts +1 -0
- package/src/daemon/conversation-store.ts +4 -4
- package/src/daemon/conversation-surface-snapshots.ts +135 -0
- package/src/daemon/conversation-surfaces.ts +113 -5
- package/src/daemon/conversation-tool-setup.ts +8 -3
- package/src/daemon/conversation.ts +143 -41
- package/src/daemon/handlers/config-model.ts +7 -5
- package/src/daemon/handlers/shared.ts +55 -16
- package/src/daemon/host-cu-proxy.ts +51 -22
- package/src/daemon/lifecycle.ts +30 -13
- package/src/daemon/message-protocol.ts +0 -1
- package/src/daemon/message-provenance.ts +28 -4
- package/src/daemon/mode-session-startup-recovery.ts +23 -0
- package/src/daemon/mode-session-tracking.ts +54 -0
- package/src/daemon/process-message.ts +13 -4
- package/src/daemon/virtual-desktop-context.ts +21 -0
- package/src/desktop/__tests__/fake-desktop.ts +1 -0
- package/src/desktop/desktop-accessibility-script.ts +88 -0
- package/src/desktop/desktop-accessibility.test.ts +160 -0
- package/src/desktop/desktop-accessibility.ts +169 -0
- package/src/desktop/desktop-automation-lease.test.ts +76 -68
- package/src/desktop/desktop-automation-lease.ts +41 -50
- package/src/desktop/desktop-browser-endpoint.ts +4 -0
- package/src/desktop/desktop-computer-use-routing.test.ts +330 -0
- package/src/desktop/desktop-computer-use.test.ts +449 -0
- package/src/desktop/desktop-computer-use.ts +502 -0
- package/src/desktop/desktop-dependencies.ts +47 -293
- package/src/desktop/desktop-display.ts +2 -2
- package/src/desktop/desktop-panel-config.test.ts +13 -3
- package/src/desktop/desktop-panel-config.ts +109 -15
- package/src/desktop/desktop-session-manager.test.ts +69 -21
- package/src/desktop/desktop-session-manager.ts +76 -22
- package/src/desktop/desktop-stream-bridge.test.ts +11 -122
- package/src/desktop/desktop-stream-bridge.ts +6 -8
- package/src/desktop/desktop-window-theme.ts +5 -25
- package/src/desktop/virtual-desktop-feature.ts +52 -2
- package/src/desktop/virtual-desktop-platform.test.ts +5 -9
- package/src/documents/document-store.ts +23 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +22 -26
- package/src/heartbeat/heartbeat-service.ts +5 -33
- package/src/ipc/__tests__/browser-ipc.test.ts +215 -6
- package/src/ipc/assistant-server.ts +2 -0
- package/src/ipc/routes/__tests__/channel-reply-ipc-routes.test.ts +111 -0
- package/src/ipc/routes/channel-reply-ipc-routes.ts +73 -0
- package/src/live-voice/__tests__/continuation-judge.test.ts +151 -0
- package/src/live-voice/__tests__/live-activity-reporter.test.ts +154 -15
- package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +743 -31
- package/src/live-voice/__tests__/live-voice-look-follow-up.test.ts +191 -10
- package/src/live-voice/__tests__/live-voice-session-groups-gate.test.ts +87 -0
- package/src/live-voice/__tests__/live-voice-session-manager.test.ts +5 -1
- package/src/live-voice/__tests__/live-voice-sight-frame-echo.test.ts +41 -0
- package/src/live-voice/__tests__/live-voice-sight-frame.test.ts +1017 -9
- package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +224 -1
- package/src/live-voice/__tests__/live-voice-tts-session.test.ts +101 -0
- package/src/live-voice/__tests__/live-voice-tts.test.ts +44 -0
- package/src/live-voice/__tests__/live-voice-vad.test.ts +939 -75
- package/src/live-voice/__tests__/microphone-idle-gate.test.ts +87 -0
- package/src/live-voice/__tests__/session-controls.test.ts +23 -0
- package/src/live-voice/__tests__/task-outcomes.test.ts +117 -0
- package/src/live-voice/__tests__/voice-input-diagnostics.test.ts +117 -0
- package/src/live-voice/camera-mode-session.test.ts +265 -0
- package/src/live-voice/camera-mode-session.ts +277 -0
- package/src/live-voice/continuation-judge.ts +123 -0
- package/src/live-voice/live-activity-reporter.ts +115 -6
- package/src/live-voice/live-voice-manager.ts +36 -1
- package/src/live-voice/live-voice-photo.ts +88 -7
- package/src/live-voice/live-voice-session-manager.ts +15 -0
- package/src/live-voice/live-voice-session.ts +1443 -747
- package/src/live-voice/live-voice-tts.ts +22 -4
- package/src/live-voice/microphone-idle-gate.ts +56 -0
- package/src/live-voice/protocol.ts +171 -4
- package/src/live-voice/session-controls.ts +11 -3
- package/src/live-voice/task-outcomes.ts +131 -0
- package/src/live-voice/voice-input-diagnostics.ts +117 -0
- package/src/mcp/__tests__/manager-tool-caps.test.ts +63 -18
- package/src/mcp/__tests__/tool-caps.test.ts +28 -1
- package/src/mcp/manager.ts +3 -0
- package/src/mcp/tool-caps.ts +12 -4
- package/src/media/__tests__/image-models.test.ts +58 -0
- package/src/media/image-credentials.ts +5 -0
- package/src/media/image-models.ts +52 -0
- package/src/media/image-service.ts +8 -0
- package/src/media/openrouter-image-service.test.ts +133 -0
- package/src/media/openrouter-image-service.ts +153 -0
- package/src/media/types.ts +1 -1
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +65 -11
- package/src/messaging/providers/discord/send.ts +4 -17
- package/src/messaging/providers/discord/transport.ts +2 -2
- package/src/messaging/providers/outlook/client.ts +16 -22
- package/src/messaging/providers/telegram-bot/send.test.ts +236 -1
- package/src/messaging/providers/telegram-bot/send.ts +10 -7
- package/src/messaging/providers/telegram-bot/transport.ts +3 -10
- package/src/messaging/providers/whatsapp/send.test.ts +169 -4
- package/src/monitoring/__tests__/control.test.ts +17 -5
- package/src/monitoring/control.ts +15 -5
- package/src/notifications/AGENTS.md +1 -1
- package/src/notifications/README.md +83 -99
- package/src/notifications/__tests__/broadcaster.test.ts +1 -1
- package/src/notifications/__tests__/channel-allowlist.test.ts +39 -0
- package/src/notifications/__tests__/copy-composer.test.ts +1 -1
- package/src/notifications/__tests__/decision-engine.test.ts +79 -2
- package/src/notifications/__tests__/deterministic-checks.test.ts +10 -10
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +93 -4
- package/src/notifications/__tests__/notification-utils.test.ts +18 -0
- package/src/notifications/adapters/macos.ts +37 -46
- package/src/notifications/broadcaster.ts +5 -6
- package/src/notifications/channel-allowlist.ts +44 -0
- package/src/notifications/copy-composer.ts +0 -23
- package/src/notifications/decision-engine.ts +24 -14
- package/src/notifications/deterministic-checks.ts +1 -1
- package/src/notifications/emit-signal.ts +123 -37
- package/src/notifications/home-feed-side-effect.ts +9 -7
- package/src/notifications/notification-utils.ts +19 -0
- package/src/notifications/signal.ts +4 -19
- package/src/notifications/types.ts +15 -0
- package/src/oauth/connection-resolver.ts +1 -2
- package/src/oauth/oauth-store.ts +1 -3
- package/src/oauth/provider-serializer.ts +7 -0
- package/src/oauth/seed-providers.ts +30 -0
- package/src/onboarding/onboarding-events-store.ts +99 -12
- package/src/persistence/__tests__/client-connection-events-store.test.ts +322 -0
- package/src/persistence/client-connection-events-store.ts +377 -0
- package/src/persistence/conversation-crud.ts +55 -6
- package/src/persistence/conversation-mode-sessions.test.ts +424 -0
- package/src/persistence/conversation-mode-sessions.ts +460 -0
- package/src/persistence/conversation-queries.ts +6 -19
- package/src/persistence/llm-usage-store.ts +3 -9
- package/src/persistence/message-metadata.ts +25 -0
- package/src/persistence/migrations/381-create-conversation-mode-sessions.ts +41 -0
- package/src/persistence/migrations/382-create-client-connection-events.ts +40 -0
- package/src/persistence/migrations/__tests__/382-create-client-connection-events.test.ts +56 -0
- package/src/persistence/schema/conversations.ts +67 -0
- package/src/persistence/schema/infrastructure.ts +29 -0
- package/src/persistence/steps.ts +17 -0
- package/src/plugin-api/__tests__/plugin-name-env.test.ts +249 -0
- package/src/plugin-api/effective-context-window.ts +33 -0
- package/src/plugin-api/index.ts +24 -5
- package/src/plugin-api/plugin-name-env.ts +125 -0
- package/src/plugin-api/resolve-credential.ts +79 -20
- package/src/plugin-api/vision-support.test.ts +22 -0
- package/src/plugin-api/vision-support.ts +17 -5
- package/src/plugins/__tests__/active-plugin-env.test.ts +136 -0
- package/src/plugins/active-plugin-env.ts +51 -0
- package/src/plugins/defaults/index.ts +24 -0
- package/src/plugins/defaults/memory/__tests__/archive-removal-framing.test.ts +64 -0
- package/src/plugins/defaults/memory/__tests__/worker-control.test.ts +19 -6
- package/src/plugins/defaults/memory/context-search/agent-protocol.ts +9 -12
- package/src/plugins/defaults/memory/context-search/agent-runner.ts +78 -22
- package/src/plugins/defaults/memory/context-search/format.ts +51 -7
- package/src/plugins/defaults/memory/context-search/limits.ts +10 -12
- package/src/plugins/defaults/memory/context-search/recall-input.ts +38 -0
- package/src/plugins/defaults/memory/context-search/search.ts +8 -14
- package/src/plugins/defaults/memory/context-search/sources/conversations.ts +1 -0
- package/src/plugins/defaults/memory/context-search/types.ts +1 -11
- package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +11 -4
- package/src/plugins/defaults/memory/graph/tool-handlers.ts +12 -21
- package/src/plugins/defaults/memory/graph/tools.ts +35 -64
- package/src/plugins/defaults/memory/src/memory-eval-routes.ts +2 -3
- package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +5 -0
- package/src/plugins/defaults/memory/src/memory-item-routes.ts +2 -1
- package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +2 -2
- package/src/plugins/defaults/memory/tools.test.ts +124 -9
- package/src/plugins/defaults/memory/tools.ts +38 -11
- package/src/plugins/defaults/memory/v3/__tests__/pool-log-store.test.ts +165 -27
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +626 -27
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +46 -27
- package/src/plugins/defaults/memory/v3/orchestrate.ts +78 -38
- package/src/plugins/defaults/memory/v3/pool-log-store.ts +65 -79
- package/src/plugins/defaults/memory/v3/pool-select.test.ts +14 -5
- package/src/plugins/defaults/memory/v3/pool-select.ts +683 -44
- package/src/plugins/defaults/memory/worker-control.ts +15 -5
- package/src/plugins/defaults/task-progress/__tests__/registration.test.ts +70 -0
- package/src/plugins/defaults/task-progress/__tests__/task-progress-context.test.ts +380 -0
- package/src/plugins/defaults/task-progress/hooks/post-compact.ts +19 -0
- package/src/plugins/defaults/task-progress/hooks/user-prompt-submit.ts +24 -0
- package/src/plugins/defaults/task-progress/package.json +14 -0
- package/src/plugins/defaults/task-progress/src/apply-task-progress-context.ts +93 -0
- package/src/plugins/defaults/task-progress/src/format-task-progress-context.ts +67 -0
- package/src/providers/__tests__/context-overflow-error.test.ts +10 -0
- package/src/providers/__tests__/search-provider-catalog.test.ts +18 -0
- package/src/providers/anthropic/client.ts +10 -1
- package/src/providers/anthropic-gateway-shared.ts +6 -0
- package/src/providers/fetch-provider-catalog.ts +11 -0
- package/src/providers/gemini/client.ts +25 -8
- package/src/providers/inference/adapter-factory.ts +1 -1
- package/src/providers/jev/client.test.ts +10 -0
- package/src/providers/jev/client.ts +20 -4
- package/src/providers/model-catalog.ts +4 -3
- package/src/providers/openai/__tests__/chat-completions-extra-body.test.ts +94 -1
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +106 -1
- package/src/providers/openai/__tests__/chat-template-flatten.test.ts +24 -0
- package/src/providers/openai/__tests__/google-thought-signature.test.ts +1 -2
- package/src/providers/openai/chat-completions-provider.ts +100 -29
- package/src/providers/openai/google-thought-signature.ts +0 -6
- package/src/providers/openai/responses-provider.ts +23 -1
- package/src/providers/ratelimit.ts +1 -3
- package/src/providers/search-provider-catalog.ts +24 -0
- package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +24 -0
- package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +7 -1
- package/src/providers/speech-to-text/__tests__/vellum-managed-realtime.test.ts +50 -1
- package/src/providers/speech-to-text/deepgram-flux-frames.ts +11 -0
- package/src/providers/speech-to-text/vellum-managed-flux-realtime.ts +13 -0
- package/src/providers/types.ts +5 -0
- package/src/routes/control.ts +7 -5
- package/src/runtime/AGENTS.md +4 -2
- package/src/runtime/actor-trust-resolver.ts +3 -3
- package/src/runtime/agent-wake.ts +1 -1
- package/src/runtime/approval-message-composer.ts +3 -69
- package/src/runtime/assistant-event-hub.ts +73 -75
- package/src/runtime/assistant-event-publish-options.ts +7 -0
- package/src/runtime/assistant-event-targeting.ts +79 -0
- package/src/runtime/assistant-stream-state.ts +13 -100
- package/src/runtime/background-job-runner.ts +5 -5
- package/src/runtime/channel-retry-sweep.ts +1 -0
- package/src/runtime/guardian-action-message-composer.ts +8 -161
- package/src/runtime/guardian-reply-router.ts +28 -32
- package/src/runtime/http-types.ts +6 -0
- package/src/runtime/message-composer-types.ts +3 -61
- package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +67 -1
- package/src/runtime/migrations/vbundle-builder.ts +24 -1
- package/src/runtime/migrations/vbundle-import-analyzer.ts +13 -4
- package/src/runtime/migrations/vbundle-import-policy.ts +10 -0
- package/src/runtime/migrations/vbundle-importer.ts +4 -1
- package/src/runtime/migrations/vbundle-streaming-importer.ts +4 -1
- package/src/runtime/migrations/vbundle-validator.ts +1 -0
- package/src/runtime/pending-interactions-mode-session.test.ts +62 -0
- package/src/runtime/pending-interactions.ts +29 -0
- package/src/runtime/routes/__tests__/client-history-routes.test.ts +104 -0
- package/src/runtime/routes/__tests__/image-generation-routes.test.ts +97 -0
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/roadmap-routes.test.ts +29 -6
- package/src/runtime/routes/browser-context.ts +31 -11
- package/src/runtime/routes/browser-routes.ts +43 -4
- package/src/runtime/routes/btw-routes.ts +9 -4
- package/src/runtime/routes/client-routes.ts +108 -0
- package/src/runtime/routes/conversation-management-routes.ts +4 -1
- package/src/runtime/routes/conversation-routes.ts +113 -27
- package/src/runtime/routes/credential-prompt-routes.ts +4 -3
- package/src/runtime/routes/credential-routes.ts +1 -2
- package/src/runtime/routes/desktop-setup-routes.test.ts +9 -18
- package/src/runtime/routes/desktop-setup-routes.ts +4 -6
- package/src/runtime/routes/documents-routes.ts +51 -0
- package/src/runtime/routes/email-routes.ts +3 -7
- package/src/runtime/routes/events-routes.ts +75 -54
- package/src/runtime/routes/identity-routes.ts +1 -5
- package/src/runtime/routes/image-generation-routes.ts +8 -14
- package/src/runtime/routes/inbound-message-handler.ts +35 -38
- package/src/runtime/routes/inbound-stages/backfill-sender-provenance.test.ts +168 -0
- package/src/runtime/routes/inbound-stages/backfill-sender-provenance.ts +96 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +38 -9
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +2 -5
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +2 -0
- package/src/runtime/routes/llm-context-normalization.ts +1 -7
- package/src/runtime/routes/migration-routes.ts +73 -2
- package/src/runtime/routes/notification-routes.ts +10 -0
- package/src/runtime/routes/oauth-providers.ts +7 -0
- package/src/runtime/routes/plugins-routes.ts +6 -0
- package/src/runtime/routes/roadmap-routes.ts +47 -8
- package/src/runtime/routes/secret-routes.ts +1 -1
- package/src/runtime/routes/settings-routes.ts +10 -4
- package/src/runtime/routes/watcher-routes.ts +1 -3
- package/src/runtime/trust-class.test.ts +7 -6
- package/src/runtime/trust-class.ts +9 -17
- package/src/schedule/__tests__/worker-control.test.ts +36 -5
- package/src/schedule/worker-control.ts +15 -5
- package/src/security/secure-keys.ts +53 -103
- package/src/skills/clawhub.ts +3 -8
- package/src/skills/managed-store.ts +1 -5
- package/src/stt/types.ts +4 -0
- package/src/subagent/notify.ts +54 -34
- package/src/subagent/parent-notification.ts +6 -0
- package/src/telemetry/__tests__/phone-call-funnel.test.ts +72 -0
- package/src/telemetry/phone-call-funnel.ts +144 -0
- package/src/tools/__tests__/tool-schema-root-combinator-guard.test.ts +81 -0
- package/src/tools/ask-question/ask-question-tool.ts +6 -4
- package/src/tools/browser/browser-execution.ts +22 -59
- package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +561 -39
- package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +435 -39
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +1 -8
- package/src/tools/client-os.ts +15 -0
- package/src/tools/computer-use/skill-proxy-bridge.ts +1 -1
- package/src/tools/computer-use/target.ts +42 -0
- package/src/tools/document/document-tool.ts +13 -18
- package/src/tools/execution-target.ts +14 -16
- package/src/tools/host-terminal/host-shell.ts +4 -1
- package/src/tools/network/__tests__/web-fetch-tinyfish.test.ts +250 -0
- package/src/tools/network/__tests__/web-search.test.ts +203 -0
- package/src/tools/network/web-fetch.ts +274 -7
- package/src/tools/network/web-search.ts +468 -6
- package/src/tools/permission-checker.ts +3 -3
- package/src/tools/policy-context.ts +3 -1
- package/src/tools/skills/load.ts +2 -1
- package/src/tools/skills/sandbox-runner.ts +11 -2
- package/src/tools/skills/skill-script-runner.ts +7 -0
- package/src/tools/skills/skill-tool-factory.ts +15 -1
- package/src/tools/terminal/__tests__/safe-env.test.ts +11 -0
- package/src/tools/terminal/safe-env.ts +4 -0
- package/src/tools/terminal/shell.ts +2 -0
- package/src/tools/tool-approval-handler.ts +5 -1
- package/src/tools/tool-types.ts +3 -3
- package/src/tools/types.ts +8 -2
- package/src/util/__tests__/worker-process-command.test.ts +5 -4
- package/src/util/abort-reasons.ts +18 -26
- package/src/util/canonicalize-identity.test.ts +21 -0
- package/src/util/canonicalize-identity.ts +16 -0
- package/src/util/errors.ts +13 -3
- package/src/util/provider-error-patterns.ts +3 -0
- package/src/util/worker-process.ts +77 -35
- package/src/workspace/migrations/157-add-desktop-files-launcher.ts +94 -0
- package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +4 -10
- package/src/workspace/migrations/__tests__/157-add-desktop-files-launcher.test.ts +113 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/__tests__/computer-use-window-schema.test.ts +0 -24
- package/src/api/events/heartbeat-alert.ts +0 -20
- package/src/daemon/message-types/web-activity.ts +0 -65
- package/src/desktop/desktop-dependencies.test.ts +0 -131
- package/src/tools/computer-use/definitions.ts +0 -607
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { getConfig } from "../../config/loader.js";
|
|
2
1
|
import type {
|
|
3
2
|
WebSearchMetadata,
|
|
4
3
|
WebSearchResultItem,
|
|
5
|
-
} from "../../
|
|
4
|
+
} from "../../api/events/tool-result.js";
|
|
5
|
+
import { getConfig } from "../../config/loader.js";
|
|
6
6
|
import { RiskLevel } from "../../permissions/types.js";
|
|
7
7
|
import { getProviderKeyAsync } from "../../security/secure-keys.js";
|
|
8
8
|
import { wrapUntrustedContent } from "../../security/untrusted-content.js";
|
|
@@ -44,6 +44,7 @@ const PERPLEXITY_API_URL = "https://api.perplexity.ai/chat/completions";
|
|
|
44
44
|
const TAVILY_API_URL = "https://api.tavily.com/search";
|
|
45
45
|
const FIRECRAWL_API_URL = "https://api.firecrawl.dev/v2/search";
|
|
46
46
|
const FASTCRW_SEARCH_PATH = "/v1/search";
|
|
47
|
+
const TINYFISH_DEFAULT_SEARCH_API_BASE = "https://api.search.tinyfish.ai";
|
|
47
48
|
// Keenable is keyless by default: the public path needs no key (rate-limited);
|
|
48
49
|
// a key switches to the authenticated path and lifts the cap.
|
|
49
50
|
const KEENABLE_API_BASE_URL = "https://api.keenable.ai";
|
|
@@ -56,7 +57,9 @@ type WebSearchProvider =
|
|
|
56
57
|
| "tavily"
|
|
57
58
|
| "firecrawl"
|
|
58
59
|
| "keenable"
|
|
59
|
-
| "fastcrw"
|
|
60
|
+
| "fastcrw"
|
|
61
|
+
| "searxng"
|
|
62
|
+
| "tinyfish";
|
|
60
63
|
|
|
61
64
|
/**
|
|
62
65
|
* Arguments passed to every {@link WebSearchAdapter}. The full superset is
|
|
@@ -167,6 +170,38 @@ interface KeenableSearchResponse {
|
|
|
167
170
|
results?: KeenableSearchResult[];
|
|
168
171
|
}
|
|
169
172
|
|
|
173
|
+
interface SearxngSearchResult {
|
|
174
|
+
title?: string;
|
|
175
|
+
url?: string;
|
|
176
|
+
content?: string;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
interface SearxngSearchResponse {
|
|
180
|
+
query?: string;
|
|
181
|
+
results?: SearxngSearchResult[];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
interface TinyfishSearchResult {
|
|
185
|
+
position?: number;
|
|
186
|
+
site_name?: string;
|
|
187
|
+
title?: string;
|
|
188
|
+
snippet?: string;
|
|
189
|
+
url?: string;
|
|
190
|
+
date?: string;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
interface TinyfishSearchResponse {
|
|
194
|
+
query?: string;
|
|
195
|
+
results?: TinyfishSearchResult[];
|
|
196
|
+
total_results?: number;
|
|
197
|
+
page?: number;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const SEARXNG_MISSING_INSTANCE_MESSAGE =
|
|
201
|
+
"SearXNG needs an instance URL. Set API Base in Settings under Web Search.";
|
|
202
|
+
const SEARXNG_JSON_DISABLED_MESSAGE =
|
|
203
|
+
"This SearXNG instance did not return JSON. Enable the JSON format on the instance, or point API Base at an instance that allows it.";
|
|
204
|
+
|
|
170
205
|
function getWebSearchProvider(): WebSearchProvider {
|
|
171
206
|
const config = getConfig();
|
|
172
207
|
const configured = config.services["web-search"].provider ?? "perplexity";
|
|
@@ -573,6 +608,159 @@ function buildKeenableMetadata(
|
|
|
573
608
|
};
|
|
574
609
|
}
|
|
575
610
|
|
|
611
|
+
function formatSearxngResults(
|
|
612
|
+
data: SearxngSearchResponse,
|
|
613
|
+
query: string,
|
|
614
|
+
): string {
|
|
615
|
+
const results = data.results ?? [];
|
|
616
|
+
if (results.length === 0) {
|
|
617
|
+
return `No results found for "${query}".`;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
const lines: string[] = [`Web search results for "${query}":\n`];
|
|
621
|
+
for (let i = 0; i < results.length; i++) {
|
|
622
|
+
const r = results[i];
|
|
623
|
+
const title = r.title?.trim() || r.url?.trim() || "Untitled result";
|
|
624
|
+
lines.push(`${i + 1}. ${title}`);
|
|
625
|
+
if (r.url) {
|
|
626
|
+
lines.push(` URL: ${r.url}`);
|
|
627
|
+
}
|
|
628
|
+
if (r.content) {
|
|
629
|
+
lines.push(` ${r.content}`);
|
|
630
|
+
}
|
|
631
|
+
lines.push("");
|
|
632
|
+
}
|
|
633
|
+
return lines.join("\n");
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
function buildSearxngMetadata(
|
|
637
|
+
data: SearxngSearchResponse,
|
|
638
|
+
query: string,
|
|
639
|
+
durationMs: number,
|
|
640
|
+
): WebSearchMetadata {
|
|
641
|
+
const results = data.results ?? [];
|
|
642
|
+
const items: WebSearchResultItem[] = results.map((r, i) => {
|
|
643
|
+
const url = r.url ?? "";
|
|
644
|
+
const domain = extractDomain(url);
|
|
645
|
+
return {
|
|
646
|
+
rank: i + 1,
|
|
647
|
+
title: r.title?.trim() || url.trim() || "Untitled result",
|
|
648
|
+
url,
|
|
649
|
+
domain,
|
|
650
|
+
faviconUrl: faviconUrlForDomain(domain),
|
|
651
|
+
snippet: r.content?.trim() || undefined,
|
|
652
|
+
};
|
|
653
|
+
});
|
|
654
|
+
return {
|
|
655
|
+
query,
|
|
656
|
+
provider: "searxng",
|
|
657
|
+
resultCount: items.length,
|
|
658
|
+
durationMs,
|
|
659
|
+
results: items,
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
function formatTinyfishResults(
|
|
664
|
+
data: TinyfishSearchResponse,
|
|
665
|
+
query: string,
|
|
666
|
+
): string {
|
|
667
|
+
const results = data.results ?? [];
|
|
668
|
+
if (results.length === 0) {
|
|
669
|
+
return `No results found for "${query}".`;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
const lines: string[] = [`Web search results for "${query}":\n`];
|
|
673
|
+
for (let i = 0; i < results.length; i++) {
|
|
674
|
+
const result = results[i];
|
|
675
|
+
const title =
|
|
676
|
+
result.title?.trim() || result.url?.trim() || "Untitled result";
|
|
677
|
+
lines.push(`${i + 1}. ${title}`);
|
|
678
|
+
if (result.url) {
|
|
679
|
+
lines.push(` URL: ${result.url}`);
|
|
680
|
+
}
|
|
681
|
+
if (result.snippet) {
|
|
682
|
+
lines.push(` ${result.snippet}`);
|
|
683
|
+
}
|
|
684
|
+
if (result.date) {
|
|
685
|
+
lines.push(` Published: ${result.date}`);
|
|
686
|
+
}
|
|
687
|
+
lines.push("");
|
|
688
|
+
}
|
|
689
|
+
return lines.join("\n");
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
function buildTinyfishMetadata(
|
|
693
|
+
data: TinyfishSearchResponse,
|
|
694
|
+
query: string,
|
|
695
|
+
durationMs: number,
|
|
696
|
+
): WebSearchMetadata {
|
|
697
|
+
const results = data.results ?? [];
|
|
698
|
+
const items: WebSearchResultItem[] = results.map((result, index) => {
|
|
699
|
+
const url = result.url ?? "";
|
|
700
|
+
const domain = extractDomain(url);
|
|
701
|
+
return {
|
|
702
|
+
rank: index + 1,
|
|
703
|
+
title: result.title?.trim() || url.trim() || "Untitled result",
|
|
704
|
+
url,
|
|
705
|
+
domain,
|
|
706
|
+
faviconUrl: faviconUrlForDomain(domain),
|
|
707
|
+
snippet: result.snippet?.trim() || undefined,
|
|
708
|
+
};
|
|
709
|
+
});
|
|
710
|
+
return {
|
|
711
|
+
query,
|
|
712
|
+
provider: "tinyfish",
|
|
713
|
+
resultCount: items.length,
|
|
714
|
+
durationMs,
|
|
715
|
+
results: items,
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
function tinyfishRecencyMinutesForFreshness(
|
|
720
|
+
freshness: string | undefined,
|
|
721
|
+
): number | undefined {
|
|
722
|
+
switch (freshness) {
|
|
723
|
+
case "pd":
|
|
724
|
+
return 24 * 60;
|
|
725
|
+
case "pw":
|
|
726
|
+
return 7 * 24 * 60;
|
|
727
|
+
case "pm":
|
|
728
|
+
return 30 * 24 * 60;
|
|
729
|
+
case "py":
|
|
730
|
+
return 365 * 24 * 60;
|
|
731
|
+
default:
|
|
732
|
+
return undefined;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
/**
|
|
737
|
+
* Map the tool's `freshness` window onto SearXNG's `time_range`
|
|
738
|
+
* (`day` / `month` / `year`). SearXNG has no week filter, so `pw` is omitted.
|
|
739
|
+
*/
|
|
740
|
+
function searxngTimeRangeForFreshness(
|
|
741
|
+
freshness: string | undefined,
|
|
742
|
+
): "day" | "month" | "year" | undefined {
|
|
743
|
+
switch (freshness) {
|
|
744
|
+
case "pd":
|
|
745
|
+
return "day";
|
|
746
|
+
case "pm":
|
|
747
|
+
return "month";
|
|
748
|
+
case "py":
|
|
749
|
+
return "year";
|
|
750
|
+
default:
|
|
751
|
+
return undefined;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
function isNonJsonSearchBody(contentType: string, bodyText: string): boolean {
|
|
756
|
+
const type = contentType.toLowerCase();
|
|
757
|
+
if (type.includes("text/html") || type.includes("application/xhtml")) {
|
|
758
|
+
return true;
|
|
759
|
+
}
|
|
760
|
+
const trimmed = bodyText.trimStart();
|
|
761
|
+
return trimmed.startsWith("<");
|
|
762
|
+
}
|
|
763
|
+
|
|
576
764
|
/**
|
|
577
765
|
* Map the tool's `freshness` window onto a Keenable `published_after` date
|
|
578
766
|
* (YYYY-MM-DD). Keenable filters by absolute publication date rather than a
|
|
@@ -1358,6 +1546,261 @@ async function executeKeenableSearch(
|
|
|
1358
1546
|
);
|
|
1359
1547
|
}
|
|
1360
1548
|
|
|
1549
|
+
async function executeSearxngSearch(
|
|
1550
|
+
query: string,
|
|
1551
|
+
count: number,
|
|
1552
|
+
freshness: string | undefined,
|
|
1553
|
+
apiKey: string,
|
|
1554
|
+
signal?: AbortSignal,
|
|
1555
|
+
): Promise<ToolExecutionResult> {
|
|
1556
|
+
const startedAt = Date.now();
|
|
1557
|
+
const apiBase = getConfig().services["web-search"]?.apiBase?.trim() ?? "";
|
|
1558
|
+
if (apiBase.length === 0) {
|
|
1559
|
+
return errorResult(
|
|
1560
|
+
query,
|
|
1561
|
+
"searxng",
|
|
1562
|
+
startedAt,
|
|
1563
|
+
SEARXNG_MISSING_INSTANCE_MESSAGE,
|
|
1564
|
+
);
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
const params = new URLSearchParams({
|
|
1568
|
+
q: query,
|
|
1569
|
+
format: "json",
|
|
1570
|
+
});
|
|
1571
|
+
const timeRange = searxngTimeRangeForFreshness(freshness);
|
|
1572
|
+
if (timeRange) {
|
|
1573
|
+
params.set("time_range", timeRange);
|
|
1574
|
+
}
|
|
1575
|
+
const url = `${resolveProviderApiUrl(apiBase, "/search", apiBase)}?${params.toString()}`;
|
|
1576
|
+
|
|
1577
|
+
const headers: Record<string, string> = {
|
|
1578
|
+
Accept: "application/json",
|
|
1579
|
+
};
|
|
1580
|
+
const trimmedKey = apiKey.trim();
|
|
1581
|
+
if (trimmedKey.length > 0) {
|
|
1582
|
+
headers.Authorization = `Bearer ${trimmedKey}`;
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
for (let attempt = 0; attempt <= DEFAULT_MAX_RETRIES; attempt++) {
|
|
1586
|
+
let response: Response;
|
|
1587
|
+
try {
|
|
1588
|
+
response = await fetch(url, {
|
|
1589
|
+
headers,
|
|
1590
|
+
signal,
|
|
1591
|
+
});
|
|
1592
|
+
} catch (err) {
|
|
1593
|
+
return networkFailureResult(query, "searxng", startedAt, err, signal);
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
const bodyText = await response.text();
|
|
1597
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
1598
|
+
if (isNonJsonSearchBody(contentType, bodyText)) {
|
|
1599
|
+
return errorResult(
|
|
1600
|
+
query,
|
|
1601
|
+
"searxng",
|
|
1602
|
+
startedAt,
|
|
1603
|
+
SEARXNG_JSON_DISABLED_MESSAGE,
|
|
1604
|
+
);
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
if (response.ok) {
|
|
1608
|
+
let data: SearxngSearchResponse;
|
|
1609
|
+
try {
|
|
1610
|
+
data = JSON.parse(bodyText) as SearxngSearchResponse;
|
|
1611
|
+
} catch {
|
|
1612
|
+
return errorResult(
|
|
1613
|
+
query,
|
|
1614
|
+
"searxng",
|
|
1615
|
+
startedAt,
|
|
1616
|
+
SEARXNG_JSON_DISABLED_MESSAGE,
|
|
1617
|
+
);
|
|
1618
|
+
}
|
|
1619
|
+
if (data.results && data.results.length > count) {
|
|
1620
|
+
data.results = data.results.slice(0, count);
|
|
1621
|
+
}
|
|
1622
|
+
const durationMs = Date.now() - startedAt;
|
|
1623
|
+
return {
|
|
1624
|
+
content:
|
|
1625
|
+
wrapUntrustedContent(formatSearxngResults(data, query), {
|
|
1626
|
+
source: "search",
|
|
1627
|
+
sourceDetail: "searxng",
|
|
1628
|
+
}) + CITATION_INSTRUCTION,
|
|
1629
|
+
isError: false,
|
|
1630
|
+
activityMetadata: {
|
|
1631
|
+
webSearch: buildSearxngMetadata(data, query, durationMs),
|
|
1632
|
+
},
|
|
1633
|
+
};
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
if (response.status === 401 || response.status === 403) {
|
|
1637
|
+
return errorResult(
|
|
1638
|
+
query,
|
|
1639
|
+
"searxng",
|
|
1640
|
+
startedAt,
|
|
1641
|
+
"SearXNG rejected the request. Check the instance URL, optional token, and that JSON search is enabled.",
|
|
1642
|
+
);
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
if (response.status === 429 && attempt < DEFAULT_MAX_RETRIES) {
|
|
1646
|
+
const delayMs = getHttpRetryDelay(
|
|
1647
|
+
response,
|
|
1648
|
+
attempt,
|
|
1649
|
+
DEFAULT_BASE_DELAY_MS,
|
|
1650
|
+
);
|
|
1651
|
+
log.warn(
|
|
1652
|
+
{ attempt: attempt + 1, delayMs },
|
|
1653
|
+
"SearXNG Search rate limited, retrying",
|
|
1654
|
+
);
|
|
1655
|
+
await sleep(delayMs);
|
|
1656
|
+
continue;
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
log.warn({ status: response.status }, "SearXNG Search API error");
|
|
1660
|
+
return backendFailureResult(
|
|
1661
|
+
query,
|
|
1662
|
+
"searxng",
|
|
1663
|
+
startedAt,
|
|
1664
|
+
{ statusCode: response.status, error: rawBodyDetail(bodyText) },
|
|
1665
|
+
response.status === 429
|
|
1666
|
+
? "SearXNG Search rate limit exceeded after retries. Try again shortly."
|
|
1667
|
+
: `SearXNG Search API returned status ${response.status}`,
|
|
1668
|
+
);
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
return backendFailureResult(
|
|
1672
|
+
query,
|
|
1673
|
+
"searxng",
|
|
1674
|
+
startedAt,
|
|
1675
|
+
{ statusCode: 429 },
|
|
1676
|
+
"SearXNG Search rate limit exceeded after retries. Try again shortly.",
|
|
1677
|
+
);
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
async function executeTinyfishSearch(
|
|
1681
|
+
query: string,
|
|
1682
|
+
count: number,
|
|
1683
|
+
freshness: string | undefined,
|
|
1684
|
+
apiKey: string,
|
|
1685
|
+
signal?: AbortSignal,
|
|
1686
|
+
): Promise<ToolExecutionResult> {
|
|
1687
|
+
const startedAt = Date.now();
|
|
1688
|
+
const apiBase = getConfig().services["web-search"]?.apiBase;
|
|
1689
|
+
const endpoint = resolveProviderApiUrl(
|
|
1690
|
+
apiBase,
|
|
1691
|
+
"/",
|
|
1692
|
+
TINYFISH_DEFAULT_SEARCH_API_BASE,
|
|
1693
|
+
);
|
|
1694
|
+
const url = new URL(endpoint);
|
|
1695
|
+
url.searchParams.set("query", query);
|
|
1696
|
+
const recencyMinutes = tinyfishRecencyMinutesForFreshness(freshness);
|
|
1697
|
+
if (recencyMinutes !== undefined) {
|
|
1698
|
+
url.searchParams.set("recency_minutes", String(recencyMinutes));
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
const headers = {
|
|
1702
|
+
Accept: "application/json",
|
|
1703
|
+
"X-API-Key": apiKey.trim(),
|
|
1704
|
+
};
|
|
1705
|
+
|
|
1706
|
+
for (let attempt = 0; attempt <= DEFAULT_MAX_RETRIES; attempt++) {
|
|
1707
|
+
let response: Response;
|
|
1708
|
+
try {
|
|
1709
|
+
response = await fetch(url.toString(), { headers, signal });
|
|
1710
|
+
} catch (err) {
|
|
1711
|
+
return networkFailureResult(query, "tinyfish", startedAt, err, signal);
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
const bodyText = await response.text();
|
|
1715
|
+
if (response.ok) {
|
|
1716
|
+
let data: TinyfishSearchResponse;
|
|
1717
|
+
try {
|
|
1718
|
+
data = JSON.parse(bodyText) as TinyfishSearchResponse;
|
|
1719
|
+
} catch {
|
|
1720
|
+
return errorResult(
|
|
1721
|
+
query,
|
|
1722
|
+
"tinyfish",
|
|
1723
|
+
startedAt,
|
|
1724
|
+
"TinyFish Search returned an invalid JSON payload.",
|
|
1725
|
+
);
|
|
1726
|
+
}
|
|
1727
|
+
if (data.results && data.results.length > count) {
|
|
1728
|
+
data.results = data.results.slice(0, count);
|
|
1729
|
+
}
|
|
1730
|
+
const durationMs = Date.now() - startedAt;
|
|
1731
|
+
return {
|
|
1732
|
+
content:
|
|
1733
|
+
wrapUntrustedContent(formatTinyfishResults(data, query), {
|
|
1734
|
+
source: "search",
|
|
1735
|
+
sourceDetail: "tinyfish",
|
|
1736
|
+
}) + CITATION_INSTRUCTION,
|
|
1737
|
+
isError: false,
|
|
1738
|
+
activityMetadata: {
|
|
1739
|
+
webSearch: buildTinyfishMetadata(data, query, durationMs),
|
|
1740
|
+
},
|
|
1741
|
+
};
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
if (response.status === 401) {
|
|
1745
|
+
return errorResult(
|
|
1746
|
+
query,
|
|
1747
|
+
"tinyfish",
|
|
1748
|
+
startedAt,
|
|
1749
|
+
"Invalid or expired TinyFish API key",
|
|
1750
|
+
);
|
|
1751
|
+
}
|
|
1752
|
+
if (response.status === 402) {
|
|
1753
|
+
return errorResult(
|
|
1754
|
+
query,
|
|
1755
|
+
"tinyfish",
|
|
1756
|
+
startedAt,
|
|
1757
|
+
"TinyFish Search API access is not enabled for this account.",
|
|
1758
|
+
);
|
|
1759
|
+
}
|
|
1760
|
+
if (response.status === 403) {
|
|
1761
|
+
return errorResult(
|
|
1762
|
+
query,
|
|
1763
|
+
"tinyfish",
|
|
1764
|
+
startedAt,
|
|
1765
|
+
"TinyFish Search request was forbidden by the upstream service.",
|
|
1766
|
+
);
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
if (response.status === 429 && attempt < DEFAULT_MAX_RETRIES) {
|
|
1770
|
+
const delayMs = getHttpRetryDelay(
|
|
1771
|
+
response,
|
|
1772
|
+
attempt,
|
|
1773
|
+
DEFAULT_BASE_DELAY_MS,
|
|
1774
|
+
);
|
|
1775
|
+
log.warn(
|
|
1776
|
+
{ attempt: attempt + 1, delayMs },
|
|
1777
|
+
"TinyFish Search rate limited, retrying",
|
|
1778
|
+
);
|
|
1779
|
+
await sleep(delayMs);
|
|
1780
|
+
continue;
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1783
|
+
log.warn({ status: response.status }, "TinyFish Search API error");
|
|
1784
|
+
return backendFailureResult(
|
|
1785
|
+
query,
|
|
1786
|
+
"tinyfish",
|
|
1787
|
+
startedAt,
|
|
1788
|
+
{ statusCode: response.status, error: rawBodyDetail(bodyText) },
|
|
1789
|
+
response.status === 429
|
|
1790
|
+
? "TinyFish Search rate limit exceeded after retries. Try again shortly."
|
|
1791
|
+
: `TinyFish Search API returned status ${response.status}`,
|
|
1792
|
+
);
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
return backendFailureResult(
|
|
1796
|
+
query,
|
|
1797
|
+
"tinyfish",
|
|
1798
|
+
startedAt,
|
|
1799
|
+
{ statusCode: 429 },
|
|
1800
|
+
"TinyFish Search rate limit exceeded after retries. Try again shortly.",
|
|
1801
|
+
);
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1361
1804
|
// ----------------------------------------------------------------------------
|
|
1362
1805
|
// Adapter registry
|
|
1363
1806
|
//
|
|
@@ -1424,6 +1867,23 @@ const fastcrwSearchAdapter: WebSearchAdapter = {
|
|
|
1424
1867
|
executeFastcrwSearch(query, count, freshness, apiKey, signal),
|
|
1425
1868
|
};
|
|
1426
1869
|
|
|
1870
|
+
const searxngSearchAdapter: WebSearchAdapter = {
|
|
1871
|
+
id: "searxng",
|
|
1872
|
+
providerKeyName: "searxng",
|
|
1873
|
+
fallbackOrder: 7,
|
|
1874
|
+
keyless: true,
|
|
1875
|
+
execute: ({ query, count, freshness, apiKey, signal }) =>
|
|
1876
|
+
executeSearxngSearch(query, count, freshness, apiKey, signal),
|
|
1877
|
+
};
|
|
1878
|
+
|
|
1879
|
+
const tinyfishSearchAdapter: WebSearchAdapter = {
|
|
1880
|
+
id: "tinyfish",
|
|
1881
|
+
providerKeyName: "tinyfish",
|
|
1882
|
+
fallbackOrder: 8,
|
|
1883
|
+
execute: ({ query, count, freshness, apiKey, signal }) =>
|
|
1884
|
+
executeTinyfishSearch(query, count, freshness, apiKey, signal),
|
|
1885
|
+
};
|
|
1886
|
+
|
|
1427
1887
|
/**
|
|
1428
1888
|
* All built-in web-search adapters keyed by provider id. The
|
|
1429
1889
|
* `Record<WebSearchProvider, ...>` shape forces TypeScript to flag any
|
|
@@ -1436,6 +1896,8 @@ const WEB_SEARCH_ADAPTERS: Record<WebSearchProvider, WebSearchAdapter> = {
|
|
|
1436
1896
|
firecrawl: firecrawlSearchAdapter,
|
|
1437
1897
|
keenable: keenableSearchAdapter,
|
|
1438
1898
|
fastcrw: fastcrwSearchAdapter,
|
|
1899
|
+
searxng: searxngSearchAdapter,
|
|
1900
|
+
tinyfish: tinyfishSearchAdapter,
|
|
1439
1901
|
};
|
|
1440
1902
|
|
|
1441
1903
|
/**
|
|
@@ -1467,7 +1929,7 @@ export const webSearchTool = {
|
|
|
1467
1929
|
count: {
|
|
1468
1930
|
type: "number",
|
|
1469
1931
|
description:
|
|
1470
|
-
"Number of results to return (1-20, default 10). Used with Brave, Tavily, Firecrawl, Keenable, and
|
|
1932
|
+
"Number of results to return (1-20, default 10). Used with Brave, Tavily, Firecrawl, Keenable, fastCRW, SearXNG, and TinyFish providers.",
|
|
1471
1933
|
},
|
|
1472
1934
|
offset: {
|
|
1473
1935
|
type: "number",
|
|
@@ -1477,7 +1939,7 @@ export const webSearchTool = {
|
|
|
1477
1939
|
freshness: {
|
|
1478
1940
|
type: "string",
|
|
1479
1941
|
description:
|
|
1480
|
-
'Filter by recency: "pd" (past day), "pw" (past week), "pm" (past month), "py" (past year). Used with Brave, Tavily, Firecrawl, Keenable, and
|
|
1942
|
+
'Filter by recency: "pd" (past day), "pw" (past week), "pm" (past month), "py" (past year). Used with Brave, Tavily, Firecrawl, Keenable, fastCRW, SearXNG, and TinyFish providers. SearXNG maps day/month/year and omits week.',
|
|
1481
1943
|
},
|
|
1482
1944
|
},
|
|
1483
1945
|
required: ["query"],
|
|
@@ -1593,7 +2055,7 @@ export const webSearchTool = {
|
|
|
1593
2055
|
query,
|
|
1594
2056
|
provider,
|
|
1595
2057
|
startedAt,
|
|
1596
|
-
"No web search API key configured. Set it via `keys set perplexity <key>`, `keys set brave <key>`, `keys set tavily <key>`, `keys set firecrawl <key>`, or `keys set fastcrw <key>`, or configure it from the Settings page under API Keys. Or switch the web-search provider to Keenable, which works without a key.",
|
|
2058
|
+
"No web search API key configured. Set it via `keys set perplexity <key>`, `keys set brave <key>`, `keys set tavily <key>`, `keys set firecrawl <key>`, or `keys set fastcrw <key>`, or `keys set tinyfish <key>`, or configure it from the Settings page under API Keys. Or switch the web-search provider to Keenable, which works without a key, or SearXNG with your instance URL.",
|
|
1597
2059
|
);
|
|
1598
2060
|
}
|
|
1599
2061
|
}
|
|
@@ -119,8 +119,8 @@ export class PermissionChecker {
|
|
|
119
119
|
>,
|
|
120
120
|
classification?: RiskClassificationWithMeta,
|
|
121
121
|
): Promise<PermissionDecision> {
|
|
122
|
-
//
|
|
123
|
-
const executionTarget = resolveExecutionTarget(tool);
|
|
122
|
+
// Policy and prompts use the invocation's execution target.
|
|
123
|
+
const executionTarget = resolveExecutionTarget(tool, input, context);
|
|
124
124
|
classification ??= await classifyRisk(
|
|
125
125
|
name,
|
|
126
126
|
input,
|
|
@@ -149,7 +149,7 @@ export class PermissionChecker {
|
|
|
149
149
|
// this, the executor's catch block would fall back to the default
|
|
150
150
|
// low risk, degrading audit/alert accuracy for high-risk attempts.
|
|
151
151
|
try {
|
|
152
|
-
const policyContext = buildPolicyContext(tool, context);
|
|
152
|
+
const policyContext = buildPolicyContext(tool, context, input);
|
|
153
153
|
const result = await check(
|
|
154
154
|
name,
|
|
155
155
|
input,
|
|
@@ -3,6 +3,7 @@ import { isSkillImprovementActive } from "../config/memory-v3-gate.js";
|
|
|
3
3
|
import type { ExecutionContext } from "../permissions/approval-policy.js";
|
|
4
4
|
import type { ChannelPermissionCoordinates } from "../permissions/channel-permission-query.js";
|
|
5
5
|
import type { PolicyContext } from "../permissions/types.js";
|
|
6
|
+
import { resolveExecutionTarget } from "./execution-target.js";
|
|
6
7
|
import { getToolOwner } from "./registry.js";
|
|
7
8
|
import type { Tool, ToolContext } from "./types.js";
|
|
8
9
|
|
|
@@ -48,6 +49,7 @@ function deriveExecutionContext(context?: ToolContext): ExecutionContext {
|
|
|
48
49
|
export function buildPolicyContext(
|
|
49
50
|
tool: Tool,
|
|
50
51
|
context?: ToolContext,
|
|
52
|
+
input?: Record<string, unknown>,
|
|
51
53
|
): PolicyContext {
|
|
52
54
|
const executionContext = deriveExecutionContext(context);
|
|
53
55
|
|
|
@@ -73,7 +75,7 @@ export function buildPolicyContext(
|
|
|
73
75
|
const ownerKind = getToolOwner(tool.name)?.kind;
|
|
74
76
|
if (ownerKind === "skill" || ownerKind === "plugin") {
|
|
75
77
|
return {
|
|
76
|
-
executionTarget: tool
|
|
78
|
+
executionTarget: resolveExecutionTarget(tool, input, context),
|
|
77
79
|
executionContext,
|
|
78
80
|
conversationId,
|
|
79
81
|
...originSignals,
|
package/src/tools/skills/load.ts
CHANGED
|
@@ -90,12 +90,13 @@ function formatToolSchemas(
|
|
|
90
90
|
manifest: SkillToolManifest,
|
|
91
91
|
context: Pick<
|
|
92
92
|
ToolContext,
|
|
93
|
-
"clientOs" | "transportInterface" | "sourceActorPrincipalId"
|
|
93
|
+
"clientOs" | "transportInterface" | "sourceActorPrincipalId" | "trustClass"
|
|
94
94
|
>,
|
|
95
95
|
childSkillName?: string,
|
|
96
96
|
): string | undefined {
|
|
97
97
|
const tools = manifest.tools.filter((tool) =>
|
|
98
98
|
supportsClientOsForSkillTool(tool.supported_client_os, tool.name, {
|
|
99
|
+
trustClass: context.trustClass,
|
|
99
100
|
clientOs: context.clientOs,
|
|
100
101
|
transportInterface: context.transportInterface,
|
|
101
102
|
sourceActorPrincipalId: context.sourceActorPrincipalId,
|
|
@@ -3,6 +3,7 @@ import { randomUUID } from "node:crypto";
|
|
|
3
3
|
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { join, resolve } from "node:path";
|
|
5
5
|
|
|
6
|
+
import { PLUGIN_NAME_ENV } from "../../plugin-api/plugin-name-env.js";
|
|
6
7
|
import { conversationRevealNonce } from "../../runtime/reveal-nonce.js";
|
|
7
8
|
import { computeSkillVersionHash } from "../../skills/version-hash.js";
|
|
8
9
|
import {
|
|
@@ -74,6 +75,7 @@ export async function runSkillToolScriptSandbox(
|
|
|
74
75
|
timeoutMs?: number;
|
|
75
76
|
expectedSkillVersionHash?: string;
|
|
76
77
|
skillDirHashResolver?: (skillDir: string) => string;
|
|
78
|
+
pluginOwner?: string;
|
|
77
79
|
},
|
|
78
80
|
): Promise<ToolExecutionResult> {
|
|
79
81
|
const scriptPath = resolve(join(skillDir, executorPath));
|
|
@@ -117,7 +119,9 @@ export async function runSkillToolScriptSandbox(
|
|
|
117
119
|
"utf-8",
|
|
118
120
|
);
|
|
119
121
|
|
|
120
|
-
return await spawnRunner(runDir, input, context, timeoutMs, executorPath
|
|
122
|
+
return await spawnRunner(runDir, input, context, timeoutMs, executorPath, {
|
|
123
|
+
pluginOwner: options?.pluginOwner,
|
|
124
|
+
});
|
|
121
125
|
} catch (err) {
|
|
122
126
|
const message = err instanceof Error ? err.message : String(err);
|
|
123
127
|
return {
|
|
@@ -139,6 +143,7 @@ function spawnRunner(
|
|
|
139
143
|
context: ToolContext,
|
|
140
144
|
timeoutMs: number,
|
|
141
145
|
executorPath: string,
|
|
146
|
+
pluginContext?: { pluginOwner?: string },
|
|
142
147
|
): Promise<ToolExecutionResult> {
|
|
143
148
|
return new Promise<ToolExecutionResult>((resolve) => {
|
|
144
149
|
const stdoutChunks: Buffer[] = [];
|
|
@@ -156,9 +161,13 @@ function spawnRunner(
|
|
|
156
161
|
conversationId: context.conversationId,
|
|
157
162
|
});
|
|
158
163
|
env.__CONVERSATION_ID = context.conversationId;
|
|
159
|
-
// Secret binding for reveal-derived chat authority
|
|
164
|
+
// Secret binding for reveal-derived chat authority. See reveal-nonce.ts.
|
|
160
165
|
env.__REVEAL_NONCE = conversationRevealNonce(context.conversationId);
|
|
161
166
|
|
|
167
|
+
if (pluginContext?.pluginOwner) {
|
|
168
|
+
env[PLUGIN_NAME_ENV] = pluginContext.pluginOwner;
|
|
169
|
+
}
|
|
170
|
+
|
|
162
171
|
const child = spawn(wrapped.command, wrapped.args, {
|
|
163
172
|
cwd: runDir,
|
|
164
173
|
env,
|
|
@@ -24,6 +24,12 @@ export interface RunSkillToolScriptOptions {
|
|
|
24
24
|
* with `execution_target: host` (in-process); non-bundled skills are forced to
|
|
25
25
|
* execute in the sandbox. */
|
|
26
26
|
bundled?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Catalog owner id when this skill is plugin-resident. The sandbox runner
|
|
29
|
+
* sets VELLUM_PLUGIN_NAME so the child can resolve credentials under
|
|
30
|
+
* that plugin's service.
|
|
31
|
+
*/
|
|
32
|
+
pluginOwner?: string;
|
|
27
33
|
}
|
|
28
34
|
|
|
29
35
|
/**
|
|
@@ -42,6 +48,7 @@ export async function runSkillToolScript(
|
|
|
42
48
|
timeoutMs: options.timeoutMs,
|
|
43
49
|
expectedSkillVersionHash: options.expectedSkillVersionHash,
|
|
44
50
|
skillDirHashResolver: options.skillDirHashResolver,
|
|
51
|
+
pluginOwner: options.pluginOwner,
|
|
45
52
|
});
|
|
46
53
|
}
|
|
47
54
|
|