@vellumai/assistant 0.10.4 → 0.10.5-dev.202607022329.d89bf2f
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +94 -91
- package/Dockerfile +5 -16
- package/README.md +7 -10
- package/bun.lock +0 -4
- package/docs/architecture/security.md +20 -20
- package/docs/stt-provider-onboarding.md +4 -5
- package/docs/trusted-contact-access.md +7 -7
- package/eslint-rules/cli-no-daemon-internals.js +4 -0
- package/eslint.config.mjs +7 -1
- package/knip.json +0 -1
- package/node_modules/@vellumai/gateway-client/src/__tests__/contact-read-contracts.test.ts +36 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/invite-contract.test.ts +233 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +40 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +20 -8
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +10 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +33 -0
- package/node_modules/@vellumai/gateway-client/src/invite-contract.ts +216 -0
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +91 -0
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +39 -3
- package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +0 -8
- package/node_modules/@vellumai/service-contracts/src/__tests__/package-boundary.test.ts +1 -5
- package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +3 -14
- package/openapi.yaml +1073 -225
- package/package.json +1 -4
- package/scripts/test.sh +35 -13
- package/src/__tests__/access-request-seed-content-blocks.test.ts +60 -4
- package/src/__tests__/acp-session.test.ts +4 -1
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +0 -6
- package/src/__tests__/add-message-preassigned-id.test.ts +56 -0
- package/src/__tests__/agent-loop-set-system-prompt.test.ts +139 -0
- package/src/__tests__/app-conversation-ids-backfill.test.ts +3 -0
- package/src/__tests__/app-source-watcher.test.ts +11 -0
- package/src/__tests__/approval-interception-trust-gates.test.ts +148 -3
- package/src/__tests__/assistant-attachments.test.ts +62 -4
- package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -1
- package/src/__tests__/attachments-store-heic-normalize.test.ts +230 -0
- package/src/__tests__/attachments-store.test.ts +3 -0
- package/src/__tests__/background-shell-bash.test.ts +34 -0
- package/src/__tests__/background-shell-host-bash.test.ts +12 -0
- package/src/__tests__/background-tool-registry.test.ts +97 -0
- package/src/__tests__/background-tool-routes.test.ts +72 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +2 -1
- package/src/__tests__/btw-routes.test.ts +57 -3
- package/src/__tests__/call-controller.test.ts +474 -84
- package/src/__tests__/call-domain.test.ts +48 -1
- package/src/__tests__/call-pointer-messages.test.ts +57 -19
- package/src/__tests__/call-pointer-no-hardcoded-copy.guard.test.ts +2 -6
- package/src/__tests__/call-routes-http.test.ts +15 -14
- package/src/__tests__/call-setup-flow-invite.test.ts +568 -0
- package/src/__tests__/call-setup-flow-midcall-trust.test.ts +231 -0
- package/src/__tests__/call-setup-flow-name-capture.test.ts +754 -0
- package/src/__tests__/call-setup-flow-verification.test.ts +925 -0
- package/src/__tests__/call-setup-flow.test.ts +311 -0
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +0 -1
- package/src/__tests__/channel-guardian.test.ts +4 -7
- package/src/__tests__/channel-readiness-service.test.ts +0 -6
- package/src/__tests__/channel-readiness-slack-remote.test.ts +0 -4
- package/src/__tests__/channel-retry-sweep.test.ts +76 -64
- package/src/__tests__/channel-setup-panel-ack.test.ts +184 -0
- package/src/__tests__/clear-all-lexical.test.ts +90 -0
- package/src/__tests__/compactor-media-strip.test.ts +177 -0
- package/src/__tests__/config-loader-backfill.test.ts +5 -5
- package/src/__tests__/config-schema.test.ts +17 -0
- package/src/__tests__/contact-store-interaction-info.test.ts +27 -70
- package/src/__tests__/contacts-relay-reads.test.ts +188 -23
- package/src/__tests__/contacts-tools.test.ts +42 -1
- package/src/__tests__/contacts-write.test.ts +181 -0
- package/src/__tests__/context-search-conversations-source.test.ts +220 -81
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop.test.ts +39 -0
- package/src/__tests__/conversation-analysis-routes.test.ts +1 -1
- package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -0
- package/src/__tests__/conversation-clear-safety.test.ts +0 -1
- package/src/__tests__/conversation-crud-enabled-plugins.test.ts +60 -0
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -1
- package/src/__tests__/conversation-disk-view.test.ts +1 -0
- package/src/__tests__/conversation-enabledplugins-route.test.ts +184 -0
- package/src/__tests__/conversation-error.test.ts +0 -18
- package/src/__tests__/conversation-fork-crud.test.ts +67 -0
- package/src/__tests__/conversation-history-web-search.test.ts +7 -137
- package/src/__tests__/conversation-initial-prompt.test.ts +110 -0
- package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +191 -0
- package/src/__tests__/conversation-process-callsite.test.ts +37 -0
- package/src/__tests__/conversation-queue.test.ts +149 -0
- package/src/__tests__/conversation-routes-enabled-plugins.test.ts +392 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +84 -0
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +407 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +36 -16
- package/src/__tests__/conversation-skill-tools.test.ts +73 -0
- package/src/__tests__/conversation-wipe.test.ts +20 -5
- package/src/__tests__/credential-prompt-route.test.ts +69 -0
- package/src/__tests__/credential-security-invariants.test.ts +1 -3
- package/src/__tests__/db-drop-messages-fts.test.ts +115 -0
- package/src/__tests__/deterministic-verification-control-plane.test.ts +1 -62
- package/src/__tests__/edit-propagation.test.ts +56 -2
- package/src/__tests__/empty-state-greeting-cache.test.ts +9 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +15 -110
- package/src/__tests__/guardian-expiry-notifier.test.ts +1 -0
- package/src/__tests__/guardian-question-mode.test.ts +57 -0
- package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -1
- package/src/__tests__/guardian-wait-controller.test.ts +619 -0
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +33 -2
- package/src/__tests__/heic-fixture.ts +55 -0
- package/src/__tests__/helpers/seed-contact-channel.ts +0 -2
- package/src/__tests__/http-conversation-lineage.test.ts +6 -1
- package/src/__tests__/image-conversion.test.ts +170 -0
- package/src/__tests__/inbound-invite-redemption.test.ts +72 -341
- package/src/__tests__/introduction-card-resolver.test.ts +354 -0
- package/src/__tests__/invite-redeemed-ipc.test.ts +97 -0
- package/src/__tests__/invite-routes-http.test.ts +246 -420
- package/src/__tests__/job-handler-registration-guard.test.ts +104 -0
- package/src/__tests__/lexical-index-dual-write.test.ts +426 -0
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +2 -2
- package/src/__tests__/list-messages-attachments.test.ts +159 -0
- package/src/__tests__/list-messages-background-tool-completion.test.ts +141 -0
- package/src/__tests__/list-messages-queued.test.ts +25 -0
- package/src/__tests__/managed-store.test.ts +129 -1
- package/src/__tests__/media-stream-audio-transcode.test.ts +113 -0
- package/src/__tests__/media-stream-output.test.ts +350 -19
- package/src/__tests__/media-stream-server-integration.test.ts +943 -169
- package/src/__tests__/media-stream-stt-session.test.ts +498 -1
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +2 -2
- package/src/__tests__/model-intents.test.ts +1 -1
- package/src/__tests__/mtime-cache.test.ts +19 -0
- package/src/__tests__/non-member-access-request.test.ts +349 -3
- package/src/__tests__/notification-decision-fallback.test.ts +104 -8
- package/src/__tests__/notification-decision-strategy.test.ts +57 -8
- package/src/__tests__/onboarding-template-contract.test.ts +27 -43
- package/src/__tests__/openai-provider.test.ts +33 -0
- package/src/__tests__/openai-responses-provider.test.ts +40 -0
- package/src/__tests__/persistence-layering-guard.test.ts +29 -20
- package/src/__tests__/persona-resolver.test.ts +56 -2
- package/src/__tests__/personal-memory-auth-bypass.test.ts +62 -0
- package/src/__tests__/phone.test.ts +1 -15
- package/src/__tests__/plugin-bootstrap.test.ts +25 -196
- package/src/__tests__/plugin-disabled-state.test.ts +33 -0
- package/src/__tests__/plugin-effective-enabled-set.test.ts +227 -0
- package/src/__tests__/plugin-event-hub-facade.test.ts +323 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +156 -42
- package/src/__tests__/plugin-injector-contribution.test.ts +4 -20
- package/src/__tests__/plugin-pipeline.test.ts +63 -1
- package/src/__tests__/plugin-route-contribution.test.ts +62 -115
- package/src/__tests__/plugin-tool-contribution.test.ts +0 -22
- package/src/__tests__/plugin-types.test.ts +0 -1
- package/src/__tests__/pointer-conversation-trust.test.ts +38 -6
- package/src/__tests__/pre-model-call-sanitize.test.ts +1 -1
- package/src/__tests__/prune-old-tool-invocations-job.test.ts +97 -0
- package/src/__tests__/public-ingress-urls.test.ts +0 -48
- package/src/__tests__/qdrant-collection-migration.test.ts +145 -2
- package/src/__tests__/reaction-intercept-member-verdict-warm.test.ts +0 -1
- package/src/__tests__/resolve-trust-class.test.ts +28 -10
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +137 -0
- package/src/__tests__/schedule-retry.test.ts +38 -14
- package/src/__tests__/schedule-routes-workflow-validation.test.ts +3 -3
- package/src/__tests__/schedule-routes.test.ts +14 -6
- package/src/__tests__/schedule-store.test.ts +3 -1
- package/src/__tests__/scheduler-disk-pressure.test.ts +17 -6
- package/src/__tests__/scheduler-recurrence.test.ts +57 -107
- package/src/__tests__/scheduler-reuse-conversation.test.ts +51 -46
- package/src/__tests__/scheduler-wake.test.ts +13 -23
- package/src/__tests__/scheduler-worker-standdown.test.ts +220 -0
- package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -1
- package/src/__tests__/shell-observability.test.ts +1 -0
- package/src/__tests__/skill-boundary-guard.test.ts +3 -4
- package/src/__tests__/skill-load-plugin-scope.test.ts +238 -0
- package/src/__tests__/skill-projection-feature-flag.test.ts +2 -0
- package/src/__tests__/skill-script-runner-host.test.ts +53 -0
- package/src/__tests__/skill-script-runner-sandbox.test.ts +5 -2
- package/src/__tests__/skill-tool-factory.test.ts +73 -1
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +37 -14
- package/src/__tests__/slack-inbound-verification.test.ts +36 -0
- package/src/__tests__/slack-notification-approval-card.test.ts +89 -2
- package/src/__tests__/slack-reaction-canonical-approval.test.ts +51 -1
- package/src/__tests__/stt-hints.test.ts +2 -256
- package/src/__tests__/subagent-allowlist-validation.test.ts +47 -0
- package/src/__tests__/subagent-call-site-routing.test.ts +72 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +14 -2
- package/src/__tests__/subagent-persistence.test.ts +122 -0
- package/src/__tests__/subagent-spawn-and-await.test.ts +1 -0
- package/src/__tests__/subagent-terminal-message.test.ts +99 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +78 -1
- package/src/__tests__/system-prompt.test.ts +17 -118
- package/src/__tests__/task-scheduler.test.ts +68 -89
- package/src/__tests__/telephony-credential-preflight.test.ts +312 -0
- package/src/__tests__/telephony-tts-guard.test.ts +538 -0
- package/src/__tests__/title-generate-hook.test.ts +16 -0
- package/src/__tests__/tool-approval-handler.test.ts +87 -1
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +45 -20
- package/src/__tests__/tool-grant-request-escalation.test.ts +39 -0
- package/src/__tests__/trust-context-guards.test.ts +21 -10
- package/src/__tests__/trusted-contact-multichannel.test.ts +4 -0
- package/src/__tests__/twilio-provider.test.ts +17 -17
- package/src/__tests__/twilio-routes-twiml.test.ts +6 -543
- package/src/__tests__/twilio-routes.test.ts +257 -387
- package/src/__tests__/twilio-validation.test.ts +1 -1
- package/src/__tests__/unified-turn-context-client-os.test.ts +45 -0
- package/src/__tests__/usage-cache-backfill-migration.test.ts +5 -0
- package/src/__tests__/voice-approval-resolver-relay.test.ts +150 -0
- package/src/__tests__/voice-ingress-preflight.test.ts +61 -0
- package/src/__tests__/voice-quality.test.ts +2 -2
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +1 -7
- package/src/__tests__/voice-session-bridge-processing-wait.test.ts +27 -0
- package/src/__tests__/voice-session-bridge.test.ts +1 -10
- package/src/__tests__/workspace-git-service.test.ts +1 -1
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +1 -0
- package/src/__tests__/workspace-migration-118-seed-now-md.test.ts +120 -0
- package/src/__tests__/workspace-migration-120-revise-onboarding-threads.test.ts +175 -0
- package/src/__tests__/workspace-migration-121-seed-default-user-guardrails.test.ts +118 -0
- package/src/__tests__/workspace-migration-122-relocate-default-user-boundary.test.ts +119 -0
- package/src/__tests__/workspace-migration-123-swap-quality-profile-to-fable.test.ts +191 -0
- package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +235 -241
- package/src/acp/__tests__/prepare-agent-env.test.ts +0 -97
- package/src/acp/__tests__/session-manager-persistence.test.ts +2 -0
- package/src/acp/__tests__/session-manager-resume.test.ts +8 -0
- package/src/acp/__tests__/session-manager-usage.test.ts +6 -0
- package/src/acp/__tests__/session-manager.test.ts +6 -0
- package/src/acp/agent-process.test.ts +116 -0
- package/src/acp/agent-process.ts +71 -0
- package/src/acp/auto-install.ts +12 -8
- package/src/acp/failure-error.test.ts +109 -0
- package/src/acp/failure-error.ts +111 -0
- package/src/acp/prepare-agent-env.ts +0 -12
- package/src/acp/resolve-agent.test.ts +6 -45
- package/src/acp/resolve-agent.ts +2 -4
- package/src/acp/session-manager.test.ts +312 -0
- package/src/acp/session-manager.ts +102 -46
- package/src/agent/ax-tree-compaction.test.ts +4 -1
- package/src/agent/image-optimize.ts +17 -127
- package/src/agent/loop.ts +45 -192
- package/src/api/events/background-tool-completed.test.ts +51 -0
- package/src/api/events/background-tool-completed.ts +29 -0
- package/src/api/events/background-tool-started.test.ts +36 -0
- package/src/api/events/background-tool-started.ts +28 -0
- package/src/api/events/conversation-error.ts +0 -1
- package/src/api/events/open-panel.ts +33 -0
- package/src/api/events/subagent-status-changed.ts +4 -1
- package/src/api/index.ts +19 -0
- package/src/api/responses/conversation-message.ts +34 -0
- package/src/approvals/guardian-decision-primitive.ts +74 -24
- package/src/approvals/guardian-request-resolvers.ts +450 -122
- package/src/apps/app-store.ts +1 -0
- package/src/apps/shared-app-links-store.ts +1 -0
- package/src/avatar/identity-avatar.ts +3 -7
- package/src/background-wake/wake-intent-hooks.test.ts +1 -1
- package/src/calls/__tests__/fish-audio-client.test.ts +73 -0
- package/src/calls/__tests__/gateway-invite-reader.test.ts +170 -0
- package/src/calls/__tests__/relay-setup-router.test.ts +126 -102
- package/src/calls/call-controller.ts +134 -48
- package/src/calls/call-domain.ts +18 -42
- package/src/calls/call-pointer-messages.ts +51 -67
- package/src/calls/call-setup-flow-types.ts +76 -0
- package/src/calls/call-setup-flow.ts +1743 -0
- package/src/calls/call-speech-output.ts +87 -23
- package/src/calls/call-store.ts +4 -0
- package/src/calls/call-transport.ts +22 -36
- package/src/calls/fish-audio-client.ts +3 -0
- package/src/calls/gateway-invite-reader.ts +98 -0
- package/src/calls/guardian-wait-controller.ts +451 -0
- package/src/calls/media-stream-audio-transcode.ts +82 -2
- package/src/calls/media-stream-output.ts +142 -36
- package/src/calls/media-stream-server.ts +297 -178
- package/src/calls/media-stream-stt-session.ts +393 -50
- package/src/calls/media-turn-detector.ts +4 -6
- package/src/calls/relay-access-wait.ts +3 -4
- package/src/calls/relay-setup-router.ts +22 -43
- package/src/calls/relay-verification.ts +17 -24
- package/src/calls/resolve-call-tts-provider.ts +96 -29
- package/src/calls/stt-hints.ts +24 -87
- package/src/calls/telephony-credential-preflight.ts +159 -0
- package/src/calls/telephony-tts-capability.ts +183 -0
- package/src/calls/tts-call-strategy.ts +18 -20
- package/src/calls/twilio-provider.ts +3 -2
- package/src/calls/twilio-routes.ts +47 -351
- package/src/calls/types.ts +5 -3
- package/src/calls/voice-ingress-preflight.ts +9 -0
- package/src/calls/voice-quality.ts +13 -18
- package/src/calls/voice-session-bridge.ts +25 -35
- package/src/channels/__tests__/types.test.ts +28 -0
- package/src/channels/channel-verification-sessions.ts +7 -2
- package/src/channels/config.ts +0 -42
- package/src/channels/slack-thread-store.ts +12 -0
- package/src/channels/types.ts +23 -0
- package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -1
- package/src/cli/commands/__tests__/schedules.test.ts +83 -34
- package/src/cli/commands/__tests__/status.test.ts +42 -2
- package/src/cli/commands/contacts.ts +2 -2
- package/src/cli/commands/credentials.ts +17 -0
- package/src/cli/commands/monitoring.ts +191 -0
- package/src/cli/commands/schedules-worker.ts +175 -0
- package/src/cli/commands/schedules.ts +169 -43
- package/src/cli/commands/status.ts +12 -1
- package/src/cli/commands/tools.ts +5 -1
- package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +1 -0
- package/src/cli/lib/__tests__/search-plugins.test.ts +29 -1
- package/src/cli/lib/__tests__/toggle-plugin.test.ts +7 -0
- package/src/cli/lib/search-plugins.ts +6 -0
- package/src/cli/lib/toggle-plugin.ts +21 -2
- package/src/cli/program.ts +3 -1
- package/src/config/__tests__/deployment-context-defaults.test.ts +23 -0
- package/src/config/acp-defaults.test.ts +0 -10
- package/src/config/acp-defaults.ts +0 -6
- package/src/config/bundled-skills/acp/SKILL.md +13 -45
- package/src/config/bundled-skills/acp/TOOLS.json +3 -3
- package/src/config/bundled-skills/app-builder/SKILL.md +3 -3
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +9 -9
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +1 -1
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +1 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +9 -9
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +10 -7
- package/src/config/bundled-skills/skill-management/TOOLS.json +10 -0
- package/src/config/call-site-defaults.ts +0 -2
- package/src/config/feature-flag-registry.json +16 -8
- package/src/config/loader.ts +11 -0
- package/src/config/schema.ts +9 -1
- package/src/config/schemas/__tests__/memory-v2.test.ts +2 -2
- package/src/config/schemas/__tests__/memory-v3.test.ts +64 -0
- package/src/config/schemas/call-site-catalog.ts +0 -12
- package/src/config/schemas/calls.ts +8 -0
- package/src/config/schemas/elevenlabs.ts +1 -1
- package/src/config/schemas/llm.ts +0 -2
- package/src/config/schemas/memory-v2.ts +1 -1
- package/src/config/schemas/memory-v3.ts +82 -0
- package/src/config/schemas/monitoring.ts +61 -0
- package/src/config/schemas/schedules.ts +35 -0
- package/src/config/seed-inference-profiles.ts +2 -2
- package/src/config/skills-plugin-filter.test.ts +96 -0
- package/src/config/skills.ts +26 -0
- package/src/contacts/__tests__/member-write-relay.test.ts +156 -4
- package/src/contacts/canonical-guardian-store.ts +5 -0
- package/src/contacts/contact-store.ts +81 -35
- package/src/contacts/contacts-write.ts +50 -25
- package/src/contacts/member-write-relay.ts +115 -31
- package/src/contacts/types.ts +0 -8
- package/src/context/compactor.ts +29 -15
- package/src/context/outbound-sanitize.ts +202 -0
- package/src/daemon/__tests__/abort-null-controller.test.ts +167 -0
- package/src/daemon/__tests__/conversation-tool-setup-plugin-scope.test.ts +122 -0
- package/src/daemon/__tests__/embedding-reconcile.test.ts +99 -16
- package/src/daemon/__tests__/wake-conversation-ops-completion.test.ts +107 -0
- package/src/daemon/abort-watchdog.ts +7 -0
- package/src/daemon/app-source-watcher.ts +9 -0
- package/src/daemon/assistant-attachments.ts +42 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +256 -147
- package/src/daemon/conversation-agent-loop.ts +61 -68
- package/src/daemon/conversation-error.ts +1 -15
- package/src/daemon/conversation-history.ts +32 -236
- package/src/daemon/conversation-initial-prompt.ts +77 -0
- package/src/daemon/conversation-lifecycle.ts +25 -1
- package/src/daemon/conversation-messaging.ts +2 -2
- package/src/daemon/conversation-plugin-scope.ts +38 -0
- package/src/daemon/conversation-process.ts +50 -14
- package/src/daemon/conversation-runtime-assembly.ts +36 -6
- package/src/daemon/conversation-skill-tools.ts +19 -3
- package/src/daemon/conversation-store.ts +3 -3
- package/src/daemon/conversation-surfaces.ts +171 -0
- package/src/daemon/conversation-tool-setup.test.ts +95 -0
- package/src/daemon/conversation-tool-setup.ts +116 -1
- package/src/daemon/conversation-turn-finalize.ts +211 -0
- package/src/daemon/conversation.ts +92 -1
- package/src/daemon/disk-pressure-policy.ts +2 -1
- package/src/daemon/event-loop-watchdog.ts +22 -6
- package/src/daemon/external-plugins-bootstrap.ts +47 -134
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +1 -1
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +26 -14
- package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +27 -14
- package/src/daemon/handlers/__tests__/config-channels.test.ts +0 -5
- package/src/daemon/handlers/config-a2a.ts +7 -14
- package/src/daemon/handlers/config-channels.ts +2 -10
- package/src/daemon/handlers/conversation-history.ts +3 -1
- package/src/daemon/handlers/conversations.ts +0 -52
- package/src/daemon/handlers/shared.ts +4 -24
- package/src/daemon/handlers/skills.ts +4 -1
- package/src/daemon/host-cu-proxy.ts +1 -1
- package/src/daemon/lifecycle.ts +59 -472
- package/src/daemon/message-protocol.ts +3 -3
- package/src/daemon/message-provenance.ts +12 -14
- package/src/daemon/message-types/background-tools.ts +28 -0
- package/src/daemon/message-types/contacts.ts +2 -10
- package/src/daemon/message-types/conversations.ts +10 -0
- package/src/daemon/message-types/integrations.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +1 -0
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/pointer-conversation-trust.ts +23 -9
- package/src/daemon/pointer-turn-runner.ts +174 -0
- package/src/daemon/providers-setup.ts +16 -0
- package/src/daemon/shutdown-handlers.ts +139 -47
- package/src/daemon/skill-memory-refresh.ts +2 -2
- package/src/daemon/sqlite-corruption-watchdog.test.ts +217 -0
- package/src/daemon/sqlite-corruption-watchdog.ts +155 -0
- package/src/daemon/tool-setup-types.ts +8 -0
- package/src/daemon/trust-context.ts +21 -6
- package/src/daemon/turn-latency-tracker.test.ts +93 -0
- package/src/daemon/turn-latency-tracker.ts +38 -0
- package/src/daemon/wake-conversation-ops.ts +10 -8
- package/src/documents/document-comments-store.test.ts +7 -1
- package/src/documents/document-comments-store.ts +8 -0
- package/src/documents/document-store.ts +15 -0
- package/src/export/__tests__/transcript-formatter.test.ts +11 -0
- package/src/export/transcript-formatter.ts +49 -67
- package/src/home/__tests__/feed-writer.test.ts +247 -1
- package/src/home/conversation-starter-checkpoints.ts +1 -0
- package/src/home/feed-writer.ts +61 -0
- package/src/home/job-handlers/conversation-starters.ts +1 -0
- package/src/hooks/hook-loader.ts +12 -0
- package/src/hooks/registry.ts +32 -4
- package/src/inbound/public-ingress-urls.ts +0 -17
- package/src/ipc/__tests__/contacts-info-ipc.test.ts +285 -0
- package/src/ipc/assistant-server.ts +28 -7
- package/src/ipc/routes/__tests__/contacts-mirror-apply-atomicity.test.ts +62 -0
- package/src/ipc/routes/__tests__/contacts-mirror-apply.test.ts +272 -0
- package/src/ipc/routes/__tests__/contacts-mirror-ipc-routes.test.ts +322 -0
- package/src/ipc/routes/__tests__/invite-ipc-routes.test.ts +60 -4
- package/src/ipc/routes/contacts-info-ipc-routes.ts +239 -0
- package/src/ipc/routes/contacts-mirror-ipc-routes.ts +202 -0
- package/src/ipc/routes/db-proxy.ts +5 -2
- package/src/ipc/routes/invite-ipc-routes.ts +53 -39
- package/src/jobs/worker.ts +9 -2
- package/src/live-voice/__tests__/live-voice-archive.test.ts +10 -1
- package/src/live-voice/live-voice-archive.ts +5 -0
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +22 -6
- package/src/messaging/providers/channel-transport.ts +6 -0
- package/src/messaging/providers/index.ts +3 -0
- package/src/messaging/providers/slack/api.test.ts +49 -1
- package/src/messaging/providers/slack/api.ts +110 -0
- package/src/messaging/providers/slack/send.test.ts +85 -0
- package/src/messaging/providers/slack/send.ts +100 -28
- package/src/messaging/providers/slack/transport.ts +7 -13
- package/src/messaging/providers/whatsapp/send.ts +29 -9
- package/src/monitoring/__tests__/control.test.ts +235 -0
- package/src/monitoring/__tests__/sample-ring-buffer.test.ts +96 -0
- package/src/monitoring/control.ts +105 -0
- package/src/monitoring/resource-sampler.ts +258 -0
- package/src/monitoring/sample-ring-buffer.ts +108 -0
- package/src/monitoring/worker.ts +94 -0
- package/src/notifications/README.md +1 -1
- package/src/notifications/access-request-copy.ts +94 -23
- package/src/notifications/adapters/slack.ts +89 -21
- package/src/notifications/approval-card-builder.ts +33 -18
- package/src/notifications/approval-card-data.ts +48 -15
- package/src/notifications/broadcaster.ts +25 -16
- package/src/notifications/decision-engine.ts +131 -32
- package/src/notifications/guardian-question-mode.ts +58 -10
- package/src/permissions/approval-policy.ts +8 -1
- package/src/permissions/checker.ts +2 -0
- package/src/permissions/gateway-threshold-reader.ts +7 -6
- package/src/permissions/ipc-risk-types.ts +1 -0
- package/src/permissions/secret-prompter.ts +11 -3
- package/src/permissions/types.ts +2 -2
- package/src/persistence/__tests__/conversation-queries-search.test.ts +397 -0
- package/src/persistence/__tests__/conversation-search-lexical.test.ts +103 -0
- package/src/persistence/__tests__/jobs-worker-memory-disabled.test.ts +95 -0
- package/src/persistence/__tests__/slow-query-log.test.ts +266 -0
- package/src/persistence/__tests__/slow-sync-log.test.ts +155 -0
- package/src/persistence/a2a-invite-store.ts +205 -0
- package/src/persistence/attachments-store.ts +94 -10
- package/src/persistence/checkpoints.ts +45 -0
- package/src/persistence/conversation-crud.ts +453 -260
- package/src/persistence/conversation-display-order-migration.ts +8 -2
- package/src/persistence/conversation-group-migration.test.ts +8 -0
- package/src/persistence/conversation-group-migration.ts +9 -0
- package/src/persistence/conversation-queries.ts +244 -125
- package/src/persistence/conversation-row-batch-delete.ts +9 -5
- package/src/persistence/conversation-search-lexical.ts +49 -0
- package/src/persistence/db-async-query.ts +42 -0
- package/src/persistence/db-connection.ts +13 -0
- package/src/persistence/delivery-channels.ts +0 -82
- package/src/persistence/delivery-crud.ts +27 -6
- package/src/persistence/embeddings/__tests__/embedding-identity.test.ts +18 -5
- package/src/persistence/embeddings/__tests__/messages-lexical-index.test.ts +334 -0
- package/src/persistence/embeddings/embedding-identity.ts +17 -5
- package/src/persistence/embeddings/embedding-runtime-manager.ts +31 -0
- package/src/persistence/embeddings/messages-lexical-index.ts +396 -0
- package/src/persistence/embeddings/qdrant-client.ts +81 -5
- package/src/persistence/group-crud.ts +13 -1
- package/src/persistence/job-handlers/__tests__/message-lexical-backfill.test.ts +506 -0
- package/src/persistence/job-handlers/__tests__/message-lexical-enqueue.test.ts +164 -0
- package/src/persistence/job-handlers/__tests__/message-lexical.test.ts +259 -0
- package/src/persistence/job-handlers/cleanup.ts +57 -9
- package/src/persistence/job-handlers/message-lexical-backfill.ts +187 -0
- package/src/persistence/job-handlers/message-lexical.ts +251 -0
- package/src/persistence/jobs-store.ts +102 -8
- package/src/persistence/jobs-worker.ts +68 -28
- package/src/persistence/llm-request-log-store.ts +35 -19
- package/src/persistence/llm-usage-store.ts +11 -0
- package/src/persistence/memory-lifecycle-hooks.test.ts +65 -0
- package/src/persistence/memory-lifecycle-hooks.ts +55 -1
- package/src/persistence/migrations/028-call-session-mode.ts +1 -1
- package/src/persistence/migrations/116-messages-fts.ts +8 -1
- package/src/persistence/migrations/311-create-subagents-table.ts +50 -0
- package/src/persistence/migrations/312-drop-inbox-conversation-state-table.ts +15 -0
- package/src/persistence/migrations/313-drop-messages-fts.ts +17 -0
- package/src/persistence/migrations/314-add-conversation-enabled-plugins.ts +25 -0
- package/src/persistence/migrations/315-create-a2a-invites.ts +58 -0
- package/src/persistence/migrations/316-drop-contact-channels-invite-id.ts +28 -0
- package/src/persistence/migrations/317-canonical-guardian-requester-signals.ts +24 -0
- package/src/persistence/migrations/318-drop-contact-channel-telemetry.ts +32 -0
- package/src/persistence/migrations/__tests__/315-create-a2a-invites.test.ts +161 -0
- package/src/persistence/migrations/__tests__/316-drop-contact-channels-invite-id.test.ts +156 -0
- package/src/persistence/migrations/__tests__/318-drop-contact-channel-telemetry.test.ts +134 -0
- package/src/persistence/migrations/__tests__/migration-prefix-guard.test.ts +99 -0
- package/src/persistence/raw-query.ts +50 -11
- package/src/persistence/schema/a2a.ts +14 -0
- package/src/persistence/schema/contacts.ts +0 -62
- package/src/persistence/schema/conversation-groups.ts +12 -0
- package/src/persistence/schema/conversations.ts +2 -0
- package/src/persistence/schema/documents.ts +65 -0
- package/src/persistence/schema/guardian.ts +4 -0
- package/src/persistence/schema/index.ts +4 -0
- package/src/persistence/schema/memory-injection.ts +62 -0
- package/src/persistence/schema/workflows.ts +55 -0
- package/src/persistence/slow-query-log.ts +437 -0
- package/src/persistence/slow-sync-log.ts +204 -0
- package/src/persistence/steps.ts +16 -0
- package/src/persistence/subagent-store.ts +125 -0
- package/src/persistence/worker-control.ts +45 -238
- package/src/plugin-api/event-hub-facade.ts +172 -0
- package/src/plugin-api/index.ts +9 -1
- package/src/plugin-api/types.ts +40 -9
- package/src/plugins/defaults/default-plugin-names.ts +60 -0
- package/src/plugins/defaults/index.ts +19 -29
- package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +46 -67
- package/src/plugins/defaults/memory/__tests__/db-async-query.test.ts +36 -1
- package/src/plugins/defaults/memory/__tests__/find-most-recent-retrospective-for.test.ts +2 -4
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +2 -2
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-schedule.test.ts +9 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +7 -4
- package/src/plugins/defaults/memory/config.ts +11 -0
- package/src/plugins/defaults/memory/context-search/agent-runner.ts +1 -1
- package/src/plugins/defaults/memory/context-search/sources/conversations.ts +124 -113
- package/src/plugins/defaults/memory/embeddings.ts +77 -0
- package/src/plugins/defaults/memory/find-most-recent-retrospective-for.ts +66 -0
- package/src/plugins/defaults/memory/frontmatter.ts +50 -0
- package/src/plugins/defaults/memory/graph/bootstrap.test.ts +36 -10
- package/src/plugins/defaults/memory/graph/bootstrap.ts +6 -5
- package/src/plugins/defaults/memory/graph/consolidation.ts +3 -5
- package/src/plugins/defaults/memory/graph/extraction.ts +3 -6
- package/src/plugins/defaults/memory/graph/graph-search.ts +12 -23
- package/src/plugins/defaults/memory/graph/narrative.ts +3 -5
- package/src/plugins/defaults/memory/graph/pattern-scan.ts +3 -5
- package/src/plugins/defaults/memory/graph/retriever.test.ts +1 -6
- package/src/plugins/defaults/memory/graph/retriever.ts +5 -10
- package/src/plugins/defaults/memory/graph/tools.ts +1 -1
- package/src/plugins/defaults/memory/hooks/init.ts +31 -5
- package/src/plugins/defaults/memory/indexer.ts +2 -3
- package/src/plugins/defaults/memory/injectors.ts +2 -2
- package/src/plugins/defaults/memory/job-handler-registration.ts +96 -0
- package/src/plugins/defaults/memory/job-handlers/backfill.ts +4 -26
- package/src/plugins/defaults/memory/job-handlers/embedding.test.ts +6 -19
- package/src/plugins/defaults/memory/job-handlers/embedding.ts +9 -22
- package/src/plugins/defaults/memory/job-handlers/index-maintenance.ts +2 -3
- package/src/plugins/defaults/memory/job-handlers.ts +13 -12
- package/src/plugins/defaults/memory/jobs/embed-concept-page.ts +1 -1
- package/src/plugins/defaults/memory/llm-helpers.ts +76 -0
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +8 -5
- package/src/plugins/defaults/memory/memory-retrospective-startup-cleanup.ts +2 -2
- package/src/plugins/defaults/memory/memory-v2-concept-frequency.ts +2 -0
- package/src/plugins/defaults/memory/persistence-hooks.ts +46 -1
- package/src/plugins/defaults/memory/pkb/pkb-index.ts +1 -5
- package/src/plugins/defaults/memory/pkb/pkb-search.ts +2 -2
- package/src/plugins/defaults/memory/routes/__tests__/memory-v2-simulate-route.test.ts +4 -6
- package/src/plugins/defaults/memory/routes/memory-item-routes.ts +1 -1
- package/src/plugins/defaults/memory/search/semantic.ts +2 -2
- package/src/plugins/defaults/memory/startup.ts +244 -0
- package/src/plugins/defaults/memory/task-memory-cleanup.ts +8 -0
- package/src/{daemon → plugins/defaults/memory/v2}/__tests__/memory-v2-startup.test.ts +6 -6
- package/src/plugins/defaults/memory/v2/__tests__/migration.test.ts +2 -13
- package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +4 -5
- package/src/plugins/defaults/memory/v2/__tests__/sweep-job.test.ts +1 -8
- package/src/plugins/defaults/memory/v2/activation.ts +2 -4
- package/src/plugins/defaults/memory/v2/cli-command-store.ts +2 -4
- package/src/plugins/defaults/memory/v2/frontmatter-sweep.ts +1 -1
- package/src/{daemon → plugins/defaults/memory/v2}/memory-v2-startup.test.ts +8 -8
- package/src/{daemon → plugins/defaults/memory/v2}/memory-v2-startup.ts +20 -22
- package/src/plugins/defaults/memory/v2/migration.ts +2 -5
- package/src/plugins/defaults/memory/v2/page-store.ts +1 -1
- package/src/plugins/defaults/memory/v2/qdrant.ts +2 -3
- package/src/plugins/defaults/memory/v2/router.ts +5 -5
- package/src/plugins/defaults/memory/v2/sim.ts +2 -4
- package/src/plugins/defaults/memory/v2/skill-store.ts +2 -4
- package/src/plugins/defaults/memory/v2/sweep-job.ts +6 -6
- package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +11 -9
- package/src/plugins/defaults/memory/v3/__tests__/dense.test.ts +107 -2
- package/src/plugins/defaults/memory/v3/__tests__/gate-flag.test.ts +69 -0
- package/src/plugins/defaults/memory/v3/__tests__/gate.test.ts +181 -0
- package/src/plugins/defaults/memory/v3/__tests__/live-integration.test.ts +7 -3
- package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +345 -8
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +1 -4
- package/src/plugins/defaults/memory/v3/__tests__/section-needle.test.ts +64 -0
- package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +18 -13
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +62 -1
- package/src/plugins/defaults/memory/v3/card.ts +1 -4
- package/src/plugins/defaults/memory/v3/dense.ts +60 -25
- package/src/plugins/defaults/memory/v3/edge.ts +1 -1
- package/src/plugins/defaults/memory/v3/gate-flag.ts +20 -0
- package/src/plugins/defaults/memory/v3/gate.ts +158 -0
- package/src/plugins/defaults/memory/v3/maintain-job.ts +2 -4
- package/src/plugins/defaults/memory/v3/orchestrate.ts +186 -25
- package/src/plugins/defaults/memory/v3/pool-select.test.ts +7 -9
- package/src/plugins/defaults/memory/v3/pool-select.ts +6 -6
- package/src/plugins/defaults/memory/v3/prune.ts +2 -2
- package/src/plugins/defaults/memory/v3/section-dense-store.ts +8 -11
- package/src/plugins/defaults/memory/v3/section-needle.ts +27 -7
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +10 -0
- package/src/plugins/defaults/memory/v3-eval/eval-packets.ts +1 -4
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +5 -0
- package/src/plugins/defaults/turn-context/injectors.ts +1 -0
- package/src/plugins/defaults/turn-context/unified-turn-context.ts +12 -0
- package/src/plugins/injector-registry.ts +13 -2
- package/src/plugins/mtime-cache.ts +36 -47
- package/src/plugins/pipeline.ts +15 -1
- package/src/plugins/types.ts +14 -23
- package/src/prompts/__tests__/system-prompt.test.ts +170 -32
- package/src/prompts/persona-resolver.ts +13 -9
- package/src/prompts/system-prompt.ts +30 -9
- package/src/prompts/templates/BOOTSTRAP.md +16 -119
- package/src/prompts/templates/SOUL.md +43 -13
- package/src/prompts/templates/system-sections.ts +32 -27
- package/src/prompts/templates/users/default.md +19 -0
- package/src/providers/__tests__/placeholder-sentinels.test.ts +56 -0
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +96 -1
- package/src/providers/model-intents.ts +2 -2
- package/src/providers/openai/chat-completions-provider.ts +14 -1
- package/src/providers/openai/responses-provider.ts +18 -0
- package/src/providers/placeholder-sentinels.ts +18 -8
- package/src/providers/retry.ts +1 -0
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +0 -64
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +92 -79
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +98 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +62 -3
- package/src/providers/speech-to-text/provider-catalog.ts +0 -89
- package/src/providers/speech-to-text/resolve.ts +55 -0
- package/src/providers/tool-progress-events.test.ts +50 -0
- package/src/providers/tool-progress-events.ts +99 -0
- package/src/providers/types.ts +1 -1
- package/src/providers/vellum-model-routing.test.ts +51 -0
- package/src/providers/vellum-model-routing.ts +84 -0
- package/src/runtime/AGENTS.md +5 -4
- package/src/runtime/__tests__/agent-wake.test.ts +158 -1
- package/src/runtime/__tests__/channel-verification-service.test.ts +2 -2
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +37 -8
- package/src/runtime/access-request-helper.ts +154 -3
- package/src/runtime/actor-trust-resolver.ts +7 -21
- package/src/runtime/agent-wake.ts +41 -1
- package/src/runtime/assistant-event.ts +86 -12
- package/src/runtime/auth/__tests__/route-policy.test.ts +31 -0
- package/src/runtime/channel-approval-types.ts +52 -2
- package/src/runtime/channel-approvals.ts +23 -8
- package/src/runtime/channel-invite-transport.ts +2 -2
- package/src/runtime/channel-invite-transports/voice.ts +1 -1
- package/src/runtime/channel-readiness-service.ts +3 -5
- package/src/runtime/channel-retry-sweep.ts +18 -24
- package/src/runtime/channel-verification-service.ts +9 -11
- package/src/runtime/finalize-event-delivery.ts +30 -16
- package/src/runtime/guardian-action-service.ts +10 -11
- package/src/runtime/guardian-reply-router.ts +122 -21
- package/src/runtime/http-server.ts +44 -101
- package/src/runtime/introduction-policy.test.ts +214 -0
- package/src/runtime/introduction-policy.ts +284 -0
- package/src/runtime/invite-service.ts +104 -361
- package/src/runtime/local-actor-identity.test.ts +38 -0
- package/src/runtime/local-actor-identity.ts +14 -0
- package/src/runtime/middleware/__tests__/rate-limiter.test.ts +22 -0
- package/src/runtime/middleware/rate-limiter.ts +30 -0
- package/src/runtime/middleware/twilio-validation.ts +5 -7
- package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +28 -0
- package/src/runtime/migrations/origin-mode.ts +6 -6
- package/src/runtime/pre-first-message-gate.ts +1 -0
- package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +6 -35
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +24 -3
- package/src/runtime/routes/__tests__/contact-routes.test.ts +80 -15
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +7 -1
- package/src/runtime/routes/__tests__/global-search-routes.test.ts +0 -3
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +142 -1
- package/src/runtime/routes/__tests__/invite-relay-routes.test.ts +119 -30
- package/src/runtime/routes/__tests__/migration-import-allowed-hosts-env.test.ts +70 -0
- package/src/runtime/routes/__tests__/monitoring-routes.test.ts +194 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +755 -29
- package/src/runtime/routes/__tests__/retrospective-routes.test.ts +4 -0
- package/src/runtime/routes/__tests__/schedule-routes-create.test.ts +70 -0
- package/src/runtime/routes/__tests__/schedule-worker-routes.test.ts +161 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +1 -1
- package/src/runtime/routes/acp-routes.ts +15 -3
- package/src/runtime/routes/app-management-routes.ts +4 -7
- package/src/runtime/routes/approval-routes.ts +4 -0
- package/src/runtime/routes/attachment-routes.ts +54 -3
- package/src/runtime/routes/avatar-routes.ts +0 -4
- package/src/runtime/routes/background-tool-routes.ts +34 -5
- package/src/runtime/routes/btw-routes.ts +32 -4
- package/src/runtime/routes/channel-route-shared.ts +18 -14
- package/src/runtime/routes/channel-verification-routes.ts +0 -3
- package/src/runtime/routes/contact-routes.ts +298 -117
- package/src/runtime/routes/conversation-list-routes.ts +6 -0
- package/src/runtime/routes/conversation-management-routes.ts +74 -37
- package/src/runtime/routes/conversation-query-routes.ts +5 -2
- package/src/runtime/routes/conversation-routes.ts +222 -82
- package/src/runtime/routes/conversations-import-routes.ts +8 -1
- package/src/runtime/routes/credential-prompt-routes.ts +20 -5
- package/src/runtime/routes/debug-routes.ts +1 -0
- package/src/runtime/routes/documents-routes.ts +5 -2
- package/src/runtime/routes/empty-state-greeting-cache.ts +37 -10
- package/src/runtime/routes/global-search-routes.ts +2 -1
- package/src/runtime/routes/guardian-approval-interception.ts +51 -0
- package/src/runtime/routes/home-feed-routes.ts +60 -1
- package/src/runtime/routes/identity-routes.ts +4 -87
- package/src/runtime/routes/inbound-message-handler.ts +82 -41
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +430 -57
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +302 -572
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +76 -270
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +21 -116
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +9 -1
- package/src/runtime/routes/inbound-stages/escalation-intercept.test.ts +158 -0
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +22 -1
- package/src/runtime/routes/index.ts +6 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +22 -16
- package/src/runtime/routes/internal-twilio-routes.ts +0 -15
- package/src/runtime/routes/messages-lexical-routes.ts +75 -0
- package/src/runtime/routes/migration-routes.ts +69 -6
- package/src/runtime/routes/monitoring-routes.ts +237 -0
- package/src/runtime/routes/plugins-routes.ts +329 -8
- package/src/runtime/routes/schedule-routes.ts +49 -8
- package/src/runtime/routes/schedule-worker-routes.ts +210 -0
- package/src/runtime/routes/secret-routes.ts +1 -1
- package/src/runtime/routes/surface-conversation-resolver.ts +1 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +54 -9
- package/src/runtime/services/__tests__/auto-analysis-enqueue.test.ts +30 -6
- package/src/runtime/services/__tests__/conversation-analyze-job.test.ts +43 -8
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +20 -0
- package/src/runtime/services/analyze-conversation.ts +14 -4
- package/src/runtime/services/conversation-serializer.ts +5 -0
- package/src/runtime/slack-no-response.ts +47 -0
- package/src/runtime/slack-reply-session.test.ts +633 -0
- package/src/runtime/slack-reply-session.ts +382 -0
- package/src/runtime/slack-task-progress.ts +95 -0
- package/src/runtime/sync/resource-sync-events.ts +25 -0
- package/src/runtime/tool-grant-request-helper.ts +17 -1
- package/src/runtime/trust-class.test.ts +141 -0
- package/src/runtime/trust-class.ts +121 -0
- package/src/runtime/trust-verdict-consumer.ts +7 -6
- package/src/schedule/__tests__/run-script.test.ts +21 -0
- package/src/schedule/__tests__/worker-control.test.ts +241 -0
- package/src/schedule/run-script.ts +13 -6
- package/src/schedule/schedule-usage-store.ts +1 -0
- package/src/schedule/scheduler.ts +178 -127
- package/src/schedule/worker-control.ts +118 -0
- package/src/schedule/worker.ts +131 -0
- package/src/skills/__tests__/categories-cache.test.ts +38 -0
- package/src/skills/categories-cache.ts +40 -5
- package/src/skills/managed-store.ts +41 -6
- package/src/skills/validate-input.ts +47 -0
- package/src/stt/types.ts +5 -9
- package/src/subagent/manager.ts +267 -39
- package/src/subagent/types.ts +6 -2
- package/src/subagent/validate-allowlists.ts +65 -0
- package/src/telemetry/watchdog-direct-emit.test.ts +109 -0
- package/src/telemetry/watchdog-direct-emit.ts +89 -0
- package/src/tools/acp/list-agents.test.ts +0 -6
- package/src/tools/background-tool-registry.ts +61 -0
- package/src/tools/document/document-comment-tool.test.ts +4 -0
- package/src/tools/host-terminal/host-shell.test.ts +397 -0
- package/src/tools/host-terminal/host-shell.ts +203 -14
- package/src/tools/skills/find-similar-skills.test.ts +152 -1
- package/src/tools/skills/find-similar-skills.ts +30 -4
- package/src/tools/skills/load.ts +36 -0
- package/src/tools/skills/scaffold-managed.ts +66 -34
- package/src/tools/skills/skill-script-runner.ts +17 -0
- package/src/tools/skills/skill-tool-factory.ts +5 -1
- package/src/tools/terminal/safe-env.ts +3 -0
- package/src/tools/terminal/shell.test.ts +177 -0
- package/src/tools/terminal/shell.ts +98 -4
- package/src/tools/tool-approval-handler.ts +106 -29
- package/{node_modules/@vellumai/skill-host-contracts/src → src/tools}/tool-types.ts +16 -17
- package/src/tools/types.ts +29 -17
- package/src/tools/ui-surface/definitions.ts +3 -1
- package/src/tts/__tests__/provider-adapters.test.ts +37 -0
- package/src/tts/__tests__/provider-catalog.test.ts +21 -0
- package/src/tts/provider-catalog.ts +40 -9
- package/src/tts/providers/fish-audio-provider.ts +19 -10
- package/src/tts/types.ts +3 -4
- package/src/util/__tests__/process-tree.test.ts +10 -2
- package/src/util/__tests__/text-spacing.test.ts +53 -0
- package/src/util/cgroup-memory.ts +142 -0
- package/src/util/image-conversion.ts +281 -0
- package/src/util/phone.ts +1 -8
- package/src/util/platform.ts +33 -0
- package/src/util/process-tree.ts +10 -2
- package/src/util/text-spacing.ts +53 -0
- package/src/util/worker-process.ts +271 -0
- package/src/workflows/journal-store.ts +16 -1
- package/src/workflows/library.test.ts +35 -20
- package/src/workflows/library.ts +105 -66
- package/src/workspace/git-service.ts +1 -0
- package/src/workspace/migrations/011-backfill-installation-id.ts +83 -31
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +41 -22
- package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +1 -1
- package/src/workspace/migrations/118-seed-now-md.ts +64 -0
- package/src/workspace/migrations/119-strip-persisted-memory-v3-tuning-defaults.ts +169 -0
- package/src/workspace/migrations/120-revise-onboarding-threads.ts +47 -0
- package/src/workspace/migrations/121-seed-default-user-guardrails.ts +82 -0
- package/src/workspace/migrations/122-relocate-default-user-boundary.ts +111 -0
- package/src/workspace/migrations/123-swap-quality-profile-to-fable.ts +85 -0
- package/src/workspace/migrations/__tests__/119-strip-persisted-memory-v3-tuning-defaults.test.ts +181 -0
- package/src/workspace/migrations/registry.ts +12 -0
- package/drizzle/0000_dizzy_maggott.sql +0 -301
- package/drizzle/meta/0000_snapshot.json +0 -1933
- package/drizzle/meta/_journal.json +0 -13
- package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +0 -887
- package/node_modules/@vellumai/skill-host-contracts/bun.lock +0 -24
- package/node_modules/@vellumai/skill-host-contracts/package.json +0 -18
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -97
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +0 -1349
- package/node_modules/@vellumai/skill-host-contracts/src/index.ts +0 -6
- package/node_modules/@vellumai/skill-host-contracts/src/runtime-mode.ts +0 -11
- package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +0 -32
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +0 -333
- package/node_modules/@vellumai/skill-host-contracts/tsconfig.json +0 -20
- package/node_modules/@vellumai/skill-host-contracts/tsconfig.test.json +0 -12
- package/src/__tests__/invite-redemption-service.test.ts +0 -1180
- package/src/__tests__/invite-service-ipc.test.ts +0 -350
- package/src/__tests__/job-handler-registry-guard.test.ts +0 -125
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +0 -203
- package/src/__tests__/relay-server.test.ts +0 -6153
- package/src/__tests__/telephony-stt-routing.test.ts +0 -329
- package/src/__tests__/voice-invite-redemption.test.ts +0 -702
- package/src/calls/relay-server.ts +0 -2463
- package/src/calls/telephony-stt-routing.ts +0 -145
- package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +0 -128
- package/src/daemon/__tests__/daemon-skill-host.test.ts +0 -273
- package/src/daemon/daemon-skill-host.ts +0 -262
- package/src/daemon/message-types/meet.ts +0 -143
- package/src/daemon/shutdown-registry.ts +0 -40
- package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -253
- package/src/ipc/__tests__/skill-server.test.ts +0 -182
- package/src/ipc/skill-ipc-types.ts +0 -54
- package/src/ipc/skill-routes/__tests__/config.test.ts +0 -146
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +0 -448
- package/src/ipc/skill-routes/__tests__/identity.test.ts +0 -62
- package/src/ipc/skill-routes/__tests__/log.test.ts +0 -133
- package/src/ipc/skill-routes/__tests__/memory.test.ts +0 -203
- package/src/ipc/skill-routes/__tests__/platform.test.ts +0 -111
- package/src/ipc/skill-routes/__tests__/providers.test.ts +0 -265
- package/src/ipc/skill-routes/__tests__/registries.test.ts +0 -400
- package/src/ipc/skill-routes/config.ts +0 -47
- package/src/ipc/skill-routes/events.ts +0 -147
- package/src/ipc/skill-routes/identity.ts +0 -21
- package/src/ipc/skill-routes/index.ts +0 -37
- package/src/ipc/skill-routes/log.ts +0 -40
- package/src/ipc/skill-routes/memory.ts +0 -92
- package/src/ipc/skill-routes/platform.ts +0 -39
- package/src/ipc/skill-routes/providers.ts +0 -162
- package/src/ipc/skill-routes/registries.ts +0 -338
- package/src/ipc/skill-server.ts +0 -831
- package/src/ipc/skill-socket-path.ts +0 -20
- package/src/jobs/register-job-handlers.ts +0 -74
- package/src/persistence/invite-store.ts +0 -481
- package/src/plugins/job-handler-registry.ts +0 -94
- package/src/providers/cache-control.ts +0 -26
- package/src/runtime/__tests__/runtime-mode.test.ts +0 -62
- package/src/runtime/invite-redemption-service.ts +0 -828
- package/src/runtime/invite-redemption-templates.ts +0 -46
- package/src/runtime/runtime-mode.ts +0 -40
- package/src/runtime/slack-dm-text-delivery.ts +0 -177
- package/src/util/voice-code.ts +0 -31
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { QdrantClient } from "@qdrant/js-client-rest";
|
|
2
2
|
|
|
3
3
|
import type { AssistantConfig } from "../../config/types.js";
|
|
4
|
+
import { getLogger } from "../../util/logger.js";
|
|
4
5
|
import {
|
|
5
6
|
resolveBackendDimension,
|
|
6
7
|
selectEmbeddingBackend,
|
|
@@ -9,6 +10,8 @@ import { isEmbeddingBillingBreakerOpen } from "./embedding-billing-breaker.js";
|
|
|
9
10
|
import type { EmbeddingProviderName } from "./embedding-types.js";
|
|
10
11
|
import { resolveQdrantUrl } from "./qdrant-client.js";
|
|
11
12
|
|
|
13
|
+
const log = getLogger("embedding-identity");
|
|
14
|
+
|
|
12
15
|
// Inlined rather than imported from `memory/v2/qdrant.ts`: the persistence
|
|
13
16
|
// layer must not import from the memory feature layer (enforced by
|
|
14
17
|
// persistence-layering-guard). The dependency direction is memory → persistence.
|
|
@@ -28,6 +31,7 @@ export interface BackendDimensionProbe {
|
|
|
28
31
|
* reconcile defers rather than committing on a measurement it could not take:
|
|
29
32
|
* - the billing breaker is open (treated as "backend down");
|
|
30
33
|
* - no backend is configured/selectable;
|
|
34
|
+
* - backend selection throws (e.g. a transient credential-store error);
|
|
31
35
|
* - the measurement probe throws (provider unreachable).
|
|
32
36
|
*
|
|
33
37
|
* Delegates the dimension measurement to {@link resolveBackendDimension}, the
|
|
@@ -40,12 +44,20 @@ export async function probeBackendDimension(
|
|
|
40
44
|
): Promise<BackendDimensionProbe | null> {
|
|
41
45
|
if (isEmbeddingBillingBreakerOpen()) return null;
|
|
42
46
|
|
|
43
|
-
|
|
44
|
-
|
|
47
|
+
try {
|
|
48
|
+
const { backend } = await selectEmbeddingBackend(config);
|
|
49
|
+
if (!backend) return null;
|
|
45
50
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
51
|
+
const dim = await resolveBackendDimension(backend);
|
|
52
|
+
if (dim == null) return null;
|
|
53
|
+
return { provider: backend.provider, model: backend.model, dim };
|
|
54
|
+
} catch (err) {
|
|
55
|
+
// `selectEmbeddingBackend` resolves provider credentials and can reject on a
|
|
56
|
+
// non-timeout credential-store error; the reconcile relies on a null return
|
|
57
|
+
// to defer, so honor the never-throws contract and treat it as degraded.
|
|
58
|
+
log.warn({ err }, "Embedding-dimension probe failed; treating as degraded");
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
49
61
|
}
|
|
50
62
|
|
|
51
63
|
/**
|
|
@@ -571,3 +571,34 @@ export class EmbeddingRuntimeManager {
|
|
|
571
571
|
}
|
|
572
572
|
}
|
|
573
573
|
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Download the local embedding runtime in the background (non-blocking).
|
|
577
|
+
*
|
|
578
|
+
* Pre-warms the runtime (bun binary + ONNX worker scripts) so the first local
|
|
579
|
+
* embed doesn't pay the download cost inline. A no-op when the runtime is
|
|
580
|
+
* already installed. Failures are swallowed with a warning: local embeddings
|
|
581
|
+
* fall back to cloud backends, so a failed download must never block or crash
|
|
582
|
+
* daemon startup. Returns immediately; the download proceeds on its own.
|
|
583
|
+
*/
|
|
584
|
+
export function startEmbeddingRuntimeManager(): void {
|
|
585
|
+
void (async () => {
|
|
586
|
+
try {
|
|
587
|
+
const runtimeManager = new EmbeddingRuntimeManager();
|
|
588
|
+
if (runtimeManager.isReady()) return;
|
|
589
|
+
log.info("Downloading embedding runtime in background...");
|
|
590
|
+
await runtimeManager.ensureInstalled();
|
|
591
|
+
// Reset the sticky local-backend failure flag so auto mode retries
|
|
592
|
+
// local embeddings without evicting a worker that may already be live.
|
|
593
|
+
const { resetLocalEmbeddingFailureState } =
|
|
594
|
+
await import("./embedding-backend.js");
|
|
595
|
+
resetLocalEmbeddingFailureState();
|
|
596
|
+
log.info("Embedding runtime download complete");
|
|
597
|
+
} catch (err) {
|
|
598
|
+
log.warn(
|
|
599
|
+
{ err },
|
|
600
|
+
"Embedding runtime download failed — local embeddings will use cloud fallback",
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
})();
|
|
604
|
+
}
|
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
import { QdrantClient as QdrantRestClient } from "@qdrant/js-client-rest";
|
|
2
|
+
import { v5 as uuidv5 } from "uuid";
|
|
3
|
+
|
|
4
|
+
import { getLogger } from "../../util/logger.js";
|
|
5
|
+
import type { SparseEmbedding } from "./embedding-types.js";
|
|
6
|
+
|
|
7
|
+
const log = getLogger("messages-lexical-index");
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Dedicated Qdrant collection holding the lexical (BM25-style sparse) index for
|
|
11
|
+
* `messages`. Sparse-only — there is no dense vector. The collection is a
|
|
12
|
+
* faithful replacement for SQLite FTS5 full-text search over message content,
|
|
13
|
+
* encoded with the local TF-IDF sparse encoder so no per-message model call is
|
|
14
|
+
* required to index a message.
|
|
15
|
+
*/
|
|
16
|
+
export const MESSAGES_LEXICAL_COLLECTION = "messages_lexical";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Stable namespace for deriving deterministic Qdrant point ids from message
|
|
20
|
+
* ids. Using a fixed namespace (instead of `uuid.URL`) keeps point-id identity
|
|
21
|
+
* scoped to this index, so the same `messageId` always maps to the same point
|
|
22
|
+
* and re-indexing is idempotent without a pre-read.
|
|
23
|
+
*/
|
|
24
|
+
const MESSAGE_POINT_NAMESPACE = "b6d0d3e2-1f1a-4c3e-9a7c-0e2f5a8d4c11";
|
|
25
|
+
|
|
26
|
+
export interface MessagesLexicalIndexConfig {
|
|
27
|
+
url: string;
|
|
28
|
+
collection?: string;
|
|
29
|
+
onDisk?: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface MessageLexicalPayload {
|
|
33
|
+
messageId: string;
|
|
34
|
+
conversationId: string;
|
|
35
|
+
createdAt: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface MessageLexicalSearchResult {
|
|
39
|
+
messageId: string;
|
|
40
|
+
score: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let _instance: MessagesLexicalIndex | null = null;
|
|
44
|
+
|
|
45
|
+
export function getMessagesLexicalIndex(): MessagesLexicalIndex {
|
|
46
|
+
if (!_instance) {
|
|
47
|
+
throw new Error(
|
|
48
|
+
"Messages lexical index not initialized. Call initMessagesLexicalIndex() first.",
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
return _instance;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function initMessagesLexicalIndex(
|
|
55
|
+
config: MessagesLexicalIndexConfig,
|
|
56
|
+
): MessagesLexicalIndex {
|
|
57
|
+
_instance = new MessagesLexicalIndex(config);
|
|
58
|
+
return _instance;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Derive the deterministic Qdrant point id for a message. Idempotent:
|
|
63
|
+
* re-indexing the same `messageId` overwrites the same point.
|
|
64
|
+
*/
|
|
65
|
+
export function messagePointId(messageId: string): string {
|
|
66
|
+
return uuidv5(messageId, MESSAGE_POINT_NAMESPACE);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export class MessagesLexicalIndex {
|
|
70
|
+
private readonly client: QdrantRestClient;
|
|
71
|
+
private readonly collection: string;
|
|
72
|
+
private readonly onDisk: boolean;
|
|
73
|
+
private collectionReady = false;
|
|
74
|
+
|
|
75
|
+
constructor(config: MessagesLexicalIndexConfig) {
|
|
76
|
+
this.client = new QdrantRestClient({
|
|
77
|
+
url: config.url,
|
|
78
|
+
checkCompatibility: false,
|
|
79
|
+
});
|
|
80
|
+
this.collection = config.collection ?? MESSAGES_LEXICAL_COLLECTION;
|
|
81
|
+
this.onDisk = config.onDisk ?? true;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async ensureCollection(): Promise<void> {
|
|
85
|
+
if (this.collectionReady) return;
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const exists = await this.client.collectionExists(this.collection);
|
|
89
|
+
if (exists.exists) {
|
|
90
|
+
if (await this.ensurePayloadIndexesSafe()) {
|
|
91
|
+
this.collectionReady = true;
|
|
92
|
+
}
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
} catch {
|
|
96
|
+
// Existence check failed — fall through to creation.
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
log.info(
|
|
100
|
+
{ collection: this.collection },
|
|
101
|
+
"Creating sparse-only Qdrant collection for messages lexical index",
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
await this.client.createCollection(this.collection, {
|
|
106
|
+
// Sparse-only: no dense `vectors` config. The lexical index is a
|
|
107
|
+
// BM25-style replacement for FTS5 and never holds a dense vector.
|
|
108
|
+
sparse_vectors: {
|
|
109
|
+
sparse: {}, // Qdrant auto-infers sparse vector params
|
|
110
|
+
},
|
|
111
|
+
on_disk_payload: this.onDisk,
|
|
112
|
+
});
|
|
113
|
+
} catch (err) {
|
|
114
|
+
// 409 = a concurrent caller created the collection first — that's fine.
|
|
115
|
+
if (
|
|
116
|
+
err instanceof Error &&
|
|
117
|
+
"status" in err &&
|
|
118
|
+
(err as { status: number }).status === 409
|
|
119
|
+
) {
|
|
120
|
+
if (await this.ensurePayloadIndexesSafe()) {
|
|
121
|
+
this.collectionReady = true;
|
|
122
|
+
}
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
throw err;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (await this.ensurePayloadIndexesSafe()) {
|
|
129
|
+
this.collectionReady = true;
|
|
130
|
+
log.info(
|
|
131
|
+
{ collection: this.collection },
|
|
132
|
+
"Messages lexical index collection created with payload indexes",
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async upsertMessage(
|
|
138
|
+
messageId: string,
|
|
139
|
+
sparse: SparseEmbedding,
|
|
140
|
+
payload: { conversationId: string; createdAt: number },
|
|
141
|
+
): Promise<void> {
|
|
142
|
+
await this.upsertMessagesBatch([
|
|
143
|
+
{
|
|
144
|
+
messageId,
|
|
145
|
+
sparse,
|
|
146
|
+
conversationId: payload.conversationId,
|
|
147
|
+
createdAt: payload.createdAt,
|
|
148
|
+
},
|
|
149
|
+
]);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async upsertMessagesBatch(
|
|
153
|
+
points: Array<{
|
|
154
|
+
messageId: string;
|
|
155
|
+
sparse: SparseEmbedding;
|
|
156
|
+
conversationId: string;
|
|
157
|
+
createdAt: number;
|
|
158
|
+
}>,
|
|
159
|
+
): Promise<void> {
|
|
160
|
+
await this.ensureCollection();
|
|
161
|
+
|
|
162
|
+
if (points.length === 0) return;
|
|
163
|
+
|
|
164
|
+
const qdrantPoints = points.map((p) => ({
|
|
165
|
+
id: messagePointId(p.messageId),
|
|
166
|
+
vector: {
|
|
167
|
+
sparse: {
|
|
168
|
+
indices: p.sparse.indices,
|
|
169
|
+
values: p.sparse.values,
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
payload: {
|
|
173
|
+
message_id: p.messageId,
|
|
174
|
+
conversation_id: p.conversationId,
|
|
175
|
+
created_at: p.createdAt,
|
|
176
|
+
},
|
|
177
|
+
}));
|
|
178
|
+
|
|
179
|
+
const doUpsert = () =>
|
|
180
|
+
this.client.upsert(this.collection, {
|
|
181
|
+
wait: true,
|
|
182
|
+
points: qdrantPoints,
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
try {
|
|
186
|
+
await doUpsert();
|
|
187
|
+
} catch (err) {
|
|
188
|
+
if (this.isCollectionMissing(err)) {
|
|
189
|
+
this.collectionReady = false;
|
|
190
|
+
await this.ensureCollection();
|
|
191
|
+
await doUpsert();
|
|
192
|
+
} else {
|
|
193
|
+
throw err;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async searchLexical(
|
|
199
|
+
sparse: SparseEmbedding,
|
|
200
|
+
limit: number,
|
|
201
|
+
opts?: { conversationId?: string },
|
|
202
|
+
): Promise<MessageLexicalSearchResult[]> {
|
|
203
|
+
await this.ensureCollection();
|
|
204
|
+
|
|
205
|
+
const filter = opts?.conversationId
|
|
206
|
+
? {
|
|
207
|
+
must: [
|
|
208
|
+
{
|
|
209
|
+
key: "conversation_id",
|
|
210
|
+
match: { value: opts.conversationId },
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
}
|
|
214
|
+
: undefined;
|
|
215
|
+
|
|
216
|
+
const queryParams = {
|
|
217
|
+
query: {
|
|
218
|
+
indices: sparse.indices,
|
|
219
|
+
values: sparse.values,
|
|
220
|
+
},
|
|
221
|
+
using: "sparse",
|
|
222
|
+
limit,
|
|
223
|
+
with_payload: true,
|
|
224
|
+
filter: filter as Record<string, unknown> | undefined,
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
let results;
|
|
228
|
+
try {
|
|
229
|
+
results = await this.client.query(this.collection, queryParams);
|
|
230
|
+
} catch (err) {
|
|
231
|
+
if (this.isCollectionMissing(err)) {
|
|
232
|
+
this.collectionReady = false;
|
|
233
|
+
await this.ensureCollection();
|
|
234
|
+
results = await this.client.query(this.collection, queryParams);
|
|
235
|
+
} else {
|
|
236
|
+
throw err;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return (results.points ?? []).map((point) => ({
|
|
241
|
+
messageId: String(
|
|
242
|
+
(point.payload as Record<string, unknown> | undefined)?.message_id ??
|
|
243
|
+
"",
|
|
244
|
+
),
|
|
245
|
+
score: point.score ?? 0,
|
|
246
|
+
}));
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async deleteByMessageId(messageId: string): Promise<void> {
|
|
250
|
+
await this.ensureCollection();
|
|
251
|
+
|
|
252
|
+
// Delete by the deterministic point id rather than a `message_id` payload
|
|
253
|
+
// filter: `message_id` has no payload index, so a filter delete would scan
|
|
254
|
+
// the whole collection. The point id is recoverable from the message id.
|
|
255
|
+
const doDelete = () =>
|
|
256
|
+
this.client.delete(this.collection, {
|
|
257
|
+
wait: true,
|
|
258
|
+
points: [messagePointId(messageId)],
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
try {
|
|
262
|
+
await doDelete();
|
|
263
|
+
} catch (err) {
|
|
264
|
+
if (this.isCollectionMissing(err)) {
|
|
265
|
+
this.collectionReady = false;
|
|
266
|
+
await this.ensureCollection();
|
|
267
|
+
await doDelete();
|
|
268
|
+
} else {
|
|
269
|
+
throw err;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
async deleteByConversation(conversationId: string): Promise<void> {
|
|
275
|
+
await this.ensureCollection();
|
|
276
|
+
|
|
277
|
+
const doDelete = () =>
|
|
278
|
+
this.client.delete(this.collection, {
|
|
279
|
+
wait: true,
|
|
280
|
+
filter: {
|
|
281
|
+
must: [{ key: "conversation_id", match: { value: conversationId } }],
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
try {
|
|
286
|
+
await doDelete();
|
|
287
|
+
} catch (err) {
|
|
288
|
+
if (this.isCollectionMissing(err)) {
|
|
289
|
+
this.collectionReady = false;
|
|
290
|
+
await this.ensureCollection();
|
|
291
|
+
await doDelete();
|
|
292
|
+
} else {
|
|
293
|
+
throw err;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
async count(): Promise<number> {
|
|
299
|
+
await this.ensureCollection();
|
|
300
|
+
|
|
301
|
+
try {
|
|
302
|
+
const result = await this.client.count(this.collection, { exact: false });
|
|
303
|
+
return result.count;
|
|
304
|
+
} catch (err) {
|
|
305
|
+
if (this.isCollectionMissing(err)) {
|
|
306
|
+
this.collectionReady = false;
|
|
307
|
+
await this.ensureCollection();
|
|
308
|
+
const result = await this.client.count(this.collection, {
|
|
309
|
+
exact: false,
|
|
310
|
+
});
|
|
311
|
+
return result.count;
|
|
312
|
+
}
|
|
313
|
+
throw err;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Remove every point from the index by dropping the whole collection. Used by
|
|
319
|
+
* "clear all conversations" — a bulk wipe with no conversation ids left to
|
|
320
|
+
* enqueue per-conversation purges against. Resetting `collectionReady` means
|
|
321
|
+
* the next write self-heals via `ensureCollection`. Returns `false` (rather
|
|
322
|
+
* than throwing) if the collection is absent or the drop fails, mirroring the
|
|
323
|
+
* shared Qdrant client's `deleteCollection` so callers can treat it as
|
|
324
|
+
* best-effort.
|
|
325
|
+
*/
|
|
326
|
+
async clear(): Promise<boolean> {
|
|
327
|
+
try {
|
|
328
|
+
const exists = await this.client.collectionExists(this.collection);
|
|
329
|
+
if (!exists.exists) {
|
|
330
|
+
this.collectionReady = false;
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
333
|
+
await this.client.deleteCollection(this.collection);
|
|
334
|
+
this.collectionReady = false;
|
|
335
|
+
return true;
|
|
336
|
+
} catch (err) {
|
|
337
|
+
log.warn(
|
|
338
|
+
{ err, collection: this.collection },
|
|
339
|
+
"Failed to clear messages lexical index collection",
|
|
340
|
+
);
|
|
341
|
+
return false;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Detect "collection not found" errors from Qdrant so callers can reset
|
|
347
|
+
* collectionReady and retry after an external deletion.
|
|
348
|
+
*/
|
|
349
|
+
private isCollectionMissing(err: unknown): boolean {
|
|
350
|
+
if (
|
|
351
|
+
err &&
|
|
352
|
+
typeof err === "object" &&
|
|
353
|
+
"status" in err &&
|
|
354
|
+
(err as { status: number }).status === 404
|
|
355
|
+
) {
|
|
356
|
+
return true;
|
|
357
|
+
}
|
|
358
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
359
|
+
return (
|
|
360
|
+
msg.includes("Not found") ||
|
|
361
|
+
msg.includes("doesn't exist") ||
|
|
362
|
+
msg.includes("not found")
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Wraps ensurePayloadIndexes so that a 404 (collection deleted between the
|
|
368
|
+
* existence check and index creation) resets collectionReady instead of
|
|
369
|
+
* propagating — the next operation self-heals via ensureCollection.
|
|
370
|
+
*/
|
|
371
|
+
private async ensurePayloadIndexesSafe(): Promise<boolean> {
|
|
372
|
+
try {
|
|
373
|
+
await this.ensurePayloadIndexes();
|
|
374
|
+
return true;
|
|
375
|
+
} catch (err) {
|
|
376
|
+
if (this.isCollectionMissing(err)) {
|
|
377
|
+
this.collectionReady = false;
|
|
378
|
+
return false;
|
|
379
|
+
}
|
|
380
|
+
throw err;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
private async ensurePayloadIndexes(): Promise<void> {
|
|
385
|
+
await Promise.all([
|
|
386
|
+
this.client.createPayloadIndex(this.collection, {
|
|
387
|
+
field_name: "conversation_id",
|
|
388
|
+
field_schema: "keyword",
|
|
389
|
+
}),
|
|
390
|
+
this.client.createPayloadIndex(this.collection, {
|
|
391
|
+
field_name: "created_at",
|
|
392
|
+
field_schema: "integer",
|
|
393
|
+
}),
|
|
394
|
+
]);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { mkdir, unlink, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
|
|
1
5
|
import { QdrantClient as QdrantRestClient } from "@qdrant/js-client-rest";
|
|
2
6
|
import { v4 as uuid } from "uuid";
|
|
3
7
|
|
|
4
8
|
import { getQdrantHttpPortEnv, getQdrantUrlEnv } from "../../config/env.js";
|
|
5
9
|
import type { AssistantConfig } from "../../config/types.js";
|
|
6
10
|
import { getLogger } from "../../util/logger.js";
|
|
11
|
+
import { getDataDir } from "../../util/platform.js";
|
|
7
12
|
|
|
8
13
|
const log = getLogger("qdrant-client");
|
|
9
14
|
|
|
@@ -85,6 +90,57 @@ export function stripLegacySparseSuffix(sentinel: string): string {
|
|
|
85
90
|
return sentinel.replace(/:sparse-v\d+$/, "");
|
|
86
91
|
}
|
|
87
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Marker file written before the v1 collection's destructive dimension/model
|
|
95
|
+
* recreate, cleared by the startup lifecycle hook once the `rebuild_index` job
|
|
96
|
+
* has been enqueued.
|
|
97
|
+
*
|
|
98
|
+
* Closes a data-loss window in {@link VellumQdrantClient.ensureCollection}: the
|
|
99
|
+
* `migrated` signal that tells the lifecycle hook to enqueue `rebuild_index`
|
|
100
|
+
* otherwise lives only in a local variable returned after `deleteCollection` +
|
|
101
|
+
* `createCollection` both succeed. If Qdrant fails between the delete and the
|
|
102
|
+
* return — or the process crashes — that signal is lost: the next startup finds
|
|
103
|
+
* the collection missing, recreates it empty, reports `migrated: false`, and
|
|
104
|
+
* the v1 vectors stay dropped until each row is individually re-touched.
|
|
105
|
+
* Persisting the intent on disk *before* the delete lets it survive crashes and
|
|
106
|
+
* transient failures: every later `ensureCollection` reports `migrated: true`
|
|
107
|
+
* until the hook enqueues the rebuild and clears the sentinel. Mirrors the v2
|
|
108
|
+
* reembed sentinel in `plugins/defaults/memory/v2/qdrant.ts`.
|
|
109
|
+
*
|
|
110
|
+
* Distinct from the in-collection model-identity sentinel point handled by
|
|
111
|
+
* {@link VellumQdrantClient.readSentinel} / `writeSentinel` — that records the
|
|
112
|
+
* embedding model; this records "a rebuild is owed".
|
|
113
|
+
*/
|
|
114
|
+
const REBUILD_SENTINEL_FILENAME = ".memory-v1-rebuild-required";
|
|
115
|
+
|
|
116
|
+
function rebuildSentinelPath(): string {
|
|
117
|
+
return join(getDataDir(), REBUILD_SENTINEL_FILENAME);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function rebuildSentinelExists(): boolean {
|
|
121
|
+
return existsSync(rebuildSentinelPath());
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async function writeRebuildSentinel(): Promise<void> {
|
|
125
|
+
const path = rebuildSentinelPath();
|
|
126
|
+
await mkdir(dirname(path), { recursive: true });
|
|
127
|
+
await writeFile(path, "");
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Remove the rebuild sentinel after the startup lifecycle hook has enqueued the
|
|
132
|
+
* `rebuild_index` job. Idempotent — a missing file is not an error.
|
|
133
|
+
*/
|
|
134
|
+
export async function clearRebuildSentinel(): Promise<void> {
|
|
135
|
+
try {
|
|
136
|
+
await unlink(rebuildSentinelPath());
|
|
137
|
+
} catch (err) {
|
|
138
|
+
if ((err as NodeJS.ErrnoException).code !== "ENOENT") {
|
|
139
|
+
throw err;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
88
144
|
let _instance: VellumQdrantClient | null = null;
|
|
89
145
|
|
|
90
146
|
export function getQdrantClient(): VellumQdrantClient {
|
|
@@ -129,7 +185,11 @@ export class VellumQdrantClient {
|
|
|
129
185
|
async ensureCollection(): Promise<{ migrated: boolean }> {
|
|
130
186
|
if (this.collectionReady) return { migrated: false };
|
|
131
187
|
|
|
132
|
-
|
|
188
|
+
// A leftover sentinel means a prior boot deleted the collection but never
|
|
189
|
+
// got to enqueue the rebuild (createCollection threw, or the process died
|
|
190
|
+
// before the lifecycle hook ran). Carry that signal forward until the hook
|
|
191
|
+
// clears it, even when the collection now looks freshly created or intact.
|
|
192
|
+
let migrated = rebuildSentinelExists();
|
|
133
193
|
|
|
134
194
|
try {
|
|
135
195
|
const exists = await this.client.collectionExists(this.collection);
|
|
@@ -186,7 +246,7 @@ export class VellumQdrantClient {
|
|
|
186
246
|
},
|
|
187
247
|
"Qdrant collection uses unnamed vectors (legacy) — deleting and recreating with named vectors. Embeddings will be re-indexed.",
|
|
188
248
|
);
|
|
189
|
-
await this.
|
|
249
|
+
await this.deleteCollectionForRebuild();
|
|
190
250
|
migrated = true;
|
|
191
251
|
// Fall through to collection creation below
|
|
192
252
|
} else if (dimMismatch || modelMismatch) {
|
|
@@ -207,7 +267,7 @@ export class VellumQdrantClient {
|
|
|
207
267
|
},
|
|
208
268
|
"Qdrant collection incompatible (dimension/model change) — deleting and recreating. Embeddings will be regenerated on demand.",
|
|
209
269
|
);
|
|
210
|
-
await this.
|
|
270
|
+
await this.deleteCollectionForRebuild();
|
|
211
271
|
migrated = true;
|
|
212
272
|
// Fall through to collection creation below
|
|
213
273
|
} else {
|
|
@@ -217,7 +277,11 @@ export class VellumQdrantClient {
|
|
|
217
277
|
if (needsSentinelRewrite && this.embeddingModel) {
|
|
218
278
|
await this.writeSentinel(this.embeddingModel);
|
|
219
279
|
}
|
|
220
|
-
|
|
280
|
+
// `migrated` is false in steady state; it is only true here when a
|
|
281
|
+
// prior recreate wrote the sentinel but never cleared it, in which
|
|
282
|
+
// case the rebuild is still owed against this (possibly empty)
|
|
283
|
+
// collection.
|
|
284
|
+
return { migrated };
|
|
221
285
|
}
|
|
222
286
|
} catch (err) {
|
|
223
287
|
log.warn(
|
|
@@ -227,7 +291,7 @@ export class VellumQdrantClient {
|
|
|
227
291
|
if (await this.ensurePayloadIndexesSafe()) {
|
|
228
292
|
this.collectionReady = true;
|
|
229
293
|
}
|
|
230
|
-
return { migrated
|
|
294
|
+
return { migrated };
|
|
231
295
|
}
|
|
232
296
|
}
|
|
233
297
|
} catch {
|
|
@@ -302,6 +366,18 @@ export class VellumQdrantClient {
|
|
|
302
366
|
return { migrated };
|
|
303
367
|
}
|
|
304
368
|
|
|
369
|
+
/**
|
|
370
|
+
* Delete the collection as the first half of a destructive dimension/model
|
|
371
|
+
* recreate. Persists the rebuild sentinel BEFORE the delete so a crash or
|
|
372
|
+
* transient Qdrant failure between the delete and the recreate still triggers
|
|
373
|
+
* `rebuild_index` on the next ensure call. Callers set `migrated = true` and
|
|
374
|
+
* fall through to recreation.
|
|
375
|
+
*/
|
|
376
|
+
private async deleteCollectionForRebuild(): Promise<void> {
|
|
377
|
+
await writeRebuildSentinel();
|
|
378
|
+
await this.client.deleteCollection(this.collection);
|
|
379
|
+
}
|
|
380
|
+
|
|
305
381
|
async upsert(
|
|
306
382
|
targetType: QdrantPointPayload["target_type"],
|
|
307
383
|
targetId: string,
|
|
@@ -37,6 +37,7 @@ export function listGroups(): ConversationGroupRow[] {
|
|
|
37
37
|
created_at: number;
|
|
38
38
|
updated_at: number;
|
|
39
39
|
}>(
|
|
40
|
+
"group:listGroups",
|
|
40
41
|
"SELECT id, name, sort_position, is_system_group, created_at, updated_at FROM conversation_groups WHERE id NOT GLOB '_*' ORDER BY sort_position ASC",
|
|
41
42
|
);
|
|
42
43
|
return rows.map((r) => ({
|
|
@@ -63,6 +64,7 @@ export function getGroup(groupId: string): ConversationGroupRow | null {
|
|
|
63
64
|
created_at: number;
|
|
64
65
|
updated_at: number;
|
|
65
66
|
}>(
|
|
67
|
+
"group:getGroup",
|
|
66
68
|
"SELECT id, name, sort_position, is_system_group, created_at, updated_at FROM conversation_groups WHERE id = ?",
|
|
67
69
|
groupId,
|
|
68
70
|
);
|
|
@@ -91,12 +93,14 @@ export function createGroup(name: string): ConversationGroupRow {
|
|
|
91
93
|
ensureGroupMigration();
|
|
92
94
|
const maxPos =
|
|
93
95
|
rawGet<{ max: number | null }>(
|
|
96
|
+
"group:createGroup:maxPos",
|
|
94
97
|
"SELECT MAX(sort_position) as max FROM conversation_groups WHERE is_system_group = 0",
|
|
95
98
|
)?.max ?? 3;
|
|
96
99
|
const sortPosition = maxPos + 1;
|
|
97
100
|
const id = uuid();
|
|
98
101
|
const now = Math.floor(Date.now() / 1000);
|
|
99
102
|
rawRun(
|
|
103
|
+
"group:createGroup:insert",
|
|
100
104
|
"INSERT INTO conversation_groups (id, name, sort_position, is_system_group, created_at, updated_at) VALUES (?, ?, ?, 0, ?, ?)",
|
|
101
105
|
id,
|
|
102
106
|
name,
|
|
@@ -146,6 +150,7 @@ export function updateGroup(
|
|
|
146
150
|
values.push(groupId);
|
|
147
151
|
|
|
148
152
|
rawRun(
|
|
153
|
+
"group:updateGroup",
|
|
149
154
|
`UPDATE conversation_groups SET ${fields.join(", ")} WHERE id = ?`,
|
|
150
155
|
...values,
|
|
151
156
|
);
|
|
@@ -164,10 +169,15 @@ export function updateGroup(
|
|
|
164
169
|
export function deleteGroup(groupId: string): boolean {
|
|
165
170
|
ensureGroupMigration();
|
|
166
171
|
rawRun(
|
|
172
|
+
"group:deleteGroup:reassign",
|
|
167
173
|
"UPDATE conversations SET group_id = 'system:all' WHERE group_id = ?",
|
|
168
174
|
groupId,
|
|
169
175
|
);
|
|
170
|
-
rawRun(
|
|
176
|
+
rawRun(
|
|
177
|
+
"group:deleteGroup:delete",
|
|
178
|
+
"DELETE FROM conversation_groups WHERE id = ?",
|
|
179
|
+
groupId,
|
|
180
|
+
);
|
|
171
181
|
return true;
|
|
172
182
|
}
|
|
173
183
|
|
|
@@ -185,6 +195,7 @@ export function reorderGroups(
|
|
|
185
195
|
for (const update of updates) {
|
|
186
196
|
// Look up the group first — skip unknown/stale IDs and system groups
|
|
187
197
|
const group = rawGet<{ id: string; is_system_group: number }>(
|
|
198
|
+
"group:reorderGroups:select",
|
|
188
199
|
"SELECT id, is_system_group FROM conversation_groups WHERE id = ?",
|
|
189
200
|
update.groupId,
|
|
190
201
|
);
|
|
@@ -197,6 +208,7 @@ export function reorderGroups(
|
|
|
197
208
|
);
|
|
198
209
|
}
|
|
199
210
|
rawRun(
|
|
211
|
+
"group:reorderGroups:update",
|
|
200
212
|
"UPDATE conversation_groups SET sort_position = ?, updated_at = ? WHERE id = ?",
|
|
201
213
|
update.sortPosition,
|
|
202
214
|
now,
|