@vellumai/assistant 0.11.2 → 0.11.3-dev.202608080427.92f668a
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +69 -9
- package/docs/flux-turn-detection-spike.md +243 -0
- package/docs/stt-provider-onboarding.md +3 -1
- package/docs/trusted-contact-access.md +9 -5
- package/docs/vellum-doctor.md +195 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +50 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/ces-client/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/src/rpc-client.ts +19 -2
- package/node_modules/@vellumai/environments/package.json +2 -1
- package/node_modules/@vellumai/environments/src/__tests__/cloud-assistant-hub-url.test.ts +38 -0
- package/node_modules/@vellumai/environments/src/__tests__/install-layout.test.ts +98 -0
- package/node_modules/@vellumai/environments/src/__tests__/package-boundary.test.ts +5 -5
- package/node_modules/@vellumai/environments/src/index.ts +17 -6
- package/node_modules/@vellumai/environments/src/install-layout.ts +49 -0
- package/node_modules/@vellumai/environments/src/seeds.ts +29 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +50 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +4 -0
- package/node_modules/@vellumai/gateway-client/src/verification-session-contract.ts +91 -6
- package/node_modules/@vellumai/ipc-server-utils/src/endpoint.test.ts +36 -0
- package/node_modules/@vellumai/ipc-server-utils/src/endpoint.ts +142 -0
- package/node_modules/@vellumai/ipc-server-utils/src/index.ts +2 -0
- package/node_modules/@vellumai/ipc-server-utils/src/listen-options.ts +3 -0
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +15 -1
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +17 -2
- package/node_modules/@vellumai/service-contracts/src/channels.ts +50 -0
- package/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +16 -2
- package/openapi.yaml +619 -47
- package/package.json +1 -1
- package/scripts/voice-ttft-spike.ts +3 -3
- package/src/__tests__/agent-image-optimize.test.ts +4 -4
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +113 -66
- package/src/__tests__/agent-loop-override-profile.test.ts +38 -48
- package/src/__tests__/agent-loop-subagent-billing-headers.test.ts +166 -0
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
- package/src/__tests__/answered-question-persistence.test.ts +240 -0
- package/src/__tests__/anthropic-provider.test.ts +165 -30
- package/src/__tests__/app-control-flow.test.ts +9 -8
- package/src/__tests__/assistant-event-hub.test.ts +48 -0
- package/src/__tests__/attachments-store-heic-normalize.test.ts +16 -12
- package/src/__tests__/attachments-store.test.ts +130 -68
- package/src/__tests__/attachments.test.ts +36 -36
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
- package/src/__tests__/call-controller.test.ts +120 -0
- package/src/__tests__/call-start-guardian-guard.test.ts +18 -4
- package/src/__tests__/canned-reply-release.test.ts +86 -0
- package/src/__tests__/channel-availability-routes.test.ts +14 -1
- package/src/__tests__/channel-guardian.test.ts +59 -29
- package/src/__tests__/channel-readiness-telegram-remote.test.ts +154 -0
- package/src/__tests__/channel-setup-panel-ack.test.ts +6 -5
- package/src/__tests__/client-os-metadata-persistence.test.ts +103 -4
- package/src/__tests__/compactor-image-manifest-trust.test.ts +1 -1
- package/src/__tests__/config-loader-backfill.test.ts +19 -0
- package/src/__tests__/config-schema.test.ts +150 -7
- package/src/__tests__/consult-deadline.test.ts +65 -0
- package/src/__tests__/conversation-agent-loop.test.ts +438 -2
- package/src/__tests__/conversation-disk-view-integration.test.ts +5 -1
- package/src/__tests__/conversation-disk-view.test.ts +4 -4
- package/src/__tests__/conversation-error.test.ts +22 -3
- package/src/__tests__/conversation-fork-crud.test.ts +5 -1
- package/src/__tests__/conversation-fork-referential.test.ts +352 -0
- package/src/__tests__/conversation-fork-retrospective.test.ts +5 -1
- package/src/__tests__/conversation-group-tools.test.ts +32 -2
- package/src/__tests__/conversation-inference-profile-route.test.ts +27 -1
- package/src/__tests__/conversation-initial-prompt.test.ts +51 -22
- package/src/__tests__/conversation-key-store-bootstrap-cleanup.test.ts +119 -0
- package/src/__tests__/conversation-key-store-origin.test.ts +105 -0
- package/src/__tests__/conversation-list-recency-ordering.test.ts +104 -0
- package/src/__tests__/conversation-origin-at-creation.test.ts +153 -0
- package/src/__tests__/conversation-origin-channel-filter.test.ts +95 -0
- package/src/__tests__/conversation-placement-promotion.test.ts +172 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +123 -0
- package/src/__tests__/conversation-queue.test.ts +433 -1
- package/src/__tests__/conversation-retry-route.test.ts +3 -1
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +64 -1
- package/src/__tests__/conversation-store-ephemeral.test.ts +4 -0
- package/src/__tests__/conversation-store.test.ts +26 -10
- package/src/__tests__/conversation-summarize-route.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +15 -6
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -5
- package/src/__tests__/conversation-surfaces-app-control.test.ts +12 -11
- package/src/__tests__/conversation-surfaces-app-open.test.ts +11 -5
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +5 -4
- package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +967 -0
- package/src/__tests__/conversation-surfaces-persisted-info.test.ts +312 -0
- package/src/__tests__/conversation-surfaces-queued-emit.test.ts +6 -5
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -8
- package/src/__tests__/conversation-surfaces-standalone.test.ts +21 -11
- package/src/__tests__/conversation-surfaces-state-update.test.ts +7 -11
- package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -6
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +11 -6
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +9 -6
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +70 -7
- package/src/__tests__/conversation-wait-for-idle.test.ts +6 -11
- package/src/__tests__/credential-prompt-route.test.ts +54 -7
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/cu-unified-flow.test.ts +89 -28
- package/src/__tests__/custom-group-listing-visibility.test.ts +1 -1
- package/src/__tests__/db-schedule-syntax-migration.test.ts +4 -1
- package/src/__tests__/discord-access-request-privacy.test.ts +366 -0
- package/src/__tests__/discord-requester-notice-privacy.test.ts +87 -0
- package/src/__tests__/disk-pressure-guard.test.ts +55 -55
- package/src/__tests__/disk-pressure-routes.test.ts +10 -10
- package/src/__tests__/disk-pressure-tools.test.ts +2 -2
- package/src/__tests__/disk-usage.test.ts +35 -20
- package/src/__tests__/document-sync-tags.test.ts +379 -0
- package/src/__tests__/document-update-default-surface.test.ts +28 -0
- package/src/__tests__/dynamic-skill-background-guard.test.ts +2 -2
- package/src/__tests__/emit-signal-routing-intent.test.ts +3 -4
- package/src/__tests__/ensure-conversation-exists.test.ts +8 -5
- package/src/__tests__/events-dev-bypass-actor.test.ts +294 -1
- package/src/__tests__/evict-conversations-for-reload.test.ts +90 -0
- package/src/__tests__/file-list-tool.test.ts +12 -10
- package/src/__tests__/file-ops-service.test.ts +151 -44
- package/src/__tests__/file-read-container-boundary.test.ts +137 -0
- package/src/__tests__/file-read-tool.test.ts +21 -9
- package/src/__tests__/file-url-path-guard.test.ts +83 -0
- package/src/__tests__/filesystem-tools.test.ts +82 -66
- package/src/__tests__/guardian-outbound-http.test.ts +8 -8
- package/src/__tests__/helpers/gateway-verification-sessions-stub.ts +14 -1
- package/src/__tests__/helpers/hub-clients.ts +42 -0
- package/src/__tests__/helpers/mock-conversation.ts +46 -0
- package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +61 -57
- package/src/__tests__/history-repair.test.ts +112 -12
- package/src/__tests__/host-bash-proxy.test.ts +10 -5
- package/src/__tests__/host-bash-routes.test.ts +67 -0
- package/src/__tests__/host-browser-proxy.test.ts +2 -2
- package/src/__tests__/host-cu-proxy.test.ts +3 -7
- package/src/__tests__/host-file-proxy.test.ts +3 -7
- package/src/__tests__/host-file-read-tool.test.ts +5 -1
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +6 -4
- package/src/__tests__/http-conversation-lineage.test.ts +2 -5
- package/src/__tests__/http-user-message-parity.test.ts +44 -0
- package/src/__tests__/identity-routes.test.ts +13 -13
- package/src/__tests__/image-conversion.test.ts +29 -26
- package/src/__tests__/image-source-path-reinject.test.ts +2 -2
- package/src/__tests__/inference-profile-session-handler.test.ts +95 -0
- package/src/__tests__/inference-profile-session-ipc.test.ts +25 -0
- package/src/__tests__/introduction-card-resolver.test.ts +6 -1
- package/src/__tests__/list-messages-attachments.test.ts +56 -32
- package/src/__tests__/list-messages-background-tool-completion.test.ts +4 -4
- package/src/__tests__/list-messages-client-message-id.test.ts +2 -2
- package/src/__tests__/list-messages-hidden-metadata.test.ts +16 -16
- package/src/__tests__/list-messages-page-latest.test.ts +61 -61
- package/src/__tests__/list-messages-provider-error.test.ts +6 -6
- package/src/__tests__/list-messages-queued.test.ts +49 -6
- package/src/__tests__/list-messages-system-card.test.ts +4 -4
- package/src/__tests__/list-messages-tool-merge.test.ts +9 -9
- package/src/__tests__/llm-resolver-override-or-default.test.ts +141 -0
- package/src/__tests__/llm-usage-store.test.ts +55 -0
- package/src/__tests__/manual-token-reconciliation.test.ts +45 -0
- package/src/__tests__/mcp-list-plugin-servers.test.ts +250 -0
- package/src/__tests__/mcp-tool-annotations-risk.test.ts +133 -0
- package/src/__tests__/media-stream-output.test.ts +175 -0
- package/src/__tests__/media-stream-server-integration.test.ts +36 -0
- package/src/__tests__/media-stream-stt-session.test.ts +67 -0
- package/src/__tests__/migration-export-http.test.ts +1 -1
- package/src/__tests__/migration-import-commit-http.test.ts +1 -1
- package/src/__tests__/migration-import-preflight-http.test.ts +1 -1
- package/src/__tests__/migration-validate-http.test.ts +1 -1
- package/src/__tests__/mtime-cache.test.ts +65 -3
- package/src/__tests__/notification-platform-adapter.test.ts +104 -0
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +1 -1
- package/src/__tests__/oauth-provider-profiles.test.ts +4 -2
- package/src/__tests__/oauth-provider-seed-logos.test.ts +65 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +17 -0
- package/src/__tests__/oauth-providers-routes.test.ts +1 -0
- package/src/__tests__/openai-responses-prompt-cache.test.ts +5 -2
- package/src/__tests__/path-policy.test.ts +164 -1
- package/src/__tests__/persist-media-references.test.ts +2 -2
- package/src/__tests__/persist-unsendable-image-downscale.test.ts +5 -5
- package/src/__tests__/persist-unsendable-image.test.ts +23 -23
- package/src/__tests__/persona-resolver.test.ts +154 -0
- package/src/__tests__/plugin-api-webhook-url.test.ts +170 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +6 -0
- package/src/__tests__/processing-flag-persist-failure.test.ts +15 -10
- package/src/__tests__/profile-availability-incomplete.test.ts +113 -0
- package/src/__tests__/profiler-routes.test.ts +13 -13
- package/src/__tests__/prompt-cache-cross-turn-stability.test.ts +593 -0
- package/src/__tests__/proxy-approval-callback.test.ts +3 -3
- package/src/__tests__/queued-message-cancel-and-steer.test.ts +189 -0
- package/src/__tests__/queued-message-steer-actor-scoping.test.ts +164 -0
- package/src/__tests__/resolve-trust-class.test.ts +20 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +1 -1
- package/src/__tests__/run-due-schedules.test.ts +174 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +15 -7
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +166 -0
- package/src/__tests__/schedule-routes.test.ts +730 -8
- package/src/__tests__/schedule-store.test.ts +540 -0
- package/src/__tests__/schedule-tools.test.ts +103 -0
- package/src/__tests__/scheduler-wake.test.ts +5 -0
- package/src/__tests__/secret-routes-platform-proxy.test.ts +29 -1
- package/src/__tests__/secure-keys.test.ts +91 -0
- package/src/__tests__/server-history-render.test.ts +97 -7
- package/src/__tests__/size-guard.test.ts +8 -8
- package/src/__tests__/skill-docs-sync-guard.test.ts +3 -2
- package/src/__tests__/skill-tool-factory.test.ts +247 -0
- package/src/__tests__/skills-install-staging.test.ts +15 -6
- package/src/__tests__/skills.test.ts +32 -0
- package/src/__tests__/slack-edit-ordering-characterization.test.ts +103 -0
- package/src/__tests__/slack-inbound-verification.test.ts +4 -1
- package/src/__tests__/slack-mention-binding-invariance.test.ts +103 -0
- package/src/__tests__/slack-mention-provider-leak-audit.test.ts +135 -0
- package/src/__tests__/starter-task-flow.test.ts +5 -4
- package/src/__tests__/steer-on-enqueue-question.test.ts +3 -2
- package/src/__tests__/stt-language-catalog-parity.test.ts +38 -0
- package/src/__tests__/subagent-allowlist-validation.test.ts +26 -4
- package/src/__tests__/subagent-cron-run-attribution.test.ts +301 -0
- package/src/__tests__/subagent-disposal.test.ts +10 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +10 -0
- package/src/__tests__/subagent-fork-prompt-role.test.ts +85 -11
- package/src/__tests__/subagent-fork-spawn.test.ts +15 -7
- package/src/__tests__/subagent-manager-notify.test.ts +148 -0
- package/src/__tests__/subagent-notify-parent.test.ts +1 -1
- package/src/__tests__/subagent-persistence.test.ts +141 -0
- package/src/__tests__/subagent-role-registry.test.ts +172 -63
- package/src/__tests__/subagent-role-resolution.test.ts +88 -0
- package/src/__tests__/subagent-spawn-and-await.test.ts +48 -0
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +111 -10
- package/src/__tests__/subagent-terminal-message.test.ts +88 -1
- package/src/__tests__/subagent-tool-gate-mode.test.ts +225 -10
- package/src/__tests__/subagent-tools.test.ts +1901 -108
- package/src/__tests__/surface-completion-compaction-boundary.test.ts +124 -0
- package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +298 -0
- package/src/__tests__/system-prompt.test.ts +82 -7
- package/src/__tests__/tool-grant-request-escalation.test.ts +40 -1
- package/src/__tests__/tool-result-spool.test.ts +74 -18
- package/src/__tests__/tool-side-effects-documents.test.ts +174 -0
- package/src/__tests__/tool-side-effects-hook-failures.test.ts +129 -0
- package/src/__tests__/tools-audio-read.test.ts +10 -10
- package/src/__tests__/tools-get-route.test.ts +85 -12
- package/src/__tests__/tools-list-cli.test.ts +171 -0
- package/src/__tests__/top-level-renderer.test.ts +54 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +68 -1
- package/src/__tests__/trusted-contact-multichannel.test.ts +4 -1
- package/src/__tests__/turn-tail-chain.test.ts +135 -0
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +6 -4
- package/src/__tests__/ui-visual-surface.test.ts +5 -4
- package/src/__tests__/ui-work-result-surface.test.ts +5 -4
- package/src/__tests__/unified-turn-context-visible-app.test.ts +7 -8
- package/src/__tests__/usage-routes.test.ts +62 -0
- package/src/__tests__/verification-outbound-delivery.test.ts +176 -0
- package/src/__tests__/visible-app-context.test.ts +20 -4
- package/src/__tests__/web-search-history.test.ts +96 -0
- package/src/__tests__/workspace-migration-139-clear-renamed-cost-profile-label.test.ts +6 -6
- package/src/__tests__/workspace-migration-140-repair-seed-pinned-memory-v3-live.test.ts +330 -0
- package/src/__tests__/workspace-migration-142-consolidate-voice-front-door.test.ts +150 -0
- package/src/acp/failure-error.ts +3 -5
- package/src/agent/attachments.ts +26 -24
- package/src/agent/history-repair/history-repair.ts +27 -26
- package/src/agent/image-optimize.ts +6 -6
- package/src/agent/loop.ts +40 -22
- package/src/agent/message-types.ts +3 -3
- package/src/api/constants/document-tools.ts +55 -0
- package/src/api/events/question-answered.ts +53 -0
- package/src/api/events/tool-result.ts +7 -0
- package/src/api/index.ts +13 -0
- package/src/api/responses/conversation-message.ts +11 -0
- package/src/api/surfaces-oauth-connect.test.ts +96 -0
- package/src/api/surfaces.ts +36 -8
- package/src/approvals/guardian-channel-delivery.ts +83 -0
- package/src/approvals/guardian-expiry-notifier.ts +13 -11
- package/src/approvals/guardian-request-resolvers.ts +222 -135
- package/src/calls/__tests__/tts-text-sanitizer.test.ts +13 -0
- package/src/calls/__tests__/voice-session-bridge.test.ts +131 -12
- package/src/calls/__tests__/voice-triage-escalate.test.ts +106 -0
- package/src/calls/call-controller.ts +30 -2
- package/src/calls/call-speech-output.ts +12 -4
- package/src/calls/call-transport.ts +18 -1
- package/src/calls/media-stream-output.ts +53 -5
- package/src/calls/media-stream-server.ts +21 -1
- package/src/calls/media-stream-stt-session.ts +49 -0
- package/src/calls/telephony-synthesis-language.ts +84 -0
- package/src/calls/tts-text-sanitizer.ts +12 -5
- package/src/calls/voice-session-bridge.ts +86 -17
- package/src/calls/voice-triage-escalate.ts +54 -7
- package/src/channels/__tests__/gateway-verification-sessions.test.ts +3 -3
- package/src/channels/__tests__/plugin-channel-declarations.test.ts +161 -0
- package/src/channels/config.ts +20 -2
- package/src/channels/gateway-verification-sessions.ts +7 -2
- package/src/channels/plugin-channel-declarations.ts +108 -0
- package/src/channels/types.ts +37 -1
- package/src/cli/AGENTS.md +5 -2
- package/src/cli/commands/__tests__/cache.test.ts +7 -4
- package/src/cli/commands/__tests__/cli-test-harness.ts +82 -0
- package/src/cli/commands/__tests__/conversations-wake.test.ts +51 -6
- package/src/cli/commands/__tests__/inference-models.test.ts +14 -0
- package/src/cli/commands/__tests__/inference-profiles.test.ts +44 -1
- package/src/cli/commands/__tests__/inference-providers.test.ts +7 -0
- package/src/cli/commands/__tests__/plugins.test.ts +692 -0
- package/src/cli/commands/__tests__/schedules.test.ts +136 -37
- package/src/cli/commands/conversations.ts +7 -3
- package/src/cli/commands/credentials.help.ts +7 -0
- package/src/cli/commands/inference-profiles.ts +9 -3
- package/src/cli/commands/inference.help.ts +16 -2
- package/src/cli/commands/mcp.help.ts +17 -6
- package/src/cli/commands/mcp.ts +9 -0
- package/src/cli/commands/memory/memory-retrospective.ts +18 -0
- package/src/cli/commands/notifications.ts +3 -6
- package/src/cli/commands/oauth/connect-surface-guidance.test.ts +16 -0
- package/src/cli/commands/oauth/connect-surface-guidance.ts +25 -7
- package/src/cli/commands/oauth/connect.test.ts +26 -1
- package/src/cli/commands/oauth/connect.ts +4 -1
- package/src/cli/commands/oauth/index.help.ts +3 -1
- package/src/cli/commands/oauth/providers.ts +3 -0
- package/src/cli/commands/plugins.help.ts +25 -2
- package/src/cli/commands/plugins.ts +289 -10
- package/src/cli/commands/schedules.help.ts +14 -12
- package/src/cli/commands/schedules.ts +19 -5
- package/src/cli/commands/stt.help.ts +27 -2
- package/src/cli/commands/tools.help.ts +4 -2
- package/src/cli/commands/tools.ts +38 -0
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +1 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +79 -0
- package/src/cli/lib/__tests__/install-from-platform.test.ts +47 -1
- package/src/cli/lib/__tests__/plugin-surfaces.test.ts +86 -7
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +161 -0
- package/src/cli/lib/install-from-github.ts +61 -0
- package/src/cli/lib/install-from-platform.ts +13 -2
- package/src/cli/lib/plugin-surfaces.ts +124 -4
- package/src/cli/lib/upgrade-plugin.ts +60 -0
- package/src/cli.ts +1 -1
- package/src/config/__tests__/default-profile-catalog.test.ts +11 -1
- package/src/config/__tests__/deployment-context-defaults.test.ts +73 -0
- package/src/config/__tests__/memory-retrospective-schema.test.ts +40 -0
- package/src/config/__tests__/plugin-updates-schema.test.ts +43 -0
- package/src/config/__tests__/profile-tool-support.test.ts +131 -0
- package/src/config/bundled-skills/AGENTS.md +1 -1
- package/src/config/bundled-skills/acp/SKILL.md +6 -7
- package/src/config/bundled-skills/app-builder/SKILL.md +1 -1
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +3 -3
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +14 -4
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +15 -15
- package/src/config/bundled-skills/schedule/SKILL.md +5 -1
- package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +1 -0
- package/src/config/bundled-skills/subagent/SKILL.md +53 -22
- package/src/config/bundled-skills/subagent/TOOLS.json +14 -13
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +22 -1
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +9 -2
- package/src/config/bundled-skills/visualize/SKILL.md +1 -1
- package/src/config/call-site-defaults.ts +4 -5
- package/src/config/default-profile-catalog.ts +9 -5
- package/src/config/feature-flag-registry.json +25 -17
- package/src/config/llm-resolver.ts +45 -15
- package/src/config/loader.ts +75 -1
- package/src/config/profile-tool-support.ts +110 -0
- package/src/config/sanitize-for-transfer.ts +11 -0
- package/src/config/schema.ts +4 -0
- package/src/config/schemas/__tests__/live-voice.test.ts +142 -4
- package/src/config/schemas/__tests__/stt.test.ts +20 -5
- package/src/config/schemas/call-site-catalog.ts +4 -4
- package/src/config/schemas/calls.ts +0 -4
- package/src/config/schemas/channels.ts +13 -0
- package/src/config/schemas/live-voice.ts +82 -23
- package/src/config/schemas/llm.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +25 -0
- package/src/config/schemas/plugin-updates.ts +59 -0
- package/src/config/schemas/services.ts +8 -4
- package/src/config/schemas/stt.ts +18 -5
- package/src/config/schemas/timeouts.ts +1 -1
- package/src/config/schemas/tts.ts +63 -0
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +16 -0
- package/src/contacts/guardian-delivery-reader.ts +29 -2
- package/src/context/compactor.ts +4 -4
- package/src/context/post-turn-tool-result-truncation.ts +32 -16
- package/src/context/strip-injections.ts +42 -0
- package/src/context/tool-result-spool.ts +32 -18
- package/src/credential-execution/ces-runtime.ts +3 -0
- package/src/credential-execution/client.ts +22 -1
- package/src/credential-execution/process-manager.test.ts +99 -0
- package/src/credential-execution/process-manager.ts +62 -16
- package/src/daemon/__tests__/abort-null-controller.test.ts +141 -5
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +8 -12
- package/src/daemon/__tests__/install-assistant-command.test.ts +234 -0
- package/src/daemon/__tests__/turn-tail-assistant-reply-notify.test.ts +2 -4
- package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +20 -29
- package/src/daemon/channel-ui-capability.ts +4 -4
- package/src/daemon/conversation-agent-loop-handlers.ts +117 -61
- package/src/daemon/conversation-agent-loop.ts +318 -148
- package/src/daemon/conversation-attachments.ts +1 -1
- package/src/daemon/conversation-error.ts +8 -1
- package/src/daemon/conversation-initial-prompt.ts +16 -38
- package/src/daemon/conversation-lifecycle.ts +154 -32
- package/src/daemon/conversation-messaging.ts +106 -43
- package/src/daemon/conversation-process.ts +131 -33
- package/src/daemon/conversation-queue-manager.ts +10 -0
- package/src/daemon/conversation-runtime-assembly.ts +9 -4
- package/src/daemon/conversation-store.ts +52 -3
- package/src/daemon/conversation-surface-state.ts +9 -0
- package/src/daemon/conversation-surfaces.ts +403 -210
- package/src/daemon/conversation-tool-setup.ts +56 -7
- package/src/daemon/conversation-turn-finalize.ts +134 -89
- package/src/daemon/conversation.ts +111 -27
- package/src/daemon/disk-pressure-guard-lifecycle.ts +2 -2
- package/src/daemon/disk-pressure-guard.ts +3 -3
- package/src/daemon/doordash-steps.ts +5 -5
- package/src/daemon/external-plugins-bootstrap.ts +7 -1
- package/src/daemon/handlers/config-channels.ts +48 -5
- package/src/daemon/handlers/conversation-history.ts +1 -1
- package/src/daemon/handlers/conversations.ts +62 -17
- package/src/daemon/handlers/shared.ts +12 -0
- package/src/daemon/handlers/skills.ts +11 -1
- package/src/daemon/identity-helpers.ts +38 -10
- package/src/daemon/install-assistant-command.ts +322 -0
- package/src/daemon/lifecycle.ts +14 -3
- package/src/daemon/message-types/conversations.ts +6 -7
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/persist-media-references.ts +23 -14
- package/src/daemon/process-message.ts +6 -6
- package/src/daemon/tool-setup-types.ts +19 -122
- package/src/daemon/tool-side-effects.ts +17 -94
- package/src/daemon/trust-context-types.ts +39 -0
- package/src/daemon/trust-context.ts +14 -6
- package/src/daemon/turn-tail-chain.ts +73 -0
- package/src/daemon/web-search-history.ts +47 -33
- package/src/heartbeat/heartbeat-service.ts +6 -6
- package/src/inbound/__tests__/oauth-callback-url.test.ts +83 -0
- package/src/inbound/oauth-callback-url.ts +61 -0
- package/src/ipc/__tests__/socket-path.test.ts +21 -0
- package/src/ipc/assistant-server.ts +17 -10
- package/src/ipc/cli-client.ts +10 -1
- package/src/ipc/routes/__tests__/documents-sync-ipc-routes.test.ts +56 -0
- package/src/ipc/routes/documents-sync-ipc-routes.ts +42 -0
- package/src/ipc/socket-cleanup.ts +9 -7
- package/src/ipc/socket-path.ts +4 -96
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +1 -104
- package/src/live-voice/__tests__/live-voice-archive.test.ts +16 -16
- package/src/live-voice/__tests__/live-voice-attach-image.test.ts +209 -0
- package/src/live-voice/__tests__/live-voice-connection.test.ts +20 -0
- package/src/live-voice/__tests__/live-voice-events.test.ts +7 -8
- package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +932 -0
- package/src/live-voice/__tests__/live-voice-integration.test.ts +12 -5
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +115 -8
- package/src/live-voice/__tests__/live-voice-photo.test.ts +100 -0
- package/src/live-voice/__tests__/live-voice-progress.test.ts +179 -146
- package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +265 -0
- package/src/live-voice/__tests__/live-voice-stt.test.ts +324 -2
- package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +131 -2
- package/src/live-voice/__tests__/live-voice-tts-session.test.ts +0 -483
- package/src/live-voice/__tests__/live-voice-tts.test.ts +148 -2
- package/src/live-voice/__tests__/live-voice-vad.test.ts +313 -32
- package/src/live-voice/__tests__/progress-narration.test.ts +214 -0
- package/src/live-voice/__tests__/progress-phrases.test.ts +167 -0
- package/src/live-voice/__tests__/protocol.test.ts +52 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +3 -0
- package/src/live-voice/live-voice-archive.ts +13 -13
- package/src/live-voice/live-voice-connection.ts +7 -1
- package/src/live-voice/live-voice-metrics.ts +57 -32
- package/src/live-voice/live-voice-photo.ts +168 -0
- package/src/live-voice/live-voice-session.ts +1137 -351
- package/src/live-voice/live-voice-tts.ts +18 -2
- package/src/live-voice/progress-narration.ts +277 -0
- package/src/live-voice/progress-phrases.ts +105 -2
- package/src/live-voice/protocol.ts +110 -2
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
- package/src/mcp/__tests__/mcp-oauth-client-registration.test.ts +196 -0
- package/src/mcp/__tests__/mcp-oauth-provider.test.ts +9 -9
- package/src/mcp/client.ts +14 -7
- package/src/mcp/mcp-auth-orchestrator.ts +13 -22
- package/src/mcp/mcp-oauth-provider.ts +195 -240
- package/src/messaging/providers/__tests__/callback-routing.test.ts +5 -1
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +66 -4
- package/src/messaging/providers/callback-routing.ts +1 -0
- package/src/messaging/providers/discord/api.ts +312 -0
- package/src/messaging/providers/discord/dm-delivery.test.ts +204 -0
- package/src/messaging/providers/discord/render.test.ts +204 -0
- package/src/messaging/providers/discord/render.ts +195 -0
- package/src/messaging/providers/discord/send.test.ts +179 -0
- package/src/messaging/providers/discord/send.ts +212 -0
- package/src/messaging/providers/discord/transport.ts +81 -0
- package/src/messaging/providers/index.ts +3 -1
- package/src/messaging/providers/retry-policy.test.ts +247 -0
- package/src/messaging/providers/retry-policy.ts +206 -0
- package/src/messaging/providers/slack/mention-source.test.ts +285 -0
- package/src/messaging/providers/slack/mention-source.ts +287 -0
- package/src/messaging/providers/telegram-bot/api.ts +47 -130
- package/src/messaging/providers/whatsapp/api.ts +47 -136
- package/src/monitoring/__tests__/db-integrity-sample.test.ts +4 -1
- package/src/monitoring/__tests__/plugin-auto-update.test.ts +495 -0
- package/src/monitoring/db-integrity-sample.ts +6 -1
- package/src/monitoring/plugin-auto-update.ts +463 -0
- package/src/monitoring/resource-sampler.ts +21 -5
- package/src/monitoring/worker.ts +13 -0
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +375 -2
- package/src/notifications/__tests__/broadcaster.test.ts +37 -1
- package/src/notifications/__tests__/copy-composer.test.ts +165 -0
- package/src/notifications/__tests__/emit-signal-pipeline-failure.test.ts +205 -0
- package/src/notifications/__tests__/notification-utils.test.ts +249 -0
- package/src/notifications/adapters/platform.ts +31 -2
- package/src/notifications/assistant-reply-producer.ts +79 -32
- package/src/notifications/broadcaster.ts +30 -10
- package/src/notifications/copy-composer.ts +69 -0
- package/src/notifications/emit-signal.ts +82 -15
- package/src/notifications/events-store.ts +10 -2
- package/src/notifications/home-feed-side-effect.ts +6 -3
- package/src/notifications/notification-utils.ts +173 -5
- package/src/notifications/signal.ts +13 -0
- package/src/oauth/AGENTS.md +4 -2
- package/src/oauth/byo-connection.ts +6 -1
- package/src/oauth/credential-token-resolver.ts +3 -10
- package/src/oauth/manual-token-connection.ts +29 -64
- package/src/oauth/manual-token-providers.ts +62 -0
- package/src/oauth/provider-serializer.ts +13 -0
- package/src/oauth/seed-providers.ts +62 -11
- package/src/onboarding/onboarding-events-store.ts +91 -1
- package/src/permissions/question-prompter.test.ts +4 -0
- package/src/permissions/question-prompter.ts +21 -4
- package/src/persistence/__tests__/conversation-lineage.test.ts +248 -0
- package/src/persistence/attachments-store.ts +15 -15
- package/src/persistence/conversation-attention-store.ts +30 -10
- package/src/persistence/conversation-bootstrap.ts +17 -0
- package/src/persistence/conversation-crud.ts +363 -97
- package/src/persistence/conversation-group-migration.ts +1 -1
- package/src/persistence/conversation-key-store.ts +38 -10
- package/src/persistence/conversation-lineage.ts +226 -0
- package/src/persistence/conversation-plugin-facade.ts +28 -3
- package/src/persistence/conversation-queries.ts +207 -33
- package/src/persistence/conversation-types.ts +107 -1
- package/src/persistence/jobs-store.ts +32 -8
- package/src/persistence/llm-usage-store.ts +22 -0
- package/src/persistence/migrations/361-normalize-managed-connection-rows.test.ts +168 -0
- package/src/persistence/migrations/361-normalize-managed-connection-rows.ts +76 -0
- package/src/persistence/migrations/362-add-conversation-subagent-kind.test.ts +187 -0
- package/src/persistence/migrations/362-add-conversation-subagent-kind.ts +93 -0
- package/src/persistence/migrations/363-backfill-schedule-inference-profile.test.ts +229 -0
- package/src/persistence/migrations/363-backfill-schedule-inference-profile.ts +127 -0
- package/src/persistence/migrations/364-add-schedule-source-key.test.ts +120 -0
- package/src/persistence/migrations/364-add-schedule-source-key.ts +43 -0
- package/src/persistence/migrations/365-add-conversation-fork-strategy.ts +27 -0
- package/src/persistence/schema/conversations.ts +32 -0
- package/src/persistence/schema/infrastructure.ts +3 -0
- package/src/persistence/steps.ts +30 -0
- package/src/persistence/subagent-store.ts +148 -6
- package/src/platform/managed-speech.test.ts +20 -0
- package/src/platform/managed-speech.ts +9 -0
- package/src/plugin-api/__tests__/oauth-callback-url-export.test.ts +29 -0
- package/src/plugin-api/index.ts +28 -5
- package/src/plugin-api/webhook-url.ts +151 -0
- package/src/plugins/__tests__/installed-plugin-dirs.test.ts +82 -0
- package/src/plugins/__tests__/mcp-servers.test.ts +370 -0
- package/src/plugins/__tests__/source-fingerprint.test.ts +5 -1
- package/src/plugins/collect-source-versions.ts +4 -27
- package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +5 -5
- package/src/plugins/defaults/exploration-drift/package.json +1 -1
- package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +4 -2
- package/src/plugins/defaults/image-recovery/recover.ts +67 -57
- package/src/plugins/defaults/index.ts +1 -1
- package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +64 -18
- package/src/plugins/defaults/memory/__tests__/jobs-worker-outcome-contract.test.ts +242 -0
- package/src/plugins/defaults/memory/__tests__/jobs-worker-retrospective-sweep.test.ts +24 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +48 -3
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +511 -19
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +39 -3
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +493 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +5 -4
- package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +5 -1
- package/src/plugins/defaults/memory/job-handlers.ts +87 -5
- package/src/plugins/defaults/memory/jobs-worker.ts +60 -6
- package/src/plugins/defaults/memory/memory-retrospective-constants.ts +11 -0
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +29 -0
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +342 -60
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +23 -3
- package/src/plugins/defaults/memory/substrate/consolidation-lock.ts +9 -4
- package/src/plugins/defaults/memory/substrate/skill-content.ts +8 -1
- package/src/plugins/defaults/memory/substrate/sweep-job.ts +7 -0
- package/src/plugins/defaults/memory/v1/graph/injection.ts +1 -1
- package/src/plugins/defaults/memory/v2/router.ts +8 -0
- package/src/plugins/defaults/turn-context/unified-turn-context.ts +1 -2
- package/src/plugins/external-plugin-loader.ts +64 -8
- package/src/plugins/installed-plugin-dirs.ts +101 -0
- package/src/plugins/mcp-servers.ts +343 -0
- package/src/plugins/mtime-cache.ts +34 -22
- package/src/plugins/types.ts +69 -8
- package/src/prompts/persona-resolver.ts +6 -2
- package/src/prompts/system-prompt.ts +72 -17
- package/src/providers/__tests__/inference.test.ts +40 -0
- package/src/providers/__tests__/preflight-resolved-config.test.ts +58 -1
- package/src/providers/__tests__/retry-callsite.test.ts +72 -2
- package/src/providers/__tests__/vellum-connection-routing.test.ts +42 -11
- package/src/providers/anthropic/client.ts +112 -95
- package/src/providers/connection-resolution.ts +35 -1
- package/src/providers/gemini/client.ts +5 -5
- package/src/providers/inference/adapter-factory.ts +16 -10
- package/src/providers/inference/auth.ts +16 -0
- package/src/providers/inference/connection-availability.ts +164 -12
- package/src/providers/inference/connections.ts +25 -1
- package/src/providers/media-resolve.ts +21 -11
- package/src/providers/model-catalog.ts +15 -0
- package/src/providers/openai/chat-completions-provider.ts +4 -4
- package/src/providers/openai/responses-provider.ts +12 -25
- package/src/providers/registry.ts +9 -4
- package/src/providers/retry.ts +25 -0
- package/src/providers/server-tool-pairing.ts +134 -0
- package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +433 -0
- package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +620 -0
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +34 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +472 -12
- package/src/providers/speech-to-text/deepgram-flux-frames.ts +395 -0
- package/src/providers/speech-to-text/deepgram-flux-realtime.ts +719 -0
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +283 -1
- package/src/providers/speech-to-text/deepgram-realtime.ts +117 -3
- package/src/providers/speech-to-text/deepgram.ts +1 -0
- package/src/providers/speech-to-text/provider-catalog.ts +137 -8
- package/src/providers/speech-to-text/resolve.ts +105 -12
- package/src/providers/speech-to-text/vellum-managed.ts +7 -1
- package/src/providers/speech-to-text/vellum-speech-relay-connection.ts +3 -1
- package/src/providers/types.ts +26 -6
- package/src/providers/vellum-model-routing.ts +6 -7
- package/src/runtime/AGENTS.md +2 -0
- package/src/runtime/__tests__/agent-wake.test.ts +16 -16
- package/src/runtime/__tests__/background-job-runner.test.ts +0 -144
- package/src/runtime/__tests__/desktop-presence.test.ts +162 -0
- package/src/runtime/__tests__/local-actor-identity-force-refresh.test.ts +104 -0
- package/src/runtime/agent-wake.ts +63 -24
- package/src/runtime/assistant-event-hub.ts +110 -12
- package/src/runtime/auth/__tests__/guard-tests.test.ts +2 -0
- package/src/runtime/auth/__tests__/scopes.test.ts +20 -0
- package/src/runtime/auth/same-actor.ts +56 -8
- package/src/runtime/auth/scopes.ts +12 -0
- package/src/runtime/auth/types.ts +2 -0
- package/src/runtime/background-job-runner.ts +5 -27
- package/src/runtime/channel-readiness-service.ts +59 -3
- package/src/runtime/channel-readiness-types.ts +18 -0
- package/src/runtime/desktop-presence.ts +69 -0
- package/src/runtime/http-server.ts +12 -0
- package/src/runtime/local-actor-identity.ts +29 -14
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
- package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/client-routes.test.ts +186 -14
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +547 -1
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +162 -7
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +14 -10
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +340 -3
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +28 -1
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +217 -1
- package/src/runtime/routes/__tests__/question-routes.test.ts +64 -0
- package/src/runtime/routes/__tests__/retrospective-routes.test.ts +20 -0
- package/src/runtime/routes/__tests__/skill-history-route.test.ts +116 -0
- package/src/runtime/routes/__tests__/sse-actor-principal-heal.test.ts +165 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +25 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +2 -0
- package/src/runtime/routes/__tests__/wake-conversation-routes.test.ts +60 -2
- package/src/runtime/routes/archive-utils.ts +16 -12
- package/src/runtime/routes/attachment-routes.ts +13 -6
- package/src/runtime/routes/canned-reply-release.ts +54 -0
- package/src/runtime/routes/channel-availability-routes.ts +32 -14
- package/src/runtime/routes/channel-verification-routes.ts +2 -27
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +5 -0
- package/src/runtime/routes/client-routes.ts +114 -2
- package/src/runtime/routes/conversation-cli-routes.ts +10 -12
- package/src/runtime/routes/conversation-list-routes.ts +59 -10
- package/src/runtime/routes/conversation-management-routes.ts +47 -18
- package/src/runtime/routes/conversation-query-routes.ts +32 -53
- package/src/runtime/routes/conversation-routes.ts +360 -293
- package/src/runtime/routes/credential-prompt-routes.ts +20 -2
- package/src/runtime/routes/debug-routes.ts +4 -1
- package/src/runtime/routes/default-provider-routes.ts +7 -11
- package/src/runtime/routes/documents-routes.ts +44 -1
- package/src/runtime/routes/events-routes.ts +29 -1
- package/src/runtime/routes/host-app-control-routes.ts +2 -0
- package/src/runtime/routes/host-bash-routes.ts +2 -0
- package/src/runtime/routes/host-browser-routes.ts +2 -0
- package/src/runtime/routes/host-cu-routes.ts +2 -0
- package/src/runtime/routes/host-file-routes.ts +2 -0
- package/src/runtime/routes/host-transfer-routes.ts +4 -0
- package/src/runtime/routes/identity-routes.ts +6 -6
- package/src/runtime/routes/inbound-message-handler.ts +5 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +7 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +14 -0
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -2
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +14 -11
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -17
- package/src/runtime/routes/inference-profile-availability-guard.ts +171 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +26 -2
- package/src/runtime/routes/inference-profile-session-routes.ts +2 -1
- package/src/runtime/routes/inference-profiles-routes.ts +152 -73
- package/src/runtime/routes/inference-provider-connection-routes.ts +0 -16
- package/src/runtime/routes/llm-call-sites-routes.ts +13 -0
- package/src/runtime/routes/log-export-routes.ts +1 -1
- package/src/runtime/routes/mcp-auth-routes.ts +141 -57
- package/src/runtime/routes/notification-routes.ts +0 -14
- package/src/runtime/routes/oauth-providers.ts +1 -0
- package/src/runtime/routes/plugins-routes.ts +127 -4
- package/src/runtime/routes/profiler-routes.ts +4 -2
- package/src/runtime/routes/question-routes.ts +28 -10
- package/src/runtime/routes/retrospective-routes.ts +9 -3
- package/src/runtime/routes/schedule-routes.ts +210 -12
- package/src/runtime/routes/secret-routes.ts +40 -23
- package/src/runtime/routes/settings-routes.ts +41 -13
- package/src/runtime/routes/skills-routes.ts +79 -0
- package/src/runtime/routes/sse-actor-principal-heal.ts +113 -0
- package/src/runtime/routes/stt-routes.ts +31 -25
- package/src/runtime/routes/ui-snapshot-routes.ts +1 -0
- package/src/runtime/routes/wake-conversation-routes.ts +23 -0
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
- package/src/runtime/services/conversation-serializer.ts +24 -9
- package/src/runtime/sync/documents-sidecar-publish.test.ts +101 -0
- package/src/runtime/sync/resource-sync-events.ts +79 -1
- package/src/runtime/sync/worker-daemon-notify.test.ts +34 -0
- package/src/runtime/sync/worker-daemon-notify.ts +44 -6
- package/src/runtime/verification-outbound-actions.ts +250 -222
- package/src/runtime/verification-templates.ts +41 -30
- package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +614 -0
- package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +1066 -0
- package/src/schedule/inference-profile.ts +64 -3
- package/src/schedule/plugin-schedule-declarations.ts +518 -0
- package/src/schedule/plugin-schedule-reconciler.ts +605 -0
- package/src/schedule/plugin-schedules-gate.ts +23 -0
- package/src/schedule/schedule-store.ts +520 -26
- package/src/schedule/scheduler.ts +38 -0
- package/src/security/credential-backend.ts +51 -4
- package/src/security/encrypted-store.ts +64 -42
- package/src/security/oauth2.ts +6 -22
- package/src/security/secure-keys.ts +55 -7
- package/src/skills/catalog-install.ts +20 -7
- package/src/skills/inline-command-runner.ts +2 -7
- package/src/skills/skill-history.test.ts +269 -0
- package/src/skills/skill-history.ts +250 -0
- package/src/skills/skillssh-registry.ts +1 -1
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +22 -0
- package/src/stt/__tests__/language-metadata.test.ts +85 -0
- package/src/stt/__tests__/speech-energy.test.ts +79 -0
- package/src/stt/__tests__/types.test.ts +94 -0
- package/src/stt/daemon-batch-transcriber.ts +18 -6
- package/src/stt/language-metadata.ts +65 -0
- package/src/stt/speech-energy.ts +115 -12
- package/src/stt/stt-stream-session.ts +8 -4
- package/src/stt/types.ts +119 -0
- package/src/subagent/__tests__/consult-prompt.test.ts +25 -0
- package/src/subagent/consult-prompt.ts +3 -1
- package/src/subagent/consult-transcript.ts +1 -1
- package/src/subagent/manager.ts +304 -44
- package/src/subagent/progress-events.ts +35 -0
- package/src/subagent/role-resolution.ts +88 -0
- package/src/subagent/types.ts +303 -67
- package/src/subagent/validate-allowlists.ts +3 -4
- package/src/telegram/__tests__/webhook-health.test.ts +73 -1
- package/src/telegram/webhook-health.ts +101 -3
- package/src/telemetry/__tests__/telemetry-event-fixtures.ts +2 -0
- package/src/telemetry/activation-funnel.ts +6 -1
- package/src/telemetry/live-voice-funnel.ts +75 -0
- package/src/telemetry/telemetry-event-sources.ts +6 -0
- package/src/telemetry/telemetry-wire-source.json +1 -1
- package/src/telemetry/telemetry-wire.generated.ts +2 -0
- package/src/telemetry/types.ts +23 -4
- package/src/telemetry/usage-telemetry-reporter.test.ts +4 -0
- package/src/tools/__tests__/subagent-workflow-tool-input-schemas.test.ts +1 -1
- package/src/tools/ask-question/ask-question-tool.test.ts +118 -3
- package/src/tools/ask-question/ask-question-tool.ts +56 -2
- package/src/tools/browser/browser-execution.ts +1 -1
- package/src/tools/calls/call-start.ts +8 -5
- package/src/tools/conversation-groups/move_to_group.ts +10 -12
- package/src/tools/document/document-tool.ts +11 -4
- package/src/tools/execution-timeout.ts +9 -2
- package/src/tools/executor.ts +7 -6
- package/src/tools/filesystem/edit.ts +1 -1
- package/src/tools/filesystem/list.ts +1 -1
- package/src/tools/filesystem/read.ts +7 -13
- package/src/tools/filesystem/search.ts +23 -21
- package/src/tools/filesystem/write.ts +4 -1
- package/src/tools/host-filesystem/edit.ts +7 -2
- package/src/tools/host-filesystem/read.ts +21 -8
- package/src/tools/host-filesystem/write.ts +10 -2
- package/src/tools/host-terminal/host-shell.ts +2 -2
- package/src/tools/mcp/mcp-tool-factory.ts +25 -1
- package/src/tools/permission-checker.ts +8 -3
- package/src/tools/schedule/delete.ts +13 -1
- package/src/tools/schedule/list.ts +14 -3
- package/src/tools/schedule/update.ts +56 -33
- package/src/tools/shared/filesystem/audio-read.ts +6 -4
- package/src/tools/shared/filesystem/file-ops-service.ts +176 -116
- package/src/tools/shared/filesystem/image-read.ts +12 -12
- package/src/tools/shared/filesystem/path-policy.ts +70 -5
- package/src/tools/shared/filesystem/size-guard.ts +6 -6
- package/src/tools/shared/input-misuse.ts +72 -0
- package/src/tools/skills/scaffold-managed.ts +82 -0
- package/src/tools/skills/skill-tool-factory.ts +14 -1
- package/src/tools/subagent/consult-deadline.ts +12 -7
- package/src/tools/subagent/message.ts +3 -1
- package/src/tools/subagent/read.ts +66 -4
- package/src/tools/subagent/spawn.ts +500 -78
- package/src/tools/tool-approval-handler.ts +45 -4
- package/src/tools/types.ts +22 -3
- package/src/tools/ui-surface/surface-shape-docs.ts +1 -1
- package/src/tools/ui-surface/visual-validation.ts +2 -0
- package/src/tts/__tests__/provider-adapters.test.ts +147 -0
- package/src/tts/__tests__/speakable-segments.test.ts +470 -0
- package/src/tts/language-voices.ts +23 -0
- package/src/tts/providers/deepgram-provider.ts +3 -1
- package/src/tts/providers/elevenlabs-provider.ts +73 -1
- package/src/tts/providers/xai-provider.ts +28 -2
- package/src/tts/speakable-segments.ts +293 -23
- package/src/tts/synthesis-stream.ts +7 -0
- package/src/tts/types.ts +7 -0
- package/src/usage/__tests__/subagent-attribution.test.ts +109 -0
- package/src/usage/subagent-attribution.ts +108 -0
- package/src/util/__tests__/language-subtag.test.ts +54 -0
- package/src/util/__tests__/sqlite-retry.test.ts +112 -0
- package/src/util/abort-reasons.ts +16 -0
- package/src/util/ansi.ts +44 -0
- package/src/util/disk-usage.ts +17 -13
- package/src/util/image-conversion.ts +20 -13
- package/src/util/language-subtag.ts +43 -0
- package/src/util/schedule-source-key.ts +23 -0
- package/src/util/unicode.ts +1 -1
- package/src/util/worker-process.ts +7 -1
- package/src/workspace/git-service.ts +33 -9
- package/src/workspace/migrations/140-repair-seed-pinned-memory-v3-live.ts +260 -0
- package/src/workspace/migrations/141-stt-english-default-to-multilingual.ts +111 -0
- package/src/workspace/migrations/142-consolidate-voice-front-door.ts +70 -0
- package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +116 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/workspace/top-level-renderer.ts +15 -2
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +0 -357
- package/src/daemon/install-symlink.ts +0 -207
- package/src/live-voice/__tests__/front-decision.test.ts +0 -525
- package/src/live-voice/front-decision.ts +0 -429
- package/src/notifications/deferred-emit.ts +0 -147
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* OAuthClientProvider implementation for MCP servers.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Credentials persist through secure-keys (the credential store). The
|
|
5
|
+
* browser callback arrives on the assistant's shared OAuth callback route,
|
|
6
|
+
* which the gateway already serves and forwards to
|
|
7
|
+
* `POST /v1/internal/oauth/callback`; the runtime matches the arriving
|
|
8
|
+
* OAuth `state` against `security/oauth-callback-registry.ts` and resolves
|
|
9
|
+
* the waiting flow.
|
|
7
10
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* URL and the in-memory oauth-callback-registry. Used when the daemon
|
|
15
|
-
* runs inside Docker/platform where localhost is unreachable from the
|
|
16
|
-
* user's browser.
|
|
11
|
+
* The redirect URI comes from `resolveOauthCallbackUrl`, so it is the same
|
|
12
|
+
* stable URL for every server and every attempt. That stability is what
|
|
13
|
+
* makes dynamic client registration and Client ID Metadata Documents
|
|
14
|
+
* usable: both pin `redirect_uris` at registration time, and the
|
|
15
|
+
* authorization server matches the value exactly on each authorization
|
|
16
|
+
* request.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import { randomBytes } from "node:crypto";
|
|
20
|
-
import { createServer, type Server } from "node:http";
|
|
21
20
|
|
|
22
21
|
import type {
|
|
23
22
|
OAuthClientProvider,
|
|
@@ -29,6 +28,8 @@ import type {
|
|
|
29
28
|
OAuthTokens,
|
|
30
29
|
} from "@modelcontextprotocol/sdk/shared/auth.js";
|
|
31
30
|
|
|
31
|
+
import { getPlatformAssistantId } from "../config/env.js";
|
|
32
|
+
import { getAssistantName } from "../daemon/identity-helpers.js";
|
|
32
33
|
import {
|
|
33
34
|
deleteSecureKeyAsync,
|
|
34
35
|
getSecureKeyAsync,
|
|
@@ -36,12 +37,10 @@ import {
|
|
|
36
37
|
} from "../security/secure-keys.js";
|
|
37
38
|
import { openInHostBrowser } from "../util/browser.js";
|
|
38
39
|
import { getLogger } from "../util/logger.js";
|
|
40
|
+
import { APP_VERSION } from "../version.js";
|
|
39
41
|
|
|
40
42
|
const log = getLogger("mcp-oauth");
|
|
41
43
|
|
|
42
|
-
const CALLBACK_PATH = "/oauth/callback";
|
|
43
|
-
const CALLBACK_TIMEOUT_MS = 2 * 60 * 1000; // 2 minutes
|
|
44
|
-
|
|
45
44
|
// Credential store key helpers
|
|
46
45
|
function tokensKey(serverId: string): string {
|
|
47
46
|
return `mcp:${serverId}:tokens`;
|
|
@@ -52,15 +51,29 @@ function clientInfoKey(serverId: string): string {
|
|
|
52
51
|
function discoveryKey(serverId: string): string {
|
|
53
52
|
return `mcp:${serverId}:discovery`;
|
|
54
53
|
}
|
|
54
|
+
function clientBindingKey(serverId: string): string {
|
|
55
|
+
return `mcp:${serverId}:client_binding`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* What a stored client registration was made against.
|
|
60
|
+
*
|
|
61
|
+
* A client identifier belongs to the authorization server that issued it and
|
|
62
|
+
* is registered for one set of redirect URIs, so reusing a registration after
|
|
63
|
+
* either changes is invalid. Recording both is what lets a registration be
|
|
64
|
+
* reused when they still hold, which is the difference between registering
|
|
65
|
+
* once per assistant and registering once per attempt.
|
|
66
|
+
*/
|
|
67
|
+
interface ClientRegistrationBinding {
|
|
68
|
+
issuer: string | null;
|
|
69
|
+
redirectUri: string;
|
|
70
|
+
}
|
|
55
71
|
|
|
56
72
|
export interface McpOAuthCallbackResult {
|
|
57
73
|
/** Resolves with the authorization code when the callback is received. */
|
|
58
74
|
codePromise: Promise<string>;
|
|
59
75
|
}
|
|
60
76
|
|
|
61
|
-
/** Which callback transport to use for receiving the OAuth redirect. */
|
|
62
|
-
export type McpOAuthCallbackTransport = "loopback" | "gateway";
|
|
63
|
-
|
|
64
77
|
export interface McpOAuthProviderOptions {
|
|
65
78
|
/**
|
|
66
79
|
* If provided, called with the authorization URL during
|
|
@@ -75,37 +88,29 @@ export class McpOAuthProvider implements OAuthClientProvider {
|
|
|
75
88
|
private readonly serverId: string;
|
|
76
89
|
private readonly serverUrl: string;
|
|
77
90
|
private readonly interactive: boolean;
|
|
78
|
-
private readonly callbackTransport: McpOAuthCallbackTransport;
|
|
79
91
|
private _codeVerifier: string | undefined;
|
|
80
92
|
private _state: string | undefined;
|
|
81
93
|
private _redirectUrl: string | undefined;
|
|
82
94
|
private _codePromise: Promise<string> | null = null;
|
|
83
|
-
|
|
84
|
-
private
|
|
85
|
-
|
|
86
|
-
private _gatewayCodeResolve: ((code: string) => void) | undefined;
|
|
87
|
-
private _gatewayCodeReject: ((err: Error) => void) | undefined;
|
|
95
|
+
/** Deferred resolver/rejector for the callback code promise. */
|
|
96
|
+
private _codeResolve: ((code: string) => void) | undefined;
|
|
97
|
+
private _codeReject: ((err: Error) => void) | undefined;
|
|
88
98
|
private readonly _onAuthorizationUrl: ((url: string) => void) | undefined;
|
|
89
99
|
|
|
90
100
|
/**
|
|
91
101
|
* @param interactive When true (e.g. `mcp auth` CLI), opens browser for OAuth.
|
|
92
102
|
* When false (daemon), logs a message instead.
|
|
93
|
-
* @param callbackTransport Which transport to use for the OAuth redirect.
|
|
94
|
-
* - `"loopback"` (default): localhost HTTP server — for desktop clients.
|
|
95
|
-
* - `"gateway"`: platform ingress + callback registry — for Docker/platform.
|
|
96
103
|
* @param options Additional options for the provider.
|
|
97
104
|
*/
|
|
98
105
|
constructor(
|
|
99
106
|
serverId: string,
|
|
100
107
|
serverUrl: string,
|
|
101
108
|
interactive = false,
|
|
102
|
-
callbackTransport: McpOAuthCallbackTransport = "loopback",
|
|
103
109
|
options: McpOAuthProviderOptions = {},
|
|
104
110
|
) {
|
|
105
111
|
this.serverId = serverId;
|
|
106
112
|
this.serverUrl = serverUrl;
|
|
107
113
|
this.interactive = interactive;
|
|
108
|
-
this.callbackTransport = callbackTransport;
|
|
109
114
|
this._onAuthorizationUrl = options.onAuthorizationUrl;
|
|
110
115
|
}
|
|
111
116
|
|
|
@@ -117,13 +122,35 @@ export class McpOAuthProvider implements OAuthClientProvider {
|
|
|
117
122
|
|
|
118
123
|
// --- clientMetadata ---
|
|
119
124
|
|
|
125
|
+
/**
|
|
126
|
+
* Identity presented at dynamic registration, and on the consent screen
|
|
127
|
+
* the user reads before approving.
|
|
128
|
+
*
|
|
129
|
+
* The client is this assistant, not the Vellum product and not the plugin
|
|
130
|
+
* that declared the server: each assistant registers separately, with its
|
|
131
|
+
* own redirect URI, so its own name is what makes the consent screen
|
|
132
|
+
* meaningful when a person runs several. `software_id` carries the
|
|
133
|
+
* assistant id so a server can correlate an assistant's registrations
|
|
134
|
+
* across servers without treating every assistant as the same client.
|
|
135
|
+
*
|
|
136
|
+
* `logo_uri` is absent deliberately. The assistant's avatar is served
|
|
137
|
+
* only behind authentication, and an authorization server fetching a logo
|
|
138
|
+
* is anonymous, so there is no URL to give it. A stable public identity
|
|
139
|
+
* per assistant is what would supply one, and the same prerequisite would
|
|
140
|
+
* let this move to Client ID Metadata Documents and drop registration
|
|
141
|
+
* altogether.
|
|
142
|
+
*/
|
|
120
143
|
get clientMetadata(): OAuthClientMetadata {
|
|
144
|
+
const assistantName = getAssistantName();
|
|
145
|
+
const assistantId = getPlatformAssistantId().trim();
|
|
121
146
|
return {
|
|
122
|
-
client_name: "Vellum Assistant",
|
|
147
|
+
client_name: assistantName ?? "Vellum Assistant",
|
|
123
148
|
redirect_uris: this._redirectUrl ? [this._redirectUrl] : [],
|
|
124
149
|
token_endpoint_auth_method: "none",
|
|
125
150
|
grant_types: ["authorization_code", "refresh_token"],
|
|
126
151
|
response_types: ["code"],
|
|
152
|
+
...(assistantId.length > 0 && { software_id: assistantId }),
|
|
153
|
+
software_version: APP_VERSION,
|
|
127
154
|
};
|
|
128
155
|
}
|
|
129
156
|
|
|
@@ -214,13 +241,26 @@ export class McpOAuthProvider implements OAuthClientProvider {
|
|
|
214
241
|
|
|
215
242
|
// --- Client Information ---
|
|
216
243
|
|
|
244
|
+
/**
|
|
245
|
+
* The stored registration, or `undefined` to make the SDK register a new
|
|
246
|
+
* one.
|
|
247
|
+
*
|
|
248
|
+
* Returning the stored value is the normal case: dynamic registration
|
|
249
|
+
* writes a record on the authorization server, so re-registering per
|
|
250
|
+
* attempt accumulates records nobody cleans up. It is withheld only when
|
|
251
|
+
* the registration provably no longer applies, because the redirect URI
|
|
252
|
+
* it was made for changed or because a different authorization server now
|
|
253
|
+
* fronts the resource.
|
|
254
|
+
*/
|
|
217
255
|
async clientInformation(): Promise<OAuthClientInformationMixed | undefined> {
|
|
218
256
|
const raw = await getSecureKeyAsync(clientInfoKey(this.serverId));
|
|
219
257
|
if (!raw) {
|
|
220
258
|
return undefined;
|
|
221
259
|
}
|
|
260
|
+
|
|
261
|
+
let info: OAuthClientInformationMixed;
|
|
222
262
|
try {
|
|
223
|
-
|
|
263
|
+
info = JSON.parse(raw) as OAuthClientInformationMixed;
|
|
224
264
|
} catch {
|
|
225
265
|
log.warn(
|
|
226
266
|
{ serverId: this.serverId },
|
|
@@ -228,6 +268,16 @@ export class McpOAuthProvider implements OAuthClientProvider {
|
|
|
228
268
|
);
|
|
229
269
|
return undefined;
|
|
230
270
|
}
|
|
271
|
+
|
|
272
|
+
const stale = await this.describeStaleBinding();
|
|
273
|
+
if (stale) {
|
|
274
|
+
log.info(
|
|
275
|
+
{ serverId: this.serverId, reason: stale },
|
|
276
|
+
"Stored client registration no longer applies; registering again",
|
|
277
|
+
);
|
|
278
|
+
return undefined;
|
|
279
|
+
}
|
|
280
|
+
return info;
|
|
231
281
|
}
|
|
232
282
|
|
|
233
283
|
async saveClientInformation(
|
|
@@ -244,9 +294,76 @@ export class McpOAuthProvider implements OAuthClientProvider {
|
|
|
244
294
|
);
|
|
245
295
|
return;
|
|
246
296
|
}
|
|
297
|
+
|
|
298
|
+
// Record what the registration was made against, so a later run can tell
|
|
299
|
+
// whether reusing it is still valid.
|
|
300
|
+
if (this._redirectUrl) {
|
|
301
|
+
const binding: ClientRegistrationBinding = {
|
|
302
|
+
issuer: await this.currentIssuer(),
|
|
303
|
+
redirectUri: this._redirectUrl,
|
|
304
|
+
};
|
|
305
|
+
const boundOk = await setSecureKeyAsync(
|
|
306
|
+
clientBindingKey(this.serverId),
|
|
307
|
+
JSON.stringify(binding),
|
|
308
|
+
);
|
|
309
|
+
if (!boundOk) {
|
|
310
|
+
log.warn(
|
|
311
|
+
{ serverId: this.serverId },
|
|
312
|
+
"Failed to persist OAuth client binding; the registration will be remade on the next flow",
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
247
317
|
log.info({ serverId: this.serverId }, "OAuth client information saved");
|
|
248
318
|
}
|
|
249
319
|
|
|
320
|
+
/** Issuer of the authorization server currently in play, when known. */
|
|
321
|
+
private async currentIssuer(): Promise<string | null> {
|
|
322
|
+
const state = await this.discoveryState();
|
|
323
|
+
return (
|
|
324
|
+
state?.authorizationServerMetadata?.issuer ??
|
|
325
|
+
state?.authorizationServerUrl ??
|
|
326
|
+
null
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Why the stored registration cannot be reused, or null when it can.
|
|
332
|
+
*
|
|
333
|
+
* The redirect URI is only checked while a flow is being prepared:
|
|
334
|
+
* outside one there is no redirect URI to compare against, and a silent
|
|
335
|
+
* reconnect must not be turned into a registration.
|
|
336
|
+
*
|
|
337
|
+
* The issuer is only checked when discovery has run. An unverifiable
|
|
338
|
+
* issuer keeps the registration rather than discarding it, since the
|
|
339
|
+
* redirect check already covers the case this plugin actually changes.
|
|
340
|
+
*/
|
|
341
|
+
private async describeStaleBinding(): Promise<string | null> {
|
|
342
|
+
const raw = await getSecureKeyAsync(clientBindingKey(this.serverId));
|
|
343
|
+
if (!raw) {
|
|
344
|
+
// Registered before the binding was recorded. Keep it: discarding
|
|
345
|
+
// every pre-existing registration would remake all of them at once.
|
|
346
|
+
return null;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
let binding: ClientRegistrationBinding;
|
|
350
|
+
try {
|
|
351
|
+
binding = JSON.parse(raw) as ClientRegistrationBinding;
|
|
352
|
+
} catch {
|
|
353
|
+
return "stored binding is unreadable";
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (this._redirectUrl && binding.redirectUri !== this._redirectUrl) {
|
|
357
|
+
return "redirect URI changed";
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const issuer = await this.currentIssuer();
|
|
361
|
+
if (issuer && binding.issuer && binding.issuer !== issuer) {
|
|
362
|
+
return "authorization server changed";
|
|
363
|
+
}
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
|
|
250
367
|
// --- Code Verifier (in-memory, ephemeral) ---
|
|
251
368
|
|
|
252
369
|
async saveCodeVerifier(verifier: string): Promise<void> {
|
|
@@ -312,31 +429,24 @@ export class McpOAuthProvider implements OAuthClientProvider {
|
|
|
312
429
|
async redirectToAuthorization(authorizationUrl: URL): Promise<void> {
|
|
313
430
|
const url = authorizationUrl.toString();
|
|
314
431
|
|
|
315
|
-
//
|
|
316
|
-
//
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
this._gatewayCodeResolve &&
|
|
320
|
-
this._gatewayCodeReject
|
|
321
|
-
) {
|
|
432
|
+
// The callback is demultiplexed by OAuth `state`, and the SDK mints it
|
|
433
|
+
// while building this URL, so this is the earliest point the pending
|
|
434
|
+
// callback can be registered.
|
|
435
|
+
if (this._codeResolve && this._codeReject) {
|
|
322
436
|
const sdkState = authorizationUrl.searchParams.get("state");
|
|
323
437
|
if (sdkState) {
|
|
324
438
|
// Dynamic import to avoid circular deps
|
|
325
439
|
const { registerPendingCallback } =
|
|
326
440
|
await import("../security/oauth-callback-registry.js");
|
|
327
|
-
registerPendingCallback(
|
|
328
|
-
sdkState,
|
|
329
|
-
this._gatewayCodeResolve,
|
|
330
|
-
this._gatewayCodeReject,
|
|
331
|
-
);
|
|
441
|
+
registerPendingCallback(sdkState, this._codeResolve, this._codeReject);
|
|
332
442
|
log.info(
|
|
333
443
|
{ serverId: this.serverId, state: sdkState },
|
|
334
|
-
"MCP OAuth
|
|
444
|
+
"MCP OAuth callback registered with SDK state",
|
|
335
445
|
);
|
|
336
446
|
} else {
|
|
337
447
|
log.warn(
|
|
338
448
|
{ serverId: this.serverId },
|
|
339
|
-
"Authorization URL missing state parameter
|
|
449
|
+
"Authorization URL missing state parameter, callback may not resolve",
|
|
340
450
|
);
|
|
341
451
|
}
|
|
342
452
|
}
|
|
@@ -404,6 +514,10 @@ export class McpOAuthProvider implements OAuthClientProvider {
|
|
|
404
514
|
"OAuth client information key not found in secure storage (already removed)",
|
|
405
515
|
);
|
|
406
516
|
}
|
|
517
|
+
// The binding describes the registration being dropped, so it goes
|
|
518
|
+
// with it. Leaving it would let a later registration inherit the
|
|
519
|
+
// previous one's issuer and redirect URI.
|
|
520
|
+
await deleteSecureKeyAsync(clientBindingKey(this.serverId));
|
|
407
521
|
}
|
|
408
522
|
if (scope === "all" || scope === "verifier") {
|
|
409
523
|
this._codeVerifier = undefined;
|
|
@@ -425,52 +539,29 @@ export class McpOAuthProvider implements OAuthClientProvider {
|
|
|
425
539
|
}
|
|
426
540
|
}
|
|
427
541
|
|
|
428
|
-
// --- Callback
|
|
542
|
+
// --- Callback ---
|
|
429
543
|
|
|
430
544
|
/**
|
|
431
|
-
*
|
|
545
|
+
* Prepare to receive the OAuth callback.
|
|
432
546
|
*
|
|
433
|
-
*
|
|
434
|
-
*
|
|
435
|
-
*
|
|
436
|
-
*
|
|
547
|
+
* Resolves the shared redirect URI the gateway serves and creates a
|
|
548
|
+
* deferred code promise. There is no listener to start: the gateway
|
|
549
|
+
* already accepts `webhooks/oauth/callback` and forwards it to
|
|
550
|
+
* `POST /v1/internal/oauth/callback`, which resolves the waiting flow
|
|
551
|
+
* by matching the arriving OAuth `state`.
|
|
437
552
|
*
|
|
438
|
-
*
|
|
439
|
-
|
|
440
|
-
startCallbackServer(): Promise<McpOAuthCallbackResult> {
|
|
441
|
-
if (this.callbackTransport === "gateway") {
|
|
442
|
-
return this.startGatewayCallback();
|
|
443
|
-
}
|
|
444
|
-
return this.startLoopbackServer();
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
/**
|
|
448
|
-
* Gateway transport: resolve the public redirect URL and create a
|
|
449
|
-
* deferred code promise. The actual `registerPendingCallback` call
|
|
450
|
-
* is deferred until `redirectToAuthorization` where we can extract
|
|
451
|
-
* the SDK-generated `state` parameter from the authorization URL.
|
|
553
|
+
* `registerPendingCallback` is deferred to `redirectToAuthorization`,
|
|
554
|
+
* the first point at which the SDK-generated `state` is known.
|
|
452
555
|
*/
|
|
453
|
-
|
|
454
|
-
const {
|
|
455
|
-
await import("../inbound/
|
|
456
|
-
const { getOAuthCallbackUrl } =
|
|
457
|
-
await import("../inbound/public-ingress-urls.js");
|
|
458
|
-
const { loadConfig } = await import("../config/loader.js");
|
|
459
|
-
|
|
460
|
-
const appConfig = loadConfig();
|
|
461
|
-
const redirectUrl = await resolveCallbackUrl(
|
|
462
|
-
() => getOAuthCallbackUrl(appConfig),
|
|
463
|
-
"webhooks/oauth/callback",
|
|
464
|
-
"mcp_oauth",
|
|
465
|
-
);
|
|
556
|
+
async startCallbackServer(): Promise<McpOAuthCallbackResult> {
|
|
557
|
+
const { resolveOauthCallbackUrl } =
|
|
558
|
+
await import("../inbound/oauth-callback-url.js");
|
|
466
559
|
|
|
467
|
-
this._redirectUrl =
|
|
560
|
+
this._redirectUrl = await resolveOauthCallbackUrl();
|
|
468
561
|
|
|
469
|
-
// Create a deferred promise — it will be wired to the callback
|
|
470
|
-
// registry in redirectToAuthorization() once we know the SDK's state.
|
|
471
562
|
const codePromise = new Promise<string>((resolve, reject) => {
|
|
472
|
-
this.
|
|
473
|
-
this.
|
|
563
|
+
this._codeResolve = resolve;
|
|
564
|
+
this._codeReject = reject;
|
|
474
565
|
});
|
|
475
566
|
this._codePromise = codePromise;
|
|
476
567
|
|
|
@@ -481,154 +572,32 @@ export class McpOAuthProvider implements OAuthClientProvider {
|
|
|
481
572
|
void codePromise.catch(() => {});
|
|
482
573
|
|
|
483
574
|
log.info(
|
|
484
|
-
{ serverId: this.serverId, redirectUrl },
|
|
485
|
-
"MCP OAuth
|
|
575
|
+
{ serverId: this.serverId, redirectUrl: this._redirectUrl },
|
|
576
|
+
"MCP OAuth callback prepared (awaiting state from auth URL)",
|
|
486
577
|
);
|
|
487
578
|
|
|
488
579
|
return { codePromise };
|
|
489
580
|
}
|
|
490
581
|
|
|
491
|
-
/**
|
|
492
|
-
* Loopback transport: start a temporary HTTP server on localhost.
|
|
493
|
-
*/
|
|
494
|
-
private startLoopbackServer(): Promise<McpOAuthCallbackResult> {
|
|
495
|
-
return new Promise((resolveSetup, rejectSetup) => {
|
|
496
|
-
let settled = false;
|
|
497
|
-
let listening = false;
|
|
498
|
-
let codeResolve: (code: string) => void;
|
|
499
|
-
let codeReject: (err: Error) => void;
|
|
500
|
-
|
|
501
|
-
const codePromise = new Promise<string>((resolve, reject) => {
|
|
502
|
-
codeResolve = resolve;
|
|
503
|
-
codeReject = reject;
|
|
504
|
-
});
|
|
505
|
-
this._codePromise = codePromise;
|
|
506
|
-
|
|
507
|
-
const server = createServer((req, res) => {
|
|
508
|
-
if (settled) {
|
|
509
|
-
res.writeHead(400, { "Content-Type": "text/html" });
|
|
510
|
-
res.end(renderPage("Authorization already completed", false));
|
|
511
|
-
return;
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
const url = new URL(req.url ?? "/", "http://127.0.0.1");
|
|
515
|
-
if (url.pathname !== CALLBACK_PATH) {
|
|
516
|
-
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
517
|
-
res.end("Not found");
|
|
518
|
-
return;
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
const code = url.searchParams.get("code");
|
|
522
|
-
const error = url.searchParams.get("error");
|
|
523
|
-
|
|
524
|
-
settled = true;
|
|
525
|
-
|
|
526
|
-
if (error) {
|
|
527
|
-
const errorDesc = url.searchParams.get("error_description") ?? error;
|
|
528
|
-
res.writeHead(200, { "Content-Type": "text/html" });
|
|
529
|
-
res.end(renderPage(`Authorization failed: ${errorDesc}`, false));
|
|
530
|
-
cleanup();
|
|
531
|
-
codeReject(new Error(`MCP OAuth authorization denied: ${error}`));
|
|
532
|
-
return;
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
if (!code) {
|
|
536
|
-
res.writeHead(400, { "Content-Type": "text/html" });
|
|
537
|
-
res.end(renderPage("Missing authorization code", false));
|
|
538
|
-
cleanup();
|
|
539
|
-
codeReject(
|
|
540
|
-
new Error("MCP OAuth callback missing authorization code"),
|
|
541
|
-
);
|
|
542
|
-
return;
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
res.writeHead(200, { "Content-Type": "text/html" });
|
|
546
|
-
res.end(
|
|
547
|
-
renderPage("Authorization successful! You can close this tab.", true),
|
|
548
|
-
);
|
|
549
|
-
cleanup();
|
|
550
|
-
codeResolve(code);
|
|
551
|
-
});
|
|
552
|
-
|
|
553
|
-
this.callbackServer = server;
|
|
554
|
-
|
|
555
|
-
const timeout = setTimeout(() => {
|
|
556
|
-
if (!settled) {
|
|
557
|
-
settled = true;
|
|
558
|
-
cleanup();
|
|
559
|
-
codeReject(new Error("MCP OAuth callback timed out"));
|
|
560
|
-
}
|
|
561
|
-
}, CALLBACK_TIMEOUT_MS);
|
|
562
|
-
if (typeof timeout === "object" && "unref" in timeout) {
|
|
563
|
-
timeout.unref();
|
|
564
|
-
}
|
|
565
|
-
this.callbackTimeout = timeout;
|
|
566
|
-
|
|
567
|
-
const cleanup = () => {
|
|
568
|
-
if (this.callbackTimeout) {
|
|
569
|
-
clearTimeout(this.callbackTimeout);
|
|
570
|
-
this.callbackTimeout = null;
|
|
571
|
-
}
|
|
572
|
-
if (this.callbackServer) {
|
|
573
|
-
this.callbackServer.close();
|
|
574
|
-
this.callbackServer = null;
|
|
575
|
-
}
|
|
576
|
-
};
|
|
577
|
-
|
|
578
|
-
server.listen(0, "127.0.0.1", () => {
|
|
579
|
-
const addr = server.address() as { port: number };
|
|
580
|
-
this._redirectUrl = `http://127.0.0.1:${addr.port}${CALLBACK_PATH}`;
|
|
581
|
-
listening = true;
|
|
582
|
-
log.info(
|
|
583
|
-
{ serverId: this.serverId, redirectUrl: this._redirectUrl },
|
|
584
|
-
"OAuth callback server started",
|
|
585
|
-
);
|
|
586
|
-
resolveSetup({ codePromise });
|
|
587
|
-
});
|
|
588
|
-
|
|
589
|
-
server.on("error", (err) => {
|
|
590
|
-
const message = `MCP OAuth callback server error: ${err.message}`;
|
|
591
|
-
if (!listening) {
|
|
592
|
-
settled = true;
|
|
593
|
-
cleanup();
|
|
594
|
-
rejectSetup(new Error(message));
|
|
595
|
-
} else if (!settled) {
|
|
596
|
-
settled = true;
|
|
597
|
-
cleanup();
|
|
598
|
-
codeReject(new Error(message));
|
|
599
|
-
}
|
|
600
|
-
});
|
|
601
|
-
});
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
/** Returns the code promise from the running callback server. */
|
|
582
|
+
/** Returns the code promise created by {@link startCallbackServer}. */
|
|
605
583
|
waitForCode(): Promise<string> {
|
|
606
584
|
if (!this._codePromise) {
|
|
607
585
|
throw new Error(
|
|
608
|
-
"Callback
|
|
586
|
+
"Callback not prepared, call startCallbackServer() first",
|
|
609
587
|
);
|
|
610
588
|
}
|
|
611
589
|
return this._codePromise;
|
|
612
590
|
}
|
|
613
591
|
|
|
614
|
-
/**
|
|
592
|
+
/**
|
|
593
|
+
* Abandon a prepared callback. Rejects the deferred promise so callers
|
|
594
|
+
* awaiting the code do not hang until the registry's own TTL fires.
|
|
595
|
+
*/
|
|
615
596
|
stopCallbackServer(): void {
|
|
616
|
-
if (this.
|
|
617
|
-
|
|
618
|
-
this.
|
|
619
|
-
|
|
620
|
-
if (this.callbackServer) {
|
|
621
|
-
this.callbackServer.close();
|
|
622
|
-
this.callbackServer = null;
|
|
623
|
-
}
|
|
624
|
-
// Gateway transport cleanup — reject the deferred promise so callers
|
|
625
|
-
// awaiting codePromise don't hang indefinitely.
|
|
626
|
-
if (this._gatewayCodeReject) {
|
|
627
|
-
this._gatewayCodeReject(
|
|
628
|
-
new Error("MCP OAuth gateway callback cancelled"),
|
|
629
|
-
);
|
|
630
|
-
this._gatewayCodeResolve = undefined;
|
|
631
|
-
this._gatewayCodeReject = undefined;
|
|
597
|
+
if (this._codeReject) {
|
|
598
|
+
this._codeReject(new Error("MCP OAuth callback cancelled"));
|
|
599
|
+
this._codeResolve = undefined;
|
|
600
|
+
this._codeReject = undefined;
|
|
632
601
|
}
|
|
633
602
|
}
|
|
634
603
|
}
|
|
@@ -650,14 +619,17 @@ export async function hasMcpOAuthTokens(serverId: string): Promise<boolean> {
|
|
|
650
619
|
export async function deleteMcpOAuthCredentials(
|
|
651
620
|
serverId: string,
|
|
652
621
|
): Promise<{ ok: boolean; failedKeys: string[] }> {
|
|
653
|
-
const [tokensResult, clientResult, discoveryResult] =
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
622
|
+
const [tokensResult, clientResult, bindingResult, discoveryResult] =
|
|
623
|
+
await Promise.all([
|
|
624
|
+
deleteSecureKeyAsync(tokensKey(serverId)),
|
|
625
|
+
deleteSecureKeyAsync(clientInfoKey(serverId)),
|
|
626
|
+
deleteSecureKeyAsync(clientBindingKey(serverId)),
|
|
627
|
+
deleteSecureKeyAsync(discoveryKey(serverId)),
|
|
628
|
+
]);
|
|
658
629
|
const results = [
|
|
659
630
|
{ key: "tokens", result: tokensResult },
|
|
660
631
|
{ key: "client_info", result: clientResult },
|
|
632
|
+
{ key: "client_binding", result: bindingResult },
|
|
661
633
|
{ key: "discovery", result: discoveryResult },
|
|
662
634
|
];
|
|
663
635
|
const failedKeys = results
|
|
@@ -678,20 +650,3 @@ export async function deleteMcpOAuthCredentials(
|
|
|
678
650
|
);
|
|
679
651
|
return { ok, failedKeys };
|
|
680
652
|
}
|
|
681
|
-
|
|
682
|
-
// --- HTML rendering ---
|
|
683
|
-
|
|
684
|
-
function escapeHtml(s: string): string {
|
|
685
|
-
return s
|
|
686
|
-
.replace(/&/g, "&")
|
|
687
|
-
.replace(/</g, "<")
|
|
688
|
-
.replace(/>/g, ">")
|
|
689
|
-
.replace(/"/g, """)
|
|
690
|
-
.replace(/'/g, "'");
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
function renderPage(message: string, success: boolean): string {
|
|
694
|
-
const title = success ? "Authorization Successful" : "Authorization Failed";
|
|
695
|
-
const color = success ? "#4CAF50" : "#f44336";
|
|
696
|
-
return `<!DOCTYPE html><html><head><title>${escapeHtml(title)}</title><style>body{font-family:system-ui,sans-serif;display:flex;justify-content:center;align-items:center;min-height:100vh;margin:0;background:#f5f5f5}div{text-align:center;padding:2rem;background:white;border-radius:8px;box-shadow:0 2px 4px rgba(0,0,0,0.1)}h1{color:${color}}</style></head><body><div><h1>${escapeHtml(title)}</h1><p>${escapeHtml(message)}</p></div></body></html>`;
|
|
697
|
-
}
|
|
@@ -10,11 +10,14 @@ describe("channelForCallback", () => {
|
|
|
10
10
|
expect(channelForCallback("http://gw/deliver/telegram")).toBe("telegram");
|
|
11
11
|
expect(channelForCallback("http://gw/deliver/whatsapp")).toBe("whatsapp");
|
|
12
12
|
expect(channelForCallback("http://gw/deliver/a2a?taskId=t1")).toBe("a2a");
|
|
13
|
+
expect(channelForCallback("http://gw/deliver/discord?threadId=T1")).toBe(
|
|
14
|
+
"discord",
|
|
15
|
+
);
|
|
13
16
|
});
|
|
14
17
|
|
|
15
18
|
test("returns undefined for channels not delivered directly", () => {
|
|
16
|
-
expect(channelForCallback("http://gw/deliver/discord")).toBeUndefined();
|
|
17
19
|
expect(channelForCallback("http://gw/deliver/phone")).toBeUndefined();
|
|
20
|
+
expect(channelForCallback("http://gw/deliver/email")).toBeUndefined();
|
|
18
21
|
});
|
|
19
22
|
|
|
20
23
|
test("returns undefined for non-delivery paths", () => {
|
|
@@ -41,5 +44,6 @@ describe("channelForCallback", () => {
|
|
|
41
44
|
expect(channelForCallback("/deliver/slack")).toBe("slack");
|
|
42
45
|
expect(channelForCallback("/deliver/telegram")).toBe("telegram");
|
|
43
46
|
expect(channelForCallback("/deliver/whatsapp")).toBe("whatsapp");
|
|
47
|
+
expect(channelForCallback("/deliver/discord")).toBe("discord");
|
|
44
48
|
});
|
|
45
49
|
});
|