@vellumai/assistant 0.10.4 → 0.10.5-dev.202607022329.d89bf2f
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +94 -91
- package/Dockerfile +5 -16
- package/README.md +7 -10
- package/bun.lock +0 -4
- package/docs/architecture/security.md +20 -20
- package/docs/stt-provider-onboarding.md +4 -5
- package/docs/trusted-contact-access.md +7 -7
- package/eslint-rules/cli-no-daemon-internals.js +4 -0
- package/eslint.config.mjs +7 -1
- package/knip.json +0 -1
- package/node_modules/@vellumai/gateway-client/src/__tests__/contact-read-contracts.test.ts +36 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/invite-contract.test.ts +233 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +40 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +20 -8
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +10 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +33 -0
- package/node_modules/@vellumai/gateway-client/src/invite-contract.ts +216 -0
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +91 -0
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +39 -3
- package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +0 -8
- package/node_modules/@vellumai/service-contracts/src/__tests__/package-boundary.test.ts +1 -5
- package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +3 -14
- package/openapi.yaml +1073 -225
- package/package.json +1 -4
- package/scripts/test.sh +35 -13
- package/src/__tests__/access-request-seed-content-blocks.test.ts +60 -4
- package/src/__tests__/acp-session.test.ts +4 -1
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +0 -6
- package/src/__tests__/add-message-preassigned-id.test.ts +56 -0
- package/src/__tests__/agent-loop-set-system-prompt.test.ts +139 -0
- package/src/__tests__/app-conversation-ids-backfill.test.ts +3 -0
- package/src/__tests__/app-source-watcher.test.ts +11 -0
- package/src/__tests__/approval-interception-trust-gates.test.ts +148 -3
- package/src/__tests__/assistant-attachments.test.ts +62 -4
- package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -1
- package/src/__tests__/attachments-store-heic-normalize.test.ts +230 -0
- package/src/__tests__/attachments-store.test.ts +3 -0
- package/src/__tests__/background-shell-bash.test.ts +34 -0
- package/src/__tests__/background-shell-host-bash.test.ts +12 -0
- package/src/__tests__/background-tool-registry.test.ts +97 -0
- package/src/__tests__/background-tool-routes.test.ts +72 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +2 -1
- package/src/__tests__/btw-routes.test.ts +57 -3
- package/src/__tests__/call-controller.test.ts +474 -84
- package/src/__tests__/call-domain.test.ts +48 -1
- package/src/__tests__/call-pointer-messages.test.ts +57 -19
- package/src/__tests__/call-pointer-no-hardcoded-copy.guard.test.ts +2 -6
- package/src/__tests__/call-routes-http.test.ts +15 -14
- package/src/__tests__/call-setup-flow-invite.test.ts +568 -0
- package/src/__tests__/call-setup-flow-midcall-trust.test.ts +231 -0
- package/src/__tests__/call-setup-flow-name-capture.test.ts +754 -0
- package/src/__tests__/call-setup-flow-verification.test.ts +925 -0
- package/src/__tests__/call-setup-flow.test.ts +311 -0
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +0 -1
- package/src/__tests__/channel-guardian.test.ts +4 -7
- package/src/__tests__/channel-readiness-service.test.ts +0 -6
- package/src/__tests__/channel-readiness-slack-remote.test.ts +0 -4
- package/src/__tests__/channel-retry-sweep.test.ts +76 -64
- package/src/__tests__/channel-setup-panel-ack.test.ts +184 -0
- package/src/__tests__/clear-all-lexical.test.ts +90 -0
- package/src/__tests__/compactor-media-strip.test.ts +177 -0
- package/src/__tests__/config-loader-backfill.test.ts +5 -5
- package/src/__tests__/config-schema.test.ts +17 -0
- package/src/__tests__/contact-store-interaction-info.test.ts +27 -70
- package/src/__tests__/contacts-relay-reads.test.ts +188 -23
- package/src/__tests__/contacts-tools.test.ts +42 -1
- package/src/__tests__/contacts-write.test.ts +181 -0
- package/src/__tests__/context-search-conversations-source.test.ts +220 -81
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop.test.ts +39 -0
- package/src/__tests__/conversation-analysis-routes.test.ts +1 -1
- package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -0
- package/src/__tests__/conversation-clear-safety.test.ts +0 -1
- package/src/__tests__/conversation-crud-enabled-plugins.test.ts +60 -0
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -1
- package/src/__tests__/conversation-disk-view.test.ts +1 -0
- package/src/__tests__/conversation-enabledplugins-route.test.ts +184 -0
- package/src/__tests__/conversation-error.test.ts +0 -18
- package/src/__tests__/conversation-fork-crud.test.ts +67 -0
- package/src/__tests__/conversation-history-web-search.test.ts +7 -137
- package/src/__tests__/conversation-initial-prompt.test.ts +110 -0
- package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +191 -0
- package/src/__tests__/conversation-process-callsite.test.ts +37 -0
- package/src/__tests__/conversation-queue.test.ts +149 -0
- package/src/__tests__/conversation-routes-enabled-plugins.test.ts +392 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +84 -0
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +407 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +36 -16
- package/src/__tests__/conversation-skill-tools.test.ts +73 -0
- package/src/__tests__/conversation-wipe.test.ts +20 -5
- package/src/__tests__/credential-prompt-route.test.ts +69 -0
- package/src/__tests__/credential-security-invariants.test.ts +1 -3
- package/src/__tests__/db-drop-messages-fts.test.ts +115 -0
- package/src/__tests__/deterministic-verification-control-plane.test.ts +1 -62
- package/src/__tests__/edit-propagation.test.ts +56 -2
- package/src/__tests__/empty-state-greeting-cache.test.ts +9 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +15 -110
- package/src/__tests__/guardian-expiry-notifier.test.ts +1 -0
- package/src/__tests__/guardian-question-mode.test.ts +57 -0
- package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -1
- package/src/__tests__/guardian-wait-controller.test.ts +619 -0
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +33 -2
- package/src/__tests__/heic-fixture.ts +55 -0
- package/src/__tests__/helpers/seed-contact-channel.ts +0 -2
- package/src/__tests__/http-conversation-lineage.test.ts +6 -1
- package/src/__tests__/image-conversion.test.ts +170 -0
- package/src/__tests__/inbound-invite-redemption.test.ts +72 -341
- package/src/__tests__/introduction-card-resolver.test.ts +354 -0
- package/src/__tests__/invite-redeemed-ipc.test.ts +97 -0
- package/src/__tests__/invite-routes-http.test.ts +246 -420
- package/src/__tests__/job-handler-registration-guard.test.ts +104 -0
- package/src/__tests__/lexical-index-dual-write.test.ts +426 -0
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +2 -2
- package/src/__tests__/list-messages-attachments.test.ts +159 -0
- package/src/__tests__/list-messages-background-tool-completion.test.ts +141 -0
- package/src/__tests__/list-messages-queued.test.ts +25 -0
- package/src/__tests__/managed-store.test.ts +129 -1
- package/src/__tests__/media-stream-audio-transcode.test.ts +113 -0
- package/src/__tests__/media-stream-output.test.ts +350 -19
- package/src/__tests__/media-stream-server-integration.test.ts +943 -169
- package/src/__tests__/media-stream-stt-session.test.ts +498 -1
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +2 -2
- package/src/__tests__/model-intents.test.ts +1 -1
- package/src/__tests__/mtime-cache.test.ts +19 -0
- package/src/__tests__/non-member-access-request.test.ts +349 -3
- package/src/__tests__/notification-decision-fallback.test.ts +104 -8
- package/src/__tests__/notification-decision-strategy.test.ts +57 -8
- package/src/__tests__/onboarding-template-contract.test.ts +27 -43
- package/src/__tests__/openai-provider.test.ts +33 -0
- package/src/__tests__/openai-responses-provider.test.ts +40 -0
- package/src/__tests__/persistence-layering-guard.test.ts +29 -20
- package/src/__tests__/persona-resolver.test.ts +56 -2
- package/src/__tests__/personal-memory-auth-bypass.test.ts +62 -0
- package/src/__tests__/phone.test.ts +1 -15
- package/src/__tests__/plugin-bootstrap.test.ts +25 -196
- package/src/__tests__/plugin-disabled-state.test.ts +33 -0
- package/src/__tests__/plugin-effective-enabled-set.test.ts +227 -0
- package/src/__tests__/plugin-event-hub-facade.test.ts +323 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +156 -42
- package/src/__tests__/plugin-injector-contribution.test.ts +4 -20
- package/src/__tests__/plugin-pipeline.test.ts +63 -1
- package/src/__tests__/plugin-route-contribution.test.ts +62 -115
- package/src/__tests__/plugin-tool-contribution.test.ts +0 -22
- package/src/__tests__/plugin-types.test.ts +0 -1
- package/src/__tests__/pointer-conversation-trust.test.ts +38 -6
- package/src/__tests__/pre-model-call-sanitize.test.ts +1 -1
- package/src/__tests__/prune-old-tool-invocations-job.test.ts +97 -0
- package/src/__tests__/public-ingress-urls.test.ts +0 -48
- package/src/__tests__/qdrant-collection-migration.test.ts +145 -2
- package/src/__tests__/reaction-intercept-member-verdict-warm.test.ts +0 -1
- package/src/__tests__/resolve-trust-class.test.ts +28 -10
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +137 -0
- package/src/__tests__/schedule-retry.test.ts +38 -14
- package/src/__tests__/schedule-routes-workflow-validation.test.ts +3 -3
- package/src/__tests__/schedule-routes.test.ts +14 -6
- package/src/__tests__/schedule-store.test.ts +3 -1
- package/src/__tests__/scheduler-disk-pressure.test.ts +17 -6
- package/src/__tests__/scheduler-recurrence.test.ts +57 -107
- package/src/__tests__/scheduler-reuse-conversation.test.ts +51 -46
- package/src/__tests__/scheduler-wake.test.ts +13 -23
- package/src/__tests__/scheduler-worker-standdown.test.ts +220 -0
- package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -1
- package/src/__tests__/shell-observability.test.ts +1 -0
- package/src/__tests__/skill-boundary-guard.test.ts +3 -4
- package/src/__tests__/skill-load-plugin-scope.test.ts +238 -0
- package/src/__tests__/skill-projection-feature-flag.test.ts +2 -0
- package/src/__tests__/skill-script-runner-host.test.ts +53 -0
- package/src/__tests__/skill-script-runner-sandbox.test.ts +5 -2
- package/src/__tests__/skill-tool-factory.test.ts +73 -1
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +37 -14
- package/src/__tests__/slack-inbound-verification.test.ts +36 -0
- package/src/__tests__/slack-notification-approval-card.test.ts +89 -2
- package/src/__tests__/slack-reaction-canonical-approval.test.ts +51 -1
- package/src/__tests__/stt-hints.test.ts +2 -256
- package/src/__tests__/subagent-allowlist-validation.test.ts +47 -0
- package/src/__tests__/subagent-call-site-routing.test.ts +72 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +14 -2
- package/src/__tests__/subagent-persistence.test.ts +122 -0
- package/src/__tests__/subagent-spawn-and-await.test.ts +1 -0
- package/src/__tests__/subagent-terminal-message.test.ts +99 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +78 -1
- package/src/__tests__/system-prompt.test.ts +17 -118
- package/src/__tests__/task-scheduler.test.ts +68 -89
- package/src/__tests__/telephony-credential-preflight.test.ts +312 -0
- package/src/__tests__/telephony-tts-guard.test.ts +538 -0
- package/src/__tests__/title-generate-hook.test.ts +16 -0
- package/src/__tests__/tool-approval-handler.test.ts +87 -1
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +45 -20
- package/src/__tests__/tool-grant-request-escalation.test.ts +39 -0
- package/src/__tests__/trust-context-guards.test.ts +21 -10
- package/src/__tests__/trusted-contact-multichannel.test.ts +4 -0
- package/src/__tests__/twilio-provider.test.ts +17 -17
- package/src/__tests__/twilio-routes-twiml.test.ts +6 -543
- package/src/__tests__/twilio-routes.test.ts +257 -387
- package/src/__tests__/twilio-validation.test.ts +1 -1
- package/src/__tests__/unified-turn-context-client-os.test.ts +45 -0
- package/src/__tests__/usage-cache-backfill-migration.test.ts +5 -0
- package/src/__tests__/voice-approval-resolver-relay.test.ts +150 -0
- package/src/__tests__/voice-ingress-preflight.test.ts +61 -0
- package/src/__tests__/voice-quality.test.ts +2 -2
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +1 -7
- package/src/__tests__/voice-session-bridge-processing-wait.test.ts +27 -0
- package/src/__tests__/voice-session-bridge.test.ts +1 -10
- package/src/__tests__/workspace-git-service.test.ts +1 -1
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +1 -0
- package/src/__tests__/workspace-migration-118-seed-now-md.test.ts +120 -0
- package/src/__tests__/workspace-migration-120-revise-onboarding-threads.test.ts +175 -0
- package/src/__tests__/workspace-migration-121-seed-default-user-guardrails.test.ts +118 -0
- package/src/__tests__/workspace-migration-122-relocate-default-user-boundary.test.ts +119 -0
- package/src/__tests__/workspace-migration-123-swap-quality-profile-to-fable.test.ts +191 -0
- package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +235 -241
- package/src/acp/__tests__/prepare-agent-env.test.ts +0 -97
- package/src/acp/__tests__/session-manager-persistence.test.ts +2 -0
- package/src/acp/__tests__/session-manager-resume.test.ts +8 -0
- package/src/acp/__tests__/session-manager-usage.test.ts +6 -0
- package/src/acp/__tests__/session-manager.test.ts +6 -0
- package/src/acp/agent-process.test.ts +116 -0
- package/src/acp/agent-process.ts +71 -0
- package/src/acp/auto-install.ts +12 -8
- package/src/acp/failure-error.test.ts +109 -0
- package/src/acp/failure-error.ts +111 -0
- package/src/acp/prepare-agent-env.ts +0 -12
- package/src/acp/resolve-agent.test.ts +6 -45
- package/src/acp/resolve-agent.ts +2 -4
- package/src/acp/session-manager.test.ts +312 -0
- package/src/acp/session-manager.ts +102 -46
- package/src/agent/ax-tree-compaction.test.ts +4 -1
- package/src/agent/image-optimize.ts +17 -127
- package/src/agent/loop.ts +45 -192
- package/src/api/events/background-tool-completed.test.ts +51 -0
- package/src/api/events/background-tool-completed.ts +29 -0
- package/src/api/events/background-tool-started.test.ts +36 -0
- package/src/api/events/background-tool-started.ts +28 -0
- package/src/api/events/conversation-error.ts +0 -1
- package/src/api/events/open-panel.ts +33 -0
- package/src/api/events/subagent-status-changed.ts +4 -1
- package/src/api/index.ts +19 -0
- package/src/api/responses/conversation-message.ts +34 -0
- package/src/approvals/guardian-decision-primitive.ts +74 -24
- package/src/approvals/guardian-request-resolvers.ts +450 -122
- package/src/apps/app-store.ts +1 -0
- package/src/apps/shared-app-links-store.ts +1 -0
- package/src/avatar/identity-avatar.ts +3 -7
- package/src/background-wake/wake-intent-hooks.test.ts +1 -1
- package/src/calls/__tests__/fish-audio-client.test.ts +73 -0
- package/src/calls/__tests__/gateway-invite-reader.test.ts +170 -0
- package/src/calls/__tests__/relay-setup-router.test.ts +126 -102
- package/src/calls/call-controller.ts +134 -48
- package/src/calls/call-domain.ts +18 -42
- package/src/calls/call-pointer-messages.ts +51 -67
- package/src/calls/call-setup-flow-types.ts +76 -0
- package/src/calls/call-setup-flow.ts +1743 -0
- package/src/calls/call-speech-output.ts +87 -23
- package/src/calls/call-store.ts +4 -0
- package/src/calls/call-transport.ts +22 -36
- package/src/calls/fish-audio-client.ts +3 -0
- package/src/calls/gateway-invite-reader.ts +98 -0
- package/src/calls/guardian-wait-controller.ts +451 -0
- package/src/calls/media-stream-audio-transcode.ts +82 -2
- package/src/calls/media-stream-output.ts +142 -36
- package/src/calls/media-stream-server.ts +297 -178
- package/src/calls/media-stream-stt-session.ts +393 -50
- package/src/calls/media-turn-detector.ts +4 -6
- package/src/calls/relay-access-wait.ts +3 -4
- package/src/calls/relay-setup-router.ts +22 -43
- package/src/calls/relay-verification.ts +17 -24
- package/src/calls/resolve-call-tts-provider.ts +96 -29
- package/src/calls/stt-hints.ts +24 -87
- package/src/calls/telephony-credential-preflight.ts +159 -0
- package/src/calls/telephony-tts-capability.ts +183 -0
- package/src/calls/tts-call-strategy.ts +18 -20
- package/src/calls/twilio-provider.ts +3 -2
- package/src/calls/twilio-routes.ts +47 -351
- package/src/calls/types.ts +5 -3
- package/src/calls/voice-ingress-preflight.ts +9 -0
- package/src/calls/voice-quality.ts +13 -18
- package/src/calls/voice-session-bridge.ts +25 -35
- package/src/channels/__tests__/types.test.ts +28 -0
- package/src/channels/channel-verification-sessions.ts +7 -2
- package/src/channels/config.ts +0 -42
- package/src/channels/slack-thread-store.ts +12 -0
- package/src/channels/types.ts +23 -0
- package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -1
- package/src/cli/commands/__tests__/schedules.test.ts +83 -34
- package/src/cli/commands/__tests__/status.test.ts +42 -2
- package/src/cli/commands/contacts.ts +2 -2
- package/src/cli/commands/credentials.ts +17 -0
- package/src/cli/commands/monitoring.ts +191 -0
- package/src/cli/commands/schedules-worker.ts +175 -0
- package/src/cli/commands/schedules.ts +169 -43
- package/src/cli/commands/status.ts +12 -1
- package/src/cli/commands/tools.ts +5 -1
- package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +1 -0
- package/src/cli/lib/__tests__/search-plugins.test.ts +29 -1
- package/src/cli/lib/__tests__/toggle-plugin.test.ts +7 -0
- package/src/cli/lib/search-plugins.ts +6 -0
- package/src/cli/lib/toggle-plugin.ts +21 -2
- package/src/cli/program.ts +3 -1
- package/src/config/__tests__/deployment-context-defaults.test.ts +23 -0
- package/src/config/acp-defaults.test.ts +0 -10
- package/src/config/acp-defaults.ts +0 -6
- package/src/config/bundled-skills/acp/SKILL.md +13 -45
- package/src/config/bundled-skills/acp/TOOLS.json +3 -3
- package/src/config/bundled-skills/app-builder/SKILL.md +3 -3
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +9 -9
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +1 -1
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +1 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +9 -9
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +10 -7
- package/src/config/bundled-skills/skill-management/TOOLS.json +10 -0
- package/src/config/call-site-defaults.ts +0 -2
- package/src/config/feature-flag-registry.json +16 -8
- package/src/config/loader.ts +11 -0
- package/src/config/schema.ts +9 -1
- package/src/config/schemas/__tests__/memory-v2.test.ts +2 -2
- package/src/config/schemas/__tests__/memory-v3.test.ts +64 -0
- package/src/config/schemas/call-site-catalog.ts +0 -12
- package/src/config/schemas/calls.ts +8 -0
- package/src/config/schemas/elevenlabs.ts +1 -1
- package/src/config/schemas/llm.ts +0 -2
- package/src/config/schemas/memory-v2.ts +1 -1
- package/src/config/schemas/memory-v3.ts +82 -0
- package/src/config/schemas/monitoring.ts +61 -0
- package/src/config/schemas/schedules.ts +35 -0
- package/src/config/seed-inference-profiles.ts +2 -2
- package/src/config/skills-plugin-filter.test.ts +96 -0
- package/src/config/skills.ts +26 -0
- package/src/contacts/__tests__/member-write-relay.test.ts +156 -4
- package/src/contacts/canonical-guardian-store.ts +5 -0
- package/src/contacts/contact-store.ts +81 -35
- package/src/contacts/contacts-write.ts +50 -25
- package/src/contacts/member-write-relay.ts +115 -31
- package/src/contacts/types.ts +0 -8
- package/src/context/compactor.ts +29 -15
- package/src/context/outbound-sanitize.ts +202 -0
- package/src/daemon/__tests__/abort-null-controller.test.ts +167 -0
- package/src/daemon/__tests__/conversation-tool-setup-plugin-scope.test.ts +122 -0
- package/src/daemon/__tests__/embedding-reconcile.test.ts +99 -16
- package/src/daemon/__tests__/wake-conversation-ops-completion.test.ts +107 -0
- package/src/daemon/abort-watchdog.ts +7 -0
- package/src/daemon/app-source-watcher.ts +9 -0
- package/src/daemon/assistant-attachments.ts +42 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +256 -147
- package/src/daemon/conversation-agent-loop.ts +61 -68
- package/src/daemon/conversation-error.ts +1 -15
- package/src/daemon/conversation-history.ts +32 -236
- package/src/daemon/conversation-initial-prompt.ts +77 -0
- package/src/daemon/conversation-lifecycle.ts +25 -1
- package/src/daemon/conversation-messaging.ts +2 -2
- package/src/daemon/conversation-plugin-scope.ts +38 -0
- package/src/daemon/conversation-process.ts +50 -14
- package/src/daemon/conversation-runtime-assembly.ts +36 -6
- package/src/daemon/conversation-skill-tools.ts +19 -3
- package/src/daemon/conversation-store.ts +3 -3
- package/src/daemon/conversation-surfaces.ts +171 -0
- package/src/daemon/conversation-tool-setup.test.ts +95 -0
- package/src/daemon/conversation-tool-setup.ts +116 -1
- package/src/daemon/conversation-turn-finalize.ts +211 -0
- package/src/daemon/conversation.ts +92 -1
- package/src/daemon/disk-pressure-policy.ts +2 -1
- package/src/daemon/event-loop-watchdog.ts +22 -6
- package/src/daemon/external-plugins-bootstrap.ts +47 -134
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +1 -1
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +26 -14
- package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +27 -14
- package/src/daemon/handlers/__tests__/config-channels.test.ts +0 -5
- package/src/daemon/handlers/config-a2a.ts +7 -14
- package/src/daemon/handlers/config-channels.ts +2 -10
- package/src/daemon/handlers/conversation-history.ts +3 -1
- package/src/daemon/handlers/conversations.ts +0 -52
- package/src/daemon/handlers/shared.ts +4 -24
- package/src/daemon/handlers/skills.ts +4 -1
- package/src/daemon/host-cu-proxy.ts +1 -1
- package/src/daemon/lifecycle.ts +59 -472
- package/src/daemon/message-protocol.ts +3 -3
- package/src/daemon/message-provenance.ts +12 -14
- package/src/daemon/message-types/background-tools.ts +28 -0
- package/src/daemon/message-types/contacts.ts +2 -10
- package/src/daemon/message-types/conversations.ts +10 -0
- package/src/daemon/message-types/integrations.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +1 -0
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/pointer-conversation-trust.ts +23 -9
- package/src/daemon/pointer-turn-runner.ts +174 -0
- package/src/daemon/providers-setup.ts +16 -0
- package/src/daemon/shutdown-handlers.ts +139 -47
- package/src/daemon/skill-memory-refresh.ts +2 -2
- package/src/daemon/sqlite-corruption-watchdog.test.ts +217 -0
- package/src/daemon/sqlite-corruption-watchdog.ts +155 -0
- package/src/daemon/tool-setup-types.ts +8 -0
- package/src/daemon/trust-context.ts +21 -6
- package/src/daemon/turn-latency-tracker.test.ts +93 -0
- package/src/daemon/turn-latency-tracker.ts +38 -0
- package/src/daemon/wake-conversation-ops.ts +10 -8
- package/src/documents/document-comments-store.test.ts +7 -1
- package/src/documents/document-comments-store.ts +8 -0
- package/src/documents/document-store.ts +15 -0
- package/src/export/__tests__/transcript-formatter.test.ts +11 -0
- package/src/export/transcript-formatter.ts +49 -67
- package/src/home/__tests__/feed-writer.test.ts +247 -1
- package/src/home/conversation-starter-checkpoints.ts +1 -0
- package/src/home/feed-writer.ts +61 -0
- package/src/home/job-handlers/conversation-starters.ts +1 -0
- package/src/hooks/hook-loader.ts +12 -0
- package/src/hooks/registry.ts +32 -4
- package/src/inbound/public-ingress-urls.ts +0 -17
- package/src/ipc/__tests__/contacts-info-ipc.test.ts +285 -0
- package/src/ipc/assistant-server.ts +28 -7
- package/src/ipc/routes/__tests__/contacts-mirror-apply-atomicity.test.ts +62 -0
- package/src/ipc/routes/__tests__/contacts-mirror-apply.test.ts +272 -0
- package/src/ipc/routes/__tests__/contacts-mirror-ipc-routes.test.ts +322 -0
- package/src/ipc/routes/__tests__/invite-ipc-routes.test.ts +60 -4
- package/src/ipc/routes/contacts-info-ipc-routes.ts +239 -0
- package/src/ipc/routes/contacts-mirror-ipc-routes.ts +202 -0
- package/src/ipc/routes/db-proxy.ts +5 -2
- package/src/ipc/routes/invite-ipc-routes.ts +53 -39
- package/src/jobs/worker.ts +9 -2
- package/src/live-voice/__tests__/live-voice-archive.test.ts +10 -1
- package/src/live-voice/live-voice-archive.ts +5 -0
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +22 -6
- package/src/messaging/providers/channel-transport.ts +6 -0
- package/src/messaging/providers/index.ts +3 -0
- package/src/messaging/providers/slack/api.test.ts +49 -1
- package/src/messaging/providers/slack/api.ts +110 -0
- package/src/messaging/providers/slack/send.test.ts +85 -0
- package/src/messaging/providers/slack/send.ts +100 -28
- package/src/messaging/providers/slack/transport.ts +7 -13
- package/src/messaging/providers/whatsapp/send.ts +29 -9
- package/src/monitoring/__tests__/control.test.ts +235 -0
- package/src/monitoring/__tests__/sample-ring-buffer.test.ts +96 -0
- package/src/monitoring/control.ts +105 -0
- package/src/monitoring/resource-sampler.ts +258 -0
- package/src/monitoring/sample-ring-buffer.ts +108 -0
- package/src/monitoring/worker.ts +94 -0
- package/src/notifications/README.md +1 -1
- package/src/notifications/access-request-copy.ts +94 -23
- package/src/notifications/adapters/slack.ts +89 -21
- package/src/notifications/approval-card-builder.ts +33 -18
- package/src/notifications/approval-card-data.ts +48 -15
- package/src/notifications/broadcaster.ts +25 -16
- package/src/notifications/decision-engine.ts +131 -32
- package/src/notifications/guardian-question-mode.ts +58 -10
- package/src/permissions/approval-policy.ts +8 -1
- package/src/permissions/checker.ts +2 -0
- package/src/permissions/gateway-threshold-reader.ts +7 -6
- package/src/permissions/ipc-risk-types.ts +1 -0
- package/src/permissions/secret-prompter.ts +11 -3
- package/src/permissions/types.ts +2 -2
- package/src/persistence/__tests__/conversation-queries-search.test.ts +397 -0
- package/src/persistence/__tests__/conversation-search-lexical.test.ts +103 -0
- package/src/persistence/__tests__/jobs-worker-memory-disabled.test.ts +95 -0
- package/src/persistence/__tests__/slow-query-log.test.ts +266 -0
- package/src/persistence/__tests__/slow-sync-log.test.ts +155 -0
- package/src/persistence/a2a-invite-store.ts +205 -0
- package/src/persistence/attachments-store.ts +94 -10
- package/src/persistence/checkpoints.ts +45 -0
- package/src/persistence/conversation-crud.ts +453 -260
- package/src/persistence/conversation-display-order-migration.ts +8 -2
- package/src/persistence/conversation-group-migration.test.ts +8 -0
- package/src/persistence/conversation-group-migration.ts +9 -0
- package/src/persistence/conversation-queries.ts +244 -125
- package/src/persistence/conversation-row-batch-delete.ts +9 -5
- package/src/persistence/conversation-search-lexical.ts +49 -0
- package/src/persistence/db-async-query.ts +42 -0
- package/src/persistence/db-connection.ts +13 -0
- package/src/persistence/delivery-channels.ts +0 -82
- package/src/persistence/delivery-crud.ts +27 -6
- package/src/persistence/embeddings/__tests__/embedding-identity.test.ts +18 -5
- package/src/persistence/embeddings/__tests__/messages-lexical-index.test.ts +334 -0
- package/src/persistence/embeddings/embedding-identity.ts +17 -5
- package/src/persistence/embeddings/embedding-runtime-manager.ts +31 -0
- package/src/persistence/embeddings/messages-lexical-index.ts +396 -0
- package/src/persistence/embeddings/qdrant-client.ts +81 -5
- package/src/persistence/group-crud.ts +13 -1
- package/src/persistence/job-handlers/__tests__/message-lexical-backfill.test.ts +506 -0
- package/src/persistence/job-handlers/__tests__/message-lexical-enqueue.test.ts +164 -0
- package/src/persistence/job-handlers/__tests__/message-lexical.test.ts +259 -0
- package/src/persistence/job-handlers/cleanup.ts +57 -9
- package/src/persistence/job-handlers/message-lexical-backfill.ts +187 -0
- package/src/persistence/job-handlers/message-lexical.ts +251 -0
- package/src/persistence/jobs-store.ts +102 -8
- package/src/persistence/jobs-worker.ts +68 -28
- package/src/persistence/llm-request-log-store.ts +35 -19
- package/src/persistence/llm-usage-store.ts +11 -0
- package/src/persistence/memory-lifecycle-hooks.test.ts +65 -0
- package/src/persistence/memory-lifecycle-hooks.ts +55 -1
- package/src/persistence/migrations/028-call-session-mode.ts +1 -1
- package/src/persistence/migrations/116-messages-fts.ts +8 -1
- package/src/persistence/migrations/311-create-subagents-table.ts +50 -0
- package/src/persistence/migrations/312-drop-inbox-conversation-state-table.ts +15 -0
- package/src/persistence/migrations/313-drop-messages-fts.ts +17 -0
- package/src/persistence/migrations/314-add-conversation-enabled-plugins.ts +25 -0
- package/src/persistence/migrations/315-create-a2a-invites.ts +58 -0
- package/src/persistence/migrations/316-drop-contact-channels-invite-id.ts +28 -0
- package/src/persistence/migrations/317-canonical-guardian-requester-signals.ts +24 -0
- package/src/persistence/migrations/318-drop-contact-channel-telemetry.ts +32 -0
- package/src/persistence/migrations/__tests__/315-create-a2a-invites.test.ts +161 -0
- package/src/persistence/migrations/__tests__/316-drop-contact-channels-invite-id.test.ts +156 -0
- package/src/persistence/migrations/__tests__/318-drop-contact-channel-telemetry.test.ts +134 -0
- package/src/persistence/migrations/__tests__/migration-prefix-guard.test.ts +99 -0
- package/src/persistence/raw-query.ts +50 -11
- package/src/persistence/schema/a2a.ts +14 -0
- package/src/persistence/schema/contacts.ts +0 -62
- package/src/persistence/schema/conversation-groups.ts +12 -0
- package/src/persistence/schema/conversations.ts +2 -0
- package/src/persistence/schema/documents.ts +65 -0
- package/src/persistence/schema/guardian.ts +4 -0
- package/src/persistence/schema/index.ts +4 -0
- package/src/persistence/schema/memory-injection.ts +62 -0
- package/src/persistence/schema/workflows.ts +55 -0
- package/src/persistence/slow-query-log.ts +437 -0
- package/src/persistence/slow-sync-log.ts +204 -0
- package/src/persistence/steps.ts +16 -0
- package/src/persistence/subagent-store.ts +125 -0
- package/src/persistence/worker-control.ts +45 -238
- package/src/plugin-api/event-hub-facade.ts +172 -0
- package/src/plugin-api/index.ts +9 -1
- package/src/plugin-api/types.ts +40 -9
- package/src/plugins/defaults/default-plugin-names.ts +60 -0
- package/src/plugins/defaults/index.ts +19 -29
- package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +46 -67
- package/src/plugins/defaults/memory/__tests__/db-async-query.test.ts +36 -1
- package/src/plugins/defaults/memory/__tests__/find-most-recent-retrospective-for.test.ts +2 -4
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +2 -2
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-schedule.test.ts +9 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +7 -4
- package/src/plugins/defaults/memory/config.ts +11 -0
- package/src/plugins/defaults/memory/context-search/agent-runner.ts +1 -1
- package/src/plugins/defaults/memory/context-search/sources/conversations.ts +124 -113
- package/src/plugins/defaults/memory/embeddings.ts +77 -0
- package/src/plugins/defaults/memory/find-most-recent-retrospective-for.ts +66 -0
- package/src/plugins/defaults/memory/frontmatter.ts +50 -0
- package/src/plugins/defaults/memory/graph/bootstrap.test.ts +36 -10
- package/src/plugins/defaults/memory/graph/bootstrap.ts +6 -5
- package/src/plugins/defaults/memory/graph/consolidation.ts +3 -5
- package/src/plugins/defaults/memory/graph/extraction.ts +3 -6
- package/src/plugins/defaults/memory/graph/graph-search.ts +12 -23
- package/src/plugins/defaults/memory/graph/narrative.ts +3 -5
- package/src/plugins/defaults/memory/graph/pattern-scan.ts +3 -5
- package/src/plugins/defaults/memory/graph/retriever.test.ts +1 -6
- package/src/plugins/defaults/memory/graph/retriever.ts +5 -10
- package/src/plugins/defaults/memory/graph/tools.ts +1 -1
- package/src/plugins/defaults/memory/hooks/init.ts +31 -5
- package/src/plugins/defaults/memory/indexer.ts +2 -3
- package/src/plugins/defaults/memory/injectors.ts +2 -2
- package/src/plugins/defaults/memory/job-handler-registration.ts +96 -0
- package/src/plugins/defaults/memory/job-handlers/backfill.ts +4 -26
- package/src/plugins/defaults/memory/job-handlers/embedding.test.ts +6 -19
- package/src/plugins/defaults/memory/job-handlers/embedding.ts +9 -22
- package/src/plugins/defaults/memory/job-handlers/index-maintenance.ts +2 -3
- package/src/plugins/defaults/memory/job-handlers.ts +13 -12
- package/src/plugins/defaults/memory/jobs/embed-concept-page.ts +1 -1
- package/src/plugins/defaults/memory/llm-helpers.ts +76 -0
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +8 -5
- package/src/plugins/defaults/memory/memory-retrospective-startup-cleanup.ts +2 -2
- package/src/plugins/defaults/memory/memory-v2-concept-frequency.ts +2 -0
- package/src/plugins/defaults/memory/persistence-hooks.ts +46 -1
- package/src/plugins/defaults/memory/pkb/pkb-index.ts +1 -5
- package/src/plugins/defaults/memory/pkb/pkb-search.ts +2 -2
- package/src/plugins/defaults/memory/routes/__tests__/memory-v2-simulate-route.test.ts +4 -6
- package/src/plugins/defaults/memory/routes/memory-item-routes.ts +1 -1
- package/src/plugins/defaults/memory/search/semantic.ts +2 -2
- package/src/plugins/defaults/memory/startup.ts +244 -0
- package/src/plugins/defaults/memory/task-memory-cleanup.ts +8 -0
- package/src/{daemon → plugins/defaults/memory/v2}/__tests__/memory-v2-startup.test.ts +6 -6
- package/src/plugins/defaults/memory/v2/__tests__/migration.test.ts +2 -13
- package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +4 -5
- package/src/plugins/defaults/memory/v2/__tests__/sweep-job.test.ts +1 -8
- package/src/plugins/defaults/memory/v2/activation.ts +2 -4
- package/src/plugins/defaults/memory/v2/cli-command-store.ts +2 -4
- package/src/plugins/defaults/memory/v2/frontmatter-sweep.ts +1 -1
- package/src/{daemon → plugins/defaults/memory/v2}/memory-v2-startup.test.ts +8 -8
- package/src/{daemon → plugins/defaults/memory/v2}/memory-v2-startup.ts +20 -22
- package/src/plugins/defaults/memory/v2/migration.ts +2 -5
- package/src/plugins/defaults/memory/v2/page-store.ts +1 -1
- package/src/plugins/defaults/memory/v2/qdrant.ts +2 -3
- package/src/plugins/defaults/memory/v2/router.ts +5 -5
- package/src/plugins/defaults/memory/v2/sim.ts +2 -4
- package/src/plugins/defaults/memory/v2/skill-store.ts +2 -4
- package/src/plugins/defaults/memory/v2/sweep-job.ts +6 -6
- package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +11 -9
- package/src/plugins/defaults/memory/v3/__tests__/dense.test.ts +107 -2
- package/src/plugins/defaults/memory/v3/__tests__/gate-flag.test.ts +69 -0
- package/src/plugins/defaults/memory/v3/__tests__/gate.test.ts +181 -0
- package/src/plugins/defaults/memory/v3/__tests__/live-integration.test.ts +7 -3
- package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +345 -8
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +1 -4
- package/src/plugins/defaults/memory/v3/__tests__/section-needle.test.ts +64 -0
- package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +18 -13
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +62 -1
- package/src/plugins/defaults/memory/v3/card.ts +1 -4
- package/src/plugins/defaults/memory/v3/dense.ts +60 -25
- package/src/plugins/defaults/memory/v3/edge.ts +1 -1
- package/src/plugins/defaults/memory/v3/gate-flag.ts +20 -0
- package/src/plugins/defaults/memory/v3/gate.ts +158 -0
- package/src/plugins/defaults/memory/v3/maintain-job.ts +2 -4
- package/src/plugins/defaults/memory/v3/orchestrate.ts +186 -25
- package/src/plugins/defaults/memory/v3/pool-select.test.ts +7 -9
- package/src/plugins/defaults/memory/v3/pool-select.ts +6 -6
- package/src/plugins/defaults/memory/v3/prune.ts +2 -2
- package/src/plugins/defaults/memory/v3/section-dense-store.ts +8 -11
- package/src/plugins/defaults/memory/v3/section-needle.ts +27 -7
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +10 -0
- package/src/plugins/defaults/memory/v3-eval/eval-packets.ts +1 -4
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +5 -0
- package/src/plugins/defaults/turn-context/injectors.ts +1 -0
- package/src/plugins/defaults/turn-context/unified-turn-context.ts +12 -0
- package/src/plugins/injector-registry.ts +13 -2
- package/src/plugins/mtime-cache.ts +36 -47
- package/src/plugins/pipeline.ts +15 -1
- package/src/plugins/types.ts +14 -23
- package/src/prompts/__tests__/system-prompt.test.ts +170 -32
- package/src/prompts/persona-resolver.ts +13 -9
- package/src/prompts/system-prompt.ts +30 -9
- package/src/prompts/templates/BOOTSTRAP.md +16 -119
- package/src/prompts/templates/SOUL.md +43 -13
- package/src/prompts/templates/system-sections.ts +32 -27
- package/src/prompts/templates/users/default.md +19 -0
- package/src/providers/__tests__/placeholder-sentinels.test.ts +56 -0
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +96 -1
- package/src/providers/model-intents.ts +2 -2
- package/src/providers/openai/chat-completions-provider.ts +14 -1
- package/src/providers/openai/responses-provider.ts +18 -0
- package/src/providers/placeholder-sentinels.ts +18 -8
- package/src/providers/retry.ts +1 -0
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +0 -64
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +92 -79
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +98 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +62 -3
- package/src/providers/speech-to-text/provider-catalog.ts +0 -89
- package/src/providers/speech-to-text/resolve.ts +55 -0
- package/src/providers/tool-progress-events.test.ts +50 -0
- package/src/providers/tool-progress-events.ts +99 -0
- package/src/providers/types.ts +1 -1
- package/src/providers/vellum-model-routing.test.ts +51 -0
- package/src/providers/vellum-model-routing.ts +84 -0
- package/src/runtime/AGENTS.md +5 -4
- package/src/runtime/__tests__/agent-wake.test.ts +158 -1
- package/src/runtime/__tests__/channel-verification-service.test.ts +2 -2
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +37 -8
- package/src/runtime/access-request-helper.ts +154 -3
- package/src/runtime/actor-trust-resolver.ts +7 -21
- package/src/runtime/agent-wake.ts +41 -1
- package/src/runtime/assistant-event.ts +86 -12
- package/src/runtime/auth/__tests__/route-policy.test.ts +31 -0
- package/src/runtime/channel-approval-types.ts +52 -2
- package/src/runtime/channel-approvals.ts +23 -8
- package/src/runtime/channel-invite-transport.ts +2 -2
- package/src/runtime/channel-invite-transports/voice.ts +1 -1
- package/src/runtime/channel-readiness-service.ts +3 -5
- package/src/runtime/channel-retry-sweep.ts +18 -24
- package/src/runtime/channel-verification-service.ts +9 -11
- package/src/runtime/finalize-event-delivery.ts +30 -16
- package/src/runtime/guardian-action-service.ts +10 -11
- package/src/runtime/guardian-reply-router.ts +122 -21
- package/src/runtime/http-server.ts +44 -101
- package/src/runtime/introduction-policy.test.ts +214 -0
- package/src/runtime/introduction-policy.ts +284 -0
- package/src/runtime/invite-service.ts +104 -361
- package/src/runtime/local-actor-identity.test.ts +38 -0
- package/src/runtime/local-actor-identity.ts +14 -0
- package/src/runtime/middleware/__tests__/rate-limiter.test.ts +22 -0
- package/src/runtime/middleware/rate-limiter.ts +30 -0
- package/src/runtime/middleware/twilio-validation.ts +5 -7
- package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +28 -0
- package/src/runtime/migrations/origin-mode.ts +6 -6
- package/src/runtime/pre-first-message-gate.ts +1 -0
- package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +6 -35
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +24 -3
- package/src/runtime/routes/__tests__/contact-routes.test.ts +80 -15
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +7 -1
- package/src/runtime/routes/__tests__/global-search-routes.test.ts +0 -3
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +142 -1
- package/src/runtime/routes/__tests__/invite-relay-routes.test.ts +119 -30
- package/src/runtime/routes/__tests__/migration-import-allowed-hosts-env.test.ts +70 -0
- package/src/runtime/routes/__tests__/monitoring-routes.test.ts +194 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +755 -29
- package/src/runtime/routes/__tests__/retrospective-routes.test.ts +4 -0
- package/src/runtime/routes/__tests__/schedule-routes-create.test.ts +70 -0
- package/src/runtime/routes/__tests__/schedule-worker-routes.test.ts +161 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +1 -1
- package/src/runtime/routes/acp-routes.ts +15 -3
- package/src/runtime/routes/app-management-routes.ts +4 -7
- package/src/runtime/routes/approval-routes.ts +4 -0
- package/src/runtime/routes/attachment-routes.ts +54 -3
- package/src/runtime/routes/avatar-routes.ts +0 -4
- package/src/runtime/routes/background-tool-routes.ts +34 -5
- package/src/runtime/routes/btw-routes.ts +32 -4
- package/src/runtime/routes/channel-route-shared.ts +18 -14
- package/src/runtime/routes/channel-verification-routes.ts +0 -3
- package/src/runtime/routes/contact-routes.ts +298 -117
- package/src/runtime/routes/conversation-list-routes.ts +6 -0
- package/src/runtime/routes/conversation-management-routes.ts +74 -37
- package/src/runtime/routes/conversation-query-routes.ts +5 -2
- package/src/runtime/routes/conversation-routes.ts +222 -82
- package/src/runtime/routes/conversations-import-routes.ts +8 -1
- package/src/runtime/routes/credential-prompt-routes.ts +20 -5
- package/src/runtime/routes/debug-routes.ts +1 -0
- package/src/runtime/routes/documents-routes.ts +5 -2
- package/src/runtime/routes/empty-state-greeting-cache.ts +37 -10
- package/src/runtime/routes/global-search-routes.ts +2 -1
- package/src/runtime/routes/guardian-approval-interception.ts +51 -0
- package/src/runtime/routes/home-feed-routes.ts +60 -1
- package/src/runtime/routes/identity-routes.ts +4 -87
- package/src/runtime/routes/inbound-message-handler.ts +82 -41
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +430 -57
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +302 -572
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +76 -270
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +21 -116
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +9 -1
- package/src/runtime/routes/inbound-stages/escalation-intercept.test.ts +158 -0
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +22 -1
- package/src/runtime/routes/index.ts +6 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +22 -16
- package/src/runtime/routes/internal-twilio-routes.ts +0 -15
- package/src/runtime/routes/messages-lexical-routes.ts +75 -0
- package/src/runtime/routes/migration-routes.ts +69 -6
- package/src/runtime/routes/monitoring-routes.ts +237 -0
- package/src/runtime/routes/plugins-routes.ts +329 -8
- package/src/runtime/routes/schedule-routes.ts +49 -8
- package/src/runtime/routes/schedule-worker-routes.ts +210 -0
- package/src/runtime/routes/secret-routes.ts +1 -1
- package/src/runtime/routes/surface-conversation-resolver.ts +1 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +54 -9
- package/src/runtime/services/__tests__/auto-analysis-enqueue.test.ts +30 -6
- package/src/runtime/services/__tests__/conversation-analyze-job.test.ts +43 -8
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +20 -0
- package/src/runtime/services/analyze-conversation.ts +14 -4
- package/src/runtime/services/conversation-serializer.ts +5 -0
- package/src/runtime/slack-no-response.ts +47 -0
- package/src/runtime/slack-reply-session.test.ts +633 -0
- package/src/runtime/slack-reply-session.ts +382 -0
- package/src/runtime/slack-task-progress.ts +95 -0
- package/src/runtime/sync/resource-sync-events.ts +25 -0
- package/src/runtime/tool-grant-request-helper.ts +17 -1
- package/src/runtime/trust-class.test.ts +141 -0
- package/src/runtime/trust-class.ts +121 -0
- package/src/runtime/trust-verdict-consumer.ts +7 -6
- package/src/schedule/__tests__/run-script.test.ts +21 -0
- package/src/schedule/__tests__/worker-control.test.ts +241 -0
- package/src/schedule/run-script.ts +13 -6
- package/src/schedule/schedule-usage-store.ts +1 -0
- package/src/schedule/scheduler.ts +178 -127
- package/src/schedule/worker-control.ts +118 -0
- package/src/schedule/worker.ts +131 -0
- package/src/skills/__tests__/categories-cache.test.ts +38 -0
- package/src/skills/categories-cache.ts +40 -5
- package/src/skills/managed-store.ts +41 -6
- package/src/skills/validate-input.ts +47 -0
- package/src/stt/types.ts +5 -9
- package/src/subagent/manager.ts +267 -39
- package/src/subagent/types.ts +6 -2
- package/src/subagent/validate-allowlists.ts +65 -0
- package/src/telemetry/watchdog-direct-emit.test.ts +109 -0
- package/src/telemetry/watchdog-direct-emit.ts +89 -0
- package/src/tools/acp/list-agents.test.ts +0 -6
- package/src/tools/background-tool-registry.ts +61 -0
- package/src/tools/document/document-comment-tool.test.ts +4 -0
- package/src/tools/host-terminal/host-shell.test.ts +397 -0
- package/src/tools/host-terminal/host-shell.ts +203 -14
- package/src/tools/skills/find-similar-skills.test.ts +152 -1
- package/src/tools/skills/find-similar-skills.ts +30 -4
- package/src/tools/skills/load.ts +36 -0
- package/src/tools/skills/scaffold-managed.ts +66 -34
- package/src/tools/skills/skill-script-runner.ts +17 -0
- package/src/tools/skills/skill-tool-factory.ts +5 -1
- package/src/tools/terminal/safe-env.ts +3 -0
- package/src/tools/terminal/shell.test.ts +177 -0
- package/src/tools/terminal/shell.ts +98 -4
- package/src/tools/tool-approval-handler.ts +106 -29
- package/{node_modules/@vellumai/skill-host-contracts/src → src/tools}/tool-types.ts +16 -17
- package/src/tools/types.ts +29 -17
- package/src/tools/ui-surface/definitions.ts +3 -1
- package/src/tts/__tests__/provider-adapters.test.ts +37 -0
- package/src/tts/__tests__/provider-catalog.test.ts +21 -0
- package/src/tts/provider-catalog.ts +40 -9
- package/src/tts/providers/fish-audio-provider.ts +19 -10
- package/src/tts/types.ts +3 -4
- package/src/util/__tests__/process-tree.test.ts +10 -2
- package/src/util/__tests__/text-spacing.test.ts +53 -0
- package/src/util/cgroup-memory.ts +142 -0
- package/src/util/image-conversion.ts +281 -0
- package/src/util/phone.ts +1 -8
- package/src/util/platform.ts +33 -0
- package/src/util/process-tree.ts +10 -2
- package/src/util/text-spacing.ts +53 -0
- package/src/util/worker-process.ts +271 -0
- package/src/workflows/journal-store.ts +16 -1
- package/src/workflows/library.test.ts +35 -20
- package/src/workflows/library.ts +105 -66
- package/src/workspace/git-service.ts +1 -0
- package/src/workspace/migrations/011-backfill-installation-id.ts +83 -31
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +41 -22
- package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +1 -1
- package/src/workspace/migrations/118-seed-now-md.ts +64 -0
- package/src/workspace/migrations/119-strip-persisted-memory-v3-tuning-defaults.ts +169 -0
- package/src/workspace/migrations/120-revise-onboarding-threads.ts +47 -0
- package/src/workspace/migrations/121-seed-default-user-guardrails.ts +82 -0
- package/src/workspace/migrations/122-relocate-default-user-boundary.ts +111 -0
- package/src/workspace/migrations/123-swap-quality-profile-to-fable.ts +85 -0
- package/src/workspace/migrations/__tests__/119-strip-persisted-memory-v3-tuning-defaults.test.ts +181 -0
- package/src/workspace/migrations/registry.ts +12 -0
- package/drizzle/0000_dizzy_maggott.sql +0 -301
- package/drizzle/meta/0000_snapshot.json +0 -1933
- package/drizzle/meta/_journal.json +0 -13
- package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +0 -887
- package/node_modules/@vellumai/skill-host-contracts/bun.lock +0 -24
- package/node_modules/@vellumai/skill-host-contracts/package.json +0 -18
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -97
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +0 -1349
- package/node_modules/@vellumai/skill-host-contracts/src/index.ts +0 -6
- package/node_modules/@vellumai/skill-host-contracts/src/runtime-mode.ts +0 -11
- package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +0 -32
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +0 -333
- package/node_modules/@vellumai/skill-host-contracts/tsconfig.json +0 -20
- package/node_modules/@vellumai/skill-host-contracts/tsconfig.test.json +0 -12
- package/src/__tests__/invite-redemption-service.test.ts +0 -1180
- package/src/__tests__/invite-service-ipc.test.ts +0 -350
- package/src/__tests__/job-handler-registry-guard.test.ts +0 -125
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +0 -203
- package/src/__tests__/relay-server.test.ts +0 -6153
- package/src/__tests__/telephony-stt-routing.test.ts +0 -329
- package/src/__tests__/voice-invite-redemption.test.ts +0 -702
- package/src/calls/relay-server.ts +0 -2463
- package/src/calls/telephony-stt-routing.ts +0 -145
- package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +0 -128
- package/src/daemon/__tests__/daemon-skill-host.test.ts +0 -273
- package/src/daemon/daemon-skill-host.ts +0 -262
- package/src/daemon/message-types/meet.ts +0 -143
- package/src/daemon/shutdown-registry.ts +0 -40
- package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -253
- package/src/ipc/__tests__/skill-server.test.ts +0 -182
- package/src/ipc/skill-ipc-types.ts +0 -54
- package/src/ipc/skill-routes/__tests__/config.test.ts +0 -146
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +0 -448
- package/src/ipc/skill-routes/__tests__/identity.test.ts +0 -62
- package/src/ipc/skill-routes/__tests__/log.test.ts +0 -133
- package/src/ipc/skill-routes/__tests__/memory.test.ts +0 -203
- package/src/ipc/skill-routes/__tests__/platform.test.ts +0 -111
- package/src/ipc/skill-routes/__tests__/providers.test.ts +0 -265
- package/src/ipc/skill-routes/__tests__/registries.test.ts +0 -400
- package/src/ipc/skill-routes/config.ts +0 -47
- package/src/ipc/skill-routes/events.ts +0 -147
- package/src/ipc/skill-routes/identity.ts +0 -21
- package/src/ipc/skill-routes/index.ts +0 -37
- package/src/ipc/skill-routes/log.ts +0 -40
- package/src/ipc/skill-routes/memory.ts +0 -92
- package/src/ipc/skill-routes/platform.ts +0 -39
- package/src/ipc/skill-routes/providers.ts +0 -162
- package/src/ipc/skill-routes/registries.ts +0 -338
- package/src/ipc/skill-server.ts +0 -831
- package/src/ipc/skill-socket-path.ts +0 -20
- package/src/jobs/register-job-handlers.ts +0 -74
- package/src/persistence/invite-store.ts +0 -481
- package/src/plugins/job-handler-registry.ts +0 -94
- package/src/providers/cache-control.ts +0 -26
- package/src/runtime/__tests__/runtime-mode.test.ts +0 -62
- package/src/runtime/invite-redemption-service.ts +0 -828
- package/src/runtime/invite-redemption-templates.ts +0 -46
- package/src/runtime/runtime-mode.ts +0 -40
- package/src/runtime/slack-dm-text-delivery.ts +0 -177
- package/src/util/voice-code.ts +0 -31
|
@@ -1,78 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Daemon-owned invite presentation and provider-call helpers.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* /v1/contacts/channels endpoints.
|
|
4
|
+
* The gateway owns the canonical invite lifecycle (its `ingress_invites`
|
|
5
|
+
* table; mint/list/revoke/redeem run gateway-natively). These helpers layer
|
|
6
|
+
* display-only fields — share link, guardian instruction, channel handle —
|
|
7
|
+
* onto gateway-minted payloads and place outbound invite calls.
|
|
9
8
|
*/
|
|
10
9
|
|
|
11
10
|
import { startInviteCall } from "../calls/call-domain.js";
|
|
12
11
|
import { isChannelId } from "../channels/types.js";
|
|
13
12
|
import { getContact } from "../contacts/contact-store.js";
|
|
14
|
-
import {
|
|
15
|
-
createInvite,
|
|
16
|
-
findById,
|
|
17
|
-
findByTokenHash,
|
|
18
|
-
hashToken,
|
|
19
|
-
type IngressInvite,
|
|
20
|
-
markInviteExpired,
|
|
21
|
-
} from "../persistence/invite-store.js";
|
|
22
13
|
import {
|
|
23
14
|
DECLINED_BY_USER_SENTINEL,
|
|
24
15
|
DEFAULT_USER_REFERENCE,
|
|
25
16
|
resolveGuardianName,
|
|
26
17
|
} from "../prompts/user-reference.js";
|
|
27
|
-
import { isValidE164 } from "../util/phone.js";
|
|
28
|
-
import { generateVoiceCode, hashVoiceCode } from "../util/voice-code.js";
|
|
29
18
|
import {
|
|
30
19
|
getInviteAdapterRegistry,
|
|
31
20
|
resolveAdapterHandle,
|
|
32
21
|
} from "./channel-invite-transport.js";
|
|
33
22
|
import { generateInviteInstruction } from "./invite-instruction-generator.js";
|
|
34
|
-
import {
|
|
35
|
-
redeemInvite as redeemInviteTyped,
|
|
36
|
-
redeemVoiceInviteCode as redeemVoiceInviteCodeTyped,
|
|
37
|
-
type VoiceRedemptionOutcome,
|
|
38
|
-
} from "./invite-redemption-service.js";
|
|
39
|
-
|
|
40
|
-
// ---------------------------------------------------------------------------
|
|
41
|
-
// Response shapes — used by both HTTP routes and message handlers
|
|
42
|
-
// ---------------------------------------------------------------------------
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Redemption outcome type surfaced to callers. `already_member` consumes no
|
|
46
|
-
* invite use, so the gateway must not mirror it into recordInviteRedemption.
|
|
47
|
-
*/
|
|
48
|
-
export type RedemptionType = "redeemed" | "already_member";
|
|
49
|
-
|
|
50
|
-
export interface InviteResponseData {
|
|
51
|
-
id: string;
|
|
52
|
-
sourceChannel: string;
|
|
53
|
-
token?: string;
|
|
54
|
-
share?: {
|
|
55
|
-
url: string;
|
|
56
|
-
displayText: string;
|
|
57
|
-
};
|
|
58
|
-
tokenHash: string;
|
|
59
|
-
maxUses: number;
|
|
60
|
-
useCount: number;
|
|
61
|
-
expiresAt: number | null;
|
|
62
|
-
status: string;
|
|
63
|
-
note?: string;
|
|
64
|
-
// Voice invite fields (present only for voice invites)
|
|
65
|
-
expectedExternalUserId?: string;
|
|
66
|
-
voiceCode?: string;
|
|
67
|
-
voiceCodeDigits?: number;
|
|
68
|
-
friendName?: string;
|
|
69
|
-
guardianName?: string;
|
|
70
|
-
// Non-voice invite fields (present only for non-voice invites)
|
|
71
|
-
inviteCode?: string;
|
|
72
|
-
guardianInstruction?: string;
|
|
73
|
-
channelHandle?: string;
|
|
74
|
-
createdAt: number;
|
|
75
|
-
}
|
|
76
23
|
|
|
77
24
|
// ---------------------------------------------------------------------------
|
|
78
25
|
// Mappers
|
|
@@ -81,7 +28,7 @@ export interface InviteResponseData {
|
|
|
81
28
|
function buildSharePayload(
|
|
82
29
|
sourceChannel: string,
|
|
83
30
|
rawToken?: string,
|
|
84
|
-
):
|
|
31
|
+
): { url: string; displayText: string } | undefined {
|
|
85
32
|
if (!rawToken || !isChannelId(sourceChannel)) return undefined;
|
|
86
33
|
const adapter = getInviteAdapterRegistry().get(sourceChannel);
|
|
87
34
|
if (!adapter?.buildShareLink) return undefined;
|
|
@@ -98,337 +45,133 @@ function buildSharePayload(
|
|
|
98
45
|
}
|
|
99
46
|
}
|
|
100
47
|
|
|
101
|
-
function inviteToResponse(
|
|
102
|
-
inv: IngressInvite,
|
|
103
|
-
opts?: {
|
|
104
|
-
rawToken?: string;
|
|
105
|
-
voiceCode?: string;
|
|
106
|
-
inviteCode?: string;
|
|
107
|
-
guardianInstruction?: string;
|
|
108
|
-
channelHandle?: string;
|
|
109
|
-
},
|
|
110
|
-
): InviteResponseData {
|
|
111
|
-
const share = buildSharePayload(inv.sourceChannel, opts?.rawToken);
|
|
112
|
-
return {
|
|
113
|
-
id: inv.id,
|
|
114
|
-
sourceChannel: inv.sourceChannel,
|
|
115
|
-
...(opts?.rawToken ? { token: opts.rawToken } : {}),
|
|
116
|
-
...(share ? { share } : {}),
|
|
117
|
-
tokenHash: inv.tokenHash,
|
|
118
|
-
maxUses: inv.maxUses,
|
|
119
|
-
useCount: inv.useCount,
|
|
120
|
-
expiresAt: inv.expiresAt,
|
|
121
|
-
status: inv.status,
|
|
122
|
-
note: inv.note ?? undefined,
|
|
123
|
-
...(inv.expectedExternalUserId
|
|
124
|
-
? { expectedExternalUserId: inv.expectedExternalUserId }
|
|
125
|
-
: {}),
|
|
126
|
-
...(opts?.voiceCode ? { voiceCode: opts.voiceCode } : {}),
|
|
127
|
-
...(inv.voiceCodeDigits != null
|
|
128
|
-
? { voiceCodeDigits: inv.voiceCodeDigits }
|
|
129
|
-
: {}),
|
|
130
|
-
...(inv.friendName ? { friendName: inv.friendName } : {}),
|
|
131
|
-
...(inv.guardianName ? { guardianName: inv.guardianName } : {}),
|
|
132
|
-
...(opts?.inviteCode ? { inviteCode: opts.inviteCode } : {}),
|
|
133
|
-
...(opts?.guardianInstruction
|
|
134
|
-
? { guardianInstruction: opts.guardianInstruction }
|
|
135
|
-
: {}),
|
|
136
|
-
...(opts?.channelHandle ? { channelHandle: opts.channelHandle } : {}),
|
|
137
|
-
createdAt: inv.createdAt,
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
|
|
141
48
|
// ---------------------------------------------------------------------------
|
|
142
49
|
// Result types
|
|
143
50
|
// ---------------------------------------------------------------------------
|
|
144
51
|
|
|
145
|
-
|
|
146
|
-
| { ok: true; data: T }
|
|
147
|
-
| { ok: false; error: string };
|
|
52
|
+
type IngressResult<T> = { ok: true; data: T } | { ok: false; error: string };
|
|
148
53
|
|
|
149
54
|
// ---------------------------------------------------------------------------
|
|
150
55
|
// Invite operations
|
|
151
56
|
// ---------------------------------------------------------------------------
|
|
152
57
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
return
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (!params.contactId) {
|
|
170
|
-
return { ok: false, error: "contactId is required for create" };
|
|
58
|
+
/**
|
|
59
|
+
* Guardian display label attached to voice invites, resolved from the
|
|
60
|
+
* guardian persona with the placeholder/declined sentinels filtered out.
|
|
61
|
+
* The daemon passes it through to the gateway mint, which stores it on the
|
|
62
|
+
* invite row and never interprets it.
|
|
63
|
+
*/
|
|
64
|
+
export function resolveInviteGuardianName(): string | undefined {
|
|
65
|
+
const name = resolveGuardianName();
|
|
66
|
+
if (
|
|
67
|
+
!name ||
|
|
68
|
+
name === DEFAULT_USER_REFERENCE ||
|
|
69
|
+
name === DECLINED_BY_USER_SENTINEL
|
|
70
|
+
) {
|
|
71
|
+
return undefined;
|
|
171
72
|
}
|
|
73
|
+
return name;
|
|
74
|
+
}
|
|
172
75
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
if (isVoice) {
|
|
194
|
-
if (!params.expectedExternalUserId) {
|
|
195
|
-
return {
|
|
196
|
-
ok: false,
|
|
197
|
-
error: "expectedExternalUserId is required for voice invites",
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
if (!isValidE164(params.expectedExternalUserId)) {
|
|
201
|
-
return {
|
|
202
|
-
ok: false,
|
|
203
|
-
error:
|
|
204
|
-
"expectedExternalUserId must be in E.164 format (e.g., +15551234567)",
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
effectiveGuardianName = resolveGuardianName();
|
|
208
|
-
if (
|
|
209
|
-
!effectiveGuardianName ||
|
|
210
|
-
effectiveGuardianName === DEFAULT_USER_REFERENCE ||
|
|
211
|
-
effectiveGuardianName === DECLINED_BY_USER_SENTINEL
|
|
212
|
-
) {
|
|
213
|
-
effectiveGuardianName = undefined;
|
|
214
|
-
}
|
|
215
|
-
voiceCode = generateVoiceCode(6);
|
|
216
|
-
voiceCodeHash = hashVoiceCode(voiceCode);
|
|
217
|
-
} else {
|
|
218
|
-
inviteCode = generateVoiceCode(6);
|
|
219
|
-
inviteCodeHash = hashVoiceCode(inviteCode);
|
|
76
|
+
/**
|
|
77
|
+
* Layer the daemon-owned presentation fields onto a gateway-minted invite
|
|
78
|
+
* payload: the share link, the guardian instruction (LLM-generated for
|
|
79
|
+
* non-voice channels), and the resolved channel handle. The gateway owns the
|
|
80
|
+
* invite row and its secrets; everything added here is display-only, derived
|
|
81
|
+
* from the one-time create response, and never persisted.
|
|
82
|
+
*/
|
|
83
|
+
export async function composeInvitePresentation(params: {
|
|
84
|
+
contactId?: string;
|
|
85
|
+
invite: Record<string, unknown>;
|
|
86
|
+
rawToken?: string;
|
|
87
|
+
}): Promise<Record<string, unknown>> {
|
|
88
|
+
const invite = params.invite;
|
|
89
|
+
const sourceChannel =
|
|
90
|
+
typeof invite.sourceChannel === "string" ? invite.sourceChannel : "";
|
|
91
|
+
const isVoice = sourceChannel === "phone";
|
|
92
|
+
const inviteCode =
|
|
93
|
+
typeof invite.inviteCode === "string" ? invite.inviteCode : undefined;
|
|
94
|
+
if (!isVoice && !inviteCode) {
|
|
95
|
+
return invite;
|
|
220
96
|
}
|
|
221
97
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
// Mirror the contact-resolved names into the legacy columns so
|
|
234
|
-
// outbound invite calls (which still read invite.friendName /
|
|
235
|
-
// invite.guardianName) keep working without a separate lookup.
|
|
236
|
-
friendName: resolvedContactName,
|
|
237
|
-
guardianName: effectiveGuardianName,
|
|
238
|
-
}
|
|
239
|
-
: { inviteCodeHash }),
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
// Build invite instruction for non-voice invites via LLM generation
|
|
243
|
-
let guardianInstruction: string | undefined;
|
|
244
|
-
let channelHandle: string | undefined;
|
|
245
|
-
if (!isVoice && inviteCode) {
|
|
246
|
-
const channelId = isChannelId(params.sourceChannel)
|
|
247
|
-
? params.sourceChannel
|
|
248
|
-
: undefined;
|
|
249
|
-
const adapter = channelId
|
|
250
|
-
? getInviteAdapterRegistry().get(channelId)
|
|
251
|
-
: undefined;
|
|
252
|
-
if (params.sourceChannel === "telegram") {
|
|
253
|
-
const { ensureTelegramBotUsernameResolved } =
|
|
254
|
-
await import("./channel-invite-transports/telegram.js");
|
|
255
|
-
await ensureTelegramBotUsernameResolved();
|
|
256
|
-
}
|
|
257
|
-
channelHandle = adapter ? await resolveAdapterHandle(adapter) : undefined;
|
|
258
|
-
const share = buildSharePayload(params.sourceChannel, rawToken);
|
|
259
|
-
guardianInstruction = await generateInviteInstruction({
|
|
260
|
-
contactName: resolvedContactName,
|
|
261
|
-
channelType: params.sourceChannel,
|
|
262
|
-
channelHandle,
|
|
263
|
-
hasShareUrl: !!share?.url,
|
|
264
|
-
shareUrl: share?.url,
|
|
265
|
-
});
|
|
266
|
-
}
|
|
98
|
+
// The invitee's name comes from the bound contact's displayName; fall back
|
|
99
|
+
// to the gateway-stamped friendName when the local mirror lacks the contact.
|
|
100
|
+
const boundContact = params.contactId
|
|
101
|
+
? getContact(params.contactId)
|
|
102
|
+
: undefined;
|
|
103
|
+
const resolvedContactName =
|
|
104
|
+
boundContact?.displayName?.trim() ||
|
|
105
|
+
(typeof invite.friendName === "string"
|
|
106
|
+
? invite.friendName.trim()
|
|
107
|
+
: undefined) ||
|
|
108
|
+
undefined;
|
|
267
109
|
|
|
268
110
|
if (isVoice) {
|
|
269
|
-
|
|
111
|
+
const resolvedFirstName = resolvedContactName?.split(/\s+/)[0];
|
|
112
|
+
const guardianInstruction = resolvedFirstName
|
|
270
113
|
? `${resolvedFirstName} will need this code when they answer. Share it with them first.`
|
|
271
114
|
: "Share this code with them — they'll need it when they answer the call.";
|
|
115
|
+
return { ...invite, guardianInstruction };
|
|
272
116
|
}
|
|
273
117
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
guardianInstruction,
|
|
283
|
-
channelHandle,
|
|
284
|
-
}),
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
// ---------------------------------------------------------------------------
|
|
289
|
-
// Mint — gateway-facing projection
|
|
290
|
-
//
|
|
291
|
-
// The gateway owns the canonical invite lifecycle in its own DB, but token
|
|
292
|
-
// generation/hashing and voice fields are assistant-owned. `mintIngressInvite`
|
|
293
|
-
// runs the same `createIngressInvite` path and surfaces the raw token plus the
|
|
294
|
-
// minimal projection the gateway mirrors. The raw token is returned exactly
|
|
295
|
-
// once and never persisted in plaintext.
|
|
296
|
-
// ---------------------------------------------------------------------------
|
|
297
|
-
|
|
298
|
-
/** Minimal invite projection the gateway mirrors into its own store. */
|
|
299
|
-
export interface GatewayInviteProjection {
|
|
300
|
-
id: string;
|
|
301
|
-
/** Hash of whatever code redeems this invite: token hash for token invites,
|
|
302
|
-
* voice code hash for voice/phone invites. Always non-null and mirrorable. */
|
|
303
|
-
inviteCodeHash: string;
|
|
304
|
-
sourceChannel: string;
|
|
305
|
-
contactId: string;
|
|
306
|
-
note: string | null;
|
|
307
|
-
maxUses: number;
|
|
308
|
-
expiresAt: number;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
export interface MintInviteResult {
|
|
312
|
-
invite: InviteResponseData;
|
|
313
|
-
rawToken?: string;
|
|
314
|
-
gateway: GatewayInviteProjection;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
export async function mintIngressInvite(
|
|
318
|
-
params: Parameters<typeof createIngressInvite>[0],
|
|
319
|
-
): Promise<IngressResult<MintInviteResult>> {
|
|
320
|
-
const result = await createIngressInvite(params);
|
|
321
|
-
if (!result.ok) return result;
|
|
322
|
-
|
|
323
|
-
// The persisted row carries fields the response projection omits
|
|
324
|
-
// (inviteCodeHash); read it back to build the gateway projection.
|
|
325
|
-
const row = findById(result.data.id);
|
|
326
|
-
if (!row) {
|
|
327
|
-
return { ok: false, error: "Invite not found after mint" };
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
// The gateway mirrors the hash of whatever code redeems this invite. Token
|
|
331
|
-
// invites carry inviteCodeHash; voice/phone invites gate on voiceCodeHash.
|
|
332
|
-
const inviteCodeHash = row.inviteCodeHash ?? row.voiceCodeHash;
|
|
333
|
-
if (!inviteCodeHash) {
|
|
334
|
-
return { ok: false, error: "Invite is missing a redemption code hash" };
|
|
118
|
+
const channelId = isChannelId(sourceChannel) ? sourceChannel : undefined;
|
|
119
|
+
const adapter = channelId
|
|
120
|
+
? getInviteAdapterRegistry().get(channelId)
|
|
121
|
+
: undefined;
|
|
122
|
+
if (sourceChannel === "telegram") {
|
|
123
|
+
const { ensureTelegramBotUsernameResolved } =
|
|
124
|
+
await import("./channel-invite-transports/telegram.js");
|
|
125
|
+
await ensureTelegramBotUsernameResolved();
|
|
335
126
|
}
|
|
127
|
+
const channelHandle = adapter
|
|
128
|
+
? await resolveAdapterHandle(adapter)
|
|
129
|
+
: undefined;
|
|
130
|
+
const share = buildSharePayload(sourceChannel, params.rawToken);
|
|
131
|
+
const guardianInstruction = await generateInviteInstruction({
|
|
132
|
+
contactName: resolvedContactName,
|
|
133
|
+
channelType: sourceChannel,
|
|
134
|
+
channelHandle,
|
|
135
|
+
hasShareUrl: !!share?.url,
|
|
136
|
+
shareUrl: share?.url,
|
|
137
|
+
});
|
|
336
138
|
|
|
337
139
|
return {
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
gateway: {
|
|
343
|
-
id: row.id,
|
|
344
|
-
inviteCodeHash,
|
|
345
|
-
sourceChannel: row.sourceChannel,
|
|
346
|
-
contactId: row.contactId,
|
|
347
|
-
note: row.note,
|
|
348
|
-
maxUses: row.maxUses,
|
|
349
|
-
expiresAt: row.expiresAt,
|
|
350
|
-
},
|
|
351
|
-
},
|
|
140
|
+
...invite,
|
|
141
|
+
...(share ? { share } : {}),
|
|
142
|
+
...(guardianInstruction ? { guardianInstruction } : {}),
|
|
143
|
+
...(channelHandle ? { channelHandle } : {}),
|
|
352
144
|
};
|
|
353
145
|
}
|
|
354
146
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
if (
|
|
368
|
-
return { ok: false, error: "
|
|
369
|
-
if (!invite.expectedExternalUserId) {
|
|
370
|
-
return { ok: false, error: "Invite is missing required voice metadata" };
|
|
147
|
+
/**
|
|
148
|
+
* Place the outbound provider call for a voice invite. Invite lifecycle
|
|
149
|
+
* validation (existence, active status, expiry, phone channel) is the
|
|
150
|
+
* gateway's responsibility — it reads its canonical row and relays the
|
|
151
|
+
* resolved call fields here; the daemon only performs the provider call.
|
|
152
|
+
*/
|
|
153
|
+
export async function triggerInviteCall(params: {
|
|
154
|
+
phoneNumber?: string;
|
|
155
|
+
friendName?: string | null;
|
|
156
|
+
guardianName?: string | null;
|
|
157
|
+
}): Promise<IngressResult<{ callSid: string }>> {
|
|
158
|
+
const phoneNumber = params.phoneNumber?.trim();
|
|
159
|
+
if (!phoneNumber) {
|
|
160
|
+
return { ok: false, error: "phoneNumber is required" };
|
|
371
161
|
}
|
|
372
|
-
//
|
|
373
|
-
//
|
|
374
|
-
|
|
375
|
-
//
|
|
376
|
-
|
|
377
|
-
const
|
|
378
|
-
// Guardian label is resolved at runtime by the relay; mirror the legacy
|
|
379
|
-
// value into the session so STT hints continue to seed correctly.
|
|
380
|
-
const guardianName = invite.guardianName || resolveGuardianName() || "";
|
|
162
|
+
// An empty friendName falls through to the neutral "Hi there" greeting
|
|
163
|
+
// downstream rather than substituting the channel address.
|
|
164
|
+
const friendName = params.friendName?.trim() || "";
|
|
165
|
+
// Guardian label is resolved at runtime by the relay; mirror the value
|
|
166
|
+
// into the session so STT hints continue to seed correctly.
|
|
167
|
+
const guardianName = params.guardianName || resolveGuardianName() || "";
|
|
381
168
|
const result = await startInviteCall({
|
|
382
|
-
phoneNumber
|
|
169
|
+
phoneNumber,
|
|
383
170
|
friendName,
|
|
384
171
|
guardianName,
|
|
385
172
|
});
|
|
386
|
-
if (!result.ok)
|
|
387
|
-
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
export async function redeemIngressInvite(params: {
|
|
391
|
-
token?: string;
|
|
392
|
-
externalUserId?: string;
|
|
393
|
-
externalChatId?: string;
|
|
394
|
-
sourceChannel?: string;
|
|
395
|
-
}): Promise<
|
|
396
|
-
IngressResult<{ invite: InviteResponseData; type: RedemptionType }>
|
|
397
|
-
> {
|
|
398
|
-
if (!params.token) {
|
|
399
|
-
return { ok: false, error: "token is required for redeem" };
|
|
400
|
-
}
|
|
401
|
-
if (!params.sourceChannel) {
|
|
402
|
-
return { ok: false, error: "sourceChannel is required for redeem" };
|
|
403
|
-
}
|
|
404
|
-
const outcome = await redeemInviteTyped({
|
|
405
|
-
rawToken: params.token,
|
|
406
|
-
sourceChannel: params.sourceChannel,
|
|
407
|
-
externalUserId: params.externalUserId,
|
|
408
|
-
externalChatId: params.externalChatId,
|
|
409
|
-
});
|
|
410
|
-
if (!outcome.ok) {
|
|
411
|
-
return { ok: false, error: outcome.reason };
|
|
173
|
+
if (!result.ok) {
|
|
174
|
+
return { ok: false, error: result.error };
|
|
412
175
|
}
|
|
413
|
-
|
|
414
|
-
// `already_member`). Using findByTokenHash avoids the pagination limit of
|
|
415
|
-
// listInvites. The `type` is surfaced so the gateway can skip mirroring an
|
|
416
|
-
// `already_member` redemption (which consumes no use).
|
|
417
|
-
const inv = findByTokenHash(hashToken(params.token));
|
|
418
|
-
if (!inv) {
|
|
419
|
-
return { ok: false, error: "Invite not found after redemption" };
|
|
420
|
-
}
|
|
421
|
-
return {
|
|
422
|
-
ok: true,
|
|
423
|
-
data: { invite: inviteToResponse(inv), type: outcome.type },
|
|
424
|
-
};
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
export function redeemVoiceInviteCode(params: {
|
|
428
|
-
assistantId?: string;
|
|
429
|
-
callerExternalUserId: string;
|
|
430
|
-
sourceChannel: "phone";
|
|
431
|
-
code: string;
|
|
432
|
-
}): Promise<VoiceRedemptionOutcome> {
|
|
433
|
-
return redeemVoiceInviteCodeTyped(params);
|
|
176
|
+
return { ok: true, data: { callSid: result.callSid } };
|
|
434
177
|
}
|
|
@@ -36,6 +36,7 @@ import { __resetGuardianDeliveryCacheForTest } from "../contacts/guardian-delive
|
|
|
36
36
|
import {
|
|
37
37
|
findLocalGuardianPrincipalIdFromStore,
|
|
38
38
|
resolveActorPrincipalIdForLocalGuardianSync,
|
|
39
|
+
resolveDecidableGuardianPrincipalId,
|
|
39
40
|
warmLocalGuardianPrincipalCache,
|
|
40
41
|
} from "./local-actor-identity.js";
|
|
41
42
|
|
|
@@ -106,3 +107,40 @@ describe("warmLocalGuardianPrincipalCache", () => {
|
|
|
106
107
|
expect(findLocalGuardianPrincipalIdFromStore()).toBe("principal-abc");
|
|
107
108
|
});
|
|
108
109
|
});
|
|
110
|
+
|
|
111
|
+
describe("resolveDecidableGuardianPrincipalId", () => {
|
|
112
|
+
beforeEach(() => {
|
|
113
|
+
__resetGuardianDeliveryCacheForTest();
|
|
114
|
+
ipcHandlers.clear();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
afterEach(() => {
|
|
118
|
+
__resetGuardianDeliveryCacheForTest();
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test("a present binding principal is returned without an anchor read", async () => {
|
|
122
|
+
// No IPC handler registered: an anchor read would resolve undefined, so a
|
|
123
|
+
// "binding-1" result proves the binding principal short-circuits.
|
|
124
|
+
expect(await resolveDecidableGuardianPrincipalId("binding-1")).toBe(
|
|
125
|
+
"binding-1",
|
|
126
|
+
);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test("a null binding principal adopts the vellum anchor principal", async () => {
|
|
130
|
+
ipcHandlers.set(METHOD, () => ({ guardians: [vellumGuardian] }));
|
|
131
|
+
|
|
132
|
+
expect(await resolveDecidableGuardianPrincipalId(null)).toBe(
|
|
133
|
+
"principal-abc",
|
|
134
|
+
);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("an empty-string binding principal is unresolved, never returned", async () => {
|
|
138
|
+
ipcHandlers.set(METHOD, () => ({ guardians: [vellumGuardian] }));
|
|
139
|
+
|
|
140
|
+
expect(await resolveDecidableGuardianPrincipalId("")).toBe("principal-abc");
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test("unresolvable everywhere → undefined (caller fails closed)", async () => {
|
|
144
|
+
expect(await resolveDecidableGuardianPrincipalId(null)).toBeUndefined();
|
|
145
|
+
});
|
|
146
|
+
});
|
|
@@ -67,6 +67,20 @@ export async function findLocalGuardianPrincipalId(): Promise<
|
|
|
67
67
|
return guardianForChannel(list, "vellum")?.principalId ?? undefined;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Resolve a decidable guardian principal for canonical guardian-request
|
|
72
|
+
* creation: the channel binding's principal when present, else the vellum
|
|
73
|
+
* anchor principal (the adopt/repair path for guardian rows that carry no
|
|
74
|
+
* principal). A falsy binding principal (`null` or `""`) is unresolved by
|
|
75
|
+
* contract — decisionable requests must never be created with an empty
|
|
76
|
+
* principal, so callers fail closed on `undefined`.
|
|
77
|
+
*/
|
|
78
|
+
export async function resolveDecidableGuardianPrincipalId(
|
|
79
|
+
bindingPrincipalId: string | null,
|
|
80
|
+
): Promise<string | undefined> {
|
|
81
|
+
return bindingPrincipalId || (await findLocalGuardianPrincipalId());
|
|
82
|
+
}
|
|
83
|
+
|
|
70
84
|
/**
|
|
71
85
|
* Eagerly warm the gateway guardian-delivery cache for the vellum channel.
|
|
72
86
|
*
|
|
@@ -3,6 +3,7 @@ import { describe, expect, test } from "bun:test";
|
|
|
3
3
|
import { isLoopbackAddress } from "../auth.js";
|
|
4
4
|
import {
|
|
5
5
|
apiRateLimiter,
|
|
6
|
+
isRateLimitExemptEndpoint,
|
|
6
7
|
loopbackApiRateLimiter,
|
|
7
8
|
selectAuthenticatedRateLimiter,
|
|
8
9
|
} from "../rate-limiter.js";
|
|
@@ -61,3 +62,24 @@ describe("selectAuthenticatedRateLimiter", () => {
|
|
|
61
62
|
expect(standard.limit).toBe(300);
|
|
62
63
|
});
|
|
63
64
|
});
|
|
65
|
+
|
|
66
|
+
describe("isRateLimitExemptEndpoint", () => {
|
|
67
|
+
test("exempts the SSE stream and liveness probes", () => {
|
|
68
|
+
// Streaming: 429-ing the events stream drops it and drives a client
|
|
69
|
+
// reconnect + re-bootstrap storm, so it bypasses the per-minute limiter.
|
|
70
|
+
expect(isRateLimitExemptEndpoint("events")).toBe(true);
|
|
71
|
+
// Liveness/readiness probes must always answer.
|
|
72
|
+
expect(isRateLimitExemptEndpoint("health")).toBe(true);
|
|
73
|
+
expect(isRateLimitExemptEndpoint("healthz")).toBe(true);
|
|
74
|
+
expect(isRateLimitExemptEndpoint("readyz")).toBe(true);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("does not exempt ordinary data endpoints", () => {
|
|
78
|
+
expect(isRateLimitExemptEndpoint("messages")).toBe(false);
|
|
79
|
+
expect(isRateLimitExemptEndpoint("conversations")).toBe(false);
|
|
80
|
+
expect(isRateLimitExemptEndpoint("home/feed")).toBe(false);
|
|
81
|
+
// Match is exact on the normalized endpoint segment, not a prefix.
|
|
82
|
+
expect(isRateLimitExemptEndpoint("events/replay")).toBe(false);
|
|
83
|
+
expect(isRateLimitExemptEndpoint("")).toBe(false);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -220,6 +220,36 @@ export function selectAuthenticatedRateLimiter(
|
|
|
220
220
|
return isLoopbackAddress(clientIp) ? loopbackApiRateLimiter : apiRateLimiter;
|
|
221
221
|
}
|
|
222
222
|
|
|
223
|
+
/**
|
|
224
|
+
* `/v1/` endpoints that bypass the per-minute request rate limiter.
|
|
225
|
+
*
|
|
226
|
+
* - Liveness/readiness (`health`, `healthz`, `readyz`): cheap probes that
|
|
227
|
+
* must always answer. The desktop app polls `/v1/health` every few seconds
|
|
228
|
+
* and the reachability probe hits `/v1/healthz`; a 429 makes the client
|
|
229
|
+
* treat the assistant as unreachable and reconnect harder.
|
|
230
|
+
* - SSE stream (`events`): a single long-lived streaming connection, not a
|
|
231
|
+
* burst of discrete requests. Metering each (re)connect against the
|
|
232
|
+
* per-minute budget is the wrong model — and 429-ing the stream drops it,
|
|
233
|
+
* which drives a client reconnect + full re-bootstrap loop that generates
|
|
234
|
+
* far more load than the limiter saves. The events route still enforces
|
|
235
|
+
* auth downstream (an unauthenticated stream request is rejected there),
|
|
236
|
+
* and daemon memory is bounded by SSE backpressure shedding and subscriber
|
|
237
|
+
* caps rather than by this request-count limiter.
|
|
238
|
+
*
|
|
239
|
+
* The argument is the `/v1/`-stripped, trailing-slash-normalized endpoint
|
|
240
|
+
* segment (e.g. `events`, `health`) as computed by the HTTP server.
|
|
241
|
+
*/
|
|
242
|
+
const RATE_LIMIT_EXEMPT_ENDPOINTS = new Set([
|
|
243
|
+
"events",
|
|
244
|
+
"health",
|
|
245
|
+
"healthz",
|
|
246
|
+
"readyz",
|
|
247
|
+
]);
|
|
248
|
+
|
|
249
|
+
export function isRateLimitExemptEndpoint(endpoint: string): boolean {
|
|
250
|
+
return RATE_LIMIT_EXEMPT_ENDPOINTS.has(endpoint);
|
|
251
|
+
}
|
|
252
|
+
|
|
223
253
|
/**
|
|
224
254
|
* Extract the client IP from a request. Only trusts proxy headers
|
|
225
255
|
* (X-Forwarded-For, X-Real-IP) when the peer IP is loopback or private,
|