@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
|
@@ -1,13 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for `startVoiceTurn`'s turn flow against real persistence: delta and
|
|
3
|
+
* error forwarding, abort handling, persisted channel metadata, the auto-built
|
|
4
|
+
* phone control prompt, and the approval-policy split between guardian and
|
|
5
|
+
* non-guardian callers. The sibling `voice-session-bridge.test.ts` covers the
|
|
6
|
+
* routing legs, transcript hygiene, tool-event forwarding, and the lock and
|
|
7
|
+
* teardown races against scripted doubles.
|
|
8
|
+
*/
|
|
1
9
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
10
|
|
|
3
|
-
import
|
|
11
|
+
import { setConfig } from "../../__tests__/helpers/set-config.js";
|
|
12
|
+
import type { AssistantEvent } from "../../api/index.js";
|
|
4
13
|
import type {
|
|
5
14
|
TurnChannelContext,
|
|
6
15
|
TurnInterfaceContext,
|
|
7
|
-
} from "
|
|
8
|
-
import type { Conversation } from "
|
|
9
|
-
import { persistUserMessage as persistUserMessageImpl } from "
|
|
10
|
-
import { setConfig } from "./helpers/set-config.js";
|
|
16
|
+
} from "../../channels/types.js";
|
|
17
|
+
import type { Conversation } from "../../daemon/conversation.js";
|
|
18
|
+
import { persistUserMessage as persistUserMessageImpl } from "../../daemon/conversation-messaging.js";
|
|
11
19
|
|
|
12
20
|
/** Seed the config the voice bridge reads: disclosure copy, plus disabled
|
|
13
21
|
* secret detection and memory so the real persist path stays inert. */
|
|
@@ -19,7 +27,7 @@ function seedVoiceConfig(disclosure: { enabled: boolean; text: string }): void {
|
|
|
19
27
|
|
|
20
28
|
let voiceConversationFactory: (() => Conversation) | null = null;
|
|
21
29
|
|
|
22
|
-
mock.module("
|
|
30
|
+
mock.module("../../daemon/conversation-store.js", () => ({
|
|
23
31
|
getOrCreateConversation: async () => {
|
|
24
32
|
if (!voiceConversationFactory) {
|
|
25
33
|
throw new Error("voiceConversationFactory not set for test");
|
|
@@ -28,18 +36,18 @@ mock.module("../daemon/conversation-store.js", () => ({
|
|
|
28
36
|
},
|
|
29
37
|
}));
|
|
30
38
|
|
|
31
|
-
import { CALL_OPENING_MARKER } from "../calls/voice-control-protocol.js";
|
|
32
|
-
import { startVoiceTurn } from "../calls/voice-session-bridge.js";
|
|
33
39
|
import {
|
|
34
40
|
createConversation,
|
|
35
41
|
getMessages,
|
|
36
|
-
} from "
|
|
37
|
-
import { getDb } from "
|
|
38
|
-
import { initializeDb } from "
|
|
42
|
+
} from "../../persistence/conversation-crud.js";
|
|
43
|
+
import { getDb } from "../../persistence/db-connection.js";
|
|
44
|
+
import { initializeDb } from "../../persistence/db-init.js";
|
|
39
45
|
import {
|
|
40
46
|
assistantEventHub,
|
|
41
47
|
broadcastMessage,
|
|
42
|
-
} from "
|
|
48
|
+
} from "../../runtime/assistant-event-hub.js";
|
|
49
|
+
import { CALL_OPENING_MARKER } from "../voice-control-protocol.js";
|
|
50
|
+
import { startVoiceTurn } from "../voice-session-bridge.js";
|
|
43
51
|
|
|
44
52
|
await initializeDb();
|
|
45
53
|
|
|
@@ -842,6 +842,42 @@ describe("startVoiceTurn triage-and-escalate control prompt", () => {
|
|
|
842
842
|
expect(installed()).toContain(escalatedContinuationRule());
|
|
843
843
|
});
|
|
844
844
|
|
|
845
|
+
test("the auto-built phone prompt carries the front-door rule anchored to the caller's words", async () => {
|
|
846
|
+
const installed = captureInstalledPrompt();
|
|
847
|
+
await startVoiceTurn({
|
|
848
|
+
...makeTurnOptions(),
|
|
849
|
+
content: "what time is it",
|
|
850
|
+
routingLeg: "front-door",
|
|
851
|
+
});
|
|
852
|
+
expect(installed()).toContain("<voice_call_control>");
|
|
853
|
+
expect(installed()).toContain(
|
|
854
|
+
`13. ${frontDoorDecisionRule({ callerUtterance: "what time is it" })}`,
|
|
855
|
+
);
|
|
856
|
+
});
|
|
857
|
+
|
|
858
|
+
test("a phone sentinel anchors the front-door rule on its persisted form", async () => {
|
|
859
|
+
const installed = captureInstalledPrompt();
|
|
860
|
+
await startVoiceTurn({ ...makeTurnOptions(), routingLeg: "front-door" });
|
|
861
|
+
expect(installed()).toContain(
|
|
862
|
+
frontDoorDecisionRule({
|
|
863
|
+
callerUtterance: "(call connected — deliver opening greeting)",
|
|
864
|
+
}),
|
|
865
|
+
);
|
|
866
|
+
expect(installed()).not.toContain(JSON.stringify(CALL_OPENING_MARKER));
|
|
867
|
+
});
|
|
868
|
+
|
|
869
|
+
test("the auto-built phone prompt carries the escalated continuation rule", async () => {
|
|
870
|
+
const installed = captureInstalledPrompt();
|
|
871
|
+
await startVoiceTurn({
|
|
872
|
+
...makeTurnOptions(),
|
|
873
|
+
routingLeg: "escalated",
|
|
874
|
+
spokenEscalationBridge: "One moment.",
|
|
875
|
+
});
|
|
876
|
+
expect(installed()).toContain(
|
|
877
|
+
`13. ${escalatedContinuationRule("One moment.")}`,
|
|
878
|
+
);
|
|
879
|
+
});
|
|
880
|
+
|
|
845
881
|
test("leaves a caller-supplied prompt verbatim when no routing leg is set", async () => {
|
|
846
882
|
const installed = captureInstalledPrompt();
|
|
847
883
|
await startVoiceTurn({
|
|
@@ -860,7 +896,7 @@ describe("default call protocol numbered rules", () => {
|
|
|
860
896
|
const installed = captureInstalledPrompt();
|
|
861
897
|
await startVoiceTurn(makeTurnOptions());
|
|
862
898
|
expect(installed()).toContain(
|
|
863
|
-
"
|
|
899
|
+
"11. Speak the caller's language: reply in the language of the caller's most recent actual speech, and follow them if they switch languages mid-call. Synthetic user turns (parenthetical markers like the call-connected and verification-completed notices) are not caller speech and never set the language. Before the caller has spoken, such as on the opening greeting turn, use the language the Task context implies, if any; otherwise default to English.",
|
|
864
900
|
);
|
|
865
901
|
});
|
|
866
902
|
|
|
@@ -2477,6 +2513,25 @@ describe("transcript hygiene (teardown pass)", () => {
|
|
|
2477
2513
|
expect(events).toContain("loadFromDb");
|
|
2478
2514
|
});
|
|
2479
2515
|
|
|
2516
|
+
test("a row ending with a session control marker persists with it stripped", async () => {
|
|
2517
|
+
const { events } = makeReservedRowConversation();
|
|
2518
|
+
getMessageByIdImpl = () =>
|
|
2519
|
+
makeRow("Muting you for thirty seconds. [MUTE:30]");
|
|
2520
|
+
|
|
2521
|
+
await startVoiceTurn({ ...makeTurnOptions(), routingLeg: "front-door" });
|
|
2522
|
+
await flushMicrotasks();
|
|
2523
|
+
|
|
2524
|
+
expect(crudLog.updates).toEqual([
|
|
2525
|
+
{
|
|
2526
|
+
messageId: "assistant-row-1",
|
|
2527
|
+
content: JSON.stringify([
|
|
2528
|
+
{ type: "text", text: "Muting you for thirty seconds." },
|
|
2529
|
+
]),
|
|
2530
|
+
},
|
|
2531
|
+
]);
|
|
2532
|
+
expect(events).toContain("loadFromDb");
|
|
2533
|
+
});
|
|
2534
|
+
|
|
2480
2535
|
test("a mid-text [-1] (content, not command) leaves the row untouched", async () => {
|
|
2481
2536
|
const { events } = makeReservedRowConversation();
|
|
2482
2537
|
getMessageByIdImpl = () =>
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
capEscalationBridge,
|
|
6
6
|
classifyFrontDoorLeading,
|
|
7
7
|
createFrontDoorStreamGate,
|
|
8
|
+
createFrontDoorVerdictMachine,
|
|
8
9
|
ESCALATE_VERDICT_TOKEN,
|
|
9
10
|
escalatedContinuationRule,
|
|
10
11
|
ESCALATION_CONTINUATION_CONTENT,
|
|
@@ -17,6 +18,7 @@ import {
|
|
|
17
18
|
isEscalationBridgeComplete,
|
|
18
19
|
MAX_ESCALATION_BRIDGE_CHARS,
|
|
19
20
|
needsFallbackBridge,
|
|
21
|
+
resolveSpokenEscalationBridge,
|
|
20
22
|
spokenBridgeText,
|
|
21
23
|
} from "../voice-triage-escalate.js";
|
|
22
24
|
|
|
@@ -281,6 +283,34 @@ describe("fallbackEscalationBridgeFor", () => {
|
|
|
281
283
|
});
|
|
282
284
|
});
|
|
283
285
|
|
|
286
|
+
describe("resolveSpokenEscalationBridge", () => {
|
|
287
|
+
test("a real capped bridge is spoken as the model's own speech", () => {
|
|
288
|
+
expect(resolveSpokenEscalationBridge("Let me check that.", "es")).toEqual({
|
|
289
|
+
spokenBridge: "Let me check that.",
|
|
290
|
+
usesFallback: false,
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
test("an empty or too-short bridge falls back to the localized canned phrase, audio-only", () => {
|
|
295
|
+
expect(resolveSpokenEscalationBridge("", "es")).toEqual({
|
|
296
|
+
spokenBridge: FALLBACK_ESCALATION_BRIDGE_BY_LANGUAGE.es,
|
|
297
|
+
usesFallback: true,
|
|
298
|
+
});
|
|
299
|
+
expect(resolveSpokenEscalationBridge("Ok", undefined)).toEqual({
|
|
300
|
+
spokenBridge: FALLBACK_ESCALATION_BRIDGE,
|
|
301
|
+
usesFallback: true,
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
test("a canned phrase the table lacks for the caller's language is English and says so", () => {
|
|
306
|
+
expect(resolveSpokenEscalationBridge("", "ko")).toEqual({
|
|
307
|
+
spokenBridge: FALLBACK_ESCALATION_BRIDGE,
|
|
308
|
+
usesFallback: true,
|
|
309
|
+
language: "en",
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
|
|
284
314
|
describe("capEscalationBridge", () => {
|
|
285
315
|
test("cuts just after the first sentence terminator", () => {
|
|
286
316
|
expect(
|
|
@@ -449,6 +479,81 @@ describe("live-voice escalation orchestration (end-to-end — TODO)", () => {
|
|
|
449
479
|
);
|
|
450
480
|
});
|
|
451
481
|
|
|
482
|
+
describe("createFrontDoorVerdictMachine", () => {
|
|
483
|
+
/** Feed `deltas` through a machine and return the step kinds, in order. */
|
|
484
|
+
function kinds(deltas: string[], holdEnabled = false): string[] {
|
|
485
|
+
const machine = createFrontDoorVerdictMachine(holdEnabled);
|
|
486
|
+
return deltas.map((delta) => machine.push(delta).kind);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
test("stays pending while the lead could still become a token", () => {
|
|
490
|
+
expect(kinds(["", "[", "1"])).toEqual(["pending", "pending", "pending"]);
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
test("an answer releases the held lead on the transition, then each delta", () => {
|
|
494
|
+
const machine = createFrontDoorVerdictMachine(false);
|
|
495
|
+
expect(machine.push("[")).toEqual({ kind: "pending" });
|
|
496
|
+
expect(machine.push("A] first")).toEqual({
|
|
497
|
+
kind: "answer",
|
|
498
|
+
text: "[A] first",
|
|
499
|
+
});
|
|
500
|
+
expect(machine.push(", second")).toEqual({
|
|
501
|
+
kind: "answer",
|
|
502
|
+
text: ", second",
|
|
503
|
+
});
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
test("escalate reports the capped bridge on the delta that completes it", () => {
|
|
507
|
+
const machine = createFrontDoorVerdictMachine(false);
|
|
508
|
+
expect(machine.push(`${ESCALATE_VERDICT_TOKEN} One `)).toEqual({
|
|
509
|
+
kind: "escalate",
|
|
510
|
+
bridge: null,
|
|
511
|
+
});
|
|
512
|
+
expect(machine.push("moment")).toEqual({ kind: "bridging" });
|
|
513
|
+
expect(machine.push(". Extra text past the cap")).toEqual({
|
|
514
|
+
kind: "bridge",
|
|
515
|
+
bridge: "One moment.",
|
|
516
|
+
});
|
|
517
|
+
expect(machine.push(" more")).toEqual({ kind: "done" });
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
test("a bridge that completes on the verdict delta is reported with it", () => {
|
|
521
|
+
const machine = createFrontDoorVerdictMachine(false);
|
|
522
|
+
expect(machine.push(`${ESCALATE_VERDICT_TOKEN} Let me check.`)).toEqual({
|
|
523
|
+
kind: "escalate",
|
|
524
|
+
bridge: "Let me check.",
|
|
525
|
+
});
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
test("finish hands off a bridge that never hit a terminator", () => {
|
|
529
|
+
const machine = createFrontDoorVerdictMachine(false);
|
|
530
|
+
machine.push(`${ESCALATE_VERDICT_TOKEN} Give me a second`);
|
|
531
|
+
expect(machine.finish()).toEqual({
|
|
532
|
+
kind: "bridge",
|
|
533
|
+
bridge: "Give me a second",
|
|
534
|
+
});
|
|
535
|
+
expect(machine.push("late")).toEqual({ kind: "done" });
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
test("finish on an answer or a pending lead is done, not a bridge", () => {
|
|
539
|
+
const answering = createFrontDoorVerdictMachine(false);
|
|
540
|
+
answering.push("Sure.");
|
|
541
|
+
expect(answering.finish()).toEqual({ kind: "done" });
|
|
542
|
+
const undecided = createFrontDoorVerdictMachine(false);
|
|
543
|
+
undecided.push("[");
|
|
544
|
+
expect(undecided.finish()).toEqual({ kind: "done" });
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
test("hold is a step only when the leg was taught the token", () => {
|
|
548
|
+
expect(kinds([HOLD_VERDICT_TOKEN], true)).toEqual(["hold"]);
|
|
549
|
+
expect(kinds([`${HOLD_VERDICT_TOKEN} trailing`], true)).toEqual(["hold"]);
|
|
550
|
+
expect(kinds([HOLD_VERDICT_TOKEN], false)).toEqual(["answer"]);
|
|
551
|
+
const held = createFrontDoorVerdictMachine(true);
|
|
552
|
+
held.push(HOLD_VERDICT_TOKEN);
|
|
553
|
+
expect(held.push("anything")).toEqual({ kind: "done" });
|
|
554
|
+
});
|
|
555
|
+
});
|
|
556
|
+
|
|
452
557
|
describe("createFrontDoorStreamGate", () => {
|
|
453
558
|
/** Feed `deltas` through a gate and return what it released, in order. */
|
|
454
559
|
function release(
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sustained-speech barge-in guard, shared by the live-voice session and
|
|
3
|
+
* the phone media-stream path.
|
|
4
|
+
*
|
|
5
|
+
* A single above-gate audio chunk is not an interruption: brief TTS bleed
|
|
6
|
+
* through imperfect echo cancellation, a cough, a line click. Speech has to
|
|
7
|
+
* accumulate to `minSpeechMs` before the assistant is cut off. Short gaps
|
|
8
|
+
* inside a run are tolerated (a browser's half-duplex echo canceller ducks
|
|
9
|
+
* the near-end voice into intermittent above-gate chunks; a phone line
|
|
10
|
+
* drops frames), but a longer continuous silence, or a run that is mostly
|
|
11
|
+
* silence, resets it, so sparse periodic blips can never sum into a
|
|
12
|
+
* barge-in.
|
|
13
|
+
*
|
|
14
|
+
* The guard is pure accounting over classified chunks. What arms it, what
|
|
15
|
+
* classifies a chunk, and what happens when it fires belong to the driver.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** Sustained speech required before a barge-in fires. */
|
|
19
|
+
export const DEFAULT_BARGE_IN_MIN_SPEECH_MS = 250;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Longest continuous sub-threshold gap tolerated inside a run. A gap of
|
|
23
|
+
* exactly this length still counts as inside the run: the web client
|
|
24
|
+
* batches PCM into 50 ms frames, so a run of ducked frames lands on the
|
|
25
|
+
* boundary exactly (four frames = 200 ms).
|
|
26
|
+
*/
|
|
27
|
+
export const BARGE_IN_GAP_TOLERANCE_MS = 200;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Ceiling on cumulative sub-threshold time across a whole run, as a
|
|
31
|
+
* multiple of `minSpeechMs`. Per-gap tolerance alone lets sparse isolated
|
|
32
|
+
* blips (a 10 ms echo spike every 200 ms) each clear the consecutive-gap
|
|
33
|
+
* timer while retaining prior speech, so they would sum to the guard over
|
|
34
|
+
* several seconds. Capping total tolerated silence imposes a minimum
|
|
35
|
+
* above-gate duty cycle (1 / (1 + ratio), about 20%): once the run is mostly
|
|
36
|
+
* silence it resets, so genuine choppy speech still lands but periodic noise
|
|
37
|
+
* cannot accumulate into one.
|
|
38
|
+
*/
|
|
39
|
+
export const BARGE_IN_MAX_TOLERATED_SILENCE_RATIO = 4;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* How a chunk reads to the guard. `echo` is the assistant's own playback
|
|
43
|
+
* heard back through the microphone, which live voice classifies; a phone
|
|
44
|
+
* line carries only the caller's track and never produces it.
|
|
45
|
+
*/
|
|
46
|
+
export type BargeInChunkClassification = "speech" | "silence" | "echo";
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* What one chunk did to the run: `pending` (still accumulating, or a
|
|
50
|
+
* tolerated gap), `reset` (echo, or a gap past the limits, dropped the run),
|
|
51
|
+
* `fired` (sustained speech reached the threshold; the guard is spent).
|
|
52
|
+
*/
|
|
53
|
+
export type BargeInGuardStep = "pending" | "reset" | "fired";
|
|
54
|
+
|
|
55
|
+
export interface BargeInGuard {
|
|
56
|
+
/** Speech accumulated in the current run. */
|
|
57
|
+
readonly speechMs: number;
|
|
58
|
+
/** Feed one classified chunk of `chunkMs` audio. */
|
|
59
|
+
track(
|
|
60
|
+
classification: BargeInChunkClassification,
|
|
61
|
+
chunkMs: number,
|
|
62
|
+
): BargeInGuardStep;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Build a guard that fires after `minSpeechMs` of sustained speech. A zero
|
|
67
|
+
* threshold fires on the first speech chunk (instant barge-in).
|
|
68
|
+
*/
|
|
69
|
+
export function createBargeInGuard(minSpeechMs: number): BargeInGuard {
|
|
70
|
+
let speechMs = 0;
|
|
71
|
+
// Consecutive sub-threshold time since the last speech chunk.
|
|
72
|
+
let silenceMs = 0;
|
|
73
|
+
// Cumulative sub-threshold time over the whole run, never reset by speech.
|
|
74
|
+
let toleratedSilenceMs = 0;
|
|
75
|
+
let fired = false;
|
|
76
|
+
|
|
77
|
+
const reset = (): BargeInGuardStep => {
|
|
78
|
+
speechMs = 0;
|
|
79
|
+
silenceMs = 0;
|
|
80
|
+
toleratedSilenceMs = 0;
|
|
81
|
+
return "reset";
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
get speechMs() {
|
|
86
|
+
return speechMs;
|
|
87
|
+
},
|
|
88
|
+
track(classification, chunkMs) {
|
|
89
|
+
if (fired) {
|
|
90
|
+
return "fired";
|
|
91
|
+
}
|
|
92
|
+
if (classification === "echo") {
|
|
93
|
+
return reset();
|
|
94
|
+
}
|
|
95
|
+
if (classification === "silence") {
|
|
96
|
+
silenceMs += chunkMs;
|
|
97
|
+
toleratedSilenceMs += chunkMs;
|
|
98
|
+
// Strictly greater on the per-gap check: a gap of exactly the
|
|
99
|
+
// tolerance is still inside the run.
|
|
100
|
+
if (
|
|
101
|
+
silenceMs > BARGE_IN_GAP_TOLERANCE_MS ||
|
|
102
|
+
toleratedSilenceMs >
|
|
103
|
+
minSpeechMs * BARGE_IN_MAX_TOLERATED_SILENCE_RATIO
|
|
104
|
+
) {
|
|
105
|
+
return reset();
|
|
106
|
+
}
|
|
107
|
+
return "pending";
|
|
108
|
+
}
|
|
109
|
+
silenceMs = 0;
|
|
110
|
+
speechMs += chunkMs;
|
|
111
|
+
if (speechMs < minSpeechMs) {
|
|
112
|
+
return "pending";
|
|
113
|
+
}
|
|
114
|
+
fired = true;
|
|
115
|
+
return "fired";
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}
|
|
@@ -69,15 +69,35 @@ export function getGuardianWaitUpdateSteadyMaxIntervalMs(): number {
|
|
|
69
69
|
return getConfig().calls.guardianWaitUpdateSteadyMaxIntervalMs;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
// Fixed conversational timings. Named here, beside the config-backed limits
|
|
73
|
+
// above, so the phone path's cadence is readable in one place.
|
|
74
|
+
|
|
75
|
+
/** Caller silence after the assistant's turn before it nudges them. */
|
|
76
|
+
export const CALLER_SILENCE_NUDGE_MS = 30_000;
|
|
77
|
+
|
|
78
|
+
/** Listen window after the goodbye drains, in case the caller re-engages. */
|
|
79
|
+
export const END_CALL_LISTEN_WINDOW_MS = 2_000;
|
|
80
|
+
|
|
81
|
+
/** Max time to wait for goodbye audio to drain before forcing hangup. */
|
|
82
|
+
export const END_CALL_DRAIN_MAX_WAIT_MS = 15_000;
|
|
83
|
+
|
|
84
|
+
/** Lead before the max call duration at which the low-on-time warning is spoken. */
|
|
85
|
+
export const DURATION_WARNING_LEAD_MS = 2 * 60 * 1000;
|
|
86
|
+
|
|
87
|
+
/** Delay after the max-duration goodbye is spoken before the call is ended. */
|
|
88
|
+
export const POST_GOODBYE_HANGUP_DELAY_MS = 3_000;
|
|
89
|
+
|
|
90
|
+
/** Cap on waiting for a superseded turn's teardown before the next caller turn starts. */
|
|
91
|
+
export const BARGE_IN_TEARDOWN_WAIT_MS = 2_000;
|
|
92
|
+
|
|
72
93
|
export function getSilenceTimeoutMs(): number {
|
|
73
|
-
return
|
|
94
|
+
return CALLER_SILENCE_NUDGE_MS;
|
|
74
95
|
}
|
|
75
96
|
|
|
76
97
|
export function getEndCallListenWindowMs(): number {
|
|
77
|
-
return
|
|
98
|
+
return END_CALL_LISTEN_WINDOW_MS;
|
|
78
99
|
}
|
|
79
100
|
|
|
80
|
-
/** Max time to wait for goodbye audio to drain before forcing hangup. */
|
|
81
101
|
export function getEndCallDrainMaxWaitMs(): number {
|
|
82
|
-
return
|
|
102
|
+
return END_CALL_DRAIN_MAX_WAIT_MS;
|
|
83
103
|
}
|