@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
|
@@ -31,7 +31,7 @@ import type { Provider } from "../../providers/types.js";
|
|
|
31
31
|
import { getLogger } from "../../util/logger.js";
|
|
32
32
|
import { type DrizzleDb, getSqliteFrom } from "../db-connection.js";
|
|
33
33
|
import { enqueueMemoryJob } from "../jobs-store.js";
|
|
34
|
-
import { slugify, writePage } from "./page-store.js";
|
|
34
|
+
import { deletePage, listPages, slugify, writePage } from "./page-store.js";
|
|
35
35
|
import type { ConceptPage } from "./types.js";
|
|
36
36
|
|
|
37
37
|
const log = getLogger("memory-v2-migration");
|
|
@@ -111,6 +111,9 @@ export function gatherV1State(
|
|
|
111
111
|
// domain layer (which v2 will eventually replace). We only need id /
|
|
112
112
|
// content / type / significance / event_date — everything else is unused
|
|
113
113
|
// by the migration.
|
|
114
|
+
// Soft-deleted nodes (`fidelity = 'gone'`) are excluded so deleted memories
|
|
115
|
+
// don't get resurrected into v2 concept pages. The rest of the codebase uses
|
|
116
|
+
// the same filter when reading live graph state.
|
|
114
117
|
const nodeRows = raw
|
|
115
118
|
.query<
|
|
116
119
|
{
|
|
@@ -122,10 +125,12 @@ export function gatherV1State(
|
|
|
122
125
|
},
|
|
123
126
|
[]
|
|
124
127
|
>(
|
|
125
|
-
/*sql*/ `SELECT id, content, type, significance, event_date FROM memory_graph_nodes`,
|
|
128
|
+
/*sql*/ `SELECT id, content, type, significance, event_date FROM memory_graph_nodes WHERE fidelity != 'gone'`,
|
|
126
129
|
)
|
|
127
130
|
.all();
|
|
131
|
+
const liveNodeIds = new Set<string>();
|
|
128
132
|
for (const row of nodeRows) {
|
|
133
|
+
liveNodeIds.add(row.id);
|
|
129
134
|
items.push({
|
|
130
135
|
id: row.id,
|
|
131
136
|
text: row.content,
|
|
@@ -138,16 +143,23 @@ export function gatherV1State(
|
|
|
138
143
|
}
|
|
139
144
|
|
|
140
145
|
// -- Graph edges --
|
|
146
|
+
// Edges with either endpoint pointing at a soft-deleted node are dropped to
|
|
147
|
+
// stay consistent with the node filter above.
|
|
141
148
|
const edgeRows = raw
|
|
142
149
|
.query<
|
|
143
150
|
{ source_node_id: string; target_node_id: string },
|
|
144
151
|
[]
|
|
145
152
|
>(/*sql*/ `SELECT source_node_id, target_node_id FROM memory_graph_edges`)
|
|
146
153
|
.all();
|
|
147
|
-
const edges: V1Edge[] =
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
154
|
+
const edges: V1Edge[] = [];
|
|
155
|
+
for (const row of edgeRows) {
|
|
156
|
+
if (!liveNodeIds.has(row.source_node_id)) continue;
|
|
157
|
+
if (!liveNodeIds.has(row.target_node_id)) continue;
|
|
158
|
+
edges.push({
|
|
159
|
+
sourceNodeId: row.source_node_id,
|
|
160
|
+
targetNodeId: row.target_node_id,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
151
163
|
|
|
152
164
|
// -- PKB content --
|
|
153
165
|
const pkbDir = join(workspaceDir, "pkb");
|
|
@@ -234,10 +246,10 @@ export interface Cluster {
|
|
|
234
246
|
/**
|
|
235
247
|
* Group v1 items into proposed concept pages.
|
|
236
248
|
*
|
|
237
|
-
* The heuristic is intentionally simple — embedding-
|
|
238
|
-
*
|
|
239
|
-
*
|
|
240
|
-
*
|
|
249
|
+
* The heuristic is intentionally simple — embedding-based clustering is a
|
|
250
|
+
* planned follow-up. For the v1-of-v2 cutover, file-based grouping for PKB
|
|
251
|
+
* plus per-graph-node singletons gives a reasonable starting set that the LLM
|
|
252
|
+
* can refine in stage 3:
|
|
241
253
|
*
|
|
242
254
|
* - Each `pkb_topic` file becomes its own cluster (slug derived from
|
|
243
255
|
* filename — that's literally what topic files were already keyed on).
|
|
@@ -333,7 +345,7 @@ export async function synthesizeConceptPage(
|
|
|
333
345
|
|
|
334
346
|
return {
|
|
335
347
|
slug: slugify(cluster.slugHint),
|
|
336
|
-
frontmatter: { edges: [], ref_files: [] },
|
|
348
|
+
frontmatter: { edges: [], ref_files: [], ref_urls: [] },
|
|
337
349
|
body: body.endsWith("\n") ? body : `${body}\n`,
|
|
338
350
|
};
|
|
339
351
|
}
|
|
@@ -447,13 +459,23 @@ export function collapseEdges(
|
|
|
447
459
|
// ---------------------------------------------------------------------------
|
|
448
460
|
|
|
449
461
|
/**
|
|
450
|
-
* Enqueue an `embed_concept_page` job for each newly-written slug. The
|
|
451
|
-
*
|
|
462
|
+
* Enqueue an `embed_concept_page` job for each newly-written slug. The handler
|
|
463
|
+
* is implemented separately — we just stage the queue here so the embeddings
|
|
452
464
|
* are ready by the time activation needs them.
|
|
465
|
+
*
|
|
466
|
+
* `database` is threaded through to `enqueueMemoryJob` as the override DB
|
|
467
|
+
* handle. Without this, jobs would be written to the global `getDb()` instead
|
|
468
|
+
* of the migration's DB — which is wrong for tests, isolated runners, and
|
|
469
|
+
* multi-workspace processes that pass an explicit `database`.
|
|
453
470
|
*/
|
|
454
|
-
export function enqueueEmbeds(slugs: string[]): number {
|
|
471
|
+
export function enqueueEmbeds(slugs: string[], database: DrizzleDb): number {
|
|
455
472
|
for (const slug of slugs) {
|
|
456
|
-
enqueueMemoryJob(
|
|
473
|
+
enqueueMemoryJob(
|
|
474
|
+
"embed_concept_page",
|
|
475
|
+
{ slug },
|
|
476
|
+
undefined,
|
|
477
|
+
database as never,
|
|
478
|
+
);
|
|
457
479
|
}
|
|
458
480
|
return slugs.length;
|
|
459
481
|
}
|
|
@@ -570,15 +592,37 @@ export async function runMemoryV2Migration(
|
|
|
570
592
|
};
|
|
571
593
|
});
|
|
572
594
|
|
|
595
|
+
// On force-rerun, drop pre-existing pages whose slugs aren't produced by
|
|
596
|
+
// this run. `writePage` is an atomic per-slug overwrite, so without this
|
|
597
|
+
// step a force rerun would leave orphan pages on disk from earlier slugs
|
|
598
|
+
// that no longer match any v1 cluster.
|
|
599
|
+
if (force) {
|
|
600
|
+
const newSlugs = new Set(finalizedPages.map((p) => p.slug));
|
|
601
|
+
const existingSlugs = await listPages(workspaceDir);
|
|
602
|
+
await Promise.all(
|
|
603
|
+
existingSlugs
|
|
604
|
+
.filter((slug) => !newSlugs.has(slug))
|
|
605
|
+
.map((slug) => deletePage(workspaceDir, slug)),
|
|
606
|
+
);
|
|
607
|
+
}
|
|
608
|
+
|
|
573
609
|
// Page writes hit different filenames so they're safe to fan out.
|
|
574
610
|
await Promise.all(
|
|
575
611
|
finalizedPages.map((page) => writePage(workspaceDir, page)),
|
|
576
612
|
);
|
|
577
613
|
|
|
578
614
|
const promotions = derivePromotions(items);
|
|
615
|
+
if (force) {
|
|
616
|
+
// Strip any prior migration block so force-reruns re-emit fresh
|
|
617
|
+
// promotions instead of being skipped by the in-file marker guard.
|
|
618
|
+
await stripPromotionMarkerBlocks(workspaceDir);
|
|
619
|
+
}
|
|
579
620
|
await appendPromotions(workspaceDir, promotions);
|
|
580
621
|
|
|
581
|
-
const embedsEnqueued = enqueueEmbeds(
|
|
622
|
+
const embedsEnqueued = enqueueEmbeds(
|
|
623
|
+
finalizedPages.map((p) => p.slug),
|
|
624
|
+
database,
|
|
625
|
+
);
|
|
582
626
|
|
|
583
627
|
await writeSentinel(workspaceDir);
|
|
584
628
|
|
|
@@ -598,10 +642,18 @@ export async function runMemoryV2Migration(
|
|
|
598
642
|
};
|
|
599
643
|
}
|
|
600
644
|
|
|
645
|
+
/**
|
|
646
|
+
* HTML marker embedded in each appended block so a crash-recovery rerun can
|
|
647
|
+
* detect already-applied promotions and skip the append. `appendLines` is a
|
|
648
|
+
* read-modify-write — without this, a crash between `appendPromotions` and
|
|
649
|
+
* `writeSentinel` would let the next boot duplicate every promotion line.
|
|
650
|
+
*/
|
|
651
|
+
const PROMOTION_MARKER = "<!-- migration:v1-to-v2 -->";
|
|
652
|
+
|
|
601
653
|
/**
|
|
602
654
|
* Append each promotion bucket to its target file. Files are created if
|
|
603
|
-
* absent — the
|
|
604
|
-
*
|
|
655
|
+
* absent — the `060-memory-v2-init` workspace migration seeds empty
|
|
656
|
+
* placeholders, so this is mostly belt-and-suspenders.
|
|
605
657
|
*/
|
|
606
658
|
async function appendPromotions(
|
|
607
659
|
workspaceDir: string,
|
|
@@ -626,7 +678,11 @@ async function appendPromotions(
|
|
|
626
678
|
}
|
|
627
679
|
}
|
|
628
680
|
|
|
629
|
-
/**
|
|
681
|
+
/**
|
|
682
|
+
* Append `lines` to `path`, creating it (with a trailing newline) if absent.
|
|
683
|
+
* If the file already contains `PROMOTION_MARKER`, the append is skipped — a
|
|
684
|
+
* prior partially-completed migration already wrote this block.
|
|
685
|
+
*/
|
|
630
686
|
async function appendLines(path: string, lines: string[]): Promise<void> {
|
|
631
687
|
let existing = "";
|
|
632
688
|
try {
|
|
@@ -634,8 +690,49 @@ async function appendLines(path: string, lines: string[]): Promise<void> {
|
|
|
634
690
|
} catch (err) {
|
|
635
691
|
if ((err as NodeJS.ErrnoException).code !== "ENOENT") throw err;
|
|
636
692
|
}
|
|
693
|
+
if (existing.includes(PROMOTION_MARKER)) return;
|
|
637
694
|
const trailing = existing.length === 0 || existing.endsWith("\n") ? "" : "\n";
|
|
638
|
-
const next = `${existing}${trailing}${lines.join("\n")}\n`;
|
|
695
|
+
const next = `${existing}${trailing}${PROMOTION_MARKER}\n${lines.join("\n")}\n`;
|
|
696
|
+
await writeFile(path, next, "utf-8");
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* Strip any prior migration-block (everything from the marker line through
|
|
701
|
+
* end of file) from each promotion target. Called on force-reruns so the
|
|
702
|
+
* marker guard in `appendLines` doesn't skip the new promotions.
|
|
703
|
+
*/
|
|
704
|
+
async function stripPromotionMarkerBlocks(workspaceDir: string): Promise<void> {
|
|
705
|
+
const memoryDir = join(workspaceDir, "memory");
|
|
706
|
+
const candidates: string[] = [
|
|
707
|
+
join(memoryDir, "essentials.md"),
|
|
708
|
+
join(memoryDir, "threads.md"),
|
|
709
|
+
];
|
|
710
|
+
const archiveDir = join(memoryDir, "archive");
|
|
711
|
+
if (existsSync(archiveDir)) {
|
|
712
|
+
for (const name of readdirSync(archiveDir)) {
|
|
713
|
+
if (name.startsWith("migrated-") && name.endsWith(".md")) {
|
|
714
|
+
candidates.push(join(archiveDir, name));
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
await Promise.all(candidates.map(stripMarkerBlock));
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
async function stripMarkerBlock(path: string): Promise<void> {
|
|
722
|
+
let existing: string;
|
|
723
|
+
try {
|
|
724
|
+
existing = await readFile(path, "utf-8");
|
|
725
|
+
} catch (err) {
|
|
726
|
+
if ((err as NodeJS.ErrnoException).code === "ENOENT") return;
|
|
727
|
+
throw err;
|
|
728
|
+
}
|
|
729
|
+
const idx = existing.indexOf(PROMOTION_MARKER);
|
|
730
|
+
if (idx === -1) return;
|
|
731
|
+
// Cut from the start of the marker line. `idx` already points at the marker,
|
|
732
|
+
// which `appendLines` always wrote at the start of its own line, so a plain
|
|
733
|
+
// slice here also drops the leading newline that preceded it (if any).
|
|
734
|
+
const trimmed = existing.slice(0, idx).replace(/\n+$/, "");
|
|
735
|
+
const next = trimmed.length === 0 ? "" : `${trimmed}\n`;
|
|
639
736
|
await writeFile(path, next, "utf-8");
|
|
640
737
|
}
|
|
641
738
|
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory v2 — Numbered page index for the router prompt.
|
|
3
|
+
*
|
|
4
|
+
* Renders a compact catalog of every concept page plus every seeded skill
|
|
5
|
+
* entry, sorted by slug ASCII for deterministic IDs, with each entry's
|
|
6
|
+
* outgoing edges resolved to numeric IDs. The router prompt consumes the
|
|
7
|
+
* pre-rendered block to choose which slugs to activate per turn.
|
|
8
|
+
*
|
|
9
|
+
* Skill entries (those in the `skills/<id>` namespace) participate alongside
|
|
10
|
+
* concept pages so the router can reach them through the same mechanism.
|
|
11
|
+
* Skill entries always have `edges: []` — the cross-page edge graph is a
|
|
12
|
+
* concept-page-only construct.
|
|
13
|
+
*
|
|
14
|
+
* The build is cached module-locally per `workspaceDir`, mirroring
|
|
15
|
+
* `edge-index.ts`. Callers must invalidate via `invalidatePageIndex` when
|
|
16
|
+
* concept pages or seeded skill entries change.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { getLogger } from "../../util/logger.js";
|
|
20
|
+
import { listPages, readPage } from "./page-store.js";
|
|
21
|
+
|
|
22
|
+
// Dynamic import for `./skill-store.js` happens inside `getPageIndex` so that
|
|
23
|
+
// modules that only need `invalidatePageIndex` (page-store.ts,
|
|
24
|
+
// tool-side-effects.ts) don't transitively pull in the embedding-backend
|
|
25
|
+
// chain via skill-store. Loading it at call time keeps the invalidation hook
|
|
26
|
+
// cheap and avoids cross-module import cycles in tests that mock jobs-store
|
|
27
|
+
// or embedding-backend.
|
|
28
|
+
|
|
29
|
+
const log = getLogger("memory-v2-page-index");
|
|
30
|
+
|
|
31
|
+
const SUMMARY_MAX_LENGTH = 200;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* One row in the rendered page index. `id` is a 1-based dense integer that is
|
|
35
|
+
* stable within a single index version (i.e. a single build). It changes when
|
|
36
|
+
* the index is rebuilt because IDs are derived from the slug-sorted position;
|
|
37
|
+
* callers must not persist them across builds.
|
|
38
|
+
*/
|
|
39
|
+
export interface PageIndexEntry {
|
|
40
|
+
/** 1-based dense numeric id, stable within an index version. */
|
|
41
|
+
id: number;
|
|
42
|
+
/** Concept-page slug or `skills/<id>`. */
|
|
43
|
+
slug: string;
|
|
44
|
+
/** Truncated to {@link SUMMARY_MAX_LENGTH} characters. */
|
|
45
|
+
summary: string;
|
|
46
|
+
/** Numeric IDs of outgoing edges, in sorted order. */
|
|
47
|
+
edges: number[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Snapshot of the page index for one workspace. `entries` is sorted by slug
|
|
52
|
+
* ASCII so IDs are deterministic across rebuilds with the same input. The
|
|
53
|
+
* `bySlug` and `byId` maps are convenience lookups; `rendered` is the prompt
|
|
54
|
+
* block consumed by the router.
|
|
55
|
+
*/
|
|
56
|
+
export interface PageIndex {
|
|
57
|
+
entries: PageIndexEntry[];
|
|
58
|
+
bySlug: Map<string, PageIndexEntry>;
|
|
59
|
+
byId: Map<number, PageIndexEntry>;
|
|
60
|
+
rendered: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface CachedIndex {
|
|
64
|
+
workspaceDir: string;
|
|
65
|
+
index: PageIndex;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let cache: CachedIndex | null = null;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Return a `PageIndex` for `workspaceDir`. Cached module-locally; the cache
|
|
72
|
+
* is invalidated by `invalidatePageIndex` (called by daemon-side hooks when
|
|
73
|
+
* concept pages or skill entries change).
|
|
74
|
+
*
|
|
75
|
+
* Cold builds list every concept page in parallel, drop pages whose read
|
|
76
|
+
* rejects, append seeded skill entries from `listSkillEntries()`, sort by
|
|
77
|
+
* slug for deterministic IDs, then resolve outgoing edges to numeric IDs.
|
|
78
|
+
*/
|
|
79
|
+
export async function getPageIndex(workspaceDir: string): Promise<PageIndex> {
|
|
80
|
+
if (cache && cache.workspaceDir === workspaceDir) {
|
|
81
|
+
return cache.index;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const slugs = await listPages(workspaceDir);
|
|
85
|
+
|
|
86
|
+
// Read pages in parallel; pages whose read rejects are dropped with a warn
|
|
87
|
+
// so a single broken page never blocks the rest of the index.
|
|
88
|
+
const settled = await Promise.allSettled(
|
|
89
|
+
slugs.map((slug) => readPage(workspaceDir, slug)),
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
// Intermediate shape used while we still need the raw outgoing slugs to
|
|
93
|
+
// resolve into numeric IDs after sorting.
|
|
94
|
+
interface DraftEntry {
|
|
95
|
+
slug: string;
|
|
96
|
+
summary: string;
|
|
97
|
+
outgoingSlugs: string[];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const drafts: DraftEntry[] = [];
|
|
101
|
+
for (let i = 0; i < settled.length; i++) {
|
|
102
|
+
const result = settled[i];
|
|
103
|
+
const slug = slugs[i];
|
|
104
|
+
if (result.status === "rejected") {
|
|
105
|
+
log.warn(
|
|
106
|
+
{ slug, err: result.reason },
|
|
107
|
+
"Dropping concept page from index — read failed",
|
|
108
|
+
);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const page = result.value;
|
|
112
|
+
if (!page) continue;
|
|
113
|
+
const summarySource = page.frontmatter.summary?.trim() || page.body.trim();
|
|
114
|
+
drafts.push({
|
|
115
|
+
slug,
|
|
116
|
+
summary: summarySource.slice(0, SUMMARY_MAX_LENGTH),
|
|
117
|
+
outgoingSlugs: page.frontmatter.edges,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const { listSkillEntries, SKILL_SLUG_PREFIX } =
|
|
122
|
+
await import("./skill-store.js");
|
|
123
|
+
for (const entry of listSkillEntries()) {
|
|
124
|
+
drafts.push({
|
|
125
|
+
slug: `${SKILL_SLUG_PREFIX}${entry.id}`,
|
|
126
|
+
summary: entry.content.trim().slice(0, SUMMARY_MAX_LENGTH),
|
|
127
|
+
outgoingSlugs: [],
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
drafts.sort((a, b) => (a.slug < b.slug ? -1 : a.slug > b.slug ? 1 : 0));
|
|
132
|
+
|
|
133
|
+
// Assign 1-based dense IDs in sort order so entries[i].id === i + 1.
|
|
134
|
+
const bySlug = new Map<string, PageIndexEntry>();
|
|
135
|
+
const byId = new Map<number, PageIndexEntry>();
|
|
136
|
+
const entries: PageIndexEntry[] = drafts.map((draft, i) => {
|
|
137
|
+
const entry: PageIndexEntry = {
|
|
138
|
+
id: i + 1,
|
|
139
|
+
slug: draft.slug,
|
|
140
|
+
summary: draft.summary,
|
|
141
|
+
edges: [],
|
|
142
|
+
};
|
|
143
|
+
bySlug.set(entry.slug, entry);
|
|
144
|
+
byId.set(entry.id, entry);
|
|
145
|
+
return entry;
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Edges whose target slug isn't in the index are dropped silently — the
|
|
149
|
+
// frontmatter sweep is responsible for surfacing those as warnings.
|
|
150
|
+
for (let i = 0; i < entries.length; i++) {
|
|
151
|
+
const draft = drafts[i];
|
|
152
|
+
const resolved: number[] = [];
|
|
153
|
+
for (const targetSlug of draft.outgoingSlugs) {
|
|
154
|
+
const target = bySlug.get(targetSlug);
|
|
155
|
+
if (target) resolved.push(target.id);
|
|
156
|
+
}
|
|
157
|
+
resolved.sort((a, b) => a - b);
|
|
158
|
+
entries[i].edges = resolved;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const rendered = renderIndex(entries);
|
|
162
|
+
const index: PageIndex = { entries, bySlug, byId, rendered };
|
|
163
|
+
cache = { workspaceDir, index };
|
|
164
|
+
return index;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Clear the cached index. Pass `workspaceDir` to scope invalidation to a
|
|
169
|
+
* specific cache entry; omit it to clear unconditionally.
|
|
170
|
+
*/
|
|
171
|
+
export function invalidatePageIndex(workspaceDir?: string): void {
|
|
172
|
+
if (!cache) return;
|
|
173
|
+
if (workspaceDir === undefined || cache.workspaceDir === workspaceDir) {
|
|
174
|
+
cache = null;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Render the prompt block: one line per entry shaped
|
|
180
|
+
* `[id] slug — summary (edges: a, b, c)`. Lines without outgoing edges drop
|
|
181
|
+
* the parenthetical entirely. Trailing newline so the block can be
|
|
182
|
+
* concatenated into a larger prompt without manual padding.
|
|
183
|
+
*/
|
|
184
|
+
function renderIndex(entries: readonly PageIndexEntry[]): string {
|
|
185
|
+
const lines = entries.map((entry) => {
|
|
186
|
+
const head = `[${entry.id}] ${entry.slug} — ${entry.summary}`;
|
|
187
|
+
if (entry.edges.length === 0) return head;
|
|
188
|
+
return `${head} (edges: ${entry.edges.join(", ")})`;
|
|
189
|
+
});
|
|
190
|
+
return lines.length > 0 ? `${lines.join("\n")}\n` : "";
|
|
191
|
+
}
|
|
@@ -33,6 +33,7 @@ import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
|
33
33
|
|
|
34
34
|
import { FRONTMATTER_REGEX } from "../../skills/frontmatter.js";
|
|
35
35
|
import { invalidateEdgeIndex } from "./edge-index.js";
|
|
36
|
+
import { invalidatePageIndex } from "./page-index.js";
|
|
36
37
|
import { type ConceptPage, ConceptPageFrontmatterSchema } from "./types.js";
|
|
37
38
|
|
|
38
39
|
/** Filename suffix for concept pages. */
|
|
@@ -287,6 +288,7 @@ export async function writePage(
|
|
|
287
288
|
throw err;
|
|
288
289
|
}
|
|
289
290
|
invalidateEdgeIndex(workspaceDir);
|
|
291
|
+
invalidatePageIndex(workspaceDir);
|
|
290
292
|
}
|
|
291
293
|
|
|
292
294
|
/**
|
|
@@ -397,6 +399,7 @@ export async function deletePage(
|
|
|
397
399
|
throw err;
|
|
398
400
|
}
|
|
399
401
|
invalidateEdgeIndex(workspaceDir);
|
|
402
|
+
invalidatePageIndex(workspaceDir);
|
|
400
403
|
}
|
|
401
404
|
|
|
402
405
|
/**
|
|
@@ -6,9 +6,11 @@
|
|
|
6
6
|
* runs with its full system prompt + tool surface; the text below is supplied
|
|
7
7
|
* as the wake hint.
|
|
8
8
|
*
|
|
9
|
-
* The single placeholder `{{CUTOFF}}` is substituted at runtime with
|
|
10
|
-
*
|
|
11
|
-
* `
|
|
9
|
+
* The single placeholder `{{CUTOFF}}` is substituted at runtime with a
|
|
10
|
+
* timestamp captured at job dispatch in the same `Mon D, h:mm AM/PM` shape
|
|
11
|
+
* that `buffer.md` entries use, so the agent's "timestamp ≥ cutoff" check
|
|
12
|
+
* compares like-with-like. Anything appended after that minute is the next
|
|
13
|
+
* pass's problem.
|
|
12
14
|
*
|
|
13
15
|
* Kept under `prompts/` rather than inlined in `consolidation-job.ts` so the
|
|
14
16
|
* prompt body is reviewable on its own and the job module stays focused on
|
|
@@ -432,10 +434,10 @@ For each article you touched:
|
|
|
432
434
|
This is the engine that decides who you are tomorrow. Be ORGANIZED. Care, judgment, voice. Your voice. Your wiki.`;
|
|
433
435
|
|
|
434
436
|
/**
|
|
435
|
-
* Resolve `CONSOLIDATION_PROMPT` with `{{CUTOFF}}` substituted. The
|
|
436
|
-
*
|
|
437
|
-
*
|
|
438
|
-
*
|
|
437
|
+
* Resolve `CONSOLIDATION_PROMPT` with `{{CUTOFF}}` substituted. The prompt
|
|
438
|
+
* treats the cutoff as opaque text — callers pass a `Mon D, h:mm AM/PM`
|
|
439
|
+
* timestamp matching the `buffer.md` entry format so the agent compares
|
|
440
|
+
* like-with-like.
|
|
439
441
|
*/
|
|
440
442
|
export function renderConsolidationPrompt(cutoff: string): string {
|
|
441
443
|
return CONSOLIDATION_PROMPT.replaceAll(CUTOFF_PLACEHOLDER, cutoff);
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory v2 — router prompt template.
|
|
3
|
+
*
|
|
4
|
+
* The router runs once per assistant turn and decides which concept pages (if
|
|
5
|
+
* any) should be injected on top of the always-on essentials/threads/recent
|
|
6
|
+
* block. The body lives here (under `prompts/`) so it is reviewable on its
|
|
7
|
+
* own, mirroring the convention established in `sweep.ts`.
|
|
8
|
+
*
|
|
9
|
+
* Three placeholders are substituted at runtime:
|
|
10
|
+
*
|
|
11
|
+
* - `{{ASSISTANT_NAME}}` — assistant display name (from IDENTITY.md when
|
|
12
|
+
* available, else the neutral fallback "the assistant").
|
|
13
|
+
* - `{{USER_NAME}}` — guardian display name (from the guardian persona when
|
|
14
|
+
* available, else "the user").
|
|
15
|
+
* - `{{PAGE_INDEX}}` — pre-rendered page index. Each line has the shape
|
|
16
|
+
* `[id] slug — summary (edges: a, b, c)` where edges are numeric IDs into
|
|
17
|
+
* the same list. The caller renders this so the prompt module stays
|
|
18
|
+
* stateless.
|
|
19
|
+
*
|
|
20
|
+
* Operators may replace the bundled body via
|
|
21
|
+
* `memory.v2.router.router_prompt_path` and {@link resolveRouterPrompt} — the
|
|
22
|
+
* same placeholder substitution applies to overrides.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { lstatSync, readFileSync } from "node:fs";
|
|
26
|
+
import { homedir } from "node:os";
|
|
27
|
+
import { isAbsolute, join } from "node:path";
|
|
28
|
+
|
|
29
|
+
import { getLogger } from "../../../util/logger.js";
|
|
30
|
+
import { getWorkspaceDir } from "../../../util/platform.js";
|
|
31
|
+
|
|
32
|
+
const log = getLogger("memory-v2-router-prompt");
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Hard upper bound on the override file size. The bundled prompt is well
|
|
36
|
+
* under 4 KiB; 1 MiB is generous-enough for any reasonable hand-edit while
|
|
37
|
+
* still preventing pathological inputs from being slurped into memory on
|
|
38
|
+
* every router call.
|
|
39
|
+
*/
|
|
40
|
+
const MAX_PROMPT_BYTES = 1 * 1024 * 1024;
|
|
41
|
+
|
|
42
|
+
/** Sentinel substituted with the assistant's display name at runtime. */
|
|
43
|
+
const ASSISTANT_NAME_PLACEHOLDER = "{{ASSISTANT_NAME}}";
|
|
44
|
+
|
|
45
|
+
/** Sentinel substituted with the guardian's display name at runtime. */
|
|
46
|
+
const USER_NAME_PLACEHOLDER = "{{USER_NAME}}";
|
|
47
|
+
|
|
48
|
+
/** Sentinel substituted with the rendered page index block at runtime. */
|
|
49
|
+
const PAGE_INDEX_PLACEHOLDER = "{{PAGE_INDEX}}";
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Router prompt — picks at most a handful of concept pages to inject for the
|
|
53
|
+
* next assistant turn. The model emits a `select_pages_to_inject` tool call
|
|
54
|
+
* with a `page_ids` array; the runtime parses the response via the tool
|
|
55
|
+
* definition declared in the router job module.
|
|
56
|
+
*
|
|
57
|
+
* Recent message context and `<now>` / `<already_injected_ids>` blocks are
|
|
58
|
+
* appended at the call site so we don't inadvertently expand `{{` inside
|
|
59
|
+
* dynamic content.
|
|
60
|
+
*/
|
|
61
|
+
const ROUTER_PROMPT = `You are a background helper for ${ASSISTANT_NAME_PLACEHOLDER}. Your job is to route memory pages for the next assistant turn between ${ASSISTANT_NAME_PLACEHOLDER} and ${USER_NAME_PLACEHOLDER}.
|
|
62
|
+
|
|
63
|
+
You will be shown the recent conversation, a \`<now>\` marker for the current time, an \`<already_injected_ids>\` block listing pages picked on the previous turn, and a \`# Concept Page Index\` listing every routable page on this workspace.
|
|
64
|
+
|
|
65
|
+
Pick the concept pages whose contents would help ${ASSISTANT_NAME_PLACEHOLDER} respond well on this turn. Lean toward inclusion when in doubt — missing a relevant page is a worse error than surfacing a few unused ones, because the assistant can ignore extras but can't summon context that wasn't loaded. Abstain (return an empty list) only when nothing in the index plausibly bears on the turn.
|
|
66
|
+
|
|
67
|
+
Index format. Each line of the index has the shape:
|
|
68
|
+
|
|
69
|
+
[id] slug — summary (edges: a, b, c)
|
|
70
|
+
|
|
71
|
+
\`id\` is a small integer used to refer to this page. \`edges\` are numeric IDs into the same list, pointing at related pages; you may follow them when one page strongly implies another.
|
|
72
|
+
|
|
73
|
+
Already-injected pages. Pages whose IDs appear in \`<already_injected_ids>\` were picked on the previous turn. Do not pick them again unless ${ASSISTANT_NAME_PLACEHOLDER} should re-anchor on that material — e.g., the topic genuinely returns after drifting away. Routine continuity does not require re-picking; the prior turn's pages are already in the assistant's working context.
|
|
74
|
+
|
|
75
|
+
Time. Bias toward pages that match the current state implied by \`<now>\` and the active conversational threads (what is happening today, what was just decided, who is being discussed). Stale pages with no bearing on the live conversation should be skipped even if their summaries look superficially relevant.
|
|
76
|
+
|
|
77
|
+
Emit your selection by calling \`select_pages_to_inject\` with the chosen \`page_ids\`. Return an empty array to abstain.
|
|
78
|
+
|
|
79
|
+
# Concept Page Index
|
|
80
|
+
|
|
81
|
+
${PAGE_INDEX_PLACEHOLDER}`;
|
|
82
|
+
|
|
83
|
+
interface RenderRouterPromptOpts {
|
|
84
|
+
assistantName: string | null;
|
|
85
|
+
userName: string | null;
|
|
86
|
+
pageIndexBlock: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Resolve `ROUTER_PROMPT` with assistant name, user name, and the rendered
|
|
91
|
+
* page index substituted in. Falls back to neutral defaults so the prompt
|
|
92
|
+
* still produces well-formed English when either name is unavailable on this
|
|
93
|
+
* workspace. The page index is substituted verbatim — callers are responsible
|
|
94
|
+
* for trimming/formatting it.
|
|
95
|
+
*/
|
|
96
|
+
export function renderRouterPrompt(opts: RenderRouterPromptOpts): string {
|
|
97
|
+
return substitutePlaceholders(ROUTER_PROMPT, opts);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Load the router prompt template, optionally overridden from the file
|
|
102
|
+
* referenced by `memory.v2.router.router_prompt_path`, then substitute the
|
|
103
|
+
* standard placeholders. Path-resolution rules mirror the consolidation
|
|
104
|
+
* prompt override: absolute paths used as-is, leading `~/` expanded to home,
|
|
105
|
+
* relative paths resolved under the workspace root.
|
|
106
|
+
*
|
|
107
|
+
* Failure handling is intentionally permissive — missing file, read error,
|
|
108
|
+
* oversized file, or empty/whitespace-only body all log a warning and fall
|
|
109
|
+
* back to the bundled prompt. Router selection must never break because of
|
|
110
|
+
* a bad override.
|
|
111
|
+
*/
|
|
112
|
+
export function resolveRouterPrompt(
|
|
113
|
+
overridePath: string | null,
|
|
114
|
+
opts: RenderRouterPromptOpts,
|
|
115
|
+
): string {
|
|
116
|
+
if (overridePath === null) return renderRouterPrompt(opts);
|
|
117
|
+
|
|
118
|
+
const resolvedPath = resolveOverridePath(overridePath);
|
|
119
|
+
let contents: string;
|
|
120
|
+
try {
|
|
121
|
+
const stat = lstatSync(resolvedPath);
|
|
122
|
+
if (!stat.isFile()) {
|
|
123
|
+
log.warn(
|
|
124
|
+
{
|
|
125
|
+
configuredPath: overridePath,
|
|
126
|
+
resolvedPath,
|
|
127
|
+
reason: "not_regular_file",
|
|
128
|
+
fallback: "bundled",
|
|
129
|
+
},
|
|
130
|
+
"router prompt override is not a regular file; using bundled prompt",
|
|
131
|
+
);
|
|
132
|
+
return renderRouterPrompt(opts);
|
|
133
|
+
}
|
|
134
|
+
if (stat.size > MAX_PROMPT_BYTES) {
|
|
135
|
+
log.warn(
|
|
136
|
+
{
|
|
137
|
+
configuredPath: overridePath,
|
|
138
|
+
resolvedPath,
|
|
139
|
+
size: stat.size,
|
|
140
|
+
limit: MAX_PROMPT_BYTES,
|
|
141
|
+
reason: "oversized_override",
|
|
142
|
+
fallback: "bundled",
|
|
143
|
+
},
|
|
144
|
+
"router prompt override exceeds size limit; using bundled prompt",
|
|
145
|
+
);
|
|
146
|
+
return renderRouterPrompt(opts);
|
|
147
|
+
}
|
|
148
|
+
contents = readFileSync(resolvedPath, "utf-8");
|
|
149
|
+
} catch (err) {
|
|
150
|
+
const code = (err as NodeJS.ErrnoException).code;
|
|
151
|
+
log.warn(
|
|
152
|
+
{ configuredPath: overridePath, resolvedPath, code, fallback: "bundled" },
|
|
153
|
+
"router prompt override unreadable; using bundled prompt",
|
|
154
|
+
);
|
|
155
|
+
return renderRouterPrompt(opts);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (contents.trim().length === 0) {
|
|
159
|
+
log.warn(
|
|
160
|
+
{
|
|
161
|
+
configuredPath: overridePath,
|
|
162
|
+
resolvedPath,
|
|
163
|
+
reason: "empty_override",
|
|
164
|
+
fallback: "bundled",
|
|
165
|
+
},
|
|
166
|
+
"router prompt override is empty; using bundled prompt",
|
|
167
|
+
);
|
|
168
|
+
return renderRouterPrompt(opts);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return substitutePlaceholders(contents, opts);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function substitutePlaceholders(
|
|
175
|
+
template: string,
|
|
176
|
+
opts: RenderRouterPromptOpts,
|
|
177
|
+
): string {
|
|
178
|
+
const assistant = opts.assistantName?.trim() || "the assistant";
|
|
179
|
+
const user = opts.userName?.trim() || "the user";
|
|
180
|
+
return template
|
|
181
|
+
.replaceAll(ASSISTANT_NAME_PLACEHOLDER, assistant)
|
|
182
|
+
.replaceAll(USER_NAME_PLACEHOLDER, user)
|
|
183
|
+
.replaceAll(PAGE_INDEX_PLACEHOLDER, opts.pageIndexBlock);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function resolveOverridePath(overridePath: string): string {
|
|
187
|
+
if (overridePath.startsWith("~/")) {
|
|
188
|
+
return join(homedir(), overridePath.slice(2));
|
|
189
|
+
}
|
|
190
|
+
if (isAbsolute(overridePath)) return overridePath;
|
|
191
|
+
return join(getWorkspaceDir(), overridePath);
|
|
192
|
+
}
|