@vellumai/assistant 0.12.2 → 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/.env.example +2 -0
- package/AGENTS.md +1 -1
- package/ARCHITECTURE.md +43 -29
- package/Dockerfile +63 -0
- package/docs/architecture/integrations.md +7 -0
- package/docs/architecture/memory.md +17 -2
- package/docs/architecture/security.md +10 -5
- package/docs/architecture/turn-actor.md +2 -0
- package/docs/credential-execution-service.md +1 -1
- package/docs/desktop-browser-cli.md +50 -5
- 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/__tests__/secret-detection.test.ts +1 -0
- 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/ces-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
- package/node_modules/@vellumai/environments/src/shell.test.ts +21 -0
- package/node_modules/@vellumai/environments/src/shell.ts +24 -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/__tests__/secret-detection.test.ts +1 -0
- 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/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +20 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +8 -2
- 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/__tests__/secret-detection.test.ts +1 -0
- 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/service-contracts/src/secret-detection.ts +4 -1
- package/node_modules/@vellumai/slack-text/src/index.ts +4 -8
- package/openapi.yaml +716 -16
- package/package.json +1 -1
- package/scripts/smoke-desktop-browser-cli.ts +11 -26
- package/scripts/smoke-desktop-window-theme.ts +2 -3
- package/scripts/sync-llm-catalog.ts +3 -0
- package/scripts/voice-ttft-spike.ts +2 -2
- 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__/agent-loop.test.ts +259 -0
- package/src/__tests__/agent-wake-delegation-prompt.test.ts +64 -2
- 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__/anthropic-provider.test.ts +55 -0
- package/src/__tests__/approval-interception-trust-gates.test.ts +40 -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__/attachments-store.test.ts +22 -3
- 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-approval.test.ts +9 -14
- package/src/__tests__/channel-reply-delivery.test.ts +56 -0
- package/src/__tests__/channel-retry-sweep.test.ts +9 -0
- package/src/__tests__/chat-credential-redaction.test.ts +23 -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-screenshot-attachments.test.ts +411 -0
- package/src/__tests__/computer-use-screenshot-selection.test.ts +50 -0
- 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-inference-profile.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop.test.ts +797 -16
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +53 -1
- package/src/__tests__/conversation-attachments.test.ts +106 -0
- package/src/__tests__/conversation-evictor.test.ts +62 -37
- package/src/__tests__/conversation-fork-crud.test.ts +191 -0
- 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-rendered-delegation-state.test.ts +276 -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 +72 -55
- package/src/__tests__/credential-prompt-route.test.ts +35 -3
- package/src/__tests__/cu-unified-flow.test.ts +82 -1
- package/src/__tests__/db-conversation-tool-surface.test.ts +221 -0
- 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 +58 -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__/history-repair.test.ts +53 -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 +26 -0
- package/src/__tests__/interrupt-on-send.test.ts +57 -43
- package/src/__tests__/interrupt-turn-note.test.ts +5 -6
- package/src/__tests__/list-messages-tool-merge.test.ts +85 -1
- package/src/__tests__/llm-catalog-parity.test.ts +27 -4
- 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-apps-routes.test.ts +1 -0
- package/src/__tests__/oauth-commands-routes.test.ts +114 -101
- package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +13 -0
- package/src/__tests__/oauth-providers-routes.test.ts +3 -0
- package/src/__tests__/outbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/persist-media-references.test.ts +50 -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 -1
- 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__/run-conversation-turn-persistence.test.ts +138 -1
- package/src/__tests__/runtime-events-sse-reconnect.test.ts +1 -1
- package/src/__tests__/schedule-routes.test.ts +20 -0
- package/src/__tests__/scheduler-result-notification.test.ts +23 -4
- package/src/__tests__/script-proxy-certs.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__/secret-routes-platform-proxy.test.ts +86 -31
- package/src/__tests__/secret-routes-scrub.test.ts +22 -27
- package/src/__tests__/secret-scanner.test.ts +20 -0
- package/src/__tests__/secure-keys-managed-failover.test.ts +8 -0
- package/src/__tests__/secure-keys.test.ts +50 -4
- package/src/__tests__/send-endpoint-busy.test.ts +163 -1
- package/src/__tests__/server-history-render.test.ts +91 -1
- package/src/__tests__/server-tool-pairing.test.ts +107 -0
- package/src/__tests__/settings-routes.test.ts +50 -1
- package/src/__tests__/skill-script-runner-sandbox.test.ts +32 -0
- package/src/__tests__/skills.test.ts +5 -4
- 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__/subagent-tool-gate-mode.test.ts +226 -0
- package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +2 -0
- package/src/__tests__/terminal-tools.test.ts +8 -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-follow-up.test.ts +99 -0
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +66 -1
- package/src/__tests__/tool-start-timestamp.test.ts +2 -0
- package/src/__tests__/twilio-routes.test.ts +1 -0
- package/src/__tests__/unicode.test.ts +36 -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 +136 -53
- package/src/agent/tool-result-follow-up.ts +70 -0
- package/src/api/attachment-provenance.test.ts +68 -0
- package/src/api/computer-use-tool.test.ts +55 -0
- package/src/api/computer-use-tool.ts +27 -0
- package/src/api/events/assistant-outbound-attachment.ts +3 -0
- package/src/api/events/assistant-turn-start.ts +3 -0
- package/src/api/events/desktop-activity-changed.ts +10 -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/question-request.ts +1 -0
- 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 +42 -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 +9 -0
- package/src/approvals/AGENTS.md +4 -2
- package/src/approvals/approval-primitive.ts +5 -2
- package/src/approvals/scoped-approval-grants.ts +6 -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 -9
- 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__/cli-test-harness.ts +21 -3
- package/src/cli/commands/__tests__/notifications.test.ts +35 -10
- package/src/cli/commands/__tests__/plugins.test.ts +20 -1
- package/src/cli/commands/__tests__/schedules.test.ts +14 -0
- package/src/cli/commands/bash.help.ts +4 -3
- package/src/cli/commands/browser.help.ts +9 -6
- 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 +9 -4
- package/src/cli/commands/notifications.help.ts +16 -2
- package/src/cli/commands/notifications.ts +30 -8
- package/src/cli/commands/oauth/index.help.ts +10 -0
- package/src/cli/commands/oauth/providers.ts +12 -0
- package/src/cli/commands/oauth/request.test.ts +179 -2
- package/src/cli/commands/oauth/request.ts +41 -10
- package/src/cli/commands/plugins.ts +12 -5
- package/src/cli/commands/roadmap.help.ts +18 -21
- package/src/cli/commands/roadmap.ts +4 -21
- package/src/cli/commands/schedules.ts +2 -0
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +41 -0
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +5 -2
- package/src/cli/lib/__tests__/local-plugin-upgrade.test.ts +133 -51
- package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +8 -2
- package/src/cli/lib/bundled-marketplace.json +906 -1
- package/src/cli/lib/bundled-plugin-packages.json +783 -1
- package/src/cli/lib/inspect-plugin.ts +11 -4
- package/src/cli/lib/plugin-marketplace.ts +8 -0
- package/src/cli/lib/publish-plugin.ts +1 -2
- package/src/cli/lib/upgrade-plugin.ts +19 -11
- package/src/cli/output.ts +18 -4
- package/src/config/__tests__/default-provider.test.ts +6 -0
- 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/schedule/SKILL.md +6 -6
- 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/loader.ts +9 -17
- package/src/config/platform-identity.ts +8 -8
- package/src/config/profile-text-generation.test.ts +51 -0
- package/src/config/profile-text-generation.ts +51 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +12 -0
- 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 +9 -2
- package/src/config/schemas/mcp.ts +6 -1
- package/src/config/schemas/memory-retrospective.ts +11 -2
- package/src/config/schemas/memory-v3.ts +12 -0
- 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 +34 -142
- package/src/credential-execution/process-manager.test.ts +20 -24
- package/src/credential-execution/process-manager.ts +24 -19
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +10 -1
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +43 -0
- package/src/daemon/__tests__/inference-profile-notification.test.ts +2 -0
- package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +36 -0
- package/src/daemon/assistant-attachments.ts +20 -12
- package/src/daemon/browser-mode-session.test.ts +402 -0
- package/src/daemon/browser-mode-session.ts +186 -0
- package/src/daemon/chat-credential-redaction.ts +16 -1
- 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 +132 -13
- package/src/daemon/conversation-agent-loop.ts +231 -25
- package/src/daemon/conversation-attachments.ts +93 -12
- 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 +79 -6
- package/src/daemon/conversation-turn-finalize.ts +26 -13
- package/src/daemon/conversation.ts +215 -58
- package/src/daemon/daemon-control.ts +3 -7
- 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/mcp-reload-service.ts +1 -1
- package/src/daemon/message-protocol.ts +0 -1
- package/src/daemon/message-provenance.ts +28 -4
- package/src/daemon/message-types/shared.ts +1 -0
- package/src/daemon/mode-session-startup-recovery.ts +23 -0
- package/src/daemon/mode-session-tracking.ts +54 -0
- package/src/daemon/orphan-reaper.ts +4 -3
- package/src/daemon/persist-media-references.ts +20 -3
- package/src/daemon/process-message.ts +13 -4
- package/src/daemon/tool-setup-types.ts +6 -0
- package/src/daemon/virtual-desktop-context.ts +21 -0
- package/src/daemon/wake-conversation-ops.ts +50 -15
- 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 +302 -64
- package/src/desktop/desktop-automation-lease.ts +129 -54
- 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-help.ts +15 -0
- 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 +76 -132
- package/src/desktop/desktop-stream-bridge.ts +9 -11
- package/src/desktop/desktop-wallpaper-renderer.ts +132 -0
- package/src/desktop/desktop-wallpaper-worker.ts +17 -0
- package/src/desktop/desktop-wallpaper.test.ts +48 -7
- package/src/desktop/desktop-wallpaper.ts +34 -102
- package/src/desktop/desktop-window-theme.ts +5 -25
- package/src/desktop/virtual-desktop-feature.ts +53 -3
- 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 +156 -0
- package/src/mcp/__tests__/startup.test.ts +30 -7
- package/src/mcp/__tests__/tool-caps.test.ts +134 -0
- package/src/mcp/manager.ts +171 -101
- package/src/mcp/startup.ts +33 -13
- package/src/mcp/tool-caps.ts +184 -0
- 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/provider-message-metadata.ts +3 -3
- 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 +71 -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 +11 -26
- 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/schedule-result-producer.ts +4 -6
- package/src/notifications/signal.ts +4 -19
- package/src/notifications/types.ts +15 -0
- package/src/oauth/AGENTS.md +2 -0
- package/src/oauth/__tests__/identity-verifier.test.ts +36 -1
- package/src/oauth/connection-resolver.ts +1 -2
- package/src/oauth/identity-verifier.ts +24 -0
- package/src/oauth/oauth-store.ts +12 -4
- package/src/oauth/provider-serializer.ts +8 -0
- package/src/oauth/seed-providers.ts +42 -0
- package/src/onboarding/onboarding-events-store.ts +99 -12
- package/src/permissions/confirmation-guardian-request.test.ts +16 -0
- package/src/permissions/confirmation-guardian-request.ts +2 -3
- package/src/permissions/question-prompter.test.ts +31 -0
- package/src/permissions/question-prompter.ts +2 -0
- package/src/persistence/__tests__/client-connection-events-store.test.ts +322 -0
- package/src/persistence/attachments-store.ts +84 -44
- package/src/persistence/client-connection-events-store.ts +377 -0
- package/src/persistence/conversation-crud.ts +166 -26
- package/src/persistence/conversation-mode-sessions.test.ts +424 -0
- package/src/persistence/conversation-mode-sessions.ts +460 -0
- package/src/persistence/conversation-plugin-facade.ts +30 -0
- package/src/persistence/conversation-queries.ts +6 -19
- package/src/persistence/conversation-tool-surface.ts +135 -0
- package/src/persistence/conversation-types.test.ts +32 -0
- package/src/persistence/conversation-types.ts +26 -4
- package/src/persistence/llm-usage-store.ts +3 -9
- package/src/persistence/message-metadata.ts +25 -0
- package/src/persistence/migrations/378-create-conversation-tool-surfaces.test.ts +78 -0
- package/src/persistence/migrations/378-create-conversation-tool-surfaces.ts +29 -0
- package/src/persistence/migrations/379-oauth-providers-response-ok-field.test.ts +92 -0
- package/src/persistence/migrations/379-oauth-providers-response-ok-field.ts +32 -0
- package/src/persistence/migrations/380-conversation-tool-surfaces-delegate-independent-tasks.test.ts +90 -0
- package/src/persistence/migrations/380-conversation-tool-surfaces-delegate-independent-tasks.ts +34 -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/conversation-tool-surfaces.ts +32 -0
- package/src/persistence/schema/conversations.ts +67 -0
- package/src/persistence/schema/index.ts +1 -0
- package/src/persistence/schema/infrastructure.ts +29 -0
- package/src/persistence/schema/oauth.ts +1 -0
- package/src/persistence/steps.ts +41 -3
- package/src/plugin-api/__tests__/plugin-name-env.test.ts +249 -0
- package/src/plugin-api/conversation-turn.ts +31 -7
- package/src/plugin-api/effective-context-window.ts +33 -0
- package/src/plugin-api/index.ts +35 -6
- package/src/plugin-api/plugin-channel-turn-trust.test.ts +133 -0
- package/src/plugin-api/plugin-channel-turn-trust.ts +71 -0
- 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/AGENTS.md +39 -5
- package/src/plugins/defaults/memory/__tests__/archive-removal-framing.test.ts +64 -0
- package/src/plugins/defaults/memory/__tests__/buffer-file.test.ts +365 -0
- package/src/plugins/defaults/memory/__tests__/buffer-format.test.ts +43 -0
- package/src/plugins/defaults/memory/__tests__/conversation-memory-purge.test.ts +1 -0
- package/src/plugins/defaults/memory/__tests__/db-memory-attach.test.ts +2 -0
- package/src/plugins/defaults/memory/__tests__/fixtures/buffer-appender.ts +17 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +74 -0
- package/src/plugins/defaults/memory/__tests__/memory-run-evidence.test.ts +161 -0
- package/src/plugins/defaults/memory/__tests__/relocated-memory-test-rows.ts +10 -0
- package/src/plugins/defaults/memory/__tests__/worker-control.test.ts +19 -6
- package/src/plugins/defaults/memory/buffer-file.ts +354 -0
- package/src/plugins/defaults/memory/buffer-format.ts +40 -0
- package/src/plugins/defaults/memory/context-search/agent-protocol.ts +9 -12
- package/src/plugins/defaults/memory/context-search/agent-runner.ts +77 -22
- package/src/plugins/defaults/memory/context-search/format.ts +53 -8
- 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/sources/memory-v2.ts +2 -1
- package/src/plugins/defaults/memory/context-search/sources/workspace.ts +2 -1
- package/src/plugins/defaults/memory/context-search/types.ts +1 -11
- package/src/plugins/defaults/memory/conversation-memory-purge.ts +4 -0
- package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +11 -4
- package/src/plugins/defaults/memory/graph/capability-seed.ts +1 -2
- package/src/plugins/defaults/memory/graph/tool-handlers.ts +13 -63
- package/src/plugins/defaults/memory/graph/tools.ts +35 -64
- package/src/plugins/defaults/memory/host-utils.ts +0 -10
- package/src/plugins/defaults/memory/injectors.ts +4 -3
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +72 -183
- package/src/plugins/defaults/memory/memory-run-evidence.ts +213 -0
- package/src/plugins/defaults/memory/src/memory-eval-routes.ts +2 -3
- package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +6 -1
- package/src/plugins/defaults/memory/src/memory-item-routes.ts +2 -1
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +407 -99
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +10 -0
- package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +107 -7
- package/src/plugins/defaults/memory/substrate/consolidation-job.ts +307 -86
- package/src/plugins/defaults/memory/substrate/consolidation-tool-surface.ts +34 -0
- package/src/plugins/defaults/memory/substrate/page-index.ts +2 -1
- package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +91 -51
- package/src/plugins/defaults/memory/substrate/sweep-job.ts +1 -1
- package/src/plugins/defaults/memory/tools.test.ts +124 -9
- package/src/plugins/defaults/memory/tools.ts +38 -11
- package/src/plugins/defaults/memory/v1/graph/consolidation.ts +2 -2
- package/src/plugins/defaults/memory/v1/graph/extraction.ts +2 -1
- package/src/plugins/defaults/memory/v1/graph/retriever.ts +1 -1
- package/src/plugins/defaults/memory/v2/__tests__/migration.test.ts +5 -0
- package/src/plugins/defaults/memory/v2/__tests__/reranker.test.ts +5 -2
- package/src/plugins/defaults/memory/v2/reranker.ts +2 -1
- package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +81 -1
- package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +87 -0
- package/src/plugins/defaults/memory/v3/__tests__/plugin-schema.test.ts +12 -0
- package/src/plugins/defaults/memory/v3/__tests__/pool-log-store.test.ts +332 -15
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +626 -27
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +148 -28
- package/src/plugins/defaults/memory/v3/card.ts +2 -1
- package/src/plugins/defaults/memory/v3/injector.ts +212 -178
- package/src/plugins/defaults/memory/v3/orchestrate.ts +159 -32
- package/src/plugins/defaults/memory/v3/plugin-schema.ts +54 -4
- package/src/plugins/defaults/memory/v3/pool-log-store.ts +275 -37
- package/src/plugins/defaults/memory/v3/pool-select.test.ts +47 -5
- package/src/plugins/defaults/memory/v3/pool-select.ts +710 -59
- package/src/plugins/defaults/memory/v3/sections.ts +2 -1
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +41 -14
- 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/plugins/defaults/tool-error/hooks/post-tool-use.ts +4 -1
- package/src/plugins/defaults/tool-result-truncate/terminal.ts +1 -46
- package/src/prompts/__tests__/parallel-tasks-section.test.ts +25 -0
- package/src/prompts/delegation-gate.ts +57 -0
- package/src/prompts/system-prompt.ts +14 -32
- 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 +6 -0
- package/src/providers/jev/client.test.ts +270 -0
- package/src/providers/jev/client.ts +534 -0
- package/src/providers/model-catalog.ts +59 -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/server-tool-pairing.ts +16 -7
- 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 +6 -4
- package/src/runtime/__tests__/agent-wake.test.ts +94 -1
- package/src/runtime/actor-trust-resolver.ts +3 -3
- package/src/runtime/agent-wake.ts +32 -5
- 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-action-service.ts +2 -17
- package/src/runtime/guardian-reply-router.ts +29 -40
- package/src/runtime/http-server.ts +2 -2
- 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/__tests__/vbundle-import-policy.test.ts +89 -0
- 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 +43 -11
- 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 +24 -2
- 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/channel-route-shared.ts +1 -9
- 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 +125 -14
- 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 +8 -7
- 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/guardian-approval-interception.ts +24 -0
- 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 +37 -41
- 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 +39 -10
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +9 -9
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +2 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +11 -1
- package/src/runtime/routes/inference-profiles-routes.ts +9 -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-commands-routes.ts +57 -54
- package/src/runtime/routes/oauth-providers.ts +11 -0
- package/src/runtime/routes/oauth-request-hints.test.ts +246 -0
- package/src/runtime/routes/oauth-request-hints.ts +149 -0
- package/src/runtime/routes/plugins-routes.ts +6 -0
- package/src/runtime/routes/roadmap-routes.ts +47 -8
- package/src/runtime/routes/schedule-routes.ts +2 -0
- package/src/runtime/routes/secret-routes.ts +99 -119
- 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/__tests__/worker-mcp-bootstrap.test.ts +107 -0
- package/src/schedule/__tests__/worker-mcp-readiness.test.ts +173 -0
- package/src/schedule/__tests__/worker-mcp-tools.test.ts +13 -47
- package/src/schedule/run-script.ts +2 -2
- package/src/schedule/scheduler.ts +47 -11
- package/src/schedule/tool-surface-readiness.ts +65 -0
- package/src/schedule/worker-control.ts +15 -5
- package/src/schedule/worker-mcp.ts +85 -0
- package/src/schedule/worker.ts +9 -31
- package/src/security/secure-keys.ts +74 -112
- 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.test.ts +167 -5
- package/src/tools/ask-question/ask-question-tool.ts +120 -22
- package/src/tools/browser/browser-execution.ts +29 -60
- 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 +16 -7
- 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/shared/filesystem/file-ops-service.ts +1 -31
- package/src/tools/shared/shell-output.test.ts +10 -0
- package/src/tools/shared/shell-output.ts +14 -2
- package/src/tools/skills/load.ts +2 -1
- package/src/tools/skills/sandbox-runner.ts +24 -4
- package/src/tools/skills/scaffold-managed.ts +2 -1
- 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 +44 -4
- package/src/tools/terminal/__tests__/sanitized-bash.test.ts +0 -14
- package/src/tools/terminal/safe-env.ts +39 -24
- package/src/tools/terminal/sanitized-bash.ts +15 -2
- package/src/tools/terminal/shell-launch.test.ts +162 -0
- package/src/tools/terminal/shell.test.ts +29 -0
- package/src/tools/terminal/shell.ts +15 -7
- 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/browser-human-verification.ts +14 -0
- 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/host-process.test.ts +17 -1
- package/src/util/host-process.ts +24 -0
- package/src/util/provider-error-patterns.ts +3 -0
- package/src/util/unicode.ts +29 -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
package/src/plugin-api/index.ts
CHANGED
|
@@ -33,9 +33,11 @@
|
|
|
33
33
|
* - {@link assistantEventHub} — the assistant's pub/sub hub for runtime events
|
|
34
34
|
* - {@link getModelProfiles} — list the workspace inference profiles a plugin
|
|
35
35
|
* can route to (e.g. a model router building its category → profile map)
|
|
36
|
-
* - {@link getConfiguredProvider}
|
|
36
|
+
* - {@link getConfiguredProvider}: resolve a {@link Provider} for a call site
|
|
37
37
|
* (optionally overriding the profile) and run inference through the
|
|
38
|
-
* workspace's configured profiles and credentials
|
|
38
|
+
* workspace's configured profiles and credentials, with no plugin-supplied API key
|
|
39
|
+
* - {@link getEffectiveContextWindow}: resolve that call site's provider,
|
|
40
|
+
* model, and effective maximum input size
|
|
39
41
|
*
|
|
40
42
|
* - {@link InitContext} — passed to `init` hook at bootstrap
|
|
41
43
|
* - {@link ShutdownContext} — passed to `shutdown` hook at teardown
|
|
@@ -169,10 +171,12 @@ export { publishEvent } from "./publish-event.js";
|
|
|
169
171
|
// `inputModalities.image` override winning when set (mix profiles are
|
|
170
172
|
// vision-capable if any arm is). Returns false when nothing resolves.
|
|
171
173
|
export { doesSupportVision } from "./vision-support.js";
|
|
172
|
-
// Resolve a stored credential to its plaintext value
|
|
173
|
-
// `assistant credentials reveal` prints
|
|
174
|
+
// Resolve a stored credential to its plaintext value (the same value
|
|
175
|
+
// `assistant credentials reveal` prints) from a UUID or a "service/field"
|
|
174
176
|
// reference. When a plugin is in context, resolution is scoped to credentials
|
|
175
|
-
// whose service matches the plugin's
|
|
177
|
+
// whose service matches the plugin's runtime name. A plugin-resident skill
|
|
178
|
+
// script or skill-tool child presents a daemon-issued invocation grant and is
|
|
179
|
+
// scoped the same way. Outside any plugin context or grant the resolver is
|
|
176
180
|
// unscoped. Throws CredentialResolutionError when the ref does not resolve, the
|
|
177
181
|
// store is unreachable, or the credential is out of the plugin's scope.
|
|
178
182
|
export {
|
|
@@ -218,6 +222,11 @@ export { resolveOauthCallbackUrl } from "../inbound/oauth-callback-url.js";
|
|
|
218
222
|
// float the chosen profile above the call-site layers when the plugin must
|
|
219
223
|
// run on a specific profile regardless of workspace tuning.
|
|
220
224
|
export { getConfiguredProvider } from "../providers/provider-send-message.js";
|
|
225
|
+
export type {
|
|
226
|
+
EffectiveContextWindowInfo,
|
|
227
|
+
EffectiveContextWindowOptions,
|
|
228
|
+
} from "./effective-context-window.js";
|
|
229
|
+
export { getEffectiveContextWindow } from "./effective-context-window.js";
|
|
221
230
|
// Resolve an image/file block's media `source` to its bytes as inline base64,
|
|
222
231
|
// whether the source is inline base64 or a persisted workspace reference
|
|
223
232
|
// (attachment-store row or a file on disk). Returns null when a reference can no
|
|
@@ -286,6 +295,11 @@ export {
|
|
|
286
295
|
// writes files under the workspace (e.g. its own `plugins/<name>/data/`
|
|
287
296
|
// directory) resolves them against this instead of hardcoding a base path.
|
|
288
297
|
export { getWorkspaceDir } from "../util/platform.js";
|
|
298
|
+
// `String.prototype.slice` that never cuts a UTF-16 surrogate pair in half.
|
|
299
|
+
// Any text a plugin truncates by character budget and hands to a model must
|
|
300
|
+
// go through this: an orphaned half is invalid UTF-16 that strict provider
|
|
301
|
+
// parsers reject.
|
|
302
|
+
export { safeStringSlice } from "../util/unicode.js";
|
|
289
303
|
// Declarative help for the top-level `assistant` CLI commands that have adopted
|
|
290
304
|
// the static-help split. Plugins (e.g. the memory capability indexer) read this
|
|
291
305
|
// to embed CLI command capabilities without importing the CLI action graph.
|
|
@@ -359,7 +373,8 @@ export {
|
|
|
359
373
|
stringifyMessageContent,
|
|
360
374
|
} from "../persistence/message-content.js";
|
|
361
375
|
// Conversation history — reads and writes on the host conversation store
|
|
362
|
-
// (rows, message history, processing state,
|
|
376
|
+
// (rows, message history, processing state, the recorded wire tool surface,
|
|
377
|
+
// disk-view paths) plus the lexical
|
|
363
378
|
// message-search surface. Every operation takes explicit parameters; nothing
|
|
364
379
|
// is resolved from config. Async because the facade loads the DB store graph
|
|
365
380
|
// lazily on first call.
|
|
@@ -371,7 +386,9 @@ export {
|
|
|
371
386
|
getConversation,
|
|
372
387
|
getConversationDirPath,
|
|
373
388
|
getConversationProcessingStartedAt,
|
|
389
|
+
getConversationToolSurface,
|
|
374
390
|
getMessages,
|
|
391
|
+
getRecordedConversationToolSurface,
|
|
375
392
|
hasLexicalTokens,
|
|
376
393
|
isConversationProcessing,
|
|
377
394
|
listConversations,
|
|
@@ -380,6 +397,7 @@ export {
|
|
|
380
397
|
syncMessageToDisk,
|
|
381
398
|
updateMessageMetadata,
|
|
382
399
|
} from "../persistence/conversation-plugin-facade.js";
|
|
400
|
+
export type { ConversationToolSurface } from "../persistence/conversation-tool-surface.js";
|
|
383
401
|
// System cards: a transcript notice authored by the daemon rather than the
|
|
384
402
|
// assistant persona, for telling the user something a turn did to their input
|
|
385
403
|
// that the model's reply cannot explain (e.g. an attachment that could not be
|
|
@@ -392,6 +410,16 @@ export { persistSystemCard } from "./system-card.js";
|
|
|
392
410
|
// what makes that true. Host tools and plugin tools share this one guard.
|
|
393
411
|
export type { CancellableToolContext } from "./tool-cancellation.js";
|
|
394
412
|
export { throwIfCancelled } from "./tool-cancellation.js";
|
|
413
|
+
// Tool input from a Zod schema: derive the advertised `input_schema` from the
|
|
414
|
+
// schema the tool parses its input with, so what the model is told and what
|
|
415
|
+
// the tool accepts share one source. The host validates built-in tools'
|
|
416
|
+
// input centrally; a plugin tool parses its own, and answers a failed parse
|
|
417
|
+
// with `invalidToolInputResult` so its message reads the same as the host's.
|
|
418
|
+
export {
|
|
419
|
+
invalidToolInputResult,
|
|
420
|
+
nullAsOmitted,
|
|
421
|
+
toToolInputSchema,
|
|
422
|
+
} from "../tools/shared/zod-tool-schema.js";
|
|
395
423
|
// Synthesize text to speech through the assistant's globally configured TTS
|
|
396
424
|
// provider (ElevenLabs, Fish Audio, etc.). Plugins that need voice output —
|
|
397
425
|
// e.g. a meeting bot speaking into a live call — use this instead of managing
|
|
@@ -438,6 +466,7 @@ export type {
|
|
|
438
466
|
RunConversationTurnResult,
|
|
439
467
|
} from "./conversation-turn.js";
|
|
440
468
|
export { runConversationTurn } from "./conversation-turn.js";
|
|
469
|
+
export { PluginTurnNotAdmittedError } from "./plugin-channel-turn-trust.js";
|
|
441
470
|
// Live voice — drive a single client's real-time voice session (STT → agent
|
|
442
471
|
// turn → TTS, with server-VAD turn-taking, pauses, and barge-in) over a
|
|
443
472
|
// transport the plugin owns. The plugin brings only a `send` callback (e.g.
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
type InboundTrustReadResult =
|
|
4
|
+
| {
|
|
5
|
+
ok: true;
|
|
6
|
+
verdict: {
|
|
7
|
+
trustClass: string;
|
|
8
|
+
canonicalSenderId: string | null;
|
|
9
|
+
contactId?: string;
|
|
10
|
+
status?: string;
|
|
11
|
+
resolutionFailed?: boolean;
|
|
12
|
+
};
|
|
13
|
+
admissionPolicy: string | null;
|
|
14
|
+
}
|
|
15
|
+
| { ok: false };
|
|
16
|
+
|
|
17
|
+
let nextRead: InboundTrustReadResult = { ok: false };
|
|
18
|
+
|
|
19
|
+
mock.module("../calls/inbound-trust-reader.js", () => ({
|
|
20
|
+
readInboundTrust: async () => nextRead,
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
import {
|
|
24
|
+
PluginTurnNotAdmittedError,
|
|
25
|
+
resolvePluginChannelTurnTrust,
|
|
26
|
+
} from "./plugin-channel-turn-trust.js";
|
|
27
|
+
|
|
28
|
+
const CHANNEL = {
|
|
29
|
+
sourceChannel: "plugin" as const,
|
|
30
|
+
externalChatId: "imessage:+12025550142",
|
|
31
|
+
externalUserId: "imessage:+12025550142",
|
|
32
|
+
displayName: "Ada",
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
beforeEach(() => {
|
|
36
|
+
nextRead = { ok: false };
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
describe("resolvePluginChannelTurnTrust", () => {
|
|
40
|
+
test("returns the gateway verdict as the turn trust context", async () => {
|
|
41
|
+
nextRead = {
|
|
42
|
+
ok: true,
|
|
43
|
+
verdict: {
|
|
44
|
+
trustClass: "trusted_contact",
|
|
45
|
+
canonicalSenderId: "imessage:+12025550142",
|
|
46
|
+
contactId: "c-ada",
|
|
47
|
+
status: "active",
|
|
48
|
+
},
|
|
49
|
+
admissionPolicy: "trusted_contacts",
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const trust = await resolvePluginChannelTurnTrust(CHANNEL);
|
|
53
|
+
expect(trust.trustClass).toBe("trusted_contact");
|
|
54
|
+
expect(trust.sourceChannel).toBe("plugin");
|
|
55
|
+
expect(trust.requesterChatId).toBe(CHANNEL.externalChatId);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("fails closed when the gateway could not vouch for the sender", async () => {
|
|
59
|
+
nextRead = {
|
|
60
|
+
ok: true,
|
|
61
|
+
verdict: {
|
|
62
|
+
trustClass: "unknown",
|
|
63
|
+
canonicalSenderId: null,
|
|
64
|
+
resolutionFailed: true,
|
|
65
|
+
},
|
|
66
|
+
admissionPolicy: "strangers",
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
await expect(resolvePluginChannelTurnTrust(CHANNEL)).rejects.toMatchObject({
|
|
70
|
+
name: "PluginTurnNotAdmittedError",
|
|
71
|
+
reason: "trust_resolution_failed",
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("fails closed when the gateway trust read fails", async () => {
|
|
76
|
+
nextRead = { ok: false };
|
|
77
|
+
await expect(resolvePluginChannelTurnTrust(CHANNEL)).rejects.toMatchObject({
|
|
78
|
+
name: "PluginTurnNotAdmittedError",
|
|
79
|
+
reason: "trust_resolution_failed",
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("rejects a sender below the channel admission floor", async () => {
|
|
84
|
+
nextRead = {
|
|
85
|
+
ok: true,
|
|
86
|
+
verdict: { trustClass: "unknown", canonicalSenderId: null },
|
|
87
|
+
admissionPolicy: "guardian_only",
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
await expect(resolvePluginChannelTurnTrust(CHANNEL)).rejects.toEqual(
|
|
91
|
+
expect.objectContaining({
|
|
92
|
+
name: "PluginTurnNotAdmittedError",
|
|
93
|
+
reason: "admission_policy_guardian_only",
|
|
94
|
+
}),
|
|
95
|
+
);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test("rejects a blocked member regardless of floor", async () => {
|
|
99
|
+
nextRead = {
|
|
100
|
+
ok: true,
|
|
101
|
+
verdict: {
|
|
102
|
+
trustClass: "trusted_contact",
|
|
103
|
+
canonicalSenderId: "imessage:+12025550142",
|
|
104
|
+
contactId: "c-ada",
|
|
105
|
+
status: "blocked",
|
|
106
|
+
},
|
|
107
|
+
admissionPolicy: "strangers",
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
await expect(resolvePluginChannelTurnTrust(CHANNEL)).rejects.toMatchObject({
|
|
111
|
+
name: "PluginTurnNotAdmittedError",
|
|
112
|
+
reason: "member_blocked",
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test("admits when the gateway reports no admission policy", async () => {
|
|
117
|
+
nextRead = {
|
|
118
|
+
ok: true,
|
|
119
|
+
verdict: { trustClass: "unknown", canonicalSenderId: null },
|
|
120
|
+
admissionPolicy: null,
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const trust = await resolvePluginChannelTurnTrust(CHANNEL);
|
|
124
|
+
expect(trust.trustClass).toBe("unknown");
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test("PluginTurnNotAdmittedError names the deny reason", () => {
|
|
128
|
+
const err = new PluginTurnNotAdmittedError("admission_policy_no_one");
|
|
129
|
+
expect(err).toBeInstanceOf(Error);
|
|
130
|
+
expect(err.reason).toBe("admission_policy_no_one");
|
|
131
|
+
expect(err.message).toContain("admission_policy_no_one");
|
|
132
|
+
});
|
|
133
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gateway admission and trust for plugin turns addressed by a channel chat.
|
|
3
|
+
*
|
|
4
|
+
* A channel address means an inbound sender, not an internal plugin job.
|
|
5
|
+
* Trust comes from the gateway verdict (`resolve_inbound_trust`); the turn
|
|
6
|
+
* runs only when that sender clears the channel admission floor.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { meetsAdmissionFloor } from "@vellumai/gateway-client";
|
|
10
|
+
|
|
11
|
+
import { readInboundTrust } from "../calls/inbound-trust-reader.js";
|
|
12
|
+
import type { ChannelId } from "../channels/types.js";
|
|
13
|
+
import type { TrustContext } from "../daemon/trust-context-types.js";
|
|
14
|
+
import { trustContextFromVerdict } from "../runtime/trust-verdict-consumer.js";
|
|
15
|
+
|
|
16
|
+
interface PluginChannelTurnAddress {
|
|
17
|
+
sourceChannel: ChannelId;
|
|
18
|
+
externalChatId: string;
|
|
19
|
+
externalUserId?: string | null;
|
|
20
|
+
displayName?: string | null;
|
|
21
|
+
username?: string | null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class PluginTurnNotAdmittedError extends Error {
|
|
25
|
+
readonly reason: string;
|
|
26
|
+
|
|
27
|
+
constructor(reason: string) {
|
|
28
|
+
super(`This inbound plugin turn was not admitted (${reason}).`);
|
|
29
|
+
this.name = "PluginTurnNotAdmittedError";
|
|
30
|
+
this.reason = reason;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function resolvePluginChannelTurnTrust(
|
|
35
|
+
channel: PluginChannelTurnAddress,
|
|
36
|
+
): Promise<TrustContext> {
|
|
37
|
+
const actorExternalId = channel.externalUserId?.trim() || undefined;
|
|
38
|
+
const read = await readInboundTrust({
|
|
39
|
+
channelType: channel.sourceChannel,
|
|
40
|
+
actorExternalId,
|
|
41
|
+
});
|
|
42
|
+
if (!read.ok) {
|
|
43
|
+
throw new PluginTurnNotAdmittedError("trust_resolution_failed");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (read.verdict.resolutionFailed) {
|
|
47
|
+
throw new PluginTurnNotAdmittedError("trust_resolution_failed");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const memberStatus = read.verdict.status;
|
|
51
|
+
if (memberStatus === "blocked" || memberStatus === "revoked") {
|
|
52
|
+
throw new PluginTurnNotAdmittedError(`member_${memberStatus}`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const trustClass = read.verdict.trustClass;
|
|
56
|
+
if (
|
|
57
|
+
read.admissionPolicy != null &&
|
|
58
|
+
!meetsAdmissionFloor(read.admissionPolicy, trustClass)
|
|
59
|
+
) {
|
|
60
|
+
throw new PluginTurnNotAdmittedError(
|
|
61
|
+
`admission_policy_${read.admissionPolicy}`,
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return trustContextFromVerdict(read.verdict, {
|
|
66
|
+
sourceChannel: channel.sourceChannel,
|
|
67
|
+
conversationExternalId: channel.externalChatId,
|
|
68
|
+
actorDisplayName: channel.displayName ?? undefined,
|
|
69
|
+
actorUsername: channel.username ?? undefined,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a child process learns which plugin it is running as.
|
|
3
|
+
*
|
|
4
|
+
* In-process plugin hooks, tools, and routes use AsyncLocalStorage
|
|
5
|
+
* ({@link getCurrentPluginName}). A bash or skill-sandbox child does not
|
|
6
|
+
* inherit that store. Those children recover the install-directory basename
|
|
7
|
+
* from `VELLUM_PLUGIN_NAME` (injected after env sanitization) or from the
|
|
8
|
+
* entry script path under `plugins/<service>/skills/<skill>/{scripts,tools}/`.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { isAbsolute, relative, resolve, sep } from "node:path";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
13
|
+
|
|
14
|
+
import { getCurrentPluginName } from "../plugins/plugin-execution-context.js";
|
|
15
|
+
import { getWorkspacePluginsDir } from "../util/platform.js";
|
|
16
|
+
|
|
17
|
+
export const PLUGIN_NAME_ENV = "VELLUM_PLUGIN_NAME";
|
|
18
|
+
|
|
19
|
+
const SKILL_SCRIPT_ROOTS = new Set(["scripts", "tools"]);
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Read a plugin install-directory name from the process environment.
|
|
23
|
+
* Empty or whitespace-only values are ignored.
|
|
24
|
+
*/
|
|
25
|
+
export function readPluginNameFromEnv(
|
|
26
|
+
env: NodeJS.ProcessEnv = process.env,
|
|
27
|
+
): string | undefined {
|
|
28
|
+
const raw = env[PLUGIN_NAME_ENV];
|
|
29
|
+
if (typeof raw !== "string") {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
const trimmed = raw.trim();
|
|
33
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* If `filePath` is a skill script or tool under an installed plugin, return
|
|
38
|
+
* that plugin's install-directory basename (the runtime service name).
|
|
39
|
+
*
|
|
40
|
+
* Expected layout:
|
|
41
|
+
* `plugins/<service>/skills/<skill-id>/scripts|tools/<file>`.
|
|
42
|
+
*/
|
|
43
|
+
export function derivePluginNameFromSkillScriptPath(
|
|
44
|
+
filePath: string,
|
|
45
|
+
pluginsDir: string = getWorkspacePluginsDir(),
|
|
46
|
+
): string | undefined {
|
|
47
|
+
if (filePath.length === 0) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
let resolved = filePath;
|
|
51
|
+
if (filePath.startsWith("file:")) {
|
|
52
|
+
try {
|
|
53
|
+
resolved = fileURLToPath(filePath);
|
|
54
|
+
} catch {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (!isAbsolute(resolved)) {
|
|
59
|
+
resolved = resolve(process.cwd(), resolved);
|
|
60
|
+
}
|
|
61
|
+
const pluginsRoot = resolve(pluginsDir);
|
|
62
|
+
const rel = relative(pluginsRoot, resolved);
|
|
63
|
+
if (rel.length === 0 || rel.startsWith("..") || isAbsolute(rel)) {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
const parts = rel.split(sep).filter((part) => part.length > 0);
|
|
67
|
+
if (parts.length < 5) {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
const [service, skillsSeg, skillId, root] = parts;
|
|
71
|
+
if (
|
|
72
|
+
service === undefined ||
|
|
73
|
+
skillsSeg !== "skills" ||
|
|
74
|
+
skillId === undefined ||
|
|
75
|
+
root === undefined ||
|
|
76
|
+
!SKILL_SCRIPT_ROOTS.has(root)
|
|
77
|
+
) {
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
return service;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Scan argv for a plugin-resident skill script path, resolving relative
|
|
85
|
+
* entries against `cwd`.
|
|
86
|
+
*/
|
|
87
|
+
export function derivePluginNameFromProcess(
|
|
88
|
+
argv: readonly string[] = process.argv,
|
|
89
|
+
cwd: string = process.cwd(),
|
|
90
|
+
pluginsDir: string = getWorkspacePluginsDir(),
|
|
91
|
+
): string | undefined {
|
|
92
|
+
for (const candidate of argv.slice(1)) {
|
|
93
|
+
if (typeof candidate !== "string" || candidate.length === 0) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (candidate.startsWith("-")) {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
const absolute = isAbsolute(candidate)
|
|
100
|
+
? candidate
|
|
101
|
+
: resolve(cwd, candidate);
|
|
102
|
+
const name = derivePluginNameFromSkillScriptPath(absolute, pluginsDir);
|
|
103
|
+
if (name !== undefined) {
|
|
104
|
+
return name;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Plugin identity for credential scoping: in-process AsyncLocalStorage,
|
|
112
|
+
* then the injected env var, then the process entry script path.
|
|
113
|
+
*/
|
|
114
|
+
export function resolveCallingPluginName(
|
|
115
|
+
env: NodeJS.ProcessEnv = process.env,
|
|
116
|
+
argv: readonly string[] = process.argv,
|
|
117
|
+
cwd: string = process.cwd(),
|
|
118
|
+
pluginsDir: string = getWorkspacePluginsDir(),
|
|
119
|
+
): string | undefined {
|
|
120
|
+
return (
|
|
121
|
+
getCurrentPluginName() ??
|
|
122
|
+
readPluginNameFromEnv(env) ??
|
|
123
|
+
derivePluginNameFromProcess(argv, cwd, pluginsDir)
|
|
124
|
+
);
|
|
125
|
+
}
|
|
@@ -1,28 +1,42 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Plugin-facing credential resolution.
|
|
3
3
|
*
|
|
4
|
-
* {@link resolveCredential} returns a stored credential's plaintext value
|
|
5
|
-
* same value `assistant credentials reveal` prints
|
|
6
|
-
* is either a credential UUID or a `"service/field"` string,
|
|
7
|
-
* reveal path does (see
|
|
8
|
-
*
|
|
4
|
+
* {@link resolveCredential} returns a stored credential's plaintext value
|
|
5
|
+
* (the same value `assistant credentials reveal` prints), resolving a
|
|
6
|
+
* reference that is either a credential UUID or a `"service/field"` string,
|
|
7
|
+
* exactly as the reveal path does (see
|
|
8
|
+
* {@link ../tools/credentials/resolve.resolveCredentialRef} and the
|
|
9
|
+
* `credentials/reveal` route).
|
|
9
10
|
*
|
|
10
11
|
* ## Plugin scoping
|
|
11
12
|
*
|
|
12
|
-
* When a plugin is in context
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
13
|
+
* When a plugin is in context, resolution is restricted to credentials
|
|
14
|
+
* whose `service` equals the plugin's runtime install-directory name
|
|
15
|
+
* (`sms/account_sid` for plugin `sms`). Context is:
|
|
16
|
+
*
|
|
17
|
+
* 1. In-process AsyncLocalStorage from `runInPluginContext` (hooks, plugin
|
|
18
|
+
* tools, plugin routes).
|
|
19
|
+
* 2. `VELLUM_PLUGIN_NAME` on a bash or skill-sandbox child.
|
|
20
|
+
* 3. The process entry path, when it sits under
|
|
21
|
+
* `plugins/<service>/skills/<skill>/{scripts,tools}/`.
|
|
22
|
+
*
|
|
23
|
+
* Outside any plugin context the resolver is unscoped and behaves like a
|
|
24
|
+
* direct reveal. A standalone child has an empty in-process metadata
|
|
25
|
+
* cache; when plugin context is set, a cache miss consults the live
|
|
26
|
+
* credential catalog so an empty cache is not reported as "not found".
|
|
20
27
|
*/
|
|
21
28
|
|
|
22
|
-
import {
|
|
29
|
+
import { credentialKey } from "@vellumai/credential-storage";
|
|
30
|
+
|
|
23
31
|
import { getSecureKeyResultAsync } from "../security/secure-keys.js";
|
|
32
|
+
import {
|
|
33
|
+
type CredentialMetadata,
|
|
34
|
+
listCredentialRecordsLive,
|
|
35
|
+
} from "../tools/credentials/metadata-store.js";
|
|
36
|
+
import { parseServiceFieldRef } from "../tools/credentials/ref-parse.js";
|
|
24
37
|
import { resolveCredentialRef } from "../tools/credentials/resolve.js";
|
|
25
38
|
import { credentialInPluginScope } from "./credential-scope.js";
|
|
39
|
+
import { resolveCallingPluginName } from "./plugin-name-env.js";
|
|
26
40
|
|
|
27
41
|
/**
|
|
28
42
|
* Raised when a credential cannot be resolved: the reference does not match a
|
|
@@ -36,6 +50,50 @@ export class CredentialResolutionError extends Error {
|
|
|
36
50
|
}
|
|
37
51
|
}
|
|
38
52
|
|
|
53
|
+
interface ResolvedRef {
|
|
54
|
+
service: string;
|
|
55
|
+
field: string;
|
|
56
|
+
storageKey: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function findLiveRecord(
|
|
60
|
+
records: CredentialMetadata[],
|
|
61
|
+
ref: string,
|
|
62
|
+
): CredentialMetadata | undefined {
|
|
63
|
+
const byId = records.find((record) => record.credentialId === ref);
|
|
64
|
+
if (byId) {
|
|
65
|
+
return byId;
|
|
66
|
+
}
|
|
67
|
+
const parsed = parseServiceFieldRef(ref);
|
|
68
|
+
if (!parsed) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
return records.find(
|
|
72
|
+
(record) =>
|
|
73
|
+
record.service === parsed.service && record.field === parsed.field,
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function resolveCredentialRefLive(
|
|
78
|
+
ref: string,
|
|
79
|
+
): Promise<ResolvedRef | undefined> {
|
|
80
|
+
const live = await listCredentialRecordsLive();
|
|
81
|
+
if (live.unreachable) {
|
|
82
|
+
throw new CredentialResolutionError(
|
|
83
|
+
"Credential store is unreachable.",
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
const record = findLiveRecord(live.records, ref);
|
|
87
|
+
if (!record) {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
service: record.service,
|
|
92
|
+
field: record.field,
|
|
93
|
+
storageKey: credentialKey(record.service, record.field),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
39
97
|
/**
|
|
40
98
|
* Resolve a credential reference to its plaintext value.
|
|
41
99
|
*
|
|
@@ -45,15 +103,16 @@ export class CredentialResolutionError extends Error {
|
|
|
45
103
|
* store is unreachable, or a plugin in context is not scoped to the credential.
|
|
46
104
|
*/
|
|
47
105
|
export async function resolveCredential(ref: string): Promise<string> {
|
|
48
|
-
const
|
|
106
|
+
const pluginName = resolveCallingPluginName();
|
|
107
|
+
|
|
108
|
+
let resolved: ResolvedRef | undefined = resolveCredentialRef(ref);
|
|
109
|
+
if (!resolved && pluginName !== undefined) {
|
|
110
|
+
resolved = await resolveCredentialRefLive(ref);
|
|
111
|
+
}
|
|
49
112
|
if (!resolved) {
|
|
50
113
|
throw new CredentialResolutionError(`Credential not found: ${ref}`);
|
|
51
114
|
}
|
|
52
115
|
|
|
53
|
-
// Scope the resolution to the plugin in context, if any. The ownership gate
|
|
54
|
-
// is enforced before the plaintext is read so an out-of-scope plugin never
|
|
55
|
-
// touches the secure backend.
|
|
56
|
-
const pluginName = getCurrentPluginName();
|
|
57
116
|
if (
|
|
58
117
|
pluginName !== undefined &&
|
|
59
118
|
!credentialInPluginScope(pluginName, resolved.service)
|
|
@@ -70,7 +129,7 @@ export async function resolveCredential(ref: string): Promise<string> {
|
|
|
70
129
|
if (value == null || value.length === 0) {
|
|
71
130
|
if (unreachable) {
|
|
72
131
|
throw new CredentialResolutionError(
|
|
73
|
-
"Credential store is unreachable
|
|
132
|
+
"Credential store is unreachable.",
|
|
74
133
|
);
|
|
75
134
|
}
|
|
76
135
|
throw new CredentialResolutionError(`Credential not found: ${ref}`);
|
|
@@ -397,3 +397,25 @@ describe("doesSupportVision with a bare string", () => {
|
|
|
397
397
|
expect(doesSupportVision("qwen2.5-vl")).toBe(true);
|
|
398
398
|
});
|
|
399
399
|
});
|
|
400
|
+
|
|
401
|
+
describe("doesSupportVision with a resolved target", () => {
|
|
402
|
+
test("profile policy can enable images for a catalog text model", () => {
|
|
403
|
+
expect(
|
|
404
|
+
doesSupportVision({
|
|
405
|
+
provider: "fireworks",
|
|
406
|
+
model: "accounts/fireworks/models/glm-5p2",
|
|
407
|
+
inputModalities: { image: { enabled: true, supported: true } },
|
|
408
|
+
}),
|
|
409
|
+
).toBe(true);
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
test("profile policy can disable images for a catalog vision model", () => {
|
|
413
|
+
expect(
|
|
414
|
+
doesSupportVision({
|
|
415
|
+
provider: "anthropic",
|
|
416
|
+
model: "claude-opus-4-6",
|
|
417
|
+
inputModalities: { image: { enabled: false } },
|
|
418
|
+
}),
|
|
419
|
+
).toBe(false);
|
|
420
|
+
});
|
|
421
|
+
});
|
|
@@ -37,15 +37,24 @@ import {
|
|
|
37
37
|
} from "../providers/model-catalog.js";
|
|
38
38
|
import type { ModelProfileInfo } from "./types.js";
|
|
39
39
|
|
|
40
|
+
/** A fully resolved provider target plus the winning profile's policy. */
|
|
41
|
+
export interface ResolvedVisionTarget {
|
|
42
|
+
readonly provider?: string;
|
|
43
|
+
readonly model: string;
|
|
44
|
+
readonly inputModalities?: InputModalities | null;
|
|
45
|
+
}
|
|
46
|
+
|
|
40
47
|
/**
|
|
41
48
|
* Whether the given model or profile can process image input.
|
|
42
49
|
*
|
|
43
|
-
* `modelOrProfile` may be a concrete model id, a profile key,
|
|
44
|
-
* {@link ModelProfileInfo}
|
|
45
|
-
*
|
|
50
|
+
* `modelOrProfile` may be a concrete model id, a profile key, a
|
|
51
|
+
* {@link ModelProfileInfo}, or a fully resolved target. A resolved target
|
|
52
|
+
* combines the final provider/model with the winning profile's modality
|
|
53
|
+
* policy. A bare string is resolved as a model id first and, failing that, as
|
|
54
|
+
* a profile key. Returns `false` when nothing resolves.
|
|
46
55
|
*/
|
|
47
56
|
export function doesSupportVision(
|
|
48
|
-
modelOrProfile: ModelProfileInfo | string,
|
|
57
|
+
modelOrProfile: ModelProfileInfo | ResolvedVisionTarget | string,
|
|
49
58
|
): boolean {
|
|
50
59
|
if (typeof modelOrProfile === "string") {
|
|
51
60
|
// Concrete catalog model id first, then a profile key, then any profile
|
|
@@ -58,7 +67,10 @@ export function doesSupportVision(
|
|
|
58
67
|
false
|
|
59
68
|
);
|
|
60
69
|
}
|
|
61
|
-
|
|
70
|
+
if ("key" in modelOrProfile) {
|
|
71
|
+
return profileVision(modelOrProfile.key) ?? false;
|
|
72
|
+
}
|
|
73
|
+
return resolveEntryVision(modelOrProfile) ?? false;
|
|
62
74
|
}
|
|
63
75
|
|
|
64
76
|
/**
|