@vellumai/assistant 0.8.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +11 -0
- package/Dockerfile +5 -4
- package/README.md +2 -2
- package/docker-entrypoint.sh +16 -0
- package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
- package/eslint-rules/cli-no-daemon-internals.js +283 -0
- package/eslint.config.mjs +12 -0
- package/knip.json +2 -1
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
- package/openapi.yaml +4847 -1698
- package/package.json +3 -1
- package/scripts/generate-openapi.ts +52 -4
- package/scripts/sync-llm-catalog.ts +165 -0
- package/scripts/sync-web-search-catalog.ts +107 -0
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
- package/src/__tests__/anthropic-provider.test.ts +92 -2
- package/src/__tests__/app-control-flow.test.ts +7 -0
- package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
- package/src/__tests__/avatar-identity-sync.test.ts +87 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
- package/src/__tests__/btw-routes.test.ts +1 -0
- package/src/__tests__/call-site-routing-provider.test.ts +172 -45
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
- package/src/__tests__/channel-policy.test.ts +12 -0
- package/src/__tests__/checker.test.ts +89 -0
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +35 -7
- package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
- package/src/__tests__/config-loader-backfill.test.ts +526 -102
- package/src/__tests__/config-loader-corrupt.test.ts +68 -0
- package/src/__tests__/config-loader-platform-defaults.test.ts +77 -23
- package/src/__tests__/config-schema-cmd.test.ts +63 -29
- package/src/__tests__/config-schema.test.ts +14 -3
- package/src/__tests__/config-set-platform-guard.test.ts +75 -152
- package/src/__tests__/config-set-route.test.ts +198 -0
- package/src/__tests__/config-watcher.test.ts +6 -0
- package/src/__tests__/contacts-tools.test.ts +51 -199
- package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
- package/src/__tests__/context-search-agent-runner.test.ts +22 -138
- package/src/__tests__/context-search-conversations-source.test.ts +42 -16
- package/src/__tests__/context-search-fanout.test.ts +20 -157
- package/src/__tests__/context-search-memory-v2-source.test.ts +3 -3
- package/src/__tests__/context-search-types.test.ts +7 -2
- package/src/__tests__/context-window-manager.test.ts +389 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
- package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
- package/src/__tests__/conversation-error.test.ts +38 -0
- package/src/__tests__/conversation-fork-crud.test.ts +241 -1
- package/src/__tests__/conversation-inference-profile-route.test.ts +14 -14
- package/src/__tests__/conversation-init.benchmark.test.ts +1 -0
- package/src/__tests__/conversation-lifecycle.test.ts +124 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
- package/src/__tests__/conversation-process-callsite.test.ts +21 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +4 -4
- package/src/__tests__/conversation-slash-commands.test.ts +194 -2
- package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
- package/src/__tests__/credential-security-invariants.test.ts +5 -6
- package/src/__tests__/daemon-credential-client.test.ts +56 -1
- package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
- package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
- package/src/__tests__/db-proxy-transaction.test.ts +206 -0
- package/src/__tests__/external-plugin-loader.test.ts +458 -0
- package/src/__tests__/filing-service.test.ts +23 -3
- package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -8
- package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
- package/src/__tests__/heartbeat-service.test.ts +50 -233
- package/src/__tests__/history-repair.test.ts +89 -0
- package/src/__tests__/host-app-control-proxy.test.ts +109 -1
- package/src/__tests__/host-app-control-routes.test.ts +247 -1
- package/src/__tests__/host-browser-proxy.test.ts +416 -20
- package/src/__tests__/host-browser-routes.test.ts +325 -33
- package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
- package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
- package/src/__tests__/inference-profile-reaper.test.ts +154 -0
- package/src/__tests__/inference-profile-session-handler.test.ts +398 -0
- package/src/__tests__/inference-profile-session-ipc.test.ts +236 -0
- package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
- package/src/__tests__/install-skill-routing.test.ts +2 -2
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +15 -0
- package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
- package/src/__tests__/llm-catalog-parity.test.ts +146 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +188 -0
- package/src/__tests__/llm-request-log-source-factory.test.ts +124 -0
- package/src/__tests__/llm-resolver.test.ts +46 -0
- package/src/__tests__/managed-profile-guard.test.ts +131 -2
- package/src/__tests__/mcp-auth-routes.test.ts +1 -0
- package/src/__tests__/mcp-cli.test.ts +182 -220
- package/src/__tests__/mcp-health-check.test.ts +56 -27
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
- package/src/__tests__/message-complete-display-id.test.ts +175 -0
- package/src/__tests__/notification-platform-adapter.test.ts +229 -0
- package/src/__tests__/oauth-cli.test.ts +38 -2009
- package/src/__tests__/oauth-commands-routes.test.ts +711 -0
- package/src/__tests__/oauth-connect-routes.test.ts +174 -11
- package/src/__tests__/oauth-providers-routes.test.ts +14 -10
- package/src/__tests__/openai-responses-cutover-guard.test.ts +33 -12
- package/src/__tests__/openai-responses-provider.test.ts +17 -0
- package/src/__tests__/plugin-bootstrap.test.ts +31 -2
- package/src/__tests__/plugin-route-contribution.test.ts +31 -3
- package/src/__tests__/plugin-tool-contribution.test.ts +31 -3
- package/src/__tests__/plugin-types.test.ts +13 -11
- package/src/__tests__/process-message-background-slack.test.ts +46 -0
- package/src/__tests__/profile-entry-status.test.ts +43 -0
- package/src/__tests__/provider-managed-proxy-integration.test.ts +12 -4
- package/src/__tests__/provider-registry-ollama.test.ts +12 -4
- package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
- package/src/__tests__/relay-server.test.ts +118 -0
- package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
- package/src/__tests__/schedule-retry.test.ts +56 -4
- package/src/__tests__/schedule-routes.test.ts +104 -0
- package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
- package/src/__tests__/scheduler-recurrence.test.ts +87 -34
- package/src/__tests__/scheduler-reuse-conversation.test.ts +161 -5
- package/src/__tests__/scheduler-wake.test.ts +0 -63
- package/src/__tests__/secret-allowlist.test.ts +1 -0
- package/src/__tests__/secret-routes-managed-proxy.test.ts +12 -4
- package/src/__tests__/shell-credential-ref.test.ts +95 -3
- package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
- package/src/__tests__/skill-load-tool.test.ts +2 -4
- package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
- package/src/__tests__/suggestion-routes.test.ts +3 -3
- package/src/__tests__/sync-message-contract.test.ts +63 -0
- package/src/__tests__/task-scheduler.test.ts +88 -23
- package/src/__tests__/update-bulletin-job.test.ts +96 -193
- package/src/__tests__/usage-cli.test.ts +11 -73
- package/src/__tests__/user-plugin-loader.test.ts +145 -0
- package/src/__tests__/vercel-config.test.ts +168 -0
- package/src/__tests__/web-search-catalog-parity.test.ts +86 -0
- package/src/__tests__/web-search.test.ts +303 -2
- package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
- package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +58 -0
- package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +53 -20
- package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +191 -0
- package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
- package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
- package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
- package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
- package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
- package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
- package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
- package/src/acp/__tests__/helpers/which-stub.ts +4 -2
- package/src/acp/resolve-agent.test.ts +25 -0
- package/src/acp/resolve-agent.ts +13 -2
- package/src/acp/session-manager.ts +14 -0
- package/src/approvals/guardian-request-resolvers.ts +32 -87
- package/src/calls/relay-server.ts +35 -0
- package/src/calls/relay-setup-router.ts +36 -0
- package/src/calls/types.ts +1 -0
- package/src/calls/voice-session-bridge.ts +23 -4
- package/src/channels/config.ts +14 -1
- package/src/channels/types.ts +1 -0
- package/src/cli/AGENTS.md +164 -4
- package/src/cli/__tests__/notifications.test.ts +54 -0
- package/src/cli/commands/__tests__/avatar.test.ts +540 -0
- package/src/cli/commands/__tests__/backup.test.ts +236 -776
- package/src/cli/commands/__tests__/cache.test.ts +1 -1
- package/src/cli/commands/__tests__/changelog.test.ts +593 -0
- package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
- package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
- package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
- package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
- package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
- package/src/cli/commands/__tests__/email-core.test.ts +579 -0
- package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
- package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
- package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
- package/src/cli/commands/__tests__/skills.test.ts +563 -0
- package/src/cli/commands/__tests__/status.test.ts +249 -0
- package/src/cli/commands/__tests__/stt.test.ts +320 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
- package/src/cli/commands/__tests__/tts.test.ts +321 -0
- package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
- package/src/cli/commands/attachment.ts +8 -3
- package/src/cli/commands/audit.ts +95 -64
- package/src/cli/commands/auth.ts +61 -58
- package/src/cli/commands/avatar.ts +276 -390
- package/src/cli/commands/backup.ts +409 -505
- package/src/cli/commands/bash.ts +9 -5
- package/src/cli/commands/browser.ts +28 -9
- package/src/cli/commands/cache.ts +9 -4
- package/src/cli/commands/changelog.ts +414 -0
- package/src/cli/commands/channel-verification-sessions.ts +238 -317
- package/src/cli/commands/clients.ts +8 -3
- package/src/cli/commands/completions.ts +9 -9
- package/src/cli/commands/config.ts +102 -72
- package/src/cli/commands/contacts.ts +575 -696
- package/src/cli/commands/conversations-defer.ts +17 -69
- package/src/cli/commands/conversations-import.ts +90 -253
- package/src/cli/commands/conversations.ts +346 -436
- package/src/cli/commands/credential-execution.ts +9 -6
- package/src/cli/commands/credentials.ts +456 -736
- package/src/cli/commands/domain.ts +128 -206
- package/src/cli/commands/email.ts +606 -794
- package/src/cli/commands/gateway.ts +8 -1
- package/src/cli/commands/image-generation.ts +157 -205
- package/src/cli/commands/inference-providers.ts +352 -0
- package/src/cli/commands/inference-session.ts +415 -0
- package/src/cli/commands/inference.ts +87 -65
- package/src/cli/commands/keys.ts +8 -3
- package/src/cli/commands/mcp.ts +103 -287
- package/src/cli/commands/memory-v2.ts +162 -516
- package/src/cli/commands/notifications.ts +33 -7
- package/src/cli/commands/oauth/apps.ts +292 -261
- package/src/cli/commands/oauth/connect.ts +176 -297
- package/src/cli/commands/oauth/disconnect.ts +16 -215
- package/src/cli/commands/oauth/index.ts +49 -45
- package/src/cli/commands/oauth/mode.ts +43 -199
- package/src/cli/commands/oauth/ping.ts +17 -125
- package/src/cli/commands/oauth/providers.ts +732 -921
- package/src/cli/commands/oauth/request.ts +60 -350
- package/src/cli/commands/oauth/shared.ts +11 -121
- package/src/cli/commands/oauth/status.ts +31 -121
- package/src/cli/commands/oauth/token.ts +13 -55
- package/src/cli/commands/pending.ts +19 -10
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
- package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
- package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
- package/src/cli/commands/platform/connect.ts +16 -80
- package/src/cli/commands/platform/disconnect.ts +14 -112
- package/src/cli/commands/platform/index.ts +177 -246
- package/src/cli/commands/routes.ts +153 -336
- package/src/cli/commands/sequence.ts +316 -360
- package/src/cli/commands/skills.ts +449 -671
- package/src/cli/commands/status.ts +58 -37
- package/src/cli/commands/stt.ts +94 -262
- package/src/cli/commands/task.ts +14 -40
- package/src/cli/commands/trust.ts +8 -3
- package/src/cli/commands/tts.ts +162 -167
- package/src/cli/commands/ui.ts +35 -42
- package/src/cli/commands/usage.ts +188 -126
- package/src/cli/commands/watchers.ts +8 -3
- package/src/cli/commands/webhooks.ts +99 -193
- package/src/cli/lib/__tests__/register-command.test.ts +85 -0
- package/src/cli/lib/daemon-credential-client.ts +4 -5
- package/src/cli/lib/nested-value.ts +44 -0
- package/src/cli/lib/open-browser.ts +36 -0
- package/src/cli/lib/register-command.ts +19 -0
- package/src/cli/lib/time-ago.ts +34 -0
- package/src/cli/program.ts +2 -4
- package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
- package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
- package/src/cli/utils/conversation-id.ts +30 -0
- package/src/cli/utils/parse-duration.ts +41 -0
- package/src/config/acp-defaults.test.ts +5 -1
- package/src/config/acp-defaults.ts +11 -4
- package/src/config/bundled-skills/acp/TOOLS.json +2 -2
- package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
- package/src/config/bundled-skills/contacts/SKILL.md +12 -45
- package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
- package/src/config/bundled-tool-registry.ts +0 -2
- package/src/config/feature-flag-registry.json +16 -0
- package/src/config/llm-resolver.ts +16 -1
- package/src/config/loader.ts +76 -14
- package/src/config/raw-config-utils.ts +2 -30
- package/src/config/schema.ts +4 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
- package/src/config/schemas/call-site-catalog.ts +29 -7
- package/src/config/schemas/llm-request-logs.ts +57 -0
- package/src/config/schemas/llm.ts +52 -2
- package/src/config/schemas/memory-retrospective.ts +48 -0
- package/src/config/schemas/memory-v2.ts +32 -1
- package/src/config/schemas/memory.ts +4 -0
- package/src/config/schemas/services.ts +15 -12
- package/src/config/seed-inference-profiles.ts +195 -134
- package/src/contacts/contact-store.ts +0 -61
- package/src/context/window-manager.ts +191 -5
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +79 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +109 -4
- package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
- package/src/daemon/approval-generators.ts +23 -29
- package/src/daemon/config-watcher.ts +2 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +24 -0
- package/src/daemon/conversation-agent-loop.ts +127 -97
- package/src/daemon/conversation-error.ts +21 -0
- package/src/daemon/conversation-lifecycle.ts +46 -5
- package/src/daemon/conversation-process.ts +36 -19
- package/src/daemon/conversation-runtime-assembly.ts +14 -5
- package/src/daemon/conversation-slash.ts +175 -23
- package/src/daemon/conversation-store.ts +17 -10
- package/src/daemon/conversation-surfaces.ts +76 -12
- package/src/daemon/conversation-tool-setup.ts +24 -14
- package/src/daemon/conversation.ts +48 -9
- package/src/daemon/external-plugins-bootstrap.ts +18 -8
- package/src/daemon/guardian-action-generators.ts +7 -22
- package/src/daemon/handlers/config-model.ts +8 -126
- package/src/daemon/handlers/config-slack-channel.ts +10 -7
- package/src/daemon/handlers/config-vercel.ts +3 -1
- package/src/daemon/handlers/skills.ts +84 -5
- package/src/daemon/history-repair.ts +33 -6
- package/src/daemon/host-app-control-proxy.ts +44 -19
- package/src/daemon/host-bash-proxy.ts +85 -158
- package/src/daemon/host-browser-proxy.ts +96 -35
- package/src/daemon/host-proxy-base.ts +13 -1
- package/src/daemon/host-proxy-preactivation.ts +25 -1
- package/src/daemon/identity-helpers.ts +19 -0
- package/src/daemon/lifecycle.ts +42 -43
- package/src/daemon/meet-host-supervisor.ts +15 -15
- package/src/daemon/memory-v2-startup.ts +9 -2
- package/src/daemon/message-protocol.ts +6 -0
- package/src/daemon/message-types/bookmarks.ts +18 -0
- package/src/daemon/message-types/conversations.ts +12 -9
- package/src/daemon/message-types/messages.ts +9 -1
- package/src/daemon/message-types/sync.ts +60 -0
- package/src/daemon/pkb-reminder-builder.test.ts +54 -13
- package/src/daemon/pkb-reminder-builder.ts +21 -7
- package/src/daemon/process-message.ts +56 -23
- package/src/daemon/server.ts +23 -18
- package/src/daemon/shutdown-handlers.ts +0 -2
- package/src/daemon/tool-setup-types.ts +9 -0
- package/src/daemon/tool-side-effects.ts +6 -4
- package/src/daemon/wake-target-adapter.ts +11 -0
- package/src/export/transcript-formatter.ts +61 -2
- package/src/filing/filing-service.ts +40 -53
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +359 -0
- package/src/heartbeat/heartbeat-run-store.ts +2 -1
- package/src/heartbeat/heartbeat-service.ts +148 -127
- package/src/home/__tests__/feed-types.test.ts +63 -131
- package/src/home/__tests__/feed-writer.test.ts +77 -278
- package/src/home/__tests__/post-connect-feed.test.ts +9 -12
- package/src/home/feed-types.ts +19 -73
- package/src/home/feed-writer.ts +25 -156
- package/src/home/post-connect-feed.ts +1 -3
- package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
- package/src/ipc/__tests__/email-ipc.test.ts +506 -0
- package/src/ipc/__tests__/exit-helper.test.ts +104 -0
- package/src/ipc/__tests__/streaming-client.test.ts +237 -0
- package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
- package/src/ipc/assistant-server.ts +55 -6
- package/src/ipc/cli-client.ts +370 -50
- package/src/ipc/routes/db-proxy-transaction.ts +151 -0
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
- package/src/ipc/skill-routes/events.ts +30 -3
- package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
- package/src/live-voice/live-voice-session-manager.ts +11 -4
- package/src/live-voice/live-voice-session.ts +14 -6
- package/src/memory/__tests__/bookmark-crud.test.ts +258 -0
- package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
- package/src/memory/__tests__/conversation-types.test.ts +36 -0
- package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +213 -0
- package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
- package/src/memory/bookmark-crud.ts +179 -0
- package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
- package/src/memory/context-search/agent-protocol.ts +5 -1
- package/src/memory/context-search/agent-runner.ts +60 -85
- package/src/memory/context-search/limits.ts +1 -4
- package/src/memory/context-search/search.ts +23 -113
- package/src/memory/context-search/sources/conversations.ts +18 -6
- package/src/memory/context-search/sources/memory-v2.ts +39 -14
- package/src/memory/context-search/sources/memory.ts +7 -0
- package/src/memory/context-search/sources/workspace.ts +13 -10
- package/src/memory/context-search/types.ts +1 -1
- package/src/memory/conversation-bootstrap.ts +11 -0
- package/src/memory/conversation-crud.ts +312 -10
- package/src/memory/conversation-queries.ts +9 -5
- package/src/memory/conversation-title-service.ts +1 -0
- package/src/memory/conversation-types.ts +16 -0
- package/src/memory/db-init.ts +14 -0
- package/src/memory/embedding-backend.ts +2 -1
- package/src/memory/embedding-runtime-manager.ts +1 -2
- package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
- package/src/memory/graph/conversation-graph-memory.ts +76 -5
- package/src/memory/graph/extraction.ts +4 -0
- package/src/memory/graph/graph-memory-state-store.ts +16 -3
- package/src/memory/graph/tool-handlers.ts +17 -7
- package/src/memory/graph/tools.ts +44 -5
- package/src/memory/indexer.ts +17 -0
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +13 -15
- package/src/memory/jobs/embed-concept-page.ts +45 -9
- package/src/memory/jobs-store.ts +51 -1
- package/src/memory/jobs-worker.ts +52 -3
- package/src/memory/llm-request-log-source-clickhouse.ts +317 -0
- package/src/memory/llm-request-log-source-local.ts +26 -0
- package/src/memory/llm-request-log-source.ts +97 -0
- package/src/memory/llm-request-log-store.ts +1 -1
- package/src/memory/memory-retrospective-constants.ts +13 -0
- package/src/memory/memory-retrospective-enqueue.ts +114 -0
- package/src/memory/memory-retrospective-job.ts +351 -0
- package/src/memory/memory-retrospective-startup-cleanup.ts +108 -0
- package/src/memory/memory-retrospective-state.ts +162 -0
- package/src/memory/memory-retrospective-trigger-check.ts +91 -0
- package/src/memory/memory-v2-activation-log-store.ts +49 -5
- package/src/memory/memory-v2-concept-frequency.ts +4 -0
- package/src/memory/message-content.ts +38 -1
- package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
- package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
- package/src/memory/migrations/229-delete-private-conversations.test.ts +70 -1
- package/src/memory/migrations/229-delete-private-conversations.ts +12 -0
- package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
- package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
- package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
- package/src/memory/migrations/242-message-bookmarks.ts +38 -0
- package/src/memory/migrations/243-provider-connections.ts +68 -0
- package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
- package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
- package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
- package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
- package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
- package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
- package/src/memory/migrations/index.ts +7 -0
- package/src/memory/published-pages-store.ts +16 -0
- package/src/memory/schema/bookmarks.ts +38 -0
- package/src/memory/schema/conversations.ts +2 -0
- package/src/memory/schema/index.ts +2 -0
- package/src/memory/schema/inference.ts +29 -0
- package/src/memory/schema/memory-core.ts +9 -0
- package/src/memory/search/semantic.ts +1 -4
- package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
- package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
- package/src/memory/v2/__tests__/activation.test.ts +11 -4
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
- package/src/memory/v2/__tests__/consolidation-job.test.ts +123 -135
- package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
- package/src/memory/v2/__tests__/injection.test.ts +628 -10
- package/src/memory/v2/__tests__/migration.test.ts +7 -3
- package/src/memory/v2/__tests__/page-index.test.ts +277 -0
- package/src/memory/v2/__tests__/page-store.test.ts +14 -1
- package/src/memory/v2/__tests__/prompts-router.test.ts +257 -0
- package/src/memory/v2/__tests__/qdrant.test.ts +72 -0
- package/src/memory/v2/__tests__/reranker.test.ts +4 -4
- package/src/memory/v2/__tests__/router.test.ts +516 -0
- package/src/memory/v2/__tests__/sim.test.ts +45 -1
- package/src/memory/v2/__tests__/skill-store.test.ts +58 -3
- package/src/memory/v2/__tests__/static-context.test.ts +7 -22
- package/src/memory/v2/__tests__/sweep-job.test.ts +95 -0
- package/src/memory/v2/activation-store.ts +34 -5
- package/src/memory/v2/activation.ts +40 -27
- package/src/memory/v2/backfill-jobs.ts +17 -84
- package/src/memory/v2/consolidation-job.ts +85 -78
- package/src/memory/v2/frontmatter-sweep.ts +91 -0
- package/src/memory/v2/injection.ts +440 -109
- package/src/memory/v2/migration.ts +117 -20
- package/src/memory/v2/page-index.ts +191 -0
- package/src/memory/v2/page-store.ts +3 -0
- package/src/memory/v2/prompts/consolidation.ts +9 -7
- package/src/memory/v2/prompts/router.ts +192 -0
- package/src/memory/v2/qdrant.ts +100 -87
- package/src/memory/v2/reranker.ts +14 -7
- package/src/memory/v2/router.ts +322 -0
- package/src/memory/v2/sim.ts +25 -12
- package/src/memory/v2/skill-store.ts +118 -29
- package/src/memory/v2/static-context.ts +16 -9
- package/src/memory/v2/sweep-job.ts +122 -96
- package/src/memory/v2/types.ts +10 -6
- package/src/memory/validation.ts +13 -0
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
- package/src/notifications/__tests__/signal-registry.test.ts +17 -0
- package/src/notifications/adapters/platform.ts +171 -0
- package/src/notifications/conversation-pairing.ts +2 -2
- package/src/notifications/copy-composer.ts +15 -0
- package/src/notifications/destination-resolver.ts +21 -0
- package/src/notifications/emit-signal.ts +28 -1
- package/src/notifications/home-feed-side-effect.ts +111 -0
- package/src/notifications/signal.ts +5 -0
- package/src/permissions/checker.ts +12 -0
- package/src/permissions/ipc-risk-types.ts +2 -0
- package/src/plugin-api/index.ts +13 -0
- package/src/plugin-api/package.json +12 -0
- package/src/plugin-api/types.ts +62 -0
- package/src/plugins/defaults/injectors.ts +19 -3
- package/src/plugins/external-plugin-loader.ts +294 -0
- package/src/plugins/types.ts +46 -30
- package/src/plugins/user-loader.ts +64 -41
- package/src/proactive-artifact/job.test.ts +12 -4
- package/src/proactive-artifact/job.ts +4 -0
- package/src/proactive-artifact/trigger-state.test.ts +9 -0
- package/src/proactive-artifact/trigger-state.ts +4 -0
- package/src/prompts/__tests__/system-prompt.test.ts +105 -0
- package/src/prompts/system-prompt.ts +22 -1
- package/src/prompts/update-bulletin-job.ts +61 -73
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
- package/src/providers/__tests__/inference.test.ts +288 -0
- package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
- package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
- package/src/providers/__tests__/retry-callsite.test.ts +14 -32
- package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
- package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
- package/src/providers/anthropic/client.ts +95 -26
- package/src/providers/call-site-routing.ts +94 -16
- package/src/providers/connection-resolution.ts +163 -0
- package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
- package/src/providers/inference/adapter-factory.ts +173 -0
- package/src/providers/inference/auth.ts +112 -0
- package/src/providers/inference/backfill.ts +196 -0
- package/src/providers/inference/connections.ts +356 -0
- package/src/providers/inference/resolve-auth.ts +65 -0
- package/src/providers/model-catalog.ts +104 -6
- package/src/providers/openai/responses-provider.ts +4 -2
- package/src/providers/provider-env-vars.ts +17 -7
- package/src/providers/provider-secret-catalog.ts +49 -30
- package/src/providers/provider-send-message.ts +41 -20
- package/src/providers/registry.ts +143 -159
- package/src/providers/retry.ts +18 -10
- package/src/providers/search-provider-catalog.ts +121 -0
- package/src/runtime/AGENTS.md +18 -5
- package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
- package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
- package/src/runtime/actor-trust-resolver.ts +32 -10
- package/src/runtime/agent-wake.ts +35 -6
- package/src/runtime/assistant-event-hub.ts +3 -85
- package/src/runtime/auth/route-policy.ts +303 -8
- package/src/runtime/auth/same-actor.ts +2 -0
- package/src/runtime/background-job-runner.ts +339 -0
- package/src/runtime/btw-sidechain.ts +1 -0
- package/src/runtime/http-router.ts +36 -1
- package/src/runtime/http-server.ts +31 -5
- package/src/runtime/http-types.ts +2 -0
- package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
- package/src/runtime/middleware/request-logger.ts +62 -1
- package/src/runtime/pre-first-message-gate.ts +83 -0
- package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +251 -0
- package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +315 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +189 -0
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +4 -4
- package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
- package/src/runtime/routes/acp-routes.ts +10 -8
- package/src/runtime/routes/app-management-routes.ts +228 -3
- package/src/runtime/routes/approval-routes.ts +0 -18
- package/src/runtime/routes/audit-routes.ts +43 -0
- package/src/runtime/routes/auth-routes.ts +72 -0
- package/src/runtime/routes/avatar-routes.ts +273 -20
- package/src/runtime/routes/backup-routes.ts +406 -2
- package/src/runtime/routes/bookmark-routes.ts +154 -0
- package/src/runtime/routes/channel-verification-routes.ts +2 -1
- package/src/runtime/routes/contact-routes.ts +0 -160
- package/src/runtime/routes/conversation-cli-routes.ts +192 -0
- package/src/runtime/routes/conversation-management-routes.ts +30 -43
- package/src/runtime/routes/conversation-query-routes.ts +334 -86
- package/src/runtime/routes/conversation-routes.ts +31 -10
- package/src/runtime/routes/conversations-import-routes.ts +229 -0
- package/src/runtime/routes/credential-routes.ts +540 -0
- package/src/runtime/routes/debug-routes.ts +2 -2
- package/src/runtime/routes/document-pdf-renderer.ts +5 -1
- package/src/runtime/routes/domain-routes.ts +167 -0
- package/src/runtime/routes/email-routes.ts +603 -0
- package/src/runtime/routes/errors.ts +2 -2
- package/src/runtime/routes/events-routes.ts +192 -0
- package/src/runtime/routes/home-feed-routes.ts +6 -78
- package/src/runtime/routes/host-app-control-routes.ts +44 -2
- package/src/runtime/routes/host-browser-routes.ts +103 -22
- package/src/runtime/routes/http-adapter.ts +2 -0
- package/src/runtime/routes/identity-routes.ts +5 -0
- package/src/runtime/routes/image-generation-routes.ts +99 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +137 -1
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +87 -7
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -4
- package/src/runtime/routes/index.ts +36 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +312 -0
- package/src/runtime/routes/inference-profile-session-reaper.ts +98 -0
- package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +317 -0
- package/src/runtime/routes/inference-send-routes.ts +115 -0
- package/src/runtime/routes/integrations/twilio.ts +1 -0
- package/src/runtime/routes/mcp-auth-routes.ts +283 -9
- package/src/runtime/routes/memory-v2-routes.ts +13 -398
- package/src/runtime/routes/notification-routes.ts +2 -0
- package/src/runtime/routes/oauth-apps.ts +112 -7
- package/src/runtime/routes/oauth-commands-routes.ts +1007 -0
- package/src/runtime/routes/oauth-connect-routes.ts +67 -5
- package/src/runtime/routes/oauth-providers.ts +298 -8
- package/src/runtime/routes/platform-routes.ts +336 -0
- package/src/runtime/routes/playground/inject-failures.ts +2 -1
- package/src/runtime/routes/playground/reset-circuit.ts +2 -1
- package/src/runtime/routes/playground/state.ts +2 -1
- package/src/runtime/routes/publish-routes.ts +221 -0
- package/src/runtime/routes/schedule-routes.ts +82 -0
- package/src/runtime/routes/sequence-routes.ts +291 -0
- package/src/runtime/routes/settings-routes.ts +2 -10
- package/src/runtime/routes/skills-routes.ts +31 -1
- package/src/runtime/routes/stt-routes.ts +240 -3
- package/src/runtime/routes/surface-action-routes.ts +43 -7
- package/src/runtime/routes/tts-routes.ts +67 -0
- package/src/runtime/routes/types.ts +32 -0
- package/src/runtime/routes/user-routes-cli.ts +243 -0
- package/src/runtime/routes/webhook-routes.ts +165 -0
- package/src/runtime/sync/resource-sync-events.ts +25 -0
- package/src/runtime/sync/sync-publisher.test.ts +105 -0
- package/src/runtime/sync/sync-publisher.ts +21 -0
- package/src/schedule/scheduler.ts +200 -123
- package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
- package/src/security/secret-patterns.ts +3 -0
- package/src/sequence/engine.ts +38 -40
- package/src/subagent/manager.ts +20 -15
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
- package/src/tools/browser/browser-execution.ts +15 -4
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
- package/src/tools/browser/cdp-client/factory.ts +66 -5
- package/src/tools/browser/runtime-check.ts +77 -0
- package/src/tools/memory/register.test.ts +3 -3
- package/src/tools/memory/register.ts +9 -1
- package/src/tools/network/__tests__/web-search.test.ts +156 -0
- package/src/tools/network/web-search.ts +280 -37
- package/src/tools/permission-checker.ts +13 -5
- package/src/tools/subagent/spawn.ts +3 -3
- package/src/tools/terminal/shell.ts +44 -0
- package/src/usage/attribution.ts +3 -2
- package/src/util/pricing.ts +86 -160
- package/src/watcher/__tests__/engine.test.ts +301 -0
- package/src/watcher/constants.ts +7 -0
- package/src/watcher/engine.ts +90 -90
- package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
- package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
- package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +28 -4
- package/src/workspace/migrations/069-seed-onboarding-threads.ts +8 -2
- package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +104 -0
- package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +93 -0
- package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
- package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
- package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
- package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
- package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
- package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
- package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
- package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
- package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
- package/src/workspace/migrations/registry.ts +22 -0
- package/src/workspace/migrations/runner.ts +13 -2
- package/src/workspace/migrations/types.ts +13 -3
- package/src/workspace/provider-commit-message-generator.ts +3 -2
- package/src/__tests__/context-search-pkb-source.test.ts +0 -498
- package/src/__tests__/credentials-cli.test.ts +0 -1225
- package/src/__tests__/memory-admin-recall.test.ts +0 -213
- package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
- package/src/cli/commands/__tests__/email-download.test.ts +0 -260
- package/src/cli/commands/__tests__/email-list.test.ts +0 -216
- package/src/cli/commands/__tests__/email-register.test.ts +0 -186
- package/src/cli/commands/__tests__/email-send.test.ts +0 -416
- package/src/cli/commands/__tests__/email-status.test.ts +0 -185
- package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
- package/src/cli/commands/__tests__/routes.test.ts +0 -562
- package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
- package/src/cli/commands/autonomy.ts +0 -365
- package/src/cli/commands/memory.ts +0 -424
- package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -947
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
- package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
- package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
- package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
- package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
- package/src/cli/lib/daemon-avatar-client.ts +0 -37
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
- package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
- package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
- package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
- package/src/home/__tests__/emit-feed-event.test.ts +0 -169
- package/src/home/__tests__/feed-population-integration.test.ts +0 -312
- package/src/home/__tests__/feed-scheduler.test.ts +0 -222
- package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
- package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
- package/src/home/__tests__/rollup-producer.test.ts +0 -507
- package/src/home/assistant-feed-authoring.ts +0 -135
- package/src/home/emit-feed-event.ts +0 -169
- package/src/home/feed-scheduler.ts +0 -281
- package/src/home/platform-gmail-digest.ts +0 -163
- package/src/home/rewrite-command-preview.ts +0 -66
- package/src/home/rewrite-feed-title.ts +0 -58
- package/src/home/rollup-producer.ts +0 -426
- package/src/memory/admin.ts +0 -326
- package/src/memory/context-search/sources/pkb.ts +0 -476
- package/src/memory/graph/compaction.ts +0 -299
- /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Memory retrospective — startup orphan cleanup.
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
//
|
|
5
|
+
// When the daemon crashes mid-retrospective, the bootstrapped background
|
|
6
|
+
// conversation lingers in the `conversations` table (and possibly the
|
|
7
|
+
// `messages` table) as an orphan. The jobs-store recovery
|
|
8
|
+
// (`resetRunningJobsToPending`) handles re-running the job, which bootstraps
|
|
9
|
+
// a NEW background conversation — but the previous one is never deleted
|
|
10
|
+
// because the original handler's cleanup path didn't get a chance to run.
|
|
11
|
+
//
|
|
12
|
+
// This module sweeps those orphans on daemon startup. Run AFTER
|
|
13
|
+
// `resetRunningJobsToPending` so legitimate in-flight retries (which are
|
|
14
|
+
// represented by their pending job row, not by a memory-retrospective
|
|
15
|
+
// conversation directly) aren't swept.
|
|
16
|
+
//
|
|
17
|
+
// Sweep predicate:
|
|
18
|
+
// - `source = "memory-retrospective"`, AND
|
|
19
|
+
// - `last_message_at < now - 1 hour` (so a freshly-running job's
|
|
20
|
+
// conversation isn't swept on a startup that happens to race),
|
|
21
|
+
// - AND no pending OR running `memory_retrospective` job exists. (The
|
|
22
|
+
// orphan background conversation references the SOURCE conversation
|
|
23
|
+
// via the wake hint; if a job exists for that source, the background
|
|
24
|
+
// conversation might be the active one. We're conservative and only
|
|
25
|
+
// sweep when no job exists at all, since the worst-case false-positive
|
|
26
|
+
// is leaving a few extra orphans for the next sweep to catch.)
|
|
27
|
+
|
|
28
|
+
import { and, eq, inArray, isNotNull, lt, notInArray, sql } from "drizzle-orm";
|
|
29
|
+
|
|
30
|
+
import { getLogger } from "../util/logger.js";
|
|
31
|
+
import { deleteConversation } from "./conversation-crud.js";
|
|
32
|
+
import { getDb } from "./db-connection.js";
|
|
33
|
+
import { MEMORY_RETROSPECTIVE_SOURCE } from "./memory-retrospective-constants.js";
|
|
34
|
+
import { conversations, memoryJobs } from "./schema.js";
|
|
35
|
+
|
|
36
|
+
const log = getLogger("memory-retrospective-startup-cleanup");
|
|
37
|
+
|
|
38
|
+
const ORPHAN_AGE_MS = 60 * 60 * 1000;
|
|
39
|
+
|
|
40
|
+
export interface CleanupResult {
|
|
41
|
+
swept: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Find and delete orphan memory-retrospective background conversations.
|
|
46
|
+
* Idempotent — safe to call repeatedly. Returns the number of conversations
|
|
47
|
+
* deleted. Best-effort: errors deleting individual rows are logged and the
|
|
48
|
+
* sweep continues.
|
|
49
|
+
*/
|
|
50
|
+
export function sweepOrphanMemoryRetrospectiveConversations(
|
|
51
|
+
now: number = Date.now(),
|
|
52
|
+
): CleanupResult {
|
|
53
|
+
const cutoff = now - ORPHAN_AGE_MS;
|
|
54
|
+
const db = getDb();
|
|
55
|
+
|
|
56
|
+
const activeJobConversationIds = db
|
|
57
|
+
.select({
|
|
58
|
+
conversationId: sql<string>`json_extract(${memoryJobs.payload}, '$.conversationId')`,
|
|
59
|
+
})
|
|
60
|
+
.from(memoryJobs)
|
|
61
|
+
.where(
|
|
62
|
+
and(
|
|
63
|
+
eq(memoryJobs.type, "memory_retrospective"),
|
|
64
|
+
inArray(memoryJobs.status, ["pending", "running"]),
|
|
65
|
+
),
|
|
66
|
+
)
|
|
67
|
+
.all()
|
|
68
|
+
.map((row) => row.conversationId)
|
|
69
|
+
.filter((id): id is string => typeof id === "string" && id.length > 0);
|
|
70
|
+
|
|
71
|
+
const orphans = db
|
|
72
|
+
.select({ id: conversations.id })
|
|
73
|
+
.from(conversations)
|
|
74
|
+
.where(
|
|
75
|
+
and(
|
|
76
|
+
eq(conversations.source, MEMORY_RETROSPECTIVE_SOURCE),
|
|
77
|
+
// Conservative: only sweep rows that have had at least one message
|
|
78
|
+
// AND haven't seen activity recently. Conversations without a
|
|
79
|
+
// last_message_at value are too fresh to assess.
|
|
80
|
+
isNotNull(conversations.lastMessageAt),
|
|
81
|
+
lt(conversations.lastMessageAt, cutoff),
|
|
82
|
+
activeJobConversationIds.length > 0
|
|
83
|
+
? notInArray(conversations.id, activeJobConversationIds)
|
|
84
|
+
: sql`1=1`,
|
|
85
|
+
),
|
|
86
|
+
)
|
|
87
|
+
.all();
|
|
88
|
+
|
|
89
|
+
let swept = 0;
|
|
90
|
+
for (const row of orphans) {
|
|
91
|
+
try {
|
|
92
|
+
deleteConversation(row.id);
|
|
93
|
+
swept++;
|
|
94
|
+
} catch (err) {
|
|
95
|
+
log.warn(
|
|
96
|
+
{ err, conversationId: row.id },
|
|
97
|
+
"Failed to delete orphan memory-retrospective conversation; continuing",
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (swept > 0) {
|
|
102
|
+
log.info(
|
|
103
|
+
{ swept, cutoff },
|
|
104
|
+
"Swept orphan memory-retrospective background conversations",
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
return { swept };
|
|
108
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Memory retrospective — per-conversation state CRUD.
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
//
|
|
5
|
+
// Two pointers move independently:
|
|
6
|
+
// - `lastProcessedMessageId` advances ONLY when a retrospective run
|
|
7
|
+
// completes successfully (correctness invariant — failures must
|
|
8
|
+
// re-process the same messages on the next attempt).
|
|
9
|
+
// - `lastRunAt` advances on EVERY job end (success or failure). Drives the
|
|
10
|
+
// per-conversation cooldown gate in the trigger-check helper so failing
|
|
11
|
+
// jobs can't loop in tight retries across trigger types.
|
|
12
|
+
//
|
|
13
|
+
// The schema enforces the foreign key with ON DELETE CASCADE, so deleting a
|
|
14
|
+
// conversation collects its state row automatically.
|
|
15
|
+
|
|
16
|
+
import { eq } from "drizzle-orm";
|
|
17
|
+
|
|
18
|
+
import { type DrizzleDb, getDb } from "./db-connection.js";
|
|
19
|
+
import { memoryRetrospectiveState } from "./schema.js";
|
|
20
|
+
|
|
21
|
+
export interface MemoryRetrospectiveState {
|
|
22
|
+
conversationId: string;
|
|
23
|
+
lastProcessedMessageId: string;
|
|
24
|
+
lastRunAt: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Load the state row for a conversation, or `null` if no row exists.
|
|
29
|
+
*/
|
|
30
|
+
export function getRetrospectiveState(
|
|
31
|
+
conversationId: string,
|
|
32
|
+
): MemoryRetrospectiveState | null {
|
|
33
|
+
const row = getDb()
|
|
34
|
+
.select()
|
|
35
|
+
.from(memoryRetrospectiveState)
|
|
36
|
+
.where(eq(memoryRetrospectiveState.conversationId, conversationId))
|
|
37
|
+
.get();
|
|
38
|
+
if (!row) return null;
|
|
39
|
+
return {
|
|
40
|
+
conversationId: row.conversationId,
|
|
41
|
+
lastProcessedMessageId: row.lastProcessedMessageId,
|
|
42
|
+
lastRunAt: row.lastRunAt,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Upsert both pointers atomically. Used on successful retrospective runs.
|
|
48
|
+
*/
|
|
49
|
+
export function upsertRetrospectiveState(args: MemoryRetrospectiveState): void {
|
|
50
|
+
const db = getDb();
|
|
51
|
+
db.insert(memoryRetrospectiveState)
|
|
52
|
+
.values({
|
|
53
|
+
conversationId: args.conversationId,
|
|
54
|
+
lastProcessedMessageId: args.lastProcessedMessageId,
|
|
55
|
+
lastRunAt: args.lastRunAt,
|
|
56
|
+
})
|
|
57
|
+
.onConflictDoUpdate({
|
|
58
|
+
target: memoryRetrospectiveState.conversationId,
|
|
59
|
+
set: {
|
|
60
|
+
lastProcessedMessageId: args.lastProcessedMessageId,
|
|
61
|
+
lastRunAt: args.lastRunAt,
|
|
62
|
+
},
|
|
63
|
+
})
|
|
64
|
+
.run();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Carry the source conversation's retrospective state into a forked child so
|
|
69
|
+
* the fork doesn't re-process content the parent already covered. Synchronous
|
|
70
|
+
* so it can run inside the bun:sqlite transaction wrapping `forkConversation`.
|
|
71
|
+
*
|
|
72
|
+
* Mapping for `lastProcessedMessageId`:
|
|
73
|
+
*
|
|
74
|
+
* - source has no state row → no-op (child inherits "first run" semantics
|
|
75
|
+
* and `findMostRecentRetrospectiveFor` walks the fork chain instead).
|
|
76
|
+
* - source pointer is the `""` sentinel (failed-only attempts, never
|
|
77
|
+
* succeeded) → child pointer is also `""`.
|
|
78
|
+
* - source pointer is within the copied range (`forkedMessageIds` has it) →
|
|
79
|
+
* child pointer is the mapped forked message ID.
|
|
80
|
+
* - source pointer is past the fork boundary (not in `forkedMessageIds`) →
|
|
81
|
+
* child pointer is the last copied message's mapped ID. All copied
|
|
82
|
+
* messages have already been retro'd by the source, so the child should
|
|
83
|
+
* wait for new post-fork messages before its first retro fires.
|
|
84
|
+
*
|
|
85
|
+
* `lastRunAt` is copied verbatim — the cooldown gate inherits from source.
|
|
86
|
+
*/
|
|
87
|
+
export function forkRetrospectiveState(args: {
|
|
88
|
+
database: DrizzleDb;
|
|
89
|
+
sourceConversationId: string;
|
|
90
|
+
forkedConversationId: string;
|
|
91
|
+
forkedMessageIds: Map<string, string>;
|
|
92
|
+
lastCopiedSourceMessageId: string | null;
|
|
93
|
+
}): void {
|
|
94
|
+
const {
|
|
95
|
+
database,
|
|
96
|
+
sourceConversationId,
|
|
97
|
+
forkedConversationId,
|
|
98
|
+
forkedMessageIds,
|
|
99
|
+
lastCopiedSourceMessageId,
|
|
100
|
+
} = args;
|
|
101
|
+
|
|
102
|
+
const sourceRow = database
|
|
103
|
+
.select()
|
|
104
|
+
.from(memoryRetrospectiveState)
|
|
105
|
+
.where(eq(memoryRetrospectiveState.conversationId, sourceConversationId))
|
|
106
|
+
.get();
|
|
107
|
+
if (!sourceRow) return;
|
|
108
|
+
|
|
109
|
+
let forkedPointer = "";
|
|
110
|
+
if (sourceRow.lastProcessedMessageId !== "") {
|
|
111
|
+
const mapped = forkedMessageIds.get(sourceRow.lastProcessedMessageId);
|
|
112
|
+
if (mapped !== undefined) {
|
|
113
|
+
forkedPointer = mapped;
|
|
114
|
+
} else if (lastCopiedSourceMessageId !== null) {
|
|
115
|
+
// Source pointer is past the fork boundary — everything copied has
|
|
116
|
+
// already been processed by the source, so clamp to the last copied
|
|
117
|
+
// message so the fork waits for new post-fork messages.
|
|
118
|
+
forkedPointer = forkedMessageIds.get(lastCopiedSourceMessageId) ?? "";
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
database
|
|
123
|
+
.insert(memoryRetrospectiveState)
|
|
124
|
+
.values({
|
|
125
|
+
conversationId: forkedConversationId,
|
|
126
|
+
lastProcessedMessageId: forkedPointer,
|
|
127
|
+
lastRunAt: sourceRow.lastRunAt,
|
|
128
|
+
})
|
|
129
|
+
.onConflictDoUpdate({
|
|
130
|
+
target: memoryRetrospectiveState.conversationId,
|
|
131
|
+
set: {
|
|
132
|
+
lastProcessedMessageId: forkedPointer,
|
|
133
|
+
lastRunAt: sourceRow.lastRunAt,
|
|
134
|
+
},
|
|
135
|
+
})
|
|
136
|
+
.run();
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Advance only `lastRunAt`. Used on every failure path so the cooldown gate
|
|
141
|
+
* applies to subsequent trigger-driven enqueues. If no row exists yet (first
|
|
142
|
+
* attempt failed), seed `lastProcessedMessageId` to the empty string — a
|
|
143
|
+
* sentinel meaning "nothing successfully processed yet" that subsequent
|
|
144
|
+
* `getMessagesSince(...)` queries treat the same as a missing row.
|
|
145
|
+
*/
|
|
146
|
+
export function bumpRetrospectiveLastRunAt(
|
|
147
|
+
conversationId: string,
|
|
148
|
+
lastRunAt: number,
|
|
149
|
+
): void {
|
|
150
|
+
const db = getDb();
|
|
151
|
+
db.insert(memoryRetrospectiveState)
|
|
152
|
+
.values({
|
|
153
|
+
conversationId,
|
|
154
|
+
lastProcessedMessageId: "",
|
|
155
|
+
lastRunAt,
|
|
156
|
+
})
|
|
157
|
+
.onConflictDoUpdate({
|
|
158
|
+
target: memoryRetrospectiveState.conversationId,
|
|
159
|
+
set: { lastRunAt },
|
|
160
|
+
})
|
|
161
|
+
.run();
|
|
162
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Memory retrospective — periodic trigger check.
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
//
|
|
5
|
+
// Called from post-turn hooks (after each agent turn completes). Decides
|
|
6
|
+
// whether to enqueue a retrospective for this conversation based on:
|
|
7
|
+
//
|
|
8
|
+
// 1. Cooldown gate: never within `minCooldownMs` of the last attempt
|
|
9
|
+
// (success or failure). Prevents tight retry loops across trigger
|
|
10
|
+
// types.
|
|
11
|
+
// 2. Interval threshold: time since last attempt >= `timeThresholdMs`.
|
|
12
|
+
// 3. Message count threshold: new messages since `lastProcessedMessageId`
|
|
13
|
+
// >= `messageThreshold`.
|
|
14
|
+
//
|
|
15
|
+
// First-run case (no state row) skips the cooldown — `lastRunAt = 0` so the
|
|
16
|
+
// gap is effectively `Infinity`. The interval threshold trips immediately;
|
|
17
|
+
// the message-count threshold trips once enough messages accumulate.
|
|
18
|
+
|
|
19
|
+
import type { AssistantConfig } from "../config/types.js";
|
|
20
|
+
import { getLogger } from "../util/logger.js";
|
|
21
|
+
import { countMessagesAfter } from "./conversation-crud.js";
|
|
22
|
+
import { enqueueMemoryRetrospectiveIfEnabled } from "./memory-retrospective-enqueue.js";
|
|
23
|
+
import { getRetrospectiveState } from "./memory-retrospective-state.js";
|
|
24
|
+
|
|
25
|
+
const log = getLogger("memory-retrospective-trigger-check");
|
|
26
|
+
|
|
27
|
+
export type RetrospectiveTrigger = "interval" | "message_count";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Returns the trigger kind that fired, or `null` if no threshold tripped.
|
|
31
|
+
* Exported separately from `maybeEnqueueRetrospective` so tests can assert on
|
|
32
|
+
* the decision without observing side effects.
|
|
33
|
+
*/
|
|
34
|
+
export function shouldEnqueueRetrospective(args: {
|
|
35
|
+
state: { lastProcessedMessageId: string; lastRunAt: number } | null;
|
|
36
|
+
newMessageCount: number;
|
|
37
|
+
now: number;
|
|
38
|
+
timeThresholdMs: number;
|
|
39
|
+
messageThreshold: number;
|
|
40
|
+
minCooldownMs: number;
|
|
41
|
+
}): RetrospectiveTrigger | null {
|
|
42
|
+
const {
|
|
43
|
+
state,
|
|
44
|
+
newMessageCount,
|
|
45
|
+
now,
|
|
46
|
+
timeThresholdMs,
|
|
47
|
+
messageThreshold,
|
|
48
|
+
minCooldownMs,
|
|
49
|
+
} = args;
|
|
50
|
+
|
|
51
|
+
if (state && now - state.lastRunAt < minCooldownMs) return null;
|
|
52
|
+
|
|
53
|
+
if (state && now - state.lastRunAt >= timeThresholdMs) return "interval";
|
|
54
|
+
if (!state) return "interval";
|
|
55
|
+
|
|
56
|
+
if (newMessageCount >= messageThreshold) return "message_count";
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Post-turn hook entry point. Looks up state, counts new messages, evaluates
|
|
62
|
+
* thresholds, and enqueues if appropriate. Best-effort — any thrown error is
|
|
63
|
+
* caught and logged so the agent turn cleanup path doesn't fail.
|
|
64
|
+
*/
|
|
65
|
+
export function maybeEnqueueRetrospective(
|
|
66
|
+
conversationId: string,
|
|
67
|
+
config: AssistantConfig,
|
|
68
|
+
): void {
|
|
69
|
+
try {
|
|
70
|
+
const state = getRetrospectiveState(conversationId);
|
|
71
|
+
const newMessageCount = countMessagesAfter(
|
|
72
|
+
conversationId,
|
|
73
|
+
state?.lastProcessedMessageId ?? null,
|
|
74
|
+
);
|
|
75
|
+
if (newMessageCount === 0) return;
|
|
76
|
+
|
|
77
|
+
const trigger = shouldEnqueueRetrospective({
|
|
78
|
+
state,
|
|
79
|
+
newMessageCount,
|
|
80
|
+
now: Date.now(),
|
|
81
|
+
timeThresholdMs: config.memory.retrospective.timeThresholdMs,
|
|
82
|
+
messageThreshold: config.memory.retrospective.messageThreshold,
|
|
83
|
+
minCooldownMs: config.memory.retrospective.minCooldownMs,
|
|
84
|
+
});
|
|
85
|
+
if (!trigger) return;
|
|
86
|
+
|
|
87
|
+
enqueueMemoryRetrospectiveIfEnabled({ conversationId, trigger });
|
|
88
|
+
} catch (err) {
|
|
89
|
+
log.warn({ err, conversationId }, "trigger-check failed; skipping enqueue");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -39,8 +39,43 @@ export interface MemoryV2ConceptRowRecord {
|
|
|
39
39
|
*/
|
|
40
40
|
inRerankPool: boolean;
|
|
41
41
|
spreadContribution: number;
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Provenance of this concept row.
|
|
44
|
+
* - `prior_state` — carried over from prior turn's activation state.
|
|
45
|
+
* - `ann_top50` — entered via ANN top-K candidate pool.
|
|
46
|
+
* - `both` — present in both prior state and ANN pool.
|
|
47
|
+
* - `router` — selected by the Sonnet router (memory-v2 router
|
|
48
|
+
* mode). Router-mode rows zero out all activation values
|
|
49
|
+
* (`finalActivation`, `ownActivation`, `priorActivation`, channel
|
|
50
|
+
* similarities, rerank boosts, `spreadContribution`) because the
|
|
51
|
+
* router does not compute spreading-activation scores.
|
|
52
|
+
* - `carry_over` — router-mode row representing a slug carried over
|
|
53
|
+
* from `priorEverInjected` that the router did NOT re-pick on this
|
|
54
|
+
* turn. The cached attachment from a prior turn is still present
|
|
55
|
+
* on a prior user message; emitting `source: "router"` for these
|
|
56
|
+
* rows would overcount router selections in inspector queries.
|
|
57
|
+
* Same zeroed activation values as `router`.
|
|
58
|
+
*/
|
|
59
|
+
source: "prior_state" | "ann_top50" | "both" | "router" | "carry_over";
|
|
60
|
+
/**
|
|
61
|
+
* Per-turn outcome for this slug:
|
|
62
|
+
* - `in_context` — already injected on a prior turn; cached attachment
|
|
63
|
+
* remains visible without re-rendering.
|
|
64
|
+
* - `injected` — freshly rendered into this turn's user message.
|
|
65
|
+
* - `not_injected`— a candidate that didn't make `slugsToRender`.
|
|
66
|
+
* - `page_missing`— would-have-been-injected, but `readPage` returned
|
|
67
|
+
* null (file vanished between selection and render — stale Qdrant
|
|
68
|
+
* or edge-index entry).
|
|
69
|
+
* - `corrupt` — would-have-been-injected, but `readPage` threw
|
|
70
|
+
* (e.g. malformed frontmatter). Other slugs in the same batch
|
|
71
|
+
* rendered normally.
|
|
72
|
+
*/
|
|
73
|
+
status:
|
|
74
|
+
| "in_context"
|
|
75
|
+
| "injected"
|
|
76
|
+
| "not_injected"
|
|
77
|
+
| "page_missing"
|
|
78
|
+
| "corrupt";
|
|
44
79
|
}
|
|
45
80
|
|
|
46
81
|
export interface MemoryV2ConfigSnapshot {
|
|
@@ -57,7 +92,16 @@ export interface MemoryV2ConfigSnapshot {
|
|
|
57
92
|
export interface RecordMemoryV2ActivationLogParams {
|
|
58
93
|
conversationId: string;
|
|
59
94
|
turn: number;
|
|
60
|
-
|
|
95
|
+
/**
|
|
96
|
+
* Call-site mode: `context-load` for fresh / post-compaction loads,
|
|
97
|
+
* `per-turn` for normal append injections, `errored` when `injectMemoryV2Block`
|
|
98
|
+
* threw before completing — telemetry is still written so silent failures
|
|
99
|
+
* are observable in the database, with whatever `concepts` rows had been
|
|
100
|
+
* built so far (possibly empty). `router` indicates the Sonnet
|
|
101
|
+
* router selected the per-turn page set; router-mode rows carry zeroed
|
|
102
|
+
* activation values and `source: "router"` on every concept row.
|
|
103
|
+
*/
|
|
104
|
+
mode: "context-load" | "per-turn" | "errored" | "router";
|
|
61
105
|
concepts: MemoryV2ConceptRowRecord[];
|
|
62
106
|
config: MemoryV2ConfigSnapshot;
|
|
63
107
|
}
|
|
@@ -105,7 +149,7 @@ export function backfillMemoryV2ActivationMessageId(
|
|
|
105
149
|
export interface MemoryV2ActivationLog {
|
|
106
150
|
conversationId: string;
|
|
107
151
|
turn: number;
|
|
108
|
-
mode: "context-load" | "per-turn";
|
|
152
|
+
mode: "context-load" | "per-turn" | "errored" | "router";
|
|
109
153
|
concepts: MemoryV2ConceptRowRecord[];
|
|
110
154
|
config: MemoryV2ConfigSnapshot;
|
|
111
155
|
}
|
|
@@ -126,7 +170,7 @@ export function getMemoryV2ActivationLogByMessageIds(
|
|
|
126
170
|
return {
|
|
127
171
|
conversationId: row.conversationId,
|
|
128
172
|
turn: row.turn,
|
|
129
|
-
mode: row.mode as "context-load" | "per-turn",
|
|
173
|
+
mode: row.mode as "context-load" | "per-turn" | "errored" | "router",
|
|
130
174
|
concepts: JSON.parse(row.conceptsJson) as MemoryV2ConceptRowRecord[],
|
|
131
175
|
config: JSON.parse(row.configJson) as MemoryV2ConfigSnapshot,
|
|
132
176
|
};
|
|
@@ -52,6 +52,7 @@ const ZERO_COUNTS: ConceptFrequencyCounts = {
|
|
|
52
52
|
in_context: 0,
|
|
53
53
|
not_injected: 0,
|
|
54
54
|
page_missing: 0,
|
|
55
|
+
corrupt: 0,
|
|
55
56
|
};
|
|
56
57
|
|
|
57
58
|
interface CountRow {
|
|
@@ -130,6 +131,9 @@ export async function getConceptFrequencySummary(
|
|
|
130
131
|
case "page_missing":
|
|
131
132
|
entry.counts.page_missing += row.count;
|
|
132
133
|
break;
|
|
134
|
+
case "corrupt":
|
|
135
|
+
entry.counts.corrupt += row.count;
|
|
136
|
+
break;
|
|
133
137
|
default:
|
|
134
138
|
// Forward-compat: unknown status values are ignored, not summed into
|
|
135
139
|
// totalEvaluations. The activation pipeline produces a closed enum.
|
|
@@ -121,7 +121,6 @@ export function extractMediaBlockMeta(
|
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
|
|
125
124
|
function stableJson(value: unknown): string {
|
|
126
125
|
try {
|
|
127
126
|
return JSON.stringify(value);
|
|
@@ -129,3 +128,41 @@ function stableJson(value: unknown): string {
|
|
|
129
128
|
return "<unserializable />";
|
|
130
129
|
}
|
|
131
130
|
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Coerce stored message content into a single human-readable text string,
|
|
134
|
+
* dropping non-text blocks (images, tool calls, tool results, thinking,
|
|
135
|
+
* …). Used by call sites that want only the spoken text — sweep-model
|
|
136
|
+
* context, RAG backfill, bookmark previews. For richer renderings that
|
|
137
|
+
* include tool metadata, use {@link extractTextFromStoredMessageContent}
|
|
138
|
+
* instead.
|
|
139
|
+
*
|
|
140
|
+
* Handles the two on-disk shapes:
|
|
141
|
+
* - Modern rows: JSON-serialized `ContentBlock[]`
|
|
142
|
+
* - Legacy rows: plain string
|
|
143
|
+
*
|
|
144
|
+
* Parse failures fall back to returning the raw input trimmed (the
|
|
145
|
+
* legacy-string path).
|
|
146
|
+
*/
|
|
147
|
+
export function stringifyMessageContent(stored: string): string {
|
|
148
|
+
let parsed: unknown;
|
|
149
|
+
try {
|
|
150
|
+
parsed = JSON.parse(stored);
|
|
151
|
+
} catch {
|
|
152
|
+
return stored.trim();
|
|
153
|
+
}
|
|
154
|
+
if (typeof parsed === "string") return parsed.trim();
|
|
155
|
+
if (!Array.isArray(parsed)) return "";
|
|
156
|
+
const parts: string[] = [];
|
|
157
|
+
for (const block of parsed) {
|
|
158
|
+
if (
|
|
159
|
+
block &&
|
|
160
|
+
typeof block === "object" &&
|
|
161
|
+
(block as { type?: string }).type === "text" &&
|
|
162
|
+
typeof (block as { text?: unknown }).text === "string"
|
|
163
|
+
) {
|
|
164
|
+
parts.push((block as { text: string }).text);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return parts.join("\n").trim();
|
|
168
|
+
}
|
|
@@ -8,8 +8,13 @@ export function migrateAddConversationInferenceProfile(
|
|
|
8
8
|
const columns = raw.query(`PRAGMA table_info(conversations)`).all() as Array<{
|
|
9
9
|
name: string;
|
|
10
10
|
}>;
|
|
11
|
+
// Skip if either the original camelCase column or the renamed snake_case
|
|
12
|
+
// column from migration 228 is already present. Without the snake_case
|
|
13
|
+
// check, this migration would re-add the camelCase column on every boot
|
|
14
|
+
// after 228 runs, leaving both columns permanently.
|
|
11
15
|
const hasColumn = columns.some(
|
|
12
|
-
(column) =>
|
|
16
|
+
(column) =>
|
|
17
|
+
column.name === "inferenceProfile" || column.name === "inference_profile",
|
|
13
18
|
);
|
|
14
19
|
if (hasColumn) {
|
|
15
20
|
return;
|
|
@@ -6,19 +6,32 @@ import { tableHasColumn } from "./schema-introspection.js";
|
|
|
6
6
|
* by migration 227) to `inference_profile` so it matches the snake_case
|
|
7
7
|
* convention used by every other column on the table.
|
|
8
8
|
*
|
|
9
|
-
* Idempotent:
|
|
10
|
-
* -
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
9
|
+
* Idempotent and self-healing:
|
|
10
|
+
* - both columns present → drop the camelCase one (heals instances that
|
|
11
|
+
* already booted twice with the original buggy migration 227, where 227
|
|
12
|
+
* re-added the camelCase column after this migration renamed it).
|
|
13
|
+
* - camelCase column present, snake_case absent → rename it.
|
|
14
|
+
* - snake_case column present, camelCase absent → no-op.
|
|
15
|
+
* - neither column present → no-op.
|
|
14
16
|
*/
|
|
15
17
|
export function migrateRenameInferenceProfileSnakeCase(
|
|
16
18
|
database: DrizzleDb,
|
|
17
19
|
): void {
|
|
18
|
-
|
|
20
|
+
const hasSnake = tableHasColumn(
|
|
21
|
+
database,
|
|
22
|
+
"conversations",
|
|
23
|
+
"inference_profile",
|
|
24
|
+
);
|
|
25
|
+
const hasCamel = tableHasColumn(
|
|
26
|
+
database,
|
|
27
|
+
"conversations",
|
|
28
|
+
"inferenceProfile",
|
|
29
|
+
);
|
|
30
|
+
if (hasSnake && hasCamel) {
|
|
31
|
+
database.run(`ALTER TABLE conversations DROP COLUMN inferenceProfile`);
|
|
19
32
|
return;
|
|
20
33
|
}
|
|
21
|
-
if (!
|
|
34
|
+
if (!hasCamel) {
|
|
22
35
|
return;
|
|
23
36
|
}
|
|
24
37
|
database.run(
|
|
@@ -615,7 +615,8 @@ function seedGuardianAndApprovalRows(raw: Database, now: number): void {
|
|
|
615
615
|
created_at,
|
|
616
616
|
updated_at
|
|
617
617
|
) VALUES
|
|
618
|
-
('call-standard-guardian', 'conv-standard', 'test-provider', '+15550100', '+15550101', 'initiated', ${now}, ${now})
|
|
618
|
+
('call-standard-guardian', 'conv-standard', 'test-provider', '+15550100', '+15550101', 'initiated', ${now}, ${now}),
|
|
619
|
+
('call-private-guardian', 'conv-private', 'test-provider', '+15550102', '+15550103', 'initiated', ${now}, ${now});
|
|
619
620
|
|
|
620
621
|
INSERT INTO call_pending_questions (
|
|
621
622
|
id,
|
|
@@ -708,6 +709,23 @@ function seedGuardianAndApprovalRows(raw: Database, now: number): void {
|
|
|
708
709
|
('scoped-grant-standard', 'request_id', 'canonical-request-standard', NULL, NULL, 'vellum', 'vellum', 'conv-standard', 'active', ${now + 60000}, ${now}, ${now}),
|
|
709
710
|
('scoped-grant-unscoped', 'tool_signature', NULL, 'test_tool', 'digest-123', 'vellum', 'vellum', NULL, 'active', ${now + 60000}, ${now}, ${now});
|
|
710
711
|
|
|
712
|
+
INSERT INTO scoped_approval_grants (
|
|
713
|
+
id,
|
|
714
|
+
scope_mode,
|
|
715
|
+
request_id,
|
|
716
|
+
tool_name,
|
|
717
|
+
input_digest,
|
|
718
|
+
request_channel,
|
|
719
|
+
decision_channel,
|
|
720
|
+
conversation_id,
|
|
721
|
+
call_session_id,
|
|
722
|
+
status,
|
|
723
|
+
expires_at,
|
|
724
|
+
created_at,
|
|
725
|
+
updated_at
|
|
726
|
+
) VALUES
|
|
727
|
+
('scoped-grant-private-call-only', 'tool_signature', NULL, 'test_tool', 'digest-456', 'vellum', 'vellum', NULL, 'call-private-guardian', 'active', ${now + 60000}, ${now}, ${now});
|
|
728
|
+
|
|
711
729
|
INSERT INTO channel_guardian_approval_requests (
|
|
712
730
|
id,
|
|
713
731
|
run_id,
|
|
@@ -1034,6 +1052,13 @@ describe("migrateDeletePrivateConversations", () => {
|
|
|
1034
1052
|
expect(
|
|
1035
1053
|
countWhere(raw, "scoped_approval_grants", `id = 'scoped-grant-unscoped'`),
|
|
1036
1054
|
).toBe(1);
|
|
1055
|
+
expect(
|
|
1056
|
+
countWhere(
|
|
1057
|
+
raw,
|
|
1058
|
+
"scoped_approval_grants",
|
|
1059
|
+
`id = 'scoped-grant-private-call-only'`,
|
|
1060
|
+
),
|
|
1061
|
+
).toBe(0);
|
|
1037
1062
|
expect(
|
|
1038
1063
|
countWhere(
|
|
1039
1064
|
raw,
|
|
@@ -1084,4 +1109,48 @@ describe("migrateDeletePrivateConversations", () => {
|
|
|
1084
1109
|
),
|
|
1085
1110
|
).toBe(1);
|
|
1086
1111
|
});
|
|
1112
|
+
|
|
1113
|
+
test("removes orphan attachments left by prior runs that deleted private messages", () => {
|
|
1114
|
+
const db = createTestDb();
|
|
1115
|
+
const raw = getSqliteFrom(db);
|
|
1116
|
+
const now = Date.now();
|
|
1117
|
+
|
|
1118
|
+
bootstrapTables(raw);
|
|
1119
|
+
seedConversation(raw, "conv-standard", "standard");
|
|
1120
|
+
raw.exec(/*sql*/ `
|
|
1121
|
+
INSERT INTO attachments (
|
|
1122
|
+
id,
|
|
1123
|
+
original_filename,
|
|
1124
|
+
mime_type,
|
|
1125
|
+
size_bytes,
|
|
1126
|
+
kind,
|
|
1127
|
+
data_base64,
|
|
1128
|
+
created_at
|
|
1129
|
+
) VALUES (
|
|
1130
|
+
'orphan-private-attachment',
|
|
1131
|
+
'leaked.txt',
|
|
1132
|
+
'text/plain',
|
|
1133
|
+
1,
|
|
1134
|
+
'text',
|
|
1135
|
+
'eA==',
|
|
1136
|
+
${now}
|
|
1137
|
+
);
|
|
1138
|
+
`);
|
|
1139
|
+
|
|
1140
|
+
expect(
|
|
1141
|
+
countWhere(raw, "attachments", `id = 'orphan-private-attachment'`),
|
|
1142
|
+
).toBe(1);
|
|
1143
|
+
expect(
|
|
1144
|
+
countWhere(raw, "attachments", `id = 'conv-standard-attachment'`),
|
|
1145
|
+
).toBe(1);
|
|
1146
|
+
|
|
1147
|
+
migrateDeletePrivateConversations(db);
|
|
1148
|
+
|
|
1149
|
+
expect(
|
|
1150
|
+
countWhere(raw, "attachments", `id = 'orphan-private-attachment'`),
|
|
1151
|
+
).toBe(0);
|
|
1152
|
+
expect(
|
|
1153
|
+
countWhere(raw, "attachments", `id = 'conv-standard-attachment'`),
|
|
1154
|
+
).toBe(1);
|
|
1155
|
+
});
|
|
1087
1156
|
});
|