@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
|
@@ -7,6 +7,7 @@ import { getLogger } from "../../util/logger.js";
|
|
|
7
7
|
import { extractRetryAfterMs } from "../../util/retry.js";
|
|
8
8
|
import { escapeXmlAttr } from "../../util/xml.js";
|
|
9
9
|
import { createStreamTimeout } from "../stream-timeout.js";
|
|
10
|
+
import { createToolProgressEmitter } from "../tool-progress-events.js";
|
|
10
11
|
import type {
|
|
11
12
|
ContentBlock,
|
|
12
13
|
Message,
|
|
@@ -293,6 +294,7 @@ export class OpenAIResponsesProvider implements Provider {
|
|
|
293
294
|
>();
|
|
294
295
|
// Maps item_id → callId so we can look up tool calls from delta events.
|
|
295
296
|
const itemIdToCallId = new Map<string, string>();
|
|
297
|
+
const toolProgress = createToolProgressEmitter(onEvent);
|
|
296
298
|
// Track web search call item IDs so we can emit server_tool_complete.
|
|
297
299
|
const webSearchCallIds: string[] = [];
|
|
298
300
|
let finishReason = "unknown";
|
|
@@ -348,6 +350,7 @@ export class OpenAIResponsesProvider implements Provider {
|
|
|
348
350
|
args: "",
|
|
349
351
|
});
|
|
350
352
|
itemIdToCallId.set(itemId, callId);
|
|
353
|
+
toolProgress.emitPreviewStart(callId, name);
|
|
351
354
|
} else if (item?.type === "web_search_call") {
|
|
352
355
|
const toolUseId = item.id ?? "";
|
|
353
356
|
webSearchCallIds.push(toolUseId);
|
|
@@ -372,6 +375,11 @@ export class OpenAIResponsesProvider implements Provider {
|
|
|
372
375
|
const entry = toolCallMap.get(callId);
|
|
373
376
|
if (entry) {
|
|
374
377
|
entry.args += delta;
|
|
378
|
+
toolProgress.emitInputJsonDelta(
|
|
379
|
+
entry.callId,
|
|
380
|
+
entry.name,
|
|
381
|
+
entry.args,
|
|
382
|
+
);
|
|
375
383
|
}
|
|
376
384
|
}
|
|
377
385
|
}
|
|
@@ -388,7 +396,14 @@ export class OpenAIResponsesProvider implements Provider {
|
|
|
388
396
|
if (callId) {
|
|
389
397
|
const entry = toolCallMap.get(callId);
|
|
390
398
|
if (entry) {
|
|
399
|
+
if (event.name) entry.name = event.name;
|
|
391
400
|
entry.args = event.arguments;
|
|
401
|
+
toolProgress.emitInputJsonDelta(
|
|
402
|
+
entry.callId,
|
|
403
|
+
entry.name,
|
|
404
|
+
entry.args,
|
|
405
|
+
{ force: true },
|
|
406
|
+
);
|
|
392
407
|
}
|
|
393
408
|
}
|
|
394
409
|
}
|
|
@@ -462,6 +477,9 @@ export class OpenAIResponsesProvider implements Provider {
|
|
|
462
477
|
content.push({ type: "text", text: contentText });
|
|
463
478
|
}
|
|
464
479
|
for (const [, tc] of toolCallMap) {
|
|
480
|
+
toolProgress.emitInputJsonDelta(tc.callId, tc.name, tc.args, {
|
|
481
|
+
force: true,
|
|
482
|
+
});
|
|
465
483
|
let input: Record<string, unknown>;
|
|
466
484
|
try {
|
|
467
485
|
input = JSON.parse(tc.args);
|
|
@@ -32,7 +32,9 @@ const PLACEHOLDER_SENTINEL_BARE: ReadonlySet<string> = new Set(
|
|
|
32
32
|
// control-stripping proxy can leave in its place.
|
|
33
33
|
function stripLeadingEdgeNoise(text: string): string {
|
|
34
34
|
let start = 0;
|
|
35
|
-
while (start < text.length && text.charCodeAt(start) <= 0x20)
|
|
35
|
+
while (start < text.length && text.charCodeAt(start) <= 0x20) {
|
|
36
|
+
start += 1;
|
|
37
|
+
}
|
|
36
38
|
return text.slice(start);
|
|
37
39
|
}
|
|
38
40
|
|
|
@@ -40,7 +42,9 @@ function stripLeadingEdgeNoise(text: string): string {
|
|
|
40
42
|
function stripSentinelEdgeNoise(text: string): string {
|
|
41
43
|
const lead = stripLeadingEdgeNoise(text);
|
|
42
44
|
let end = lead.length;
|
|
43
|
-
while (end > 0 && lead.charCodeAt(end - 1) <= 0x20)
|
|
45
|
+
while (end > 0 && lead.charCodeAt(end - 1) <= 0x20) {
|
|
46
|
+
end -= 1;
|
|
47
|
+
}
|
|
44
48
|
return lead.slice(0, end);
|
|
45
49
|
}
|
|
46
50
|
|
|
@@ -56,14 +60,20 @@ export function isPlaceholderSentinelText(text: string): boolean {
|
|
|
56
60
|
}
|
|
57
61
|
|
|
58
62
|
/**
|
|
59
|
-
* True when `text` could still grow into a sentinel
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
63
|
+
* True when `text` could still grow into a sentinel — or already is one carrying
|
|
64
|
+
* trailing edge noise. Once whitespace and control bytes are stripped from BOTH
|
|
65
|
+
* edges, the remainder must be a prefix of a bare sentinel: the empty string
|
|
66
|
+
* (pure edge noise) and a complete sentinel (a prefix of itself, so
|
|
67
|
+
* `"<sentinel>\n"`) both qualify and stay held until block stop, where
|
|
68
|
+
* `isPlaceholderSentinelText` drops them. The streaming guard uses this to keep
|
|
69
|
+
* a sentinel — or an echo whose `\x00` guard arrived as whitespace — off the
|
|
70
|
+
* live UI before completion.
|
|
71
|
+
*
|
|
72
|
+
* Genuine content is never withheld: any non-whitespace byte breaks the prefix,
|
|
73
|
+
* extending the trimmed remainder past every bare form, so the buffer flushes.
|
|
64
74
|
*/
|
|
65
75
|
export function couldBePlaceholderSentinelPrefix(text: string): boolean {
|
|
66
|
-
const normalized =
|
|
76
|
+
const normalized = stripSentinelEdgeNoise(text);
|
|
67
77
|
return PLACEHOLDER_SENTINEL_BARE_FORMS.some((form) =>
|
|
68
78
|
form.startsWith(normalized),
|
|
69
79
|
);
|
package/src/providers/retry.ts
CHANGED
|
@@ -713,6 +713,7 @@ export class RetryProvider implements Provider {
|
|
|
713
713
|
retryAfterHeader: retryAfter !== undefined,
|
|
714
714
|
errorType,
|
|
715
715
|
provider: this.name,
|
|
716
|
+
message: error instanceof Error ? error.message : String(error),
|
|
716
717
|
},
|
|
717
718
|
"Retrying after transient error",
|
|
718
719
|
);
|
|
@@ -136,70 +136,6 @@ describe("STT provider catalog", () => {
|
|
|
136
136
|
expect(entry?.conversationStreamingMode).toBe("incremental-batch");
|
|
137
137
|
});
|
|
138
138
|
|
|
139
|
-
// -----------------------------------------------------------------------
|
|
140
|
-
// Telephony routing metadata
|
|
141
|
-
// -----------------------------------------------------------------------
|
|
142
|
-
|
|
143
|
-
test("every entry has telephonyRouting metadata", () => {
|
|
144
|
-
for (const entry of listProviderEntries()) {
|
|
145
|
-
expect(entry.telephonyRouting).toBeDefined();
|
|
146
|
-
expect(["conversation-relay-native", "media-stream-custom"]).toContain(
|
|
147
|
-
entry.telephonyRouting.strategyKind,
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
test("conversation-relay-native entries have twilioNativeMapping", () => {
|
|
153
|
-
for (const entry of listProviderEntries()) {
|
|
154
|
-
if (entry.telephonyRouting.strategyKind === "conversation-relay-native") {
|
|
155
|
-
expect(entry.telephonyRouting.twilioNativeMapping).toBeDefined();
|
|
156
|
-
expect(
|
|
157
|
-
entry.telephonyRouting.twilioNativeMapping!.provider.length,
|
|
158
|
-
).toBeGreaterThan(0);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
test("media-stream-custom entries do not have twilioNativeMapping", () => {
|
|
164
|
-
for (const entry of listProviderEntries()) {
|
|
165
|
-
if (entry.telephonyRouting.strategyKind === "media-stream-custom") {
|
|
166
|
-
expect(entry.telephonyRouting.twilioNativeMapping).toBeUndefined();
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
test("deepgram has conversation-relay-native strategy with Deepgram Twilio mapping", () => {
|
|
172
|
-
const entry = getProviderEntry("deepgram");
|
|
173
|
-
expect(entry?.telephonyRouting.strategyKind).toBe(
|
|
174
|
-
"conversation-relay-native",
|
|
175
|
-
);
|
|
176
|
-
expect(entry?.telephonyRouting.twilioNativeMapping?.provider).toBe(
|
|
177
|
-
"Deepgram",
|
|
178
|
-
);
|
|
179
|
-
expect(
|
|
180
|
-
entry?.telephonyRouting.twilioNativeMapping?.defaultSpeechModel,
|
|
181
|
-
).toBe("nova-3");
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
test("google-gemini has conversation-relay-native strategy with Google Twilio mapping", () => {
|
|
185
|
-
const entry = getProviderEntry("google-gemini");
|
|
186
|
-
expect(entry?.telephonyRouting.strategyKind).toBe(
|
|
187
|
-
"conversation-relay-native",
|
|
188
|
-
);
|
|
189
|
-
expect(entry?.telephonyRouting.twilioNativeMapping?.provider).toBe(
|
|
190
|
-
"Google",
|
|
191
|
-
);
|
|
192
|
-
expect(
|
|
193
|
-
entry?.telephonyRouting.twilioNativeMapping?.defaultSpeechModel,
|
|
194
|
-
).toBeUndefined();
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
test("openai-whisper has media-stream-custom strategy without Twilio mapping", () => {
|
|
198
|
-
const entry = getProviderEntry("openai-whisper");
|
|
199
|
-
expect(entry?.telephonyRouting.strategyKind).toBe("media-stream-custom");
|
|
200
|
-
expect(entry?.telephonyRouting.twilioNativeMapping).toBeUndefined();
|
|
201
|
-
});
|
|
202
|
-
|
|
203
139
|
// -----------------------------------------------------------------------
|
|
204
140
|
// Credential lookup
|
|
205
141
|
// -----------------------------------------------------------------------
|
|
@@ -406,33 +406,33 @@ describe("resolveTelephonySttCapability", () => {
|
|
|
406
406
|
});
|
|
407
407
|
|
|
408
408
|
// ---------------------------------------------------------------------------
|
|
409
|
-
// Tests — telephony
|
|
409
|
+
// Tests — telephony capability alignment with provider catalog
|
|
410
410
|
// ---------------------------------------------------------------------------
|
|
411
411
|
|
|
412
412
|
import { getProviderEntry, listProviderIds } from "../provider-catalog.js";
|
|
413
413
|
|
|
414
|
-
describe("telephony
|
|
414
|
+
describe("telephony capability catalog alignment", () => {
|
|
415
415
|
/**
|
|
416
416
|
* These tests verify that the assumptions made by the telephony STT
|
|
417
|
-
*
|
|
418
|
-
* the provider catalog entries. If a catalog entry changes its
|
|
419
|
-
* telephonyMode
|
|
420
|
-
*
|
|
417
|
+
* capability resolver (resolveTelephonySttCapability) remain consistent
|
|
418
|
+
* with the provider catalog entries. If a catalog entry changes its
|
|
419
|
+
* telephonyMode or a new provider is added, these tests will catch
|
|
420
|
+
* misalignment early.
|
|
421
421
|
*/
|
|
422
422
|
|
|
423
|
-
test("deepgram catalog entry has realtime-ws telephonyMode
|
|
423
|
+
test("deepgram catalog entry has realtime-ws telephonyMode", () => {
|
|
424
424
|
const entry = getProviderEntry("deepgram");
|
|
425
425
|
expect(entry).toBeDefined();
|
|
426
426
|
expect(entry!.telephonyMode).toBe("realtime-ws");
|
|
427
427
|
});
|
|
428
428
|
|
|
429
|
-
test("google-gemini catalog entry has batch-only telephonyMode
|
|
429
|
+
test("google-gemini catalog entry has batch-only telephonyMode", () => {
|
|
430
430
|
const entry = getProviderEntry("google-gemini");
|
|
431
431
|
expect(entry).toBeDefined();
|
|
432
432
|
expect(entry!.telephonyMode).toBe("batch-only");
|
|
433
433
|
});
|
|
434
434
|
|
|
435
|
-
test("openai-whisper catalog entry has batch-only telephonyMode
|
|
435
|
+
test("openai-whisper catalog entry has batch-only telephonyMode", () => {
|
|
436
436
|
const entry = getProviderEntry("openai-whisper");
|
|
437
437
|
expect(entry).toBeDefined();
|
|
438
438
|
expect(entry!.telephonyMode).toBe("batch-only");
|
|
@@ -454,10 +454,10 @@ describe("telephony routing catalog alignment", () => {
|
|
|
454
454
|
});
|
|
455
455
|
|
|
456
456
|
test("every catalog provider has a non-none telephonyMode", () => {
|
|
457
|
-
// The telephony
|
|
458
|
-
// participate in
|
|
459
|
-
//
|
|
460
|
-
//
|
|
457
|
+
// The telephony capability resolver assumes all known providers
|
|
458
|
+
// participate in telephony over the media-stream transport. If a
|
|
459
|
+
// provider with telephonyMode: "none" is added, the resolver reports
|
|
460
|
+
// it as unsupported.
|
|
461
461
|
for (const id of listProviderIds()) {
|
|
462
462
|
const entry = getProviderEntry(id);
|
|
463
463
|
expect(entry).toBeDefined();
|
|
@@ -465,72 +465,6 @@ describe("telephony routing catalog alignment", () => {
|
|
|
465
465
|
}
|
|
466
466
|
});
|
|
467
467
|
|
|
468
|
-
// -----------------------------------------------------------------------
|
|
469
|
-
// Telephony routing metadata invariants
|
|
470
|
-
// -----------------------------------------------------------------------
|
|
471
|
-
|
|
472
|
-
test("every catalog provider has telephonyRouting metadata", () => {
|
|
473
|
-
for (const id of listProviderIds()) {
|
|
474
|
-
const entry = getProviderEntry(id);
|
|
475
|
-
expect(entry).toBeDefined();
|
|
476
|
-
expect(entry!.telephonyRouting).toBeDefined();
|
|
477
|
-
expect(["conversation-relay-native", "media-stream-custom"]).toContain(
|
|
478
|
-
entry!.telephonyRouting.strategyKind,
|
|
479
|
-
);
|
|
480
|
-
}
|
|
481
|
-
});
|
|
482
|
-
|
|
483
|
-
test("conversation-relay-native providers have twilioNativeMapping with non-empty provider name", () => {
|
|
484
|
-
for (const id of listProviderIds()) {
|
|
485
|
-
const entry = getProviderEntry(id)!;
|
|
486
|
-
if (entry.telephonyRouting.strategyKind === "conversation-relay-native") {
|
|
487
|
-
expect(entry.telephonyRouting.twilioNativeMapping).toBeDefined();
|
|
488
|
-
expect(
|
|
489
|
-
entry.telephonyRouting.twilioNativeMapping!.provider.length,
|
|
490
|
-
).toBeGreaterThan(0);
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
});
|
|
494
|
-
|
|
495
|
-
test("media-stream-custom providers do not have twilioNativeMapping", () => {
|
|
496
|
-
for (const id of listProviderIds()) {
|
|
497
|
-
const entry = getProviderEntry(id)!;
|
|
498
|
-
if (entry.telephonyRouting.strategyKind === "media-stream-custom") {
|
|
499
|
-
expect(entry.telephonyRouting.twilioNativeMapping).toBeUndefined();
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
});
|
|
503
|
-
|
|
504
|
-
test("deepgram routing metadata maps to Twilio-native Deepgram with nova-3 speech model", () => {
|
|
505
|
-
const entry = getProviderEntry("deepgram")!;
|
|
506
|
-
expect(entry.telephonyRouting.strategyKind).toBe(
|
|
507
|
-
"conversation-relay-native",
|
|
508
|
-
);
|
|
509
|
-
expect(entry.telephonyRouting.twilioNativeMapping?.provider).toBe(
|
|
510
|
-
"Deepgram",
|
|
511
|
-
);
|
|
512
|
-
expect(entry.telephonyRouting.twilioNativeMapping?.defaultSpeechModel).toBe(
|
|
513
|
-
"nova-3",
|
|
514
|
-
);
|
|
515
|
-
});
|
|
516
|
-
|
|
517
|
-
test("google-gemini routing metadata maps to Twilio-native Google with no default speech model", () => {
|
|
518
|
-
const entry = getProviderEntry("google-gemini")!;
|
|
519
|
-
expect(entry.telephonyRouting.strategyKind).toBe(
|
|
520
|
-
"conversation-relay-native",
|
|
521
|
-
);
|
|
522
|
-
expect(entry.telephonyRouting.twilioNativeMapping?.provider).toBe("Google");
|
|
523
|
-
expect(
|
|
524
|
-
entry.telephonyRouting.twilioNativeMapping?.defaultSpeechModel,
|
|
525
|
-
).toBeUndefined();
|
|
526
|
-
});
|
|
527
|
-
|
|
528
|
-
test("openai-whisper routing metadata uses media-stream-custom without Twilio mapping", () => {
|
|
529
|
-
const entry = getProviderEntry("openai-whisper")!;
|
|
530
|
-
expect(entry.telephonyRouting.strategyKind).toBe("media-stream-custom");
|
|
531
|
-
expect(entry.telephonyRouting.twilioNativeMapping).toBeUndefined();
|
|
532
|
-
});
|
|
533
|
-
|
|
534
468
|
// -----------------------------------------------------------------------
|
|
535
469
|
// Stable provider identity
|
|
536
470
|
// -----------------------------------------------------------------------
|
|
@@ -880,4 +814,83 @@ describe("resolveStreamingTranscriber diarize preference", () => {
|
|
|
880
814
|
expect(transcriber).toBeNull();
|
|
881
815
|
expect(xaiCtorCalls).toHaveLength(0);
|
|
882
816
|
});
|
|
817
|
+
|
|
818
|
+
// -------------------------------------------------------------------------
|
|
819
|
+
// Utterance-boundary finals (telephony)
|
|
820
|
+
// -------------------------------------------------------------------------
|
|
821
|
+
|
|
822
|
+
test("utteranceBoundaryFinals with xai returns null with a warning (per-segment finals cannot be boundary-gated)", async () => {
|
|
823
|
+
mockProviderKeys["xai"] = "xai-key";
|
|
824
|
+
mockConfig = buildConfig({ provider: "xai" });
|
|
825
|
+
|
|
826
|
+
const transcriber = await resolveStreamingTranscriber({
|
|
827
|
+
utteranceBoundaryFinals: true,
|
|
828
|
+
});
|
|
829
|
+
|
|
830
|
+
expect(transcriber).toBeNull();
|
|
831
|
+
expect(xaiCtorCalls).toHaveLength(0);
|
|
832
|
+
expect(loggerWarnings).toHaveLength(1);
|
|
833
|
+
expect(loggerWarnings[0]!.message).toContain("falling back to batch");
|
|
834
|
+
expect(
|
|
835
|
+
(loggerWarnings[0]!.data as { providerId?: unknown }).providerId,
|
|
836
|
+
).toBe("xai");
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
test("utteranceBoundaryFinals with Deepgram forwards the gating options", async () => {
|
|
840
|
+
mockProviderKeys["deepgram"] = "dg-key";
|
|
841
|
+
mockConfig = buildConfig({ provider: "deepgram" });
|
|
842
|
+
|
|
843
|
+
const transcriber = await resolveStreamingTranscriber({
|
|
844
|
+
utteranceBoundaryFinals: true,
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
expect(transcriber).not.toBeNull();
|
|
848
|
+
expect(deepgramCtorCalls).toHaveLength(1);
|
|
849
|
+
const options = deepgramCtorCalls[0]!.options as Record<string, unknown>;
|
|
850
|
+
expect(options.utteranceBoundaryFinals).toBe(true);
|
|
851
|
+
expect(options.utteranceEndMs).toBe(1000);
|
|
852
|
+
});
|
|
853
|
+
|
|
854
|
+
test("utteranceBoundaryFinals with google-gemini returns null (catalog telephonyMode is batch-only)", async () => {
|
|
855
|
+
mockProviderKeys["gemini"] = "gemini-key";
|
|
856
|
+
mockConfig = buildConfig({ provider: "google-gemini" });
|
|
857
|
+
|
|
858
|
+
const transcriber = await resolveStreamingTranscriber({
|
|
859
|
+
utteranceBoundaryFinals: true,
|
|
860
|
+
});
|
|
861
|
+
|
|
862
|
+
expect(transcriber).toBeNull();
|
|
863
|
+
expect(geminiCtorCalls).toHaveLength(0);
|
|
864
|
+
expect(loggerWarnings).toHaveLength(1);
|
|
865
|
+
expect(
|
|
866
|
+
(loggerWarnings[0]!.data as { providerId?: unknown }).providerId,
|
|
867
|
+
).toBe("google-gemini");
|
|
868
|
+
});
|
|
869
|
+
|
|
870
|
+
test("utteranceBoundaryFinals with openai-whisper returns null with a warning (finals fire only on stop — end-of-stream, not utterance boundary)", async () => {
|
|
871
|
+
mockProviderKeys["openai"] = "openai-key";
|
|
872
|
+
mockConfig = buildConfig({ provider: "openai-whisper" });
|
|
873
|
+
|
|
874
|
+
const transcriber = await resolveStreamingTranscriber({
|
|
875
|
+
utteranceBoundaryFinals: true,
|
|
876
|
+
});
|
|
877
|
+
|
|
878
|
+
expect(transcriber).toBeNull();
|
|
879
|
+
expect(whisperCtorCalls).toHaveLength(0);
|
|
880
|
+
expect(loggerWarnings).toHaveLength(1);
|
|
881
|
+
expect(loggerWarnings[0]!.message).toContain("falling back to batch");
|
|
882
|
+
expect(
|
|
883
|
+
(loggerWarnings[0]!.data as { providerId?: unknown }).providerId,
|
|
884
|
+
).toBe("openai-whisper");
|
|
885
|
+
});
|
|
886
|
+
|
|
887
|
+
test("openai-whisper still resolves a streaming transcriber without utteranceBoundaryFinals", async () => {
|
|
888
|
+
mockProviderKeys["openai"] = "openai-key";
|
|
889
|
+
mockConfig = buildConfig({ provider: "openai-whisper" });
|
|
890
|
+
|
|
891
|
+
const transcriber = await resolveStreamingTranscriber();
|
|
892
|
+
|
|
893
|
+
expect(transcriber).not.toBeNull();
|
|
894
|
+
expect(whisperCtorCalls).toHaveLength(1);
|
|
895
|
+
});
|
|
883
896
|
});
|
|
@@ -557,6 +557,104 @@ describe("DeepgramRealtimeTranscriber", () => {
|
|
|
557
557
|
});
|
|
558
558
|
});
|
|
559
559
|
|
|
560
|
+
// ─────────────────────────────────────────────────────────────────
|
|
561
|
+
// Utterance-boundary finals (telephony gating)
|
|
562
|
+
// ─────────────────────────────────────────────────────────────────
|
|
563
|
+
|
|
564
|
+
describe("utteranceBoundaryFinals", () => {
|
|
565
|
+
test("withholds is_final segments until speech_final, then emits one aggregated final", async () => {
|
|
566
|
+
const { events } = await startSession({ utteranceBoundaryFinals: true });
|
|
567
|
+
|
|
568
|
+
mockWs.simulateMessage(resultsFrame("this is a", { is_final: true }));
|
|
569
|
+
mockWs.simulateMessage(resultsFrame("long sentence", { is_final: true }));
|
|
570
|
+
expect(events.filter((e) => e.type === "final")).toHaveLength(0);
|
|
571
|
+
|
|
572
|
+
mockWs.simulateMessage(
|
|
573
|
+
resultsFrame("with a pause", { is_final: true, speech_final: true }),
|
|
574
|
+
);
|
|
575
|
+
|
|
576
|
+
const finals = events.filter((e) => e.type === "final");
|
|
577
|
+
expect(finals).toHaveLength(1);
|
|
578
|
+
expect(finals[0]).toEqual({
|
|
579
|
+
type: "final",
|
|
580
|
+
text: "this is a long sentence with a pause",
|
|
581
|
+
});
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
test("still emits partials while segments are withheld", async () => {
|
|
585
|
+
const { events } = await startSession({ utteranceBoundaryFinals: true });
|
|
586
|
+
|
|
587
|
+
mockWs.simulateMessage(resultsFrame("this is", { is_final: false }));
|
|
588
|
+
mockWs.simulateMessage(resultsFrame("this is a", { is_final: true }));
|
|
589
|
+
mockWs.simulateMessage(resultsFrame("long sen", { is_final: false }));
|
|
590
|
+
|
|
591
|
+
expect(events.filter((e) => e.type === "partial")).toHaveLength(2);
|
|
592
|
+
expect(events.filter((e) => e.type === "final")).toHaveLength(0);
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
test("UtteranceEnd flushes withheld segments as a single final", async () => {
|
|
596
|
+
const { events } = await startSession({ utteranceBoundaryFinals: true });
|
|
597
|
+
|
|
598
|
+
mockWs.simulateMessage(resultsFrame("trailing words", { is_final: true }));
|
|
599
|
+
mockWs.simulateMessage(utteranceEndFrame());
|
|
600
|
+
|
|
601
|
+
const finals = events.filter((e) => e.type === "final");
|
|
602
|
+
expect(finals).toHaveLength(1);
|
|
603
|
+
expect(finals[0]).toEqual({ type: "final", text: "trailing words" });
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
test("boundary signals over silence emit nothing", async () => {
|
|
607
|
+
const { events } = await startSession({ utteranceBoundaryFinals: true });
|
|
608
|
+
|
|
609
|
+
mockWs.simulateMessage(
|
|
610
|
+
resultsFrame("", { is_final: true, speech_final: true }),
|
|
611
|
+
);
|
|
612
|
+
mockWs.simulateMessage(utteranceEndFrame());
|
|
613
|
+
|
|
614
|
+
expect(events).toHaveLength(0);
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
test("close flushes withheld segments before the closed event", async () => {
|
|
618
|
+
const { transcriber, events } = await startSession({
|
|
619
|
+
utteranceBoundaryFinals: true,
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
mockWs.simulateMessage(resultsFrame("cut off", { is_final: true }));
|
|
623
|
+
transcriber.stop();
|
|
624
|
+
mockWs.simulateClose(1000, "normal");
|
|
625
|
+
|
|
626
|
+
const finalIndex = events.findIndex((e) => e.type === "final");
|
|
627
|
+
const closedIndex = events.findIndex((e) => e.type === "closed");
|
|
628
|
+
expect(finalIndex).toBeGreaterThanOrEqual(0);
|
|
629
|
+
expect(closedIndex).toBeGreaterThan(finalIndex);
|
|
630
|
+
expect(events[finalIndex]).toEqual({ type: "final", text: "cut off" });
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
test("each utterance aggregates independently", async () => {
|
|
634
|
+
const { events } = await startSession({ utteranceBoundaryFinals: true });
|
|
635
|
+
|
|
636
|
+
mockWs.simulateMessage(resultsFrame("first part", { is_final: true }));
|
|
637
|
+
mockWs.simulateMessage(
|
|
638
|
+
resultsFrame("done", { is_final: true, speech_final: true }),
|
|
639
|
+
);
|
|
640
|
+
mockWs.simulateMessage(
|
|
641
|
+
resultsFrame("second utterance", {
|
|
642
|
+
is_final: true,
|
|
643
|
+
speech_final: true,
|
|
644
|
+
}),
|
|
645
|
+
);
|
|
646
|
+
|
|
647
|
+
const finals = events.filter((e) => e.type === "final") as {
|
|
648
|
+
type: "final";
|
|
649
|
+
text: string;
|
|
650
|
+
}[];
|
|
651
|
+
expect(finals.map((f) => f.text)).toEqual([
|
|
652
|
+
"first part done",
|
|
653
|
+
"second utterance",
|
|
654
|
+
]);
|
|
655
|
+
});
|
|
656
|
+
});
|
|
657
|
+
|
|
560
658
|
// ─────────────────────────────────────────────────────────────────
|
|
561
659
|
// Non-transcript frames
|
|
562
660
|
// ─────────────────────────────────────────────────────────────────
|
|
@@ -123,6 +123,23 @@ export interface DeepgramRealtimeOptions {
|
|
|
123
123
|
* composer) preserve their current lean URL + response shape.
|
|
124
124
|
*/
|
|
125
125
|
diarize?: boolean;
|
|
126
|
+
/**
|
|
127
|
+
* Emit `final` events only at utterance boundaries. Default: false.
|
|
128
|
+
*
|
|
129
|
+
* Deepgram commits a long sentence as multiple `is_final` segments
|
|
130
|
+
* before the speaker pauses. When `true`, committed segment texts are
|
|
131
|
+
* withheld and accumulated, and a single aggregated `final` is emitted
|
|
132
|
+
* when Deepgram signals an utterance boundary (`speech_final` on a
|
|
133
|
+
* Results frame, or an `UtteranceEnd` frame), or when the session
|
|
134
|
+
* closes with text still pending. Boundary signals with no accumulated
|
|
135
|
+
* text emit nothing. Aggregated finals omit `speakerLabel` /
|
|
136
|
+
* `confidence` (segment-level scores do not compose across segments).
|
|
137
|
+
*
|
|
138
|
+
* Used by telephony call ingestion so replies trigger once per caller
|
|
139
|
+
* utterance. When `false`, every `is_final` segment emits its own
|
|
140
|
+
* `final` event (chat composer / live-voice behavior).
|
|
141
|
+
*/
|
|
142
|
+
utteranceBoundaryFinals?: boolean;
|
|
126
143
|
}
|
|
127
144
|
|
|
128
145
|
// ---------------------------------------------------------------------------
|
|
@@ -249,6 +266,19 @@ export class DeepgramRealtimeTranscriber implements StreamingTranscriber {
|
|
|
249
266
|
*/
|
|
250
267
|
private readonly diarize: boolean;
|
|
251
268
|
|
|
269
|
+
/**
|
|
270
|
+
* Whether `final` events are gated on utterance boundaries — see
|
|
271
|
+
* {@link DeepgramRealtimeOptions.utteranceBoundaryFinals}.
|
|
272
|
+
*/
|
|
273
|
+
private readonly utteranceBoundaryFinals: boolean;
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Committed (`is_final`) segment texts withheld until the next
|
|
277
|
+
* utterance boundary. Only populated when
|
|
278
|
+
* {@link utteranceBoundaryFinals} is enabled.
|
|
279
|
+
*/
|
|
280
|
+
private pendingFinalSegments: string[] = [];
|
|
281
|
+
|
|
252
282
|
/** The live WebSocket connection, set during start(). */
|
|
253
283
|
private ws: WsLike | null = null;
|
|
254
284
|
|
|
@@ -290,6 +320,7 @@ export class DeepgramRealtimeTranscriber implements StreamingTranscriber {
|
|
|
290
320
|
options.keepaliveIntervalMs ?? DEFAULT_KEEPALIVE_INTERVAL_MS;
|
|
291
321
|
this.sampleRate = options.sampleRate ?? 16_000;
|
|
292
322
|
this.diarize = options.diarize ?? false;
|
|
323
|
+
this.utteranceBoundaryFinals = options.utteranceBoundaryFinals ?? false;
|
|
293
324
|
}
|
|
294
325
|
|
|
295
326
|
// ── StreamingTranscriber interface ──────────────────────────────────
|
|
@@ -497,10 +528,11 @@ export class DeepgramRealtimeTranscriber implements StreamingTranscriber {
|
|
|
497
528
|
|
|
498
529
|
// `UtteranceEnd` is an endpointing signal — no transcript text, but
|
|
499
530
|
// it confirms the previous is_final segment is a natural boundary.
|
|
500
|
-
//
|
|
501
|
-
// finals on is_final=true.
|
|
531
|
+
// In utterance-boundary mode it flushes any withheld segments; in
|
|
532
|
+
// pass-through mode finals were already emitted on is_final=true.
|
|
502
533
|
if (frame.type === "UtteranceEnd") {
|
|
503
534
|
log.debug("Received UtteranceEnd signal");
|
|
535
|
+
this.flushPendingUtterance();
|
|
504
536
|
return;
|
|
505
537
|
}
|
|
506
538
|
|
|
@@ -543,6 +575,16 @@ export class DeepgramRealtimeTranscriber implements StreamingTranscriber {
|
|
|
543
575
|
: undefined;
|
|
544
576
|
|
|
545
577
|
if (frame.is_final) {
|
|
578
|
+
if (this.utteranceBoundaryFinals) {
|
|
579
|
+
// Withhold committed segments until an utterance boundary.
|
|
580
|
+
if (text.length > 0) {
|
|
581
|
+
this.pendingFinalSegments.push(text);
|
|
582
|
+
}
|
|
583
|
+
if (frame.speech_final) {
|
|
584
|
+
this.flushPendingUtterance();
|
|
585
|
+
}
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
546
588
|
// Committed transcript — emit as final.
|
|
547
589
|
this.emitEvent({
|
|
548
590
|
type: "final",
|
|
@@ -630,9 +672,25 @@ export class DeepgramRealtimeTranscriber implements StreamingTranscriber {
|
|
|
630
672
|
}
|
|
631
673
|
}
|
|
632
674
|
|
|
675
|
+
/**
|
|
676
|
+
* Emit a single aggregated `final` for the withheld `is_final` segments
|
|
677
|
+
* of the current utterance. No-op when nothing is pending, so boundary
|
|
678
|
+
* signals over silence emit nothing.
|
|
679
|
+
*/
|
|
680
|
+
private flushPendingUtterance(): void {
|
|
681
|
+
if (this.pendingFinalSegments.length === 0) {
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
const text = this.pendingFinalSegments.join(" ");
|
|
685
|
+
this.pendingFinalSegments = [];
|
|
686
|
+
this.emitEvent({ type: "final", text });
|
|
687
|
+
}
|
|
688
|
+
|
|
633
689
|
/**
|
|
634
690
|
* Emit a `closed` event and clean up all resources (timers, WebSocket).
|
|
635
|
-
*
|
|
691
|
+
* Flushes any withheld utterance text first so boundary-gated sessions
|
|
692
|
+
* never lose committed transcript on close. Idempotent — safe to call
|
|
693
|
+
* multiple times.
|
|
636
694
|
*/
|
|
637
695
|
private emitClosedAndCleanup(): void {
|
|
638
696
|
if (this.closed) return;
|
|
@@ -641,6 +699,7 @@ export class DeepgramRealtimeTranscriber implements StreamingTranscriber {
|
|
|
641
699
|
this.clearTimers();
|
|
642
700
|
this.forceClose();
|
|
643
701
|
|
|
702
|
+
this.flushPendingUtterance();
|
|
644
703
|
this.emitEvent({ type: "closed" });
|
|
645
704
|
this.onEvent = null;
|
|
646
705
|
}
|