@vellumai/assistant 0.10.2 → 0.10.3-dev.202606252046.9075fd5
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/bun.lock +20 -0
- package/docs/workspace-tools.md +42 -33
- package/eslint-rules/cli-no-daemon-internals.js +6 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-delivery-contract.test.ts +91 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +31 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +44 -0
- package/node_modules/@vellumai/gateway-client/src/guardian-delivery-contract.ts +48 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +14 -0
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +17 -0
- package/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +28 -0
- package/node_modules/@vellumai/service-contracts/src/channels.ts +41 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/openapi.yaml +196 -56
- package/package.json +4 -1
- package/scripts/test.sh +36 -15
- package/src/__tests__/actor-token-service.test.ts +36 -14
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +83 -31
- package/src/__tests__/agent-loop-override-profile.test.ts +1 -0
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +2 -0
- package/src/__tests__/annotate-activity-metadata.test.ts +2 -0
- package/src/__tests__/annotate-risk-options.test.ts +2 -0
- package/src/__tests__/approval-cascade.test.ts +2 -0
- package/src/__tests__/assistant-attachments.test.ts +42 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +2 -0
- package/src/__tests__/btw-routes.test.ts +2 -0
- package/src/__tests__/build-persisted-content.test.ts +2 -0
- package/src/__tests__/call-controller.test.ts +19 -0
- package/src/__tests__/channel-approval-routes.test.ts +21 -26
- package/src/__tests__/channel-delivery-store.test.ts +28 -0
- package/src/__tests__/channel-guardian.test.ts +164 -78
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +11 -19
- package/src/__tests__/channel-reply-delivery.test.ts +2 -0
- package/src/__tests__/code-search-tool.test.ts +585 -0
- package/src/__tests__/compaction-events.test.ts +2 -0
- package/src/__tests__/compaction-ledger-store.test.ts +128 -0
- package/src/__tests__/compaction.benchmark.test.ts +2 -0
- package/src/__tests__/compactor-call-site-logging.test.ts +2 -0
- package/src/__tests__/compactor-low-watermark-cut.test.ts +2 -0
- package/src/__tests__/compactor-preserved-tail-count.test.ts +2 -0
- package/src/__tests__/compactor-summary-call-truncation.test.ts +2 -0
- package/src/__tests__/compactor-web-search-strip.test.ts +2 -0
- package/src/__tests__/config-loader-backfill.test.ts +123 -10
- package/src/__tests__/config-schema.test.ts +1 -0
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +31 -29
- package/src/__tests__/consult-deadline.test.ts +60 -0
- package/src/__tests__/contact-store-interaction-info.test.ts +156 -0
- package/src/__tests__/contact-store-user-file.test.ts +7 -10
- package/src/__tests__/contacts-relay-reads.test.ts +19 -24
- package/src/__tests__/contacts-write.test.ts +0 -2
- package/src/__tests__/conversation-abort-tool-results.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop.test.ts +134 -0
- package/src/__tests__/conversation-analysis-routes.test.ts +2 -0
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +2 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +9 -11
- package/src/__tests__/conversation-confirmation-signals.test.ts +2 -0
- package/src/__tests__/conversation-fork-crud.test.ts +354 -24
- package/src/__tests__/conversation-history-web-search.test.ts +2 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +2 -0
- package/src/__tests__/conversation-load-history-stripped.test.ts +2 -0
- package/src/__tests__/conversation-pairing.test.ts +2 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +2 -0
- package/src/__tests__/conversation-process-callsite.test.ts +2 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -0
- package/src/__tests__/conversation-queue.test.ts +91 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +14 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +14 -0
- package/src/__tests__/conversation-slash-queue.test.ts +2 -0
- package/src/__tests__/conversation-slash-unknown.test.ts +2 -0
- package/src/__tests__/conversation-speed-override.test.ts +2 -0
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +29 -0
- package/src/__tests__/conversation-title-service.test.ts +2 -0
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +47 -0
- package/src/__tests__/conversation-usage.test.ts +2 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +2 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +2 -0
- package/src/__tests__/credential-security-invariants.test.ts +1 -1
- package/src/__tests__/db-compaction-events-migration.test.ts +129 -0
- package/src/__tests__/db-migration-rollback.test.ts +205 -171
- package/src/__tests__/db-test-helpers.ts +5 -4
- package/src/__tests__/delete-propagation.test.ts +5 -3
- package/src/__tests__/deterministic-verification-control-plane.test.ts +4 -2
- package/src/__tests__/disk-pressure-guard.test.ts +41 -0
- package/src/__tests__/dm-backfill.test.ts +6 -4
- package/src/__tests__/dm-persistence.test.ts +2 -0
- package/src/__tests__/emit-signal-routing-intent.test.ts +7 -6
- package/src/__tests__/events-dev-bypass-actor.test.ts +7 -1
- package/src/__tests__/exploration-drift-hook.test.ts +3 -2
- package/src/__tests__/filing-service.test.ts +2 -0
- package/src/__tests__/guardian-binding-drift-heal.test.ts +104 -19
- package/src/__tests__/guardian-dispatch.test.ts +140 -1
- package/src/__tests__/guardian-expiry-notifier.test.ts +282 -0
- package/src/__tests__/guardian-outbound-http.test.ts +13 -0
- package/src/__tests__/guardian-routing-state.test.ts +6 -10
- package/src/__tests__/heartbeat-disk-pressure.test.ts +2 -0
- package/src/__tests__/heartbeat-service.test.ts +2 -0
- package/src/__tests__/helpers/channel-test-adapter.ts +46 -19
- package/src/__tests__/helpers/create-guardian-binding.ts +15 -23
- package/src/__tests__/helpers/mock-logger.ts +1 -0
- package/src/__tests__/helpers/seed-contact-channel.ts +96 -0
- package/src/__tests__/host-app-control-routes.test.ts +24 -30
- package/src/__tests__/host-bash-routes.test.ts +31 -41
- package/src/__tests__/host-browser-routes.test.ts +26 -32
- package/src/__tests__/host-cu-routes-targeted.test.ts +25 -33
- package/src/__tests__/host-file-routes-targeted.test.ts +40 -52
- package/src/__tests__/host-transfer-routes-targeted.test.ts +31 -43
- package/src/__tests__/http-user-message-parity.test.ts +290 -8
- package/src/__tests__/inbound-invite-redemption.test.ts +115 -10
- package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/invite-redemption-service.test.ts +471 -53
- package/src/__tests__/invite-routes-http.test.ts +34 -0
- package/src/__tests__/invite-service-ipc.test.ts +65 -2
- package/src/__tests__/llm-context-normalization.test.ts +105 -0
- package/src/__tests__/llm-request-log-error-payload.test.ts +71 -9
- package/src/__tests__/llm-usage-store.test.ts +25 -0
- package/src/__tests__/mcp-config-secret-boundary.test.ts +392 -0
- package/src/__tests__/mcp-health-check.test.ts +2 -1
- package/src/__tests__/media-stream-server-integration.test.ts +127 -0
- package/src/__tests__/memory-retrieval-hook.test.ts +2 -0
- package/src/__tests__/messaging-send-tool.test.ts +2 -0
- package/src/__tests__/migration-import-from-url.test.ts +2 -2
- package/src/__tests__/mtime-cache.test.ts +275 -5
- package/src/__tests__/native-web-search.test.ts +2 -0
- package/src/__tests__/non-member-access-request.test.ts +191 -17
- package/src/__tests__/notification-broadcaster.test.ts +4 -0
- package/src/__tests__/notification-decision-recipient-context.test.ts +33 -32
- package/src/__tests__/notification-deep-link.test.ts +6 -0
- package/src/__tests__/notification-guardian-path.test.ts +19 -0
- package/src/__tests__/onboarding-persona-write.test.ts +52 -22
- package/src/__tests__/openai-provider.test.ts +22 -12
- package/src/__tests__/openai-responses-provider.test.ts +12 -2
- package/src/__tests__/outbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/pending-interactions-resolved-event.test.ts +7 -4
- package/src/__tests__/persist-onboarding-artifacts.test.ts +1 -0
- package/src/__tests__/persistence-secret-redaction.test.ts +2 -0
- package/src/__tests__/persona-resolver.test.ts +75 -45
- package/src/__tests__/plugin-bootstrap.test.ts +21 -83
- package/src/__tests__/plugin-disabled-state.test.ts +190 -0
- package/src/__tests__/plugin-pipeline.test.ts +96 -0
- package/src/__tests__/plugin-route-contribution.test.ts +6 -19
- package/src/__tests__/plugin-tool-contribution.test.ts +5 -20
- package/src/__tests__/plugin-types.test.ts +2 -4
- package/src/__tests__/process-message-background-slack.test.ts +2 -0
- package/src/__tests__/process-message-display-content.test.ts +2 -0
- package/src/__tests__/provider-error-scenarios.test.ts +5 -4
- package/src/__tests__/provider-usage-tracking.test.ts +39 -0
- package/src/__tests__/reaction-intercept-cold-cache-warm.test.ts +135 -0
- package/src/__tests__/reaction-intercept-member-verdict-warm.test.ts +158 -0
- package/src/__tests__/reaction-persistence.test.ts +51 -4
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +2 -0
- package/src/__tests__/registry.test.ts +4 -1
- package/src/__tests__/relay-server.test.ts +758 -32
- package/src/__tests__/runtime-attachment-metadata.test.ts +9 -12
- package/src/__tests__/secret-ingress-http.test.ts +14 -0
- package/src/__tests__/send-endpoint-busy.test.ts +30 -8
- package/src/__tests__/settings-routes.test.ts +32 -0
- package/src/__tests__/skills.test.ts +44 -0
- package/src/__tests__/slack-inbound-verification.test.ts +47 -2
- package/src/__tests__/sse-actor-principal-guardian-source.test.ts +79 -0
- package/src/__tests__/steer-on-enqueue-question.test.ts +181 -0
- package/src/__tests__/stt-hints.test.ts +49 -15
- package/src/__tests__/subagent-detail.test.ts +27 -0
- package/src/__tests__/subagent-disposal.test.ts +65 -0
- package/src/__tests__/subagent-fork-prompt-role.test.ts +195 -0
- package/src/__tests__/subagent-fork-spawn.test.ts +6 -7
- package/src/__tests__/subagent-notify-parent.test.ts +2 -0
- package/src/__tests__/subagent-role-registry.test.ts +24 -6
- package/src/__tests__/subagent-spawn-and-await.test.ts +546 -0
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +2 -0
- package/src/__tests__/subagent-tools.test.ts +398 -1
- package/src/__tests__/suggestion-routes.test.ts +2 -0
- package/src/__tests__/thread-backfill.test.ts +3 -3
- package/src/__tests__/title-generate-hook.test.ts +2 -0
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -0
- package/src/__tests__/tool-executor.test.ts +16 -11
- package/src/__tests__/tool-preview-lifecycle.test.ts +2 -0
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +2 -0
- package/src/__tests__/tool-start-timestamp.test.ts +2 -0
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +37 -51
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +12 -12
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +9 -7
- package/src/__tests__/trusted-contact-multichannel.test.ts +16 -7
- package/src/__tests__/trusted-contact-verification.test.ts +79 -54
- package/src/__tests__/twilio-routes.test.ts +96 -0
- package/src/__tests__/ui-file-upload-surface.test.ts +86 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -0
- package/src/__tests__/voice-guardian-cold-cache-warm.test.ts +137 -0
- package/src/__tests__/voice-invite-redemption.test.ts +216 -20
- package/src/__tests__/web-search-backend-failure.test.ts +2 -0
- package/src/__tests__/workspace-migration-102-preserve-heartbeat-enabled-for-existing-workspaces.test.ts +3 -3
- package/src/__tests__/workspace-migration-111-prune-seeded-callsite-defaults.test.ts +208 -0
- package/src/__tests__/workspace-migration-112-remove-advisor-callsite-override.test.ts +170 -0
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +196 -238
- package/src/__tests__/workspace-migration-remove-hooks.test.ts +14 -35
- package/src/__tests__/workspace-tool-loader.test.ts +195 -2
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +35 -47
- package/src/agent/loop-exclusive-tool.test.ts +154 -0
- package/src/agent/loop-native-web-search.test.ts +200 -0
- package/src/agent/loop.ts +164 -1
- package/src/api/constants/sse-replay.ts +41 -0
- package/src/api/events/conversation-notice.ts +26 -0
- package/src/api/index.ts +19 -1
- package/src/api/responses/llm-request-log-entry.ts +29 -0
- package/src/api/responses/subagent-detail.ts +17 -0
- package/src/api/surfaces.ts +39 -3
- package/src/approvals/guardian-channel-delivery.ts +30 -0
- package/src/approvals/guardian-expiry-notifier.ts +148 -0
- package/src/approvals/guardian-request-resolvers.ts +17 -15
- package/src/calls/__tests__/relay-setup-router.test.ts +267 -17
- package/src/calls/call-domain.ts +3 -3
- package/src/calls/guardian-dispatch.ts +14 -9
- package/src/calls/inbound-trust-reader.ts +24 -2
- package/src/calls/media-stream-server.ts +21 -0
- package/src/calls/relay-access-wait.ts +6 -6
- package/src/calls/relay-server.ts +188 -51
- package/src/calls/relay-setup-router.ts +47 -17
- package/src/calls/relay-verification.ts +4 -4
- package/src/calls/stt-hints.ts +9 -12
- package/src/calls/twilio-routes.ts +14 -4
- package/src/channels/types.ts +10 -20
- package/src/cli/commands/__tests__/cache.test.ts +8 -1
- package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -0
- package/src/cli/commands/cache.ts +194 -181
- package/src/cli/commands/contacts.ts +10 -7
- package/src/cli/commands/db/__tests__/repair.test.ts +6 -5
- package/src/cli/commands/db/status.ts +37 -1
- package/src/cli/commands/mcp.ts +252 -218
- package/src/cli/commands/memory/__tests__/worker.test.ts +432 -0
- package/src/cli/commands/memory/index.ts +2 -0
- package/src/cli/commands/memory/worker.ts +242 -0
- package/src/cli/commands/plugins.ts +125 -13
- package/src/cli/lib/__tests__/install-from-github.test.ts +102 -0
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +160 -1
- package/src/cli/lib/__tests__/publish-plugin.test.ts +404 -0
- package/src/cli/lib/list-installed-plugins.ts +179 -1
- package/src/cli/lib/publish-plugin.ts +633 -0
- package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +143 -0
- package/src/config/__tests__/sync-gated-profiles.test.ts +16 -10
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +27 -17
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +13 -3
- package/src/config/bundled-skills/subagent/SKILL.md +17 -2
- package/src/config/bundled-skills/subagent/TOOLS.json +5 -4
- package/src/config/call-site-defaults.ts +0 -6
- package/src/config/feature-flag-registry.json +5 -13
- package/src/config/llm-resolver.ts +0 -3
- package/src/config/loader.ts +38 -5
- package/src/config/prune-seeded-callsite-defaults.ts +110 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
- package/src/config/schemas/call-site-catalog.ts +0 -7
- package/src/config/schemas/heartbeat.ts +2 -5
- package/src/config/schemas/llm.ts +3 -12
- package/src/config/schemas/memory-lifecycle.ts +12 -0
- package/src/config/schemas/memory-v3.ts +7 -0
- package/src/config/schemas/memory.ts +4 -0
- package/src/config/schemas/timeouts.ts +8 -0
- package/src/config/seed-inference-profiles.ts +30 -34
- package/src/config/skills.ts +27 -5
- package/src/config/sync-gated-profiles.ts +12 -16
- package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +128 -0
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +312 -0
- package/src/contacts/__tests__/member-write-relay.test.ts +226 -0
- package/src/contacts/contact-store.ts +27 -237
- package/src/contacts/contacts-write.ts +18 -55
- package/src/contacts/gateway-channel-read.ts +51 -0
- package/src/contacts/guardian-delivery-reader.ts +223 -0
- package/src/contacts/member-write-relay.ts +183 -0
- package/src/contacts/types.ts +3 -15
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +35 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +0 -44
- package/src/daemon/assistant-attachments.ts +27 -4
- package/src/daemon/conversation-agent-loop.ts +28 -0
- package/src/daemon/conversation-notices.ts +60 -0
- package/src/daemon/conversation-process.ts +35 -16
- package/src/daemon/conversation-surfaces.ts +111 -38
- package/src/daemon/conversation-tool-setup.ts +71 -30
- package/src/daemon/conversation.ts +23 -1
- package/src/daemon/disk-pressure-guard.ts +12 -2
- package/src/daemon/event-loop-watchdog.ts +28 -1
- package/src/daemon/external-plugins-bootstrap.ts +17 -41
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +0 -1
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +0 -2
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +25 -2
- package/src/daemon/handlers/__tests__/config-channels.test.ts +220 -0
- package/src/daemon/handlers/config-a2a.ts +6 -14
- package/src/daemon/handlers/config-channels.ts +67 -26
- package/src/daemon/handlers/conversations.ts +77 -0
- package/src/daemon/lifecycle.ts +16 -0
- package/src/daemon/mcp-reload-service.ts +10 -0
- package/src/daemon/memory-v2-startup.test.ts +72 -0
- package/src/daemon/memory-v2-startup.ts +87 -19
- package/src/daemon/message-types/conversations.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +12 -12
- package/src/daemon/server.ts +0 -4
- package/src/daemon/shutdown-handlers.ts +20 -0
- package/src/daemon/tool-setup-types.ts +9 -0
- package/src/heartbeat/heartbeat-service.ts +5 -0
- package/src/home/relationship-state-writer.ts +5 -0
- package/src/hooks/hook-loader.ts +341 -0
- package/src/ipc/__tests__/clients-list-ipc.test.ts +1 -1
- package/src/ipc/assistant-server.ts +2 -2
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +1 -0
- package/src/mcp/client.ts +15 -1
- package/src/mcp/mcp-auth-orchestrator.ts +6 -1
- package/src/mcp/mcp-header-store.ts +134 -0
- package/src/mcp/mcp-oauth-provider.ts +19 -8
- package/src/memory/__tests__/301-create-watchdog-events.test.ts +110 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +8 -0
- package/src/memory/__tests__/prompt-override.test.ts +192 -0
- package/src/memory/__tests__/watchdog-events-store.test.ts +161 -0
- package/src/memory/compaction-ledger-store.ts +107 -0
- package/src/memory/conversation-crud.ts +129 -61
- package/src/memory/db-connection.ts +22 -3
- package/src/memory/db-init.ts +37 -503
- package/src/memory/db-singleton.ts +6 -4
- package/src/memory/jobs-worker.ts +104 -0
- package/src/memory/llm-request-log-store.ts +26 -1
- package/src/memory/llm-usage-store.ts +48 -20
- package/src/memory/memory-retrospective-job.ts +14 -8
- package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +152 -56
- package/src/memory/migrations/300-add-processing-started-at.ts +30 -0
- package/src/memory/migrations/301-create-watchdog-events.ts +45 -0
- package/src/memory/migrations/302-create-compaction-events.ts +107 -0
- package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +297 -0
- package/src/memory/migrations/__tests__/run-migrations.test.ts +2 -2
- package/src/memory/migrations/run-migrations.ts +106 -10
- package/src/memory/migrations/validate-migration-state.ts +105 -67
- package/src/memory/prompt-override.ts +129 -0
- package/src/memory/schema/contacts.ts +6 -2
- package/src/memory/schema/conversations.ts +37 -0
- package/src/memory/schema/infrastructure.ts +20 -0
- package/src/memory/steps.ts +1294 -0
- package/src/memory/v2/__tests__/cli-command-store.test.ts +25 -0
- package/src/memory/v2/__tests__/skill-store.test.ts +80 -0
- package/src/memory/v2/cli-command-store.ts +75 -38
- package/src/memory/v2/prompts/consolidation.ts +13 -82
- package/src/memory/v2/prompts/router.ts +21 -93
- package/src/memory/v2/skill-store.ts +68 -31
- package/src/memory/watchdog-events-store.ts +87 -0
- package/src/memory/worker-control.ts +204 -0
- package/src/memory/worker-process.ts +89 -0
- package/src/messaging/channel-binding-metadata.ts +31 -0
- package/src/messaging/provider-types.ts +8 -0
- package/src/messaging/providers/slack/binding-metadata.ts +60 -0
- package/src/notifications/__tests__/broadcaster.test.ts +8 -8
- package/src/notifications/__tests__/connected-channels.test.ts +86 -0
- package/src/notifications/__tests__/decision-engine.test.ts +78 -9
- package/src/notifications/__tests__/destination-resolver.test.ts +151 -0
- package/src/notifications/broadcaster.ts +8 -1
- package/src/notifications/decision-engine.ts +15 -7
- package/src/notifications/destination-resolver.ts +53 -25
- package/src/notifications/emit-signal.ts +34 -15
- package/src/onboarding/checkin-event.test.ts +222 -0
- package/src/onboarding/checkin-event.ts +321 -0
- package/src/onboarding/schedule-checkin.ts +190 -0
- package/src/permissions/question-prompter.test.ts +1 -1
- package/src/permissions/question-prompter.ts +7 -4
- package/src/plugin-api/index.ts +12 -12
- package/src/plugin-api/types.ts +12 -14
- package/src/plugin-api/vision-support.test.ts +28 -4
- package/src/plugin-api/vision-support.ts +66 -31
- package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +2 -2
- package/src/plugins/defaults/empty-response/hooks/stop.ts +2 -2
- package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +4 -3
- package/src/plugins/defaults/history-repair/hooks/post-model-call.ts +2 -2
- package/src/plugins/defaults/history-repair/hooks/stop.ts +2 -2
- package/src/plugins/defaults/history-repair/hooks/user-prompt-submit.ts +2 -2
- package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +47 -7
- package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +12 -13
- package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +14 -22
- package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +42 -11
- package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +2 -2
- package/src/plugins/defaults/image-recovery/hooks/stop.ts +2 -2
- package/src/plugins/defaults/index.ts +0 -35
- package/src/plugins/defaults/max-tokens-continue/hooks/post-model-call.ts +2 -2
- package/src/plugins/defaults/max-tokens-continue/hooks/stop.ts +2 -2
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +2 -2
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +2 -2
- package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +33 -3
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +48 -4
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +4 -8
- package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +2 -2
- package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +2 -2
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +43 -15
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +11 -2
- package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +146 -0
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +77 -13
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +12 -11
- package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +2 -2
- package/src/plugins/defaults/surface-completion-nudge/hooks/stop.ts +2 -2
- package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +2 -2
- package/src/plugins/defaults/title-generate/hooks/stop.ts +2 -2
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +2 -2
- package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +2 -2
- package/src/plugins/defaults/tool-result-truncate/hooks/post-tool-use.ts +2 -2
- package/src/plugins/disabled-state.ts +31 -0
- package/src/plugins/external-plugin-loader.ts +2 -2
- package/src/plugins/mtime-cache.ts +186 -330
- package/src/plugins/pipeline.ts +111 -13
- package/src/plugins/registry.ts +59 -16
- package/src/plugins/surface-import.ts +121 -0
- package/src/plugins/types.ts +7 -9
- package/src/prompts/persona-resolver.ts +43 -11
- package/src/providers/anthropic/client.ts +5 -0
- package/src/providers/call-site-routing.ts +45 -0
- package/src/providers/model-catalog.ts +16 -0
- package/src/providers/openai/__tests__/api-error-normalization.test.ts +321 -0
- package/src/providers/openai/api-error-normalization.ts +270 -0
- package/src/providers/openai/chat-completions-provider.ts +37 -83
- package/src/providers/openai/responses-provider.ts +50 -46
- package/src/providers/openrouter/client.ts +5 -0
- package/src/providers/provider-send-message.ts +10 -0
- package/src/providers/ratelimit.ts +10 -0
- package/src/providers/registry.ts +1 -1
- package/src/providers/retry.ts +10 -0
- package/src/providers/types.ts +22 -0
- package/src/providers/usage-tracking.ts +10 -0
- package/src/runtime/__tests__/channel-verification-service.test.ts +133 -0
- package/src/runtime/__tests__/guardian-vellum-migration.test.ts +184 -0
- package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +66 -0
- package/src/runtime/__tests__/local-principal-trust.test.ts +162 -0
- package/src/runtime/__tests__/member-verdict-cache.test.ts +119 -0
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +402 -123
- package/src/runtime/access-request-helper.ts +18 -39
- package/src/runtime/actor-trust-resolver.ts +46 -19
- package/src/runtime/anchored-guardian.test.ts +109 -0
- package/src/runtime/anchored-guardian.ts +86 -0
- package/src/runtime/assistant-event-hub.ts +1 -1
- package/src/runtime/assistant-stream-state.ts +9 -2
- package/src/runtime/auth/__tests__/require-bound-guardian.test.ts +99 -0
- package/src/runtime/auth/require-bound-guardian.ts +21 -11
- package/src/runtime/channel-verification-service.ts +56 -31
- package/src/runtime/confirmation-request-guardian-bridge.ts +3 -3
- package/src/runtime/guardian-vellum-migration.ts +69 -8
- package/src/runtime/invite-redemption-service.ts +213 -187
- package/src/runtime/local-actor-identity.test.ts +108 -0
- package/src/runtime/local-actor-identity.ts +85 -13
- package/src/runtime/local-principal-trust.ts +52 -0
- package/src/runtime/member-verdict-cache.ts +0 -0
- package/src/runtime/pending-interactions.ts +11 -1
- package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +56 -5
- package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/contact-routes.test.ts +305 -0
- package/src/runtime/routes/__tests__/global-search-routes.test.ts +92 -0
- package/src/runtime/routes/__tests__/http-adapter-actor-header.test.ts +129 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +188 -0
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +13 -5
- package/src/runtime/routes/channel-verification-routes.ts +3 -3
- package/src/runtime/routes/contact-routes.ts +48 -57
- package/src/runtime/routes/conversation-cli-routes.ts +4 -5
- package/src/runtime/routes/conversation-list-routes.ts +4 -7
- package/src/runtime/routes/conversation-query-routes.ts +72 -0
- package/src/runtime/routes/conversation-routes.ts +84 -85
- package/src/runtime/routes/events-routes.ts +2 -2
- package/src/runtime/routes/global-search-routes.ts +3 -1
- package/src/runtime/routes/guardian-action-routes.ts +4 -5
- package/src/runtime/routes/host-app-control-routes.ts +5 -4
- package/src/runtime/routes/host-bash-routes.ts +5 -4
- package/src/runtime/routes/host-browser-routes.ts +9 -11
- package/src/runtime/routes/host-cu-routes.ts +5 -4
- package/src/runtime/routes/host-file-routes.ts +5 -4
- package/src/runtime/routes/host-transfer-routes.ts +6 -6
- package/src/runtime/routes/http-adapter.ts +16 -1
- package/src/runtime/routes/identity-routes.ts +3 -2
- package/src/runtime/routes/inbound-message-handler.ts +5 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +97 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +61 -59
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +13 -5
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +7 -7
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +21 -8
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -3
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +19 -0
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/llm-context-normalization.ts +83 -0
- package/src/runtime/routes/mcp-auth-routes.ts +171 -19
- package/src/runtime/routes/migration-rollback-routes.ts +4 -3
- package/src/runtime/routes/migration-routes.ts +4 -1
- package/src/runtime/routes/onboarding-checkin-routes.ts +86 -0
- package/src/runtime/routes/settings-routes.ts +8 -3
- package/src/runtime/routes/subagents-routes.ts +5 -0
- package/src/runtime/routes/surface-action-routes.ts +42 -56
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
- package/src/runtime/services/conversation-serializer.ts +13 -58
- package/src/runtime/tool-grant-request-helper.ts +3 -3
- package/src/runtime/trust-verdict-consumer.ts +111 -40
- package/src/runtime/verification-outbound-actions.ts +18 -18
- package/src/signals/user-message.ts +16 -0
- package/src/subagent/__tests__/consult-prompt.test.ts +35 -0
- package/src/{plugins/defaults/advisor/__tests__/transcript.test.ts → subagent/__tests__/consult-transcript.test.ts} +47 -10
- package/src/{plugins/defaults/advisor/steering.ts → subagent/consult-prompt.ts} +22 -32
- package/src/{plugins/defaults/advisor/transcript.ts → subagent/consult-transcript.ts} +18 -8
- package/src/subagent/index.ts +1 -1
- package/src/subagent/manager.ts +254 -33
- package/src/subagent/types.ts +11 -4
- package/src/telemetry/types.ts +34 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +3 -2
- package/src/telemetry/usage-telemetry-reporter.ts +87 -3
- package/src/tools/ask-question/ask-question-tool.test.ts +29 -0
- package/src/tools/ask-question/ask-question-tool.ts +13 -0
- package/src/tools/executor.ts +4 -4
- package/src/tools/filesystem/search.ts +543 -0
- package/src/tools/registry.ts +38 -0
- package/src/tools/shared/filesystem/path-policy.ts +12 -5
- package/src/tools/subagent/consult-deadline.ts +49 -0
- package/src/tools/subagent/spawn.ts +234 -5
- package/src/tools/tool-approval-handler.ts +1 -1
- package/src/tools/tool-defaults.ts +9 -2
- package/src/tools/tool-manifest.ts +3 -0
- package/src/tools/types.ts +131 -25
- package/src/tools/workspace-tools/loader.ts +348 -244
- package/src/util/errors.ts +26 -1
- package/src/util/logger.ts +9 -0
- package/src/util/platform.ts +19 -0
- package/src/util/telemetry-db-path.ts +24 -0
- package/src/workflows/library.test.ts +140 -0
- package/src/workflows/library.ts +82 -28
- package/src/workspace/migrations/017-seed-persona-dirs.ts +3 -34
- package/src/workspace/migrations/019-scope-journal-to-guardian.ts +3 -24
- package/src/workspace/migrations/031-drop-user-md.ts +232 -148
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +14 -66
- package/src/workspace/migrations/111-prune-seeded-callsite-defaults.ts +134 -0
- package/src/workspace/migrations/112-remove-advisor-callsite-override.ts +64 -0
- package/src/workspace/migrations/registry.ts +4 -0
- package/src/__tests__/workspace-tools-watcher-flag.test.ts +0 -70
- package/src/daemon/workspace-tools-watcher.ts +0 -328
- package/src/memory/migrations/registry.ts +0 -573
- package/src/plugins/defaults/advisor/__tests__/advisor-gate.test.ts +0 -56
- package/src/plugins/defaults/advisor/__tests__/advisor-state-store.test.ts +0 -43
- package/src/plugins/defaults/advisor/__tests__/agent-loop-integration.test.ts +0 -137
- package/src/plugins/defaults/advisor/__tests__/consult.test.ts +0 -153
- package/src/plugins/defaults/advisor/__tests__/hooks.test.ts +0 -138
- package/src/plugins/defaults/advisor/advisor-gate.ts +0 -29
- package/src/plugins/defaults/advisor/advisor-state-store.ts +0 -94
- package/src/plugins/defaults/advisor/config.ts +0 -21
- package/src/plugins/defaults/advisor/consult.ts +0 -93
- package/src/plugins/defaults/advisor/hooks/post-model-call.ts +0 -34
- package/src/plugins/defaults/advisor/hooks/pre-model-call.ts +0 -30
- package/src/plugins/defaults/advisor/hooks/user-prompt-submit.ts +0 -19
- package/src/plugins/defaults/advisor/package.json +0 -14
- package/src/plugins/defaults/advisor/tools/advisor.ts +0 -65
- package/src/providers/openai/__tests__/api-error-detail.test.ts +0 -120
|
@@ -10,10 +10,14 @@
|
|
|
10
10
|
* fail-closed); this reader only reports the verdict or `null`.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
type TrustVerdict,
|
|
15
|
+
TrustVerdictSchema,
|
|
16
|
+
} from "@vellumai/gateway-client";
|
|
14
17
|
|
|
15
18
|
import type { ChannelId } from "../channels/types.js";
|
|
16
19
|
import { ipcCall } from "../ipc/gateway-client.js";
|
|
20
|
+
import { setMemberVerdict } from "../runtime/member-verdict-cache.js";
|
|
17
21
|
|
|
18
22
|
// Short IPC timeout so the read resolves promptly rather than stalling call
|
|
19
23
|
// setup on a gateway that accepts the socket but hangs.
|
|
@@ -33,8 +37,26 @@ export async function getInboundTrustVerdict(input: {
|
|
|
33
37
|
if (!result) return null;
|
|
34
38
|
|
|
35
39
|
const parsed = TrustVerdictSchema.safeParse(result.verdict);
|
|
36
|
-
|
|
40
|
+
if (!parsed.success) return null;
|
|
41
|
+
|
|
42
|
+
// Single choke point: warm the member-verdict cache so the sync trust
|
|
43
|
+
// fallback resolves the member without a local ACL read.
|
|
44
|
+
setMemberVerdict(input.channelType, input.actorExternalId, parsed.data);
|
|
45
|
+
return parsed.data;
|
|
37
46
|
} catch {
|
|
38
47
|
return null;
|
|
39
48
|
}
|
|
40
49
|
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Resolve the verdict for a phone caller by their external number. Callers
|
|
53
|
+
* compute `otherPartyNumber` from their own transport-specific direction.
|
|
54
|
+
*/
|
|
55
|
+
export function getPhoneCallerVerdict(
|
|
56
|
+
otherPartyNumber: string | undefined,
|
|
57
|
+
): Promise<TrustVerdict | null> {
|
|
58
|
+
return getInboundTrustVerdict({
|
|
59
|
+
channelType: "phone",
|
|
60
|
+
actorExternalId: otherPartyNumber || undefined,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
@@ -52,6 +52,7 @@ import {
|
|
|
52
52
|
} from "./call-store.js";
|
|
53
53
|
import { getChannelAdmissionPolicy } from "./channel-admission-reader.js";
|
|
54
54
|
import { finalizeCall } from "./finalize-call.js";
|
|
55
|
+
import { getPhoneCallerVerdict } from "./inbound-trust-reader.js";
|
|
55
56
|
import { MediaStreamOutput } from "./media-stream-output.js";
|
|
56
57
|
import { parseMediaStreamFrame } from "./media-stream-parser.js";
|
|
57
58
|
import type { MediaStreamStartEvent } from "./media-stream-protocol.js";
|
|
@@ -391,6 +392,25 @@ export class MediaStreamCallSession {
|
|
|
391
392
|
return;
|
|
392
393
|
}
|
|
393
394
|
|
|
395
|
+
// Verdict-first caller trust so this transport enforces the same gateway
|
|
396
|
+
// ACL as ConversationRelay. routeSetup uses it when present and not
|
|
397
|
+
// resolutionFailed, else falls back to local resolution. The reader returns
|
|
398
|
+
// null on failure, keeping the local path on a gateway blip.
|
|
399
|
+
const isInbound = session?.initiatedFromConversationId == null;
|
|
400
|
+
const otherPartyNumber = isInbound ? from : to;
|
|
401
|
+
const verdict = await getPhoneCallerVerdict(otherPartyNumber);
|
|
402
|
+
|
|
403
|
+
// The verdict read above yields the event loop; abort if the session was
|
|
404
|
+
// disposed meanwhile, matching the admission-read guard above.
|
|
405
|
+
if (this.disposed) {
|
|
406
|
+
log.info(
|
|
407
|
+
{ callSessionId: this.callSessionId },
|
|
408
|
+
"Media-stream session disposed during verdict read — aborting setup",
|
|
409
|
+
);
|
|
410
|
+
this.setupRouting = false;
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
|
|
394
414
|
const { outcome, resolved } = routeSetup({
|
|
395
415
|
callSessionId: this.callSessionId,
|
|
396
416
|
session: session ?? null,
|
|
@@ -398,6 +418,7 @@ export class MediaStreamCallSession {
|
|
|
398
418
|
to,
|
|
399
419
|
customParameters: event.start.customParameters,
|
|
400
420
|
admissionPolicy,
|
|
421
|
+
verdict,
|
|
401
422
|
});
|
|
402
423
|
|
|
403
424
|
log.info(
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { findContactChannel } from "../contacts/contact-store.js";
|
|
10
10
|
import { getCanonicalGuardianRequest } from "../memory/canonical-guardian-store.js";
|
|
11
11
|
import { emitNotificationSignal } from "../notifications/emit-signal.js";
|
|
12
|
+
import { getCachedMemberAcl } from "../runtime/member-verdict-cache.js";
|
|
12
13
|
import { getLogger } from "../util/logger.js";
|
|
13
14
|
import {
|
|
14
15
|
getGuardianWaitUpdateInitialIntervalMs,
|
|
@@ -252,12 +253,11 @@ export function emitAccessRequestCallbackHandoff(
|
|
|
252
253
|
address: fromNumber,
|
|
253
254
|
externalChatId: fromNumber,
|
|
254
255
|
});
|
|
255
|
-
if (
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
requesterMemberId = contactResult.channel.id;
|
|
256
|
+
if (contactResult) {
|
|
257
|
+
const acl = getCachedMemberAcl("phone", fromNumber);
|
|
258
|
+
if (acl?.status === "active" && acl.policy === "allow") {
|
|
259
|
+
requesterMemberId = contactResult.channel.id;
|
|
260
|
+
}
|
|
261
261
|
}
|
|
262
262
|
} catch (err) {
|
|
263
263
|
log.warn(
|
|
@@ -8,15 +8,17 @@
|
|
|
8
8
|
|
|
9
9
|
import { randomInt } from "node:crypto";
|
|
10
10
|
|
|
11
|
-
import type { AdmissionPolicy } from "@vellumai/gateway-client";
|
|
11
|
+
import type { AdmissionPolicy, TrustVerdict } from "@vellumai/gateway-client";
|
|
12
12
|
import type { ServerWebSocket } from "bun";
|
|
13
13
|
|
|
14
14
|
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
getGuardianDelivery,
|
|
16
|
+
getGuardianDeliveryFresh,
|
|
17
|
+
voiceGuardianDisplayName,
|
|
18
|
+
} from "../contacts/guardian-delivery-reader.js";
|
|
18
19
|
import { getAssistantName } from "../daemon/identity-helpers.js";
|
|
19
20
|
import type { ServerMessage } from "../daemon/message-protocol.js";
|
|
21
|
+
import type { TrustContext } from "../daemon/trust-context.js";
|
|
20
22
|
import { getCanonicalGuardianRequest } from "../memory/canonical-guardian-store.js";
|
|
21
23
|
import { addMessage } from "../memory/conversation-crud.js";
|
|
22
24
|
import { revokeScopedApprovalGrantsForContext } from "../memory/scoped-approval-grants.js";
|
|
@@ -26,6 +28,11 @@ import {
|
|
|
26
28
|
resolveActorTrust,
|
|
27
29
|
toTrustContext,
|
|
28
30
|
} from "../runtime/actor-trust-resolver.js";
|
|
31
|
+
import {
|
|
32
|
+
trustContextFromVerdict,
|
|
33
|
+
verdictHasMemberIdentity,
|
|
34
|
+
verdictMemberUnresolvable,
|
|
35
|
+
} from "../runtime/trust-verdict-consumer.js";
|
|
29
36
|
import {
|
|
30
37
|
composeVerificationVoice,
|
|
31
38
|
GUARDIAN_VERIFY_TEMPLATE_KEYS,
|
|
@@ -50,6 +57,10 @@ import {
|
|
|
50
57
|
import { ConversationRelayTransport } from "./call-transport.js";
|
|
51
58
|
import { getChannelAdmissionPolicy } from "./channel-admission-reader.js";
|
|
52
59
|
import { finalizeCall } from "./finalize-call.js";
|
|
60
|
+
import {
|
|
61
|
+
getInboundTrustVerdict,
|
|
62
|
+
getPhoneCallerVerdict,
|
|
63
|
+
} from "./inbound-trust-reader.js";
|
|
53
64
|
import {
|
|
54
65
|
classifyWaitUtterance,
|
|
55
66
|
emitAccessRequestCallbackHandoff,
|
|
@@ -252,6 +263,10 @@ export class RelayConnection {
|
|
|
252
263
|
private accessRequestWaitStartedAt: number = 0;
|
|
253
264
|
private heartbeatSequence = 0;
|
|
254
265
|
|
|
266
|
+
// Guardian displayName primed from the gateway binding at setup, read
|
|
267
|
+
// synchronously by the heartbeat-driven wait-label path.
|
|
268
|
+
private primedGuardianDisplayName: string | undefined;
|
|
269
|
+
|
|
255
270
|
// In-wait prompt handling state
|
|
256
271
|
private lastInWaitReplyAt = 0;
|
|
257
272
|
private static readonly IN_WAIT_REPLY_COOLDOWN_MS = 3000;
|
|
@@ -261,6 +276,12 @@ export class RelayConnection {
|
|
|
261
276
|
private callbackOptIn = false;
|
|
262
277
|
private callbackHandoffNotified = false;
|
|
263
278
|
|
|
279
|
+
// True while mid-call trust is being re-resolved (async). handlePrompt defers
|
|
280
|
+
// prompts to trustReResolvePending so a verified caller can't start a turn
|
|
281
|
+
// under the stale pre-verification trust context during the await window.
|
|
282
|
+
private trustReResolving = false;
|
|
283
|
+
private trustReResolvePending: RelayPromptMessage[] = [];
|
|
284
|
+
|
|
264
285
|
constructor(ws: ServerWebSocket<RelayWebSocketData>, callSessionId: string) {
|
|
265
286
|
this.ws = ws;
|
|
266
287
|
this.callSessionId = callSessionId;
|
|
@@ -581,12 +602,33 @@ export class RelayConnection {
|
|
|
581
602
|
const session = getCallSession(this.callSessionId);
|
|
582
603
|
this.recordSetupBookkeeping(session, msg);
|
|
583
604
|
|
|
605
|
+
// Prime the guardian displayName and warm the phone-channel guardian-
|
|
606
|
+
// delivery cache before routeSetup's SYNC resolveActorTrust fallback. That
|
|
607
|
+
// fallback reads the IO-free cache snapshot keyed per channel-filter; daemon
|
|
608
|
+
// startup warms only `vellum`, so a cold-process phone call would otherwise
|
|
609
|
+
// misclassify a guardian during a gateway verdict blip. Read fresh: gateway-
|
|
610
|
+
// side binding writes don't invalidate the daemon cache, so a stale empty
|
|
611
|
+
// snapshot from an earlier setup would survive the TTL otherwise. Both are
|
|
612
|
+
// independent IPC reads on different cache keys, so run them concurrently
|
|
613
|
+
// off the sync resolver's hot path.
|
|
614
|
+
await Promise.all([
|
|
615
|
+
this.primeGuardianDisplayName(),
|
|
616
|
+
getGuardianDeliveryFresh({ channelTypes: ["phone"] }),
|
|
617
|
+
]);
|
|
618
|
+
|
|
584
619
|
// Resolve the phone channel's inbound admission floor. The reader fails
|
|
585
620
|
// open to `null` by contract, so a transport hiccup admits the caller.
|
|
586
621
|
const admissionPolicy = await getChannelAdmissionPolicy("phone");
|
|
587
622
|
|
|
623
|
+
// Verdict-first caller trust. routeSetup uses it when present and not
|
|
624
|
+
// resolutionFailed, else falls back to local resolution. The reader
|
|
625
|
+
// returns null on failure, so a gateway blip keeps the local path.
|
|
626
|
+
const isInbound = session?.initiatedFromConversationId == null;
|
|
627
|
+
const otherPartyNumber = isInbound ? msg.from : msg.to;
|
|
628
|
+
const verdict = await getPhoneCallerVerdict(otherPartyNumber);
|
|
629
|
+
|
|
588
630
|
try {
|
|
589
|
-
await this.routeSetupOutcome(msg, session, admissionPolicy);
|
|
631
|
+
await this.routeSetupOutcome(msg, session, admissionPolicy, verdict);
|
|
590
632
|
} catch (err) {
|
|
591
633
|
// Never leave the connection stranded in "setting_up": a setup that
|
|
592
634
|
// throws before reaching a terminal outcome would otherwise drop every
|
|
@@ -615,6 +657,7 @@ export class RelayConnection {
|
|
|
615
657
|
msg: RelaySetupMessage,
|
|
616
658
|
session: ReturnType<typeof getCallSession>,
|
|
617
659
|
admissionPolicy: AdmissionPolicy | null,
|
|
660
|
+
verdict: TrustVerdict | null,
|
|
618
661
|
): Promise<void> {
|
|
619
662
|
const { outcome, resolved } = routeSetup({
|
|
620
663
|
callSessionId: this.callSessionId,
|
|
@@ -623,6 +666,7 @@ export class RelayConnection {
|
|
|
623
666
|
to: msg.to,
|
|
624
667
|
customParameters: msg.customParameters,
|
|
625
668
|
admissionPolicy,
|
|
669
|
+
verdict,
|
|
626
670
|
});
|
|
627
671
|
|
|
628
672
|
const initialTrustContext = toTrustContext(
|
|
@@ -780,7 +824,7 @@ export class RelayConnection {
|
|
|
780
824
|
from,
|
|
781
825
|
trustClass: resolved.actorTrust.trustClass,
|
|
782
826
|
channelId: resolved.actorTrust.memberRecord?.channel.id,
|
|
783
|
-
memberPolicy: resolved.actorTrust.memberRecord?.
|
|
827
|
+
memberPolicy: resolved.actorTrust.memberRecord?.policy,
|
|
784
828
|
});
|
|
785
829
|
this.connectionState = "disconnecting";
|
|
786
830
|
updateCallSession(this.callSessionId, {
|
|
@@ -871,6 +915,102 @@ export class RelayConnection {
|
|
|
871
915
|
);
|
|
872
916
|
}
|
|
873
917
|
|
|
918
|
+
/**
|
|
919
|
+
* Re-resolve caller trust after a mid-call verification/activation. Prefers
|
|
920
|
+
* the gateway verdict (authoritative right after the gateway updated the
|
|
921
|
+
* binding); falls back to local resolution on a missing/failed/unusable
|
|
922
|
+
* verdict so a blip never drops the call. Mirrors the setup path's
|
|
923
|
+
* verdict-first-with-fallback condition.
|
|
924
|
+
*/
|
|
925
|
+
private async resolveMidCallTrustContext(
|
|
926
|
+
assistantId: string,
|
|
927
|
+
fromNumber: string,
|
|
928
|
+
): Promise<TrustContext> {
|
|
929
|
+
const verdict = await getInboundTrustVerdict({
|
|
930
|
+
channelType: "phone",
|
|
931
|
+
actorExternalId: fromNumber,
|
|
932
|
+
});
|
|
933
|
+
|
|
934
|
+
// Only a MEMBERLESS unknown verdict is treated as a stale gateway view and
|
|
935
|
+
// falls back to local: the caller was just activated, and invite redemption
|
|
936
|
+
// writes the channel assistant-side, so the gateway may not see the member
|
|
937
|
+
// yet — local resolution has it. A MEMBERFUL unknown verdict (blocked/revoked
|
|
938
|
+
// member, carrying contactId/channelId) is honored so its deny ACL is
|
|
939
|
+
// enforced; falling back could lose the gateway's member status if local
|
|
940
|
+
// state is stale.
|
|
941
|
+
const memberlessUnknown =
|
|
942
|
+
verdict?.trustClass === "unknown" && !verdictHasMemberIdentity(verdict);
|
|
943
|
+
const usable =
|
|
944
|
+
verdict &&
|
|
945
|
+
!verdict.resolutionFailed &&
|
|
946
|
+
!verdictMemberUnresolvable(verdict) &&
|
|
947
|
+
!memberlessUnknown;
|
|
948
|
+
|
|
949
|
+
if (usable) {
|
|
950
|
+
return trustContextFromVerdict(verdict, {
|
|
951
|
+
sourceChannel: "phone",
|
|
952
|
+
conversationExternalId: fromNumber,
|
|
953
|
+
});
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
// Warm the phone-channel guardian-delivery cache before the SYNC
|
|
957
|
+
// resolveActorTrust fallback, which reads the IO-free per-channel snapshot
|
|
958
|
+
// that daemon startup leaves cold for `phone`. Read fresh: gateway-side
|
|
959
|
+
// binding writes don't invalidate the daemon cache, so a stale empty
|
|
960
|
+
// snapshot would otherwise survive the TTL and misclassify the guardian.
|
|
961
|
+
await getGuardianDeliveryFresh({ channelTypes: ["phone"] });
|
|
962
|
+
|
|
963
|
+
return toTrustContext(
|
|
964
|
+
resolveActorTrust({
|
|
965
|
+
assistantId,
|
|
966
|
+
sourceChannel: "phone",
|
|
967
|
+
conversationExternalId: fromNumber,
|
|
968
|
+
actorExternalId: fromNumber,
|
|
969
|
+
}),
|
|
970
|
+
fromNumber,
|
|
971
|
+
);
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
/**
|
|
975
|
+
* Re-resolve mid-call trust and install it on the controller, deferring any
|
|
976
|
+
* prompt that arrives during the async window. Guards the gap between
|
|
977
|
+
* connectionState flipping to "connected" and the upgraded context landing so
|
|
978
|
+
* a verified caller never starts a turn under the stale pre-verification
|
|
979
|
+
* trust. Clears the guard in a finally and flushes buffered prompts under the
|
|
980
|
+
* new context, so an IPC error can't wedge the call.
|
|
981
|
+
*/
|
|
982
|
+
private async reResolveAndApplyTrustContext(
|
|
983
|
+
assistantId: string,
|
|
984
|
+
fromNumber: string,
|
|
985
|
+
): Promise<void> {
|
|
986
|
+
if (!this.controller) return;
|
|
987
|
+
this.trustReResolving = true;
|
|
988
|
+
try {
|
|
989
|
+
const context = await this.resolveMidCallTrustContext(
|
|
990
|
+
assistantId,
|
|
991
|
+
fromNumber,
|
|
992
|
+
);
|
|
993
|
+
this.controller.setTrustContext(context);
|
|
994
|
+
} finally {
|
|
995
|
+
this.trustReResolving = false;
|
|
996
|
+
this.flushDeferredPrompts();
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
/**
|
|
1001
|
+
* Replay prompts buffered while trust was re-resolving. Runs after the
|
|
1002
|
+
* upgraded context is installed so deferred utterances are answered under the
|
|
1003
|
+
* correct trust.
|
|
1004
|
+
*/
|
|
1005
|
+
private flushDeferredPrompts(): void {
|
|
1006
|
+
if (this.trustReResolvePending.length === 0) return;
|
|
1007
|
+
const pending = this.trustReResolvePending;
|
|
1008
|
+
this.trustReResolvePending = [];
|
|
1009
|
+
for (const msg of pending) {
|
|
1010
|
+
void this.handlePrompt(msg);
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
|
|
874
1014
|
/**
|
|
875
1015
|
* Shared post-activation handoff for all trusted-contact success paths
|
|
876
1016
|
* (access-request approval, invite redemption, verification code).
|
|
@@ -878,7 +1018,7 @@ export class RelayConnection {
|
|
|
878
1018
|
* transition copy, and marks the next utterance as opening-ack so the
|
|
879
1019
|
* LLM continues naturally.
|
|
880
1020
|
*/
|
|
881
|
-
private continueCallAfterTrustedContactActivation(params: {
|
|
1021
|
+
private async continueCallAfterTrustedContactActivation(params: {
|
|
882
1022
|
assistantId: string;
|
|
883
1023
|
fromNumber: string;
|
|
884
1024
|
activationReason?:
|
|
@@ -893,26 +1033,25 @@ export class RelayConnection {
|
|
|
893
1033
|
* address.
|
|
894
1034
|
*/
|
|
895
1035
|
inviteeName?: string | null;
|
|
896
|
-
}): void {
|
|
1036
|
+
}): Promise<void> {
|
|
897
1037
|
const { assistantId, fromNumber } = params;
|
|
898
1038
|
|
|
899
1039
|
// Contact activation is handled by the gateway — the assistant no
|
|
900
1040
|
// longer writes contact/channel records on inbound voice calls.
|
|
901
1041
|
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
1042
|
+
// Reach connected and clear wait/verification flags before re-resolving
|
|
1043
|
+
// trust, so a prompt buffered during re-resolution flushes onto the
|
|
1044
|
+
// real-turn path, not the verification/wait branches.
|
|
1045
|
+
this.connectionState = "connected";
|
|
1046
|
+
this.verificationSessionActive = false;
|
|
1047
|
+
this.inviteRedemptionActive = false;
|
|
1048
|
+
this.accessRequestWaitActive = false;
|
|
1049
|
+
updateCallSession(this.callSessionId, { status: "in_progress" });
|
|
908
1050
|
|
|
909
1051
|
if (this.controller) {
|
|
910
|
-
this.
|
|
1052
|
+
await this.reResolveAndApplyTrustContext(assistantId, fromNumber);
|
|
911
1053
|
}
|
|
912
1054
|
|
|
913
|
-
this.connectionState = "connected";
|
|
914
|
-
updateCallSession(this.callSessionId, { status: "in_progress" });
|
|
915
|
-
|
|
916
1055
|
const guardianLabel = this.resolveGuardianLabel();
|
|
917
1056
|
let handoffText: string;
|
|
918
1057
|
|
|
@@ -1045,7 +1184,7 @@ export class RelayConnection {
|
|
|
1045
1184
|
const assistantId = this.verificationAssistantId;
|
|
1046
1185
|
const fromNumber = this.verificationFromNumber;
|
|
1047
1186
|
|
|
1048
|
-
const result = attemptVerificationCode({
|
|
1187
|
+
const result = await attemptVerificationCode({
|
|
1049
1188
|
verificationAssistantId: assistantId,
|
|
1050
1189
|
verificationFromNumber: fromNumber,
|
|
1051
1190
|
enteredCode,
|
|
@@ -1091,15 +1230,7 @@ export class RelayConnection {
|
|
|
1091
1230
|
|
|
1092
1231
|
// Update trust context on the controller so the LLM knows this is the guardian
|
|
1093
1232
|
if (this.controller) {
|
|
1094
|
-
|
|
1095
|
-
assistantId,
|
|
1096
|
-
sourceChannel: "phone",
|
|
1097
|
-
conversationExternalId: fromNumber,
|
|
1098
|
-
actorExternalId: fromNumber,
|
|
1099
|
-
});
|
|
1100
|
-
this.controller.setTrustContext(
|
|
1101
|
-
toTrustContext(verifiedActorTrust, fromNumber),
|
|
1102
|
-
);
|
|
1233
|
+
await this.reResolveAndApplyTrustContext(assistantId, fromNumber);
|
|
1103
1234
|
}
|
|
1104
1235
|
|
|
1105
1236
|
// Mark session as in-progress and transition to guardian conversation
|
|
@@ -1116,7 +1247,7 @@ export class RelayConnection {
|
|
|
1116
1247
|
);
|
|
1117
1248
|
}
|
|
1118
1249
|
} else if (result.verificationType === "trusted_contact") {
|
|
1119
|
-
this.continueCallAfterTrustedContactActivation({
|
|
1250
|
+
await this.continueCallAfterTrustedContactActivation({
|
|
1120
1251
|
assistantId,
|
|
1121
1252
|
fromNumber,
|
|
1122
1253
|
activationReason: "trusted_contact_verified",
|
|
@@ -1125,15 +1256,7 @@ export class RelayConnection {
|
|
|
1125
1256
|
// Inbound guardian verification: binding already handled above,
|
|
1126
1257
|
// proceed to normal call flow.
|
|
1127
1258
|
if (this.controller) {
|
|
1128
|
-
|
|
1129
|
-
assistantId,
|
|
1130
|
-
sourceChannel: "phone",
|
|
1131
|
-
conversationExternalId: fromNumber,
|
|
1132
|
-
actorExternalId: fromNumber,
|
|
1133
|
-
});
|
|
1134
|
-
this.controller.setTrustContext(
|
|
1135
|
-
toTrustContext(verifiedActorTrust, fromNumber),
|
|
1136
|
-
);
|
|
1259
|
+
await this.reResolveAndApplyTrustContext(assistantId, fromNumber);
|
|
1137
1260
|
this.startNormalCallFlow(this.controller, true);
|
|
1138
1261
|
}
|
|
1139
1262
|
}
|
|
@@ -1296,7 +1419,7 @@ export class RelayConnection {
|
|
|
1296
1419
|
* Creates a canonical access request, notifies the guardian, and
|
|
1297
1420
|
* enters the bounded wait loop for the guardian decision.
|
|
1298
1421
|
*/
|
|
1299
|
-
private handleNameCaptureResponse(callerName: string): void {
|
|
1422
|
+
private async handleNameCaptureResponse(callerName: string): Promise<void> {
|
|
1300
1423
|
if (!this.accessRequestAssistantId || !this.accessRequestFromNumber) {
|
|
1301
1424
|
return;
|
|
1302
1425
|
}
|
|
@@ -1317,7 +1440,7 @@ export class RelayConnection {
|
|
|
1317
1440
|
// Create canonical access request and notify the guardian, including
|
|
1318
1441
|
// the caller's spoken name and voice channel metadata.
|
|
1319
1442
|
try {
|
|
1320
|
-
const accessResult = notifyGuardianOfAccessRequest({
|
|
1443
|
+
const accessResult = await notifyGuardianOfAccessRequest({
|
|
1321
1444
|
canonicalAssistantId: this.accessRequestAssistantId,
|
|
1322
1445
|
sourceChannel: "phone",
|
|
1323
1446
|
conversationExternalId: this.accessRequestFromNumber,
|
|
@@ -1410,7 +1533,7 @@ export class RelayConnection {
|
|
|
1410
1533
|
}
|
|
1411
1534
|
|
|
1412
1535
|
if (request.status === "approved") {
|
|
1413
|
-
this.handleAccessRequestApproved();
|
|
1536
|
+
void this.handleAccessRequestApproved();
|
|
1414
1537
|
} else if (request.status === "denied") {
|
|
1415
1538
|
void this.handleAccessRequestDenied();
|
|
1416
1539
|
}
|
|
@@ -1462,7 +1585,7 @@ export class RelayConnection {
|
|
|
1462
1585
|
* Handle an approved access request: activate the caller as a trusted
|
|
1463
1586
|
* contact, update runtime context, and continue with normal call flow.
|
|
1464
1587
|
*/
|
|
1465
|
-
private handleAccessRequestApproved(): void {
|
|
1588
|
+
private async handleAccessRequestApproved(): Promise<void> {
|
|
1466
1589
|
this.clearAccessRequestWait();
|
|
1467
1590
|
|
|
1468
1591
|
const assistantId = this.accessRequestAssistantId!;
|
|
@@ -1480,7 +1603,7 @@ export class RelayConnection {
|
|
|
1480
1603
|
"Access request approved — caller activated and continuing call",
|
|
1481
1604
|
);
|
|
1482
1605
|
|
|
1483
|
-
this.continueCallAfterTrustedContactActivation({
|
|
1606
|
+
await this.continueCallAfterTrustedContactActivation({
|
|
1484
1607
|
assistantId,
|
|
1485
1608
|
fromNumber,
|
|
1486
1609
|
activationReason: "access_approved",
|
|
@@ -1688,7 +1811,7 @@ export class RelayConnection {
|
|
|
1688
1811
|
"Voice invite redemption succeeded",
|
|
1689
1812
|
);
|
|
1690
1813
|
|
|
1691
|
-
this.continueCallAfterTrustedContactActivation({
|
|
1814
|
+
await this.continueCallAfterTrustedContactActivation({
|
|
1692
1815
|
assistantId: this.inviteRedemptionAssistantId,
|
|
1693
1816
|
fromNumber: this.inviteRedemptionFromNumber,
|
|
1694
1817
|
activationReason: "invite_redeemed",
|
|
@@ -1731,15 +1854,20 @@ export class RelayConnection {
|
|
|
1731
1854
|
* Resolve a human-readable guardian label for voice wait copy.
|
|
1732
1855
|
* Delegates to the shared resolveGuardianName() which checks the
|
|
1733
1856
|
* guardian's per-user persona file (users/<slug>.md) first, then falls
|
|
1734
|
-
* back to
|
|
1857
|
+
* back to the primed gateway-binding displayName, then
|
|
1858
|
+
* DEFAULT_USER_REFERENCE.
|
|
1735
1859
|
*/
|
|
1736
1860
|
private resolveGuardianLabel(): string {
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
const guardianChannels = voiceGuardian ? null : listGuardianChannels();
|
|
1740
|
-
const guardianContact = voiceGuardian?.contact ?? guardianChannels?.contact;
|
|
1861
|
+
return resolveGuardianName(this.primedGuardianDisplayName);
|
|
1862
|
+
}
|
|
1741
1863
|
|
|
1742
|
-
|
|
1864
|
+
/**
|
|
1865
|
+
* Prime the guardian displayName from the gateway binding so the
|
|
1866
|
+
* synchronous wait-label path can read it without an IPC round-trip.
|
|
1867
|
+
*/
|
|
1868
|
+
private async primeGuardianDisplayName(): Promise<void> {
|
|
1869
|
+
const list = await getGuardianDelivery();
|
|
1870
|
+
this.primedGuardianDisplayName = voiceGuardianDisplayName(list);
|
|
1743
1871
|
}
|
|
1744
1872
|
|
|
1745
1873
|
/**
|
|
@@ -1917,6 +2045,15 @@ export class RelayConnection {
|
|
|
1917
2045
|
return;
|
|
1918
2046
|
}
|
|
1919
2047
|
|
|
2048
|
+
// Defer (don't drop) prompts while trust is being re-resolved mid-call so a
|
|
2049
|
+
// verified caller's first utterance runs under the upgraded context, not the
|
|
2050
|
+
// stale pre-verification one. flushDeferredPrompts replays them in order
|
|
2051
|
+
// once the new context lands.
|
|
2052
|
+
if (this.trustReResolving) {
|
|
2053
|
+
this.trustReResolvePending.push(msg);
|
|
2054
|
+
return;
|
|
2055
|
+
}
|
|
2056
|
+
|
|
1920
2057
|
// Prompts arriving before setup routing/ACL completes are dropped — never
|
|
1921
2058
|
// persisted or emitted — so a not-yet-authorized caller's speech can't be
|
|
1922
2059
|
// stored ahead of the admission floor / trust ACL decision.
|
|
@@ -1942,7 +2079,7 @@ export class RelayConnection {
|
|
|
1942
2079
|
{ callSessionId: this.callSessionId, callerName },
|
|
1943
2080
|
"Name captured from unknown inbound caller",
|
|
1944
2081
|
);
|
|
1945
|
-
this.handleNameCaptureResponse(callerName);
|
|
2082
|
+
await this.handleNameCaptureResponse(callerName);
|
|
1946
2083
|
return;
|
|
1947
2084
|
}
|
|
1948
2085
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* next — without performing any side effects itself.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import type { AdmissionPolicy } from "@vellumai/gateway-client";
|
|
9
|
+
import type { AdmissionPolicy, TrustVerdict } from "@vellumai/gateway-client";
|
|
10
10
|
|
|
11
11
|
import { getConfig } from "../config/loader.js";
|
|
12
12
|
import { getContact } from "../contacts/contact-store.js";
|
|
@@ -21,6 +21,10 @@ import {
|
|
|
21
21
|
type AdmissionPolicyResult,
|
|
22
22
|
enforceAdmissionPolicy,
|
|
23
23
|
} from "../runtime/routes/inbound-stages/admission-policy.js";
|
|
24
|
+
import {
|
|
25
|
+
actorTrustContextFromVerdict,
|
|
26
|
+
verdictMemberUnresolvable,
|
|
27
|
+
} from "../runtime/trust-verdict-consumer.js";
|
|
24
28
|
import { getLogger } from "../util/logger.js";
|
|
25
29
|
import type { CallSession } from "./types.js";
|
|
26
30
|
|
|
@@ -40,6 +44,12 @@ interface SetupContext {
|
|
|
40
44
|
* preserving all pre-admission behavior.
|
|
41
45
|
*/
|
|
42
46
|
admissionPolicy?: AdmissionPolicy | null;
|
|
47
|
+
/**
|
|
48
|
+
* Gateway-stamped caller trust verdict. When present and not
|
|
49
|
+
* `resolutionFailed`, the caller's trust is built from it; otherwise the
|
|
50
|
+
* router falls back to local resolution.
|
|
51
|
+
*/
|
|
52
|
+
verdict?: TrustVerdict | null;
|
|
43
53
|
}
|
|
44
54
|
|
|
45
55
|
// ── Setup outcomes ───────────────────────────────────────────────────
|
|
@@ -112,12 +122,32 @@ export function routeSetup(ctx: SetupContext): {
|
|
|
112
122
|
const isInbound = ctx.session?.initiatedFromConversationId == null;
|
|
113
123
|
const otherPartyNumber = isInbound ? ctx.from : ctx.to;
|
|
114
124
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
125
|
+
// Verdict-first: build caller trust from the gateway verdict when present.
|
|
126
|
+
// Voice falls back to local resolution on a missing/failed verdict so a
|
|
127
|
+
// gateway blip does not drop a known guardian's call — the deliberate
|
|
128
|
+
// difference from the fail-closed text path.
|
|
129
|
+
//
|
|
130
|
+
// A verdict that claims a member (contactId/channelId) but whose ACL can't be
|
|
131
|
+
// reassembled (malformed/mixed-version status·policy) also falls back to local
|
|
132
|
+
// resolution, so voice never trusts a member it cannot ACL-check. A real
|
|
133
|
+
// stranger verdict (no member identity) still takes the verdict path —
|
|
134
|
+
// memberRecord null is correct there.
|
|
135
|
+
const usable =
|
|
136
|
+
ctx.verdict &&
|
|
137
|
+
!ctx.verdict.resolutionFailed &&
|
|
138
|
+
!verdictMemberUnresolvable(ctx.verdict);
|
|
139
|
+
const actorTrust = usable
|
|
140
|
+
? actorTrustContextFromVerdict(ctx.verdict!, {
|
|
141
|
+
sourceChannel: "phone",
|
|
142
|
+
conversationExternalId: otherPartyNumber,
|
|
143
|
+
actorDisplayName: undefined,
|
|
144
|
+
})
|
|
145
|
+
: resolveActorTrust({
|
|
146
|
+
assistantId,
|
|
147
|
+
sourceChannel: "phone",
|
|
148
|
+
conversationExternalId: otherPartyNumber,
|
|
149
|
+
actorExternalId: otherPartyNumber || undefined,
|
|
150
|
+
});
|
|
121
151
|
|
|
122
152
|
const resolved: SetupResolved = {
|
|
123
153
|
assistantId,
|
|
@@ -216,7 +246,7 @@ export function routeSetup(ctx: SetupContext): {
|
|
|
216
246
|
? enforceAdmissionPolicy({
|
|
217
247
|
sourceChannel: "phone",
|
|
218
248
|
trustClass: actorTrust.trustClass,
|
|
219
|
-
memberStatus: actorTrust.memberRecord?.
|
|
249
|
+
memberStatus: actorTrust.memberRecord?.status,
|
|
220
250
|
policy: ctx.admissionPolicy!,
|
|
221
251
|
})
|
|
222
252
|
: ({ admitted: true } as const);
|
|
@@ -253,7 +283,7 @@ export function routeSetup(ctx: SetupContext): {
|
|
|
253
283
|
!pendingChallenge
|
|
254
284
|
) {
|
|
255
285
|
// Check for blocked caller
|
|
256
|
-
if (actorTrust.memberRecord?.
|
|
286
|
+
if (actorTrust.memberRecord?.status === "blocked") {
|
|
257
287
|
log.info(
|
|
258
288
|
{
|
|
259
289
|
callSessionId: ctx.callSessionId,
|
|
@@ -336,14 +366,14 @@ export function routeSetup(ctx: SetupContext): {
|
|
|
336
366
|
// gateway and assistant DBs) still get useful guidance instead of
|
|
337
367
|
// the "I don't recognize this number" name-capture script.
|
|
338
368
|
const unverifiedStatuses = new Set(["unverified", "pending"]);
|
|
339
|
-
const
|
|
340
|
-
if (
|
|
369
|
+
const member = actorTrust.memberRecord;
|
|
370
|
+
if (member && unverifiedStatuses.has(member.status)) {
|
|
341
371
|
log.info(
|
|
342
372
|
{
|
|
343
373
|
callSessionId: ctx.callSessionId,
|
|
344
374
|
from: ctx.from,
|
|
345
|
-
channelId:
|
|
346
|
-
channelStatus:
|
|
375
|
+
channelId: member.channel.id,
|
|
376
|
+
channelStatus: member.status,
|
|
347
377
|
},
|
|
348
378
|
"Inbound voice ACL: known but unverified caller — returning verification guidance",
|
|
349
379
|
);
|
|
@@ -352,8 +382,8 @@ export function routeSetup(ctx: SetupContext): {
|
|
|
352
382
|
action: "unverified_caller",
|
|
353
383
|
assistantId,
|
|
354
384
|
fromNumber: ctx.from,
|
|
355
|
-
displayName:
|
|
356
|
-
isGuardian:
|
|
385
|
+
displayName: member.contact.displayName,
|
|
386
|
+
isGuardian: member.role === "guardian",
|
|
357
387
|
},
|
|
358
388
|
resolved,
|
|
359
389
|
};
|
|
@@ -379,7 +409,7 @@ export function routeSetup(ctx: SetupContext): {
|
|
|
379
409
|
}
|
|
380
410
|
|
|
381
411
|
// Members with policy: 'deny'
|
|
382
|
-
if (actorTrust.memberRecord?.
|
|
412
|
+
if (actorTrust.memberRecord?.policy === "deny") {
|
|
383
413
|
log.info(
|
|
384
414
|
{
|
|
385
415
|
callSessionId: ctx.callSessionId,
|
|
@@ -400,7 +430,7 @@ export function routeSetup(ctx: SetupContext): {
|
|
|
400
430
|
}
|
|
401
431
|
|
|
402
432
|
// Members with policy: 'escalate' — live calls can't wait for approval
|
|
403
|
-
if (actorTrust.memberRecord?.
|
|
433
|
+
if (actorTrust.memberRecord?.policy === "escalate") {
|
|
404
434
|
log.info(
|
|
405
435
|
{
|
|
406
436
|
callSessionId: ctx.callSessionId,
|