@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
|
@@ -1,11 +1,30 @@
|
|
|
1
|
+
import { existsSync, mkdtempSync, rmSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
1
4
|
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
5
|
|
|
3
6
|
import { makeMockLogger } from "../../../__tests__/helpers/mock-logger.js";
|
|
4
7
|
|
|
8
|
+
// Per-suite tmp data dir so the reembed sentinel never lands in the
|
|
9
|
+
// developer's real ~/.vellum workspace.
|
|
10
|
+
const TEST_DATA_DIR = mkdtempSync(join(tmpdir(), "memory-v2-qdrant-test-"));
|
|
11
|
+
const REEMBED_SENTINEL_PATH = join(
|
|
12
|
+
TEST_DATA_DIR,
|
|
13
|
+
".memory-v2-reembed-required",
|
|
14
|
+
);
|
|
15
|
+
|
|
5
16
|
mock.module("../../../util/logger.js", () => ({
|
|
6
17
|
getLogger: () => makeMockLogger(),
|
|
7
18
|
}));
|
|
8
19
|
|
|
20
|
+
mock.module("../../../util/platform.js", () => ({
|
|
21
|
+
getDataDir: () => TEST_DATA_DIR,
|
|
22
|
+
// Bun shares mocked modules across test files; some peer tests import
|
|
23
|
+
// `getWorkspaceDir` from this same module, so re-export it here to avoid
|
|
24
|
+
// an `undefined` if this mock is the one that wins evaluation order.
|
|
25
|
+
getWorkspaceDir: () => TEST_DATA_DIR,
|
|
26
|
+
}));
|
|
27
|
+
|
|
9
28
|
// Stub getConfig — only the qdrant.url / vectorSize / onDisk fields matter.
|
|
10
29
|
mock.module("../../../config/loader.js", () => ({
|
|
11
30
|
getConfig: () => ({
|
|
@@ -27,10 +46,39 @@ mock.module("../../qdrant-client.js", () => ({
|
|
|
27
46
|
// records every call and lets each test program the next response.
|
|
28
47
|
type MockPoint = {
|
|
29
48
|
id: string;
|
|
30
|
-
vector: {
|
|
49
|
+
vector: {
|
|
50
|
+
dense: number[];
|
|
51
|
+
sparse: { indices: number[]; values: number[] };
|
|
52
|
+
summary_dense?: number[];
|
|
53
|
+
summary_sparse?: { indices: number[]; values: number[] };
|
|
54
|
+
};
|
|
31
55
|
payload: { slug: string; updated_at: number };
|
|
32
56
|
};
|
|
33
57
|
|
|
58
|
+
type MockCollectionInfo = {
|
|
59
|
+
config: {
|
|
60
|
+
params: {
|
|
61
|
+
vectors?: Record<string, { size: number }> | { size: number };
|
|
62
|
+
sparse_vectors?: Record<string, unknown>;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const FULL_SCHEMA_INFO: MockCollectionInfo = {
|
|
68
|
+
config: {
|
|
69
|
+
params: {
|
|
70
|
+
vectors: {
|
|
71
|
+
dense: { size: 384 },
|
|
72
|
+
summary_dense: { size: 384 },
|
|
73
|
+
},
|
|
74
|
+
sparse_vectors: {
|
|
75
|
+
sparse: {},
|
|
76
|
+
summary_sparse: {},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
|
|
34
82
|
const state = {
|
|
35
83
|
collectionExistsBeforeCreate: false,
|
|
36
84
|
collectionExistsCalls: 0,
|
|
@@ -39,6 +87,10 @@ const state = {
|
|
|
39
87
|
createIndexCalls: [] as Array<{ field_name: string; field_schema: string }>,
|
|
40
88
|
upsertCalls: [] as Array<{ wait: boolean; points: MockPoint[] }>,
|
|
41
89
|
deleteCalls: [] as Array<{ wait: boolean; points: string[] }>,
|
|
90
|
+
// Tracks `client.deleteCollection(name)` calls (distinct from `delete()`,
|
|
91
|
+
// which targets points). The schema-drift recreate path drops the
|
|
92
|
+
// collection entirely and we want to assert it ran exactly once.
|
|
93
|
+
deleteCollectionCalls: [] as string[],
|
|
42
94
|
queryCalls: [] as Array<{
|
|
43
95
|
using: string;
|
|
44
96
|
query: unknown;
|
|
@@ -55,6 +107,17 @@ const state = {
|
|
|
55
107
|
}>,
|
|
56
108
|
},
|
|
57
109
|
createCollectionThrows: null as Error | null,
|
|
110
|
+
// Schema returned by `client.getCollection`. Tests that exercise the
|
|
111
|
+
// drift path point this at a partial schema; the default mirrors a fully
|
|
112
|
+
// migrated collection so the no-drift path is the silent default.
|
|
113
|
+
getCollectionInfo: FULL_SCHEMA_INFO as MockCollectionInfo,
|
|
114
|
+
getCollectionThrows: null as Error | null,
|
|
115
|
+
getCollectionCalls: 0,
|
|
116
|
+
// Point count returned by `client.count`. Used by `countConceptPagePoints`
|
|
117
|
+
// which the lifecycle hook reads for the empty-after-create recovery path.
|
|
118
|
+
countResult: 0,
|
|
119
|
+
countThrows: null as Error | null,
|
|
120
|
+
countCalls: 0,
|
|
58
121
|
// Throw queue for upsert: first call shifts and throws if non-null;
|
|
59
122
|
// subsequent calls succeed once the queue is exhausted.
|
|
60
123
|
upsertThrowQueue: [] as Array<Error | null>,
|
|
@@ -66,13 +129,29 @@ class MockQdrantClient {
|
|
|
66
129
|
state.collectionExistsCalls++;
|
|
67
130
|
return { exists: state.collectionExistsBeforeCreate };
|
|
68
131
|
}
|
|
132
|
+
async getCollection(_name: string) {
|
|
133
|
+
state.getCollectionCalls++;
|
|
134
|
+
if (state.getCollectionThrows) throw state.getCollectionThrows;
|
|
135
|
+
return state.getCollectionInfo;
|
|
136
|
+
}
|
|
69
137
|
async createCollection(_name: string, params: unknown) {
|
|
70
138
|
state.createCollectionCalls++;
|
|
71
139
|
state.createCollectionParams = params;
|
|
72
140
|
if (state.createCollectionThrows) throw state.createCollectionThrows;
|
|
73
141
|
state.collectionExistsBeforeCreate = true;
|
|
142
|
+
state.getCollectionInfo = FULL_SCHEMA_INFO;
|
|
143
|
+
return {};
|
|
144
|
+
}
|
|
145
|
+
async deleteCollection(name: string) {
|
|
146
|
+
state.deleteCollectionCalls.push(name);
|
|
147
|
+
state.collectionExistsBeforeCreate = false;
|
|
74
148
|
return {};
|
|
75
149
|
}
|
|
150
|
+
async count(_name: string, _opts: { exact: boolean }) {
|
|
151
|
+
state.countCalls++;
|
|
152
|
+
if (state.countThrows) throw state.countThrows;
|
|
153
|
+
return { count: state.countResult };
|
|
154
|
+
}
|
|
76
155
|
async createPayloadIndex(
|
|
77
156
|
_name: string,
|
|
78
157
|
params: { field_name: string; field_schema: string },
|
|
@@ -102,7 +181,14 @@ class MockQdrantClient {
|
|
|
102
181
|
},
|
|
103
182
|
) {
|
|
104
183
|
state.queryCalls.push(params);
|
|
105
|
-
|
|
184
|
+
// Both `dense` and `summary_dense` consume from the dense queue (and
|
|
185
|
+
// similarly for sparse). The four-channel hybrid query fires them in
|
|
186
|
+
// order: body-dense, body-sparse, summary-dense, summary-sparse — so
|
|
187
|
+
// queue order matches call order.
|
|
188
|
+
const queue =
|
|
189
|
+
state.queryResponses[
|
|
190
|
+
params.using.endsWith("sparse") ? "sparse" : "dense"
|
|
191
|
+
];
|
|
106
192
|
return queue.shift() ?? { points: [] };
|
|
107
193
|
}
|
|
108
194
|
}
|
|
@@ -116,6 +202,8 @@ const {
|
|
|
116
202
|
upsertConceptPageEmbedding,
|
|
117
203
|
deleteConceptPageEmbedding,
|
|
118
204
|
hybridQueryConceptPages,
|
|
205
|
+
countConceptPagePoints,
|
|
206
|
+
clearReembedSentinel,
|
|
119
207
|
MEMORY_V2_COLLECTION,
|
|
120
208
|
_resetMemoryV2QdrantForTests,
|
|
121
209
|
} = await import("../qdrant.js");
|
|
@@ -128,19 +216,31 @@ function resetState(): void {
|
|
|
128
216
|
state.createIndexCalls.length = 0;
|
|
129
217
|
state.upsertCalls.length = 0;
|
|
130
218
|
state.deleteCalls.length = 0;
|
|
219
|
+
state.deleteCollectionCalls.length = 0;
|
|
131
220
|
state.queryCalls.length = 0;
|
|
132
221
|
state.queryResponses.dense.length = 0;
|
|
133
222
|
state.queryResponses.sparse.length = 0;
|
|
134
223
|
state.createCollectionThrows = null;
|
|
224
|
+
state.getCollectionInfo = FULL_SCHEMA_INFO;
|
|
225
|
+
state.getCollectionThrows = null;
|
|
226
|
+
state.getCollectionCalls = 0;
|
|
227
|
+
state.countResult = 0;
|
|
228
|
+
state.countThrows = null;
|
|
229
|
+
state.countCalls = 0;
|
|
135
230
|
state.upsertThrowQueue.length = 0;
|
|
136
231
|
_resetMemoryV2QdrantForTests();
|
|
232
|
+
// Drop any sentinel a prior test left behind so the no-drift default path
|
|
233
|
+
// doesn't accidentally report `migrated: true`.
|
|
234
|
+
if (existsSync(REEMBED_SENTINEL_PATH)) {
|
|
235
|
+
rmSync(REEMBED_SENTINEL_PATH);
|
|
236
|
+
}
|
|
137
237
|
}
|
|
138
238
|
|
|
139
239
|
describe("memory v2 qdrant — collection lifecycle", () => {
|
|
140
240
|
beforeEach(resetState);
|
|
141
241
|
afterEach(resetState);
|
|
142
242
|
|
|
143
|
-
test("creates the collection with named dense + sparse vectors", async () => {
|
|
243
|
+
test("creates the collection with named dense + sparse vectors (body and summary)", async () => {
|
|
144
244
|
state.collectionExistsBeforeCreate = false;
|
|
145
245
|
|
|
146
246
|
await ensureConceptPageCollection();
|
|
@@ -149,8 +249,12 @@ describe("memory v2 qdrant — collection lifecycle", () => {
|
|
|
149
249
|
const params = state.createCollectionParams as {
|
|
150
250
|
vectors: {
|
|
151
251
|
dense: { size: number; distance: string; on_disk: boolean };
|
|
252
|
+
summary_dense: { size: number; distance: string; on_disk: boolean };
|
|
253
|
+
};
|
|
254
|
+
sparse_vectors: {
|
|
255
|
+
sparse: Record<string, unknown>;
|
|
256
|
+
summary_sparse: Record<string, unknown>;
|
|
152
257
|
};
|
|
153
|
-
sparse_vectors: { sparse: Record<string, unknown> };
|
|
154
258
|
hnsw_config: { on_disk: boolean; m: number; ef_construct: number };
|
|
155
259
|
on_disk_payload: boolean;
|
|
156
260
|
};
|
|
@@ -159,7 +263,14 @@ describe("memory v2 qdrant — collection lifecycle", () => {
|
|
|
159
263
|
distance: "Cosine",
|
|
160
264
|
on_disk: true,
|
|
161
265
|
});
|
|
266
|
+
// Summary side mirrors body so the activation pipeline can fuse symmetrically.
|
|
267
|
+
expect(params.vectors.summary_dense).toEqual({
|
|
268
|
+
size: 384,
|
|
269
|
+
distance: "Cosine",
|
|
270
|
+
on_disk: true,
|
|
271
|
+
});
|
|
162
272
|
expect(params.sparse_vectors.sparse).toEqual({});
|
|
273
|
+
expect(params.sparse_vectors.summary_sparse).toEqual({});
|
|
163
274
|
expect(params.hnsw_config).toEqual({
|
|
164
275
|
on_disk: true,
|
|
165
276
|
m: 16,
|
|
@@ -219,6 +330,162 @@ describe("memory v2 qdrant — collection lifecycle", () => {
|
|
|
219
330
|
// expected to have created it (it ran the same code).
|
|
220
331
|
expect(state.createIndexCalls).toEqual([]);
|
|
221
332
|
});
|
|
333
|
+
|
|
334
|
+
test("detects missing summary_dense / summary_sparse on an existing collection and recreates", async () => {
|
|
335
|
+
// Pre-#29823 schema: only body channels, no summary_*.
|
|
336
|
+
state.collectionExistsBeforeCreate = true;
|
|
337
|
+
state.getCollectionInfo = {
|
|
338
|
+
config: {
|
|
339
|
+
params: {
|
|
340
|
+
vectors: { dense: { size: 384 } },
|
|
341
|
+
sparse_vectors: { sparse: {} },
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
const result = await ensureConceptPageCollection();
|
|
347
|
+
|
|
348
|
+
// Drift path probed once, dropped the collection once, and recreated
|
|
349
|
+
// with the full four-vector schema (the create-success branch resets
|
|
350
|
+
// `getCollectionInfo` to FULL_SCHEMA_INFO so a follow-up probe agrees).
|
|
351
|
+
expect(state.getCollectionCalls).toBe(1);
|
|
352
|
+
expect(state.deleteCollectionCalls).toEqual([MEMORY_V2_COLLECTION]);
|
|
353
|
+
expect(state.createCollectionCalls).toBe(1);
|
|
354
|
+
expect(result).toEqual({ migrated: true });
|
|
355
|
+
|
|
356
|
+
// Recreated schema carries summary_dense + summary_sparse.
|
|
357
|
+
const params = state.createCollectionParams as {
|
|
358
|
+
vectors: Record<string, unknown>;
|
|
359
|
+
sparse_vectors: Record<string, unknown>;
|
|
360
|
+
};
|
|
361
|
+
expect(params.vectors.summary_dense).toBeDefined();
|
|
362
|
+
expect(params.sparse_vectors.summary_sparse).toBeDefined();
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
test("leaves a fully migrated collection untouched", async () => {
|
|
366
|
+
// Default `getCollectionInfo` is FULL_SCHEMA_INFO — already migrated.
|
|
367
|
+
state.collectionExistsBeforeCreate = true;
|
|
368
|
+
|
|
369
|
+
const result = await ensureConceptPageCollection();
|
|
370
|
+
|
|
371
|
+
expect(state.getCollectionCalls).toBe(1);
|
|
372
|
+
expect(state.deleteCollectionCalls).toEqual([]);
|
|
373
|
+
expect(state.createCollectionCalls).toBe(0);
|
|
374
|
+
expect(result).toEqual({ migrated: false });
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
test("getCollection failure is treated as compatible (no destructive recreate)", async () => {
|
|
378
|
+
state.collectionExistsBeforeCreate = true;
|
|
379
|
+
state.getCollectionThrows = new Error("transient REST error");
|
|
380
|
+
|
|
381
|
+
const result = await ensureConceptPageCollection();
|
|
382
|
+
|
|
383
|
+
expect(state.getCollectionCalls).toBe(1);
|
|
384
|
+
expect(state.deleteCollectionCalls).toEqual([]);
|
|
385
|
+
expect(state.createCollectionCalls).toBe(0);
|
|
386
|
+
expect(result).toEqual({ migrated: false });
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
test("preserves the reembed signal across calls when createCollection fails after delete", async () => {
|
|
390
|
+
// Pre-#29823 schema triggers the destructive recreate path.
|
|
391
|
+
state.collectionExistsBeforeCreate = true;
|
|
392
|
+
state.getCollectionInfo = {
|
|
393
|
+
config: {
|
|
394
|
+
params: {
|
|
395
|
+
vectors: { dense: { size: 384 } },
|
|
396
|
+
sparse_vectors: { sparse: {} },
|
|
397
|
+
},
|
|
398
|
+
},
|
|
399
|
+
};
|
|
400
|
+
state.createCollectionThrows = new Error("Qdrant transient failure");
|
|
401
|
+
|
|
402
|
+
let firstError: unknown = null;
|
|
403
|
+
try {
|
|
404
|
+
await ensureConceptPageCollection();
|
|
405
|
+
} catch (err) {
|
|
406
|
+
firstError = err;
|
|
407
|
+
}
|
|
408
|
+
expect(firstError).not.toBeNull();
|
|
409
|
+
// The sentinel must outlive the failed call so the retry knows data was lost.
|
|
410
|
+
expect(existsSync(REEMBED_SENTINEL_PATH)).toBe(true);
|
|
411
|
+
|
|
412
|
+
// Simulate a follow-up call after the transient failure clears. The
|
|
413
|
+
// collection no longer exists (delete succeeded earlier) so the ensure
|
|
414
|
+
// path falls through to createCollection without re-entering the drift
|
|
415
|
+
// branch — but the sentinel must still surface as `migrated: true` so
|
|
416
|
+
// the lifecycle hook enqueues reembed.
|
|
417
|
+
state.createCollectionThrows = null;
|
|
418
|
+
_resetMemoryV2QdrantForTests();
|
|
419
|
+
const result = await ensureConceptPageCollection();
|
|
420
|
+
|
|
421
|
+
expect(result).toEqual({ migrated: true });
|
|
422
|
+
|
|
423
|
+
// Lifecycle hook clears the sentinel after enqueueing the reembed job.
|
|
424
|
+
await clearReembedSentinel();
|
|
425
|
+
expect(existsSync(REEMBED_SENTINEL_PATH)).toBe(false);
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
test("clearReembedSentinel is a no-op when no sentinel exists", async () => {
|
|
429
|
+
// Idempotent: missing-file does not throw, so the lifecycle hook can
|
|
430
|
+
// call it unconditionally without guarding.
|
|
431
|
+
expect(existsSync(REEMBED_SENTINEL_PATH)).toBe(false);
|
|
432
|
+
await clearReembedSentinel();
|
|
433
|
+
expect(existsSync(REEMBED_SENTINEL_PATH)).toBe(false);
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
test("concurrent ensure during a schema rebuild only deletes/creates once", async () => {
|
|
437
|
+
state.collectionExistsBeforeCreate = true;
|
|
438
|
+
state.getCollectionInfo = {
|
|
439
|
+
config: {
|
|
440
|
+
params: {
|
|
441
|
+
vectors: { dense: { size: 384 } },
|
|
442
|
+
sparse_vectors: { sparse: {} },
|
|
443
|
+
},
|
|
444
|
+
},
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
const results = await Promise.all([
|
|
448
|
+
ensureConceptPageCollection(),
|
|
449
|
+
ensureConceptPageCollection(),
|
|
450
|
+
ensureConceptPageCollection(),
|
|
451
|
+
]);
|
|
452
|
+
|
|
453
|
+
expect(state.deleteCollectionCalls).toEqual([MEMORY_V2_COLLECTION]);
|
|
454
|
+
expect(state.createCollectionCalls).toBe(1);
|
|
455
|
+
// All three concurrent callers see the same migrated signal so any one
|
|
456
|
+
// of them is safe to enqueue the reembed (the lifecycle hook is the
|
|
457
|
+
// single producer in practice).
|
|
458
|
+
expect(results).toEqual([
|
|
459
|
+
{ migrated: true },
|
|
460
|
+
{ migrated: true },
|
|
461
|
+
{ migrated: true },
|
|
462
|
+
]);
|
|
463
|
+
});
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
describe("memory v2 qdrant — point count", () => {
|
|
467
|
+
beforeEach(resetState);
|
|
468
|
+
afterEach(resetState);
|
|
469
|
+
|
|
470
|
+
test("returns the approximate Qdrant count for the v2 collection", async () => {
|
|
471
|
+
state.collectionExistsBeforeCreate = true;
|
|
472
|
+
state.countResult = 1185;
|
|
473
|
+
|
|
474
|
+
const count = await countConceptPagePoints();
|
|
475
|
+
|
|
476
|
+
expect(count).toBe(1185);
|
|
477
|
+
expect(state.countCalls).toBe(1);
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
test("returns 0 when the count call fails (treated as needs-reembed)", async () => {
|
|
481
|
+
state.collectionExistsBeforeCreate = true;
|
|
482
|
+
state.countThrows = new Error("Qdrant unreachable");
|
|
483
|
+
|
|
484
|
+
const count = await countConceptPagePoints();
|
|
485
|
+
|
|
486
|
+
expect(count).toBe(0);
|
|
487
|
+
expect(state.countCalls).toBe(1);
|
|
488
|
+
});
|
|
222
489
|
});
|
|
223
490
|
|
|
224
491
|
describe("memory v2 qdrant — upsert", () => {
|
|
@@ -249,12 +516,67 @@ describe("memory v2 qdrant — upsert", () => {
|
|
|
249
516
|
indices: [1, 2],
|
|
250
517
|
values: [0.5, 0.5],
|
|
251
518
|
});
|
|
519
|
+
// No summary vectors when caller didn't pass them — Qdrant accepts a
|
|
520
|
+
// partial named-vector subset, and pages without a frontmatter summary
|
|
521
|
+
// legitimately have nothing to embed on the summary side.
|
|
522
|
+
const vectorRecord = point.vector as unknown as Record<string, unknown>;
|
|
523
|
+
expect(vectorRecord.summary_dense).toBeUndefined();
|
|
524
|
+
expect(vectorRecord.summary_sparse).toBeUndefined();
|
|
252
525
|
// Point ID is a UUID-shaped string derived from the slug.
|
|
253
526
|
expect(point.id).toMatch(
|
|
254
527
|
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/,
|
|
255
528
|
);
|
|
256
529
|
});
|
|
257
530
|
|
|
531
|
+
test("upserts summary vectors alongside body vectors when both are provided", async () => {
|
|
532
|
+
state.collectionExistsBeforeCreate = true;
|
|
533
|
+
|
|
534
|
+
await upsertConceptPageEmbedding({
|
|
535
|
+
slug: "summarized-page",
|
|
536
|
+
dense: [0.1, 0.2, 0.3],
|
|
537
|
+
sparse: { indices: [1, 2], values: [0.5, 0.5] },
|
|
538
|
+
summary: {
|
|
539
|
+
dense: [0.4, 0.5, 0.6],
|
|
540
|
+
sparse: { indices: [3, 4], values: [0.7, 0.7] },
|
|
541
|
+
},
|
|
542
|
+
updatedAt: 1714000000000,
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
expect(state.upsertCalls).toHaveLength(1);
|
|
546
|
+
const [point] = state.upsertCalls[0].points;
|
|
547
|
+
const vectorRecord = point.vector as unknown as Record<string, unknown>;
|
|
548
|
+
expect(vectorRecord.dense).toEqual([0.1, 0.2, 0.3]);
|
|
549
|
+
expect(vectorRecord.sparse).toEqual({
|
|
550
|
+
indices: [1, 2],
|
|
551
|
+
values: [0.5, 0.5],
|
|
552
|
+
});
|
|
553
|
+
expect(vectorRecord.summary_dense).toEqual([0.4, 0.5, 0.6]);
|
|
554
|
+
expect(vectorRecord.summary_sparse).toEqual({
|
|
555
|
+
indices: [3, 4],
|
|
556
|
+
values: [0.7, 0.7],
|
|
557
|
+
});
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
test("omits summary vectors when the summary block is undefined", async () => {
|
|
561
|
+
// The grouped-shape signature enforces summary as a paired { dense, sparse }
|
|
562
|
+
// block; passing `undefined` (or omitting it) leaves the summary vectors off
|
|
563
|
+
// the point entirely so query-time fusion stays symmetric.
|
|
564
|
+
state.collectionExistsBeforeCreate = true;
|
|
565
|
+
|
|
566
|
+
await upsertConceptPageEmbedding({
|
|
567
|
+
slug: "no-summary",
|
|
568
|
+
dense: [0.1],
|
|
569
|
+
sparse: { indices: [1], values: [1] },
|
|
570
|
+
// summary intentionally omitted
|
|
571
|
+
updatedAt: 1,
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
const [point] = state.upsertCalls[0].points;
|
|
575
|
+
const vectorRecord = point.vector as unknown as Record<string, unknown>;
|
|
576
|
+
expect(vectorRecord.summary_dense).toBeUndefined();
|
|
577
|
+
expect(vectorRecord.summary_sparse).toBeUndefined();
|
|
578
|
+
});
|
|
579
|
+
|
|
258
580
|
test("two upserts for the same slug share the same point id (overwrites in place)", async () => {
|
|
259
581
|
state.collectionExistsBeforeCreate = true;
|
|
260
582
|
|
|
@@ -357,8 +679,9 @@ describe("memory v2 qdrant — hybrid query", () => {
|
|
|
357
679
|
beforeEach(resetState);
|
|
358
680
|
afterEach(resetState);
|
|
359
681
|
|
|
360
|
-
test("runs
|
|
682
|
+
test("runs all four channels (body dense/sparse + summary dense/sparse) and returns per-channel scores", async () => {
|
|
361
683
|
state.collectionExistsBeforeCreate = true;
|
|
684
|
+
// Body channel hits.
|
|
362
685
|
state.queryResponses.dense.push({
|
|
363
686
|
points: [
|
|
364
687
|
{ score: 0.91, payload: { slug: "alice-prefers-vs-code" } },
|
|
@@ -371,6 +694,14 @@ describe("memory v2 qdrant — hybrid query", () => {
|
|
|
371
694
|
{ score: 3, payload: { slug: "bob-uses-zsh" } },
|
|
372
695
|
],
|
|
373
696
|
});
|
|
697
|
+
// Summary channel hits — queue order is body-dense, body-sparse,
|
|
698
|
+
// summary-dense, summary-sparse, so push summaries after bodies.
|
|
699
|
+
state.queryResponses.dense.push({
|
|
700
|
+
points: [{ score: 0.81, payload: { slug: "alice-prefers-vs-code" } }],
|
|
701
|
+
});
|
|
702
|
+
state.queryResponses.sparse.push({
|
|
703
|
+
points: [{ score: 9, payload: { slug: "alice-prefers-vs-code" } }],
|
|
704
|
+
});
|
|
374
705
|
|
|
375
706
|
const results = await hybridQueryConceptPages(
|
|
376
707
|
[0.1, 0.2, 0.3],
|
|
@@ -378,14 +709,19 @@ describe("memory v2 qdrant — hybrid query", () => {
|
|
|
378
709
|
5,
|
|
379
710
|
);
|
|
380
711
|
|
|
381
|
-
//
|
|
382
|
-
expect(state.queryCalls).toHaveLength(
|
|
712
|
+
// All four queries fired with the same limit and distinct `using`.
|
|
713
|
+
expect(state.queryCalls).toHaveLength(4);
|
|
383
714
|
const usings = state.queryCalls.map((c) => c.using).sort();
|
|
384
|
-
expect(usings).toEqual([
|
|
715
|
+
expect(usings).toEqual([
|
|
716
|
+
"dense",
|
|
717
|
+
"sparse",
|
|
718
|
+
"summary_dense",
|
|
719
|
+
"summary_sparse",
|
|
720
|
+
]);
|
|
385
721
|
expect(state.queryCalls.every((c) => c.limit === 5)).toBe(true);
|
|
386
722
|
expect(state.queryCalls.every((c) => c.with_payload === true)).toBe(true);
|
|
387
723
|
|
|
388
|
-
//
|
|
724
|
+
// Alice has hits on all four channels; bob is body-only.
|
|
389
725
|
expect(results).toHaveLength(2);
|
|
390
726
|
const alice = results.find((r) => r.slug === "alice-prefers-vs-code");
|
|
391
727
|
const bob = results.find((r) => r.slug === "bob-uses-zsh");
|
|
@@ -393,6 +729,8 @@ describe("memory v2 qdrant — hybrid query", () => {
|
|
|
393
729
|
slug: "alice-prefers-vs-code",
|
|
394
730
|
denseScore: 0.91,
|
|
395
731
|
sparseScore: 12,
|
|
732
|
+
summaryDenseScore: 0.81,
|
|
733
|
+
summarySparseScore: 9,
|
|
396
734
|
});
|
|
397
735
|
expect(bob).toEqual({
|
|
398
736
|
slug: "bob-uses-zsh",
|
|
@@ -403,6 +741,8 @@ describe("memory v2 qdrant — hybrid query", () => {
|
|
|
403
741
|
|
|
404
742
|
test("dense-only hits leave sparseScore undefined (and vice versa)", async () => {
|
|
405
743
|
state.collectionExistsBeforeCreate = true;
|
|
744
|
+
// Body dense + sparse hits. Summary channels stay empty (no push) →
|
|
745
|
+
// they fall through to `{ points: [] }` and produce no summary scores.
|
|
406
746
|
state.queryResponses.dense.push({
|
|
407
747
|
points: [{ score: 0.7, payload: { slug: "dense-only" } }],
|
|
408
748
|
});
|
|
@@ -420,8 +760,41 @@ describe("memory v2 qdrant — hybrid query", () => {
|
|
|
420
760
|
const sparseOnly = results.find((r) => r.slug === "sparse-only");
|
|
421
761
|
expect(denseOnly).toEqual({ slug: "dense-only", denseScore: 0.7 });
|
|
422
762
|
expect(denseOnly?.sparseScore).toBeUndefined();
|
|
763
|
+
expect(denseOnly?.summaryDenseScore).toBeUndefined();
|
|
423
764
|
expect(sparseOnly).toEqual({ slug: "sparse-only", sparseScore: 2 });
|
|
424
765
|
expect(sparseOnly?.denseScore).toBeUndefined();
|
|
766
|
+
expect(sparseOnly?.summarySparseScore).toBeUndefined();
|
|
767
|
+
});
|
|
768
|
+
|
|
769
|
+
test("returns summary-channel scores when only the summary side hits", async () => {
|
|
770
|
+
// Page has no body hits but matches via the summary embedding —
|
|
771
|
+
// exercises the path where `simBatch` falls back to summary-only.
|
|
772
|
+
state.collectionExistsBeforeCreate = true;
|
|
773
|
+
// Body channels empty.
|
|
774
|
+
state.queryResponses.dense.push({ points: [] });
|
|
775
|
+
state.queryResponses.sparse.push({ points: [] });
|
|
776
|
+
// Summary channels hit.
|
|
777
|
+
state.queryResponses.dense.push({
|
|
778
|
+
points: [{ score: 0.6, payload: { slug: "summary-only" } }],
|
|
779
|
+
});
|
|
780
|
+
state.queryResponses.sparse.push({
|
|
781
|
+
points: [{ score: 4, payload: { slug: "summary-only" } }],
|
|
782
|
+
});
|
|
783
|
+
|
|
784
|
+
const results = await hybridQueryConceptPages(
|
|
785
|
+
[0.1],
|
|
786
|
+
{ indices: [1], values: [1] },
|
|
787
|
+
5,
|
|
788
|
+
);
|
|
789
|
+
|
|
790
|
+
const summaryOnly = results.find((r) => r.slug === "summary-only");
|
|
791
|
+
expect(summaryOnly).toEqual({
|
|
792
|
+
slug: "summary-only",
|
|
793
|
+
summaryDenseScore: 0.6,
|
|
794
|
+
summarySparseScore: 4,
|
|
795
|
+
});
|
|
796
|
+
expect(summaryOnly?.denseScore).toBeUndefined();
|
|
797
|
+
expect(summaryOnly?.sparseScore).toBeUndefined();
|
|
425
798
|
});
|
|
426
799
|
|
|
427
800
|
test("does not use Qdrant-side RRF fusion (separate per-channel queries)", async () => {
|
|
@@ -215,8 +215,8 @@ describe("rerankCandidates", () => {
|
|
|
215
215
|
expect(backendState.calls).toHaveLength(1);
|
|
216
216
|
});
|
|
217
217
|
|
|
218
|
-
test("passage construction caps at
|
|
219
|
-
const longBody = "a".repeat(
|
|
218
|
+
test("passage construction caps at 1500 chars after slug newline", async () => {
|
|
219
|
+
const longBody = "a".repeat(2000);
|
|
220
220
|
pageState.pages.set("slug", { body: longBody });
|
|
221
221
|
backendState.scores = [0.5];
|
|
222
222
|
|
|
@@ -224,9 +224,9 @@ describe("rerankCandidates", () => {
|
|
|
224
224
|
|
|
225
225
|
expect(backendState.calls).toHaveLength(1);
|
|
226
226
|
const passage = backendState.calls[0].passages[0];
|
|
227
|
-
// "slug\n" prefix +
|
|
227
|
+
// "slug\n" prefix + 1500 chars of body
|
|
228
228
|
expect(passage.startsWith("slug\n")).toBe(true);
|
|
229
|
-
expect(passage.length).toBeLessThanOrEqual(5 +
|
|
229
|
+
expect(passage.length).toBeLessThanOrEqual(5 + 1500);
|
|
230
230
|
});
|
|
231
231
|
|
|
232
232
|
test("first paragraph is taken (body truncated at blank line)", async () => {
|