@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
|
@@ -14,10 +14,16 @@
|
|
|
14
14
|
import { answerCall } from "../calls/call-domain.js";
|
|
15
15
|
import {
|
|
16
16
|
type CanonicalGuardianRequest,
|
|
17
|
+
type CanonicalRequestStatus,
|
|
17
18
|
getCanonicalGuardianRequest,
|
|
19
|
+
resolveCanonicalGuardianRequest,
|
|
18
20
|
} from "../contacts/canonical-guardian-store.js";
|
|
19
21
|
import { findContactChannel } from "../contacts/contact-store.js";
|
|
20
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
activateMemberChannel,
|
|
24
|
+
blockSenderChannel,
|
|
25
|
+
seedUnverifiedMemberChannel,
|
|
26
|
+
} from "../contacts/member-write-relay.js";
|
|
21
27
|
import { findConversation } from "../daemon/conversation-registry.js";
|
|
22
28
|
import { emitNotificationSignal } from "../notifications/emit-signal.js";
|
|
23
29
|
import {
|
|
@@ -30,9 +36,16 @@ import type {
|
|
|
30
36
|
} from "../notifications/trusted-contact-payloads.js";
|
|
31
37
|
import type { UserDecision } from "../permissions/types.js";
|
|
32
38
|
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
|
|
33
|
-
import
|
|
39
|
+
import {
|
|
40
|
+
type ApprovalAction,
|
|
41
|
+
DENYING_ACTION_SET,
|
|
42
|
+
} from "../runtime/channel-approval-types.js";
|
|
34
43
|
import { createOutboundSession } from "../runtime/channel-verification-service.js";
|
|
35
44
|
import { deliverChannelReply } from "../runtime/gateway-client.js";
|
|
45
|
+
import {
|
|
46
|
+
parseRequesterSignals,
|
|
47
|
+
resolveTrustBinding,
|
|
48
|
+
} from "../runtime/introduction-policy.js";
|
|
36
49
|
import * as pendingInteractions from "../runtime/pending-interactions.js";
|
|
37
50
|
import { TC_GRANT_WAIT_MAX_MS } from "../tools/tool-approval-handler.js";
|
|
38
51
|
import { getLogger } from "../util/logger.js";
|
|
@@ -60,6 +73,22 @@ function shouldUseEphemeral(sourceChannel: string, chatId: string): boolean {
|
|
|
60
73
|
return sourceChannel === "slack" && chatId.startsWith("C");
|
|
61
74
|
}
|
|
62
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Strip the `threadTs` query param from a reply callback URL. The param
|
|
78
|
+
* addresses the guardian's channel thread; reusing it for a DM delivery
|
|
79
|
+
* raises `thread_not_found`. Relative or malformed URLs are returned as-is —
|
|
80
|
+
* they carry no threadTs to strip.
|
|
81
|
+
*/
|
|
82
|
+
function stripThreadTsParam(replyCallbackUrl: string): string {
|
|
83
|
+
try {
|
|
84
|
+
const url = new URL(replyCallbackUrl);
|
|
85
|
+
url.searchParams.delete("threadTs");
|
|
86
|
+
return url.toString();
|
|
87
|
+
} catch {
|
|
88
|
+
return replyCallbackUrl;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
63
92
|
/**
|
|
64
93
|
* Deliver the verification code straight to the requester's Slack DM so the
|
|
65
94
|
* guardian is never an out-of-band courier for the secret.
|
|
@@ -82,15 +111,7 @@ async function deliverVerificationCodeToSlackRequester(params: {
|
|
|
82
111
|
verificationCode: string;
|
|
83
112
|
assistantId: string;
|
|
84
113
|
}): Promise<boolean> {
|
|
85
|
-
|
|
86
|
-
try {
|
|
87
|
-
const url = new URL(params.replyCallbackUrl);
|
|
88
|
-
url.searchParams.delete("threadTs");
|
|
89
|
-
callbackUrl = url.toString();
|
|
90
|
-
} catch {
|
|
91
|
-
// Relative path (e.g. the desktop "/deliver/slack" target) — use as-is;
|
|
92
|
-
// it carries no threadTs to strip.
|
|
93
|
-
}
|
|
114
|
+
const callbackUrl = stripThreadTsParam(params.replyCallbackUrl);
|
|
94
115
|
|
|
95
116
|
try {
|
|
96
117
|
await deliverChannelReply(callbackUrl, {
|
|
@@ -298,8 +319,9 @@ const pendingInteractionResolver: GuardianRequestResolver = {
|
|
|
298
319
|
|
|
299
320
|
// Map action to the permission system's UserDecision type and notify session.
|
|
300
321
|
// resolveConfirmation() owns pendingInteractions deregistration.
|
|
301
|
-
const userDecision: UserDecision =
|
|
302
|
-
|
|
322
|
+
const userDecision: UserDecision = DENYING_ACTION_SET.has(decision.action)
|
|
323
|
+
? "deny"
|
|
324
|
+
: "allow";
|
|
303
325
|
|
|
304
326
|
// Route-owned confirmations (e.g. the ACP spawn/steer approval gate in
|
|
305
327
|
// acp-routes.ts) carry a `directResolve` and are NOT owned by any
|
|
@@ -435,20 +457,216 @@ const pendingQuestionResolver: GuardianRequestResolver = {
|
|
|
435
457
|
};
|
|
436
458
|
|
|
437
459
|
/**
|
|
438
|
-
*
|
|
460
|
+
* The four introduction-card outcomes for an access request. The generic
|
|
461
|
+
* decision pair maps onto them: `approve_once` → `verify_code` (handshake),
|
|
462
|
+
* `reject` → `leave_unverified`.
|
|
463
|
+
*/
|
|
464
|
+
type IntroductionOutcome =
|
|
465
|
+
| "verify_code"
|
|
466
|
+
| "trust"
|
|
467
|
+
| "leave_unverified"
|
|
468
|
+
| "block";
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Wire action → introduction outcome. Exhaustive over `ApprovalAction` so a
|
|
472
|
+
* future action addition fails to compile here instead of silently falling
|
|
473
|
+
* into a default outcome.
|
|
474
|
+
*/
|
|
475
|
+
const OUTCOME_BY_ACTION = {
|
|
476
|
+
approve_once: "verify_code",
|
|
477
|
+
verify_code: "verify_code",
|
|
478
|
+
trust: "trust",
|
|
479
|
+
reject: "leave_unverified",
|
|
480
|
+
leave_unverified: "leave_unverified",
|
|
481
|
+
block: "block",
|
|
482
|
+
} as const satisfies Record<ApprovalAction, IntroductionOutcome>;
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Reopen an access request whose gateway-side persist failed after the CAS
|
|
486
|
+
* already committed a terminal status. Leaving the row terminal would lie
|
|
487
|
+
* about the ACL state: a `denied` row from a failed Block permanently
|
|
488
|
+
* suppresses re-prompts for the sender (isAccessRequestDenied) even though
|
|
489
|
+
* the revoke never landed, and an `approved` row from a failed activation
|
|
490
|
+
* suppresses re-prompts for the verification window. Reopening keeps the
|
|
491
|
+
* request decidable (the request code stays live) and lets the expiry sweep
|
|
492
|
+
* re-enable discovery if the guardian never retries.
|
|
439
493
|
*
|
|
440
|
-
*
|
|
441
|
-
*
|
|
442
|
-
|
|
494
|
+
* CAS-guarded on the status this decision committed, so a concurrent writer
|
|
495
|
+
* is never clobbered.
|
|
496
|
+
*/
|
|
497
|
+
function reopenAccessRequestAfterFailedPersist(
|
|
498
|
+
requestId: string,
|
|
499
|
+
fromStatus: CanonicalRequestStatus,
|
|
500
|
+
): void {
|
|
501
|
+
const reopened = resolveCanonicalGuardianRequest(requestId, fromStatus, {
|
|
502
|
+
status: "pending",
|
|
503
|
+
});
|
|
504
|
+
if (!reopened) {
|
|
505
|
+
log.warn(
|
|
506
|
+
{ event: "access_request_reopen_failed", requestId, fromStatus },
|
|
507
|
+
"Failed to reopen access request after gateway persist failure",
|
|
508
|
+
);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Deliver a requester-facing decision notice. On-channel decisions reply via
|
|
514
|
+
* the channel delivery context (ephemeral on Slack shared channels);
|
|
515
|
+
* off-channel (desktop) decisions post via the channel's deliver URL — on
|
|
516
|
+
* Slack routed to the requester's user ID so the notice opens a DM instead
|
|
517
|
+
* of posting into a shared channel. Delivery failures are logged, never
|
|
518
|
+
* thrown: the notice is best-effort and must not fail the decision.
|
|
519
|
+
*/
|
|
520
|
+
async function deliverRequesterNotice(params: {
|
|
521
|
+
channel: NotificationSourceChannel;
|
|
522
|
+
requesterChatId: string;
|
|
523
|
+
requesterExternalUserId: string;
|
|
524
|
+
assistantId: string;
|
|
525
|
+
channelDeliveryContext: ChannelDeliveryContext | undefined;
|
|
526
|
+
desktopDeliverUrl: string | null;
|
|
527
|
+
text: string;
|
|
528
|
+
}): Promise<void> {
|
|
529
|
+
const {
|
|
530
|
+
channel,
|
|
531
|
+
requesterChatId,
|
|
532
|
+
requesterExternalUserId,
|
|
533
|
+
assistantId,
|
|
534
|
+
channelDeliveryContext,
|
|
535
|
+
desktopDeliverUrl,
|
|
536
|
+
text,
|
|
537
|
+
} = params;
|
|
538
|
+
|
|
539
|
+
if (channelDeliveryContext) {
|
|
540
|
+
try {
|
|
541
|
+
await deliverChannelReply(
|
|
542
|
+
channelDeliveryContext.replyCallbackUrl,
|
|
543
|
+
buildRequesterChannelNotice({
|
|
544
|
+
channel,
|
|
545
|
+
requesterChatId,
|
|
546
|
+
requesterExternalUserId,
|
|
547
|
+
text,
|
|
548
|
+
assistantId,
|
|
549
|
+
}),
|
|
550
|
+
);
|
|
551
|
+
} catch (err) {
|
|
552
|
+
log.error(
|
|
553
|
+
{ err, requesterChatId },
|
|
554
|
+
"Failed to deliver requester decision notice",
|
|
555
|
+
);
|
|
556
|
+
}
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
if (desktopDeliverUrl && requesterChatId) {
|
|
561
|
+
const targetChatId =
|
|
562
|
+
channel === "slack" && requesterExternalUserId
|
|
563
|
+
? requesterExternalUserId
|
|
564
|
+
: requesterChatId;
|
|
565
|
+
try {
|
|
566
|
+
await deliverChannelReply(desktopDeliverUrl, {
|
|
567
|
+
chatId: targetChatId,
|
|
568
|
+
text,
|
|
569
|
+
assistantId,
|
|
570
|
+
});
|
|
571
|
+
} catch (err) {
|
|
572
|
+
log.error(
|
|
573
|
+
{ err, requesterChatId },
|
|
574
|
+
"Failed to deliver requester decision notice (desktop decision path)",
|
|
575
|
+
);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* Deliver the "denied" notice to the requester and emit the denial lifecycle
|
|
582
|
+
* signals. Shared by the `leave_unverified` and `block` outcomes — both look
|
|
583
|
+
* identical to the requester (the block is not revealed).
|
|
584
|
+
*/
|
|
585
|
+
async function notifyRequesterOfDenial(params: {
|
|
586
|
+
channel: NotificationSourceChannel;
|
|
587
|
+
requesterChatId: string;
|
|
588
|
+
requesterExternalUserId: string;
|
|
589
|
+
assistantId: string;
|
|
590
|
+
channelDeliveryContext: ChannelDeliveryContext | undefined;
|
|
591
|
+
desktopDeliverUrl: string | null;
|
|
592
|
+
deniedPayload: TrustedContactDecisionPayload;
|
|
593
|
+
requestId: string;
|
|
594
|
+
conversationId: string | null;
|
|
595
|
+
}): Promise<void> {
|
|
596
|
+
const {
|
|
597
|
+
channel,
|
|
598
|
+
requesterChatId,
|
|
599
|
+
requesterExternalUserId,
|
|
600
|
+
assistantId,
|
|
601
|
+
channelDeliveryContext,
|
|
602
|
+
desktopDeliverUrl,
|
|
603
|
+
deniedPayload,
|
|
604
|
+
requestId,
|
|
605
|
+
conversationId,
|
|
606
|
+
} = params;
|
|
607
|
+
|
|
608
|
+
await deliverRequesterNotice({
|
|
609
|
+
channel,
|
|
610
|
+
requesterChatId,
|
|
611
|
+
requesterExternalUserId,
|
|
612
|
+
assistantId,
|
|
613
|
+
channelDeliveryContext,
|
|
614
|
+
desktopDeliverUrl,
|
|
615
|
+
text: "Your access request has been denied.",
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
if (channelDeliveryContext) {
|
|
619
|
+
void emitNotificationSignal({
|
|
620
|
+
sourceEventName: "ingress.trusted_contact.guardian_decision",
|
|
621
|
+
sourceChannel: channel,
|
|
622
|
+
sourceContextId: conversationId ?? "",
|
|
623
|
+
attentionHints: {
|
|
624
|
+
requiresAction: false,
|
|
625
|
+
urgency: "medium",
|
|
626
|
+
isAsyncBackground: false,
|
|
627
|
+
visibleInSourceNow: false,
|
|
628
|
+
},
|
|
629
|
+
contextPayload: deniedPayload,
|
|
630
|
+
dedupeKey: `trusted-contact:guardian-decision:${requestId}`,
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
void emitNotificationSignal({
|
|
634
|
+
sourceEventName: "ingress.trusted_contact.denied",
|
|
635
|
+
sourceChannel: channel,
|
|
636
|
+
sourceContextId: conversationId ?? "",
|
|
637
|
+
attentionHints: {
|
|
638
|
+
requiresAction: false,
|
|
639
|
+
urgency: "low",
|
|
640
|
+
isAsyncBackground: false,
|
|
641
|
+
visibleInSourceNow: false,
|
|
642
|
+
},
|
|
643
|
+
contextPayload: deniedPayload,
|
|
644
|
+
dedupeKey: `trusted-contact:denied:${requestId}`,
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Resolves `access_request` requests — the introduction card's trust-setting
|
|
651
|
+
* decision for a first-contact sender.
|
|
443
652
|
*
|
|
444
|
-
*
|
|
653
|
+
* Four outcomes (see `introduction-policy.ts`):
|
|
654
|
+
* - `verify_code` (also reached via `approve_once`): mints an identity-bound
|
|
655
|
+
* verification session so the requester proves control of the channel.
|
|
656
|
+
* - `trust`: activates the contact directly, no code. `verifiedVia` records
|
|
657
|
+
* the binding strength: `manual` for a workspace-vouched identity,
|
|
658
|
+
* `manual_channel_claim` for an external/stranger the platform is not
|
|
659
|
+
* vouching for.
|
|
660
|
+
* - `leave_unverified` (also reached via `reject`): persists the sender as an
|
|
661
|
+
* `unverified_contact` so discovery does not re-fire.
|
|
662
|
+
* - `block`: persists the sender's channel as `revoked` (gateway ACL is the
|
|
663
|
+
* source of truth).
|
|
445
664
|
*
|
|
446
|
-
*
|
|
447
|
-
*
|
|
448
|
-
* and emits lifecycle notification signals.
|
|
665
|
+
* A bot requester can never return a code, so handshake approvals are
|
|
666
|
+
* coerced to direct trust.
|
|
449
667
|
*
|
|
450
|
-
*
|
|
451
|
-
*
|
|
668
|
+
* When a `channelDeliveryContext` is provided (channel path), the resolver
|
|
669
|
+
* also delivers codes/notices on-channel and emits lifecycle signals.
|
|
452
670
|
*/
|
|
453
671
|
const accessRequestResolver: GuardianRequestResolver = {
|
|
454
672
|
kind: "access_request",
|
|
@@ -493,104 +711,137 @@ const accessRequestResolver: GuardianRequestResolver = {
|
|
|
493
711
|
const decidedByDisplayName =
|
|
494
712
|
decidedByContactResult?.contact.displayName ?? null;
|
|
495
713
|
|
|
496
|
-
|
|
714
|
+
const signals = parseRequesterSignals(request.requesterSignals);
|
|
715
|
+
let outcome: IntroductionOutcome = OUTCOME_BY_ACTION[decision.action];
|
|
716
|
+
|
|
717
|
+
// A bot cannot return a verification code, so a handshake approval on a
|
|
718
|
+
// bot requester can never complete. Coerce it to direct trust — the
|
|
719
|
+
// guardian's intent ("let it in") is unambiguous.
|
|
720
|
+
if (outcome === "verify_code" && signals.isBot === true) {
|
|
497
721
|
log.info(
|
|
498
|
-
{
|
|
499
|
-
|
|
722
|
+
{
|
|
723
|
+
event: "resolver_access_request_bot_coercion",
|
|
724
|
+
requestId: request.id,
|
|
725
|
+
action: decision.action,
|
|
726
|
+
},
|
|
727
|
+
"Access request resolver: handshake approval on a bot coerced to direct trust",
|
|
500
728
|
);
|
|
729
|
+
outcome = "trust";
|
|
730
|
+
}
|
|
501
731
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
text: "Your access request has been denied.",
|
|
512
|
-
assistantId,
|
|
513
|
-
}),
|
|
514
|
-
);
|
|
515
|
-
} catch (err) {
|
|
516
|
-
log.error(
|
|
517
|
-
{ err, requesterChatId },
|
|
518
|
-
"Failed to notify requester of access request denial",
|
|
519
|
-
);
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
const deniedPayload: TrustedContactDecisionPayload = {
|
|
523
|
-
sourceChannel: channel,
|
|
524
|
-
requesterExternalUserId,
|
|
525
|
-
requesterChatId,
|
|
526
|
-
decidedByExternalUserId,
|
|
527
|
-
requesterDisplayName,
|
|
528
|
-
decidedByDisplayName,
|
|
529
|
-
decision: "denied",
|
|
530
|
-
};
|
|
732
|
+
const deniedPayload: TrustedContactDecisionPayload = {
|
|
733
|
+
sourceChannel: channel,
|
|
734
|
+
requesterExternalUserId,
|
|
735
|
+
requesterChatId,
|
|
736
|
+
decidedByExternalUserId,
|
|
737
|
+
requesterDisplayName,
|
|
738
|
+
decidedByDisplayName,
|
|
739
|
+
decision: "denied",
|
|
740
|
+
};
|
|
531
741
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
requiresAction: false,
|
|
538
|
-
urgency: "medium",
|
|
539
|
-
isAsyncBackground: false,
|
|
540
|
-
visibleInSourceNow: false,
|
|
541
|
-
},
|
|
542
|
-
contextPayload: deniedPayload,
|
|
543
|
-
dedupeKey: `trusted-contact:guardian-decision:${request.id}`,
|
|
544
|
-
});
|
|
742
|
+
if (outcome === "leave_unverified") {
|
|
743
|
+
log.info(
|
|
744
|
+
{ event: "resolver_access_request_denied", requestId: request.id },
|
|
745
|
+
"Access request resolver: leave unverified",
|
|
746
|
+
);
|
|
545
747
|
|
|
546
|
-
|
|
547
|
-
|
|
748
|
+
// Persist the denied sender as an unverified_contact (gateway-first).
|
|
749
|
+
// Denial is a terminal decision: the sender becomes a known, unverified
|
|
750
|
+
// contact so future inbound resolves as unverified_contact rather than
|
|
751
|
+
// re-triggering discovery. Paired with the denied-request suppression in
|
|
752
|
+
// notifyGuardianOfAccessRequest, this stops the prompt from re-firing on
|
|
753
|
+
// every subsequent DM. The guardian can still verify them later. Skipped
|
|
754
|
+
// for desktop-origin (vellum) requests, which carry no channel identity.
|
|
755
|
+
if (requesterExternalUserId && channel !== "vellum") {
|
|
756
|
+
await seedUnverifiedMemberChannel({
|
|
548
757
|
sourceChannel: channel,
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
isAsyncBackground: false,
|
|
554
|
-
visibleInSourceNow: false,
|
|
555
|
-
},
|
|
556
|
-
contextPayload: deniedPayload,
|
|
557
|
-
dedupeKey: `trusted-contact:denied:${request.id}`,
|
|
758
|
+
externalUserId: requesterExternalUserId,
|
|
759
|
+
...(requesterDisplayName
|
|
760
|
+
? { displayName: requesterDisplayName }
|
|
761
|
+
: {}),
|
|
558
762
|
});
|
|
559
|
-
} else if (desktopDeliverUrl && requesterChatId) {
|
|
560
|
-
// For Slack, route to DM via requesterExternalUserId (user ID) instead
|
|
561
|
-
// of requesterChatId (channel ID) to avoid posting in public channels.
|
|
562
|
-
const targetChatId =
|
|
563
|
-
channel === "slack" && requesterExternalUserId
|
|
564
|
-
? requesterExternalUserId
|
|
565
|
-
: requesterChatId;
|
|
566
|
-
try {
|
|
567
|
-
await deliverChannelReply(desktopDeliverUrl, {
|
|
568
|
-
chatId: targetChatId,
|
|
569
|
-
text: "Your access request has been denied.",
|
|
570
|
-
assistantId,
|
|
571
|
-
});
|
|
572
|
-
} catch (err) {
|
|
573
|
-
log.error(
|
|
574
|
-
{ err, requesterChatId },
|
|
575
|
-
"Failed to notify requester of access request denial (desktop decision path)",
|
|
576
|
-
);
|
|
577
|
-
}
|
|
578
763
|
}
|
|
579
764
|
|
|
765
|
+
await notifyRequesterOfDenial({
|
|
766
|
+
channel,
|
|
767
|
+
requesterChatId,
|
|
768
|
+
requesterExternalUserId,
|
|
769
|
+
assistantId,
|
|
770
|
+
channelDeliveryContext,
|
|
771
|
+
desktopDeliverUrl,
|
|
772
|
+
deniedPayload,
|
|
773
|
+
requestId: request.id,
|
|
774
|
+
conversationId: request.conversationId,
|
|
775
|
+
});
|
|
776
|
+
|
|
580
777
|
return {
|
|
581
778
|
ok: true,
|
|
582
779
|
applied: true,
|
|
583
780
|
// Desktop actors (vellum channel) receive inline reply text; channel
|
|
584
781
|
// actors get replies delivered via the channel delivery context.
|
|
585
782
|
...(ctx.actor.channel === "vellum"
|
|
586
|
-
? {
|
|
783
|
+
? {
|
|
784
|
+
guardianReplyText: `${requesterLabel} will stay unverified. They won't be able to message the assistant.`,
|
|
785
|
+
}
|
|
786
|
+
: {}),
|
|
787
|
+
};
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
if (outcome === "block") {
|
|
791
|
+
log.info(
|
|
792
|
+
{ event: "resolver_access_request_blocked", requestId: request.id },
|
|
793
|
+
"Access request resolver: block",
|
|
794
|
+
);
|
|
795
|
+
|
|
796
|
+
if (!requesterExternalUserId || channel === "vellum") {
|
|
797
|
+
// No channel identity to revoke — nothing landed on the gateway, so
|
|
798
|
+
// the request must not stay terminally denied.
|
|
799
|
+
reopenAccessRequestAfterFailedPersist(request.id, "denied");
|
|
800
|
+
return { ok: false, reason: "block_missing_channel_identity" };
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// Gateway-first: persist the revoked verdict on the ACL source of
|
|
804
|
+
// truth. Fail closed — a block the gateway did not persist must not be
|
|
805
|
+
// reported as applied.
|
|
806
|
+
const blockResult = await blockSenderChannel({
|
|
807
|
+
sourceChannel: channel,
|
|
808
|
+
externalUserId: requesterExternalUserId,
|
|
809
|
+
...(requesterDisplayName ? { displayName: requesterDisplayName } : {}),
|
|
810
|
+
reason: "introduction_block",
|
|
811
|
+
});
|
|
812
|
+
if (!blockResult.revoked) {
|
|
813
|
+
reopenAccessRequestAfterFailedPersist(request.id, "denied");
|
|
814
|
+
return { ok: false, reason: "block_persist_failed" };
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
// The requester sees the same denial notice as leave-unverified — the
|
|
818
|
+
// block itself is not revealed.
|
|
819
|
+
await notifyRequesterOfDenial({
|
|
820
|
+
channel,
|
|
821
|
+
requesterChatId,
|
|
822
|
+
requesterExternalUserId,
|
|
823
|
+
assistantId,
|
|
824
|
+
channelDeliveryContext,
|
|
825
|
+
desktopDeliverUrl,
|
|
826
|
+
deniedPayload,
|
|
827
|
+
requestId: request.id,
|
|
828
|
+
conversationId: request.conversationId,
|
|
829
|
+
});
|
|
830
|
+
|
|
831
|
+
return {
|
|
832
|
+
ok: true,
|
|
833
|
+
applied: true,
|
|
834
|
+
...(ctx.actor.channel === "vellum"
|
|
835
|
+
? {
|
|
836
|
+
guardianReplyText: `Blocked ${requesterLabel}. Their messages will no longer reach the assistant.`,
|
|
837
|
+
}
|
|
587
838
|
: {}),
|
|
588
839
|
};
|
|
589
840
|
}
|
|
590
841
|
|
|
591
842
|
// Voice approvals: directly activate the trusted contact without minting
|
|
592
843
|
// a verification session. The caller is already on the line and the
|
|
593
|
-
//
|
|
844
|
+
// call setup flow's in-call wait loop will detect the approved status.
|
|
594
845
|
if (channel === "phone") {
|
|
595
846
|
let activation: Awaited<ReturnType<typeof activateMemberChannel>>;
|
|
596
847
|
try {
|
|
@@ -606,6 +857,7 @@ const accessRequestResolver: GuardianRequestResolver = {
|
|
|
606
857
|
{ err, requesterExternalUserId },
|
|
607
858
|
"Access request resolver: failed to activate voice caller as trusted contact",
|
|
608
859
|
);
|
|
860
|
+
reopenAccessRequestAfterFailedPersist(request.id, "approved");
|
|
609
861
|
return { ok: false, reason: "voice_activation_failed" };
|
|
610
862
|
}
|
|
611
863
|
|
|
@@ -616,6 +868,7 @@ const accessRequestResolver: GuardianRequestResolver = {
|
|
|
616
868
|
{ requesterExternalUserId },
|
|
617
869
|
"Access request resolver: gateway refused voice caller activation",
|
|
618
870
|
);
|
|
871
|
+
reopenAccessRequestAfterFailedPersist(request.id, "approved");
|
|
619
872
|
return { ok: false, reason: "voice_activation_refused" };
|
|
620
873
|
}
|
|
621
874
|
|
|
@@ -643,6 +896,96 @@ const accessRequestResolver: GuardianRequestResolver = {
|
|
|
643
896
|
};
|
|
644
897
|
}
|
|
645
898
|
|
|
899
|
+
// Direct trust: activate the contact without a handshake. The binding
|
|
900
|
+
// strength is derived from the platform's identity signals — a
|
|
901
|
+
// workspace-vouched identity records `manual` (internal_workspace_match);
|
|
902
|
+
// an external/stranger records `manual_channel_claim`
|
|
903
|
+
// (inbound_channel_claim), never handshake-equivalent provenance.
|
|
904
|
+
if (outcome === "trust") {
|
|
905
|
+
// A trust without a channel identity cannot land on the gateway ACL —
|
|
906
|
+
// the local mirror alone would report a success the source of truth
|
|
907
|
+
// never recorded. Fail closed, mirroring the block guard.
|
|
908
|
+
if (!requesterExternalUserId || channel === "vellum") {
|
|
909
|
+
reopenAccessRequestAfterFailedPersist(request.id, "approved");
|
|
910
|
+
return { ok: false, reason: "trust_missing_channel_identity" };
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
const binding = resolveTrustBinding(channel, signals);
|
|
914
|
+
|
|
915
|
+
let activation: Awaited<ReturnType<typeof activateMemberChannel>>;
|
|
916
|
+
try {
|
|
917
|
+
activation = await activateMemberChannel({
|
|
918
|
+
sourceChannel: channel,
|
|
919
|
+
externalUserId: requesterExternalUserId,
|
|
920
|
+
externalChatId: requesterChatId,
|
|
921
|
+
...(requesterDisplayName
|
|
922
|
+
? { displayName: requesterDisplayName }
|
|
923
|
+
: {}),
|
|
924
|
+
verifiedVia: binding.verifiedVia,
|
|
925
|
+
});
|
|
926
|
+
} catch (err) {
|
|
927
|
+
log.error(
|
|
928
|
+
{ err, requesterExternalUserId },
|
|
929
|
+
"Access request resolver: failed to activate directly-trusted contact",
|
|
930
|
+
);
|
|
931
|
+
reopenAccessRequestAfterFailedPersist(request.id, "approved");
|
|
932
|
+
return { ok: false, reason: "trust_activation_failed" };
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
// Fail-closed: a refused activation did not land on the gateway source
|
|
936
|
+
// of truth, so the sender is not actually trusted.
|
|
937
|
+
if (activation.status === "refused") {
|
|
938
|
+
log.error(
|
|
939
|
+
{ requesterExternalUserId },
|
|
940
|
+
"Access request resolver: gateway refused direct-trust activation",
|
|
941
|
+
);
|
|
942
|
+
reopenAccessRequestAfterFailedPersist(request.id, "approved");
|
|
943
|
+
return { ok: false, reason: "trust_activation_refused" };
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
log.info(
|
|
947
|
+
{
|
|
948
|
+
event: "resolver_access_request_trusted",
|
|
949
|
+
requestId: request.id,
|
|
950
|
+
channel,
|
|
951
|
+
requesterExternalUserId,
|
|
952
|
+
verifiedVia: binding.verifiedVia,
|
|
953
|
+
bindingStrength: binding.bindingStrength,
|
|
954
|
+
isBot: signals.isBot === true,
|
|
955
|
+
},
|
|
956
|
+
"Access request resolver: direct trust — contact activated without handshake",
|
|
957
|
+
);
|
|
958
|
+
|
|
959
|
+
// Notify the requester they're in.
|
|
960
|
+
await deliverRequesterNotice({
|
|
961
|
+
channel,
|
|
962
|
+
requesterChatId,
|
|
963
|
+
requesterExternalUserId,
|
|
964
|
+
assistantId,
|
|
965
|
+
channelDeliveryContext,
|
|
966
|
+
desktopDeliverUrl,
|
|
967
|
+
text: "Your access request has been approved. You can message the assistant here.",
|
|
968
|
+
});
|
|
969
|
+
|
|
970
|
+
return {
|
|
971
|
+
ok: true,
|
|
972
|
+
applied: true,
|
|
973
|
+
activatedContact: {
|
|
974
|
+
sourceChannel: channel,
|
|
975
|
+
externalUserId: requesterExternalUserId,
|
|
976
|
+
...(requesterChatId ? { externalChatId: requesterChatId } : {}),
|
|
977
|
+
...(requesterDisplayName
|
|
978
|
+
? { displayName: requesterDisplayName }
|
|
979
|
+
: {}),
|
|
980
|
+
},
|
|
981
|
+
...(ctx.actor.channel === "vellum"
|
|
982
|
+
? {
|
|
983
|
+
guardianReplyText: `Trusted ${requesterLabel}. They can now message the assistant — no verification code needed.`,
|
|
984
|
+
}
|
|
985
|
+
: {}),
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
|
|
646
989
|
// Non-voice approvals: mint an identity-bound verification session so the
|
|
647
990
|
// requester can verify their identity.
|
|
648
991
|
const session = createOutboundSession({
|
|
@@ -713,16 +1056,9 @@ const accessRequestResolver: GuardianRequestResolver = {
|
|
|
713
1056
|
guardianUserId &&
|
|
714
1057
|
!channelDeliveryContext.guardianChatId.startsWith("D")
|
|
715
1058
|
) {
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
try {
|
|
720
|
-
const url = new URL(channelDeliveryContext.replyCallbackUrl);
|
|
721
|
-
url.searchParams.delete("threadTs");
|
|
722
|
-
dmCallbackUrl = url.toString();
|
|
723
|
-
} catch {
|
|
724
|
-
// Malformed URL — use as-is
|
|
725
|
-
}
|
|
1059
|
+
const dmCallbackUrl = stripThreadTsParam(
|
|
1060
|
+
channelDeliveryContext.replyCallbackUrl,
|
|
1061
|
+
);
|
|
726
1062
|
|
|
727
1063
|
try {
|
|
728
1064
|
await deliverChannelReply(dmCallbackUrl, {
|
|
@@ -739,18 +1075,10 @@ const accessRequestResolver: GuardianRequestResolver = {
|
|
|
739
1075
|
}
|
|
740
1076
|
}
|
|
741
1077
|
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
try {
|
|
747
|
-
const url = new URL(channelDeliveryContext.replyCallbackUrl);
|
|
748
|
-
url.searchParams.delete("threadTs");
|
|
749
|
-
requesterCallbackUrl = url.toString();
|
|
750
|
-
} catch {
|
|
751
|
-
// Malformed URL — use as-is
|
|
752
|
-
}
|
|
753
|
-
}
|
|
1078
|
+
const requesterCallbackUrl =
|
|
1079
|
+
channel === "slack" && requesterExternalUserId
|
|
1080
|
+
? stripThreadTsParam(channelDeliveryContext.replyCallbackUrl)
|
|
1081
|
+
: channelDeliveryContext.replyCallbackUrl;
|
|
754
1082
|
|
|
755
1083
|
if (codeDelivered) {
|
|
756
1084
|
// On Slack, deliver the code straight to the requester's DM so the
|
package/src/apps/app-store.ts
CHANGED
|
@@ -986,6 +986,7 @@ export function backfillAppConversationIds(): void {
|
|
|
986
986
|
|
|
987
987
|
try {
|
|
988
988
|
const rows = rawAll<{ conversation_id: string; content: string }>(
|
|
989
|
+
"apps:backfillConversationIds",
|
|
989
990
|
`SELECT conversation_id, content FROM messages WHERE content LIKE '%"type":"ui_surface"%'`,
|
|
990
991
|
);
|
|
991
992
|
|