@vellumai/assistant 0.12.1-dev.202609141913.5e16607 → 0.12.1-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 +0 -4
- package/ARCHITECTURE.md +12 -11
- package/docs/architecture/turn-actor.md +8 -15
- package/docs/guardian-request-flow.md +0 -16
- package/openapi.yaml +49 -291
- package/package.json +1 -1
- package/src/__tests__/always-loaded-tools-guard.test.ts +10 -18
- package/src/__tests__/app-compiler.test.ts +0 -6
- package/src/__tests__/app-control-tool-schemas.test.ts +2 -5
- package/src/__tests__/app-dir-path-guard.test.ts +3 -1
- package/src/__tests__/app-source-watcher.test.ts +218 -0
- package/src/{calls/__tests__ → __tests__}/call-controller.test.ts +82 -503
- package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +2 -5
- package/src/__tests__/computer-use-tools.test.ts +5 -17
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +29 -28
- package/src/__tests__/config-watcher-skill-reseed.test.ts +359 -0
- package/src/__tests__/config-watcher.test.ts +8 -23
- 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 +0 -26
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +10 -4
- package/src/__tests__/conversation-queue.test.ts +207 -48
- package/src/__tests__/conversation-retry-discard.test.ts +1 -54
- package/src/__tests__/conversation-skill-tools.test.ts +0 -27
- package/src/__tests__/conversation-surfaces-app-control.test.ts +3 -8
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -67
- package/src/__tests__/conversation-title-service.test.ts +10 -14
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +5 -3
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -51
- package/src/__tests__/credential-record-retire.test.ts +1 -171
- package/src/__tests__/credential-routes.test.ts +3 -212
- package/src/__tests__/credential-security-invariants.test.ts +2 -4
- package/src/__tests__/cu-unified-flow.test.ts +2 -8
- package/src/__tests__/document-sync-tags.test.ts +0 -25
- package/src/__tests__/drain-kick-guard.test.ts +2 -0
- package/src/__tests__/drain-requeue-on-contention.test.ts +6 -0
- package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
- package/src/__tests__/host-bash-proxy.test.ts +45 -26
- package/src/__tests__/host-browser-proxy.test.ts +17 -6
- package/src/__tests__/host-file-proxy-targeted.test.ts +0 -23
- package/src/__tests__/host-file-proxy.test.ts +23 -11
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +9 -30
- package/src/__tests__/llm-catalog-parity.test.ts +0 -25
- package/src/__tests__/mcp-auth-routes.test.ts +9 -6
- package/src/__tests__/mcp-config-secret-boundary.test.ts +136 -78
- package/src/__tests__/mcp-health-check.test.ts +11 -8
- package/src/__tests__/mcp-list-plugin-servers.test.ts +10 -8
- package/src/{calls/__tests__ → __tests__}/media-stream-audio-transcode.test.ts +1 -1
- package/src/{calls/__tests__ → __tests__}/media-stream-output.test.ts +8 -37
- package/src/{calls/__tests__ → __tests__}/media-stream-parser.test.ts +1 -1
- package/src/{calls/__tests__ → __tests__}/media-stream-server-integration.test.ts +57 -150
- package/src/{calls/__tests__ → __tests__}/media-stream-stt-session.test.ts +5 -5
- package/src/{calls/__tests__ → __tests__}/media-turn-detector.test.ts +1 -1
- package/src/__tests__/messages-after-tiebreaker.test.ts +0 -91
- package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
- package/src/__tests__/messaging-send-tool.test.ts +548 -355
- package/src/__tests__/model-intents.test.ts +0 -3
- package/src/__tests__/notification-vellum-adapter.test.ts +2 -85
- package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
- package/src/__tests__/platform-callback-registration.test.ts +16 -8
- package/src/__tests__/platform-client-verify-credential.test.ts +0 -2
- package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -13
- package/src/__tests__/script-proxy-certs.test.ts +0 -35
- package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/speaker-identification.test.ts +56 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +3 -19
- package/src/__tests__/subagent-tools.test.ts +2 -3
- package/src/__tests__/telephony-tts-guard.test.ts +3 -38
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +0 -4
- package/src/{calls/__tests__/voice-session-bridge-turn-flow.test.ts → __tests__/voice-session-bridge.test.ts} +12 -20
- package/src/__tests__/watch-retro-tool-availability.test.ts +17 -8
- package/src/__tests__/workspace-git-service.test.ts +0 -26
- package/src/acp/__tests__/agent-process.test.ts +4 -258
- package/src/acp/__tests__/auth-required.test.ts +0 -96
- package/src/acp/__tests__/client-handler.test.ts +2 -90
- package/src/acp/__tests__/session-manager-persistence.test.ts +1 -5
- package/src/acp/__tests__/session-manager-resume.test.ts +6 -270
- package/src/acp/__tests__/session-manager-usage.test.ts +2 -4
- package/src/acp/__tests__/session-manager.test.ts +4 -895
- package/src/acp/agent-process.test.ts +1 -4
- package/src/acp/agent-process.ts +9 -94
- package/src/acp/auth-required.ts +1 -50
- package/src/acp/auto-install.test.ts +7 -9
- package/src/acp/client-handler.ts +3 -16
- package/src/acp/resolve-agent.test.ts +6 -220
- package/src/acp/resolve-agent.ts +23 -88
- package/src/acp/session-manager.test.ts +3 -196
- package/src/acp/session-manager.ts +18 -441
- package/src/acp/types.ts +5 -50
- package/src/api/events/app-files-changed.ts +3 -4
- package/src/api/events/notification-intent.ts +0 -2
- package/src/api/index.ts +0 -6
- package/src/apps/app-store.ts +1 -1
- package/src/bundler/app-compiler.ts +0 -15
- package/src/calls/__tests__/voice-control-protocol.test.ts +25 -58
- package/src/calls/__tests__/voice-session-bridge.test.ts +1 -37
- package/src/calls/__tests__/voice-triage-escalate.test.ts +0 -105
- package/src/calls/call-constants.ts +4 -24
- package/src/calls/call-controller.ts +199 -499
- package/src/calls/call-transport.ts +0 -16
- package/src/calls/media-stream-output.ts +0 -32
- package/src/calls/media-stream-server.ts +30 -82
- package/src/calls/media-stream-stt-session.ts +0 -15
- package/src/calls/resolve-call-tts-provider.ts +2 -33
- package/src/calls/speaker-identification.ts +233 -0
- package/src/calls/tts-call-strategy.ts +5 -9
- package/src/calls/types.ts +0 -2
- package/src/calls/voice-control-protocol.ts +21 -53
- package/src/calls/voice-session-bridge.ts +46 -59
- package/src/calls/voice-triage-escalate.ts +56 -175
- package/src/cli/commands/apps.help.ts +13 -67
- package/src/cli/commands/apps.ts +0 -183
- package/src/cli/commands/bash.help.ts +13 -8
- package/src/cli/commands/bash.ts +25 -7
- package/src/cli/commands/channels/index.help.ts +2 -70
- package/src/cli/commands/channels/index.ts +3 -16
- package/src/cli/commands/credentials.help.ts +2 -6
- 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/roadmap.help.ts +1 -5
- package/src/cli/commands/roadmap.ts +1 -1
- package/src/cli/lib/bundled-marketplace.json +90 -103
- package/src/config/__tests__/default-profile-catalog.test.ts +0 -22
- package/src/config/__tests__/memory-retrospective-schema.test.ts +1 -15
- package/src/config/__tests__/platform-rehydration.test.ts +9 -99
- package/src/config/acp-defaults.test.ts +3 -13
- package/src/config/acp-defaults.ts +6 -23
- package/src/config/acp-schema.ts +2 -30
- package/src/config/bundled-skills/acp/SKILL.md +14 -22
- package/src/config/bundled-skills/acp/TOOLS.json +1 -5
- package/src/config/bundled-skills/app-builder/SKILL.md +9 -12
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -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 +139 -67
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
- package/src/config/bundled-skills/schedule/SKILL.md +4 -3
- package/src/config/bundled-skills/screen-annotation/SKILL.md +1 -8
- package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +1 -4
- package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
- package/src/config/default-profile-catalog.ts +1 -1
- package/src/config/env.ts +2 -2
- package/src/config/feature-flag-registry.json +12 -24
- package/src/config/loader.ts +0 -1
- package/src/config/memory-v3-gate.test.ts +0 -31
- package/src/config/memory-v3-gate.ts +16 -20
- package/src/config/platform-rehydration.ts +27 -11
- package/src/config/schema.ts +2 -2
- package/src/config/schemas/__tests__/live-voice.test.ts +158 -8
- package/src/config/schemas/calls.ts +28 -1
- package/src/config/schemas/live-voice.ts +173 -1
- package/src/config/schemas/mcp.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +0 -10
- package/src/config/schemas/services.ts +0 -8
- package/src/config/schemas/skills.ts +14 -0
- package/src/credential-execution/process-manager.test.ts +19 -18
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +121 -66
- package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +1 -4
- package/src/daemon/app-source-watcher.ts +218 -0
- package/src/daemon/config-watcher.ts +194 -13
- package/src/daemon/conversation-process.ts +64 -35
- package/src/daemon/conversation-skill-tools.ts +31 -13
- package/src/daemon/conversation-store.ts +1 -1
- package/src/daemon/conversation-surfaces.ts +8 -10
- package/src/daemon/conversation-tool-setup.ts +43 -37
- package/src/daemon/conversation.ts +3 -0
- package/src/daemon/host-bash-proxy.ts +12 -8
- package/src/daemon/host-browser-proxy.ts +1 -15
- package/src/daemon/host-file-proxy.ts +10 -8
- package/src/daemon/host-transfer-proxy.ts +18 -14
- package/src/daemon/lifecycle.ts +5 -0
- package/src/daemon/mcp-reload-service.ts +5 -5
- package/src/daemon/message-types/sync.ts +0 -1
- package/src/daemon/orphan-reaper.ts +1 -1
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/shutdown-handlers.ts +9 -1
- package/src/daemon/skill-memory-refresh.ts +0 -64
- package/src/daemon/tool-side-effects.ts +18 -7
- package/src/home/__tests__/feed-writer.test.ts +0 -22
- package/src/home/feed-writer.ts +2 -11
- package/src/hooks/types.ts +0 -33
- package/src/inbound/platform-callback-registration.ts +5 -4
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +3 -0
- package/src/live-voice/__tests__/live-voice-progress.test.ts +15 -15
- package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
- package/src/{calls → live-voice}/__tests__/progress-narration.test.ts +4 -4
- package/src/{calls → live-voice}/__tests__/progress-phrases.test.ts +1 -1
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +69 -13
- package/src/live-voice/live-voice-session.ts +693 -213
- package/src/{calls → live-voice}/progress-narration.ts +2 -2
- package/src/live-voice/protocol.ts +2 -0
- package/src/mcp/__tests__/effective-config.test.ts +2 -2
- package/src/mcp/effective-config.ts +3 -3
- package/src/mcp/mcp-header-store.ts +45 -29
- package/src/mcp/startup.ts +4 -8
- package/src/messaging/provider.ts +3 -10
- package/src/messaging/providers/callback-routing.ts +0 -18
- package/src/messaging/providers/channel-transport.ts +0 -56
- package/src/messaging/providers/discord/transport.ts +0 -17
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +17 -6
- package/src/messaging/providers/slack/adapter.ts +44 -7
- package/src/messaging/providers/slack/transport.ts +0 -16
- package/src/messaging/providers/telegram-bot/adapter.ts +48 -1
- package/src/messaging/providers/telegram-bot/client.ts +26 -0
- package/src/messaging/providers/telegram-bot/transport.ts +0 -20
- package/src/messaging/providers/whatsapp/adapter.ts +48 -1
- package/src/messaging/providers/whatsapp/client.ts +29 -0
- package/src/messaging/providers/whatsapp/transport.ts +0 -18
- package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +0 -8
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +0 -55
- package/src/notifications/__tests__/guardian-feed-projection.test.ts +2 -158
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +3 -153
- package/src/notifications/__tests__/schedule-result-producer.test.ts +3 -99
- package/src/notifications/adapters/macos.ts +0 -3
- package/src/notifications/assistant-reply-producer.ts +3 -8
- package/src/notifications/conversation-pairing.ts +16 -36
- package/src/notifications/delivered-post-record.ts +1 -11
- package/src/notifications/guardian-feed-projection.ts +5 -125
- package/src/notifications/home-feed-side-effect.ts +7 -55
- package/src/notifications/schedule-result-producer.ts +22 -66
- package/src/oauth/__tests__/seed-providers-managed.test.ts +0 -54
- package/src/oauth/byo-connection.test.ts +0 -45
- package/src/oauth/byo-connection.ts +6 -36
- package/src/oauth/connection-resolver.test.ts +0 -73
- package/src/oauth/connection-resolver.ts +2 -95
- package/src/oauth/seed-providers.ts +0 -165
- package/src/outbound-proxy/certs.ts +5 -3
- package/src/permissions/checker.test.ts +6 -11
- package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
- package/src/persistence/conversation-crud.ts +63 -71
- package/src/persistence/conversation-lineage.ts +4 -12
- package/src/persistence/conversation-title-service.ts +26 -9
- 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-reads.ts +0 -30
- package/src/persistence/migrations/157-invite-contact-id.ts +6 -18
- package/src/persistence/schema/memory-core.ts +0 -5
- package/src/platform/client.test.ts +2 -4
- package/src/platform/client.ts +10 -2
- package/src/plugin-api/constants.ts +0 -2
- package/src/plugin-api/index.ts +0 -1
- package/src/plugin-api/types.ts +0 -2
- package/src/plugins/defaults/index.ts +0 -2
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +0 -46
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +5 -9
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +10 -20
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +0 -219
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +0 -31
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +0 -63
- package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +0 -4
- package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -4
- package/src/plugins/defaults/memory/hooks/init.ts +0 -10
- package/src/plugins/defaults/memory/hooks/shutdown.ts +0 -2
- package/src/plugins/defaults/memory/jobs-worker.ts +0 -13
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +60 -34
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +5 -3
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +3 -12
- package/src/plugins/defaults/memory/memory-retrospective-state.ts +71 -312
- package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +1 -2
- package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +3 -5
- package/src/plugins/defaults/memory/startup.ts +1 -6
- package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +9 -7
- package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +0 -89
- package/src/plugins/defaults/memory/worker.ts +0 -6
- package/src/plugins/mcp-servers.ts +75 -15
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
- package/src/providers/gemini/client.ts +23 -9
- package/src/providers/inference/auth.ts +3 -2
- package/src/providers/inference/connection-availability.ts +8 -27
- package/src/providers/inference/resolve-auth.ts +4 -22
- package/src/providers/model-catalog.ts +0 -34
- package/src/providers/model-intents.ts +5 -10
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +18 -146
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +1 -83
- package/src/providers/openai/chat-completions-provider.ts +78 -192
- package/src/providers/openai/codex-models.ts +4 -0
- package/src/runtime/AGENTS.md +0 -2
- package/src/runtime/auth/same-actor.ts +3 -38
- package/src/runtime/http-server.ts +151 -160
- package/src/runtime/routes/__tests__/acp-routes.test.ts +4 -159
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -108
- package/src/runtime/routes/__tests__/default-provider-routes.test.ts +2 -2
- package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +12 -16
- package/src/runtime/routes/acp-routes.test.ts +0 -15
- package/src/runtime/routes/acp-routes.ts +9 -72
- package/src/runtime/routes/app-management-routes.ts +0 -73
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/conversation-list-routes.ts +3 -14
- package/src/runtime/routes/conversation-query-routes.ts +0 -40
- package/src/runtime/routes/credential-routes.ts +10 -19
- package/src/runtime/routes/debug-bash-routes.ts +173 -0
- package/src/runtime/routes/diagnostics-routes.ts +3 -55
- package/src/runtime/routes/index.ts +2 -4
- package/src/runtime/routes/log-export-routes.ts +0 -2
- package/src/runtime/routes/mcp-auth-routes.ts +47 -39
- package/src/runtime/routes/migration-routes.ts +20 -6
- package/src/runtime/routes/platform-routes.ts +15 -18
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -28
- package/src/runtime/services/conversation-serializer.ts +3 -16
- package/src/runtime/sync/resource-sync-events.ts +1 -2
- package/src/schedule/worker.ts +1 -1
- package/src/security/ces-rpc-record-backend.ts +0 -7
- package/src/subagent/consult-context.ts +25 -12
- package/src/tools/acp/list-agents.test.ts +1 -3
- package/src/tools/acp/spawn.test.ts +11 -146
- package/src/tools/acp/spawn.ts +3 -21
- package/src/tools/acp/status.ts +3 -40
- package/src/tools/app-control/skill-proxy-bridge.ts +1 -2
- package/src/tools/capability-offer.test.ts +2 -22
- package/src/tools/capability-offer.ts +1 -16
- package/src/tools/computer-use/definitions.ts +2 -4
- package/src/tools/computer-use/skill-proxy-bridge.ts +1 -2
- package/src/tools/credentials/metadata-store.ts +0 -100
- package/src/tools/host-filesystem/edit.test.ts +1 -2
- package/src/tools/host-filesystem/edit.ts +2 -2
- package/src/tools/host-filesystem/read.test.ts +1 -2
- package/src/tools/host-filesystem/read.ts +2 -2
- package/src/tools/host-filesystem/transfer.test.ts +1 -2
- package/src/tools/host-filesystem/transfer.ts +2 -2
- package/src/tools/host-filesystem/write.test.ts +1 -2
- package/src/tools/host-filesystem/write.ts +2 -2
- package/src/tools/host-terminal/host-shell.test.ts +0 -16
- package/src/tools/host-terminal/host-shell.ts +20 -4
- package/src/tools/policy-context.ts +7 -6
- package/src/tools/subagent/spawn.ts +8 -5
- package/src/tools/watch/watch-retro-report.ts +8 -0
- package/src/util/__tests__/language-subtag.test.ts +1 -23
- package/src/util/fs-watcher-error.ts +36 -0
- package/src/util/language-subtag.ts +0 -16
- package/src/util/platform.ts +0 -8
- package/src/workspace/git-service.ts +54 -5
- package/src/workspace/migrations/registry.ts +0 -6
- package/scripts/smoke-desktop-window-theme.ts +0 -186
- package/src/__tests__/git-porcelain.test.ts +0 -47
- package/src/__tests__/helpers/set-workspace-mcp.ts +0 -11
- package/src/__tests__/message-deleted-hook-dispatch.test.ts +0 -119
- package/src/__tests__/resolve-app.test.ts +0 -135
- package/src/__tests__/service-account-token.test.ts +0 -247
- package/src/__tests__/source-fingerprint.test.ts +0 -184
- package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +0 -336
- package/src/acp/__tests__/helpers/acp-model-option.ts +0 -51
- package/src/acp/model-config.test.ts +0 -166
- package/src/acp/model-config.ts +0 -138
- package/src/api/events/acp-session-model-update.test.ts +0 -88
- package/src/api/events/acp-session-model-update.ts +0 -46
- package/src/apps/resolve-app.ts +0 -81
- package/src/apps/source-fingerprint.ts +0 -266
- package/src/calls/__tests__/barge-in-guard.test.ts +0 -81
- package/src/calls/__tests__/voice-leg-coordinator.test.ts +0 -229
- package/src/calls/__tests__/voice-progress-cadence.test.ts +0 -274
- package/src/calls/barge-in-guard.ts +0 -118
- package/src/calls/voice-leg-coordinator.ts +0 -189
- package/src/calls/voice-progress-cadence.ts +0 -423
- package/src/cli/commands/__tests__/apps.test.ts +0 -245
- package/src/cli/commands/__tests__/bash.test.ts +0 -53
- package/src/cli/commands/__tests__/roadmap.help.test.ts +0 -19
- package/src/cli/commands/channels/__tests__/send.test.ts +0 -218
- package/src/cli/commands/channels/send.ts +0 -128
- package/src/config/__tests__/platform-identity.test.ts +0 -255
- package/src/config/acp-agent-write.ts +0 -43
- package/src/config/acp-schema.test.ts +0 -81
- package/src/config/platform-identity.ts +0 -201
- package/src/config/schemas/__tests__/voice.test.ts +0 -148
- package/src/config/schemas/voice.ts +0 -150
- package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +0 -133
- package/src/daemon/app-change-notify.ts +0 -45
- package/src/desktop/__tests__/fake-desktop.ts +0 -119
- package/src/desktop/desktop-chrome-policy.test.ts +0 -71
- package/src/desktop/desktop-chrome-policy.ts +0 -42
- package/src/desktop/desktop-dependencies.test.ts +0 -102
- package/src/desktop/desktop-dependencies.ts +0 -306
- package/src/desktop/desktop-feature.test.ts +0 -18
- package/src/desktop/desktop-feature.ts +0 -19
- package/src/desktop/desktop-panel-config.test.ts +0 -135
- package/src/desktop/desktop-panel-config.ts +0 -149
- package/src/desktop/desktop-session-manager.test.ts +0 -627
- package/src/desktop/desktop-session-manager.ts +0 -814
- package/src/desktop/desktop-stream-bridge.test.ts +0 -395
- package/src/desktop/desktop-stream-bridge.ts +0 -214
- package/src/desktop/desktop-wallpaper.test.ts +0 -191
- package/src/desktop/desktop-wallpaper.ts +0 -113
- package/src/desktop/desktop-window-theme.ts +0 -170
- package/src/i18n/AGENTS.md +0 -22
- package/src/i18n/__tests__/i18n.test.ts +0 -108
- package/src/i18n/index.ts +0 -16
- package/src/i18n/locales.ts +0 -93
- package/src/i18n/messages.ts +0 -61
- package/src/i18n/title.ts +0 -25
- package/src/mcp/__tests__/workspace-mcp-config.test.ts +0 -135
- package/src/mcp/spec-schema.ts +0 -111
- package/src/mcp/workspace-mcp-config.ts +0 -188
- package/src/messaging/providers/__tests__/proactive-address.test.ts +0 -95
- package/src/persistence/conversation-title-placeholders.ts +0 -23
- package/src/persistence/message-cursor.ts +0 -78
- package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +0 -149
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +0 -118
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +0 -83
- package/src/plugins/defaults/memory/hooks/message-deleted.ts +0 -21
- package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +0 -126
- package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +0 -79
- package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +0 -28
- package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +0 -9
- package/src/providers/gemini-thought-signature.test.ts +0 -63
- package/src/providers/gemini-thought-signature.ts +0 -44
- package/src/providers/inference/service-account-token.ts +0 -248
- package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +0 -613
- package/src/providers/openai/__tests__/google-thought-signature.test.ts +0 -235
- package/src/providers/openai/google-thought-signature.ts +0 -320
- package/src/runtime/__tests__/channel-send.test.ts +0 -443
- package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +0 -89
- package/src/runtime/__tests__/live-voice-upgrade.test.ts +0 -58
- package/src/runtime/__tests__/runtime-ws-test-utils.ts +0 -72
- package/src/runtime/__tests__/watch-stream-upgrade.test.ts +0 -59
- package/src/runtime/channel-send.ts +0 -316
- package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +0 -205
- package/src/runtime/routes/__tests__/channel-send-routes.test.ts +0 -127
- package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +0 -107
- package/src/runtime/routes/channel-send-routes.ts +0 -85
- package/src/runtime/routes/desktop-setup-routes.test.ts +0 -74
- package/src/runtime/routes/desktop-setup-routes.ts +0 -35
- package/src/security/__tests__/ces-http-record-backend.test.ts +0 -137
- package/src/security/ces-http-record-backend.ts +0 -120
- package/src/skills/__tests__/workspace-skill-md-signature.test.ts +0 -60
- package/src/skills/workspace-skill-md-signature.ts +0 -50
- package/src/tools/acp/status.test.ts +0 -94
- package/src/tools/terminal/__tests__/sanitized-bash.test.ts +0 -57
- package/src/tools/terminal/sanitized-bash.ts +0 -105
- package/src/util/ca-bundle.ts +0 -13
- package/src/workspace/git-porcelain.ts +0 -66
- package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +0 -258
- package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +0 -78
- package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +0 -214
- package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +0 -102
- package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +0 -199
- /package/src/{calls → live-voice}/progress-phrases.ts +0 -0
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
// Mock the STT resolve module (used by MediaStreamSttSession).
|
|
16
16
|
// resolveStreamingTranscriber yields no transcriber, so sessions settle on
|
|
17
17
|
// the batch path regardless of the calls.voice.telephonyStreaming default.
|
|
18
|
-
mock.module("
|
|
18
|
+
mock.module("../providers/speech-to-text/resolve.js", () => ({
|
|
19
19
|
resolveTelephonySttCapability: jest.fn(),
|
|
20
20
|
resolveBatchTranscriber: jest.fn(),
|
|
21
21
|
resolveStreamingTranscriber: jest.fn(async () => null),
|
|
@@ -29,7 +29,7 @@ const mockEvents: Array<{
|
|
|
29
29
|
data: unknown;
|
|
30
30
|
}> = [];
|
|
31
31
|
|
|
32
|
-
mock.module("../call-store.js", () => ({
|
|
32
|
+
mock.module("../calls/call-store.js", () => ({
|
|
33
33
|
getCallSession: jest.fn((id: string) => mockSessions.get(id) ?? null),
|
|
34
34
|
updateCallSession: jest.fn((id: string, updates: Record<string, unknown>) => {
|
|
35
35
|
const session = mockSessions.get(id);
|
|
@@ -52,7 +52,7 @@ mock.module("../call-store.js", () => ({
|
|
|
52
52
|
}));
|
|
53
53
|
|
|
54
54
|
// Mock the call state machine
|
|
55
|
-
mock.module("../call-state-machine.js", () => ({
|
|
55
|
+
mock.module("../calls/call-state-machine.js", () => ({
|
|
56
56
|
isTerminalState: jest.fn(
|
|
57
57
|
(status: string) =>
|
|
58
58
|
status === "completed" || status === "failed" || status === "cancelled",
|
|
@@ -61,7 +61,7 @@ mock.module("../call-state-machine.js", () => ({
|
|
|
61
61
|
|
|
62
62
|
// Mock the call state (controller registry)
|
|
63
63
|
const mockControllers = new Map<string, unknown>();
|
|
64
|
-
mock.module("../call-state.js", () => ({
|
|
64
|
+
mock.module("../calls/call-state.js", () => ({
|
|
65
65
|
registerCallController: jest.fn(
|
|
66
66
|
(callSessionId: string, controller: unknown) => {
|
|
67
67
|
mockControllers.set(callSessionId, controller);
|
|
@@ -85,12 +85,12 @@ mock.module("../call-state.js", () => ({
|
|
|
85
85
|
}));
|
|
86
86
|
|
|
87
87
|
// Mock the finalize-call module
|
|
88
|
-
mock.module("../finalize-call.js", () => ({
|
|
88
|
+
mock.module("../calls/finalize-call.js", () => ({
|
|
89
89
|
finalizeCall: jest.fn(),
|
|
90
90
|
}));
|
|
91
91
|
|
|
92
92
|
// Mock the call pointer messages
|
|
93
|
-
mock.module("../call-pointer-messages.js", () => ({
|
|
93
|
+
mock.module("../calls/call-pointer-messages.js", () => ({
|
|
94
94
|
postPointerMessageSafe: jest.fn(),
|
|
95
95
|
formatDuration: jest.fn((ms: number) => `${Math.round(ms / 1000)}s`),
|
|
96
96
|
}));
|
|
@@ -104,13 +104,10 @@ const mockHandleInterrupt = jest.fn();
|
|
|
104
104
|
const mockDestroy = jest.fn();
|
|
105
105
|
|
|
106
106
|
// Mirrors CallController.handleBargeIn: invokes onAccepted only when the
|
|
107
|
-
// barge-in passes the
|
|
107
|
+
// barge-in passes the speaking gate.
|
|
108
108
|
const mockHandleBargeIn = jest.fn((_onAccepted?: () => void) => false);
|
|
109
|
-
// What the mocked controller reports as its state; the media-stream
|
|
110
|
-
// session arms the barge-in guard only while a turn is in flight.
|
|
111
|
-
let mockControllerState: "idle" | "processing" | "speaking" = "idle";
|
|
112
109
|
|
|
113
|
-
mock.module("../call-controller.js", () => ({
|
|
110
|
+
mock.module("../calls/call-controller.js", () => ({
|
|
114
111
|
CallController: jest.fn().mockImplementation(() => ({
|
|
115
112
|
startInitialGreeting: mockStartInitialGreeting,
|
|
116
113
|
startPostVerificationGreeting: mockStartPostVerificationGreeting,
|
|
@@ -119,7 +116,7 @@ mock.module("../call-controller.js", () => ({
|
|
|
119
116
|
handleInterrupt: mockHandleInterrupt,
|
|
120
117
|
handleBargeIn: mockHandleBargeIn,
|
|
121
118
|
destroy: mockDestroy,
|
|
122
|
-
getState: jest.fn(() =>
|
|
119
|
+
getState: jest.fn(() => "idle"),
|
|
123
120
|
setTrustContext: jest.fn(),
|
|
124
121
|
getPendingConsultationQuestionId: jest.fn(),
|
|
125
122
|
handleUserAnswer: jest.fn(),
|
|
@@ -128,7 +125,7 @@ mock.module("../call-controller.js", () => ({
|
|
|
128
125
|
}));
|
|
129
126
|
|
|
130
127
|
// Mock the assistant scope
|
|
131
|
-
mock.module("
|
|
128
|
+
mock.module("../runtime/assistant-scope.js", () => ({
|
|
132
129
|
DAEMON_INTERNAL_ASSISTANT_ID: "self",
|
|
133
130
|
}));
|
|
134
131
|
|
|
@@ -160,7 +157,7 @@ let mockRouteSetupResult: {
|
|
|
160
157
|
// teardown (e.g. the outbound unusable-verdict abort).
|
|
161
158
|
let mockRouteSetupError: Error | null = null;
|
|
162
159
|
|
|
163
|
-
mock.module("../call-setup-router.js", () => ({
|
|
160
|
+
mock.module("../calls/call-setup-router.js", () => ({
|
|
164
161
|
routeSetup: jest.fn(() => {
|
|
165
162
|
if (mockRouteSetupError) {
|
|
166
163
|
throw mockRouteSetupError;
|
|
@@ -224,7 +221,7 @@ const mockReadPhoneCallerTrust = jest.fn(
|
|
|
224
221
|
};
|
|
225
222
|
},
|
|
226
223
|
);
|
|
227
|
-
mock.module("../inbound-trust-reader.js", () => ({
|
|
224
|
+
mock.module("../calls/inbound-trust-reader.js", () => ({
|
|
228
225
|
readPhoneCallerTrust: mockReadPhoneCallerTrust,
|
|
229
226
|
getPhoneCallerVerdict: (otherPartyNumber: string | undefined) =>
|
|
230
227
|
mockGetInboundTrustVerdict({
|
|
@@ -234,7 +231,7 @@ mock.module("../inbound-trust-reader.js", () => ({
|
|
|
234
231
|
}));
|
|
235
232
|
|
|
236
233
|
// Mock the actor trust resolver (used by handleStart to derive trust context)
|
|
237
|
-
mock.module("
|
|
234
|
+
mock.module("../runtime/actor-trust-resolver.js", () => ({
|
|
238
235
|
toTrustContext: jest.fn(() => ({
|
|
239
236
|
sourceChannel: "phone",
|
|
240
237
|
trustClass: "guardian",
|
|
@@ -246,19 +243,19 @@ mock.module("../../runtime/actor-trust-resolver.js", () => ({
|
|
|
246
243
|
}));
|
|
247
244
|
|
|
248
245
|
// Mock the call speech output (speakSystemPrompt used in deny/unsupported paths)
|
|
249
|
-
mock.module("../call-speech-output.js", () => ({
|
|
246
|
+
mock.module("../calls/call-speech-output.js", () => ({
|
|
250
247
|
speakSystemPrompt: jest.fn(async () => {}),
|
|
251
248
|
}));
|
|
252
249
|
|
|
253
250
|
// Mock scoped approval grants (used in handleTransportClosed and early teardown)
|
|
254
|
-
mock.module("
|
|
251
|
+
mock.module("../approvals/scoped-approval-grants.js", () => ({
|
|
255
252
|
revokeScopedApprovalGrantsForContext: jest.fn(),
|
|
256
253
|
}));
|
|
257
254
|
|
|
258
255
|
// Mock the TTS provider resolution so that the dynamic import inside
|
|
259
256
|
// MediaStreamOutput.processSynthesizeItem() doesn't pull in the real
|
|
260
257
|
// config/provider chain (which would hang or error in a test environment).
|
|
261
|
-
mock.module("../resolve-call-tts-provider.js", () => ({
|
|
258
|
+
mock.module("../calls/resolve-call-tts-provider.js", () => ({
|
|
262
259
|
resolveCallTtsProvider: jest.fn(() => ({
|
|
263
260
|
provider: null,
|
|
264
261
|
useSynthesizedPath: false,
|
|
@@ -277,10 +274,7 @@ mock.module("../resolve-call-tts-provider.js", () => ({
|
|
|
277
274
|
let mockTtsPlaybackDelayMs = 5;
|
|
278
275
|
let mockAccessRequestPollIntervalMs = 5;
|
|
279
276
|
let mockUserConsultationTimeoutMs = 500;
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
mock.module("../call-constants.js", () => ({
|
|
283
|
-
...realCallConstants,
|
|
277
|
+
mock.module("../calls/call-constants.js", () => ({
|
|
284
278
|
isDeniedNumber: jest.fn(() => false),
|
|
285
279
|
getMaxCallDurationMs: jest.fn(() => 3_600_000),
|
|
286
280
|
getUserConsultationTimeoutMs: jest.fn(() => mockUserConsultationTimeoutMs),
|
|
@@ -304,7 +298,7 @@ const mockGetGuardianDelivery = jest.fn(async () => [
|
|
|
304
298
|
{ channelType: "phone", status: "active", displayName: "Alex" },
|
|
305
299
|
]);
|
|
306
300
|
const mockGetGuardianDeliveryFresh = jest.fn(async () => []);
|
|
307
|
-
mock.module("
|
|
301
|
+
mock.module("../contacts/guardian-delivery-reader.js", () => ({
|
|
308
302
|
getGuardianDelivery: mockGetGuardianDelivery,
|
|
309
303
|
getGuardianDeliveryFresh: mockGetGuardianDeliveryFresh,
|
|
310
304
|
peekCachedGuardianDelivery: jest.fn(() => null),
|
|
@@ -315,20 +309,20 @@ mock.module("../../contacts/guardian-delivery-reader.js", () => ({
|
|
|
315
309
|
}));
|
|
316
310
|
|
|
317
311
|
// Guardian/assistant display labels (filesystem-backed).
|
|
318
|
-
mock.module("
|
|
312
|
+
mock.module("../prompts/user-reference.js", () => ({
|
|
319
313
|
DEFAULT_USER_REFERENCE: "my human",
|
|
320
314
|
resolveGuardianName: jest.fn(
|
|
321
315
|
(primed?: string | null) => primed ?? "my human",
|
|
322
316
|
),
|
|
323
317
|
}));
|
|
324
|
-
mock.module("
|
|
318
|
+
mock.module("../daemon/identity-helpers.js", () => ({
|
|
325
319
|
getAssistantName: jest.fn(() => "Aria"),
|
|
326
320
|
resolveUserName: jest.fn(() => null),
|
|
327
321
|
}));
|
|
328
322
|
|
|
329
323
|
// Conversation persistence (used by callee verification code posting).
|
|
330
324
|
const mockAddMessage = jest.fn(async () => ({}));
|
|
331
|
-
mock.module("
|
|
325
|
+
mock.module("../persistence/conversation-crud.js", () => ({
|
|
332
326
|
addMessage: mockAddMessage,
|
|
333
327
|
}));
|
|
334
328
|
|
|
@@ -368,7 +362,7 @@ let mockInviteResult: MockInviteResult = {
|
|
|
368
362
|
type: "trusted_contact",
|
|
369
363
|
};
|
|
370
364
|
const mockAttemptInviteCodeRedemption = jest.fn(async () => mockInviteResult);
|
|
371
|
-
mock.module("../call-verification.js", () => ({
|
|
365
|
+
mock.module("../calls/call-verification.js", () => ({
|
|
372
366
|
attemptVerificationCode: mockAttemptVerificationCode,
|
|
373
367
|
attemptInviteCodeRedemption: mockAttemptInviteCodeRedemption,
|
|
374
368
|
parseDigitsFromSpeech: jest.fn((text: string) => text.replace(/\D+/g, "")),
|
|
@@ -384,7 +378,7 @@ let mockNotifyResult: MockNotifyResult = {
|
|
|
384
378
|
requestId: "req-1",
|
|
385
379
|
};
|
|
386
380
|
const mockNotifyGuardianOfAccessRequest = jest.fn(async () => mockNotifyResult);
|
|
387
|
-
mock.module("
|
|
381
|
+
mock.module("../runtime/access-request-helper.js", () => ({
|
|
388
382
|
notifyGuardianOfAccessRequest: mockNotifyGuardianOfAccessRequest,
|
|
389
383
|
}));
|
|
390
384
|
|
|
@@ -395,8 +389,8 @@ const mockGetGuardianRequest = jest.fn(async () => mockGuardianRequest);
|
|
|
395
389
|
// factory does not stub keep resolving (a partial factory breaks at
|
|
396
390
|
// import time when the graph gains a new named import).
|
|
397
391
|
const actualGatewayGuardianRequests =
|
|
398
|
-
await import("
|
|
399
|
-
mock.module("
|
|
392
|
+
await import("../channels/gateway-guardian-requests.js");
|
|
393
|
+
mock.module("../channels/gateway-guardian-requests.js", () => ({
|
|
400
394
|
...actualGatewayGuardianRequests,
|
|
401
395
|
getGuardianRequestOrNull: mockGetGuardianRequest,
|
|
402
396
|
}));
|
|
@@ -408,7 +402,7 @@ const mockEmitCallbackHandoff = jest.fn(
|
|
|
408
402
|
notified: false,
|
|
409
403
|
}),
|
|
410
404
|
);
|
|
411
|
-
mock.module("../access-request-wait.js", () => ({
|
|
405
|
+
mock.module("../calls/access-request-wait.js", () => ({
|
|
412
406
|
classifyWaitUtterance: jest.fn(() => "neutral"),
|
|
413
407
|
scheduleNextHeartbeat: jest.fn(() => null),
|
|
414
408
|
emitAccessRequestCallbackHandoff: mockEmitCallbackHandoff,
|
|
@@ -420,21 +414,21 @@ mock.module("../access-request-wait.js", () => ({
|
|
|
420
414
|
|
|
421
415
|
import { GATEWAY_TUNNEL_LOST_WS_CLOSE_CODE } from "@vellumai/service-contracts/ingress";
|
|
422
416
|
|
|
423
|
-
import { revokeScopedApprovalGrantsForContext } from "
|
|
424
|
-
import { CallController } from "../call-controller.js";
|
|
425
|
-
import { postPointerMessageSafe } from "../call-pointer-messages.js";
|
|
426
|
-
import { routeSetup } from "../call-setup-router.js";
|
|
427
|
-
import { speakSystemPrompt } from "../call-speech-output.js";
|
|
417
|
+
import { revokeScopedApprovalGrantsForContext } from "../approvals/scoped-approval-grants.js";
|
|
418
|
+
import { CallController } from "../calls/call-controller.js";
|
|
419
|
+
import { postPointerMessageSafe } from "../calls/call-pointer-messages.js";
|
|
420
|
+
import { routeSetup } from "../calls/call-setup-router.js";
|
|
421
|
+
import { speakSystemPrompt } from "../calls/call-speech-output.js";
|
|
428
422
|
import {
|
|
429
423
|
fireCallTranscriptNotifier,
|
|
430
424
|
registerCallController,
|
|
431
|
-
} from "../call-state.js";
|
|
432
|
-
import { recordCallEvent, updateCallSession } from "../call-store.js";
|
|
433
|
-
import { finalizeCall } from "../finalize-call.js";
|
|
425
|
+
} from "../calls/call-state.js";
|
|
426
|
+
import { recordCallEvent, updateCallSession } from "../calls/call-store.js";
|
|
427
|
+
import { finalizeCall } from "../calls/finalize-call.js";
|
|
434
428
|
import {
|
|
435
429
|
activeMediaStreamSessions,
|
|
436
430
|
MediaStreamCallSession,
|
|
437
|
-
} from "../media-stream-server.js";
|
|
431
|
+
} from "../calls/media-stream-server.js";
|
|
438
432
|
|
|
439
433
|
// ---------------------------------------------------------------------------
|
|
440
434
|
// Mock WebSocket factory
|
|
@@ -563,7 +557,6 @@ beforeEach(() => {
|
|
|
563
557
|
mockHandleInterrupt.mockClear();
|
|
564
558
|
mockHandleBargeIn.mockClear();
|
|
565
559
|
mockHandleBargeIn.mockReturnValue(false);
|
|
566
|
-
mockControllerState = "idle";
|
|
567
560
|
mockDestroy.mockClear();
|
|
568
561
|
(CallController as unknown as jest.Mock).mockClear();
|
|
569
562
|
(registerCallController as jest.Mock).mockClear();
|
|
@@ -1315,23 +1308,28 @@ describe("media-stream setup outcome scenarios", () => {
|
|
|
1315
1308
|
await session.whenSetupSettled();
|
|
1316
1309
|
expect(mockStartInitialGreeting).toHaveBeenCalled();
|
|
1317
1310
|
|
|
1318
|
-
// Immediate inbound audio (speech-like payloads) before the
|
|
1319
|
-
// has spoken. The
|
|
1320
|
-
//
|
|
1321
|
-
//
|
|
1311
|
+
// Immediate inbound audio (speech-like payloads) — before the
|
|
1312
|
+
// assistant has spoken. The speech detector classifies these as
|
|
1313
|
+
// speech, so onSpeechStart fires and calls handleBargeIn. Since
|
|
1314
|
+
// the controller mock returns false (not speaking), handleInterrupt
|
|
1315
|
+
// should NOT be called.
|
|
1322
1316
|
const speechPayload = Buffer.alloc(160, 0x00).toString("base64");
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1317
|
+
session.handleMessage(makeMediaMessage(speechPayload, "1"));
|
|
1318
|
+
session.handleMessage(makeMediaMessage(speechPayload, "2"));
|
|
1319
|
+
session.handleMessage(makeMediaMessage(speechPayload, "3"));
|
|
1320
|
+
|
|
1321
|
+
// handleBargeIn was called but returned false
|
|
1322
|
+
expect(mockHandleBargeIn).toHaveBeenCalled();
|
|
1327
1323
|
expect(mockHandleInterrupt).not.toHaveBeenCalled();
|
|
1328
1324
|
|
|
1329
|
-
//
|
|
1330
|
-
//
|
|
1325
|
+
// An ignored barge-in flushes only Twilio's buffered audio (to
|
|
1326
|
+
// stop a completed turn's tail talking over the caller). The
|
|
1327
|
+
// internal playback queue is untouched, so the queued greeting
|
|
1328
|
+
// still plays — handleInterrupt must not have run.
|
|
1331
1329
|
const clearCommands = mockWs.sent.filter(
|
|
1332
1330
|
(s) => JSON.parse(s).event === "clear",
|
|
1333
1331
|
);
|
|
1334
|
-
expect(clearCommands.length).
|
|
1332
|
+
expect(clearCommands.length).toBeGreaterThan(0);
|
|
1335
1333
|
|
|
1336
1334
|
// voice_session_aborted should NOT appear in recorded events
|
|
1337
1335
|
const abortEvents = mockEvents.filter(
|
|
@@ -1351,7 +1349,6 @@ describe("media-stream setup outcome scenarios", () => {
|
|
|
1351
1349
|
onAccepted?.();
|
|
1352
1350
|
return true;
|
|
1353
1351
|
});
|
|
1354
|
-
mockControllerState = "speaking";
|
|
1355
1352
|
|
|
1356
1353
|
const mockWs = createMockWs();
|
|
1357
1354
|
mockSessions.set("call-bargein-2", {
|
|
@@ -1367,17 +1364,14 @@ describe("media-stream setup outcome scenarios", () => {
|
|
|
1367
1364
|
session.handleMessage(makeStartMessage());
|
|
1368
1365
|
await session.whenSetupSettled();
|
|
1369
1366
|
|
|
1370
|
-
//
|
|
1371
|
-
// high-amplitude mu-law payload
|
|
1372
|
-
// 20 ms frame; the guard fires once 250 ms have accumulated.
|
|
1367
|
+
// Simulate inbound speech audio while assistant is speaking.
|
|
1368
|
+
// Use a high-amplitude mu-law payload so speech detection triggers.
|
|
1373
1369
|
const speechPayload = Buffer.alloc(160, 0x00).toString("base64");
|
|
1374
|
-
|
|
1375
|
-
session.handleMessage(makeMediaMessage(speechPayload, String(i)));
|
|
1376
|
-
}
|
|
1370
|
+
session.handleMessage(makeMediaMessage(speechPayload, "1"));
|
|
1377
1371
|
|
|
1378
|
-
// handleBargeIn
|
|
1379
|
-
// barge-in
|
|
1380
|
-
expect(mockHandleBargeIn).
|
|
1372
|
+
// handleBargeIn should have been called (returning true), and the
|
|
1373
|
+
// accepted barge-in flushes outbound audio via the onAccepted hook.
|
|
1374
|
+
expect(mockHandleBargeIn).toHaveBeenCalled();
|
|
1381
1375
|
const clearCommands = mockWs.sent.filter(
|
|
1382
1376
|
(s) => JSON.parse(s).event === "clear",
|
|
1383
1377
|
);
|
|
@@ -1385,93 +1379,6 @@ describe("media-stream setup outcome scenarios", () => {
|
|
|
1385
1379
|
|
|
1386
1380
|
session.destroy();
|
|
1387
1381
|
});
|
|
1388
|
-
|
|
1389
|
-
test("speech from the caller's own utterance does not carry into a turn that starts mid-utterance", async () => {
|
|
1390
|
-
mockHandleBargeIn.mockImplementation((onAccepted?: () => void) => {
|
|
1391
|
-
onAccepted?.();
|
|
1392
|
-
return true;
|
|
1393
|
-
});
|
|
1394
|
-
|
|
1395
|
-
const mockWs = createMockWs();
|
|
1396
|
-
mockSessions.set("call-bargein-4", {
|
|
1397
|
-
id: "call-bargein-4",
|
|
1398
|
-
conversationId: "conv-bargein-4",
|
|
1399
|
-
status: "in_progress",
|
|
1400
|
-
task: null,
|
|
1401
|
-
startedAt: Date.now() - 5000,
|
|
1402
|
-
toNumber: "+15555550198",
|
|
1403
|
-
});
|
|
1404
|
-
|
|
1405
|
-
const session = new MediaStreamCallSession(mockWs.ws, "call-bargein-4");
|
|
1406
|
-
session.handleMessage(makeStartMessage());
|
|
1407
|
-
await session.whenSetupSettled();
|
|
1408
|
-
|
|
1409
|
-
// 240 ms of the caller's own utterance while the controller is idle.
|
|
1410
|
-
const speechPayload = Buffer.alloc(160, 0x00).toString("base64");
|
|
1411
|
-
let chunk = 1;
|
|
1412
|
-
for (let i = 0; i < 12; i++) {
|
|
1413
|
-
session.handleMessage(makeMediaMessage(speechPayload, String(chunk++)));
|
|
1414
|
-
}
|
|
1415
|
-
// A streaming final starts the assistant turn before the local VAD
|
|
1416
|
-
// ends the utterance. One more speech frame must not cut it off.
|
|
1417
|
-
mockControllerState = "processing";
|
|
1418
|
-
session.handleMessage(makeMediaMessage(speechPayload, String(chunk++)));
|
|
1419
|
-
expect(mockHandleBargeIn).not.toHaveBeenCalled();
|
|
1420
|
-
|
|
1421
|
-
// Sustained speech during the turn still does.
|
|
1422
|
-
for (let i = 0; i < 12; i++) {
|
|
1423
|
-
session.handleMessage(makeMediaMessage(speechPayload, String(chunk++)));
|
|
1424
|
-
}
|
|
1425
|
-
expect(mockHandleBargeIn).toHaveBeenCalledTimes(1);
|
|
1426
|
-
|
|
1427
|
-
session.destroy();
|
|
1428
|
-
});
|
|
1429
|
-
|
|
1430
|
-
test("speech that stops short of the guard never reaches the controller", async () => {
|
|
1431
|
-
mockHandleBargeIn.mockImplementation((onAccepted?: () => void) => {
|
|
1432
|
-
onAccepted?.();
|
|
1433
|
-
return true;
|
|
1434
|
-
});
|
|
1435
|
-
mockControllerState = "processing";
|
|
1436
|
-
|
|
1437
|
-
const mockWs = createMockWs();
|
|
1438
|
-
mockSessions.set("call-bargein-3", {
|
|
1439
|
-
id: "call-bargein-3",
|
|
1440
|
-
conversationId: "conv-bargein-3",
|
|
1441
|
-
status: "in_progress",
|
|
1442
|
-
task: null,
|
|
1443
|
-
startedAt: Date.now() - 5000,
|
|
1444
|
-
toNumber: "+15555550199",
|
|
1445
|
-
});
|
|
1446
|
-
|
|
1447
|
-
const session = new MediaStreamCallSession(mockWs.ws, "call-bargein-3");
|
|
1448
|
-
session.handleMessage(makeStartMessage());
|
|
1449
|
-
await session.whenSetupSettled();
|
|
1450
|
-
|
|
1451
|
-
// 100 ms of speech, then a silence gap past the tolerance: the run
|
|
1452
|
-
// resets, and another 100 ms of speech is still short of the guard.
|
|
1453
|
-
const speechPayload = Buffer.alloc(160, 0x00).toString("base64");
|
|
1454
|
-
const silencePayload = Buffer.alloc(160, 0xff).toString("base64");
|
|
1455
|
-
let chunk = 1;
|
|
1456
|
-
for (let i = 0; i < 5; i++) {
|
|
1457
|
-
session.handleMessage(makeMediaMessage(speechPayload, String(chunk++)));
|
|
1458
|
-
}
|
|
1459
|
-
for (let i = 0; i < 15; i++) {
|
|
1460
|
-
session.handleMessage(
|
|
1461
|
-
makeMediaMessage(silencePayload, String(chunk++)),
|
|
1462
|
-
);
|
|
1463
|
-
}
|
|
1464
|
-
for (let i = 0; i < 5; i++) {
|
|
1465
|
-
session.handleMessage(makeMediaMessage(speechPayload, String(chunk++)));
|
|
1466
|
-
}
|
|
1467
|
-
|
|
1468
|
-
expect(mockHandleBargeIn).not.toHaveBeenCalled();
|
|
1469
|
-
expect(
|
|
1470
|
-
mockWs.sent.filter((s) => JSON.parse(s).event === "clear").length,
|
|
1471
|
-
).toBe(0);
|
|
1472
|
-
|
|
1473
|
-
session.destroy();
|
|
1474
|
-
});
|
|
1475
1382
|
});
|
|
1476
1383
|
|
|
1477
1384
|
// ── E2E regression scenario ──────────────────────────────────────
|
|
@@ -13,27 +13,27 @@ import type {
|
|
|
13
13
|
StreamingTranscriber,
|
|
14
14
|
SttStreamServerEvent,
|
|
15
15
|
SttTranscribeRequest,
|
|
16
|
-
} from "
|
|
16
|
+
} from "../stt/types.js";
|
|
17
17
|
|
|
18
18
|
// ---------------------------------------------------------------------------
|
|
19
19
|
// Module mocks — must be declared before the module under test is imported.
|
|
20
20
|
// ---------------------------------------------------------------------------
|
|
21
21
|
|
|
22
22
|
// Mock the STT resolve module
|
|
23
|
-
mock.module("
|
|
23
|
+
mock.module("../providers/speech-to-text/resolve.js", () => ({
|
|
24
24
|
resolveTelephonySttCapability: jest.fn(),
|
|
25
25
|
resolveBatchTranscriber: jest.fn(),
|
|
26
26
|
resolveStreamingTranscriber: jest.fn(),
|
|
27
27
|
}));
|
|
28
28
|
|
|
29
29
|
// Now import the mocked modules and the module under test.
|
|
30
|
-
import {
|
|
30
|
+
import { MediaStreamSttSession } from "../calls/media-stream-stt-session.js";
|
|
31
31
|
import {
|
|
32
32
|
resolveBatchTranscriber,
|
|
33
33
|
resolveStreamingTranscriber,
|
|
34
34
|
resolveTelephonySttCapability,
|
|
35
|
-
} from "
|
|
36
|
-
import {
|
|
35
|
+
} from "../providers/speech-to-text/resolve.js";
|
|
36
|
+
import { setConfig } from "./helpers/set-config.js";
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
39
|
* Seed the session's `calls.voice` settings in the real workspace config.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, expect, jest, test } from "bun:test";
|
|
2
2
|
|
|
3
|
-
import { MediaTurnDetector } from "../media-turn-detector.js";
|
|
3
|
+
import { MediaTurnDetector } from "../calls/media-turn-detector.js";
|
|
4
4
|
|
|
5
5
|
// ---------------------------------------------------------------------------
|
|
6
6
|
// Helpers
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, test } from "bun:test";
|
|
2
2
|
|
|
3
|
-
import { eq } from "drizzle-orm";
|
|
4
|
-
|
|
5
3
|
import {
|
|
6
4
|
countMessagesAfter,
|
|
7
5
|
getMessagesAfter,
|
|
8
6
|
} from "../persistence/conversation-crud.js";
|
|
9
7
|
import { getDb } from "../persistence/db-connection.js";
|
|
10
8
|
import { initializeDb } from "../persistence/db-init.js";
|
|
11
|
-
import { resolveMessagesAfterBound } from "../persistence/message-cursor.js";
|
|
12
9
|
import { conversations, messages } from "../persistence/schema/index.js";
|
|
13
10
|
|
|
14
11
|
await initializeDb();
|
|
@@ -116,91 +113,3 @@ describe("countMessagesAfter / getMessagesAfter — millisecond-collision tie-br
|
|
|
116
113
|
expect(getMessagesAfter(CONV_ID, "")).toHaveLength(2);
|
|
117
114
|
});
|
|
118
115
|
});
|
|
119
|
-
|
|
120
|
-
describe("countMessagesAfter / getMessagesAfter: a cursor survives its row's deletion", () => {
|
|
121
|
-
beforeEach(() => {
|
|
122
|
-
clearDb();
|
|
123
|
-
seedConversation();
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
test("a cursor carrying createdAt keeps bounding the read after its row is deleted", () => {
|
|
127
|
-
const ts = 1_700_000_000_000;
|
|
128
|
-
insertMessage("a", ts);
|
|
129
|
-
// The row the cursor points at: a reply the user then regenerates.
|
|
130
|
-
insertMessage("b", ts + 1);
|
|
131
|
-
insertMessage("c", ts + 2);
|
|
132
|
-
getDb().delete(messages).where(eq(messages.id, "b")).run();
|
|
133
|
-
// The regenerated reply.
|
|
134
|
-
insertMessage("d", ts + 3);
|
|
135
|
-
|
|
136
|
-
const cursor = { id: "b", createdAt: ts + 1 };
|
|
137
|
-
expect(countMessagesAfter(CONV_ID, cursor)).toBe(2);
|
|
138
|
-
expect(getMessagesAfter(CONV_ID, cursor).map((m) => m.id)).toEqual([
|
|
139
|
-
"c",
|
|
140
|
-
"d",
|
|
141
|
-
]);
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
test("a cursor without createdAt keeps the conservative id-only semantics once its row is gone", () => {
|
|
145
|
-
insertMessage("a", 1_700_000_000_000);
|
|
146
|
-
|
|
147
|
-
const cursor = { id: "nonexistent", createdAt: null };
|
|
148
|
-
expect(countMessagesAfter(CONV_ID, cursor)).toBe(0);
|
|
149
|
-
expect(getMessagesAfter(CONV_ID, cursor)).toEqual([]);
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
test("the live row wins over the timestamp the cursor carries", () => {
|
|
153
|
-
const ts = 1_700_000_000_000;
|
|
154
|
-
insertMessage("a", ts);
|
|
155
|
-
insertMessage("b", ts + 10);
|
|
156
|
-
|
|
157
|
-
// A stale cursor timestamp must not pull processed rows back in, nor
|
|
158
|
-
// hide unprocessed ones, while the row itself can still be read.
|
|
159
|
-
expect(countMessagesAfter(CONV_ID, { id: "b", createdAt: ts - 100 })).toBe(
|
|
160
|
-
0,
|
|
161
|
-
);
|
|
162
|
-
expect(countMessagesAfter(CONV_ID, { id: "a", createdAt: ts + 999 })).toBe(
|
|
163
|
-
1,
|
|
164
|
-
);
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
test("a cursor with an empty id reads everything, like null and the empty string", () => {
|
|
168
|
-
insertMessage("a", 1_700_000_000_000);
|
|
169
|
-
|
|
170
|
-
expect(countMessagesAfter(CONV_ID, { id: "", createdAt: 5 })).toBe(1);
|
|
171
|
-
expect(getMessagesAfter(CONV_ID, { id: "", createdAt: 5 })).toHaveLength(1);
|
|
172
|
-
});
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
describe("resolveMessagesAfterBound", () => {
|
|
176
|
-
beforeEach(() => {
|
|
177
|
-
clearDb();
|
|
178
|
-
seedConversation();
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
test("resolves the unbounded, live-row, stored-timestamp, and vanished cases", () => {
|
|
182
|
-
insertMessage("a", 1_000);
|
|
183
|
-
|
|
184
|
-
expect(resolveMessagesAfterBound(null)).toEqual({ kind: "all" });
|
|
185
|
-
expect(resolveMessagesAfterBound("")).toEqual({ kind: "all" });
|
|
186
|
-
expect(resolveMessagesAfterBound({ id: "", createdAt: 3 })).toEqual({
|
|
187
|
-
kind: "all",
|
|
188
|
-
});
|
|
189
|
-
expect(resolveMessagesAfterBound("a")).toEqual({
|
|
190
|
-
kind: "after",
|
|
191
|
-
bound: { createdAt: 1_000, id: "a" },
|
|
192
|
-
});
|
|
193
|
-
expect(resolveMessagesAfterBound({ id: "a", createdAt: 99 })).toEqual({
|
|
194
|
-
kind: "after",
|
|
195
|
-
bound: { createdAt: 1_000, id: "a" },
|
|
196
|
-
});
|
|
197
|
-
expect(resolveMessagesAfterBound("gone")).toEqual({ kind: "vanished" });
|
|
198
|
-
expect(resolveMessagesAfterBound({ id: "gone", createdAt: null })).toEqual({
|
|
199
|
-
kind: "vanished",
|
|
200
|
-
});
|
|
201
|
-
expect(resolveMessagesAfterBound({ id: "gone", createdAt: 7 })).toEqual({
|
|
202
|
-
kind: "after",
|
|
203
|
-
bound: { createdAt: 7, id: "gone" },
|
|
204
|
-
});
|
|
205
|
-
});
|
|
206
|
-
});
|
|
@@ -52,7 +52,7 @@ const BASELINE: Readonly<Record<string, number>> = {
|
|
|
52
52
|
"src/plugins/defaults/memory/context-search/sources/conversations.ts": 1,
|
|
53
53
|
"src/plugins/defaults/memory/graph/image-ref-utils.ts": 1,
|
|
54
54
|
"src/plugins/defaults/memory/indexer.ts": 2,
|
|
55
|
-
"src/plugins/defaults/memory/memory-retrospective-accounting.ts":
|
|
55
|
+
"src/plugins/defaults/memory/memory-retrospective-accounting.ts": 4,
|
|
56
56
|
"src/plugins/defaults/memory/substrate/sweep-job.ts": 1,
|
|
57
57
|
"src/plugins/defaults/memory/v1/graph/extraction.ts": 3,
|
|
58
58
|
"src/plugins/defaults/memory/v1/job-handlers/backfill.ts": 1,
|