@vellumai/assistant 0.12.1 → 0.12.2-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/AGENTS.md +4 -0
- package/ARCHITECTURE.md +20 -21
- package/docs/architecture/turn-actor.md +15 -8
- package/docs/guardian-request-flow.md +16 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +13 -8
- package/node_modules/@vellumai/slack-text/src/label-resolution-entities.test.ts +95 -0
- package/openapi.yaml +360 -51
- package/package.json +3 -1
- package/scripts/smoke-desktop-window-theme.ts +186 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +18 -10
- package/src/__tests__/anthropic-provider.test.ts +0 -63
- package/src/__tests__/app-compiler.test.ts +6 -0
- package/src/__tests__/app-control-tool-schemas.test.ts +5 -2
- package/src/__tests__/app-dir-path-guard.test.ts +1 -3
- package/src/__tests__/assistant-event-hub-machine-name.test.ts +6 -7
- package/src/__tests__/assistant-event-hub.test.ts +44 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
- package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +5 -2
- package/src/__tests__/computer-use-tools.test.ts +19 -7
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +28 -29
- package/src/__tests__/config-watcher.test.ts +23 -8
- package/src/__tests__/connection-model-compat.test.ts +2 -2
- package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-pairing.test.ts +26 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +4 -10
- package/src/__tests__/conversation-queue.test.ts +48 -207
- package/src/__tests__/conversation-retry-discard.test.ts +54 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +28 -0
- package/src/__tests__/conversation-skill-tools.test.ts +27 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +8 -3
- package/src/__tests__/conversation-surfaces-point-at-budget.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-point-at-capability.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +67 -0
- package/src/__tests__/conversation-title-service.test.ts +14 -10
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +3 -5
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +51 -0
- package/src/__tests__/credential-record-retire.test.ts +171 -1
- package/src/__tests__/credential-routes.test.ts +250 -3
- package/src/__tests__/credential-security-invariants.test.ts +5 -3
- package/src/__tests__/cu-unified-flow.test.ts +14 -4
- package/src/__tests__/document-sync-tags.test.ts +25 -0
- package/src/__tests__/drain-kick-guard.test.ts +0 -2
- package/src/__tests__/drain-requeue-on-contention.test.ts +0 -6
- package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
- package/src/__tests__/git-porcelain.test.ts +47 -0
- package/src/__tests__/heartbeat-service.test.ts +56 -40
- package/src/__tests__/helpers/set-workspace-mcp.ts +11 -0
- package/src/__tests__/host-bash-proxy.test.ts +26 -45
- package/src/__tests__/host-browser-proxy.test.ts +6 -17
- package/src/__tests__/host-cu-proxy.test.ts +596 -0
- package/src/__tests__/host-file-proxy-targeted.test.ts +23 -0
- package/src/__tests__/host-file-proxy.test.ts +11 -23
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +30 -9
- package/src/__tests__/list-messages-camera-frame.test.ts +121 -0
- package/src/__tests__/llm-catalog-parity.test.ts +25 -0
- package/src/__tests__/mcp-auth-routes.test.ts +6 -9
- package/src/__tests__/mcp-config-secret-boundary.test.ts +78 -136
- package/src/__tests__/mcp-health-check.test.ts +8 -11
- package/src/__tests__/mcp-list-plugin-servers.test.ts +8 -10
- package/src/__tests__/message-deleted-hook-dispatch.test.ts +119 -0
- package/src/__tests__/messages-after-tiebreaker.test.ts +91 -0
- package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
- package/src/__tests__/messaging-send-tool.test.ts +355 -548
- package/src/__tests__/model-intents.test.ts +3 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +85 -2
- package/src/__tests__/oauth-commands-routes.test.ts +168 -0
- package/src/__tests__/oauth-provider-profiles.test.ts +18 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +22 -0
- package/src/__tests__/oauth-providers-routes.test.ts +1 -0
- package/src/__tests__/openai-provider.test.ts +1 -0
- package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
- package/src/__tests__/platform-callback-registration.test.ts +8 -16
- package/src/__tests__/platform-client-verify-credential.test.ts +2 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +14 -0
- package/src/__tests__/qdrant-manager.test.ts +132 -0
- package/src/__tests__/resolve-app.test.ts +135 -0
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +229 -6
- package/src/__tests__/script-proxy-certs.test.ts +35 -0
- package/src/__tests__/secret-routes-acp-guard.test.ts +59 -1
- package/src/__tests__/service-account-token.test.ts +247 -0
- package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/skills.test.ts +9 -4
- package/src/__tests__/source-fingerprint.test.ts +184 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +70 -3
- package/src/__tests__/subagent-tools.test.ts +3 -2
- package/src/__tests__/telephony-tts-guard.test.ts +38 -3
- package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
- package/src/__tests__/ui-channel-variants.test.ts +1 -56
- package/src/__tests__/unicode.test.ts +13 -0
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +4 -0
- package/src/__tests__/watch-retro-tool-availability.test.ts +8 -17
- package/src/__tests__/workspace-git-service.test.ts +26 -0
- package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +336 -0
- package/src/acp/__tests__/acp-claude-oauth.test.ts +257 -6
- package/src/acp/__tests__/acp-credentials.test.ts +13 -0
- package/src/acp/__tests__/agent-process.test.ts +258 -4
- package/src/acp/__tests__/auth-required.test.ts +96 -0
- package/src/acp/__tests__/claude-token-refresh.test.ts +257 -0
- package/src/acp/__tests__/client-handler.test.ts +90 -2
- package/src/acp/__tests__/helpers/acp-model-option.ts +51 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +60 -1
- package/src/acp/__tests__/session-manager-persistence.test.ts +5 -1
- package/src/acp/__tests__/session-manager-resume.test.ts +270 -6
- package/src/acp/__tests__/session-manager-usage.test.ts +4 -2
- package/src/acp/__tests__/session-manager.test.ts +895 -4
- package/src/acp/acp-claude-oauth.ts +328 -14
- package/src/acp/acp-credentials.ts +19 -0
- package/src/acp/agent-process.test.ts +4 -1
- package/src/acp/agent-process.ts +96 -10
- package/src/acp/auth-required.ts +50 -1
- package/src/acp/auto-install.test.ts +9 -7
- package/src/acp/claude-token-refresh.ts +150 -0
- package/src/acp/client-handler.ts +16 -3
- package/src/acp/model-config.test.ts +166 -0
- package/src/acp/model-config.ts +138 -0
- package/src/acp/prepare-agent-env.ts +21 -6
- package/src/acp/resolve-agent.test.ts +220 -6
- package/src/acp/resolve-agent.ts +88 -23
- package/src/acp/session-manager.test.ts +196 -3
- package/src/acp/session-manager.ts +441 -18
- package/src/acp/types.ts +50 -5
- package/src/agent/loop.ts +1 -0
- package/src/api/events/acp-session-model-update.test.ts +88 -0
- package/src/api/events/acp-session-model-update.ts +46 -0
- package/src/api/events/app-files-changed.ts +4 -3
- package/src/api/events/notification-intent.ts +2 -0
- package/src/api/events/user-message-echo.ts +7 -1
- package/src/api/index.ts +6 -0
- package/src/api/responses/conversation-message.ts +5 -0
- package/src/apps/app-store.ts +1 -1
- package/src/apps/resolve-app.ts +81 -0
- package/src/apps/source-fingerprint.ts +266 -0
- package/src/avatar/identity-avatar.ts +7 -2
- package/src/bundler/app-compiler.ts +15 -0
- package/src/calls/__tests__/barge-in-guard.test.ts +81 -0
- package/src/{__tests__ → calls/__tests__}/call-controller.test.ts +503 -82
- package/src/{__tests__ → calls/__tests__}/media-stream-audio-transcode.test.ts +1 -1
- package/src/{__tests__ → calls/__tests__}/media-stream-output.test.ts +37 -8
- package/src/{__tests__ → calls/__tests__}/media-stream-parser.test.ts +1 -1
- package/src/{__tests__ → calls/__tests__}/media-stream-server-integration.test.ts +150 -57
- package/src/{__tests__ → calls/__tests__}/media-stream-stt-session.test.ts +5 -5
- package/src/{__tests__ → calls/__tests__}/media-turn-detector.test.ts +1 -1
- package/src/{live-voice → calls}/__tests__/progress-narration.test.ts +4 -4
- package/src/{live-voice → calls}/__tests__/progress-phrases.test.ts +1 -1
- package/src/calls/__tests__/voice-control-protocol.test.ts +120 -25
- package/src/calls/__tests__/voice-leg-coordinator.test.ts +229 -0
- package/src/calls/__tests__/voice-progress-cadence.test.ts +274 -0
- package/src/{__tests__/voice-session-bridge.test.ts → calls/__tests__/voice-session-bridge-turn-flow.test.ts} +20 -12
- package/src/calls/__tests__/voice-session-bridge.test.ts +56 -1
- package/src/calls/__tests__/voice-triage-escalate.test.ts +105 -0
- package/src/calls/barge-in-guard.ts +118 -0
- package/src/calls/call-constants.ts +24 -4
- package/src/calls/call-controller.ts +499 -199
- package/src/calls/call-transport.ts +16 -0
- package/src/calls/media-stream-output.ts +32 -0
- package/src/calls/media-stream-server.ts +82 -30
- package/src/calls/media-stream-stt-session.ts +15 -0
- package/src/{live-voice → calls}/progress-narration.ts +2 -2
- package/src/calls/resolve-call-tts-provider.ts +33 -2
- package/src/calls/tts-call-strategy.ts +9 -5
- package/src/calls/types.ts +2 -0
- package/src/calls/voice-control-protocol.ts +155 -21
- package/src/calls/voice-leg-coordinator.ts +189 -0
- package/src/calls/voice-progress-cadence.ts +423 -0
- package/src/calls/voice-session-bridge.ts +92 -72
- package/src/calls/voice-triage-escalate.ts +178 -59
- package/src/cli/commands/__tests__/apps.test.ts +245 -0
- package/src/cli/commands/__tests__/bash.test.ts +53 -0
- package/src/cli/commands/__tests__/roadmap.help.test.ts +19 -0
- package/src/cli/commands/apps.help.ts +67 -13
- package/src/cli/commands/apps.ts +183 -0
- package/src/cli/commands/bash.help.ts +8 -13
- package/src/cli/commands/bash.ts +7 -25
- package/src/cli/commands/channels/__tests__/send.test.ts +218 -0
- package/src/cli/commands/channels/index.help.ts +70 -2
- package/src/cli/commands/channels/index.ts +16 -3
- package/src/cli/commands/channels/send.ts +128 -0
- package/src/cli/commands/credentials.help.ts +6 -2
- package/src/cli/commands/credentials.ts +2 -2
- package/src/cli/commands/mcp.help.ts +8 -8
- package/src/cli/commands/mcp.ts +1 -1
- package/src/cli/commands/oauth/status.ts +5 -0
- package/src/cli/commands/roadmap.help.ts +5 -1
- package/src/cli/commands/roadmap.ts +1 -1
- package/src/cli/lib/bundled-marketplace.json +103 -90
- package/src/config/__tests__/default-profile-catalog.test.ts +22 -0
- package/src/config/__tests__/memory-retrospective-schema.test.ts +15 -1
- package/src/config/__tests__/platform-identity.test.ts +255 -0
- package/src/config/__tests__/platform-rehydration.test.ts +99 -9
- package/src/config/acp-agent-write.ts +43 -0
- package/src/config/acp-defaults.test.ts +13 -3
- package/src/config/acp-defaults.ts +23 -6
- package/src/config/acp-schema.test.ts +81 -0
- package/src/config/acp-schema.ts +30 -2
- package/src/config/bundled-skills/acp/SKILL.md +22 -14
- package/src/config/bundled-skills/acp/TOOLS.json +5 -1
- package/src/config/bundled-skills/app-builder/SKILL.md +12 -9
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
- package/src/config/bundled-skills/computer-use/SKILL.md +29 -2
- package/src/config/bundled-skills/computer-use/TOOLS.json +99 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-sequence.ts +12 -0
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +2 -1
- package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +2 -1
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -1
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +67 -139
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -1
- package/src/config/bundled-skills/schedule/SKILL.md +3 -4
- package/src/config/bundled-skills/screen-annotation/SKILL.md +8 -1
- package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +4 -1
- package/src/config/bundled-skills/skill-management/TOOLS.json +6 -2
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +5 -2
- package/src/config/default-profile-catalog.ts +1 -1
- package/src/config/env.ts +2 -2
- package/src/config/feature-flag-registry.json +33 -13
- package/src/config/loader.ts +2 -0
- package/src/config/memory-v3-gate.test.ts +31 -0
- package/src/config/memory-v3-gate.ts +20 -16
- package/src/config/platform-identity.ts +201 -0
- package/src/config/platform-rehydration.ts +11 -27
- package/src/config/schema.ts +2 -2
- package/src/config/schemas/__tests__/live-voice.test.ts +8 -158
- package/src/config/schemas/__tests__/voice.test.ts +148 -0
- package/src/config/schemas/calls.ts +1 -28
- package/src/config/schemas/live-voice.ts +1 -173
- package/src/config/schemas/mcp.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +10 -0
- package/src/config/schemas/services.ts +18 -0
- package/src/config/schemas/skills.ts +0 -14
- package/src/config/schemas/voice.ts +150 -0
- package/src/credential-execution/process-manager.test.ts +18 -19
- package/src/credential-health/credential-health-service.ts +11 -17
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -121
- package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +4 -1
- package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +133 -0
- package/src/daemon/app-change-notify.ts +45 -0
- package/src/daemon/config-watcher.ts +13 -194
- package/src/daemon/conversation-error.ts +3 -2
- package/src/daemon/conversation-media-retry.ts +2 -1
- package/src/daemon/conversation-process.ts +35 -64
- package/src/daemon/conversation-runtime-assembly.ts +20 -7
- package/src/daemon/conversation-skill-tools.ts +13 -31
- package/src/daemon/conversation-store.ts +1 -1
- package/src/daemon/conversation-surfaces.ts +21 -10
- package/src/daemon/conversation-tool-setup.ts +45 -59
- package/src/daemon/conversation.ts +0 -3
- package/src/daemon/dictation-profile-store.ts +2 -1
- package/src/daemon/handlers/shared.ts +2 -1
- package/src/daemon/handlers/skills.ts +6 -3
- package/src/daemon/host-bash-proxy.ts +8 -12
- package/src/daemon/host-browser-proxy.ts +15 -1
- package/src/daemon/host-cu-proxy.ts +224 -19
- package/src/daemon/host-file-proxy.ts +8 -10
- package/src/daemon/host-proxy-preactivation.ts +2 -1
- package/src/daemon/host-transfer-proxy.ts +14 -18
- package/src/daemon/lifecycle.ts +0 -5
- package/src/daemon/mcp-reload-service.ts +5 -5
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/orphan-reaper.ts +1 -1
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/reaction-history-render.ts +2 -1
- package/src/daemon/shutdown-handlers.ts +1 -9
- package/src/daemon/skill-memory-refresh.ts +64 -0
- package/src/daemon/tool-side-effects.ts +7 -18
- package/src/desktop/__tests__/fake-desktop.ts +122 -0
- package/src/desktop/desktop-chrome-policy.test.ts +79 -0
- package/src/desktop/desktop-chrome-policy.ts +47 -0
- package/src/desktop/desktop-chrome-session.ts +37 -0
- package/src/desktop/desktop-dependencies.test.ts +102 -0
- package/src/desktop/desktop-dependencies.ts +308 -0
- package/src/desktop/desktop-feature.test.ts +18 -0
- package/src/desktop/desktop-feature.ts +19 -0
- package/src/desktop/desktop-panel-config.test.ts +135 -0
- package/src/desktop/desktop-panel-config.ts +149 -0
- package/src/desktop/desktop-session-manager.test.ts +730 -0
- package/src/desktop/desktop-session-manager.ts +850 -0
- package/src/desktop/desktop-stream-bridge.test.ts +395 -0
- package/src/desktop/desktop-stream-bridge.ts +214 -0
- package/src/desktop/desktop-wallpaper.test.ts +191 -0
- package/src/desktop/desktop-wallpaper.ts +113 -0
- package/src/desktop/desktop-window-drag.ts +177 -0
- package/src/desktop/desktop-window-manager-config.test.ts +230 -0
- package/src/desktop/desktop-window-manager-config.ts +238 -0
- package/src/desktop/desktop-window-theme.ts +170 -0
- package/src/heartbeat/heartbeat-service.ts +21 -3
- package/src/home/__tests__/feed-writer.test.ts +22 -0
- package/src/home/feed-writer.ts +11 -2
- package/src/hooks/types.ts +33 -0
- package/src/i18n/AGENTS.md +22 -0
- package/src/i18n/__tests__/i18n.test.ts +108 -0
- package/src/i18n/index.ts +16 -0
- package/src/i18n/locales.ts +93 -0
- package/src/i18n/messages.ts +61 -0
- package/src/i18n/title.ts +25 -0
- package/src/inbound/platform-callback-registration.ts +4 -5
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +121 -0
- package/src/live-voice/__tests__/live-voice-events.test.ts +8 -7
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +0 -3
- package/src/live-voice/__tests__/live-voice-progress.test.ts +94 -15
- package/src/live-voice/__tests__/live-voice-sight-frame-echo.test.ts +238 -0
- package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
- package/src/live-voice/__tests__/protocol.test.ts +39 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +13 -69
- package/src/live-voice/__tests__/session-controls.test.ts +79 -0
- package/src/live-voice/live-voice-photo.ts +25 -6
- package/src/live-voice/live-voice-session.ts +297 -699
- package/src/live-voice/protocol.ts +60 -2
- package/src/live-voice/session-controls.ts +111 -0
- package/src/mcp/__tests__/effective-config.test.ts +2 -2
- package/src/mcp/__tests__/workspace-mcp-config.test.ts +135 -0
- package/src/mcp/effective-config.ts +3 -3
- package/src/mcp/mcp-header-store.ts +29 -45
- package/src/mcp/spec-schema.ts +111 -0
- package/src/mcp/startup.ts +8 -4
- package/src/mcp/workspace-mcp-config.ts +188 -0
- package/src/messaging/provider.ts +10 -3
- package/src/messaging/providers/__tests__/proactive-address.test.ts +95 -0
- package/src/messaging/providers/callback-routing.ts +18 -0
- package/src/messaging/providers/channel-transport.ts +56 -0
- package/src/messaging/providers/discord/transport.ts +17 -0
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +6 -17
- package/src/messaging/providers/slack/adapter.ts +7 -44
- package/src/messaging/providers/slack/transport.ts +16 -0
- package/src/messaging/providers/telegram-bot/adapter.ts +1 -48
- package/src/messaging/providers/telegram-bot/client.ts +0 -26
- package/src/messaging/providers/telegram-bot/transport.ts +20 -0
- package/src/messaging/providers/whatsapp/adapter.ts +1 -48
- package/src/messaging/providers/whatsapp/transport.ts +18 -0
- package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +8 -0
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +55 -0
- package/src/notifications/__tests__/guardian-feed-projection.test.ts +158 -2
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +153 -3
- package/src/notifications/__tests__/schedule-result-producer.test.ts +99 -3
- package/src/notifications/adapters/macos.ts +3 -0
- package/src/notifications/assistant-reply-producer.ts +8 -3
- package/src/notifications/conversation-pairing.ts +36 -16
- package/src/notifications/delivered-post-record.ts +11 -1
- package/src/notifications/guardian-feed-projection.ts +125 -5
- package/src/notifications/home-feed-side-effect.ts +55 -7
- package/src/notifications/schedule-result-producer.ts +66 -22
- package/src/oauth/AGENTS.md +2 -0
- package/src/oauth/__tests__/seed-providers-managed.test.ts +149 -0
- package/src/oauth/byo-connection.test.ts +105 -0
- package/src/oauth/byo-connection.ts +36 -6
- package/src/oauth/connection-resolver.test.ts +100 -0
- package/src/oauth/connection-resolver.ts +120 -3
- package/src/oauth/provider-serializer.ts +9 -0
- package/src/oauth/scope-utils.ts +24 -0
- package/src/oauth/seed-providers.ts +314 -27
- package/src/outbound-proxy/certs.ts +3 -5
- package/src/permissions/checker.test.ts +11 -6
- package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
- package/src/persistence/conversation-crud.ts +71 -63
- package/src/persistence/conversation-lineage.ts +12 -4
- package/src/persistence/conversation-queries.ts +2 -2
- package/src/persistence/conversation-title-placeholders.ts +23 -0
- package/src/persistence/conversation-title-service.ts +9 -26
- package/src/persistence/embeddings/qdrant-manager.ts +163 -18
- package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
- package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
- package/src/persistence/message-cursor.ts +78 -0
- package/src/persistence/message-reads.ts +30 -0
- package/src/persistence/migrations/157-invite-contact-id.ts +18 -6
- package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +149 -0
- package/src/persistence/schema/memory-core.ts +5 -0
- package/src/platform/client.test.ts +4 -2
- package/src/platform/client.ts +2 -10
- package/src/plugin-api/constants.ts +2 -0
- package/src/plugin-api/index.ts +1 -0
- package/src/plugin-api/types.ts +2 -0
- package/src/plugins/defaults/index.ts +2 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +46 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +118 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +83 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +9 -5
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +20 -10
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +5 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +219 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +31 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +63 -0
- package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +4 -0
- package/src/plugins/defaults/memory/context-search/agent-runner.ts +3 -2
- package/src/plugins/defaults/memory/context-search/format.ts +3 -2
- package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +6 -3
- package/src/plugins/defaults/memory/context-search/sources/workspace.ts +3 -2
- package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -7
- package/src/plugins/defaults/memory/hooks/init.ts +10 -0
- package/src/plugins/defaults/memory/hooks/message-deleted.ts +21 -0
- package/src/plugins/defaults/memory/hooks/shutdown.ts +2 -0
- package/src/plugins/defaults/memory/host-utils.ts +10 -0
- package/src/plugins/defaults/memory/jobs-worker.ts +13 -0
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +34 -60
- package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +126 -0
- package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +79 -0
- package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +28 -0
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +3 -5
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +12 -3
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +1 -1
- package/src/plugins/defaults/memory/memory-retrospective-state.ts +312 -71
- package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +2 -1
- package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +5 -3
- package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +9 -0
- package/src/plugins/defaults/memory/startup.ts +28 -2
- package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +7 -9
- package/src/plugins/defaults/memory/substrate/page-index.ts +6 -1
- package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
- package/src/plugins/defaults/memory/v1/graph/consolidation.ts +4 -2
- package/src/plugins/defaults/memory/v1/graph/extraction.ts +4 -2
- package/src/plugins/defaults/memory/v1/graph/retriever.ts +4 -1
- package/src/plugins/defaults/memory/v2/reranker.ts +6 -1
- package/src/plugins/defaults/memory/v3/__tests__/card.test.ts +24 -0
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +125 -0
- package/src/plugins/defaults/memory/v3/__tests__/sections.test.ts +26 -0
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +30 -0
- package/src/plugins/defaults/memory/v3/card.ts +3 -2
- package/src/plugins/defaults/memory/v3/pool-select.ts +5 -3
- package/src/plugins/defaults/memory/v3/sections.ts +9 -3
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +5 -2
- package/src/plugins/defaults/memory/worker.ts +6 -0
- package/src/plugins/mcp-servers.ts +15 -75
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
- package/src/providers/__tests__/retry-callsite.test.ts +41 -0
- package/src/providers/__tests__/retry-outbound-sanitize.test.ts +176 -0
- package/src/providers/anthropic/client.ts +0 -47
- package/src/providers/gemini/client.ts +9 -23
- package/src/providers/gemini-thought-signature.test.ts +63 -0
- package/src/providers/gemini-thought-signature.ts +44 -0
- package/src/providers/inference/__tests__/endpoint-probe.test.ts +42 -3
- package/src/providers/inference/auth.ts +2 -3
- package/src/providers/inference/connection-availability.ts +27 -8
- package/src/providers/inference/endpoint-probe.ts +10 -1
- package/src/providers/inference/resolve-auth.ts +22 -4
- package/src/providers/inference/service-account-token.ts +248 -0
- package/src/providers/model-catalog.ts +34 -0
- package/src/providers/model-intents.ts +10 -5
- package/src/providers/openai/__tests__/chat-completions-output-token-limit.test.ts +141 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +146 -18
- package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +613 -0
- package/src/providers/openai/__tests__/google-thought-signature.test.ts +235 -0
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +83 -1
- package/src/providers/openai/chat-completions-provider.ts +212 -79
- package/src/providers/openai/codex-models.ts +0 -4
- package/src/providers/openai/google-thought-signature.ts +320 -0
- package/src/providers/opencode/client.test.ts +73 -4
- package/src/providers/opencode/client.ts +60 -3
- package/src/providers/openrouter/client.ts +20 -0
- package/src/providers/outbound-request-sanitize.ts +96 -0
- package/src/providers/retry.ts +30 -19
- package/src/providers/unparseable-tool-args.ts +5 -1
- package/src/runtime/AGENTS.md +3 -1
- package/src/runtime/__tests__/channel-send.test.ts +443 -0
- package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +89 -0
- package/src/runtime/__tests__/host-observe.test.ts +40 -1
- package/src/runtime/__tests__/live-voice-upgrade.test.ts +58 -0
- package/src/runtime/__tests__/runtime-ws-test-utils.ts +72 -0
- package/src/runtime/__tests__/watch-stream-upgrade.test.ts +59 -0
- package/src/runtime/agent-wake.ts +2 -1
- package/src/runtime/assistant-event-hub.ts +21 -3
- package/src/runtime/auth/same-actor.ts +38 -3
- package/src/runtime/channel-send.ts +316 -0
- package/src/runtime/host-observe.ts +11 -1
- package/src/runtime/http-server.ts +160 -151
- package/src/runtime/routes/__tests__/acp-claude-auth-routes.test.ts +16 -5
- package/src/runtime/routes/__tests__/acp-routes.test.ts +159 -4
- package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +275 -0
- package/src/runtime/routes/__tests__/channel-send-routes.test.ts +127 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +108 -1
- package/src/runtime/routes/__tests__/default-provider-routes.test.ts +2 -2
- package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +107 -0
- package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +16 -12
- package/src/runtime/routes/acp-claude-auth-routes.ts +11 -3
- package/src/runtime/routes/acp-routes.test.ts +15 -0
- package/src/runtime/routes/acp-routes.ts +72 -9
- package/src/runtime/routes/app-management-routes.ts +90 -2
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/channel-send-routes.ts +85 -0
- package/src/runtime/routes/conversation-list-routes.ts +14 -3
- package/src/runtime/routes/conversation-query-routes.ts +40 -0
- package/src/runtime/routes/conversation-routes.ts +16 -3
- package/src/runtime/routes/credential-routes.ts +20 -14
- package/src/runtime/routes/desktop-setup-routes.test.ts +74 -0
- package/src/runtime/routes/desktop-setup-routes.ts +35 -0
- package/src/runtime/routes/diagnostics-routes.ts +61 -4
- package/src/runtime/routes/events-routes.ts +4 -0
- package/src/runtime/routes/host-cu-routes.ts +6 -0
- package/src/runtime/routes/index.ts +4 -2
- package/src/runtime/routes/log-export-routes.ts +2 -0
- package/src/runtime/routes/mcp-auth-routes.ts +39 -47
- package/src/runtime/routes/migration-routes.ts +6 -20
- package/src/runtime/routes/oauth-commands-routes.ts +50 -0
- package/src/runtime/routes/oauth-providers.ts +7 -0
- package/src/runtime/routes/platform-routes.ts +18 -15
- package/src/runtime/routes/workspace-routes.test.ts +55 -26
- package/src/runtime/routes/workspace-routes.ts +46 -63
- package/src/runtime/routes/workspace-tree-walk.test.ts +244 -0
- package/src/runtime/routes/workspace-tree-walk.ts +240 -0
- package/src/runtime/routes/workspace-utils.ts +17 -0
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +28 -0
- package/src/runtime/services/conversation-serializer.ts +16 -3
- package/src/runtime/sync/resource-sync-events.ts +2 -1
- package/src/schedule/run-script.ts +2 -1
- package/src/schedule/schedule-store.ts +9 -2
- package/src/schedule/worker.ts +1 -1
- package/src/security/__tests__/ces-http-record-backend.test.ts +137 -0
- package/src/security/ces-http-record-backend.ts +120 -0
- package/src/security/ces-rpc-record-backend.ts +7 -0
- package/src/security/untrusted-content.ts +3 -1
- package/src/skills/__tests__/workspace-skill-md-signature.test.ts +60 -0
- package/src/skills/workspace-skill-md-signature.ts +50 -0
- package/src/subagent/consult-context.ts +12 -25
- package/src/tools/__tests__/side-effect-abort-guard.test.ts +1 -0
- package/src/tools/acp/list-agents.test.ts +3 -1
- package/src/tools/acp/spawn.test.ts +146 -11
- package/src/tools/acp/spawn.ts +21 -3
- package/src/tools/acp/status.test.ts +94 -0
- package/src/tools/acp/status.ts +40 -3
- package/src/tools/app-control/skill-proxy-bridge.ts +2 -1
- package/src/tools/browser/browser-execution.ts +1 -1
- package/src/tools/browser/cdp-client/accessibility-snapshot.ts +9 -3
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +2 -1
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +3 -2
- package/src/tools/browser/network-recorder.ts +2 -1
- package/src/tools/capability-offer.test.ts +22 -2
- package/src/tools/capability-offer.ts +16 -1
- package/src/tools/computer-use/definitions.ts +121 -2
- package/src/tools/computer-use/skill-proxy-bridge.ts +2 -1
- package/src/tools/credentials/metadata-store.ts +100 -0
- package/src/tools/filesystem/search.ts +2 -1
- package/src/tools/host-filesystem/edit.test.ts +2 -1
- package/src/tools/host-filesystem/edit.ts +2 -2
- package/src/tools/host-filesystem/read.test.ts +2 -1
- package/src/tools/host-filesystem/read.ts +2 -2
- package/src/tools/host-filesystem/transfer.test.ts +2 -1
- package/src/tools/host-filesystem/transfer.ts +2 -2
- package/src/tools/host-filesystem/write.test.ts +2 -1
- package/src/tools/host-filesystem/write.ts +2 -2
- package/src/tools/host-terminal/host-shell.test.ts +16 -0
- package/src/tools/host-terminal/host-shell.ts +4 -20
- package/src/tools/network/web-search.ts +6 -1
- package/src/tools/policy-context.ts +6 -7
- package/src/tools/skills/scaffold-managed.ts +61 -3
- package/src/tools/subagent/spawn.ts +5 -8
- package/src/tools/terminal/__tests__/sanitized-bash.test.ts +57 -0
- package/src/tools/terminal/sanitized-bash.ts +105 -0
- package/src/tools/ui-surface/channel-variants.ts +10 -59
- package/src/tools/watch/watch-retro-report.ts +0 -8
- package/src/types/host-capabilities.ts +5 -3
- package/src/util/__tests__/language-subtag.test.ts +23 -1
- package/src/util/ca-bundle.ts +13 -0
- package/src/util/language-subtag.ts +16 -0
- package/src/util/platform.ts +8 -0
- package/src/util/unicode.ts +15 -1
- package/src/watch/watch-retro.ts +6 -8
- package/src/watch/watch-timeline.ts +2 -2
- package/src/workflows/run-manager.ts +2 -1
- package/src/workspace/git-porcelain.ts +66 -0
- package/src/workspace/git-service.ts +6 -55
- package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +258 -0
- package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +78 -0
- package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +214 -0
- package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +102 -0
- package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +199 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/__tests__/app-source-watcher.test.ts +0 -218
- package/src/__tests__/config-watcher-skill-reseed.test.ts +0 -359
- package/src/__tests__/speaker-identification.test.ts +0 -56
- package/src/calls/speaker-identification.ts +0 -233
- package/src/daemon/app-source-watcher.ts +0 -218
- package/src/messaging/providers/whatsapp/client.ts +0 -29
- package/src/runtime/routes/debug-bash-routes.ts +0 -173
- package/src/util/fs-watcher-error.ts +0 -36
- /package/src/{live-voice → calls}/progress-phrases.ts +0 -0
|
@@ -32,6 +32,12 @@ import {
|
|
|
32
32
|
} from "../daemon/daemon-readiness.js";
|
|
33
33
|
import { processMessage } from "../daemon/process-message.js";
|
|
34
34
|
import { makeAddrInUseError } from "../daemon/startup-error.js";
|
|
35
|
+
import { isAssistantDesktopEnabled } from "../desktop/desktop-feature.js";
|
|
36
|
+
import {
|
|
37
|
+
DESKTOP_CLOSE,
|
|
38
|
+
destroyDesktopSessionManager,
|
|
39
|
+
} from "../desktop/desktop-session-manager.js";
|
|
40
|
+
import { DesktopStreamBridge } from "../desktop/desktop-stream-bridge.js";
|
|
35
41
|
import {
|
|
36
42
|
createLiveVoiceConnection,
|
|
37
43
|
type LiveVoiceConnection,
|
|
@@ -229,6 +235,32 @@ interface WatchStreamWebSocketData {
|
|
|
229
235
|
session?: WatchStreamSession;
|
|
230
236
|
}
|
|
231
237
|
|
|
238
|
+
/**
|
|
239
|
+
* WebSocket data for `/v1/desktop/stream`: raw RFB bytes to the assistant
|
|
240
|
+
* desktop.
|
|
241
|
+
*/
|
|
242
|
+
interface DesktopStreamWebSocketData {
|
|
243
|
+
wsType: "desktop-stream";
|
|
244
|
+
/** Bound at open time so message/close handlers reach this socket's pump. */
|
|
245
|
+
bridge?: DesktopStreamBridge;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
type AllWebSocketData =
|
|
249
|
+
| MediaStreamWebSocketData
|
|
250
|
+
| SttStreamWebSocketData
|
|
251
|
+
| LiveVoiceWebSocketData
|
|
252
|
+
| WatchStreamWebSocketData
|
|
253
|
+
| DesktopStreamWebSocketData;
|
|
254
|
+
|
|
255
|
+
function assistantDesktopEnabled(): boolean {
|
|
256
|
+
try {
|
|
257
|
+
return isAssistantDesktopEnabled(getConfig());
|
|
258
|
+
} catch (err) {
|
|
259
|
+
log.warn({ err }, "Failed to read config for desktop stream gate");
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
232
264
|
export class RuntimeHttpServer {
|
|
233
265
|
private server: ReturnType<typeof Bun.serve> | null = null;
|
|
234
266
|
private port: number;
|
|
@@ -264,11 +296,6 @@ export class RuntimeHttpServer {
|
|
|
264
296
|
}
|
|
265
297
|
|
|
266
298
|
async start(): Promise<void> {
|
|
267
|
-
type AllWebSocketData =
|
|
268
|
-
| MediaStreamWebSocketData
|
|
269
|
-
| SttStreamWebSocketData
|
|
270
|
-
| LiveVoiceWebSocketData
|
|
271
|
-
| WatchStreamWebSocketData;
|
|
272
299
|
this.server = Bun.serve<AllWebSocketData>({
|
|
273
300
|
port: this.port,
|
|
274
301
|
hostname: this.hostname,
|
|
@@ -424,6 +451,22 @@ export class RuntimeHttpServer {
|
|
|
424
451
|
void session.start();
|
|
425
452
|
return;
|
|
426
453
|
}
|
|
454
|
+
if (data.wsType === "desktop-stream") {
|
|
455
|
+
log.info("Desktop stream WebSocket opened");
|
|
456
|
+
if (!assistantDesktopEnabled()) {
|
|
457
|
+
ws.close(
|
|
458
|
+
DESKTOP_CLOSE.unavailable,
|
|
459
|
+
"Desktop is not available on this assistant",
|
|
460
|
+
);
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
const bridge = new DesktopStreamBridge(ws, {
|
|
464
|
+
isEnabled: assistantDesktopEnabled,
|
|
465
|
+
});
|
|
466
|
+
data.bridge = bridge;
|
|
467
|
+
void bridge.start();
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
427
470
|
log.warn("WebSocket opened with unknown data type — closing");
|
|
428
471
|
ws.close(1008, "Unknown WebSocket type");
|
|
429
472
|
},
|
|
@@ -474,6 +517,10 @@ export class RuntimeHttpServer {
|
|
|
474
517
|
}
|
|
475
518
|
return;
|
|
476
519
|
}
|
|
520
|
+
if (data.wsType === "desktop-stream") {
|
|
521
|
+
data.bridge?.handleClientFrame(message);
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
477
524
|
log.warn("WebSocket message on unknown data type — closing");
|
|
478
525
|
ws.close(1008, "Unknown WebSocket type");
|
|
479
526
|
},
|
|
@@ -567,6 +614,14 @@ export class RuntimeHttpServer {
|
|
|
567
614
|
}
|
|
568
615
|
return;
|
|
569
616
|
}
|
|
617
|
+
if (data.wsType === "desktop-stream") {
|
|
618
|
+
log.info(
|
|
619
|
+
{ code, reason: reason?.toString() },
|
|
620
|
+
"Desktop stream WebSocket closed",
|
|
621
|
+
);
|
|
622
|
+
data.bridge?.handleClose();
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
570
625
|
log.warn(
|
|
571
626
|
{ code, reason: reason?.toString() },
|
|
572
627
|
"WebSocket with unknown data type closed",
|
|
@@ -707,6 +762,9 @@ export class RuntimeHttpServer {
|
|
|
707
762
|
// that a socket closing just before shutdown had already under way.
|
|
708
763
|
await drainWatchRetros();
|
|
709
764
|
|
|
765
|
+
// Bounded by the manager's kill grace, so shutdown never hangs on X.
|
|
766
|
+
await destroyDesktopSessionManager();
|
|
767
|
+
|
|
710
768
|
const liveVoiceManager = getLiveVoiceSessionManager();
|
|
711
769
|
const liveVoiceSessionId = liveVoiceManager.activeSessionId;
|
|
712
770
|
if (liveVoiceSessionId) {
|
|
@@ -810,6 +868,15 @@ export class RuntimeHttpServer {
|
|
|
810
868
|
return this.handleWatchStreamUpgrade(req, server);
|
|
811
869
|
}
|
|
812
870
|
|
|
871
|
+
// WebSocket upgrade for the assistant desktop RFB stream, under the same
|
|
872
|
+
// private-network restrictions and gateway-service token verification.
|
|
873
|
+
if (
|
|
874
|
+
path === "/v1/desktop/stream" &&
|
|
875
|
+
req.headers.get("upgrade")?.toLowerCase() === "websocket"
|
|
876
|
+
) {
|
|
877
|
+
return this.handleDesktopStreamUpgrade(req, server);
|
|
878
|
+
}
|
|
879
|
+
|
|
813
880
|
// Twilio webhook endpoints — before auth check because Twilio
|
|
814
881
|
// webhook POSTs don't include bearer tokens.
|
|
815
882
|
const twilioResponse = await this.handleTwilioWebhook(req, path);
|
|
@@ -949,199 +1016,141 @@ export class RuntimeHttpServer {
|
|
|
949
1016
|
return null;
|
|
950
1017
|
}
|
|
951
1018
|
|
|
952
|
-
|
|
1019
|
+
/**
|
|
1020
|
+
* Shared path for gateway-proxied WebSocket upgrades: private network peers
|
|
1021
|
+
* and origins only, then a gateway service token, then `parse` builds the
|
|
1022
|
+
* socket data (or a 4xx Response) and the upgrade happens. The gateway owns
|
|
1023
|
+
* downstream client auth and dials these upstreams on the client's behalf.
|
|
1024
|
+
* Returns a Response on failure. On success Bun has consumed the request and
|
|
1025
|
+
* nothing is returned; the type is `Response` only to fit the router.
|
|
1026
|
+
*/
|
|
1027
|
+
private upgradeRuntimeStream(
|
|
953
1028
|
req: Request,
|
|
954
1029
|
server: ReturnType<typeof Bun.serve>,
|
|
1030
|
+
label: string,
|
|
1031
|
+
parse: (query: URLSearchParams) => AllWebSocketData | Response,
|
|
955
1032
|
): Response {
|
|
956
1033
|
if (!isPrivateNetworkPeer(server, req) || !isPrivateNetworkOrigin(req)) {
|
|
957
1034
|
return httpError(
|
|
958
1035
|
"FORBIDDEN",
|
|
959
|
-
|
|
1036
|
+
`Direct ${label} access disabled: only private network peers allowed`,
|
|
960
1037
|
403,
|
|
961
1038
|
);
|
|
962
1039
|
}
|
|
963
|
-
|
|
964
|
-
// Verify the gateway service token before accepting the upgrade.
|
|
965
1040
|
const tokenError = this.verifyGatewayServiceToken(req);
|
|
966
1041
|
if (tokenError) {
|
|
967
1042
|
return tokenError;
|
|
968
1043
|
}
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
if (!callSessionId) {
|
|
973
|
-
return new Response("Missing callSessionId", { status: 400 });
|
|
1044
|
+
const data = parse(new URL(req.url).searchParams);
|
|
1045
|
+
if (data instanceof Response) {
|
|
1046
|
+
return data;
|
|
974
1047
|
}
|
|
975
|
-
|
|
976
|
-
// handlers route them to MediaStreamCallSession.
|
|
977
|
-
const upgraded = server.upgrade(req, {
|
|
978
|
-
data: {
|
|
979
|
-
wsType: "media-stream",
|
|
980
|
-
callSessionId,
|
|
981
|
-
} satisfies MediaStreamWebSocketData,
|
|
982
|
-
});
|
|
983
|
-
if (!upgraded) {
|
|
1048
|
+
if (!server.upgrade(req, { data })) {
|
|
984
1049
|
return new Response("WebSocket upgrade failed", { status: 500 });
|
|
985
1050
|
}
|
|
986
|
-
// Bun's WebSocket upgrade consumes the request — no Response is sent.
|
|
987
1051
|
return undefined!;
|
|
988
1052
|
}
|
|
989
1053
|
|
|
990
|
-
|
|
991
|
-
* Handle WebSocket upgrade for `/v1/stt/stream`.
|
|
992
|
-
*
|
|
993
|
-
* Private-network restrictions apply (same as media-stream) so the
|
|
994
|
-
* runtime remains unreachable from the public internet. The gateway
|
|
995
|
-
* authenticates the downstream client and proxies the upgrade with a
|
|
996
|
-
* short-lived gateway service token.
|
|
997
|
-
*/
|
|
998
|
-
private handleSttStreamUpgrade(
|
|
1054
|
+
private handleMediaStreamUpgrade(
|
|
999
1055
|
req: Request,
|
|
1000
1056
|
server: ReturnType<typeof Bun.serve>,
|
|
1001
1057
|
): Response {
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1016
|
-
const wsUrl = new URL(req.url);
|
|
1017
|
-
// provider is optional compatibility metadata — the runtime resolves
|
|
1018
|
-
// the streaming transcriber from config (`services.stt.provider`).
|
|
1019
|
-
const provider = wsUrl.searchParams.get("provider") ?? undefined;
|
|
1020
|
-
const mimeType = wsUrl.searchParams.get("mimeType");
|
|
1021
|
-
if (!mimeType) {
|
|
1022
|
-
return new Response("Missing required query parameter: mimeType", {
|
|
1023
|
-
status: 400,
|
|
1024
|
-
});
|
|
1025
|
-
}
|
|
1026
|
-
|
|
1027
|
-
const sampleRateRaw = wsUrl.searchParams.get("sampleRate");
|
|
1028
|
-
const sampleRate = sampleRateRaw ? parseInt(sampleRateRaw, 10) : undefined;
|
|
1058
|
+
return this.upgradeRuntimeStream(req, server, "media-stream", (query) => {
|
|
1059
|
+
const callSessionId = query.get("callSessionId");
|
|
1060
|
+
if (!callSessionId) {
|
|
1061
|
+
return new Response("Missing callSessionId", { status: 400 });
|
|
1062
|
+
}
|
|
1063
|
+
// A distinct wsType routes these to MediaStreamCallSession.
|
|
1064
|
+
return {
|
|
1065
|
+
wsType: "media-stream",
|
|
1066
|
+
callSessionId,
|
|
1067
|
+
} satisfies MediaStreamWebSocketData;
|
|
1068
|
+
});
|
|
1069
|
+
}
|
|
1029
1070
|
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1071
|
+
/** Handle WebSocket upgrade for `/v1/stt/stream`. */
|
|
1072
|
+
private handleSttStreamUpgrade(
|
|
1073
|
+
req: Request,
|
|
1074
|
+
server: ReturnType<typeof Bun.serve>,
|
|
1075
|
+
): Response {
|
|
1076
|
+
return this.upgradeRuntimeStream(req, server, "STT stream", (query) => {
|
|
1077
|
+
// provider is optional compatibility metadata; the runtime resolves
|
|
1078
|
+
// the streaming transcriber from config (`services.stt.provider`).
|
|
1079
|
+
const provider = query.get("provider") ?? undefined;
|
|
1080
|
+
const mimeType = query.get("mimeType");
|
|
1081
|
+
if (!mimeType) {
|
|
1082
|
+
return new Response("Missing required query parameter: mimeType", {
|
|
1083
|
+
status: 400,
|
|
1084
|
+
});
|
|
1085
|
+
}
|
|
1086
|
+
const sampleRateRaw = query.get("sampleRate");
|
|
1087
|
+
return {
|
|
1033
1088
|
wsType: "stt-stream",
|
|
1034
1089
|
provider,
|
|
1035
1090
|
mimeType,
|
|
1036
|
-
sampleRate,
|
|
1037
|
-
sessionId,
|
|
1038
|
-
} satisfies SttStreamWebSocketData
|
|
1091
|
+
sampleRate: sampleRateRaw ? parseInt(sampleRateRaw, 10) : undefined,
|
|
1092
|
+
sessionId: crypto.randomUUID(),
|
|
1093
|
+
} satisfies SttStreamWebSocketData;
|
|
1039
1094
|
});
|
|
1040
|
-
if (!upgraded) {
|
|
1041
|
-
return new Response("WebSocket upgrade failed", { status: 500 });
|
|
1042
|
-
}
|
|
1043
|
-
// Bun's WebSocket upgrade consumes the request — no Response is sent.
|
|
1044
|
-
return undefined!;
|
|
1045
1095
|
}
|
|
1046
1096
|
|
|
1047
|
-
/**
|
|
1048
|
-
* Handle WebSocket upgrade for `/v1/live-voice`.
|
|
1049
|
-
*
|
|
1050
|
-
* The gateway owns downstream client auth and forwards this upstream with
|
|
1051
|
-
* a short-lived gateway service token. The runtime accepts only private
|
|
1052
|
-
* network peers/origins so the shell is not publicly reachable.
|
|
1053
|
-
*/
|
|
1097
|
+
/** Handle WebSocket upgrade for `/v1/live-voice`. */
|
|
1054
1098
|
private handleLiveVoiceUpgrade(
|
|
1055
1099
|
req: Request,
|
|
1056
1100
|
server: ReturnType<typeof Bun.serve>,
|
|
1057
1101
|
): Response {
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
"Direct live voice access disabled — only private network peers allowed",
|
|
1062
|
-
403,
|
|
1063
|
-
);
|
|
1064
|
-
}
|
|
1065
|
-
|
|
1066
|
-
const tokenError = this.verifyGatewayServiceToken(req);
|
|
1067
|
-
if (tokenError) {
|
|
1068
|
-
return tokenError;
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
const guardianPrincipalId =
|
|
1072
|
-
new URL(req.url).searchParams.get("guardianPrincipalId")?.trim() ||
|
|
1073
|
-
undefined;
|
|
1074
|
-
|
|
1075
|
-
const upgraded = server.upgrade(req, {
|
|
1076
|
-
data: {
|
|
1102
|
+
return this.upgradeRuntimeStream(req, server, "live voice", (query) => {
|
|
1103
|
+
const guardianPrincipalId = query.get("guardianPrincipalId")?.trim();
|
|
1104
|
+
return {
|
|
1077
1105
|
wsType: "live-voice",
|
|
1078
1106
|
...(guardianPrincipalId ? { guardianPrincipalId } : {}),
|
|
1079
|
-
} satisfies LiveVoiceWebSocketData
|
|
1107
|
+
} satisfies LiveVoiceWebSocketData;
|
|
1080
1108
|
});
|
|
1081
|
-
if (!upgraded) {
|
|
1082
|
-
return new Response("WebSocket upgrade failed", { status: 500 });
|
|
1083
|
-
}
|
|
1084
|
-
return undefined!;
|
|
1085
1109
|
}
|
|
1086
1110
|
|
|
1087
|
-
/**
|
|
1088
|
-
* Handle WebSocket upgrade for `/v1/watch/stream`.
|
|
1089
|
-
*
|
|
1090
|
-
* Gated exactly as `/v1/stt/stream` is: private network peers and origins
|
|
1091
|
-
* only, then a gateway service token. The gateway owns downstream client
|
|
1092
|
-
* auth and dials this upstream on the client's behalf.
|
|
1093
|
-
*/
|
|
1111
|
+
/** Handle WebSocket upgrade for `/v1/watch/stream`. */
|
|
1094
1112
|
private handleWatchStreamUpgrade(
|
|
1095
1113
|
req: Request,
|
|
1096
1114
|
server: ReturnType<typeof Bun.serve>,
|
|
1097
1115
|
): Response {
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
"
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
const wsUrl = new URL(req.url);
|
|
1112
|
-
const mimeType = wsUrl.searchParams.get("mimeType");
|
|
1113
|
-
if (!mimeType) {
|
|
1114
|
-
return new Response("Missing required query parameter: mimeType", {
|
|
1115
|
-
status: 400,
|
|
1116
|
-
});
|
|
1117
|
-
}
|
|
1118
|
-
|
|
1119
|
-
const sampleRateRaw = wsUrl.searchParams.get("sampleRate");
|
|
1120
|
-
const sampleRate = sampleRateRaw ? parseInt(sampleRateRaw, 10) : undefined;
|
|
1121
|
-
const conversationId =
|
|
1122
|
-
wsUrl.searchParams.get("conversationId")?.trim() || undefined;
|
|
1123
|
-
const clientId = wsUrl.searchParams.get("clientId")?.trim() || undefined;
|
|
1124
|
-
const parsedTarget = parseWatchCaptureTarget(wsUrl.searchParams);
|
|
1125
|
-
if ("error" in parsedTarget) {
|
|
1126
|
-
return new Response(parsedTarget.error, { status: 400 });
|
|
1127
|
-
}
|
|
1128
|
-
|
|
1129
|
-
const upgraded = server.upgrade(req, {
|
|
1130
|
-
data: {
|
|
1116
|
+
return this.upgradeRuntimeStream(req, server, "watch stream", (query) => {
|
|
1117
|
+
const mimeType = query.get("mimeType");
|
|
1118
|
+
if (!mimeType) {
|
|
1119
|
+
return new Response("Missing required query parameter: mimeType", {
|
|
1120
|
+
status: 400,
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
1123
|
+
const sampleRateRaw = query.get("sampleRate");
|
|
1124
|
+
const parsedTarget = parseWatchCaptureTarget(query);
|
|
1125
|
+
if ("error" in parsedTarget) {
|
|
1126
|
+
return new Response(parsedTarget.error, { status: 400 });
|
|
1127
|
+
}
|
|
1128
|
+
return {
|
|
1131
1129
|
wsType: "watch-stream",
|
|
1132
1130
|
mimeType,
|
|
1133
|
-
sampleRate,
|
|
1134
|
-
conversationId,
|
|
1135
|
-
clientId,
|
|
1131
|
+
sampleRate: sampleRateRaw ? parseInt(sampleRateRaw, 10) : undefined,
|
|
1132
|
+
conversationId: query.get("conversationId")?.trim() || undefined,
|
|
1133
|
+
clientId: query.get("clientId")?.trim() || undefined,
|
|
1136
1134
|
captureTarget: parsedTarget.captureTarget,
|
|
1137
1135
|
sessionId: crypto.randomUUID(),
|
|
1138
|
-
} satisfies WatchStreamWebSocketData
|
|
1136
|
+
} satisfies WatchStreamWebSocketData;
|
|
1139
1137
|
});
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
/**
|
|
1141
|
+
* Handle WebSocket upgrade for `/v1/desktop/stream`. The feature gate runs
|
|
1142
|
+
* in the open handler, as close code 4008.
|
|
1143
|
+
*/
|
|
1144
|
+
private handleDesktopStreamUpgrade(
|
|
1145
|
+
req: Request,
|
|
1146
|
+
server: ReturnType<typeof Bun.serve>,
|
|
1147
|
+
): Response {
|
|
1148
|
+
return this.upgradeRuntimeStream(
|
|
1149
|
+
req,
|
|
1150
|
+
server,
|
|
1151
|
+
"desktop stream",
|
|
1152
|
+
() => ({ wsType: "desktop-stream" }) satisfies DesktopStreamWebSocketData,
|
|
1153
|
+
);
|
|
1145
1154
|
}
|
|
1146
1155
|
|
|
1147
1156
|
private async handleTwilioWebhook(
|
|
@@ -48,7 +48,7 @@ mock.module("../../../security/oauth2.js", () => ({
|
|
|
48
48
|
|
|
49
49
|
const actualClaudeOauth = await import("../../../acp/acp-claude-oauth.js");
|
|
50
50
|
const { CLAUDE_MANUAL_REDIRECT_URI, CLAUDE_OAUTH_CONFIG } = actualClaudeOauth;
|
|
51
|
-
const storeAcpClaudeTokenMock = mock(async (
|
|
51
|
+
const storeAcpClaudeTokenMock = mock(async (_tokens: unknown) => {});
|
|
52
52
|
// The connect-status route reads token presence; mock it so the route test
|
|
53
53
|
// doesn't reach real secure storage.
|
|
54
54
|
const hasAcpClaudeTokenMock = mock(async () => false);
|
|
@@ -228,9 +228,12 @@ describe("loopback capture", () => {
|
|
|
228
228
|
const status = await waitForStatus(state, "connected");
|
|
229
229
|
expect(status).toEqual({ status: "connected" });
|
|
230
230
|
|
|
231
|
-
// Access token persisted via storeAcpClaudeToken.
|
|
232
231
|
expect(storeAcpClaudeTokenMock).toHaveBeenCalledTimes(1);
|
|
233
|
-
expect(storeAcpClaudeTokenMock).toHaveBeenCalledWith(
|
|
232
|
+
expect(storeAcpClaudeTokenMock).toHaveBeenCalledWith({
|
|
233
|
+
accessToken: "sk-ant-oat-access",
|
|
234
|
+
refreshToken: "refresh-xyz",
|
|
235
|
+
expiresIn: 3600,
|
|
236
|
+
});
|
|
234
237
|
});
|
|
235
238
|
|
|
236
239
|
test("flips status to error when the exchange fails", async () => {
|
|
@@ -339,7 +342,11 @@ describe("acp_claude_auth_exchange", () => {
|
|
|
339
342
|
expect(call[1]).toBe("auth-code-123");
|
|
340
343
|
expect(call[2]).toBe(CLAUDE_MANUAL_REDIRECT_URI);
|
|
341
344
|
expect(call[3]).toBeTruthy(); // PKCE verifier from the start call
|
|
342
|
-
expect(storeAcpClaudeTokenMock).toHaveBeenCalledWith(
|
|
345
|
+
expect(storeAcpClaudeTokenMock).toHaveBeenCalledWith({
|
|
346
|
+
accessToken: "sk-ant-oat-manual",
|
|
347
|
+
refreshToken: "refresh-manual",
|
|
348
|
+
expiresIn: 3600,
|
|
349
|
+
});
|
|
343
350
|
|
|
344
351
|
// The pending entry is consumed — a second exchange fails.
|
|
345
352
|
await expect(
|
|
@@ -360,7 +367,11 @@ describe("acp_claude_auth_exchange", () => {
|
|
|
360
367
|
string,
|
|
361
368
|
];
|
|
362
369
|
expect(call[1]).toBe("raw-code-xyz");
|
|
363
|
-
expect(storeAcpClaudeTokenMock).toHaveBeenCalledWith(
|
|
370
|
+
expect(storeAcpClaudeTokenMock).toHaveBeenCalledWith({
|
|
371
|
+
accessToken: "sk-ant-oat-manual",
|
|
372
|
+
refreshToken: "refresh-manual",
|
|
373
|
+
expiresIn: 3600,
|
|
374
|
+
});
|
|
364
375
|
});
|
|
365
376
|
|
|
366
377
|
test("malformed paste (no `#`, no state) is rejected", async () => {
|