@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
|
@@ -12,7 +12,7 @@ const mockProvider = {
|
|
|
12
12
|
synthesize: mockSynthesize,
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
-
mock.module("../
|
|
15
|
+
mock.module("../resolve-call-tts-provider.js", () => ({
|
|
16
16
|
resolveCallTtsProvider: jest.fn(() => ({
|
|
17
17
|
provider: mockProvider,
|
|
18
18
|
useSynthesizedPath: false,
|
|
@@ -20,13 +20,10 @@ mock.module("../calls/resolve-call-tts-provider.js", () => ({
|
|
|
20
20
|
})),
|
|
21
21
|
}));
|
|
22
22
|
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
} from "../
|
|
27
|
-
import { MediaStreamOutput } from "../calls/media-stream-output.js";
|
|
28
|
-
import { resolveCallTtsProvider } from "../calls/resolve-call-tts-provider.js";
|
|
29
|
-
import { setConfig } from "./helpers/set-config.js";
|
|
23
|
+
import { setConfig } from "../../__tests__/helpers/set-config.js";
|
|
24
|
+
import { mulawToPcm16, pcm16ToMulaw } from "../media-stream-audio-transcode.js";
|
|
25
|
+
import { MediaStreamOutput } from "../media-stream-output.js";
|
|
26
|
+
import { resolveCallTtsProvider } from "../resolve-call-tts-provider.js";
|
|
30
27
|
|
|
31
28
|
const mockResolveCallTtsProvider = resolveCallTtsProvider as ReturnType<
|
|
32
29
|
typeof jest.fn
|
|
@@ -857,6 +854,38 @@ describe("MediaStreamOutput", () => {
|
|
|
857
854
|
// Initially empty
|
|
858
855
|
expect(output.getPlaybackQueueLength()).toBe(0);
|
|
859
856
|
});
|
|
857
|
+
|
|
858
|
+
test("isPlaybackIdle tracks buffered text, the queue, and the sent-audio tail", async () => {
|
|
859
|
+
const samples = Array.from({ length: 4000 }, (_, i) =>
|
|
860
|
+
Math.round(Math.sin(i * 0.1) * 10000),
|
|
861
|
+
);
|
|
862
|
+
mockSynthesize.mockResolvedValue({
|
|
863
|
+
audio: makeWavBuffer(samples),
|
|
864
|
+
contentType: "audio/wav",
|
|
865
|
+
});
|
|
866
|
+
|
|
867
|
+
const { ws, sent } = createMockWs();
|
|
868
|
+
const output = makeOutput(ws, "stream-1");
|
|
869
|
+
expect(output.isPlaybackIdle()).toBe(true);
|
|
870
|
+
expect(output.playbackTailUntilMs()).toBe(0);
|
|
871
|
+
|
|
872
|
+
// Text buffered toward a sentence boundary is pending speech.
|
|
873
|
+
output.sendTextToken("Still thinking", false);
|
|
874
|
+
expect(output.isPlaybackIdle()).toBe(false);
|
|
875
|
+
|
|
876
|
+
output.sendTextToken(" about it.", true);
|
|
877
|
+
await drain(() => countEvents(sent, "mark") > 0);
|
|
878
|
+
|
|
879
|
+
// Frames left faster than real time: the tail estimate still covers
|
|
880
|
+
// the audio Twilio is playing out.
|
|
881
|
+
expect(output.playbackTailUntilMs()).toBeGreaterThan(Date.now());
|
|
882
|
+
expect(output.isPlaybackIdle()).toBe(false);
|
|
883
|
+
|
|
884
|
+
// A barge-in clear drops Twilio's buffer, so nothing is audible.
|
|
885
|
+
output.clearAudio();
|
|
886
|
+
expect(output.playbackTailUntilMs()).toBe(0);
|
|
887
|
+
expect(output.isPlaybackIdle()).toBe(true);
|
|
888
|
+
});
|
|
860
889
|
});
|
|
861
890
|
|
|
862
891
|
// ---------------------------------------------------------------------------
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
2
|
|
|
3
|
-
import { parseMediaStreamFrame } from "../
|
|
3
|
+
import { parseMediaStreamFrame } from "../media-stream-parser.js";
|
|
4
4
|
|
|
5
5
|
// ---------------------------------------------------------------------------
|
|
6
6
|
// Fixture factories
|
|
@@ -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("../
|
|
32
|
+
mock.module("../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("../calls/call-store.js", () => ({
|
|
|
52
52
|
}));
|
|
53
53
|
|
|
54
54
|
// Mock the call state machine
|
|
55
|
-
mock.module("../
|
|
55
|
+
mock.module("../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("../calls/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("../
|
|
64
|
+
mock.module("../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("../calls/call-state.js", () => ({
|
|
|
85
85
|
}));
|
|
86
86
|
|
|
87
87
|
// Mock the finalize-call module
|
|
88
|
-
mock.module("../
|
|
88
|
+
mock.module("../finalize-call.js", () => ({
|
|
89
89
|
finalizeCall: jest.fn(),
|
|
90
90
|
}));
|
|
91
91
|
|
|
92
92
|
// Mock the call pointer messages
|
|
93
|
-
mock.module("../
|
|
93
|
+
mock.module("../call-pointer-messages.js", () => ({
|
|
94
94
|
postPointerMessageSafe: jest.fn(),
|
|
95
95
|
formatDuration: jest.fn((ms: number) => `${Math.round(ms / 1000)}s`),
|
|
96
96
|
}));
|
|
@@ -104,10 +104,13 @@ 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 controller's 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";
|
|
109
112
|
|
|
110
|
-
mock.module("../
|
|
113
|
+
mock.module("../call-controller.js", () => ({
|
|
111
114
|
CallController: jest.fn().mockImplementation(() => ({
|
|
112
115
|
startInitialGreeting: mockStartInitialGreeting,
|
|
113
116
|
startPostVerificationGreeting: mockStartPostVerificationGreeting,
|
|
@@ -116,7 +119,7 @@ mock.module("../calls/call-controller.js", () => ({
|
|
|
116
119
|
handleInterrupt: mockHandleInterrupt,
|
|
117
120
|
handleBargeIn: mockHandleBargeIn,
|
|
118
121
|
destroy: mockDestroy,
|
|
119
|
-
getState: jest.fn(() =>
|
|
122
|
+
getState: jest.fn(() => mockControllerState),
|
|
120
123
|
setTrustContext: jest.fn(),
|
|
121
124
|
getPendingConsultationQuestionId: jest.fn(),
|
|
122
125
|
handleUserAnswer: jest.fn(),
|
|
@@ -125,7 +128,7 @@ mock.module("../calls/call-controller.js", () => ({
|
|
|
125
128
|
}));
|
|
126
129
|
|
|
127
130
|
// Mock the assistant scope
|
|
128
|
-
mock.module("
|
|
131
|
+
mock.module("../../runtime/assistant-scope.js", () => ({
|
|
129
132
|
DAEMON_INTERNAL_ASSISTANT_ID: "self",
|
|
130
133
|
}));
|
|
131
134
|
|
|
@@ -157,7 +160,7 @@ let mockRouteSetupResult: {
|
|
|
157
160
|
// teardown (e.g. the outbound unusable-verdict abort).
|
|
158
161
|
let mockRouteSetupError: Error | null = null;
|
|
159
162
|
|
|
160
|
-
mock.module("../
|
|
163
|
+
mock.module("../call-setup-router.js", () => ({
|
|
161
164
|
routeSetup: jest.fn(() => {
|
|
162
165
|
if (mockRouteSetupError) {
|
|
163
166
|
throw mockRouteSetupError;
|
|
@@ -221,7 +224,7 @@ const mockReadPhoneCallerTrust = jest.fn(
|
|
|
221
224
|
};
|
|
222
225
|
},
|
|
223
226
|
);
|
|
224
|
-
mock.module("../
|
|
227
|
+
mock.module("../inbound-trust-reader.js", () => ({
|
|
225
228
|
readPhoneCallerTrust: mockReadPhoneCallerTrust,
|
|
226
229
|
getPhoneCallerVerdict: (otherPartyNumber: string | undefined) =>
|
|
227
230
|
mockGetInboundTrustVerdict({
|
|
@@ -231,7 +234,7 @@ mock.module("../calls/inbound-trust-reader.js", () => ({
|
|
|
231
234
|
}));
|
|
232
235
|
|
|
233
236
|
// Mock the actor trust resolver (used by handleStart to derive trust context)
|
|
234
|
-
mock.module("
|
|
237
|
+
mock.module("../../runtime/actor-trust-resolver.js", () => ({
|
|
235
238
|
toTrustContext: jest.fn(() => ({
|
|
236
239
|
sourceChannel: "phone",
|
|
237
240
|
trustClass: "guardian",
|
|
@@ -243,19 +246,19 @@ mock.module("../runtime/actor-trust-resolver.js", () => ({
|
|
|
243
246
|
}));
|
|
244
247
|
|
|
245
248
|
// Mock the call speech output (speakSystemPrompt used in deny/unsupported paths)
|
|
246
|
-
mock.module("../
|
|
249
|
+
mock.module("../call-speech-output.js", () => ({
|
|
247
250
|
speakSystemPrompt: jest.fn(async () => {}),
|
|
248
251
|
}));
|
|
249
252
|
|
|
250
253
|
// Mock scoped approval grants (used in handleTransportClosed and early teardown)
|
|
251
|
-
mock.module("
|
|
254
|
+
mock.module("../../approvals/scoped-approval-grants.js", () => ({
|
|
252
255
|
revokeScopedApprovalGrantsForContext: jest.fn(),
|
|
253
256
|
}));
|
|
254
257
|
|
|
255
258
|
// Mock the TTS provider resolution so that the dynamic import inside
|
|
256
259
|
// MediaStreamOutput.processSynthesizeItem() doesn't pull in the real
|
|
257
260
|
// config/provider chain (which would hang or error in a test environment).
|
|
258
|
-
mock.module("../
|
|
261
|
+
mock.module("../resolve-call-tts-provider.js", () => ({
|
|
259
262
|
resolveCallTtsProvider: jest.fn(() => ({
|
|
260
263
|
provider: null,
|
|
261
264
|
useSynthesizedPath: false,
|
|
@@ -274,7 +277,10 @@ mock.module("../calls/resolve-call-tts-provider.js", () => ({
|
|
|
274
277
|
let mockTtsPlaybackDelayMs = 5;
|
|
275
278
|
let mockAccessRequestPollIntervalMs = 5;
|
|
276
279
|
let mockUserConsultationTimeoutMs = 500;
|
|
277
|
-
|
|
280
|
+
import * as realCallConstants from "../call-constants.js";
|
|
281
|
+
|
|
282
|
+
mock.module("../call-constants.js", () => ({
|
|
283
|
+
...realCallConstants,
|
|
278
284
|
isDeniedNumber: jest.fn(() => false),
|
|
279
285
|
getMaxCallDurationMs: jest.fn(() => 3_600_000),
|
|
280
286
|
getUserConsultationTimeoutMs: jest.fn(() => mockUserConsultationTimeoutMs),
|
|
@@ -298,7 +304,7 @@ const mockGetGuardianDelivery = jest.fn(async () => [
|
|
|
298
304
|
{ channelType: "phone", status: "active", displayName: "Alex" },
|
|
299
305
|
]);
|
|
300
306
|
const mockGetGuardianDeliveryFresh = jest.fn(async () => []);
|
|
301
|
-
mock.module("
|
|
307
|
+
mock.module("../../contacts/guardian-delivery-reader.js", () => ({
|
|
302
308
|
getGuardianDelivery: mockGetGuardianDelivery,
|
|
303
309
|
getGuardianDeliveryFresh: mockGetGuardianDeliveryFresh,
|
|
304
310
|
peekCachedGuardianDelivery: jest.fn(() => null),
|
|
@@ -309,20 +315,20 @@ mock.module("../contacts/guardian-delivery-reader.js", () => ({
|
|
|
309
315
|
}));
|
|
310
316
|
|
|
311
317
|
// Guardian/assistant display labels (filesystem-backed).
|
|
312
|
-
mock.module("
|
|
318
|
+
mock.module("../../prompts/user-reference.js", () => ({
|
|
313
319
|
DEFAULT_USER_REFERENCE: "my human",
|
|
314
320
|
resolveGuardianName: jest.fn(
|
|
315
321
|
(primed?: string | null) => primed ?? "my human",
|
|
316
322
|
),
|
|
317
323
|
}));
|
|
318
|
-
mock.module("
|
|
324
|
+
mock.module("../../daemon/identity-helpers.js", () => ({
|
|
319
325
|
getAssistantName: jest.fn(() => "Aria"),
|
|
320
326
|
resolveUserName: jest.fn(() => null),
|
|
321
327
|
}));
|
|
322
328
|
|
|
323
329
|
// Conversation persistence (used by callee verification code posting).
|
|
324
330
|
const mockAddMessage = jest.fn(async () => ({}));
|
|
325
|
-
mock.module("
|
|
331
|
+
mock.module("../../persistence/conversation-crud.js", () => ({
|
|
326
332
|
addMessage: mockAddMessage,
|
|
327
333
|
}));
|
|
328
334
|
|
|
@@ -362,7 +368,7 @@ let mockInviteResult: MockInviteResult = {
|
|
|
362
368
|
type: "trusted_contact",
|
|
363
369
|
};
|
|
364
370
|
const mockAttemptInviteCodeRedemption = jest.fn(async () => mockInviteResult);
|
|
365
|
-
mock.module("../
|
|
371
|
+
mock.module("../call-verification.js", () => ({
|
|
366
372
|
attemptVerificationCode: mockAttemptVerificationCode,
|
|
367
373
|
attemptInviteCodeRedemption: mockAttemptInviteCodeRedemption,
|
|
368
374
|
parseDigitsFromSpeech: jest.fn((text: string) => text.replace(/\D+/g, "")),
|
|
@@ -378,7 +384,7 @@ let mockNotifyResult: MockNotifyResult = {
|
|
|
378
384
|
requestId: "req-1",
|
|
379
385
|
};
|
|
380
386
|
const mockNotifyGuardianOfAccessRequest = jest.fn(async () => mockNotifyResult);
|
|
381
|
-
mock.module("
|
|
387
|
+
mock.module("../../runtime/access-request-helper.js", () => ({
|
|
382
388
|
notifyGuardianOfAccessRequest: mockNotifyGuardianOfAccessRequest,
|
|
383
389
|
}));
|
|
384
390
|
|
|
@@ -389,8 +395,8 @@ const mockGetGuardianRequest = jest.fn(async () => mockGuardianRequest);
|
|
|
389
395
|
// factory does not stub keep resolving (a partial factory breaks at
|
|
390
396
|
// import time when the graph gains a new named import).
|
|
391
397
|
const actualGatewayGuardianRequests =
|
|
392
|
-
await import("
|
|
393
|
-
mock.module("
|
|
398
|
+
await import("../../channels/gateway-guardian-requests.js");
|
|
399
|
+
mock.module("../../channels/gateway-guardian-requests.js", () => ({
|
|
394
400
|
...actualGatewayGuardianRequests,
|
|
395
401
|
getGuardianRequestOrNull: mockGetGuardianRequest,
|
|
396
402
|
}));
|
|
@@ -402,7 +408,7 @@ const mockEmitCallbackHandoff = jest.fn(
|
|
|
402
408
|
notified: false,
|
|
403
409
|
}),
|
|
404
410
|
);
|
|
405
|
-
mock.module("../
|
|
411
|
+
mock.module("../access-request-wait.js", () => ({
|
|
406
412
|
classifyWaitUtterance: jest.fn(() => "neutral"),
|
|
407
413
|
scheduleNextHeartbeat: jest.fn(() => null),
|
|
408
414
|
emitAccessRequestCallbackHandoff: mockEmitCallbackHandoff,
|
|
@@ -414,21 +420,21 @@ mock.module("../calls/access-request-wait.js", () => ({
|
|
|
414
420
|
|
|
415
421
|
import { GATEWAY_TUNNEL_LOST_WS_CLOSE_CODE } from "@vellumai/service-contracts/ingress";
|
|
416
422
|
|
|
417
|
-
import { revokeScopedApprovalGrantsForContext } from "
|
|
418
|
-
import { CallController } from "../
|
|
419
|
-
import { postPointerMessageSafe } from "../
|
|
420
|
-
import { routeSetup } from "../
|
|
421
|
-
import { speakSystemPrompt } from "../
|
|
423
|
+
import { revokeScopedApprovalGrantsForContext } from "../../approvals/scoped-approval-grants.js";
|
|
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";
|
|
422
428
|
import {
|
|
423
429
|
fireCallTranscriptNotifier,
|
|
424
430
|
registerCallController,
|
|
425
|
-
} from "../
|
|
426
|
-
import { recordCallEvent, updateCallSession } from "../
|
|
427
|
-
import { finalizeCall } from "../
|
|
431
|
+
} from "../call-state.js";
|
|
432
|
+
import { recordCallEvent, updateCallSession } from "../call-store.js";
|
|
433
|
+
import { finalizeCall } from "../finalize-call.js";
|
|
428
434
|
import {
|
|
429
435
|
activeMediaStreamSessions,
|
|
430
436
|
MediaStreamCallSession,
|
|
431
|
-
} from "../
|
|
437
|
+
} from "../media-stream-server.js";
|
|
432
438
|
|
|
433
439
|
// ---------------------------------------------------------------------------
|
|
434
440
|
// Mock WebSocket factory
|
|
@@ -557,6 +563,7 @@ beforeEach(() => {
|
|
|
557
563
|
mockHandleInterrupt.mockClear();
|
|
558
564
|
mockHandleBargeIn.mockClear();
|
|
559
565
|
mockHandleBargeIn.mockReturnValue(false);
|
|
566
|
+
mockControllerState = "idle";
|
|
560
567
|
mockDestroy.mockClear();
|
|
561
568
|
(CallController as unknown as jest.Mock).mockClear();
|
|
562
569
|
(registerCallController as jest.Mock).mockClear();
|
|
@@ -1308,28 +1315,23 @@ describe("media-stream setup outcome scenarios", () => {
|
|
|
1308
1315
|
await session.whenSetupSettled();
|
|
1309
1316
|
expect(mockStartInitialGreeting).toHaveBeenCalled();
|
|
1310
1317
|
|
|
1311
|
-
// Immediate inbound audio (speech-like payloads)
|
|
1312
|
-
//
|
|
1313
|
-
//
|
|
1314
|
-
//
|
|
1315
|
-
// should NOT be called.
|
|
1318
|
+
// Immediate inbound audio (speech-like payloads) before the assistant
|
|
1319
|
+
// has spoken. The controller is idle and nothing is playing, so there
|
|
1320
|
+
// is nothing to interrupt: the guard never arms, however long the
|
|
1321
|
+
// caller talks, and the controller is never consulted.
|
|
1316
1322
|
const speechPayload = Buffer.alloc(160, 0x00).toString("base64");
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
// handleBargeIn was called but returned false
|
|
1322
|
-
expect(mockHandleBargeIn).toHaveBeenCalled();
|
|
1323
|
+
for (let i = 1; i <= 16; i++) {
|
|
1324
|
+
session.handleMessage(makeMediaMessage(speechPayload, String(i)));
|
|
1325
|
+
}
|
|
1326
|
+
expect(mockHandleBargeIn).not.toHaveBeenCalled();
|
|
1323
1327
|
expect(mockHandleInterrupt).not.toHaveBeenCalled();
|
|
1324
1328
|
|
|
1325
|
-
//
|
|
1326
|
-
//
|
|
1327
|
-
// internal playback queue is untouched, so the queued greeting
|
|
1328
|
-
// still plays — handleInterrupt must not have run.
|
|
1329
|
+
// Nothing was audible, so nothing was cleared: the queued greeting
|
|
1330
|
+
// still plays.
|
|
1329
1331
|
const clearCommands = mockWs.sent.filter(
|
|
1330
1332
|
(s) => JSON.parse(s).event === "clear",
|
|
1331
1333
|
);
|
|
1332
|
-
expect(clearCommands.length).
|
|
1334
|
+
expect(clearCommands.length).toBe(0);
|
|
1333
1335
|
|
|
1334
1336
|
// voice_session_aborted should NOT appear in recorded events
|
|
1335
1337
|
const abortEvents = mockEvents.filter(
|
|
@@ -1349,6 +1351,7 @@ describe("media-stream setup outcome scenarios", () => {
|
|
|
1349
1351
|
onAccepted?.();
|
|
1350
1352
|
return true;
|
|
1351
1353
|
});
|
|
1354
|
+
mockControllerState = "speaking";
|
|
1352
1355
|
|
|
1353
1356
|
const mockWs = createMockWs();
|
|
1354
1357
|
mockSessions.set("call-bargein-2", {
|
|
@@ -1364,14 +1367,17 @@ describe("media-stream setup outcome scenarios", () => {
|
|
|
1364
1367
|
session.handleMessage(makeStartMessage());
|
|
1365
1368
|
await session.whenSetupSettled();
|
|
1366
1369
|
|
|
1367
|
-
//
|
|
1368
|
-
//
|
|
1370
|
+
// Sustained inbound speech while the assistant is speaking. A
|
|
1371
|
+
// high-amplitude mu-law payload trips speech detection on every
|
|
1372
|
+
// 20 ms frame; the guard fires once 250 ms have accumulated.
|
|
1369
1373
|
const speechPayload = Buffer.alloc(160, 0x00).toString("base64");
|
|
1370
|
-
|
|
1374
|
+
for (let i = 1; i <= 13; i++) {
|
|
1375
|
+
session.handleMessage(makeMediaMessage(speechPayload, String(i)));
|
|
1376
|
+
}
|
|
1371
1377
|
|
|
1372
|
-
// handleBargeIn
|
|
1373
|
-
//
|
|
1374
|
-
expect(mockHandleBargeIn).
|
|
1378
|
+
// handleBargeIn was called once (returning true), and the accepted
|
|
1379
|
+
// barge-in flushed outbound audio via the onAccepted hook.
|
|
1380
|
+
expect(mockHandleBargeIn).toHaveBeenCalledTimes(1);
|
|
1375
1381
|
const clearCommands = mockWs.sent.filter(
|
|
1376
1382
|
(s) => JSON.parse(s).event === "clear",
|
|
1377
1383
|
);
|
|
@@ -1379,6 +1385,93 @@ describe("media-stream setup outcome scenarios", () => {
|
|
|
1379
1385
|
|
|
1380
1386
|
session.destroy();
|
|
1381
1387
|
});
|
|
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
|
+
});
|
|
1382
1475
|
});
|
|
1383
1476
|
|
|
1384
1477
|
// ── 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 { setConfig } from "../../__tests__/helpers/set-config.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 { MediaStreamSttSession } from "../media-stream-stt-session.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 "../
|
|
3
|
+
import { MediaTurnDetector } from "../media-turn-detector.js";
|
|
4
4
|
|
|
5
5
|
// ---------------------------------------------------------------------------
|
|
6
6
|
// Helpers
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { VoiceProgressConfigSchema } from "../../config/schemas/voice.js";
|
|
4
4
|
import type { Provider, ProviderResponse } from "../../providers/types.js";
|
|
5
5
|
import {
|
|
6
6
|
createVoiceProgressNarrator,
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
type VoiceProgressTextInput,
|
|
9
9
|
} from "../progress-narration.js";
|
|
10
10
|
|
|
11
|
-
const config =
|
|
11
|
+
const config = VoiceProgressConfigSchema.parse({});
|
|
12
12
|
const progressInput: VoiceProgressTextInput = {
|
|
13
13
|
transcriptSoFar: "compare flight prices for next month",
|
|
14
14
|
completedOps: [
|
|
@@ -177,7 +177,7 @@ describe("createVoiceProgressNarrator", () => {
|
|
|
177
177
|
|
|
178
178
|
test("bounds provider resolution by the configured timeout", async () => {
|
|
179
179
|
const narrator = createVoiceProgressNarrator({
|
|
180
|
-
config:
|
|
180
|
+
config: VoiceProgressConfigSchema.parse({ generationTimeoutMs: 20 }),
|
|
181
181
|
getProvider: () => new Promise<Provider | null>(() => {}),
|
|
182
182
|
});
|
|
183
183
|
const startedAt = Date.now();
|
|
@@ -187,7 +187,7 @@ describe("createVoiceProgressNarrator", () => {
|
|
|
187
187
|
|
|
188
188
|
test("a caller abort settles promptly", async () => {
|
|
189
189
|
const narrator = createVoiceProgressNarrator({
|
|
190
|
-
config:
|
|
190
|
+
config: VoiceProgressConfigSchema.parse({
|
|
191
191
|
generationTimeoutMs: 60_000,
|
|
192
192
|
}),
|
|
193
193
|
getProvider: async () =>
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
|
|
9
9
|
import { describe, expect, test } from "bun:test";
|
|
10
10
|
|
|
11
|
-
import { BRIDGE_SENTENCE_END_REGEX } from "../../calls/voice-triage-escalate.js";
|
|
12
11
|
import { DEEPGRAM_MULTI_LANGUAGE_CODES } from "../../providers/speech-to-text/deepgram.js";
|
|
13
12
|
import {
|
|
14
13
|
APPROVAL_PENDING_PHRASE,
|
|
@@ -18,6 +17,7 @@ import {
|
|
|
18
17
|
PROGRESS_FALLBACK_PHRASES,
|
|
19
18
|
PROGRESS_FALLBACK_PHRASES_BY_LANGUAGE,
|
|
20
19
|
} from "../progress-phrases.js";
|
|
20
|
+
import { BRIDGE_SENTENCE_END_REGEX } from "../voice-triage-escalate.js";
|
|
21
21
|
|
|
22
22
|
// Scripts without space-delimited words, where a word budget is
|
|
23
23
|
// meaningless and length is asserted instead.
|