@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
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The hint the request doors attach to a provider response, composed from
|
|
3
|
+
* the response and the connection facts alone. The route gathers the facts;
|
|
4
|
+
* nothing here reads a store, a config, or a connection, so a hint's wording
|
|
5
|
+
* is assertable without booting the route.
|
|
6
|
+
*
|
|
7
|
+
* The status hints are an ordered list and the first rule that applies wins.
|
|
8
|
+
* The order is precedence, not coincidence: a provider's own reported failure
|
|
9
|
+
* outranks every status, and an HTML 403 must be judged before the generic
|
|
10
|
+
* 401/403 rule or it is never reached. The missing-scope hint is not a rule
|
|
11
|
+
* in the list; it is prepended to whichever hint applied, or stands alone.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export interface RequestHintFacts {
|
|
15
|
+
/** The provider key the request was made under. */
|
|
16
|
+
provider: string;
|
|
17
|
+
status: number;
|
|
18
|
+
headers: Record<string, string>;
|
|
19
|
+
/**
|
|
20
|
+
* The provider's own one-line account of a refusal inside a 2xx, from its
|
|
21
|
+
* declared ok field; absent when the status is the whole verdict.
|
|
22
|
+
*/
|
|
23
|
+
reportedFailure?: string;
|
|
24
|
+
/**
|
|
25
|
+
* The channel whose bot credential served the request. Absent when the
|
|
26
|
+
* request acted as a person through their OAuth integration.
|
|
27
|
+
*/
|
|
28
|
+
botChannel?: string;
|
|
29
|
+
/** The provider runs in platform-managed mode. */
|
|
30
|
+
managed: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* The base URL the request resolved against: an absolute URL's own origin,
|
|
33
|
+
* otherwise the provider's configured base. Absent when neither is set.
|
|
34
|
+
*/
|
|
35
|
+
resolvedBaseUrl?: string;
|
|
36
|
+
/** Required scopes the resolved connection's stored grant lacks. */
|
|
37
|
+
missingScopes: readonly string[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface RequestHintRule {
|
|
41
|
+
name: string;
|
|
42
|
+
applies(facts: RequestHintFacts): boolean;
|
|
43
|
+
render(facts: RequestHintFacts): string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** The status hints in precedence order; the first rule that applies wins. */
|
|
47
|
+
export const REQUEST_HINT_RULES: readonly RequestHintRule[] = [
|
|
48
|
+
{
|
|
49
|
+
// The body carries the provider's own error code, so the hint says only
|
|
50
|
+
// why a 2xx is being reported as a failure.
|
|
51
|
+
name: "provider reported failure",
|
|
52
|
+
applies: (facts) => facts.reportedFailure !== undefined,
|
|
53
|
+
render: (facts) =>
|
|
54
|
+
`${facts.reportedFailure} in the response body. The body names the error.`,
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
// An API refuses with JSON. A 403 carrying an HTML page is a resource
|
|
58
|
+
// host (a file host, a sign-in page) refusing this identity: the same
|
|
59
|
+
// token is what the API accepts, and the resource is simply not visible
|
|
60
|
+
// to it. Blaming the credential sends the caller off to reconnect one
|
|
61
|
+
// that works.
|
|
62
|
+
name: "resource not visible",
|
|
63
|
+
applies: (facts) => facts.status === 403 && isHtmlResponse(facts.headers),
|
|
64
|
+
render: (facts) => {
|
|
65
|
+
const identity = facts.botChannel
|
|
66
|
+
? `${facts.botChannel} bot`
|
|
67
|
+
: "connected account";
|
|
68
|
+
const requestHost = hostnameOf(facts.resolvedBaseUrl);
|
|
69
|
+
return (
|
|
70
|
+
`Request returned HTTP 403 with an HTML page${requestHost ? ` from ${requestHost}` : ""}, not an API error. ` +
|
|
71
|
+
`That usually means the ${identity} cannot see this resource: it is not shared with it, or the scope it needs is missing. ` +
|
|
72
|
+
`Check the resource's access before treating the credential as revoked; ` +
|
|
73
|
+
(facts.botChannel
|
|
74
|
+
? `'assistant channels get ${facts.botChannel}' reports the credential itself.`
|
|
75
|
+
: `'assistant oauth status ${facts.provider}' reports the credential itself.`)
|
|
76
|
+
);
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
// The recovery steps follow the credential's kind, not the door the
|
|
81
|
+
// request came through: a channel bot's token was stored by the channel's
|
|
82
|
+
// setup, so the OAuth status and connect commands cannot repair it.
|
|
83
|
+
name: "credential rejected",
|
|
84
|
+
applies: (facts) => facts.status === 401 || facts.status === 403,
|
|
85
|
+
render: (facts) =>
|
|
86
|
+
facts.botChannel
|
|
87
|
+
? `Request returned HTTP ${facts.status}. The ${facts.botChannel} bot credential was rejected; it may have been revoked or reinstalled with fewer scopes.\n\n` +
|
|
88
|
+
`Run 'assistant channels get ${facts.botChannel}' to re-probe the channel and see what it reports.\n` +
|
|
89
|
+
`To reconnect, run the channel's setup skill again.`
|
|
90
|
+
: facts.managed
|
|
91
|
+
? `Request returned HTTP ${facts.status}. The OAuth token may be expired or revoked.\n\n` +
|
|
92
|
+
`Run 'assistant oauth status ${facts.provider}' to check connection health.\n` +
|
|
93
|
+
`To reconnect, run 'assistant oauth connect --help'.`
|
|
94
|
+
: `Request returned HTTP ${facts.status}. The OAuth token may be expired or revoked.\n\n` +
|
|
95
|
+
`Run 'assistant oauth status ${facts.provider}' to check connection status.\n` +
|
|
96
|
+
`To reconnect, run 'assistant oauth connect --help'.`,
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
// An HTML 404 (rather than a JSON API error) is the signature of a request
|
|
100
|
+
// reaching a valid host but a path that host does not serve, such as a
|
|
101
|
+
// relative path resolved against a base URL that points at the wrong
|
|
102
|
+
// product. Surface the resolved base so the caller can tell where the path
|
|
103
|
+
// landed, and steer them to an absolute URL for non-default services.
|
|
104
|
+
name: "path not served",
|
|
105
|
+
applies: (facts) => facts.status === 404 && isHtmlResponse(facts.headers),
|
|
106
|
+
render: (facts) =>
|
|
107
|
+
`Request returned HTTP ${facts.status} with an HTML body, which usually means ` +
|
|
108
|
+
`the path does not exist on the base URL it resolved against.\n\n` +
|
|
109
|
+
`This request used base URL "${facts.resolvedBaseUrl ?? "(none configured)"}" (relative paths are joined onto it). ` +
|
|
110
|
+
`If you meant a different service on this provider, pass an absolute URL ` +
|
|
111
|
+
`(e.g. https://host/full/path) so the host and full path are set explicitly.`,
|
|
112
|
+
},
|
|
113
|
+
];
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* The hint for one provider response, or undefined when nothing applies.
|
|
117
|
+
* A missing-scope hint is prepended to the status hint, or stands alone: a
|
|
118
|
+
* connection made before a scope was required keeps working for every call
|
|
119
|
+
* that does not need it, so the gap is named on every request.
|
|
120
|
+
*/
|
|
121
|
+
export function composeRequestHint(
|
|
122
|
+
facts: RequestHintFacts,
|
|
123
|
+
): string | undefined {
|
|
124
|
+
const hint = REQUEST_HINT_RULES.find((rule) => rule.applies(facts))?.render(
|
|
125
|
+
facts,
|
|
126
|
+
);
|
|
127
|
+
if (facts.missingScopes.length === 0) {
|
|
128
|
+
return hint;
|
|
129
|
+
}
|
|
130
|
+
const scopeHint =
|
|
131
|
+
`The ${facts.provider} connection is missing required scopes: ${facts.missingScopes.join(", ")}. ` +
|
|
132
|
+
`It was connected before they were required, so calls that need them fail. ` +
|
|
133
|
+
`Reconnect it from Integrations, or run 'assistant oauth connect ${facts.provider}', to grant them.`;
|
|
134
|
+
return hint ? `${scopeHint}\n\n${hint}` : scopeHint;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** True when the response's Content-Type header indicates an HTML body. */
|
|
138
|
+
function isHtmlResponse(headers: Record<string, string>): boolean {
|
|
139
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
140
|
+
if (key.toLowerCase() === "content-type") {
|
|
141
|
+
return value.toLowerCase().includes("text/html");
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function hostnameOf(url: string | undefined): string | undefined {
|
|
148
|
+
return url && URL.canParse(url) ? new URL(url).hostname : undefined;
|
|
149
|
+
}
|
|
@@ -226,6 +226,12 @@ const mcpPluginIntegrationSchema = z.object({
|
|
|
226
226
|
}),
|
|
227
227
|
logo: z.string(),
|
|
228
228
|
oauthProvider: z.string().optional(),
|
|
229
|
+
category: z
|
|
230
|
+
.string()
|
|
231
|
+
.optional()
|
|
232
|
+
.describe(
|
|
233
|
+
"Where the integrations catalog files the entry: a slug from the shared integration-category vocabulary, passed through as the catalog declares it.",
|
|
234
|
+
),
|
|
229
235
|
});
|
|
230
236
|
|
|
231
237
|
const pluginSearchMatchSchema = z.object({
|
|
@@ -379,16 +379,55 @@ const createRequestSchema = z.object({
|
|
|
379
379
|
tags: z.array(z.string()).optional().describe("Tag slugs"),
|
|
380
380
|
});
|
|
381
381
|
|
|
382
|
+
/** Item fields the roadmap service reserves for staff on an update. */
|
|
383
|
+
const STAFF_ONLY_UPDATE_FIELDS = new Set(["status", "tags"]);
|
|
384
|
+
|
|
385
|
+
function listFields(fields: string[]): string {
|
|
386
|
+
return `${fields.join(", ")} ${fields.length === 1 ? "is" : "are"}`;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Why an update carrying fields other than title and description is refused.
|
|
391
|
+
* A staff-only field and an unknown one need different remedies, so each is
|
|
392
|
+
* named for what it is.
|
|
393
|
+
*/
|
|
394
|
+
function unsupportedUpdateFieldsMessage(keys: string[]): string {
|
|
395
|
+
const staffOnly = keys.filter((k) => STAFF_ONLY_UPDATE_FIELDS.has(k));
|
|
396
|
+
const unknown = keys.filter((k) => !STAFF_ONLY_UPDATE_FIELDS.has(k));
|
|
397
|
+
const reasons = [
|
|
398
|
+
...(staffOnly.length > 0
|
|
399
|
+
? [`${listFields(staffOnly)} set by Vellum staff`]
|
|
400
|
+
: []),
|
|
401
|
+
...(unknown.length > 0
|
|
402
|
+
? [`${listFields(unknown)} not a roadmap update field`]
|
|
403
|
+
: []),
|
|
404
|
+
];
|
|
405
|
+
return `An assistant can change only an item's title and description; ${reasons.join("; ")}.`;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Only the fields the roadmap service lets this assistant change. An
|
|
410
|
+
* assistant is always the author tier there, never staff, and an author may
|
|
411
|
+
* edit only an open item's title and description; status and tags are staff
|
|
412
|
+
* triage and answer 403. Strict, so a caller that sends anything else learns
|
|
413
|
+
* why here instead of from the upstream refusal.
|
|
414
|
+
*/
|
|
382
415
|
const updateRequestSchema = z
|
|
383
|
-
.
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
416
|
+
.strictObject(
|
|
417
|
+
{
|
|
418
|
+
title: z.string().optional(),
|
|
419
|
+
description: z.string().optional(),
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
error: (issue) =>
|
|
423
|
+
issue.code === "unrecognized_keys"
|
|
424
|
+
? unsupportedUpdateFieldsMessage(issue.keys)
|
|
425
|
+
: undefined,
|
|
426
|
+
},
|
|
427
|
+
)
|
|
389
428
|
.refine(
|
|
390
429
|
(patch) => Object.values(patch).some((v) => v !== undefined),
|
|
391
|
-
"At least one of title
|
|
430
|
+
"At least one of title or description is required.",
|
|
392
431
|
);
|
|
393
432
|
|
|
394
433
|
type RoadmapItem = z.infer<typeof itemSchema>;
|
|
@@ -684,7 +723,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
684
723
|
},
|
|
685
724
|
summary: "Update a roadmap item",
|
|
686
725
|
description:
|
|
687
|
-
"Updates a roadmap item
|
|
726
|
+
"Updates the title or description of a roadmap item this assistant filed, while the item is still open. Status and tags are set by Vellum staff.",
|
|
688
727
|
tags: ["roadmap"],
|
|
689
728
|
pathParams: SLUG_PARAM,
|
|
690
729
|
requestBody: updateRequestSchema,
|
|
@@ -213,6 +213,7 @@ const scheduleSchema = z.object({
|
|
|
213
213
|
mode: z.enum(["notify", "execute", "script", "wake", "workflow"]),
|
|
214
214
|
status: z.enum(["active", "firing", "fired", "cancelled"]),
|
|
215
215
|
routingIntent: z.enum(["single_channel", "multi_channel", "all_channels"]),
|
|
216
|
+
quiet: z.boolean(),
|
|
216
217
|
reuseConversation: z.boolean(),
|
|
217
218
|
wakeConversationId: z.string().nullable(),
|
|
218
219
|
workflowName: z.string().nullable(),
|
|
@@ -381,6 +382,7 @@ function serializeSchedule(
|
|
|
381
382
|
mode: j.mode,
|
|
382
383
|
status: j.status,
|
|
383
384
|
routingIntent: j.routingIntent,
|
|
385
|
+
quiet: j.quiet,
|
|
384
386
|
reuseConversation: j.reuseConversation,
|
|
385
387
|
wakeConversationId: j.wakeConversationId,
|
|
386
388
|
workflowName: j.workflowName,
|
|
@@ -16,10 +16,7 @@ import {
|
|
|
16
16
|
} from "../../acp/acp-credentials.js";
|
|
17
17
|
import {
|
|
18
18
|
getPlatformAssistantId,
|
|
19
|
-
setPlatformAssistantId,
|
|
20
19
|
setPlatformBaseUrl,
|
|
21
|
-
setPlatformOrganizationId,
|
|
22
|
-
setPlatformUserId,
|
|
23
20
|
} from "../../config/env.js";
|
|
24
21
|
import { getConfig } from "../../config/loader.js";
|
|
25
22
|
import { maybeDefaultSpeechToManaged } from "../../config/managed-speech-defaults.js";
|
|
@@ -41,6 +38,7 @@ import {
|
|
|
41
38
|
refreshProvidersAfterSecretChange,
|
|
42
39
|
refreshProvidersForRotatedCredential,
|
|
43
40
|
} from "../../providers/inference/credential-rotation.js";
|
|
41
|
+
import { validateJevApiKey } from "../../providers/jev/client.js";
|
|
44
42
|
import { validateMinimaxApiKey } from "../../providers/minimax/client.js";
|
|
45
43
|
import { validateOpenAIApiKey } from "../../providers/openai/client.js";
|
|
46
44
|
import { validatePoolsideApiKey } from "../../providers/poolside/client.js";
|
|
@@ -79,6 +77,48 @@ const log = getLogger("runtime-http");
|
|
|
79
77
|
const CES_READY_POLL_INTERVAL_MS = 500;
|
|
80
78
|
const CES_READY_POLL_TIMEOUT_MS = 30_000;
|
|
81
79
|
|
|
80
|
+
const WRITABLE_VELLUM_CREDENTIAL_FIELDS = [
|
|
81
|
+
"assistant_api_key",
|
|
82
|
+
"webhook_secret",
|
|
83
|
+
"platform_base_url",
|
|
84
|
+
] as const;
|
|
85
|
+
|
|
86
|
+
function isWritableVellumCredentialField(field: string): boolean {
|
|
87
|
+
return (WRITABLE_VELLUM_CREDENTIAL_FIELDS as readonly string[]).includes(
|
|
88
|
+
field,
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function persistCredential(
|
|
93
|
+
service: string,
|
|
94
|
+
field: string,
|
|
95
|
+
value: string,
|
|
96
|
+
): Promise<void> {
|
|
97
|
+
const key = credentialKey(service, field);
|
|
98
|
+
const stored = await setSecureKeyAsync(key, value);
|
|
99
|
+
if (!stored) {
|
|
100
|
+
throw new InternalError(
|
|
101
|
+
`Failed to store credential in secure storage (backend: ${getActiveBackendName()})`,
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
if (!isNonSecretPlatformField(service, field)) {
|
|
105
|
+
try {
|
|
106
|
+
const scrubbed = await scrubStoredCredentialFromTranscripts(value);
|
|
107
|
+
log.info(
|
|
108
|
+
{ service, field, ...scrubbed },
|
|
109
|
+
"Credential stored; scrubbed value from recent transcripts",
|
|
110
|
+
);
|
|
111
|
+
} catch (err) {
|
|
112
|
+
log.warn(
|
|
113
|
+
{ err, service, field },
|
|
114
|
+
"Credential stored, but transcript scrub failed",
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
upsertCredentialMetadata(service, field, {});
|
|
119
|
+
await syncManualTokenConnection(service);
|
|
120
|
+
}
|
|
121
|
+
|
|
82
122
|
let apiKeyGeneration = 0;
|
|
83
123
|
|
|
84
124
|
async function queueApiKeyPropagation(
|
|
@@ -263,6 +303,15 @@ async function handleAddSecret({ body }: RouteHandlerArgs) {
|
|
|
263
303
|
);
|
|
264
304
|
return { success: false, error: validation.reason };
|
|
265
305
|
}
|
|
306
|
+
} else if (name === "typesafe") {
|
|
307
|
+
const validation = await validateJevApiKey(value);
|
|
308
|
+
if (!validation.valid) {
|
|
309
|
+
log.warn(
|
|
310
|
+
{ provider: name, reason: validation.reason },
|
|
311
|
+
"API key validation failed",
|
|
312
|
+
);
|
|
313
|
+
return { success: false, error: validation.reason };
|
|
314
|
+
}
|
|
266
315
|
}
|
|
267
316
|
|
|
268
317
|
const stored = await setSecureKeyAsync(
|
|
@@ -307,10 +356,50 @@ async function handleAddSecret({ body }: RouteHandlerArgs) {
|
|
|
307
356
|
'For credential type, name must be in "service:field" format (e.g. "github:api_token")',
|
|
308
357
|
);
|
|
309
358
|
}
|
|
310
|
-
assertMetadataWritable();
|
|
311
359
|
const service = name.slice(0, colonIdx);
|
|
312
360
|
const field = name.slice(colonIdx + 1);
|
|
313
361
|
|
|
362
|
+
if (service === "vellum") {
|
|
363
|
+
if (!isWritableVellumCredentialField(field)) {
|
|
364
|
+
throw new BadRequestError(
|
|
365
|
+
`Unknown vellum credential: ${field}. Allowed fields: ${WRITABLE_VELLUM_CREDENTIAL_FIELDS.join(", ")}`,
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
assertMetadataWritable();
|
|
369
|
+
await persistCredential(service, field, value);
|
|
370
|
+
if (field === "platform_base_url") {
|
|
371
|
+
setPlatformBaseUrl(value);
|
|
372
|
+
}
|
|
373
|
+
if (isPlatformManagedCredential(service, field)) {
|
|
374
|
+
await refreshProvidersAfterSecretChange();
|
|
375
|
+
// Close the first-boot race where the startup capability seed ran before
|
|
376
|
+
// the managed embedding credential was provisioned, leaving skill/CLI
|
|
377
|
+
// pages unseeded until restart. Detached, must not block the response.
|
|
378
|
+
void maybeReseedCapabilitiesAfterManagedCredential(getConfig());
|
|
379
|
+
if (field === "assistant_api_key") {
|
|
380
|
+
await notifyCesOfAssistantApiKeyUpdate(value, getCesClient());
|
|
381
|
+
}
|
|
382
|
+
} else {
|
|
383
|
+
await refreshProvidersForRotatedCredential(service, field);
|
|
384
|
+
}
|
|
385
|
+
if (field === "assistant_api_key" || field === "platform_base_url") {
|
|
386
|
+
// Managed-speech availability needs the API key, the assistant ID,
|
|
387
|
+
// and the base URL. Fire on each write that completes a piece of
|
|
388
|
+
// that set; the hook no-ops until the connection is complete.
|
|
389
|
+
// Detached, must not block the response.
|
|
390
|
+
void maybeDefaultSpeechToManaged();
|
|
391
|
+
// Same last-write-wins shape: the startup syncs no-op before live
|
|
392
|
+
// registration, so re-enqueue them here. Both dedup and no-op until
|
|
393
|
+
// the client and assistant id exist.
|
|
394
|
+
syncWorkspaceIdentityToPlatform();
|
|
395
|
+
syncAvatarToPlatform();
|
|
396
|
+
}
|
|
397
|
+
log.info({ service, field }, "Credential added via HTTP");
|
|
398
|
+
return { success: true, type, name };
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
assertMetadataWritable();
|
|
402
|
+
|
|
314
403
|
// Reject an Anthropic API key pasted into the ACP OAuth-token field (a 401
|
|
315
404
|
// footgun) as a 400 rather than letting it persist and fail at runtime.
|
|
316
405
|
if (service === ACP_SERVICE) {
|
|
@@ -324,104 +413,8 @@ async function handleAddSecret({ body }: RouteHandlerArgs) {
|
|
|
324
413
|
}
|
|
325
414
|
}
|
|
326
415
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
const TRIMMED_IDENTITY_FIELDS = new Set([
|
|
330
|
-
"platform_assistant_id",
|
|
331
|
-
"platform_organization_id",
|
|
332
|
-
"platform_user_id",
|
|
333
|
-
]);
|
|
334
|
-
const isTrimmedIdentity =
|
|
335
|
-
service === "vellum" && TRIMMED_IDENTITY_FIELDS.has(field);
|
|
336
|
-
const effectiveValue = isTrimmedIdentity ? value.trim() : value;
|
|
337
|
-
|
|
338
|
-
if (isTrimmedIdentity && effectiveValue === "") {
|
|
339
|
-
const deleteResult = await deleteSecureKeyAsync(key);
|
|
340
|
-
if (deleteResult === "error") {
|
|
341
|
-
throw new InternalError(
|
|
342
|
-
`Failed to delete stale credential from secure storage: ${service}:${field}`,
|
|
343
|
-
);
|
|
344
|
-
}
|
|
345
|
-
if (field === "platform_assistant_id") {
|
|
346
|
-
setPlatformAssistantId(undefined);
|
|
347
|
-
} else if (field === "platform_organization_id") {
|
|
348
|
-
setPlatformOrganizationId(undefined);
|
|
349
|
-
} else if (field === "platform_user_id") {
|
|
350
|
-
setPlatformUserId(undefined);
|
|
351
|
-
}
|
|
352
|
-
deleteCredentialMetadata(service, field);
|
|
353
|
-
} else {
|
|
354
|
-
const stored = await setSecureKeyAsync(key, effectiveValue);
|
|
355
|
-
if (!stored) {
|
|
356
|
-
throw new InternalError(
|
|
357
|
-
`Failed to store credential in secure storage (backend: ${getActiveBackendName()})`,
|
|
358
|
-
);
|
|
359
|
-
}
|
|
360
|
-
if (!isNonSecretPlatformField(service, field)) {
|
|
361
|
-
// Same seam as the api_key branch: the scrub runs immediately after
|
|
362
|
-
// the secure-store write, before side effects that can throw. The
|
|
363
|
-
// value IS stored at this point; the scrub is best-effort hygiene
|
|
364
|
-
// and must stay invisible to the caller. Counts only — never the
|
|
365
|
-
// value.
|
|
366
|
-
try {
|
|
367
|
-
const scrubbed =
|
|
368
|
-
await scrubStoredCredentialFromTranscripts(effectiveValue);
|
|
369
|
-
log.info(
|
|
370
|
-
{ service, field, ...scrubbed },
|
|
371
|
-
"Credential stored; scrubbed value from recent transcripts",
|
|
372
|
-
);
|
|
373
|
-
} catch (err) {
|
|
374
|
-
log.warn(
|
|
375
|
-
{ err, service, field },
|
|
376
|
-
"Credential stored, but transcript scrub failed",
|
|
377
|
-
);
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
upsertCredentialMetadata(service, field, {});
|
|
381
|
-
await syncManualTokenConnection(service);
|
|
382
|
-
if (service === "vellum" && field === "platform_base_url") {
|
|
383
|
-
setPlatformBaseUrl(effectiveValue);
|
|
384
|
-
}
|
|
385
|
-
if (service === "vellum" && field === "platform_assistant_id") {
|
|
386
|
-
setPlatformAssistantId(effectiveValue || undefined);
|
|
387
|
-
}
|
|
388
|
-
if (service === "vellum" && field === "platform_organization_id") {
|
|
389
|
-
setPlatformOrganizationId(effectiveValue || undefined);
|
|
390
|
-
}
|
|
391
|
-
if (service === "vellum" && field === "platform_user_id") {
|
|
392
|
-
setPlatformUserId(effectiveValue || undefined);
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
if (isPlatformManagedCredential(service, field)) {
|
|
396
|
-
await refreshProvidersAfterSecretChange();
|
|
397
|
-
// Close the first-boot race where the startup capability seed ran before
|
|
398
|
-
// the managed embedding credential was provisioned, leaving skill/CLI
|
|
399
|
-
// pages unseeded until restart. Detached — must not block the response.
|
|
400
|
-
void maybeReseedCapabilitiesAfterManagedCredential(getConfig());
|
|
401
|
-
if (service === "vellum" && field === "assistant_api_key") {
|
|
402
|
-
await notifyCesOfAssistantApiKeyUpdate(value, getCesClient());
|
|
403
|
-
}
|
|
404
|
-
} else if (!isTrimmedIdentity) {
|
|
405
|
-
await refreshProvidersForRotatedCredential(service, field);
|
|
406
|
-
}
|
|
407
|
-
if (
|
|
408
|
-
service === "vellum" &&
|
|
409
|
-
(field === "assistant_api_key" ||
|
|
410
|
-
field === "platform_assistant_id" ||
|
|
411
|
-
field === "platform_base_url")
|
|
412
|
-
) {
|
|
413
|
-
// Managed-speech availability needs the API key, the assistant ID,
|
|
414
|
-
// and the base URL, and the CLI connect path stores all three
|
|
415
|
-
// concurrently — fire on each so the last write to land triggers the
|
|
416
|
-
// defaulting; the hook no-ops until the connection is complete.
|
|
417
|
-
// Detached — must not block the response.
|
|
418
|
-
void maybeDefaultSpeechToManaged();
|
|
419
|
-
// Same last-write-wins shape: the startup syncs no-op before live
|
|
420
|
-
// registration, so re-enqueue them here. Both dedup and no-op until
|
|
421
|
-
// the client and assistant id exist.
|
|
422
|
-
syncWorkspaceIdentityToPlatform();
|
|
423
|
-
syncAvatarToPlatform();
|
|
424
|
-
}
|
|
416
|
+
await persistCredential(service, field, value);
|
|
417
|
+
await refreshProvidersForRotatedCredential(service, field);
|
|
425
418
|
log.info({ service, field }, "Credential added via HTTP");
|
|
426
419
|
return { success: true, type, name };
|
|
427
420
|
}
|
|
@@ -464,8 +457,7 @@ async function handleReadSecret({ body }: RouteHandlerArgs) {
|
|
|
464
457
|
try {
|
|
465
458
|
let accountKey: string;
|
|
466
459
|
let prefetchedResult:
|
|
467
|
-
|
|
468
|
-
| undefined;
|
|
460
|
+
Awaited<ReturnType<typeof getSecureKeyResultAsync>> | undefined;
|
|
469
461
|
|
|
470
462
|
if (type === "api_key") {
|
|
471
463
|
if (
|
|
@@ -609,6 +601,9 @@ async function handleDeleteSecret({ body }: RouteHandlerArgs) {
|
|
|
609
601
|
);
|
|
610
602
|
}
|
|
611
603
|
const service = name.slice(0, colonIdx);
|
|
604
|
+
if (service === "vellum") {
|
|
605
|
+
throw new BadRequestError("Vellum credentials cannot be deleted");
|
|
606
|
+
}
|
|
612
607
|
const field = name.slice(colonIdx + 1);
|
|
613
608
|
assertMetadataWritable();
|
|
614
609
|
const key = credentialKey(service, field);
|
|
@@ -624,21 +619,6 @@ async function handleDeleteSecret({ body }: RouteHandlerArgs) {
|
|
|
624
619
|
);
|
|
625
620
|
}
|
|
626
621
|
deleteCredentialMetadata(service, field);
|
|
627
|
-
if (service === "vellum" && field === "platform_base_url") {
|
|
628
|
-
setPlatformBaseUrl(undefined);
|
|
629
|
-
}
|
|
630
|
-
if (service === "vellum" && field === "platform_assistant_id") {
|
|
631
|
-
setPlatformAssistantId(undefined);
|
|
632
|
-
}
|
|
633
|
-
if (service === "vellum" && field === "platform_organization_id") {
|
|
634
|
-
setPlatformOrganizationId(undefined);
|
|
635
|
-
}
|
|
636
|
-
if (service === "vellum" && field === "platform_user_id") {
|
|
637
|
-
setPlatformUserId(undefined);
|
|
638
|
-
}
|
|
639
|
-
if (isPlatformManagedCredential(service, field)) {
|
|
640
|
-
await refreshProvidersAfterSecretChange();
|
|
641
|
-
}
|
|
642
622
|
invalidateConnectionsAfterCredentialDelete(affectedConnections);
|
|
643
623
|
log.info({ service, field }, "Credential deleted via HTTP");
|
|
644
624
|
return { success: true, type, name };
|
|
@@ -662,10 +662,16 @@ async function handleToolPermissionSimulate({ body = {} }: RouteHandlerArgs) {
|
|
|
662
662
|
const manifestOverride = resolveManifestOverride(toolName);
|
|
663
663
|
// Permission Simulator path: registered tool wins, then explicit
|
|
664
664
|
// manifest override, then the standard inference rules.
|
|
665
|
-
const
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
665
|
+
const tool = getTool(toolName);
|
|
666
|
+
const executionTarget = resolveExecutionTarget(
|
|
667
|
+
{
|
|
668
|
+
name: toolName,
|
|
669
|
+
executionTarget:
|
|
670
|
+
tool?.executionTarget ?? manifestOverride?.execution_target,
|
|
671
|
+
getExecutionTarget: tool?.getExecutionTarget,
|
|
672
|
+
},
|
|
673
|
+
input,
|
|
674
|
+
);
|
|
669
675
|
const executionContext =
|
|
670
676
|
isInteractive === false ? "headless" : "conversation";
|
|
671
677
|
const policyContext = { executionTarget, executionContext } as const;
|
|
@@ -86,7 +86,7 @@ function handleWatcherCreate({ body = {} }: RouteHandlerArgs) {
|
|
|
86
86
|
const credentialService =
|
|
87
87
|
credentialServiceOverride ?? provider.requiredCredentialService;
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
return createWatcher({
|
|
90
90
|
name,
|
|
91
91
|
providerId,
|
|
92
92
|
actionPrompt,
|
|
@@ -94,8 +94,6 @@ function handleWatcherCreate({ body = {} }: RouteHandlerArgs) {
|
|
|
94
94
|
pollIntervalMs,
|
|
95
95
|
configJson: config ? JSON.stringify(config) : null,
|
|
96
96
|
});
|
|
97
|
-
|
|
98
|
-
return watcher;
|
|
99
97
|
}
|
|
100
98
|
|
|
101
99
|
function handleWatcherList({ body = {} }: RouteHandlerArgs) {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { afterEach, describe, expect, test } from "bun:test";
|
|
2
2
|
|
|
3
|
+
import { TRUST_CLASS_VALUES } from "@vellumai/gateway-client";
|
|
4
|
+
|
|
3
5
|
import { resolveCapabilities } from "./capabilities.js";
|
|
4
6
|
import {
|
|
5
7
|
derivePersonaTrustFlags,
|
|
6
8
|
isContactTrustClass,
|
|
7
9
|
type PersonaTrustFlags,
|
|
8
|
-
trustClassSchema,
|
|
9
10
|
} from "./trust-class.js";
|
|
10
11
|
|
|
11
12
|
describe("isContactTrustClass", () => {
|
|
@@ -27,7 +28,7 @@ describe("isContactTrustClass", () => {
|
|
|
27
28
|
test("agrees with derivePersonaTrustFlags for every trust class", () => {
|
|
28
29
|
// The predicate and the persona flags encode the same grouping; pin them
|
|
29
30
|
// together so neither can drift without failing here.
|
|
30
|
-
for (const trustClass of
|
|
31
|
+
for (const trustClass of TRUST_CLASS_VALUES) {
|
|
31
32
|
expect(isContactTrustClass(trustClass)).toBe(
|
|
32
33
|
derivePersonaTrustFlags(trustClass).isTrustedContact,
|
|
33
34
|
);
|
|
@@ -46,7 +47,7 @@ describe("derivePersonaTrustFlags", () => {
|
|
|
46
47
|
});
|
|
47
48
|
|
|
48
49
|
test("trusted_contact and unverified_contact derive identical contact flags", () => {
|
|
49
|
-
// The admission-only equivalence documented
|
|
50
|
+
// The admission-only equivalence documented in trust-class.ts: the two
|
|
50
51
|
// classes must never drift apart at the persona layer.
|
|
51
52
|
const expected: PersonaTrustFlags = {
|
|
52
53
|
trustClass: "trusted_contact",
|
|
@@ -82,9 +83,9 @@ describe("derivePersonaTrustFlags", () => {
|
|
|
82
83
|
});
|
|
83
84
|
|
|
84
85
|
test("exactly one flag is true for every trust class", () => {
|
|
85
|
-
// Iterates the
|
|
86
|
+
// Iterates the canonical class list so a newly added class is covered
|
|
86
87
|
// (the helper itself won't compile until the new class gets a case).
|
|
87
|
-
for (const trustClass of
|
|
88
|
+
for (const trustClass of TRUST_CLASS_VALUES) {
|
|
88
89
|
const flags = derivePersonaTrustFlags(trustClass);
|
|
89
90
|
const trueCount = [
|
|
90
91
|
flags.isGuardian,
|
|
@@ -128,7 +129,7 @@ describe("derivePersonaTrustFlags", () => {
|
|
|
128
129
|
isTrustedContact: "social-engineering-defense",
|
|
129
130
|
isStranger: "stranger-warning",
|
|
130
131
|
};
|
|
131
|
-
for (const trustClass of
|
|
132
|
+
for (const trustClass of TRUST_CLASS_VALUES) {
|
|
132
133
|
const flags = derivePersonaTrustFlags(trustClass);
|
|
133
134
|
const guidance = resolveCapabilities(trustClass).promptTrustGuidance;
|
|
134
135
|
for (const [flag, expected] of Object.entries(guidanceByFlag)) {
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* persistence schema can share one definition without a circular import.
|
|
2
|
+
* The daemon's reading of an inbound actor's trust class. The vocabulary
|
|
3
|
+
* itself ({@link TrustClass}, `TrustClassSchema`) belongs to the gateway,
|
|
4
|
+
* which classifies every actor; it lives in `@vellumai/gateway-client`
|
|
5
|
+
* (`trust-verdict-contract.ts`) and is re-exported here, never redeclared.
|
|
6
|
+
* This module holds what the daemon derives from a class:
|
|
8
7
|
*
|
|
9
8
|
* - `'guardian'`: The sender matches the active guardian binding for this
|
|
10
9
|
* (assistant, channel). Guardians have full control-plane access and
|
|
@@ -21,21 +20,14 @@
|
|
|
21
20
|
* actors are fail-closed with no escalation path.
|
|
22
21
|
*/
|
|
23
22
|
|
|
24
|
-
import {
|
|
25
|
-
|
|
26
|
-
export const trustClassSchema = z.enum([
|
|
27
|
-
"guardian",
|
|
28
|
-
"trusted_contact",
|
|
29
|
-
"unverified_contact",
|
|
30
|
-
"unknown",
|
|
31
|
-
]);
|
|
23
|
+
import type { TrustClass } from "@vellumai/gateway-client";
|
|
32
24
|
|
|
33
|
-
export type TrustClass
|
|
25
|
+
export type { TrustClass };
|
|
34
26
|
|
|
35
27
|
/**
|
|
36
28
|
* Whether a trust class names a known non-guardian contact — the
|
|
37
29
|
* `trusted_contact` / `unverified_contact` pair whose admission-only
|
|
38
|
-
* equivalence is documented
|
|
30
|
+
* equivalence is documented in this module's header.
|
|
39
31
|
*
|
|
40
32
|
* Accepts a raw string (not just `TrustClass`) because several call sites
|
|
41
33
|
* classify trust classes read back from persisted turn metadata, which may
|
|
@@ -75,7 +67,7 @@ export interface PersonaTrustFlags {
|
|
|
75
67
|
* needs the opposite default — fail closed, so a turn that never resolved an
|
|
76
68
|
* actor still renders the guardrail rather than a guardian exemption.
|
|
77
69
|
* - `unverified_contact` derives identically to `trusted_contact`, making the
|
|
78
|
-
* admission-only equivalence documented
|
|
70
|
+
* admission-only equivalence documented in this module's header
|
|
79
71
|
* executable in one place.
|
|
80
72
|
* - The switch is exhaustive with no default: adding a `TrustClass` member is a
|
|
81
73
|
* compile error here, forcing a deliberate persona decision for the new
|