@vellumai/assistant 0.7.3 → 0.8.1
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/AGENTS.md +11 -0
- package/ARCHITECTURE.md +29 -28
- package/Dockerfile +6 -4
- package/README.md +2 -2
- package/__tests__/permissions/gateway-threshold-reader.test.ts +236 -9
- package/bun.lock +3 -0
- package/docker-entrypoint.sh +16 -0
- package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
- package/eslint-rules/cli-no-daemon-internals.js +283 -0
- package/eslint.config.mjs +12 -0
- package/knip.json +3 -1
- package/node_modules/@vellumai/ipc-server-utils/bun.lock +24 -0
- package/node_modules/@vellumai/ipc-server-utils/package.json +18 -0
- package/node_modules/@vellumai/ipc-server-utils/src/index.ts +6 -0
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +430 -0
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +221 -0
- package/node_modules/@vellumai/ipc-server-utils/tsconfig.json +20 -0
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
- package/openapi.yaml +4126 -959
- package/package.json +5 -1
- package/scripts/generate-openapi.ts +52 -4
- package/scripts/sync-llm-catalog.ts +165 -0
- package/scripts/sync-web-search-catalog.ts +107 -0
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
- package/src/__tests__/annotate-risk-options.test.ts +291 -0
- package/src/__tests__/anthropic-provider.test.ts +92 -2
- package/src/__tests__/app-control-flow.test.ts +7 -0
- package/src/__tests__/approval-cascade.test.ts +8 -16
- package/src/__tests__/approval-routes-http.test.ts +6 -0
- package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
- package/src/__tests__/auto-analysis-end-to-end.test.ts +12 -25
- package/src/__tests__/avatar-identity-sync.test.ts +87 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
- package/src/__tests__/btw-routes.test.ts +1 -0
- package/src/__tests__/call-constants.test.ts +10 -1
- package/src/__tests__/call-controller.test.ts +127 -0
- package/src/__tests__/call-site-routing-provider.test.ts +172 -45
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
- package/src/__tests__/channel-policy.test.ts +12 -0
- package/src/__tests__/checker.test.ts +89 -0
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +88 -30
- package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
- package/src/__tests__/config-loader-backfill.test.ts +526 -102
- package/src/__tests__/config-loader-corrupt.test.ts +68 -0
- package/src/__tests__/config-loader-platform-defaults.test.ts +345 -8
- package/src/__tests__/config-schema-cmd.test.ts +63 -29
- package/src/__tests__/config-schema.test.ts +14 -3
- package/src/__tests__/config-set-platform-guard.test.ts +75 -152
- package/src/__tests__/config-set-route.test.ts +198 -0
- package/src/__tests__/config-watcher.test.ts +6 -0
- package/src/__tests__/contacts-tools.test.ts +51 -199
- package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
- package/src/__tests__/context-search-agent-runner.test.ts +22 -138
- package/src/__tests__/context-search-conversations-source.test.ts +42 -16
- package/src/__tests__/context-search-fanout.test.ts +20 -157
- package/src/__tests__/context-search-memory-source.test.ts +3 -26
- package/src/__tests__/context-search-memory-v2-source.test.ts +3 -3
- package/src/__tests__/context-search-types.test.ts +7 -2
- package/src/__tests__/context-window-manager.test.ts +389 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +1 -6
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -1
- package/src/__tests__/conversation-agent-loop.test.ts +3 -3
- package/src/__tests__/conversation-confirmation-signals.test.ts +5 -13
- package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
- package/src/__tests__/conversation-error.test.ts +38 -0
- package/src/__tests__/conversation-fork-crud.test.ts +241 -1
- package/src/__tests__/conversation-inference-profile-route.test.ts +14 -14
- package/src/__tests__/conversation-init.benchmark.test.ts +2 -1
- package/src/__tests__/conversation-lifecycle.test.ts +124 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
- package/src/__tests__/conversation-process-callsite.test.ts +22 -7
- package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -6
- package/src/__tests__/conversation-runtime-assembly.test.ts +19 -10
- package/src/__tests__/conversation-slash-commands.test.ts +194 -2
- package/src/__tests__/conversation-slash-unknown.test.ts +1 -6
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +170 -9
- package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +73 -1
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +59 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +1 -7
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -7
- package/src/__tests__/credential-security-invariants.test.ts +5 -6
- package/src/__tests__/daemon-credential-client.test.ts +56 -1
- package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
- package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
- package/src/__tests__/db-proxy-transaction.test.ts +206 -0
- package/src/__tests__/external-plugin-loader.test.ts +458 -0
- package/src/__tests__/filing-service.test.ts +25 -22
- package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +10 -34
- package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
- package/src/__tests__/heartbeat-service.test.ts +50 -233
- package/src/__tests__/history-repair.test.ts +89 -0
- package/src/__tests__/host-app-control-proxy.test.ts +109 -1
- package/src/__tests__/host-app-control-routes.test.ts +247 -1
- package/src/__tests__/host-browser-proxy.test.ts +416 -20
- package/src/__tests__/host-browser-routes.test.ts +325 -33
- package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
- package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
- package/src/__tests__/inference-profile-reaper.test.ts +154 -0
- package/src/__tests__/inference-profile-session-handler.test.ts +398 -0
- package/src/__tests__/inference-profile-session-ipc.test.ts +236 -0
- package/src/__tests__/injector-chain.test.ts +24 -16
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +10 -7
- package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
- package/src/__tests__/install-skill-routing.test.ts +2 -2
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +169 -67
- package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
- package/src/__tests__/llm-catalog-parity.test.ts +146 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +188 -0
- package/src/__tests__/llm-request-log-source-factory.test.ts +124 -0
- package/src/__tests__/llm-resolver.test.ts +46 -0
- package/src/__tests__/managed-profile-guard.test.ts +131 -2
- package/src/__tests__/mcp-auth-routes.test.ts +1 -0
- package/src/__tests__/mcp-cli.test.ts +182 -220
- package/src/__tests__/mcp-health-check.test.ts +56 -27
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
- package/src/__tests__/message-complete-display-id.test.ts +175 -0
- package/src/__tests__/notification-decision-fallback.test.ts +91 -0
- package/src/__tests__/notification-decision-strategy.test.ts +22 -0
- package/src/__tests__/notification-platform-adapter.test.ts +229 -0
- package/src/__tests__/oauth-cli.test.ts +38 -1888
- package/src/__tests__/oauth-commands-routes.test.ts +711 -0
- package/src/__tests__/oauth-connect-routes.test.ts +174 -11
- package/src/__tests__/oauth-providers-routes.test.ts +14 -10
- package/src/__tests__/openai-responses-cutover-guard.test.ts +33 -12
- package/src/__tests__/openai-responses-provider.test.ts +17 -0
- package/src/__tests__/plugin-bootstrap.test.ts +31 -2
- package/src/__tests__/plugin-route-contribution.test.ts +31 -3
- package/src/__tests__/plugin-tool-contribution.test.ts +31 -3
- package/src/__tests__/plugin-types.test.ts +13 -11
- package/src/__tests__/process-message-background-slack.test.ts +46 -0
- package/src/__tests__/profile-entry-status.test.ts +43 -0
- package/src/__tests__/provider-managed-proxy-integration.test.ts +12 -4
- package/src/__tests__/provider-registry-ollama.test.ts +12 -4
- package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
- package/src/__tests__/relay-server.test.ts +164 -2
- package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
- package/src/__tests__/schedule-retry.test.ts +56 -4
- package/src/__tests__/schedule-routes.test.ts +104 -0
- package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
- package/src/__tests__/scheduler-recurrence.test.ts +87 -34
- package/src/__tests__/scheduler-reuse-conversation.test.ts +161 -5
- package/src/__tests__/scheduler-wake.test.ts +0 -63
- package/src/__tests__/secret-allowlist.test.ts +1 -0
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +7 -5
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +7 -5
- package/src/__tests__/secret-response-routing.test.ts +7 -5
- package/src/__tests__/secret-routes-managed-proxy.test.ts +12 -4
- package/src/__tests__/server-history-render.test.ts +82 -0
- package/src/__tests__/shell-credential-ref.test.ts +95 -3
- package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
- package/src/__tests__/skill-include-graph.test.ts +31 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
- package/src/__tests__/skill-load-tool.test.ts +42 -16
- package/src/__tests__/skills.test.ts +39 -0
- package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
- package/src/__tests__/suggestion-routes.test.ts +3 -3
- package/src/__tests__/sync-message-contract.test.ts +63 -0
- package/src/__tests__/task-scheduler.test.ts +88 -23
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -42
- package/src/__tests__/tool-executor.test.ts +155 -0
- package/src/__tests__/update-bulletin-job.test.ts +96 -193
- package/src/__tests__/usage-cli.test.ts +11 -73
- package/src/__tests__/user-plugin-loader.test.ts +145 -0
- package/src/__tests__/vercel-config.test.ts +168 -0
- package/src/__tests__/voice-session-bridge.test.ts +3 -0
- package/src/__tests__/web-search-catalog-parity.test.ts +86 -0
- package/src/__tests__/web-search.test.ts +303 -2
- package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
- package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +58 -0
- package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +153 -0
- package/src/__tests__/workspace-migration-071-remove-safe-storage-release-note.test.ts +206 -0
- package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +191 -0
- package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
- package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
- package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
- package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
- package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
- package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
- package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +15 -27
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
- package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
- package/src/acp/__tests__/helpers/which-stub.ts +4 -2
- package/src/acp/resolve-agent.test.ts +25 -0
- package/src/acp/resolve-agent.ts +13 -2
- package/src/acp/session-manager.ts +14 -0
- package/src/agent/loop.ts +11 -0
- package/src/approvals/guardian-decision-primitive.ts +0 -13
- package/src/approvals/guardian-request-resolvers.ts +19 -102
- package/src/calls/call-constants.ts +5 -8
- package/src/calls/call-controller.ts +130 -67
- package/src/calls/relay-server.ts +42 -1
- package/src/calls/relay-setup-router.ts +36 -0
- package/src/calls/types.ts +1 -0
- package/src/calls/voice-session-bridge.ts +24 -5
- package/src/channels/config.ts +14 -1
- package/src/channels/types.ts +1 -0
- package/src/cli/AGENTS.md +164 -4
- package/src/cli/__tests__/notifications.test.ts +54 -0
- package/src/cli/commands/__tests__/avatar.test.ts +540 -0
- package/src/cli/commands/__tests__/backup.test.ts +236 -776
- package/src/cli/commands/__tests__/cache.test.ts +1 -1
- package/src/cli/commands/__tests__/changelog.test.ts +593 -0
- package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
- package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
- package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
- package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
- package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
- package/src/cli/commands/__tests__/email-core.test.ts +579 -0
- package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
- package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
- package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
- package/src/cli/commands/__tests__/skills.test.ts +563 -0
- package/src/cli/commands/__tests__/status.test.ts +249 -0
- package/src/cli/commands/__tests__/stt.test.ts +320 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
- package/src/cli/commands/__tests__/tts.test.ts +321 -0
- package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
- package/src/cli/commands/attachment.ts +8 -3
- package/src/cli/commands/audit.ts +95 -64
- package/src/cli/commands/auth.ts +61 -58
- package/src/cli/commands/avatar.ts +276 -390
- package/src/cli/commands/backup.ts +409 -505
- package/src/cli/commands/bash.ts +9 -5
- package/src/cli/commands/browser.ts +28 -9
- package/src/cli/commands/cache.ts +9 -4
- package/src/cli/commands/changelog.ts +414 -0
- package/src/cli/commands/channel-verification-sessions.ts +238 -317
- package/src/cli/commands/clients.ts +8 -3
- package/src/cli/commands/completions.ts +9 -9
- package/src/cli/commands/config.ts +102 -72
- package/src/cli/commands/contacts.ts +575 -696
- package/src/cli/commands/conversations-defer.ts +17 -69
- package/src/cli/commands/conversations-import.ts +90 -253
- package/src/cli/commands/conversations.ts +346 -436
- package/src/cli/commands/credential-execution.ts +9 -6
- package/src/cli/commands/credentials.ts +456 -736
- package/src/cli/commands/domain.ts +128 -206
- package/src/cli/commands/email.ts +606 -794
- package/src/cli/commands/gateway.ts +8 -1
- package/src/cli/commands/image-generation.ts +157 -205
- package/src/cli/commands/inference-providers.ts +352 -0
- package/src/cli/commands/inference-session.ts +415 -0
- package/src/cli/commands/inference.ts +87 -65
- package/src/cli/commands/keys.ts +8 -3
- package/src/cli/commands/mcp.ts +103 -287
- package/src/cli/commands/memory-v2.ts +163 -517
- package/src/cli/commands/notifications.ts +33 -7
- package/src/cli/commands/oauth/apps.ts +292 -261
- package/src/cli/commands/oauth/connect.ts +182 -345
- package/src/cli/commands/oauth/disconnect.ts +16 -215
- package/src/cli/commands/oauth/index.ts +49 -45
- package/src/cli/commands/oauth/mode.ts +43 -199
- package/src/cli/commands/oauth/ping.ts +17 -125
- package/src/cli/commands/oauth/providers.ts +732 -921
- package/src/cli/commands/oauth/request.ts +60 -350
- package/src/cli/commands/oauth/shared.ts +11 -121
- package/src/cli/commands/oauth/status.ts +31 -121
- package/src/cli/commands/oauth/token.ts +13 -55
- package/src/cli/commands/pending.ts +19 -10
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
- package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
- package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
- package/src/cli/commands/platform/connect.ts +16 -80
- package/src/cli/commands/platform/disconnect.ts +14 -112
- package/src/cli/commands/platform/index.ts +177 -246
- package/src/cli/commands/routes.ts +153 -336
- package/src/cli/commands/sequence.ts +316 -360
- package/src/cli/commands/skills.ts +449 -671
- package/src/cli/commands/status.ts +58 -37
- package/src/cli/commands/stt.ts +94 -262
- package/src/cli/commands/task.ts +14 -40
- package/src/cli/commands/trust.ts +8 -3
- package/src/cli/commands/tts.ts +162 -167
- package/src/cli/commands/ui.ts +35 -42
- package/src/cli/commands/usage.ts +188 -126
- package/src/cli/commands/watchers.ts +8 -3
- package/src/cli/commands/webhooks.ts +99 -193
- package/src/cli/lib/__tests__/register-command.test.ts +85 -0
- package/src/cli/lib/daemon-credential-client.ts +4 -5
- package/src/cli/lib/nested-value.ts +44 -0
- package/src/cli/lib/open-browser.ts +36 -0
- package/src/cli/lib/register-command.ts +19 -0
- package/src/cli/lib/time-ago.ts +34 -0
- package/src/cli/program.ts +2 -4
- package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
- package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
- package/src/cli/utils/conversation-id.ts +30 -0
- package/src/cli/utils/parse-duration.ts +41 -0
- package/src/config/acp-defaults.test.ts +5 -1
- package/src/config/acp-defaults.ts +11 -4
- package/src/config/bundled-skills/acp/TOOLS.json +2 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +1 -3
- package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
- package/src/config/bundled-skills/contacts/SKILL.md +12 -45
- package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
- package/src/config/bundled-tool-registry.ts +0 -2
- package/src/config/feature-flag-registry.json +17 -17
- package/src/config/llm-resolver.ts +16 -1
- package/src/config/loader.ts +148 -33
- package/src/config/raw-config-utils.ts +2 -30
- package/src/config/schema.ts +4 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
- package/src/config/schemas/call-site-catalog.ts +29 -7
- package/src/config/schemas/llm-request-logs.ts +57 -0
- package/src/config/schemas/llm.ts +52 -2
- package/src/config/schemas/memory-retrospective.ts +48 -0
- package/src/config/schemas/memory-v2.ts +33 -2
- package/src/config/schemas/memory.ts +4 -0
- package/src/config/schemas/services.ts +15 -12
- package/src/config/seed-inference-profiles.ts +195 -134
- package/src/contacts/contact-store.ts +0 -61
- package/src/context/window-manager.ts +191 -5
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +111 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +109 -4
- package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
- package/src/daemon/approval-generators.ts +23 -29
- package/src/daemon/config-watcher.ts +2 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +56 -0
- package/src/daemon/conversation-agent-loop.ts +140 -107
- package/src/daemon/conversation-error.ts +21 -0
- package/src/daemon/conversation-lifecycle.ts +68 -13
- package/src/daemon/conversation-process.ts +36 -19
- package/src/daemon/conversation-runtime-assembly.ts +14 -5
- package/src/daemon/conversation-slash.ts +175 -23
- package/src/daemon/conversation-store.ts +17 -10
- package/src/daemon/conversation-surfaces.ts +92 -26
- package/src/daemon/conversation-tool-setup.ts +33 -19
- package/src/daemon/conversation.ts +49 -10
- package/src/daemon/external-plugins-bootstrap.ts +18 -8
- package/src/daemon/guardian-action-generators.ts +7 -22
- package/src/daemon/handlers/config-model.ts +8 -126
- package/src/daemon/handlers/config-slack-channel.ts +10 -7
- package/src/daemon/handlers/config-vercel.ts +3 -1
- package/src/daemon/handlers/shared.ts +26 -0
- package/src/daemon/handlers/skills.ts +84 -5
- package/src/daemon/history-repair.ts +33 -6
- package/src/daemon/host-app-control-proxy.ts +44 -19
- package/src/daemon/host-bash-proxy.ts +85 -158
- package/src/daemon/host-browser-proxy.ts +97 -36
- package/src/daemon/host-cu-proxy.ts +1 -1
- package/src/daemon/host-file-proxy.ts +1 -1
- package/src/daemon/host-proxy-base.ts +13 -1
- package/src/daemon/host-proxy-preactivation.ts +25 -1
- package/src/daemon/host-transfer-proxy.ts +2 -2
- package/src/daemon/identity-helpers.ts +19 -0
- package/src/daemon/lifecycle.ts +128 -114
- package/src/daemon/meet-host-supervisor.ts +15 -15
- package/src/daemon/memory-v2-startup.ts +62 -14
- package/src/daemon/message-protocol.ts +6 -0
- package/src/daemon/message-types/bookmarks.ts +18 -0
- package/src/daemon/message-types/conversations.ts +12 -9
- package/src/daemon/message-types/messages.ts +28 -2
- package/src/daemon/message-types/sync.ts +60 -0
- package/src/daemon/pkb-reminder-builder.test.ts +54 -13
- package/src/daemon/pkb-reminder-builder.ts +21 -7
- package/src/daemon/process-message.ts +56 -23
- package/src/daemon/server.ts +23 -18
- package/src/daemon/shutdown-handlers.ts +0 -2
- package/src/daemon/tool-setup-types.ts +9 -0
- package/src/daemon/tool-side-effects.ts +6 -4
- package/src/daemon/wake-target-adapter.ts +11 -0
- package/src/documents/document-store.ts +35 -1
- package/src/export/transcript-formatter.ts +61 -2
- package/src/filing/filing-service.ts +42 -56
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +359 -0
- package/src/heartbeat/heartbeat-run-store.ts +2 -1
- package/src/heartbeat/heartbeat-service.ts +149 -128
- package/src/home/__tests__/feed-types.test.ts +63 -131
- package/src/home/__tests__/feed-writer.test.ts +77 -278
- package/src/home/__tests__/post-connect-feed.test.ts +9 -12
- package/src/home/feed-types.ts +19 -73
- package/src/home/feed-writer.ts +25 -156
- package/src/home/post-connect-feed.ts +1 -3
- package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
- package/src/ipc/__tests__/email-ipc.test.ts +506 -0
- package/src/ipc/__tests__/exit-helper.test.ts +104 -0
- package/src/ipc/__tests__/streaming-client.test.ts +237 -0
- package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
- package/src/ipc/assistant-server.ts +148 -42
- package/src/ipc/cli-client.ts +370 -50
- package/src/ipc/routes/db-proxy-transaction.ts +151 -0
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
- package/src/ipc/skill-routes/events.ts +30 -3
- package/src/ipc/skill-server.ts +99 -42
- package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
- package/src/live-voice/live-voice-session-manager.ts +11 -4
- package/src/live-voice/live-voice-session.ts +14 -6
- package/src/memory/__tests__/bookmark-crud.test.ts +258 -0
- package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
- package/src/memory/__tests__/conversation-types.test.ts +36 -0
- package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +10 -57
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +213 -0
- package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
- package/src/memory/bookmark-crud.ts +179 -0
- package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
- package/src/memory/context-search/agent-protocol.ts +5 -1
- package/src/memory/context-search/agent-runner.ts +60 -85
- package/src/memory/context-search/limits.ts +1 -4
- package/src/memory/context-search/search.ts +23 -113
- package/src/memory/context-search/sources/conversations.ts +18 -6
- package/src/memory/context-search/sources/memory-v2.ts +40 -31
- package/src/memory/context-search/sources/memory.ts +9 -2
- package/src/memory/context-search/sources/workspace.ts +13 -10
- package/src/memory/context-search/types.ts +1 -1
- package/src/memory/conversation-bootstrap.ts +11 -0
- package/src/memory/conversation-crud.ts +312 -10
- package/src/memory/conversation-queries.ts +9 -5
- package/src/memory/conversation-title-service.ts +1 -0
- package/src/memory/conversation-types.ts +16 -0
- package/src/memory/db-init.ts +14 -0
- package/src/memory/embedding-backend.ts +2 -1
- package/src/memory/embedding-runtime-manager.ts +1 -2
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +104 -61
- package/src/memory/graph/__tests__/handle-remember-v2.test.ts +11 -26
- package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
- package/src/memory/graph/conversation-graph-memory.ts +108 -14
- package/src/memory/graph/extraction.ts +4 -0
- package/src/memory/graph/graph-memory-state-store.ts +16 -3
- package/src/memory/graph/graph-search.test.ts +6 -5
- package/src/memory/graph/graph-search.ts +3 -4
- package/src/memory/graph/retriever.test.ts +12 -7
- package/src/memory/graph/retriever.ts +4 -5
- package/src/memory/graph/tool-handlers.ts +20 -11
- package/src/memory/graph/tools.ts +48 -9
- package/src/memory/indexer.ts +18 -2
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +120 -6
- package/src/memory/jobs/embed-concept-page.ts +261 -89
- package/src/memory/jobs-store.ts +51 -1
- package/src/memory/jobs-worker.ts +60 -7
- package/src/memory/llm-request-log-source-clickhouse.ts +317 -0
- package/src/memory/llm-request-log-source-local.ts +26 -0
- package/src/memory/llm-request-log-source.ts +97 -0
- package/src/memory/llm-request-log-store.ts +1 -1
- package/src/memory/memory-retrospective-constants.ts +13 -0
- package/src/memory/memory-retrospective-enqueue.ts +114 -0
- package/src/memory/memory-retrospective-job.ts +351 -0
- package/src/memory/memory-retrospective-startup-cleanup.ts +108 -0
- package/src/memory/memory-retrospective-state.ts +162 -0
- package/src/memory/memory-retrospective-trigger-check.ts +91 -0
- package/src/memory/memory-v2-activation-log-store.ts +49 -5
- package/src/memory/memory-v2-concept-frequency.ts +4 -0
- package/src/memory/message-content.ts +38 -1
- package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
- package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
- package/src/memory/migrations/229-delete-private-conversations.test.ts +70 -1
- package/src/memory/migrations/229-delete-private-conversations.ts +12 -0
- package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
- package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
- package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
- package/src/memory/migrations/242-message-bookmarks.ts +38 -0
- package/src/memory/migrations/243-provider-connections.ts +68 -0
- package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
- package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
- package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
- package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
- package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
- package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
- package/src/memory/migrations/index.ts +7 -0
- package/src/memory/pkb/pkb-search.test.ts +6 -5
- package/src/memory/pkb/pkb-search.ts +4 -5
- package/src/memory/published-pages-store.ts +16 -0
- package/src/memory/qdrant-client.ts +3 -0
- package/src/memory/schema/bookmarks.ts +38 -0
- package/src/memory/schema/conversations.ts +2 -0
- package/src/memory/schema/index.ts +2 -0
- package/src/memory/schema/inference.ts +29 -0
- package/src/memory/schema/memory-core.ts +9 -0
- package/src/memory/search/semantic.ts +5 -9
- package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
- package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
- package/src/memory/v2/__tests__/activation.test.ts +46 -9
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
- package/src/memory/v2/__tests__/consolidation-job.test.ts +140 -163
- package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
- package/src/memory/v2/__tests__/injection.test.ts +768 -33
- package/src/memory/v2/__tests__/migration.test.ts +7 -3
- package/src/memory/v2/__tests__/page-index.test.ts +277 -0
- package/src/memory/v2/__tests__/page-store.test.ts +14 -1
- package/src/memory/v2/__tests__/prompts-router.test.ts +257 -0
- package/src/memory/v2/__tests__/qdrant.test.ts +382 -9
- package/src/memory/v2/__tests__/reranker.test.ts +4 -4
- package/src/memory/v2/__tests__/router.test.ts +516 -0
- package/src/memory/v2/__tests__/sim.test.ts +163 -8
- package/src/memory/v2/__tests__/skill-store.test.ts +58 -3
- package/src/memory/v2/__tests__/static-context.test.ts +8 -35
- package/src/memory/v2/__tests__/sweep-job.test.ts +114 -33
- package/src/memory/v2/activation-store.ts +34 -5
- package/src/memory/v2/activation.ts +40 -27
- package/src/memory/v2/backfill-jobs.ts +17 -84
- package/src/memory/v2/consolidation-job.ts +92 -86
- package/src/memory/v2/frontmatter-sweep.ts +91 -0
- package/src/memory/v2/injection.ts +466 -115
- package/src/memory/v2/migration.ts +117 -20
- package/src/memory/v2/page-index.ts +191 -0
- package/src/memory/v2/page-store.ts +42 -0
- package/src/memory/v2/prompts/consolidation.ts +14 -7
- package/src/memory/v2/prompts/router.ts +192 -0
- package/src/memory/v2/qdrant.ts +307 -133
- package/src/memory/v2/reranker.ts +14 -7
- package/src/memory/v2/router.ts +322 -0
- package/src/memory/v2/sim.ts +88 -34
- package/src/memory/v2/skill-store.ts +118 -29
- package/src/memory/v2/static-context.ts +20 -17
- package/src/memory/v2/sweep-job.ts +127 -102
- package/src/memory/v2/types.ts +16 -5
- package/src/memory/validation.ts +13 -0
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
- package/src/notifications/__tests__/signal-registry.test.ts +17 -0
- package/src/notifications/adapters/platform.ts +171 -0
- package/src/notifications/conversation-pairing.ts +2 -2
- package/src/notifications/copy-composer.ts +61 -12
- package/src/notifications/decision-engine.ts +46 -0
- package/src/notifications/destination-resolver.ts +21 -0
- package/src/notifications/emit-signal.ts +28 -1
- package/src/notifications/home-feed-side-effect.ts +111 -0
- package/src/notifications/signal.ts +5 -0
- package/src/permissions/checker.ts +12 -0
- package/src/permissions/gateway-threshold-reader.ts +116 -8
- package/src/permissions/ipc-risk-types.ts +2 -0
- package/src/permissions/prompter.ts +86 -96
- package/src/permissions/secret-prompter.ts +31 -31
- package/src/plugin-api/index.ts +13 -0
- package/src/plugin-api/package.json +12 -0
- package/src/plugin-api/types.ts +62 -0
- package/src/plugins/defaults/injectors.ts +20 -5
- package/src/plugins/external-plugin-loader.ts +294 -0
- package/src/plugins/types.ts +46 -30
- package/src/plugins/user-loader.ts +64 -41
- package/src/proactive-artifact/job.test.ts +63 -8
- package/src/proactive-artifact/job.ts +20 -2
- package/src/proactive-artifact/message-copy.ts +18 -1
- package/src/proactive-artifact/trigger-state.test.ts +9 -0
- package/src/proactive-artifact/trigger-state.ts +4 -0
- package/src/prompts/__tests__/system-prompt.test.ts +105 -0
- package/src/prompts/system-prompt.ts +22 -1
- package/src/prompts/templates/SOUL.md +13 -28
- package/src/prompts/update-bulletin-job.ts +61 -73
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
- package/src/providers/__tests__/inference.test.ts +288 -0
- package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
- package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
- package/src/providers/__tests__/retry-callsite.test.ts +14 -32
- package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
- package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
- package/src/providers/anthropic/client.ts +95 -26
- package/src/providers/call-site-routing.ts +94 -16
- package/src/providers/connection-resolution.ts +163 -0
- package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
- package/src/providers/inference/adapter-factory.ts +173 -0
- package/src/providers/inference/auth.ts +112 -0
- package/src/providers/inference/backfill.ts +196 -0
- package/src/providers/inference/connections.ts +356 -0
- package/src/providers/inference/resolve-auth.ts +65 -0
- package/src/providers/model-catalog.ts +104 -6
- package/src/providers/openai/responses-provider.ts +4 -2
- package/src/providers/provider-env-vars.ts +17 -7
- package/src/providers/provider-secret-catalog.ts +49 -30
- package/src/providers/provider-send-message.ts +41 -20
- package/src/providers/registry.ts +143 -159
- package/src/providers/retry.ts +18 -10
- package/src/providers/search-provider-catalog.ts +121 -0
- package/src/runtime/AGENTS.md +18 -5
- package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
- package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
- package/src/runtime/actor-trust-resolver.ts +32 -10
- package/src/runtime/agent-wake.ts +35 -6
- package/src/runtime/assistant-event-hub.ts +3 -85
- package/src/runtime/auth/route-policy.ts +304 -8
- package/src/runtime/auth/same-actor.ts +2 -0
- package/src/runtime/background-job-runner.ts +339 -0
- package/src/runtime/btw-sidechain.ts +1 -0
- package/src/runtime/channel-approvals.ts +3 -2
- package/src/runtime/guardian-reply-router.ts +0 -10
- package/src/runtime/http-router.ts +36 -1
- package/src/runtime/http-server.ts +31 -5
- package/src/runtime/http-types.ts +2 -0
- package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
- package/src/runtime/middleware/request-logger.ts +62 -1
- package/src/runtime/pending-interactions.ts +19 -15
- package/src/runtime/pre-first-message-gate.ts +83 -0
- package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +251 -0
- package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +315 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +189 -0
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +147 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
- package/src/runtime/routes/acp-routes.ts +10 -8
- package/src/runtime/routes/app-management-routes.ts +228 -3
- package/src/runtime/routes/approval-routes.ts +7 -21
- package/src/runtime/routes/audit-routes.ts +43 -0
- package/src/runtime/routes/auth-routes.ts +72 -0
- package/src/runtime/routes/avatar-routes.ts +273 -20
- package/src/runtime/routes/backup-routes.ts +406 -2
- package/src/runtime/routes/bookmark-routes.ts +154 -0
- package/src/runtime/routes/channel-verification-routes.ts +2 -1
- package/src/runtime/routes/consolidation-routes.ts +8 -9
- package/src/runtime/routes/contact-routes.ts +0 -160
- package/src/runtime/routes/conversation-cli-routes.ts +192 -0
- package/src/runtime/routes/conversation-management-routes.ts +30 -43
- package/src/runtime/routes/conversation-query-routes.ts +373 -82
- package/src/runtime/routes/conversation-routes.ts +31 -10
- package/src/runtime/routes/conversations-import-routes.ts +229 -0
- package/src/runtime/routes/credential-routes.ts +540 -0
- package/src/runtime/routes/debug-bash-routes.ts +2 -0
- package/src/runtime/routes/debug-routes.ts +2 -2
- package/src/runtime/routes/document-pdf-renderer.ts +5 -1
- package/src/runtime/routes/domain-routes.ts +167 -0
- package/src/runtime/routes/email-routes.ts +603 -0
- package/src/runtime/routes/errors.ts +2 -2
- package/src/runtime/routes/events-routes.ts +192 -0
- package/src/runtime/routes/filing-routes.ts +2 -3
- package/src/runtime/routes/home-feed-routes.ts +6 -78
- package/src/runtime/routes/host-app-control-routes.ts +44 -2
- package/src/runtime/routes/host-browser-routes.ts +103 -22
- package/src/runtime/routes/http-adapter.ts +2 -0
- package/src/runtime/routes/identity-routes.ts +5 -0
- package/src/runtime/routes/image-generation-routes.ts +99 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +137 -1
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +87 -7
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -7
- package/src/runtime/routes/index.ts +36 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +312 -0
- package/src/runtime/routes/inference-profile-session-reaper.ts +98 -0
- package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +317 -0
- package/src/runtime/routes/inference-send-routes.ts +115 -0
- package/src/runtime/routes/integrations/twilio.ts +1 -0
- package/src/runtime/routes/mcp-auth-routes.ts +283 -9
- package/src/runtime/routes/memory-item-routes.test.ts +3 -9
- package/src/runtime/routes/memory-item-routes.ts +5 -6
- package/src/runtime/routes/memory-v2-routes.ts +105 -404
- package/src/runtime/routes/notification-routes.ts +2 -0
- package/src/runtime/routes/oauth-apps.ts +112 -7
- package/src/runtime/routes/oauth-commands-routes.ts +1007 -0
- package/src/runtime/routes/oauth-connect-routes.ts +67 -5
- package/src/runtime/routes/oauth-providers.ts +298 -8
- package/src/runtime/routes/platform-routes.ts +336 -0
- package/src/runtime/routes/playground/inject-failures.ts +2 -1
- package/src/runtime/routes/playground/reset-circuit.ts +2 -1
- package/src/runtime/routes/playground/state.ts +2 -1
- package/src/runtime/routes/publish-routes.ts +221 -0
- package/src/runtime/routes/schedule-routes.ts +82 -0
- package/src/runtime/routes/sequence-routes.ts +291 -0
- package/src/runtime/routes/settings-routes.ts +2 -10
- package/src/runtime/routes/skills-routes.ts +31 -1
- package/src/runtime/routes/stt-routes.ts +240 -3
- package/src/runtime/routes/surface-action-routes.ts +43 -7
- package/src/runtime/routes/tts-routes.ts +67 -0
- package/src/runtime/routes/types.ts +32 -0
- package/src/runtime/routes/user-routes-cli.ts +243 -0
- package/src/runtime/routes/webhook-routes.ts +165 -0
- package/src/runtime/sync/resource-sync-events.ts +25 -0
- package/src/runtime/sync/sync-publisher.test.ts +105 -0
- package/src/runtime/sync/sync-publisher.ts +21 -0
- package/src/schedule/scheduler.ts +200 -123
- package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
- package/src/security/secret-patterns.ts +3 -0
- package/src/sequence/engine.ts +38 -40
- package/src/skills/include-graph.ts +35 -13
- package/src/subagent/manager.ts +20 -15
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
- package/src/tools/browser/browser-execution.ts +15 -4
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
- package/src/tools/browser/cdp-client/factory.ts +66 -5
- package/src/tools/browser/runtime-check.ts +77 -0
- package/src/tools/document/document-tool.ts +20 -0
- package/src/tools/executor.ts +18 -2
- package/src/tools/memory/register.test.ts +10 -8
- package/src/tools/memory/register.ts +9 -1
- package/src/tools/network/__tests__/web-search.test.ts +156 -0
- package/src/tools/network/web-search.ts +280 -37
- package/src/tools/permission-checker.ts +28 -5
- package/src/tools/skills/load.ts +24 -20
- package/src/tools/subagent/spawn.ts +3 -3
- package/src/tools/terminal/shell.ts +44 -0
- package/src/tools/tool-name-aliases.ts +19 -0
- package/src/tools/types.ts +19 -1
- package/src/usage/attribution.ts +3 -2
- package/src/util/pricing.ts +86 -160
- package/src/watcher/__tests__/engine.test.ts +301 -0
- package/src/watcher/constants.ts +7 -0
- package/src/watcher/engine.ts +90 -90
- package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
- package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
- package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +28 -4
- package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +4 -62
- package/src/workspace/migrations/069-seed-onboarding-threads.ts +34 -0
- package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +31 -0
- package/src/workspace/migrations/071-remove-safe-storage-release-note.ts +111 -0
- package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +104 -0
- package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +93 -0
- package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
- package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
- package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
- package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
- package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
- package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
- package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
- package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
- package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
- package/src/workspace/migrations/registry.ts +28 -0
- package/src/workspace/migrations/runner.ts +13 -2
- package/src/workspace/migrations/types.ts +13 -3
- package/src/workspace/provider-commit-message-generator.ts +3 -2
- package/src/__tests__/context-search-pkb-source.test.ts +0 -492
- package/src/__tests__/credentials-cli.test.ts +0 -1225
- package/src/__tests__/memory-admin-recall.test.ts +0 -213
- package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
- package/src/cli/commands/__tests__/email-download.test.ts +0 -260
- package/src/cli/commands/__tests__/email-list.test.ts +0 -216
- package/src/cli/commands/__tests__/email-register.test.ts +0 -186
- package/src/cli/commands/__tests__/email-send.test.ts +0 -416
- package/src/cli/commands/__tests__/email-status.test.ts +0 -185
- package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
- package/src/cli/commands/__tests__/routes.test.ts +0 -562
- package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
- package/src/cli/commands/autonomy.ts +0 -365
- package/src/cli/commands/memory.ts +0 -424
- package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -1201
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
- package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
- package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
- package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
- package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
- package/src/cli/lib/daemon-avatar-client.ts +0 -37
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
- package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
- package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
- package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
- package/src/home/__tests__/emit-feed-event.test.ts +0 -169
- package/src/home/__tests__/feed-population-integration.test.ts +0 -312
- package/src/home/__tests__/feed-scheduler.test.ts +0 -222
- package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
- package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
- package/src/home/__tests__/rollup-producer.test.ts +0 -507
- package/src/home/assistant-feed-authoring.ts +0 -135
- package/src/home/emit-feed-event.ts +0 -169
- package/src/home/feed-scheduler.ts +0 -281
- package/src/home/platform-gmail-digest.ts +0 -163
- package/src/home/rewrite-command-preview.ts +0 -66
- package/src/home/rewrite-feed-title.ts +0 -58
- package/src/home/rollup-producer.ts +0 -426
- package/src/memory/admin.ts +0 -326
- package/src/memory/context-search/sources/pkb.ts +0 -477
- package/src/memory/graph/compaction.ts +0 -299
- /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
package/src/memory/v2/qdrant.ts
CHANGED
|
@@ -18,11 +18,16 @@
|
|
|
18
18
|
// fusion using `dense_weight` / `sparse_weight` from `config.memory.v2`,
|
|
19
19
|
// which RRF fusion would discard.
|
|
20
20
|
|
|
21
|
+
import { existsSync } from "node:fs";
|
|
22
|
+
import { mkdir, unlink, writeFile } from "node:fs/promises";
|
|
23
|
+
import { dirname, join } from "node:path";
|
|
24
|
+
|
|
21
25
|
import { QdrantClient as QdrantRestClient } from "@qdrant/js-client-rest";
|
|
22
26
|
import { v5 as uuidv5 } from "uuid";
|
|
23
27
|
|
|
24
28
|
import { getConfig } from "../../config/loader.js";
|
|
25
29
|
import { getLogger } from "../../util/logger.js";
|
|
30
|
+
import { getDataDir } from "../../util/platform.js";
|
|
26
31
|
import type { SparseEmbedding } from "../embedding-types.js";
|
|
27
32
|
import { resolveQdrantUrl } from "../qdrant-client.js";
|
|
28
33
|
|
|
@@ -48,21 +53,86 @@ export interface ConceptPagePayload {
|
|
|
48
53
|
export interface ConceptPageQueryResult {
|
|
49
54
|
slug: string;
|
|
50
55
|
/**
|
|
51
|
-
* Dense cosine similarity, when the slug appeared in
|
|
52
|
-
* `undefined` if the slug only appeared in the
|
|
56
|
+
* Dense cosine similarity against the page body, when the slug appeared in
|
|
57
|
+
* the body dense top-`limit`. `undefined` if the slug only appeared in the
|
|
58
|
+
* sparse channel — or in a summary-side channel.
|
|
53
59
|
*/
|
|
54
60
|
denseScore?: number;
|
|
55
61
|
/**
|
|
56
|
-
* Sparse score, when the slug appeared in the
|
|
57
|
-
* `undefined` if the slug only appeared in the dense
|
|
58
|
-
* different scale than `denseScore` — callers must
|
|
62
|
+
* Sparse score against the page body, when the slug appeared in the body
|
|
63
|
+
* sparse top-`limit`. `undefined` if the slug only appeared in the dense
|
|
64
|
+
* channel. Lives on a different scale than `denseScore` — callers must
|
|
65
|
+
* normalize before fusing.
|
|
59
66
|
*/
|
|
60
67
|
sparseScore?: number;
|
|
68
|
+
/**
|
|
69
|
+
* Dense cosine similarity against the page's frontmatter `summary`, when
|
|
70
|
+
* the page has a summary embedded and the slug appeared in the summary
|
|
71
|
+
* dense top-`limit`. `undefined` for pages without a summary embedding —
|
|
72
|
+
* those fall back to body-only scoring.
|
|
73
|
+
*/
|
|
74
|
+
summaryDenseScore?: number;
|
|
75
|
+
/**
|
|
76
|
+
* Sparse score against the page's frontmatter `summary`, paired with
|
|
77
|
+
* `summaryDenseScore`. `undefined` for pages without a summary embedding.
|
|
78
|
+
*/
|
|
79
|
+
summarySparseScore?: number;
|
|
61
80
|
}
|
|
62
81
|
|
|
63
82
|
let _client: QdrantRestClient | null = null;
|
|
64
83
|
let _collectionReady = false;
|
|
65
|
-
let _collectionReadyPromise: Promise<
|
|
84
|
+
let _collectionReadyPromise: Promise<{ migrated: boolean }> | null = null;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Named vectors the v2 concept-page collection must expose. Existing
|
|
88
|
+
* collections that lack any of these get destructively recreated by
|
|
89
|
+
* `ensureConceptPageCollectionOnce` — see the `migrated` return flag.
|
|
90
|
+
*/
|
|
91
|
+
const REQUIRED_DENSE_VECTORS = ["dense", "summary_dense"] as const;
|
|
92
|
+
const REQUIRED_SPARSE_VECTORS = ["sparse", "summary_sparse"] as const;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Marker file written before the destructive collection-recreate path runs,
|
|
96
|
+
* cleared by the lifecycle hook once the reembed job has been enqueued.
|
|
97
|
+
*
|
|
98
|
+
* The sentinel exists to close a narrow data-loss window in
|
|
99
|
+
* `ensureConceptPageCollectionOnce`: a transient Qdrant failure between
|
|
100
|
+
* `deleteCollection` and `createCollection` would otherwise lose the
|
|
101
|
+
* "needs reembed" signal — `migrated` is reinitialized on the next call,
|
|
102
|
+
* any subsequent caller (e.g. an upsert) recreates the collection empty,
|
|
103
|
+
* and the lifecycle hook never enqueues the backfill. By persisting the
|
|
104
|
+
* intent on disk *before* delete, the signal survives crashes and
|
|
105
|
+
* intra-process retries: every later `ensureConceptPageCollection` call
|
|
106
|
+
* returns `migrated: true` until the lifecycle hook enqueues the reembed
|
|
107
|
+
* and clears the sentinel.
|
|
108
|
+
*/
|
|
109
|
+
const REEMBED_SENTINEL_FILENAME = ".memory-v2-reembed-required";
|
|
110
|
+
|
|
111
|
+
function reembedSentinelPath(): string {
|
|
112
|
+
return join(getDataDir(), REEMBED_SENTINEL_FILENAME);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function reembedSentinelExists(): boolean {
|
|
116
|
+
return existsSync(reembedSentinelPath());
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async function writeReembedSentinel(): Promise<void> {
|
|
120
|
+
const path = reembedSentinelPath();
|
|
121
|
+
await mkdir(dirname(path), { recursive: true });
|
|
122
|
+
await writeFile(path, "");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Remove the reembed sentinel after the lifecycle hook has enqueued the
|
|
127
|
+
* `memory_v2_reembed` job. Idempotent — missing-file is not an error.
|
|
128
|
+
*/
|
|
129
|
+
export async function clearReembedSentinel(): Promise<void> {
|
|
130
|
+
try {
|
|
131
|
+
await unlink(reembedSentinelPath());
|
|
132
|
+
} catch (err) {
|
|
133
|
+
if ((err as NodeJS.ErrnoException).code !== "ENOENT") throw err;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
66
136
|
|
|
67
137
|
/** Lazily create a Qdrant REST client bound to the resolved URL. */
|
|
68
138
|
function getClient(): QdrantRestClient {
|
|
@@ -76,16 +146,19 @@ function getClient(): QdrantRestClient {
|
|
|
76
146
|
}
|
|
77
147
|
|
|
78
148
|
/**
|
|
79
|
-
* Create the v2 concept-page collection if it does not already exist
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
149
|
+
* Create the v2 concept-page collection if it does not already exist, or
|
|
150
|
+
* destructively recreate it when the existing schema is missing any of the
|
|
151
|
+
* required named vectors (see `REQUIRED_DENSE_VECTORS` /
|
|
152
|
+
* `REQUIRED_SPARSE_VECTORS`). The latter case is signalled to callers via
|
|
153
|
+
* `{ migrated: true }` so they can enqueue a backfill — pre-#29823
|
|
154
|
+
* collections lack `summary_dense` / `summary_sparse` and every query
|
|
155
|
+
* referencing those named vectors fails with HTTP 400 until the collection
|
|
156
|
+
* is rebuilt. Mirrors `VellumQdrantClient.ensureCollection` for v1.
|
|
86
157
|
*/
|
|
87
|
-
export async function ensureConceptPageCollection(): Promise<
|
|
88
|
-
|
|
158
|
+
export async function ensureConceptPageCollection(): Promise<{
|
|
159
|
+
migrated: boolean;
|
|
160
|
+
}> {
|
|
161
|
+
if (_collectionReady) return { migrated: false };
|
|
89
162
|
if (_collectionReadyPromise) return _collectionReadyPromise;
|
|
90
163
|
|
|
91
164
|
_collectionReadyPromise = ensureConceptPageCollectionOnce().finally(() => {
|
|
@@ -94,17 +167,54 @@ export async function ensureConceptPageCollection(): Promise<void> {
|
|
|
94
167
|
return _collectionReadyPromise;
|
|
95
168
|
}
|
|
96
169
|
|
|
97
|
-
async function ensureConceptPageCollectionOnce(): Promise<
|
|
170
|
+
async function ensureConceptPageCollectionOnce(): Promise<{
|
|
171
|
+
migrated: boolean;
|
|
172
|
+
}> {
|
|
98
173
|
const client = getClient();
|
|
99
174
|
const config = getConfig();
|
|
100
175
|
const vectorSize = config.memory.qdrant.vectorSize;
|
|
101
176
|
const onDisk = config.memory.qdrant.onDisk;
|
|
102
177
|
|
|
178
|
+
// A leftover sentinel means a prior call deleted the collection but never
|
|
179
|
+
// got to enqueue the reembed (e.g. createCollection threw, or the process
|
|
180
|
+
// died mid-rebuild). Carry that signal forward until the lifecycle hook
|
|
181
|
+
// clears it.
|
|
182
|
+
let migrated = reembedSentinelExists();
|
|
183
|
+
|
|
103
184
|
try {
|
|
104
185
|
const exists = await client.collectionExists(MEMORY_V2_COLLECTION);
|
|
105
186
|
if (exists.exists) {
|
|
106
|
-
|
|
107
|
-
|
|
187
|
+
// Assume compatible on probe failure rather than risk a destructive
|
|
188
|
+
// recreate — mirrors v1's posture in `VellumQdrantClient.ensureCollection`.
|
|
189
|
+
let info: Awaited<ReturnType<typeof client.getCollection>>;
|
|
190
|
+
try {
|
|
191
|
+
info = await client.getCollection(MEMORY_V2_COLLECTION);
|
|
192
|
+
} catch (err) {
|
|
193
|
+
log.warn(
|
|
194
|
+
{ err, collection: MEMORY_V2_COLLECTION },
|
|
195
|
+
"Failed to probe v2 collection schema; assuming compatible",
|
|
196
|
+
);
|
|
197
|
+
_collectionReady = true;
|
|
198
|
+
return { migrated: false };
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const missing = missingNamedVectors(info);
|
|
202
|
+
if (missing.length === 0) {
|
|
203
|
+
_collectionReady = true;
|
|
204
|
+
return { migrated: false };
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
log.warn(
|
|
208
|
+
{ collection: MEMORY_V2_COLLECTION, missingNamedVectors: missing },
|
|
209
|
+
"Memory v2 concept-page collection schema drift detected — deleting and recreating; embeddings will be regenerated by background reembed",
|
|
210
|
+
);
|
|
211
|
+
// Persist the reembed intent BEFORE the destructive delete so a crash
|
|
212
|
+
// (or transient createCollection failure) between delete and recreate
|
|
213
|
+
// still triggers reembed on the next ensure call.
|
|
214
|
+
await writeReembedSentinel();
|
|
215
|
+
await client.deleteCollection(MEMORY_V2_COLLECTION);
|
|
216
|
+
migrated = true;
|
|
217
|
+
// Fall through to creation below.
|
|
108
218
|
}
|
|
109
219
|
} catch (err) {
|
|
110
220
|
// Treat "not found"-shaped errors as "needs creation" and fall through.
|
|
@@ -124,15 +234,28 @@ async function ensureConceptPageCollectionOnce(): Promise<void> {
|
|
|
124
234
|
distance: "Cosine",
|
|
125
235
|
on_disk: onDisk,
|
|
126
236
|
},
|
|
237
|
+
// Optional second dense vector covering the page's frontmatter
|
|
238
|
+
// `summary`. Pages without a summary store nothing under this name —
|
|
239
|
+
// Qdrant supports per-point named-vector subsets — so the named-vector
|
|
240
|
+
// index stays cheap until summaries are populated.
|
|
241
|
+
summary_dense: {
|
|
242
|
+
size: vectorSize,
|
|
243
|
+
distance: "Cosine",
|
|
244
|
+
on_disk: onDisk,
|
|
245
|
+
},
|
|
127
246
|
},
|
|
128
247
|
sparse_vectors: {
|
|
129
248
|
sparse: {}, // Qdrant auto-infers sparse vector params
|
|
249
|
+
summary_sparse: {}, // BM25 sparse vector for the summary
|
|
130
250
|
},
|
|
131
251
|
hnsw_config: {
|
|
132
252
|
on_disk: onDisk,
|
|
133
253
|
m: 16,
|
|
134
254
|
ef_construct: 100,
|
|
135
255
|
},
|
|
256
|
+
optimizers_config: {
|
|
257
|
+
default_segment_number: 2,
|
|
258
|
+
},
|
|
136
259
|
on_disk_payload: onDisk,
|
|
137
260
|
});
|
|
138
261
|
} catch (err) {
|
|
@@ -143,7 +266,7 @@ async function ensureConceptPageCollectionOnce(): Promise<void> {
|
|
|
143
266
|
(err as { status: number }).status === 409
|
|
144
267
|
) {
|
|
145
268
|
_collectionReady = true;
|
|
146
|
-
return;
|
|
269
|
+
return { migrated };
|
|
147
270
|
}
|
|
148
271
|
throw err;
|
|
149
272
|
}
|
|
@@ -156,33 +279,97 @@ async function ensureConceptPageCollectionOnce(): Promise<void> {
|
|
|
156
279
|
});
|
|
157
280
|
|
|
158
281
|
_collectionReady = true;
|
|
282
|
+
return { migrated };
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Return the names of required named vectors absent from the collection's
|
|
287
|
+
* current schema. An empty array means the collection is fully migrated.
|
|
288
|
+
*
|
|
289
|
+
* If the response shape is unparseable (e.g. Qdrant returns an unexpected
|
|
290
|
+
* structure) we treat it as "everything is missing" so the caller's drift
|
|
291
|
+
* branch fires — combined with the `getCollection` try/catch in the caller,
|
|
292
|
+
* a thrown probe falls back to "assume compatible" while a parsed-but-empty
|
|
293
|
+
* response triggers the safer recreate.
|
|
294
|
+
*/
|
|
295
|
+
function missingNamedVectors(
|
|
296
|
+
info: Awaited<ReturnType<QdrantRestClient["getCollection"]>>,
|
|
297
|
+
): string[] {
|
|
298
|
+
const params = info.config?.params;
|
|
299
|
+
const dense = params?.vectors;
|
|
300
|
+
const sparse = (params as { sparse_vectors?: unknown } | undefined)
|
|
301
|
+
?.sparse_vectors;
|
|
302
|
+
const denseNames =
|
|
303
|
+
dense && typeof dense === "object" && !("size" in dense)
|
|
304
|
+
? new Set(Object.keys(dense))
|
|
305
|
+
: new Set<string>();
|
|
306
|
+
const sparseNames =
|
|
307
|
+
sparse && typeof sparse === "object"
|
|
308
|
+
? new Set(Object.keys(sparse as Record<string, unknown>))
|
|
309
|
+
: new Set<string>();
|
|
310
|
+
|
|
311
|
+
const missing: string[] = [];
|
|
312
|
+
for (const name of REQUIRED_DENSE_VECTORS) {
|
|
313
|
+
if (!denseNames.has(name)) missing.push(name);
|
|
314
|
+
}
|
|
315
|
+
for (const name of REQUIRED_SPARSE_VECTORS) {
|
|
316
|
+
if (!sparseNames.has(name)) missing.push(name);
|
|
317
|
+
}
|
|
318
|
+
return missing;
|
|
159
319
|
}
|
|
160
320
|
|
|
161
321
|
/**
|
|
162
322
|
* Upsert a concept page's dense + sparse embedding. The point ID is derived
|
|
163
323
|
* deterministically from the slug so subsequent calls for the same slug
|
|
164
324
|
* replace the prior point in place rather than accumulating duplicates.
|
|
325
|
+
*
|
|
326
|
+
* `summary` is optional — supplied when the page's frontmatter carries a
|
|
327
|
+
* `summary`, omitted otherwise. Pages without a summary store only the body
|
|
328
|
+
* vectors and fall back to body-only scoring at query time. The grouped
|
|
329
|
+
* shape enforces at the type level that summary dense and sparse are
|
|
330
|
+
* always written together.
|
|
165
331
|
*/
|
|
166
332
|
export async function upsertConceptPageEmbedding(params: {
|
|
167
333
|
slug: string;
|
|
168
334
|
dense: number[];
|
|
169
335
|
sparse: SparseEmbedding;
|
|
336
|
+
summary?: { dense: number[]; sparse: SparseEmbedding };
|
|
170
337
|
updatedAt: number;
|
|
338
|
+
/**
|
|
339
|
+
* Optional payload discriminator. Used to distinguish skill-seeded points
|
|
340
|
+
* (`kind: "skill"`) from user-authored concept pages so namespace pruning
|
|
341
|
+
* via {@link pruneSlugsWithPrefixExcept} can scope deletes to a single kind.
|
|
342
|
+
* Omitted for plain concept pages.
|
|
343
|
+
*/
|
|
344
|
+
kind?: string;
|
|
171
345
|
}): Promise<void> {
|
|
172
346
|
await ensureConceptPageCollection();
|
|
173
347
|
|
|
174
|
-
const { slug, dense, sparse, updatedAt } = params;
|
|
348
|
+
const { slug, dense, sparse, summary, updatedAt, kind } = params;
|
|
175
349
|
const client = getClient();
|
|
176
350
|
const pointId = pointIdForSlug(slug);
|
|
177
351
|
|
|
352
|
+
// Qdrant lets us upsert any subset of named vectors per point. The summary
|
|
353
|
+
// entries appear only when the caller passed a `summary` block — pairing
|
|
354
|
+
// them at the type level keeps query-time fusion symmetric with the body
|
|
355
|
+
// channels.
|
|
356
|
+
const vector: Record<string, number[] | SparseEmbedding> = { dense, sparse };
|
|
357
|
+
if (summary) {
|
|
358
|
+
vector.summary_dense = summary.dense;
|
|
359
|
+
vector.summary_sparse = summary.sparse;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const payload: Record<string, unknown> = { slug, updated_at: updatedAt };
|
|
363
|
+
if (kind !== undefined) payload.kind = kind;
|
|
364
|
+
|
|
178
365
|
const upsertOnce = () =>
|
|
179
366
|
client.upsert(MEMORY_V2_COLLECTION, {
|
|
180
367
|
wait: true,
|
|
181
368
|
points: [
|
|
182
369
|
{
|
|
183
370
|
id: pointId,
|
|
184
|
-
vector
|
|
185
|
-
payload
|
|
371
|
+
vector,
|
|
372
|
+
payload,
|
|
186
373
|
},
|
|
187
374
|
],
|
|
188
375
|
});
|
|
@@ -231,17 +418,25 @@ export async function deleteConceptPageEmbedding(slug: string): Promise<void> {
|
|
|
231
418
|
* since skills now share the concept-page collection rather than living in a
|
|
232
419
|
* dedicated one.
|
|
233
420
|
*
|
|
421
|
+
* `kind` scopes pruning to a payload discriminator: only points whose
|
|
422
|
+
* `payload.kind` matches are eligible for deletion. This is critical because
|
|
423
|
+
* `validateSlug` permits user-authored concept pages slugged like
|
|
424
|
+
* `skills/foo`; without a kind filter they would collide with the skill
|
|
425
|
+
* namespace and be repeatedly pruned every seed run.
|
|
426
|
+
*
|
|
234
427
|
* Idempotent: when the live `<prefix>*` slugs already match `activeSuffixes`,
|
|
235
428
|
* the function performs a single scroll and no deletes.
|
|
236
429
|
*/
|
|
237
430
|
export async function pruneSlugsWithPrefixExcept(
|
|
238
431
|
prefix: string,
|
|
239
432
|
activeSuffixes: readonly string[],
|
|
433
|
+
options: { kind?: string } = {},
|
|
240
434
|
): Promise<void> {
|
|
241
435
|
await ensureConceptPageCollection();
|
|
242
436
|
|
|
243
437
|
const client = getClient();
|
|
244
438
|
const activeSet = new Set(activeSuffixes);
|
|
439
|
+
const requiredKind = options.kind;
|
|
245
440
|
|
|
246
441
|
const doPrune = async (): Promise<void> => {
|
|
247
442
|
const stalePointIds: Array<string | number> = [];
|
|
@@ -256,9 +451,15 @@ export async function pruneSlugsWithPrefixExcept(
|
|
|
256
451
|
...(offset !== undefined ? { offset } : {}),
|
|
257
452
|
});
|
|
258
453
|
for (const point of result.points) {
|
|
259
|
-
const
|
|
454
|
+
const payload = point.payload as {
|
|
455
|
+
slug?: unknown;
|
|
456
|
+
kind?: unknown;
|
|
457
|
+
} | null;
|
|
458
|
+
const slug = payload?.slug;
|
|
260
459
|
if (typeof slug !== "string") continue;
|
|
261
460
|
if (!slug.startsWith(prefix)) continue;
|
|
461
|
+
if (requiredKind !== undefined && payload?.kind !== requiredKind)
|
|
462
|
+
continue;
|
|
262
463
|
const suffix = slug.slice(prefix.length);
|
|
263
464
|
if (!activeSet.has(suffix)) {
|
|
264
465
|
stalePointIds.push(point.id);
|
|
@@ -290,6 +491,46 @@ export async function pruneSlugsWithPrefixExcept(
|
|
|
290
491
|
}
|
|
291
492
|
}
|
|
292
493
|
|
|
494
|
+
/**
|
|
495
|
+
* Approximate count of points in the v2 concept-page collection. Used by the
|
|
496
|
+
* daemon-startup rebuild hook to detect "collection exists but empty" — the
|
|
497
|
+
* crash-mid-rebuild recovery case where a prior boot dropped + recreated the
|
|
498
|
+
* collection but died before reembed completed. Returns `0` if the collection
|
|
499
|
+
* does not exist or the count call fails (treated as "needs reembed" by the
|
|
500
|
+
* caller).
|
|
501
|
+
*/
|
|
502
|
+
export async function countConceptPagePoints(): Promise<number> {
|
|
503
|
+
await ensureConceptPageCollection();
|
|
504
|
+
try {
|
|
505
|
+
const result = await getClient().count(MEMORY_V2_COLLECTION, {
|
|
506
|
+
exact: false,
|
|
507
|
+
});
|
|
508
|
+
return result.count;
|
|
509
|
+
} catch (err) {
|
|
510
|
+
log.warn(
|
|
511
|
+
{ err, collection: MEMORY_V2_COLLECTION },
|
|
512
|
+
"Failed to count v2 concept-page collection — treating as empty",
|
|
513
|
+
);
|
|
514
|
+
return 0;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Probe whether the v2 concept-page collection currently exists in Qdrant
|
|
520
|
+
* **without** triggering creation. Read-only diagnostics use this to avoid
|
|
521
|
+
* the side effect of bootstrapping storage just by inspecting it.
|
|
522
|
+
*/
|
|
523
|
+
export async function conceptPageCollectionExists(): Promise<boolean> {
|
|
524
|
+
const client = getClient();
|
|
525
|
+
try {
|
|
526
|
+
const result = await client.collectionExists(MEMORY_V2_COLLECTION);
|
|
527
|
+
return result.exists;
|
|
528
|
+
} catch (err) {
|
|
529
|
+
if (isCollectionMissing(err)) return false;
|
|
530
|
+
throw err;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
293
534
|
/**
|
|
294
535
|
* Best-effort delete of the legacy `memory_v2_skills` Qdrant collection. Skill
|
|
295
536
|
* embeddings now live alongside concept pages in `memory_v2_concept_pages`
|
|
@@ -319,9 +560,15 @@ export async function dropLegacySkillsCollection(): Promise<void> {
|
|
|
319
560
|
* a normalized weighted-sum — because RRF would discard the score magnitudes
|
|
320
561
|
* the activation formula needs.
|
|
321
562
|
*
|
|
563
|
+
* Four channels are queried concurrently: body dense, body sparse, summary
|
|
564
|
+
* dense, summary sparse. The summary channels only return hits for pages whose
|
|
565
|
+
* frontmatter carries a `summary` (and therefore stored `summary_dense` /
|
|
566
|
+
* `summary_sparse` named vectors at upsert time). Pages without a summary
|
|
567
|
+
* surface body-only scores; callers fall back to body-only fusion for those.
|
|
568
|
+
*
|
|
322
569
|
* Each channel returns up to `limit` hits. A slug is included in the result
|
|
323
|
-
* if it appears in
|
|
324
|
-
*
|
|
570
|
+
* if it appears in any channel; missing channel scores stay `undefined` so
|
|
571
|
+
* callers can distinguish "no match in this channel" from "match with score 0".
|
|
325
572
|
*
|
|
326
573
|
* `restrictToSlugs`, when provided, filters the search server-side to only
|
|
327
574
|
* those slugs (Qdrant `slug IN [...]` filter). Used by `simBatch` when the
|
|
@@ -355,42 +602,51 @@ export async function hybridQueryConceptPages(
|
|
|
355
602
|
// Qdrant 1.13.x sparse-index crash that we've reproduced in the wild.
|
|
356
603
|
const skipSparse = options?.skipSparse ?? false;
|
|
357
604
|
|
|
358
|
-
const
|
|
605
|
+
const queryDense = (using: string) =>
|
|
359
606
|
client.query(MEMORY_V2_COLLECTION, {
|
|
360
607
|
query: dense,
|
|
361
|
-
using
|
|
608
|
+
using,
|
|
362
609
|
limit,
|
|
363
610
|
with_payload: true,
|
|
364
611
|
filter,
|
|
365
612
|
});
|
|
366
|
-
const
|
|
613
|
+
const querySparse = (using: string) =>
|
|
367
614
|
client.query(MEMORY_V2_COLLECTION, {
|
|
368
615
|
query: sparse,
|
|
369
|
-
using
|
|
616
|
+
using,
|
|
370
617
|
limit,
|
|
371
618
|
with_payload: true,
|
|
372
619
|
filter,
|
|
373
620
|
});
|
|
374
621
|
|
|
375
|
-
// Run
|
|
376
|
-
// When sparse is gated off
|
|
377
|
-
// below stays uniform; the empty `points: []` matches
|
|
378
|
-
// no-hit Qdrant response.
|
|
622
|
+
// Run all four channels concurrently — they hit independent named vectors.
|
|
623
|
+
// When sparse is gated off the sparse channels still resolve a Promise so
|
|
624
|
+
// the destructuring below stays uniform; the empty `points: []` matches
|
|
625
|
+
// the shape of a no-hit Qdrant response.
|
|
379
626
|
const emptyResult = {
|
|
380
627
|
points: [] as Array<{ payload?: unknown; score?: number }>,
|
|
381
628
|
};
|
|
382
629
|
const runQueries = async () =>
|
|
383
|
-
Promise.all([
|
|
630
|
+
Promise.all([
|
|
631
|
+
queryDense("dense"),
|
|
632
|
+
skipSparse ? emptyResult : querySparse("sparse"),
|
|
633
|
+
queryDense("summary_dense"),
|
|
634
|
+
skipSparse ? emptyResult : querySparse("summary_sparse"),
|
|
635
|
+
]);
|
|
384
636
|
|
|
385
637
|
let denseResults;
|
|
386
638
|
let sparseResults;
|
|
639
|
+
let summaryDenseResults;
|
|
640
|
+
let summarySparseResults;
|
|
387
641
|
try {
|
|
388
|
-
[denseResults, sparseResults] =
|
|
642
|
+
[denseResults, sparseResults, summaryDenseResults, summarySparseResults] =
|
|
643
|
+
await runQueries();
|
|
389
644
|
} catch (err) {
|
|
390
645
|
if (isCollectionMissing(err)) {
|
|
391
646
|
_collectionReady = false;
|
|
392
647
|
await ensureConceptPageCollection();
|
|
393
|
-
[denseResults, sparseResults] =
|
|
648
|
+
[denseResults, sparseResults, summaryDenseResults, summarySparseResults] =
|
|
649
|
+
await runQueries();
|
|
394
650
|
} else {
|
|
395
651
|
throw err;
|
|
396
652
|
}
|
|
@@ -399,108 +655,26 @@ export async function hybridQueryConceptPages(
|
|
|
399
655
|
// Merge by slug. Missing-side scores stay undefined so the fuser can tell
|
|
400
656
|
// "no match in this channel" apart from "match with score 0".
|
|
401
657
|
const merged = new Map<string, ConceptPageQueryResult>();
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
existing.sparseScore = point.score ?? 0;
|
|
413
|
-
} else {
|
|
414
|
-
merged.set(slug, { slug, sparseScore: point.score ?? 0 });
|
|
658
|
+
const recordHit = (
|
|
659
|
+
points: Array<{ payload?: unknown; score?: number }> | undefined,
|
|
660
|
+
set: (entry: ConceptPageQueryResult, score: number) => void,
|
|
661
|
+
): void => {
|
|
662
|
+
for (const point of points ?? []) {
|
|
663
|
+
const slug = (point.payload as { slug?: unknown } | null)?.slug;
|
|
664
|
+
if (typeof slug !== "string") continue;
|
|
665
|
+
const existing = merged.get(slug) ?? { slug };
|
|
666
|
+
set(existing, point.score ?? 0);
|
|
667
|
+
merged.set(slug, existing);
|
|
415
668
|
}
|
|
416
|
-
}
|
|
669
|
+
};
|
|
670
|
+
recordHit(denseResults.points, (e, s) => (e.denseScore = s));
|
|
671
|
+
recordHit(sparseResults.points, (e, s) => (e.sparseScore = s));
|
|
672
|
+
recordHit(summaryDenseResults.points, (e, s) => (e.summaryDenseScore = s));
|
|
673
|
+
recordHit(summarySparseResults.points, (e, s) => (e.summarySparseScore = s));
|
|
417
674
|
|
|
418
675
|
return Array.from(merged.values());
|
|
419
676
|
}
|
|
420
677
|
|
|
421
|
-
/**
|
|
422
|
-
* Page through the v2 concept-page collection and return up to `maxSamples`
|
|
423
|
-
* stored dense vectors. Used by the anisotropy-fit pipeline to compute a
|
|
424
|
-
* corpus mean + top-k principal components without re-embedding every page.
|
|
425
|
-
*
|
|
426
|
-
* Sparse vectors are skipped — anisotropy is a dense-embedding phenomenon, and
|
|
427
|
-
* pulling the sparse side would just inflate the response. Payload is also
|
|
428
|
-
* skipped because the fit doesn't need slug identity.
|
|
429
|
-
*
|
|
430
|
-
* Returns an empty array when the collection is empty or missing. Caller
|
|
431
|
-
* decides what to do (typically: surface a "no vectors to fit" error).
|
|
432
|
-
*/
|
|
433
|
-
export async function sampleConceptPageDenseVectors(
|
|
434
|
-
maxSamples: number,
|
|
435
|
-
): Promise<number[][]> {
|
|
436
|
-
if (maxSamples <= 0) return [];
|
|
437
|
-
await ensureConceptPageCollection();
|
|
438
|
-
|
|
439
|
-
const client = getClient();
|
|
440
|
-
const out: number[][] = [];
|
|
441
|
-
let offset: string | number | undefined = undefined;
|
|
442
|
-
// Same pagination guard pattern as the rest of the file — bounds the loop
|
|
443
|
-
// even if Qdrant somehow keeps handing back a non-null offset.
|
|
444
|
-
const maxIterations = 10_000;
|
|
445
|
-
const batchSize = Math.min(256, maxSamples);
|
|
446
|
-
|
|
447
|
-
for (let i = 0; i < maxIterations; i++) {
|
|
448
|
-
if (out.length >= maxSamples) break;
|
|
449
|
-
const remaining = maxSamples - out.length;
|
|
450
|
-
let result;
|
|
451
|
-
try {
|
|
452
|
-
result = await client.scroll(MEMORY_V2_COLLECTION, {
|
|
453
|
-
limit: Math.min(batchSize, remaining),
|
|
454
|
-
with_payload: false,
|
|
455
|
-
// Fetch only the dense named vector — sparse is irrelevant for
|
|
456
|
-
// anisotropy correction.
|
|
457
|
-
with_vector: ["dense"],
|
|
458
|
-
...(offset !== undefined ? { offset } : {}),
|
|
459
|
-
});
|
|
460
|
-
} catch (err) {
|
|
461
|
-
if (isCollectionMissing(err)) {
|
|
462
|
-
_collectionReady = false;
|
|
463
|
-
return out;
|
|
464
|
-
}
|
|
465
|
-
throw err;
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
for (const point of result.points) {
|
|
469
|
-
const v = extractDenseVector(point.vector);
|
|
470
|
-
if (v) out.push(v);
|
|
471
|
-
if (out.length >= maxSamples) break;
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
const next = result.next_page_offset;
|
|
475
|
-
if (next == null) break;
|
|
476
|
-
offset = typeof next === "string" ? next : (next as number);
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
return out;
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
/**
|
|
483
|
-
* Pull the `dense` named-vector payload out of a Qdrant point. Defensively
|
|
484
|
-
* handles both the named-vector shape (`{ dense: [...] }`) and the legacy
|
|
485
|
-
* unnamed-vector shape (`number[]`) so older collection layouts don't trip
|
|
486
|
-
* the sampler. Returns `null` for shapes we don't recognise.
|
|
487
|
-
*/
|
|
488
|
-
function extractDenseVector(vector: unknown): number[] | null {
|
|
489
|
-
if (Array.isArray(vector)) {
|
|
490
|
-
if (vector.every((n) => typeof n === "number")) {
|
|
491
|
-
return vector as number[];
|
|
492
|
-
}
|
|
493
|
-
return null;
|
|
494
|
-
}
|
|
495
|
-
if (vector && typeof vector === "object") {
|
|
496
|
-
const dense = (vector as { dense?: unknown }).dense;
|
|
497
|
-
if (Array.isArray(dense) && dense.every((n) => typeof n === "number")) {
|
|
498
|
-
return dense as number[];
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
return null;
|
|
502
|
-
}
|
|
503
|
-
|
|
504
678
|
/**
|
|
505
679
|
* Detect "collection not found" errors so callers can reset readiness and
|
|
506
680
|
* retry after an external deletion (e.g. workspace reset).
|
|
@@ -10,8 +10,8 @@ import { readPage } from "./page-store.js";
|
|
|
10
10
|
|
|
11
11
|
const log = getLogger("memory-v2-reranker");
|
|
12
12
|
|
|
13
|
-
//
|
|
14
|
-
const PASSAGE_CHAR_CAP =
|
|
13
|
+
// Cap passage input to bound batched payload size and tokenization cost.
|
|
14
|
+
const PASSAGE_CHAR_CAP = 1500;
|
|
15
15
|
|
|
16
16
|
interface CacheEntry {
|
|
17
17
|
scores: Map<string, number>;
|
|
@@ -22,9 +22,16 @@ const CACHE_TTL_MS = 2 * 60 * 1000;
|
|
|
22
22
|
const CACHE_MAX_ENTRIES = 64;
|
|
23
23
|
const cache = new Map<string, CacheEntry>();
|
|
24
24
|
|
|
25
|
-
function cacheKey(
|
|
25
|
+
function cacheKey(
|
|
26
|
+
query: string,
|
|
27
|
+
slugs: readonly string[],
|
|
28
|
+
model: string,
|
|
29
|
+
dtype: string,
|
|
30
|
+
): string {
|
|
26
31
|
const sorted = [...slugs].sort().join("\0");
|
|
27
|
-
return createHash("sha256")
|
|
32
|
+
return createHash("sha256")
|
|
33
|
+
.update(`${model}\0${dtype}\0${query}\0${sorted}`)
|
|
34
|
+
.digest("hex");
|
|
28
35
|
}
|
|
29
36
|
|
|
30
37
|
function evictExpired(now: number): void {
|
|
@@ -73,6 +80,7 @@ export async function rerankCandidates(
|
|
|
73
80
|
if (queries.length === 0) return [];
|
|
74
81
|
if (candidates.length === 0) return queries.map(() => new Map());
|
|
75
82
|
|
|
83
|
+
const { model, dtype } = config.memory.v2.rerank;
|
|
76
84
|
const now = Date.now();
|
|
77
85
|
evictExpired(now);
|
|
78
86
|
|
|
@@ -84,7 +92,7 @@ export async function rerankCandidates(
|
|
|
84
92
|
results[i] = new Map();
|
|
85
93
|
continue;
|
|
86
94
|
}
|
|
87
|
-
const key = cacheKey(q, candidates);
|
|
95
|
+
const key = cacheKey(q, candidates, model, dtype);
|
|
88
96
|
const cached = cache.get(key);
|
|
89
97
|
if (cached) {
|
|
90
98
|
// Refresh insertion order so frequently-hit entries survive eviction.
|
|
@@ -137,7 +145,6 @@ export async function rerankCandidates(
|
|
|
137
145
|
}
|
|
138
146
|
}
|
|
139
147
|
|
|
140
|
-
const { model, dtype } = config.memory.v2.rerank;
|
|
141
148
|
let scores: number[];
|
|
142
149
|
try {
|
|
143
150
|
const backend = getOrCreateRerankBackend(model, dtype);
|
|
@@ -162,7 +169,7 @@ export async function rerankCandidates(
|
|
|
162
169
|
result.set(slugsForPassages[i], Math.max(0, Math.min(1, s)));
|
|
163
170
|
}
|
|
164
171
|
results[qi] = result;
|
|
165
|
-
cache.set(cacheKey(queries[qi], candidates), {
|
|
172
|
+
cache.set(cacheKey(queries[qi], candidates, model, dtype), {
|
|
166
173
|
scores: new Map(result),
|
|
167
174
|
ts: now,
|
|
168
175
|
});
|