@vellumai/assistant 0.8.7 → 0.8.8-dev.202606052332.17fc8ea
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/Dockerfile +20 -4
- package/bun.lock +2 -2
- package/docker-entrypoint.sh +4 -2
- package/docker-init-apt-root.sh +3 -1
- package/docker-kata-apt-env.sh +3 -1
- package/docker-kata-runtime-family.sh +12 -0
- package/docs/architecture/memory.md +1 -1
- package/examples/plugins/echo/README.md +61 -66
- package/examples/plugins/echo/hooks/post-tool-use.ts +18 -0
- package/examples/plugins/echo/hooks/stop.ts +16 -0
- package/examples/plugins/echo/hooks/user-prompt-submit.ts +18 -0
- package/examples/plugins/echo/package.json +1 -2
- package/examples/plugins/echo/src/emit.ts +19 -0
- package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +3 -3
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
- package/openapi.yaml +3378 -335
- package/package.json +2 -2
- package/scripts/generate-openapi.ts +68 -41
- package/src/__tests__/agent-loop-exit-reason.test.ts +35 -93
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +1 -1
- package/src/__tests__/agent-loop.test.ts +37 -87
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
- package/src/__tests__/annotate-activity-metadata.test.ts +262 -0
- package/src/__tests__/annotate-risk-options.test.ts +2 -3
- package/src/__tests__/anthropic-provider.test.ts +95 -2
- package/src/__tests__/app-control-flow.test.ts +1 -1
- package/src/__tests__/app-dir-path-guard.test.ts +1 -0
- package/src/__tests__/approval-routes-http.test.ts +4 -1
- package/src/__tests__/assistant-event-hub.test.ts +25 -0
- package/src/__tests__/assistant-events-sse-shed.test.ts +8 -0
- package/src/__tests__/{conversation-stream-state.test.ts → assistant-stream-state.test.ts} +252 -91
- package/src/__tests__/auth-fallback-events-store.test.ts +116 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +6 -0
- package/src/__tests__/btw-routes.test.ts +62 -3
- package/src/__tests__/build-persisted-content.test.ts +184 -0
- package/src/__tests__/catalog-files.test.ts +1 -1
- package/src/__tests__/channel-approval-routes.test.ts +1 -1
- package/src/__tests__/channel-approvals.test.ts +1 -1
- package/src/__tests__/clawhub-files.test.ts +1 -1
- package/src/__tests__/compaction-circuit.test.ts +258 -0
- package/src/__tests__/compaction-direct.test.ts +132 -0
- package/src/__tests__/compaction.benchmark.test.ts +0 -30
- package/src/__tests__/config-watcher.test.ts +1 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +57 -19
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +6 -5
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +10 -7
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +316 -1143
- package/src/__tests__/conversation-agent-loop.test.ts +638 -1655
- package/src/__tests__/conversation-analysis-routes.test.ts +6 -0
- package/src/__tests__/conversation-clean-command.test.ts +5 -2
- package/src/__tests__/conversation-history-web-search.test.ts +11 -1
- package/src/__tests__/conversation-pairing.test.ts +4 -31
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +6 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +30 -10
- package/src/__tests__/conversation-queue.test.ts +2 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +3 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +6 -5
- package/src/__tests__/conversation-runtime-assembly.test.ts +310 -300
- package/src/__tests__/conversation-runtime-workspace.test.ts +105 -45
- package/src/__tests__/conversation-slash-commands.test.ts +8 -42
- package/src/__tests__/conversation-slash-queue.test.ts +6 -1
- package/src/__tests__/conversation-starter-routes.test.ts +14 -6
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +84 -0
- package/src/__tests__/conversation-sync-tags.test.ts +27 -15
- package/src/__tests__/conversation-title-service.test.ts +135 -2
- package/src/__tests__/conversation-workspace-cache-state.test.ts +17 -16
- package/src/__tests__/conversation-workspace-injection.test.ts +67 -2
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +7 -6
- package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
- package/src/__tests__/cross-provider-web-search.test.ts +214 -1
- package/src/__tests__/db-acp-history.test.ts +101 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +5 -0
- package/src/__tests__/dm-persistence.test.ts +5 -1
- package/src/__tests__/dynamic-page-surface.test.ts +31 -0
- package/src/__tests__/empty-response-hook.test.ts +304 -0
- package/src/__tests__/feature-flag-test-helpers.ts +2 -2
- package/src/__tests__/file-write-tool.test.ts +63 -0
- package/src/__tests__/gateway-only-guard.test.ts +12 -2
- package/src/__tests__/gemini-image-service.test.ts +13 -0
- package/src/__tests__/guardian-grant-minting.test.ts +1 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +2 -4
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +1 -0
- package/src/__tests__/helpers/mock-provider.ts +110 -0
- package/src/__tests__/helpers/native-web-search-harness.ts +129 -0
- package/src/__tests__/history-repair-hook.test.ts +1 -0
- package/src/__tests__/host-app-control-routes.test.ts +1 -1
- package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
- package/src/__tests__/identity-intro-cache.test.ts +12 -100
- package/src/__tests__/identity-routes.test.ts +248 -7
- package/src/__tests__/inbound-slack-persistence.test.ts +5 -1
- package/src/__tests__/injector-background-turn.test.ts +3 -9
- package/src/__tests__/injector-chain.test.ts +139 -275
- package/src/__tests__/injector-disk-pressure.test.ts +75 -41
- package/src/__tests__/injector-document-comments.test.ts +3 -3
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +30 -22
- package/src/__tests__/injector-v3-suppression.test.ts +31 -37
- package/src/__tests__/internal-telemetry-routes.test.ts +109 -0
- package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
- package/src/__tests__/list-messages-page-latest.test.ts +60 -0
- package/src/__tests__/list-messages-tool-merge.test.ts +20 -0
- package/src/__tests__/llm-usage-store.test.ts +223 -1
- package/src/__tests__/memory-retrieval-hook.test.ts +297 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +103 -35
- package/src/__tests__/native-web-search.test.ts +191 -0
- package/src/__tests__/onboarding-template-contract.test.ts +2 -0
- package/src/__tests__/openai-image-service.test.ts +17 -0
- package/src/__tests__/openai-provider.test.ts +31 -1
- package/src/__tests__/{overflow-reduce-pipeline.test.ts → overflow-reduction-loop.test.ts} +64 -284
- package/src/__tests__/persist-unsendable-image.test.ts +215 -0
- package/src/__tests__/persistence-secret-redaction.test.ts +1 -0
- package/src/__tests__/pkb-autoinject.test.ts +2 -5
- package/src/__tests__/plugin-api-shim.test.ts +3 -6
- package/src/__tests__/plugin-bootstrap.test.ts +14 -40
- package/src/__tests__/plugin-registry.test.ts +3 -76
- package/src/__tests__/plugin-types.test.ts +0 -193
- package/src/__tests__/process-message-display-content.test.ts +6 -2
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +5 -1
- package/src/__tests__/resolve-trust-class.test.ts +4 -4
- package/src/__tests__/runtime-events-sse-reconnect.test.ts +60 -23
- package/src/__tests__/schedule-routes.test.ts +603 -2
- package/src/__tests__/schedule-store.test.ts +41 -0
- package/src/__tests__/schedule-tools.test.ts +35 -0
- package/src/__tests__/send-endpoint-busy.test.ts +4 -1
- package/src/__tests__/server-history-render.test.ts +314 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +33 -0
- package/src/__tests__/skillssh-files.test.ts +1 -1
- package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
- package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
- package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
- package/src/__tests__/subagent-manager-notify.test.ts +1 -3
- package/src/__tests__/subagent-notify-parent.test.ts +1 -3
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
- package/src/__tests__/system-prompt.test.ts +20 -0
- package/src/__tests__/task-scheduler.test.ts +162 -1
- package/src/__tests__/terminal-tools.test.ts +6 -1
- package/src/__tests__/title-generate-hook.test.ts +319 -0
- package/src/__tests__/tool-error-hook.test.ts +278 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +468 -5
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
- package/src/__tests__/tool-result-truncate-hook.test.ts +127 -0
- package/src/__tests__/tool-result-truncation.test.ts +0 -2
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +254 -0
- package/src/__tests__/ui-work-result-surface.test.ts +159 -0
- package/src/__tests__/usage-routes.test.ts +285 -1
- package/src/__tests__/user-plugin-loader.test.ts +54 -286
- package/src/__tests__/voice-session-bridge.test.ts +6 -3
- package/src/__tests__/web-search-backend-failure.test.ts +166 -0
- package/src/acp/__tests__/agent-process.test.ts +161 -0
- package/src/acp/__tests__/client-handler.test.ts +40 -0
- package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
- package/src/acp/__tests__/helpers/exec-file-stub.ts +101 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +137 -0
- package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
- package/src/acp/__tests__/session-manager-resume.test.ts +736 -0
- package/src/acp/agent-process.ts +61 -1
- package/src/acp/auto-install.test.ts +196 -0
- package/src/acp/auto-install.ts +177 -0
- package/src/acp/client-handler.ts +31 -0
- package/src/acp/feature-gate.test.ts +48 -0
- package/src/acp/feature-gate.ts +34 -0
- package/src/acp/prepare-agent-env.ts +83 -29
- package/src/acp/resolve-agent.test.ts +320 -7
- package/src/acp/resolve-agent.ts +182 -18
- package/src/acp/resume-hint.ts +25 -0
- package/src/acp/session-manager.ts +495 -73
- package/src/acp/types.ts +8 -0
- package/src/agent/compaction-circuit.ts +60 -102
- package/src/agent/loop.ts +362 -485
- package/src/api/events/assistant-thinking-delta.ts +33 -0
- package/src/api/events/tool-output-chunk.ts +45 -0
- package/src/api/events/tool-use-preview-start.ts +32 -0
- package/src/api/events/trace-event.ts +69 -0
- package/src/api/index.ts +48 -13
- package/src/api/responses/conversation-message.ts +374 -0
- package/src/approvals/guardian-request-resolvers.ts +1 -1
- package/src/avatar/__tests__/avatar-store.test.ts +34 -29
- package/src/background-wake/next-wake.ts +1 -0
- package/src/cli/commands/__tests__/notifications.test.ts +58 -14
- package/src/cli/commands/notifications.ts +112 -60
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
- package/src/config/acp-defaults.test.ts +10 -0
- package/src/config/acp-defaults.ts +6 -0
- package/src/config/assistant-feature-flags.ts +22 -11
- package/src/config/bundled-skills/acp/SKILL.md +83 -31
- package/src/config/bundled-skills/acp/TOOLS.json +4 -4
- package/src/config/bundled-skills/app-builder/SKILL.md +224 -398
- package/src/config/bundled-skills/app-builder/TOOLS.json +29 -0
- package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
- package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
- package/src/config/bundled-skills/app-builder/references/examples/README.md +17 -0
- package/src/config/bundled-skills/app-builder/references/examples/expense-tracker.md +515 -0
- package/src/config/bundled-skills/app-builder/references/examples/focus-timer.md +342 -0
- package/src/config/bundled-skills/app-builder/references/examples/habit-tracker.md +490 -0
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
- package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
- package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +0 -7
- package/src/config/bundled-tool-registry.ts +2 -0
- package/src/config/feature-flag-cache.ts +3 -3
- package/src/config/feature-flag-registry.json +48 -7
- package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +25 -0
- package/src/config/schemas/heartbeat.ts +9 -0
- package/src/config/schemas/llm.ts +1 -0
- package/src/config/schemas/memory-v2.ts +8 -0
- package/src/config/schemas/memory-v3.ts +8 -0
- package/src/config/schemas/platform.ts +8 -0
- package/src/config/seed-inference-profiles.ts +2 -2
- package/src/config/skills.ts +13 -0
- package/src/context/compactor.ts +1 -1
- package/src/context/strip-injections.ts +128 -0
- package/src/context/token-estimator.ts +23 -0
- package/src/context/tool-result-truncation.ts +0 -23
- package/src/context/window-manager.ts +5 -7
- package/src/credential-execution/executable-discovery.ts +16 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +6 -0
- package/src/daemon/__tests__/inference-profile-notification.test.ts +153 -0
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +10 -8
- package/src/daemon/assistant-attachments.ts +1 -1
- package/src/daemon/config-watcher.ts +2 -2
- package/src/daemon/context-overflow-reducer.ts +0 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +594 -153
- package/src/daemon/conversation-agent-loop.ts +301 -997
- package/src/daemon/conversation-history.ts +5 -4
- package/src/daemon/conversation-lifecycle.ts +3 -4
- package/src/daemon/conversation-messaging.ts +7 -6
- package/src/daemon/conversation-process.ts +11 -16
- package/src/daemon/conversation-registry.ts +159 -0
- package/src/daemon/conversation-runtime-assembly.ts +218 -398
- package/src/daemon/conversation-slash.ts +6 -25
- package/src/daemon/conversation-store.ts +9 -90
- package/src/daemon/conversation-surfaces.ts +222 -4
- package/src/daemon/conversation-tool-setup.ts +2 -29
- package/src/daemon/conversation-workspace.ts +17 -0
- package/src/daemon/conversation.ts +32 -20
- package/src/daemon/external-plugins-bootstrap.ts +17 -18
- package/src/daemon/handlers/config-a2a.ts +51 -36
- package/src/daemon/handlers/config-slack-channel.ts +20 -14
- package/src/daemon/handlers/config-telegram.ts +16 -2
- package/src/daemon/handlers/conversations.ts +3 -1
- package/src/daemon/handlers/shared.ts +156 -84
- package/src/daemon/handlers/skills.ts +42 -10
- package/src/daemon/lifecycle.ts +25 -0
- package/src/daemon/message-types/apps.ts +1 -29
- package/src/daemon/message-types/messages.ts +9 -57
- package/src/daemon/message-types/skills.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +136 -3
- package/src/daemon/now-scratchpad.ts +21 -0
- package/src/daemon/orphan-reaper.test.ts +210 -0
- package/src/daemon/orphan-reaper.ts +240 -0
- package/src/daemon/overflow-reduction-loop.ts +230 -0
- package/src/daemon/persist-unsendable-image.ts +117 -0
- package/src/daemon/process-message.ts +1 -3
- package/src/daemon/server.ts +2 -0
- package/src/daemon/trace-emitter.ts +6 -4
- package/src/daemon/trust-context.ts +19 -0
- package/src/daemon/wake-target-adapter.ts +3 -1
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
- package/src/heartbeat/heartbeat-run-store.ts +23 -1
- package/src/heartbeat/heartbeat-service.ts +26 -0
- package/src/home/home-greeting-cache.ts +24 -1
- package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
- package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
- package/src/ipc/gateway-client.test.ts +2 -2
- package/src/ipc/gateway-client.ts +3 -3
- package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
- package/src/ipc/skill-routes/memory.ts +4 -2
- package/src/media/gemini-image-service.ts +15 -0
- package/src/media/openai-image-service.ts +14 -0
- package/src/media/types.ts +34 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +56 -0
- package/src/memory/auth-fallback-events-store.ts +94 -0
- package/src/memory/conversation-starter-checkpoints.ts +1 -0
- package/src/memory/conversation-title-service.ts +65 -41
- package/src/memory/db-init.ts +6 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-registry.test.ts +119 -0
- package/src/memory/graph/conversation-graph-memory.ts +65 -0
- package/src/memory/job-handlers/conversation-starters.ts +13 -2
- package/src/memory/jobs-store.ts +33 -0
- package/src/memory/jobs-worker.ts +32 -5
- package/src/memory/llm-usage-store.ts +224 -50
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +6 -5
- package/src/memory/migrations/270-schedule-source-conversation.ts +13 -0
- package/src/memory/migrations/271-create-auth-fallback-events.ts +21 -0
- package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
- package/src/memory/migrations/index.ts +3 -0
- package/src/memory/pkb/autoinject.ts +61 -0
- package/src/memory/pkb/context.ts +50 -0
- package/src/memory/pkb/types.ts +14 -0
- package/src/memory/schedule-attribution-sql.ts +104 -0
- package/src/memory/schema/acp.ts +4 -0
- package/src/memory/schema/infrastructure.ts +16 -0
- package/src/memory/usage-grouped-buckets.ts +6 -1
- package/src/memory/v2/__tests__/consolidation-job.test.ts +4 -4
- package/src/memory/v2/consolidation-job.ts +14 -5
- package/src/notifications/conversation-pairing.ts +8 -15
- package/src/notifications/decision-engine.ts +6 -3
- package/src/notifications/home-feed-side-effect.ts +12 -1
- package/src/permissions/prompter.ts +4 -0
- package/src/plugin-api/constants.ts +4 -0
- package/src/plugin-api/index.ts +7 -5
- package/src/plugin-api/types.ts +151 -1
- package/src/plugins/defaults/compaction/compact.ts +59 -0
- package/src/plugins/defaults/compaction/package.json +1 -1
- package/src/plugins/defaults/compaction/register.ts +8 -19
- package/src/plugins/defaults/empty-response/hooks/stop.ts +126 -0
- package/src/plugins/defaults/empty-response/register.ts +8 -13
- package/src/plugins/defaults/index.ts +2 -18
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +95 -0
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +216 -0
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +35 -0
- package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +288 -81
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/assign.test.ts +4 -4
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/health.test.ts +16 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +4 -4
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/maintain-job.test.ts +5 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/orchestrate.test.ts +48 -12
- package/src/plugins/defaults/memory-v3-shadow/__tests__/provider-blocks.test.ts +13 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/reconcile.test.ts +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/render-injection.test.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/router.test.ts +104 -32
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +8 -8
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selector.test.ts +96 -30
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/shadow-plugin.test.ts +34 -16
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/assign.ts +5 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/capabilities.ts +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/health.ts +0 -0
- package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
- package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +75 -0
- package/src/plugins/defaults/memory-v3-shadow/llm-retry.ts +32 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/maintain-job.ts +8 -8
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/orchestrate.ts +26 -14
- package/src/plugins/defaults/{llm-call → memory-v3-shadow}/package.json +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/page-content.ts +2 -2
- package/src/plugins/defaults/memory-v3-shadow/provider-blocks.ts +26 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/reconcile.ts +3 -3
- package/src/plugins/defaults/memory-v3-shadow/register.ts +26 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/router.ts +51 -45
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selection-log-store.ts +4 -4
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selector.ts +61 -46
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/shadow-plugin.ts +69 -99
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/tree.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/types.ts +8 -0
- package/src/plugins/defaults/title-generate/hooks/stop.ts +75 -0
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +35 -0
- package/src/plugins/defaults/title-generate/package.json +1 -1
- package/src/plugins/defaults/title-generate/register.ts +18 -18
- package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +118 -0
- package/src/plugins/defaults/tool-error/package.json +1 -1
- package/src/plugins/defaults/tool-error/register.ts +9 -21
- package/src/plugins/defaults/tool-result-truncate/hooks/post-tool-use.ts +32 -0
- package/src/plugins/defaults/tool-result-truncate/register.ts +10 -21
- package/src/plugins/defaults/tool-result-truncate/terminal.ts +37 -18
- package/src/plugins/external-api.ts +2 -2
- package/src/plugins/pipeline.ts +6 -305
- package/src/plugins/registry.ts +10 -55
- package/src/plugins/types.ts +62 -797
- package/src/plugins/user-loader.ts +30 -127
- package/src/proactive-artifact/aux-message-injector.ts +4 -4
- package/src/proactive-artifact/job.test.ts +8 -13
- package/src/prompts/__tests__/system-prompt.test.ts +42 -0
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +64 -0
- package/src/prompts/templates/BOOTSTRAP.md +2 -2
- package/src/prompts/templates/system-sections.ts +15 -0
- package/src/providers/anthropic/client.ts +37 -29
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +112 -0
- package/src/providers/openai/chat-completions-provider.ts +44 -0
- package/src/providers/openrouter/client.ts +1 -0
- package/src/providers/placeholder-sentinels.ts +35 -0
- package/src/runtime/__tests__/agent-wake.test.ts +10 -6
- package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
- package/src/runtime/agent-wake.ts +2 -5
- package/src/runtime/assistant-event-hub.ts +37 -7
- package/src/runtime/{conversation-stream-state.ts → assistant-stream-state.ts} +132 -58
- package/src/runtime/channel-approvals.ts +1 -1
- package/src/runtime/http-router.ts +16 -21
- package/src/runtime/http-types.ts +16 -70
- package/src/runtime/interactive-ui.ts +1 -1
- package/src/runtime/pending-interactions.ts +1 -0
- package/src/runtime/routes/__tests__/acp-routes.test.ts +283 -55
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +265 -2
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +31 -1
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +6 -2
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
- package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
- package/src/runtime/routes/acp-routes.test.ts +89 -25
- package/src/runtime/routes/acp-routes.ts +81 -29
- package/src/runtime/routes/app-management-routes.ts +6 -117
- package/src/runtime/routes/app-routes.ts +13 -15
- package/src/runtime/routes/approval-routes.ts +1 -1
- package/src/runtime/routes/attachment-routes.ts +26 -15
- package/src/runtime/routes/avatar-routes.ts +26 -0
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/browser-tabs-routes.ts +6 -10
- package/src/runtime/routes/btw-routes.ts +29 -23
- package/src/runtime/routes/consolidation-routes.ts +120 -20
- package/src/runtime/routes/conversation-cli-routes.ts +1 -1
- package/src/runtime/routes/conversation-list-routes.ts +1 -1
- package/src/runtime/routes/conversation-query-routes.ts +3 -1
- package/src/runtime/routes/conversation-routes.ts +372 -185
- package/src/runtime/routes/conversation-starter-routes.ts +13 -7
- package/src/runtime/routes/conversations-import-routes.ts +24 -7
- package/src/runtime/routes/documents-routes.ts +4 -0
- package/src/runtime/routes/domain-routes.ts +51 -37
- package/src/runtime/routes/epoch-millis-range.ts +34 -0
- package/src/runtime/routes/events-routes.ts +28 -34
- package/src/runtime/routes/gateway-log-routes.ts +26 -4
- package/src/runtime/routes/heartbeat-routes.ts +32 -12
- package/src/runtime/routes/host-app-control-routes.ts +1 -1
- package/src/runtime/routes/host-cu-routes.ts +1 -1
- package/src/runtime/routes/identity-intro-cache.ts +11 -34
- package/src/runtime/routes/identity-routes.ts +224 -18
- package/src/runtime/routes/image-generation-routes.ts +40 -2
- package/src/runtime/routes/inbound-message-handler.ts +1 -1
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/integrations/a2a.ts +12 -10
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +16 -0
- package/src/runtime/routes/integrations/slack/channel.ts +4 -0
- package/src/runtime/routes/integrations/slack/share.ts +27 -6
- package/src/runtime/routes/integrations/telegram.ts +6 -0
- package/src/runtime/routes/integrations/twilio.ts +42 -0
- package/src/runtime/routes/internal-telemetry-routes.ts +88 -0
- package/src/runtime/routes/log-export-routes.ts +8 -0
- package/src/runtime/routes/memory-v2-routes.ts +15 -8
- package/src/runtime/routes/memory-v3-routes.ts +66 -34
- package/src/runtime/routes/oauth-apps.ts +66 -12
- package/src/runtime/routes/oauth-providers.ts +44 -5
- package/src/runtime/routes/platform-routes.ts +81 -5
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +6 -4
- package/src/runtime/routes/playground/force-compact.ts +1 -1
- package/src/runtime/routes/playground/helpers.ts +1 -1
- package/src/runtime/routes/rename-conversation-routes.ts +5 -0
- package/src/runtime/routes/schedule-routes.ts +152 -42
- package/src/runtime/routes/secret-routes.ts +14 -2
- package/src/runtime/routes/skills-routes.ts +43 -14
- package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
- package/src/runtime/routes/tool-call-confirmation-enrichment.test.ts +161 -0
- package/src/runtime/routes/tool-call-confirmation-enrichment.ts +107 -0
- package/src/runtime/routes/trust-rules-routes.ts +26 -2
- package/src/runtime/routes/tts-routes.ts +35 -0
- package/src/runtime/routes/types.ts +66 -8
- package/src/runtime/routes/usage-routes.ts +47 -39
- package/src/runtime/routes/webhook-routes.ts +41 -2
- package/src/runtime/routes/work-items-routes.ts +2 -4
- package/src/runtime/routes/workspace-routes.ts +4 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +6 -0
- package/src/runtime/services/analyze-conversation.ts +2 -2
- package/src/runtime/services/conversation-serializer.ts +1 -1
- package/src/schedule/schedule-store.ts +20 -1
- package/src/schedule/schedule-usage-store.ts +83 -0
- package/src/schedule/scheduler.ts +12 -5
- package/src/signals/cancel.ts +2 -4
- package/src/skills/catalog-files.ts +2 -2
- package/src/skills/catalog-install.ts +3 -0
- package/src/skills/categories-cache.ts +118 -0
- package/src/skills/clawhub-files.ts +1 -2
- package/src/skills/skillssh-files.ts +1 -2
- package/src/subagent/manager.ts +17 -5
- package/src/telemetry/types.ts +29 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +112 -3
- package/src/telemetry/usage-telemetry-reporter.ts +57 -2
- package/src/tools/acp/context.ts +20 -0
- package/src/tools/acp/list-agents.test.ts +7 -1
- package/src/tools/acp/spawn.test.ts +158 -55
- package/src/tools/acp/spawn.ts +47 -72
- package/src/tools/acp/steer.test.ts +105 -8
- package/src/tools/acp/steer.ts +48 -17
- package/src/tools/apps/executors.ts +13 -8
- package/src/tools/executor.ts +1 -53
- package/src/tools/filesystem/write.ts +34 -0
- package/src/tools/network/__tests__/web-search-metadata.test.ts +7 -1
- package/src/tools/network/__tests__/web-search.test.ts +11 -3
- package/src/tools/network/web-search-error.test.ts +248 -0
- package/src/tools/network/web-search-error.ts +267 -0
- package/src/tools/network/web-search.ts +207 -48
- package/src/tools/schedule/create.ts +2 -0
- package/src/tools/subagent/spawn.ts +2 -4
- package/src/tools/terminal/safe-env.ts +10 -1
- package/src/tools/ui-surface/definitions.ts +34 -5
- package/src/tts/__tests__/provider-catalog-consistency.test.ts +85 -1
- package/src/tts/provider-catalog.ts +76 -1
- package/src/util/mutex.ts +47 -0
- package/src/workspace/git-service.ts +1 -42
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
- package/src/workspace/migrations/095-bump-heartbeat-interval-30m-to-60m.ts +51 -0
- package/src/workspace/migrations/096-reduce-quality-profile-effort.ts +72 -0
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +117 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/docs/plugins.md +0 -836
- package/examples/plugins/echo/register.ts +0 -184
- package/src/__tests__/bootstrap-turn-cleanup.test.ts +0 -44
- package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
- package/src/__tests__/compaction-pipeline.test.ts +0 -210
- package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
- package/src/__tests__/empty-response-pipeline.test.ts +0 -423
- package/src/__tests__/llm-call-pipeline.test.ts +0 -287
- package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -418
- package/src/__tests__/persistence-pipeline.test.ts +0 -503
- package/src/__tests__/pipeline-runner.test.ts +0 -564
- package/src/__tests__/title-generate-pipeline.test.ts +0 -211
- package/src/__tests__/token-estimate-pipeline.test.ts +0 -479
- package/src/__tests__/tool-error-pipeline.test.ts +0 -241
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -417
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -341
- package/src/daemon/bootstrap-turn-cleanup.ts +0 -45
- package/src/gallery/default-gallery.ts +0 -1359
- package/src/gallery/gallery-manifest.ts +0 -28
- package/src/home/feature-gate.ts +0 -22
- package/src/memory/v3/provider-blocks.ts +0 -16
- package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
- package/src/plugins/defaults/circuit-breaker/package.json +0 -15
- package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
- package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
- package/src/plugins/defaults/compaction/terminal.ts +0 -73
- package/src/plugins/defaults/empty-response/middlewares/emptyResponse.ts +0 -22
- package/src/plugins/defaults/empty-response/terminal.ts +0 -106
- package/src/plugins/defaults/injectors/package.json +0 -15
- package/src/plugins/defaults/llm-call/middlewares/llmCall.ts +0 -17
- package/src/plugins/defaults/llm-call/register.ts +0 -45
- package/src/plugins/defaults/memory-retrieval/middlewares/memoryRetrieval.ts +0 -17
- package/src/plugins/defaults/memory-retrieval/package.json +0 -15
- package/src/plugins/defaults/memory-retrieval/register.ts +0 -181
- package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +0 -126
- package/src/plugins/defaults/overflow-reduce/package.json +0 -15
- package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
- package/src/plugins/defaults/persistence/middlewares/persistence.ts +0 -19
- package/src/plugins/defaults/persistence/package.json +0 -15
- package/src/plugins/defaults/persistence/register.ts +0 -38
- package/src/plugins/defaults/persistence/terminal.ts +0 -83
- package/src/plugins/defaults/title-generate/terminal.ts +0 -31
- package/src/plugins/defaults/token-estimate/middlewares/tokenEstimate.ts +0 -23
- package/src/plugins/defaults/token-estimate/package.json +0 -15
- package/src/plugins/defaults/token-estimate/register.ts +0 -34
- package/src/plugins/defaults/token-estimate/terminal.ts +0 -40
- package/src/plugins/defaults/tool-error/middlewares/toolError.ts +0 -21
- package/src/plugins/defaults/tool-error/terminal.ts +0 -47
- package/src/plugins/defaults/tool-execute/middlewares/toolExecute.ts +0 -23
- package/src/plugins/defaults/tool-execute/package.json +0 -15
- package/src/plugins/defaults/tool-execute/register.ts +0 -49
- package/src/plugins/defaults/tool-result-truncate/middlewares/toolResultTruncate.ts +0 -23
- package/src/plugins/defaults/tool-result-truncate/types.ts +0 -22
- package/src/skills/category-inference.ts +0 -111
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/capabilities.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/core.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/eval-turns.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/live-turns.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/needle.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/snapshot.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/tree.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-eviction.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-skeleton.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/core.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/README.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/assignments.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/core.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-x.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-y.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-b/topic-z.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/needle.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/snapshot.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +0 -0
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
import { getConfiguredProvider } from "../providers/provider-send-message.js";
|
|
11
11
|
import type { Provider } from "../providers/types.js";
|
|
12
12
|
import { runBtwSidechain } from "../runtime/btw-sidechain.js";
|
|
13
|
+
import { publishConversationTitleChanged } from "../runtime/sync/resource-sync-events.js";
|
|
13
14
|
import { getLogger } from "../util/logger.js";
|
|
15
|
+
import { Mutex } from "../util/mutex.js";
|
|
14
16
|
import {
|
|
15
17
|
getConversation,
|
|
16
18
|
getMessages,
|
|
@@ -93,8 +95,6 @@ export interface GenerateTitleParams {
|
|
|
93
95
|
userMessage?: string;
|
|
94
96
|
/** Assistant response text (first turn). */
|
|
95
97
|
assistantResponse?: string;
|
|
96
|
-
/** Callback to emit title update events. */
|
|
97
|
-
onTitleUpdated?: (title: string) => void;
|
|
98
98
|
/** Abort signal. */
|
|
99
99
|
signal?: AbortSignal;
|
|
100
100
|
}
|
|
@@ -106,14 +106,8 @@ export interface GenerateTitleParams {
|
|
|
106
106
|
export async function generateAndPersistConversationTitle(
|
|
107
107
|
params: GenerateTitleParams,
|
|
108
108
|
): Promise<{ title: string; updated: boolean }> {
|
|
109
|
-
const {
|
|
110
|
-
|
|
111
|
-
context,
|
|
112
|
-
userMessage,
|
|
113
|
-
assistantResponse,
|
|
114
|
-
onTitleUpdated,
|
|
115
|
-
signal,
|
|
116
|
-
} = params;
|
|
109
|
+
const { conversationId, context, userMessage, assistantResponse, signal } =
|
|
110
|
+
params;
|
|
117
111
|
|
|
118
112
|
// Check current title is replaceable
|
|
119
113
|
const conversation = getConversation(conversationId);
|
|
@@ -127,7 +121,7 @@ export async function generateAndPersistConversationTitle(
|
|
|
127
121
|
// No provider available — fall back to context-derived title or untitled
|
|
128
122
|
const fallback = deriveFallbackTitle(context) ?? UNTITLED_FALLBACK;
|
|
129
123
|
updateConversationTitle(conversationId, fallback, 1);
|
|
130
|
-
|
|
124
|
+
publishConversationTitleChanged(conversationId, fallback);
|
|
131
125
|
return { title: fallback, updated: true };
|
|
132
126
|
}
|
|
133
127
|
|
|
@@ -139,7 +133,7 @@ export async function generateAndPersistConversationTitle(
|
|
|
139
133
|
tools: [],
|
|
140
134
|
callSite: "conversationTitle",
|
|
141
135
|
signal,
|
|
142
|
-
timeoutMs:
|
|
136
|
+
timeoutMs: 15_000,
|
|
143
137
|
});
|
|
144
138
|
const title = normalizeTitle(result.text);
|
|
145
139
|
if (title) {
|
|
@@ -150,7 +144,7 @@ export async function generateAndPersistConversationTitle(
|
|
|
150
144
|
}
|
|
151
145
|
|
|
152
146
|
updateConversationTitle(conversationId, title, 1);
|
|
153
|
-
|
|
147
|
+
publishConversationTitleChanged(conversationId, title);
|
|
154
148
|
log.info({ conversationId, title }, "Auto-generated conversation title");
|
|
155
149
|
return { title, updated: true };
|
|
156
150
|
}
|
|
@@ -167,36 +161,61 @@ export async function generateAndPersistConversationTitle(
|
|
|
167
161
|
|
|
168
162
|
const fallback = deriveFallbackTitle(context) ?? UNTITLED_FALLBACK;
|
|
169
163
|
updateConversationTitle(conversationId, fallback, 1);
|
|
170
|
-
|
|
164
|
+
publishConversationTitleChanged(conversationId, fallback);
|
|
171
165
|
return { title: fallback, updated: true };
|
|
172
166
|
}
|
|
173
167
|
|
|
168
|
+
// ── Serial title-generation queue ────────────────────────────────────
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Each title generation makes an LLM call. Without serialization, burst
|
|
172
|
+
* conversation creation (e.g. 5 new chats in quick succession) fires N
|
|
173
|
+
* concurrent requests that can hit provider rate limits or contend for
|
|
174
|
+
* API capacity, causing later calls to time out and fall back to
|
|
175
|
+
* "Untitled Conversation".
|
|
176
|
+
*
|
|
177
|
+
* A serial queue ensures at most one title-generation LLM call is
|
|
178
|
+
* in-flight at a time. Each call is lightweight (~1–3 s for a ≤5-word
|
|
179
|
+
* title), so the added serial latency is modest and invisible to the
|
|
180
|
+
* user (the UI shows "Generating title…" as a placeholder during the
|
|
181
|
+
* wait). Both initial generation and second-pass regeneration share
|
|
182
|
+
* this queue since they hit the same provider.
|
|
183
|
+
*/
|
|
184
|
+
export const titleMutex = new Mutex();
|
|
185
|
+
|
|
174
186
|
/**
|
|
175
187
|
* Fire-and-forget wrapper for title generation. Failures are logged
|
|
176
188
|
* but do not propagate. On failure, replaces loading placeholder with
|
|
177
189
|
* a stable fallback title so loading state is never permanent.
|
|
190
|
+
*
|
|
191
|
+
* Calls are serialized via {@link titleMutex} so burst conversation
|
|
192
|
+
* creation does not overwhelm the LLM provider.
|
|
178
193
|
*/
|
|
179
194
|
export function queueGenerateConversationTitle(
|
|
180
195
|
params: GenerateTitleParams,
|
|
181
196
|
): void {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
)
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
197
|
+
void titleMutex
|
|
198
|
+
.withLock(async () => {
|
|
199
|
+
await generateAndPersistConversationTitle(params);
|
|
200
|
+
})
|
|
201
|
+
.catch((err) => {
|
|
202
|
+
log.warn(
|
|
203
|
+
{ err, conversationId: params.conversationId },
|
|
204
|
+
"Failed to generate conversation title (non-fatal)",
|
|
205
|
+
);
|
|
206
|
+
// Replace loading placeholder with stable fallback
|
|
207
|
+
try {
|
|
208
|
+
const conversation = getConversation(params.conversationId);
|
|
209
|
+
if (conversation && conversation.title === GENERATING_TITLE) {
|
|
210
|
+
const fallback =
|
|
211
|
+
deriveFallbackTitle(params.context) ?? UNTITLED_FALLBACK;
|
|
212
|
+
updateConversationTitle(params.conversationId, fallback);
|
|
213
|
+
publishConversationTitleChanged(params.conversationId, fallback);
|
|
214
|
+
}
|
|
215
|
+
} catch {
|
|
216
|
+
// Best-effort
|
|
195
217
|
}
|
|
196
|
-
}
|
|
197
|
-
// Best-effort
|
|
198
|
-
}
|
|
199
|
-
});
|
|
218
|
+
});
|
|
200
219
|
}
|
|
201
220
|
|
|
202
221
|
// ── Title regeneration (second pass) ─────────────────────────────────
|
|
@@ -204,7 +223,6 @@ export function queueGenerateConversationTitle(
|
|
|
204
223
|
export interface RegenerateTitleParams {
|
|
205
224
|
conversationId: string;
|
|
206
225
|
provider?: Provider;
|
|
207
|
-
onTitleUpdated?: (title: string) => void;
|
|
208
226
|
signal?: AbortSignal;
|
|
209
227
|
}
|
|
210
228
|
|
|
@@ -216,7 +234,7 @@ export interface RegenerateTitleParams {
|
|
|
216
234
|
export async function regenerateConversationTitle(
|
|
217
235
|
params: RegenerateTitleParams,
|
|
218
236
|
): Promise<{ title: string; updated: boolean }> {
|
|
219
|
-
const { conversationId,
|
|
237
|
+
const { conversationId, signal } = params;
|
|
220
238
|
|
|
221
239
|
const conversation = getConversation(conversationId);
|
|
222
240
|
if (!conversation || !conversation.isAutoTitle) {
|
|
@@ -249,7 +267,7 @@ export async function regenerateConversationTitle(
|
|
|
249
267
|
tools: [],
|
|
250
268
|
callSite: "conversationTitle",
|
|
251
269
|
signal,
|
|
252
|
-
timeoutMs:
|
|
270
|
+
timeoutMs: 15_000,
|
|
253
271
|
});
|
|
254
272
|
const title = normalizeTitle(result.text);
|
|
255
273
|
if (title) {
|
|
@@ -260,7 +278,7 @@ export async function regenerateConversationTitle(
|
|
|
260
278
|
}
|
|
261
279
|
|
|
262
280
|
updateConversationTitle(conversationId, title, 1);
|
|
263
|
-
|
|
281
|
+
publishConversationTitleChanged(conversationId, title);
|
|
264
282
|
log.info(
|
|
265
283
|
{ conversationId, title },
|
|
266
284
|
"Re-generated conversation title (second pass)",
|
|
@@ -273,16 +291,22 @@ export async function regenerateConversationTitle(
|
|
|
273
291
|
|
|
274
292
|
/**
|
|
275
293
|
* Fire-and-forget wrapper for title regeneration.
|
|
294
|
+
*
|
|
295
|
+
* Serialized via the same {@link titleMutex} as initial generation.
|
|
276
296
|
*/
|
|
277
297
|
export function queueRegenerateConversationTitle(
|
|
278
298
|
params: RegenerateTitleParams,
|
|
279
299
|
): void {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
)
|
|
285
|
-
|
|
300
|
+
void titleMutex
|
|
301
|
+
.withLock(async () => {
|
|
302
|
+
await regenerateConversationTitle(params);
|
|
303
|
+
})
|
|
304
|
+
.catch((err) => {
|
|
305
|
+
log.warn(
|
|
306
|
+
{ err, conversationId: params.conversationId },
|
|
307
|
+
"Failed to regenerate conversation title (non-fatal)",
|
|
308
|
+
);
|
|
309
|
+
});
|
|
286
310
|
}
|
|
287
311
|
|
|
288
312
|
// ── Internal helpers ─────────────────────────────────────────────────
|
package/src/memory/db-init.ts
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
addCoreColumns,
|
|
19
19
|
createApprovalPromptTsTrackerTable,
|
|
20
20
|
createAssistantInboxTables,
|
|
21
|
+
createAuthFallbackEventsTable,
|
|
21
22
|
createCallSessionsTables,
|
|
22
23
|
createCanonicalGuardianTables,
|
|
23
24
|
createChannelGuardianTables,
|
|
@@ -40,6 +41,7 @@ import {
|
|
|
40
41
|
migrate230AcpSessionHistory,
|
|
41
42
|
migrate231RepairMemoryGraphEventDates,
|
|
42
43
|
migrateA2ATasks,
|
|
44
|
+
migrateAcpSessionHistoryCwd,
|
|
43
45
|
migrateActivationState,
|
|
44
46
|
migrateActivationStateFkCascade,
|
|
45
47
|
migrateAddConversationInferenceProfile,
|
|
@@ -188,6 +190,7 @@ import {
|
|
|
188
190
|
migrateScheduleReuseConversation,
|
|
189
191
|
migrateScheduleScriptColumn,
|
|
190
192
|
migrateScheduleScriptTimeout,
|
|
193
|
+
migrateScheduleSourceConversation,
|
|
191
194
|
migrateScheduleWakeConversationId,
|
|
192
195
|
migrateSchemaIndexesAndColumns,
|
|
193
196
|
migrateScrubCorruptedImageAttachments,
|
|
@@ -473,7 +476,10 @@ export function initializeDb(): void {
|
|
|
473
476
|
migrateLlmUsageEventsAddAssistantVersion,
|
|
474
477
|
migrateAddMemoryV3Selections,
|
|
475
478
|
migrateScheduleScriptTimeout,
|
|
479
|
+
migrateScheduleSourceConversation,
|
|
476
480
|
migrateMessagesRoleCreatedAtIndex,
|
|
481
|
+
createAuthFallbackEventsTable,
|
|
482
|
+
migrateAcpSessionHistoryCwd,
|
|
477
483
|
];
|
|
478
484
|
|
|
479
485
|
// Run each migration step, catching and logging individual failures so one
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the live, per-conversation {@link ConversationGraphMemory} registry
|
|
3
|
+
* (`getLiveGraphMemory`). The registry lets memory-domain code that only knows
|
|
4
|
+
* a conversation id — notably the post-compaction re-injection hook — reach the
|
|
5
|
+
* same in-memory handle the turn's retrieval mutated, without the agent loop
|
|
6
|
+
* threading the handle through its generic context.
|
|
7
|
+
*/
|
|
8
|
+
import { describe, expect, mock, test } from "bun:test";
|
|
9
|
+
|
|
10
|
+
import { createMockLoggerModule } from "../../../__tests__/helpers/mock-logger.js";
|
|
11
|
+
|
|
12
|
+
mock.module("../../../util/logger.js", () => createMockLoggerModule());
|
|
13
|
+
|
|
14
|
+
const { ConversationGraphMemory, getLiveGraphMemory } =
|
|
15
|
+
await import("../conversation-graph-memory.js");
|
|
16
|
+
|
|
17
|
+
describe("ConversationGraphMemory live registry", () => {
|
|
18
|
+
test("a constructed handle is discoverable by its conversation id", () => {
|
|
19
|
+
/**
|
|
20
|
+
* Tests that constructing a handle registers it so it can be looked up.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
// GIVEN a conversation id
|
|
24
|
+
const conversationId = `conv-registry-${crypto.randomUUID()}`;
|
|
25
|
+
|
|
26
|
+
// WHEN a graph handle is constructed for it
|
|
27
|
+
const handle = new ConversationGraphMemory(conversationId);
|
|
28
|
+
|
|
29
|
+
// THEN the registry returns that exact instance
|
|
30
|
+
expect(getLiveGraphMemory(conversationId)).toBe(handle);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("dispose removes the handle from the registry", () => {
|
|
34
|
+
/**
|
|
35
|
+
* Tests that disposing a handle unregisters it.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
// GIVEN a registered graph handle
|
|
39
|
+
const conversationId = `conv-registry-${crypto.randomUUID()}`;
|
|
40
|
+
const handle = new ConversationGraphMemory(conversationId);
|
|
41
|
+
|
|
42
|
+
// WHEN it is disposed
|
|
43
|
+
handle.dispose();
|
|
44
|
+
|
|
45
|
+
// THEN the registry no longer resolves the conversation id
|
|
46
|
+
expect(getLiveGraphMemory(conversationId)).toBeUndefined();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("missing id and undefined id both resolve to undefined", () => {
|
|
50
|
+
/**
|
|
51
|
+
* Tests the lookup's absence handling for unknown and undefined keys.
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
// GIVEN no handle registered for these keys
|
|
55
|
+
// WHEN the registry is queried with an unknown id and with undefined
|
|
56
|
+
// THEN both resolve to undefined (the hook treats absence as "no graph")
|
|
57
|
+
expect(
|
|
58
|
+
getLiveGraphMemory(`conv-never-${crypto.randomUUID()}`),
|
|
59
|
+
).toBeUndefined();
|
|
60
|
+
expect(getLiveGraphMemory(undefined)).toBeUndefined();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("recreating for the same id replaces the registered handle", () => {
|
|
64
|
+
/**
|
|
65
|
+
* Tests that the latest constructed handle wins for a conversation id.
|
|
66
|
+
*/
|
|
67
|
+
|
|
68
|
+
// GIVEN a handle already registered for a conversation id
|
|
69
|
+
const conversationId = `conv-registry-${crypto.randomUUID()}`;
|
|
70
|
+
new ConversationGraphMemory(conversationId);
|
|
71
|
+
|
|
72
|
+
// WHEN a second handle is constructed for the same id
|
|
73
|
+
const recreated = new ConversationGraphMemory(conversationId);
|
|
74
|
+
|
|
75
|
+
// THEN the registry resolves to the most recent instance
|
|
76
|
+
expect(getLiveGraphMemory(conversationId)).toBe(recreated);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("disposing a stale handle does not evict the current one", () => {
|
|
80
|
+
/**
|
|
81
|
+
* Tests the dispose guard during an eviction + recreation race: a stale
|
|
82
|
+
* handle must not delete the live entry that now points at a newer handle.
|
|
83
|
+
*/
|
|
84
|
+
|
|
85
|
+
// GIVEN a superseded (stale) handle and the current handle for one id
|
|
86
|
+
const conversationId = `conv-registry-${crypto.randomUUID()}`;
|
|
87
|
+
const stale = new ConversationGraphMemory(conversationId);
|
|
88
|
+
const current = new ConversationGraphMemory(conversationId);
|
|
89
|
+
|
|
90
|
+
// WHEN the stale handle is disposed
|
|
91
|
+
stale.dispose();
|
|
92
|
+
|
|
93
|
+
// THEN the registry still resolves to the current handle
|
|
94
|
+
expect(getLiveGraphMemory(conversationId)).toBe(current);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("records and exposes the PKB query vector pair from the registry", () => {
|
|
98
|
+
/**
|
|
99
|
+
* Tests that the dense/sparse PKB query pair recorded during retrieval is
|
|
100
|
+
* readable off the same live handle the PKB-reminder injector looks up.
|
|
101
|
+
*/
|
|
102
|
+
|
|
103
|
+
// GIVEN a registered graph handle with no recorded vectors yet
|
|
104
|
+
const conversationId = `conv-registry-${crypto.randomUUID()}`;
|
|
105
|
+
const handle = new ConversationGraphMemory(conversationId);
|
|
106
|
+
expect(handle.pkbQueryVector).toBeUndefined();
|
|
107
|
+
expect(handle.pkbSparseVector).toBeUndefined();
|
|
108
|
+
|
|
109
|
+
// WHEN a retrieval records the turn's dense/sparse pair
|
|
110
|
+
const dense = [0.1, 0.2, 0.3];
|
|
111
|
+
const sparse = { indices: [0, 2], values: [0.5, 0.9] };
|
|
112
|
+
handle.recordPkbQueryVectors(dense, sparse);
|
|
113
|
+
|
|
114
|
+
// THEN a registry consumer reads back the same pair by conversation id
|
|
115
|
+
const looked = getLiveGraphMemory(conversationId);
|
|
116
|
+
expect(looked?.pkbQueryVector).toBe(dense);
|
|
117
|
+
expect(looked?.pkbSparseVector).toBe(sparse);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
@@ -62,6 +62,31 @@ const ESTIMATED_IMAGE_TOKENS = 1000;
|
|
|
62
62
|
// Per-conversation state
|
|
63
63
|
// ---------------------------------------------------------------------------
|
|
64
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Registry of the live, per-conversation graph handles keyed by conversation
|
|
67
|
+
* id. A handle registers itself on construction and removes itself on
|
|
68
|
+
* {@link ConversationGraphMemory.dispose}, so memory-domain code that only
|
|
69
|
+
* knows a conversation id (e.g. the post-compaction re-injection hook) can
|
|
70
|
+
* reach the same in-memory handle the turn's retrieval used — its live
|
|
71
|
+
* `tracker` / cached-node state, which a DB-reconstructed handle would not
|
|
72
|
+
* carry. Not a general service locator: it holds only the graph handle, and
|
|
73
|
+
* the daemon's `Conversation` remains the owner of the instance's lifecycle.
|
|
74
|
+
*/
|
|
75
|
+
const liveByConversation = new Map<string, ConversationGraphMemory>();
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Look up the live {@link ConversationGraphMemory} for a conversation, or
|
|
79
|
+
* `undefined` when none is registered (no active conversation, or a context
|
|
80
|
+
* with no conversation id). Returns the same instance the turn's retrieval
|
|
81
|
+
* mutated, so cached-node re-tracking operates on real state.
|
|
82
|
+
*/
|
|
83
|
+
export function getLiveGraphMemory(
|
|
84
|
+
conversationId: string | undefined,
|
|
85
|
+
): ConversationGraphMemory | undefined {
|
|
86
|
+
if (!conversationId) return undefined;
|
|
87
|
+
return liveByConversation.get(conversationId);
|
|
88
|
+
}
|
|
89
|
+
|
|
65
90
|
/**
|
|
66
91
|
* Manages memory graph state for a single conversation.
|
|
67
92
|
* Create one per Conversation instance. Persists across turns.
|
|
@@ -75,9 +100,24 @@ export class ConversationGraphMemory {
|
|
|
75
100
|
private lastInjectedBlock: string | null = null;
|
|
76
101
|
private lastInjectedNodeIds: string[] = [];
|
|
77
102
|
private lastInjectedImages: Map<string, ResolvedImage> = new Map();
|
|
103
|
+
private lastPkbQueryVector: number[] | undefined;
|
|
104
|
+
private lastPkbSparseVector: QdrantSparseVector | undefined;
|
|
78
105
|
|
|
79
106
|
constructor(conversationId: string) {
|
|
80
107
|
this.conversationId = conversationId;
|
|
108
|
+
liveByConversation.set(conversationId, this);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Remove this handle from the live registry. Called from
|
|
113
|
+
* `Conversation.dispose`. Guards against clobbering a newer handle for the
|
|
114
|
+
* same conversation (eviction + recreation) by only deleting the entry when
|
|
115
|
+
* it still points at this instance.
|
|
116
|
+
*/
|
|
117
|
+
dispose(): void {
|
|
118
|
+
if (liveByConversation.get(this.conversationId) === this) {
|
|
119
|
+
liveByConversation.delete(this.conversationId);
|
|
120
|
+
}
|
|
81
121
|
}
|
|
82
122
|
|
|
83
123
|
/**
|
|
@@ -305,6 +345,31 @@ export class ConversationGraphMemory {
|
|
|
305
345
|
this.tracker.add(this.lastInjectedNodeIds);
|
|
306
346
|
}
|
|
307
347
|
|
|
348
|
+
/**
|
|
349
|
+
* Record the dense/sparse query-vector pair this turn's retrieval produced
|
|
350
|
+
* for PKB hybrid search. The PKB-reminder injector reuses the same
|
|
351
|
+
* embedding (looked up by conversation id via {@link getLiveGraphMemory})
|
|
352
|
+
* rather than receiving it threaded through the agent loop, so the vectors
|
|
353
|
+
* stay owned by the memory-retrieval domain that computes them.
|
|
354
|
+
*/
|
|
355
|
+
recordPkbQueryVectors(
|
|
356
|
+
dense: number[] | undefined,
|
|
357
|
+
sparse: QdrantSparseVector | undefined,
|
|
358
|
+
): void {
|
|
359
|
+
this.lastPkbQueryVector = dense;
|
|
360
|
+
this.lastPkbSparseVector = sparse;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/** Dense PKB query vector from this turn's retrieval, or `undefined`. */
|
|
364
|
+
get pkbQueryVector(): number[] | undefined {
|
|
365
|
+
return this.lastPkbQueryVector;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/** Sparse PKB query vector paired with {@link pkbQueryVector}. */
|
|
369
|
+
get pkbSparseVector(): QdrantSparseVector | undefined {
|
|
370
|
+
return this.lastPkbSparseVector;
|
|
371
|
+
}
|
|
372
|
+
|
|
308
373
|
/**
|
|
309
374
|
* Main entry point — called on every turn before the LLM sees the messages.
|
|
310
375
|
*
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
checkpointKey,
|
|
23
23
|
CK_BATCH,
|
|
24
24
|
CK_ITEM_COUNT,
|
|
25
|
+
CK_LAST_ATTEMPT_AT,
|
|
25
26
|
CK_LAST_GEN_AT,
|
|
26
27
|
countActiveMemoryNodes,
|
|
27
28
|
getCheckpointValue,
|
|
@@ -336,6 +337,7 @@ Bad → Good (incomplete phrase → complete):
|
|
|
336
337
|
config: {
|
|
337
338
|
callSite: "conversationStarters" as const,
|
|
338
339
|
max_tokens: 2048,
|
|
340
|
+
temperature: 0.7,
|
|
339
341
|
tool_choice: {
|
|
340
342
|
type: "tool" as const,
|
|
341
343
|
name: "store_conversation_starters",
|
|
@@ -395,18 +397,27 @@ export async function generateConversationStartersJob(
|
|
|
395
397
|
const db = getDb();
|
|
396
398
|
const now = Date.now();
|
|
397
399
|
|
|
400
|
+
// Record attempt time so the route handler's cooldown prevents rapid retries
|
|
401
|
+
// even when generation produces 0 valid starters.
|
|
402
|
+
upsertCheckpoint(
|
|
403
|
+
checkpointKey(CK_LAST_ATTEMPT_AT, scopeId),
|
|
404
|
+
String(now),
|
|
405
|
+
now,
|
|
406
|
+
);
|
|
407
|
+
|
|
398
408
|
const starters = await generateStarters(scopeId);
|
|
399
409
|
if (starters.length === 0) {
|
|
400
410
|
log.info({ scopeId }, "No conversation starters generated");
|
|
401
411
|
|
|
402
|
-
// Sync
|
|
412
|
+
// Sync the item count checkpoint so `checkpointAhead` clears, but do NOT
|
|
413
|
+
// update `CK_LAST_GEN_AT` — the stale TTL should trigger a retry on the
|
|
414
|
+
// next GET rather than blocking retries for the full TTL window.
|
|
403
415
|
const totalActive = countActiveMemoryNodes(scopeId);
|
|
404
416
|
upsertCheckpoint(
|
|
405
417
|
checkpointKey(CK_ITEM_COUNT, scopeId),
|
|
406
418
|
String(totalActive),
|
|
407
419
|
now,
|
|
408
420
|
);
|
|
409
|
-
upsertCheckpoint(checkpointKey(CK_LAST_GEN_AT, scopeId), String(now), now);
|
|
410
421
|
return;
|
|
411
422
|
}
|
|
412
423
|
|
package/src/memory/jobs-store.ts
CHANGED
|
@@ -79,6 +79,11 @@ export const SLOW_LLM_JOB_TYPES: MemoryJobType[] = [
|
|
|
79
79
|
"graph_bootstrap",
|
|
80
80
|
];
|
|
81
81
|
|
|
82
|
+
export const MEMORY_V2_CONSOLIDATION_JOB_TRIGGERS = {
|
|
83
|
+
automatic: "automatic",
|
|
84
|
+
manual: "manual",
|
|
85
|
+
} as const;
|
|
86
|
+
|
|
82
87
|
/** Returns `false` only when `config.memory.enabled` is explicitly `false`; defaults to `true` on missing config or load errors. */
|
|
83
88
|
export function isMemoryEnabled(): boolean {
|
|
84
89
|
try {
|
|
@@ -337,6 +342,34 @@ export function hasActiveJobOfType(type: MemoryJobType): boolean {
|
|
|
337
342
|
);
|
|
338
343
|
}
|
|
339
344
|
|
|
345
|
+
export function isAutomaticConsolidationJob(job: MemoryJob): boolean {
|
|
346
|
+
return job.payload.trigger !== MEMORY_V2_CONSOLIDATION_JOB_TRIGGERS.manual;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export function cancelPendingAutomaticConsolidationJobs(): number {
|
|
350
|
+
const db = getDb();
|
|
351
|
+
db.update(memoryJobs)
|
|
352
|
+
.set({
|
|
353
|
+
status: "failed",
|
|
354
|
+
lastError: "automatic_consolidation_disabled",
|
|
355
|
+
updatedAt: Date.now(),
|
|
356
|
+
})
|
|
357
|
+
.where(
|
|
358
|
+
and(
|
|
359
|
+
eq(memoryJobs.type, "memory_v2_consolidate"),
|
|
360
|
+
eq(memoryJobs.status, "pending"),
|
|
361
|
+
or(
|
|
362
|
+
sql`json_extract(${memoryJobs.payload}, '$.trigger') = ${MEMORY_V2_CONSOLIDATION_JOB_TRIGGERS.automatic}`,
|
|
363
|
+
// Legacy rows predate trigger markers and are indistinguishable from
|
|
364
|
+
// automatic enqueues, so disabling the schedule treats them as auto.
|
|
365
|
+
sql`json_extract(${memoryJobs.payload}, '$.trigger') IS NULL`,
|
|
366
|
+
),
|
|
367
|
+
),
|
|
368
|
+
)
|
|
369
|
+
.run();
|
|
370
|
+
return rawChanges();
|
|
371
|
+
}
|
|
372
|
+
|
|
340
373
|
export function enqueuePruneOldLlmRequestLogsJob(retentionMs?: number): string {
|
|
341
374
|
const db = getDb();
|
|
342
375
|
const existing = db
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
diskPressureBackgroundSkipLogFields,
|
|
9
9
|
shouldLogDiskPressureBackgroundSkip,
|
|
10
10
|
} from "../daemon/disk-pressure-background-gate.js";
|
|
11
|
+
import { maintainJob as memoryV3MaintainJob } from "../plugins/defaults/memory-v3-shadow/maintain-job.js";
|
|
11
12
|
import { getLogger } from "../util/logger.js";
|
|
12
13
|
import { getWorkspaceDir } from "../util/platform.js";
|
|
13
14
|
import { getMemoryCheckpoint, setMemoryCheckpoint } from "./checkpoints.js";
|
|
@@ -67,6 +68,8 @@ import {
|
|
|
67
68
|
failMemoryJob,
|
|
68
69
|
failStalledJobs,
|
|
69
70
|
hasActiveJobOfType,
|
|
71
|
+
isAutomaticConsolidationJob,
|
|
72
|
+
MEMORY_V2_CONSOLIDATION_JOB_TRIGGERS,
|
|
70
73
|
type MemoryJob,
|
|
71
74
|
type MemoryJobType,
|
|
72
75
|
resetRunningJobsToPending,
|
|
@@ -85,10 +88,13 @@ import {
|
|
|
85
88
|
memoryV2ConsolidateJob,
|
|
86
89
|
} from "./v2/consolidation-job.js";
|
|
87
90
|
import { memoryV2SweepJob } from "./v2/sweep-job.js";
|
|
88
|
-
import { maintainJob as memoryV3MaintainJob } from "./v3/maintain-job.js";
|
|
89
91
|
|
|
90
92
|
const log = getLogger("memory-jobs-worker");
|
|
91
93
|
|
|
94
|
+
const AUTOMATIC_CONSOLIDATION_JOB_PAYLOAD = {
|
|
95
|
+
trigger: MEMORY_V2_CONSOLIDATION_JOB_TRIGGERS.automatic,
|
|
96
|
+
} as const;
|
|
97
|
+
|
|
92
98
|
/**
|
|
93
99
|
* V1 job types that read or write the v1 Qdrant collection via
|
|
94
100
|
* `getQdrantClient()`. When `memory.v2.enabled` is true, the v1 client is
|
|
@@ -609,6 +615,16 @@ async function processJob(
|
|
|
609
615
|
await memoryV2SweepJob(job, config);
|
|
610
616
|
return;
|
|
611
617
|
case "memory_v2_consolidate":
|
|
618
|
+
if (
|
|
619
|
+
isAutomaticConsolidationJob(job) &&
|
|
620
|
+
!config.memory.v2.consolidation_enabled
|
|
621
|
+
) {
|
|
622
|
+
log.info(
|
|
623
|
+
{ jobId: job.id },
|
|
624
|
+
"Skipping automatic memory v2 consolidation because scheduled consolidation is disabled",
|
|
625
|
+
);
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
612
628
|
await memoryV2ConsolidateJob(job, config);
|
|
613
629
|
return;
|
|
614
630
|
case "memory_v2_migrate":
|
|
@@ -734,6 +750,8 @@ export function maybeEnqueueGraphMaintenanceJobs(
|
|
|
734
750
|
nowMs = Date.now(),
|
|
735
751
|
): void {
|
|
736
752
|
const v2Active = config.memory.v2.enabled;
|
|
753
|
+
const v2ConsolidationAutomaticEnabled =
|
|
754
|
+
v2Active && config.memory.v2.consolidation_enabled;
|
|
737
755
|
|
|
738
756
|
// The single buffer-drainer entry for the v2-active branch. Referenced again
|
|
739
757
|
// below by the size-based trigger.
|
|
@@ -748,7 +766,9 @@ export function maybeEnqueueGraphMaintenanceJobs(
|
|
|
748
766
|
intervalMs: number;
|
|
749
767
|
jobType: MemoryJobType;
|
|
750
768
|
}> = v2Active
|
|
751
|
-
?
|
|
769
|
+
? v2ConsolidationAutomaticEnabled
|
|
770
|
+
? [consolidateEntry]
|
|
771
|
+
: []
|
|
752
772
|
: [
|
|
753
773
|
{
|
|
754
774
|
key: GRAPH_MAINTENANCE_CHECKPOINTS.decay,
|
|
@@ -795,7 +815,11 @@ export function maybeEnqueueGraphMaintenanceJobs(
|
|
|
795
815
|
for (const { key, intervalMs, jobType } of schedule) {
|
|
796
816
|
const lastRun = parseInt(getMemoryCheckpoint(key) ?? "0", 10);
|
|
797
817
|
if (nowMs - lastRun >= intervalMs) {
|
|
798
|
-
|
|
818
|
+
const payload =
|
|
819
|
+
jobType === consolidateEntry.jobType
|
|
820
|
+
? AUTOMATIC_CONSOLIDATION_JOB_PAYLOAD
|
|
821
|
+
: {};
|
|
822
|
+
enqueueMemoryJob(jobType, payload);
|
|
799
823
|
setMemoryCheckpoint(key, String(nowMs));
|
|
800
824
|
if (jobType === consolidateEntry.jobType) enqueuedConsolidate = true;
|
|
801
825
|
}
|
|
@@ -811,14 +835,17 @@ export function maybeEnqueueGraphMaintenanceJobs(
|
|
|
811
835
|
// buffer stays over threshold, flooding the queue with redundant LLM work.
|
|
812
836
|
const maxLines = config.memory.v2.consolidation_max_buffer_lines;
|
|
813
837
|
if (
|
|
814
|
-
|
|
838
|
+
v2ConsolidationAutomaticEnabled &&
|
|
815
839
|
!enqueuedConsolidate &&
|
|
816
840
|
maxLines !== null &&
|
|
817
841
|
!hasActiveJobOfType(consolidateEntry.jobType)
|
|
818
842
|
) {
|
|
819
843
|
const bufferPath = join(getWorkspaceDir(), "memory", "buffer.md");
|
|
820
844
|
if (countBufferLines(bufferPath) >= maxLines) {
|
|
821
|
-
enqueueMemoryJob(
|
|
845
|
+
enqueueMemoryJob(
|
|
846
|
+
consolidateEntry.jobType,
|
|
847
|
+
AUTOMATIC_CONSOLIDATION_JOB_PAYLOAD,
|
|
848
|
+
);
|
|
822
849
|
setMemoryCheckpoint(consolidateEntry.key, String(nowMs));
|
|
823
850
|
}
|
|
824
851
|
}
|