@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
|
@@ -87,6 +87,13 @@ interface WakeConversationProbe {
|
|
|
87
87
|
* persistent `setTrustContext`) and restores the prior value in its finally.
|
|
88
88
|
*/
|
|
89
89
|
turnTrustContextSets: Array<{ ctx: unknown; order: number }>;
|
|
90
|
+
/**
|
|
91
|
+
* `setTrustContext` writes to the persistent `conversation.trustContext`,
|
|
92
|
+
* in order. A trust-carrying wake's resolver leaves its trust here; the
|
|
93
|
+
* wake must put the prior value back so it doesn't linger for a later
|
|
94
|
+
* no-trust wake.
|
|
95
|
+
*/
|
|
96
|
+
trustContextSets: unknown[];
|
|
90
97
|
/**
|
|
91
98
|
* Every assignment to `conversation.wakePersonaOverride`, in order. A
|
|
92
99
|
* wake that applies an override records `[override, undefined]` — the
|
|
@@ -340,6 +347,10 @@ import type {
|
|
|
340
347
|
AgentLoopRunResult,
|
|
341
348
|
} from "../../agent/loop.js";
|
|
342
349
|
import type { Conversation } from "../../daemon/conversation.js";
|
|
350
|
+
import {
|
|
351
|
+
deleteConversation,
|
|
352
|
+
setConversation,
|
|
353
|
+
} from "../../daemon/conversation-registry.js";
|
|
343
354
|
import { ContextOverflowError, type Message } from "../../providers/types.js";
|
|
344
355
|
import {
|
|
345
356
|
__resetWakeChainForTests,
|
|
@@ -387,6 +398,8 @@ function makeWakeConversation(options: {
|
|
|
387
398
|
* (always under the mocked 200k window).
|
|
388
399
|
*/
|
|
389
400
|
estimatedInputTokens?: number;
|
|
401
|
+
/** Seed for the conversation's resting `trustContext`. */
|
|
402
|
+
initialTrustContext?: unknown;
|
|
390
403
|
}): WakeConversation {
|
|
391
404
|
const conversationId = options.conversationId ?? "conv-test";
|
|
392
405
|
const probe: WakeConversationProbe = {
|
|
@@ -401,6 +414,7 @@ function makeWakeConversation(options: {
|
|
|
401
414
|
processingDuringDrain: [],
|
|
402
415
|
allowedToolSnapshots: [],
|
|
403
416
|
turnTrustContextSets: [],
|
|
417
|
+
trustContextSets: [],
|
|
404
418
|
personaOverrideSets: [],
|
|
405
419
|
persistedAtEachEmit: [],
|
|
406
420
|
maybeCompactOrders: [],
|
|
@@ -413,6 +427,7 @@ function makeWakeConversation(options: {
|
|
|
413
427
|
let activeAllowedTools = options.initialAllowedTools;
|
|
414
428
|
let wakePersonaOverride: unknown;
|
|
415
429
|
let currentTurnTrustContext: unknown;
|
|
430
|
+
let persistentTrustContext: unknown = options.initialTrustContext;
|
|
416
431
|
const snapshotAllowedTools = (): string[] | undefined =>
|
|
417
432
|
activeAllowedTools ? [...activeAllowedTools].sort() : undefined;
|
|
418
433
|
|
|
@@ -526,7 +541,14 @@ function makeWakeConversation(options: {
|
|
|
526
541
|
},
|
|
527
542
|
getTurnChannelContext: () => null,
|
|
528
543
|
getTurnInterfaceContext: () => null,
|
|
529
|
-
trustContext
|
|
544
|
+
get trustContext() {
|
|
545
|
+
return persistentTrustContext;
|
|
546
|
+
},
|
|
547
|
+
// Mirrors Conversation.setTrustContext (coerces null → undefined).
|
|
548
|
+
setTrustContext(ctx: unknown) {
|
|
549
|
+
persistentTrustContext = ctx ?? undefined;
|
|
550
|
+
probe.trustContextSets.push(ctx);
|
|
551
|
+
},
|
|
530
552
|
buildCurrentSystemPrompt: () => "mock-system-prompt",
|
|
531
553
|
modelOverride: undefined,
|
|
532
554
|
...(drainQueue ? { drainQueue } : {}),
|
|
@@ -1535,6 +1557,141 @@ describe("wakeAgentForOpportunity", () => {
|
|
|
1535
1557
|
expect(conversation.currentTurnTrustContext).toBeUndefined();
|
|
1536
1558
|
});
|
|
1537
1559
|
|
|
1560
|
+
// ── Persistent-trust restore ────────────────────────────────────────
|
|
1561
|
+
// The resolver leaves the wake's trust on the conversation. The wake must
|
|
1562
|
+
// put the prior resting value back, or a later no-trust wake inherits it
|
|
1563
|
+
// through tool setup's `currentTurnTrustContext ?? trustContext` fallback.
|
|
1564
|
+
|
|
1565
|
+
const GUARDIAN_TRUST = {
|
|
1566
|
+
sourceChannel: "vellum",
|
|
1567
|
+
trustClass: "guardian",
|
|
1568
|
+
} as const;
|
|
1569
|
+
|
|
1570
|
+
// The wake reads the prior trust from the live registry, so a test that
|
|
1571
|
+
// wants to exercise the restore registers its double there and simulates
|
|
1572
|
+
// the resolver's write by setting the trust in resolveTarget.
|
|
1573
|
+
const withRegisteredConversation = async (
|
|
1574
|
+
conversation: WakeConversation,
|
|
1575
|
+
run: () => Promise<unknown>,
|
|
1576
|
+
): Promise<void> => {
|
|
1577
|
+
setConversation(conversation.conversationId, conversation as Conversation);
|
|
1578
|
+
try {
|
|
1579
|
+
await run();
|
|
1580
|
+
} finally {
|
|
1581
|
+
deleteConversation(conversation.conversationId);
|
|
1582
|
+
}
|
|
1583
|
+
};
|
|
1584
|
+
|
|
1585
|
+
test("restores the conversation's prior trust once the wake ends", async () => {
|
|
1586
|
+
const priorTrust = {
|
|
1587
|
+
sourceChannel: "slack",
|
|
1588
|
+
trustClass: "trusted_contact",
|
|
1589
|
+
} as const;
|
|
1590
|
+
const conversation = makeWakeConversation({
|
|
1591
|
+
conversationId: "conv-trust-restore",
|
|
1592
|
+
initialTrustContext: priorTrust,
|
|
1593
|
+
});
|
|
1594
|
+
|
|
1595
|
+
await withRegisteredConversation(conversation, () =>
|
|
1596
|
+
wakeAgentForOpportunity(
|
|
1597
|
+
{
|
|
1598
|
+
conversationId: "conv-trust-restore",
|
|
1599
|
+
hint: "x",
|
|
1600
|
+
source: "t",
|
|
1601
|
+
trustContext: GUARDIAN_TRUST,
|
|
1602
|
+
},
|
|
1603
|
+
{
|
|
1604
|
+
resolveTarget: async () => {
|
|
1605
|
+
conversation.setTrustContext(GUARDIAN_TRUST);
|
|
1606
|
+
return conversation;
|
|
1607
|
+
},
|
|
1608
|
+
},
|
|
1609
|
+
),
|
|
1610
|
+
);
|
|
1611
|
+
|
|
1612
|
+
// Resolver installs guardian, wake restores the prior value.
|
|
1613
|
+
expect(conversation.trustContextSets).toEqual([GUARDIAN_TRUST, priorTrust]);
|
|
1614
|
+
expect(conversation.trustContext).toEqual(priorTrust);
|
|
1615
|
+
});
|
|
1616
|
+
|
|
1617
|
+
test("restores the prior trust even when the agent loop throws", async () => {
|
|
1618
|
+
const conversation = makeWakeConversation({
|
|
1619
|
+
conversationId: "conv-trust-restore-throw",
|
|
1620
|
+
runImpl: async () => {
|
|
1621
|
+
throw new Error("boom");
|
|
1622
|
+
},
|
|
1623
|
+
});
|
|
1624
|
+
|
|
1625
|
+
await withRegisteredConversation(conversation, () =>
|
|
1626
|
+
wakeAgentForOpportunity(
|
|
1627
|
+
{
|
|
1628
|
+
conversationId: "conv-trust-restore-throw",
|
|
1629
|
+
hint: "x",
|
|
1630
|
+
source: "t",
|
|
1631
|
+
trustContext: GUARDIAN_TRUST,
|
|
1632
|
+
},
|
|
1633
|
+
{
|
|
1634
|
+
resolveTarget: async () => {
|
|
1635
|
+
conversation.setTrustContext(GUARDIAN_TRUST);
|
|
1636
|
+
return conversation;
|
|
1637
|
+
},
|
|
1638
|
+
},
|
|
1639
|
+
),
|
|
1640
|
+
);
|
|
1641
|
+
|
|
1642
|
+
// Nothing was resting before the wake, so it goes back to unset.
|
|
1643
|
+
expect(conversation.trustContext).toBeUndefined();
|
|
1644
|
+
});
|
|
1645
|
+
|
|
1646
|
+
test("leaves a trust that was re-set mid-run alone (identity guard)", async () => {
|
|
1647
|
+
const replaced = {
|
|
1648
|
+
sourceChannel: "vellum",
|
|
1649
|
+
trustClass: "unknown",
|
|
1650
|
+
} as const;
|
|
1651
|
+
const conversation = makeWakeConversation({
|
|
1652
|
+
conversationId: "conv-trust-guard",
|
|
1653
|
+
runImpl: async (input) => {
|
|
1654
|
+
conversation.setTrustContext(replaced);
|
|
1655
|
+
return runResult(input);
|
|
1656
|
+
},
|
|
1657
|
+
});
|
|
1658
|
+
|
|
1659
|
+
await withRegisteredConversation(conversation, () =>
|
|
1660
|
+
wakeAgentForOpportunity(
|
|
1661
|
+
{
|
|
1662
|
+
conversationId: "conv-trust-guard",
|
|
1663
|
+
hint: "x",
|
|
1664
|
+
source: "t",
|
|
1665
|
+
trustContext: GUARDIAN_TRUST,
|
|
1666
|
+
},
|
|
1667
|
+
{
|
|
1668
|
+
resolveTarget: async () => {
|
|
1669
|
+
conversation.setTrustContext(GUARDIAN_TRUST);
|
|
1670
|
+
return conversation;
|
|
1671
|
+
},
|
|
1672
|
+
},
|
|
1673
|
+
),
|
|
1674
|
+
);
|
|
1675
|
+
|
|
1676
|
+
// The wake sees a different reference than it installed, so it doesn't
|
|
1677
|
+
// restore: two writes (resolver install, mid-run replacement), no third.
|
|
1678
|
+
expect(conversation.trustContext).toEqual(replaced);
|
|
1679
|
+
expect(conversation.trustContextSets).toHaveLength(2);
|
|
1680
|
+
});
|
|
1681
|
+
|
|
1682
|
+
test("never touches the persistent trust when the wake carries none", async () => {
|
|
1683
|
+
const conversation = makeWakeConversation({
|
|
1684
|
+
conversationId: "conv-trust-none",
|
|
1685
|
+
});
|
|
1686
|
+
|
|
1687
|
+
await wakeAgentForOpportunity(
|
|
1688
|
+
{ conversationId: "conv-trust-none", hint: "x", source: "t" },
|
|
1689
|
+
{ resolveTarget: async () => conversation },
|
|
1690
|
+
);
|
|
1691
|
+
|
|
1692
|
+
expect(conversation.trustContextSets).toHaveLength(0);
|
|
1693
|
+
});
|
|
1694
|
+
|
|
1538
1695
|
test("two concurrent wakes on the same conversation are serialized", async () => {
|
|
1539
1696
|
// Build a target whose agentLoop.run resolves only when we signal.
|
|
1540
1697
|
const gate1 = Promise.withResolvers<void>();
|
|
@@ -73,7 +73,7 @@ describe("getGuardianBinding", () => {
|
|
|
73
73
|
expect(binding?.verifiedVia).toBe("verified");
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
-
test("
|
|
76
|
+
test("a missing principal surfaces as null (unresolved), never an empty string", async () => {
|
|
77
77
|
mockGuardianList = [
|
|
78
78
|
{
|
|
79
79
|
channelType: "telegram",
|
|
@@ -85,7 +85,7 @@ describe("getGuardianBinding", () => {
|
|
|
85
85
|
|
|
86
86
|
const binding = await getGuardianBinding("asst-1", "telegram");
|
|
87
87
|
|
|
88
|
-
expect(binding?.guardianPrincipalId).
|
|
88
|
+
expect(binding?.guardianPrincipalId).toBeNull();
|
|
89
89
|
expect(binding?.guardianDeliveryChatId).toBe("");
|
|
90
90
|
expect(binding?.verifiedAt).toBe(0);
|
|
91
91
|
});
|
|
@@ -128,6 +128,43 @@ describe("trustContextFromVerdict", () => {
|
|
|
128
128
|
expect(result.memberPolicy).toBe("escalate");
|
|
129
129
|
});
|
|
130
130
|
|
|
131
|
+
test("carries the verdict's gateway-owned interaction count onto the context", () => {
|
|
132
|
+
const verdict = {
|
|
133
|
+
trustClass: "trusted_contact",
|
|
134
|
+
canonicalSenderId: "u-1",
|
|
135
|
+
contactId: "contact-1",
|
|
136
|
+
channelId: "channel-1",
|
|
137
|
+
status: "active",
|
|
138
|
+
policy: "allow",
|
|
139
|
+
interactionCount: 9,
|
|
140
|
+
} satisfies TrustVerdict;
|
|
141
|
+
|
|
142
|
+
const result = trustContextFromVerdict(verdict, {
|
|
143
|
+
sourceChannel: "slack",
|
|
144
|
+
conversationExternalId: CONV,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
expect(result.requesterInteractionCount).toBe(9);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test("leaves interaction count undefined when the verdict carries none", () => {
|
|
151
|
+
const verdict = {
|
|
152
|
+
trustClass: "trusted_contact",
|
|
153
|
+
canonicalSenderId: "u-1",
|
|
154
|
+
contactId: "contact-1",
|
|
155
|
+
channelId: "channel-1",
|
|
156
|
+
status: "active",
|
|
157
|
+
policy: "allow",
|
|
158
|
+
} satisfies TrustVerdict;
|
|
159
|
+
|
|
160
|
+
const result = trustContextFromVerdict(verdict, {
|
|
161
|
+
sourceChannel: "slack",
|
|
162
|
+
conversationExternalId: CONV,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
expect(result.requesterInteractionCount).toBeUndefined();
|
|
166
|
+
});
|
|
167
|
+
|
|
131
168
|
test("memberless verdict leaves ACL member fields undefined", () => {
|
|
132
169
|
const verdict = {
|
|
133
170
|
trustClass: "unknown",
|
|
@@ -322,8 +359,6 @@ describe("actorTrustContextFromVerdict", () => {
|
|
|
322
359
|
// INFO fields must be null/default placeholders.
|
|
323
360
|
expect(memberRecord!.contact.notes).toBeNull();
|
|
324
361
|
expect(memberRecord!.contact.userFile).toBeNull();
|
|
325
|
-
expect(memberRecord!.contact.interactionCount).toBe(0);
|
|
326
|
-
expect(memberRecord!.contact.lastInteraction).toBeNull();
|
|
327
362
|
});
|
|
328
363
|
|
|
329
364
|
test("guardian member verdict maps role guardian + principalId", () => {
|
|
@@ -436,10 +471,6 @@ describe("toTrustContext member grounding", () => {
|
|
|
436
471
|
address: "+15550100",
|
|
437
472
|
isPrimary: true,
|
|
438
473
|
externalChatId: null,
|
|
439
|
-
inviteId: null,
|
|
440
|
-
lastSeenAt: null,
|
|
441
|
-
interactionCount: 0,
|
|
442
|
-
lastInteraction: null,
|
|
443
474
|
updatedAt: null,
|
|
444
475
|
createdAt: 0,
|
|
445
476
|
};
|
|
@@ -451,8 +482,6 @@ describe("toTrustContext member grounding", () => {
|
|
|
451
482
|
displayName: "Frank",
|
|
452
483
|
notes: null,
|
|
453
484
|
role: "contact",
|
|
454
|
-
lastInteraction: null,
|
|
455
|
-
interactionCount: 0,
|
|
456
485
|
createdAt: 0,
|
|
457
486
|
updatedAt: 0,
|
|
458
487
|
contactType: "human",
|
|
@@ -26,6 +26,8 @@ import { emitNotificationSignal } from "../notifications/emit-signal.js";
|
|
|
26
26
|
import type { GuardianResolutionSource } from "../notifications/signal.js";
|
|
27
27
|
import { getLogger } from "../util/logger.js";
|
|
28
28
|
import { resolveAnchoredGuardian } from "./anchored-guardian.js";
|
|
29
|
+
import { CHALLENGE_TTL_MS } from "./channel-verification-service.js";
|
|
30
|
+
import { serializeRequesterSignals } from "./introduction-policy.js";
|
|
29
31
|
import { GUARDIAN_APPROVAL_TTL_MS } from "./routes/channel-route-shared.js";
|
|
30
32
|
|
|
31
33
|
const log = getLogger("access-request-helper");
|
|
@@ -44,6 +46,8 @@ export interface AccessRequestParams {
|
|
|
44
46
|
previousMemberStatus?: Exclude<ChannelStatus, "unverified">;
|
|
45
47
|
/** Preview of the requester's original message, shown to the guardian. */
|
|
46
48
|
messagePreview?: string;
|
|
49
|
+
/** The sender is a bot / integration account (no verification handshake possible). */
|
|
50
|
+
isBot?: boolean;
|
|
47
51
|
/** Slack-specific: user is from an external workspace (Slack Connect). */
|
|
48
52
|
isStranger?: boolean;
|
|
49
53
|
/** Slack-specific: user is a guest / restricted account. */
|
|
@@ -54,7 +58,98 @@ export interface AccessRequestParams {
|
|
|
54
58
|
|
|
55
59
|
export type AccessRequestResult =
|
|
56
60
|
| { notified: true; created: boolean; requestId: string }
|
|
57
|
-
| {
|
|
61
|
+
| {
|
|
62
|
+
notified: false;
|
|
63
|
+
reason:
|
|
64
|
+
| "no_sender_id"
|
|
65
|
+
| "already_denied"
|
|
66
|
+
| "approval_pending_verification";
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
// Terminal-deny lookup
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Assistant-scoped conversation id for an actor's access requests. Stable key
|
|
75
|
+
* that dedupes pending prompts and detects a prior terminal deny for the same
|
|
76
|
+
* (assistant, channel, actor).
|
|
77
|
+
*/
|
|
78
|
+
export function accessRequestConversationId(
|
|
79
|
+
canonicalAssistantId: string,
|
|
80
|
+
sourceChannel: string,
|
|
81
|
+
actorExternalId: string,
|
|
82
|
+
): string {
|
|
83
|
+
return `access-req-${canonicalAssistantId}-${sourceChannel}-${actorExternalId}`;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Whether the guardian has already terminally denied an access request from
|
|
88
|
+
* this actor on this channel. Callers use it to suppress re-engagement — both
|
|
89
|
+
* the guardian prompt and the self-verify challenge — for a sender the guardian
|
|
90
|
+
* explicitly rejected. Reads the retained `denied` canonical request scoped by
|
|
91
|
+
* the assistant-scoped conversation id.
|
|
92
|
+
*/
|
|
93
|
+
export function isAccessRequestDenied(params: {
|
|
94
|
+
canonicalAssistantId: string;
|
|
95
|
+
sourceChannel: string;
|
|
96
|
+
actorExternalId: string;
|
|
97
|
+
}): boolean {
|
|
98
|
+
const conversationId = accessRequestConversationId(
|
|
99
|
+
params.canonicalAssistantId,
|
|
100
|
+
params.sourceChannel,
|
|
101
|
+
params.actorExternalId,
|
|
102
|
+
);
|
|
103
|
+
return (
|
|
104
|
+
listCanonicalGuardianRequests({
|
|
105
|
+
status: "denied",
|
|
106
|
+
requesterExternalUserId: params.actorExternalId,
|
|
107
|
+
sourceChannel: params.sourceChannel,
|
|
108
|
+
kind: "access_request",
|
|
109
|
+
conversationId,
|
|
110
|
+
}).length > 0
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Whether this sender is inside the post-approval verification window: the
|
|
116
|
+
* guardian approved their access request recently enough that the minted
|
|
117
|
+
* 6-digit code could still be redeemable. In that state the handshake is in
|
|
118
|
+
* progress — the sender needs to enter the code, not trigger a fresh access
|
|
119
|
+
* request.
|
|
120
|
+
*
|
|
121
|
+
* Keyed on the approval decision time (the request row's `updatedAt`) bounded
|
|
122
|
+
* by the verification-code TTL, deliberately NOT on live verification-session
|
|
123
|
+
* rows: session lookups cannot distinguish the approval-minted session from a
|
|
124
|
+
* self-verify challenge session the ACL mints on the same inbound, or from an
|
|
125
|
+
* unrelated session bound to the same identity (guardian-initiated
|
|
126
|
+
* verification, invites).
|
|
127
|
+
*
|
|
128
|
+
* Voice is excluded: phone approvals activate the caller directly and never
|
|
129
|
+
* mint a code.
|
|
130
|
+
*/
|
|
131
|
+
export function isApprovalHandshakeInProgress(params: {
|
|
132
|
+
canonicalAssistantId: string;
|
|
133
|
+
sourceChannel: string;
|
|
134
|
+
actorExternalId: string;
|
|
135
|
+
}): boolean {
|
|
136
|
+
if (params.sourceChannel === "phone") {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
const conversationId = accessRequestConversationId(
|
|
140
|
+
params.canonicalAssistantId,
|
|
141
|
+
params.sourceChannel,
|
|
142
|
+
params.actorExternalId,
|
|
143
|
+
);
|
|
144
|
+
const windowStart = Date.now() - CHALLENGE_TTL_MS;
|
|
145
|
+
return listCanonicalGuardianRequests({
|
|
146
|
+
status: "approved",
|
|
147
|
+
requesterExternalUserId: params.actorExternalId,
|
|
148
|
+
sourceChannel: params.sourceChannel,
|
|
149
|
+
kind: "access_request",
|
|
150
|
+
conversationId,
|
|
151
|
+
}).some((request) => request.updatedAt >= windowStart);
|
|
152
|
+
}
|
|
58
153
|
|
|
59
154
|
// ---------------------------------------------------------------------------
|
|
60
155
|
// Helper
|
|
@@ -86,6 +181,7 @@ export async function notifyGuardianOfAccessRequest(
|
|
|
86
181
|
actorUsername,
|
|
87
182
|
previousMemberStatus,
|
|
88
183
|
messagePreview,
|
|
184
|
+
isBot,
|
|
89
185
|
isStranger,
|
|
90
186
|
isRestricted,
|
|
91
187
|
messageTs,
|
|
@@ -122,7 +218,11 @@ export async function notifyGuardianOfAccessRequest(
|
|
|
122
218
|
// matches requests for the same assistant. Without this, a pending request
|
|
123
219
|
// from assistant A could be returned for assistant B, allowing the caller
|
|
124
220
|
// to piggyback on A's guardian approval.
|
|
125
|
-
const conversationId =
|
|
221
|
+
const conversationId = accessRequestConversationId(
|
|
222
|
+
canonicalAssistantId,
|
|
223
|
+
sourceChannel,
|
|
224
|
+
actorExternalId,
|
|
225
|
+
);
|
|
126
226
|
|
|
127
227
|
// Deduplicate: skip creation if there is already a pending canonical request
|
|
128
228
|
// for the same requester on this channel *and* assistant. Still return
|
|
@@ -147,6 +247,47 @@ export async function notifyGuardianOfAccessRequest(
|
|
|
147
247
|
};
|
|
148
248
|
}
|
|
149
249
|
|
|
250
|
+
// Terminal-deny suppression: once the guardian has denied an access request
|
|
251
|
+
// for this sender on this channel, subsequent inbound must not re-prompt.
|
|
252
|
+
// The denied decision persists the sender as an unverified_contact (see the
|
|
253
|
+
// accessRequestResolver deny path); re-surfacing the same request the
|
|
254
|
+
// guardian already rejected would be noise. The guardian can still verify the
|
|
255
|
+
// contact manually — that path does not go through here. Checked before the
|
|
256
|
+
// handshake window below so a standing deny always wins over an earlier
|
|
257
|
+
// approval.
|
|
258
|
+
if (
|
|
259
|
+
isAccessRequestDenied({
|
|
260
|
+
canonicalAssistantId,
|
|
261
|
+
sourceChannel,
|
|
262
|
+
actorExternalId,
|
|
263
|
+
})
|
|
264
|
+
) {
|
|
265
|
+
log.debug(
|
|
266
|
+
{ sourceChannel, actorExternalId },
|
|
267
|
+
"Suppressing access request notification — guardian already denied this sender",
|
|
268
|
+
);
|
|
269
|
+
return { notified: false, reason: "already_denied" };
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Handshake-in-progress suppression: within the verification-code window
|
|
273
|
+
// after the guardian approves, the flow is waiting on the requester to enter
|
|
274
|
+
// their code. Inbound from the sender in that window must not create a new
|
|
275
|
+
// request or re-notify the guardian; once the window lapses unconsumed,
|
|
276
|
+
// re-prompting is allowed again.
|
|
277
|
+
if (
|
|
278
|
+
isApprovalHandshakeInProgress({
|
|
279
|
+
canonicalAssistantId,
|
|
280
|
+
sourceChannel,
|
|
281
|
+
actorExternalId,
|
|
282
|
+
})
|
|
283
|
+
) {
|
|
284
|
+
log.debug(
|
|
285
|
+
{ sourceChannel, actorExternalId },
|
|
286
|
+
"Suppressing access request notification — approval granted, verification window still open",
|
|
287
|
+
);
|
|
288
|
+
return { notified: false, reason: "approval_pending_verification" };
|
|
289
|
+
}
|
|
290
|
+
|
|
150
291
|
const senderIdentifier = actorDisplayName || actorUsername || actorExternalId;
|
|
151
292
|
const requestId = `access-req-${canonicalAssistantId}-${sourceChannel}-${actorExternalId}-${Date.now()}`;
|
|
152
293
|
|
|
@@ -162,6 +303,11 @@ export async function notifyGuardianOfAccessRequest(
|
|
|
162
303
|
guardianPrincipalId: guardianPrincipalId ?? undefined,
|
|
163
304
|
toolName: "ingress_access_request",
|
|
164
305
|
questionText: `${senderIdentifier} is requesting access to the assistant`,
|
|
306
|
+
requesterSignals: serializeRequesterSignals({
|
|
307
|
+
isBot,
|
|
308
|
+
isStranger,
|
|
309
|
+
isRestricted,
|
|
310
|
+
}),
|
|
165
311
|
expiresAt: Date.now() + GUARDIAN_APPROVAL_TTL_MS,
|
|
166
312
|
});
|
|
167
313
|
|
|
@@ -207,14 +353,19 @@ export async function notifyGuardianOfAccessRequest(
|
|
|
207
353
|
guardianResolutionSource,
|
|
208
354
|
previousMemberStatus: previousMemberStatus ?? null,
|
|
209
355
|
messagePreview: messagePreview ?? null,
|
|
356
|
+
...(isBot !== undefined ? { isBot } : {}),
|
|
210
357
|
...(isStranger !== undefined ? { isStranger } : {}),
|
|
211
358
|
...(isRestricted !== undefined ? { isRestricted } : {}),
|
|
212
359
|
...(messageTs ? { messageTs } : {}),
|
|
213
360
|
},
|
|
214
361
|
dedupeKey: `access-request:${canonicalRequest.id}`,
|
|
215
362
|
onConversationCreated: (info) => {
|
|
216
|
-
if (
|
|
363
|
+
if (
|
|
364
|
+
info.sourceEventName !== "ingress.access_request" ||
|
|
365
|
+
vellumDeliveryId
|
|
366
|
+
) {
|
|
217
367
|
return;
|
|
368
|
+
}
|
|
218
369
|
vellumDeliveryId = recordApprovalCardDelivery({
|
|
219
370
|
requestId: canonicalRequest.id,
|
|
220
371
|
channel: "vellum",
|
|
@@ -34,6 +34,7 @@ import type { TrustContext } from "../daemon/trust-context.js";
|
|
|
34
34
|
import { canonicalizeInboundIdentity } from "../util/canonicalize-identity.js";
|
|
35
35
|
import { getLogger } from "../util/logger.js";
|
|
36
36
|
import { getCachedMemberAcl } from "./member-verdict-cache.js";
|
|
37
|
+
import type { TrustClass } from "./trust-class.js";
|
|
37
38
|
|
|
38
39
|
const log = getLogger("actor-trust-resolver");
|
|
39
40
|
|
|
@@ -44,27 +45,11 @@ export type { TrustContext } from "../daemon/trust-context.js";
|
|
|
44
45
|
// ---------------------------------------------------------------------------
|
|
45
46
|
|
|
46
47
|
/**
|
|
47
|
-
* Trust classification for an inbound actor.
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* (assistant, channel). Guardians have full control-plane access and
|
|
51
|
-
* self-approve tool invocations.
|
|
52
|
-
* - `'trusted_contact'`: The sender is an active contact with a channel
|
|
53
|
-
* (not the guardian). Trusted contacts can invoke tools but require
|
|
54
|
-
* guardian approval for sensitive operations.
|
|
55
|
-
* - `'unverified_contact'`: The sender matches a contact channel whose
|
|
56
|
-
* status is `pending` or `unverified` — known to the guardian but not yet
|
|
57
|
-
* verified. Treated identically to `trusted_contact` for every downstream
|
|
58
|
-
* capability/tool/approval decision; the distinction is admission-only.
|
|
59
|
-
* - `'unknown'`: The sender has no contact record, no identity could be
|
|
60
|
-
* established, or the sender is a blocked/revoked contact. Unknown
|
|
61
|
-
* actors are fail-closed with no escalation path.
|
|
48
|
+
* Trust classification for an inbound actor. Defined once in `./trust-class.ts`
|
|
49
|
+
* (shared with the persistence metadata schema) and re-exported here, the
|
|
50
|
+
* canonical import site for the resolver's consumers.
|
|
62
51
|
*/
|
|
63
|
-
export type TrustClass
|
|
64
|
-
| "guardian"
|
|
65
|
-
| "trusted_contact"
|
|
66
|
-
| "unverified_contact"
|
|
67
|
-
| "unknown";
|
|
52
|
+
export type { TrustClass };
|
|
68
53
|
|
|
69
54
|
/**
|
|
70
55
|
* Fully resolved trust context from the actor trust resolver.
|
|
@@ -211,7 +196,8 @@ export function resolveActorTrust(
|
|
|
211
196
|
};
|
|
212
197
|
guardianPrincipalId = guardianDelivery.principalId ?? undefined;
|
|
213
198
|
isGuardian =
|
|
214
|
-
guardianDelivery.address.toLowerCase() ===
|
|
199
|
+
guardianDelivery.address.toLowerCase() ===
|
|
200
|
+
canonicalSenderId.toLowerCase();
|
|
215
201
|
}
|
|
216
202
|
|
|
217
203
|
log.debug(
|
|
@@ -108,6 +108,7 @@ import {
|
|
|
108
108
|
type UntrustedContentSource,
|
|
109
109
|
wrapUntrustedContent,
|
|
110
110
|
} from "../security/untrusted-content.js";
|
|
111
|
+
import type { CompletedBackgroundTool } from "../tools/background-tool-registry.js";
|
|
111
112
|
import { getLogger } from "../util/logger.js";
|
|
112
113
|
|
|
113
114
|
const log = getLogger("agent-wake");
|
|
@@ -323,6 +324,12 @@ export interface WakeOptions {
|
|
|
323
324
|
* framing outside the fence.
|
|
324
325
|
*/
|
|
325
326
|
untrustedOutput?: WakeUntrustedOutput;
|
|
327
|
+
/**
|
|
328
|
+
* Structured terminal record for a backgrounded bash/host_bash run, stamped
|
|
329
|
+
* onto the persisted background-event wake so the web can rebuild the inline
|
|
330
|
+
* card from history after a daemon restart.
|
|
331
|
+
*/
|
|
332
|
+
backgroundToolCompletion?: CompletedBackgroundTool;
|
|
326
333
|
/**
|
|
327
334
|
* Schedule-run id to stamp on the usage rows this wake records. Set when the
|
|
328
335
|
* wake is triggered by a script-mode schedule (the firing's run id), so the
|
|
@@ -612,6 +619,18 @@ export async function wakeAgentForOpportunity(
|
|
|
612
619
|
const startedAt = nowFn();
|
|
613
620
|
|
|
614
621
|
return runSingleFlight(conversationId, async () => {
|
|
622
|
+
// Snapshot the conversation's resting trust before the resolver runs, so
|
|
623
|
+
// it can be restored after. The resolver leaves the wake's trust on the
|
|
624
|
+
// conversation, and a following no-trust wake would otherwise read it via
|
|
625
|
+
// tool setup's `currentTurnTrustContext ?? trustContext` fallback. Null
|
|
626
|
+
// when the conversation isn't resident yet (a fresh hydrate or a fork).
|
|
627
|
+
let priorPersistentTrust: TrustContext | null = null;
|
|
628
|
+
if (opts.trustContext) {
|
|
629
|
+
const { findConversation } =
|
|
630
|
+
await import("../daemon/conversation-registry.js");
|
|
631
|
+
priorPersistentTrust =
|
|
632
|
+
findConversation(conversationId)?.trustContext ?? null;
|
|
633
|
+
}
|
|
615
634
|
const resolved = await resolveTarget(opts);
|
|
616
635
|
if (resolved === "archived") {
|
|
617
636
|
log.info(
|
|
@@ -633,6 +652,18 @@ export async function wakeAgentForOpportunity(
|
|
|
633
652
|
}
|
|
634
653
|
const conversation = resolved;
|
|
635
654
|
|
|
655
|
+
// Put the resting trust back on exit. The guard restores only our own
|
|
656
|
+
// elevation, so a trust re-set by another turn is left alone; it's also
|
|
657
|
+
// idempotent, so the several call sites below are safe.
|
|
658
|
+
const restorePersistentWakeTrust = (): void => {
|
|
659
|
+
if (
|
|
660
|
+
opts.trustContext &&
|
|
661
|
+
conversation.trustContext === opts.trustContext
|
|
662
|
+
) {
|
|
663
|
+
conversation.setTrustContext(priorPersistentTrust);
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
|
|
636
667
|
const { decision: diskPressureDecision, status: diskPressureStatus } =
|
|
637
668
|
classifyWakeDiskPressurePolicy(opts);
|
|
638
669
|
if (diskPressureDecision.action === "block") {
|
|
@@ -650,6 +681,7 @@ export async function wakeAgentForOpportunity(
|
|
|
650
681
|
},
|
|
651
682
|
"agent-wake: blocked by disk pressure cleanup mode",
|
|
652
683
|
);
|
|
684
|
+
restorePersistentWakeTrust();
|
|
653
685
|
return {
|
|
654
686
|
invoked: false,
|
|
655
687
|
producedToolCalls: false,
|
|
@@ -663,6 +695,7 @@ export async function wakeAgentForOpportunity(
|
|
|
663
695
|
{ conversationId, source },
|
|
664
696
|
"agent-wake: conversation still processing after timeout; skipping",
|
|
665
697
|
);
|
|
698
|
+
restorePersistentWakeTrust();
|
|
666
699
|
return { invoked: false, producedToolCalls: false, reason: "timeout" };
|
|
667
700
|
}
|
|
668
701
|
|
|
@@ -784,7 +817,12 @@ export async function wakeAgentForOpportunity(
|
|
|
784
817
|
};
|
|
785
818
|
conversation.messages.push(triggerMessage);
|
|
786
819
|
try {
|
|
787
|
-
await persistWakeTriggerMessage(
|
|
820
|
+
await persistWakeTriggerMessage(
|
|
821
|
+
conversation,
|
|
822
|
+
triggerMessage,
|
|
823
|
+
source,
|
|
824
|
+
opts.backgroundToolCompletion,
|
|
825
|
+
);
|
|
788
826
|
} catch (err) {
|
|
789
827
|
log.warn(
|
|
790
828
|
{ conversationId, source, err },
|
|
@@ -1412,6 +1450,8 @@ export async function wakeAgentForOpportunity(
|
|
|
1412
1450
|
|
|
1413
1451
|
return { invoked: true, producedToolCalls };
|
|
1414
1452
|
} finally {
|
|
1453
|
+
// Put the conversation's resting trust back on every exit path.
|
|
1454
|
+
restorePersistentWakeTrust();
|
|
1415
1455
|
// The success path (above) already called setProcessing(false)
|
|
1416
1456
|
// + drainQueue after tail persist. This catch-all handles the
|
|
1417
1457
|
// error and early-return paths where no tail was produced — those
|