@vellumai/assistant 0.7.2 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +16 -1
- package/docs/architecture/memory.md +5 -2
- package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +13 -4
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -9
- package/node_modules/@vellumai/slack-text/src/index.test.ts +18 -35
- package/node_modules/@vellumai/slack-text/src/index.ts +2 -48
- package/openapi.yaml +449 -22
- package/package.json +1 -1
- package/src/__tests__/app-control-flow.test.ts +21 -11
- package/src/__tests__/assistant-event-hub.test.ts +48 -0
- package/src/__tests__/assistant-event.test.ts +0 -10
- package/src/__tests__/assistant-events-sse-hardening.test.ts +2 -7
- package/src/__tests__/assistant-feature-flags-integration.test.ts +18 -0
- package/src/__tests__/auto-analysis-end-to-end.test.ts +62 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +268 -0
- package/src/__tests__/call-conversation-messages.test.ts +8 -2
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +537 -0
- package/src/__tests__/channel-readiness-service.test.ts +4 -2
- package/src/__tests__/config-loader-backfill.test.ts +379 -0
- package/src/__tests__/config-schema.test.ts +1 -0
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +18 -9
- package/src/__tests__/config-watcher.test.ts +140 -69
- package/src/__tests__/context-search-agent-runner.test.ts +61 -3
- package/src/__tests__/context-search-conversations-source.test.ts +0 -24
- package/src/__tests__/context-search-fanout.test.ts +0 -1
- package/src/__tests__/context-search-memory-source.test.ts +3 -7
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -2
- package/src/__tests__/context-search-pkb-source.test.ts +0 -1
- package/src/__tests__/context-search-workspace-source.test.ts +0 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +223 -0
- package/src/__tests__/conversation-agent-loop.test.ts +454 -5
- package/src/__tests__/conversation-error.test.ts +150 -3
- package/src/__tests__/conversation-process-callsite.test.ts +43 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +65 -0
- package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
- package/src/__tests__/conversation-speed-override.test.ts +0 -3
- package/src/__tests__/conversation-store.test.ts +0 -18
- package/src/__tests__/conversation-surfaces-app-control.test.ts +15 -4
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +404 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +2 -5
- package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
- package/src/__tests__/credentials-cli.test.ts +7 -0
- package/src/__tests__/cu-unified-flow.test.ts +176 -10
- package/src/__tests__/date-context.test.ts +164 -2
- package/src/__tests__/disk-pressure-guard.test.ts +262 -0
- package/src/__tests__/disk-pressure-lifecycle.test.ts +168 -0
- package/src/__tests__/disk-pressure-policy.test.ts +241 -0
- package/src/__tests__/disk-pressure-routes.test.ts +379 -0
- package/src/__tests__/disk-pressure-tools.test.ts +277 -0
- package/src/__tests__/disk-usage.test.ts +150 -0
- package/src/__tests__/events-client-registration.test.ts +52 -0
- package/src/__tests__/events-dev-bypass-actor.test.ts +162 -0
- package/src/__tests__/file-write-tool.test.ts +4 -10
- package/src/__tests__/filing-service.test.ts +3 -4
- package/src/__tests__/heartbeat-disk-pressure.test.ts +183 -0
- package/src/__tests__/heartbeat-service.test.ts +260 -11
- package/src/__tests__/host-app-control-proxy.test.ts +195 -25
- package/src/__tests__/host-bash-proxy.test.ts +227 -34
- package/src/__tests__/host-bash-routes.test.ts +178 -13
- package/src/__tests__/host-cu-proxy.test.ts +210 -3
- package/src/__tests__/host-cu-routes-targeted.test.ts +141 -12
- package/src/__tests__/host-file-proxy-targeted.test.ts +48 -9
- package/src/__tests__/host-file-proxy.test.ts +268 -6
- package/src/__tests__/host-file-routes-targeted.test.ts +175 -17
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +408 -59
- package/src/__tests__/host-transfer-routes-targeted.test.ts +232 -17
- package/src/__tests__/http-user-message-parity.test.ts +107 -1
- package/src/__tests__/injector-chain.test.ts +18 -6
- package/src/__tests__/injector-disk-pressure.test.ts +224 -0
- package/src/__tests__/managed-profile-guard.test.ts +18 -0
- package/src/__tests__/mcp-abort-signal.test.ts +130 -0
- package/src/__tests__/memory-admin-recall.test.ts +3 -11
- package/src/__tests__/memory-retrieval-pipeline.test.ts +22 -1
- package/src/__tests__/normalize-onboarding.test.ts +180 -0
- package/src/__tests__/oauth-connect-routes.test.ts +316 -0
- package/src/__tests__/oauth-provider-seed-logos.test.ts +24 -2
- package/src/__tests__/onboarding-persona-write.test.ts +308 -0
- package/src/__tests__/openai-provider.test.ts +45 -8
- package/src/__tests__/persist-onboarding-artifacts.test.ts +44 -64
- package/src/__tests__/platform-callback-registration.test.ts +21 -4
- package/src/__tests__/platform.test.ts +2 -1
- package/src/__tests__/playbook-execution.test.ts +0 -43
- package/src/__tests__/plugin-tool-contribution.test.ts +47 -0
- package/src/__tests__/prechat-onboarding-contract.test.ts +214 -27
- package/src/__tests__/provider-tool-name.test.ts +23 -0
- package/src/__tests__/relay-server.test.ts +15 -4
- package/src/__tests__/runtime-events-sse.test.ts +4 -8
- package/src/__tests__/scheduler-disk-pressure.test.ts +148 -0
- package/src/__tests__/secret-ingress-http.test.ts +0 -1
- package/src/__tests__/suggestion-routes.test.ts +46 -0
- package/src/__tests__/twilio-validation.test.ts +2 -2
- package/src/__tests__/workspace-migration-065-bump-stale-heartbeat-interval.test.ts +122 -0
- package/src/__tests__/workspace-migration-066-seed-heartbeat-callsite-cost-default.test.ts +285 -0
- package/src/__tests__/workspace-migration-068-release-notes-local-timezone.test.ts +90 -0
- package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +90 -0
- package/src/approvals/guardian-decision-primitive.ts +13 -0
- package/src/approvals/guardian-request-resolvers.ts +16 -17
- package/src/backup/snapshot-lock.ts +2 -27
- package/src/bundler/compiler-tools.ts +3 -2
- package/src/calls/call-conversation-messages.ts +46 -10
- package/src/cli/commands/__tests__/webhooks.test.ts +0 -4
- package/src/cli/commands/bash.ts +35 -108
- package/src/cli/commands/contacts.ts +64 -25
- package/src/cli/commands/credentials.ts +56 -0
- package/src/cli/commands/memory-v2.ts +7 -6
- package/src/cli/commands/oauth/__tests__/connect.test.ts +437 -1
- package/src/cli/commands/oauth/connect.ts +127 -1
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -3
- package/src/cli/commands/platform/__tests__/connect.test.ts +7 -1
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +103 -6
- package/src/cli/commands/platform/index.ts +16 -7
- package/src/cli/commands/status.ts +57 -0
- package/src/cli/program.ts +4 -2
- package/src/config/assistant-feature-flags.ts +13 -3
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -3
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +13 -7
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -2
- package/src/config/env.ts +0 -8
- package/src/config/feature-flag-registry.json +27 -3
- package/src/config/loader.ts +127 -8
- package/src/config/schemas/__tests__/memory-v2.test.ts +10 -5
- package/src/config/schemas/call-site-catalog.ts +14 -0
- package/src/config/schemas/channels.ts +0 -5
- package/src/config/schemas/heartbeat.ts +1 -1
- package/src/config/schemas/llm.ts +2 -0
- package/src/config/schemas/memory-lifecycle.ts +13 -0
- package/src/config/schemas/memory-v2.ts +75 -11
- package/src/config/schemas/platform.ts +43 -3
- package/src/config/schemas/services.ts +28 -0
- package/src/config/seed-inference-profiles.ts +230 -33
- package/src/contacts/contact-store.ts +0 -25
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +86 -25
- package/src/daemon/assistant-attachments.ts +4 -4
- package/src/daemon/config-watcher.ts +85 -57
- package/src/daemon/conversation-agent-loop-handlers.ts +6 -0
- package/src/daemon/conversation-agent-loop.ts +170 -33
- package/src/daemon/conversation-error.ts +87 -15
- package/src/daemon/conversation-lifecycle.ts +1 -3
- package/src/daemon/conversation-process.ts +8 -0
- package/src/daemon/conversation-runtime-assembly.ts +26 -0
- package/src/daemon/conversation-store.ts +2 -2
- package/src/daemon/conversation-surfaces.ts +195 -15
- package/src/daemon/conversation-tool-setup.ts +57 -14
- package/src/daemon/conversation.ts +17 -22
- package/src/daemon/date-context.ts +71 -22
- package/src/daemon/disk-pressure-background-gate.ts +73 -0
- package/src/daemon/disk-pressure-guard.ts +343 -0
- package/src/daemon/disk-pressure-policy.ts +163 -0
- package/src/daemon/handlers/shared.ts +0 -1
- package/src/daemon/handlers/skills.ts +3 -4
- package/src/daemon/host-app-control-proxy.ts +137 -41
- package/src/daemon/host-bash-proxy.ts +46 -21
- package/src/daemon/host-cu-proxy.ts +49 -3
- package/src/daemon/host-file-proxy.ts +43 -7
- package/src/daemon/host-transfer-proxy.ts +95 -4
- package/src/daemon/lifecycle.ts +79 -28
- package/src/daemon/meet-host-supervisor.ts +4 -4
- package/src/daemon/meet-manifest-loader.ts +0 -1
- package/src/daemon/memory-v2-startup.ts +14 -4
- package/src/daemon/message-protocol.ts +3 -0
- package/src/daemon/message-types/conversations.ts +4 -0
- package/src/daemon/message-types/disk-pressure.ts +9 -0
- package/src/daemon/message-types/messages.ts +3 -0
- package/src/daemon/profiler-run-store.ts +5 -5
- package/src/daemon/tool-setup-types.ts +2 -2
- package/src/documents/document-store.ts +85 -0
- package/src/filing/filing-service.ts +30 -5
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +9 -16
- package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +36 -0
- package/src/heartbeat/heartbeat-run-store.ts +13 -0
- package/src/heartbeat/heartbeat-service.ts +205 -31
- package/src/home/feed-scheduler.ts +18 -0
- package/src/inbound/platform-callback-registration.ts +8 -15
- package/src/ipc/__tests__/clients-list-ipc.test.ts +169 -0
- package/src/ipc/assistant-server.ts +56 -2
- package/src/ipc/gateway-client.ts +37 -3
- package/src/live-voice/live-voice-archive.ts +4 -4
- package/src/live-voice/protocol.ts +5 -7
- package/src/media/image-service.ts +1 -7
- package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +21 -13
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +52 -22
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +0 -6
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +272 -0
- package/src/memory/admin.ts +5 -9
- package/src/memory/context-search/agent-runner.ts +19 -2
- package/src/memory/context-search/sources/conversations.ts +2 -11
- package/src/memory/context-search/sources/memory-v2.ts +5 -4
- package/src/memory/context-search/sources/memory.ts +0 -1
- package/src/memory/context-search/types.ts +0 -1
- package/src/memory/conversation-crud.ts +4 -12
- package/src/memory/db-init.ts +2 -0
- package/src/memory/embedding-runtime-manager.ts +119 -5
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +32 -21
- package/src/memory/graph/conversation-graph-memory.ts +42 -54
- package/src/memory/graph/extraction.ts +1 -3
- package/src/memory/graph/graph-search.test.ts +10 -67
- package/src/memory/graph/graph-search.ts +1 -20
- package/src/memory/graph/retriever.test.ts +6 -0
- package/src/memory/graph/retriever.ts +6 -10
- package/src/memory/indexer.ts +54 -45
- package/src/memory/job-handlers/backfill.ts +2 -11
- package/src/memory/job-handlers/cleanup.ts +43 -0
- package/src/memory/job-handlers/embedding.ts +6 -8
- package/src/memory/job-handlers/summarization.ts +2 -7
- package/src/memory/jobs-store.ts +48 -0
- package/src/memory/jobs-worker.ts +81 -43
- package/src/memory/memory-v2-activation-log-store.ts +32 -14
- package/src/memory/memory-v2-concept-frequency.ts +169 -0
- package/src/memory/migrations/239-trace-events-created-at-index.ts +18 -0
- package/src/memory/migrations/index.ts +1 -0
- package/src/memory/pkb/pkb-search.test.ts +6 -0
- package/src/memory/qdrant-client.ts +0 -13
- package/src/memory/rerank-local.ts +374 -0
- package/src/memory/search/semantic.ts +6 -67
- package/src/memory/trace-event-store.ts +1 -17
- package/src/memory/v2/__tests__/activation.test.ts +311 -250
- package/src/memory/v2/__tests__/consolidation-job.test.ts +40 -8
- package/src/memory/v2/__tests__/injection.test.ts +157 -167
- package/src/memory/v2/__tests__/prompts-consolidation.test.ts +61 -2
- package/src/memory/v2/__tests__/qdrant.test.ts +16 -0
- package/src/memory/v2/__tests__/reranker.test.ts +338 -0
- package/src/memory/v2/__tests__/sim.test.ts +5 -199
- package/src/memory/v2/__tests__/skill-store.test.ts +71 -65
- package/src/memory/v2/__tests__/static-context.test.ts +76 -1
- package/src/memory/v2/activation.ts +149 -156
- package/src/memory/v2/consolidation-job.ts +62 -12
- package/src/memory/v2/injection.ts +47 -60
- package/src/memory/v2/prompts/consolidation.ts +36 -1
- package/src/memory/v2/qdrant.ts +99 -0
- package/src/memory/v2/reranker.ts +177 -0
- package/src/memory/v2/sim.ts +10 -84
- package/src/memory/v2/skill-content.ts +4 -3
- package/src/memory/v2/skill-store.ts +82 -59
- package/src/memory/v2/static-context.ts +22 -0
- package/src/memory/v2/types.ts +10 -10
- package/src/notifications/copy-composer.ts +13 -0
- package/src/notifications/signal.ts +4 -0
- package/src/oauth/AGENTS.md +3 -1
- package/src/oauth/__tests__/oauth-connect-state.test.ts +137 -0
- package/src/oauth/connect-orchestrator.ts +2 -0
- package/src/oauth/connection-resolver.test.ts +66 -1
- package/src/oauth/connection-resolver.ts +55 -1
- package/src/oauth/oauth-connect-state.ts +77 -0
- package/src/oauth/seed-providers.ts +58 -1
- package/src/plugins/defaults/injectors.ts +35 -2
- package/src/plugins/defaults/memory-retrieval.ts +5 -6
- package/src/plugins/types.ts +7 -0
- package/src/proactive-artifact/aux-message-injector.ts +74 -0
- package/src/proactive-artifact/decision.test.ts +226 -0
- package/src/proactive-artifact/decision.ts +165 -0
- package/src/proactive-artifact/index.ts +7 -0
- package/src/proactive-artifact/job.test.ts +867 -0
- package/src/proactive-artifact/job.ts +352 -0
- package/src/proactive-artifact/message-copy.ts +41 -0
- package/src/proactive-artifact/trigger-state.test.ts +277 -0
- package/src/proactive-artifact/trigger-state.ts +119 -0
- package/src/prompts/normalize-onboarding.ts +80 -0
- package/src/prompts/persona-resolver.ts +101 -9
- package/src/prompts/system-prompt.ts +21 -7
- package/src/prompts/templates/BOOTSTRAP.md +13 -5
- package/src/providers/__tests__/retry-callsite.test.ts +222 -1
- package/src/providers/model-intents.ts +7 -0
- package/src/providers/openrouter/client.ts +8 -0
- package/src/providers/retry.ts +50 -0
- package/src/providers/types.ts +1 -0
- package/src/runtime/__tests__/agent-wake.test.ts +456 -3
- package/src/runtime/agent-wake.ts +238 -100
- package/src/runtime/assistant-event-hub.ts +36 -6
- package/src/runtime/assistant-event.ts +0 -1
- package/src/runtime/auth/__tests__/route-policy.test.ts +64 -0
- package/src/runtime/auth/route-policy.ts +14 -1
- package/src/runtime/auth/same-actor.ts +216 -0
- package/src/runtime/channel-retry-sweep.ts +65 -1
- package/src/runtime/guardian-reply-router.ts +10 -0
- package/src/runtime/local-actor-identity.ts +52 -11
- package/src/runtime/pending-interactions.ts +8 -0
- package/src/runtime/routes/__tests__/client-routes.test.ts +155 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +0 -5
- package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
- package/src/runtime/routes/client-routes.ts +20 -2
- package/src/runtime/routes/contact-routes.ts +0 -25
- package/src/runtime/routes/conversation-routes.ts +35 -26
- package/src/runtime/routes/debug-bash-routes.ts +163 -0
- package/src/runtime/routes/disk-pressure-routes.ts +121 -0
- package/src/runtime/routes/document-pdf-renderer.ts +6 -2
- package/src/runtime/routes/documents-routes.ts +2 -75
- package/src/runtime/routes/events-routes.ts +41 -9
- package/src/runtime/routes/host-bash-routes.ts +23 -3
- package/src/runtime/routes/host-cu-routes.ts +33 -6
- package/src/runtime/routes/host-file-routes.ts +32 -6
- package/src/runtime/routes/host-transfer-routes.ts +79 -16
- package/src/runtime/routes/identity-routes.ts +7 -138
- package/src/runtime/routes/inbound-message-handler.ts +77 -12
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -0
- package/src/runtime/routes/index.ts +6 -0
- package/src/runtime/routes/memory-item-routes.test.ts +41 -15
- package/src/runtime/routes/memory-v2-routes.ts +33 -0
- package/src/runtime/routes/oauth-connect-routes.ts +153 -0
- package/src/runtime/verification-outbound-actions.ts +4 -4
- package/src/schedule/run-script.ts +37 -5
- package/src/schedule/scheduler.ts +20 -1
- package/src/security/encrypted-store.ts +2 -0
- package/src/security/secure-keys.ts +55 -0
- package/src/skills/remote-skill-policy.ts +4 -10
- package/src/subagent/index.ts +1 -7
- package/src/subagent/manager.ts +1 -15
- package/src/tasks/task-runner.ts +0 -1
- package/src/tasks/task-store.ts +0 -3
- package/src/tools/background-tool-registry.ts +17 -3
- package/src/tools/host-filesystem/edit.test.ts +151 -0
- package/src/tools/host-filesystem/edit.ts +43 -1
- package/src/tools/host-filesystem/read.test.ts +129 -0
- package/src/tools/host-filesystem/read.ts +43 -1
- package/src/tools/host-filesystem/transfer.test.ts +127 -2
- package/src/tools/host-filesystem/transfer.ts +56 -11
- package/src/tools/host-filesystem/write.test.ts +134 -0
- package/src/tools/host-filesystem/write.ts +43 -1
- package/src/tools/host-terminal/host-shell.ts +13 -6
- package/src/tools/mcp/mcp-tool-factory.ts +2 -1
- package/src/tools/memory/register.test.ts +12 -9
- package/src/tools/memory/register.ts +1 -2
- package/src/tools/provider-tool-name.ts +28 -0
- package/src/tools/registry.ts +30 -9
- package/src/tools/terminal/shell.ts +9 -1
- package/src/tools/tool-approval-handler.ts +31 -6
- package/src/tools/types.ts +24 -2
- package/src/tts/provider-catalog.ts +3 -5
- package/src/util/disk-usage.ts +138 -0
- package/src/util/platform.ts +21 -11
- package/src/util/process-liveness.ts +26 -0
- package/src/workspace/heartbeat-service.ts +19 -0
- package/src/workspace/migrations/065-bump-stale-heartbeat-interval.ts +60 -0
- package/src/workspace/migrations/066-seed-heartbeat-callsite-cost-default.ts +146 -0
- package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +72 -0
- package/src/workspace/migrations/068-release-notes-local-timezone.ts +65 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +0 -167
- package/src/memory/v2/__tests__/skill-qdrant.test.ts +0 -657
- package/src/memory/v2/skill-qdrant.ts +0 -404
- package/src/signals/bash.ts +0 -198
|
@@ -351,7 +351,7 @@ async function dedupCrossCategory(
|
|
|
351
351
|
// Context load — conversation start
|
|
352
352
|
// ---------------------------------------------------------------------------
|
|
353
353
|
|
|
354
|
-
|
|
354
|
+
interface ContextLoadOpts {
|
|
355
355
|
/** Scope for memory isolation. */
|
|
356
356
|
scopeId: string;
|
|
357
357
|
/** Recent conversation summaries (used as retrieval queries). */
|
|
@@ -373,7 +373,7 @@ export interface ContextLoadOpts {
|
|
|
373
373
|
userQuery?: string;
|
|
374
374
|
}
|
|
375
375
|
|
|
376
|
-
|
|
376
|
+
interface ContextLoadResult {
|
|
377
377
|
nodes: ScoredNode[];
|
|
378
378
|
serendipityNodes: ScoredNode[];
|
|
379
379
|
triggeredNodes: TriggeredResult[];
|
|
@@ -525,7 +525,6 @@ export async function loadContextMemory(
|
|
|
525
525
|
const results = await searchGraphNodes(
|
|
526
526
|
queryVector,
|
|
527
527
|
maxNodes * 3,
|
|
528
|
-
[opts.scopeId],
|
|
529
528
|
sparseVector,
|
|
530
529
|
);
|
|
531
530
|
for (const r of results) {
|
|
@@ -548,7 +547,6 @@ export async function loadContextMemory(
|
|
|
548
547
|
const results = await searchGraphNodes(
|
|
549
548
|
userQueryVector,
|
|
550
549
|
maxNodes * 3,
|
|
551
|
-
[opts.scopeId],
|
|
552
550
|
undefined,
|
|
553
551
|
);
|
|
554
552
|
for (const r of results) {
|
|
@@ -873,7 +871,7 @@ export async function loadContextMemory(
|
|
|
873
871
|
// Per-turn retrieval — mid-conversation injection
|
|
874
872
|
// ---------------------------------------------------------------------------
|
|
875
873
|
|
|
876
|
-
|
|
874
|
+
interface TurnRetrievalOpts {
|
|
877
875
|
/** The assistant's last message content. */
|
|
878
876
|
assistantLastMessage: string;
|
|
879
877
|
/** The user's last message content. */
|
|
@@ -886,7 +884,7 @@ export interface TurnRetrievalOpts {
|
|
|
886
884
|
signal?: AbortSignal;
|
|
887
885
|
}
|
|
888
886
|
|
|
889
|
-
|
|
887
|
+
interface TurnRetrievalResult {
|
|
890
888
|
/** New nodes to inject (not already in context). */
|
|
891
889
|
nodes: ScoredNode[];
|
|
892
890
|
/** Serendipity picks included in nodes. */
|
|
@@ -1007,9 +1005,7 @@ export async function retrieveForTurn(
|
|
|
1007
1005
|
}
|
|
1008
1006
|
const imgVector = imgResult.vectors[0];
|
|
1009
1007
|
if (imgVector) {
|
|
1010
|
-
const imgResults = await searchGraphNodes(imgVector, 40
|
|
1011
|
-
opts.scopeId,
|
|
1012
|
-
]);
|
|
1008
|
+
const imgResults = await searchGraphNodes(imgVector, 40);
|
|
1013
1009
|
for (const r of imgResults) {
|
|
1014
1010
|
const current = allCandidateIds.get(r.nodeId) ?? 0;
|
|
1015
1011
|
allCandidateIds.set(r.nodeId, Math.max(current, r.score));
|
|
@@ -1097,7 +1093,7 @@ export async function retrieveForTurn(
|
|
|
1097
1093
|
queryEmbeddings = embedResults.vectors;
|
|
1098
1094
|
|
|
1099
1095
|
const searchPromises = queryEmbeddings.map((vec) =>
|
|
1100
|
-
searchGraphNodes(vec, 40
|
|
1096
|
+
searchGraphNodes(vec, 40),
|
|
1101
1097
|
);
|
|
1102
1098
|
const searchResults = await Promise.all(searchPromises);
|
|
1103
1099
|
|
package/src/memory/indexer.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { getLogger } from "../util/logger.js";
|
|
|
9
9
|
import { enqueueAutoAnalysisIfEnabled } from "./auto-analysis-enqueue.js";
|
|
10
10
|
import { isAutoAnalysisConversation } from "./auto-analysis-guard.js";
|
|
11
11
|
import { getMemoryCheckpoint, setMemoryCheckpoint } from "./checkpoints.js";
|
|
12
|
+
import { isMemoryV2ReadActive } from "./context-search/sources/memory-v2.js";
|
|
12
13
|
import { getDb } from "./db-connection.js";
|
|
13
14
|
import { selectedBackendSupportsMultimodal } from "./embedding-backend.js";
|
|
14
15
|
import { enqueueMemoryJob, upsertDebouncedJob } from "./jobs-store.js";
|
|
@@ -175,39 +176,9 @@ export async function indexMessageNow(
|
|
|
175
176
|
// Summaries still run — they feed the graph retrieval pipeline and
|
|
176
177
|
// are not recursion-prone.
|
|
177
178
|
if (!isAutoAnalysisSource) {
|
|
178
|
-
//
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const graphPendingCount =
|
|
182
|
-
(graphCurrentVal ? parseInt(graphCurrentVal, 10) : 0) + 1;
|
|
183
|
-
setMemoryCheckpoint(graphPendingKey, String(graphPendingCount));
|
|
184
|
-
|
|
185
|
-
const graphBatchFired = graphPendingCount >= batchSize;
|
|
186
|
-
if (graphBatchFired) {
|
|
187
|
-
setMemoryCheckpoint(graphPendingKey, "0");
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Single pending `graph_extract` row per conversation. If the
|
|
191
|
-
// batch threshold just fired, pull `runAfter` back to now so the
|
|
192
|
-
// job runs immediately; otherwise debounce by the idle timeout.
|
|
193
|
-
// Routing both paths through `upsertDebouncedJob` ensures the
|
|
194
|
-
// row's `runAfter` reflects whichever trigger ran last, so a
|
|
195
|
-
// batch crossing always takes effect immediately.
|
|
196
|
-
const extractRunAfter = graphBatchFired
|
|
197
|
-
? Date.now()
|
|
198
|
-
: Date.now() + idleTimeoutMs;
|
|
199
|
-
upsertDebouncedJob(
|
|
200
|
-
"graph_extract",
|
|
201
|
-
{
|
|
202
|
-
conversationId: input.conversationId,
|
|
203
|
-
scopeId: input.scopeId ?? "default",
|
|
204
|
-
},
|
|
205
|
-
extractRunAfter,
|
|
206
|
-
);
|
|
207
|
-
|
|
208
|
-
// Reading config here is best-effort: feature-gated triggers below
|
|
209
|
-
// (memory v2 sweep, auto-analyze batch) skip when it fails — the
|
|
210
|
-
// idle-debounced enqueues above are unaffected.
|
|
179
|
+
// Reading config here is best-effort: when it fails we treat v2 as
|
|
180
|
+
// inactive (failing-open to v1) so a config error never silently
|
|
181
|
+
// drops both extraction paths.
|
|
211
182
|
let triggerConfig: ReturnType<typeof getConfig> | null = null;
|
|
212
183
|
try {
|
|
213
184
|
triggerConfig = getConfig();
|
|
@@ -218,20 +189,58 @@ export async function indexMessageNow(
|
|
|
218
189
|
);
|
|
219
190
|
}
|
|
220
191
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
//
|
|
192
|
+
const v2Config =
|
|
193
|
+
triggerConfig != null && isMemoryV2ReadActive(triggerConfig)
|
|
194
|
+
? triggerConfig
|
|
195
|
+
: null;
|
|
196
|
+
|
|
197
|
+
// ── Graph extraction (v1) ───────────────────────────────────────
|
|
198
|
+
// Suppressed when v2 is active — v2 reads memory from buffer.md
|
|
199
|
+
// and concept pages, so the v1 graph would be stale data nobody
|
|
200
|
+
// consumes. Pending-count tracking is suppressed too; otherwise a
|
|
201
|
+
// flag flip back to v1 would fire an immediate batch from counts
|
|
202
|
+
// accumulated during the v2 window.
|
|
203
|
+
let extractRunAfter: number;
|
|
204
|
+
if (v2Config == null) {
|
|
205
|
+
const graphPendingKey = `graph_extract:${input.conversationId}:pending_count`;
|
|
206
|
+
const graphCurrentVal = getMemoryCheckpoint(graphPendingKey);
|
|
207
|
+
const graphPendingCount =
|
|
208
|
+
(graphCurrentVal ? parseInt(graphCurrentVal, 10) : 0) + 1;
|
|
209
|
+
setMemoryCheckpoint(graphPendingKey, String(graphPendingCount));
|
|
210
|
+
|
|
211
|
+
const graphBatchFired = graphPendingCount >= batchSize;
|
|
212
|
+
if (graphBatchFired) {
|
|
213
|
+
setMemoryCheckpoint(graphPendingKey, "0");
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Single pending `graph_extract` row per conversation. If the
|
|
217
|
+
// batch threshold just fired, pull `runAfter` back to now so the
|
|
218
|
+
// job runs immediately; otherwise debounce by the idle timeout.
|
|
219
|
+
// Routing both paths through `upsertDebouncedJob` ensures the
|
|
220
|
+
// row's `runAfter` reflects whichever trigger ran last, so a
|
|
221
|
+
// batch crossing always takes effect immediately.
|
|
222
|
+
extractRunAfter = graphBatchFired
|
|
223
|
+
? Date.now()
|
|
224
|
+
: Date.now() + idleTimeoutMs;
|
|
225
|
+
upsertDebouncedJob(
|
|
226
|
+
"graph_extract",
|
|
227
|
+
{
|
|
228
|
+
conversationId: input.conversationId,
|
|
229
|
+
scopeId: input.scopeId ?? "default",
|
|
230
|
+
},
|
|
231
|
+
extractRunAfter,
|
|
232
|
+
);
|
|
233
|
+
} else {
|
|
234
|
+
extractRunAfter = Date.now() + idleTimeoutMs;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Memory v2 sweep: when v2 is on AND `sweep_enabled` is set, every
|
|
238
|
+
// extraction trigger also enqueues a sweep. The sweep itself reads
|
|
239
|
+
// recent messages globally, so the `conversationId` here is just
|
|
240
|
+
// the dedup key — one pending row per active conversation.
|
|
227
241
|
// `sweep_enabled` defaults to false because `remember()` is the
|
|
228
242
|
// primary capture path; the sweep is opt-in.
|
|
229
|
-
if (
|
|
230
|
-
triggerConfig != null &&
|
|
231
|
-
isAssistantFeatureFlagEnabled("memory-v2-enabled", triggerConfig) &&
|
|
232
|
-
triggerConfig.memory.v2.enabled &&
|
|
233
|
-
triggerConfig.memory.v2.sweep_enabled
|
|
234
|
-
) {
|
|
243
|
+
if (v2Config != null && v2Config.memory.v2.sweep_enabled) {
|
|
235
244
|
upsertDebouncedJob(
|
|
236
245
|
"memory_v2_sweep",
|
|
237
246
|
{ conversationId: input.conversationId },
|
|
@@ -7,10 +7,7 @@ import {
|
|
|
7
7
|
resetMessageCursorCheckpoint,
|
|
8
8
|
writeMessageCursorCheckpoint,
|
|
9
9
|
} from "../checkpoints.js";
|
|
10
|
-
import {
|
|
11
|
-
getConversationMemoryScopeId,
|
|
12
|
-
messageMetadataSchema,
|
|
13
|
-
} from "../conversation-crud.js";
|
|
10
|
+
import { messageMetadataSchema } from "../conversation-crud.js";
|
|
14
11
|
import { getDb } from "../db-connection.js";
|
|
15
12
|
import { indexMessageNow } from "../indexer.js";
|
|
16
13
|
import { enqueueMemoryJob, type MemoryJob } from "../jobs-store.js";
|
|
@@ -72,13 +69,7 @@ export async function backfillJob(
|
|
|
72
69
|
.all();
|
|
73
70
|
|
|
74
71
|
if (batch.length > 0) {
|
|
75
|
-
const scopeCache = new Map<string, string>();
|
|
76
72
|
for (const message of batch) {
|
|
77
|
-
let scopeId = scopeCache.get(message.conversationId);
|
|
78
|
-
if (scopeId === undefined) {
|
|
79
|
-
scopeId = getConversationMemoryScopeId(message.conversationId);
|
|
80
|
-
scopeCache.set(message.conversationId, scopeId);
|
|
81
|
-
}
|
|
82
73
|
const { provenanceTrustClass, automated } = parseMessageMetadata(
|
|
83
74
|
message.metadata ?? null,
|
|
84
75
|
);
|
|
@@ -89,7 +80,7 @@ export async function backfillJob(
|
|
|
89
80
|
role: message.role,
|
|
90
81
|
content: message.content,
|
|
91
82
|
createdAt: message.createdAt,
|
|
92
|
-
scopeId,
|
|
83
|
+
scopeId: "default",
|
|
93
84
|
provenanceTrustClass,
|
|
94
85
|
automated,
|
|
95
86
|
},
|
|
@@ -54,6 +54,49 @@ export function pruneOldLlmRequestLogsJob(
|
|
|
54
54
|
);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Delete trace events older than the configured retention period.
|
|
59
|
+
* Processes in batches to avoid long DB locks and excessive WAL growth.
|
|
60
|
+
* Re-enqueues itself if more rows remain.
|
|
61
|
+
*/
|
|
62
|
+
export function pruneOldTraceEventsJob(
|
|
63
|
+
job: MemoryJob,
|
|
64
|
+
config: AssistantConfig,
|
|
65
|
+
): void {
|
|
66
|
+
const rawRetention = job.payload.retentionDays;
|
|
67
|
+
const retentionDays =
|
|
68
|
+
typeof rawRetention === "number" &&
|
|
69
|
+
Number.isFinite(rawRetention) &&
|
|
70
|
+
rawRetention >= 0
|
|
71
|
+
? rawRetention
|
|
72
|
+
: config.memory.cleanup.traceEventRetentionDays;
|
|
73
|
+
|
|
74
|
+
// 0 means disabled
|
|
75
|
+
if (retentionDays === 0) return;
|
|
76
|
+
|
|
77
|
+
const cutoffMs = Date.now() - retentionDays * 86_400_000;
|
|
78
|
+
|
|
79
|
+
rawRun(
|
|
80
|
+
`DELETE FROM trace_events WHERE rowid IN (SELECT rowid FROM trace_events WHERE created_at < ? LIMIT ?)`,
|
|
81
|
+
cutoffMs,
|
|
82
|
+
PRUNE_LOG_BATCH_LIMIT,
|
|
83
|
+
);
|
|
84
|
+
const deleted = rawChanges();
|
|
85
|
+
|
|
86
|
+
if (deleted >= PRUNE_LOG_BATCH_LIMIT) {
|
|
87
|
+
enqueueMemoryJob("prune_old_trace_events", { retentionDays });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
log.info(
|
|
91
|
+
{
|
|
92
|
+
deleted,
|
|
93
|
+
retentionDays,
|
|
94
|
+
cutoffMs,
|
|
95
|
+
},
|
|
96
|
+
"Pruned old trace events",
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
57
100
|
/**
|
|
58
101
|
* Delete conversations that have had no activity (updatedAt) for longer than
|
|
59
102
|
* the configured retention period. Processes in batches so a single job doesn't
|
|
@@ -3,7 +3,6 @@ import { readFile } from "node:fs/promises";
|
|
|
3
3
|
import { eq } from "drizzle-orm";
|
|
4
4
|
|
|
5
5
|
import type { AssistantConfig } from "../../config/types.js";
|
|
6
|
-
import { getConversationMemoryScopeId } from "../conversation-crud.js";
|
|
7
6
|
import { getDb } from "../db-connection.js";
|
|
8
7
|
import type { EmbeddingInput } from "../embedding-types.js";
|
|
9
8
|
import { asString, embedAndUpsert } from "../job-utils.js";
|
|
@@ -18,7 +17,7 @@ import {
|
|
|
18
17
|
|
|
19
18
|
export async function embedSegmentJob(
|
|
20
19
|
job: MemoryJob,
|
|
21
|
-
config: AssistantConfig
|
|
20
|
+
config: AssistantConfig,
|
|
22
21
|
): Promise<void> {
|
|
23
22
|
const segmentId = asString(job.payload.segmentId);
|
|
24
23
|
if (!segmentId) return;
|
|
@@ -39,7 +38,7 @@ export async function embedSegmentJob(
|
|
|
39
38
|
|
|
40
39
|
export async function embedSummaryJob(
|
|
41
40
|
job: MemoryJob,
|
|
42
|
-
config: AssistantConfig
|
|
41
|
+
config: AssistantConfig,
|
|
43
42
|
): Promise<void> {
|
|
44
43
|
const summaryId = asString(job.payload.summaryId);
|
|
45
44
|
if (!summaryId) return;
|
|
@@ -60,13 +59,13 @@ export async function embedSummaryJob(
|
|
|
60
59
|
created_at: summary.startAt,
|
|
61
60
|
last_seen_at: summary.endAt,
|
|
62
61
|
memory_scope_id: summary.scopeId,
|
|
63
|
-
}
|
|
62
|
+
},
|
|
64
63
|
);
|
|
65
64
|
}
|
|
66
65
|
|
|
67
66
|
export async function embedMediaJob(
|
|
68
67
|
job: MemoryJob,
|
|
69
|
-
config: AssistantConfig
|
|
68
|
+
config: AssistantConfig,
|
|
70
69
|
): Promise<void> {
|
|
71
70
|
const assetId = asString(job.payload.assetId);
|
|
72
71
|
if (!assetId) return;
|
|
@@ -99,7 +98,7 @@ export async function embedMediaJob(
|
|
|
99
98
|
|
|
100
99
|
export async function embedAttachmentJob(
|
|
101
100
|
job: MemoryJob,
|
|
102
|
-
config: AssistantConfig
|
|
101
|
+
config: AssistantConfig,
|
|
103
102
|
): Promise<void> {
|
|
104
103
|
const messageId = asString(job.payload.messageId);
|
|
105
104
|
const blockIndex = job.payload.blockIndex as number;
|
|
@@ -125,11 +124,10 @@ export async function embedAttachmentJob(
|
|
|
125
124
|
|
|
126
125
|
// Use messageId + blockIndex as targetId for uniqueness
|
|
127
126
|
const targetId = `${messageId}:${blockIndex}`;
|
|
128
|
-
const memoryScopeId = getConversationMemoryScopeId(message.conversationId);
|
|
129
127
|
await embedAndUpsert(config, "media", targetId, input, {
|
|
130
128
|
created_at: message.createdAt,
|
|
131
129
|
message_id: messageId,
|
|
132
130
|
conversation_id: message.conversationId,
|
|
133
|
-
memory_scope_id:
|
|
131
|
+
memory_scope_id: "default",
|
|
134
132
|
});
|
|
135
133
|
}
|
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
userMessage,
|
|
11
11
|
} from "../../providers/provider-send-message.js";
|
|
12
12
|
import { getLogger } from "../../util/logger.js";
|
|
13
|
-
import { getConversationMemoryScopeId } from "../conversation-crud.js";
|
|
14
13
|
import { getDb } from "../db-connection.js";
|
|
15
14
|
import { asString, truncate } from "../job-utils.js";
|
|
16
15
|
import { enqueueMemoryJob, type MemoryJob } from "../jobs-store.js";
|
|
@@ -91,10 +90,6 @@ export async function buildConversationSummaryJob(
|
|
|
91
90
|
"conversation",
|
|
92
91
|
);
|
|
93
92
|
|
|
94
|
-
// Inherit the conversation's memory scope so summaries stay aligned with
|
|
95
|
-
// the retrieval scope used by the source conversation.
|
|
96
|
-
const scopeId = getConversationMemoryScopeId(conversationId);
|
|
97
|
-
|
|
98
93
|
const now = Date.now();
|
|
99
94
|
const summaryId = existing?.id ?? uuid();
|
|
100
95
|
const nextVersion = (existing?.version ?? 0) + 1;
|
|
@@ -108,7 +103,7 @@ export async function buildConversationSummaryJob(
|
|
|
108
103
|
id: summaryId,
|
|
109
104
|
scope: "conversation",
|
|
110
105
|
scopeKey: conversationId,
|
|
111
|
-
scopeId,
|
|
106
|
+
scopeId: "default",
|
|
112
107
|
summary: summaryText,
|
|
113
108
|
tokenEstimate: estimateTextTokens(summaryText),
|
|
114
109
|
version: nextVersion,
|
|
@@ -123,7 +118,7 @@ export async function buildConversationSummaryJob(
|
|
|
123
118
|
summary: summaryText,
|
|
124
119
|
tokenEstimate: estimateTextTokens(summaryText),
|
|
125
120
|
version: sql`${memorySummaries.version} + 1`,
|
|
126
|
-
scopeId,
|
|
121
|
+
scopeId: "default",
|
|
127
122
|
startAt: earliestCovered,
|
|
128
123
|
endAt: latestCovered,
|
|
129
124
|
updatedAt: now,
|
package/src/memory/jobs-store.ts
CHANGED
|
@@ -18,6 +18,7 @@ export type MemoryJobType =
|
|
|
18
18
|
| "embed_summary"
|
|
19
19
|
| "prune_old_conversations"
|
|
20
20
|
| "prune_old_llm_request_logs"
|
|
21
|
+
| "prune_old_trace_events"
|
|
21
22
|
| "build_conversation_summary"
|
|
22
23
|
| "conversation_analyze"
|
|
23
24
|
| "backfill"
|
|
@@ -366,6 +367,53 @@ export function enqueuePruneOldConversationsJob(
|
|
|
366
367
|
return enqueueMemoryJob("prune_old_conversations", payload);
|
|
367
368
|
}
|
|
368
369
|
|
|
370
|
+
export function enqueuePruneOldTraceEventsJob(retentionDays?: number): string {
|
|
371
|
+
const db = getDb();
|
|
372
|
+
const existing = db
|
|
373
|
+
.select()
|
|
374
|
+
.from(memoryJobs)
|
|
375
|
+
.where(
|
|
376
|
+
and(
|
|
377
|
+
eq(memoryJobs.type, "prune_old_trace_events"),
|
|
378
|
+
inArray(memoryJobs.status, ["pending", "running"]),
|
|
379
|
+
),
|
|
380
|
+
)
|
|
381
|
+
.orderBy(asc(memoryJobs.createdAt))
|
|
382
|
+
.get();
|
|
383
|
+
if (existing) {
|
|
384
|
+
if (
|
|
385
|
+
existing.status === "pending" &&
|
|
386
|
+
typeof retentionDays === "number" &&
|
|
387
|
+
Number.isFinite(retentionDays) &&
|
|
388
|
+
retentionDays >= 0
|
|
389
|
+
) {
|
|
390
|
+
let payload: Record<string, unknown> = {};
|
|
391
|
+
try {
|
|
392
|
+
payload = JSON.parse(existing.payload) as Record<string, unknown>;
|
|
393
|
+
} catch {
|
|
394
|
+
payload = {};
|
|
395
|
+
}
|
|
396
|
+
if (payload.retentionDays !== retentionDays) {
|
|
397
|
+
db.update(memoryJobs)
|
|
398
|
+
.set({
|
|
399
|
+
payload: JSON.stringify({ ...payload, retentionDays }),
|
|
400
|
+
updatedAt: Date.now(),
|
|
401
|
+
})
|
|
402
|
+
.where(eq(memoryJobs.id, existing.id))
|
|
403
|
+
.run();
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
return existing.id;
|
|
407
|
+
}
|
|
408
|
+
const payload =
|
|
409
|
+
typeof retentionDays === "number" &&
|
|
410
|
+
Number.isFinite(retentionDays) &&
|
|
411
|
+
retentionDays >= 0
|
|
412
|
+
? { retentionDays }
|
|
413
|
+
: {};
|
|
414
|
+
return enqueueMemoryJob("prune_old_trace_events", payload);
|
|
415
|
+
}
|
|
416
|
+
|
|
369
417
|
export interface LaneBudgets {
|
|
370
418
|
slowLlm: number;
|
|
371
419
|
fast: number;
|
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
|
|
2
1
|
import { getConfig } from "../config/loader.js";
|
|
3
2
|
import type { AssistantConfig } from "../config/types.js";
|
|
3
|
+
import {
|
|
4
|
+
checkDiskPressureBackgroundGate,
|
|
5
|
+
diskPressureBackgroundSkipLogFields,
|
|
6
|
+
shouldLogDiskPressureBackgroundSkip,
|
|
7
|
+
} from "../daemon/disk-pressure-background-gate.js";
|
|
4
8
|
import { getLogger } from "../util/logger.js";
|
|
5
9
|
import { getMemoryCheckpoint, setMemoryCheckpoint } from "./checkpoints.js";
|
|
6
10
|
import {
|
|
7
11
|
getLastScheduledCleanupEnqueueMs,
|
|
8
12
|
markScheduledCleanupEnqueued,
|
|
9
13
|
} from "./cleanup-schedule-state.js";
|
|
14
|
+
import { isMemoryV2ReadActive } from "./context-search/sources/memory-v2.js";
|
|
10
15
|
import { conversationAnalyzeJob } from "./conversation-analyze-job.js";
|
|
11
16
|
import { maybeRunDbMaintenance } from "./db-maintenance.js";
|
|
12
17
|
import { bootstrapFromHistory } from "./graph/bootstrap.js";
|
|
@@ -23,6 +28,7 @@ import { backfillJob } from "./job-handlers/backfill.js";
|
|
|
23
28
|
import {
|
|
24
29
|
pruneOldConversationsJob,
|
|
25
30
|
pruneOldLlmRequestLogsJob,
|
|
31
|
+
pruneOldTraceEventsJob,
|
|
26
32
|
} from "./job-handlers/cleanup.js";
|
|
27
33
|
import { generateConversationStartersJob } from "./job-handlers/conversation-starters.js";
|
|
28
34
|
// ── Per-job-type handlers ──────────────────────────────────────────
|
|
@@ -54,6 +60,7 @@ import {
|
|
|
54
60
|
enqueueMemoryJob,
|
|
55
61
|
enqueuePruneOldConversationsJob,
|
|
56
62
|
enqueuePruneOldLlmRequestLogsJob,
|
|
63
|
+
enqueuePruneOldTraceEventsJob,
|
|
57
64
|
failMemoryJob,
|
|
58
65
|
failStalledJobs,
|
|
59
66
|
type MemoryJob,
|
|
@@ -167,6 +174,20 @@ export async function runMemoryJobsOnce(
|
|
|
167
174
|
if (!config.memory.enabled) return 0;
|
|
168
175
|
const enableScheduledCleanup = options.enableScheduledCleanup === true;
|
|
169
176
|
|
|
177
|
+
const diskPressureGate = checkDiskPressureBackgroundGate("background-work");
|
|
178
|
+
if (diskPressureGate.action === "skip") {
|
|
179
|
+
if (shouldLogDiskPressureBackgroundSkip("memory-jobs-worker")) {
|
|
180
|
+
log.warn(
|
|
181
|
+
{
|
|
182
|
+
source: "memory",
|
|
183
|
+
...diskPressureBackgroundSkipLogFields(diskPressureGate),
|
|
184
|
+
},
|
|
185
|
+
"Memory jobs worker skipped during disk pressure cleanup mode",
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
return 0;
|
|
189
|
+
}
|
|
190
|
+
|
|
170
191
|
// Fail jobs that have been running longer than the configured timeout
|
|
171
192
|
const timedOut = failStalledJobs(config.memory.jobs.stalledJobTimeoutMs);
|
|
172
193
|
if (timedOut > 0) {
|
|
@@ -455,6 +476,9 @@ async function processJob(
|
|
|
455
476
|
case "prune_old_llm_request_logs":
|
|
456
477
|
pruneOldLlmRequestLogsJob(job, config);
|
|
457
478
|
return;
|
|
479
|
+
case "prune_old_trace_events":
|
|
480
|
+
pruneOldTraceEventsJob(job, config);
|
|
481
|
+
return;
|
|
458
482
|
case "build_conversation_summary":
|
|
459
483
|
await buildConversationSummaryJob(job, config);
|
|
460
484
|
return;
|
|
@@ -560,14 +584,20 @@ function maybeEnqueueScheduledCleanupJobs(
|
|
|
560
584
|
cleanup.llmRequestLogRetentionMs !== null
|
|
561
585
|
? enqueuePruneOldLlmRequestLogsJob(cleanup.llmRequestLogRetentionMs)
|
|
562
586
|
: null;
|
|
587
|
+
const pruneTraceEventsJobId =
|
|
588
|
+
cleanup.traceEventRetentionDays > 0
|
|
589
|
+
? enqueuePruneOldTraceEventsJob(cleanup.traceEventRetentionDays)
|
|
590
|
+
: null;
|
|
563
591
|
markScheduledCleanupEnqueued(nowMs);
|
|
564
592
|
log.debug(
|
|
565
593
|
{
|
|
566
594
|
pruneConversationsJobId,
|
|
567
595
|
pruneLlmRequestLogsJobId,
|
|
596
|
+
pruneTraceEventsJobId,
|
|
568
597
|
enqueueIntervalMs: cleanup.enqueueIntervalMs,
|
|
569
598
|
conversationRetentionDays: cleanup.conversationRetentionDays,
|
|
570
599
|
llmRequestLogRetentionMs: cleanup.llmRequestLogRetentionMs,
|
|
600
|
+
traceEventRetentionDays: cleanup.traceEventRetentionDays,
|
|
571
601
|
},
|
|
572
602
|
"Enqueued scheduled memory cleanup jobs",
|
|
573
603
|
);
|
|
@@ -590,58 +620,66 @@ export const GRAPH_MAINTENANCE_CHECKPOINTS = {
|
|
|
590
620
|
} as const;
|
|
591
621
|
|
|
592
622
|
/**
|
|
593
|
-
* Enqueue periodic graph maintenance jobs
|
|
594
|
-
*
|
|
595
|
-
*
|
|
623
|
+
* Enqueue periodic graph maintenance jobs.
|
|
624
|
+
*
|
|
625
|
+
* Mutually exclusive between v1 and v2:
|
|
626
|
+
* - v2 active (both `memory-v2-enabled` flag and `memory.v2.enabled`
|
|
627
|
+
* config on) → only `memory_v2_consolidate` is scheduled.
|
|
628
|
+
* - v2 inactive → the four v1 entries (decay, consolidate, pattern_scan,
|
|
629
|
+
* narrative) are scheduled instead.
|
|
596
630
|
*
|
|
597
|
-
*
|
|
598
|
-
*
|
|
599
|
-
*
|
|
600
|
-
*
|
|
601
|
-
*
|
|
631
|
+
* Read/write paths route to v2 when the flag is on, so v1 graph data goes
|
|
632
|
+
* unread; running v1 maintenance alongside v2 is wasted compute and LLM
|
|
633
|
+
* spend. The v1 code path remains live so flipping the flag back to off
|
|
634
|
+
* fully re-engages v1.
|
|
635
|
+
*
|
|
636
|
+
* Uses durable checkpoints so intervals survive daemon restarts — jobs only
|
|
637
|
+
* fire when the actual elapsed time since last run exceeds the interval.
|
|
638
|
+
* Sweep is intentionally not on this schedule: it is debounced from the
|
|
639
|
+
* live `graph_extract` trigger path (see `indexMessageNow` in `indexer.ts`)
|
|
640
|
+
* so it runs on the same idle/message-count cadence.
|
|
602
641
|
*/
|
|
603
642
|
export function maybeEnqueueGraphMaintenanceJobs(
|
|
604
643
|
config: AssistantConfig,
|
|
605
644
|
nowMs = Date.now(),
|
|
606
645
|
): void {
|
|
646
|
+
const v2Active = isMemoryV2ReadActive(config);
|
|
647
|
+
|
|
607
648
|
const schedule: Array<{
|
|
608
649
|
key: string;
|
|
609
650
|
intervalMs: number;
|
|
610
651
|
jobType: MemoryJobType;
|
|
611
|
-
}> =
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
jobType: "memory_v2_consolidate",
|
|
643
|
-
});
|
|
644
|
-
}
|
|
652
|
+
}> = v2Active
|
|
653
|
+
? [
|
|
654
|
+
{
|
|
655
|
+
key: GRAPH_MAINTENANCE_CHECKPOINTS.memoryV2Consolidate,
|
|
656
|
+
intervalMs:
|
|
657
|
+
config.memory.v2.consolidation_interval_hours * 60 * 60 * 1000,
|
|
658
|
+
jobType: "memory_v2_consolidate",
|
|
659
|
+
},
|
|
660
|
+
]
|
|
661
|
+
: [
|
|
662
|
+
{
|
|
663
|
+
key: GRAPH_MAINTENANCE_CHECKPOINTS.decay,
|
|
664
|
+
intervalMs: GRAPH_DECAY_INTERVAL_MS,
|
|
665
|
+
jobType: "graph_decay",
|
|
666
|
+
},
|
|
667
|
+
{
|
|
668
|
+
key: GRAPH_MAINTENANCE_CHECKPOINTS.consolidate,
|
|
669
|
+
intervalMs: GRAPH_CONSOLIDATE_INTERVAL_MS,
|
|
670
|
+
jobType: "graph_consolidate",
|
|
671
|
+
},
|
|
672
|
+
{
|
|
673
|
+
key: GRAPH_MAINTENANCE_CHECKPOINTS.patternScan,
|
|
674
|
+
intervalMs: GRAPH_PATTERN_SCAN_INTERVAL_MS,
|
|
675
|
+
jobType: "graph_pattern_scan",
|
|
676
|
+
},
|
|
677
|
+
{
|
|
678
|
+
key: GRAPH_MAINTENANCE_CHECKPOINTS.narrative,
|
|
679
|
+
intervalMs: GRAPH_NARRATIVE_INTERVAL_MS,
|
|
680
|
+
jobType: "graph_narrative_refine",
|
|
681
|
+
},
|
|
682
|
+
];
|
|
645
683
|
|
|
646
684
|
for (const { key, intervalMs, jobType } of schedule) {
|
|
647
685
|
const lastRun = parseInt(getMemoryCheckpoint(key) ?? "0", 10);
|