@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
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { and, desc, eq, gte, inArray, isNull, lte, sql } from "drizzle-orm";
|
|
1
|
+
import { and, asc, desc, eq, gte, inArray, isNull, lte, sql } from "drizzle-orm";
|
|
2
2
|
import { v4 as uuid } from "uuid";
|
|
3
3
|
|
|
4
|
+
import type { LLMCallSite } from "../config/schemas/llm.js";
|
|
4
5
|
import { AssistantError, ProviderError } from "../util/errors.js";
|
|
5
6
|
import {
|
|
6
7
|
getAssistantMessageIdsInTurn,
|
|
@@ -26,6 +27,12 @@ export type LogRow = {
|
|
|
26
27
|
* `AgentLoopExitReason` in `agent/loop.ts`.
|
|
27
28
|
*/
|
|
28
29
|
agentLoopExitReason: string | null;
|
|
30
|
+
/**
|
|
31
|
+
* Logical call site that produced this row — `mainAgent`,
|
|
32
|
+
* `compactionAgent`, etc. NULL on pre-migration-264 rows (no backfill).
|
|
33
|
+
* In practice values come from `LLMCallSite` (`config/schemas/llm.ts`).
|
|
34
|
+
*/
|
|
35
|
+
callSite: string | null;
|
|
29
36
|
};
|
|
30
37
|
|
|
31
38
|
/**
|
|
@@ -73,6 +80,7 @@ export function recordRequestLog(
|
|
|
73
80
|
responsePayload: string,
|
|
74
81
|
messageId?: string,
|
|
75
82
|
provider?: string,
|
|
83
|
+
callSite?: LLMCallSite,
|
|
76
84
|
): string {
|
|
77
85
|
const db = getDb();
|
|
78
86
|
const id = uuid();
|
|
@@ -88,6 +96,10 @@ export function recordRequestLog(
|
|
|
88
96
|
// Stamped later via setAgentLoopExitReasonOnLatestLog, once the
|
|
89
97
|
// agent loop body actually exits. Intermediate rows stay NULL.
|
|
90
98
|
agentLoopExitReason: null,
|
|
99
|
+
// Logical call site (`mainAgent`, `compactionAgent`, …). NULL when
|
|
100
|
+
// a caller hasn't been updated yet — preserves backward compat
|
|
101
|
+
// while we plumb call sites through one site at a time.
|
|
102
|
+
callSite: callSite ?? null,
|
|
91
103
|
})
|
|
92
104
|
.run();
|
|
93
105
|
return id;
|
|
@@ -182,6 +194,7 @@ function selectLogsByMessageIds(messageIds: string[]): LogRow[] {
|
|
|
182
194
|
responsePayload: llmRequestLogs.responsePayload,
|
|
183
195
|
createdAt: llmRequestLogs.createdAt,
|
|
184
196
|
agentLoopExitReason: llmRequestLogs.agentLoopExitReason,
|
|
197
|
+
callSite: llmRequestLogs.callSite,
|
|
185
198
|
})
|
|
186
199
|
.from(llmRequestLogs)
|
|
187
200
|
.where(inArray(llmRequestLogs.messageId, messageIds))
|
|
@@ -189,6 +202,32 @@ function selectLogsByMessageIds(messageIds: string[]): LogRow[] {
|
|
|
189
202
|
.all();
|
|
190
203
|
}
|
|
191
204
|
|
|
205
|
+
/**
|
|
206
|
+
* Query every LLM request log recorded for a conversation, ordered by
|
|
207
|
+
* creation time. Conversation-scoped inspector views intentionally do
|
|
208
|
+
* not apply turn recovery: the `conversation_id` column already includes
|
|
209
|
+
* linked, unlinked, and orphaned rows for the full conversation.
|
|
210
|
+
*/
|
|
211
|
+
export function getRequestLogsByConversationId(conversationId: string): LogRow[] {
|
|
212
|
+
const db = getDb();
|
|
213
|
+
return db
|
|
214
|
+
.select({
|
|
215
|
+
id: llmRequestLogs.id,
|
|
216
|
+
conversationId: llmRequestLogs.conversationId,
|
|
217
|
+
messageId: llmRequestLogs.messageId,
|
|
218
|
+
provider: llmRequestLogs.provider,
|
|
219
|
+
requestPayload: llmRequestLogs.requestPayload,
|
|
220
|
+
responsePayload: llmRequestLogs.responsePayload,
|
|
221
|
+
createdAt: llmRequestLogs.createdAt,
|
|
222
|
+
agentLoopExitReason: llmRequestLogs.agentLoopExitReason,
|
|
223
|
+
callSite: llmRequestLogs.callSite,
|
|
224
|
+
})
|
|
225
|
+
.from(llmRequestLogs)
|
|
226
|
+
.where(eq(llmRequestLogs.conversationId, conversationId))
|
|
227
|
+
.orderBy(asc(llmRequestLogs.createdAt), asc(llmRequestLogs.id))
|
|
228
|
+
.all();
|
|
229
|
+
}
|
|
230
|
+
|
|
192
231
|
/**
|
|
193
232
|
* Find orphaned logs — logs whose `message_id` references a message that no
|
|
194
233
|
* longer exists in the DB. These are left behind when intermediate assistant
|
|
@@ -214,6 +253,7 @@ function selectOrphanedLogsInRange(
|
|
|
214
253
|
responsePayload: llmRequestLogs.responsePayload,
|
|
215
254
|
createdAt: llmRequestLogs.createdAt,
|
|
216
255
|
agentLoopExitReason: llmRequestLogs.agentLoopExitReason,
|
|
256
|
+
callSite: llmRequestLogs.callSite,
|
|
217
257
|
})
|
|
218
258
|
.from(llmRequestLogs)
|
|
219
259
|
.leftJoin(messages, eq(llmRequestLogs.messageId, messages.id))
|
|
@@ -255,6 +295,7 @@ function selectUnlinkedLogsInRange(
|
|
|
255
295
|
responsePayload: llmRequestLogs.responsePayload,
|
|
256
296
|
createdAt: llmRequestLogs.createdAt,
|
|
257
297
|
agentLoopExitReason: llmRequestLogs.agentLoopExitReason,
|
|
298
|
+
callSite: llmRequestLogs.callSite,
|
|
258
299
|
})
|
|
259
300
|
.from(llmRequestLogs)
|
|
260
301
|
.where(
|
|
@@ -282,6 +323,7 @@ export function getRequestLogById(logId: string): LogRow | null {
|
|
|
282
323
|
responsePayload: llmRequestLogs.responsePayload,
|
|
283
324
|
createdAt: llmRequestLogs.createdAt,
|
|
284
325
|
agentLoopExitReason: llmRequestLogs.agentLoopExitReason,
|
|
326
|
+
callSite: llmRequestLogs.callSite,
|
|
285
327
|
})
|
|
286
328
|
.from(llmRequestLogs)
|
|
287
329
|
.where(eq(llmRequestLogs.id, logId))
|
|
@@ -57,6 +57,7 @@ export function recordUsageEvent(
|
|
|
57
57
|
outputTokens: event.outputTokens,
|
|
58
58
|
cacheCreationInputTokens: event.cacheCreationInputTokens,
|
|
59
59
|
cacheReadInputTokens: event.cacheReadInputTokens,
|
|
60
|
+
rawUsage: event.rawUsage === null ? null : JSON.stringify(event.rawUsage),
|
|
60
61
|
estimatedCostUsd: event.estimatedCostUsd,
|
|
61
62
|
pricingStatus: event.pricingStatus,
|
|
62
63
|
llmCallCount: event.llmCallCount ?? 1,
|
|
@@ -87,6 +88,7 @@ function rowToUsageEvent(row: {
|
|
|
87
88
|
outputTokens: number;
|
|
88
89
|
cacheCreationInputTokens: number | null;
|
|
89
90
|
cacheReadInputTokens: number | null;
|
|
91
|
+
rawUsage: string | null;
|
|
90
92
|
estimatedCostUsd: number | null;
|
|
91
93
|
pricingStatus: string;
|
|
92
94
|
}): UsageEvent {
|
|
@@ -107,11 +109,32 @@ function rowToUsageEvent(row: {
|
|
|
107
109
|
outputTokens: row.outputTokens,
|
|
108
110
|
cacheCreationInputTokens: row.cacheCreationInputTokens,
|
|
109
111
|
cacheReadInputTokens: row.cacheReadInputTokens,
|
|
112
|
+
rawUsage: parseRawUsage(row.rawUsage),
|
|
110
113
|
estimatedCostUsd: row.estimatedCostUsd,
|
|
111
114
|
pricingStatus: row.pricingStatus as "priced" | "unpriced",
|
|
112
115
|
};
|
|
113
116
|
}
|
|
114
117
|
|
|
118
|
+
/**
|
|
119
|
+
* Parse the JSON-serialized provider usage payload stored in `raw_usage`.
|
|
120
|
+
* Returns `null` for missing or malformed values; malformed JSON is logged
|
|
121
|
+
* and discarded rather than failing the read, because callers (admin
|
|
122
|
+
* dashboards, telemetry forwarders) treat `raw_usage` as opaque diagnostic
|
|
123
|
+
* data and shouldn't be blocked by a single corrupt row.
|
|
124
|
+
*/
|
|
125
|
+
function parseRawUsage(value: string | null): Record<string, unknown> | null {
|
|
126
|
+
if (value === null) return null;
|
|
127
|
+
try {
|
|
128
|
+
const parsed = JSON.parse(value);
|
|
129
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
130
|
+
return parsed as Record<string, unknown>;
|
|
131
|
+
}
|
|
132
|
+
return null;
|
|
133
|
+
} catch {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
115
138
|
export function listUsageEvents(options?: { limit?: number }): UsageEvent[] {
|
|
116
139
|
const db = getDb();
|
|
117
140
|
const rows = db
|
|
@@ -187,6 +210,7 @@ export function queryUnreportedUsageEvents(
|
|
|
187
210
|
outputTokens: llmUsageEvents.outputTokens,
|
|
188
211
|
cacheCreationInputTokens: llmUsageEvents.cacheCreationInputTokens,
|
|
189
212
|
cacheReadInputTokens: llmUsageEvents.cacheReadInputTokens,
|
|
213
|
+
rawUsage: llmUsageEvents.rawUsage,
|
|
190
214
|
estimatedCostUsd: llmUsageEvents.estimatedCostUsd,
|
|
191
215
|
pricingStatus: llmUsageEvents.pricingStatus,
|
|
192
216
|
conversationType: conversations.conversationType,
|
|
@@ -19,7 +19,10 @@ import {
|
|
|
19
19
|
} from "../runtime/actor-trust-resolver.js";
|
|
20
20
|
import { getLogger } from "../util/logger.js";
|
|
21
21
|
import { getConversationSource } from "./conversation-crud.js";
|
|
22
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
isMemoryEnabled,
|
|
24
|
+
upsertMemoryRetrospectiveJob,
|
|
25
|
+
} from "./jobs-store.js";
|
|
23
26
|
import { MEMORY_RETROSPECTIVE_SOURCES } from "./memory-retrospective-constants.js";
|
|
24
27
|
|
|
25
28
|
const log = getLogger("memory-retrospective-enqueue");
|
|
@@ -38,6 +41,10 @@ export function enqueueMemoryRetrospectiveIfEnabled(args: {
|
|
|
38
41
|
}): void {
|
|
39
42
|
const { conversationId, trigger } = args;
|
|
40
43
|
|
|
44
|
+
if (!isMemoryEnabled()) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
41
48
|
if (isMemoryRetrospectiveConversation(conversationId)) {
|
|
42
49
|
log.debug(
|
|
43
50
|
{ conversationId, trigger },
|
|
@@ -208,6 +208,11 @@ async function runLegacyRetrospective(
|
|
|
208
208
|
source: MEMORY_RETROSPECTIVE_SOURCE,
|
|
209
209
|
trustContext: INTERNAL_GUARDIAN_TRUST_CONTEXT,
|
|
210
210
|
callSite: "memoryRetrospective",
|
|
211
|
+
// The background conversation's title already reads "Memory
|
|
212
|
+
// Retrospective", and `hint` is the full retrospective prompt — surfacing
|
|
213
|
+
// it verbatim as a "Conversation Woke" card body is noisy internal
|
|
214
|
+
// scaffolding for the user. Suppress it, matching the fork-based path.
|
|
215
|
+
suppressWakeSurface: true,
|
|
211
216
|
});
|
|
212
217
|
wakeSucceeded = result.invoked;
|
|
213
218
|
failureReason = result.reason;
|
|
@@ -115,11 +115,15 @@ export interface RecordMemoryV2ActivationLogParams {
|
|
|
115
115
|
* `per-turn` for normal append injections, `errored` when `injectMemoryV2Block`
|
|
116
116
|
* threw before completing — telemetry is still written so silent failures
|
|
117
117
|
* are observable in the database, with whatever `concepts` rows had been
|
|
118
|
-
* built so far (possibly empty). `router` indicates the
|
|
119
|
-
*
|
|
120
|
-
*
|
|
118
|
+
* built so far (possibly empty). `router` indicates the LLM router selected
|
|
119
|
+
* the per-turn page set; router-mode rows carry zeroed activation values and
|
|
120
|
+
* `source: "router"` on every concept row. `v3_shadow` is written by the
|
|
121
|
+
* live-shadow v3 retrieval middleware: it records v3's selection set for
|
|
122
|
+
* comparison without affecting injected context. The harness oracle filters
|
|
123
|
+
* `mode='router'`, so `v3_shadow` rows never pollute it; the inspector can
|
|
124
|
+
* still surface them.
|
|
121
125
|
*/
|
|
122
|
-
mode: "context-load" | "per-turn" | "errored" | "router";
|
|
126
|
+
mode: "context-load" | "per-turn" | "errored" | "router" | "v3_shadow";
|
|
123
127
|
concepts: MemoryV2ConceptRowRecord[];
|
|
124
128
|
config: MemoryV2ConfigSnapshot;
|
|
125
129
|
}
|
|
@@ -167,7 +171,7 @@ export function backfillMemoryV2ActivationMessageId(
|
|
|
167
171
|
export interface MemoryV2ActivationLog {
|
|
168
172
|
conversationId: string;
|
|
169
173
|
turn: number;
|
|
170
|
-
mode: "context-load" | "per-turn" | "errored" | "router";
|
|
174
|
+
mode: "context-load" | "per-turn" | "errored" | "router" | "v3_shadow";
|
|
171
175
|
concepts: MemoryV2ConceptRowRecord[];
|
|
172
176
|
config: MemoryV2ConfigSnapshot;
|
|
173
177
|
}
|
|
@@ -188,7 +192,12 @@ export function getMemoryV2ActivationLogByMessageIds(
|
|
|
188
192
|
return {
|
|
189
193
|
conversationId: row.conversationId,
|
|
190
194
|
turn: row.turn,
|
|
191
|
-
mode: row.mode as
|
|
195
|
+
mode: row.mode as
|
|
196
|
+
| "context-load"
|
|
197
|
+
| "per-turn"
|
|
198
|
+
| "errored"
|
|
199
|
+
| "router"
|
|
200
|
+
| "v3_shadow",
|
|
192
201
|
concepts: JSON.parse(row.conceptsJson) as MemoryV2ConceptRowRecord[],
|
|
193
202
|
config: JSON.parse(row.configJson) as MemoryV2ConfigSnapshot,
|
|
194
203
|
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
+
import { tableHasColumn } from "./schema-introspection.js";
|
|
3
|
+
import { withCrashRecovery } from "./validate-migration-state.js";
|
|
4
|
+
|
|
5
|
+
const CHECKPOINT_KEY = "migration_rename_cleaned_at_v1";
|
|
6
|
+
|
|
7
|
+
const OLD_COLUMN = "cleaned_at";
|
|
8
|
+
const NEW_COLUMN = "history_stripped_at";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Rename `conversations.cleaned_at` → `conversations.history_stripped_at`.
|
|
12
|
+
*
|
|
13
|
+
* The marker now records any injection-strip event (`/clean` or compaction),
|
|
14
|
+
* not just `/clean`. Renaming reflects the broader semantics; compaction
|
|
15
|
+
* sets it alongside its summary state instead of destructively wiping
|
|
16
|
+
* message metadata.
|
|
17
|
+
*/
|
|
18
|
+
export function migrateRenameCleanedAt(database: DrizzleDb): void {
|
|
19
|
+
withCrashRecovery(database, CHECKPOINT_KEY, () => {
|
|
20
|
+
if (tableHasColumn(database, "conversations", NEW_COLUMN)) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (!tableHasColumn(database, "conversations", OLD_COLUMN)) {
|
|
24
|
+
// 259 didn't run (fresh install on a newer schema where 259's column
|
|
25
|
+
// was added under the new name) — nothing to rename.
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
database.run(
|
|
29
|
+
`ALTER TABLE conversations RENAME COLUMN ${OLD_COLUMN} TO ${NEW_COLUMN}`,
|
|
30
|
+
);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function downRenameCleanedAt(database: DrizzleDb): void {
|
|
35
|
+
if (!tableHasColumn(database, "conversations", NEW_COLUMN)) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (tableHasColumn(database, "conversations", OLD_COLUMN)) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
database.run(
|
|
42
|
+
`ALTER TABLE conversations RENAME COLUMN ${NEW_COLUMN} TO ${OLD_COLUMN}`,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
+
import { tableHasColumn } from "./schema-introspection.js";
|
|
3
|
+
import { withCrashRecovery } from "./validate-migration-state.js";
|
|
4
|
+
|
|
5
|
+
const CHECKPOINT_KEY = "migration_llm_usage_add_raw_usage_v1";
|
|
6
|
+
|
|
7
|
+
const TABLE = "llm_usage_events";
|
|
8
|
+
const COLUMN = "raw_usage";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Add a `raw_usage` TEXT column to `llm_usage_events` for storing the
|
|
12
|
+
* provider's untouched `usage` block as JSON.
|
|
13
|
+
*
|
|
14
|
+
* The Anthropic API surfaces a TTL breakdown of cache writes
|
|
15
|
+
* (`usage.cache_creation.ephemeral_5m_input_tokens`,
|
|
16
|
+
* `usage.cache_creation.ephemeral_1h_input_tokens`); OpenAI surfaces
|
|
17
|
+
* nested `prompt_tokens_details` and `completion_tokens_details`; both
|
|
18
|
+
* are kept as opaque JSON so admin charts and downstream consumers can
|
|
19
|
+
* extract provider-specific detail without requiring a new column every
|
|
20
|
+
* time a provider adds a usage field. `NULL` for rows persisted before
|
|
21
|
+
* this migration ran and for providers that did not return a usage
|
|
22
|
+
* payload.
|
|
23
|
+
*/
|
|
24
|
+
export function migrateLlmUsageAddRawUsage(database: DrizzleDb): void {
|
|
25
|
+
withCrashRecovery(database, CHECKPOINT_KEY, () => {
|
|
26
|
+
if (!tableHasColumn(database, TABLE, COLUMN)) {
|
|
27
|
+
database.run(`ALTER TABLE ${TABLE} ADD COLUMN ${COLUMN} TEXT`);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function downLlmUsageAddRawUsage(database: DrizzleDb): void {
|
|
33
|
+
if (tableHasColumn(database, TABLE, COLUMN)) {
|
|
34
|
+
database.run(`ALTER TABLE ${TABLE} DROP COLUMN ${COLUMN}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
+
import { getSqliteFrom } from "../db-connection.js";
|
|
3
|
+
import { withCrashRecovery } from "./validate-migration-state.js";
|
|
4
|
+
|
|
5
|
+
const CHECKPOINT_KEY = "migration_memory_v3_coactivation_v1";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Create the memory_v3_coactivation table — an append-only log of
|
|
9
|
+
* pass-1 → pass-N co-activation pairs observed during a v3 retrieval loop.
|
|
10
|
+
*
|
|
11
|
+
* Each row records that a page (`target_slug`) first surfaced on a later
|
|
12
|
+
* descent pass was co-selected alongside a page (`source_slug`) that surfaced
|
|
13
|
+
* on pass 1, with `pass_gap` = passOf(target) − passOf(source). This is the
|
|
14
|
+
* raw gradient signal that edge-learning later reconciles into curated-graph
|
|
15
|
+
* edge weights: a source that repeatedly precedes a target across turns is a
|
|
16
|
+
* candidate association. `used` is the usefulness flag (0 here — the loop
|
|
17
|
+
* cannot know whether the target was actually load-bearing for the turn; a
|
|
18
|
+
* later edge-learning pass reconciles it).
|
|
19
|
+
*
|
|
20
|
+
* The table just accumulates raw events; the edge-learning formula or the
|
|
21
|
+
* decay/weighting can change later without losing signal.
|
|
22
|
+
*
|
|
23
|
+
* Indexes:
|
|
24
|
+
* - `(source_slug, target_slug)` for per-pair aggregation (the hot path for
|
|
25
|
+
* edge-learning reads).
|
|
26
|
+
* - `(created_at)` for time-range pruning later.
|
|
27
|
+
*/
|
|
28
|
+
export function migrateMemoryV3Coactivation(database: DrizzleDb): void {
|
|
29
|
+
withCrashRecovery(database, CHECKPOINT_KEY, () => {
|
|
30
|
+
const raw = getSqliteFrom(database);
|
|
31
|
+
raw.exec(/*sql*/ `
|
|
32
|
+
CREATE TABLE IF NOT EXISTS memory_v3_coactivation (
|
|
33
|
+
id INTEGER PRIMARY KEY,
|
|
34
|
+
conversation_id TEXT NOT NULL,
|
|
35
|
+
turn INTEGER NOT NULL,
|
|
36
|
+
source_slug TEXT NOT NULL,
|
|
37
|
+
target_slug TEXT NOT NULL,
|
|
38
|
+
pass_gap INTEGER NOT NULL,
|
|
39
|
+
used INTEGER NOT NULL,
|
|
40
|
+
created_at INTEGER NOT NULL
|
|
41
|
+
)
|
|
42
|
+
`);
|
|
43
|
+
raw.exec(/*sql*/ `
|
|
44
|
+
CREATE INDEX IF NOT EXISTS idx_memory_v3_coactivation_pair
|
|
45
|
+
ON memory_v3_coactivation (source_slug, target_slug)
|
|
46
|
+
`);
|
|
47
|
+
raw.exec(/*sql*/ `
|
|
48
|
+
CREATE INDEX IF NOT EXISTS idx_memory_v3_coactivation_time
|
|
49
|
+
ON memory_v3_coactivation (created_at)
|
|
50
|
+
`);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function downMemoryV3Coactivation(database: DrizzleDb): void {
|
|
55
|
+
const raw = getSqliteFrom(database);
|
|
56
|
+
raw.exec(/*sql*/ `DROP TABLE IF EXISTS memory_v3_coactivation`);
|
|
57
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
+
import { getSqliteFrom } from "../db-connection.js";
|
|
3
|
+
import { withCrashRecovery } from "./validate-migration-state.js";
|
|
4
|
+
|
|
5
|
+
const CHECKPOINT_KEY = "migration_memory_v3_auto_edges_v1";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Create the memory_v3_auto_edges table — the **learned** edge graph, a
|
|
9
|
+
* distinct class from the curated `edges:` frontmatter graph.
|
|
10
|
+
*
|
|
11
|
+
* Each row is a weighted directed association `source_slug → target_slug` that
|
|
12
|
+
* the edge-learning job (`memory_v3_edge_learning`) accrues from *used*
|
|
13
|
+
* co-activations (migration 262's `memory_v3_coactivation` rows) and decays
|
|
14
|
+
* over time. `weight` is a multiplicatively-decaying real; `last_reinforced_at`
|
|
15
|
+
* is the wall-clock ms of the most recent reinforcement, used by the decay
|
|
16
|
+
* pass to compute elapsed time per pair.
|
|
17
|
+
*
|
|
18
|
+
* Auto-edges are advisory: the read path consumes only above-threshold pairs
|
|
19
|
+
* via edge-expansion's `extraAdjacency` seam, and high-weight pairs surface as
|
|
20
|
+
* promotion *candidates* for the assistant to ratify into curated `edges:`
|
|
21
|
+
* during consolidation. This table never auto-writes page frontmatter.
|
|
22
|
+
*
|
|
23
|
+
* `PRIMARY KEY(source_slug, target_slug)` makes each ordered pair unique, so
|
|
24
|
+
* reinforce is a single UPSERT. The index on `(weight)` keeps the
|
|
25
|
+
* above-threshold scan and top-N promotion-candidate read cheap as the learned
|
|
26
|
+
* graph grows.
|
|
27
|
+
*/
|
|
28
|
+
export function migrateMemoryV3AutoEdges(database: DrizzleDb): void {
|
|
29
|
+
withCrashRecovery(database, CHECKPOINT_KEY, () => {
|
|
30
|
+
const raw = getSqliteFrom(database);
|
|
31
|
+
raw.exec(/*sql*/ `
|
|
32
|
+
CREATE TABLE IF NOT EXISTS memory_v3_auto_edges (
|
|
33
|
+
source_slug TEXT NOT NULL,
|
|
34
|
+
target_slug TEXT NOT NULL,
|
|
35
|
+
weight REAL NOT NULL,
|
|
36
|
+
last_reinforced_at INTEGER NOT NULL,
|
|
37
|
+
PRIMARY KEY (source_slug, target_slug)
|
|
38
|
+
)
|
|
39
|
+
`);
|
|
40
|
+
raw.exec(/*sql*/ `
|
|
41
|
+
CREATE INDEX IF NOT EXISTS idx_memory_v3_auto_edges_weight
|
|
42
|
+
ON memory_v3_auto_edges (weight)
|
|
43
|
+
`);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function downMemoryV3AutoEdges(database: DrizzleDb): void {
|
|
48
|
+
const raw = getSqliteFrom(database);
|
|
49
|
+
raw.exec(/*sql*/ `DROP TABLE IF EXISTS memory_v3_auto_edges`);
|
|
50
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type DrizzleDb, getSqliteFrom } from "../db-connection.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Adds `call_site` (nullable TEXT) to the `llm_request_logs` table.
|
|
5
|
+
*
|
|
6
|
+
* Records the logical call site that produced the row — `mainAgent`,
|
|
7
|
+
* `compactionAgent`, etc. (string values from `LLMCallSite` in
|
|
8
|
+
* `config/schemas/llm.ts`). Lets the LLM Context Inspector and other
|
|
9
|
+
* observability tools filter "show me only compaction calls" without
|
|
10
|
+
* having to infer from request payload shape.
|
|
11
|
+
*
|
|
12
|
+
* No backfill — historical rows stay NULL ("we don't know"). New rows
|
|
13
|
+
* stamped at insertion time by callers of `recordRequestLog`.
|
|
14
|
+
*
|
|
15
|
+
* Idempotent — re-running is a no-op once the column exists. Modeled on
|
|
16
|
+
* migration 252 (`llm-request-log-agent-loop-exit-reason`).
|
|
17
|
+
*/
|
|
18
|
+
export function migrateLlmRequestLogCallSite(database: DrizzleDb): void {
|
|
19
|
+
const raw = getSqliteFrom(database);
|
|
20
|
+
|
|
21
|
+
const columns = raw
|
|
22
|
+
.query(`PRAGMA table_info(llm_request_logs)`)
|
|
23
|
+
.all() as Array<{ name: string }>;
|
|
24
|
+
const columnNames = new Set(columns.map((c) => c.name));
|
|
25
|
+
|
|
26
|
+
if (!columnNames.has("call_site")) {
|
|
27
|
+
raw.exec(`ALTER TABLE llm_request_logs ADD COLUMN call_site TEXT`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -234,6 +234,23 @@ export {
|
|
|
234
234
|
downConversationCleanedAt,
|
|
235
235
|
migrateConversationCleanedAt,
|
|
236
236
|
} from "./259-conversation-cleaned-at.js";
|
|
237
|
+
export {
|
|
238
|
+
downRenameCleanedAt,
|
|
239
|
+
migrateRenameCleanedAt,
|
|
240
|
+
} from "./260-rename-cleaned-at.js";
|
|
241
|
+
export {
|
|
242
|
+
downLlmUsageAddRawUsage,
|
|
243
|
+
migrateLlmUsageAddRawUsage,
|
|
244
|
+
} from "./261-llm-usage-add-raw-usage.js";
|
|
245
|
+
export {
|
|
246
|
+
downMemoryV3Coactivation,
|
|
247
|
+
migrateMemoryV3Coactivation,
|
|
248
|
+
} from "./262-memory-v3-coactivation.js";
|
|
249
|
+
export {
|
|
250
|
+
downMemoryV3AutoEdges,
|
|
251
|
+
migrateMemoryV3AutoEdges,
|
|
252
|
+
} from "./263-memory-v3-auto-edges.js";
|
|
253
|
+
export { migrateLlmRequestLogCallSite } from "./264-llm-request-log-call-site.js";
|
|
237
254
|
export {
|
|
238
255
|
MIGRATION_REGISTRY,
|
|
239
256
|
type MigrationRegistryEntry,
|
|
@@ -53,6 +53,10 @@ import { downA2ATasks } from "./251-a2a-tasks.js";
|
|
|
53
53
|
import { downExternalConversationBindingChatName } from "./254-external-conversation-binding-chat-name.js";
|
|
54
54
|
import { downMemoryV2InjectionEvents } from "./256-memory-v2-injection-events.js";
|
|
55
55
|
import { downConversationCleanedAt } from "./259-conversation-cleaned-at.js";
|
|
56
|
+
import { downRenameCleanedAt } from "./260-rename-cleaned-at.js";
|
|
57
|
+
import { downLlmUsageAddRawUsage } from "./261-llm-usage-add-raw-usage.js";
|
|
58
|
+
import { downMemoryV3Coactivation } from "./262-memory-v3-coactivation.js";
|
|
59
|
+
import { downMemoryV3AutoEdges } from "./263-memory-v3-auto-edges.js";
|
|
56
60
|
|
|
57
61
|
export interface MigrationRegistryEntry {
|
|
58
62
|
/** The checkpoint key written to memory_checkpoints on completion. */
|
|
@@ -453,6 +457,35 @@ export const MIGRATION_REGISTRY: MigrationRegistryEntry[] = [
|
|
|
453
457
|
"Add cleaned_at timestamp to conversations so /clean survives reload and forks inherit conditionally on fork point",
|
|
454
458
|
down: downConversationCleanedAt,
|
|
455
459
|
},
|
|
460
|
+
{
|
|
461
|
+
key: "migration_rename_cleaned_at_v1",
|
|
462
|
+
version: 53,
|
|
463
|
+
dependsOn: ["migration_conversation_cleaned_at_v1"],
|
|
464
|
+
description:
|
|
465
|
+
"Rename conversations.cleaned_at to history_stripped_at; the marker now records any injection-strip event (including compaction), not just /clean",
|
|
466
|
+
down: downRenameCleanedAt,
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
key: "migration_llm_usage_add_raw_usage_v1",
|
|
470
|
+
version: 54,
|
|
471
|
+
description:
|
|
472
|
+
"Add raw_usage TEXT column to llm_usage_events for storing the provider's untouched usage block as JSON (Anthropic TTL breakdown, OpenAI prompt/completion token details, etc.) so downstream consumers can extract provider-specific detail without per-field schema changes",
|
|
473
|
+
down: downLlmUsageAddRawUsage,
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
key: "migration_memory_v3_coactivation_v1",
|
|
477
|
+
version: 55,
|
|
478
|
+
description:
|
|
479
|
+
"Create memory_v3_coactivation table — append-only log of pass-1 → pass-N co-activation pairs (gradient signal) emitted by the v3 retrieval loop and reconciled later by edge-learning",
|
|
480
|
+
down: downMemoryV3Coactivation,
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
key: "migration_memory_v3_auto_edges_v1",
|
|
484
|
+
version: 56,
|
|
485
|
+
description:
|
|
486
|
+
"Create memory_v3_auto_edges table — weighted, decaying learned association graph (distinct from curated edges:) accrued by the edge-learning job from used co-activations and consumed above-threshold by edge expansion",
|
|
487
|
+
down: downMemoryV3AutoEdges,
|
|
488
|
+
},
|
|
456
489
|
];
|
|
457
490
|
|
|
458
491
|
export function getMaxMigrationVersion(): number {
|
|
@@ -21,7 +21,7 @@ export const conversations = sqliteTable(
|
|
|
21
21
|
.notNull()
|
|
22
22
|
.default(0),
|
|
23
23
|
contextCompactedAt: integer("context_compacted_at"),
|
|
24
|
-
|
|
24
|
+
historyStrippedAt: integer("history_stripped_at"),
|
|
25
25
|
slackContextCompactionWatermarkTs: text(
|
|
26
26
|
"slack_context_compaction_watermark_ts",
|
|
27
27
|
),
|
|
@@ -138,6 +138,16 @@ export const llmRequestLogs = sqliteTable(
|
|
|
138
138
|
responsePayload: text("response_payload").notNull(),
|
|
139
139
|
createdAt: integer("created_at").notNull(),
|
|
140
140
|
agentLoopExitReason: text("agent_loop_exit_reason"),
|
|
141
|
+
/**
|
|
142
|
+
* Logical call site that produced this row — e.g. `mainAgent`,
|
|
143
|
+
* `compactionAgent`. Stored as free-form text rather than enum-bound
|
|
144
|
+
* so a new call site can ship without a schema bump, but in practice
|
|
145
|
+
* callers pass values from `LLMCallSite` (`config/schemas/llm.ts`).
|
|
146
|
+
*
|
|
147
|
+
* Historical rows (pre-migration 264) stay NULL — "we don't know"
|
|
148
|
+
* rather than guessing `mainAgent`.
|
|
149
|
+
*/
|
|
150
|
+
callSite: text("call_site"),
|
|
141
151
|
},
|
|
142
152
|
(table) => [
|
|
143
153
|
index("idx_llm_request_logs_message_id").on(table.messageId),
|
|
@@ -217,6 +227,17 @@ export const llmUsageEvents = sqliteTable(
|
|
|
217
227
|
outputTokens: integer("output_tokens").notNull(),
|
|
218
228
|
cacheCreationInputTokens: integer("cache_creation_input_tokens"),
|
|
219
229
|
cacheReadInputTokens: integer("cache_read_input_tokens"),
|
|
230
|
+
/**
|
|
231
|
+
* The provider's untouched `usage` block, serialized as JSON. Anthropic
|
|
232
|
+
* nests the TTL breakdown under `cache_creation.ephemeral_{5m,1h}_input_tokens`;
|
|
233
|
+
* OpenAI nests cached-read details under `prompt_tokens_details`; both are
|
|
234
|
+
* just preserved verbatim so admin charts and downstream consumers can
|
|
235
|
+
* extract whatever provider-specific detail they need without a schema
|
|
236
|
+
* change every time a provider exposes a new field. `null` when the
|
|
237
|
+
* provider didn't return a usage block or for rows persisted before
|
|
238
|
+
* migration 260.
|
|
239
|
+
*/
|
|
240
|
+
rawUsage: text("raw_usage"),
|
|
220
241
|
estimatedCostUsd: real("estimated_cost_usd"),
|
|
221
242
|
pricingStatus: text("pricing_status").notNull(),
|
|
222
243
|
llmCallCount: integer("llm_call_count"),
|
|
@@ -2,6 +2,7 @@ import { count, desc, lt } from "drizzle-orm";
|
|
|
2
2
|
import { v4 as uuid } from "uuid";
|
|
3
3
|
|
|
4
4
|
import { getLogger } from "../util/logger.js";
|
|
5
|
+
import { runAsyncSqlite } from "./db-async-query.js";
|
|
5
6
|
import { getDb } from "./db-connection.js";
|
|
6
7
|
import { toolInvocations } from "./schema.js";
|
|
7
8
|
|
|
@@ -47,25 +48,52 @@ export function getRecentInvocations(limit: number) {
|
|
|
47
48
|
const log = getLogger("audit-log");
|
|
48
49
|
|
|
49
50
|
/**
|
|
50
|
-
* Delete tool invocation records older than the specified number of
|
|
51
|
-
* Returns the number of deleted records. Does nothing if
|
|
51
|
+
* Delete tool invocation records older than the specified number of
|
|
52
|
+
* days. Returns the number of deleted records. Does nothing if
|
|
53
|
+
* `retentionDays` is zero, negative, or non-finite.
|
|
54
|
+
*
|
|
55
|
+
* The DELETE runs through {@link runAsyncSqlite}: when the host has a
|
|
56
|
+
* `sqlite3` CLI it executes in a subprocess and the daemon's main
|
|
57
|
+
* event loop stays responsive. On hosts without the CLI the
|
|
58
|
+
* abstraction falls back to in-process blocking execution — the same
|
|
59
|
+
* behaviour the daemon had before this abstraction existed.
|
|
52
60
|
*/
|
|
53
|
-
export function rotateToolInvocations(
|
|
54
|
-
|
|
61
|
+
export async function rotateToolInvocations(
|
|
62
|
+
retentionDays: number,
|
|
63
|
+
): Promise<number> {
|
|
64
|
+
if (!Number.isFinite(retentionDays) || retentionDays <= 0) return 0;
|
|
55
65
|
|
|
56
|
-
|
|
66
|
+
// Math.floor guarantees a plain integer literal in the inlined SQL
|
|
67
|
+
// below; no decimal, no exponent, no surprise characters.
|
|
68
|
+
const cutoffMs = Math.floor(
|
|
69
|
+
Date.now() - retentionDays * 24 * 60 * 60 * 1000,
|
|
70
|
+
);
|
|
57
71
|
const db = getDb();
|
|
58
72
|
|
|
59
|
-
// Count before delete
|
|
73
|
+
// Count before delete so we can return + log the affected row count
|
|
74
|
+
// (`runAsyncSqlite` does not surface SQLite's `changes()` value).
|
|
60
75
|
const [countRow] = db
|
|
61
76
|
.select({ value: count() })
|
|
62
77
|
.from(toolInvocations)
|
|
63
|
-
.where(lt(toolInvocations.createdAt,
|
|
78
|
+
.where(lt(toolInvocations.createdAt, cutoffMs))
|
|
64
79
|
.all();
|
|
65
80
|
const toDelete = countRow?.value ?? 0;
|
|
66
81
|
if (toDelete === 0) return 0;
|
|
67
82
|
|
|
68
|
-
|
|
83
|
+
// `runAsyncSqlite` takes a raw SQL string — sqlite3 CLI subprocesses
|
|
84
|
+
// see SQL on stdin without a binding layer. `cutoffMs` is a plain
|
|
85
|
+
// integer (see Math.floor above), so inlining it here is safe.
|
|
86
|
+
const result = await runAsyncSqlite(
|
|
87
|
+
`DELETE FROM tool_invocations WHERE created_at < ${cutoffMs}`,
|
|
88
|
+
);
|
|
89
|
+
if (!result.ok) {
|
|
90
|
+
log.error(
|
|
91
|
+
{ error: result.error, backend: result.backend, toDelete },
|
|
92
|
+
"tool_invocations purge failed",
|
|
93
|
+
);
|
|
94
|
+
return 0;
|
|
95
|
+
}
|
|
96
|
+
|
|
69
97
|
log.info(
|
|
70
98
|
`Rotated ${toDelete} audit log entries older than ${retentionDays} day(s)`,
|
|
71
99
|
);
|