@vellumai/assistant 0.10.4 → 0.10.5-dev.202607022329.d89bf2f
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +94 -91
- package/Dockerfile +5 -16
- package/README.md +7 -10
- package/bun.lock +0 -4
- package/docs/architecture/security.md +20 -20
- package/docs/stt-provider-onboarding.md +4 -5
- package/docs/trusted-contact-access.md +7 -7
- package/eslint-rules/cli-no-daemon-internals.js +4 -0
- package/eslint.config.mjs +7 -1
- package/knip.json +0 -1
- package/node_modules/@vellumai/gateway-client/src/__tests__/contact-read-contracts.test.ts +36 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/invite-contract.test.ts +233 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +40 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +20 -8
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +10 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +33 -0
- package/node_modules/@vellumai/gateway-client/src/invite-contract.ts +216 -0
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +91 -0
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +39 -3
- package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +0 -8
- package/node_modules/@vellumai/service-contracts/src/__tests__/package-boundary.test.ts +1 -5
- package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +3 -14
- package/openapi.yaml +1073 -225
- package/package.json +1 -4
- package/scripts/test.sh +35 -13
- package/src/__tests__/access-request-seed-content-blocks.test.ts +60 -4
- package/src/__tests__/acp-session.test.ts +4 -1
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +0 -6
- package/src/__tests__/add-message-preassigned-id.test.ts +56 -0
- package/src/__tests__/agent-loop-set-system-prompt.test.ts +139 -0
- package/src/__tests__/app-conversation-ids-backfill.test.ts +3 -0
- package/src/__tests__/app-source-watcher.test.ts +11 -0
- package/src/__tests__/approval-interception-trust-gates.test.ts +148 -3
- package/src/__tests__/assistant-attachments.test.ts +62 -4
- package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -1
- package/src/__tests__/attachments-store-heic-normalize.test.ts +230 -0
- package/src/__tests__/attachments-store.test.ts +3 -0
- package/src/__tests__/background-shell-bash.test.ts +34 -0
- package/src/__tests__/background-shell-host-bash.test.ts +12 -0
- package/src/__tests__/background-tool-registry.test.ts +97 -0
- package/src/__tests__/background-tool-routes.test.ts +72 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +2 -1
- package/src/__tests__/btw-routes.test.ts +57 -3
- package/src/__tests__/call-controller.test.ts +474 -84
- package/src/__tests__/call-domain.test.ts +48 -1
- package/src/__tests__/call-pointer-messages.test.ts +57 -19
- package/src/__tests__/call-pointer-no-hardcoded-copy.guard.test.ts +2 -6
- package/src/__tests__/call-routes-http.test.ts +15 -14
- package/src/__tests__/call-setup-flow-invite.test.ts +568 -0
- package/src/__tests__/call-setup-flow-midcall-trust.test.ts +231 -0
- package/src/__tests__/call-setup-flow-name-capture.test.ts +754 -0
- package/src/__tests__/call-setup-flow-verification.test.ts +925 -0
- package/src/__tests__/call-setup-flow.test.ts +311 -0
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +0 -1
- package/src/__tests__/channel-guardian.test.ts +4 -7
- package/src/__tests__/channel-readiness-service.test.ts +0 -6
- package/src/__tests__/channel-readiness-slack-remote.test.ts +0 -4
- package/src/__tests__/channel-retry-sweep.test.ts +76 -64
- package/src/__tests__/channel-setup-panel-ack.test.ts +184 -0
- package/src/__tests__/clear-all-lexical.test.ts +90 -0
- package/src/__tests__/compactor-media-strip.test.ts +177 -0
- package/src/__tests__/config-loader-backfill.test.ts +5 -5
- package/src/__tests__/config-schema.test.ts +17 -0
- package/src/__tests__/contact-store-interaction-info.test.ts +27 -70
- package/src/__tests__/contacts-relay-reads.test.ts +188 -23
- package/src/__tests__/contacts-tools.test.ts +42 -1
- package/src/__tests__/contacts-write.test.ts +181 -0
- package/src/__tests__/context-search-conversations-source.test.ts +220 -81
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop.test.ts +39 -0
- package/src/__tests__/conversation-analysis-routes.test.ts +1 -1
- package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -0
- package/src/__tests__/conversation-clear-safety.test.ts +0 -1
- package/src/__tests__/conversation-crud-enabled-plugins.test.ts +60 -0
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -1
- package/src/__tests__/conversation-disk-view.test.ts +1 -0
- package/src/__tests__/conversation-enabledplugins-route.test.ts +184 -0
- package/src/__tests__/conversation-error.test.ts +0 -18
- package/src/__tests__/conversation-fork-crud.test.ts +67 -0
- package/src/__tests__/conversation-history-web-search.test.ts +7 -137
- package/src/__tests__/conversation-initial-prompt.test.ts +110 -0
- package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +191 -0
- package/src/__tests__/conversation-process-callsite.test.ts +37 -0
- package/src/__tests__/conversation-queue.test.ts +149 -0
- package/src/__tests__/conversation-routes-enabled-plugins.test.ts +392 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +84 -0
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +407 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +36 -16
- package/src/__tests__/conversation-skill-tools.test.ts +73 -0
- package/src/__tests__/conversation-wipe.test.ts +20 -5
- package/src/__tests__/credential-prompt-route.test.ts +69 -0
- package/src/__tests__/credential-security-invariants.test.ts +1 -3
- package/src/__tests__/db-drop-messages-fts.test.ts +115 -0
- package/src/__tests__/deterministic-verification-control-plane.test.ts +1 -62
- package/src/__tests__/edit-propagation.test.ts +56 -2
- package/src/__tests__/empty-state-greeting-cache.test.ts +9 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +15 -110
- package/src/__tests__/guardian-expiry-notifier.test.ts +1 -0
- package/src/__tests__/guardian-question-mode.test.ts +57 -0
- package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -1
- package/src/__tests__/guardian-wait-controller.test.ts +619 -0
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +33 -2
- package/src/__tests__/heic-fixture.ts +55 -0
- package/src/__tests__/helpers/seed-contact-channel.ts +0 -2
- package/src/__tests__/http-conversation-lineage.test.ts +6 -1
- package/src/__tests__/image-conversion.test.ts +170 -0
- package/src/__tests__/inbound-invite-redemption.test.ts +72 -341
- package/src/__tests__/introduction-card-resolver.test.ts +354 -0
- package/src/__tests__/invite-redeemed-ipc.test.ts +97 -0
- package/src/__tests__/invite-routes-http.test.ts +246 -420
- package/src/__tests__/job-handler-registration-guard.test.ts +104 -0
- package/src/__tests__/lexical-index-dual-write.test.ts +426 -0
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +2 -2
- package/src/__tests__/list-messages-attachments.test.ts +159 -0
- package/src/__tests__/list-messages-background-tool-completion.test.ts +141 -0
- package/src/__tests__/list-messages-queued.test.ts +25 -0
- package/src/__tests__/managed-store.test.ts +129 -1
- package/src/__tests__/media-stream-audio-transcode.test.ts +113 -0
- package/src/__tests__/media-stream-output.test.ts +350 -19
- package/src/__tests__/media-stream-server-integration.test.ts +943 -169
- package/src/__tests__/media-stream-stt-session.test.ts +498 -1
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +2 -2
- package/src/__tests__/model-intents.test.ts +1 -1
- package/src/__tests__/mtime-cache.test.ts +19 -0
- package/src/__tests__/non-member-access-request.test.ts +349 -3
- package/src/__tests__/notification-decision-fallback.test.ts +104 -8
- package/src/__tests__/notification-decision-strategy.test.ts +57 -8
- package/src/__tests__/onboarding-template-contract.test.ts +27 -43
- package/src/__tests__/openai-provider.test.ts +33 -0
- package/src/__tests__/openai-responses-provider.test.ts +40 -0
- package/src/__tests__/persistence-layering-guard.test.ts +29 -20
- package/src/__tests__/persona-resolver.test.ts +56 -2
- package/src/__tests__/personal-memory-auth-bypass.test.ts +62 -0
- package/src/__tests__/phone.test.ts +1 -15
- package/src/__tests__/plugin-bootstrap.test.ts +25 -196
- package/src/__tests__/plugin-disabled-state.test.ts +33 -0
- package/src/__tests__/plugin-effective-enabled-set.test.ts +227 -0
- package/src/__tests__/plugin-event-hub-facade.test.ts +323 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +156 -42
- package/src/__tests__/plugin-injector-contribution.test.ts +4 -20
- package/src/__tests__/plugin-pipeline.test.ts +63 -1
- package/src/__tests__/plugin-route-contribution.test.ts +62 -115
- package/src/__tests__/plugin-tool-contribution.test.ts +0 -22
- package/src/__tests__/plugin-types.test.ts +0 -1
- package/src/__tests__/pointer-conversation-trust.test.ts +38 -6
- package/src/__tests__/pre-model-call-sanitize.test.ts +1 -1
- package/src/__tests__/prune-old-tool-invocations-job.test.ts +97 -0
- package/src/__tests__/public-ingress-urls.test.ts +0 -48
- package/src/__tests__/qdrant-collection-migration.test.ts +145 -2
- package/src/__tests__/reaction-intercept-member-verdict-warm.test.ts +0 -1
- package/src/__tests__/resolve-trust-class.test.ts +28 -10
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +137 -0
- package/src/__tests__/schedule-retry.test.ts +38 -14
- package/src/__tests__/schedule-routes-workflow-validation.test.ts +3 -3
- package/src/__tests__/schedule-routes.test.ts +14 -6
- package/src/__tests__/schedule-store.test.ts +3 -1
- package/src/__tests__/scheduler-disk-pressure.test.ts +17 -6
- package/src/__tests__/scheduler-recurrence.test.ts +57 -107
- package/src/__tests__/scheduler-reuse-conversation.test.ts +51 -46
- package/src/__tests__/scheduler-wake.test.ts +13 -23
- package/src/__tests__/scheduler-worker-standdown.test.ts +220 -0
- package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -1
- package/src/__tests__/shell-observability.test.ts +1 -0
- package/src/__tests__/skill-boundary-guard.test.ts +3 -4
- package/src/__tests__/skill-load-plugin-scope.test.ts +238 -0
- package/src/__tests__/skill-projection-feature-flag.test.ts +2 -0
- package/src/__tests__/skill-script-runner-host.test.ts +53 -0
- package/src/__tests__/skill-script-runner-sandbox.test.ts +5 -2
- package/src/__tests__/skill-tool-factory.test.ts +73 -1
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +37 -14
- package/src/__tests__/slack-inbound-verification.test.ts +36 -0
- package/src/__tests__/slack-notification-approval-card.test.ts +89 -2
- package/src/__tests__/slack-reaction-canonical-approval.test.ts +51 -1
- package/src/__tests__/stt-hints.test.ts +2 -256
- package/src/__tests__/subagent-allowlist-validation.test.ts +47 -0
- package/src/__tests__/subagent-call-site-routing.test.ts +72 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +14 -2
- package/src/__tests__/subagent-persistence.test.ts +122 -0
- package/src/__tests__/subagent-spawn-and-await.test.ts +1 -0
- package/src/__tests__/subagent-terminal-message.test.ts +99 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +78 -1
- package/src/__tests__/system-prompt.test.ts +17 -118
- package/src/__tests__/task-scheduler.test.ts +68 -89
- package/src/__tests__/telephony-credential-preflight.test.ts +312 -0
- package/src/__tests__/telephony-tts-guard.test.ts +538 -0
- package/src/__tests__/title-generate-hook.test.ts +16 -0
- package/src/__tests__/tool-approval-handler.test.ts +87 -1
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +45 -20
- package/src/__tests__/tool-grant-request-escalation.test.ts +39 -0
- package/src/__tests__/trust-context-guards.test.ts +21 -10
- package/src/__tests__/trusted-contact-multichannel.test.ts +4 -0
- package/src/__tests__/twilio-provider.test.ts +17 -17
- package/src/__tests__/twilio-routes-twiml.test.ts +6 -543
- package/src/__tests__/twilio-routes.test.ts +257 -387
- package/src/__tests__/twilio-validation.test.ts +1 -1
- package/src/__tests__/unified-turn-context-client-os.test.ts +45 -0
- package/src/__tests__/usage-cache-backfill-migration.test.ts +5 -0
- package/src/__tests__/voice-approval-resolver-relay.test.ts +150 -0
- package/src/__tests__/voice-ingress-preflight.test.ts +61 -0
- package/src/__tests__/voice-quality.test.ts +2 -2
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +1 -7
- package/src/__tests__/voice-session-bridge-processing-wait.test.ts +27 -0
- package/src/__tests__/voice-session-bridge.test.ts +1 -10
- package/src/__tests__/workspace-git-service.test.ts +1 -1
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +1 -0
- package/src/__tests__/workspace-migration-118-seed-now-md.test.ts +120 -0
- package/src/__tests__/workspace-migration-120-revise-onboarding-threads.test.ts +175 -0
- package/src/__tests__/workspace-migration-121-seed-default-user-guardrails.test.ts +118 -0
- package/src/__tests__/workspace-migration-122-relocate-default-user-boundary.test.ts +119 -0
- package/src/__tests__/workspace-migration-123-swap-quality-profile-to-fable.test.ts +191 -0
- package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +235 -241
- package/src/acp/__tests__/prepare-agent-env.test.ts +0 -97
- package/src/acp/__tests__/session-manager-persistence.test.ts +2 -0
- package/src/acp/__tests__/session-manager-resume.test.ts +8 -0
- package/src/acp/__tests__/session-manager-usage.test.ts +6 -0
- package/src/acp/__tests__/session-manager.test.ts +6 -0
- package/src/acp/agent-process.test.ts +116 -0
- package/src/acp/agent-process.ts +71 -0
- package/src/acp/auto-install.ts +12 -8
- package/src/acp/failure-error.test.ts +109 -0
- package/src/acp/failure-error.ts +111 -0
- package/src/acp/prepare-agent-env.ts +0 -12
- package/src/acp/resolve-agent.test.ts +6 -45
- package/src/acp/resolve-agent.ts +2 -4
- package/src/acp/session-manager.test.ts +312 -0
- package/src/acp/session-manager.ts +102 -46
- package/src/agent/ax-tree-compaction.test.ts +4 -1
- package/src/agent/image-optimize.ts +17 -127
- package/src/agent/loop.ts +45 -192
- package/src/api/events/background-tool-completed.test.ts +51 -0
- package/src/api/events/background-tool-completed.ts +29 -0
- package/src/api/events/background-tool-started.test.ts +36 -0
- package/src/api/events/background-tool-started.ts +28 -0
- package/src/api/events/conversation-error.ts +0 -1
- package/src/api/events/open-panel.ts +33 -0
- package/src/api/events/subagent-status-changed.ts +4 -1
- package/src/api/index.ts +19 -0
- package/src/api/responses/conversation-message.ts +34 -0
- package/src/approvals/guardian-decision-primitive.ts +74 -24
- package/src/approvals/guardian-request-resolvers.ts +450 -122
- package/src/apps/app-store.ts +1 -0
- package/src/apps/shared-app-links-store.ts +1 -0
- package/src/avatar/identity-avatar.ts +3 -7
- package/src/background-wake/wake-intent-hooks.test.ts +1 -1
- package/src/calls/__tests__/fish-audio-client.test.ts +73 -0
- package/src/calls/__tests__/gateway-invite-reader.test.ts +170 -0
- package/src/calls/__tests__/relay-setup-router.test.ts +126 -102
- package/src/calls/call-controller.ts +134 -48
- package/src/calls/call-domain.ts +18 -42
- package/src/calls/call-pointer-messages.ts +51 -67
- package/src/calls/call-setup-flow-types.ts +76 -0
- package/src/calls/call-setup-flow.ts +1743 -0
- package/src/calls/call-speech-output.ts +87 -23
- package/src/calls/call-store.ts +4 -0
- package/src/calls/call-transport.ts +22 -36
- package/src/calls/fish-audio-client.ts +3 -0
- package/src/calls/gateway-invite-reader.ts +98 -0
- package/src/calls/guardian-wait-controller.ts +451 -0
- package/src/calls/media-stream-audio-transcode.ts +82 -2
- package/src/calls/media-stream-output.ts +142 -36
- package/src/calls/media-stream-server.ts +297 -178
- package/src/calls/media-stream-stt-session.ts +393 -50
- package/src/calls/media-turn-detector.ts +4 -6
- package/src/calls/relay-access-wait.ts +3 -4
- package/src/calls/relay-setup-router.ts +22 -43
- package/src/calls/relay-verification.ts +17 -24
- package/src/calls/resolve-call-tts-provider.ts +96 -29
- package/src/calls/stt-hints.ts +24 -87
- package/src/calls/telephony-credential-preflight.ts +159 -0
- package/src/calls/telephony-tts-capability.ts +183 -0
- package/src/calls/tts-call-strategy.ts +18 -20
- package/src/calls/twilio-provider.ts +3 -2
- package/src/calls/twilio-routes.ts +47 -351
- package/src/calls/types.ts +5 -3
- package/src/calls/voice-ingress-preflight.ts +9 -0
- package/src/calls/voice-quality.ts +13 -18
- package/src/calls/voice-session-bridge.ts +25 -35
- package/src/channels/__tests__/types.test.ts +28 -0
- package/src/channels/channel-verification-sessions.ts +7 -2
- package/src/channels/config.ts +0 -42
- package/src/channels/slack-thread-store.ts +12 -0
- package/src/channels/types.ts +23 -0
- package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -1
- package/src/cli/commands/__tests__/schedules.test.ts +83 -34
- package/src/cli/commands/__tests__/status.test.ts +42 -2
- package/src/cli/commands/contacts.ts +2 -2
- package/src/cli/commands/credentials.ts +17 -0
- package/src/cli/commands/monitoring.ts +191 -0
- package/src/cli/commands/schedules-worker.ts +175 -0
- package/src/cli/commands/schedules.ts +169 -43
- package/src/cli/commands/status.ts +12 -1
- package/src/cli/commands/tools.ts +5 -1
- package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +1 -0
- package/src/cli/lib/__tests__/search-plugins.test.ts +29 -1
- package/src/cli/lib/__tests__/toggle-plugin.test.ts +7 -0
- package/src/cli/lib/search-plugins.ts +6 -0
- package/src/cli/lib/toggle-plugin.ts +21 -2
- package/src/cli/program.ts +3 -1
- package/src/config/__tests__/deployment-context-defaults.test.ts +23 -0
- package/src/config/acp-defaults.test.ts +0 -10
- package/src/config/acp-defaults.ts +0 -6
- package/src/config/bundled-skills/acp/SKILL.md +13 -45
- package/src/config/bundled-skills/acp/TOOLS.json +3 -3
- package/src/config/bundled-skills/app-builder/SKILL.md +3 -3
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +9 -9
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +1 -1
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +1 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +9 -9
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +10 -7
- package/src/config/bundled-skills/skill-management/TOOLS.json +10 -0
- package/src/config/call-site-defaults.ts +0 -2
- package/src/config/feature-flag-registry.json +16 -8
- package/src/config/loader.ts +11 -0
- package/src/config/schema.ts +9 -1
- package/src/config/schemas/__tests__/memory-v2.test.ts +2 -2
- package/src/config/schemas/__tests__/memory-v3.test.ts +64 -0
- package/src/config/schemas/call-site-catalog.ts +0 -12
- package/src/config/schemas/calls.ts +8 -0
- package/src/config/schemas/elevenlabs.ts +1 -1
- package/src/config/schemas/llm.ts +0 -2
- package/src/config/schemas/memory-v2.ts +1 -1
- package/src/config/schemas/memory-v3.ts +82 -0
- package/src/config/schemas/monitoring.ts +61 -0
- package/src/config/schemas/schedules.ts +35 -0
- package/src/config/seed-inference-profiles.ts +2 -2
- package/src/config/skills-plugin-filter.test.ts +96 -0
- package/src/config/skills.ts +26 -0
- package/src/contacts/__tests__/member-write-relay.test.ts +156 -4
- package/src/contacts/canonical-guardian-store.ts +5 -0
- package/src/contacts/contact-store.ts +81 -35
- package/src/contacts/contacts-write.ts +50 -25
- package/src/contacts/member-write-relay.ts +115 -31
- package/src/contacts/types.ts +0 -8
- package/src/context/compactor.ts +29 -15
- package/src/context/outbound-sanitize.ts +202 -0
- package/src/daemon/__tests__/abort-null-controller.test.ts +167 -0
- package/src/daemon/__tests__/conversation-tool-setup-plugin-scope.test.ts +122 -0
- package/src/daemon/__tests__/embedding-reconcile.test.ts +99 -16
- package/src/daemon/__tests__/wake-conversation-ops-completion.test.ts +107 -0
- package/src/daemon/abort-watchdog.ts +7 -0
- package/src/daemon/app-source-watcher.ts +9 -0
- package/src/daemon/assistant-attachments.ts +42 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +256 -147
- package/src/daemon/conversation-agent-loop.ts +61 -68
- package/src/daemon/conversation-error.ts +1 -15
- package/src/daemon/conversation-history.ts +32 -236
- package/src/daemon/conversation-initial-prompt.ts +77 -0
- package/src/daemon/conversation-lifecycle.ts +25 -1
- package/src/daemon/conversation-messaging.ts +2 -2
- package/src/daemon/conversation-plugin-scope.ts +38 -0
- package/src/daemon/conversation-process.ts +50 -14
- package/src/daemon/conversation-runtime-assembly.ts +36 -6
- package/src/daemon/conversation-skill-tools.ts +19 -3
- package/src/daemon/conversation-store.ts +3 -3
- package/src/daemon/conversation-surfaces.ts +171 -0
- package/src/daemon/conversation-tool-setup.test.ts +95 -0
- package/src/daemon/conversation-tool-setup.ts +116 -1
- package/src/daemon/conversation-turn-finalize.ts +211 -0
- package/src/daemon/conversation.ts +92 -1
- package/src/daemon/disk-pressure-policy.ts +2 -1
- package/src/daemon/event-loop-watchdog.ts +22 -6
- package/src/daemon/external-plugins-bootstrap.ts +47 -134
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +1 -1
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +26 -14
- package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +27 -14
- package/src/daemon/handlers/__tests__/config-channels.test.ts +0 -5
- package/src/daemon/handlers/config-a2a.ts +7 -14
- package/src/daemon/handlers/config-channels.ts +2 -10
- package/src/daemon/handlers/conversation-history.ts +3 -1
- package/src/daemon/handlers/conversations.ts +0 -52
- package/src/daemon/handlers/shared.ts +4 -24
- package/src/daemon/handlers/skills.ts +4 -1
- package/src/daemon/host-cu-proxy.ts +1 -1
- package/src/daemon/lifecycle.ts +59 -472
- package/src/daemon/message-protocol.ts +3 -3
- package/src/daemon/message-provenance.ts +12 -14
- package/src/daemon/message-types/background-tools.ts +28 -0
- package/src/daemon/message-types/contacts.ts +2 -10
- package/src/daemon/message-types/conversations.ts +10 -0
- package/src/daemon/message-types/integrations.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +1 -0
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/pointer-conversation-trust.ts +23 -9
- package/src/daemon/pointer-turn-runner.ts +174 -0
- package/src/daemon/providers-setup.ts +16 -0
- package/src/daemon/shutdown-handlers.ts +139 -47
- package/src/daemon/skill-memory-refresh.ts +2 -2
- package/src/daemon/sqlite-corruption-watchdog.test.ts +217 -0
- package/src/daemon/sqlite-corruption-watchdog.ts +155 -0
- package/src/daemon/tool-setup-types.ts +8 -0
- package/src/daemon/trust-context.ts +21 -6
- package/src/daemon/turn-latency-tracker.test.ts +93 -0
- package/src/daemon/turn-latency-tracker.ts +38 -0
- package/src/daemon/wake-conversation-ops.ts +10 -8
- package/src/documents/document-comments-store.test.ts +7 -1
- package/src/documents/document-comments-store.ts +8 -0
- package/src/documents/document-store.ts +15 -0
- package/src/export/__tests__/transcript-formatter.test.ts +11 -0
- package/src/export/transcript-formatter.ts +49 -67
- package/src/home/__tests__/feed-writer.test.ts +247 -1
- package/src/home/conversation-starter-checkpoints.ts +1 -0
- package/src/home/feed-writer.ts +61 -0
- package/src/home/job-handlers/conversation-starters.ts +1 -0
- package/src/hooks/hook-loader.ts +12 -0
- package/src/hooks/registry.ts +32 -4
- package/src/inbound/public-ingress-urls.ts +0 -17
- package/src/ipc/__tests__/contacts-info-ipc.test.ts +285 -0
- package/src/ipc/assistant-server.ts +28 -7
- package/src/ipc/routes/__tests__/contacts-mirror-apply-atomicity.test.ts +62 -0
- package/src/ipc/routes/__tests__/contacts-mirror-apply.test.ts +272 -0
- package/src/ipc/routes/__tests__/contacts-mirror-ipc-routes.test.ts +322 -0
- package/src/ipc/routes/__tests__/invite-ipc-routes.test.ts +60 -4
- package/src/ipc/routes/contacts-info-ipc-routes.ts +239 -0
- package/src/ipc/routes/contacts-mirror-ipc-routes.ts +202 -0
- package/src/ipc/routes/db-proxy.ts +5 -2
- package/src/ipc/routes/invite-ipc-routes.ts +53 -39
- package/src/jobs/worker.ts +9 -2
- package/src/live-voice/__tests__/live-voice-archive.test.ts +10 -1
- package/src/live-voice/live-voice-archive.ts +5 -0
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +22 -6
- package/src/messaging/providers/channel-transport.ts +6 -0
- package/src/messaging/providers/index.ts +3 -0
- package/src/messaging/providers/slack/api.test.ts +49 -1
- package/src/messaging/providers/slack/api.ts +110 -0
- package/src/messaging/providers/slack/send.test.ts +85 -0
- package/src/messaging/providers/slack/send.ts +100 -28
- package/src/messaging/providers/slack/transport.ts +7 -13
- package/src/messaging/providers/whatsapp/send.ts +29 -9
- package/src/monitoring/__tests__/control.test.ts +235 -0
- package/src/monitoring/__tests__/sample-ring-buffer.test.ts +96 -0
- package/src/monitoring/control.ts +105 -0
- package/src/monitoring/resource-sampler.ts +258 -0
- package/src/monitoring/sample-ring-buffer.ts +108 -0
- package/src/monitoring/worker.ts +94 -0
- package/src/notifications/README.md +1 -1
- package/src/notifications/access-request-copy.ts +94 -23
- package/src/notifications/adapters/slack.ts +89 -21
- package/src/notifications/approval-card-builder.ts +33 -18
- package/src/notifications/approval-card-data.ts +48 -15
- package/src/notifications/broadcaster.ts +25 -16
- package/src/notifications/decision-engine.ts +131 -32
- package/src/notifications/guardian-question-mode.ts +58 -10
- package/src/permissions/approval-policy.ts +8 -1
- package/src/permissions/checker.ts +2 -0
- package/src/permissions/gateway-threshold-reader.ts +7 -6
- package/src/permissions/ipc-risk-types.ts +1 -0
- package/src/permissions/secret-prompter.ts +11 -3
- package/src/permissions/types.ts +2 -2
- package/src/persistence/__tests__/conversation-queries-search.test.ts +397 -0
- package/src/persistence/__tests__/conversation-search-lexical.test.ts +103 -0
- package/src/persistence/__tests__/jobs-worker-memory-disabled.test.ts +95 -0
- package/src/persistence/__tests__/slow-query-log.test.ts +266 -0
- package/src/persistence/__tests__/slow-sync-log.test.ts +155 -0
- package/src/persistence/a2a-invite-store.ts +205 -0
- package/src/persistence/attachments-store.ts +94 -10
- package/src/persistence/checkpoints.ts +45 -0
- package/src/persistence/conversation-crud.ts +453 -260
- package/src/persistence/conversation-display-order-migration.ts +8 -2
- package/src/persistence/conversation-group-migration.test.ts +8 -0
- package/src/persistence/conversation-group-migration.ts +9 -0
- package/src/persistence/conversation-queries.ts +244 -125
- package/src/persistence/conversation-row-batch-delete.ts +9 -5
- package/src/persistence/conversation-search-lexical.ts +49 -0
- package/src/persistence/db-async-query.ts +42 -0
- package/src/persistence/db-connection.ts +13 -0
- package/src/persistence/delivery-channels.ts +0 -82
- package/src/persistence/delivery-crud.ts +27 -6
- package/src/persistence/embeddings/__tests__/embedding-identity.test.ts +18 -5
- package/src/persistence/embeddings/__tests__/messages-lexical-index.test.ts +334 -0
- package/src/persistence/embeddings/embedding-identity.ts +17 -5
- package/src/persistence/embeddings/embedding-runtime-manager.ts +31 -0
- package/src/persistence/embeddings/messages-lexical-index.ts +396 -0
- package/src/persistence/embeddings/qdrant-client.ts +81 -5
- package/src/persistence/group-crud.ts +13 -1
- package/src/persistence/job-handlers/__tests__/message-lexical-backfill.test.ts +506 -0
- package/src/persistence/job-handlers/__tests__/message-lexical-enqueue.test.ts +164 -0
- package/src/persistence/job-handlers/__tests__/message-lexical.test.ts +259 -0
- package/src/persistence/job-handlers/cleanup.ts +57 -9
- package/src/persistence/job-handlers/message-lexical-backfill.ts +187 -0
- package/src/persistence/job-handlers/message-lexical.ts +251 -0
- package/src/persistence/jobs-store.ts +102 -8
- package/src/persistence/jobs-worker.ts +68 -28
- package/src/persistence/llm-request-log-store.ts +35 -19
- package/src/persistence/llm-usage-store.ts +11 -0
- package/src/persistence/memory-lifecycle-hooks.test.ts +65 -0
- package/src/persistence/memory-lifecycle-hooks.ts +55 -1
- package/src/persistence/migrations/028-call-session-mode.ts +1 -1
- package/src/persistence/migrations/116-messages-fts.ts +8 -1
- package/src/persistence/migrations/311-create-subagents-table.ts +50 -0
- package/src/persistence/migrations/312-drop-inbox-conversation-state-table.ts +15 -0
- package/src/persistence/migrations/313-drop-messages-fts.ts +17 -0
- package/src/persistence/migrations/314-add-conversation-enabled-plugins.ts +25 -0
- package/src/persistence/migrations/315-create-a2a-invites.ts +58 -0
- package/src/persistence/migrations/316-drop-contact-channels-invite-id.ts +28 -0
- package/src/persistence/migrations/317-canonical-guardian-requester-signals.ts +24 -0
- package/src/persistence/migrations/318-drop-contact-channel-telemetry.ts +32 -0
- package/src/persistence/migrations/__tests__/315-create-a2a-invites.test.ts +161 -0
- package/src/persistence/migrations/__tests__/316-drop-contact-channels-invite-id.test.ts +156 -0
- package/src/persistence/migrations/__tests__/318-drop-contact-channel-telemetry.test.ts +134 -0
- package/src/persistence/migrations/__tests__/migration-prefix-guard.test.ts +99 -0
- package/src/persistence/raw-query.ts +50 -11
- package/src/persistence/schema/a2a.ts +14 -0
- package/src/persistence/schema/contacts.ts +0 -62
- package/src/persistence/schema/conversation-groups.ts +12 -0
- package/src/persistence/schema/conversations.ts +2 -0
- package/src/persistence/schema/documents.ts +65 -0
- package/src/persistence/schema/guardian.ts +4 -0
- package/src/persistence/schema/index.ts +4 -0
- package/src/persistence/schema/memory-injection.ts +62 -0
- package/src/persistence/schema/workflows.ts +55 -0
- package/src/persistence/slow-query-log.ts +437 -0
- package/src/persistence/slow-sync-log.ts +204 -0
- package/src/persistence/steps.ts +16 -0
- package/src/persistence/subagent-store.ts +125 -0
- package/src/persistence/worker-control.ts +45 -238
- package/src/plugin-api/event-hub-facade.ts +172 -0
- package/src/plugin-api/index.ts +9 -1
- package/src/plugin-api/types.ts +40 -9
- package/src/plugins/defaults/default-plugin-names.ts +60 -0
- package/src/plugins/defaults/index.ts +19 -29
- package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +46 -67
- package/src/plugins/defaults/memory/__tests__/db-async-query.test.ts +36 -1
- package/src/plugins/defaults/memory/__tests__/find-most-recent-retrospective-for.test.ts +2 -4
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +2 -2
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-schedule.test.ts +9 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +7 -4
- package/src/plugins/defaults/memory/config.ts +11 -0
- package/src/plugins/defaults/memory/context-search/agent-runner.ts +1 -1
- package/src/plugins/defaults/memory/context-search/sources/conversations.ts +124 -113
- package/src/plugins/defaults/memory/embeddings.ts +77 -0
- package/src/plugins/defaults/memory/find-most-recent-retrospective-for.ts +66 -0
- package/src/plugins/defaults/memory/frontmatter.ts +50 -0
- package/src/plugins/defaults/memory/graph/bootstrap.test.ts +36 -10
- package/src/plugins/defaults/memory/graph/bootstrap.ts +6 -5
- package/src/plugins/defaults/memory/graph/consolidation.ts +3 -5
- package/src/plugins/defaults/memory/graph/extraction.ts +3 -6
- package/src/plugins/defaults/memory/graph/graph-search.ts +12 -23
- package/src/plugins/defaults/memory/graph/narrative.ts +3 -5
- package/src/plugins/defaults/memory/graph/pattern-scan.ts +3 -5
- package/src/plugins/defaults/memory/graph/retriever.test.ts +1 -6
- package/src/plugins/defaults/memory/graph/retriever.ts +5 -10
- package/src/plugins/defaults/memory/graph/tools.ts +1 -1
- package/src/plugins/defaults/memory/hooks/init.ts +31 -5
- package/src/plugins/defaults/memory/indexer.ts +2 -3
- package/src/plugins/defaults/memory/injectors.ts +2 -2
- package/src/plugins/defaults/memory/job-handler-registration.ts +96 -0
- package/src/plugins/defaults/memory/job-handlers/backfill.ts +4 -26
- package/src/plugins/defaults/memory/job-handlers/embedding.test.ts +6 -19
- package/src/plugins/defaults/memory/job-handlers/embedding.ts +9 -22
- package/src/plugins/defaults/memory/job-handlers/index-maintenance.ts +2 -3
- package/src/plugins/defaults/memory/job-handlers.ts +13 -12
- package/src/plugins/defaults/memory/jobs/embed-concept-page.ts +1 -1
- package/src/plugins/defaults/memory/llm-helpers.ts +76 -0
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +8 -5
- package/src/plugins/defaults/memory/memory-retrospective-startup-cleanup.ts +2 -2
- package/src/plugins/defaults/memory/memory-v2-concept-frequency.ts +2 -0
- package/src/plugins/defaults/memory/persistence-hooks.ts +46 -1
- package/src/plugins/defaults/memory/pkb/pkb-index.ts +1 -5
- package/src/plugins/defaults/memory/pkb/pkb-search.ts +2 -2
- package/src/plugins/defaults/memory/routes/__tests__/memory-v2-simulate-route.test.ts +4 -6
- package/src/plugins/defaults/memory/routes/memory-item-routes.ts +1 -1
- package/src/plugins/defaults/memory/search/semantic.ts +2 -2
- package/src/plugins/defaults/memory/startup.ts +244 -0
- package/src/plugins/defaults/memory/task-memory-cleanup.ts +8 -0
- package/src/{daemon → plugins/defaults/memory/v2}/__tests__/memory-v2-startup.test.ts +6 -6
- package/src/plugins/defaults/memory/v2/__tests__/migration.test.ts +2 -13
- package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +4 -5
- package/src/plugins/defaults/memory/v2/__tests__/sweep-job.test.ts +1 -8
- package/src/plugins/defaults/memory/v2/activation.ts +2 -4
- package/src/plugins/defaults/memory/v2/cli-command-store.ts +2 -4
- package/src/plugins/defaults/memory/v2/frontmatter-sweep.ts +1 -1
- package/src/{daemon → plugins/defaults/memory/v2}/memory-v2-startup.test.ts +8 -8
- package/src/{daemon → plugins/defaults/memory/v2}/memory-v2-startup.ts +20 -22
- package/src/plugins/defaults/memory/v2/migration.ts +2 -5
- package/src/plugins/defaults/memory/v2/page-store.ts +1 -1
- package/src/plugins/defaults/memory/v2/qdrant.ts +2 -3
- package/src/plugins/defaults/memory/v2/router.ts +5 -5
- package/src/plugins/defaults/memory/v2/sim.ts +2 -4
- package/src/plugins/defaults/memory/v2/skill-store.ts +2 -4
- package/src/plugins/defaults/memory/v2/sweep-job.ts +6 -6
- package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +11 -9
- package/src/plugins/defaults/memory/v3/__tests__/dense.test.ts +107 -2
- package/src/plugins/defaults/memory/v3/__tests__/gate-flag.test.ts +69 -0
- package/src/plugins/defaults/memory/v3/__tests__/gate.test.ts +181 -0
- package/src/plugins/defaults/memory/v3/__tests__/live-integration.test.ts +7 -3
- package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +345 -8
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +1 -4
- package/src/plugins/defaults/memory/v3/__tests__/section-needle.test.ts +64 -0
- package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +18 -13
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +62 -1
- package/src/plugins/defaults/memory/v3/card.ts +1 -4
- package/src/plugins/defaults/memory/v3/dense.ts +60 -25
- package/src/plugins/defaults/memory/v3/edge.ts +1 -1
- package/src/plugins/defaults/memory/v3/gate-flag.ts +20 -0
- package/src/plugins/defaults/memory/v3/gate.ts +158 -0
- package/src/plugins/defaults/memory/v3/maintain-job.ts +2 -4
- package/src/plugins/defaults/memory/v3/orchestrate.ts +186 -25
- package/src/plugins/defaults/memory/v3/pool-select.test.ts +7 -9
- package/src/plugins/defaults/memory/v3/pool-select.ts +6 -6
- package/src/plugins/defaults/memory/v3/prune.ts +2 -2
- package/src/plugins/defaults/memory/v3/section-dense-store.ts +8 -11
- package/src/plugins/defaults/memory/v3/section-needle.ts +27 -7
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +10 -0
- package/src/plugins/defaults/memory/v3-eval/eval-packets.ts +1 -4
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +5 -0
- package/src/plugins/defaults/turn-context/injectors.ts +1 -0
- package/src/plugins/defaults/turn-context/unified-turn-context.ts +12 -0
- package/src/plugins/injector-registry.ts +13 -2
- package/src/plugins/mtime-cache.ts +36 -47
- package/src/plugins/pipeline.ts +15 -1
- package/src/plugins/types.ts +14 -23
- package/src/prompts/__tests__/system-prompt.test.ts +170 -32
- package/src/prompts/persona-resolver.ts +13 -9
- package/src/prompts/system-prompt.ts +30 -9
- package/src/prompts/templates/BOOTSTRAP.md +16 -119
- package/src/prompts/templates/SOUL.md +43 -13
- package/src/prompts/templates/system-sections.ts +32 -27
- package/src/prompts/templates/users/default.md +19 -0
- package/src/providers/__tests__/placeholder-sentinels.test.ts +56 -0
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +96 -1
- package/src/providers/model-intents.ts +2 -2
- package/src/providers/openai/chat-completions-provider.ts +14 -1
- package/src/providers/openai/responses-provider.ts +18 -0
- package/src/providers/placeholder-sentinels.ts +18 -8
- package/src/providers/retry.ts +1 -0
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +0 -64
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +92 -79
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +98 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +62 -3
- package/src/providers/speech-to-text/provider-catalog.ts +0 -89
- package/src/providers/speech-to-text/resolve.ts +55 -0
- package/src/providers/tool-progress-events.test.ts +50 -0
- package/src/providers/tool-progress-events.ts +99 -0
- package/src/providers/types.ts +1 -1
- package/src/providers/vellum-model-routing.test.ts +51 -0
- package/src/providers/vellum-model-routing.ts +84 -0
- package/src/runtime/AGENTS.md +5 -4
- package/src/runtime/__tests__/agent-wake.test.ts +158 -1
- package/src/runtime/__tests__/channel-verification-service.test.ts +2 -2
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +37 -8
- package/src/runtime/access-request-helper.ts +154 -3
- package/src/runtime/actor-trust-resolver.ts +7 -21
- package/src/runtime/agent-wake.ts +41 -1
- package/src/runtime/assistant-event.ts +86 -12
- package/src/runtime/auth/__tests__/route-policy.test.ts +31 -0
- package/src/runtime/channel-approval-types.ts +52 -2
- package/src/runtime/channel-approvals.ts +23 -8
- package/src/runtime/channel-invite-transport.ts +2 -2
- package/src/runtime/channel-invite-transports/voice.ts +1 -1
- package/src/runtime/channel-readiness-service.ts +3 -5
- package/src/runtime/channel-retry-sweep.ts +18 -24
- package/src/runtime/channel-verification-service.ts +9 -11
- package/src/runtime/finalize-event-delivery.ts +30 -16
- package/src/runtime/guardian-action-service.ts +10 -11
- package/src/runtime/guardian-reply-router.ts +122 -21
- package/src/runtime/http-server.ts +44 -101
- package/src/runtime/introduction-policy.test.ts +214 -0
- package/src/runtime/introduction-policy.ts +284 -0
- package/src/runtime/invite-service.ts +104 -361
- package/src/runtime/local-actor-identity.test.ts +38 -0
- package/src/runtime/local-actor-identity.ts +14 -0
- package/src/runtime/middleware/__tests__/rate-limiter.test.ts +22 -0
- package/src/runtime/middleware/rate-limiter.ts +30 -0
- package/src/runtime/middleware/twilio-validation.ts +5 -7
- package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +28 -0
- package/src/runtime/migrations/origin-mode.ts +6 -6
- package/src/runtime/pre-first-message-gate.ts +1 -0
- package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +6 -35
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +24 -3
- package/src/runtime/routes/__tests__/contact-routes.test.ts +80 -15
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +7 -1
- package/src/runtime/routes/__tests__/global-search-routes.test.ts +0 -3
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +142 -1
- package/src/runtime/routes/__tests__/invite-relay-routes.test.ts +119 -30
- package/src/runtime/routes/__tests__/migration-import-allowed-hosts-env.test.ts +70 -0
- package/src/runtime/routes/__tests__/monitoring-routes.test.ts +194 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +755 -29
- package/src/runtime/routes/__tests__/retrospective-routes.test.ts +4 -0
- package/src/runtime/routes/__tests__/schedule-routes-create.test.ts +70 -0
- package/src/runtime/routes/__tests__/schedule-worker-routes.test.ts +161 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +1 -1
- package/src/runtime/routes/acp-routes.ts +15 -3
- package/src/runtime/routes/app-management-routes.ts +4 -7
- package/src/runtime/routes/approval-routes.ts +4 -0
- package/src/runtime/routes/attachment-routes.ts +54 -3
- package/src/runtime/routes/avatar-routes.ts +0 -4
- package/src/runtime/routes/background-tool-routes.ts +34 -5
- package/src/runtime/routes/btw-routes.ts +32 -4
- package/src/runtime/routes/channel-route-shared.ts +18 -14
- package/src/runtime/routes/channel-verification-routes.ts +0 -3
- package/src/runtime/routes/contact-routes.ts +298 -117
- package/src/runtime/routes/conversation-list-routes.ts +6 -0
- package/src/runtime/routes/conversation-management-routes.ts +74 -37
- package/src/runtime/routes/conversation-query-routes.ts +5 -2
- package/src/runtime/routes/conversation-routes.ts +222 -82
- package/src/runtime/routes/conversations-import-routes.ts +8 -1
- package/src/runtime/routes/credential-prompt-routes.ts +20 -5
- package/src/runtime/routes/debug-routes.ts +1 -0
- package/src/runtime/routes/documents-routes.ts +5 -2
- package/src/runtime/routes/empty-state-greeting-cache.ts +37 -10
- package/src/runtime/routes/global-search-routes.ts +2 -1
- package/src/runtime/routes/guardian-approval-interception.ts +51 -0
- package/src/runtime/routes/home-feed-routes.ts +60 -1
- package/src/runtime/routes/identity-routes.ts +4 -87
- package/src/runtime/routes/inbound-message-handler.ts +82 -41
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +430 -57
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +302 -572
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +76 -270
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +21 -116
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +9 -1
- package/src/runtime/routes/inbound-stages/escalation-intercept.test.ts +158 -0
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +22 -1
- package/src/runtime/routes/index.ts +6 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +22 -16
- package/src/runtime/routes/internal-twilio-routes.ts +0 -15
- package/src/runtime/routes/messages-lexical-routes.ts +75 -0
- package/src/runtime/routes/migration-routes.ts +69 -6
- package/src/runtime/routes/monitoring-routes.ts +237 -0
- package/src/runtime/routes/plugins-routes.ts +329 -8
- package/src/runtime/routes/schedule-routes.ts +49 -8
- package/src/runtime/routes/schedule-worker-routes.ts +210 -0
- package/src/runtime/routes/secret-routes.ts +1 -1
- package/src/runtime/routes/surface-conversation-resolver.ts +1 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +54 -9
- package/src/runtime/services/__tests__/auto-analysis-enqueue.test.ts +30 -6
- package/src/runtime/services/__tests__/conversation-analyze-job.test.ts +43 -8
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +20 -0
- package/src/runtime/services/analyze-conversation.ts +14 -4
- package/src/runtime/services/conversation-serializer.ts +5 -0
- package/src/runtime/slack-no-response.ts +47 -0
- package/src/runtime/slack-reply-session.test.ts +633 -0
- package/src/runtime/slack-reply-session.ts +382 -0
- package/src/runtime/slack-task-progress.ts +95 -0
- package/src/runtime/sync/resource-sync-events.ts +25 -0
- package/src/runtime/tool-grant-request-helper.ts +17 -1
- package/src/runtime/trust-class.test.ts +141 -0
- package/src/runtime/trust-class.ts +121 -0
- package/src/runtime/trust-verdict-consumer.ts +7 -6
- package/src/schedule/__tests__/run-script.test.ts +21 -0
- package/src/schedule/__tests__/worker-control.test.ts +241 -0
- package/src/schedule/run-script.ts +13 -6
- package/src/schedule/schedule-usage-store.ts +1 -0
- package/src/schedule/scheduler.ts +178 -127
- package/src/schedule/worker-control.ts +118 -0
- package/src/schedule/worker.ts +131 -0
- package/src/skills/__tests__/categories-cache.test.ts +38 -0
- package/src/skills/categories-cache.ts +40 -5
- package/src/skills/managed-store.ts +41 -6
- package/src/skills/validate-input.ts +47 -0
- package/src/stt/types.ts +5 -9
- package/src/subagent/manager.ts +267 -39
- package/src/subagent/types.ts +6 -2
- package/src/subagent/validate-allowlists.ts +65 -0
- package/src/telemetry/watchdog-direct-emit.test.ts +109 -0
- package/src/telemetry/watchdog-direct-emit.ts +89 -0
- package/src/tools/acp/list-agents.test.ts +0 -6
- package/src/tools/background-tool-registry.ts +61 -0
- package/src/tools/document/document-comment-tool.test.ts +4 -0
- package/src/tools/host-terminal/host-shell.test.ts +397 -0
- package/src/tools/host-terminal/host-shell.ts +203 -14
- package/src/tools/skills/find-similar-skills.test.ts +152 -1
- package/src/tools/skills/find-similar-skills.ts +30 -4
- package/src/tools/skills/load.ts +36 -0
- package/src/tools/skills/scaffold-managed.ts +66 -34
- package/src/tools/skills/skill-script-runner.ts +17 -0
- package/src/tools/skills/skill-tool-factory.ts +5 -1
- package/src/tools/terminal/safe-env.ts +3 -0
- package/src/tools/terminal/shell.test.ts +177 -0
- package/src/tools/terminal/shell.ts +98 -4
- package/src/tools/tool-approval-handler.ts +106 -29
- package/{node_modules/@vellumai/skill-host-contracts/src → src/tools}/tool-types.ts +16 -17
- package/src/tools/types.ts +29 -17
- package/src/tools/ui-surface/definitions.ts +3 -1
- package/src/tts/__tests__/provider-adapters.test.ts +37 -0
- package/src/tts/__tests__/provider-catalog.test.ts +21 -0
- package/src/tts/provider-catalog.ts +40 -9
- package/src/tts/providers/fish-audio-provider.ts +19 -10
- package/src/tts/types.ts +3 -4
- package/src/util/__tests__/process-tree.test.ts +10 -2
- package/src/util/__tests__/text-spacing.test.ts +53 -0
- package/src/util/cgroup-memory.ts +142 -0
- package/src/util/image-conversion.ts +281 -0
- package/src/util/phone.ts +1 -8
- package/src/util/platform.ts +33 -0
- package/src/util/process-tree.ts +10 -2
- package/src/util/text-spacing.ts +53 -0
- package/src/util/worker-process.ts +271 -0
- package/src/workflows/journal-store.ts +16 -1
- package/src/workflows/library.test.ts +35 -20
- package/src/workflows/library.ts +105 -66
- package/src/workspace/git-service.ts +1 -0
- package/src/workspace/migrations/011-backfill-installation-id.ts +83 -31
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +41 -22
- package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +1 -1
- package/src/workspace/migrations/118-seed-now-md.ts +64 -0
- package/src/workspace/migrations/119-strip-persisted-memory-v3-tuning-defaults.ts +169 -0
- package/src/workspace/migrations/120-revise-onboarding-threads.ts +47 -0
- package/src/workspace/migrations/121-seed-default-user-guardrails.ts +82 -0
- package/src/workspace/migrations/122-relocate-default-user-boundary.ts +111 -0
- package/src/workspace/migrations/123-swap-quality-profile-to-fable.ts +85 -0
- package/src/workspace/migrations/__tests__/119-strip-persisted-memory-v3-tuning-defaults.test.ts +181 -0
- package/src/workspace/migrations/registry.ts +12 -0
- package/drizzle/0000_dizzy_maggott.sql +0 -301
- package/drizzle/meta/0000_snapshot.json +0 -1933
- package/drizzle/meta/_journal.json +0 -13
- package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +0 -887
- package/node_modules/@vellumai/skill-host-contracts/bun.lock +0 -24
- package/node_modules/@vellumai/skill-host-contracts/package.json +0 -18
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -97
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +0 -1349
- package/node_modules/@vellumai/skill-host-contracts/src/index.ts +0 -6
- package/node_modules/@vellumai/skill-host-contracts/src/runtime-mode.ts +0 -11
- package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +0 -32
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +0 -333
- package/node_modules/@vellumai/skill-host-contracts/tsconfig.json +0 -20
- package/node_modules/@vellumai/skill-host-contracts/tsconfig.test.json +0 -12
- package/src/__tests__/invite-redemption-service.test.ts +0 -1180
- package/src/__tests__/invite-service-ipc.test.ts +0 -350
- package/src/__tests__/job-handler-registry-guard.test.ts +0 -125
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +0 -203
- package/src/__tests__/relay-server.test.ts +0 -6153
- package/src/__tests__/telephony-stt-routing.test.ts +0 -329
- package/src/__tests__/voice-invite-redemption.test.ts +0 -702
- package/src/calls/relay-server.ts +0 -2463
- package/src/calls/telephony-stt-routing.ts +0 -145
- package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +0 -128
- package/src/daemon/__tests__/daemon-skill-host.test.ts +0 -273
- package/src/daemon/daemon-skill-host.ts +0 -262
- package/src/daemon/message-types/meet.ts +0 -143
- package/src/daemon/shutdown-registry.ts +0 -40
- package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -253
- package/src/ipc/__tests__/skill-server.test.ts +0 -182
- package/src/ipc/skill-ipc-types.ts +0 -54
- package/src/ipc/skill-routes/__tests__/config.test.ts +0 -146
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +0 -448
- package/src/ipc/skill-routes/__tests__/identity.test.ts +0 -62
- package/src/ipc/skill-routes/__tests__/log.test.ts +0 -133
- package/src/ipc/skill-routes/__tests__/memory.test.ts +0 -203
- package/src/ipc/skill-routes/__tests__/platform.test.ts +0 -111
- package/src/ipc/skill-routes/__tests__/providers.test.ts +0 -265
- package/src/ipc/skill-routes/__tests__/registries.test.ts +0 -400
- package/src/ipc/skill-routes/config.ts +0 -47
- package/src/ipc/skill-routes/events.ts +0 -147
- package/src/ipc/skill-routes/identity.ts +0 -21
- package/src/ipc/skill-routes/index.ts +0 -37
- package/src/ipc/skill-routes/log.ts +0 -40
- package/src/ipc/skill-routes/memory.ts +0 -92
- package/src/ipc/skill-routes/platform.ts +0 -39
- package/src/ipc/skill-routes/providers.ts +0 -162
- package/src/ipc/skill-routes/registries.ts +0 -338
- package/src/ipc/skill-server.ts +0 -831
- package/src/ipc/skill-socket-path.ts +0 -20
- package/src/jobs/register-job-handlers.ts +0 -74
- package/src/persistence/invite-store.ts +0 -481
- package/src/plugins/job-handler-registry.ts +0 -94
- package/src/providers/cache-control.ts +0 -26
- package/src/runtime/__tests__/runtime-mode.test.ts +0 -62
- package/src/runtime/invite-redemption-service.ts +0 -828
- package/src/runtime/invite-redemption-templates.ts +0 -46
- package/src/runtime/runtime-mode.ts +0 -40
- package/src/runtime/slack-dm-text-delivery.ts +0 -177
- package/src/util/voice-code.ts +0 -31
|
@@ -1,30 +1,58 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* STT session module for media-stream call ingestion.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Transcribes inbound caller audio in one of two modes, selected at the
|
|
5
|
+
* `start` event (streaming additionally falls back to batch if the
|
|
6
|
+
* provider closes the stream mid-call):
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
8
|
+
* - **Streaming** (default, `calls.voice.telephonyStreaming: true`) —
|
|
9
|
+
* inbound mu-law audio is decoded to 16 kHz PCM16 and fed to a
|
|
10
|
+
* {@link StreamingTranscriber} resolved for the configured
|
|
11
|
+
* `services.stt` provider. Replies trigger on the provider's
|
|
12
|
+
* utterance-boundary `final` events; barge-in (`onSpeechStart`) always
|
|
13
|
+
* fires from the local energy VAD, never from transcriber partials.
|
|
14
|
+
* Frames arriving while the provider session is still starting are
|
|
15
|
+
* held in a bounded buffer and flushed on start (overflow drops the
|
|
16
|
+
* oldest frames and is counted + logged at teardown).
|
|
17
|
+
* - **Batch** — segmented audio turns (produced by
|
|
18
|
+
* {@link MediaTurnDetector}) are transcribed per turn via the batch
|
|
19
|
+
* transcriber. Used when the streaming flag is off, no streaming
|
|
20
|
+
* transcriber is available for the configured provider, or the
|
|
21
|
+
* provider closed the streaming session unexpectedly mid-call.
|
|
22
|
+
*
|
|
23
|
+
* This module is **transport-neutral** — it exposes callback hooks
|
|
24
|
+
* (`onSpeechStart`, `onTranscriptFinal`, `onDtmf`, `onStop`) rather than
|
|
25
|
+
* driving any call flow itself; `media-stream-server.ts` instantiates and
|
|
26
|
+
* connects it to the media-stream WebSocket ingress.
|
|
12
27
|
*
|
|
13
28
|
* Error handling:
|
|
14
29
|
* - When the telephony resolver returns a non-supported status, the
|
|
15
30
|
* session reports the failure through `onError` and stops processing.
|
|
16
31
|
* - Individual turn transcription failures (timeouts, provider errors)
|
|
17
32
|
* are reported through `onError` without tearing down the session.
|
|
33
|
+
* - Streaming transcriber errors are reported through `onError` with the
|
|
34
|
+
* provider's normalized category.
|
|
18
35
|
*/
|
|
19
36
|
|
|
37
|
+
import { getConfig } from "../config/loader.js";
|
|
20
38
|
import {
|
|
39
|
+
resolveBatchTranscriber,
|
|
40
|
+
resolveStreamingTranscriber,
|
|
21
41
|
resolveTelephonySttCapability,
|
|
22
42
|
type TelephonySttCapability,
|
|
23
43
|
} from "../providers/speech-to-text/resolve.js";
|
|
24
|
-
import { resolveBatchTranscriber } from "../providers/speech-to-text/resolve.js";
|
|
25
44
|
import { normalizeSttError } from "../stt/daemon-batch-transcriber.js";
|
|
26
|
-
import type {
|
|
45
|
+
import type {
|
|
46
|
+
StreamingTranscriber,
|
|
47
|
+
SttCallContextHints,
|
|
48
|
+
SttStreamServerEvent,
|
|
49
|
+
} from "../stt/types.js";
|
|
27
50
|
import { getLogger } from "../util/logger.js";
|
|
51
|
+
import {
|
|
52
|
+
mulawToLinear,
|
|
53
|
+
mulawToPcm16,
|
|
54
|
+
resamplePcm16,
|
|
55
|
+
} from "./media-stream-audio-transcode.js";
|
|
28
56
|
import { parseMediaStreamFrame } from "./media-stream-parser.js";
|
|
29
57
|
import type {
|
|
30
58
|
MediaStreamMediaEvent,
|
|
@@ -50,10 +78,38 @@ export interface MediaStreamSttSessionConfig {
|
|
|
50
78
|
|
|
51
79
|
/** Optional call-context hints forwarded to the STT provider. */
|
|
52
80
|
callContextHints?: SttCallContextHints;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Maximum number of media frames buffered while the streaming
|
|
84
|
+
* transcriber starts up. Default: 500 (~10 s of 20 ms frames).
|
|
85
|
+
*/
|
|
86
|
+
streamingStartupBufferFrames?: number;
|
|
53
87
|
}
|
|
54
88
|
|
|
55
89
|
const DEFAULT_TRANSCRIPTION_TIMEOUT_MS = 10_000;
|
|
56
90
|
|
|
91
|
+
/** Twilio media streams deliver 8 kHz mono mu-law audio. */
|
|
92
|
+
const TELEPHONY_SOURCE_SAMPLE_RATE = 8_000;
|
|
93
|
+
|
|
94
|
+
/** Sample rate expected by the daemon streaming transcribers. */
|
|
95
|
+
const STREAMING_SAMPLE_RATE = 16_000;
|
|
96
|
+
|
|
97
|
+
/** MIME type for the PCM16 frames fed to the streaming transcriber. */
|
|
98
|
+
const STREAMING_AUDIO_MIME_TYPE = `audio/pcm;rate=${STREAMING_SAMPLE_RATE}`;
|
|
99
|
+
|
|
100
|
+
/** Default bound for the startup frame buffer (~10 s of 20 ms frames). */
|
|
101
|
+
const DEFAULT_STREAMING_STARTUP_BUFFER_FRAMES = 500;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Transcription mode, selected at the `start` event:
|
|
105
|
+
* - `"batch"` — per-turn batch transcription via {@link MediaTurnDetector}.
|
|
106
|
+
* - `"streaming-pending"` — streaming selected; provider session still
|
|
107
|
+
* starting, frames buffered.
|
|
108
|
+
* - `"streaming"` — live streaming session active. Falls back to
|
|
109
|
+
* `"batch"` if the provider closes the stream unexpectedly mid-call.
|
|
110
|
+
*/
|
|
111
|
+
type SttSessionMode = "batch" | "streaming-pending" | "streaming";
|
|
112
|
+
|
|
57
113
|
// ---------------------------------------------------------------------------
|
|
58
114
|
// Callback hooks
|
|
59
115
|
// ---------------------------------------------------------------------------
|
|
@@ -63,9 +119,13 @@ export interface MediaStreamSttSessionCallbacks {
|
|
|
63
119
|
onSpeechStart?: () => void;
|
|
64
120
|
|
|
65
121
|
/**
|
|
66
|
-
* Called when a completed
|
|
122
|
+
* Called when a completed caller utterance has been transcribed.
|
|
67
123
|
*
|
|
68
|
-
*
|
|
124
|
+
* Batch mode: fires per detected turn; text may be empty for silence
|
|
125
|
+
* turns. Streaming mode: fires per utterance-boundary final from the
|
|
126
|
+
* provider; empty finals are suppressed.
|
|
127
|
+
*
|
|
128
|
+
* @param text - The transcribed text (trimmed).
|
|
69
129
|
* @param durationMs - Approximate duration of the audio turn.
|
|
70
130
|
*/
|
|
71
131
|
onTranscriptFinal?: (text: string, durationMs: number) => void;
|
|
@@ -116,6 +176,43 @@ export class MediaStreamSttSession {
|
|
|
116
176
|
/** Session-level abort controller for the active transcription request. */
|
|
117
177
|
private activeTranscriptionAbort: AbortController | null = null;
|
|
118
178
|
|
|
179
|
+
/** Transcription mode — selected once in {@link handleStart}. */
|
|
180
|
+
private mode: SttSessionMode = "batch";
|
|
181
|
+
|
|
182
|
+
/** Live streaming transcriber (streaming mode only). */
|
|
183
|
+
private streamingTranscriber: StreamingTranscriber | null = null;
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Whether the session deliberately stopped the streaming transcriber
|
|
187
|
+
* (stream `stop` event or dispose). Distinguishes expected `closed`
|
|
188
|
+
* events from provider-initiated closes, which trigger batch fallback.
|
|
189
|
+
*/
|
|
190
|
+
private deliberateStreamingStop = false;
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Turns the local VAD completed while the mode was `streaming-pending`,
|
|
194
|
+
* queued with their buffered audio. {@link enterBatchMode} transcribes
|
|
195
|
+
* them in order if streaming never materializes. Cleared when streaming
|
|
196
|
+
* settles active and on dispose.
|
|
197
|
+
*/
|
|
198
|
+
private pendingCompletedTurns: { chunks: string[]; durationMs: number }[] =
|
|
199
|
+
[];
|
|
200
|
+
|
|
201
|
+
/** PCM16 frames buffered while the streaming transcriber starts up. */
|
|
202
|
+
private startupFrames: Buffer[] = [];
|
|
203
|
+
|
|
204
|
+
/** Bound for {@link startupFrames}. */
|
|
205
|
+
private readonly startupBufferFrames: number;
|
|
206
|
+
|
|
207
|
+
/** Frames evicted from the startup buffer on overflow. */
|
|
208
|
+
private startupFramesDroppedCount = 0;
|
|
209
|
+
|
|
210
|
+
/** Whether the startup-drop metric has been logged at teardown. */
|
|
211
|
+
private startupDropsLogged = false;
|
|
212
|
+
|
|
213
|
+
/** Speech-bearing audio milliseconds since the last streaming final. */
|
|
214
|
+
private utteranceAudioMs = 0;
|
|
215
|
+
|
|
119
216
|
constructor(
|
|
120
217
|
config: MediaStreamSttSessionConfig = {},
|
|
121
218
|
callbacks: MediaStreamSttSessionCallbacks = {},
|
|
@@ -124,6 +221,9 @@ export class MediaStreamSttSession {
|
|
|
124
221
|
this.callbacks = callbacks;
|
|
125
222
|
this.transcriptionTimeoutMs =
|
|
126
223
|
config.transcriptionTimeoutMs ?? DEFAULT_TRANSCRIPTION_TIMEOUT_MS;
|
|
224
|
+
this.startupBufferFrames =
|
|
225
|
+
config.streamingStartupBufferFrames ??
|
|
226
|
+
DEFAULT_STREAMING_STARTUP_BUFFER_FRAMES;
|
|
127
227
|
|
|
128
228
|
this.turnDetector = new MediaTurnDetector(config.turnDetector, {
|
|
129
229
|
onTurnStart: () => {
|
|
@@ -172,14 +272,27 @@ export class MediaStreamSttSession {
|
|
|
172
272
|
}
|
|
173
273
|
|
|
174
274
|
/**
|
|
175
|
-
* Dispose of the session, clearing all timers and buffers
|
|
275
|
+
* Dispose of the session, clearing all timers and buffers and stopping
|
|
276
|
+
* any active streaming transcriber.
|
|
176
277
|
*/
|
|
177
278
|
dispose(): void {
|
|
178
279
|
this.disposed = true;
|
|
280
|
+
this.deliberateStreamingStop = true;
|
|
179
281
|
this.activeTranscriptionAbort?.abort();
|
|
180
282
|
this.activeTranscriptionAbort = null;
|
|
181
283
|
this.turnDetector.dispose();
|
|
182
284
|
this.currentTurnChunks = [];
|
|
285
|
+
this.pendingCompletedTurns = [];
|
|
286
|
+
this.startupFrames = [];
|
|
287
|
+
const transcriber = this.streamingTranscriber;
|
|
288
|
+
this.streamingTranscriber = null;
|
|
289
|
+
stopStreamingBestEffort(transcriber);
|
|
290
|
+
this.logStartupDrops();
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/** Frames dropped from the bounded streaming startup buffer. */
|
|
294
|
+
get streamingStartupFramesDropped(): number {
|
|
295
|
+
return this.startupFramesDroppedCount;
|
|
183
296
|
}
|
|
184
297
|
|
|
185
298
|
// ── Event handlers ─────────────────────────────────────────────────
|
|
@@ -189,19 +302,26 @@ export class MediaStreamSttSession {
|
|
|
189
302
|
this.callSid = event.start.callSid;
|
|
190
303
|
this.encoding = event.start.mediaFormat.encoding;
|
|
191
304
|
|
|
305
|
+
const streamingEnabled = getConfig().calls.voice.telephonyStreaming;
|
|
306
|
+
|
|
192
307
|
log.info(
|
|
193
308
|
{
|
|
194
309
|
streamSid: this.streamSid,
|
|
195
310
|
callSid: this.callSid,
|
|
196
311
|
encoding: this.encoding,
|
|
197
312
|
sampleRate: event.start.mediaFormat.sampleRate,
|
|
313
|
+
telephonyStreaming: streamingEnabled,
|
|
198
314
|
},
|
|
199
315
|
"Media stream STT session started",
|
|
200
316
|
);
|
|
201
317
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
318
|
+
if (streamingEnabled) {
|
|
319
|
+
this.mode = "streaming-pending";
|
|
320
|
+
void this.startStreaming();
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
this.enterBatchMode();
|
|
205
325
|
}
|
|
206
326
|
|
|
207
327
|
private handleMedia(event: MediaStreamMediaEvent): void {
|
|
@@ -215,24 +335,246 @@ export class MediaStreamSttSession {
|
|
|
215
335
|
// The detector call runs BEFORE the push so that the onTurnStart
|
|
216
336
|
// callback can clear stale inter-turn silence from the buffer
|
|
217
337
|
// without also wiping the first speech chunk of the new turn.
|
|
218
|
-
|
|
338
|
+
//
|
|
339
|
+
// The detector runs in every mode: in streaming mode it only drives
|
|
340
|
+
// barge-in (`onSpeechStart` fires from this local VAD, never from
|
|
341
|
+
// transcriber partials).
|
|
342
|
+
const raw = Buffer.from(event.media.payload, "base64");
|
|
343
|
+
const hasSpeech = detectSpeechActivity(raw);
|
|
219
344
|
this.turnDetector.onMediaChunk(hasSpeech);
|
|
220
345
|
|
|
346
|
+
if (this.mode === "batch") {
|
|
347
|
+
this.currentTurnChunks.push(event.media.payload);
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Approximate the utterance duration reported with streaming finals:
|
|
352
|
+
// count audio while the local VAD sees an active turn.
|
|
353
|
+
if (hasSpeech || this.turnDetector.isActive) {
|
|
354
|
+
this.utteranceAudioMs +=
|
|
355
|
+
raw.length / (TELEPHONY_SOURCE_SAMPLE_RATE / 1000);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const pcm = resamplePcm16(
|
|
359
|
+
mulawToPcm16(raw),
|
|
360
|
+
TELEPHONY_SOURCE_SAMPLE_RATE,
|
|
361
|
+
STREAMING_SAMPLE_RATE,
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
if (this.mode === "streaming") {
|
|
365
|
+
this.streamingTranscriber?.sendAudio(pcm, STREAMING_AUDIO_MIME_TYPE);
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// streaming-pending: the provider session is still starting. Buffer
|
|
370
|
+
// the PCM for the flush, and keep filling the turn buffer so a batch
|
|
371
|
+
// fallback still has the audio.
|
|
372
|
+
this.bufferStartupFrame(pcm);
|
|
221
373
|
this.currentTurnChunks.push(event.media.payload);
|
|
222
374
|
}
|
|
223
375
|
|
|
224
376
|
private handleStop(): void {
|
|
225
377
|
// Finalize any in-flight turn
|
|
226
378
|
this.turnDetector.forceEnd();
|
|
379
|
+
// Streaming: signal end-of-audio so the provider flushes any withheld
|
|
380
|
+
// utterance text as a trailing final before closing.
|
|
381
|
+
this.deliberateStreamingStop = true;
|
|
382
|
+
stopStreamingBestEffort(this.streamingTranscriber);
|
|
383
|
+
this.logStartupDrops();
|
|
227
384
|
this.callbacks.onStop?.();
|
|
228
385
|
}
|
|
229
386
|
|
|
387
|
+
// ── Streaming mode ─────────────────────────────────────────────────
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Resolve and start the streaming transcriber, then flush the frames
|
|
391
|
+
* buffered during startup. Falls back to the batch path when no
|
|
392
|
+
* streaming transcriber is available or the provider session cannot be
|
|
393
|
+
* established — the mode is settled before streaming ever becomes
|
|
394
|
+
* active, so modes are never mixed mid-session.
|
|
395
|
+
*/
|
|
396
|
+
private async startStreaming(): Promise<void> {
|
|
397
|
+
let transcriber: StreamingTranscriber | null = null;
|
|
398
|
+
try {
|
|
399
|
+
transcriber = await resolveStreamingTranscriber({
|
|
400
|
+
sampleRate: STREAMING_SAMPLE_RATE,
|
|
401
|
+
utteranceBoundaryFinals: true,
|
|
402
|
+
});
|
|
403
|
+
} catch (err) {
|
|
404
|
+
log.warn(
|
|
405
|
+
{ error: err, streamSid: this.streamSid },
|
|
406
|
+
"Streaming transcriber resolution failed — falling back to batch STT",
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
if (this.disposed) {
|
|
411
|
+
stopStreamingBestEffort(transcriber);
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (!transcriber) {
|
|
416
|
+
this.enterBatchMode();
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
try {
|
|
421
|
+
await transcriber.start((event) => this.handleStreamingEvent(event));
|
|
422
|
+
} catch (err) {
|
|
423
|
+
log.warn(
|
|
424
|
+
{ error: err, streamSid: this.streamSid },
|
|
425
|
+
"Streaming transcriber failed to start — falling back to batch STT",
|
|
426
|
+
);
|
|
427
|
+
if (!this.disposed) {
|
|
428
|
+
this.enterBatchMode();
|
|
429
|
+
}
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
if (this.disposed) {
|
|
434
|
+
stopStreamingBestEffort(transcriber);
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
this.streamingTranscriber = transcriber;
|
|
439
|
+
this.mode = "streaming";
|
|
440
|
+
|
|
441
|
+
// Flush audio buffered while the provider session was starting.
|
|
442
|
+
const buffered = this.startupFrames;
|
|
443
|
+
this.startupFrames = [];
|
|
444
|
+
for (const frame of buffered) {
|
|
445
|
+
transcriber.sendAudio(frame, STREAMING_AUDIO_MIME_TYPE);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// The batch fallback is settled — drop its turn buffers.
|
|
449
|
+
this.currentTurnChunks = [];
|
|
450
|
+
this.pendingCompletedTurns = [];
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Settle on the batch path: clear streaming startup state and eagerly
|
|
455
|
+
* resolve the telephony capability so it's cached by the time the
|
|
456
|
+
* first turn completes.
|
|
457
|
+
*
|
|
458
|
+
* Turns the local VAD already completed while streaming was pending
|
|
459
|
+
* are stranded — {@link handleTurnEnd} deferred them to streaming
|
|
460
|
+
* finals that will never arrive — so the queue is batch-transcribed
|
|
461
|
+
* here in order. This recovery applies only to the pending path: on a
|
|
462
|
+
* mid-call provider close, an in-progress turn's earlier audio already
|
|
463
|
+
* went to the dead provider, and only audio arriving after the
|
|
464
|
+
* fallback is batch-transcribed.
|
|
465
|
+
*/
|
|
466
|
+
private enterBatchMode(): void {
|
|
467
|
+
this.mode = "batch";
|
|
468
|
+
this.startupFrames = [];
|
|
469
|
+
this.capabilityPromise ??= resolveTelephonySttCapability();
|
|
470
|
+
|
|
471
|
+
const pending = this.pendingCompletedTurns;
|
|
472
|
+
this.pendingCompletedTurns = [];
|
|
473
|
+
if (pending.length > 0) {
|
|
474
|
+
log.info(
|
|
475
|
+
{ streamSid: this.streamSid, turnCount: pending.length },
|
|
476
|
+
"Transcribing turns completed during streaming startup via batch fallback",
|
|
477
|
+
);
|
|
478
|
+
void (async () => {
|
|
479
|
+
for (const { chunks, durationMs } of pending) {
|
|
480
|
+
await this.transcribeTurn(chunks, durationMs);
|
|
481
|
+
}
|
|
482
|
+
})();
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Map streaming transcriber events onto the session callbacks.
|
|
488
|
+
*
|
|
489
|
+
* Partials are ignored for turn-taking: replies trigger only on the
|
|
490
|
+
* provider's utterance-boundary finals, and barge-in comes from the
|
|
491
|
+
* local VAD.
|
|
492
|
+
*/
|
|
493
|
+
private handleStreamingEvent(event: SttStreamServerEvent): void {
|
|
494
|
+
if (this.disposed) {
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
switch (event.type) {
|
|
499
|
+
case "partial":
|
|
500
|
+
return;
|
|
501
|
+
case "final": {
|
|
502
|
+
const durationMs = Math.round(this.utteranceAudioMs);
|
|
503
|
+
this.utteranceAudioMs = 0;
|
|
504
|
+
const text = event.text.trim();
|
|
505
|
+
if (text.length > 0) {
|
|
506
|
+
this.callbacks.onTranscriptFinal?.(text, durationMs);
|
|
507
|
+
}
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
case "error":
|
|
511
|
+
this.callbacks.onError?.(event.category, event.message);
|
|
512
|
+
return;
|
|
513
|
+
case "closed":
|
|
514
|
+
this.streamingTranscriber = null;
|
|
515
|
+
// Provider-initiated close mid-call: without a live transcriber
|
|
516
|
+
// the streaming mode would silently drop all subsequent audio.
|
|
517
|
+
// Fall back to per-turn batch transcription (the local VAD/turn
|
|
518
|
+
// detector already runs in streaming mode).
|
|
519
|
+
if (this.mode === "streaming" && !this.deliberateStreamingStop) {
|
|
520
|
+
log.warn(
|
|
521
|
+
{ streamSid: this.streamSid, callSid: this.callSid },
|
|
522
|
+
"Streaming transcriber closed unexpectedly mid-call — falling back to batch STT",
|
|
523
|
+
);
|
|
524
|
+
this.enterBatchMode();
|
|
525
|
+
}
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Append a decoded frame to the bounded startup buffer. On overflow the
|
|
532
|
+
* oldest frame is dropped and counted; the total is logged at teardown.
|
|
533
|
+
*/
|
|
534
|
+
private bufferStartupFrame(pcm: Buffer): void {
|
|
535
|
+
this.startupFrames.push(pcm);
|
|
536
|
+
if (this.startupFrames.length > this.startupBufferFrames) {
|
|
537
|
+
this.startupFrames.shift();
|
|
538
|
+
this.startupFramesDroppedCount++;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/** Log the startup-buffer drop count once, if any frames were dropped. */
|
|
543
|
+
private logStartupDrops(): void {
|
|
544
|
+
if (this.startupDropsLogged || this.startupFramesDroppedCount === 0) {
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
this.startupDropsLogged = true;
|
|
548
|
+
log.warn(
|
|
549
|
+
{
|
|
550
|
+
streamingStartupFramesDropped: this.startupFramesDroppedCount,
|
|
551
|
+
streamSid: this.streamSid,
|
|
552
|
+
},
|
|
553
|
+
"Dropped media frames during streaming transcriber startup",
|
|
554
|
+
);
|
|
555
|
+
}
|
|
556
|
+
|
|
230
557
|
// ── Turn completion ────────────────────────────────────────────────
|
|
231
558
|
|
|
232
559
|
private async handleTurnEnd(
|
|
233
560
|
_reason: "silence" | "max-duration",
|
|
234
561
|
durationMs: number,
|
|
235
562
|
): Promise<void> {
|
|
563
|
+
// Streaming modes take turn boundaries from the transcriber's
|
|
564
|
+
// utterance-boundary finals, not the local VAD. Turns completed
|
|
565
|
+
// while streaming is still pending are queued so a later batch
|
|
566
|
+
// fallback can transcribe their buffered audio.
|
|
567
|
+
if (this.mode !== "batch") {
|
|
568
|
+
if (this.mode === "streaming-pending") {
|
|
569
|
+
const chunks = this.currentTurnChunks;
|
|
570
|
+
this.currentTurnChunks = [];
|
|
571
|
+
if (chunks.length > 0) {
|
|
572
|
+
this.pendingCompletedTurns.push({ chunks, durationMs });
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
|
|
236
578
|
const chunks = this.currentTurnChunks;
|
|
237
579
|
this.currentTurnChunks = [];
|
|
238
580
|
|
|
@@ -242,6 +584,14 @@ export class MediaStreamSttSession {
|
|
|
242
584
|
return;
|
|
243
585
|
}
|
|
244
586
|
|
|
587
|
+
await this.transcribeTurn(chunks, durationMs);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/** Batch-transcribe a completed turn's audio chunks. */
|
|
591
|
+
private async transcribeTurn(
|
|
592
|
+
chunks: string[],
|
|
593
|
+
durationMs: number,
|
|
594
|
+
): Promise<void> {
|
|
245
595
|
// Resolve telephony capability (cached after first call)
|
|
246
596
|
if (!this.capabilityPromise) {
|
|
247
597
|
this.capabilityPromise = resolveTelephonySttCapability();
|
|
@@ -334,6 +684,24 @@ export class MediaStreamSttSession {
|
|
|
334
684
|
}
|
|
335
685
|
}
|
|
336
686
|
|
|
687
|
+
// ---------------------------------------------------------------------------
|
|
688
|
+
// Helpers
|
|
689
|
+
// ---------------------------------------------------------------------------
|
|
690
|
+
|
|
691
|
+
/** Stop a streaming transcriber, swallowing best-effort stop failures. */
|
|
692
|
+
function stopStreamingBestEffort(
|
|
693
|
+
transcriber: StreamingTranscriber | null,
|
|
694
|
+
): void {
|
|
695
|
+
if (!transcriber) {
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
try {
|
|
699
|
+
transcriber.stop();
|
|
700
|
+
} catch (err) {
|
|
701
|
+
log.debug({ error: err }, "Streaming transcriber stop failed");
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
337
705
|
// ---------------------------------------------------------------------------
|
|
338
706
|
// Speech activity detection
|
|
339
707
|
// ---------------------------------------------------------------------------
|
|
@@ -345,56 +713,31 @@ export class MediaStreamSttSession {
|
|
|
345
713
|
* around 0xFF (negative zero) and 0x7F (positive zero). Speech produces
|
|
346
714
|
* samples with lower byte values (higher decoded amplitude).
|
|
347
715
|
*
|
|
348
|
-
* This function
|
|
349
|
-
*
|
|
350
|
-
*
|
|
351
|
-
*
|
|
716
|
+
* This function computes the average absolute G.711-decoded amplitude of
|
|
717
|
+
* the mu-law samples and compares it against a threshold. The threshold is
|
|
718
|
+
* tuned for Twilio's 8 kHz, 8-bit mu-law stream where typical silence
|
|
719
|
+
* averages ~200-400 and speech >1200 on the full 16-bit linear scale.
|
|
352
720
|
*
|
|
353
|
-
* @param
|
|
721
|
+
* @param raw - Decoded mu-law audio chunk from Twilio.
|
|
354
722
|
* @returns `true` if the chunk likely contains speech, `false` otherwise.
|
|
355
723
|
*/
|
|
356
|
-
function detectSpeechActivity(
|
|
357
|
-
const SPEECH_ENERGY_THRESHOLD =
|
|
724
|
+
function detectSpeechActivity(raw: Buffer): boolean {
|
|
725
|
+
const SPEECH_ENERGY_THRESHOLD = 800;
|
|
358
726
|
|
|
359
|
-
|
|
360
|
-
try {
|
|
361
|
-
raw = Buffer.from(base64Payload, "base64");
|
|
362
|
-
} catch {
|
|
727
|
+
if (raw.length === 0) {
|
|
363
728
|
return false;
|
|
364
729
|
}
|
|
365
730
|
|
|
366
|
-
if (raw.length === 0) return false;
|
|
367
|
-
|
|
368
731
|
// Compute average absolute linear amplitude from mu-law samples.
|
|
369
732
|
let totalAmplitude = 0;
|
|
370
733
|
for (let i = 0; i < raw.length; i++) {
|
|
371
|
-
totalAmplitude +=
|
|
734
|
+
totalAmplitude += Math.abs(mulawToLinear(raw[i]));
|
|
372
735
|
}
|
|
373
736
|
const avgAmplitude = totalAmplitude / raw.length;
|
|
374
737
|
|
|
375
738
|
return avgAmplitude > SPEECH_ENERGY_THRESHOLD;
|
|
376
739
|
}
|
|
377
740
|
|
|
378
|
-
/**
|
|
379
|
-
* Convert a single mu-law byte to its approximate absolute linear magnitude.
|
|
380
|
-
*
|
|
381
|
-
* mu-law decoding formula (ITU-T G.711):
|
|
382
|
-
* - Bit 7 is the sign bit (0 = positive, 1 = negative).
|
|
383
|
-
* - Bits 6-4 are the exponent (3 bits).
|
|
384
|
-
* - Bits 3-0 are the mantissa (4 bits).
|
|
385
|
-
*
|
|
386
|
-
* The decoded value is: sign * ((mantissa << 1 | 0x21) << exponent) - 0x21
|
|
387
|
-
* We return the absolute value since we only care about energy.
|
|
388
|
-
*/
|
|
389
|
-
function mulawToLinearMagnitude(mulawByte: number): number {
|
|
390
|
-
// mu-law bytes are bitwise-inverted in Twilio's encoding
|
|
391
|
-
const b = ~mulawByte & 0xff;
|
|
392
|
-
const exponent = (b >> 4) & 0x07;
|
|
393
|
-
const mantissa = b & 0x0f;
|
|
394
|
-
const magnitude = ((mantissa << 1) | 0x21) << exponent;
|
|
395
|
-
return magnitude - 0x21;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
741
|
// ---------------------------------------------------------------------------
|
|
399
742
|
// WAV helpers
|
|
400
743
|
// ---------------------------------------------------------------------------
|
|
@@ -2,12 +2,10 @@
|
|
|
2
2
|
* Speech-aware turn detector for segmenting inbound audio from a
|
|
3
3
|
* Twilio Media Stream into discrete utterance "turns".
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* This module bridges that gap by detecting turns based on speech
|
|
10
|
-
* activity signals derived from the audio content:
|
|
5
|
+
* A Twilio Media Stream delivers a continuous stream of audio chunks
|
|
6
|
+
* with no built-in turn boundaries. This module supplies those
|
|
7
|
+
* boundaries by detecting turns based on speech activity signals
|
|
8
|
+
* derived from the audio content:
|
|
11
9
|
*
|
|
12
10
|
* 1. **Speech-to-silence transition** — when a period of speech is
|
|
13
11
|
* followed by silence frames exceeding `silenceThresholdMs`, the
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Helper functions for the guardian access-request wait flow.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* and makes the wait-state logic independently testable.
|
|
4
|
+
* Standalone module so the wait-state logic is independently testable and
|
|
5
|
+
* decoupled from any transport's WebSocket lifecycle.
|
|
7
6
|
*/
|
|
8
7
|
|
|
9
8
|
import { getCanonicalGuardianRequest } from "../contacts/canonical-guardian-store.js";
|