@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
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared lexical candidate helper for message-content search.
|
|
3
|
+
*
|
|
4
|
+
* Encodes a free-text query with the local TF-IDF sparse encoder and queries
|
|
5
|
+
* the BM25-style sparse Qdrant lexical index (`messages_lexical`) for matching
|
|
6
|
+
* message ids. This is the single entry point the message-search read sites use
|
|
7
|
+
* when they select the `qdrant` backend, mirroring the
|
|
8
|
+
* candidate set SQLite FTS5 would return.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { generateSparseEmbedding } from "./embeddings/embedding-backend.js";
|
|
12
|
+
import {
|
|
13
|
+
getMessagesLexicalIndex,
|
|
14
|
+
type MessageLexicalSearchResult,
|
|
15
|
+
} from "./embeddings/messages-lexical-index.js";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Resolve message-id candidates for `query` from the Qdrant lexical index,
|
|
19
|
+
* ranked by sparse similarity score (highest first).
|
|
20
|
+
*
|
|
21
|
+
* This is a **pure lexical candidate generator**: it returns the top-`limit`
|
|
22
|
+
* message ids by sparse score with NO visibility, source, or
|
|
23
|
+
* active-conversation filtering (the only scoping it applies is the optional
|
|
24
|
+
* `conversationId` restriction). Those exclusions (active conversation,
|
|
25
|
+
* private conversations, non-message sources) live in SQL at the read sites.
|
|
26
|
+
*
|
|
27
|
+
* Callers that apply such post-retrieval SQL filters MUST over-fetch: pass an
|
|
28
|
+
* inflated `limit` (the `QDRANT_RECALL_CANDIDATE_MULTIPLIER` /
|
|
29
|
+
* `QDRANT_SEARCH_CANDIDATE_LIMIT` pattern the read sites use) and re-limit
|
|
30
|
+
* after filtering in SQL. Applying the caller's real limit here first would
|
|
31
|
+
* let excluded rows consume the candidate slots and drop valid visible
|
|
32
|
+
* matches below the fold.
|
|
33
|
+
*
|
|
34
|
+
* @param query free-text search query
|
|
35
|
+
* @param limit maximum number of candidates to return
|
|
36
|
+
* @param opts.conversationId restrict results to a single conversation
|
|
37
|
+
*/
|
|
38
|
+
export async function searchMessageIdsLexical(
|
|
39
|
+
query: string,
|
|
40
|
+
limit: number,
|
|
41
|
+
opts?: { conversationId?: string },
|
|
42
|
+
): Promise<MessageLexicalSearchResult[]> {
|
|
43
|
+
const sparse = generateSparseEmbedding(query);
|
|
44
|
+
// A query that tokenizes to nothing (whitespace/punctuation-only) yields an
|
|
45
|
+
// empty sparse vector; matching the FTS paths and other sparse callers,
|
|
46
|
+
// return no candidates without querying Qdrant on an empty vector.
|
|
47
|
+
if (sparse.indices.length === 0) return [];
|
|
48
|
+
return getMessagesLexicalIndex().searchLexical(sparse, limit, opts);
|
|
49
|
+
}
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
* ms) should keep using the in-process drizzle / `bun:sqlite` handle
|
|
27
27
|
* directly — the subprocess overhead would dominate.
|
|
28
28
|
*/
|
|
29
|
+
import { spawn } from "node:child_process";
|
|
29
30
|
import { Database } from "bun:sqlite";
|
|
30
31
|
|
|
31
32
|
import { getLogger } from "../util/logger.js";
|
|
@@ -327,3 +328,44 @@ async function runInProcessBlocking(
|
|
|
327
328
|
transient?.close();
|
|
328
329
|
}
|
|
329
330
|
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Fire-and-forget `PRAGMA wal_checkpoint(TRUNCATE)` against the main
|
|
334
|
+
* assistant DB in a detached `sqlite3` subprocess.
|
|
335
|
+
*
|
|
336
|
+
* For exit paths that cannot wait for a fold to finish (the force-exit
|
|
337
|
+
* timeout in `shutdown-handlers.ts`): the child runs in its own process
|
|
338
|
+
* group with no inherited stdio, so it survives the daemon's `process.exit`
|
|
339
|
+
* — and any group-directed follow-up signal from a supervisor — and
|
|
340
|
+
* finishes the fold in the background. A concurrent checkpointer just makes
|
|
341
|
+
* this one give up after its busy timeout; the fold is best-effort either
|
|
342
|
+
* way, with the pre-open checkpoint in `db-init.ts` as the backstop.
|
|
343
|
+
*
|
|
344
|
+
* Returns false when no `sqlite3` binary is on the host or the spawn fails —
|
|
345
|
+
* there is no in-process fallback because the caller is exiting.
|
|
346
|
+
*/
|
|
347
|
+
export function spawnDetachedWalCheckpoint(): boolean {
|
|
348
|
+
const sqlite3Path = findSqlite3();
|
|
349
|
+
if (!sqlite3Path) {
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
try {
|
|
353
|
+
const child = spawn(
|
|
354
|
+
sqlite3Path,
|
|
355
|
+
[
|
|
356
|
+
getDbPath(),
|
|
357
|
+
`PRAGMA busy_timeout=${SQLITE_BUSY_TIMEOUT_MS}; PRAGMA wal_checkpoint(TRUNCATE);`,
|
|
358
|
+
],
|
|
359
|
+
{ detached: true, stdio: "ignore" },
|
|
360
|
+
);
|
|
361
|
+
// A post-spawn failure can't be acted on — the daemon is exiting — but an
|
|
362
|
+
// unlistened ChildProcess "error" event would throw as an uncaught
|
|
363
|
+
// exception.
|
|
364
|
+
child.on("error", () => {});
|
|
365
|
+
child.unref();
|
|
366
|
+
log.info({ pid: child.pid }, "Spawned detached WAL checkpoint subprocess");
|
|
367
|
+
return true;
|
|
368
|
+
} catch {
|
|
369
|
+
return false;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
@@ -11,6 +11,7 @@ import { ensureDataDir, getDbPath } from "../util/platform.js";
|
|
|
11
11
|
import { getTelemetryDbPath } from "../util/telemetry-db-path.js";
|
|
12
12
|
import { clearStoredDb, getStoredDb, setStoredDb } from "./db-singleton.js";
|
|
13
13
|
import * as schema from "./schema/index.js";
|
|
14
|
+
import { wrapSqliteForSlowQueryLogging } from "./slow-query-log.js";
|
|
14
15
|
|
|
15
16
|
export type DrizzleDb = ReturnType<typeof drizzle<typeof schema>>;
|
|
16
17
|
|
|
@@ -113,11 +114,22 @@ export function getDb(): DrizzleDb {
|
|
|
113
114
|
ensureDataDir();
|
|
114
115
|
const sqlite = new Database(getDbPath());
|
|
115
116
|
applyConnectionPragmas(sqlite);
|
|
117
|
+
wrapSqliteForSlowQueryLogging(sqlite);
|
|
116
118
|
const db = drizzle(sqlite, { schema });
|
|
117
119
|
setStoredDb("main", db, () => sqlite.close());
|
|
118
120
|
return db;
|
|
119
121
|
}
|
|
120
122
|
|
|
123
|
+
/**
|
|
124
|
+
* Whether the main assistant DB connection is currently open. Lets exit paths
|
|
125
|
+
* decide between DB teardown work and skipping it entirely — `getDb()` /
|
|
126
|
+
* `getSqlite()` lazily open the connection, so probing with those would
|
|
127
|
+
* create the very state being checked for.
|
|
128
|
+
*/
|
|
129
|
+
export function isDbOpen(): boolean {
|
|
130
|
+
return getStoredDb<DrizzleDb>("main") !== null;
|
|
131
|
+
}
|
|
132
|
+
|
|
121
133
|
/**
|
|
122
134
|
* Get the underlying bun:sqlite Database from the global Drizzle instance.
|
|
123
135
|
*
|
|
@@ -159,6 +171,7 @@ function openDedicatedDb(
|
|
|
159
171
|
try {
|
|
160
172
|
const sqlite = new Database(dbPath);
|
|
161
173
|
applyConnectionPragmas(sqlite);
|
|
174
|
+
wrapSqliteForSlowQueryLogging(sqlite);
|
|
162
175
|
const db = drizzle(sqlite, { schema });
|
|
163
176
|
setStoredDb(key, db, () => sqlite.close());
|
|
164
177
|
return db;
|
|
@@ -10,36 +10,6 @@ import { eq } from "drizzle-orm";
|
|
|
10
10
|
import { getDb } from "./db-connection.js";
|
|
11
11
|
import { channelInboundEvents } from "./schema.js";
|
|
12
12
|
|
|
13
|
-
const SLACK_DM_LIVE_DELIVERED_TEXT_RESPONSE_INDEXES =
|
|
14
|
-
"slackDmLiveDeliveredTextResponseIndexes";
|
|
15
|
-
|
|
16
|
-
function parseRawPayload(
|
|
17
|
-
rawPayload: string | null,
|
|
18
|
-
): Record<string, unknown> | undefined {
|
|
19
|
-
if (!rawPayload) return undefined;
|
|
20
|
-
try {
|
|
21
|
-
const parsed = JSON.parse(rawPayload) as unknown;
|
|
22
|
-
if (
|
|
23
|
-
parsed === null ||
|
|
24
|
-
typeof parsed !== "object" ||
|
|
25
|
-
Array.isArray(parsed)
|
|
26
|
-
) {
|
|
27
|
-
return undefined;
|
|
28
|
-
}
|
|
29
|
-
return parsed as Record<string, unknown>;
|
|
30
|
-
} catch {
|
|
31
|
-
return undefined;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function normalizePositiveIntegerIndexes(value: unknown): number[] {
|
|
36
|
-
if (!Array.isArray(value)) return [];
|
|
37
|
-
const indexes = value.filter(
|
|
38
|
-
(item): item is number => Number.isSafeInteger(item) && item > 0,
|
|
39
|
-
);
|
|
40
|
-
return [...new Set(indexes)].sort((a, b) => a - b);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
13
|
// ── Per-segment delivery progress ──────────────────────────────────
|
|
44
14
|
//
|
|
45
15
|
// When a split reply (multiple text segments from tool boundaries) fails
|
|
@@ -61,58 +31,6 @@ export function updateDeliveredSegmentCount(
|
|
|
61
31
|
.run();
|
|
62
32
|
}
|
|
63
33
|
|
|
64
|
-
export function getSlackDmLiveDeliveredTextResponseIndexes(
|
|
65
|
-
eventId: string,
|
|
66
|
-
): number[] {
|
|
67
|
-
const db = getDb();
|
|
68
|
-
const row = db
|
|
69
|
-
.select({ rawPayload: channelInboundEvents.rawPayload })
|
|
70
|
-
.from(channelInboundEvents)
|
|
71
|
-
.where(eq(channelInboundEvents.id, eventId))
|
|
72
|
-
.get();
|
|
73
|
-
const payload = parseRawPayload(row?.rawPayload ?? null);
|
|
74
|
-
if (!payload) return [];
|
|
75
|
-
return normalizePositiveIntegerIndexes(
|
|
76
|
-
payload[SLACK_DM_LIVE_DELIVERED_TEXT_RESPONSE_INDEXES],
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function addSlackDmLiveDeliveredTextResponseIndex(
|
|
81
|
-
eventId: string,
|
|
82
|
-
responseIndex: number,
|
|
83
|
-
): void {
|
|
84
|
-
if (!Number.isSafeInteger(responseIndex) || responseIndex <= 0) return;
|
|
85
|
-
|
|
86
|
-
const db = getDb();
|
|
87
|
-
db.transaction((tx) => {
|
|
88
|
-
const row = tx
|
|
89
|
-
.select({ rawPayload: channelInboundEvents.rawPayload })
|
|
90
|
-
.from(channelInboundEvents)
|
|
91
|
-
.where(eq(channelInboundEvents.id, eventId))
|
|
92
|
-
.get();
|
|
93
|
-
if (!row?.rawPayload) return;
|
|
94
|
-
|
|
95
|
-
const payload = parseRawPayload(row.rawPayload);
|
|
96
|
-
if (!payload) return;
|
|
97
|
-
const indexes = normalizePositiveIntegerIndexes(
|
|
98
|
-
payload[SLACK_DM_LIVE_DELIVERED_TEXT_RESPONSE_INDEXES],
|
|
99
|
-
);
|
|
100
|
-
if (!indexes.includes(responseIndex)) indexes.push(responseIndex);
|
|
101
|
-
indexes.sort((a, b) => a - b);
|
|
102
|
-
|
|
103
|
-
tx.update(channelInboundEvents)
|
|
104
|
-
.set({
|
|
105
|
-
rawPayload: JSON.stringify({
|
|
106
|
-
...payload,
|
|
107
|
-
[SLACK_DM_LIVE_DELIVERED_TEXT_RESPONSE_INDEXES]: indexes,
|
|
108
|
-
}),
|
|
109
|
-
updatedAt: Date.now(),
|
|
110
|
-
})
|
|
111
|
-
.where(eq(channelInboundEvents.id, eventId))
|
|
112
|
-
.run();
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
|
|
116
34
|
// ── Deliver-once guard for terminal reply idempotency ────────────────
|
|
117
35
|
//
|
|
118
36
|
// When both the main poll (processChannelMessageWithApprovals) and the
|
|
@@ -314,13 +314,13 @@ export function storePayload(
|
|
|
314
314
|
}
|
|
315
315
|
|
|
316
316
|
/**
|
|
317
|
-
*
|
|
318
|
-
*
|
|
319
|
-
*
|
|
317
|
+
* Merge a patch into an inbound event's stored payload, preserving existing
|
|
318
|
+
* keys. No-ops when the event has no payload or the stored value is not a JSON
|
|
319
|
+
* object.
|
|
320
320
|
*/
|
|
321
|
-
|
|
321
|
+
function mergeRawPayload(
|
|
322
322
|
eventId: string,
|
|
323
|
-
|
|
323
|
+
patch: Record<string, unknown>,
|
|
324
324
|
): void {
|
|
325
325
|
const db = getDb();
|
|
326
326
|
const row = db
|
|
@@ -347,13 +347,34 @@ export function storeReplyMessageId(
|
|
|
347
347
|
|
|
348
348
|
db.update(channelInboundEvents)
|
|
349
349
|
.set({
|
|
350
|
-
rawPayload: JSON.stringify({ ...payload,
|
|
350
|
+
rawPayload: JSON.stringify({ ...payload, ...patch }),
|
|
351
351
|
updatedAt: Date.now(),
|
|
352
352
|
})
|
|
353
353
|
.where(eq(channelInboundEvents.id, eventId))
|
|
354
354
|
.run();
|
|
355
355
|
}
|
|
356
356
|
|
|
357
|
+
/**
|
|
358
|
+
* Persist the assistant reply row generated for an inbound event so callback
|
|
359
|
+
* delivery retries target that exact response instead of the latest message in
|
|
360
|
+
* the conversation.
|
|
361
|
+
*/
|
|
362
|
+
export function storeReplyMessageId(
|
|
363
|
+
eventId: string,
|
|
364
|
+
replyMessageId: string,
|
|
365
|
+
): void {
|
|
366
|
+
mergeRawPayload(eventId, { replyMessageId });
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Persist the `ts` of a Slack message already streamed for an inbound event.
|
|
371
|
+
* A processing retry reconciles its durable delivery into this message instead
|
|
372
|
+
* of opening a second stream, preventing a duplicate reply.
|
|
373
|
+
*/
|
|
374
|
+
export function storeStreamedReplyTs(eventId: string, streamTs: string): void {
|
|
375
|
+
mergeRawPayload(eventId, { slackStreamMessageTs: streamTs });
|
|
376
|
+
}
|
|
377
|
+
|
|
357
378
|
/**
|
|
358
379
|
* Clear a previously stored payload. Used when the ingress check
|
|
359
380
|
* detects secret-bearing content — the payload must not remain on disk.
|
|
@@ -13,11 +13,15 @@ let backendToReturn: {
|
|
|
13
13
|
embed: (inputs: string[]) => Promise<number[][]>;
|
|
14
14
|
} | null = null;
|
|
15
15
|
let breakerOpen = false;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
let selectBackendThrows = false;
|
|
17
|
+
|
|
18
|
+
const selectEmbeddingBackendMock = mock(async () => {
|
|
19
|
+
if (selectBackendThrows) throw new Error("credential store unavailable");
|
|
20
|
+
return {
|
|
21
|
+
backend: backendToReturn,
|
|
22
|
+
reason: backendToReturn ? null : "no backend",
|
|
23
|
+
};
|
|
24
|
+
});
|
|
21
25
|
// probeBackendDimension delegates the measurement to resolveBackendDimension;
|
|
22
26
|
// the mock mirrors the real resolver's "embed → vector length, null on throw"
|
|
23
27
|
// contract so these tests drive behavior through the stub backend's embed().
|
|
@@ -69,6 +73,7 @@ const { probeBackendDimension, readConceptPageCollectionDim } =
|
|
|
69
73
|
describe("probeBackendDimension", () => {
|
|
70
74
|
beforeEach(() => {
|
|
71
75
|
breakerOpen = false;
|
|
76
|
+
selectBackendThrows = false;
|
|
72
77
|
backendToReturn = {
|
|
73
78
|
provider: "openai",
|
|
74
79
|
model: "text-embedding-3-small",
|
|
@@ -110,6 +115,14 @@ describe("probeBackendDimension", () => {
|
|
|
110
115
|
};
|
|
111
116
|
expect(await probeBackendDimension(CONFIG)).toBeNull();
|
|
112
117
|
});
|
|
118
|
+
|
|
119
|
+
test("returns null (does not reject) when backend selection rejects", async () => {
|
|
120
|
+
// `selectEmbeddingBackend` resolves provider credentials, which reject on a
|
|
121
|
+
// non-timeout credential-store error. The probe must uphold its never-throws
|
|
122
|
+
// contract so the reconcile defers instead of crashing.
|
|
123
|
+
selectBackendThrows = true;
|
|
124
|
+
expect(await probeBackendDimension(CONFIG)).toBeNull();
|
|
125
|
+
});
|
|
113
126
|
});
|
|
114
127
|
|
|
115
128
|
describe("readConceptPageCollectionDim", () => {
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
mock.module("../../../util/logger.js", () => ({
|
|
4
|
+
getLogger: () =>
|
|
5
|
+
new Proxy({} as Record<string, unknown>, {
|
|
6
|
+
get: () => () => {},
|
|
7
|
+
}),
|
|
8
|
+
}));
|
|
9
|
+
|
|
10
|
+
// ── Mock Qdrant REST client ───────────────────────────────────────────
|
|
11
|
+
|
|
12
|
+
interface CreateCollectionCall {
|
|
13
|
+
name: string;
|
|
14
|
+
config: Record<string, unknown>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface UpsertCall {
|
|
18
|
+
name: string;
|
|
19
|
+
opts: { points: Array<Record<string, unknown>> };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface QueryCall {
|
|
23
|
+
name: string;
|
|
24
|
+
opts: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface DeleteCall {
|
|
28
|
+
name: string;
|
|
29
|
+
opts: { filter?: Record<string, unknown>; points?: Array<string | number> };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let mockCollectionExists: boolean;
|
|
33
|
+
let createCollectionCalls: CreateCollectionCall[];
|
|
34
|
+
let upsertCalls: UpsertCall[];
|
|
35
|
+
let queryCalls: QueryCall[];
|
|
36
|
+
let deleteCalls: DeleteCall[];
|
|
37
|
+
let deleteCollectionCalls: string[];
|
|
38
|
+
let payloadIndexCalls: Array<Record<string, unknown>>;
|
|
39
|
+
let mockQueryPoints: Array<{
|
|
40
|
+
id: string | number;
|
|
41
|
+
score: number;
|
|
42
|
+
payload: Record<string, unknown>;
|
|
43
|
+
}>;
|
|
44
|
+
|
|
45
|
+
function resetMockState() {
|
|
46
|
+
mockCollectionExists = false;
|
|
47
|
+
createCollectionCalls = [];
|
|
48
|
+
upsertCalls = [];
|
|
49
|
+
queryCalls = [];
|
|
50
|
+
deleteCalls = [];
|
|
51
|
+
deleteCollectionCalls = [];
|
|
52
|
+
payloadIndexCalls = [];
|
|
53
|
+
mockQueryPoints = [];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
mock.module("@qdrant/js-client-rest", () => ({
|
|
57
|
+
QdrantClient: class MockQdrantClient {
|
|
58
|
+
async collectionExists(_name: string) {
|
|
59
|
+
return { exists: mockCollectionExists };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async createCollection(name: string, config: Record<string, unknown>) {
|
|
63
|
+
createCollectionCalls.push({ name, config });
|
|
64
|
+
mockCollectionExists = true;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async createPayloadIndex(_name: string, config: Record<string, unknown>) {
|
|
68
|
+
payloadIndexCalls.push(config);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async upsert(
|
|
72
|
+
name: string,
|
|
73
|
+
opts: { points: Array<Record<string, unknown>> },
|
|
74
|
+
) {
|
|
75
|
+
upsertCalls.push({ name, opts });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async query(name: string, opts: Record<string, unknown>) {
|
|
79
|
+
queryCalls.push({ name, opts });
|
|
80
|
+
return { points: mockQueryPoints };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async delete(name: string, opts: DeleteCall["opts"]) {
|
|
84
|
+
deleteCalls.push({ name, opts });
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async deleteCollection(name: string) {
|
|
88
|
+
deleteCollectionCalls.push(name);
|
|
89
|
+
mockCollectionExists = false;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async count(_name: string, _opts: unknown) {
|
|
93
|
+
return { count: 7 };
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
}));
|
|
97
|
+
|
|
98
|
+
import type { SparseEmbedding } from "../embedding-types.js";
|
|
99
|
+
import {
|
|
100
|
+
messagePointId,
|
|
101
|
+
MessagesLexicalIndex,
|
|
102
|
+
} from "../messages-lexical-index.js";
|
|
103
|
+
|
|
104
|
+
const SPARSE: SparseEmbedding = { indices: [1, 5, 9], values: [0.5, 0.2, 0.8] };
|
|
105
|
+
|
|
106
|
+
function makeIndex() {
|
|
107
|
+
return new MessagesLexicalIndex({ url: "http://localhost:6333" });
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
beforeEach(() => {
|
|
111
|
+
resetMockState();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe("MessagesLexicalIndex", () => {
|
|
115
|
+
test("creates a sparse-only collection (no dense vectors config)", async () => {
|
|
116
|
+
const index = makeIndex();
|
|
117
|
+
await index.ensureCollection();
|
|
118
|
+
|
|
119
|
+
expect(createCollectionCalls.length).toBe(1);
|
|
120
|
+
const config = createCollectionCalls[0].config;
|
|
121
|
+
|
|
122
|
+
// Sparse vector named "sparse" must be present.
|
|
123
|
+
expect(config.sparse_vectors).toBeDefined();
|
|
124
|
+
expect(
|
|
125
|
+
(config.sparse_vectors as Record<string, unknown>).sparse,
|
|
126
|
+
).toBeDefined();
|
|
127
|
+
|
|
128
|
+
// No dense `vectors` config at all.
|
|
129
|
+
expect(config.vectors).toBeUndefined();
|
|
130
|
+
expect("vectors" in config).toBe(false);
|
|
131
|
+
|
|
132
|
+
// Payload indexes on conversation_id (keyword) + created_at (integer).
|
|
133
|
+
const fields = payloadIndexCalls.map((c) => c.field_name);
|
|
134
|
+
expect(fields).toContain("conversation_id");
|
|
135
|
+
expect(fields).toContain("created_at");
|
|
136
|
+
const convIdx = payloadIndexCalls.find(
|
|
137
|
+
(c) => c.field_name === "conversation_id",
|
|
138
|
+
);
|
|
139
|
+
const createdIdx = payloadIndexCalls.find(
|
|
140
|
+
(c) => c.field_name === "created_at",
|
|
141
|
+
);
|
|
142
|
+
expect(convIdx?.field_schema).toBe("keyword");
|
|
143
|
+
expect(createdIdx?.field_schema).toBe("integer");
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("upsertMessage writes a deterministic point id and a sparse-only vector with the right payload", async () => {
|
|
147
|
+
const index = makeIndex();
|
|
148
|
+
await index.upsertMessage("msg-123", SPARSE, {
|
|
149
|
+
conversationId: "conv-abc",
|
|
150
|
+
createdAt: 1700000000,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
expect(upsertCalls.length).toBe(1);
|
|
154
|
+
const points = upsertCalls[0].opts.points;
|
|
155
|
+
expect(points.length).toBe(1);
|
|
156
|
+
const point = points[0] as {
|
|
157
|
+
id: string;
|
|
158
|
+
vector: Record<string, unknown>;
|
|
159
|
+
payload: Record<string, unknown>;
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// Deterministic point id derived from message id.
|
|
163
|
+
expect(point.id).toBe(messagePointId("msg-123"));
|
|
164
|
+
|
|
165
|
+
// Sparse-only vector under the "sparse" named vector, no dense vector.
|
|
166
|
+
expect(point.vector.sparse).toEqual({
|
|
167
|
+
indices: SPARSE.indices,
|
|
168
|
+
values: SPARSE.values,
|
|
169
|
+
});
|
|
170
|
+
expect(point.vector.dense).toBeUndefined();
|
|
171
|
+
expect("dense" in point.vector).toBe(false);
|
|
172
|
+
// The vector field carries only the sparse named vector.
|
|
173
|
+
expect(Object.keys(point.vector)).toEqual(["sparse"]);
|
|
174
|
+
|
|
175
|
+
// Payload carries message_id, conversation_id, created_at.
|
|
176
|
+
expect(point.payload.message_id).toBe("msg-123");
|
|
177
|
+
expect(point.payload.conversation_id).toBe("conv-abc");
|
|
178
|
+
expect(point.payload.created_at).toBe(1700000000);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
test("re-upserting the same messageId yields the same point id (idempotent)", async () => {
|
|
182
|
+
const index = makeIndex();
|
|
183
|
+
await index.upsertMessage("msg-same", SPARSE, {
|
|
184
|
+
conversationId: "conv-1",
|
|
185
|
+
createdAt: 1,
|
|
186
|
+
});
|
|
187
|
+
await index.upsertMessage("msg-same", SPARSE, {
|
|
188
|
+
conversationId: "conv-1",
|
|
189
|
+
createdAt: 2,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
expect(upsertCalls.length).toBe(2);
|
|
193
|
+
const id1 = (upsertCalls[0].opts.points[0] as { id: string }).id;
|
|
194
|
+
const id2 = (upsertCalls[1].opts.points[0] as { id: string }).id;
|
|
195
|
+
expect(id1).toBe(id2);
|
|
196
|
+
expect(id1).toBe(messagePointId("msg-same"));
|
|
197
|
+
// Distinct message ids map to distinct point ids.
|
|
198
|
+
expect(messagePointId("msg-same")).not.toBe(messagePointId("msg-other"));
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
test("upsertMessagesBatch writes many points in a single upsert call", async () => {
|
|
202
|
+
const index = makeIndex();
|
|
203
|
+
await index.upsertMessagesBatch([
|
|
204
|
+
{ messageId: "m1", sparse: SPARSE, conversationId: "c1", createdAt: 10 },
|
|
205
|
+
{ messageId: "m2", sparse: SPARSE, conversationId: "c2", createdAt: 20 },
|
|
206
|
+
]);
|
|
207
|
+
|
|
208
|
+
expect(upsertCalls.length).toBe(1);
|
|
209
|
+
expect(upsertCalls[0].opts.points.length).toBe(2);
|
|
210
|
+
const ids = upsertCalls[0].opts.points.map((p) => (p as { id: string }).id);
|
|
211
|
+
expect(ids).toEqual([messagePointId("m1"), messagePointId("m2")]);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
test("searchLexical queries the sparse named vector and returns {messageId, score}", async () => {
|
|
215
|
+
mockQueryPoints = [
|
|
216
|
+
{ id: "pt-1", score: 0.91, payload: { message_id: "msg-A" } },
|
|
217
|
+
{ id: "pt-2", score: 0.42, payload: { message_id: "msg-B" } },
|
|
218
|
+
];
|
|
219
|
+
|
|
220
|
+
const index = makeIndex();
|
|
221
|
+
const results = await index.searchLexical(SPARSE, 5);
|
|
222
|
+
|
|
223
|
+
expect(queryCalls.length).toBe(1);
|
|
224
|
+
const opts = queryCalls[0].opts;
|
|
225
|
+
// Query targets the sparse named vector.
|
|
226
|
+
expect(opts.using).toBe("sparse");
|
|
227
|
+
expect(opts.query).toEqual({
|
|
228
|
+
indices: SPARSE.indices,
|
|
229
|
+
values: SPARSE.values,
|
|
230
|
+
});
|
|
231
|
+
expect(opts.limit).toBe(5);
|
|
232
|
+
// No filter when no conversation scope is given.
|
|
233
|
+
expect(opts.filter).toBeUndefined();
|
|
234
|
+
|
|
235
|
+
expect(results).toEqual([
|
|
236
|
+
{ messageId: "msg-A", score: 0.91 },
|
|
237
|
+
{ messageId: "msg-B", score: 0.42 },
|
|
238
|
+
]);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test("searchLexical passes a conversation_id payload filter when given", async () => {
|
|
242
|
+
mockQueryPoints = [
|
|
243
|
+
{ id: "pt-1", score: 0.5, payload: { message_id: "msg-A" } },
|
|
244
|
+
];
|
|
245
|
+
|
|
246
|
+
const index = makeIndex();
|
|
247
|
+
await index.searchLexical(SPARSE, 3, { conversationId: "conv-xyz" });
|
|
248
|
+
|
|
249
|
+
expect(queryCalls.length).toBe(1);
|
|
250
|
+
const filter = queryCalls[0].opts.filter as {
|
|
251
|
+
must: Array<{ key: string; match: { value: string } }>;
|
|
252
|
+
};
|
|
253
|
+
expect(filter).toBeDefined();
|
|
254
|
+
expect(filter.must).toEqual([
|
|
255
|
+
{ key: "conversation_id", match: { value: "conv-xyz" } },
|
|
256
|
+
]);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
test("deleteByConversation issues a conversation_id payload-filter delete", async () => {
|
|
260
|
+
const index = makeIndex();
|
|
261
|
+
await index.deleteByConversation("conv-del");
|
|
262
|
+
|
|
263
|
+
expect(deleteCalls.length).toBe(1);
|
|
264
|
+
const filter = deleteCalls[0].opts.filter as {
|
|
265
|
+
must: Array<{ key: string; match: { value: string } }>;
|
|
266
|
+
};
|
|
267
|
+
expect(filter.must).toEqual([
|
|
268
|
+
{ key: "conversation_id", match: { value: "conv-del" } },
|
|
269
|
+
]);
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
test("deleteByMessageId deletes by the deterministic point id (not a payload filter)", async () => {
|
|
273
|
+
const index = makeIndex();
|
|
274
|
+
await index.deleteByMessageId("msg-del");
|
|
275
|
+
|
|
276
|
+
expect(deleteCalls.length).toBe(1);
|
|
277
|
+
// `message_id` is unindexed, so deletes target the deterministic point id.
|
|
278
|
+
expect(deleteCalls[0].opts.points).toEqual([messagePointId("msg-del")]);
|
|
279
|
+
expect(deleteCalls[0].opts.filter).toBeUndefined();
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
test("count returns the collection count", async () => {
|
|
283
|
+
const index = makeIndex();
|
|
284
|
+
expect(await index.count()).toBe(7);
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
test("clear drops the whole collection when it exists", async () => {
|
|
288
|
+
mockCollectionExists = true;
|
|
289
|
+
const index = makeIndex();
|
|
290
|
+
|
|
291
|
+
const dropped = await index.clear();
|
|
292
|
+
|
|
293
|
+
expect(dropped).toBe(true);
|
|
294
|
+
expect(deleteCollectionCalls).toEqual(["messages_lexical"]);
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
test("clear returns false (no throw) when the collection is absent", async () => {
|
|
298
|
+
mockCollectionExists = false;
|
|
299
|
+
const index = makeIndex();
|
|
300
|
+
|
|
301
|
+
const dropped = await index.clear();
|
|
302
|
+
|
|
303
|
+
expect(dropped).toBe(false);
|
|
304
|
+
expect(deleteCollectionCalls).toEqual([]);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
test("no dense vector is ever written or queried across operations", async () => {
|
|
308
|
+
mockQueryPoints = [
|
|
309
|
+
{ id: "pt-1", score: 0.5, payload: { message_id: "msg-A" } },
|
|
310
|
+
];
|
|
311
|
+
const index = makeIndex();
|
|
312
|
+
await index.upsertMessage("m1", SPARSE, {
|
|
313
|
+
conversationId: "c1",
|
|
314
|
+
createdAt: 1,
|
|
315
|
+
});
|
|
316
|
+
await index.searchLexical(SPARSE, 5);
|
|
317
|
+
|
|
318
|
+
// Collection config never declares a dense vector.
|
|
319
|
+
for (const call of createCollectionCalls) {
|
|
320
|
+
expect("vectors" in call.config).toBe(false);
|
|
321
|
+
}
|
|
322
|
+
// No upsert point carries a dense vector.
|
|
323
|
+
for (const call of upsertCalls) {
|
|
324
|
+
for (const point of call.opts.points) {
|
|
325
|
+
const vector = (point as { vector: Record<string, unknown> }).vector;
|
|
326
|
+
expect("dense" in vector).toBe(false);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
// No query targets a dense vector.
|
|
330
|
+
for (const call of queryCalls) {
|
|
331
|
+
expect(call.opts.using).toBe("sparse");
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
});
|