@vellumai/assistant 0.10.5-dev.202607042025.8a04d0b → 0.10.5-staging.1
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 +61 -64
- package/README.md +10 -7
- package/docs/stt-provider-onboarding.md +5 -4
- package/docs/trusted-contact-access.md +7 -7
- package/eslint-rules/cli-no-daemon-internals.js +0 -3
- package/node_modules/@vellumai/gateway-client/src/__tests__/contact-read-contracts.test.ts +0 -36
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +0 -22
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +8 -20
- package/node_modules/@vellumai/gateway-client/src/index.ts +0 -27
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +0 -4
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +0 -6
- package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +8 -0
- package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +14 -3
- package/openapi.yaml +42 -299
- package/package.json +1 -1
- package/src/__tests__/access-request-seed-content-blocks.test.ts +4 -60
- package/src/__tests__/acp-session.test.ts +1 -4
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +6 -0
- package/src/__tests__/anthropic-provider.test.ts +19 -60
- package/src/__tests__/app-conversation-ids-backfill.test.ts +0 -3
- package/src/__tests__/app-source-watcher.test.ts +0 -11
- package/src/__tests__/assistant-event-hub.test.ts +0 -65
- package/src/__tests__/assistant-id-boundary-guard.test.ts +1 -0
- package/src/__tests__/assistant-stream-state.test.ts +0 -18
- package/src/__tests__/attachments-store.test.ts +0 -3
- package/src/__tests__/background-workers-disk-pressure.test.ts +26 -0
- package/src/__tests__/btw-routes.test.ts +3 -57
- package/src/__tests__/call-controller.test.ts +79 -260
- package/src/__tests__/call-domain.test.ts +1 -48
- package/src/__tests__/call-pointer-no-hardcoded-copy.guard.test.ts +6 -2
- package/src/__tests__/call-routes-http.test.ts +14 -15
- package/src/__tests__/channel-guardian.test.ts +7 -4
- package/src/__tests__/channel-readiness-service.test.ts +6 -0
- package/src/__tests__/channel-readiness-slack-remote.test.ts +4 -0
- package/src/__tests__/config-schema.test.ts +12 -27
- package/src/__tests__/contact-store-interaction-info.test.ts +70 -27
- package/src/__tests__/contacts-relay-reads.test.ts +23 -188
- package/src/__tests__/contacts-tools.test.ts +1 -42
- package/src/__tests__/contacts-write.test.ts +0 -181
- package/src/__tests__/context-search-conversations-source.test.ts +0 -4
- package/src/__tests__/conversation-analysis-routes.test.ts +1 -1
- package/src/__tests__/conversation-disk-view.test.ts +0 -1
- package/src/__tests__/conversation-error.test.ts +0 -26
- package/src/__tests__/conversation-fork-crud.test.ts +0 -3
- package/src/__tests__/conversation-history-web-search.test.ts +0 -7
- package/src/__tests__/conversation-key-store-disk-view.test.ts +0 -80
- package/src/__tests__/conversation-queue.test.ts +0 -156
- package/src/__tests__/conversation-routes-enabled-plugins.test.ts +3 -7
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -1
- package/src/__tests__/conversation-routes-slash-commands.test.ts +0 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +16 -59
- package/src/__tests__/credential-prompt-route.test.ts +0 -69
- package/src/__tests__/credential-security-invariants.test.ts +0 -1
- package/src/__tests__/deterministic-verification-control-plane.test.ts +62 -1
- package/src/__tests__/disk-pressure-tools.test.ts +0 -6
- package/src/__tests__/empty-response-hook.test.ts +0 -2
- package/src/__tests__/empty-state-greeting-cache.test.ts +0 -9
- package/src/__tests__/exploration-drift-hook.test.ts +0 -1
- package/src/__tests__/filing-service.test.ts +584 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +110 -15
- package/src/__tests__/guardian-expiry-notifier.test.ts +0 -1
- package/src/__tests__/guardian-question-mode.test.ts +0 -57
- package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -1
- package/src/__tests__/helpers/seed-contact-channel.ts +2 -0
- package/src/__tests__/history-repair-hook.test.ts +0 -3
- package/src/__tests__/http-conversation-lineage.test.ts +1 -6
- package/src/__tests__/http-user-message-parity.test.ts +0 -1
- package/src/__tests__/image-recovery-hook.test.ts +0 -2
- package/src/__tests__/inbound-invite-redemption.test.ts +341 -72
- package/src/__tests__/injector-chain.test.ts +0 -4
- package/src/__tests__/invite-redemption-service.test.ts +1180 -0
- package/src/__tests__/invite-routes-http.test.ts +420 -246
- package/src/__tests__/invite-service-ipc.test.ts +350 -0
- package/src/__tests__/job-handler-registry-guard.test.ts +131 -0
- package/src/__tests__/lexical-index-dual-write.test.ts +0 -3
- package/src/__tests__/list-messages-attachments.test.ts +0 -1
- package/src/__tests__/list-messages-background-tool-completion.test.ts +6 -6
- package/src/__tests__/list-messages-queued.test.ts +0 -25
- package/src/__tests__/managed-profile-guard.test.ts +78 -567
- package/src/__tests__/max-tokens-continue-hook.test.ts +0 -1
- package/src/__tests__/mcp-config-secret-boundary.test.ts +0 -1
- package/src/__tests__/media-stream-output.test.ts +19 -350
- package/src/__tests__/media-stream-server-integration.test.ts +169 -943
- package/src/__tests__/media-stream-stt-session.test.ts +1 -498
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +2 -2
- package/src/__tests__/memory-retrieval-hook.test.ts +0 -1
- package/src/__tests__/notification-decision-fallback.test.ts +8 -104
- package/src/__tests__/notification-decision-strategy.test.ts +8 -57
- package/src/__tests__/phone.test.ts +15 -1
- package/src/__tests__/plugin-bootstrap.test.ts +191 -6
- package/src/__tests__/plugin-disabled-state.test.ts +2 -12
- package/src/__tests__/plugin-effective-enabled-set.test.ts +62 -41
- package/src/__tests__/plugin-import-boundary-guard.test.ts +2 -8
- package/src/__tests__/plugin-pipeline.test.ts +2 -98
- package/src/__tests__/plugin-types.test.ts +1 -0
- package/src/__tests__/pre-model-call-sanitize.test.ts +1 -1
- package/src/__tests__/public-ingress-urls.test.ts +48 -0
- package/src/__tests__/reaction-intercept-member-verdict-warm.test.ts +1 -0
- package/src/__tests__/relay-server.test.ts +6149 -0
- package/src/__tests__/schedule-routes.test.ts +0 -6
- package/src/__tests__/secret-ingress-http.test.ts +0 -1
- package/src/__tests__/secret-routes-platform-proxy.test.ts +2 -5
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +0 -24
- package/src/__tests__/slack-notification-approval-card.test.ts +2 -89
- package/src/__tests__/slack-reaction-canonical-approval.test.ts +1 -51
- package/src/__tests__/stt-hints.test.ts +256 -2
- package/src/__tests__/surface-completion-nudge-hook.test.ts +0 -2
- package/src/__tests__/task-progress-nudge-hook.test.ts +0 -1
- package/src/__tests__/telephony-stt-routing.test.ts +329 -0
- package/src/__tests__/title-generate-hook.test.ts +0 -18
- package/src/__tests__/tool-approval-handler.test.ts +1 -87
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +20 -45
- package/src/__tests__/tool-error-hook.test.ts +0 -1
- package/src/__tests__/tool-grant-request-escalation.test.ts +0 -39
- package/src/__tests__/tool-result-truncate-hook.test.ts +0 -1
- package/src/__tests__/twilio-provider.test.ts +17 -17
- package/src/__tests__/twilio-routes-twiml.test.ts +543 -6
- package/src/__tests__/twilio-routes.test.ts +387 -257
- package/src/__tests__/twilio-validation.test.ts +1 -1
- package/src/__tests__/usage-cache-backfill-migration.test.ts +0 -5
- package/src/__tests__/voice-ingress-preflight.test.ts +0 -61
- package/src/__tests__/voice-invite-redemption.test.ts +702 -0
- package/src/__tests__/voice-quality.test.ts +53 -21
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +0 -1
- package/src/acp/__tests__/session-manager-persistence.test.ts +0 -2
- package/src/acp/__tests__/session-manager-resume.test.ts +0 -8
- package/src/acp/__tests__/session-manager-usage.test.ts +0 -6
- package/src/acp/__tests__/session-manager.test.ts +0 -6
- package/src/acp/agent-process.ts +0 -71
- package/src/acp/session-manager.ts +46 -102
- package/src/agent/ax-tree-compaction.test.ts +1 -4
- package/src/agent/loop.ts +247 -39
- package/src/api/events/open-panel.ts +0 -7
- package/src/api/index.ts +0 -8
- package/src/api/responses/conversation-message.ts +6 -6
- package/src/approvals/guardian-decision-primitive.ts +24 -74
- package/src/approvals/guardian-request-resolvers.ts +123 -431
- package/src/apps/app-store.ts +0 -1
- package/src/apps/shared-app-links-store.ts +0 -1
- package/src/calls/__tests__/relay-setup-router.test.ts +102 -126
- package/src/calls/call-controller.ts +50 -97
- package/src/calls/call-domain.ts +42 -18
- package/src/calls/call-pointer-messages.ts +0 -18
- package/src/calls/call-speech-output.ts +24 -87
- package/src/calls/call-store.ts +0 -4
- package/src/calls/call-transport.ts +36 -22
- package/src/calls/fish-audio-client.ts +0 -3
- package/src/calls/media-stream-audio-transcode.ts +2 -82
- package/src/calls/media-stream-output.ts +36 -142
- package/src/calls/media-stream-server.ts +178 -297
- package/src/calls/media-stream-stt-session.ts +50 -393
- package/src/calls/media-turn-detector.ts +6 -4
- package/src/calls/relay-access-wait.ts +4 -3
- package/src/calls/relay-server.ts +2465 -0
- package/src/calls/relay-setup-router.ts +43 -22
- package/src/calls/relay-verification.ts +24 -17
- package/src/calls/resolve-call-tts-provider.ts +30 -97
- package/src/calls/stt-hints.ts +87 -24
- package/src/calls/telephony-stt-routing.ts +145 -0
- package/src/calls/tts-call-strategy.ts +93 -35
- package/src/calls/twilio-provider.ts +2 -3
- package/src/calls/twilio-routes.ts +351 -47
- package/src/calls/types.ts +3 -5
- package/src/calls/voice-ingress-preflight.ts +0 -9
- package/src/calls/voice-quality.ts +64 -36
- package/src/calls/voice-session-bridge.ts +4 -4
- package/src/channels/channel-verification-sessions.ts +1 -1
- package/src/channels/config.ts +42 -0
- package/src/cli/commands/contacts.ts +2 -2
- package/src/cli/commands/credentials.ts +0 -17
- package/src/cli/commands/keys.ts +83 -86
- package/src/cli/commands/monitoring.ts +1 -50
- 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 +7 -10
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +1 -1
- package/src/config/feature-flag-registry.json +2 -2
- package/src/config/loader.ts +2 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +0 -12
- package/src/config/schemas/calls.ts +0 -8
- package/src/config/schemas/elevenlabs.ts +1 -1
- package/src/config/schemas/llm.ts +9 -9
- package/src/config/schemas/memory-v3.ts +4 -10
- package/src/config/schemas/tts.ts +15 -5
- package/src/config/seed-inference-profiles.ts +19 -30
- package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +128 -0
- package/src/contacts/__tests__/member-write-relay.test.ts +5 -101
- package/src/contacts/canonical-guardian-store.ts +0 -5
- package/src/contacts/contact-store.ts +35 -81
- package/src/contacts/contacts-write.ts +25 -50
- package/src/contacts/member-write-relay.ts +31 -74
- package/src/contacts/types.ts +8 -0
- package/src/context/compactor.ts +15 -29
- package/src/credential-execution/executable-discovery.ts +4 -63
- package/src/credential-execution/process-manager.ts +7 -13
- package/src/daemon/app-source-watcher.ts +0 -9
- package/src/daemon/conversation-agent-loop.ts +21 -51
- package/src/daemon/conversation-error.ts +0 -43
- package/src/daemon/conversation-messaging.ts +1 -1
- package/src/daemon/conversation-process.ts +40 -134
- package/src/daemon/conversation-runtime-assembly.ts +40 -25
- package/src/daemon/conversation-surfaces.ts +8 -162
- package/src/daemon/conversation-tool-setup.test.ts +1 -51
- package/src/daemon/conversation-tool-setup.ts +19 -59
- package/src/daemon/conversation.ts +7 -32
- package/src/daemon/external-plugins-bootstrap.ts +60 -14
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +1 -1
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +14 -26
- package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +14 -27
- package/src/daemon/handlers/__tests__/config-channels.test.ts +5 -0
- package/src/daemon/handlers/config-a2a.ts +14 -7
- package/src/daemon/handlers/config-channels.ts +10 -2
- package/src/daemon/handlers/shared.ts +24 -2
- package/src/daemon/host-cu-proxy.ts +1 -1
- package/src/daemon/lifecycle.ts +26 -5
- package/src/daemon/message-protocol.ts +0 -2
- package/src/daemon/message-types/contacts.ts +10 -2
- package/src/daemon/trust-context.ts +0 -7
- package/src/daemon/wake-conversation-ops.ts +8 -7
- package/src/documents/document-comments-store.test.ts +1 -7
- package/src/documents/document-comments-store.ts +0 -8
- package/src/documents/document-store.ts +0 -15
- package/src/home/conversation-starter-checkpoints.ts +0 -1
- package/src/home/job-handlers/conversation-starters.ts +0 -1
- package/src/hooks/hook-loader.ts +5 -31
- package/src/hooks/registry.ts +14 -48
- package/src/inbound/public-ingress-urls.ts +17 -0
- package/src/ipc/assistant-server.ts +7 -28
- package/src/ipc/routes/__tests__/invite-ipc-routes.test.ts +4 -60
- package/src/ipc/routes/db-proxy.ts +2 -5
- package/src/ipc/routes/invite-ipc-routes.ts +39 -53
- package/src/jobs/register-job-handlers.ts +101 -0
- package/src/jobs/worker.ts +2 -9
- package/src/live-voice/__tests__/live-voice-archive.test.ts +1 -10
- package/src/live-voice/__tests__/live-voice-tts.test.ts +10 -10
- package/src/live-voice/live-voice-archive.ts +0 -5
- package/src/live-voice/live-voice-tts.ts +1 -1
- package/src/messaging/providers/slack/send.test.ts +0 -79
- package/src/messaging/providers/slack/send.ts +12 -48
- package/src/messaging/providers/whatsapp/send.ts +9 -29
- package/src/monitoring/resource-sampler.ts +4 -79
- package/src/notifications/README.md +1 -1
- package/src/notifications/access-request-copy.ts +23 -94
- package/src/notifications/adapters/slack.ts +21 -89
- package/src/notifications/approval-card-builder.ts +18 -33
- package/src/notifications/approval-card-data.ts +15 -48
- package/src/notifications/broadcaster.ts +16 -25
- package/src/notifications/decision-engine.ts +32 -131
- package/src/notifications/guardian-question-mode.ts +10 -58
- package/src/permissions/approval-policy.ts +1 -8
- package/src/permissions/gateway-threshold-reader.ts +6 -7
- package/src/permissions/secret-prompter.ts +3 -11
- package/src/persistence/__tests__/conversation-queries-search.test.ts +0 -4
- package/src/persistence/__tests__/slow-query-log.test.ts +1 -77
- package/src/persistence/attachments-store.ts +2 -24
- package/src/persistence/conversation-crud.ts +8 -73
- package/src/persistence/conversation-display-order-migration.ts +2 -8
- package/src/persistence/conversation-group-migration.test.ts +0 -8
- package/src/persistence/conversation-group-migration.ts +0 -9
- package/src/persistence/conversation-key-store.ts +0 -5
- package/src/persistence/conversation-queries.ts +0 -4
- package/src/persistence/embeddings/embedding-local.ts +0 -2
- package/src/persistence/group-crud.ts +1 -13
- package/src/persistence/invite-store.ts +481 -0
- package/src/persistence/job-handlers/cleanup.ts +5 -27
- package/src/persistence/jobs-store.ts +2 -10
- package/src/persistence/jobs-worker.ts +0 -90
- package/src/persistence/llm-usage-store.ts +0 -11
- package/src/persistence/memory-lifecycle-hooks.test.ts +0 -3
- package/src/persistence/memory-lifecycle-hooks.ts +0 -12
- package/src/persistence/migrations/028-call-session-mode.ts +1 -1
- package/src/persistence/raw-query.ts +13 -49
- package/src/persistence/schema/a2a.ts +0 -14
- package/src/persistence/schema/contacts.ts +34 -0
- package/src/persistence/schema/guardian.ts +0 -4
- package/src/persistence/slow-query-log.ts +19 -195
- package/src/persistence/steps.ts +0 -8
- package/src/persistence/subagent-store.ts +2 -5
- package/src/plugin-api/index.ts +1 -5
- package/src/plugin-api/types.ts +510 -19
- package/src/plugins/defaults/default-plugin-names.ts +60 -0
- package/src/plugins/defaults/index.ts +31 -7
- package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +3 -34
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +2 -2
- package/src/plugins/defaults/memory/context-search/sources/conversations.ts +0 -1
- package/src/plugins/defaults/memory/filing-service.ts +430 -0
- package/src/plugins/defaults/memory/graph/bootstrap.test.ts +10 -36
- package/src/plugins/defaults/memory/graph/bootstrap.ts +0 -3
- package/src/plugins/defaults/memory/hooks/init.ts +13 -28
- package/src/plugins/defaults/memory/hooks/shutdown.ts +14 -0
- package/src/plugins/defaults/memory/job-handlers.ts +6 -14
- package/src/plugins/defaults/memory/memory-v2-concept-frequency.ts +0 -2
- package/src/plugins/defaults/memory/persistence-hooks.ts +0 -5
- package/src/plugins/defaults/memory/rerank-local.ts +0 -2
- package/src/plugins/defaults/memory/startup.ts +10 -15
- package/src/plugins/defaults/memory/task-memory-cleanup.ts +0 -8
- package/src/plugins/defaults/memory/v3/__tests__/gate-flag.test.ts +4 -17
- package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +2 -114
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +6 -25
- package/src/plugins/defaults/memory/v3/gate-flag.ts +4 -9
- package/src/plugins/defaults/memory/v3/gate.ts +3 -3
- package/src/plugins/defaults/memory/v3/orchestrate.ts +0 -32
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +5 -7
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +0 -5
- package/src/plugins/injector-registry.ts +12 -6
- package/src/plugins/job-handler-registry.ts +94 -0
- package/src/plugins/mtime-cache.ts +4 -20
- package/src/plugins/pipeline.ts +21 -62
- package/src/plugins/types.ts +23 -19
- package/src/prompts/templates/SOUL.md +14 -40
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +1 -96
- package/src/providers/provider-availability.ts +4 -11
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +64 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +79 -92
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +0 -98
- package/src/providers/speech-to-text/deepgram-realtime.ts +3 -62
- package/src/providers/speech-to-text/provider-catalog.ts +89 -0
- package/src/providers/speech-to-text/resolve.ts +0 -55
- package/src/runtime/AGENTS.md +2 -0
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +8 -37
- package/src/runtime/access-request-helper.ts +1 -15
- package/src/runtime/assistant-stream-state.ts +25 -80
- package/src/runtime/auth/__tests__/route-policy.test.ts +0 -31
- package/src/runtime/background-job-runner.ts +1 -9
- package/src/runtime/channel-approval-types.ts +2 -52
- package/src/runtime/channel-approvals.ts +8 -23
- 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 +5 -3
- package/src/runtime/channel-verification-service.ts +8 -0
- package/src/runtime/guardian-action-service.ts +11 -10
- package/src/runtime/guardian-reply-router.ts +21 -122
- package/src/runtime/http-server.ts +97 -32
- package/src/runtime/invite-redemption-service.ts +828 -0
- package/src/runtime/invite-redemption-templates.ts +46 -0
- package/src/runtime/invite-service.ts +361 -104
- package/src/runtime/middleware/twilio-validation.ts +7 -5
- package/src/runtime/pre-first-message-gate.ts +0 -1
- package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +35 -6
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +3 -24
- package/src/runtime/routes/__tests__/contact-routes.test.ts +15 -80
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -7
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +51 -137
- package/src/runtime/routes/__tests__/global-search-routes.test.ts +3 -0
- package/src/runtime/routes/__tests__/invite-relay-routes.test.ts +30 -119
- package/src/runtime/routes/__tests__/monitoring-routes.test.ts +1 -26
- package/src/runtime/routes/__tests__/retrospective-routes.test.ts +0 -4
- 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 +3 -15
- package/src/runtime/routes/approval-routes.ts +0 -4
- package/src/runtime/routes/btw-routes.ts +4 -32
- package/src/runtime/routes/channel-route-shared.ts +14 -18
- package/src/runtime/routes/channel-verification-routes.ts +3 -0
- package/src/runtime/routes/contact-routes.ts +117 -298
- package/src/runtime/routes/conversation-list-routes.ts +0 -6
- package/src/runtime/routes/conversation-management-routes.ts +0 -71
- package/src/runtime/routes/conversation-query-routes.ts +55 -222
- package/src/runtime/routes/conversation-routes.ts +70 -123
- package/src/runtime/routes/credential-prompt-routes.ts +5 -20
- package/src/runtime/routes/debug-routes.ts +0 -1
- package/src/runtime/routes/documents-routes.ts +2 -5
- package/src/runtime/routes/empty-state-greeting-cache.ts +10 -37
- package/src/runtime/routes/filing-routes.ts +27 -50
- package/src/runtime/routes/global-search-routes.ts +0 -1
- package/src/runtime/routes/inbound-message-handler.ts +3 -3
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +67 -87
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +507 -48
- package/src/runtime/routes/inference-provider-connection-routes.ts +16 -22
- package/src/runtime/routes/internal-twilio-routes.ts +15 -0
- package/src/runtime/routes/monitoring-routes.ts +0 -32
- package/src/runtime/routes/secret-routes.ts +9 -14
- package/src/runtime/routes/surface-conversation-resolver.ts +0 -1
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +9 -54
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -19
- package/src/runtime/services/analyze-conversation.ts +4 -14
- package/src/runtime/services/conversation-serializer.ts +0 -5
- package/src/runtime/slack-reply-session.test.ts +0 -81
- package/src/runtime/slack-reply-session.ts +0 -13
- package/src/runtime/sync/resource-sync-events.ts +0 -10
- package/src/runtime/trust-verdict-consumer.ts +6 -7
- package/src/schedule/schedule-usage-store.ts +0 -1
- package/src/stt/types.ts +9 -5
- package/src/tools/document/document-comment-tool.test.ts +0 -4
- package/src/tools/terminal/safe-env.ts +0 -2
- package/src/tools/tool-approval-handler.ts +29 -106
- package/src/tools/ui-surface/definitions.ts +1 -1
- package/src/tts/__tests__/provider-adapters.test.ts +65 -65
- package/src/tts/__tests__/provider-catalog-consistency.test.ts +5 -8
- package/src/tts/__tests__/provider-catalog.test.ts +0 -21
- package/src/tts/__tests__/provider-registry.test.ts +90 -0
- package/src/tts/provider-catalog.ts +232 -106
- package/src/tts/provider-registry.ts +73 -0
- package/src/tts/providers/deepgram-provider.ts +0 -41
- package/src/tts/providers/elevenlabs-provider.ts +0 -89
- package/src/tts/providers/fish-audio-provider.ts +10 -61
- package/src/tts/providers/index.ts +44 -0
- package/src/tts/providers/register-builtins.ts +130 -0
- package/src/tts/providers/xai-provider.ts +0 -41
- package/src/tts/synthesize-text.ts +1 -1
- package/src/tts/types.ts +16 -35
- package/src/util/cgroup-memory.ts +7 -128
- package/src/util/phone.ts +8 -1
- package/src/util/voice-code.ts +31 -0
- package/src/util/worker-process.ts +1 -5
- package/src/workflows/journal-store.ts +1 -16
- package/node_modules/@vellumai/gateway-client/src/__tests__/invite-contract.test.ts +0 -233
- package/node_modules/@vellumai/gateway-client/src/invite-contract.ts +0 -216
- package/src/__tests__/add-message-preassigned-id.test.ts +0 -56
- package/src/__tests__/call-setup-flow-invite.test.ts +0 -568
- package/src/__tests__/call-setup-flow-midcall-trust.test.ts +0 -231
- package/src/__tests__/call-setup-flow-name-capture.test.ts +0 -754
- package/src/__tests__/call-setup-flow-verification.test.ts +0 -925
- package/src/__tests__/call-setup-flow.test.ts +0 -311
- package/src/__tests__/channel-setup-panel-ack.test.ts +0 -184
- package/src/__tests__/compactor-media-strip.test.ts +0 -177
- package/src/__tests__/conversation-enabledplugins-route.test.ts +0 -184
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +0 -408
- package/src/__tests__/guardian-wait-controller.test.ts +0 -628
- package/src/__tests__/hook-broadcast.test.ts +0 -188
- package/src/__tests__/introduction-card-resolver.test.ts +0 -354
- package/src/__tests__/invite-redeemed-ipc.test.ts +0 -97
- package/src/__tests__/job-handler-registration-guard.test.ts +0 -106
- package/src/__tests__/media-stream-audio-transcode.test.ts +0 -113
- package/src/__tests__/telephony-credential-preflight.test.ts +0 -312
- package/src/__tests__/telephony-tts-guard.test.ts +0 -531
- package/src/__tests__/voice-approval-resolver-relay.test.ts +0 -150
- package/src/acp/agent-process.test.ts +0 -116
- package/src/acp/failure-error.test.ts +0 -109
- package/src/acp/failure-error.ts +0 -111
- package/src/acp/session-manager.test.ts +0 -312
- package/src/api/events/hook-event.ts +0 -53
- package/src/calls/__tests__/fish-audio-client.test.ts +0 -73
- package/src/calls/__tests__/gateway-invite-reader.test.ts +0 -170
- package/src/calls/call-setup-flow-types.ts +0 -76
- package/src/calls/call-setup-flow.ts +0 -1743
- package/src/calls/gateway-invite-reader.ts +0 -98
- package/src/calls/guardian-wait-controller.ts +0 -451
- package/src/calls/telephony-credential-preflight.ts +0 -159
- package/src/calls/telephony-tts-capability.ts +0 -186
- package/src/context/outbound-sanitize.ts +0 -202
- package/src/daemon/conversation-plugin-scope.ts +0 -38
- package/src/daemon/sqlite-corruption-watchdog.test.ts +0 -217
- package/src/daemon/sqlite-corruption-watchdog.ts +0 -155
- package/src/hooks/hook-broadcast.ts +0 -60
- package/src/hooks/hook-logger.ts +0 -28
- package/src/hooks/types.ts +0 -613
- package/src/ipc/__tests__/contacts-info-ipc.test.ts +0 -285
- package/src/ipc/routes/__tests__/contacts-mirror-apply-atomicity.test.ts +0 -62
- package/src/ipc/routes/__tests__/contacts-mirror-apply.test.ts +0 -272
- package/src/ipc/routes/__tests__/contacts-mirror-ipc-routes.test.ts +0 -322
- package/src/ipc/routes/contacts-info-ipc-routes.ts +0 -239
- package/src/ipc/routes/contacts-mirror-ipc-routes.ts +0 -202
- package/src/monitoring/__tests__/resource-sampler.test.ts +0 -84
- package/src/persistence/a2a-invite-store.ts +0 -205
- package/src/persistence/migrations/315-create-a2a-invites.ts +0 -58
- package/src/persistence/migrations/316-drop-contact-channels-invite-id.ts +0 -28
- package/src/persistence/migrations/317-canonical-guardian-requester-signals.ts +0 -24
- package/src/persistence/migrations/318-drop-contact-channel-telemetry.ts +0 -32
- package/src/persistence/migrations/__tests__/315-create-a2a-invites.test.ts +0 -161
- package/src/persistence/migrations/__tests__/316-drop-contact-channels-invite-id.test.ts +0 -156
- package/src/persistence/migrations/__tests__/318-drop-contact-channel-telemetry.test.ts +0 -134
- package/src/plugins/defaults/memory/__tests__/filing-jobs.test.ts +0 -123
- package/src/plugins/defaults/memory/__tests__/jobs-worker-pkb-schedule.test.ts +0 -282
- package/src/plugins/defaults/memory/filing-jobs.ts +0 -133
- package/src/plugins/defaults/memory/job-handler-registration.ts +0 -96
- package/src/plugins/defaults/memory/pkb-schedule.ts +0 -31
- package/src/providers/vellum-model-routing.test.ts +0 -51
- package/src/providers/vellum-model-routing.ts +0 -84
- package/src/runtime/introduction-policy.test.ts +0 -214
- package/src/runtime/introduction-policy.ts +0 -284
- package/src/telemetry/watchdog-direct-emit.test.ts +0 -109
- package/src/telemetry/watchdog-direct-emit.ts +0 -89
- package/src/tts/__tests__/provider-resolution.test.ts +0 -83
- package/src/tts/provider-definition.ts +0 -202
- package/src/util/__tests__/cgroup-memory.test.ts +0 -104
- package/src/util/__tests__/text-spacing.test.ts +0 -53
- package/src/util/__tests__/worker-memory.test.ts +0 -64
- package/src/util/text-spacing.ts +0 -53
- package/src/util/worker-memory.ts +0 -77
package/ARCHITECTURE.md
CHANGED
|
@@ -16,10 +16,10 @@ This document owns assistant-runtime architecture details. The repo-level archit
|
|
|
16
16
|
- Guardian/non-guardian/unverified classification is centralized in `assistant/src/runtime/trust-context-resolver.ts`.
|
|
17
17
|
- The same resolver is used by:
|
|
18
18
|
- `/channels/inbound` (Telegram/WhatsApp path) before run orchestration.
|
|
19
|
-
- Inbound Twilio voice setup (
|
|
19
|
+
- Inbound Twilio voice setup (`RelayConnection.handleSetup`) to seed call-time actor context.
|
|
20
20
|
- Runtime channel runs pass this as `trustContext`, and conversation runtime assembly includes actor context in the unified `<turn_context>` block (via `buildUnifiedTurnContextBlock()`) injected into provider-facing prompts.
|
|
21
21
|
- Voice calls mirror the same prompt contract: `CallController` receives guardian context on setup and refreshes it immediately after successful voice challenge verification, so the first post-verification turn is grounded as `actor_role: guardian`.
|
|
22
|
-
- Voice-specific behavior (DTMF/speech verification flow,
|
|
22
|
+
- Voice-specific behavior (DTMF/speech verification flow, relay state machine) remains voice-local; only actor-role resolution is shared.
|
|
23
23
|
|
|
24
24
|
### Safe Storage Limits
|
|
25
25
|
|
|
@@ -429,8 +429,9 @@ External users who are not the guardian can gain access to the assistant through
|
|
|
429
429
|
| `src/runtime/routes/access-request-decision.ts` | Guardian decision → verification session creation |
|
|
430
430
|
| `src/runtime/routes/guardian-approval-interception.ts` | Routes guardian decisions (button + conversational) to access request handler |
|
|
431
431
|
| `src/runtime/channel-verification-service.ts` | Verification session lifecycle, identity binding, rate limiting |
|
|
432
|
-
| `src/runtime/routes/contact-routes.ts` | HTTP
|
|
433
|
-
| `src/runtime/invite-
|
|
432
|
+
| `src/runtime/routes/contact-routes.ts` | HTTP API handlers for contact and channel management |
|
|
433
|
+
| `src/runtime/routes/invite-routes.ts` | HTTP API handlers for invite management |
|
|
434
|
+
| `src/runtime/invite-service.ts` | Business logic for invite operations |
|
|
434
435
|
| `src/contacts/contact-store.ts` | Contact read queries — lookup, search, list, and channel operations |
|
|
435
436
|
| `src/memory/guardian-approvals.ts` | Approval request persistence |
|
|
436
437
|
| `src/channels/channel-verification-sessions.ts` | Verification challenge persistence |
|
|
@@ -454,12 +455,11 @@ A complementary access-granting flow where the guardian proactively creates a sh
|
|
|
454
455
|
│ • extractInboundToken(payload) → token | undefined │
|
|
455
456
|
│ Registered: Telegram │ Deferred: Slack, Voice │
|
|
456
457
|
├─────────────────────────────────────────────────────────────┤
|
|
457
|
-
│ Core Redemption Engine (
|
|
458
|
-
│
|
|
459
|
-
│
|
|
460
|
-
│ enforcement, atomic claim, gateway ACL activation │
|
|
458
|
+
│ Core Redemption Engine (invite-redemption-service.ts) │
|
|
459
|
+
│ Channel-agnostic token validation, expiry, use-count, │
|
|
460
|
+
│ channel-match enforcement, contact activation/reactivation │
|
|
461
461
|
│ Returns: InviteRedemptionOutcome (discriminated union) │
|
|
462
|
-
│
|
|
462
|
+
│ Reply templates: invite-redemption-templates.ts │
|
|
463
463
|
└─────────────────────────────────────────────────────────────┘
|
|
464
464
|
```
|
|
465
465
|
|
|
@@ -467,42 +467,42 @@ A complementary access-granting flow where the guardian proactively creates a sh
|
|
|
467
467
|
|
|
468
468
|
1. Guardian asks the assistant to create an invite via desktop chat.
|
|
469
469
|
2. `guardian-invite-intent.ts` detects the intent and rewrites the message to force-load the `contacts` skill.
|
|
470
|
-
3. The skill calls the
|
|
470
|
+
3. The skill calls the ingress HTTP API to create an invite token, then calls the Telegram transport adapter to build a deep link: `https://t.me/<bot>?start=iv_<token>`.
|
|
471
471
|
4. Guardian shares the link with the invitee out-of-band.
|
|
472
472
|
5. Invitee clicks the link, opening Telegram which sends `/start iv_<token>` to the bot.
|
|
473
|
-
6. The gateway
|
|
474
|
-
7. The
|
|
473
|
+
6. The gateway forwards the message to `/channels/inbound`. The inbound handler calls `getInviteAdapterRegistry().get('telegram').extractInboundToken()` to parse the `iv_` token.
|
|
474
|
+
7. The token is redeemed via `invite-redemption-service.ts`, which validates, activates the contact, and returns a `redeemed` outcome.
|
|
475
475
|
8. A deterministic welcome message is delivered to the invitee (bypasses the LLM pipeline).
|
|
476
476
|
|
|
477
477
|
**Token prefix convention:** The `iv_` prefix distinguishes invite tokens from `gv_` (guardian verification) tokens. Both use the same Telegram `/start` deep-link mechanism but are routed to different handlers.
|
|
478
478
|
|
|
479
|
-
**Inbound intercept points:** Invite token
|
|
479
|
+
**Inbound intercept points:** Invite token extraction runs early in the inbound handler, before ACL denial, so valid invites short-circuit the contact check. Two intercept branches handle: (a) unknown contacts — the invite creates their first contact record; (b) inactive contacts (revoked/pending) — the invite reactivates them.
|
|
480
480
|
|
|
481
481
|
**Channel adapter status:**
|
|
482
482
|
|
|
483
483
|
| Channel | Status | Prerequisites |
|
|
484
484
|
| -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
485
485
|
| Telegram | Shipped | Bot username resolved from credential metadata or config |
|
|
486
|
-
| Voice | Shipped | Identity-bound voice code redemption via DTMF/speech in the
|
|
486
|
+
| Voice | Shipped | Identity-bound voice code redemption via DTMF/speech in the relay state machine. Always-on canonical behavior with personalized friend/guardian name prompts. |
|
|
487
487
|
| Slack | Deferred | Needs DM-safe ingress — Socket Mode handles channel messages but DM-initiated invite flows need routing |
|
|
488
488
|
|
|
489
|
-
### Voice Invite Flow (
|
|
489
|
+
### Voice Invite Flow (invite_redemption_pending)
|
|
490
490
|
|
|
491
|
-
Voice invites use a short numeric code (
|
|
491
|
+
Voice invites use a short numeric code (4-10 digits, default 6) instead of a URL token. The guardian creates an invite bound to the invitee's E.164 phone number; the invitee redeems it by entering the code during an inbound voice call.
|
|
492
492
|
|
|
493
493
|
**Creation flow:**
|
|
494
494
|
|
|
495
495
|
1. Guardian creates a voice invite via `POST /v1/contacts/invites` with `sourceChannel: "phone"` and `expectedExternalUserId` (E.164 phone).
|
|
496
|
-
2.
|
|
496
|
+
2. `invite-service.ts` generates a cryptographically random numeric code (`generateVoiceCode`), hashes it with SHA-256 (`hashVoiceCode`), and stores only the hash.
|
|
497
497
|
3. The one-time plaintext `voiceCode` is returned in the creation response. The raw token is NOT returned for voice invites — redemption uses the identity-bound code flow exclusively.
|
|
498
498
|
4. Guardian communicates the code to the invitee out-of-band.
|
|
499
499
|
|
|
500
|
-
**Call-time redemption subflow (`
|
|
500
|
+
**Call-time redemption subflow (`invite_redemption_pending`):**
|
|
501
501
|
|
|
502
|
-
1. Unknown caller dials in.
|
|
503
|
-
2.
|
|
504
|
-
3. If
|
|
505
|
-
4.
|
|
502
|
+
1. Unknown caller dials in. `relay-server.ts` resolves trust via `resolveActorTrust`. Caller is `unknown`, no pending guardian challenge.
|
|
503
|
+
2. The relay checks `findActiveVoiceInvites` for invites bound to the caller's phone number.
|
|
504
|
+
3. If active, non-expired invites exist, the relay enters the `invite_redemption_pending` state (reuses the `verification_pending` connection state) and prompts the caller with personalized copy: `Welcome <friend-name>. Please enter the 6-digit code that <guardian-name> provided you to verify your identity.`
|
|
505
|
+
4. `redeemVoiceInviteCode` validates: identity match, code hash match, expiry, use count. On success, the contact is activated and the call transitions to the normal call flow.
|
|
506
506
|
5. On invalid/expired code, the caller hears deterministic failure copy: `Sorry, the code you provided is incorrect or has since expired. Please ask <guardian-name> for a new code. Goodbye.` and the call ends immediately.
|
|
507
507
|
|
|
508
508
|
**Security invariants:**
|
|
@@ -516,19 +516,22 @@ Voice invites use a short numeric code (6 digits) instead of a URL token. The gu
|
|
|
516
516
|
|
|
517
517
|
| File | Purpose |
|
|
518
518
|
| --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
519
|
-
| `
|
|
519
|
+
| `src/runtime/invite-redemption-service.ts` | Core redemption engine — token validation, voice code redemption, contact activation, discriminated-union outcomes |
|
|
520
|
+
| `src/runtime/invite-redemption-templates.ts` | Deterministic reply templates for each redemption outcome |
|
|
520
521
|
| `src/runtime/channel-invite-transport.ts` | Transport adapter registry with `buildShareableInvite` / `extractInboundToken` interface |
|
|
521
522
|
| `src/runtime/channel-invite-transports/telegram.ts` | Telegram adapter — `t.me/<bot>?start=iv_<token>` deep links, `/start iv_<token>` extraction |
|
|
522
523
|
| `src/runtime/channel-invite-transports/voice.ts` | Voice transport adapter — code-based redemption metadata |
|
|
523
524
|
| `src/daemon/guardian-invite-intent.ts` | Intent detection — routes create/list/revoke requests into the contacts skill |
|
|
524
|
-
| `src/runtime/invite-service.ts` |
|
|
525
|
-
| `src/runtime/routes/
|
|
526
|
-
| `src/
|
|
527
|
-
| `src/calls/
|
|
525
|
+
| `src/runtime/invite-service.ts` | Shared business logic for invite operations (used by HTTP routes) |
|
|
526
|
+
| `src/runtime/routes/invite-routes.ts` | HTTP API handlers for invite management including voice invite creation and redemption |
|
|
527
|
+
| `src/runtime/routes/inbound-message-handler.ts` | Invite token intercept in the inbound flow (unknown-contact and inactive-contact branches) |
|
|
528
|
+
| `src/calls/relay-server.ts` | Voice relay state machine — `invite_redemption_pending` subflow (always-on canonical behavior) |
|
|
529
|
+
| `src/util/voice-code.ts` | Cryptographic voice code generation and SHA-256 hashing |
|
|
530
|
+
| `src/persistence/invite-store.ts` | Invite persistence including `findActiveVoiceInvites` for identity-bound lookup |
|
|
528
531
|
|
|
529
532
|
### Voice Inbound Security Model (Canonical)
|
|
530
533
|
|
|
531
|
-
The voice inbound security model determines how unknown callers are handled when they dial in. Three paths exist, evaluated in priority order by `
|
|
534
|
+
The voice inbound security model determines how unknown callers are handled when they dial in. Three paths exist, evaluated in priority order by `relay-server.ts` during the `handleSetup` phase. All guardian decisions route through `applyCanonicalGuardianDecision` in the canonical guardian request system.
|
|
532
535
|
|
|
533
536
|
**Decision tree for inbound unknown callers:**
|
|
534
537
|
|
|
@@ -547,7 +550,7 @@ resolveActorTrust() → trustClass
|
|
|
547
550
|
|
|
|
548
551
|
┌────────────────────┼──────────────────────┐
|
|
549
552
|
| | |
|
|
550
|
-
pendingChallenge?
|
|
553
|
+
pendingChallenge? activeVoiceInvites? no invite, no challenge
|
|
551
554
|
| | |
|
|
552
555
|
v v v
|
|
553
556
|
Guardian verification Invite redemption Name capture +
|
|
@@ -556,17 +559,17 @@ resolveActorTrust() → trustClass
|
|
|
556
559
|
|
|
557
560
|
**Path 1: Voice invite code redemption (guardian-initiated)**
|
|
558
561
|
|
|
559
|
-
The guardian proactively creates a voice invite bound to the caller's E.164 phone number. When the unknown caller dials in and has an active, non-expired invite, the
|
|
562
|
+
The guardian proactively creates a voice invite bound to the caller's E.164 phone number. When the unknown caller dials in and has an active, non-expired invite, the relay enters the `invite_redemption_pending` subflow with personalized prompts using the friend's and guardian's names. This is always-on canonical behavior (no feature flag). See [Voice Invite Flow](#voice-invite-flow-invite_redemption_pending) above.
|
|
560
563
|
|
|
561
564
|
**Path 2: Live in-call guardian approval (friend-initiated)**
|
|
562
565
|
|
|
563
|
-
When no invite exists and no pending guardian challenge is active, the
|
|
566
|
+
When no invite exists and no pending guardian challenge is active, the relay enters the name capture + guardian approval wait flow:
|
|
564
567
|
|
|
565
|
-
1. The
|
|
568
|
+
1. The relay transitions to `awaiting_name` state and prompts the caller for their name with a timeout.
|
|
566
569
|
2. On name capture, `notifyGuardianOfAccessRequest` creates a canonical guardian request (`kind: 'access_request'`) and notifies the guardian via the notification pipeline.
|
|
567
|
-
3. The
|
|
570
|
+
3. The relay transitions to `awaiting_guardian_decision` and plays hold music/messaging while polling the canonical request status.
|
|
568
571
|
4. The guardian approves or denies via any channel (Telegram, desktop). All decisions route through `applyCanonicalGuardianDecision`, which dispatches to the `access_request` resolver in `guardian-request-resolvers.ts`.
|
|
569
|
-
5. On approval: the resolver directly activates the caller as a trusted contact (sets channel `status: 'active'`, `policy: 'allow'`), the poll detects the approved status,
|
|
572
|
+
5. On approval: the resolver directly activates the caller as a trusted contact (sets channel `status: 'active'`, `policy: 'allow'`), the poll detects the approved status, the relay transitions to the normal call flow with the caller's guardian context updated.
|
|
570
573
|
6. On denial or timeout: the caller hears a denial message and the call ends.
|
|
571
574
|
|
|
572
575
|
**Path 3: Inbound guardian verification (pending challenge)**
|
|
@@ -586,9 +589,7 @@ All guardian decisions for voice access requests flow through:
|
|
|
586
589
|
|
|
587
590
|
| File | Purpose |
|
|
588
591
|
| ---------------------------------------------- | -------------------------------------------------------------------------------------- |
|
|
589
|
-
| `src/calls/relay-
|
|
590
|
-
| `src/calls/call-setup-flow.ts` | Name capture, verification, and invite sub-flows over the media-stream transport |
|
|
591
|
-
| `src/calls/guardian-wait-controller.ts` | Guardian approval wait — hold messaging, heartbeats, poll/timeout |
|
|
592
|
+
| `src/calls/relay-server.ts` | Inbound call decision tree, name capture, guardian approval wait polling |
|
|
592
593
|
| `src/runtime/access-request-helper.ts` | Creates canonical access request and notifies guardian |
|
|
593
594
|
| `src/approvals/guardian-decision-primitive.ts` | `applyCanonicalGuardianDecision` — unified decision primitive |
|
|
594
595
|
| `src/approvals/guardian-request-resolvers.ts` | `access_request` resolver — voice direct activation, text-channel verification session |
|
|
@@ -605,41 +606,37 @@ Audio-to-text conversion occurs in six distinct runtime boundaries, each with it
|
|
|
605
606
|
|
|
606
607
|
| Boundary | Runtime | Provider (current) | Adapter module | Caller |
|
|
607
608
|
| -------------------------- | ----------------------------------------------------------------------------- | -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
|
|
608
|
-
| **Telephony (
|
|
609
|
+
| **Telephony (hybrid)** | Twilio-native ConversationRelay or daemon media-stream (provider-conditional) | Configured STT provider (via `services.stt`) | `src/calls/telephony-stt-routing.ts` | `src/calls/twilio-routes.ts` |
|
|
609
610
|
| **Daemon batch** | Daemon process (REST API to provider) | Configured STT provider (via `services.stt`) | `src/stt/daemon-batch-transcriber.ts` | `src/runtime/routes/inbound-stages/transcribe-audio.ts` |
|
|
610
611
|
| **Conversation streaming** | Daemon process (WebSocket-based) | Configured STT provider (via `services.stt`) | `src/stt/stt-stream-session.ts`, `src/providers/speech-to-text/deepgram-realtime.ts`, `src/providers/speech-to-text/google-gemini-live-stream.ts`, `src/providers/speech-to-text/openai-whisper-stream.ts`, `src/providers/speech-to-text/xai-realtime.ts` | Web/Electron dictation client via gateway WS proxy |
|
|
611
612
|
| **Live voice channel** | Assistant process (gateway-authenticated WebSocket) | Configured STT provider (via `services.stt`) | `src/runtime/http-server.ts`, `src/live-voice/live-voice-session-manager.ts`, `src/live-voice/live-voice-session.ts`, `src/providers/speech-to-text/resolve.ts`, streaming provider adapters | Web/Electron live voice client via `/v1/live-voice` |
|
|
612
613
|
| **Client service-first** | Web/Electron via gateway → daemon | Configured STT provider (via `services.stt`) | `src/runtime/routes/stt-routes.ts` | Web/Electron dictation and voice clients |
|
|
613
614
|
|
|
614
|
-
**Telephony boundary (
|
|
615
|
+
**Telephony boundary (hybrid routing):**
|
|
615
616
|
|
|
616
|
-
|
|
617
|
+
Telephony STT uses a provider-conditional hybrid model driven by `services.stt.provider`. The routing resolver (`src/calls/telephony-stt-routing.ts`) maps the configured provider to a discriminated strategy at call setup time:
|
|
617
618
|
|
|
618
|
-
|
|
619
|
+
- **`conversation-relay-native`** (Deepgram, Google) — TwiML emits `<Connect><ConversationRelay>` with `transcriptionProvider` and `speechModel` attributes. Twilio handles audio ingestion and transcription natively; the daemon receives transcribed text via the relay WebSocket. The Twilio-native provider name and default speech model are read from the provider catalog entry's `telephonyRouting.twilioNativeMapping` (e.g. Deepgram maps to `provider: "Deepgram"` with `defaultSpeechModel: "nova-3"`; Google maps to `provider: "Google"` with `defaultSpeechModel: undefined`).
|
|
619
620
|
|
|
620
|
-
-
|
|
621
|
-
- **Batch fallback** — otherwise the session segments turns with the energy-based `MediaTurnDetector` and transcribes each completed turn via the provider's batch API.
|
|
622
|
-
|
|
623
|
-
A credential preflight (`resolveTelephonyCredentialReadiness()` in `src/calls/telephony-credential-preflight.ts`) gates every call: it requires a credentialed, telephony-capable STT provider **and** a media-stream-playable TTS provider (the configured one or a credentialed playable fallback). Inbound calls that fail the preflight receive `<Say>` setup-required copy plus `<Hangup/>` instead of a doomed stream; outbound placement fails before dialing via `preflightVoiceIngress()` with the same user-facing message.
|
|
621
|
+
- **`media-stream-custom`** (OpenAI Whisper) — TwiML emits `<Connect><Stream>` pointing to the gateway's media-stream proxy. The `<Stream url="...">` encodes `callSessionId` and auth `token` as **URL path segments** (e.g. `.../media-stream/<callSessionId>/<token>`) because Twilio Media Streams does not reliably preserve query parameters across the WebSocket upgrade. The gateway extracts metadata from path segments (with query-parameter fallback for backward compatibility) and proxies raw audio frames to the daemon, which transcribes server-side via the provider's batch API.
|
|
624
622
|
|
|
625
623
|
Key modules:
|
|
626
624
|
|
|
627
|
-
| Module | Purpose
|
|
628
|
-
| --------------------------------------------------- |
|
|
629
|
-
| `src/calls/
|
|
630
|
-
| `src/calls/
|
|
631
|
-
| `src/calls/media-stream-parser.ts` | Twilio Media Streams protocol parser
|
|
632
|
-
| `src/calls/media-turn-detector.ts` | Energy-based VAD turn detector for raw audio
|
|
633
|
-
| `src/calls/media-stream-stt-session.ts` | STT session
|
|
634
|
-
| `src/calls/
|
|
635
|
-
| `src/calls/
|
|
636
|
-
| `src/calls/media-stream-
|
|
637
|
-
| `src/
|
|
638
|
-
| `gateway/src/http/routes/twilio-media-websocket.ts` | Gateway WebSocket proxy for Media Streams frames |
|
|
625
|
+
| Module | Purpose |
|
|
626
|
+
| --------------------------------------------------- | ---------------------------------------------------------------------- |
|
|
627
|
+
| `src/calls/telephony-stt-routing.ts` | Maps `services.stt.provider` to a discriminated `TelephonySttStrategy` |
|
|
628
|
+
| `src/calls/twilio-routes.ts` | Voice webhook handler; generates provider-conditional TwiML |
|
|
629
|
+
| `src/calls/media-stream-parser.ts` | Twilio Media Streams protocol parser |
|
|
630
|
+
| `src/calls/media-turn-detector.ts` | Energy-based VAD turn detector for raw audio |
|
|
631
|
+
| `src/calls/media-stream-stt-session.ts` | STT session that transcribes audio turns via `services.stt` |
|
|
632
|
+
| `src/calls/call-transport.ts` | Transport interface decoupling CallController from wire protocol |
|
|
633
|
+
| `src/calls/media-stream-output.ts` | Output adapter for sending TTS audio back via Media Streams |
|
|
634
|
+
| `src/calls/media-stream-server.ts` | WebSocket server binding media-stream lifecycle to call sessions |
|
|
635
|
+
| `gateway/src/http/routes/twilio-media-websocket.ts` | Gateway WebSocket proxy for Media Streams frames |
|
|
639
636
|
|
|
640
|
-
Guard tests in `__tests__/twilio-routes-twiml.test.ts` and `__tests__/twilio-routes.test.ts` assert that
|
|
637
|
+
Guard tests in `__tests__/twilio-routes-twiml.test.ts` and `__tests__/twilio-routes.test.ts` assert that TwiML generation matches the provider-conditional strategy for each supported provider.
|
|
641
638
|
|
|
642
|
-
To add a new telephony STT provider:
|
|
639
|
+
To add a new telephony STT provider: add a `telephonyRouting` entry to the provider's catalog entry in `provider-catalog.ts`. Set `strategyKind` to `"conversation-relay-native"` for Twilio-native providers (and include a `twilioNativeMapping` with the Twilio `provider` name and `defaultSpeechModel`), or `"media-stream-custom"` for providers that require daemon-side transcription. The routing resolver reads these fields from the catalog — no hardcoded maps to update.
|
|
643
640
|
|
|
644
641
|
**Daemon batch boundary:**
|
|
645
642
|
|
|
@@ -750,7 +747,7 @@ The web client implements these flows in `clients/web/src/domains/chat/voice/`:
|
|
|
750
747
|
|
|
751
748
|
**Cross-boundary notes:**
|
|
752
749
|
|
|
753
|
-
- The `services.stt` config block is the single source of truth for STT provider selection across the daemon batch boundary, the conversation streaming boundary, the client service-first boundary, and the telephony boundary. The batch and streaming resolvers (`resolveBatchTranscriber()`, `resolveStreamingTranscriber()`) both read from `services.stt.provider` and resolve credentials through the same catalog; the telephony boundary
|
|
750
|
+
- The `services.stt` config block is the single source of truth for STT provider selection across the daemon batch boundary, the conversation streaming boundary, the client service-first boundary, and the telephony boundary. The batch and streaming resolvers (`resolveBatchTranscriber()`, `resolveStreamingTranscriber()`) both read from `services.stt.provider` and resolve credentials through the same catalog; the telephony boundary uses `resolveTelephonySttRouting()` to determine the Twilio integration strategy. The daemon provider catalog (`src/providers/speech-to-text/provider-catalog.ts`) is the authoritative registry of supported providers. Native clients fetch display metadata via `GET /v1/stt/providers`.
|
|
754
751
|
- Conversation streaming does not replace the client service-first batch path. When streaming is available, it runs concurrently during recording and provides real-time partials and finals. The batch path remains the fallback for providers that do not support streaming, when streaming fails mid-session, or when streaming produces no final transcript.
|
|
755
752
|
- Credential mapping is catalog-driven: `provider-secret-catalog.ts` derives STT API-key provider names from the daemon catalog via `listCredentialProviderNames()`, deduplicating against the LLM/search provider list. Adding a provider to the catalog automatically includes its credential name in `API_KEY_PROVIDERS`.
|
|
756
753
|
- Terminology: "STT", "transcription", and "speech recognition" all refer to the same operation (converting audio to text).
|
|
@@ -2204,12 +2201,12 @@ The `TtsUseCase` discriminator (`"phone-call"` or `"message-playback"`) lets pro
|
|
|
2204
2201
|
|
|
2205
2202
|
**Synthesis orchestrator (`synthesize-text.ts`):** `synthesizeText()` is the top-level entry point. It resolves the globally configured provider via the config resolver, looks up the adapter in the registry, and delegates synthesis. Provider selection is always global — per-use-case policy only gates capabilities (e.g. format checks), never overrides the chosen provider.
|
|
2206
2203
|
|
|
2207
|
-
**Call strategy abstraction (`tts-call-strategy.ts`):** The call strategy layer determines how a TTS provider integrates with the telephony path. Instead of inferring call behavior from runtime capabilities, `resolveCallStrategy(config)` reads the provider's `callMode` from the canonical catalog and returns a `TtsCallStrategy` with the provider ID and call mode. Two modes exist:
|
|
2204
|
+
**Call strategy abstraction (`tts-call-strategy.ts`):** The call strategy layer determines how a TTS provider integrates with the Twilio ConversationRelay telephony path. Instead of inferring call behavior from runtime capabilities, `resolveCallStrategy(config)` reads the provider's `callMode` from the canonical catalog and returns a `TtsCallStrategy` with the provider ID and call mode. Two modes exist:
|
|
2208
2205
|
|
|
2209
|
-
- **`native-twilio`** —
|
|
2210
|
-
- **`synthesized-play`** — The assistant synthesises audio via the provider's HTTP API and streams
|
|
2206
|
+
- **`native-twilio`** — Twilio handles TTS natively via ConversationRelay. The profile needs a real `ttsProvider` name (e.g. `"ElevenLabs"`) and a provider-specific voice spec string. New native providers plug in by registering a `NativeTwilioVoiceSpecBuilder` via `registerNativeTwilioVoiceSpec()` — no edits to core call routing logic required.
|
|
2207
|
+
- **`synthesized-play`** — The assistant synthesises audio via the provider's HTTP API and streams chunks to Twilio via `play` messages. Uses a placeholder TTS provider (`"Google"`) and an empty voice string because Twilio never drives TTS itself on this path.
|
|
2211
2208
|
|
|
2212
|
-
**Phone call integration:**
|
|
2209
|
+
**Phone call integration:** `resolveVoiceQualityProfile()` in `voice-quality.ts` uses `resolveCallStrategy()` to determine the call mode, then dispatches to the appropriate path. For `native-twilio`, it looks up the registered `NativeTwilioVoiceSpec` to build the voice string. For `synthesized-play`, it uses the placeholder profile. This replaces the previous `supportsStreaming`-based branching with explicit catalog-declared modes.
|
|
2213
2210
|
|
|
2214
2211
|
**Adding a new TTS provider (catalog-first checklist):**
|
|
2215
2212
|
|
package/README.md
CHANGED
|
@@ -174,7 +174,7 @@ Guardian actor-role _classification_ (determining whether a sender is guardian,
|
|
|
174
174
|
|
|
175
175
|
### Ingress Boundary Guarantees (Gateway-Only Mode)
|
|
176
176
|
|
|
177
|
-
The runtime operates in **gateway-only mode**: all public-facing webhook paths are blocked at the runtime level. Direct access to Twilio webhook routes (`/webhooks/twilio/voice`, `/webhooks/twilio/status`) and their legacy equivalents (`/v1/calls/twilio/*`) returns `410 GATEWAY_ONLY`. This ensures external webhook traffic can only reach the runtime through the gateway, which performs signature validation before forwarding.
|
|
177
|
+
The runtime operates in **gateway-only mode**: all public-facing webhook paths are blocked at the runtime level. Direct access to Twilio webhook routes (`/webhooks/twilio/voice`, `/webhooks/twilio/status`, `/webhooks/twilio/connect-action`) and their legacy equivalents (`/v1/calls/twilio/*`) returns `410 GATEWAY_ONLY`. This ensures external webhook traffic can only reach the runtime through the gateway, which performs signature validation before forwarding.
|
|
178
178
|
|
|
179
179
|
Internal forwarding routes (`/v1/internal/twilio/*`) are unaffected — these accept pre-validated payloads from the gateway over the private network.
|
|
180
180
|
|
|
@@ -309,6 +309,7 @@ Guardian verification and ingress contact management are complementary but indep
|
|
|
309
309
|
| `src/runtime/trust-context-resolver.ts` | Actor role classification: guardian / non-guardian / unverified_channel |
|
|
310
310
|
| `src/runtime/routes/inbound-message-handler.ts` | Ingress ACL enforcement, verification-code intercept, escalation creation |
|
|
311
311
|
| `src/contacts/contact-store.ts` | Contact + channel CRUD: `findContactChannel`, `upsertContact`, `updateChannelStatus`, `searchContacts` |
|
|
312
|
+
| `src/memory/invite-store.ts` | Invite lifecycle: `createInvite`, `redeemInvite` (atomically creates member record) |
|
|
312
313
|
| `src/memory/channel-verification-sessions.ts` | Guardian binding types and verification challenge persistence |
|
|
313
314
|
| `src/memory/guardian-approvals.ts` | Approval request persistence |
|
|
314
315
|
| `src/runtime/verification-outbound-actions.ts` | Shared business logic for outbound verification (start/resend/cancel) |
|
|
@@ -382,7 +383,7 @@ External users join through **invite tokens**. There are two invite flows:
|
|
|
382
383
|
1. **Guardian requests invite** — The guardian asks the assistant (via desktop chat) to create a Telegram invite link. The `guardian-invite-intent.ts` module detects the intent and routes the request into the `contacts` skill.
|
|
383
384
|
2. **Invite creation** — The skill creates an invite token via the ingress HTTP API, looks up the Telegram bot username from the integration config endpoint, and constructs a shareable deep link: `https://t.me/<bot>?start=iv_<token>`.
|
|
384
385
|
3. **Guardian shares link** — The guardian copies the deep link and shares it with the invitee through any messaging channel.
|
|
385
|
-
4. **Invitee redeems** — The invitee clicks the link, which opens Telegram and sends `/start iv_<token>` to the bot. The
|
|
386
|
+
4. **Invitee redeems** — The invitee clicks the link, which opens Telegram and sends `/start iv_<token>` to the bot. The inbound message handler extracts the token via the transport adapter, redeems it through the invite redemption service, and auto-creates an active member record.
|
|
386
387
|
5. **Access granted** — The invitee receives a welcome message and all subsequent messages pass the ingress ACL.
|
|
387
388
|
|
|
388
389
|
The `iv_` prefix distinguishes invite tokens from `gv_` (guardian verification) tokens, which use the same Telegram `/start` deep-link mechanism.
|
|
@@ -391,7 +392,7 @@ The `iv_` prefix distinguishes invite tokens from `gv_` (guardian verification)
|
|
|
391
392
|
|
|
392
393
|
The invite redemption system uses a three-layer architecture:
|
|
393
394
|
|
|
394
|
-
- **Core redemption engine** (
|
|
395
|
+
- **Core redemption engine** (`invite-redemption-service.ts`) — Channel-agnostic business logic that validates tokens, enforces expiry/use-count/channel-match constraints, handles member reactivation, and returns a discriminated-union `InviteRedemptionOutcome`. Deterministic reply templates (`invite-redemption-templates.ts`) map each outcome to a user-facing message without passing through the LLM.
|
|
395
396
|
- **Channel transport adapters** (`channel-invite-transport.ts` + `channel-invite-transports/`) — A registry of per-channel adapters that know how to build shareable links (`buildShareLink`) and extract inbound tokens (`extractInboundToken`). Adapters are implemented for Telegram, Voice, Email, WhatsApp, and Slack.
|
|
396
397
|
- **Conversational orchestration** (`guardian-invite-intent.ts`) — Pattern-based intent detection that intercepts guardian invite management requests (create, list, revoke) in the session pipeline and forces immediate entry into the `contacts` skill, bypassing the normal agent loop.
|
|
397
398
|
|
|
@@ -421,14 +422,16 @@ If no guardian binding exists, escalation fails closed — the message is denied
|
|
|
421
422
|
|
|
422
423
|
| File | Purpose |
|
|
423
424
|
| --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
425
|
+
| `src/memory/invite-store.ts` | CRUD for invite tokens with SHA-256 hashing and expiry |
|
|
424
426
|
| `src/contacts/contact-store.ts` | Contact + channel CRUD with policy enforcement |
|
|
425
|
-
| `src/
|
|
426
|
-
| `src/runtime/routes/
|
|
427
|
-
| `
|
|
427
|
+
| `src/daemon/handlers/config-inbox.ts` | HTTP handlers for invite operations |
|
|
428
|
+
| `src/runtime/routes/channel-routes.ts` | ACL enforcement point — member lookup, policy check, escalation creation |
|
|
429
|
+
| `src/runtime/invite-redemption-service.ts` | Core redemption engine — token validation, member creation, discriminated-union outcomes |
|
|
430
|
+
| `src/runtime/invite-redemption-templates.ts` | Deterministic reply templates for each redemption outcome |
|
|
428
431
|
| `src/runtime/channel-invite-transport.ts` | Transport adapter registry — `buildShareableInvite` / `extractInboundToken` per channel |
|
|
429
432
|
| `src/runtime/channel-invite-transports/telegram.ts` | Telegram adapter — builds `t.me/<bot>?start=iv_<token>` deep links, extracts `iv_` tokens from `/start` commands |
|
|
430
433
|
| `src/daemon/guardian-invite-intent.ts` | Intent detection — routes guardian invite management requests into the `contacts` skill |
|
|
431
|
-
| `src/runtime/invite-service.ts` |
|
|
434
|
+
| `src/runtime/invite-service.ts` | Shared business logic for invite and contact operations |
|
|
432
435
|
|
|
433
436
|
## Database
|
|
434
437
|
|
|
@@ -12,7 +12,8 @@ Add a new entry to the `CATALOG` map with:
|
|
|
12
12
|
- `credentialProvider` — the credential-store key name used by `getProviderKeyAsync` to retrieve the API key. If the provider shares an API key with another service (e.g. `openai-whisper` shares the `"openai"` key, or `google-gemini` shares the `"gemini"` key), reuse that name; otherwise use the provider's own name (e.g. `"deepgram"` maps to `"deepgram"`).
|
|
13
13
|
- `supportedBoundaries` — the set of `SttBoundaryId` values the provider supports. Valid values are `"daemon-batch"` (post-recording transcription) and `"daemon-streaming"` (real-time streaming transcription during conversation).
|
|
14
14
|
- `conversationStreamingMode` — how the provider handles streaming transcription in conversation mode: `"realtime-ws"` (provider supports real-time streaming natively via WebSocket), `"incremental-batch"` (streaming emulated via throttled polling), or `"none"` (no streaming support). Required for all providers.
|
|
15
|
-
- `telephonyMode` — how the provider participates in real-time telephony STT: `"realtime-ws"`, `"batch-only"`, or `"none"`.
|
|
15
|
+
- `telephonyMode` — how the provider participates in real-time telephony STT: `"realtime-ws"`, `"batch-only"`, or `"none"`.
|
|
16
|
+
- `telephonyRouting` — telephony routing metadata that drives Twilio call setup strategy selection. Declare `strategyKind` as `"conversation-relay-native"` or `"media-stream-custom"`. For native providers, include `twilioNativeMapping` with the Twilio `provider` name and `defaultSpeechModel`.
|
|
16
17
|
|
|
17
18
|
## 2. Type-system registration
|
|
18
19
|
|
|
@@ -83,8 +84,8 @@ Clients derive shared-vs-exclusive key behavior from the catalog automatically:
|
|
|
83
84
|
|
|
84
85
|
Before submitting the PR, verify that:
|
|
85
86
|
|
|
86
|
-
1. **No stale config references** — grep for any references to a separate telephony transcription config.
|
|
87
|
+
1. **No stale config references** — grep for any references to a separate telephony transcription config. The telephony routing module (`src/calls/telephony-stt-routing.ts`) reads `services.stt.provider` and maps it to the appropriate Twilio strategy (either `conversation-relay-native` for providers Twilio supports natively, or `media-stream-custom` for server-side transcription).
|
|
87
88
|
|
|
88
|
-
2. **Provider catalog
|
|
89
|
+
2. **Provider catalog `telephonyRouting` metadata** — the new provider's catalog entry (step 1) includes a `telephonyRouting` object that is the single source of truth for strategy selection in `telephony-stt-routing.ts`. This object declares the `strategyKind` (`"conversation-relay-native"` or `"media-stream-custom"`) and, for native providers, provides a `twilioNativeMapping` with the Twilio `provider` name and `defaultSpeechModel`. The routing module contains no hardcoded provider-to-Twilio maps — it reads these values directly from the catalog.
|
|
89
90
|
|
|
90
|
-
3. **No duplicate wiring** — a provider should appear only once in `services.stt`. The telephony layer consumes the same provider ID; there is no second registration step for telephony.
|
|
91
|
+
3. **No duplicate wiring** — a provider should appear only once in `services.stt`. The telephony routing layer consumes the same provider ID; there is no second registration step for telephony.
|
|
@@ -114,11 +114,11 @@ No member record is created. No verification session is created.
|
|
|
114
114
|
|
|
115
115
|
### Invites (alternative path)
|
|
116
116
|
|
|
117
|
-
|
|
117
|
+
The `assistant_ingress_invites` table supports a parallel invite-based onboarding path. An invite carries a SHA-256 hashed token and can be redeemed via `redeemInvite()`, which atomically creates an active contact channel record. This path is distinct from the trusted contact flow but serves the same end state: an active `contact_channels` entry with `status: 'active'` and `policy: 'allow'`.
|
|
118
118
|
|
|
119
|
-
| Table
|
|
120
|
-
|
|
|
121
|
-
| `
|
|
119
|
+
| Table | Purpose in trusted contact flow |
|
|
120
|
+
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
121
|
+
| `assistant_ingress_invites` | Not used in the guardian-mediated flow. Available as an alternative for direct invite links (e.g., guardian shares a URL instead of going through the approval + verification flow). |
|
|
122
122
|
|
|
123
123
|
### Voice In-Call Guardian Approval (friend-initiated)
|
|
124
124
|
|
|
@@ -126,10 +126,10 @@ Voice calls have a dedicated in-call guardian approval flow that differs from th
|
|
|
126
126
|
|
|
127
127
|
**Flow:**
|
|
128
128
|
|
|
129
|
-
1. Unknown caller dials in. `
|
|
130
|
-
2.
|
|
129
|
+
1. Unknown caller dials in. `relay-server.ts` resolves trust — caller is `unknown`, no pending challenge, no active invite.
|
|
130
|
+
2. Relay enters `awaiting_name` state and prompts the caller for their name (with a timeout).
|
|
131
131
|
3. On name capture, `notifyGuardianOfAccessRequest` creates a canonical guardian request (`kind: 'access_request'`) and notifies the guardian.
|
|
132
|
-
4.
|
|
132
|
+
4. Relay transitions to `awaiting_guardian_decision` and polls `canonical_guardian_requests` for status changes.
|
|
133
133
|
5. Guardian approves or denies via any channel. All decisions route through `applyCanonicalGuardianDecision`.
|
|
134
134
|
6. On approval: the `access_request` resolver directly activates the caller as a trusted contact (`upsertContactChannel` with `status: 'active'`, `policy: 'allow'`) — no verification session needed since the caller is already authenticated by their phone number.
|
|
135
135
|
7. On denial or timeout: the caller hears a denial message and the call ends.
|
|
@@ -78,9 +78,6 @@ const ALLOWED_PREFIXES = {
|
|
|
78
78
|
// Secure key storage (keys.ts) needs direct security module access —
|
|
79
79
|
// by design, the secure-key helpers run in-process (not over IPC).
|
|
80
80
|
"../../security/",
|
|
81
|
-
// Canonical API-key provider list (keys.ts help text + validation) —
|
|
82
|
-
// a static metadata catalog with no daemon state.
|
|
83
|
-
"../../providers/provider-secret-catalog",
|
|
84
81
|
// CES bridge (credential-execution.ts) speaks to the CES sidecar via
|
|
85
82
|
// service-contracts RPC; daemon is not involved.
|
|
86
83
|
"../../credential-execution/",
|
|
@@ -48,42 +48,6 @@ describe("contact read contracts", () => {
|
|
|
48
48
|
expect(parsed.updatedAt).toBe(1700000000);
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
-
test("ContactReadSchema accepts null interactionCount (daemon-native gateway-telemetry outage fail-soft)", () => {
|
|
52
|
-
const contact = {
|
|
53
|
-
id: "c1",
|
|
54
|
-
displayName: "Example User",
|
|
55
|
-
role: "contact",
|
|
56
|
-
contactType: "human",
|
|
57
|
-
lastInteraction: null,
|
|
58
|
-
interactionCount: null,
|
|
59
|
-
createdAt: 1699000000,
|
|
60
|
-
updatedAt: 1700000000,
|
|
61
|
-
channels: [
|
|
62
|
-
{
|
|
63
|
-
id: "ch1",
|
|
64
|
-
contactId: "c1",
|
|
65
|
-
type: "imessage",
|
|
66
|
-
address: "+15555550100",
|
|
67
|
-
isPrimary: true,
|
|
68
|
-
externalUserId: null,
|
|
69
|
-
status: "active",
|
|
70
|
-
policy: "allow",
|
|
71
|
-
verifiedAt: null,
|
|
72
|
-
verifiedVia: null,
|
|
73
|
-
lastSeenAt: null,
|
|
74
|
-
interactionCount: null,
|
|
75
|
-
lastInteraction: null,
|
|
76
|
-
revokedReason: null,
|
|
77
|
-
blockedReason: null,
|
|
78
|
-
},
|
|
79
|
-
],
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
const parsed = ContactReadSchema.parse(contact);
|
|
83
|
-
expect(parsed.interactionCount).toBeNull();
|
|
84
|
-
expect(parsed.channels[0].interactionCount).toBeNull();
|
|
85
|
-
});
|
|
86
|
-
|
|
87
51
|
test("ContactReadSchema requires createdAt/updatedAt", () => {
|
|
88
52
|
const withoutTimestamps = {
|
|
89
53
|
id: "c1",
|
|
@@ -29,8 +29,6 @@ const fullVerdict: TrustVerdict = {
|
|
|
29
29
|
policy: "allow",
|
|
30
30
|
verifiedAt: 1699999999,
|
|
31
31
|
verifiedVia: "voice",
|
|
32
|
-
interactionCount: 12,
|
|
33
|
-
lastInteraction: 1699999998,
|
|
34
32
|
memberDisplayName: "Member Name",
|
|
35
33
|
};
|
|
36
34
|
|
|
@@ -94,26 +92,6 @@ describe("TrustVerdictSchema", () => {
|
|
|
94
92
|
});
|
|
95
93
|
});
|
|
96
94
|
|
|
97
|
-
test("carries interaction telemetry and tolerates a null lastInteraction", () => {
|
|
98
|
-
const parsed = TrustVerdictSchema.parse({
|
|
99
|
-
trustClass: "trusted_contact",
|
|
100
|
-
canonicalSenderId: "+15555550100",
|
|
101
|
-
interactionCount: 0,
|
|
102
|
-
lastInteraction: null,
|
|
103
|
-
});
|
|
104
|
-
expect(parsed.interactionCount).toBe(0);
|
|
105
|
-
expect(parsed.lastInteraction).toBeNull();
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
test("leaves interaction telemetry undefined when absent", () => {
|
|
109
|
-
const parsed = TrustVerdictSchema.parse({
|
|
110
|
-
trustClass: "unknown",
|
|
111
|
-
canonicalSenderId: null,
|
|
112
|
-
});
|
|
113
|
-
expect(parsed.interactionCount).toBeUndefined();
|
|
114
|
-
expect(parsed.lastInteraction).toBeUndefined();
|
|
115
|
-
});
|
|
116
|
-
|
|
117
95
|
test("rejects an invalid trustClass", () => {
|
|
118
96
|
expect(() =>
|
|
119
97
|
TrustVerdictSchema.parse({
|
|
@@ -181,17 +181,6 @@ export type UpsertVerifiedChannelIpcResponse = z.infer<
|
|
|
181
181
|
typeof UpsertVerifiedChannelIpcResponseSchema
|
|
182
182
|
>;
|
|
183
183
|
|
|
184
|
-
export const CreateContactIpcResponseSchema = z.object({
|
|
185
|
-
contactId: z.string(),
|
|
186
|
-
// Gateway channel id for the (channelType, address) pair, resolved from the
|
|
187
|
-
// gateway DB (source of truth). Empty when the read-back found no row.
|
|
188
|
-
channelId: z.string(),
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
export type CreateContactIpcResponse = z.infer<
|
|
192
|
-
typeof CreateContactIpcResponseSchema
|
|
193
|
-
>;
|
|
194
|
-
|
|
195
184
|
export const MarkChannelRevokedIpcParamsSchema = z.object({
|
|
196
185
|
contactChannelId: z.string().min(1),
|
|
197
186
|
// Audit reason for the downgrade. The verification-revoke flow passes
|
|
@@ -233,7 +222,7 @@ export const ContactReadChannelSchema = z.object({
|
|
|
233
222
|
verifiedAt: z.number().nullable(),
|
|
234
223
|
verifiedVia: z.string().nullable(),
|
|
235
224
|
lastSeenAt: z.number().nullable(),
|
|
236
|
-
interactionCount: z.number()
|
|
225
|
+
interactionCount: z.number(),
|
|
237
226
|
lastInteraction: z.number().nullable(),
|
|
238
227
|
revokedReason: z.string().nullable(),
|
|
239
228
|
blockedReason: z.string().nullable(),
|
|
@@ -248,7 +237,7 @@ export const ContactReadSchema = z.object({
|
|
|
248
237
|
notes: z.string().nullable().optional(),
|
|
249
238
|
contactType: z.string().nullable().optional(),
|
|
250
239
|
lastInteraction: z.number().nullable().optional(),
|
|
251
|
-
interactionCount: z.number()
|
|
240
|
+
interactionCount: z.number(),
|
|
252
241
|
createdAt: z.number(),
|
|
253
242
|
updatedAt: z.number(),
|
|
254
243
|
channels: z.array(ContactReadChannelSchema),
|
|
@@ -270,16 +259,13 @@ export const ListContactsIpcParamsSchema = z
|
|
|
270
259
|
.object({
|
|
271
260
|
limit: z.number().optional(),
|
|
272
261
|
role: z.string().optional(),
|
|
273
|
-
// Restrict the read to these contact ids (any order). Used by the daemon to
|
|
274
|
-
// batch-hydrate gateway-owned telemetry onto daemon-native filtered/search
|
|
275
|
-
// results without re-implementing search in the gateway. When present,
|
|
276
|
-
// `role`/`limit` filtering is bypassed — the id set is the filter.
|
|
277
|
-
ids: z.array(z.string()).optional(),
|
|
278
262
|
})
|
|
279
263
|
.strict()
|
|
280
264
|
.default({});
|
|
281
265
|
|
|
282
|
-
export type ListContactsIpcParams = z.infer<
|
|
266
|
+
export type ListContactsIpcParams = z.infer<
|
|
267
|
+
typeof ListContactsIpcParamsSchema
|
|
268
|
+
>;
|
|
283
269
|
|
|
284
270
|
export const ListContactsIpcResponseSchema = z.object({
|
|
285
271
|
ok: z.boolean(),
|
|
@@ -302,7 +288,9 @@ export const GetContactIpcResponseSchema = z.object({
|
|
|
302
288
|
assistantMetadata: AssistantContactMetadataSchema.optional(),
|
|
303
289
|
});
|
|
304
290
|
|
|
305
|
-
export type GetContactIpcResponse = z.infer<
|
|
291
|
+
export type GetContactIpcResponse = z.infer<
|
|
292
|
+
typeof GetContactIpcResponseSchema
|
|
293
|
+
>;
|
|
306
294
|
|
|
307
295
|
export const GetGuardianContactIpcParamsSchema = z
|
|
308
296
|
.object({})
|