@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
|
@@ -31,7 +31,10 @@ import {
|
|
|
31
31
|
getSilenceTimeoutMs,
|
|
32
32
|
getUserConsultationTimeoutMs,
|
|
33
33
|
} from "./call-constants.js";
|
|
34
|
-
import {
|
|
34
|
+
import {
|
|
35
|
+
formatDuration,
|
|
36
|
+
postPointerMessageSafe,
|
|
37
|
+
} from "./call-pointer-messages.js";
|
|
35
38
|
import {
|
|
36
39
|
fireCallQuestionNotifier,
|
|
37
40
|
fireCallTranscriptNotifier,
|
|
@@ -239,7 +242,7 @@ export class CallController {
|
|
|
239
242
|
}
|
|
240
243
|
|
|
241
244
|
/**
|
|
242
|
-
* Handle a final caller utterance from the
|
|
245
|
+
* Handle a final caller utterance from the call transport.
|
|
243
246
|
* Caller utterances always trigger normal turns, even when a guardian
|
|
244
247
|
* consultation is pending — the consultation is tracked separately.
|
|
245
248
|
*/
|
|
@@ -361,10 +364,15 @@ export class CallController {
|
|
|
361
364
|
* interruption on initial inbound media frames that arrive before
|
|
362
365
|
* the assistant has had a chance to produce its first response.
|
|
363
366
|
*
|
|
367
|
+
* @param onAccepted Invoked synchronously after the speaking gate
|
|
368
|
+
* passes but before {@link handleInterrupt} runs. Transports use this
|
|
369
|
+
* to flush queued outbound audio without wiping the end-of-turn mark
|
|
370
|
+
* that handleInterrupt enqueues — and without flushing at all when
|
|
371
|
+
* the barge-in is ignored.
|
|
364
372
|
* @returns `true` if the barge-in was accepted (assistant was speaking),
|
|
365
373
|
* `false` if it was ignored (assistant idle or processing).
|
|
366
374
|
*/
|
|
367
|
-
handleBargeIn(): boolean {
|
|
375
|
+
handleBargeIn(onAccepted?: () => void): boolean {
|
|
368
376
|
if (this.state !== "speaking") {
|
|
369
377
|
log.debug(
|
|
370
378
|
{
|
|
@@ -380,6 +388,7 @@ export class CallController {
|
|
|
380
388
|
{ callSessionId: this.callSessionId },
|
|
381
389
|
"Barge-in accepted — interrupting assistant speech",
|
|
382
390
|
);
|
|
391
|
+
onAccepted?.();
|
|
383
392
|
this.handleInterrupt();
|
|
384
393
|
return true;
|
|
385
394
|
}
|
|
@@ -395,11 +404,6 @@ export class CallController {
|
|
|
395
404
|
const wasSpeaking = this.state === "speaking";
|
|
396
405
|
this.abortCurrentTurn();
|
|
397
406
|
this.llmRunVersion++;
|
|
398
|
-
// Cancel in-flight synthesized TTS on barge-in
|
|
399
|
-
if (this.activeSynthesisAbort) {
|
|
400
|
-
this.activeSynthesisAbort.abort();
|
|
401
|
-
this.activeSynthesisAbort = null;
|
|
402
|
-
}
|
|
403
407
|
// Explicitly terminate the in-progress TTS turn so the relay can
|
|
404
408
|
// immediately hand control back to the caller after barge-in.
|
|
405
409
|
if (wasSpeaking) {
|
|
@@ -483,6 +487,16 @@ export class CallController {
|
|
|
483
487
|
}
|
|
484
488
|
this.abortController.abort();
|
|
485
489
|
this.abortController = new AbortController();
|
|
490
|
+
// Abort any in-flight synthesized-TTS playback too, so a superseded or
|
|
491
|
+
// torn-down turn's audio isn't streamed to the caller after they move on.
|
|
492
|
+
if (this.activeSynthesisAbort) {
|
|
493
|
+
this.activeSynthesisAbort.abort();
|
|
494
|
+
this.activeSynthesisAbort = null;
|
|
495
|
+
}
|
|
496
|
+
// Drop the aborted turn's unsent buffered text on transports that
|
|
497
|
+
// accumulate tokens (media-stream), so it cannot leak into the next
|
|
498
|
+
// turn's synthesis.
|
|
499
|
+
this.transport.discardPendingText?.();
|
|
486
500
|
}
|
|
487
501
|
|
|
488
502
|
private formatCallerUtterance(
|
|
@@ -523,7 +537,10 @@ export class CallController {
|
|
|
523
537
|
}
|
|
524
538
|
|
|
525
539
|
try {
|
|
526
|
-
|
|
540
|
+
// Stay in `processing` through the lock-wait and LLM generation; flip to
|
|
541
|
+
// `speaking` only when real outbound audio/tokens start (see
|
|
542
|
+
// beginSpeaking). This keeps barge-in from aborting a silent turn.
|
|
543
|
+
this.state = "processing";
|
|
527
544
|
|
|
528
545
|
const fullResponseText = await this.streamTtsTokens(
|
|
529
546
|
content,
|
|
@@ -561,6 +578,21 @@ export class CallController {
|
|
|
561
578
|
);
|
|
562
579
|
return;
|
|
563
580
|
}
|
|
581
|
+
if (this.isLockContentionError(err) && this.isCurrentRun(runVersion)) {
|
|
582
|
+
log.debug(
|
|
583
|
+
{ callSessionId: this.callSessionId },
|
|
584
|
+
"Prior voice turn wedged past lock-hold budget; re-prompting caller",
|
|
585
|
+
);
|
|
586
|
+
// Reaching here means the prior turn is genuinely wedged past the full
|
|
587
|
+
// lock-hold wait budget, so surface a brief natural re-prompt (never a
|
|
588
|
+
// technical-error message) and re-arm listening. last=true doubles as
|
|
589
|
+
// the end-of-turn marker.
|
|
590
|
+
this.transport.sendTextToken("Sorry, could you say that again?", true);
|
|
591
|
+
this.state = "idle";
|
|
592
|
+
this.resetSilenceTimer();
|
|
593
|
+
this.flushPendingInstructions();
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
564
596
|
log.error({ err, callSessionId: this.callSessionId }, "Voice turn error");
|
|
565
597
|
this.transport.sendTextToken(
|
|
566
598
|
"I'm sorry, I encountered a technical issue. Could you repeat that?",
|
|
@@ -586,13 +618,14 @@ export class CallController {
|
|
|
586
618
|
// The catalog's callMode determines the call path: synthesized-play
|
|
587
619
|
// providers buffer text, synthesize via provider API, and stream
|
|
588
620
|
// audio chunks to Twilio via play-URL. Native-twilio providers
|
|
589
|
-
// stream text tokens
|
|
621
|
+
// stream text tokens through the transport, which re-synthesizes
|
|
622
|
+
// them via daemon TTS on media-stream.
|
|
590
623
|
//
|
|
591
624
|
// When the transport requires WAV (media-stream), request WAV so
|
|
592
625
|
// the audio store entry and any downstream fetch/transcode receives
|
|
593
626
|
// PCM that audioBufferToFrames can convert to mu-law.
|
|
594
627
|
const { provider, useSynthesizedPath, audioFormat } =
|
|
595
|
-
resolveCallTtsProvider({
|
|
628
|
+
await resolveCallTtsProvider({
|
|
596
629
|
preferWav: this.transport.requiresWavAudio,
|
|
597
630
|
});
|
|
598
631
|
|
|
@@ -613,6 +646,7 @@ export class CallController {
|
|
|
613
646
|
if (useSynthesizedPath) {
|
|
614
647
|
synthesizedTextBuffer += cleaned;
|
|
615
648
|
} else {
|
|
649
|
+
this.beginSpeakingOnAudioStart(runVersion);
|
|
616
650
|
this.transport.sendTextToken(cleaned, false);
|
|
617
651
|
}
|
|
618
652
|
};
|
|
@@ -732,6 +766,10 @@ export class CallController {
|
|
|
732
766
|
const sanitizedSynthText = sanitizeForTts(synthesizedTextBuffer.trim());
|
|
733
767
|
if (useSynthesizedPath && provider && sanitizedSynthText.length > 0) {
|
|
734
768
|
if (!this.isCurrentRun(runVersion)) return fullResponseText;
|
|
769
|
+
// Do NOT flip to `speaking` here — provider synthesis latency (or the
|
|
770
|
+
// no-audio fallback window) would still be silent. The transition happens
|
|
771
|
+
// inside synthesizeAndStreamAudio when the play URL / first audio chunk
|
|
772
|
+
// (or native fallback token) is actually emitted.
|
|
735
773
|
await this.synthesizeAndStreamAudio(
|
|
736
774
|
provider,
|
|
737
775
|
sanitizedSynthText,
|
|
@@ -740,12 +778,18 @@ export class CallController {
|
|
|
740
778
|
);
|
|
741
779
|
}
|
|
742
780
|
|
|
781
|
+
// Synthesized playback (and its native fallback) can await provider
|
|
782
|
+
// latency; re-check the run wasn't superseded meanwhile so a stale turn
|
|
783
|
+
// doesn't inject its end-of-turn marker (or fallback text) into the next
|
|
784
|
+
// turn's output stream.
|
|
785
|
+
if (!this.isCurrentRun(runVersion)) return fullResponseText;
|
|
786
|
+
|
|
743
787
|
// Signal end of this turn's speech. An empty token with `last: true`
|
|
744
|
-
// tells
|
|
788
|
+
// tells the transport to start listening — it does NOT trigger TTS
|
|
745
789
|
// synthesis. This is required even when a synthesized provider handled
|
|
746
|
-
// all audio playback, because
|
|
747
|
-
//
|
|
748
|
-
//
|
|
790
|
+
// all audio playback, because the transport still needs the end-of-turn
|
|
791
|
+
// signal to transition from "assistant speaking" to "caller speaking"
|
|
792
|
+
// state.
|
|
749
793
|
this.transport.sendTextToken("", true);
|
|
750
794
|
|
|
751
795
|
// Mark the greeting's first response as awaiting ack
|
|
@@ -764,7 +808,7 @@ export class CallController {
|
|
|
764
808
|
private async synthesizeAndStreamAudio(
|
|
765
809
|
provider: TtsProvider,
|
|
766
810
|
text: string,
|
|
767
|
-
|
|
811
|
+
runVersion: number,
|
|
768
812
|
format: "mp3" | "wav" | "opus" = "mp3",
|
|
769
813
|
): Promise<void> {
|
|
770
814
|
let handle: ReturnType<typeof createStreamingEntry> | null = null;
|
|
@@ -788,6 +832,14 @@ export class CallController {
|
|
|
788
832
|
const url = `${baseUrl}/v1/audio/${handle.audioId}`;
|
|
789
833
|
const sendPlayUrlOnce = (): void => {
|
|
790
834
|
if (playUrlSent) return;
|
|
835
|
+
// Superseded/aborted while synthesis was pending — don't start playing
|
|
836
|
+
// a stale response after the caller has already moved on.
|
|
837
|
+
if (!this.isCurrentRun(runVersion)) return;
|
|
838
|
+
// Audio is now reaching the caller (or, on transports with an
|
|
839
|
+
// audio-start signal, will be the moment the first fetched frame
|
|
840
|
+
// goes out) — flip to `speaking` so barge-in can interrupt (it
|
|
841
|
+
// stays `processing` until this point).
|
|
842
|
+
this.beginSpeakingOnAudioStart(runVersion);
|
|
791
843
|
this.transport.sendPlayUrl(url);
|
|
792
844
|
playUrlSent = true;
|
|
793
845
|
};
|
|
@@ -870,11 +922,18 @@ export class CallController {
|
|
|
870
922
|
{ err, provider: provider.id, errName, errCode },
|
|
871
923
|
"TTS synthesis failed — falling back to native token TTS",
|
|
872
924
|
);
|
|
873
|
-
// If synthesis fails before any audio has started
|
|
874
|
-
// token-based speech
|
|
925
|
+
// If synthesis fails before any audio has started on a non-WAV
|
|
926
|
+
// transport, degrade to token-based speech so the caller still
|
|
875
927
|
// hears a response instead of silence. This fallback is only
|
|
876
928
|
// used for providers whose catalog entry allows native fallback.
|
|
877
|
-
|
|
929
|
+
// Skip it entirely for a superseded run so a stale response can't
|
|
930
|
+
// leak into the next caller turn.
|
|
931
|
+
if (
|
|
932
|
+
!playUrlSent &&
|
|
933
|
+
!this.transport.requiresWavAudio &&
|
|
934
|
+
this.isCurrentRun(runVersion)
|
|
935
|
+
) {
|
|
936
|
+
this.beginSpeakingOnAudioStart(runVersion);
|
|
878
937
|
this.transport.sendTextToken(text, false);
|
|
879
938
|
}
|
|
880
939
|
}
|
|
@@ -1196,22 +1255,14 @@ export class CallController {
|
|
|
1196
1255
|
const durationMs = currentSession.startedAt
|
|
1197
1256
|
? Date.now() - currentSession.startedAt
|
|
1198
1257
|
: 0;
|
|
1199
|
-
|
|
1258
|
+
postPointerMessageSafe(
|
|
1200
1259
|
currentSession.initiatedFromConversationId,
|
|
1201
1260
|
"completed",
|
|
1202
1261
|
currentSession.toNumber,
|
|
1203
1262
|
{
|
|
1204
1263
|
duration: durationMs > 0 ? formatDuration(durationMs) : undefined,
|
|
1205
1264
|
},
|
|
1206
|
-
)
|
|
1207
|
-
log.warn(
|
|
1208
|
-
{
|
|
1209
|
-
conversationId: currentSession.initiatedFromConversationId,
|
|
1210
|
-
err,
|
|
1211
|
-
},
|
|
1212
|
-
"Skipping pointer write — origin conversation may no longer exist",
|
|
1213
|
-
);
|
|
1214
|
-
});
|
|
1265
|
+
);
|
|
1215
1266
|
}
|
|
1216
1267
|
this.state = "idle";
|
|
1217
1268
|
}
|
|
@@ -1221,6 +1272,54 @@ export class CallController {
|
|
|
1221
1272
|
return err.name === "AbortError" || err.name === "APIUserAbortError";
|
|
1222
1273
|
}
|
|
1223
1274
|
|
|
1275
|
+
/**
|
|
1276
|
+
* Transient teardown race: a new voice turn reached the session bridge
|
|
1277
|
+
* before the previous turn released the conversation processing lock.
|
|
1278
|
+
* This is not a real error and must never be spoken to the caller.
|
|
1279
|
+
*/
|
|
1280
|
+
private isLockContentionError(err: unknown): boolean {
|
|
1281
|
+
return (
|
|
1282
|
+
err instanceof Error &&
|
|
1283
|
+
err.message.includes("already processing a message")
|
|
1284
|
+
);
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
/**
|
|
1288
|
+
* Flip from the pre-speech `processing` phase to `speaking` at the moment the
|
|
1289
|
+
* first real outbound audio/token is emitted. Guarded so a superseded or
|
|
1290
|
+
* aborted (idle) turn never (re)enters `speaking`, and so barge-in
|
|
1291
|
+
* (handleBargeIn, gated on `speaking`) can't abort a turn that is still
|
|
1292
|
+
* waiting for the processing lock or generating with no audio yet.
|
|
1293
|
+
*/
|
|
1294
|
+
private beginSpeaking(runVersion: number): void {
|
|
1295
|
+
if (!this.isCurrentRun(runVersion)) return;
|
|
1296
|
+
if (this.state === "processing") {
|
|
1297
|
+
this.state = "speaking";
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
/**
|
|
1302
|
+
* Flip to `speaking` when outbound audio genuinely starts.
|
|
1303
|
+
*
|
|
1304
|
+
* Transports that buffer text and synthesize asynchronously (e.g.
|
|
1305
|
+
* media-stream) expose an audio-start signal; on those, the flip is
|
|
1306
|
+
* deferred until the transport reports the first audio frame actually
|
|
1307
|
+
* went out — otherwise a turn whose tokens are merely buffered (no
|
|
1308
|
+
* audible output yet) would be barge-in-abortable, leaving the caller
|
|
1309
|
+
* with silence. Transports without the signal emit audio immediately,
|
|
1310
|
+
* so the flip happens inline. Both paths stay gated by isCurrentRun
|
|
1311
|
+
* via {@link beginSpeaking}.
|
|
1312
|
+
*/
|
|
1313
|
+
private beginSpeakingOnAudioStart(runVersion: number): void {
|
|
1314
|
+
if (this.transport.setAudioStartCallback) {
|
|
1315
|
+
this.transport.setAudioStartCallback(() =>
|
|
1316
|
+
this.beginSpeaking(runVersion),
|
|
1317
|
+
);
|
|
1318
|
+
} else {
|
|
1319
|
+
this.beginSpeaking(runVersion);
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1224
1323
|
private isCurrentRun(runVersion: number): boolean {
|
|
1225
1324
|
return runVersion === this.llmRunVersion;
|
|
1226
1325
|
}
|
|
@@ -1456,22 +1555,14 @@ export class CallController {
|
|
|
1456
1555
|
const durationMs = currentSession.startedAt
|
|
1457
1556
|
? Date.now() - currentSession.startedAt
|
|
1458
1557
|
: 0;
|
|
1459
|
-
|
|
1558
|
+
postPointerMessageSafe(
|
|
1460
1559
|
currentSession.initiatedFromConversationId,
|
|
1461
1560
|
"completed",
|
|
1462
1561
|
currentSession.toNumber,
|
|
1463
1562
|
{
|
|
1464
1563
|
duration: durationMs > 0 ? formatDuration(durationMs) : undefined,
|
|
1465
1564
|
},
|
|
1466
|
-
)
|
|
1467
|
-
log.warn(
|
|
1468
|
-
{
|
|
1469
|
-
conversationId: currentSession.initiatedFromConversationId,
|
|
1470
|
-
err,
|
|
1471
|
-
},
|
|
1472
|
-
"Skipping pointer write — origin conversation may no longer exist",
|
|
1473
|
-
);
|
|
1474
|
-
});
|
|
1565
|
+
);
|
|
1475
1566
|
}
|
|
1476
1567
|
}, 3000);
|
|
1477
1568
|
}, maxDurationMs);
|
|
@@ -1481,15 +1572,10 @@ export class CallController {
|
|
|
1481
1572
|
if (this.silenceTimer) clearTimeout(this.silenceTimer);
|
|
1482
1573
|
if (this.destroyed) return;
|
|
1483
1574
|
this.silenceTimer = setTimeout(() => {
|
|
1484
|
-
// During guardian
|
|
1485
|
-
//
|
|
1486
|
-
//
|
|
1487
|
-
|
|
1488
|
-
// inbound access-request wait (relay state).
|
|
1489
|
-
if (
|
|
1490
|
-
this.pendingGuardianInput ||
|
|
1491
|
-
this.transport.getConnectionState() === "awaiting_guardian_decision"
|
|
1492
|
-
) {
|
|
1575
|
+
// During an in-call guardian consultation, suppress the generic
|
|
1576
|
+
// "Are you still there?" — it is confusing when the caller is
|
|
1577
|
+
// waiting on a decision.
|
|
1578
|
+
if (this.pendingGuardianInput) {
|
|
1493
1579
|
log.debug(
|
|
1494
1580
|
{ callSessionId: this.callSessionId },
|
|
1495
1581
|
"Silence timeout suppressed during guardian wait",
|
package/src/calls/call-domain.ts
CHANGED
|
@@ -25,7 +25,7 @@ import { getSecureKeyAsync } from "../security/secure-keys.js";
|
|
|
25
25
|
import { getLogger } from "../util/logger.js";
|
|
26
26
|
import { upsertActiveCallLease } from "./active-call-lease.js";
|
|
27
27
|
import { isDeniedNumber } from "./call-constants.js";
|
|
28
|
-
import {
|
|
28
|
+
import { postPointerMessageSafe } from "./call-pointer-messages.js";
|
|
29
29
|
import { getCallController, unregisterCallController } from "./call-state.js";
|
|
30
30
|
import { isTerminalState } from "./call-state-machine.js";
|
|
31
31
|
import {
|
|
@@ -39,9 +39,8 @@ import {
|
|
|
39
39
|
updateCallSession,
|
|
40
40
|
} from "./call-store.js";
|
|
41
41
|
import { activeMediaStreamSessions } from "./media-stream-server.js";
|
|
42
|
-
import { activeRelayConnections } from "./relay-server.js";
|
|
43
42
|
import { getTwilioConfig } from "./twilio-config.js";
|
|
44
|
-
import {
|
|
43
|
+
import { TwilioVoiceProvider } from "./twilio-provider.js";
|
|
45
44
|
import type { CallSession } from "./types.js";
|
|
46
45
|
import { preflightVoiceIngress } from "./voice-ingress-preflight.js";
|
|
47
46
|
|
|
@@ -49,21 +48,6 @@ const log = getLogger("call-domain");
|
|
|
49
48
|
|
|
50
49
|
const E164_REGEX = /^\+\d+$/;
|
|
51
50
|
|
|
52
|
-
function postFailedCallPointer(
|
|
53
|
-
conversationId: string,
|
|
54
|
-
phoneNumber: string,
|
|
55
|
-
reason: string,
|
|
56
|
-
): void {
|
|
57
|
-
addPointerMessage(conversationId, "failed", phoneNumber, {
|
|
58
|
-
reason,
|
|
59
|
-
}).catch((pointerErr) => {
|
|
60
|
-
log.warn(
|
|
61
|
-
{ conversationId, err: pointerErr },
|
|
62
|
-
"Failed to post call-failed pointer message",
|
|
63
|
-
);
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
|
|
67
51
|
// ── Result types ─────────────────────────────────────────────────────
|
|
68
52
|
|
|
69
53
|
interface StartCallResult {
|
|
@@ -228,7 +212,7 @@ export async function resolveCallerIdentity(
|
|
|
228
212
|
}
|
|
229
213
|
|
|
230
214
|
// Verify the user number is eligible as a caller ID with Twilio
|
|
231
|
-
const provider = new
|
|
215
|
+
const provider = new TwilioVoiceProvider();
|
|
232
216
|
const eligibility = await provider.checkCallerIdEligibility(userNumber);
|
|
233
217
|
if (!eligibility.eligible) {
|
|
234
218
|
log.warn(
|
|
@@ -428,12 +412,14 @@ export async function startCall(
|
|
|
428
412
|
|
|
429
413
|
const preflightResult = await preflightVoiceIngress();
|
|
430
414
|
if (!preflightResult.ok) {
|
|
431
|
-
|
|
415
|
+
postPointerMessageSafe(conversationId, "failed", phoneNumber, {
|
|
416
|
+
reason: preflightResult.error,
|
|
417
|
+
});
|
|
432
418
|
return preflightResult;
|
|
433
419
|
}
|
|
434
420
|
|
|
435
421
|
const ingressConfig = preflightResult.ingressConfig;
|
|
436
|
-
const provider = new
|
|
422
|
+
const provider = new TwilioVoiceProvider();
|
|
437
423
|
|
|
438
424
|
const session = createCallSession({
|
|
439
425
|
conversationId,
|
|
@@ -531,12 +517,7 @@ export async function startCall(
|
|
|
531
517
|
);
|
|
532
518
|
|
|
533
519
|
// Post a concise pointer message in the initiating conversation
|
|
534
|
-
|
|
535
|
-
log.warn(
|
|
536
|
-
{ conversationId, err },
|
|
537
|
-
"Failed to post call-started pointer message",
|
|
538
|
-
);
|
|
539
|
-
});
|
|
520
|
+
postPointerMessageSafe(conversationId, "started", phoneNumber);
|
|
540
521
|
|
|
541
522
|
return {
|
|
542
523
|
ok: true,
|
|
@@ -569,7 +550,9 @@ export async function startCall(
|
|
|
569
550
|
});
|
|
570
551
|
}
|
|
571
552
|
|
|
572
|
-
|
|
553
|
+
postPointerMessageSafe(conversationId, "failed", phoneNumber, {
|
|
554
|
+
reason: msg,
|
|
555
|
+
});
|
|
573
556
|
|
|
574
557
|
return { ok: false, error: `Error initiating call: ${msg}`, status: 500 };
|
|
575
558
|
}
|
|
@@ -662,7 +645,7 @@ export async function cancelCall(
|
|
|
662
645
|
// Terminate the call via the provider API
|
|
663
646
|
if (session.providerCallSid) {
|
|
664
647
|
try {
|
|
665
|
-
const provider = new
|
|
648
|
+
const provider = new TwilioVoiceProvider();
|
|
666
649
|
await provider.endCall(session.providerCallSid);
|
|
667
650
|
} catch (endErr) {
|
|
668
651
|
log.warn(
|
|
@@ -672,14 +655,6 @@ export async function cancelCall(
|
|
|
672
655
|
}
|
|
673
656
|
}
|
|
674
657
|
|
|
675
|
-
// End the relay connection if active
|
|
676
|
-
const relayConnection = activeRelayConnections.get(callSessionId);
|
|
677
|
-
if (relayConnection) {
|
|
678
|
-
relayConnection.endSession(reason);
|
|
679
|
-
relayConnection.destroy();
|
|
680
|
-
activeRelayConnections.delete(callSessionId);
|
|
681
|
-
}
|
|
682
|
-
|
|
683
658
|
// End the media-stream session if active
|
|
684
659
|
const mediaStreamSession = activeMediaStreamSessions.get(callSessionId);
|
|
685
660
|
if (mediaStreamSession) {
|
|
@@ -914,7 +889,8 @@ type StartVerificationCallResult =
|
|
|
914
889
|
*
|
|
915
890
|
* Creates a minimal call session with a voice channel binding and
|
|
916
891
|
* passes `verificationSessionId` as a custom parameter so the
|
|
917
|
-
*
|
|
892
|
+
* media-stream server's `routeSetup` can detect this is a guardian
|
|
893
|
+
* verification call.
|
|
918
894
|
*/
|
|
919
895
|
export async function startVerificationCall(
|
|
920
896
|
input: StartVerificationCallInput,
|
|
@@ -933,7 +909,7 @@ export async function startVerificationCall(
|
|
|
933
909
|
|
|
934
910
|
try {
|
|
935
911
|
const config = loadConfig();
|
|
936
|
-
const provider = new
|
|
912
|
+
const provider = new TwilioVoiceProvider();
|
|
937
913
|
|
|
938
914
|
// Resolve the assistant's Twilio number as the caller ID
|
|
939
915
|
const identityResult = await resolveCallerIdentity(config);
|
|
@@ -1045,8 +1021,8 @@ type StartInviteCallResult = { ok: true; callSid: string } | CallError;
|
|
|
1045
1021
|
* Initiate an outbound call to deliver a voice invite to a contact.
|
|
1046
1022
|
*
|
|
1047
1023
|
* Creates a minimal call session with a voice channel binding and
|
|
1048
|
-
* passes invite-specific custom parameters so the
|
|
1049
|
-
* detect this is an invite redemption call.
|
|
1024
|
+
* passes invite-specific custom parameters so the media-stream
|
|
1025
|
+
* server's `routeSetup` can detect this is an invite redemption call.
|
|
1050
1026
|
*/
|
|
1051
1027
|
export async function startInviteCall(
|
|
1052
1028
|
input: StartInviteCallInput,
|
|
@@ -1065,7 +1041,7 @@ export async function startInviteCall(
|
|
|
1065
1041
|
|
|
1066
1042
|
try {
|
|
1067
1043
|
const config = loadConfig();
|
|
1068
|
-
const provider = new
|
|
1044
|
+
const provider = new TwilioVoiceProvider();
|
|
1069
1045
|
|
|
1070
1046
|
// Resolve the assistant's Twilio number as the caller ID
|
|
1071
1047
|
const identityResult = await resolveCallerIdentity(config);
|
|
@@ -3,17 +3,21 @@
|
|
|
3
3
|
* so the user sees call lifecycle events without the full transcript
|
|
4
4
|
* (which lives in the dedicated voice conversation).
|
|
5
5
|
*
|
|
6
|
-
* Trust-aware:
|
|
7
|
-
* daemon conversation as
|
|
8
|
-
*
|
|
9
|
-
* written directly to the conversation store
|
|
6
|
+
* Trust-aware: the owner's own conversations get pointer messages routed through
|
|
7
|
+
* the daemon conversation as an owner self-maintenance turn (the assistant
|
|
8
|
+
* generates the text). Contact and unknown audiences always receive
|
|
9
|
+
* deterministic fallback text written directly to the conversation store, so a
|
|
10
|
+
* guardian-elevated turn never rehydrates private history into a non-owner
|
|
11
|
+
* conversation.
|
|
10
12
|
*/
|
|
11
13
|
|
|
14
|
+
import { runPointerMessageTurn } from "../daemon/pointer-turn-runner.js";
|
|
12
15
|
import {
|
|
13
16
|
addMessage,
|
|
14
17
|
getConversationOriginChannel,
|
|
15
18
|
getConversationRecentProvenanceTrustClass,
|
|
16
19
|
} from "../persistence/conversation-crud.js";
|
|
20
|
+
import { isContactTrustClass } from "../runtime/trust-class.js";
|
|
17
21
|
import { getLogger } from "../util/logger.js";
|
|
18
22
|
import {
|
|
19
23
|
buildPointerInstruction,
|
|
@@ -32,77 +36,39 @@ type PointerEvent =
|
|
|
32
36
|
|
|
33
37
|
type PointerAudienceMode = "auto" | "trusted" | "untrusted";
|
|
34
38
|
|
|
35
|
-
/**
|
|
36
|
-
* Daemon-injected function that sends a message through the daemon conversation
|
|
37
|
-
* pipeline (persistAndProcessMessage), letting the assistant generate the
|
|
38
|
-
* pointer text as a natural conversation turn.
|
|
39
|
-
*
|
|
40
|
-
* @param requiredFacts - facts that must appear verbatim in the generated
|
|
41
|
-
* text (phone number, duration, outcome keyword, etc.). The processor
|
|
42
|
-
* should validate the output and throw if any are missing so the
|
|
43
|
-
* deterministic fallback fires.
|
|
44
|
-
*/
|
|
45
|
-
type PointerMessageProcessor = (
|
|
46
|
-
conversationId: string,
|
|
47
|
-
instruction: string,
|
|
48
|
-
requiredFacts?: string[],
|
|
49
|
-
) => Promise<void>;
|
|
50
|
-
|
|
51
|
-
// ---------------------------------------------------------------------------
|
|
52
|
-
// Module-level processor injection (set by daemon lifecycle at startup)
|
|
53
|
-
// ---------------------------------------------------------------------------
|
|
54
|
-
|
|
55
|
-
let pointerMessageProcessor: PointerMessageProcessor | undefined;
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Inject the daemon-provided pointer message processor.
|
|
59
|
-
* Called from daemon/lifecycle.ts at startup, following the same pattern
|
|
60
|
-
* as setRelayBroadcast.
|
|
61
|
-
*/
|
|
62
|
-
export function setPointerMessageProcessor(
|
|
63
|
-
processor: PointerMessageProcessor,
|
|
64
|
-
): void {
|
|
65
|
-
pointerMessageProcessor = processor;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/** @internal Reset for tests. */
|
|
69
|
-
export function resetPointerMessageProcessor(): void {
|
|
70
|
-
pointerMessageProcessor = undefined;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
39
|
// ---------------------------------------------------------------------------
|
|
74
40
|
// Trust resolution
|
|
75
41
|
// ---------------------------------------------------------------------------
|
|
76
42
|
|
|
77
43
|
/**
|
|
78
|
-
* Resolve whether the audience
|
|
44
|
+
* Resolve whether the pointer audience is the assistant's owner (guardian)
|
|
45
|
+
* rather than a contact or unknown caller.
|
|
79
46
|
*
|
|
80
|
-
*
|
|
81
|
-
* - recent message provenance trust class is 'guardian',
|
|
82
|
-
*
|
|
83
|
-
* - conversation origin channel is 'vellum' (desktop app)
|
|
47
|
+
* Owner when:
|
|
48
|
+
* - recent message provenance trust class is 'guardian', or
|
|
49
|
+
* - conversation origin channel is 'vellum' (desktop app).
|
|
84
50
|
*
|
|
85
|
-
*
|
|
51
|
+
* Known non-guardian contacts ('trusted_contact' / 'unverified_contact') and
|
|
52
|
+
* unknown callers are NOT the owner: routing their pointer status through the
|
|
53
|
+
* daemon turn would run it under the internal guardian context, rehydrating
|
|
54
|
+
* guardian-only history that then leaks into the contact's own conversation.
|
|
55
|
+
* They take the deterministic fallback instead. Defaults to non-owner when
|
|
56
|
+
* evidence is insufficient.
|
|
86
57
|
*/
|
|
87
|
-
function
|
|
58
|
+
function resolvePointerAudienceIsOwner(conversationId: string): boolean {
|
|
88
59
|
try {
|
|
89
|
-
//
|
|
90
|
-
//
|
|
91
|
-
//
|
|
92
|
-
// conversation itself isn't desktop-origin.
|
|
60
|
+
// Provenance is read from persisted message metadata, so it survives
|
|
61
|
+
// conversation eviction — a known contact is diverted to the deterministic
|
|
62
|
+
// fallback even on a cold load where the in-memory trust context is absent.
|
|
93
63
|
const provenance =
|
|
94
64
|
getConversationRecentProvenanceTrustClass(conversationId);
|
|
95
|
-
if (
|
|
96
|
-
|
|
97
|
-
provenance === "trusted_contact" ||
|
|
98
|
-
provenance === "unverified_contact"
|
|
99
|
-
)
|
|
100
|
-
return true;
|
|
65
|
+
if (isContactTrustClass(provenance)) return false;
|
|
66
|
+
if (provenance === "guardian") return true;
|
|
101
67
|
|
|
102
68
|
const originChannel = getConversationOriginChannel(conversationId);
|
|
103
69
|
if (originChannel === "vellum") return true;
|
|
104
70
|
} catch {
|
|
105
|
-
// Conversation may not exist or DB may be unavailable — default
|
|
71
|
+
// Conversation may not exist or DB may be unavailable — default to non-owner.
|
|
106
72
|
}
|
|
107
73
|
|
|
108
74
|
return false;
|
|
@@ -153,17 +119,17 @@ export async function addPointerMessage(
|
|
|
153
119
|
const outcomeKeyword = eventOutcomeKeywords[event];
|
|
154
120
|
if (outcomeKeyword) requiredFacts.push(outcomeKeyword);
|
|
155
121
|
|
|
156
|
-
const
|
|
122
|
+
const ownerAudience =
|
|
157
123
|
audienceMode === "trusted" ||
|
|
158
|
-
(audienceMode === "auto" &&
|
|
124
|
+
(audienceMode === "auto" && resolvePointerAudienceIsOwner(conversationId));
|
|
159
125
|
|
|
160
|
-
if (
|
|
126
|
+
if (ownerAudience) {
|
|
161
127
|
// Route through the daemon conversation — the assistant generates the
|
|
162
|
-
// pointer text as a natural
|
|
128
|
+
// pointer text as a natural owner self-maintenance turn, shaped by context,
|
|
163
129
|
// identity, and preferences.
|
|
164
130
|
const instruction = buildPointerInstruction(context);
|
|
165
131
|
try {
|
|
166
|
-
await
|
|
132
|
+
await runPointerMessageTurn(conversationId, instruction, requiredFacts);
|
|
167
133
|
return;
|
|
168
134
|
} catch (err) {
|
|
169
135
|
log.warn(
|
|
@@ -171,10 +137,10 @@ export async function addPointerMessage(
|
|
|
171
137
|
"Daemon pointer processing failed, falling back to deterministic",
|
|
172
138
|
);
|
|
173
139
|
}
|
|
174
|
-
} else
|
|
140
|
+
} else {
|
|
175
141
|
log.debug(
|
|
176
142
|
{ event, conversationId },
|
|
177
|
-
"
|
|
143
|
+
"Non-owner audience — using deterministic pointer copy",
|
|
178
144
|
);
|
|
179
145
|
}
|
|
180
146
|
|
|
@@ -194,6 +160,24 @@ export async function addPointerMessage(
|
|
|
194
160
|
);
|
|
195
161
|
}
|
|
196
162
|
|
|
163
|
+
/**
|
|
164
|
+
* Fire-and-forget pointer write that tolerates an evicted origin
|
|
165
|
+
* conversation: failures are logged at warn level and swallowed.
|
|
166
|
+
*/
|
|
167
|
+
export function postPointerMessageSafe(
|
|
168
|
+
conversationId: string,
|
|
169
|
+
event: PointerEvent,
|
|
170
|
+
phoneNumber: string,
|
|
171
|
+
extra?: Parameters<typeof addPointerMessage>[3],
|
|
172
|
+
): void {
|
|
173
|
+
addPointerMessage(conversationId, event, phoneNumber, extra).catch((err) => {
|
|
174
|
+
log.warn(
|
|
175
|
+
{ conversationId, err },
|
|
176
|
+
"Skipping pointer write — origin conversation may no longer exist",
|
|
177
|
+
);
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
197
181
|
/**
|
|
198
182
|
* Format a duration in milliseconds into a human-friendly string.
|
|
199
183
|
*/
|