@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
|
@@ -20,11 +20,13 @@ import { createReadStream } from "node:fs";
|
|
|
20
20
|
import { hostname } from "node:os";
|
|
21
21
|
import { PassThrough, Readable } from "node:stream";
|
|
22
22
|
|
|
23
|
+
import { GatewayDebugExportIpcResponseSchema } from "@vellumai/gateway-client/gateway-ipc-contracts";
|
|
23
24
|
import { z } from "zod";
|
|
24
25
|
|
|
25
26
|
import { invalidateConfigCache } from "../../config/loader.js";
|
|
26
27
|
import { resolvePlatformAssistantId } from "../../config/platform-identity.js";
|
|
27
28
|
import { getAssistantName } from "../../daemon/identity-helpers.js";
|
|
29
|
+
import { ipcCallPersistent } from "../../ipc/gateway-client.js";
|
|
28
30
|
import { runAsyncSqlite } from "../../persistence/db-async-query.js";
|
|
29
31
|
import {
|
|
30
32
|
getDb,
|
|
@@ -470,8 +472,40 @@ const EXPORT_TO_GCS_PUT_TIMEOUT_MS = 60 * 60 * 1000;
|
|
|
470
472
|
const MigrationExportToGcsBody = z.object({
|
|
471
473
|
upload_url: z.string().url(),
|
|
472
474
|
description: z.string().optional(),
|
|
475
|
+
/**
|
|
476
|
+
* `debug`: a bundle for Vellum staff to inspect. Adds the gateway's
|
|
477
|
+
* database and recent logs under `gateway/`. `migration` is the default.
|
|
478
|
+
*/
|
|
479
|
+
profile: z.enum(["migration", "debug"]).default("migration"),
|
|
473
480
|
});
|
|
474
481
|
|
|
482
|
+
/** Archive path of the gateway's contribution to a debug bundle. */
|
|
483
|
+
export const GATEWAY_DEBUG_EXPORT_PATH = "gateway/export.tar.gz";
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Ask the gateway for its debug archive over the local socket. The daemon
|
|
487
|
+
* cannot read the gateway's files itself: in local mode they sit in the
|
|
488
|
+
* protected directory beside the encryption keys, and in Docker on a volume
|
|
489
|
+
* the daemon does not mount.
|
|
490
|
+
*/
|
|
491
|
+
async function collectGatewayDebugExport(): Promise<{
|
|
492
|
+
archivePath: string;
|
|
493
|
+
data: Uint8Array;
|
|
494
|
+
}> {
|
|
495
|
+
const raw = await ipcCallPersistent(
|
|
496
|
+
"gateway_debug_export",
|
|
497
|
+
{},
|
|
498
|
+
GATEWAY_DEBUG_EXPORT_TIMEOUT_MS,
|
|
499
|
+
);
|
|
500
|
+
const parsed = GatewayDebugExportIpcResponseSchema.parse(raw);
|
|
501
|
+
return {
|
|
502
|
+
archivePath: GATEWAY_DEBUG_EXPORT_PATH,
|
|
503
|
+
data: new Uint8Array(Buffer.from(parsed.archive_base64, "base64")),
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
const GATEWAY_DEBUG_EXPORT_TIMEOUT_MS = 120_000;
|
|
508
|
+
|
|
475
509
|
/**
|
|
476
510
|
* Collected credentials plus warning markers if the credential store was
|
|
477
511
|
* unreachable. The caller surfaces the warning in logs; production callers
|
|
@@ -559,9 +593,10 @@ export async function handleMigrationExportToGcs({ body }: RouteHandlerArgs) {
|
|
|
559
593
|
const parsed = MigrationExportToGcsBody.safeParse(body);
|
|
560
594
|
if (!parsed.success) {
|
|
561
595
|
throw new BadRequestError(
|
|
562
|
-
"Request body must be { upload_url: string, description?: string } with a valid URL",
|
|
596
|
+
"Request body must be { upload_url: string, description?: string, profile?: 'migration' | 'debug' } with a valid URL",
|
|
563
597
|
);
|
|
564
598
|
}
|
|
599
|
+
const isDebugProfile = parsed.data.profile === "debug";
|
|
565
600
|
|
|
566
601
|
// ── 2. Validate the upload URL. Never log `parsed.data.upload_url`.
|
|
567
602
|
const validated = validateGcsSignedUrl(
|
|
@@ -608,8 +643,11 @@ export async function handleMigrationExportToGcs({ body }: RouteHandlerArgs) {
|
|
|
608
643
|
// "managed"), and teleport clients re-provision platform identity after
|
|
609
644
|
// a platform→local import — so redact instead of emitting a bundle the
|
|
610
645
|
// importer is guaranteed to reject.
|
|
646
|
+
//
|
|
647
|
+
// A debug bundle goes to Vellum staff, so it never carries credentials
|
|
648
|
+
// either, whatever the deployment mode.
|
|
611
649
|
let collected: CollectedCredentials;
|
|
612
|
-
if (manifestInputs.origin.mode === "managed") {
|
|
650
|
+
if (manifestInputs.origin.mode === "managed" || isDebugProfile) {
|
|
613
651
|
collected = {
|
|
614
652
|
credentials: [],
|
|
615
653
|
unreachable: false,
|
|
@@ -632,17 +670,44 @@ export async function handleMigrationExportToGcs({ body }: RouteHandlerArgs) {
|
|
|
632
670
|
collected.perAccountUnreachable,
|
|
633
671
|
);
|
|
634
672
|
|
|
673
|
+
if (isDebugProfile) {
|
|
674
|
+
manifestInputs = {
|
|
675
|
+
...manifestInputs,
|
|
676
|
+
exportOptions: { ...manifestInputs.exportOptions, include_gateway: true },
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
|
|
635
680
|
// ── 4. Enqueue the job. The runner captures the collected credentials.
|
|
636
681
|
let job;
|
|
637
682
|
try {
|
|
638
683
|
job = migrationJobs.startJob("export", async () => {
|
|
639
684
|
let cleanup: (() => Promise<void>) | undefined;
|
|
640
685
|
try {
|
|
686
|
+
// The gateway snapshot can take a while on a large database, so it
|
|
687
|
+
// runs inside the job (after the export slot is held) rather than
|
|
688
|
+
// before the 202. A debug bundle without the gateway's data is not
|
|
689
|
+
// what staff asked for, so a failure fails the job and nothing is
|
|
690
|
+
// uploaded.
|
|
691
|
+
let extraFiles: Array<{ archivePath: string; data: Uint8Array }> = [];
|
|
692
|
+
if (isDebugProfile) {
|
|
693
|
+
try {
|
|
694
|
+
extraFiles = [await collectGatewayDebugExport()];
|
|
695
|
+
} catch (err) {
|
|
696
|
+
log.error({ err }, "Failed to collect the gateway's debug export");
|
|
697
|
+
const wrapped = new Error(
|
|
698
|
+
"The gateway did not provide its debug export; the bundle was not sent.",
|
|
699
|
+
);
|
|
700
|
+
(wrapped as { code?: string }).code = "gateway_debug_export_failed";
|
|
701
|
+
throw wrapped;
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
641
705
|
const result = await streamExportVBundle({
|
|
642
706
|
workspaceDir: getWorkspaceDir(),
|
|
643
707
|
...manifestInputs,
|
|
644
708
|
secretsRedacted,
|
|
645
709
|
credentials: collected.credentials,
|
|
710
|
+
extraFiles,
|
|
646
711
|
checkpoint: checkpointDbsForExport,
|
|
647
712
|
});
|
|
648
713
|
|
|
@@ -2402,6 +2467,12 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
2402
2467
|
.string()
|
|
2403
2468
|
.optional()
|
|
2404
2469
|
.describe("Human-readable export description."),
|
|
2470
|
+
profile: z
|
|
2471
|
+
.enum(["migration", "debug"])
|
|
2472
|
+
.optional()
|
|
2473
|
+
.describe(
|
|
2474
|
+
"Export profile. 'migration' (default) builds a teleport bundle. 'debug' builds a bundle for Vellum staff to open on a debug clone: no credentials, plus the gateway's database and logs under gateway/.",
|
|
2475
|
+
),
|
|
2405
2476
|
}),
|
|
2406
2477
|
responseStatus: "202",
|
|
2407
2478
|
responseBody: z.object({
|
|
@@ -14,6 +14,10 @@ import {
|
|
|
14
14
|
NotificationSourceChannelSchema,
|
|
15
15
|
RoutingIntentSchema,
|
|
16
16
|
} from "../../notifications/signal.js";
|
|
17
|
+
import {
|
|
18
|
+
NotificationDeliveryResultSchema,
|
|
19
|
+
NotificationReceiptClassSchema,
|
|
20
|
+
} from "../../notifications/types.js";
|
|
17
21
|
import { UrgencySchema } from "../../notifications/urgency.js";
|
|
18
22
|
import { getDb } from "../../persistence/db-connection.js";
|
|
19
23
|
import { notificationDeliveries } from "../../persistence/schema/index.js";
|
|
@@ -78,6 +82,9 @@ const EmitSignalResponse = z.object({
|
|
|
78
82
|
dispatched: z.boolean(),
|
|
79
83
|
deduplicated: z.boolean(),
|
|
80
84
|
reason: z.string(),
|
|
85
|
+
selectedChannels: z.array(z.string()),
|
|
86
|
+
deliveryResults: z.array(NotificationDeliveryResultSchema),
|
|
87
|
+
receiptClass: NotificationReceiptClassSchema,
|
|
81
88
|
});
|
|
82
89
|
|
|
83
90
|
async function handleEmitSignal({ body = {} }: RouteHandlerArgs) {
|
|
@@ -94,6 +101,9 @@ async function handleEmitSignal({ body = {} }: RouteHandlerArgs) {
|
|
|
94
101
|
dispatched: result.dispatched,
|
|
95
102
|
deduplicated: result.deduplicated,
|
|
96
103
|
reason: result.reason,
|
|
104
|
+
selectedChannels: result.selectedChannels,
|
|
105
|
+
deliveryResults: result.deliveryResults,
|
|
106
|
+
receiptClass: result.receiptClass,
|
|
97
107
|
};
|
|
98
108
|
}
|
|
99
109
|
|
|
@@ -20,7 +20,10 @@ import {
|
|
|
20
20
|
type Services,
|
|
21
21
|
ServicesSchema,
|
|
22
22
|
} from "../../config/schemas/services.js";
|
|
23
|
-
import type {
|
|
23
|
+
import type {
|
|
24
|
+
OAuthConnectionRequest,
|
|
25
|
+
OAuthConnectionResponse,
|
|
26
|
+
} from "../../oauth/connection.js";
|
|
24
27
|
import {
|
|
25
28
|
isBinaryOAuthBody,
|
|
26
29
|
jsonSafeOAuthBody,
|
|
@@ -30,6 +33,7 @@ import {
|
|
|
30
33
|
type ResolveOAuthConnectionOptions,
|
|
31
34
|
resolveOAuthConnectionWithMeta,
|
|
32
35
|
} from "../../oauth/connection-resolver.js";
|
|
36
|
+
import { providerReportsFailure } from "../../oauth/identity-verifier.js";
|
|
33
37
|
import { syncManualTokenConnection } from "../../oauth/manual-token-connection.js";
|
|
34
38
|
import {
|
|
35
39
|
disconnectOAuthProvider,
|
|
@@ -54,6 +58,7 @@ import {
|
|
|
54
58
|
} from "../../util/oauth-request-body.js";
|
|
55
59
|
import { LOCAL_PRINCIPALS } from "../auth/route-policy.js";
|
|
56
60
|
import { BadRequestError, InternalError, NotFoundError } from "./errors.js";
|
|
61
|
+
import { composeRequestHint } from "./oauth-request-hints.js";
|
|
57
62
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
58
63
|
|
|
59
64
|
const log = getLogger("oauth-commands-routes");
|
|
@@ -233,6 +238,27 @@ function assertOAuthRequestUrlAllowed(
|
|
|
233
238
|
}
|
|
234
239
|
}
|
|
235
240
|
|
|
241
|
+
/**
|
|
242
|
+
* The verdict on a provider exchange: whether the status said success, and
|
|
243
|
+
* whether the provider's declared ok field (`responseOkField`) then took it
|
|
244
|
+
* back. The field is read only under a 2xx, so a 429 or 5xx whose body
|
|
245
|
+
* happens to carry it stays a transport failure rather than a refusal.
|
|
246
|
+
* `reportedFailure` is the one-line account of a refusal, absent otherwise.
|
|
247
|
+
*/
|
|
248
|
+
function judgeProviderResponse(
|
|
249
|
+
providerRow: OAuthProviderRow,
|
|
250
|
+
response: OAuthConnectionResponse,
|
|
251
|
+
): { ok: boolean; reportedFailure?: string } {
|
|
252
|
+
const httpOk = response.status >= 200 && response.status < 300;
|
|
253
|
+
if (httpOk && providerReportsFailure(providerRow, response.body)) {
|
|
254
|
+
return {
|
|
255
|
+
ok: false,
|
|
256
|
+
reportedFailure: `${providerRow.provider} answered HTTP ${response.status} but reported ${providerRow.responseOkField}: false`,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
return { ok: httpOk };
|
|
260
|
+
}
|
|
261
|
+
|
|
236
262
|
/**
|
|
237
263
|
* Required scopes the resolved connection's stored grant lacks. Credential
|
|
238
264
|
* health measures the same thing on the heartbeat; measuring it on the
|
|
@@ -689,7 +715,8 @@ async function handlePing({ body = {} }: RouteHandlerArgs) {
|
|
|
689
715
|
...(pingBody !== undefined ? { body: pingBody } : {}),
|
|
690
716
|
});
|
|
691
717
|
|
|
692
|
-
|
|
718
|
+
const verdict = judgeProviderResponse(providerRow, response);
|
|
719
|
+
if (verdict.ok) {
|
|
693
720
|
return { ok: true, provider: b.provider, status: response.status };
|
|
694
721
|
}
|
|
695
722
|
|
|
@@ -697,10 +724,21 @@ async function handlePing({ body = {} }: RouteHandlerArgs) {
|
|
|
697
724
|
ok: false,
|
|
698
725
|
provider: b.provider,
|
|
699
726
|
status: response.status,
|
|
700
|
-
error:
|
|
727
|
+
error: verdict.reportedFailure
|
|
728
|
+
? `Ping failed: ${verdict.reportedFailure}`
|
|
729
|
+
: `Ping failed with HTTP ${response.status}`,
|
|
701
730
|
};
|
|
731
|
+
if (verdict.reportedFailure) {
|
|
732
|
+
payload.body = response.body;
|
|
733
|
+
}
|
|
702
734
|
|
|
703
|
-
|
|
735
|
+
// A provider that refuses the ping inside a 2xx is refusing the credential
|
|
736
|
+
// the same way a 401 does.
|
|
737
|
+
if (
|
|
738
|
+
response.status === 401 ||
|
|
739
|
+
response.status === 403 ||
|
|
740
|
+
verdict.reportedFailure
|
|
741
|
+
) {
|
|
704
742
|
payload.hint =
|
|
705
743
|
`Run 'assistant oauth status ${b.provider}' to check connection health. ` +
|
|
706
744
|
`To reconnect, run 'assistant oauth connect --help'.`;
|
|
@@ -978,8 +1016,10 @@ export async function handleRequest({ body = {} }: RouteHandlerArgs) {
|
|
|
978
1016
|
const response = await connection.request(req);
|
|
979
1017
|
const encodedBody = jsonSafeOAuthBody(response.body);
|
|
980
1018
|
|
|
1019
|
+
const verdict = judgeProviderResponse(providerRow, response);
|
|
1020
|
+
|
|
981
1021
|
const result: Record<string, unknown> = {
|
|
982
|
-
ok:
|
|
1022
|
+
ok: verdict.ok,
|
|
983
1023
|
status: response.status,
|
|
984
1024
|
headers: response.headers,
|
|
985
1025
|
body: encodedBody.body,
|
|
@@ -1001,60 +1041,23 @@ export async function handleRequest({ body = {} }: RouteHandlerArgs) {
|
|
|
1001
1041
|
`used "${selected}". Pass --account to select a specific one.`;
|
|
1002
1042
|
}
|
|
1003
1043
|
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
`To reconnect, run 'assistant oauth connect --help'.`
|
|
1017
|
-
: `Request returned HTTP ${response.status}. The OAuth token may be expired or revoked.\n\n` +
|
|
1018
|
-
`Run 'assistant oauth status ${b.provider}' to check connection status.\n` +
|
|
1019
|
-
`To reconnect, run 'assistant oauth connect --help'.`;
|
|
1020
|
-
} else if (response.status === 404 && isHtmlResponse(response.headers)) {
|
|
1021
|
-
// An HTML 404 (rather than a JSON API error) is the signature of a request
|
|
1022
|
-
// reaching a valid host but a path that host does not serve — e.g. a
|
|
1023
|
-
// relative path resolved against a base URL that points at the wrong
|
|
1024
|
-
// product. Surface the resolved base so the caller can tell where the path
|
|
1025
|
-
// landed, and steer them to an absolute URL for non-default services.
|
|
1026
|
-
const resolvedBaseUrl =
|
|
1027
|
-
baseUrl ?? providerRow.baseUrl ?? "(none configured)";
|
|
1028
|
-
result.hint =
|
|
1029
|
-
`Request returned HTTP ${response.status} with an HTML body, which usually means ` +
|
|
1030
|
-
`the path does not exist on the base URL it resolved against.\n\n` +
|
|
1031
|
-
`This request used base URL "${resolvedBaseUrl}" (relative paths are joined onto it). ` +
|
|
1032
|
-
`If you meant a different service on this provider, pass an absolute URL ` +
|
|
1033
|
-
`(e.g. https://host/full/path) so the host and full path are set explicitly.`;
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
const missingScopes = missingScopesForConnection(providerRow, connection.id);
|
|
1037
|
-
if (missingScopes.length > 0) {
|
|
1038
|
-
const scopeHint =
|
|
1039
|
-
`The ${b.provider} connection is missing required scopes: ${missingScopes.join(", ")}. ` +
|
|
1040
|
-
`It was connected before they were required, so calls that need them fail. ` +
|
|
1041
|
-
`Reconnect it from Integrations, or run 'assistant oauth connect ${b.provider}', to grant them.`;
|
|
1042
|
-
result.hint = result.hint ? `${scopeHint}\n\n${result.hint}` : scopeHint;
|
|
1044
|
+
const hint = composeRequestHint({
|
|
1045
|
+
provider: b.provider,
|
|
1046
|
+
status: response.status,
|
|
1047
|
+
headers: response.headers,
|
|
1048
|
+
reportedFailure: verdict.reportedFailure,
|
|
1049
|
+
botChannel: channelForBotProvider(b.provider),
|
|
1050
|
+
managed,
|
|
1051
|
+
resolvedBaseUrl: baseUrl ?? providerRow.baseUrl ?? undefined,
|
|
1052
|
+
missingScopes: missingScopesForConnection(providerRow, connection.id),
|
|
1053
|
+
});
|
|
1054
|
+
if (hint) {
|
|
1055
|
+
result.hint = hint;
|
|
1043
1056
|
}
|
|
1044
1057
|
|
|
1045
1058
|
return result;
|
|
1046
1059
|
}
|
|
1047
1060
|
|
|
1048
|
-
/** True when the response's Content-Type header indicates an HTML body. */
|
|
1049
|
-
function isHtmlResponse(headers: Record<string, string>): boolean {
|
|
1050
|
-
for (const [key, value] of Object.entries(headers)) {
|
|
1051
|
-
if (key.toLowerCase() === "content-type") {
|
|
1052
|
-
return value.toLowerCase().includes("text/html");
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
return false;
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
1061
|
// ---------------------------------------------------------------------------
|
|
1059
1062
|
// Connect handler (managed path for platform OAuth)
|
|
1060
1063
|
// ---------------------------------------------------------------------------
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* the standard runtime auth middleware.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { INTEGRATION_CATEGORIES } from "@vellumai/service-contracts/integration-categories";
|
|
9
10
|
import { z } from "zod";
|
|
10
11
|
|
|
11
12
|
import { loadConfig } from "../../config/loader.js";
|
|
@@ -176,6 +177,7 @@ function handleRegisterProvider({ body = {} }: RouteHandlerArgs) {
|
|
|
176
177
|
(b.identity_response_paths as string[]) ?? undefined,
|
|
177
178
|
identityFormat: (b.identity_format as string) ?? undefined,
|
|
178
179
|
identityOkField: (b.identity_ok_field as string) ?? undefined,
|
|
180
|
+
responseOkField: (b.response_ok_field as string) ?? undefined,
|
|
179
181
|
setupNotes: (b.setup_notes as string[]) ?? undefined,
|
|
180
182
|
});
|
|
181
183
|
|
|
@@ -312,6 +314,9 @@ function handleUpdateProvider({
|
|
|
312
314
|
if (b.identity_ok_field !== undefined) {
|
|
313
315
|
params.identityOkField = b.identity_ok_field;
|
|
314
316
|
}
|
|
317
|
+
if (b.response_ok_field !== undefined) {
|
|
318
|
+
params.responseOkField = b.response_ok_field;
|
|
319
|
+
}
|
|
315
320
|
if (b.setup_notes !== undefined) {
|
|
316
321
|
params.setupNotes = b.setup_notes;
|
|
317
322
|
}
|
|
@@ -397,6 +402,12 @@ export const oauthProviderSummarySchema = z.object({
|
|
|
397
402
|
supports_managed_mode: z.boolean(),
|
|
398
403
|
managed_service_is_paid: z.boolean(),
|
|
399
404
|
feature_flag: z.string().nullable(),
|
|
405
|
+
category: z
|
|
406
|
+
.enum(INTEGRATION_CATEGORIES)
|
|
407
|
+
.nullable()
|
|
408
|
+
.describe(
|
|
409
|
+
"Where the integrations catalog files the provider; null for a provider without a seed entry.",
|
|
410
|
+
),
|
|
400
411
|
tenant_host: z
|
|
401
412
|
.object({
|
|
402
413
|
pattern: z.string(),
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The request doors' hint, asserted on the composer directly. Every case
|
|
3
|
+
* pins the rendered text in full, so a wording change is a visible diff here
|
|
4
|
+
* and never a silent one behind a route test's substring match.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, expect, test } from "bun:test";
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
composeRequestHint,
|
|
11
|
+
REQUEST_HINT_RULES,
|
|
12
|
+
type RequestHintFacts,
|
|
13
|
+
} from "./oauth-request-hints.js";
|
|
14
|
+
|
|
15
|
+
const JSON_HEADERS = { "content-type": "application/json" };
|
|
16
|
+
const HTML_HEADERS = { "content-type": "text/html; charset=utf-8" };
|
|
17
|
+
|
|
18
|
+
function asBot(overrides: Partial<RequestHintFacts> = {}): RequestHintFacts {
|
|
19
|
+
return {
|
|
20
|
+
provider: "slack_channel",
|
|
21
|
+
status: 200,
|
|
22
|
+
headers: JSON_HEADERS,
|
|
23
|
+
botChannel: "slack",
|
|
24
|
+
managed: false,
|
|
25
|
+
resolvedBaseUrl: "https://slack.com/api",
|
|
26
|
+
missingScopes: [],
|
|
27
|
+
...overrides,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function asPerson(overrides: Partial<RequestHintFacts> = {}): RequestHintFacts {
|
|
32
|
+
return {
|
|
33
|
+
provider: "google",
|
|
34
|
+
status: 200,
|
|
35
|
+
headers: JSON_HEADERS,
|
|
36
|
+
managed: false,
|
|
37
|
+
resolvedBaseUrl: "https://api.google.com",
|
|
38
|
+
missingScopes: [],
|
|
39
|
+
...overrides,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
describe("composeRequestHint", () => {
|
|
44
|
+
test("the rules are applied in this precedence order", () => {
|
|
45
|
+
// The generic 401/403 rule matches every 403, so the HTML 403 rule has
|
|
46
|
+
// to be judged before it; a provider's own reported failure outranks
|
|
47
|
+
// every status. The list is the order, and this pins it.
|
|
48
|
+
expect(REQUEST_HINT_RULES.map((rule) => rule.name)).toEqual([
|
|
49
|
+
"provider reported failure",
|
|
50
|
+
"resource not visible",
|
|
51
|
+
"credential rejected",
|
|
52
|
+
"path not served",
|
|
53
|
+
]);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("a 2xx is silent", () => {
|
|
57
|
+
expect(composeRequestHint(asBot())).toBeUndefined();
|
|
58
|
+
expect(composeRequestHint(asPerson())).toBeUndefined();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("a provider's reported failure names only why the 2xx failed", () => {
|
|
62
|
+
expect(
|
|
63
|
+
composeRequestHint(
|
|
64
|
+
asBot({
|
|
65
|
+
reportedFailure:
|
|
66
|
+
"slack_channel answered HTTP 200 but reported ok: false",
|
|
67
|
+
}),
|
|
68
|
+
),
|
|
69
|
+
).toBe(
|
|
70
|
+
"slack_channel answered HTTP 200 but reported ok: false in the response body. The body names the error.",
|
|
71
|
+
);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("a reported failure outranks every status rule", () => {
|
|
75
|
+
expect(
|
|
76
|
+
composeRequestHint(
|
|
77
|
+
asBot({
|
|
78
|
+
status: 403,
|
|
79
|
+
headers: HTML_HEADERS,
|
|
80
|
+
reportedFailure:
|
|
81
|
+
"slack_channel answered HTTP 403 but reported ok: false",
|
|
82
|
+
}),
|
|
83
|
+
),
|
|
84
|
+
).toBe(
|
|
85
|
+
"slack_channel answered HTTP 403 but reported ok: false in the response body. The body names the error.",
|
|
86
|
+
);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test("an HTML 403 as a bot names the resource's access and the channel's diagnostics", () => {
|
|
90
|
+
expect(
|
|
91
|
+
composeRequestHint(
|
|
92
|
+
asBot({
|
|
93
|
+
status: 403,
|
|
94
|
+
headers: HTML_HEADERS,
|
|
95
|
+
resolvedBaseUrl: "https://files.slack.com",
|
|
96
|
+
}),
|
|
97
|
+
),
|
|
98
|
+
).toBe(
|
|
99
|
+
"Request returned HTTP 403 with an HTML page from files.slack.com, not an API error. " +
|
|
100
|
+
"That usually means the slack bot cannot see this resource: it is not shared with it, or the scope it needs is missing. " +
|
|
101
|
+
"Check the resource's access before treating the credential as revoked; " +
|
|
102
|
+
"'assistant channels get slack' reports the credential itself.",
|
|
103
|
+
);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test("an HTML 403 as a person names the connected account and oauth status", () => {
|
|
107
|
+
expect(
|
|
108
|
+
composeRequestHint(asPerson({ status: 403, headers: HTML_HEADERS })),
|
|
109
|
+
).toBe(
|
|
110
|
+
"Request returned HTTP 403 with an HTML page from api.google.com, not an API error. " +
|
|
111
|
+
"That usually means the connected account cannot see this resource: it is not shared with it, or the scope it needs is missing. " +
|
|
112
|
+
"Check the resource's access before treating the credential as revoked; " +
|
|
113
|
+
"'assistant oauth status google' reports the credential itself.",
|
|
114
|
+
);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("an HTML 403 with no resolved base omits the host", () => {
|
|
118
|
+
expect(
|
|
119
|
+
composeRequestHint(
|
|
120
|
+
asPerson({
|
|
121
|
+
status: 403,
|
|
122
|
+
headers: HTML_HEADERS,
|
|
123
|
+
resolvedBaseUrl: undefined,
|
|
124
|
+
}),
|
|
125
|
+
),
|
|
126
|
+
).toBe(
|
|
127
|
+
"Request returned HTTP 403 with an HTML page, not an API error. " +
|
|
128
|
+
"That usually means the connected account cannot see this resource: it is not shared with it, or the scope it needs is missing. " +
|
|
129
|
+
"Check the resource's access before treating the credential as revoked; " +
|
|
130
|
+
"'assistant oauth status google' reports the credential itself.",
|
|
131
|
+
);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test("a JSON 403 keeps the credential reading on any host", () => {
|
|
135
|
+
// An API's own refusal, on the base host or on a provider's other API
|
|
136
|
+
// hosts alike.
|
|
137
|
+
const onApiHost = composeRequestHint(asBot({ status: 403 }));
|
|
138
|
+
expect(onApiHost).toContain("slack bot credential was rejected");
|
|
139
|
+
expect(onApiHost).not.toContain("cannot see this resource");
|
|
140
|
+
|
|
141
|
+
const onOtherApiHost = composeRequestHint(
|
|
142
|
+
asPerson({
|
|
143
|
+
status: 403,
|
|
144
|
+
resolvedBaseUrl: "https://calendar.googleapis.com",
|
|
145
|
+
}),
|
|
146
|
+
);
|
|
147
|
+
expect(onOtherApiHost).toContain(
|
|
148
|
+
"The OAuth token may be expired or revoked",
|
|
149
|
+
);
|
|
150
|
+
expect(onOtherApiHost).not.toContain("cannot see this resource");
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test("a rejected bot credential points at the channel's diagnostics, never the OAuth commands", () => {
|
|
154
|
+
expect(composeRequestHint(asBot({ status: 401 }))).toBe(
|
|
155
|
+
"Request returned HTTP 401. The slack bot credential was rejected; it may have been revoked or reinstalled with fewer scopes.\n\n" +
|
|
156
|
+
"Run 'assistant channels get slack' to re-probe the channel and see what it reports.\n" +
|
|
157
|
+
"To reconnect, run the channel's setup skill again.",
|
|
158
|
+
);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test("a rejected managed credential points at connection health", () => {
|
|
162
|
+
expect(composeRequestHint(asPerson({ status: 403, managed: true }))).toBe(
|
|
163
|
+
"Request returned HTTP 403. The OAuth token may be expired or revoked.\n\n" +
|
|
164
|
+
"Run 'assistant oauth status google' to check connection health.\n" +
|
|
165
|
+
"To reconnect, run 'assistant oauth connect --help'.",
|
|
166
|
+
);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test("a rejected your-own credential points at connection status", () => {
|
|
170
|
+
expect(composeRequestHint(asPerson({ status: 401 }))).toBe(
|
|
171
|
+
"Request returned HTTP 401. The OAuth token may be expired or revoked.\n\n" +
|
|
172
|
+
"Run 'assistant oauth status google' to check connection status.\n" +
|
|
173
|
+
"To reconnect, run 'assistant oauth connect --help'.",
|
|
174
|
+
);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
test("an HTML 404 reports the base the path resolved against", () => {
|
|
178
|
+
expect(
|
|
179
|
+
composeRequestHint(asPerson({ status: 404, headers: HTML_HEADERS })),
|
|
180
|
+
).toBe(
|
|
181
|
+
"Request returned HTTP 404 with an HTML body, which usually means " +
|
|
182
|
+
"the path does not exist on the base URL it resolved against.\n\n" +
|
|
183
|
+
'This request used base URL "https://api.google.com" (relative paths are joined onto it). ' +
|
|
184
|
+
"If you meant a different service on this provider, pass an absolute URL " +
|
|
185
|
+
"(e.g. https://host/full/path) so the host and full path are set explicitly.",
|
|
186
|
+
);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
test("an HTML 404 with no base says so", () => {
|
|
190
|
+
expect(
|
|
191
|
+
composeRequestHint(
|
|
192
|
+
asPerson({
|
|
193
|
+
status: 404,
|
|
194
|
+
headers: HTML_HEADERS,
|
|
195
|
+
resolvedBaseUrl: undefined,
|
|
196
|
+
}),
|
|
197
|
+
),
|
|
198
|
+
).toContain('This request used base URL "(none configured)"');
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
test("a JSON 404 and every other status are silent", () => {
|
|
202
|
+
expect(composeRequestHint(asPerson({ status: 404 }))).toBeUndefined();
|
|
203
|
+
expect(composeRequestHint(asPerson({ status: 429 }))).toBeUndefined();
|
|
204
|
+
expect(composeRequestHint(asPerson({ status: 500 }))).toBeUndefined();
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
test("the Content-Type check is case-insensitive on key and value", () => {
|
|
208
|
+
expect(
|
|
209
|
+
composeRequestHint(
|
|
210
|
+
asPerson({ status: 404, headers: { "Content-Type": "TEXT/HTML" } }),
|
|
211
|
+
),
|
|
212
|
+
).toContain("with an HTML body");
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
test("a missing-scope hint stands alone on a successful call", () => {
|
|
216
|
+
expect(
|
|
217
|
+
composeRequestHint(
|
|
218
|
+
asPerson({ provider: "slack", missingScopes: ["files:read"] }),
|
|
219
|
+
),
|
|
220
|
+
).toBe(
|
|
221
|
+
"The slack connection is missing required scopes: files:read. " +
|
|
222
|
+
"It was connected before they were required, so calls that need them fail. " +
|
|
223
|
+
"Reconnect it from Integrations, or run 'assistant oauth connect slack', to grant them.",
|
|
224
|
+
);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
test("a missing-scope hint is prepended to the status hint", () => {
|
|
228
|
+
expect(
|
|
229
|
+
composeRequestHint(
|
|
230
|
+
asPerson({
|
|
231
|
+
provider: "slack",
|
|
232
|
+
status: 401,
|
|
233
|
+
missingScopes: ["files:read", "search:read"],
|
|
234
|
+
}),
|
|
235
|
+
),
|
|
236
|
+
).toBe(
|
|
237
|
+
"The slack connection is missing required scopes: files:read, search:read. " +
|
|
238
|
+
"It was connected before they were required, so calls that need them fail. " +
|
|
239
|
+
"Reconnect it from Integrations, or run 'assistant oauth connect slack', to grant them." +
|
|
240
|
+
"\n\n" +
|
|
241
|
+
"Request returned HTTP 401. The OAuth token may be expired or revoked.\n\n" +
|
|
242
|
+
"Run 'assistant oauth status slack' to check connection status.\n" +
|
|
243
|
+
"To reconnect, run 'assistant oauth connect --help'.",
|
|
244
|
+
);
|
|
245
|
+
});
|
|
246
|
+
});
|