@vellumai/assistant 0.8.4 → 0.8.5
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 +2 -2
- package/docs/browser-use-architecture-phase2.md +1 -1
- package/knip.json +2 -1
- package/openapi.yaml +809 -11
- package/package.json +1 -1
- package/src/__tests__/anthropic-provider.test.ts +34 -37
- package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +293 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +3 -3
- package/src/__tests__/audit-log-rotation.test.ts +70 -16
- package/src/__tests__/background-workers-disk-pressure.test.ts +3 -3
- package/src/__tests__/btw-routes.test.ts +2 -3
- package/src/__tests__/call-controller.test.ts +0 -1
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
- package/src/__tests__/channel-guardian.test.ts +3 -3
- package/src/__tests__/checker.test.ts +6 -15
- package/src/__tests__/compaction-events.test.ts +1 -0
- package/src/__tests__/compactor-call-site-logging.test.ts +214 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +5 -11
- package/src/__tests__/computer-use-tools.test.ts +2 -4
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +197 -2
- package/src/__tests__/conversation-agent-loop.test.ts +163 -122
- package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -5
- package/src/__tests__/conversation-clear-safety.test.ts +25 -25
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +1 -1
- package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
- package/src/__tests__/conversation-error.test.ts +31 -0
- package/src/__tests__/conversation-fork-crud.test.ts +178 -15
- package/src/__tests__/conversation-lifecycle.test.ts +52 -11
- package/src/__tests__/{conversation-load-cleaned-at.test.ts → conversation-load-history-stripped.test.ts} +13 -13
- package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +109 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +35 -0
- package/src/__tests__/conversation-skill-tools.test.ts +2 -5
- package/src/__tests__/conversation-store.test.ts +1 -1
- package/src/__tests__/conversation-sync-tags.test.ts +99 -32
- package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +1 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -1
- package/src/__tests__/credential-execution-feature-gates.test.ts +9 -7
- package/src/__tests__/credential-execution-tools.test.ts +6 -6
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/credential-vault-unit.test.ts +2 -2
- package/src/__tests__/dynamic-page-surface.test.ts +2 -2
- package/src/__tests__/email-html-renderer.test.ts +12 -0
- package/src/__tests__/gateway-flag-listener.test.ts +237 -0
- package/src/__tests__/gemini-provider.test.ts +78 -0
- package/src/__tests__/guardian-dispatch.test.ts +0 -1
- package/src/__tests__/guardian-outbound-http.test.ts +7 -5
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
- package/src/__tests__/heartbeat-service.test.ts +4 -0
- package/src/__tests__/host-shell-tool.test.ts +1 -1
- package/src/__tests__/init-feature-flag-overrides.test.ts +5 -6
- package/src/__tests__/list-messages-tool-merge.test.ts +70 -11
- package/src/__tests__/llm-request-log-call-site.test.ts +136 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +26 -0
- package/src/__tests__/llm-resolver.test.ts +77 -9
- package/src/__tests__/llm-usage-store.test.ts +66 -0
- package/src/__tests__/logger.test.ts +89 -0
- package/src/__tests__/mcp-abort-signal.test.ts +2 -2
- package/src/__tests__/media-generate-image.test.ts +31 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +7 -7
- package/src/__tests__/model-intents.test.ts +2 -4
- package/src/__tests__/notification-guardian-path.test.ts +0 -1
- package/src/__tests__/onboarding-template-contract.test.ts +1 -1
- package/src/__tests__/openai-provider.test.ts +46 -0
- package/src/__tests__/openai-responses-provider.test.ts +114 -12
- package/src/__tests__/pending-interactions-resolved-event.test.ts +0 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +2 -2
- package/src/__tests__/platform.test.ts +2 -2
- package/src/__tests__/plugin-api-tool-definition.test.ts +92 -0
- package/src/__tests__/plugin-bootstrap.test.ts +2 -2
- package/src/__tests__/plugin-tool-contribution.test.ts +13 -6
- package/src/__tests__/plugin-types.test.ts +3 -2
- package/src/__tests__/prechat-onboarding-contract.test.ts +131 -98
- package/src/__tests__/pricing.test.ts +12 -0
- package/src/__tests__/prune-jobs-changes-parser.test.ts +61 -0
- package/src/__tests__/registry.test.ts +2 -8
- package/src/__tests__/require-fresh-approval.test.ts +2 -2
- package/src/__tests__/runtime-events-sse-bilingual.test.ts +154 -0
- package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/skill-projection-feature-flag.test.ts +4 -7
- package/src/__tests__/skill-projection.benchmark.test.ts +2 -6
- package/src/__tests__/skill-tool-factory.test.ts +1 -1
- package/src/__tests__/subagent-notify-parent.test.ts +1 -1
- package/src/__tests__/suggestion-routes.test.ts +1 -0
- package/src/__tests__/sync-message-contract.test.ts +59 -0
- package/src/__tests__/system-prompt.test.ts +145 -131
- package/src/__tests__/terminal-tools.test.ts +1 -1
- package/src/__tests__/tool-approval-handler.test.ts +1 -5
- package/src/__tests__/tool-execute-pipeline.test.ts +2 -2
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -5
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +15 -5
- package/src/__tests__/tool-executor.test.ts +9 -62
- package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -6
- package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
- package/src/__tests__/ui-file-upload-surface.test.ts +2 -2
- package/src/__tests__/usage-routes.test.ts +3 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
- package/src/__tests__/workspace-git-service.test.ts +6 -5
- package/src/__tests__/workspace-migration-089-move-memory-tree-out-of-v3.test.ts +86 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +146 -0
- package/src/acp/prepare-agent-env.ts +78 -0
- package/src/acp/session-manager.ts +1 -1
- package/src/agent/loop.ts +8 -0
- package/src/api/README.md +5 -0
- package/src/api/index.ts +4 -0
- package/src/api/package.json +10 -0
- package/src/background-wake/background-wake-routes.test.ts +233 -0
- package/src/background-wake/runtime-registry.ts +24 -0
- package/src/cli/commands/__tests__/browser.test.ts +23 -5
- package/src/cli/commands/__tests__/domain-register.test.ts +110 -0
- package/src/cli/commands/__tests__/domain-status.test.ts +33 -33
- package/src/cli/commands/__tests__/inference-send.test.ts +108 -5
- package/src/cli/commands/__tests__/memory-v2-compare-render.test.ts +98 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +1 -0
- package/src/cli/commands/__tests__/memory-v3-render.test.ts +340 -0
- package/src/cli/commands/browser.ts +247 -0
- package/src/cli/commands/domain.ts +91 -41
- package/src/cli/commands/inference.ts +93 -40
- package/src/cli/commands/memory-v2-compare-render.ts +115 -0
- package/src/cli/commands/memory-v2.ts +176 -1
- package/src/cli/commands/memory-v3-render.ts +344 -0
- package/src/cli/commands/memory-v3.ts +316 -0
- package/src/cli/program.ts +2 -0
- package/src/config/assistant-feature-flags.ts +21 -9
- package/src/config/bundled-skills/document-editor/SKILL.md +11 -2
- package/src/config/bundled-skills/document-editor/TOOLS.json +18 -0
- package/src/config/bundled-skills/document-editor/tools/document-open.ts +12 -0
- package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
- package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +13 -8
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +10 -3
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +16 -14
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +7 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -2
- package/src/config/bundled-tool-registry.ts +2 -0
- package/src/config/call-site-defaults.ts +7 -6
- package/src/config/feature-flag-registry.json +16 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +213 -1
- package/src/config/schemas/call-site-catalog.ts +21 -7
- package/src/config/schemas/llm.ts +12 -1
- package/src/config/schemas/memory-v2.ts +246 -0
- package/src/config/schemas/memory.ts +2 -1
- package/src/context/compactor.ts +52 -0
- package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
- package/src/conversations/message-consolidation.ts +404 -0
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -1
- package/src/daemon/__tests__/meet-manifest-loader.test.ts +1 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +2 -13
- package/src/daemon/conversation-agent-loop.ts +126 -76
- package/src/daemon/conversation-error.ts +31 -1
- package/src/daemon/conversation-lifecycle.ts +27 -22
- package/src/daemon/conversation-runtime-assembly.ts +10 -9
- package/src/daemon/conversation-tool-setup.ts +63 -3
- package/src/daemon/conversation-usage.ts +2 -0
- package/src/daemon/conversation.ts +14 -29
- package/src/daemon/disk-pressure-guard.ts +14 -2
- package/src/daemon/handlers/config-model.test.ts +1 -0
- package/src/daemon/handlers/conversations.ts +11 -3
- package/src/daemon/host-browser-proxy.ts +5 -5
- package/src/daemon/host-cu-proxy.ts +4 -4
- package/src/daemon/host-file-proxy.ts +4 -4
- package/src/daemon/host-proxy-base.ts +4 -4
- package/src/daemon/host-transfer-proxy.ts +10 -10
- package/src/daemon/lifecycle.ts +23 -20
- package/src/daemon/meet-manifest-loader.ts +1 -7
- package/src/daemon/message-types/conversations.ts +6 -9
- package/src/daemon/message-types/home.ts +1 -13
- package/src/daemon/message-types/messages.ts +6 -14
- package/src/daemon/message-types/sync.ts +14 -0
- package/src/daemon/shutdown-handlers.ts +24 -5
- package/src/daemon/switch-inference-profile-tool.ts +52 -0
- package/src/daemon/tool-setup-types.ts +13 -0
- package/src/events/relationship-state-updated.ts +25 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +1 -1
- package/src/home/home-greeting.ts +0 -9
- package/src/home/suggested-prompts.ts +0 -9
- package/src/ipc/gateway-flag-listener.ts +123 -0
- package/src/ipc/skill-routes/registries.ts +8 -12
- package/src/memory/__tests__/db-async-query.test.ts +165 -0
- package/src/memory/__tests__/db-maintenance.test.ts +115 -0
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +241 -0
- package/src/memory/__tests__/jobs-store-job-classes.test.ts +28 -1
- package/src/memory/__tests__/memory-retrospective-job.test.ts +7 -0
- package/src/memory/auto-analysis-enqueue.ts +5 -1
- package/src/memory/conversation-crud.ts +71 -70
- package/src/memory/conversation-starters-cadence.ts +3 -1
- package/src/memory/conversation-title-service.ts +19 -3
- package/src/memory/db-async-query.ts +214 -0
- package/src/memory/db-init.ts +10 -0
- package/src/memory/db-maintenance.ts +30 -21
- package/src/memory/graph/bootstrap.ts +8 -1
- package/src/memory/graph/capability-seed.ts +7 -3
- package/src/memory/graph/conversation-graph-memory.ts +100 -17
- package/src/memory/graph/extraction.ts +1 -5
- package/src/memory/graph/graph-search.ts +7 -1
- package/src/memory/indexer.ts +28 -18
- package/src/memory/job-handlers/cleanup.ts +76 -18
- package/src/memory/job-handlers/conversation-starters.ts +1 -4
- package/src/memory/jobs/embed-pkb-file.ts +6 -1
- package/src/memory/jobs-store.ts +14 -0
- package/src/memory/jobs-worker.ts +55 -22
- package/src/memory/llm-request-log-source-clickhouse.ts +42 -2
- package/src/memory/llm-request-log-source-local.ts +7 -0
- package/src/memory/llm-request-log-source.ts +9 -2
- package/src/memory/llm-request-log-store.ts +43 -1
- package/src/memory/llm-usage-store.ts +24 -0
- package/src/memory/memory-retrospective-enqueue.ts +8 -1
- package/src/memory/memory-retrospective-job.ts +5 -0
- package/src/memory/memory-v2-activation-log-store.ts +15 -6
- package/src/memory/migrations/260-rename-cleaned-at.ts +44 -0
- package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +36 -0
- package/src/memory/migrations/262-memory-v3-coactivation.ts +57 -0
- package/src/memory/migrations/263-memory-v3-auto-edges.ts +50 -0
- package/src/memory/migrations/264-llm-request-log-call-site.ts +29 -0
- package/src/memory/migrations/index.ts +17 -0
- package/src/memory/migrations/registry.ts +33 -0
- package/src/memory/schema/conversations.ts +1 -1
- package/src/memory/schema/infrastructure.ts +21 -0
- package/src/memory/tool-usage-store.ts +36 -8
- package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -0
- package/src/memory/v2/__tests__/harness-compare.test.ts +186 -0
- package/src/memory/v2/__tests__/harness-metrics.test.ts +74 -0
- package/src/memory/v2/__tests__/harness-oracle.test.ts +257 -0
- package/src/memory/v2/__tests__/harness-replay-input.test.ts +225 -0
- package/src/memory/v2/__tests__/harness-runner.test.ts +109 -0
- package/src/memory/v2/__tests__/injection.test.ts +127 -98
- package/src/memory/v2/__tests__/qdrant.test.ts +36 -0
- package/src/memory/v2/__tests__/router.test.ts +171 -3
- package/src/memory/v2/harness/compare.ts +57 -0
- package/src/memory/v2/harness/metrics.ts +124 -0
- package/src/memory/v2/harness/oracle.ts +145 -0
- package/src/memory/v2/harness/replay-input.ts +224 -0
- package/src/memory/v2/harness/retriever.ts +74 -0
- package/src/memory/v2/harness/router-retriever.ts +43 -0
- package/src/memory/v2/harness/runner.ts +106 -0
- package/src/memory/v2/harness/trace.ts +58 -0
- package/src/memory/v2/injection.ts +21 -15
- package/src/memory/v2/prompts/router.ts +26 -1
- package/src/memory/v2/qdrant.ts +14 -2
- package/src/memory/v2/router.ts +171 -18
- package/src/memory/v3/__tests__/coactivation-store.test.ts +422 -0
- package/src/memory/v3/__tests__/consolidation-job.test.ts +468 -0
- package/src/memory/v3/__tests__/edge-learning-job.test.ts +324 -0
- package/src/memory/v3/__tests__/edges.test.ts +563 -0
- package/src/memory/v3/__tests__/filter.test.ts +512 -0
- package/src/memory/v3/__tests__/gate.test.ts +574 -0
- package/src/memory/v3/__tests__/index-composition.test.ts +233 -0
- package/src/memory/v3/__tests__/loop.test.ts +530 -0
- package/src/memory/v3/__tests__/retriever.test.ts +226 -0
- package/src/memory/v3/__tests__/scouts.test.ts +440 -0
- package/src/memory/v3/__tests__/shadow-middleware.test.ts +312 -0
- package/src/memory/v3/__tests__/system-prompts.test.ts +154 -0
- package/src/memory/v3/__tests__/traversal.test.ts +469 -0
- package/src/memory/v3/__tests__/tree-index.test.ts +280 -0
- package/src/memory/v3/__tests__/tree-store.test.ts +529 -0
- package/src/memory/v3/__tests__/tree-walk.test.ts +707 -0
- package/src/memory/v3/__tests__/validate.test.ts +245 -0
- package/src/memory/v3/auto-edges.ts +223 -0
- package/src/memory/v3/coactivation-store.ts +124 -0
- package/src/memory/v3/consolidation-job.ts +323 -0
- package/src/memory/v3/edge-learning-job.ts +160 -0
- package/src/memory/v3/edges.ts +249 -0
- package/src/memory/v3/filter.ts +281 -0
- package/src/memory/v3/gate.ts +334 -0
- package/src/memory/v3/index-composition.ts +113 -0
- package/src/memory/v3/llm-capture.ts +46 -0
- package/src/memory/v3/loop.ts +382 -0
- package/src/memory/v3/maintenance.ts +144 -0
- package/src/memory/v3/prompt-context.ts +33 -0
- package/src/memory/v3/prompts/consolidation.ts +458 -0
- package/src/memory/v3/prompts/system-prompts.ts +196 -0
- package/src/memory/v3/retriever.ts +33 -0
- package/src/memory/v3/scouts.ts +420 -0
- package/src/memory/v3/shadow-middleware.ts +305 -0
- package/src/memory/v3/traversal.ts +206 -0
- package/src/memory/v3/tree-index.ts +237 -0
- package/src/memory/v3/tree-store.ts +394 -0
- package/src/memory/v3/tree-walk.ts +351 -0
- package/src/memory/v3/types.ts +65 -0
- package/src/memory/v3/validate.ts +300 -0
- package/src/notifications/adapters/macos.ts +18 -1
- package/src/notifications/adapters/platform.ts +1 -1
- package/src/notifications/decision-engine.ts +1 -4
- package/src/notifications/emit-signal.ts +29 -49
- package/src/permissions/prompter.ts +3 -3
- package/src/permissions/question-prompter.ts +5 -2
- package/src/permissions/secret-prompter.ts +2 -2
- package/src/plugin-api/index.ts +4 -0
- package/src/plugin-api/types.ts +7 -33
- package/src/plugins/defaults/index.ts +6 -0
- package/src/plugins/defaults/injectors.ts +18 -11
- package/src/plugins/external-plugin-loader.ts +5 -68
- package/src/plugins/types.ts +11 -16
- package/src/proactive-artifact/aux-message-injector.ts +17 -4
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +3 -9
- package/src/prompts/persona-resolver.ts +36 -21
- package/src/prompts/sections.ts +39 -7
- package/src/prompts/system-prompt.ts +50 -185
- package/src/prompts/templates/BOOTSTRAP.md +2 -2
- package/src/prompts/templates/system-sections.ts +230 -8
- package/src/providers/__tests__/connection-model-compat.test.ts +234 -0
- package/src/providers/__tests__/retry-callsite.test.ts +85 -5
- package/src/providers/anthropic/client.ts +32 -66
- package/src/providers/call-site-routing.ts +14 -2
- package/src/providers/connection-model-compat.ts +38 -0
- package/src/providers/connection-resolution.ts +16 -2
- package/src/providers/gemini/client.ts +49 -6
- package/src/providers/inference/adapter-factory.ts +3 -0
- package/src/providers/minimax/client.ts +106 -0
- package/src/providers/model-catalog.ts +43 -0
- package/src/providers/model-intents.ts +1 -1
- package/src/providers/openai/chat-completions-provider.ts +6 -3
- package/src/providers/openai/codex-models.ts +18 -0
- package/src/providers/openai/responses-provider.ts +78 -21
- package/src/providers/provider-send-message.ts +7 -1
- package/src/providers/retry.ts +34 -3
- package/src/providers/thinking-config.ts +26 -1
- package/src/providers/usage-tracking.ts +2 -0
- package/src/runtime/AGENTS.md +2 -2
- package/src/runtime/agent-wake.ts +1 -0
- package/src/runtime/assistant-event-hub.ts +76 -6
- package/src/runtime/auth/route-policy.ts +36 -0
- package/src/runtime/btw-sidechain.ts +0 -6
- package/src/runtime/http-types.ts +0 -2
- package/src/runtime/migrations/vbundle-builder.ts +10 -3
- package/src/runtime/pending-interactions.ts +0 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +106 -0
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +25 -6
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -0
- package/src/runtime/routes/acp-routes.test.ts +255 -6
- package/src/runtime/routes/acp-routes.ts +8 -1
- package/src/runtime/routes/avatar-routes.ts +10 -10
- package/src/runtime/routes/background-wake-routes.ts +188 -0
- package/src/runtime/routes/browser-tabs-routes.ts +200 -0
- package/src/runtime/routes/btw-routes.ts +0 -6
- package/src/runtime/routes/conversation-cli-routes.ts +1 -1
- package/src/runtime/routes/conversation-list-routes.ts +12 -4
- package/src/runtime/routes/conversation-management-routes.ts +77 -20
- package/src/runtime/routes/conversation-query-routes.ts +142 -36
- package/src/runtime/routes/conversation-routes.ts +252 -410
- package/src/runtime/routes/conversation-starter-routes.ts +6 -3
- package/src/runtime/routes/disk-pressure-routes.ts +1 -1
- package/src/runtime/routes/domain-routes.ts +60 -10
- package/src/runtime/routes/email-routes.ts +5 -2
- package/src/runtime/routes/events-routes.ts +54 -10
- package/src/runtime/routes/group-routes.ts +24 -8
- package/src/runtime/routes/host-browser-routes.ts +10 -2
- package/src/runtime/routes/host-cu-routes.ts +2 -2
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +96 -3
- package/src/runtime/routes/index.ts +8 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +22 -12
- package/src/runtime/routes/inference-profile-session-routes.ts +7 -1
- package/src/runtime/routes/llm-call-sites-routes.ts +32 -5
- package/src/runtime/routes/memory-item-routes.ts +8 -3
- package/src/runtime/routes/memory-v2-routes.ts +215 -5
- package/src/runtime/routes/memory-v3-routes.ts +316 -0
- package/src/runtime/routes/migration-routes.ts +21 -24
- package/src/runtime/routes/plugins-routes.ts +337 -0
- package/src/runtime/routes/rename-conversation-routes.ts +6 -2
- package/src/runtime/routes/secret-routes.ts +25 -5
- package/src/runtime/routes/settings-routes.ts +12 -11
- package/src/runtime/routes/slack-channel-routes.ts +5 -4
- package/src/runtime/routes/workspace-routes.ts +25 -10
- package/src/runtime/sync/resource-sync-events.ts +106 -38
- package/src/runtime/sync/sync-publisher.test.ts +49 -0
- package/src/runtime/sync/sync-publisher.ts +2 -1
- package/src/runtime/verification-outbound-actions.ts +73 -1
- package/src/telemetry/types.ts +12 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
- package/src/telemetry/usage-telemetry-reporter.ts +1 -0
- package/src/tools/acp/spawn.test.ts +119 -0
- package/src/tools/acp/spawn.ts +15 -2
- package/src/tools/apps/definitions.ts +2 -8
- package/src/tools/ask-question/ask-question-tool.test.ts +3 -3
- package/src/tools/ask-question/ask-question-tool.ts +38 -45
- package/src/tools/browser/__tests__/pinned-tabs.test.ts +70 -0
- package/src/tools/browser/browser-execution.ts +16 -3
- package/src/tools/browser/cdp-client/__tests__/browser-tabs-factory.test.ts +402 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +3 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +12 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +27 -1
- package/src/tools/browser/cdp-client/factory.ts +100 -17
- package/src/tools/browser/cdp-client/local-cdp-client.ts +12 -0
- package/src/tools/browser/cdp-client/types.ts +65 -0
- package/src/tools/browser/pinned-tabs.ts +96 -40
- package/src/tools/computer-use/definitions.ts +22 -78
- package/src/tools/credential-execution/make-authenticated-request.ts +3 -9
- package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -9
- package/src/tools/credential-execution/run-authenticated-command.ts +3 -9
- package/src/tools/credentials/vault.ts +3 -9
- package/src/tools/document/document-tool.ts +59 -0
- package/src/tools/execution-target.ts +21 -23
- package/src/tools/executor.ts +6 -1
- package/src/tools/filesystem/edit.ts +3 -9
- package/src/tools/filesystem/list.ts +3 -9
- package/src/tools/filesystem/read.ts +3 -9
- package/src/tools/filesystem/write.ts +3 -9
- package/src/tools/host-filesystem/edit.ts +3 -9
- package/src/tools/host-filesystem/read.ts +3 -9
- package/src/tools/host-filesystem/transfer.ts +3 -9
- package/src/tools/host-filesystem/write.ts +3 -9
- package/src/tools/host-terminal/host-shell.ts +3 -9
- package/src/tools/mcp/mcp-tool-factory.ts +1 -8
- package/src/tools/memory/register.test.ts +1 -1
- package/src/tools/memory/register.ts +4 -9
- package/src/tools/network/web-fetch.ts +3 -9
- package/src/tools/network/web-search.ts +25 -32
- package/src/tools/registry.ts +7 -23
- package/src/tools/schema-transforms.ts +1 -1
- package/src/tools/skills/execute.ts +3 -9
- package/src/tools/skills/load.ts +3 -9
- package/src/tools/skills/skill-tool-factory.ts +1 -8
- package/src/tools/subagent/notify-parent.ts +3 -9
- package/src/tools/system/request-permission.ts +3 -9
- package/src/tools/terminal/shell.ts +3 -9
- package/src/tools/tool-defaults.ts +94 -0
- package/src/tools/types.ts +27 -98
- package/src/tools/ui-surface/definitions.ts +6 -22
- package/src/usage/pricing.ts +23 -0
- package/src/usage/types.ts +12 -0
- package/src/util/logger.ts +16 -7
- package/src/util/platform.ts +7 -2
- package/src/util/sqlite3-runtime.ts +65 -0
- package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +1 -0
- package/src/workspace/migrations/089-move-memory-tree-out-of-v3.ts +86 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +0 -206
- package/src/__tests__/message-complete-display-id.test.ts +0 -175
- package/src/daemon/query-complexity-router.ts +0 -75
- package/src/prompts/cache-boundary.ts +0 -8
|
@@ -12,7 +12,6 @@ import { join } from "node:path";
|
|
|
12
12
|
import { and, asc, desc, eq, gt } from "drizzle-orm";
|
|
13
13
|
|
|
14
14
|
import type { AssistantConfig } from "../../config/types.js";
|
|
15
|
-
import { resolveGuardianPersona } from "../../prompts/persona-resolver.js";
|
|
16
15
|
import { buildCoreIdentityContext } from "../../prompts/system-prompt.js";
|
|
17
16
|
import {
|
|
18
17
|
extractToolUse,
|
|
@@ -1026,10 +1025,7 @@ export async function runGraphExtraction(
|
|
|
1026
1025
|
const candidateNodeIds = new Set(candidateNodes.map((n) => n.id));
|
|
1027
1026
|
|
|
1028
1027
|
// 4. Build prompt
|
|
1029
|
-
const
|
|
1030
|
-
const identityContext = buildCoreIdentityContext({
|
|
1031
|
-
userPersona: userPersona ?? undefined,
|
|
1032
|
-
});
|
|
1028
|
+
const identityContext = buildCoreIdentityContext();
|
|
1033
1029
|
|
|
1034
1030
|
const activeSet = opts?.activeContextNodeIds
|
|
1035
1031
|
? new Set(opts.activeContextNodeIds)
|
|
@@ -9,7 +9,11 @@ import { selectedBackendSupportsMultimodal } from "../embedding-backend.js";
|
|
|
9
9
|
import type { EmbeddingInput } from "../embedding-types.js";
|
|
10
10
|
import { embedAndUpsert } from "../job-utils.js";
|
|
11
11
|
import { asString } from "../job-utils.js";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
enqueueMemoryJob,
|
|
14
|
+
isMemoryEnabled,
|
|
15
|
+
type MemoryJob,
|
|
16
|
+
} from "../jobs-store.js";
|
|
13
17
|
import { isQdrantBreakerOpen } from "../qdrant-circuit-breaker.js";
|
|
14
18
|
import { withQdrantBreaker } from "../qdrant-circuit-breaker.js";
|
|
15
19
|
import {
|
|
@@ -238,6 +242,7 @@ export async function embedGraphNodeJob(
|
|
|
238
242
|
* Enqueue an embedding job for a graph node (async, for live conversations).
|
|
239
243
|
*/
|
|
240
244
|
export function enqueueGraphNodeEmbed(nodeId: string): void {
|
|
245
|
+
if (!isMemoryEnabled()) return;
|
|
241
246
|
enqueueMemoryJob("embed_graph_node", { nodeId });
|
|
242
247
|
}
|
|
243
248
|
|
|
@@ -282,5 +287,6 @@ export async function embedGraphTriggerJob(
|
|
|
282
287
|
* Enqueue a trigger embedding job.
|
|
283
288
|
*/
|
|
284
289
|
export function enqueueGraphTriggerEmbed(triggerId: string): void {
|
|
290
|
+
if (!isMemoryEnabled()) return;
|
|
285
291
|
enqueueMemoryJob("graph_trigger_embed", { triggerId });
|
|
286
292
|
}
|
package/src/memory/indexer.ts
CHANGED
|
@@ -11,7 +11,11 @@ import { isAutoAnalysisConversation } from "./auto-analysis-guard.js";
|
|
|
11
11
|
import { getMemoryCheckpoint, setMemoryCheckpoint } from "./checkpoints.js";
|
|
12
12
|
import { getDb } from "./db-connection.js";
|
|
13
13
|
import { selectedBackendSupportsMultimodal } from "./embedding-backend.js";
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
enqueueMemoryJob,
|
|
16
|
+
isMemoryEnabled,
|
|
17
|
+
upsertDebouncedJob,
|
|
18
|
+
} from "./jobs-store.js";
|
|
15
19
|
import { isMemoryRetrospectiveConversation } from "./memory-retrospective-enqueue.js";
|
|
16
20
|
import { maybeEnqueueRetrospective } from "./memory-retrospective-trigger-check.js";
|
|
17
21
|
import {
|
|
@@ -139,20 +143,22 @@ export async function indexMessageNow(
|
|
|
139
143
|
|
|
140
144
|
if (existing?.contentHash === hash) {
|
|
141
145
|
skippedEmbedJobs++;
|
|
142
|
-
} else {
|
|
146
|
+
} else if (isMemoryEnabled()) {
|
|
143
147
|
enqueueMemoryJob("embed_segment", { segmentId }, Date.now(), tx);
|
|
144
148
|
}
|
|
145
149
|
}
|
|
146
150
|
|
|
147
151
|
// Enqueue embed_attachment jobs for image content blocks when the
|
|
148
152
|
// embedding provider supports multimodal (Gemini only).
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
153
|
+
if (isMemoryEnabled()) {
|
|
154
|
+
for (const block of mediaBlocks) {
|
|
155
|
+
enqueueMemoryJob(
|
|
156
|
+
"embed_attachment",
|
|
157
|
+
{ messageId: input.messageId, blockIndex: block.index },
|
|
158
|
+
Date.now(),
|
|
159
|
+
tx,
|
|
160
|
+
);
|
|
161
|
+
}
|
|
156
162
|
}
|
|
157
163
|
});
|
|
158
164
|
|
|
@@ -221,14 +227,16 @@ export async function indexMessageNow(
|
|
|
221
227
|
extractRunAfter = graphBatchFired
|
|
222
228
|
? Date.now()
|
|
223
229
|
: Date.now() + idleTimeoutMs;
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
230
|
+
if (isMemoryEnabled()) {
|
|
231
|
+
upsertDebouncedJob(
|
|
232
|
+
"graph_extract",
|
|
233
|
+
{
|
|
234
|
+
conversationId: input.conversationId,
|
|
235
|
+
scopeId: input.scopeId ?? "default",
|
|
236
|
+
},
|
|
237
|
+
extractRunAfter,
|
|
238
|
+
);
|
|
239
|
+
}
|
|
232
240
|
} else {
|
|
233
241
|
extractRunAfter = Date.now() + idleTimeoutMs;
|
|
234
242
|
}
|
|
@@ -309,7 +317,7 @@ export async function indexMessageNow(
|
|
|
309
317
|
// jobs-worker.ts. Debounced on the same idle timeout — no threshold
|
|
310
318
|
// trigger needed since summaries compress the whole conversation, not
|
|
311
319
|
// incremental batches.
|
|
312
|
-
if (v2Config == null) {
|
|
320
|
+
if (v2Config == null && isMemoryEnabled()) {
|
|
313
321
|
upsertDebouncedJob(
|
|
314
322
|
"build_conversation_summary",
|
|
315
323
|
{ conversationId: input.conversationId },
|
|
@@ -372,10 +380,12 @@ export async function indexMessageNow(
|
|
|
372
380
|
}
|
|
373
381
|
|
|
374
382
|
export function enqueueBackfillJob(force = false): string {
|
|
383
|
+
if (!isMemoryEnabled()) return "";
|
|
375
384
|
return enqueueMemoryJob("backfill", { force });
|
|
376
385
|
}
|
|
377
386
|
|
|
378
387
|
export function enqueueRebuildIndexJob(): string {
|
|
388
|
+
if (!isMemoryEnabled()) return "";
|
|
379
389
|
return enqueueMemoryJob("rebuild_index", {});
|
|
380
390
|
}
|
|
381
391
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { AssistantConfig } from "../../config/types.js";
|
|
2
2
|
import { getLogger } from "../../util/logger.js";
|
|
3
|
+
import { runAsyncSqlite } from "../db-async-query.js";
|
|
3
4
|
import { getDb } from "../db-connection.js";
|
|
4
5
|
import { enqueueMemoryJob, type MemoryJob } from "../jobs-store.js";
|
|
5
|
-
import { rawAll,
|
|
6
|
+
import { rawAll, rawRun } from "../raw-query.js";
|
|
6
7
|
|
|
7
8
|
const log = getLogger("memory-jobs-worker");
|
|
8
9
|
|
|
@@ -13,11 +14,18 @@ const PRUNE_LOG_BATCH_LIMIT = 1000;
|
|
|
13
14
|
* Delete LLM request/response logs older than the configured retention period.
|
|
14
15
|
* Processes in batches to avoid long DB locks and excessive WAL growth.
|
|
15
16
|
* Re-enqueues itself if more rows remain.
|
|
17
|
+
*
|
|
18
|
+
* The DELETE is dispatched through `runAsyncSqlite` so it runs in a
|
|
19
|
+
* sqlite3 subprocess (when available) and does not block the daemon's
|
|
20
|
+
* main event loop. The two bind parameters (`cutoffMs`, batch limit)
|
|
21
|
+
* are integers — they're inlined directly into the SQL after a
|
|
22
|
+
* `Math.floor` + `Number.isFinite` guard so there is no string
|
|
23
|
+
* interpolation surface.
|
|
16
24
|
*/
|
|
17
|
-
export function pruneOldLlmRequestLogsJob(
|
|
25
|
+
export async function pruneOldLlmRequestLogsJob(
|
|
18
26
|
job: MemoryJob,
|
|
19
27
|
config: AssistantConfig,
|
|
20
|
-
): void {
|
|
28
|
+
): Promise<void> {
|
|
21
29
|
const rawRetention = job.payload.retentionMs;
|
|
22
30
|
const retentionMs =
|
|
23
31
|
rawRetention === null
|
|
@@ -31,14 +39,29 @@ export function pruneOldLlmRequestLogsJob(
|
|
|
31
39
|
// null means "keep forever" — skip pruning entirely
|
|
32
40
|
if (retentionMs === null || retentionMs === undefined) return;
|
|
33
41
|
|
|
34
|
-
const cutoffMs = Date.now() - retentionMs;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
const cutoffMs = Math.floor(Date.now() - retentionMs);
|
|
43
|
+
if (!Number.isFinite(cutoffMs)) return;
|
|
44
|
+
|
|
45
|
+
// Inline the cutoff and batch limit (both integers, both validated)
|
|
46
|
+
// and chain `SELECT changes()` so we can read the row count from the
|
|
47
|
+
// subprocess's stdout. The sqlite3 CLI prints `changes()` as a bare
|
|
48
|
+
// integer on its own line in default output mode; the in-process
|
|
49
|
+
// fallback backend in `db-async-query.ts` synthesizes the same shape
|
|
50
|
+
// by capturing `changes()` atomically after `exec()`. Both backends
|
|
51
|
+
// end up on the parser path below.
|
|
52
|
+
const result = await runAsyncSqlite(
|
|
53
|
+
`DELETE FROM llm_request_logs WHERE rowid IN (SELECT rowid FROM llm_request_logs WHERE created_at < ${cutoffMs} LIMIT ${PRUNE_LOG_BATCH_LIMIT});
|
|
54
|
+
SELECT changes();`,
|
|
40
55
|
);
|
|
41
|
-
|
|
56
|
+
if (!result.ok) {
|
|
57
|
+
log.warn(
|
|
58
|
+
{ error: result.error, backend: result.backend },
|
|
59
|
+
"pruneOldLlmRequestLogsJob: DELETE failed",
|
|
60
|
+
);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const deleted = parseDeletedCount(result.stdout);
|
|
42
65
|
|
|
43
66
|
if (deleted >= PRUNE_LOG_BATCH_LIMIT) {
|
|
44
67
|
enqueueMemoryJob("prune_old_llm_request_logs", { retentionMs });
|
|
@@ -58,11 +81,14 @@ export function pruneOldLlmRequestLogsJob(
|
|
|
58
81
|
* Delete trace events older than the configured retention period.
|
|
59
82
|
* Processes in batches to avoid long DB locks and excessive WAL growth.
|
|
60
83
|
* Re-enqueues itself if more rows remain.
|
|
84
|
+
*
|
|
85
|
+
* Same async dispatch + integer inlining shape as
|
|
86
|
+
* {@link pruneOldLlmRequestLogsJob}.
|
|
61
87
|
*/
|
|
62
|
-
export function pruneOldTraceEventsJob(
|
|
88
|
+
export async function pruneOldTraceEventsJob(
|
|
63
89
|
job: MemoryJob,
|
|
64
90
|
config: AssistantConfig,
|
|
65
|
-
): void {
|
|
91
|
+
): Promise<void> {
|
|
66
92
|
const rawRetention = job.payload.retentionDays;
|
|
67
93
|
const retentionDays =
|
|
68
94
|
typeof rawRetention === "number" &&
|
|
@@ -74,14 +100,22 @@ export function pruneOldTraceEventsJob(
|
|
|
74
100
|
// 0 means disabled
|
|
75
101
|
if (retentionDays === 0) return;
|
|
76
102
|
|
|
77
|
-
const cutoffMs = Date.now() - retentionDays * 86_400_000;
|
|
103
|
+
const cutoffMs = Math.floor(Date.now() - retentionDays * 86_400_000);
|
|
104
|
+
if (!Number.isFinite(cutoffMs)) return;
|
|
78
105
|
|
|
79
|
-
|
|
80
|
-
`DELETE FROM trace_events WHERE rowid IN (SELECT rowid FROM trace_events WHERE created_at <
|
|
81
|
-
|
|
82
|
-
PRUNE_LOG_BATCH_LIMIT,
|
|
106
|
+
const result = await runAsyncSqlite(
|
|
107
|
+
`DELETE FROM trace_events WHERE rowid IN (SELECT rowid FROM trace_events WHERE created_at < ${cutoffMs} LIMIT ${PRUNE_LOG_BATCH_LIMIT});
|
|
108
|
+
SELECT changes();`,
|
|
83
109
|
);
|
|
84
|
-
|
|
110
|
+
if (!result.ok) {
|
|
111
|
+
log.warn(
|
|
112
|
+
{ error: result.error, backend: result.backend },
|
|
113
|
+
"pruneOldTraceEventsJob: DELETE failed",
|
|
114
|
+
);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const deleted = parseDeletedCount(result.stdout);
|
|
85
119
|
|
|
86
120
|
if (deleted >= PRUNE_LOG_BATCH_LIMIT) {
|
|
87
121
|
enqueueMemoryJob("prune_old_trace_events", { retentionDays });
|
|
@@ -97,6 +131,30 @@ export function pruneOldTraceEventsJob(
|
|
|
97
131
|
);
|
|
98
132
|
}
|
|
99
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Parse the `SELECT changes()` result emitted by the sqlite3 CLI after
|
|
136
|
+
* the prune DELETE. Returns 0 if stdout is missing or unparseable —
|
|
137
|
+
* callers treat that the same as "no rows deleted, do not re-enqueue".
|
|
138
|
+
*
|
|
139
|
+
* In the CLI's default output mode the value is a bare integer on its
|
|
140
|
+
* own line. We tolerate trailing whitespace/blank lines and pick the
|
|
141
|
+
* last numeric line so any incidental output (warnings, etc.) above it
|
|
142
|
+
* doesn't throw the parse off.
|
|
143
|
+
*/
|
|
144
|
+
export function _parseDeletedCount(stdout: string | undefined): number {
|
|
145
|
+
return parseDeletedCount(stdout);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function parseDeletedCount(stdout: string | undefined): number {
|
|
149
|
+
if (!stdout) return 0;
|
|
150
|
+
const lines = stdout.split(/\r?\n/).filter((s) => s.trim().length > 0);
|
|
151
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
152
|
+
const n = parseInt(lines[i].trim(), 10);
|
|
153
|
+
if (Number.isFinite(n) && n >= 0) return n;
|
|
154
|
+
}
|
|
155
|
+
return 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
100
158
|
/**
|
|
101
159
|
* Delete conversations that have had no activity (updatedAt) for longer than
|
|
102
160
|
* the configured retention period. Processes in batches so a single job doesn't
|
|
@@ -9,7 +9,6 @@ import { and, desc, eq, sql } from "drizzle-orm";
|
|
|
9
9
|
import { v4 as uuid } from "uuid";
|
|
10
10
|
|
|
11
11
|
import { loadSkillCatalog } from "../../config/skills.js";
|
|
12
|
-
import { resolveGuardianPersona } from "../../prompts/persona-resolver.js";
|
|
13
12
|
import { buildCoreIdentityContext } from "../../prompts/system-prompt.js";
|
|
14
13
|
import {
|
|
15
14
|
createTimeout,
|
|
@@ -200,9 +199,7 @@ async function generateStarters(scopeId: string): Promise<GeneratedStarter[]> {
|
|
|
200
199
|
|
|
201
200
|
// Truncate identity context to prevent oversized prompts when SOUL.md /
|
|
202
201
|
// IDENTITY.md / users/<slug>.md are large.
|
|
203
|
-
const rawIdentityContext = buildCoreIdentityContext(
|
|
204
|
-
userPersona: resolveGuardianPersona(),
|
|
205
|
-
});
|
|
202
|
+
const rawIdentityContext = buildCoreIdentityContext();
|
|
206
203
|
const identityContext = rawIdentityContext
|
|
207
204
|
? truncate(rawIdentityContext, 2000, "\n…[truncated]")
|
|
208
205
|
: null;
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { AssistantConfig } from "../../config/types.js";
|
|
2
2
|
import { asString } from "../job-utils.js";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
enqueueMemoryJob,
|
|
5
|
+
isMemoryEnabled,
|
|
6
|
+
type MemoryJob,
|
|
7
|
+
} from "../jobs-store.js";
|
|
4
8
|
import { indexPkbFile } from "../pkb/pkb-index.js";
|
|
5
9
|
|
|
6
10
|
/**
|
|
@@ -46,6 +50,7 @@ export async function embedPkbFileJob(
|
|
|
46
50
|
* Enqueue an `embed_pkb_file` job (async, fire-and-forget).
|
|
47
51
|
*/
|
|
48
52
|
export function enqueuePkbIndexJob(input: EmbedPkbFileJobInput): string {
|
|
53
|
+
if (!isMemoryEnabled()) return "";
|
|
49
54
|
return enqueueMemoryJob("embed_pkb_file", {
|
|
50
55
|
pkbRoot: input.pkbRoot,
|
|
51
56
|
absPath: input.absPath,
|
package/src/memory/jobs-store.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { and, asc, eq, inArray, lte, notInArray, or, sql } from "drizzle-orm";
|
|
2
2
|
import { v4 as uuid } from "uuid";
|
|
3
3
|
|
|
4
|
+
import { getConfig } from "../config/loader.js";
|
|
4
5
|
import { getLogger } from "../util/logger.js";
|
|
5
6
|
import { truncate } from "../util/truncate.js";
|
|
6
7
|
import { getDb } from "./db-connection.js";
|
|
@@ -43,6 +44,9 @@ export type MemoryJobType =
|
|
|
43
44
|
| "memory_v2_migrate"
|
|
44
45
|
| "memory_v2_reembed"
|
|
45
46
|
| "memory_v2_activation_recompute"
|
|
47
|
+
| "memory_v3_consolidate"
|
|
48
|
+
| "memory_v3_index_maintenance"
|
|
49
|
+
| "memory_v3_edge_learning"
|
|
46
50
|
| "memory_retrospective";
|
|
47
51
|
|
|
48
52
|
export const EMBED_JOB_TYPES: MemoryJobType[] = [
|
|
@@ -66,12 +70,22 @@ export const SLOW_LLM_JOB_TYPES: MemoryJobType[] = [
|
|
|
66
70
|
"generate_conversation_starters",
|
|
67
71
|
"memory_v2_sweep",
|
|
68
72
|
"memory_v2_consolidate",
|
|
73
|
+
"memory_v3_consolidate",
|
|
69
74
|
"memory_v2_migrate",
|
|
70
75
|
"memory_retrospective",
|
|
71
76
|
"backfill",
|
|
72
77
|
"graph_bootstrap",
|
|
73
78
|
];
|
|
74
79
|
|
|
80
|
+
/** Returns `false` only when `config.memory.enabled` is explicitly `false`; defaults to `true` on missing config or load errors. */
|
|
81
|
+
export function isMemoryEnabled(): boolean {
|
|
82
|
+
try {
|
|
83
|
+
return getConfig().memory?.enabled !== false;
|
|
84
|
+
} catch {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
75
89
|
export interface MemoryJob<T = Record<string, unknown>> {
|
|
76
90
|
id: string;
|
|
77
91
|
type: MemoryJobType;
|
|
@@ -83,6 +83,9 @@ import {
|
|
|
83
83
|
memoryV2ConsolidateJob,
|
|
84
84
|
} from "./v2/consolidation-job.js";
|
|
85
85
|
import { memoryV2SweepJob } from "./v2/sweep-job.js";
|
|
86
|
+
import { memoryV3ConsolidateJob } from "./v3/consolidation-job.js";
|
|
87
|
+
import { memoryV3EdgeLearningJob } from "./v3/edge-learning-job.js";
|
|
88
|
+
import { memoryV3IndexMaintenanceJob } from "./v3/maintenance.js";
|
|
86
89
|
|
|
87
90
|
const log = getLogger("memory-jobs-worker");
|
|
88
91
|
|
|
@@ -259,7 +262,7 @@ export async function runMemoryJobsOnce(
|
|
|
259
262
|
maybeEnqueueScheduledCleanupJobs(config);
|
|
260
263
|
}
|
|
261
264
|
maybeEnqueueGraphMaintenanceJobs(config);
|
|
262
|
-
maybeRunDbMaintenance();
|
|
265
|
+
await maybeRunDbMaintenance();
|
|
263
266
|
return 0;
|
|
264
267
|
}
|
|
265
268
|
|
|
@@ -313,7 +316,7 @@ export async function runMemoryJobsOnce(
|
|
|
313
316
|
maybeEnqueueScheduledCleanupJobs(config);
|
|
314
317
|
}
|
|
315
318
|
maybeEnqueueGraphMaintenanceJobs(config);
|
|
316
|
-
maybeRunDbMaintenance();
|
|
319
|
+
await maybeRunDbMaintenance();
|
|
317
320
|
return slowProcessed + fastProcessed + embedProcessed;
|
|
318
321
|
}
|
|
319
322
|
|
|
@@ -524,10 +527,10 @@ async function processJob(
|
|
|
524
527
|
pruneOldConversationsJob(job, config);
|
|
525
528
|
return;
|
|
526
529
|
case "prune_old_llm_request_logs":
|
|
527
|
-
pruneOldLlmRequestLogsJob(job, config);
|
|
530
|
+
await pruneOldLlmRequestLogsJob(job, config);
|
|
528
531
|
return;
|
|
529
532
|
case "prune_old_trace_events":
|
|
530
|
-
pruneOldTraceEventsJob(job, config);
|
|
533
|
+
await pruneOldTraceEventsJob(job, config);
|
|
531
534
|
return;
|
|
532
535
|
case "build_conversation_summary":
|
|
533
536
|
// Stale rows enqueued before v2 was enabled must not consume the
|
|
@@ -603,6 +606,16 @@ async function processJob(
|
|
|
603
606
|
case "memory_v2_consolidate":
|
|
604
607
|
await memoryV2ConsolidateJob(job, config);
|
|
605
608
|
return;
|
|
609
|
+
case "memory_v3_consolidate":
|
|
610
|
+
await memoryV3ConsolidateJob(job, config);
|
|
611
|
+
return;
|
|
612
|
+
case "memory_v3_index_maintenance":
|
|
613
|
+
await memoryV3IndexMaintenanceJob(job);
|
|
614
|
+
return;
|
|
615
|
+
case "memory_v3_edge_learning":
|
|
616
|
+
// Fast lane: bounded DB work (decay + reinforce + read), no LLM.
|
|
617
|
+
memoryV3EdgeLearningJob(job);
|
|
618
|
+
return;
|
|
606
619
|
case "memory_v2_migrate":
|
|
607
620
|
await memoryV2MigrateJob(job, config);
|
|
608
621
|
return;
|
|
@@ -681,17 +694,28 @@ export const GRAPH_MAINTENANCE_CHECKPOINTS = {
|
|
|
681
694
|
patternScan: "graph_maintenance:pattern_scan:last_run",
|
|
682
695
|
narrative: "graph_maintenance:narrative:last_run",
|
|
683
696
|
memoryV2Consolidate: "memory_v2_consolidate_last_run",
|
|
697
|
+
memoryV3Consolidate: "memory_v3_consolidate_last_run",
|
|
684
698
|
} as const;
|
|
685
699
|
|
|
686
700
|
/**
|
|
687
701
|
* Enqueue periodic graph maintenance jobs.
|
|
688
702
|
*
|
|
689
703
|
* Mutually exclusive between v1 and v2:
|
|
690
|
-
* - v2 active (`memory.v2.enabled` on) → only
|
|
691
|
-
* scheduled.
|
|
704
|
+
* - v2 active (`memory.v2.enabled` on) → only one buffer-drainer is
|
|
705
|
+
* scheduled (see below).
|
|
692
706
|
* - v2 inactive → the four v1 entries (decay, consolidate, pattern_scan,
|
|
693
707
|
* narrative) are scheduled instead.
|
|
694
708
|
*
|
|
709
|
+
* **Buffer-drainer retarget (v2 vs v3).** The `memory/buffer.md` is shared, so
|
|
710
|
+
* exactly one consolidator may own the drain at a time. When
|
|
711
|
+
* `memory.v3.write.enabled` is on, the v3 consolidator (`memory_v3_consolidate`)
|
|
712
|
+
* is scheduled INSTEAD of `memory_v2_consolidate` — same shared buffer +
|
|
713
|
+
* standing-context files, additionally authored into the v3 tree. When the v3
|
|
714
|
+
* write flag is off (default) the v2 consolidator stays the sole drainer,
|
|
715
|
+
* unchanged. The retarget is a clean conditional, fully reversible via the flag.
|
|
716
|
+
* Concept pages stay the shared canonical store, so the v2 router keeps working
|
|
717
|
+
* off pages v3 writes regardless of which consolidator ran.
|
|
718
|
+
*
|
|
695
719
|
* Read/write paths route to v2 when the flag is on, so v1 graph data goes
|
|
696
720
|
* unread; running v1 maintenance alongside v2 is wasted compute and LLM
|
|
697
721
|
* spend. The v1 code path remains live so flipping the flag back to off
|
|
@@ -708,20 +732,29 @@ export function maybeEnqueueGraphMaintenanceJobs(
|
|
|
708
732
|
nowMs = Date.now(),
|
|
709
733
|
): void {
|
|
710
734
|
const v2Active = config.memory.v2.enabled;
|
|
735
|
+
const v3WriteActive = config.memory.v3.write.enabled;
|
|
736
|
+
|
|
737
|
+
// The single buffer-drainer entry for the v2-active branch: v3 when the v3
|
|
738
|
+
// write flag owns the drain, v2 otherwise. Same shared buffer either way.
|
|
739
|
+
const consolidateEntry = v3WriteActive
|
|
740
|
+
? {
|
|
741
|
+
key: GRAPH_MAINTENANCE_CHECKPOINTS.memoryV3Consolidate,
|
|
742
|
+
intervalMs: config.memory.v3.write.consolidateIntervalMs,
|
|
743
|
+
jobType: "memory_v3_consolidate" as MemoryJobType,
|
|
744
|
+
}
|
|
745
|
+
: {
|
|
746
|
+
key: GRAPH_MAINTENANCE_CHECKPOINTS.memoryV2Consolidate,
|
|
747
|
+
intervalMs:
|
|
748
|
+
config.memory.v2.consolidation_interval_hours * 60 * 60 * 1000,
|
|
749
|
+
jobType: "memory_v2_consolidate" as MemoryJobType,
|
|
750
|
+
};
|
|
711
751
|
|
|
712
752
|
const schedule: Array<{
|
|
713
753
|
key: string;
|
|
714
754
|
intervalMs: number;
|
|
715
755
|
jobType: MemoryJobType;
|
|
716
756
|
}> = v2Active
|
|
717
|
-
? [
|
|
718
|
-
{
|
|
719
|
-
key: GRAPH_MAINTENANCE_CHECKPOINTS.memoryV2Consolidate,
|
|
720
|
-
intervalMs:
|
|
721
|
-
config.memory.v2.consolidation_interval_hours * 60 * 60 * 1000,
|
|
722
|
-
jobType: "memory_v2_consolidate",
|
|
723
|
-
},
|
|
724
|
-
]
|
|
757
|
+
? [consolidateEntry]
|
|
725
758
|
: [
|
|
726
759
|
{
|
|
727
760
|
key: GRAPH_MAINTENANCE_CHECKPOINTS.decay,
|
|
@@ -745,25 +778,25 @@ export function maybeEnqueueGraphMaintenanceJobs(
|
|
|
745
778
|
},
|
|
746
779
|
];
|
|
747
780
|
|
|
748
|
-
let
|
|
781
|
+
let enqueuedConsolidate = false;
|
|
749
782
|
for (const { key, intervalMs, jobType } of schedule) {
|
|
750
783
|
const lastRun = parseInt(getMemoryCheckpoint(key) ?? "0", 10);
|
|
751
784
|
if (nowMs - lastRun >= intervalMs) {
|
|
752
785
|
enqueueMemoryJob(jobType, {});
|
|
753
786
|
setMemoryCheckpoint(key, String(nowMs));
|
|
754
|
-
if (jobType ===
|
|
787
|
+
if (jobType === consolidateEntry.jobType) enqueuedConsolidate = true;
|
|
755
788
|
}
|
|
756
789
|
}
|
|
757
790
|
|
|
791
|
+
// Size-based trigger: when the shared buffer crosses the configured line
|
|
792
|
+
// count, drain it now rather than waiting out the interval. Retargets to the
|
|
793
|
+
// same consolidator the interval branch above selected.
|
|
758
794
|
const maxLines = config.memory.v2.consolidation_max_buffer_lines;
|
|
759
|
-
if (v2Active && !
|
|
795
|
+
if (v2Active && !enqueuedConsolidate && maxLines !== null) {
|
|
760
796
|
const bufferPath = join(getWorkspaceDir(), "memory", "buffer.md");
|
|
761
797
|
if (countBufferLines(bufferPath) >= maxLines) {
|
|
762
|
-
enqueueMemoryJob(
|
|
763
|
-
setMemoryCheckpoint(
|
|
764
|
-
GRAPH_MAINTENANCE_CHECKPOINTS.memoryV2Consolidate,
|
|
765
|
-
String(nowMs),
|
|
766
|
-
);
|
|
798
|
+
enqueueMemoryJob(consolidateEntry.jobType, {});
|
|
799
|
+
setMemoryCheckpoint(consolidateEntry.key, String(nowMs));
|
|
767
800
|
}
|
|
768
801
|
}
|
|
769
802
|
}
|
|
@@ -58,6 +58,16 @@ interface ClickHouseRow {
|
|
|
58
58
|
response_payload: string;
|
|
59
59
|
created_at: string;
|
|
60
60
|
agent_loop_exit_reason: string;
|
|
61
|
+
/**
|
|
62
|
+
* Mirrors `llm_request_logs.call_site` from the SQLite source. Added
|
|
63
|
+
* to the CH `default.llm_request_logs` table via ALTER TABLE (matching
|
|
64
|
+
* the `agent_loop_exit_reason` precedent — see
|
|
65
|
+
* `memory/concepts/objects/clickhouse-mirror.md`).
|
|
66
|
+
*
|
|
67
|
+
* CH columns are `DEFAULT ''` rather than Nullable, so empty-string
|
|
68
|
+
* means "not set" — `toLogRow` maps that back to NULL on the JS side.
|
|
69
|
+
*/
|
|
70
|
+
call_site: string;
|
|
61
71
|
}
|
|
62
72
|
|
|
63
73
|
/** Injectable fetch override for tests. Defaults to globalThis.fetch. */
|
|
@@ -125,7 +135,8 @@ export class ClickHouseLlmRequestLogSource implements LlmRequestLogSource {
|
|
|
125
135
|
request_payload,
|
|
126
136
|
response_payload,
|
|
127
137
|
toUnixTimestamp64Milli(created_at) AS created_at,
|
|
128
|
-
agent_loop_exit_reason
|
|
138
|
+
agent_loop_exit_reason,
|
|
139
|
+
call_site
|
|
129
140
|
FROM ${this.tableRef()}
|
|
130
141
|
WHERE assistant_id = {assistant_id:String}
|
|
131
142
|
AND id = {log_id:String}
|
|
@@ -171,6 +182,33 @@ export class ClickHouseLlmRequestLogSource implements LlmRequestLogSource {
|
|
|
171
182
|
);
|
|
172
183
|
}
|
|
173
184
|
|
|
185
|
+
async getRequestLogsByConversationId(
|
|
186
|
+
conversationId: string,
|
|
187
|
+
): Promise<LogRow[]> {
|
|
188
|
+
const aid = await this.assistantId();
|
|
189
|
+
const sql = `SELECT
|
|
190
|
+
id,
|
|
191
|
+
conversation_id,
|
|
192
|
+
message_id,
|
|
193
|
+
provider,
|
|
194
|
+
request_payload,
|
|
195
|
+
response_payload,
|
|
196
|
+
toUnixTimestamp64Milli(created_at) AS created_at,
|
|
197
|
+
agent_loop_exit_reason,
|
|
198
|
+
call_site
|
|
199
|
+
FROM ${this.tableRef()}
|
|
200
|
+
WHERE assistant_id = {assistant_id:String}
|
|
201
|
+
AND conversation_id = {conversation_id:String}
|
|
202
|
+
ORDER BY created_at ASC, id ASC
|
|
203
|
+
LIMIT 1 BY id
|
|
204
|
+
FORMAT JSONEachRow`;
|
|
205
|
+
const rows = await this.exec(sql, {
|
|
206
|
+
assistant_id: aid,
|
|
207
|
+
conversation_id: conversationId,
|
|
208
|
+
});
|
|
209
|
+
return rows.map((r) => this.toLogRow(r));
|
|
210
|
+
}
|
|
211
|
+
|
|
174
212
|
private async selectByMessageIds(ids: string[]): Promise<LogRow[]> {
|
|
175
213
|
if (ids.length === 0) return [];
|
|
176
214
|
const aid = await this.assistantId();
|
|
@@ -197,7 +235,8 @@ export class ClickHouseLlmRequestLogSource implements LlmRequestLogSource {
|
|
|
197
235
|
request_payload,
|
|
198
236
|
response_payload,
|
|
199
237
|
toUnixTimestamp64Milli(created_at) AS created_at,
|
|
200
|
-
agent_loop_exit_reason
|
|
238
|
+
agent_loop_exit_reason,
|
|
239
|
+
call_site
|
|
201
240
|
FROM ${this.tableRef()}
|
|
202
241
|
WHERE assistant_id = {assistant_id:String}
|
|
203
242
|
AND message_id IN (${placeholders.join(",")})
|
|
@@ -288,6 +327,7 @@ export class ClickHouseLlmRequestLogSource implements LlmRequestLogSource {
|
|
|
288
327
|
createdAt: Number(row.created_at),
|
|
289
328
|
agentLoopExitReason:
|
|
290
329
|
row.agent_loop_exit_reason === "" ? null : row.agent_loop_exit_reason,
|
|
330
|
+
callSite: row.call_site === "" ? null : row.call_site,
|
|
291
331
|
};
|
|
292
332
|
}
|
|
293
333
|
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import type { LlmRequestLogSource } from "./llm-request-log-source.js";
|
|
12
12
|
import {
|
|
13
13
|
getRequestLogById,
|
|
14
|
+
getRequestLogsByConversationId,
|
|
14
15
|
getRequestLogsByMessageId,
|
|
15
16
|
type LogRow,
|
|
16
17
|
} from "./llm-request-log-store.js";
|
|
@@ -23,4 +24,10 @@ export class LocalLlmRequestLogSource implements LlmRequestLogSource {
|
|
|
23
24
|
async getRequestLogsByMessageId(messageId: string): Promise<LogRow[]> {
|
|
24
25
|
return getRequestLogsByMessageId(messageId);
|
|
25
26
|
}
|
|
27
|
+
|
|
28
|
+
async getRequestLogsByConversationId(
|
|
29
|
+
conversationId: string,
|
|
30
|
+
): Promise<LogRow[]> {
|
|
31
|
+
return getRequestLogsByConversationId(conversationId);
|
|
32
|
+
}
|
|
26
33
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pluggable read source for LLM request logs.
|
|
3
3
|
*
|
|
4
|
-
* The Inspector
|
|
5
|
-
* single-log payload route) historically read directly from the local
|
|
4
|
+
* The Inspector views at `GET /v1/messages/:id/llm-context` and
|
|
5
|
+
* `GET /v1/conversations/llm-context` (plus the single-log payload route) historically read directly from the local
|
|
6
6
|
* SQLite `llm_request_logs` table via `llm-request-log-store.ts`. The
|
|
7
7
|
* source-of-truth remains local, but the *read path* is now configurable
|
|
8
8
|
* via `llmRequestLogs.readSource` in workspace config.
|
|
@@ -31,6 +31,13 @@ export interface LlmRequestLogSource {
|
|
|
31
31
|
* INSERT-only against the source-of-truth).
|
|
32
32
|
*/
|
|
33
33
|
getRequestLogsByMessageId(messageId: string): Promise<LogRow[]>;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Fetch every LLM request log associated with the given conversation.
|
|
37
|
+
* This is the conversation-wide inspector read path: linked, unlinked,
|
|
38
|
+
* and orphaned logs are all included because they share conversation_id.
|
|
39
|
+
*/
|
|
40
|
+
getRequestLogsByConversationId(conversationId: string): Promise<LogRow[]>;
|
|
34
41
|
}
|
|
35
42
|
|
|
36
43
|
/**
|