@vellumai/assistant 0.10.4-staging.1 → 0.10.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +13 -13
- package/bun.lock +165 -0
- package/docs/architecture/memory.md +26 -0
- package/eslint-rules/cli-no-daemon-internals.js +9 -8
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +18 -0
- package/openapi.yaml +677 -15
- package/package.json +8 -1
- package/scripts/generate-openapi.ts +149 -62
- package/src/__tests__/acp-session.test.ts +2 -2
- package/src/__tests__/activation-early-marking.test.ts +4 -4
- package/src/__tests__/actor-token-service.test.ts +2 -3
- package/src/__tests__/agent-loop-compaction-events.test.ts +1 -0
- package/src/__tests__/agent-loop-compaction-strip.test.ts +2 -0
- package/src/__tests__/agent-loop-exit-reason.test.ts +4 -1
- package/src/__tests__/agent-loop-override-profile.test.ts +2 -2
- package/src/__tests__/agent-loop-regrowth-guard.test.ts +8 -0
- package/src/__tests__/agent-loop.test.ts +1 -0
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +3 -3
- package/src/__tests__/agent-wake-override-profile.test.ts +3 -3
- package/src/__tests__/annotate-activity-metadata.test.ts +4 -4
- package/src/__tests__/annotate-risk-options.test.ts +4 -4
- package/src/__tests__/anthropic-provider.test.ts +53 -2
- package/src/__tests__/app-builder-tool-scripts.test.ts +2 -2
- package/src/__tests__/app-bundler.test.ts +1 -1
- package/src/__tests__/app-conversation-ids-backfill.test.ts +4 -4
- package/src/__tests__/app-conversation-ids.test.ts +1 -1
- package/src/__tests__/app-dir-path-guard.test.ts +2 -2
- package/src/__tests__/app-executors.test.ts +1 -1
- package/src/__tests__/app-git-history.test.ts +2 -2
- package/src/__tests__/app-git-service.test.ts +2 -2
- package/src/__tests__/app-routes-csp.test.ts +2 -2
- package/src/__tests__/app-source-watcher.test.ts +1 -1
- package/src/__tests__/app-store-dir-names.test.ts +1 -1
- package/src/__tests__/approval-cascade.test.ts +7 -7
- package/src/__tests__/approval-interception-trust-gates.test.ts +1 -1
- package/src/__tests__/approval-primitive.test.ts +3 -3
- package/src/__tests__/approval-routes-http.test.ts +2 -2
- package/src/__tests__/assistant-event-hub-machine-name.test.ts +1 -1
- package/src/__tests__/assistant-events-sse-hardening.test.ts +2 -2
- package/src/__tests__/assistant-events-sse-shed.test.ts +2 -2
- package/src/__tests__/attachment-upload-trusted-source.test.ts +4 -2
- package/src/__tests__/attachments-store.test.ts +9 -6
- package/src/__tests__/audit-log-rotation.test.ts +6 -4
- package/src/__tests__/auth-fallback-events-store.test.ts +4 -4
- package/src/__tests__/auto-analysis-end-to-end.test.ts +13 -9
- package/src/__tests__/background-workers-disk-pressure.test.ts +12 -7
- package/src/__tests__/btw-routes.test.ts +4 -5
- package/src/__tests__/build-persisted-content.test.ts +4 -4
- package/src/__tests__/call-controller.test.ts +6 -6
- package/src/__tests__/call-conversation-messages.test.ts +4 -4
- package/src/__tests__/call-domain.test.ts +5 -5
- package/src/__tests__/call-pointer-messages.test.ts +5 -5
- package/src/__tests__/call-recovery.test.ts +3 -3
- package/src/__tests__/call-routes-http.test.ts +3 -3
- package/src/__tests__/call-store.test.ts +3 -3
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +2 -2
- package/src/__tests__/canonical-guardian-store.test.ts +3 -3
- package/src/__tests__/channel-approval-routes.test.ts +9 -7
- package/src/__tests__/channel-delivery-store.test.ts +8 -8
- package/src/__tests__/channel-guardian.test.ts +24 -66
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +4 -4
- package/src/__tests__/channel-reply-delivery.test.ts +2 -2
- package/src/__tests__/channel-retry-sweep.test.ts +49 -4
- package/src/__tests__/clawhub.test.ts +4 -0
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +2 -2
- package/src/__tests__/compaction-events.test.ts +8 -8
- package/src/__tests__/compaction-ledger-store.test.ts +4 -4
- package/src/__tests__/compaction-trail-store.test.ts +5 -5
- package/src/__tests__/compaction.benchmark.test.ts +5 -5
- package/src/__tests__/compactor-call-site-logging.test.ts +5 -5
- package/src/__tests__/compactor-image-manifest-trust.test.ts +7 -4
- package/src/__tests__/compactor-low-watermark-cut.test.ts +5 -5
- package/src/__tests__/compactor-preserved-tail-count.test.ts +4 -4
- package/src/__tests__/compactor-summary-call-truncation.test.ts +5 -5
- package/src/__tests__/compactor-web-search-strip.test.ts +4 -4
- package/src/__tests__/config-get-vision-flag.test.ts +1 -1
- package/src/__tests__/config-loader-backfill.test.ts +84 -104
- package/src/__tests__/config-set-route.test.ts +5 -2
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +3 -3
- package/src/__tests__/config-watcher-skill-reseed.test.ts +39 -112
- package/src/__tests__/config-watcher.test.ts +54 -31
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +4 -4
- package/src/__tests__/contact-store-interaction-info.test.ts +3 -3
- package/src/__tests__/contact-store-user-file.test.ts +91 -81
- package/src/__tests__/contacts-relay-reads.test.ts +21 -3
- package/src/__tests__/contacts-tools.test.ts +2 -2
- package/src/__tests__/contacts-write.test.ts +2 -2
- package/src/__tests__/context-search-agent-protocol.test.ts +2 -2
- package/src/__tests__/context-search-agent-runner.test.ts +2 -2
- package/src/__tests__/context-search-conversations-source.test.ts +5 -5
- package/src/__tests__/context-search-fanout.test.ts +3 -3
- package/src/__tests__/context-search-memory-source.test.ts +9 -8
- package/src/__tests__/context-search-memory-v2-source.test.ts +9 -8
- package/src/__tests__/context-search-types.test.ts +2 -2
- package/src/__tests__/context-search-workspace-source.test.ts +2 -2
- package/src/__tests__/conversation-abort-tool-results.test.ts +5 -5
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +3 -3
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +39 -11
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +6 -6
- package/src/__tests__/conversation-agent-loop.test.ts +51 -13
- package/src/__tests__/conversation-analysis-routes.test.ts +4 -4
- package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -1
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +7 -7
- package/src/__tests__/conversation-attachments.test.ts +7 -4
- package/src/__tests__/conversation-attention-store.test.ts +4 -4
- package/src/__tests__/conversation-attention-telegram.test.ts +8 -5
- package/src/__tests__/conversation-clear-safety.test.ts +3 -3
- package/src/__tests__/conversation-confirmation-signals.test.ts +7 -7
- package/src/__tests__/conversation-crud-inference-profile.test.ts +3 -3
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +25 -25
- package/src/__tests__/conversation-directories-parse.test.ts +1 -1
- package/src/__tests__/conversation-disk-view-integration.test.ts +5 -5
- package/src/__tests__/conversation-disk-view.test.ts +6 -6
- package/src/__tests__/conversation-evictor.test.ts +32 -7
- package/src/__tests__/conversation-fork-crud.test.ts +24 -21
- package/src/__tests__/conversation-fork-retrospective.test.ts +12 -10
- package/src/__tests__/conversation-fork-route.test.ts +6 -3
- package/src/__tests__/conversation-history-web-search.test.ts +8 -8
- package/src/__tests__/conversation-inference-profile-list.test.ts +3 -3
- package/src/__tests__/conversation-inference-profile-route.test.ts +3 -3
- package/src/__tests__/conversation-init.benchmark.test.ts +1 -1
- package/src/__tests__/conversation-key-store-disk-view.test.ts +7 -4
- package/src/__tests__/conversation-lifecycle.test.ts +10 -13
- package/src/__tests__/conversation-list-source.test.ts +3 -3
- package/src/__tests__/conversation-load-history-repair.test.ts +4 -4
- package/src/__tests__/conversation-load-history-stripped.test.ts +4 -4
- package/src/__tests__/conversation-pairing.test.ts +4 -4
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +5 -5
- package/src/__tests__/conversation-process-callsite.test.ts +5 -5
- package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -5
- package/src/__tests__/conversation-queue.test.ts +55 -9
- package/src/__tests__/conversation-routes-disk-view.test.ts +5 -5
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +6 -6
- package/src/__tests__/conversation-routes-slash-commands.test.ts +57 -10
- package/src/__tests__/conversation-runtime-assembly.test.ts +25 -19
- package/src/__tests__/conversation-runtime-workspace.test.ts +8 -1
- package/src/__tests__/conversation-skill-tools.test.ts +155 -2
- package/src/__tests__/conversation-slash-queue.test.ts +6 -6
- package/src/__tests__/conversation-slash-unknown.test.ts +6 -6
- package/src/__tests__/conversation-speed-override.test.ts +7 -7
- package/src/__tests__/conversation-starter-routes.test.ts +2 -2
- package/src/__tests__/conversation-store.test.ts +6 -6
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +8 -5
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +2 -2
- package/src/__tests__/conversation-sync-tags.test.ts +7 -4
- package/src/__tests__/conversation-title-service.test.ts +2 -3
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +1 -1
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +1 -1
- package/src/__tests__/conversation-unread-route.test.ts +2 -2
- package/src/__tests__/conversation-usage.test.ts +6 -6
- package/src/__tests__/conversation-wipe.test.ts +6 -4
- package/src/__tests__/conversation-workspace-cache-state.test.ts +9 -9
- package/src/__tests__/conversation-workspace-injection.test.ts +9 -9
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +9 -9
- package/src/__tests__/conversations-import-system-filter.test.ts +5 -5
- package/src/__tests__/credential-security-invariants.test.ts +4 -4
- package/src/__tests__/db-acp-history.test.ts +4 -4
- package/src/__tests__/db-activation-state-fk-cascade.test.ts +4 -4
- package/src/__tests__/db-activation-state.test.ts +3 -3
- package/src/__tests__/db-compaction-events-migration.test.ts +3 -3
- package/src/__tests__/db-connection-isolation.test.ts +1 -1
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +3 -3
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +6 -6
- package/src/__tests__/db-drop-contact-acl-columns-migration.test.ts +159 -0
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +3 -3
- package/src/__tests__/db-memory-graph-event-date-repair.test.ts +3 -3
- package/src/__tests__/db-migration-rollback.test.ts +48 -43
- package/src/__tests__/db-proxy-transaction.test.ts +2 -2
- package/src/__tests__/db-rename-inference-profile-snake-case-migration.test.ts +3 -3
- package/src/__tests__/db-schedule-syntax-migration.test.ts +4 -4
- package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +3 -3
- package/src/__tests__/db-slack-external-content-normalization.test.ts +4 -4
- package/src/__tests__/db-test-helpers.ts +7 -0
- package/src/__tests__/delete-propagation.test.ts +4 -4
- package/src/__tests__/deterministic-verification-control-plane.test.ts +3 -3
- package/src/__tests__/device-id.test.ts +38 -1
- package/src/__tests__/dm-backfill.test.ts +3 -3
- package/src/__tests__/dm-persistence.test.ts +5 -5
- package/src/__tests__/document-conversations.test.ts +3 -3
- package/src/__tests__/document-create-dedupe.test.ts +1 -1
- package/src/__tests__/document-find-replace.test.ts +1 -1
- package/src/__tests__/document-tool-security.test.ts +1 -1
- package/src/__tests__/document-update-default-surface.test.ts +1 -1
- package/src/__tests__/drop-capability-card-state-migration.test.ts +3 -5
- package/src/__tests__/edit-propagation.test.ts +6 -6
- package/src/__tests__/embedding-managed-proxy-selection.test.ts +2 -2
- package/src/__tests__/empty-state-greeting-cache.test.ts +1 -1
- package/src/__tests__/events-client-registration.test.ts +1 -1
- package/src/__tests__/exploration-drift-hook.test.ts +7 -23
- package/src/__tests__/file-write-tool.test.ts +3 -3
- package/src/__tests__/filing-service.test.ts +6 -5
- package/src/__tests__/followup-tools.test.ts +2 -2
- package/src/__tests__/get-skill-detail-audit.test.ts +1 -1
- package/src/__tests__/graph-extraction-event-date.test.ts +1 -1
- package/src/__tests__/guardian-action-sweep.test.ts +3 -3
- package/src/__tests__/guardian-binding-drift-heal.test.ts +6 -3
- package/src/__tests__/guardian-card-withdrawal.test.ts +3 -3
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +4 -4
- package/src/__tests__/guardian-dispatch.test.ts +14 -42
- package/src/__tests__/guardian-expiry-notifier.test.ts +4 -4
- package/src/__tests__/guardian-outbound-http.test.ts +3 -4
- package/src/__tests__/guardian-principal-id-roundtrip.test.ts +3 -3
- package/src/__tests__/guardian-routing-invariants.test.ts +3 -3
- package/src/__tests__/guardian-routing-state.test.ts +6 -4
- package/src/__tests__/guardian-verification-voice-binding.test.ts +4 -4
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +1 -1
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +3 -3
- package/src/__tests__/heartbeat-disk-pressure.test.ts +7 -13
- package/src/__tests__/heartbeat-service.test.ts +31 -19
- package/src/__tests__/helpers/channel-test-adapter.ts +22 -48
- package/src/__tests__/helpers/create-guardian-binding.ts +1 -1
- package/src/__tests__/helpers/derive-guardian-delivery.ts +66 -0
- package/src/__tests__/helpers/gateway-acl-store.ts +81 -0
- package/src/__tests__/helpers/seed-contact-channel.ts +50 -29
- package/src/__tests__/history-repair-hook.test.ts +1 -1
- package/src/__tests__/home-state-routes.test.ts +1 -1
- package/src/__tests__/http-conversation-lineage.test.ts +4 -4
- package/src/__tests__/http-user-message-parity.test.ts +8 -12
- package/src/__tests__/identity-routes.test.ts +113 -25
- package/src/__tests__/image-recovery-hook.test.ts +3 -3
- package/src/__tests__/inbound-invite-redemption.test.ts +36 -38
- package/src/__tests__/inbound-slack-persistence.test.ts +5 -5
- package/src/__tests__/inbound-trust-verdict.test.ts +5 -4
- package/src/__tests__/inference-no-mode-boot-e2e.test.ts +13 -6
- package/src/__tests__/inference-profile-reaper.test.ts +3 -3
- package/src/__tests__/inference-profile-session-handler.test.ts +3 -3
- package/src/__tests__/inference-profile-session-ipc.test.ts +3 -3
- package/src/__tests__/init-feature-flag-overrides.test.ts +1 -4
- package/src/__tests__/injection-block.test.ts +5 -2
- package/src/__tests__/injector-background-turn.test.ts +3 -5
- package/src/__tests__/injector-chain.test.ts +25 -16
- package/src/__tests__/injector-config-quarantine-notice.test.ts +3 -5
- package/src/__tests__/injector-disk-pressure.test.ts +10 -8
- package/src/__tests__/injector-document-comments.test.ts +5 -3
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +5 -2
- package/src/__tests__/injector-registry-order-guard.test.ts +132 -0
- package/src/__tests__/injector-v3-suppression.test.ts +15 -9
- package/src/__tests__/install-meta.test.ts +104 -0
- package/src/__tests__/install-skill-routing.test.ts +1 -1
- package/src/__tests__/internal-telemetry-routes.test.ts +4 -4
- package/src/__tests__/invite-redemption-service.test.ts +42 -45
- package/src/__tests__/invite-routes-http.test.ts +3 -3
- package/src/__tests__/invite-service-ipc.test.ts +3 -3
- package/src/__tests__/job-handler-registry-guard.test.ts +125 -0
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +8 -8
- package/src/__tests__/jobs-store-upsert-debounced.test.ts +7 -4
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +7 -6
- package/src/__tests__/list-messages-attachments.test.ts +7 -4
- package/src/__tests__/list-messages-client-message-id.test.ts +6 -3
- package/src/__tests__/list-messages-hidden-metadata.test.ts +5 -5
- package/src/__tests__/list-messages-page-latest.test.ts +5 -5
- package/src/__tests__/list-messages-queued.test.ts +223 -0
- package/src/__tests__/list-messages-tool-merge.test.ts +6 -3
- package/src/__tests__/llm-context-route-provider.test.ts +3 -3
- package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +4 -4
- package/src/__tests__/llm-request-log-call-site.test.ts +5 -5
- package/src/__tests__/llm-request-log-error-payload.test.ts +1 -1
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +2 -1
- package/src/__tests__/llm-request-log-source-factory.test.ts +3 -3
- package/src/__tests__/llm-request-log-turn-query.test.ts +9 -6
- package/src/__tests__/llm-usage-store.test.ts +137 -3
- package/src/__tests__/log-export-routes.test.ts +3 -3
- package/src/__tests__/log-export-workspace.test.ts +3 -3
- package/src/__tests__/managed-profile-guard.test.ts +1 -1
- package/src/__tests__/managed-skill-lifecycle.test.ts +3 -3
- package/src/__tests__/managed-store.test.ts +307 -0
- package/src/__tests__/mcp-config-secret-boundary.test.ts +2 -1
- package/src/__tests__/media-stream-server-integration.test.ts +1 -1
- package/src/__tests__/memory-jobs-worker-backoff.test.ts +4 -4
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +11 -9
- package/src/__tests__/memory-recall-log-store.test.ts +4 -4
- package/src/__tests__/memory-retrieval-budget.test.ts +1 -1
- package/src/__tests__/memory-retrieval-hook.test.ts +8 -8
- package/src/__tests__/memory-upsert-concurrency.test.ts +9 -5
- package/src/__tests__/memory-v2-static-injector.test.ts +3 -3
- package/src/__tests__/messages-after-tiebreaker.test.ts +4 -4
- package/src/__tests__/messaging-send-tool.test.ts +5 -5
- package/src/__tests__/mock-gateway-ipc.ts +1 -1
- package/src/__tests__/native-web-search.test.ts +11 -11
- package/src/__tests__/non-member-access-request.test.ts +9 -7
- package/src/__tests__/notification-candidate-guardian-context.test.ts +4 -4
- package/src/__tests__/notification-deep-link.test.ts +3 -3
- package/src/__tests__/notification-guardian-path.test.ts +3 -3
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +3 -3
- package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
- package/src/__tests__/oauth-provider-visibility.test.ts +2 -2
- package/src/__tests__/oauth-store.test.ts +6 -6
- package/src/__tests__/outbound-slack-persistence.test.ts +8 -8
- package/src/__tests__/persist-unsendable-image-downscale.test.ts +3 -3
- package/src/__tests__/persist-unsendable-image.test.ts +3 -3
- package/src/__tests__/persist-user-message-set-processing-failure.test.ts +70 -0
- package/src/__tests__/persistence-layering-guard.test.ts +207 -0
- package/src/__tests__/persistence-secret-redaction.test.ts +6 -6
- package/src/__tests__/pkb-autoinject.test.ts +1 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +3 -3
- package/src/__tests__/playbook-execution.test.ts +4 -4
- package/src/__tests__/playbook-tools.test.ts +3 -3
- package/src/__tests__/plugin-bootstrap.test.ts +40 -3
- package/src/__tests__/plugin-config-data-migration.test.ts +263 -0
- package/src/__tests__/plugin-disabled-state.test.ts +137 -4
- package/src/__tests__/plugin-import-boundary-guard.test.ts +495 -0
- package/src/__tests__/plugin-injector-contribution.test.ts +149 -0
- package/src/__tests__/pointer-conversation-trust.test.ts +141 -0
- package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +8 -1
- package/src/__tests__/process-message-background-slack.test.ts +6 -6
- package/src/__tests__/process-message-display-content.test.ts +5 -5
- package/src/__tests__/processing-flag-persist-failure.test.ts +280 -0
- package/src/__tests__/provider-usage-tracking.test.ts +3 -3
- package/src/__tests__/prune-jobs-changes-parser.test.ts +1 -1
- package/src/__tests__/prune-old-conversations-job.test.ts +5 -5
- package/src/__tests__/published-app-updater.test.ts +3 -3
- package/src/__tests__/qdrant-collection-migration.test.ts +5 -2
- package/src/__tests__/qdrant-manager.test.ts +1 -1
- package/src/__tests__/reaction-intercept-cold-cache-warm.test.ts +18 -12
- package/src/__tests__/reaction-intercept-member-verdict-warm.test.ts +4 -4
- package/src/__tests__/reaction-persistence.test.ts +13 -10
- package/src/__tests__/rebuild-index-graph-nodes.test.ts +5 -5
- package/src/__tests__/recording-handler.test.ts +2 -2
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +8 -8
- package/src/__tests__/relay-server.test.ts +140 -156
- package/src/__tests__/require-fresh-approval.test.ts +1 -1
- package/src/__tests__/resolve-app-id.test.ts +3 -3
- package/src/__tests__/runtime-attachment-metadata.test.ts +7 -7
- package/src/__tests__/runtime-events-sse-bilingual.test.ts +3 -3
- package/src/__tests__/runtime-events-sse-parity.test.ts +3 -3
- package/src/__tests__/runtime-events-sse-reconnect.test.ts +3 -3
- package/src/__tests__/runtime-events-sse.test.ts +3 -3
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +489 -2
- package/src/__tests__/schedule-retry.test.ts +53 -53
- package/src/__tests__/schedule-routes-workflow-validation.test.ts +47 -43
- package/src/__tests__/schedule-routes.test.ts +197 -187
- package/src/__tests__/schedule-store.test.ts +174 -172
- package/src/__tests__/schedule-tools.test.ts +2 -2
- package/src/__tests__/scheduler-disk-pressure.test.ts +3 -3
- package/src/__tests__/scheduler-recurrence.test.ts +15 -15
- package/src/__tests__/scheduler-reuse-conversation.test.ts +14 -14
- package/src/__tests__/scheduler-wake.test.ts +8 -8
- package/src/__tests__/scoped-approval-grants.test.ts +4 -4
- package/src/__tests__/scoped-grant-security-matrix.test.ts +4 -4
- package/src/__tests__/scrub-corrupted-image-attachments.test.ts +2 -2
- package/src/__tests__/search-skills-unified.test.ts +1 -1
- package/src/__tests__/secret-ingress-channel.test.ts +3 -3
- package/src/__tests__/secret-ingress-http.test.ts +6 -6
- package/src/__tests__/secret-routes-platform-proxy.test.ts +8 -7
- package/src/__tests__/send-endpoint-busy.test.ts +6 -6
- package/src/__tests__/sequence-store.test.ts +3 -3
- package/src/__tests__/server-history-render.test.ts +7 -4
- package/src/__tests__/settings-routes.test.ts +2 -2
- package/src/__tests__/skill-docs-sync-guard.test.ts +34 -0
- package/src/__tests__/skill-projection-feature-flag.test.ts +2 -1
- package/src/__tests__/skill-projection.benchmark.test.ts +2 -1
- package/src/__tests__/skill-version-hash.test.ts +32 -0
- package/src/__tests__/skills-file-content-endpoint.test.ts +1 -1
- package/src/__tests__/skills-files-catalog-fallback.test.ts +1 -1
- package/src/__tests__/slack-inbound-verification.test.ts +2 -2
- package/src/__tests__/slack-messaging-token-resolution.test.ts +2 -2
- package/src/__tests__/slack-reaction-canonical-approval.test.ts +4 -4
- package/src/__tests__/slack-share-routes.test.ts +1 -1
- package/src/__tests__/slim-skill-category.test.ts +34 -2
- package/src/__tests__/starter-task-flow.test.ts +1 -1
- package/src/__tests__/strip-memory-injections.test.ts +2 -2
- package/src/__tests__/subagent-call-site-routing.test.ts +2 -2
- package/src/__tests__/subagent-detail.test.ts +1 -1
- package/src/__tests__/subagent-fork-prompt-role.test.ts +1 -1
- package/src/__tests__/subagent-notify-parent.test.ts +3 -3
- package/src/__tests__/subagent-spawn-and-await.test.ts +1 -1
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +3 -3
- package/src/__tests__/subagent-tool-gate-mode.test.ts +1 -1
- package/src/__tests__/subagent-tools.test.ts +2 -5
- package/src/__tests__/suggestion-routes.test.ts +4 -4
- package/src/__tests__/task-compiler.test.ts +2 -2
- package/src/__tests__/task-management-tools.test.ts +2 -2
- package/src/__tests__/task-memory-cleanup.test.ts +9 -7
- package/src/__tests__/task-progress-nudge-hook.test.ts +37 -94
- package/src/__tests__/task-scheduler.test.ts +26 -26
- package/src/__tests__/test-support/tool-invocation-seed.ts +5 -2
- package/src/__tests__/thread-backfill.test.ts +4 -4
- package/src/__tests__/title-generate-hook.test.ts +6 -6
- package/src/__tests__/tool-approval-handler.test.ts +4 -4
- package/src/__tests__/tool-audit-listener.test.ts +1 -1
- package/src/__tests__/tool-error-hook.test.ts +2 -0
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +5 -5
- package/src/__tests__/tool-executor-redaction.test.ts +11 -0
- package/src/__tests__/tool-executor.test.ts +24 -2
- package/src/__tests__/tool-grant-request-escalation.test.ts +5 -5
- package/src/__tests__/tool-preview-lifecycle.test.ts +77 -8
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +4 -4
- package/src/__tests__/tool-result-truncate-hook.test.ts +2 -0
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -1
- package/src/__tests__/tool-start-timestamp.test.ts +65 -2
- package/src/__tests__/tools-get-route.test.ts +44 -1
- package/src/__tests__/trace-emitter.test.ts +1 -1
- package/src/__tests__/trust-context-guards.test.ts +1 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +5 -5
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +11 -5
- package/src/__tests__/trusted-contact-multichannel.test.ts +9 -9
- package/src/__tests__/trusted-contact-verification.test.ts +8 -30
- package/src/__tests__/turn-boundary-resolution.test.ts +7 -4
- package/src/__tests__/turn-call-site.test.ts +29 -0
- package/src/__tests__/turn-events-store.test.ts +8 -5
- package/src/__tests__/twilio-routes.test.ts +3 -3
- package/src/__tests__/usage-cache-backfill-migration.test.ts +4 -8
- package/src/__tests__/usage-grouped-buckets.test.ts +1 -1
- package/src/__tests__/usage-routes.test.ts +61 -3
- package/src/__tests__/verification-control-plane-policy.test.ts +6 -6
- package/src/__tests__/voice-invite-redemption.test.ts +41 -45
- package/src/__tests__/voice-quality.test.ts +38 -12
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +22 -14
- package/src/__tests__/voice-session-bridge.test.ts +16 -10
- package/src/__tests__/web-search-backend-failure.test.ts +4 -4
- package/src/__tests__/workspace-lifecycle.test.ts +29 -18
- package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +4 -4
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +5 -5
- package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +3 -3
- package/src/__tests__/workspace-migration-113-swap-balanced-profile-to-glm-5p2.test.ts +241 -0
- package/src/__tests__/workspace-migration-114-swap-quality-profile-to-opus.test.ts +172 -0
- package/src/__tests__/workspace-migration-116-rename-memory-plugin-disabled-sentinel.test.ts +128 -0
- package/src/__tests__/workspace-migration-117-normalize-stale-lean-memory-v3-defaults.test.ts +221 -0
- package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +1 -1
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +84 -7
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +10 -6
- package/src/a2a/__tests__/task-store.test.ts +2 -2
- package/src/a2a/task-store.ts +4 -4
- package/src/acp/__tests__/client-handler.test.ts +680 -0
- package/src/acp/__tests__/helpers/acp-history-db.ts +32 -4
- package/src/acp/__tests__/session-manager-persistence.test.ts +215 -7
- package/src/acp/__tests__/session-manager-resume.test.ts +113 -2
- package/src/acp/__tests__/session-manager-startup.test.ts +3 -3
- package/src/acp/__tests__/session-manager-usage.test.ts +113 -0
- package/src/acp/client-handler.ts +140 -21
- package/src/acp/session-manager.ts +127 -4
- package/src/acp/types.ts +18 -0
- package/src/agent/loop.ts +200 -148
- package/src/api/events/acp-session-completed.ts +33 -0
- package/src/api/events/acp-session-error.ts +21 -0
- package/src/api/events/acp-session-spawned.ts +32 -0
- package/src/api/events/acp-session-update.test.ts +122 -0
- package/src/api/events/acp-session-update.ts +51 -0
- package/src/api/events/acp-session-usage.test.ts +49 -0
- package/src/api/events/acp-session-usage.ts +31 -0
- package/src/api/events/tool-use-preview-start.ts +11 -0
- package/src/api/events/tool-use-start.ts +14 -0
- package/src/api/index.ts +38 -0
- package/src/api/responses/conversation-message.ts +37 -1
- package/src/api/responses/llm-request-log-entry.ts +41 -0
- package/src/api/responses/memory-v3-selection-log.ts +5 -7
- package/src/approvals/approval-primitive.ts +1 -1
- package/src/approvals/guardian-card-withdrawal.ts +2 -2
- package/src/approvals/guardian-decision-primitive.ts +1 -1
- package/src/approvals/guardian-expiry-notifier.ts +1 -1
- package/src/approvals/guardian-request-resolvers.ts +4 -4
- package/src/approvals/scoped-approval-grants.ts +551 -0
- package/src/apps/app-store.ts +1058 -0
- package/src/apps/published-pages-store.ts +67 -0
- package/src/apps/shared-app-links-store.ts +130 -0
- package/src/background-wake/background-wake-routes.test.ts +53 -23
- package/src/background-wake/wake-intent-hooks.test.ts +18 -12
- package/src/backup/restore.ts +1 -1
- package/src/bundler/app-bundler.ts +1 -1
- package/src/calls/__tests__/relay-setup-router.test.ts +1 -1
- package/src/calls/call-controller.ts +5 -5
- package/src/calls/call-conversation-messages.ts +1 -1
- package/src/calls/call-domain.ts +5 -5
- package/src/calls/call-pointer-messages.ts +1 -1
- package/src/calls/call-store.ts +3 -3
- package/src/calls/guardian-action-sweep.ts +1 -1
- package/src/calls/guardian-dispatch.ts +5 -5
- package/src/calls/media-stream-server.ts +1 -1
- package/src/calls/relay-access-wait.ts +1 -1
- package/src/calls/relay-server.ts +3 -3
- package/src/calls/relay-setup-router.ts +1 -1
- package/src/calls/tts-call-strategy.ts +4 -3
- package/src/calls/voice-quality.ts +47 -59
- package/src/calls/voice-session-bridge.ts +2 -16
- package/src/channels/channel-verification-sessions.ts +557 -0
- package/src/cli/commands/__tests__/conversations-new.test.ts +186 -0
- package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -1
- package/src/cli/commands/__tests__/conversations-wake.test.ts +147 -0
- package/src/cli/commands/__tests__/ps.test.ts +205 -0
- package/src/cli/commands/conversations.ts +90 -30
- package/src/cli/commands/db/__tests__/repair.test.ts +4 -3
- package/src/cli/commands/db/repair-step-conversation-backfill.ts +2 -2
- package/src/cli/commands/memory/__tests__/memory-v2-compare-render.test.ts +1 -1
- package/src/cli/commands/memory/__tests__/worker.test.ts +106 -307
- package/src/cli/commands/memory/memory-retrospective.ts +32 -28
- package/src/cli/commands/memory/memory-v2-compare-render.ts +1 -1
- package/src/cli/commands/memory/memory-v2.ts +2 -2
- package/src/cli/commands/memory/memory-v3.ts +2 -2
- package/src/cli/commands/memory/worker.ts +83 -160
- package/src/cli/commands/plugins.ts +147 -11
- package/src/cli/commands/ps.ts +90 -0
- package/src/cli/commands/tools-run.ts +114 -0
- package/src/cli/commands/tools.ts +19 -5
- package/src/cli/lib/__tests__/cli-colors.test.ts +30 -1
- package/src/cli/lib/__tests__/install-from-github.test.ts +168 -8
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +9 -4
- package/src/cli/lib/__tests__/parse-github-plugin-spec.test.ts +121 -0
- package/src/cli/lib/__tests__/toggle-plugin.test.ts +10 -4
- package/src/cli/lib/cli-colors.ts +6 -0
- package/src/cli/lib/diff-plugin.ts +3 -7
- package/src/cli/lib/inspect-plugin.ts +2 -4
- package/src/cli/lib/install-from-github.ts +96 -24
- package/src/cli/lib/merge-plugin-tree.ts +5 -3
- package/src/cli/lib/parse-github-plugin-spec.ts +163 -0
- package/src/cli/lib/plugin-fingerprint.ts +22 -0
- package/src/cli/lib/upgrade-plugin.ts +6 -5
- package/src/cli/program.ts +4 -7
- package/src/cli.ts +6 -3
- package/src/config/__tests__/deployment-context-defaults.test.ts +228 -0
- package/src/config/__tests__/proc-to-skills.test.ts +21 -0
- package/src/config/__tests__/sync-gated-profiles.test.ts +2 -2
- package/src/config/bundled-skills/AGENTS.md +11 -0
- package/src/config/bundled-skills/app-builder/SKILL.md +2 -0
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +2 -2
- package/src/config/bundled-skills/app-builder/tools/app-delete.ts +2 -2
- package/src/config/bundled-skills/app-builder/tools/app-generate-icon.ts +2 -2
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +1 -1
- package/src/config/bundled-skills/app-builder/tools/app-refresh.ts +2 -2
- package/src/config/bundled-skills/app-builder/tools/app-update.ts +2 -2
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
- package/src/config/bundled-skills/media-processing/__tests__/extract-keyframes.test.ts +1 -1
- package/src/config/bundled-skills/media-processing/__tests__/preprocess-audio.test.ts +1 -1
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +1 -1
- package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +1 -1
- package/src/config/bundled-skills/media-processing/services/reduce.ts +1 -1
- package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +1 -1
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +1 -1
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -2
- package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +2 -2
- package/src/config/bundled-skills/media-processing/tools/media-status.ts +1 -1
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +5 -5
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +6 -6
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +8 -5
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +4 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -4
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +7 -7
- package/src/config/bundled-skills/skill-management/TOOLS.json +45 -0
- package/src/config/bundled-skills/skill-management/tools/find-similar.ts +12 -0
- package/src/config/bundled-tool-registry.ts +2 -0
- package/src/config/feature-flag-registry.json +8 -16
- package/src/config/llm-resolver.ts +17 -0
- package/src/config/loader.ts +38 -58
- package/src/config/memory-v3-gate.ts +16 -0
- package/src/config/schema.ts +2 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +16 -5
- package/src/config/schemas/conversations.ts +8 -0
- package/src/config/schemas/memory-lifecycle.ts +9 -0
- package/src/config/schemas/memory-v3.ts +56 -6
- package/src/config/schemas/migrations.ts +25 -0
- package/src/config/schemas/services.ts +0 -37
- package/src/config/seed-inference-profiles.ts +13 -50
- package/src/config/sync-gated-profiles.ts +6 -17
- package/src/contacts/__tests__/guardian-contact-reader.test.ts +89 -0
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +3 -14
- package/src/contacts/canonical-guardian-store.ts +891 -0
- package/src/contacts/contact-store.ts +11 -9
- package/src/contacts/guardian-contact-reader.ts +52 -0
- package/src/contacts/guardian-delivery-reader.ts +21 -23
- package/src/contacts/guardian-rate-limits.ts +191 -0
- package/src/contacts/notify-contacts-changed.ts +17 -0
- package/src/context/compactor.ts +3 -3
- package/src/context/strip-injections.ts +1 -1
- package/src/conversations/__tests__/message-consolidation.test.ts +10 -26
- package/src/conversations/job-handlers/summarization.ts +246 -0
- package/src/conversations/message-consolidation.ts +1 -1
- package/src/credential-execution/ces-runtime.ts +285 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +25 -22
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +5 -4
- package/src/daemon/__tests__/daemon-readiness.test.ts +51 -0
- package/src/daemon/__tests__/daemon-skill-host.test.ts +1 -1
- package/src/daemon/__tests__/embedding-reconcile.test.ts +456 -0
- package/src/daemon/__tests__/inference-profile-notification.test.ts +9 -6
- package/src/daemon/__tests__/lifecycle-embedding-reconcile.test.ts +119 -0
- package/src/daemon/__tests__/memory-v2-startup.test.ts +86 -0
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +2 -2
- package/src/daemon/__tests__/web-search-status-text.test.ts +3 -5
- package/src/daemon/app-source-watcher.ts +71 -10
- package/src/daemon/channel-ui-capability.ts +25 -0
- package/src/daemon/config-watcher.ts +71 -47
- package/src/daemon/conversation-agent-loop-handlers.ts +150 -23
- package/src/daemon/conversation-agent-loop.ts +84 -28
- package/src/daemon/conversation-attachments.ts +2 -2
- package/src/daemon/conversation-evictor.ts +42 -9
- package/src/daemon/conversation-history.ts +6 -6
- package/src/daemon/conversation-launch.ts +2 -2
- package/src/daemon/conversation-lifecycle.ts +7 -4
- package/src/daemon/conversation-messaging.ts +25 -11
- package/src/daemon/conversation-notifiers.ts +1 -1
- package/src/daemon/conversation-process.ts +17 -15
- package/src/daemon/conversation-queue-manager.ts +6 -0
- package/src/daemon/conversation-registry.ts +6 -5
- package/src/daemon/conversation-runtime-assembly.ts +37 -31
- package/src/daemon/conversation-skill-tools.ts +26 -2
- package/src/daemon/conversation-slash.ts +1 -1
- package/src/daemon/conversation-store.ts +44 -39
- package/src/daemon/conversation-surfaces.ts +4 -4
- package/src/daemon/conversation-tool-setup.ts +2 -1
- package/src/daemon/conversation-usage.ts +4 -2
- package/src/daemon/conversation-workspace.ts +2 -2
- package/src/daemon/conversation.ts +45 -17
- package/src/daemon/daemon-readiness.ts +33 -0
- package/src/daemon/daemon-skill-host.ts +1 -1
- package/src/daemon/embedding-reconcile.ts +340 -0
- package/src/daemon/event-loop-watchdog.ts +1 -1
- package/src/daemon/external-plugins-bootstrap.ts +80 -14
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +2 -2
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +3 -3
- package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +3 -3
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +7 -11
- package/src/daemon/handlers/__tests__/config-a2a.test.ts +2 -2
- package/src/daemon/handlers/__tests__/config-channels.test.ts +17 -11
- package/src/daemon/handlers/config-a2a.ts +3 -3
- package/src/daemon/handlers/config-channels.ts +7 -4
- package/src/daemon/handlers/config-embeddings.ts +1 -1
- package/src/daemon/handlers/conversation-history.ts +2 -2
- package/src/daemon/handlers/conversations.ts +7 -4
- package/src/daemon/handlers/recording.ts +6 -3
- package/src/daemon/handlers/shared.ts +2 -0
- package/src/daemon/handlers/skills.ts +9 -1
- package/src/daemon/lifecycle.ts +890 -1208
- package/src/daemon/memory-v2-startup.test.ts +3 -3
- package/src/daemon/memory-v2-startup.ts +47 -12
- package/src/daemon/message-provenance.ts +1 -1
- package/src/daemon/message-types/acp.ts +27 -1
- package/src/daemon/message-types/bookmarks.ts +1 -1
- package/src/daemon/message-types/skills.ts +20 -2
- package/src/daemon/pointer-conversation-trust.ts +66 -0
- package/src/daemon/process-message.ts +24 -3
- package/src/daemon/providers-setup.ts +0 -14
- package/src/daemon/shutdown-handlers.ts +185 -165
- package/src/daemon/skill-memory-refresh.ts +1 -1
- package/src/daemon/status.ts +15 -0
- package/src/daemon/tool-setup-types.ts +17 -0
- package/src/daemon/tool-side-effects.ts +4 -4
- package/src/daemon/trace-emitter.ts +1 -1
- package/src/daemon/trust-context.ts +1 -1
- package/src/daemon/turn-call-site.ts +25 -0
- package/src/daemon/turn-latency-tracker.test.ts +137 -0
- package/src/daemon/turn-latency-tracker.ts +134 -0
- package/src/daemon/wake-conversation-ops.ts +11 -4
- package/src/documents/document-comments-store.test.ts +2 -2
- package/src/documents/document-comments-store.ts +1 -1
- package/src/documents/document-store.ts +1 -1
- package/src/events/tool-audit-listener.ts +4 -4
- package/src/events/tool-permission-telemetry-listener.ts +1 -1
- package/src/export/__tests__/transcript-formatter.test.ts +1 -1
- package/src/export/transcript-formatter.ts +1 -1
- package/src/followups/followup-store.ts +2 -2
- package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +2 -2
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +45 -39
- package/src/heartbeat/heartbeat-run-store.ts +3 -3
- package/src/heartbeat/heartbeat-service.ts +29 -11
- package/src/home/__tests__/relationship-state-writer.test.ts +1 -1
- package/src/home/__tests__/suggested-prompts.test.ts +1 -1
- package/src/home/conversation-starter-checkpoints.ts +64 -0
- package/src/home/feed-source-enrichment.ts +3 -3
- package/src/home/home-greeting-cache.ts +1 -1
- package/src/home/job-handlers/conversation-starters.ts +484 -0
- package/src/home/relationship-state-writer.ts +1 -1
- package/src/home/suggested-prompts.ts +1 -1
- package/src/hooks/hook-loader.ts +141 -6
- package/src/hooks/registry.ts +129 -0
- package/src/ipc/__tests__/attachment-ipc.test.ts +1 -1
- package/src/ipc/__tests__/cli-ipc.test.ts +1 -1
- package/src/ipc/__tests__/inject-local-actor-header.test.ts +33 -0
- package/src/ipc/__tests__/watcher-ipc.test.ts +1 -1
- package/src/ipc/assistant-server.ts +79 -33
- package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +3 -3
- package/src/ipc/routes/db-proxy-transaction.ts +1 -1
- package/src/ipc/routes/db-proxy.ts +4 -2
- package/src/ipc/skill-routes/__tests__/memory.test.ts +1 -1
- package/src/ipc/skill-routes/memory.ts +1 -1
- package/src/ipc/skill-routes/registries.ts +8 -10
- package/src/ipc/skill-server.ts +42 -6
- package/src/jobs/register-job-handlers.ts +74 -0
- package/src/jobs/worker.ts +91 -0
- package/src/live-voice/__tests__/live-voice-archive.test.ts +5 -5
- package/src/live-voice/live-voice-archive.ts +2 -2
- package/src/mcp/manager.ts +11 -0
- package/src/media/app-icon-generator.ts +1 -1
- package/src/media/job-handlers/media-processing.ts +126 -0
- package/src/messaging/channel-binding-metadata.ts +1 -1
- package/src/messaging/content/parse.test.ts +34 -0
- package/src/messaging/content/parse.ts +23 -0
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +1 -0
- package/src/messaging/providers/slack/binding-metadata.ts +1 -1
- package/src/messaging/providers/slack/render.test.ts +309 -0
- package/src/messaging/providers/slack/render.ts +459 -0
- package/src/messaging/providers/slack/send.test.ts +39 -0
- package/src/messaging/providers/slack/send.ts +38 -18
- package/src/messaging/providers/telegram-bot/adapter.ts +2 -2
- package/src/messaging/providers/telegram-bot/api.ts +17 -3
- package/src/messaging/providers/telegram-bot/render.test.ts +146 -0
- package/src/messaging/providers/telegram-bot/render.ts +292 -0
- package/src/messaging/providers/telegram-bot/send.test.ts +197 -0
- package/src/messaging/providers/telegram-bot/send.ts +70 -2
- package/src/messaging/providers/telegram-bot/transport.ts +10 -1
- package/src/messaging/providers/whatsapp/adapter.ts +2 -2
- package/src/messaging/providers/whatsapp/send.ts +1 -1
- package/src/notifications/__tests__/deterministic-checks.test.ts +3 -3
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +1 -1
- package/src/notifications/broadcaster.ts +1 -1
- package/src/notifications/canonical-delivery-recorder.ts +1 -1
- package/src/notifications/conversation-candidates.ts +3 -3
- package/src/notifications/conversation-pairing.ts +25 -16
- package/src/notifications/decisions-store.ts +2 -2
- package/src/notifications/deliveries-store.ts +3 -3
- package/src/notifications/deterministic-checks.ts +2 -2
- package/src/notifications/emit-signal.ts +1 -1
- package/src/notifications/events-store.ts +2 -2
- package/src/notifications/home-feed-side-effect.ts +2 -2
- package/src/notifications/preferences-store.ts +2 -2
- package/src/notifications/signal.ts +1 -1
- package/src/oauth/oauth-store.ts +3 -3
- package/src/onboarding/__tests__/onboarding-events-store.test.ts +80 -0
- package/src/onboarding/checkin-event.test.ts +5 -2
- package/src/onboarding/checkin-event.ts +7 -1
- package/src/onboarding/onboarding-events-store.ts +161 -0
- package/src/permissions/checker.test.ts +319 -1
- package/src/permissions/checker.ts +52 -0
- package/src/permissions/types.ts +21 -0
- package/src/persistence/__tests__/db-init-migrations-ok.test.ts +20 -0
- package/src/persistence/__tests__/worker-control.test.ts +260 -0
- package/src/persistence/attachments-store.ts +1136 -0
- package/src/persistence/checkpoints.ts +65 -0
- package/src/persistence/compaction-ledger-store.ts +107 -0
- package/src/persistence/conversation-attention-store.ts +689 -0
- package/src/persistence/conversation-bootstrap.ts +59 -0
- package/src/persistence/conversation-crud.ts +3437 -0
- package/src/persistence/conversation-group-migration.test.ts +99 -0
- package/src/persistence/conversation-key-store.ts +274 -0
- package/src/persistence/conversation-queries.ts +768 -0
- package/src/persistence/conversation-row-batch-delete.ts +205 -0
- package/src/persistence/db-async-query.ts +329 -0
- package/src/persistence/db-connection.ts +242 -0
- package/src/persistence/db-init.ts +282 -0
- package/src/persistence/db-maintenance.ts +158 -0
- package/src/persistence/embeddings/__tests__/embedding-identity.test.ts +156 -0
- package/src/persistence/embeddings/__tests__/reconcile-decision.test.ts +95 -0
- package/src/persistence/embeddings/embed.ts +87 -0
- package/src/persistence/embeddings/embedding-backend.test.ts +355 -0
- package/src/persistence/embeddings/embedding-backend.ts +968 -0
- package/src/persistence/embeddings/embedding-billing-breaker.ts +96 -0
- package/src/persistence/embeddings/embedding-cache.ts +139 -0
- package/src/persistence/embeddings/embedding-identity.ts +88 -0
- package/src/persistence/embeddings/embedding-local.ts +587 -0
- package/src/persistence/embeddings/embedding-ollama.ts +79 -0
- package/src/persistence/embeddings/embedding-runtime-manager.ts +573 -0
- package/src/persistence/embeddings/embedding-types.ts +97 -0
- package/src/persistence/embeddings/qdrant-circuit-breaker.ts +119 -0
- package/src/persistence/embeddings/qdrant-client.test.ts +60 -0
- package/src/persistence/embeddings/qdrant-client.ts +842 -0
- package/src/persistence/embeddings/qdrant-manager.ts +450 -0
- package/src/persistence/embeddings/reconcile-decision.ts +53 -0
- package/src/persistence/embeddings/sparse-tokenize.ts +51 -0
- package/src/persistence/external-conversation-store.ts +315 -0
- package/src/persistence/fork-message-copy.ts +225 -0
- package/src/persistence/job-handlers/cleanup.ts +239 -0
- package/src/persistence/job-utils.ts +286 -0
- package/src/persistence/jobs-store.ts +813 -0
- package/src/persistence/jobs-worker.ts +833 -0
- package/src/persistence/llm-request-log-source-clickhouse.ts +525 -0
- package/src/persistence/llm-request-log-store.ts +740 -0
- package/src/persistence/llm-usage-store.ts +961 -0
- package/src/persistence/memory-lifecycle-hooks.test.ts +81 -0
- package/src/persistence/memory-lifecycle-hooks.ts +120 -0
- package/src/persistence/message-content.test.ts +35 -0
- package/src/persistence/migrations/126-backfill-guardian-principal-id.ts +300 -0
- package/src/persistence/migrations/140-backfill-usage-cache-accounting.ts +364 -0
- package/src/persistence/migrations/142-rename-verification-session-id-column.ts +55 -0
- package/src/persistence/migrations/182-oauth-providers-display-metadata.ts +22 -0
- package/src/persistence/migrations/196-strip-integration-prefix-from-provider-keys.ts +175 -0
- package/src/persistence/migrations/199-guardian-request-enrichment-columns.ts +50 -0
- package/src/persistence/migrations/202-memory-graph-tables.ts +128 -0
- package/src/persistence/migrations/203-drop-memory-items-tables.ts +53 -0
- package/src/persistence/migrations/206-scrub-corrupted-image-attachments.ts +121 -0
- package/src/persistence/migrations/209-strip-thinking-from-consolidated.ts +196 -0
- package/src/persistence/migrations/211-memory-recall-logs-query-context.ts +14 -0
- package/src/persistence/migrations/220-normalize-user-file-by-principal.ts +171 -0
- package/src/persistence/migrations/222-strip-placeholder-sentinels-from-messages.ts +179 -0
- package/src/persistence/migrations/236-tool-invocations-matched-rule-id.ts +23 -0
- package/src/persistence/migrations/243-provider-connections.ts +80 -0
- package/src/persistence/migrations/244-provider-connection-status-label.ts +29 -0
- package/src/persistence/migrations/246-backfill-provider-connection-label.ts +83 -0
- package/src/persistence/migrations/255-channel-inbound-delivery-attempts.ts +17 -0
- package/src/persistence/migrations/301-create-watchdog-events.ts +42 -0
- package/src/persistence/migrations/304-add-llm-usage-cron-run-id.ts +31 -0
- package/src/persistence/migrations/305-drop-contact-acl-columns.ts +49 -0
- package/src/persistence/migrations/306-rewrite-frontier-profile-pins.test.ts +110 -0
- package/src/persistence/migrations/306-rewrite-frontier-profile-pins.ts +65 -0
- package/src/persistence/migrations/307-acp-session-history-usage-columns.test.ts +124 -0
- package/src/persistence/migrations/307-acp-session-history-usage-columns.ts +36 -0
- package/src/persistence/migrations/308-acp-session-history-token-columns.test.ts +119 -0
- package/src/persistence/migrations/308-acp-session-history-token-columns.ts +32 -0
- package/src/persistence/migrations/309-drop-redundant-indexes.ts +60 -0
- package/src/persistence/migrations/310-llm-request-log-latency-breakdown.ts +37 -0
- package/src/persistence/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +328 -0
- package/src/persistence/migrations/__tests__/222-strip-placeholder-sentinels-from-messages.test.ts +273 -0
- package/src/persistence/migrations/__tests__/244-provider-connection-status-label.test.ts +90 -0
- package/src/persistence/migrations/__tests__/246-backfill-provider-connection-label.test.ts +250 -0
- package/src/persistence/migrations/__tests__/run-migrations.test.ts +380 -0
- package/src/persistence/migrations/helpers/relocation.ts +230 -0
- package/src/persistence/migrations/validate-migration-state.ts +279 -0
- package/src/persistence/schedule-attribution-sql.ts +106 -0
- package/src/persistence/schema/acp.ts +51 -0
- package/src/persistence/schema/contacts.ts +110 -0
- package/src/persistence/schema/conversations.ts +235 -0
- package/src/persistence/schema/infrastructure.ts +389 -0
- package/src/persistence/steps.ts +1310 -0
- package/src/persistence/worker-control.ts +277 -0
- package/src/platform/sync-identity.ts +24 -0
- package/src/playbooks/playbook-compiler.ts +2 -2
- package/src/plugin-api/index.ts +5 -0
- package/src/plugin-api/types.ts +40 -15
- package/src/plugins/defaults/channel/injectors.ts +101 -0
- package/src/plugins/defaults/channel/package.json +14 -0
- package/src/plugins/defaults/compaction/compact.ts +2 -1
- package/src/plugins/defaults/compaction/context-overflow-reducer.ts +2 -1
- package/src/plugins/defaults/compaction/window-manager.ts +8 -7
- package/src/plugins/defaults/documents/injectors.ts +125 -0
- package/src/plugins/defaults/documents/package.json +14 -0
- package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +6 -2
- package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +10 -11
- package/src/plugins/defaults/history-repair/terminal.ts +1 -1
- package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +23 -9
- package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +2 -3
- package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +7 -14
- package/src/plugins/defaults/image-fallback/src/vision-caption.ts +12 -4
- package/src/plugins/defaults/image-recovery/recover.ts +6 -3
- package/src/plugins/defaults/index.ts +235 -43
- package/src/plugins/defaults/injection-presence.ts +80 -0
- package/src/plugins/defaults/injector-order.ts +54 -0
- package/src/plugins/defaults/max-tokens-continue/hooks/post-model-call.ts +5 -2
- package/src/plugins/defaults/memory/__tests__/301-create-watchdog-events.test.ts +110 -0
- package/src/plugins/defaults/memory/__tests__/activation-session-store.test.ts +41 -0
- package/src/plugins/defaults/memory/__tests__/bookmark-crud.test.ts +264 -0
- package/src/plugins/defaults/memory/__tests__/bookmark-schema.test.ts +181 -0
- package/src/plugins/defaults/memory/__tests__/clear-stale-processing-flags.test.ts +52 -0
- package/src/plugins/defaults/memory/__tests__/compaction-log-store-clickhouse.test.ts +432 -0
- package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +843 -0
- package/src/plugins/defaults/memory/__tests__/conversation-row-batch-delete.test.ts +199 -0
- package/src/plugins/defaults/memory/__tests__/conversation-types.test.ts +36 -0
- package/src/plugins/defaults/memory/__tests__/db-async-query.test.ts +172 -0
- package/src/plugins/defaults/memory/__tests__/db-busy-timeout.test.ts +26 -0
- package/src/plugins/defaults/memory/__tests__/db-logs-attach.test.ts +113 -0
- package/src/plugins/defaults/memory/__tests__/db-maintenance.test.ts +238 -0
- package/src/plugins/defaults/memory/__tests__/db-memory-attach.test.ts +116 -0
- package/src/plugins/defaults/memory/__tests__/embedding-cache.test.ts +137 -0
- package/src/plugins/defaults/memory/__tests__/find-analysis-conversation.test.ts +197 -0
- package/src/plugins/defaults/memory/__tests__/find-most-recent-retrospective-for.test.ts +140 -0
- package/src/plugins/defaults/memory/__tests__/fork-message-copy.test.ts +232 -0
- package/src/plugins/defaults/memory/__tests__/jobs-store-enqueue-gate.test.ts +245 -0
- package/src/plugins/defaults/memory/__tests__/jobs-store-job-classes.test.ts +52 -0
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +115 -0
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-schedule.test.ts +508 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +160 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +1565 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +549 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +195 -0
- package/src/plugins/defaults/memory/__tests__/memory-v2-activation-log-store.test.ts +221 -0
- package/src/plugins/defaults/memory/__tests__/memory-v2-concept-frequency.test.ts +275 -0
- package/src/plugins/defaults/memory/__tests__/memory-v3-selections-migration.test.ts +103 -0
- package/src/plugins/defaults/memory/__tests__/prompt-override.test.ts +192 -0
- package/src/plugins/defaults/memory/__tests__/qdrant-client-sentinel.test.ts +49 -0
- package/src/plugins/defaults/memory/__tests__/table-relocation.test.ts +130 -0
- package/src/plugins/defaults/memory/activation-session-store.ts +43 -0
- package/src/plugins/defaults/memory/anisotropy.ts +443 -0
- package/src/plugins/defaults/memory/context-search/agent-protocol.ts +428 -0
- package/src/plugins/defaults/memory/context-search/agent-runner.ts +1311 -0
- package/src/plugins/defaults/memory/context-search/search.ts +297 -0
- package/src/plugins/defaults/memory/context-search/sources/conversations.ts +341 -0
- package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +600 -0
- package/src/plugins/defaults/memory/context-search/sources/memory.ts +101 -0
- package/src/plugins/defaults/memory/context-search/types.ts +48 -0
- package/src/plugins/defaults/memory/filing-service.ts +430 -0
- package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-registry.test.ts +119 -0
- package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +663 -0
- package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +321 -0
- package/src/plugins/defaults/memory/graph/bootstrap.test.ts +287 -0
- package/src/plugins/defaults/memory/graph/bootstrap.ts +544 -0
- package/src/plugins/defaults/memory/graph/capability-seed.ts +454 -0
- package/src/plugins/defaults/memory/graph/consolidation.ts +712 -0
- package/src/plugins/defaults/memory/graph/conversation-graph-memory.ts +1181 -0
- package/src/plugins/defaults/memory/graph/decay.ts +195 -0
- package/src/plugins/defaults/memory/graph/extraction-job.ts +77 -0
- package/src/plugins/defaults/memory/graph/extraction.ts +1462 -0
- package/src/plugins/defaults/memory/graph/graph-memory-state-store.ts +50 -0
- package/src/plugins/defaults/memory/graph/graph-search.test.ts +132 -0
- package/src/plugins/defaults/memory/graph/graph-search.ts +294 -0
- package/src/plugins/defaults/memory/graph/image-ref-utils.ts +29 -0
- package/src/plugins/defaults/memory/graph/injection.ts +469 -0
- package/src/plugins/defaults/memory/graph/narrative.ts +267 -0
- package/src/plugins/defaults/memory/graph/pattern-scan.ts +269 -0
- package/src/plugins/defaults/memory/graph/retriever.test.ts +624 -0
- package/src/plugins/defaults/memory/graph/retriever.ts +1357 -0
- package/src/plugins/defaults/memory/graph/store.test.ts +1093 -0
- package/src/plugins/defaults/memory/graph/store.ts +923 -0
- package/src/plugins/defaults/memory/graph/tool-handlers.ts +195 -0
- package/src/plugins/defaults/memory/graph/tools.ts +95 -0
- package/src/plugins/defaults/memory/hooks/init.ts +26 -0
- package/src/plugins/defaults/memory/hooks/post-compact.ts +115 -0
- package/src/plugins/defaults/memory/hooks/shutdown.ts +14 -0
- package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +371 -0
- package/src/plugins/defaults/memory/indexer.ts +409 -0
- package/src/plugins/defaults/memory/injectors.ts +388 -0
- package/src/plugins/defaults/memory/job-handlers/backfill.ts +107 -0
- package/src/plugins/defaults/memory/job-handlers/embedding.test.ts +236 -0
- package/src/plugins/defaults/memory/job-handlers/embedding.ts +133 -0
- package/src/plugins/defaults/memory/job-handlers/index-maintenance.ts +117 -0
- package/src/plugins/defaults/memory/job-handlers.ts +203 -0
- package/src/plugins/defaults/memory/jobs/__tests__/embed-concept-page.test.ts +565 -0
- package/src/plugins/defaults/memory/jobs/embed-concept-page.ts +424 -0
- package/src/plugins/defaults/memory/jobs/embed-pkb-file.test.ts +169 -0
- package/src/plugins/defaults/memory/jobs/embed-pkb-file.ts +59 -0
- package/src/plugins/defaults/memory/memory-recall-log-store.ts +172 -0
- package/src/plugins/defaults/memory/memory-retrospective-constants.ts +60 -0
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +131 -0
- package/src/plugins/defaults/memory/memory-retrospective-fork-boundary.ts +94 -0
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +958 -0
- package/src/plugins/defaults/memory/memory-retrospective-startup-cleanup.ts +264 -0
- package/src/plugins/defaults/memory/memory-retrospective-state.ts +259 -0
- package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +91 -0
- package/src/plugins/defaults/memory/memory-v2-activation-log-store.ts +216 -0
- package/src/plugins/defaults/memory/memory-v2-concept-frequency.ts +173 -0
- package/src/plugins/defaults/memory/package.json +14 -0
- package/src/plugins/defaults/memory/persistence-hooks.ts +119 -0
- package/src/plugins/defaults/memory/pkb/autoinject.ts +61 -0
- package/src/plugins/defaults/memory/pkb/context.ts +50 -0
- package/src/plugins/defaults/memory/pkb/pkb-index.test.ts +371 -0
- package/src/plugins/defaults/memory/pkb/pkb-index.ts +256 -0
- package/src/plugins/defaults/memory/pkb/pkb-reconcile.test.ts +254 -0
- package/src/plugins/defaults/memory/pkb/pkb-reconcile.ts +144 -0
- package/src/plugins/defaults/memory/pkb/pkb-search.test.ts +589 -0
- package/src/plugins/defaults/memory/pkb/pkb-search.ts +178 -0
- package/src/plugins/defaults/memory/pkb/types.ts +67 -0
- package/src/plugins/defaults/memory/rerank-local.ts +374 -0
- package/src/plugins/defaults/memory/routes/__tests__/memory-v2-routes.test.ts +165 -0
- package/src/plugins/defaults/memory/routes/__tests__/memory-v2-simulate-route.test.ts +347 -0
- package/src/plugins/defaults/memory/routes/memory-eval-routes.ts +179 -0
- package/src/plugins/defaults/memory/routes/memory-item-routes.test.ts +922 -0
- package/src/plugins/defaults/memory/routes/memory-item-routes.ts +814 -0
- package/src/plugins/defaults/memory/routes/memory-v2-routes.ts +850 -0
- package/src/plugins/defaults/memory/routes/memory-v3-routes.ts +125 -0
- package/src/plugins/defaults/memory/search/semantic.ts +241 -0
- package/src/plugins/defaults/memory/segmenter.ts +76 -0
- package/src/plugins/defaults/memory/tail-reinjection-strip.ts +65 -0
- package/src/plugins/defaults/memory/task-memory-cleanup.ts +241 -0
- package/src/plugins/defaults/memory/tools.test.ts +382 -0
- package/src/plugins/defaults/memory/tools.ts +87 -0
- package/src/plugins/defaults/memory/v2/__tests__/activation-store.test.ts +207 -0
- package/src/plugins/defaults/memory/v2/__tests__/activation.test.ts +1273 -0
- package/src/plugins/defaults/memory/v2/__tests__/backfill-jobs.test.ts +510 -0
- package/src/plugins/defaults/memory/v2/__tests__/cli-command-store.test.ts +432 -0
- package/src/plugins/defaults/memory/v2/__tests__/consolidation-job.test.ts +744 -0
- package/src/plugins/defaults/memory/v2/__tests__/consolidation-prompt-flag-gating-guard.test.ts +205 -0
- package/src/plugins/defaults/memory/v2/__tests__/frontmatter-sweep.test.ts +136 -0
- package/src/plugins/defaults/memory/v2/__tests__/harness-compare.test.ts +186 -0
- package/src/plugins/defaults/memory/v2/__tests__/harness-oracle.test.ts +257 -0
- package/src/plugins/defaults/memory/v2/__tests__/harness-replay-input.test.ts +230 -0
- package/src/plugins/defaults/memory/v2/__tests__/harness-runner.test.ts +135 -0
- package/src/plugins/defaults/memory/v2/__tests__/injection-events.test.ts +318 -0
- package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +2308 -0
- package/src/plugins/defaults/memory/v2/__tests__/migration.test.ts +940 -0
- package/src/plugins/defaults/memory/v2/__tests__/page-index.test.ts +760 -0
- package/src/plugins/defaults/memory/v2/__tests__/prompts-consolidation.test.ts +332 -0
- package/src/plugins/defaults/memory/v2/__tests__/qdrant.test.ts +974 -0
- package/src/plugins/defaults/memory/v2/__tests__/reranker.test.ts +338 -0
- package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +1198 -0
- package/src/plugins/defaults/memory/v2/__tests__/sim.test.ts +704 -0
- package/src/plugins/defaults/memory/v2/__tests__/skill-content.test.ts +115 -0
- package/src/plugins/defaults/memory/v2/__tests__/skill-store.test.ts +986 -0
- package/src/plugins/defaults/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
- package/src/plugins/defaults/memory/v2/__tests__/static-context.test.ts +223 -0
- package/src/plugins/defaults/memory/v2/__tests__/sweep-job.test.ts +530 -0
- package/src/plugins/defaults/memory/v2/activation-store.ts +185 -0
- package/src/plugins/defaults/memory/v2/activation.ts +560 -0
- package/src/plugins/defaults/memory/v2/backfill-jobs.ts +296 -0
- package/src/plugins/defaults/memory/v2/cli-command-store.ts +341 -0
- package/src/plugins/defaults/memory/v2/consolidation-job.ts +550 -0
- package/src/plugins/defaults/memory/v2/frontmatter-sweep.ts +98 -0
- package/src/plugins/defaults/memory/v2/harness/compare.ts +57 -0
- package/src/plugins/defaults/memory/v2/harness/oracle.ts +148 -0
- package/src/plugins/defaults/memory/v2/harness/replay-input.ts +243 -0
- package/src/plugins/defaults/memory/v2/harness/retriever.ts +74 -0
- package/src/plugins/defaults/memory/v2/harness/router-retriever.ts +43 -0
- package/src/plugins/defaults/memory/v2/injected-block-slugs.ts +79 -0
- package/src/plugins/defaults/memory/v2/injection-events.ts +101 -0
- package/src/plugins/defaults/memory/v2/injection.ts +932 -0
- package/src/plugins/defaults/memory/v2/migration.ts +774 -0
- package/src/plugins/defaults/memory/v2/page-index.ts +459 -0
- package/src/plugins/defaults/memory/v2/page-store.ts +443 -0
- package/src/plugins/defaults/memory/v2/prompts/consolidation.ts +868 -0
- package/src/plugins/defaults/memory/v2/prompts/router.ts +148 -0
- package/src/plugins/defaults/memory/v2/qdrant.ts +939 -0
- package/src/plugins/defaults/memory/v2/reranker.ts +184 -0
- package/src/plugins/defaults/memory/v2/router.ts +602 -0
- package/src/plugins/defaults/memory/v2/sim.ts +310 -0
- package/src/plugins/defaults/memory/v2/skill-content.ts +61 -0
- package/src/plugins/defaults/memory/v2/skill-store.ts +431 -0
- package/src/plugins/defaults/memory/v2/sparse-bm25.ts +245 -0
- package/src/plugins/defaults/memory/v2/static-context.ts +100 -0
- package/src/plugins/defaults/memory/v2/sweep-job.ts +323 -0
- package/src/plugins/defaults/memory/v3/__tests__/candidate-match.test.ts +316 -0
- package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +1163 -0
- package/src/plugins/defaults/memory/v3/__tests__/dense.test.ts +211 -0
- package/src/plugins/defaults/memory/v3/__tests__/edge.test.ts +247 -0
- package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +685 -0
- package/src/plugins/defaults/memory/v3/__tests__/live-integration.test.ts +365 -0
- package/src/plugins/defaults/memory/v3/__tests__/maintain-job.test.ts +1012 -0
- package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +977 -0
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +599 -0
- package/src/plugins/defaults/memory/v3/__tests__/render-injection.test.ts +128 -0
- package/src/plugins/defaults/memory/v3/__tests__/section-dense-store.test.ts +756 -0
- package/src/plugins/defaults/memory/v3/__tests__/selection-log-store.test.ts +422 -0
- package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +501 -0
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +885 -0
- package/src/plugins/defaults/memory/v3/__tests__/tuning-profile.test.ts +96 -0
- package/src/plugins/defaults/memory/v3/candidate-match.ts +197 -0
- package/src/plugins/defaults/memory/v3/capabilities.ts +88 -0
- package/src/plugins/defaults/memory/v3/card.ts +160 -0
- package/src/plugins/defaults/memory/v3/dense.ts +108 -0
- package/src/plugins/defaults/memory/v3/edge.ts +252 -0
- package/src/plugins/defaults/memory/v3/entity-lane.test.ts +124 -0
- package/src/plugins/defaults/memory/v3/entity-lane.ts +113 -0
- package/src/plugins/defaults/memory/v3/ever-injected-store.test.ts +307 -0
- package/src/plugins/defaults/memory/v3/ever-injected-store.ts +278 -0
- package/src/plugins/defaults/memory/v3/hot-set.test.ts +143 -0
- package/src/plugins/defaults/memory/v3/hot-set.ts +85 -0
- package/src/plugins/defaults/memory/v3/injector.ts +423 -0
- package/src/plugins/defaults/memory/v3/learned-edges.test.ts +169 -0
- package/src/plugins/defaults/memory/v3/learned-edges.ts +178 -0
- package/src/plugins/defaults/memory/v3/maintain-job.ts +988 -0
- package/src/plugins/defaults/memory/v3/orchestrate.ts +483 -0
- package/src/plugins/defaults/memory/v3/page-content.ts +102 -0
- package/src/plugins/defaults/memory/v3/pool-select.test.ts +147 -0
- package/src/plugins/defaults/memory/v3/pool-select.ts +586 -0
- package/src/plugins/defaults/memory/v3/prune.test.ts +760 -0
- package/src/plugins/defaults/memory/v3/prune.ts +469 -0
- package/src/plugins/defaults/memory/v3/render-injection.ts +92 -0
- package/src/plugins/defaults/memory/v3/section-dense-store.ts +471 -0
- package/src/plugins/defaults/memory/v3/section-needle.ts +215 -0
- package/src/plugins/defaults/memory/v3/selection-log-store.ts +277 -0
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +656 -0
- package/src/plugins/defaults/memory/v3/tuning-profile.ts +91 -0
- package/src/plugins/defaults/memory/v3/types.ts +130 -0
- package/src/plugins/defaults/memory/v3-eval/eval-packets.ts +731 -0
- package/src/plugins/defaults/session/injectors.ts +84 -0
- package/src/plugins/defaults/session/package.json +14 -0
- package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +6 -2
- package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +39 -45
- package/src/plugins/defaults/title-generate/hooks/stop.ts +4 -5
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +3 -3
- package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +5 -3
- package/src/plugins/defaults/turn-context/injectors.ts +52 -0
- package/src/plugins/defaults/turn-context/package.json +14 -0
- package/src/plugins/defaults/workspace/injectors.ts +295 -0
- package/src/plugins/defaults/workspace/package.json +14 -0
- package/src/plugins/injector-registry.ts +127 -0
- package/src/plugins/job-handler-registry.ts +94 -0
- package/src/plugins/mtime-cache.ts +1 -1
- package/src/plugins/pipeline.ts +1 -1
- package/src/plugins/registry.ts +37 -172
- package/src/plugins/types.ts +36 -1
- package/src/prompts/system-prompt.ts +1 -1
- package/src/providers/__tests__/connection-model-compat.test.ts +1 -1
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +1 -1
- package/src/providers/__tests__/inference.test.ts +6 -6
- package/src/providers/__tests__/placeholder-sentinels.test.ts +80 -0
- package/src/providers/__tests__/retry-callsite.test.ts +31 -3
- package/src/providers/__tests__/satellite-connection-routing.test.ts +1 -1
- package/src/providers/anthropic/client.ts +23 -24
- package/src/providers/call-site-routing.ts +1 -1
- package/src/providers/connection-resolution.ts +7 -3
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +7 -8
- package/src/providers/inference/__tests__/base-url-security.test.ts +8 -8
- package/src/providers/inference/__tests__/connections-label.test.ts +5 -5
- package/src/providers/inference/__tests__/connections-openai-compatible.test.ts +4 -4
- package/src/providers/inference/backfill.ts +9 -5
- package/src/providers/inference/connections.ts +2 -2
- package/src/providers/inference/resolve-auth.ts +3 -3
- package/src/providers/model-catalog.ts +38 -0
- package/src/providers/placeholder-sentinels.ts +50 -15
- package/src/providers/provider-send-message.ts +1 -1
- package/src/providers/registry.ts +2 -0
- package/src/providers/retry.ts +16 -0
- package/src/providers/stop-reasons.ts +32 -0
- package/src/providers/usage-tracking.ts +1 -1
- package/src/runtime/__tests__/agent-wake.test.ts +100 -29
- package/src/runtime/__tests__/background-job-runner.test.ts +19 -2
- package/src/runtime/__tests__/channel-verification-service.test.ts +9 -5
- package/src/runtime/__tests__/guardian-vellum-migration.test.ts +7 -5
- package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +3 -3
- package/src/runtime/__tests__/pre-first-message-gate.test.ts +1 -1
- package/src/runtime/access-request-helper.ts +3 -3
- package/src/runtime/agent-wake.ts +56 -11
- package/src/runtime/assistant-event-hub.ts +1 -1
- package/src/runtime/background-job-runner.ts +30 -10
- package/src/runtime/channel-reply-delivery.ts +3 -3
- package/src/runtime/channel-retry-sweep.ts +23 -3
- package/src/runtime/channel-verification-service.ts +9 -9
- package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
- package/src/runtime/finalize-event-delivery.ts +2 -2
- package/src/runtime/guardian-action-service.ts +1 -2
- package/src/runtime/guardian-reply-router.ts +1 -1
- package/src/runtime/http-server.ts +45 -1
- package/src/runtime/invite-redemption-service.ts +11 -3
- package/src/runtime/invite-service.ts +6 -4
- package/src/runtime/migrations/vbundle-streaming-importer.ts +1 -1
- package/src/runtime/pre-first-message-gate.ts +1 -1
- package/src/runtime/routes/__tests__/acp-routes.test.ts +74 -8
- package/src/runtime/routes/__tests__/backup-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +3 -3
- package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +17 -23
- package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +3 -3
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +5 -5
- package/src/runtime/routes/__tests__/contact-routes.test.ts +90 -9
- package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +5 -5
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +5 -5
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +3 -3
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +12 -12
- package/src/runtime/routes/__tests__/conversation-surface-routes.test.ts +4 -4
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +3 -3
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +3 -3
- package/src/runtime/routes/__tests__/invite-relay-routes.test.ts +21 -7
- package/src/runtime/routes/__tests__/memory-worker-routes.test.ts +306 -0
- package/src/runtime/routes/__tests__/ps-routes.test.ts +114 -0
- package/src/runtime/routes/__tests__/retrospective-routes.test.ts +6 -6
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +4 -4
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/wake-conversation-routes.test.ts +125 -0
- package/src/runtime/routes/acp-routes-event-log.test.ts +283 -0
- package/src/runtime/routes/acp-routes-list.test.ts +24 -25
- package/src/runtime/routes/acp-routes.test.ts +4 -4
- package/src/runtime/routes/acp-routes.ts +31 -4
- package/src/runtime/routes/app-management-routes.ts +9 -9
- package/src/runtime/routes/app-routes.ts +3 -7
- package/src/runtime/routes/approval-routes.ts +2 -4
- package/src/runtime/routes/attachment-routes.ts +2 -2
- package/src/runtime/routes/audit-routes.ts +2 -3
- package/src/runtime/routes/background-wake-routes.ts +19 -5
- package/src/runtime/routes/backup-routes.ts +1 -1
- package/src/runtime/routes/bookmark-routes.ts +3 -3
- package/src/runtime/routes/brain-graph-routes.ts +2 -2
- package/src/runtime/routes/btw-routes.ts +1 -1
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +1 -1
- package/src/runtime/routes/channel-delivery-routes.ts +1 -1
- package/src/runtime/routes/channel-readiness-routes.ts +7 -3
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +3 -8
- package/src/runtime/routes/consolidation-routes.ts +6 -6
- package/src/runtime/routes/contact-routes.ts +66 -15
- package/src/runtime/routes/conversation-attention-routes.ts +2 -2
- package/src/runtime/routes/conversation-cli-routes.ts +32 -7
- package/src/runtime/routes/conversation-compaction-routes.ts +4 -4
- package/src/runtime/routes/conversation-list-routes.ts +9 -9
- package/src/runtime/routes/conversation-management-routes.ts +9 -9
- package/src/runtime/routes/conversation-query-routes.ts +34 -11
- package/src/runtime/routes/conversation-routes.ts +99 -16
- package/src/runtime/routes/conversation-starter-routes.ts +11 -5
- package/src/runtime/routes/conversations-import-routes.ts +10 -6
- package/src/runtime/routes/debug-routes.ts +3 -3
- package/src/runtime/routes/defer-routes.ts +4 -4
- package/src/runtime/routes/documents-routes.ts +1 -1
- package/src/runtime/routes/empty-state-greeting-cache.ts +1 -1
- package/src/runtime/routes/events-routes.ts +4 -4
- package/src/runtime/routes/filing-routes.ts +1 -1
- package/src/runtime/routes/global-search-routes.ts +4 -4
- package/src/runtime/routes/group-routes.ts +1 -1
- package/src/runtime/routes/guardian-action-routes.ts +1 -1
- package/src/runtime/routes/heartbeat-routes.ts +2 -2
- package/src/runtime/routes/home-feed-routes.ts +10 -5
- package/src/runtime/routes/identity-routes.ts +33 -14
- package/src/runtime/routes/inbound-conversation.ts +3 -3
- package/src/runtime/routes/inbound-message-handler.ts +25 -25
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +8 -4
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +13 -6
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +5 -5
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +11 -11
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +12 -12
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +2 -2
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +1 -1
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +1 -1
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +8 -8
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +5 -2
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +1 -1
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +1 -1
- package/src/runtime/routes/index.ts +6 -4
- package/src/runtime/routes/inference-profile-session-handler.ts +2 -2
- package/src/runtime/routes/inference-profile-session-reaper.ts +1 -1
- package/src/runtime/routes/inference-provider-connection-routes.ts +5 -2
- package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +3 -4
- package/src/runtime/routes/integrations/slack/share.ts +1 -1
- package/src/runtime/routes/internal-telemetry-routes.ts +1 -1
- package/src/runtime/routes/log-export/__tests__/workspace-allowlist-error-contract.test.ts +1 -1
- package/src/runtime/routes/log-export/workspace-allowlist.ts +1 -1
- package/src/runtime/routes/log-export-routes.ts +2 -2
- package/src/runtime/routes/memory-worker-routes.ts +227 -0
- package/src/runtime/routes/migration-rollback-routes.ts +11 -12
- package/src/runtime/routes/migration-routes.ts +143 -5
- package/src/runtime/routes/notification-routes.ts +2 -2
- package/src/runtime/routes/platform-routes.ts +3 -0
- package/src/runtime/routes/playground/helpers.ts +3 -3
- package/src/runtime/routes/ps-routes.ts +37 -66
- package/src/runtime/routes/publish-routes.ts +3 -3
- package/src/runtime/routes/rename-conversation-routes.ts +1 -1
- package/src/runtime/routes/retrospective-routes.ts +5 -5
- package/src/runtime/routes/schedule-routes.ts +42 -40
- package/src/runtime/routes/secret-routes.ts +10 -9
- package/src/runtime/routes/sequence-routes.ts +1 -1
- package/src/runtime/routes/settings-routes.ts +18 -9
- package/src/runtime/routes/skills-routes.ts +11 -1
- package/src/runtime/routes/slack-channel-routes.ts +4 -4
- package/src/runtime/routes/subagents-routes.ts +2 -2
- package/src/runtime/routes/surface-conversation-resolver.ts +1 -1
- package/src/runtime/routes/task-routes.ts +18 -29
- package/src/runtime/routes/telemetry-routes.ts +1 -1
- package/src/runtime/routes/trace-event-routes.ts +1 -1
- package/src/runtime/routes/types.ts +7 -0
- package/src/runtime/routes/usage-routes.ts +2 -2
- package/src/runtime/routes/wake-conversation-routes.ts +44 -8
- package/src/runtime/routes/wipe-conversation-routes.ts +3 -3
- package/src/runtime/routes/work-items-routes.test.ts +1 -1
- package/src/runtime/routes/work-items-routes.ts +1 -1
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -2
- package/src/runtime/services/__tests__/auto-analysis-enqueue.test.ts +362 -0
- package/src/runtime/services/__tests__/auto-analysis-guard.test.ts +57 -0
- package/src/runtime/services/__tests__/conversation-analyze-job.test.ts +178 -0
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -1
- package/src/runtime/services/analyze-conversation.ts +22 -13
- package/src/runtime/services/auto-analysis-enqueue.ts +130 -0
- package/src/runtime/services/auto-analysis-guard.ts +13 -0
- package/src/runtime/services/conversation-analyze-job.ts +53 -0
- package/src/runtime/services/conversation-serializer.ts +5 -5
- package/src/runtime/tool-grant-request-helper.ts +1 -1
- package/src/schedule/retry-policy.ts +8 -8
- package/src/schedule/run-script.ts +7 -2
- package/src/schedule/schedule-recovery.ts +8 -5
- package/src/schedule/schedule-store.ts +270 -162
- package/src/schedule/schedule-usage-store.ts +2 -2
- package/src/schedule/scheduler-types.ts +6 -0
- package/src/schedule/scheduler.ts +189 -59
- package/src/security/auth-fallback-events-store.ts +94 -0
- package/src/security/redaction.ts +18 -14
- package/src/sequence/engine.ts +1 -1
- package/src/sequence/store.ts +3 -3
- package/src/services/published-app-updater.ts +2 -2
- package/src/signals/cancel.ts +1 -1
- package/src/signals/user-message.ts +2 -2
- package/src/skills/catalog-install.ts +2 -1
- package/src/skills/clawhub.ts +1 -0
- package/src/skills/install-meta.ts +44 -0
- package/src/skills/managed-store.ts +101 -3
- package/src/skills/skillssh-registry.ts +1 -0
- package/src/skills/version-hash.ts +20 -0
- package/src/subagent/manager.ts +5 -4
- package/src/tasks/task-compiler.ts +2 -2
- package/src/tasks/task-runner.ts +3 -3
- package/src/tasks/task-store.ts +2 -2
- package/src/telemetry/__tests__/watchdog-events-store.test.ts +161 -0
- package/src/telemetry/skill-loaded-events-store.test.ts +152 -0
- package/src/telemetry/skill-loaded-events-store.ts +95 -0
- package/src/telemetry/tool-executed-events-store.test.ts +219 -0
- package/src/telemetry/tool-executed-events-store.ts +102 -0
- package/src/telemetry/tool-usage-store.ts +114 -0
- package/src/telemetry/trace-event-store.ts +133 -0
- package/src/telemetry/turn-events-store.ts +173 -0
- package/src/telemetry/turn-trace-store.test.ts +736 -0
- package/src/telemetry/turn-trace-store.ts +364 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +12 -12
- package/src/telemetry/usage-telemetry-reporter.ts +46 -17
- package/src/telemetry/watchdog-events-store.ts +87 -0
- package/src/tools/__tests__/run-standalone.test.ts +19 -0
- package/src/tools/acp/spawn.test.ts +18 -7
- package/src/tools/acp/spawn.ts +1 -0
- package/src/tools/apps/executors.ts +2 -2
- package/src/tools/apps/resolve-app-id.ts +1 -1
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +3 -3
- package/src/tools/document/document-comment-tool.test.ts +2 -2
- package/src/tools/filesystem/write.ts +5 -4
- package/src/tools/policy-context.ts +21 -0
- package/src/tools/registry.ts +31 -1
- package/src/tools/run-standalone.ts +101 -0
- package/src/tools/schedule/create.ts +2 -2
- package/src/tools/schedule/delete.ts +1 -1
- package/src/tools/schedule/update.ts +1 -1
- package/src/tools/skills/find-similar-skills.test.ts +277 -0
- package/src/tools/skills/find-similar-skills.ts +120 -0
- package/src/tools/skills/scaffold-managed.ts +123 -4
- package/src/tools/subagent/read.ts +1 -1
- package/src/tools/subagent/spawn.ts +1 -1
- package/src/tools/tool-approval-handler.ts +1 -1
- package/src/tools/tool-manifest.ts +1 -1
- package/src/tools/types.ts +11 -0
- package/src/usage/types.ts +7 -0
- package/src/util/__tests__/process-tree.test.ts +123 -0
- package/src/util/device-id.ts +52 -12
- package/src/util/platform.ts +0 -14
- package/src/util/process-tree.ts +203 -0
- package/src/util/sqlite-retry.ts +90 -0
- package/src/watcher/__tests__/telemetry.test.ts +2 -2
- package/src/watcher/telemetry.ts +2 -2
- package/src/watcher/watcher-store.ts +3 -3
- package/src/work-items/work-item-store.ts +2 -2
- package/src/workflows/engine-integration.test.ts +2 -2
- package/src/workflows/engine.test.ts +2 -2
- package/src/workflows/fanout-load.test.ts +2 -2
- package/src/workflows/journal-store.test.ts +3 -3
- package/src/workflows/journal-store.ts +1 -1
- package/src/workflows/leaf-runner.test.ts +9 -6
- package/src/workflows/leaf-runner.ts +1 -1
- package/src/workspace/heartbeat-service.ts +29 -0
- package/src/workspace/migrations/011-backfill-installation-id.ts +1 -1
- package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +5 -2
- package/src/workspace/migrations/031-drop-user-md.ts +26 -0
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +1 -1
- package/src/workspace/migrations/113-swap-balanced-profile-to-glm-5p2.ts +101 -0
- package/src/workspace/migrations/114-swap-quality-profile-to-opus.ts +83 -0
- package/src/workspace/migrations/115-drop-frontier-profile.ts +129 -0
- package/src/workspace/migrations/116-rename-memory-plugin-disabled-sentinel.ts +53 -0
- package/src/workspace/migrations/117-normalize-stale-lean-memory-v3-defaults.ts +116 -0
- package/src/workspace/migrations/__tests__/backfill-v3-leaves.test.ts +5 -2
- package/src/workspace/migrations/rebuild-conversation-disk-view.ts +4 -4
- package/src/workspace/migrations/registry.ts +10 -0
- package/src/__tests__/config-managed-gemini-defaults.test.ts +0 -277
- package/src/__tests__/slack-block-formatting.test.ts +0 -173
- package/src/background-wake/runtime-registry.ts +0 -24
- package/src/contacts/contact-events.ts +0 -21
- package/src/daemon/__tests__/meet-host-supervisor.test.ts +0 -587
- package/src/daemon/__tests__/meet-manifest-loader.test.ts +0 -476
- package/src/daemon/meet-host-startup.ts +0 -51
- package/src/daemon/meet-host-supervisor.ts +0 -782
- package/src/daemon/meet-manifest-loader.ts +0 -396
- package/src/daemon/server.ts +0 -423
- package/src/filing/filing-service.ts +0 -429
- package/src/memory/__tests__/301-create-watchdog-events.test.ts +0 -110
- package/src/memory/__tests__/activation-session-store.test.ts +0 -41
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +0 -359
- package/src/memory/__tests__/auto-analysis-guard.test.ts +0 -57
- package/src/memory/__tests__/bookmark-crud.test.ts +0 -264
- package/src/memory/__tests__/bookmark-schema.test.ts +0 -181
- package/src/memory/__tests__/compaction-log-store-clickhouse.test.ts +0 -432
- package/src/memory/__tests__/conversation-analyze-job.test.ts +0 -178
- package/src/memory/__tests__/conversation-group-migration.test.ts +0 -99
- package/src/memory/__tests__/conversation-queries.test.ts +0 -843
- package/src/memory/__tests__/conversation-types.test.ts +0 -36
- package/src/memory/__tests__/db-async-query.test.ts +0 -165
- package/src/memory/__tests__/db-logs-attach.test.ts +0 -110
- package/src/memory/__tests__/db-maintenance.test.ts +0 -235
- package/src/memory/__tests__/db-memory-attach.test.ts +0 -113
- package/src/memory/__tests__/embedding-cache.test.ts +0 -136
- package/src/memory/__tests__/find-analysis-conversation.test.ts +0 -197
- package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +0 -140
- package/src/memory/__tests__/fork-message-copy.test.ts +0 -232
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +0 -241
- package/src/memory/__tests__/jobs-store-job-classes.test.ts +0 -52
- package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +0 -113
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +0 -505
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +0 -160
- package/src/memory/__tests__/memory-retrospective-job.test.ts +0 -1443
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +0 -544
- package/src/memory/__tests__/memory-retrospective-state.test.ts +0 -195
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +0 -221
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +0 -275
- package/src/memory/__tests__/memory-v3-selections-migration.test.ts +0 -103
- package/src/memory/__tests__/message-content.test.ts +0 -35
- package/src/memory/__tests__/onboarding-events-store.test.ts +0 -80
- package/src/memory/__tests__/prompt-override.test.ts +0 -192
- package/src/memory/__tests__/qdrant-client-sentinel.test.ts +0 -49
- package/src/memory/__tests__/table-relocation.test.ts +0 -129
- package/src/memory/__tests__/watchdog-events-store.test.ts +0 -161
- package/src/memory/activation-session-store.ts +0 -43
- package/src/memory/anisotropy.ts +0 -443
- package/src/memory/app-store.ts +0 -1058
- package/src/memory/attachments-store.ts +0 -1136
- package/src/memory/auth-fallback-events-store.ts +0 -94
- package/src/memory/auto-analysis-enqueue.ts +0 -127
- package/src/memory/auto-analysis-guard.ts +0 -17
- package/src/memory/canonical-guardian-store.ts +0 -891
- package/src/memory/channel-verification-sessions.ts +0 -557
- package/src/memory/checkpoints.ts +0 -65
- package/src/memory/compaction-ledger-store.ts +0 -107
- package/src/memory/context-search/agent-protocol.ts +0 -428
- package/src/memory/context-search/agent-runner.ts +0 -1310
- package/src/memory/context-search/search.ts +0 -297
- package/src/memory/context-search/sources/conversations.ts +0 -341
- package/src/memory/context-search/sources/memory-v2.ts +0 -600
- package/src/memory/context-search/sources/memory.ts +0 -101
- package/src/memory/context-search/types.ts +0 -48
- package/src/memory/conversation-analyze-job.ts +0 -53
- package/src/memory/conversation-attention-store.ts +0 -689
- package/src/memory/conversation-bootstrap.ts +0 -50
- package/src/memory/conversation-crud.ts +0 -3436
- package/src/memory/conversation-key-store.ts +0 -274
- package/src/memory/conversation-queries.ts +0 -768
- package/src/memory/conversation-starter-checkpoints.ts +0 -64
- package/src/memory/db-async-query.ts +0 -298
- package/src/memory/db-connection.ts +0 -228
- package/src/memory/db-init.ts +0 -265
- package/src/memory/db-maintenance.ts +0 -154
- package/src/memory/embed.ts +0 -73
- package/src/memory/embedding-backend.test.ts +0 -204
- package/src/memory/embedding-backend.ts +0 -862
- package/src/memory/embedding-billing-breaker.ts +0 -96
- package/src/memory/embedding-cache.ts +0 -139
- package/src/memory/embedding-local.ts +0 -587
- package/src/memory/embedding-ollama.ts +0 -79
- package/src/memory/embedding-runtime-manager.ts +0 -573
- package/src/memory/embedding-types.ts +0 -90
- package/src/memory/external-conversation-store.ts +0 -315
- package/src/memory/fork-message-copy.ts +0 -170
- package/src/memory/graph/__tests__/conversation-graph-memory-registry.test.ts +0 -119
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +0 -655
- package/src/memory/graph/__tests__/handle-remember-v2.test.ts +0 -321
- package/src/memory/graph/bootstrap.test.ts +0 -280
- package/src/memory/graph/bootstrap.ts +0 -532
- package/src/memory/graph/capability-seed.ts +0 -451
- package/src/memory/graph/consolidation.ts +0 -712
- package/src/memory/graph/conversation-graph-memory.ts +0 -1185
- package/src/memory/graph/decay.ts +0 -195
- package/src/memory/graph/extraction-job.ts +0 -74
- package/src/memory/graph/extraction.ts +0 -1462
- package/src/memory/graph/graph-memory-state-store.ts +0 -50
- package/src/memory/graph/graph-search.test.ts +0 -129
- package/src/memory/graph/graph-search.ts +0 -292
- package/src/memory/graph/image-ref-utils.ts +0 -29
- package/src/memory/graph/injection.ts +0 -469
- package/src/memory/graph/narrative.ts +0 -267
- package/src/memory/graph/pattern-scan.ts +0 -269
- package/src/memory/graph/retriever.test.ts +0 -624
- package/src/memory/graph/retriever.ts +0 -1356
- package/src/memory/graph/store.test.ts +0 -1093
- package/src/memory/graph/store.ts +0 -923
- package/src/memory/graph/tool-handlers.ts +0 -195
- package/src/memory/graph/tools.ts +0 -95
- package/src/memory/guardian-rate-limits.ts +0 -191
- package/src/memory/indexer.ts +0 -406
- package/src/memory/job-handlers/backfill.ts +0 -104
- package/src/memory/job-handlers/cleanup.ts +0 -237
- package/src/memory/job-handlers/conversation-starters.ts +0 -481
- package/src/memory/job-handlers/embedding.test.ts +0 -234
- package/src/memory/job-handlers/embedding.ts +0 -133
- package/src/memory/job-handlers/index-maintenance.ts +0 -111
- package/src/memory/job-handlers/media-processing.ts +0 -120
- package/src/memory/job-handlers/summarization.ts +0 -240
- package/src/memory/job-utils.ts +0 -286
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +0 -559
- package/src/memory/jobs/embed-concept-page.ts +0 -417
- package/src/memory/jobs/embed-pkb-file.test.ts +0 -169
- package/src/memory/jobs/embed-pkb-file.ts +0 -59
- package/src/memory/jobs-store.ts +0 -813
- package/src/memory/jobs-worker.ts +0 -1021
- package/src/memory/llm-request-log-source-clickhouse.ts +0 -521
- package/src/memory/llm-request-log-store.ts +0 -717
- package/src/memory/llm-usage-store.ts +0 -900
- package/src/memory/memory-recall-log-store.ts +0 -172
- package/src/memory/memory-retrospective-constants.ts +0 -50
- package/src/memory/memory-retrospective-enqueue.ts +0 -125
- package/src/memory/memory-retrospective-fork-boundary.ts +0 -94
- package/src/memory/memory-retrospective-job.ts +0 -884
- package/src/memory/memory-retrospective-startup-cleanup.ts +0 -261
- package/src/memory/memory-retrospective-state.ts +0 -245
- package/src/memory/memory-retrospective-trigger-check.ts +0 -91
- package/src/memory/memory-v2-activation-log-store.ts +0 -216
- package/src/memory/memory-v2-concept-frequency.ts +0 -173
- package/src/memory/migrations/126-backfill-guardian-principal-id.ts +0 -303
- package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +0 -365
- package/src/memory/migrations/142-rename-verification-session-id-column.ts +0 -55
- package/src/memory/migrations/182-oauth-providers-display-metadata.ts +0 -20
- package/src/memory/migrations/196-strip-integration-prefix-from-provider-keys.ts +0 -179
- package/src/memory/migrations/199-guardian-request-enrichment-columns.ts +0 -64
- package/src/memory/migrations/202-memory-graph-tables.ts +0 -130
- package/src/memory/migrations/203-drop-memory-items-tables.ts +0 -55
- package/src/memory/migrations/206-scrub-corrupted-image-attachments.ts +0 -124
- package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +0 -174
- package/src/memory/migrations/211-memory-recall-logs-query-context.ts +0 -16
- package/src/memory/migrations/220-normalize-user-file-by-principal.ts +0 -183
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +0 -76
- package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +0 -21
- package/src/memory/migrations/243-provider-connections.ts +0 -68
- package/src/memory/migrations/244-provider-connection-status-label.ts +0 -23
- package/src/memory/migrations/246-backfill-provider-connection-label.ts +0 -81
- package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +0 -19
- package/src/memory/migrations/301-create-watchdog-events.ts +0 -45
- package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +0 -297
- package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +0 -84
- package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +0 -192
- package/src/memory/migrations/__tests__/run-migrations.test.ts +0 -378
- package/src/memory/migrations/helpers/relocation.ts +0 -227
- package/src/memory/migrations/validate-migration-state.ts +0 -277
- package/src/memory/onboarding-events-store.ts +0 -161
- package/src/memory/pkb/autoinject.ts +0 -61
- package/src/memory/pkb/context.ts +0 -50
- package/src/memory/pkb/pkb-index.test.ts +0 -368
- package/src/memory/pkb/pkb-index.ts +0 -255
- package/src/memory/pkb/pkb-reconcile.test.ts +0 -251
- package/src/memory/pkb/pkb-reconcile.ts +0 -148
- package/src/memory/pkb/pkb-search.test.ts +0 -586
- package/src/memory/pkb/pkb-search.ts +0 -178
- package/src/memory/pkb/types.ts +0 -67
- package/src/memory/published-pages-store.ts +0 -67
- package/src/memory/qdrant-circuit-breaker.ts +0 -119
- package/src/memory/qdrant-client.test.ts +0 -60
- package/src/memory/qdrant-client.ts +0 -834
- package/src/memory/qdrant-manager.ts +0 -422
- package/src/memory/rerank-local.ts +0 -374
- package/src/memory/schedule-attribution-sql.ts +0 -104
- package/src/memory/schema/acp.ts +0 -34
- package/src/memory/schema/contacts.ts +0 -120
- package/src/memory/schema/conversations.ts +0 -236
- package/src/memory/schema/infrastructure.ts +0 -381
- package/src/memory/scoped-approval-grants.ts +0 -551
- package/src/memory/search/semantic.ts +0 -238
- package/src/memory/segmenter.ts +0 -76
- package/src/memory/shared-app-links-store.ts +0 -130
- package/src/memory/skill-loaded-events-store.test.ts +0 -152
- package/src/memory/skill-loaded-events-store.ts +0 -95
- package/src/memory/sparse-tokenize.ts +0 -49
- package/src/memory/steps.ts +0 -1296
- package/src/memory/task-memory-cleanup.ts +0 -236
- package/src/memory/tool-executed-events-store.test.ts +0 -219
- package/src/memory/tool-executed-events-store.ts +0 -102
- package/src/memory/tool-usage-store.ts +0 -113
- package/src/memory/trace-event-store.ts +0 -133
- package/src/memory/turn-events-store.ts +0 -173
- package/src/memory/turn-trace-store.test.ts +0 -736
- package/src/memory/turn-trace-store.ts +0 -364
- package/src/memory/v2/__tests__/activation-store.test.ts +0 -204
- package/src/memory/v2/__tests__/activation.test.ts +0 -1227
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +0 -504
- package/src/memory/v2/__tests__/cli-command-store.test.ts +0 -429
- package/src/memory/v2/__tests__/consolidation-job.test.ts +0 -747
- package/src/memory/v2/__tests__/consolidation-prompt-flag-gating-guard.test.ts +0 -189
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +0 -136
- package/src/memory/v2/__tests__/harness-compare.test.ts +0 -186
- package/src/memory/v2/__tests__/harness-oracle.test.ts +0 -257
- package/src/memory/v2/__tests__/harness-replay-input.test.ts +0 -230
- package/src/memory/v2/__tests__/harness-runner.test.ts +0 -135
- package/src/memory/v2/__tests__/injection-events.test.ts +0 -318
- package/src/memory/v2/__tests__/injection.test.ts +0 -2301
- package/src/memory/v2/__tests__/migration.test.ts +0 -939
- package/src/memory/v2/__tests__/page-index.test.ts +0 -760
- package/src/memory/v2/__tests__/prompts-consolidation.test.ts +0 -313
- package/src/memory/v2/__tests__/qdrant.test.ts +0 -950
- package/src/memory/v2/__tests__/reranker.test.ts +0 -338
- package/src/memory/v2/__tests__/router.test.ts +0 -1197
- package/src/memory/v2/__tests__/sim.test.ts +0 -670
- package/src/memory/v2/__tests__/skill-content.test.ts +0 -115
- package/src/memory/v2/__tests__/skill-store.test.ts +0 -983
- package/src/memory/v2/__tests__/sparse-bm25.test.ts +0 -292
- package/src/memory/v2/__tests__/static-context.test.ts +0 -223
- package/src/memory/v2/__tests__/sweep-job.test.ts +0 -526
- package/src/memory/v2/activation-store.ts +0 -185
- package/src/memory/v2/activation.ts +0 -548
- package/src/memory/v2/backfill-jobs.ts +0 -296
- package/src/memory/v2/cli-command-store.ts +0 -341
- package/src/memory/v2/consolidation-job.ts +0 -561
- package/src/memory/v2/frontmatter-sweep.ts +0 -98
- package/src/memory/v2/harness/compare.ts +0 -57
- package/src/memory/v2/harness/oracle.ts +0 -145
- package/src/memory/v2/harness/replay-input.ts +0 -240
- package/src/memory/v2/harness/retriever.ts +0 -74
- package/src/memory/v2/harness/router-retriever.ts +0 -43
- package/src/memory/v2/injected-block-slugs.ts +0 -79
- package/src/memory/v2/injection-events.ts +0 -101
- package/src/memory/v2/injection.ts +0 -932
- package/src/memory/v2/migration.ts +0 -776
- package/src/memory/v2/page-index.ts +0 -459
- package/src/memory/v2/page-store.ts +0 -443
- package/src/memory/v2/prompts/consolidation.ts +0 -857
- package/src/memory/v2/prompts/router.ts +0 -148
- package/src/memory/v2/qdrant.ts +0 -892
- package/src/memory/v2/reranker.ts +0 -184
- package/src/memory/v2/router.ts +0 -601
- package/src/memory/v2/sim.ts +0 -296
- package/src/memory/v2/skill-content.ts +0 -61
- package/src/memory/v2/skill-store.ts +0 -431
- package/src/memory/v2/sparse-bm25.ts +0 -245
- package/src/memory/v2/static-context.ts +0 -100
- package/src/memory/v2/sweep-job.ts +0 -320
- package/src/memory/v3-eval/eval-packets.ts +0 -731
- package/src/memory/watchdog-events-store.ts +0 -87
- package/src/memory/worker-control.ts +0 -204
- package/src/memory/worker-process.ts +0 -89
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +0 -116
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +0 -370
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +0 -41
- package/src/plugins/defaults/memory-retrieval/injectors.ts +0 -1061
- package/src/plugins/defaults/memory-retrieval/package.json +0 -14
- package/src/plugins/defaults/memory-retrieval/tail-reinjection-strip.ts +0 -64
- package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +0 -1164
- package/src/plugins/defaults/memory-v3-shadow/__tests__/dense.test.ts +0 -192
- package/src/plugins/defaults/memory-v3-shadow/__tests__/edge.test.ts +0 -247
- package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +0 -717
- package/src/plugins/defaults/memory-v3-shadow/__tests__/live-integration.test.ts +0 -365
- package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +0 -736
- package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +0 -839
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +0 -598
- package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +0 -128
- package/src/plugins/defaults/memory-v3-shadow/__tests__/section-dense-store.test.ts +0 -710
- package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +0 -425
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +0 -493
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +0 -856
- package/src/plugins/defaults/memory-v3-shadow/capabilities.ts +0 -91
- package/src/plugins/defaults/memory-v3-shadow/card.ts +0 -160
- package/src/plugins/defaults/memory-v3-shadow/dense.ts +0 -97
- package/src/plugins/defaults/memory-v3-shadow/edge.ts +0 -252
- package/src/plugins/defaults/memory-v3-shadow/ever-injected-store.test.ts +0 -305
- package/src/plugins/defaults/memory-v3-shadow/ever-injected-store.ts +0 -278
- package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +0 -14
- package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +0 -19
- package/src/plugins/defaults/memory-v3-shadow/hot-set.test.ts +0 -138
- package/src/plugins/defaults/memory-v3-shadow/hot-set.ts +0 -85
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +0 -453
- package/src/plugins/defaults/memory-v3-shadow/learned-edges.test.ts +0 -169
- package/src/plugins/defaults/memory-v3-shadow/learned-edges.ts +0 -178
- package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +0 -794
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +0 -431
- package/src/plugins/defaults/memory-v3-shadow/package.json +0 -14
- package/src/plugins/defaults/memory-v3-shadow/page-content.ts +0 -102
- package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +0 -146
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +0 -578
- package/src/plugins/defaults/memory-v3-shadow/prune.test.ts +0 -758
- package/src/plugins/defaults/memory-v3-shadow/prune.ts +0 -471
- package/src/plugins/defaults/memory-v3-shadow/render-injection.ts +0 -92
- package/src/plugins/defaults/memory-v3-shadow/section-dense-store.ts +0 -422
- package/src/plugins/defaults/memory-v3-shadow/section-needle.ts +0 -200
- package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +0 -281
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +0 -642
- package/src/plugins/defaults/memory-v3-shadow/types.ts +0 -127
- package/src/plugins/feature-gate.ts +0 -22
- package/src/runtime/__tests__/slack-block-formatting.test.ts +0 -510
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +0 -165
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +0 -347
- package/src/runtime/routes/memory-eval-routes.ts +0 -179
- package/src/runtime/routes/memory-item-routes.test.ts +0 -912
- package/src/runtime/routes/memory-item-routes.ts +0 -815
- package/src/runtime/routes/memory-v2-routes.ts +0 -850
- package/src/runtime/routes/memory-v3-routes.ts +0 -122
- package/src/runtime/routes/secrets-deps.ts +0 -24
- package/src/runtime/slack-block-formatting.ts +0 -586
- package/src/tools/memory/register.test.ts +0 -382
- package/src/tools/memory/register.ts +0 -81
- /package/src/{memory → apps}/app-git-service.ts +0 -0
- /package/src/{memory → channels}/slack-thread-store.ts +0 -0
- /package/src/{memory → home}/conversation-starter-validation.ts +0 -0
- /package/src/{memory → persistence}/auto-analysis-constants.ts +0 -0
- /package/src/{memory → persistence}/bookmark-crud.ts +0 -0
- /package/src/{memory → persistence}/cleanup-schedule-state.ts +0 -0
- /package/src/{memory → persistence}/compaction-log-store-clickhouse.ts +0 -0
- /package/src/{memory → persistence}/conversation-directories.ts +0 -0
- /package/src/{memory → persistence}/conversation-disk-view.ts +0 -0
- /package/src/{memory → persistence}/conversation-display-order-migration.ts +0 -0
- /package/src/{memory → persistence}/conversation-group-migration.ts +0 -0
- /package/src/{memory → persistence}/conversation-title-service.ts +0 -0
- /package/src/{memory → persistence}/conversation-types.ts +0 -0
- /package/src/{memory → persistence}/db-singleton.ts +0 -0
- /package/src/{memory → persistence}/delivery-channels.ts +0 -0
- /package/src/{memory → persistence}/delivery-crud.ts +0 -0
- /package/src/{memory → persistence}/delivery-status.ts +0 -0
- /package/src/{memory → persistence/embeddings}/__tests__/sparse-tokenize.test.ts +0 -0
- /package/src/{memory → persistence/embeddings}/embedding-gemini.test.ts +0 -0
- /package/src/{memory → persistence/embeddings}/embedding-gemini.ts +0 -0
- /package/src/{memory → persistence/embeddings}/embedding-openai.ts +0 -0
- /package/src/{memory → persistence/embeddings}/embedding-types.test.ts +0 -0
- /package/src/{memory → persistence}/fingerprint.ts +0 -0
- /package/src/{memory → persistence}/group-crud.ts +0 -0
- /package/src/{memory → persistence}/invite-store.ts +0 -0
- /package/src/{memory → persistence}/lifecycle-events-store.ts +0 -0
- /package/src/{memory → persistence}/llm-request-log-source-local.ts +0 -0
- /package/src/{memory → persistence}/llm-request-log-source.ts +0 -0
- /package/src/{memory → persistence}/media-store.ts +0 -0
- /package/src/{memory → persistence}/message-content.ts +0 -0
- /package/src/{memory → persistence}/migrations/000-core-tables.ts +0 -0
- /package/src/{memory → persistence}/migrations/001-job-deferrals.ts +0 -0
- /package/src/{memory → persistence}/migrations/002-tool-invocations-fk.ts +0 -0
- /package/src/{memory → persistence}/migrations/003-memory-fts-backfill.ts +0 -0
- /package/src/{memory → persistence}/migrations/004-entity-relation-dedup.ts +0 -0
- /package/src/{memory → persistence}/migrations/005-fingerprint-scope-unique.ts +0 -0
- /package/src/{memory → persistence}/migrations/006-scope-salted-fingerprints.ts +0 -0
- /package/src/{memory → persistence}/migrations/007-assistant-id-to-self.ts +0 -0
- /package/src/{memory → persistence}/migrations/008-remove-assistant-id-columns.ts +0 -0
- /package/src/{memory → persistence}/migrations/009-llm-usage-events-drop-assistant-id.ts +0 -0
- /package/src/{memory → persistence}/migrations/011-call-sessions-provider-sid-dedup.ts +0 -0
- /package/src/{memory → persistence}/migrations/012-call-sessions-add-initiated-from.ts +0 -0
- /package/src/{memory → persistence}/migrations/013-guardian-action-tables.ts +0 -0
- /package/src/{memory → persistence}/migrations/014-backfill-inbox-thread-state.ts +0 -0
- /package/src/{memory → persistence}/migrations/015-drop-active-search-index.ts +0 -0
- /package/src/{memory → persistence}/migrations/016-memory-segments-indexes.ts +0 -0
- /package/src/{memory → persistence}/migrations/017-memory-items-indexes.ts +0 -0
- /package/src/{memory → persistence}/migrations/018-remaining-table-indexes.ts +0 -0
- /package/src/{memory → persistence}/migrations/019-notification-tables-schema-migration.ts +0 -0
- /package/src/{memory → persistence}/migrations/020-rename-macos-ios-channel-to-vellum.ts +0 -0
- /package/src/{memory → persistence}/migrations/021-conversation-status-indexes.ts +0 -0
- /package/src/{memory → persistence}/migrations/022-add-origin-interface.ts +0 -0
- /package/src/{memory → persistence}/migrations/023-memory-item-sources-indexes.ts +0 -0
- /package/src/{memory → persistence}/migrations/024-embedding-vector-blob.ts +0 -0
- /package/src/{memory → persistence}/migrations/025-messages-fts-backfill.ts +0 -0
- /package/src/{memory → persistence}/migrations/026-guardian-verification-sessions.ts +0 -0
- /package/src/{memory → persistence}/migrations/026a-embeddings-nullable-vector-json.ts +0 -0
- /package/src/{memory → persistence}/migrations/027-notification-delivery-pairing-columns.ts +0 -0
- /package/src/{memory → persistence}/migrations/027a-guardian-bootstrap-token.ts +0 -0
- /package/src/{memory → persistence}/migrations/028-call-session-mode.ts +0 -0
- /package/src/{memory → persistence}/migrations/028-notification-delivery-client-ack.ts +0 -0
- /package/src/{memory → persistence}/migrations/029-channel-inbound-delivered-segments.ts +0 -0
- /package/src/{memory → persistence}/migrations/030-guardian-action-followup.ts +0 -0
- /package/src/{memory → persistence}/migrations/030-guardian-verification-purpose.ts +0 -0
- /package/src/{memory → persistence}/migrations/031-conversations-thread-type-index.ts +0 -0
- /package/src/{memory → persistence}/migrations/032-guardian-delivery-conversation-index.ts +0 -0
- /package/src/{memory → persistence}/migrations/032-notification-delivery-thread-decision.ts +0 -0
- /package/src/{memory → persistence}/migrations/033-scoped-approval-grants.ts +0 -0
- /package/src/{memory → persistence}/migrations/034-guardian-action-tool-metadata.ts +0 -0
- /package/src/{memory → persistence}/migrations/035-guardian-action-supersession.ts +0 -0
- /package/src/{memory → persistence}/migrations/036-normalize-phone-identities.ts +0 -0
- /package/src/{memory → persistence}/migrations/037-voice-invite-columns.ts +0 -0
- /package/src/{memory → persistence}/migrations/040-invite-code-hash-column.ts +0 -0
- /package/src/{memory → persistence}/migrations/041-approval-prompt-ts-tracker.ts +0 -0
- /package/src/{memory → persistence}/migrations/101-watchers-and-logs.ts +0 -0
- /package/src/{memory → persistence}/migrations/102-alter-table-columns.ts +0 -0
- /package/src/{memory → persistence}/migrations/104-core-indexes.ts +0 -0
- /package/src/{memory → persistence}/migrations/105-contacts-and-triage.ts +0 -0
- /package/src/{memory → persistence}/migrations/106-call-sessions.ts +0 -0
- /package/src/{memory → persistence}/migrations/107-followups.ts +0 -0
- /package/src/{memory → persistence}/migrations/108-tasks-and-work-items.ts +0 -0
- /package/src/{memory → persistence}/migrations/109-external-conversation-bindings.ts +0 -0
- /package/src/{memory → persistence}/migrations/110-channel-guardian.ts +0 -0
- /package/src/{memory → persistence}/migrations/111-media-assets.ts +0 -0
- /package/src/{memory → persistence}/migrations/112-assistant-inbox.ts +0 -0
- /package/src/{memory → persistence}/migrations/114-notifications.ts +0 -0
- /package/src/{memory → persistence}/migrations/115-sequences.ts +0 -0
- /package/src/{memory → persistence}/migrations/116-messages-fts.ts +0 -0
- /package/src/{memory → persistence}/migrations/117-conversation-attention.ts +0 -0
- /package/src/{memory → persistence}/migrations/118-reminder-routing-intent.ts +0 -0
- /package/src/{memory → persistence}/migrations/119-schema-indexes-and-columns.ts +0 -0
- /package/src/{memory → persistence}/migrations/120-fk-cascade-rebuilds.ts +0 -0
- /package/src/{memory → persistence}/migrations/121-canonical-guardian-requests.ts +0 -0
- /package/src/{memory → persistence}/migrations/122-canonical-guardian-requester-chat-id.ts +0 -0
- /package/src/{memory → persistence}/migrations/123-canonical-guardian-deliveries-destination-index.ts +0 -0
- /package/src/{memory → persistence}/migrations/124-voice-invite-display-metadata.ts +0 -0
- /package/src/{memory → persistence}/migrations/125-guardian-principal-id-columns.ts +0 -0
- /package/src/{memory → persistence}/migrations/127-guardian-principal-id-not-null.ts +0 -0
- /package/src/{memory → persistence}/migrations/128-contacts-role-principal.ts +0 -0
- /package/src/{memory → persistence}/migrations/129-contact-channels-access-fields.ts +0 -0
- /package/src/{memory → persistence}/migrations/130-contact-channels-type-ext-chat-id-index.ts +0 -0
- /package/src/{memory → persistence}/migrations/131-drop-legacy-member-guardian-tables.ts +0 -0
- /package/src/{memory → persistence}/migrations/132-contacts-assistant-id.ts +0 -0
- /package/src/{memory → persistence}/migrations/133-assistant-contact-metadata.ts +0 -0
- /package/src/{memory → persistence}/migrations/134-contacts-notes-column.ts +0 -0
- /package/src/{memory → persistence}/migrations/135-backfill-contact-interaction-stats.ts +0 -0
- /package/src/{memory → persistence}/migrations/136-drop-assistant-id-columns.ts +0 -0
- /package/src/{memory → persistence}/migrations/137-usage-dashboard-indexes.ts +0 -0
- /package/src/{memory → persistence}/migrations/139-drop-usage-composite-indexes.ts +0 -0
- /package/src/{memory → persistence}/migrations/141-rename-verification-table.ts +0 -0
- /package/src/{memory → persistence}/migrations/143-rename-guardian-verification-values.ts +0 -0
- /package/src/{memory → persistence}/migrations/144-rename-voice-to-phone.ts +0 -0
- /package/src/{memory → persistence}/migrations/145-drop-accounts-table.ts +0 -0
- /package/src/{memory → persistence}/migrations/146-schedule-oneshot-routing.ts +0 -0
- /package/src/{memory → persistence}/migrations/147-migrate-reminders-to-schedules.ts +0 -0
- /package/src/{memory → persistence}/migrations/148-drop-reminders-table.ts +0 -0
- /package/src/{memory → persistence}/migrations/149-oauth-tables.ts +0 -0
- /package/src/{memory → persistence}/migrations/150-oauth-apps-client-secret-path.ts +0 -0
- /package/src/{memory → persistence}/migrations/151-oauth-providers-ping-url.ts +0 -0
- /package/src/{memory → persistence}/migrations/152-memory-item-supersession.ts +0 -0
- /package/src/{memory → persistence}/migrations/153-drop-entity-tables.ts +0 -0
- /package/src/{memory → persistence}/migrations/154-drop-fts.ts +0 -0
- /package/src/{memory → persistence}/migrations/155-drop-conflicts.ts +0 -0
- /package/src/{memory → persistence}/migrations/156-call-session-invite-metadata.ts +0 -0
- /package/src/{memory → persistence}/migrations/157-invite-contact-id.ts +0 -0
- /package/src/{memory → persistence}/migrations/158-channel-interaction-columns.ts +0 -0
- /package/src/{memory → persistence}/migrations/159-drop-contact-interaction-columns.ts +0 -0
- /package/src/{memory → persistence}/migrations/160-drop-loopback-port-column.ts +0 -0
- /package/src/{memory → persistence}/migrations/161-drop-orphaned-media-tables.ts +0 -0
- /package/src/{memory → persistence}/migrations/162-guardian-timestamps-epoch-ms.ts +0 -0
- /package/src/{memory → persistence}/migrations/163-rename-notification-thread-columns.ts +0 -0
- /package/src/{memory → persistence}/migrations/164-rename-conversation-type-column.ts +0 -0
- /package/src/{memory → persistence}/migrations/165-rename-inbox-thread-state-table.ts +0 -0
- /package/src/{memory → persistence}/migrations/166-rename-followups-thread-id.ts +0 -0
- /package/src/{memory → persistence}/migrations/167-rename-sequence-enrollments-thread-id.ts +0 -0
- /package/src/{memory → persistence}/migrations/168-rename-sequence-steps-reply-key.ts +0 -0
- /package/src/{memory → persistence}/migrations/169-rename-gmail-provider-key-to-google.ts +0 -0
- /package/src/{memory → persistence}/migrations/170-thread-starters-table.ts +0 -0
- /package/src/{memory → persistence}/migrations/171-capability-card-columns.ts +0 -0
- /package/src/{memory → persistence}/migrations/172-rename-created-by-session-id.ts +0 -0
- /package/src/{memory → persistence}/migrations/173-rename-source-session-id.ts +0 -0
- /package/src/{memory → persistence}/migrations/174-rename-thread-starters-table.ts +0 -0
- /package/src/{memory → persistence}/migrations/175-create-lifecycle-events.ts +0 -0
- /package/src/{memory → persistence}/migrations/176-drop-capability-card-state.ts +0 -0
- /package/src/{memory → persistence}/migrations/177-create-trace-events-table.ts +0 -0
- /package/src/{memory → persistence}/migrations/178-oauth-providers-managed-service-config-key.ts +0 -0
- /package/src/{memory → persistence}/migrations/179-llm-request-log-message-id.ts +0 -0
- /package/src/{memory → persistence}/migrations/180-backfill-inline-attachments-to-disk.ts +0 -0
- /package/src/{memory → persistence}/migrations/181-rename-thread-starters-checkpoints.ts +0 -0
- /package/src/{memory → persistence}/migrations/183-add-conversation-fork-lineage.ts +0 -0
- /package/src/{memory → persistence}/migrations/184-llm-request-log-provider.ts +0 -0
- /package/src/{memory → persistence}/migrations/188-schedule-quiet-flag.ts +0 -0
- /package/src/{memory → persistence}/migrations/189-drop-simplified-memory.ts +0 -0
- /package/src/{memory → persistence}/migrations/190-call-session-skip-disclosure.ts +0 -0
- /package/src/{memory → persistence}/migrations/191-backfill-audio-attachment-mime-types.ts +0 -0
- /package/src/{memory → persistence}/migrations/192-contacts-user-file-column.ts +0 -0
- /package/src/{memory → persistence}/migrations/193-add-source-type-columns.ts +0 -0
- /package/src/{memory → persistence}/migrations/194-memory-recall-logs.ts +0 -0
- /package/src/{memory → persistence}/migrations/195-oauth-providers-ping-config.ts +0 -0
- /package/src/{memory → persistence}/migrations/196-messages-conversation-created-at-index.ts +0 -0
- /package/src/{memory → persistence}/migrations/197-oauth-providers-behavior-columns.ts +0 -0
- /package/src/{memory → persistence}/migrations/198-drop-setup-skill-id-column.ts +0 -0
- /package/src/{memory → persistence}/migrations/200-usage-llm-call-count.ts +0 -0
- /package/src/{memory → persistence}/migrations/201-oauth-providers-feature-flag.ts +0 -0
- /package/src/{memory → persistence}/migrations/202-drop-callback-transport-column.ts +0 -0
- /package/src/{memory → persistence}/migrations/204-rename-memory-graph-type-values.ts +0 -0
- /package/src/{memory → persistence}/migrations/205-memory-graph-image-refs.ts +0 -0
- /package/src/{memory → persistence}/migrations/206-memory-graph-node-edits.ts +0 -0
- /package/src/{memory → persistence}/migrations/207-conversation-graph-memory-state.ts +0 -0
- /package/src/{memory → persistence}/migrations/208-conversations-last-message-at.ts +0 -0
- /package/src/{memory → persistence}/migrations/210-schedule-reuse-conversation.ts +0 -0
- /package/src/{memory → persistence}/migrations/212-llm-request-logs-created-at-index.ts +0 -0
- /package/src/{memory → persistence}/migrations/213-oauth-providers-scope-separator.ts +0 -0
- /package/src/{memory → persistence}/migrations/214-oauth-providers-refresh-url.ts +0 -0
- /package/src/{memory → persistence}/migrations/215-oauth-providers-revoke.ts +0 -0
- /package/src/{memory → persistence}/migrations/216-oauth-providers-token-auth-method.ts +0 -0
- /package/src/{memory → persistence}/migrations/217-conversation-host-access.ts +0 -0
- /package/src/{memory → persistence}/migrations/218-oauth-providers-logo-url.ts +0 -0
- /package/src/{memory → persistence}/migrations/219-oauth-providers-token-exchange-body-format.ts +0 -0
- /package/src/{memory → persistence}/migrations/221-conversations-archived-at.ts +0 -0
- /package/src/{memory → persistence}/migrations/223-schedule-script-column.ts +0 -0
- /package/src/{memory → persistence}/migrations/224-oauth-providers-managed-service-is-paid.ts +0 -0
- /package/src/{memory → persistence}/migrations/225-oauth-providers-available-scopes.ts +0 -0
- /package/src/{memory → persistence}/migrations/226-schedule-wake-conversation-id.ts +0 -0
- /package/src/{memory → persistence}/migrations/227-add-conversation-inference-profile.ts +0 -0
- /package/src/{memory → persistence}/migrations/228-rename-inference-profile-snake-case.ts +0 -0
- /package/src/{memory → persistence}/migrations/229-delete-private-conversations.test.ts +0 -0
- /package/src/{memory → persistence}/migrations/229-delete-private-conversations.ts +0 -0
- /package/src/{memory → persistence}/migrations/230-acp-session-history.ts +0 -0
- /package/src/{memory → persistence}/migrations/231-repair-memory-graph-event-dates.ts +0 -0
- /package/src/{memory → persistence}/migrations/232-activation-state.ts +0 -0
- /package/src/{memory → persistence}/migrations/233-document-conversations.ts +0 -0
- /package/src/{memory → persistence}/migrations/234-memory-v2-activation-logs.ts +0 -0
- /package/src/{memory → persistence}/migrations/235-llm-usage-attribution.ts +0 -0
- /package/src/{memory → persistence}/migrations/235-slack-compaction-watermark.ts +0 -0
- /package/src/{memory → persistence}/migrations/237-heartbeat-runs.ts +0 -0
- /package/src/{memory → persistence}/migrations/238-schedule-retry-policy.ts +0 -0
- /package/src/{memory → persistence}/migrations/239-trace-events-created-at-index.ts +0 -0
- /package/src/{memory → persistence}/migrations/240-conversation-inference-profile-session.ts +0 -0
- /package/src/{memory → persistence}/migrations/241-activation-state-fk-cascade.ts +0 -0
- /package/src/{memory → persistence}/migrations/242-message-bookmarks.ts +0 -0
- /package/src/{memory → persistence}/migrations/245-memory-retrospective-state.ts +0 -0
- /package/src/{memory → persistence}/migrations/247-external-conversation-binding-thread-id.ts +0 -0
- /package/src/{memory → persistence}/migrations/248-create-onboarding-events.ts +0 -0
- /package/src/{memory → persistence}/migrations/249-normalize-slack-external-content.ts +0 -0
- /package/src/{memory → persistence}/migrations/250-provider-connection-base-url-and-models.ts +0 -0
- /package/src/{memory → persistence}/migrations/251-a2a-tasks.ts +0 -0
- /package/src/{memory → persistence}/migrations/252-llm-request-log-agent-loop-exit-reason.ts +0 -0
- /package/src/{memory → persistence}/migrations/253-conversation-last-notified-profile.ts +0 -0
- /package/src/{memory → persistence}/migrations/253-document-comments.ts +0 -0
- /package/src/{memory → persistence}/migrations/254-external-conversation-binding-chat-name.ts +0 -0
- /package/src/{memory → persistence}/migrations/256-memory-v2-injection-events.ts +0 -0
- /package/src/{memory → persistence}/migrations/257-strip-base-url-non-openai-compatible.ts +0 -0
- /package/src/{memory → persistence}/migrations/258-onboarding-events-prior-assistants.ts +0 -0
- /package/src/{memory → persistence}/migrations/259-conversation-cleaned-at.ts +0 -0
- /package/src/{memory → persistence}/migrations/260-rename-cleaned-at.ts +0 -0
- /package/src/{memory → persistence}/migrations/261-llm-usage-add-raw-usage.ts +0 -0
- /package/src/{memory → persistence}/migrations/262-memory-v3-coactivation.ts +0 -0
- /package/src/{memory → persistence}/migrations/263-memory-v3-auto-edges.ts +0 -0
- /package/src/{memory → persistence}/migrations/264-llm-request-log-call-site.ts +0 -0
- /package/src/{memory → persistence}/migrations/265-drop-provider-connection-status.ts +0 -0
- /package/src/{memory → persistence}/migrations/266-messages-client-message-id.ts +0 -0
- /package/src/{memory → persistence}/migrations/267-llm-usage-events-add-assistant-version.ts +0 -0
- /package/src/{memory → persistence}/migrations/268-add-memory-v3-selections.ts +0 -0
- /package/src/{memory → persistence}/migrations/269-schedule-script-timeout.ts +0 -0
- /package/src/{memory → persistence}/migrations/270-messages-role-created-at-index.ts +0 -0
- /package/src/{memory → persistence}/migrations/270-schedule-description.ts +0 -0
- /package/src/{memory → persistence}/migrations/270-schedule-source-conversation.ts +0 -0
- /package/src/{memory → persistence}/migrations/271-create-auth-fallback-events.ts +0 -0
- /package/src/{memory → persistence}/migrations/272-acp-session-history-cwd.ts +0 -0
- /package/src/{memory → persistence}/migrations/273-onboarding-events-funnel-columns.ts +0 -0
- /package/src/{memory → persistence}/migrations/274-create-activation-sessions.ts +0 -0
- /package/src/{memory → persistence}/migrations/275-tool-invocations-add-skill-id.test.ts +0 -0
- /package/src/{memory → persistence}/migrations/275-tool-invocations-add-skill-id.ts +0 -0
- /package/src/{memory → persistence}/migrations/276-tool-invocations-created-at-id-index.test.ts +0 -0
- /package/src/{memory → persistence}/migrations/276-tool-invocations-created-at-id-index.ts +0 -0
- /package/src/{memory → persistence}/migrations/277-add-memory-v3-ever-injected.ts +0 -0
- /package/src/{memory → persistence}/migrations/278-tool-invocations-telemetry-columns.test.ts +0 -0
- /package/src/{memory → persistence}/migrations/278-tool-invocations-telemetry-columns.ts +0 -0
- /package/src/{memory → persistence}/migrations/279-create-skill-loaded-events.test.ts +0 -0
- /package/src/{memory → persistence}/migrations/279-create-skill-loaded-events.ts +0 -0
- /package/src/{memory → persistence}/migrations/280-conversations-surfaced-at.test.ts +0 -0
- /package/src/{memory → persistence}/migrations/280-conversations-surfaced-at.ts +0 -0
- /package/src/{memory → persistence}/migrations/281-memory-retrospective-remembered-log.ts +0 -0
- /package/src/{memory → persistence}/migrations/282-schedule-inference-profile.test.ts +0 -0
- /package/src/{memory → persistence}/migrations/282-schedule-inference-profile.ts +0 -0
- /package/src/{memory → persistence}/migrations/283-memory-v3-selections-message-id-and-sections.test.ts +0 -0
- /package/src/{memory → persistence}/migrations/283-memory-v3-selections-message-id-and-sections.ts +0 -0
- /package/src/{memory → persistence}/migrations/284-workflow-runs.ts +0 -0
- /package/src/{memory → persistence}/migrations/285-schedule-workflow-mode.ts +0 -0
- /package/src/{memory → persistence}/migrations/286-workflow-run-trust.ts +0 -0
- /package/src/{memory → persistence}/migrations/287-conversation-origin-channel-index.ts +0 -0
- /package/src/{memory → persistence}/migrations/288-backfill-origin-channel-from-bindings.ts +0 -0
- /package/src/{memory → persistence}/migrations/289-contact-channels-unique-ext-user.ts +0 -0
- /package/src/{memory → persistence}/migrations/290-schedule-capabilities.test.ts +0 -0
- /package/src/{memory → persistence}/migrations/290-schedule-capabilities.ts +0 -0
- /package/src/{memory → persistence}/migrations/291-contact-channels-renormalize-addresses.ts +0 -0
- /package/src/{memory → persistence}/migrations/292-schedule-default-no-reuse-conversation.test.ts +0 -0
- /package/src/{memory → persistence}/migrations/292-schedule-default-no-reuse-conversation.ts +0 -0
- /package/src/{memory → persistence}/migrations/293-workflow-journal-leaf-tokens.ts +0 -0
- /package/src/{memory → persistence}/migrations/294-drop-external-user-id.ts +0 -0
- /package/src/{memory → persistence}/migrations/295-drop-approval-prompt-ts-tracker.ts +0 -0
- /package/src/{memory → persistence}/migrations/296-rewrite-balanced-economy-profile-pins.test.ts +0 -0
- /package/src/{memory → persistence}/migrations/296-rewrite-balanced-economy-profile-pins.ts +0 -0
- /package/src/{memory → persistence}/migrations/297-move-llm-request-logs-to-logs-db.ts +0 -0
- /package/src/{memory → persistence}/migrations/298-move-memory-jobs-to-memory-db.ts +0 -0
- /package/src/{memory → persistence}/migrations/299-canonical-guardian-deliveries-conversation-index.ts +0 -0
- /package/src/{memory → persistence}/migrations/300-add-processing-started-at.ts +0 -0
- /package/src/{memory → persistence}/migrations/302-create-compaction-events.ts +0 -0
- /package/src/{memory → persistence}/migrations/303-add-conversation-creation-seq.ts +0 -0
- /package/src/{memory → persistence}/migrations/__tests__/014-backfill-inbox-thread-state.test.ts +0 -0
- /package/src/{memory → persistence}/migrations/__tests__/131-drop-legacy-member-guardian-tables.test.ts +0 -0
- /package/src/{memory → persistence}/migrations/__tests__/136-drop-assistant-id-columns.test.ts +0 -0
- /package/src/{memory → persistence}/migrations/__tests__/234-memory-v2-activation-logs.test.ts +0 -0
- /package/src/{memory → persistence}/migrations/__tests__/245-memory-retrospective-state.test.ts +0 -0
- /package/src/{memory → persistence}/migrations/__tests__/267-llm-usage-events-add-assistant-version.test.ts +0 -0
- /package/src/{memory → persistence}/migrations/__tests__/281-memory-retrospective-remembered-log.test.ts +0 -0
- /package/src/{memory → persistence}/migrations/__tests__/289-contact-channels-unique-ext-user.test.ts +0 -0
- /package/src/{memory → persistence}/migrations/__tests__/291-contact-channels-renormalize-addresses.test.ts +0 -0
- /package/src/{memory → persistence}/migrations/__tests__/297-move-llm-request-logs.test.ts +0 -0
- /package/src/{memory → persistence}/migrations/run-migrations.ts +0 -0
- /package/src/{memory → persistence}/migrations/schema-introspection.ts +0 -0
- /package/src/{memory → persistence}/raw-query.ts +0 -0
- /package/src/{memory → persistence}/schema/a2a.ts +0 -0
- /package/src/{memory → persistence}/schema/bookmarks.ts +0 -0
- /package/src/{memory → persistence}/schema/calls.ts +0 -0
- /package/src/{memory → persistence}/schema/guardian.ts +0 -0
- /package/src/{memory → persistence}/schema/index.ts +0 -0
- /package/src/{memory → persistence}/schema/inference.ts +0 -0
- /package/src/{memory → persistence}/schema/memory-core.ts +0 -0
- /package/src/{memory → persistence}/schema/memory-graph.ts +0 -0
- /package/src/{memory → persistence}/schema/notifications.ts +0 -0
- /package/src/{memory → persistence}/schema/oauth.ts +0 -0
- /package/src/{memory → persistence}/schema/tasks.ts +0 -0
- /package/src/{memory → persistence}/schema.ts +0 -0
- /package/src/{memory → persistence}/usage-buckets.ts +0 -0
- /package/src/{memory → persistence}/usage-grouped-buckets.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/__tests__/fixtures/memory-v2-activation-fixtures.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/__tests__/memory-retrospective-trigger-check.test.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/anisotropy.test.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/context-search/__tests__/agent-runner-redaction.test.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/context-search/format.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/context-search/limits.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/context-search/sources/workspace.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/graph/decay.test.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/graph/extraction.test.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/graph/injection.test.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/graph/scoring.test.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/graph/scoring.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/graph/serendipity.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/graph/triggers.test.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/graph/triggers.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/graph/types.ts +0 -0
- /package/src/plugins/defaults/{memory-retrieval → memory}/hooks/__tests__/user-prompt-submit.test.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/memory-marker.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/prompt-override.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/retrieval-budget.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +0 -0
- /package/src/{memory → plugins/defaults/memory}/v2/__tests__/concept-page-frontmatter-schema.test.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/v2/__tests__/edge-index.test.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/v2/__tests__/harness-metrics.test.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/v2/__tests__/injected-block-slugs.test.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/v2/__tests__/page-store.test.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/v2/__tests__/prompts-router.test.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/v2/cli-command-content.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/v2/constants.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/v2/edge-index.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/v2/harness/metrics.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/v2/harness/runner.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/v2/harness/trace.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/v2/now-text.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/v2/prompts/sweep.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/v2/types.ts +0 -0
- /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/__tests__/capabilities.test.ts +0 -0
- /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/__tests__/card.test.ts +0 -0
- /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/__tests__/fresh-set.test.ts +0 -0
- /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/__tests__/section-needle.test.ts +0 -0
- /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/__tests__/sections.test.ts +0 -0
- /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/__tests__/types.test.ts +0 -0
- /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/card.test.ts +0 -0
- /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/core-set.test.ts +0 -0
- /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/core-set.ts +0 -0
- /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/data/README.md +0 -0
- /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/data/assignments.json +0 -0
- /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/data/core.json +0 -0
- /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/data/leaves/domain-a/topic-x.md +0 -0
- /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/data/leaves/domain-a/topic-y.md +0 -0
- /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/data/leaves/domain-b/topic-z.md +0 -0
- /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/fresh-set.ts +0 -0
- /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/llm-retry.ts +0 -0
- /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/sections.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/v3-eval/__tests__/eval-packets.test.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/v3-eval/__tests__/eval-tally.test.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/v3-eval/eval-tally.ts +0 -0
- /package/src/{memory → plugins/defaults/memory}/validation.ts +0 -0
- /package/src/plugins/defaults/{memory-retrieval → turn-context}/unified-turn-context.ts +0 -0
|
@@ -1,2301 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for `assistant/src/memory/v2/injection.ts`.
|
|
3
|
-
*
|
|
4
|
-
* Coverage matrix:
|
|
5
|
-
* - Empty state seeds the first injection (initial conversation turn).
|
|
6
|
-
* - Second turn whose `topNow` overlaps prior `everInjected` returns
|
|
7
|
-
* `toInject = []` and `block = null` (cache-stable empty path).
|
|
8
|
-
* - A new topic appearing on a later turn injects only the new slug.
|
|
9
|
-
* - `evictCompactedTurns` re-enables a previously-injected slug —
|
|
10
|
-
* after eviction the same slug appears again in `toInject`.
|
|
11
|
-
* - Unified-pool skills: a `skills/<id>` slug ranked into the top-K is
|
|
12
|
-
* rendered under `### Skills You Can Use`, mixed concept-page+skill
|
|
13
|
-
* blocks render concept sections first then the skills suffix, both
|
|
14
|
-
* empty → null block, skills participate in `everInjected` so they
|
|
15
|
-
* deduplicate across turns just like concepts.
|
|
16
|
-
*
|
|
17
|
-
* Hermetic by design: the embedding backend, qdrant client, and `getConfig`
|
|
18
|
-
* are mocked at the module level so the suite never reaches a real backend.
|
|
19
|
-
* The skill-store cache (`getSkillCapability`, `isSkillSlug`) is mocked so
|
|
20
|
-
* each test can stage skill content without touching the real catalog.
|
|
21
|
-
* The activation-store uses an in-memory SQLite database so writes are
|
|
22
|
-
* real but contained.
|
|
23
|
-
*
|
|
24
|
-
* Tests use a temp workspace (mkdtemp) and never touch `~/.vellum/`. Sample
|
|
25
|
-
* page content uses generic placeholders (Alice, Bob, etc.) per the cross-
|
|
26
|
-
* cutting safety rules.
|
|
27
|
-
*/
|
|
28
|
-
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
29
|
-
import { tmpdir } from "node:os";
|
|
30
|
-
import { join } from "node:path";
|
|
31
|
-
import { Database } from "bun:sqlite";
|
|
32
|
-
import {
|
|
33
|
-
afterAll,
|
|
34
|
-
afterEach,
|
|
35
|
-
beforeAll,
|
|
36
|
-
beforeEach,
|
|
37
|
-
describe,
|
|
38
|
-
expect,
|
|
39
|
-
mock,
|
|
40
|
-
test,
|
|
41
|
-
} from "bun:test";
|
|
42
|
-
|
|
43
|
-
import { drizzle } from "drizzle-orm/bun-sqlite";
|
|
44
|
-
import { z } from "zod";
|
|
45
|
-
|
|
46
|
-
import { makeMockLogger } from "../../../__tests__/helpers/mock-logger.js";
|
|
47
|
-
import type { AssistantConfig } from "../../../config/types.js";
|
|
48
|
-
|
|
49
|
-
// ---------------------------------------------------------------------------
|
|
50
|
-
// Module-level mocks
|
|
51
|
-
// ---------------------------------------------------------------------------
|
|
52
|
-
|
|
53
|
-
mock.module("../../../util/logger.js", () => ({
|
|
54
|
-
getLogger: () => makeMockLogger(),
|
|
55
|
-
}));
|
|
56
|
-
|
|
57
|
-
const STUB_QDRANT_CONFIG = {
|
|
58
|
-
memory: {
|
|
59
|
-
qdrant: {
|
|
60
|
-
url: "http://127.0.0.1:6333",
|
|
61
|
-
vectorSize: 384,
|
|
62
|
-
onDisk: true,
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
};
|
|
66
|
-
mock.module("../../../config/loader.js", () => ({
|
|
67
|
-
getConfig: () => STUB_QDRANT_CONFIG,
|
|
68
|
-
loadConfig: () => STUB_QDRANT_CONFIG,
|
|
69
|
-
}));
|
|
70
|
-
|
|
71
|
-
const realQdrantClient = await import("../../qdrant-client.js");
|
|
72
|
-
mock.module("../../qdrant-client.js", () => ({
|
|
73
|
-
...realQdrantClient,
|
|
74
|
-
resolveQdrantUrl: () => "http://127.0.0.1:6333",
|
|
75
|
-
}));
|
|
76
|
-
|
|
77
|
-
// Programmable embedding + Qdrant state — drives `selectCandidates`,
|
|
78
|
-
// `simBatch`, and friends without a live backend.
|
|
79
|
-
const state = {
|
|
80
|
-
embedReturn: [[0.1, 0.2, 0.3]] as number[][],
|
|
81
|
-
sparseReturn: { indices: [1, 2, 3], values: [0.5, 0.5, 0.5] },
|
|
82
|
-
queryResponses: {
|
|
83
|
-
dense: [] as Array<{
|
|
84
|
-
points: Array<{ score?: number; payload: Record<string, unknown> }>;
|
|
85
|
-
}>,
|
|
86
|
-
sparse: [] as Array<{
|
|
87
|
-
points: Array<{ score?: number; payload: Record<string, unknown> }>;
|
|
88
|
-
}>,
|
|
89
|
-
},
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const realEmbeddingBackend = await import("../../embedding-backend.js");
|
|
93
|
-
mock.module("../../embedding-backend.js", () => ({
|
|
94
|
-
...realEmbeddingBackend,
|
|
95
|
-
embedWithBackend: async () => ({
|
|
96
|
-
provider: "local",
|
|
97
|
-
model: "test-model",
|
|
98
|
-
vectors: state.embedReturn,
|
|
99
|
-
}),
|
|
100
|
-
generateSparseEmbedding: () => state.sparseReturn,
|
|
101
|
-
}));
|
|
102
|
-
|
|
103
|
-
class MockQdrantClient {
|
|
104
|
-
constructor(_opts: unknown) {}
|
|
105
|
-
async collectionExists(_name: string) {
|
|
106
|
-
return { exists: true };
|
|
107
|
-
}
|
|
108
|
-
async createCollection() {
|
|
109
|
-
return {};
|
|
110
|
-
}
|
|
111
|
-
async createPayloadIndex() {
|
|
112
|
-
return {};
|
|
113
|
-
}
|
|
114
|
-
async query(
|
|
115
|
-
_name: string,
|
|
116
|
-
params: { using: string; limit: number; filter?: unknown },
|
|
117
|
-
) {
|
|
118
|
-
// The four-channel hybrid query fires body-dense, body-sparse,
|
|
119
|
-
// summary-dense, summary-sparse in order; both dense channels share
|
|
120
|
-
// the dense queue and both sparse channels share the sparse queue.
|
|
121
|
-
const channel = params.using.endsWith("sparse") ? "sparse" : "dense";
|
|
122
|
-
return state.queryResponses[channel].shift() ?? { points: [] };
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
mock.module("@qdrant/js-client-rest", () => ({
|
|
127
|
-
QdrantClient: MockQdrantClient,
|
|
128
|
-
}));
|
|
129
|
-
|
|
130
|
-
// ---------------------------------------------------------------------------
|
|
131
|
-
// Skill-store mock
|
|
132
|
-
// ---------------------------------------------------------------------------
|
|
133
|
-
//
|
|
134
|
-
// Skills now flow through the unified pipeline under the `skills/<id>` slug
|
|
135
|
-
// prefix — they are scored by `simBatch` against the same Qdrant collection
|
|
136
|
-
// as concept pages, ranked by `selectInjections`, and rendered alongside
|
|
137
|
-
// concept sections. The render path branches on `isSkillSlug(slug)` to fetch
|
|
138
|
-
// content from the in-process cache via `getSkillCapability` instead of
|
|
139
|
-
// reading a page from disk. Tests stage that cache and rely on the regular
|
|
140
|
-
// `stageTurn` plumbing to land skill slugs in the candidate set.
|
|
141
|
-
|
|
142
|
-
const skillState = {
|
|
143
|
-
/** id → SkillEntry consulted by `getSkillCapability`. */
|
|
144
|
-
entries: new Map<string, SkillEntry>(),
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
mock.module("../skill-store.js", () => ({
|
|
148
|
-
getSkillCapability: (idOrSlug: string) => {
|
|
149
|
-
const id = idOrSlug.startsWith("skills/")
|
|
150
|
-
? idOrSlug.slice("skills/".length)
|
|
151
|
-
: idOrSlug;
|
|
152
|
-
return skillState.entries.get(id) ?? null;
|
|
153
|
-
},
|
|
154
|
-
isSkillSlug: (slug: string) => slug.startsWith("skills/"),
|
|
155
|
-
SKILL_SLUG_PREFIX: "skills/",
|
|
156
|
-
skillSlugFor: (id: string) => `skills/${id}`,
|
|
157
|
-
// PR 4 added `listSkillEntries`; `page-index.ts` (transitively imported
|
|
158
|
-
// via `page-store.ts` and `skill-store.ts`) consumes it at module-init
|
|
159
|
-
// time. Tests stage skill content via `skillState.entries`; expose them
|
|
160
|
-
// here so the page-index loader sees a consistent view.
|
|
161
|
-
listSkillEntries: () => Array.from(skillState.entries.values()),
|
|
162
|
-
}));
|
|
163
|
-
|
|
164
|
-
// ---------------------------------------------------------------------------
|
|
165
|
-
// CLI-command-store mock
|
|
166
|
-
// ---------------------------------------------------------------------------
|
|
167
|
-
//
|
|
168
|
-
// Mirrors the skill-store mock. CLI subcommand synthetic entries flow through
|
|
169
|
-
// the unified pipeline under the `cli-commands/<name>` slug prefix and render
|
|
170
|
-
// under `### CLI Commands You Can Use`. Tests stage `cliCommandState.entries`
|
|
171
|
-
// and rely on `stageTurn` plumbing to land slugs in the candidate set.
|
|
172
|
-
|
|
173
|
-
interface CliCommandEntryStub {
|
|
174
|
-
id: string;
|
|
175
|
-
description: string;
|
|
176
|
-
content: string;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const cliCommandState = {
|
|
180
|
-
entries: new Map<string, CliCommandEntryStub>(),
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
mock.module("../cli-command-store.js", () => ({
|
|
184
|
-
getCliCommandCapability: (idOrSlug: string) => {
|
|
185
|
-
const id = idOrSlug.startsWith("cli-commands/")
|
|
186
|
-
? idOrSlug.slice("cli-commands/".length)
|
|
187
|
-
: idOrSlug;
|
|
188
|
-
return cliCommandState.entries.get(id) ?? null;
|
|
189
|
-
},
|
|
190
|
-
isCliCommandSlug: (slug: string) => slug.startsWith("cli-commands/"),
|
|
191
|
-
CLI_COMMAND_SLUG_PREFIX: "cli-commands/",
|
|
192
|
-
cliCommandSlugFor: (name: string) => `cli-commands/${name}`,
|
|
193
|
-
listCliCommandEntries: () => Array.from(cliCommandState.entries.values()),
|
|
194
|
-
}));
|
|
195
|
-
|
|
196
|
-
// ---------------------------------------------------------------------------
|
|
197
|
-
// Activation-log store mock
|
|
198
|
-
// ---------------------------------------------------------------------------
|
|
199
|
-
//
|
|
200
|
-
// The real `recordMemoryV2ActivationLog` writes to the singleton
|
|
201
|
-
// `getDb()` — but this test uses an isolated in-memory database, so we mock
|
|
202
|
-
// the writer to capture calls in-process. `recordCalls` is the captured log
|
|
203
|
-
// array; `recordShouldThrow` makes the next call throw to verify the caller
|
|
204
|
-
// swallows the failure.
|
|
205
|
-
|
|
206
|
-
const telemetryState = {
|
|
207
|
-
recordCalls: [] as Array<Record<string, unknown>>,
|
|
208
|
-
recordShouldThrow: false,
|
|
209
|
-
};
|
|
210
|
-
|
|
211
|
-
mock.module("../../memory-v2-activation-log-store.js", () => ({
|
|
212
|
-
recordMemoryV2ActivationLog: (params: Record<string, unknown>) => {
|
|
213
|
-
if (telemetryState.recordShouldThrow) {
|
|
214
|
-
throw new Error("simulated telemetry write failure");
|
|
215
|
-
}
|
|
216
|
-
telemetryState.recordCalls.push(params);
|
|
217
|
-
},
|
|
218
|
-
}));
|
|
219
|
-
|
|
220
|
-
// ---------------------------------------------------------------------------
|
|
221
|
-
// Page-store mock — pass-through with optional per-slug failure injection
|
|
222
|
-
// ---------------------------------------------------------------------------
|
|
223
|
-
//
|
|
224
|
-
// Most tests want the real `readPage` (it walks the temp workspace seeded in
|
|
225
|
-
// `beforeAll`). The error-isolation tests stage a slug whose `readPage` call
|
|
226
|
-
// must throw — typically a Zod validation error mimicking the real-world
|
|
227
|
-
// "unrecognized frontmatter key" failure that motivated this work. Tests
|
|
228
|
-
// stage entries via `pageStoreState.failingSlugs` and reset in `resetState`.
|
|
229
|
-
//
|
|
230
|
-
// Bun's `mock.module` mutates the module's exports object in place, so
|
|
231
|
-
// `realPageStore.readPage` AFTER the mock applies would resolve to the mock
|
|
232
|
-
// itself — calling it would recurse. We capture the original function value
|
|
233
|
-
// (not a property lookup) before installing the mock so the pass-through
|
|
234
|
-
// path has a real reference to the underlying implementation.
|
|
235
|
-
|
|
236
|
-
const realPageStoreModule = await import("../page-store.js");
|
|
237
|
-
const realReadPage = realPageStoreModule.readPage;
|
|
238
|
-
const pageStoreState = {
|
|
239
|
-
failingSlugs: new Map<string, Error>(),
|
|
240
|
-
};
|
|
241
|
-
mock.module("../page-store.js", () => ({
|
|
242
|
-
...realPageStoreModule,
|
|
243
|
-
readPage: async (workspaceDir: string, slug: string) => {
|
|
244
|
-
const err = pageStoreState.failingSlugs.get(slug);
|
|
245
|
-
if (err) throw err;
|
|
246
|
-
return realReadPage(workspaceDir, slug);
|
|
247
|
-
},
|
|
248
|
-
}));
|
|
249
|
-
|
|
250
|
-
// ---------------------------------------------------------------------------
|
|
251
|
-
// Router mock — programmable per-call result
|
|
252
|
-
// ---------------------------------------------------------------------------
|
|
253
|
-
//
|
|
254
|
-
// PR 10 wires `runRouter` into `injectMemoryV2Block` behind the
|
|
255
|
-
// `memory.v2.router.enabled` flag. The activation-mode tests above never
|
|
256
|
-
// flip the flag, so the default mock returns a no-op result and the router
|
|
257
|
-
// branch is never exercised. Router-mode tests set `routerState.nextResult`
|
|
258
|
-
// to stage a deterministic outcome before each call.
|
|
259
|
-
|
|
260
|
-
interface RouterResultStub {
|
|
261
|
-
selectedSlugs: string[];
|
|
262
|
-
failureReason: string | null;
|
|
263
|
-
/** Tier provenance per slug. Defaults to `tier3:0` for any selected slug. */
|
|
264
|
-
sourceBySlug?: Map<string, string>;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
const routerState = {
|
|
268
|
-
nextResult: null as RouterResultStub | null,
|
|
269
|
-
callCount: 0,
|
|
270
|
-
};
|
|
271
|
-
|
|
272
|
-
mock.module("../router.js", () => ({
|
|
273
|
-
runRouter: async () => {
|
|
274
|
-
routerState.callCount++;
|
|
275
|
-
const result = routerState.nextResult ?? {
|
|
276
|
-
selectedSlugs: [],
|
|
277
|
-
failureReason: null,
|
|
278
|
-
};
|
|
279
|
-
// Synthesize a default sourceBySlug for stubs that don't set one — pre-
|
|
280
|
-
// tier-provenance tests stage `selectedSlugs` only and expect every pick
|
|
281
|
-
// to flow through as a router selection. Treating them as `tier3:0` is
|
|
282
|
-
// the closest equivalent under the new model.
|
|
283
|
-
if (!result.sourceBySlug) {
|
|
284
|
-
const map = new Map<string, string>();
|
|
285
|
-
for (const slug of result.selectedSlugs) map.set(slug, "tier3:0");
|
|
286
|
-
result.sourceBySlug = map;
|
|
287
|
-
}
|
|
288
|
-
return result;
|
|
289
|
-
},
|
|
290
|
-
}));
|
|
291
|
-
|
|
292
|
-
// ---------------------------------------------------------------------------
|
|
293
|
-
// Activation-store mock — pass-through with optional `save` failure injection
|
|
294
|
-
// ---------------------------------------------------------------------------
|
|
295
|
-
//
|
|
296
|
-
// One regression test forces `save` to throw to exercise the
|
|
297
|
-
// `injectMemoryV2Block` outer try/finally — telemetry must still be flushed
|
|
298
|
-
// (with `mode: "errored"`) and the error must propagate. Default behavior
|
|
299
|
-
// delegates to the real activation-store so the rest of the suite stays
|
|
300
|
-
// untouched. Same pre-mock function-capture trick as `readPage` above.
|
|
301
|
-
|
|
302
|
-
const realActivationStoreModule = await import("../activation-store.js");
|
|
303
|
-
const realSave = realActivationStoreModule.save;
|
|
304
|
-
const activationStoreState = {
|
|
305
|
-
saveShouldThrow: false,
|
|
306
|
-
};
|
|
307
|
-
mock.module("../activation-store.js", () => ({
|
|
308
|
-
...realActivationStoreModule,
|
|
309
|
-
save: async (...args: Parameters<typeof realSave>) => {
|
|
310
|
-
if (activationStoreState.saveShouldThrow) {
|
|
311
|
-
throw new Error("simulated activation-store save failure");
|
|
312
|
-
}
|
|
313
|
-
return realSave(...args);
|
|
314
|
-
},
|
|
315
|
-
}));
|
|
316
|
-
|
|
317
|
-
// ---------------------------------------------------------------------------
|
|
318
|
-
// Workspace + DB setup
|
|
319
|
-
// ---------------------------------------------------------------------------
|
|
320
|
-
|
|
321
|
-
let tmpWorkspace: string;
|
|
322
|
-
let previousWorkspaceEnv: string | undefined;
|
|
323
|
-
|
|
324
|
-
beforeAll(() => {
|
|
325
|
-
tmpWorkspace = mkdtempSync(join(tmpdir(), "memory-v2-injection-test-"));
|
|
326
|
-
previousWorkspaceEnv = process.env.VELLUM_WORKSPACE_DIR;
|
|
327
|
-
process.env.VELLUM_WORKSPACE_DIR = tmpWorkspace;
|
|
328
|
-
|
|
329
|
-
// Seed the v2 directory layout the migration would normally create.
|
|
330
|
-
mkdirSync(join(tmpWorkspace, "memory", "concepts"), { recursive: true });
|
|
331
|
-
// Three concept pages with generic, placeholder bodies. Outgoing edges
|
|
332
|
-
// live in each page's frontmatter `edges:` list — there is no separate
|
|
333
|
-
// edges-index file under the directed-edges model.
|
|
334
|
-
writeFileSync(
|
|
335
|
-
join(tmpWorkspace, "memory", "concepts", "alice-vscode.md"),
|
|
336
|
-
`---
|
|
337
|
-
edges: [bob-coffee]
|
|
338
|
-
ref_files: []
|
|
339
|
-
---
|
|
340
|
-
Alice prefers VS Code as her editor.`,
|
|
341
|
-
);
|
|
342
|
-
writeFileSync(
|
|
343
|
-
join(tmpWorkspace, "memory", "concepts", "bob-coffee.md"),
|
|
344
|
-
`---
|
|
345
|
-
edges: [alice-vscode]
|
|
346
|
-
ref_files: []
|
|
347
|
-
---
|
|
348
|
-
Bob takes his coffee black, no sugar.`,
|
|
349
|
-
);
|
|
350
|
-
writeFileSync(
|
|
351
|
-
join(tmpWorkspace, "memory", "concepts", "carol-jazz.md"),
|
|
352
|
-
`---
|
|
353
|
-
edges: []
|
|
354
|
-
ref_files: []
|
|
355
|
-
---
|
|
356
|
-
Carol loves jazz music — Coltrane in particular.`,
|
|
357
|
-
);
|
|
358
|
-
// A page with both `edges` and `ref_files` populated so the frontmatter-
|
|
359
|
-
// injection test can assert the full canonical shape.
|
|
360
|
-
writeFileSync(
|
|
361
|
-
join(tmpWorkspace, "memory", "concepts", "frontmatter-demo.md"),
|
|
362
|
-
`---
|
|
363
|
-
edges:
|
|
364
|
-
- alice-vscode
|
|
365
|
-
ref_files:
|
|
366
|
-
- images/demo.jpg
|
|
367
|
-
---
|
|
368
|
-
Demo body content.`,
|
|
369
|
-
);
|
|
370
|
-
// A page WITH a `summary` in its frontmatter — exercises the summary-only
|
|
371
|
-
// injection path. Body is intentionally longer than the summary so tests
|
|
372
|
-
// can assert that the body is *not* injected when the summary is present.
|
|
373
|
-
writeFileSync(
|
|
374
|
-
join(tmpWorkspace, "memory", "concepts", "summarized-page.md"),
|
|
375
|
-
`---
|
|
376
|
-
edges: []
|
|
377
|
-
ref_files: []
|
|
378
|
-
summary: A short prose description of the summarized page that retrieval injects in place of the full body.
|
|
379
|
-
---
|
|
380
|
-
Long-form body content that should NOT appear in the injection block when the page has a summary in frontmatter — the agent reads the file on demand instead.`,
|
|
381
|
-
);
|
|
382
|
-
});
|
|
383
|
-
|
|
384
|
-
afterAll(() => {
|
|
385
|
-
if (previousWorkspaceEnv === undefined) {
|
|
386
|
-
delete process.env.VELLUM_WORKSPACE_DIR;
|
|
387
|
-
} else {
|
|
388
|
-
process.env.VELLUM_WORKSPACE_DIR = previousWorkspaceEnv;
|
|
389
|
-
}
|
|
390
|
-
rmSync(tmpWorkspace, { recursive: true, force: true });
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
// Static `import type` is fine — types erase, so they don't run module-init
|
|
394
|
-
// code that would race the mocks above.
|
|
395
|
-
import type { DrizzleDb } from "../../db-connection.js";
|
|
396
|
-
import type { SkillEntry } from "../types.js";
|
|
397
|
-
|
|
398
|
-
const { getSqliteFrom } = await import("../../db-connection.js");
|
|
399
|
-
const { migrateActivationState } =
|
|
400
|
-
await import("../../migrations/232-activation-state.js");
|
|
401
|
-
const { migrateMemoryV2InjectionEvents } =
|
|
402
|
-
await import("../../migrations/256-memory-v2-injection-events.js");
|
|
403
|
-
const schema = await import("../../schema.js");
|
|
404
|
-
const { clearEverInjected, hydrate, save } =
|
|
405
|
-
await import("../activation-store.js");
|
|
406
|
-
const { injectMemoryV2Block } = await import("../injection.js");
|
|
407
|
-
const { _resetMemoryV2QdrantForTests } = await import("../qdrant.js");
|
|
408
|
-
|
|
409
|
-
function createTestDb(): DrizzleDb {
|
|
410
|
-
const sqlite = new Database(":memory:");
|
|
411
|
-
sqlite.exec("PRAGMA journal_mode=WAL");
|
|
412
|
-
sqlite.exec("PRAGMA foreign_keys = ON");
|
|
413
|
-
const db = drizzle(sqlite, { schema });
|
|
414
|
-
|
|
415
|
-
// Migration uses the checkpoints table for crash recovery — bootstrap it.
|
|
416
|
-
getSqliteFrom(db).exec(/*sql*/ `
|
|
417
|
-
CREATE TABLE IF NOT EXISTS memory_checkpoints (
|
|
418
|
-
key TEXT PRIMARY KEY,
|
|
419
|
-
value TEXT NOT NULL,
|
|
420
|
-
updated_at INTEGER NOT NULL
|
|
421
|
-
)
|
|
422
|
-
`);
|
|
423
|
-
migrateActivationState(db);
|
|
424
|
-
migrateMemoryV2InjectionEvents(db);
|
|
425
|
-
return db;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
function makeConfig(
|
|
429
|
-
overrides: Partial<{
|
|
430
|
-
d: number;
|
|
431
|
-
c_user: number;
|
|
432
|
-
c_assistant: number;
|
|
433
|
-
c_now: number;
|
|
434
|
-
k: number;
|
|
435
|
-
hops: number;
|
|
436
|
-
top_k: number;
|
|
437
|
-
epsilon: number;
|
|
438
|
-
dense_weight: number;
|
|
439
|
-
sparse_weight: number;
|
|
440
|
-
router: { enabled: boolean; max_page_ids?: number };
|
|
441
|
-
}> = {},
|
|
442
|
-
): AssistantConfig {
|
|
443
|
-
const { router, ...rest } = overrides;
|
|
444
|
-
return {
|
|
445
|
-
memory: {
|
|
446
|
-
v2: {
|
|
447
|
-
d: 0.3,
|
|
448
|
-
c_user: 0.3,
|
|
449
|
-
c_assistant: 0.2,
|
|
450
|
-
c_now: 0.2,
|
|
451
|
-
k: 0.5,
|
|
452
|
-
hops: 2,
|
|
453
|
-
top_k: 25,
|
|
454
|
-
epsilon: 0.01,
|
|
455
|
-
dense_weight: 1.0,
|
|
456
|
-
sparse_weight: 0.0,
|
|
457
|
-
router: { enabled: false, max_page_ids: 25, ...(router ?? {}) },
|
|
458
|
-
...rest,
|
|
459
|
-
},
|
|
460
|
-
},
|
|
461
|
-
} as unknown as AssistantConfig;
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
/**
|
|
465
|
-
* Stage one set of dense/sparse hits, used uniformly by every `simBatch`
|
|
466
|
-
* channel call (user/assistant/now) AND by the un-restricted ANN candidate
|
|
467
|
-
* query. The candidate query runs first, then three simBatch calls — that's
|
|
468
|
-
* `channels` (= 4) logical hybrid queries. Each logical hybrid query now
|
|
469
|
-
* fires a four-channel fan-out (body dense, body sparse, summary dense,
|
|
470
|
-
* summary sparse), so we push 2 dense + 2 sparse responses per logical
|
|
471
|
-
* call to match the post-summary-vector wire pattern.
|
|
472
|
-
*
|
|
473
|
-
* Each entry is mapped to a hit per channel; pass `denseScore`/`sparseScore`
|
|
474
|
-
* undefined to omit a slug from that channel. `summaryDenseScore` /
|
|
475
|
-
* `summarySparseScore` route to the summary-side channels — tests that
|
|
476
|
-
* don't care about summary scoring leave them undefined and the summary
|
|
477
|
-
* channel falls back to body-only behavior.
|
|
478
|
-
*/
|
|
479
|
-
function stageTurn(
|
|
480
|
-
hits: Array<{
|
|
481
|
-
slug: string;
|
|
482
|
-
denseScore?: number;
|
|
483
|
-
sparseScore?: number;
|
|
484
|
-
summaryDenseScore?: number;
|
|
485
|
-
summarySparseScore?: number;
|
|
486
|
-
}>,
|
|
487
|
-
channels = 4,
|
|
488
|
-
): void {
|
|
489
|
-
// Clear any leftovers from a prior turn before staging this one so unused
|
|
490
|
-
// staged responses can't bleed into the next injection. The activation
|
|
491
|
-
// pipeline now skips the embedding round-trip for empty texts (turn 1's
|
|
492
|
-
// assistantMessage), so consumed-channel counts vary per turn — staging
|
|
493
|
-
// exclusively is the only way multi-turn tests stay aligned.
|
|
494
|
-
state.queryResponses.dense.length = 0;
|
|
495
|
-
state.queryResponses.sparse.length = 0;
|
|
496
|
-
for (let i = 0; i < channels; i++) {
|
|
497
|
-
state.queryResponses.dense.push({
|
|
498
|
-
points: hits
|
|
499
|
-
.filter((h) => h.denseScore !== undefined)
|
|
500
|
-
.map((h) => ({ score: h.denseScore, payload: { slug: h.slug } })),
|
|
501
|
-
});
|
|
502
|
-
state.queryResponses.sparse.push({
|
|
503
|
-
points: hits
|
|
504
|
-
.filter((h) => h.sparseScore !== undefined)
|
|
505
|
-
.map((h) => ({ score: h.sparseScore, payload: { slug: h.slug } })),
|
|
506
|
-
});
|
|
507
|
-
state.queryResponses.dense.push({
|
|
508
|
-
points: hits
|
|
509
|
-
.filter((h) => h.summaryDenseScore !== undefined)
|
|
510
|
-
.map((h) => ({
|
|
511
|
-
score: h.summaryDenseScore,
|
|
512
|
-
payload: { slug: h.slug },
|
|
513
|
-
})),
|
|
514
|
-
});
|
|
515
|
-
state.queryResponses.sparse.push({
|
|
516
|
-
points: hits
|
|
517
|
-
.filter((h) => h.summarySparseScore !== undefined)
|
|
518
|
-
.map((h) => ({
|
|
519
|
-
score: h.summarySparseScore,
|
|
520
|
-
payload: { slug: h.slug },
|
|
521
|
-
})),
|
|
522
|
-
});
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
function resetState(): void {
|
|
527
|
-
state.embedReturn = [[0.1, 0.2, 0.3]];
|
|
528
|
-
state.sparseReturn = { indices: [1, 2, 3], values: [0.5, 0.5, 0.5] };
|
|
529
|
-
state.queryResponses.dense.length = 0;
|
|
530
|
-
state.queryResponses.sparse.length = 0;
|
|
531
|
-
skillState.entries.clear();
|
|
532
|
-
cliCommandState.entries.clear();
|
|
533
|
-
telemetryState.recordCalls.length = 0;
|
|
534
|
-
telemetryState.recordShouldThrow = false;
|
|
535
|
-
pageStoreState.failingSlugs.clear();
|
|
536
|
-
activationStoreState.saveShouldThrow = false;
|
|
537
|
-
routerState.nextResult = null;
|
|
538
|
-
routerState.callCount = 0;
|
|
539
|
-
// The qdrant module caches its client; the cached client may be a
|
|
540
|
-
// MockQdrantClient instance from a sibling test file. Reset to force a
|
|
541
|
-
// fresh `new QdrantClient()` against this file's mock.
|
|
542
|
-
_resetMemoryV2QdrantForTests();
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
/** Stage skill-store cache entries for the upcoming render. */
|
|
546
|
-
function stageSkills(entries: SkillEntry[]): void {
|
|
547
|
-
for (const entry of entries) {
|
|
548
|
-
skillState.entries.set(entry.id, entry);
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
/** Stage cli-command-store cache entries for the upcoming render. */
|
|
553
|
-
function stageCliCommands(entries: CliCommandEntryStub[]): void {
|
|
554
|
-
for (const entry of entries) {
|
|
555
|
-
cliCommandState.entries.set(entry.id, entry);
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
let db: DrizzleDb;
|
|
560
|
-
beforeEach(() => {
|
|
561
|
-
db = createTestDb();
|
|
562
|
-
resetState();
|
|
563
|
-
});
|
|
564
|
-
afterEach(resetState);
|
|
565
|
-
|
|
566
|
-
// ---------------------------------------------------------------------------
|
|
567
|
-
// Tests
|
|
568
|
-
// ---------------------------------------------------------------------------
|
|
569
|
-
|
|
570
|
-
describe("injectMemoryV2Block", () => {
|
|
571
|
-
test("seeds first injection from an empty state", async () => {
|
|
572
|
-
// First turn: no prior state. The ANN candidate call surfaces alice; the
|
|
573
|
-
// three simBatch channels score her highly enough to dominate top-K.
|
|
574
|
-
stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
|
|
575
|
-
|
|
576
|
-
const result = await injectMemoryV2Block({
|
|
577
|
-
database: db,
|
|
578
|
-
conversationId: "conv-1",
|
|
579
|
-
currentTurn: 1,
|
|
580
|
-
recentTurnPairs: [
|
|
581
|
-
{ assistantMessage: "", userMessage: "Tell me about Alice's editor" },
|
|
582
|
-
],
|
|
583
|
-
nowText: "Spring afternoon",
|
|
584
|
-
messageId: "msg-1",
|
|
585
|
-
config: makeConfig(),
|
|
586
|
-
});
|
|
587
|
-
|
|
588
|
-
expect(result.toInject).toEqual(["alice-vscode"]);
|
|
589
|
-
expect(result.block).not.toBeNull();
|
|
590
|
-
// `block` is the unwrapped inner content; the caller adds the
|
|
591
|
-
// `<memory>...</memory>` wrapper exactly once at injection time.
|
|
592
|
-
expect(result.block).not.toContain("<memory>");
|
|
593
|
-
expect(result.block).not.toContain("</memory>");
|
|
594
|
-
expect(result.block).not.toContain("## What I Remember Right Now");
|
|
595
|
-
expect(result.block).toContain("# memory/concepts/alice-vscode.md");
|
|
596
|
-
expect(result.block).toContain("VS Code");
|
|
597
|
-
|
|
598
|
-
// State persisted: alice's activation is above epsilon and recorded;
|
|
599
|
-
// everInjected captured the new slug + currentTurn.
|
|
600
|
-
const persisted = await hydrate(db, "conv-1");
|
|
601
|
-
expect(persisted).not.toBeNull();
|
|
602
|
-
expect(persisted!.everInjected).toEqual([
|
|
603
|
-
{ slug: "alice-vscode", turn: 1 },
|
|
604
|
-
]);
|
|
605
|
-
expect(persisted!.state["alice-vscode"]).toBeGreaterThan(0.01);
|
|
606
|
-
expect(persisted!.currentTurn).toBe(1);
|
|
607
|
-
expect(persisted!.messageId).toBe("msg-1");
|
|
608
|
-
});
|
|
609
|
-
|
|
610
|
-
test("second turn with overlapping topNow returns null block + empty toInject", async () => {
|
|
611
|
-
// Turn 1 — seed alice as injected.
|
|
612
|
-
stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
|
|
613
|
-
await injectMemoryV2Block({
|
|
614
|
-
database: db,
|
|
615
|
-
conversationId: "conv-1",
|
|
616
|
-
currentTurn: 1,
|
|
617
|
-
recentTurnPairs: [
|
|
618
|
-
{ assistantMessage: "", userMessage: "Alice's editor" },
|
|
619
|
-
],
|
|
620
|
-
nowText: "Now",
|
|
621
|
-
messageId: "msg-1",
|
|
622
|
-
config: makeConfig(),
|
|
623
|
-
});
|
|
624
|
-
|
|
625
|
-
// Turn 2 — the same slug is still top-of-mind. After subtracting
|
|
626
|
-
// everInjected, toInject is empty → block is null.
|
|
627
|
-
stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
|
|
628
|
-
const result = await injectMemoryV2Block({
|
|
629
|
-
database: db,
|
|
630
|
-
conversationId: "conv-1",
|
|
631
|
-
currentTurn: 2,
|
|
632
|
-
recentTurnPairs: [
|
|
633
|
-
{
|
|
634
|
-
assistantMessage: "Alice loves it.",
|
|
635
|
-
userMessage: "And what about VS Code?",
|
|
636
|
-
},
|
|
637
|
-
],
|
|
638
|
-
nowText: "Now",
|
|
639
|
-
messageId: "msg-2",
|
|
640
|
-
config: makeConfig(),
|
|
641
|
-
});
|
|
642
|
-
|
|
643
|
-
expect(result.toInject).toEqual([]);
|
|
644
|
-
expect(result.block).toBeNull();
|
|
645
|
-
|
|
646
|
-
// State still advanced (currentTurn moved forward) and the existing
|
|
647
|
-
// everInjected entry is preserved (no duplicate added).
|
|
648
|
-
const persisted = await hydrate(db, "conv-1");
|
|
649
|
-
expect(persisted!.currentTurn).toBe(2);
|
|
650
|
-
expect(persisted!.everInjected).toEqual([
|
|
651
|
-
{ slug: "alice-vscode", turn: 1 },
|
|
652
|
-
]);
|
|
653
|
-
expect(persisted!.messageId).toBe("msg-2");
|
|
654
|
-
});
|
|
655
|
-
|
|
656
|
-
test("new topic appears → only the new slug attaches", async () => {
|
|
657
|
-
// Turn 1 — seed alice.
|
|
658
|
-
stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
|
|
659
|
-
await injectMemoryV2Block({
|
|
660
|
-
database: db,
|
|
661
|
-
conversationId: "conv-1",
|
|
662
|
-
currentTurn: 1,
|
|
663
|
-
recentTurnPairs: [
|
|
664
|
-
{ assistantMessage: "", userMessage: "Editor preferences" },
|
|
665
|
-
],
|
|
666
|
-
nowText: "Now",
|
|
667
|
-
messageId: "msg-1",
|
|
668
|
-
config: makeConfig(),
|
|
669
|
-
});
|
|
670
|
-
|
|
671
|
-
// Turn 2 — carol is now in the candidate pool with high relevance.
|
|
672
|
-
// Both alice (carry-forward) and carol should appear in topNow, but only
|
|
673
|
-
// carol should be in toInject (alice was already attached on turn 1).
|
|
674
|
-
stageTurn([
|
|
675
|
-
{ slug: "alice-vscode", denseScore: 0.6 },
|
|
676
|
-
{ slug: "carol-jazz", denseScore: 0.95 },
|
|
677
|
-
]);
|
|
678
|
-
const result = await injectMemoryV2Block({
|
|
679
|
-
database: db,
|
|
680
|
-
conversationId: "conv-1",
|
|
681
|
-
currentTurn: 2,
|
|
682
|
-
recentTurnPairs: [
|
|
683
|
-
{
|
|
684
|
-
assistantMessage: "",
|
|
685
|
-
userMessage: "Tell me about Carol's music taste",
|
|
686
|
-
},
|
|
687
|
-
],
|
|
688
|
-
nowText: "Now",
|
|
689
|
-
messageId: "msg-2",
|
|
690
|
-
config: makeConfig(),
|
|
691
|
-
});
|
|
692
|
-
|
|
693
|
-
expect(result.toInject).toEqual(["carol-jazz"]);
|
|
694
|
-
expect(result.block).toContain("# memory/concepts/carol-jazz.md");
|
|
695
|
-
// The block only shows the new slug — alice's attachment lives on the
|
|
696
|
-
// previous turn's user message.
|
|
697
|
-
expect(result.block).not.toContain("# memory/concepts/alice-vscode.md");
|
|
698
|
-
|
|
699
|
-
const persisted = await hydrate(db, "conv-1");
|
|
700
|
-
expect(persisted!.everInjected).toEqual([
|
|
701
|
-
{ slug: "alice-vscode", turn: 1 },
|
|
702
|
-
{ slug: "carol-jazz", turn: 2 },
|
|
703
|
-
]);
|
|
704
|
-
});
|
|
705
|
-
|
|
706
|
-
test("compaction eviction makes a previously-injected slug eligible again", async () => {
|
|
707
|
-
// Turn 1 — seed alice.
|
|
708
|
-
stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
|
|
709
|
-
await injectMemoryV2Block({
|
|
710
|
-
database: db,
|
|
711
|
-
conversationId: "conv-1",
|
|
712
|
-
currentTurn: 1,
|
|
713
|
-
recentTurnPairs: [
|
|
714
|
-
{ assistantMessage: "", userMessage: "Alice's editor" },
|
|
715
|
-
],
|
|
716
|
-
nowText: "Now",
|
|
717
|
-
messageId: "msg-1",
|
|
718
|
-
config: makeConfig(),
|
|
719
|
-
});
|
|
720
|
-
|
|
721
|
-
// Simulate compaction: clear the entire everInjected list.
|
|
722
|
-
const beforeEvict = await hydrate(db, "conv-1");
|
|
723
|
-
expect(beforeEvict).not.toBeNull();
|
|
724
|
-
const afterEvict = clearEverInjected(beforeEvict!);
|
|
725
|
-
expect(afterEvict.everInjected).toEqual([]);
|
|
726
|
-
await save(db, "conv-1", afterEvict);
|
|
727
|
-
|
|
728
|
-
// Turn 2 — alice should now be re-injectable since eviction cleared the
|
|
729
|
-
// everInjected entry. Same simulated relevance as before.
|
|
730
|
-
stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
|
|
731
|
-
const result = await injectMemoryV2Block({
|
|
732
|
-
database: db,
|
|
733
|
-
conversationId: "conv-1",
|
|
734
|
-
currentTurn: 2,
|
|
735
|
-
recentTurnPairs: [
|
|
736
|
-
{ assistantMessage: "", userMessage: "Alice's editor again" },
|
|
737
|
-
],
|
|
738
|
-
nowText: "Now",
|
|
739
|
-
messageId: "msg-2",
|
|
740
|
-
config: makeConfig(),
|
|
741
|
-
});
|
|
742
|
-
|
|
743
|
-
expect(result.toInject).toEqual(["alice-vscode"]);
|
|
744
|
-
expect(result.block).toContain("# memory/concepts/alice-vscode.md");
|
|
745
|
-
|
|
746
|
-
const persisted = await hydrate(db, "conv-1");
|
|
747
|
-
expect(persisted!.everInjected).toEqual([
|
|
748
|
-
{ slug: "alice-vscode", turn: 2 },
|
|
749
|
-
]);
|
|
750
|
-
});
|
|
751
|
-
|
|
752
|
-
test("page with summary renders as path + summary, no body, with the CRITICAL header", async () => {
|
|
753
|
-
// Pages whose frontmatter carries a `summary` should inject only the
|
|
754
|
-
// summary text behind the path header — the agent reads the full file
|
|
755
|
-
// on demand. The leading `**CRITICAL:**` line tells the agent how to
|
|
756
|
-
// read the block.
|
|
757
|
-
stageTurn([{ slug: "summarized-page", denseScore: 0.9 }]);
|
|
758
|
-
|
|
759
|
-
const result = await injectMemoryV2Block({
|
|
760
|
-
database: db,
|
|
761
|
-
conversationId: "conv-1",
|
|
762
|
-
currentTurn: 1,
|
|
763
|
-
recentTurnPairs: [
|
|
764
|
-
{
|
|
765
|
-
assistantMessage: "",
|
|
766
|
-
userMessage: "tell me about the summarized page",
|
|
767
|
-
},
|
|
768
|
-
],
|
|
769
|
-
nowText: "Now",
|
|
770
|
-
messageId: "msg-1",
|
|
771
|
-
config: makeConfig(),
|
|
772
|
-
});
|
|
773
|
-
|
|
774
|
-
expect(result.block).not.toBeNull();
|
|
775
|
-
expect(result.block).toContain(
|
|
776
|
-
'Use `file_read("memory/concepts/path/to/file.md")` to read the full pages for any of the injected memory summaries you want more information on.',
|
|
777
|
-
);
|
|
778
|
-
expect(result.block).toContain(
|
|
779
|
-
"# memory/concepts/summarized-page.md\nA short prose description",
|
|
780
|
-
);
|
|
781
|
-
// Body is NOT in the block — the agent must follow up with a read tool.
|
|
782
|
-
expect(result.block).not.toContain("Long-form body content");
|
|
783
|
-
// Frontmatter is also omitted; the path header carries the identifying
|
|
784
|
-
// information by itself, and edges flow through the activation graph.
|
|
785
|
-
expect(result.block).not.toContain("---\nedges:");
|
|
786
|
-
});
|
|
787
|
-
|
|
788
|
-
test("mixed batch — summary page renders short, fallback page renders full", async () => {
|
|
789
|
-
// Both pages rank into top-K. summarized-page has a summary → short
|
|
790
|
-
// form. frontmatter-demo has no summary → full-page fallback. The
|
|
791
|
-
// single CRITICAL header sits at the top regardless.
|
|
792
|
-
stageTurn([
|
|
793
|
-
{ slug: "summarized-page", denseScore: 0.95 },
|
|
794
|
-
{ slug: "frontmatter-demo", denseScore: 0.85 },
|
|
795
|
-
]);
|
|
796
|
-
|
|
797
|
-
const result = await injectMemoryV2Block({
|
|
798
|
-
database: db,
|
|
799
|
-
conversationId: "conv-1",
|
|
800
|
-
currentTurn: 1,
|
|
801
|
-
recentTurnPairs: [
|
|
802
|
-
{ assistantMessage: "", userMessage: "show me everything" },
|
|
803
|
-
],
|
|
804
|
-
nowText: "Now",
|
|
805
|
-
messageId: "msg-1",
|
|
806
|
-
config: makeConfig(),
|
|
807
|
-
});
|
|
808
|
-
|
|
809
|
-
expect(result.block).not.toBeNull();
|
|
810
|
-
// Header appears exactly once.
|
|
811
|
-
const headerCount = (
|
|
812
|
-
result.block!.match(
|
|
813
|
-
/Use `file_read\("memory\/concepts\/path\/to\/file\.md"\)` to read/g,
|
|
814
|
-
) ?? []
|
|
815
|
-
).length;
|
|
816
|
-
expect(headerCount).toBe(1);
|
|
817
|
-
// summarized-page → short form (path + summary, no body, no frontmatter).
|
|
818
|
-
expect(result.block).toContain("# memory/concepts/summarized-page.md\nA");
|
|
819
|
-
expect(result.block).not.toContain("Long-form body content");
|
|
820
|
-
// frontmatter-demo → full-page fallback (path + frontmatter + body).
|
|
821
|
-
expect(result.block).toContain(
|
|
822
|
-
"# memory/concepts/frontmatter-demo.md\n---\n",
|
|
823
|
-
);
|
|
824
|
-
expect(result.block).toContain("Demo body content.");
|
|
825
|
-
});
|
|
826
|
-
|
|
827
|
-
test("includes the page frontmatter (edges, ref_files) in each rendered section", async () => {
|
|
828
|
-
// The frontmatter (`edges`, `ref_files`) lives on disk above the page
|
|
829
|
-
// body and is part of the page's content. Injection must reproduce both
|
|
830
|
-
// fields verbatim — bracketed by the canonical `---` delimiters — so the
|
|
831
|
-
// agent sees the page's edges and any referenced media paths alongside
|
|
832
|
-
// the prose body.
|
|
833
|
-
stageTurn([{ slug: "frontmatter-demo", denseScore: 0.9 }]);
|
|
834
|
-
|
|
835
|
-
const result = await injectMemoryV2Block({
|
|
836
|
-
database: db,
|
|
837
|
-
conversationId: "conv-1",
|
|
838
|
-
currentTurn: 1,
|
|
839
|
-
recentTurnPairs: [
|
|
840
|
-
{ assistantMessage: "", userMessage: "show me the demo" },
|
|
841
|
-
],
|
|
842
|
-
nowText: "Now",
|
|
843
|
-
messageId: "msg-1",
|
|
844
|
-
config: makeConfig(),
|
|
845
|
-
});
|
|
846
|
-
|
|
847
|
-
expect(result.block).not.toBeNull();
|
|
848
|
-
// Path header is immediately followed by the frontmatter open delimiter.
|
|
849
|
-
// The fallback path renders the full page (frontmatter + body) when the
|
|
850
|
-
// page has no `summary` field — `frontmatter-demo` predates the field.
|
|
851
|
-
expect(result.block).toContain(
|
|
852
|
-
"# memory/concepts/frontmatter-demo.md\n---\n",
|
|
853
|
-
);
|
|
854
|
-
// Both fields render in YAML block style with their populated values.
|
|
855
|
-
expect(result.block).toContain("edges:\n - alice-vscode");
|
|
856
|
-
expect(result.block).toContain("ref_files:\n - images/demo.jpg");
|
|
857
|
-
// Body still renders after the closing delimiter.
|
|
858
|
-
expect(result.block).toContain("Demo body content.");
|
|
859
|
-
});
|
|
860
|
-
|
|
861
|
-
test("renders pages in activation-descending order", async () => {
|
|
862
|
-
// Both slugs are fresh (no prior state). carol scores higher than alice
|
|
863
|
-
// on every channel — so carol should be ranked first in topNow and
|
|
864
|
-
// therefore appear first in the rendered block.
|
|
865
|
-
stageTurn([
|
|
866
|
-
{ slug: "carol-jazz", denseScore: 0.95 },
|
|
867
|
-
{ slug: "alice-vscode", denseScore: 0.5 },
|
|
868
|
-
]);
|
|
869
|
-
const result = await injectMemoryV2Block({
|
|
870
|
-
database: db,
|
|
871
|
-
conversationId: "conv-1",
|
|
872
|
-
currentTurn: 1,
|
|
873
|
-
recentTurnPairs: [
|
|
874
|
-
{ assistantMessage: "", userMessage: "music and editors" },
|
|
875
|
-
],
|
|
876
|
-
nowText: "Now",
|
|
877
|
-
messageId: "msg-1",
|
|
878
|
-
config: makeConfig(),
|
|
879
|
-
});
|
|
880
|
-
|
|
881
|
-
expect(result.toInject).toEqual(["carol-jazz", "alice-vscode"]);
|
|
882
|
-
const carolIdx = result.block!.indexOf("# memory/concepts/carol-jazz.md");
|
|
883
|
-
const aliceIdx = result.block!.indexOf("# memory/concepts/alice-vscode.md");
|
|
884
|
-
expect(carolIdx).toBeGreaterThan(-1);
|
|
885
|
-
expect(aliceIdx).toBeGreaterThan(-1);
|
|
886
|
-
expect(carolIdx).toBeLessThan(aliceIdx);
|
|
887
|
-
});
|
|
888
|
-
|
|
889
|
-
test("persists sparse state — only slugs above epsilon survive", async () => {
|
|
890
|
-
// Carol scores high; alice essentially zero. After saving, only carol
|
|
891
|
-
// should appear in the persisted state map. denseScore is the raw
|
|
892
|
-
// Qdrant cosine in [-1, 1]; alice uses -1 so the post `(x+1)/2`
|
|
893
|
-
// unit-mapping pins her fused score to 0 — below epsilon.
|
|
894
|
-
stageTurn([
|
|
895
|
-
{ slug: "carol-jazz", denseScore: 1.0 },
|
|
896
|
-
{ slug: "alice-vscode", denseScore: -1.0 },
|
|
897
|
-
]);
|
|
898
|
-
await injectMemoryV2Block({
|
|
899
|
-
database: db,
|
|
900
|
-
conversationId: "conv-1",
|
|
901
|
-
currentTurn: 1,
|
|
902
|
-
recentTurnPairs: [{ assistantMessage: "", userMessage: "carol" }],
|
|
903
|
-
nowText: "",
|
|
904
|
-
messageId: "msg-1",
|
|
905
|
-
config: makeConfig({ epsilon: 0.05 }),
|
|
906
|
-
});
|
|
907
|
-
|
|
908
|
-
const persisted = await hydrate(db, "conv-1");
|
|
909
|
-
expect(persisted!.state["carol-jazz"]).toBeGreaterThan(0.05);
|
|
910
|
-
expect(persisted!.state["alice-vscode"]).toBeUndefined();
|
|
911
|
-
});
|
|
912
|
-
|
|
913
|
-
test("returns null block when toInject slugs all reference missing pages", async () => {
|
|
914
|
-
// The ANN response contains a slug that is NOT on disk. After ranking,
|
|
915
|
-
// toInject is non-empty (we don't pre-filter), but `renderInjectionBlock`
|
|
916
|
-
// discovers the page is missing and returns null. The state is still
|
|
917
|
-
// persisted so we don't keep re-attempting.
|
|
918
|
-
stageTurn([{ slug: "phantom-slug", denseScore: 0.99 }]);
|
|
919
|
-
const result = await injectMemoryV2Block({
|
|
920
|
-
database: db,
|
|
921
|
-
conversationId: "conv-1",
|
|
922
|
-
currentTurn: 1,
|
|
923
|
-
recentTurnPairs: [{ assistantMessage: "", userMessage: "phantom" }],
|
|
924
|
-
nowText: "",
|
|
925
|
-
messageId: "msg-1",
|
|
926
|
-
config: makeConfig(),
|
|
927
|
-
});
|
|
928
|
-
|
|
929
|
-
expect(result.toInject).toEqual(["phantom-slug"]);
|
|
930
|
-
expect(result.block).toBeNull();
|
|
931
|
-
|
|
932
|
-
// everInjected still records the slug so future turns subtract it and
|
|
933
|
-
// we don't infinite-loop on a missing page.
|
|
934
|
-
const persisted = await hydrate(db, "conv-1");
|
|
935
|
-
expect(persisted!.everInjected).toEqual([
|
|
936
|
-
{ slug: "phantom-slug", turn: 1 },
|
|
937
|
-
]);
|
|
938
|
-
|
|
939
|
-
// Activation log marks the slug `page_missing` (not `injected`) so a
|
|
940
|
-
// stale Qdrant / edge-index entry pointing at a vanished page is
|
|
941
|
-
// visible in telemetry instead of masquerading as a successful inject.
|
|
942
|
-
expect(telemetryState.recordCalls.length).toBe(1);
|
|
943
|
-
const row = telemetryState.recordCalls[0] as {
|
|
944
|
-
concepts: Array<{ slug: string; status: string }>;
|
|
945
|
-
};
|
|
946
|
-
const phantom = row.concepts.find((c) => c.slug === "phantom-slug");
|
|
947
|
-
expect(phantom).toBeDefined();
|
|
948
|
-
expect(phantom!.status).toBe("page_missing");
|
|
949
|
-
});
|
|
950
|
-
|
|
951
|
-
// ---------------------------------------------------------------------------
|
|
952
|
-
// Unified pool — skills as `skills/<id>` slugs
|
|
953
|
-
// ---------------------------------------------------------------------------
|
|
954
|
-
|
|
955
|
-
test("renders a retrieved skills/<id> slug under Skills You Can Use", async () => {
|
|
956
|
-
// No concept-page candidates this turn — the only ANN hit is a skill
|
|
957
|
-
// slug. The render path branches on `skills/` prefix: it pulls the
|
|
958
|
-
// entry from the skill-store cache (mocked) and emits the bullet under
|
|
959
|
-
// the `### Skills You Can Use` subsection.
|
|
960
|
-
stageTurn([{ slug: "skills/retrieved-skill", denseScore: 0.9 }]);
|
|
961
|
-
stageSkills([
|
|
962
|
-
{
|
|
963
|
-
id: "retrieved-skill",
|
|
964
|
-
content:
|
|
965
|
-
'The "Retrieved Skill" skill (retrieved-skill) is available. Helps with retrieved skills.',
|
|
966
|
-
},
|
|
967
|
-
]);
|
|
968
|
-
|
|
969
|
-
const result = await injectMemoryV2Block({
|
|
970
|
-
database: db,
|
|
971
|
-
conversationId: "conv-1",
|
|
972
|
-
currentTurn: 1,
|
|
973
|
-
recentTurnPairs: [
|
|
974
|
-
{ assistantMessage: "", userMessage: "Help me with examples" },
|
|
975
|
-
],
|
|
976
|
-
nowText: "Now",
|
|
977
|
-
messageId: "msg-1",
|
|
978
|
-
config: makeConfig(),
|
|
979
|
-
});
|
|
980
|
-
|
|
981
|
-
expect(result.toInject).toEqual(["skills/retrieved-skill"]);
|
|
982
|
-
expect(result.block).not.toBeNull();
|
|
983
|
-
expect(result.block).not.toContain("<memory>");
|
|
984
|
-
expect(result.block).not.toContain("</memory>");
|
|
985
|
-
expect(result.block).not.toContain("## What I Remember Right Now");
|
|
986
|
-
expect(result.block).not.toContain("# memory/concepts/alice-vscode.md");
|
|
987
|
-
const headerIdx = result.block!.indexOf("### Skills You Can Use");
|
|
988
|
-
const skillIdx = result.block!.indexOf(
|
|
989
|
-
'- The "Retrieved Skill" skill (retrieved-skill) is available. Helps with retrieved skills. → use skill_load to activate',
|
|
990
|
-
);
|
|
991
|
-
expect(headerIdx).toBeGreaterThan(-1);
|
|
992
|
-
expect(skillIdx).toBeGreaterThan(headerIdx);
|
|
993
|
-
});
|
|
994
|
-
|
|
995
|
-
test("renders concept-page sections before the skills subsection in mixed blocks", async () => {
|
|
996
|
-
// Concept page hit AND a skill — concept-page sections come first, then
|
|
997
|
-
// the skills subsection.
|
|
998
|
-
stageTurn([
|
|
999
|
-
{ slug: "alice-vscode", denseScore: 0.9 },
|
|
1000
|
-
{ slug: "skills/example-skill-a", denseScore: 0.7 },
|
|
1001
|
-
]);
|
|
1002
|
-
stageSkills([
|
|
1003
|
-
{
|
|
1004
|
-
id: "example-skill-a",
|
|
1005
|
-
content:
|
|
1006
|
-
'The "Example Skill A" skill (example-skill-a) is available. Helps with examples.',
|
|
1007
|
-
},
|
|
1008
|
-
]);
|
|
1009
|
-
|
|
1010
|
-
const result = await injectMemoryV2Block({
|
|
1011
|
-
database: db,
|
|
1012
|
-
conversationId: "conv-1",
|
|
1013
|
-
currentTurn: 1,
|
|
1014
|
-
recentTurnPairs: [
|
|
1015
|
-
{ assistantMessage: "", userMessage: "Alice's editor" },
|
|
1016
|
-
],
|
|
1017
|
-
nowText: "Now",
|
|
1018
|
-
messageId: "msg-1",
|
|
1019
|
-
config: makeConfig(),
|
|
1020
|
-
});
|
|
1021
|
-
|
|
1022
|
-
// Both slugs ranked into top-K and got freshly attached.
|
|
1023
|
-
expect(new Set(result.toInject)).toEqual(
|
|
1024
|
-
new Set(["alice-vscode", "skills/example-skill-a"]),
|
|
1025
|
-
);
|
|
1026
|
-
expect(result.block).not.toBeNull();
|
|
1027
|
-
|
|
1028
|
-
const aliceHeaderIdx = result.block!.indexOf(
|
|
1029
|
-
"# memory/concepts/alice-vscode.md",
|
|
1030
|
-
);
|
|
1031
|
-
const skillsIdx = result.block!.indexOf("### Skills You Can Use");
|
|
1032
|
-
expect(aliceHeaderIdx).toBeGreaterThan(-1);
|
|
1033
|
-
expect(skillsIdx).toBeGreaterThan(-1);
|
|
1034
|
-
expect(aliceHeaderIdx).toBeLessThan(skillsIdx);
|
|
1035
|
-
|
|
1036
|
-
expect(result.block).toContain(
|
|
1037
|
-
'- The "Example Skill A" skill (example-skill-a) is available. Helps with examples. → use skill_load to activate',
|
|
1038
|
-
);
|
|
1039
|
-
});
|
|
1040
|
-
|
|
1041
|
-
test("skills participate in everInjected — an attached skill is not re-attached on the next turn", async () => {
|
|
1042
|
-
// Turn 1: skill ranks high, gets attached.
|
|
1043
|
-
const skillEntry = {
|
|
1044
|
-
id: "example-skill-a",
|
|
1045
|
-
content:
|
|
1046
|
-
'The "Example Skill A" skill (example-skill-a) is available. Helps with examples.',
|
|
1047
|
-
};
|
|
1048
|
-
stageTurn([{ slug: "skills/example-skill-a", denseScore: 0.9 }]);
|
|
1049
|
-
stageSkills([skillEntry]);
|
|
1050
|
-
const result1 = await injectMemoryV2Block({
|
|
1051
|
-
database: db,
|
|
1052
|
-
conversationId: "conv-1",
|
|
1053
|
-
currentTurn: 1,
|
|
1054
|
-
recentTurnPairs: [{ assistantMessage: "", userMessage: "examples" }],
|
|
1055
|
-
nowText: "Now",
|
|
1056
|
-
messageId: "msg-1",
|
|
1057
|
-
config: makeConfig(),
|
|
1058
|
-
});
|
|
1059
|
-
expect(result1.toInject).toEqual(["skills/example-skill-a"]);
|
|
1060
|
-
expect(result1.block).toContain("### Skills You Can Use");
|
|
1061
|
-
|
|
1062
|
-
// Turn 2: same skill ranks top again. It is already in `everInjected`, so
|
|
1063
|
-
// `toInject` is empty and the block is null — the attachment from turn 1
|
|
1064
|
-
// remains visible to the agent via the cached prior user message.
|
|
1065
|
-
stageTurn([{ slug: "skills/example-skill-a", denseScore: 0.9 }]);
|
|
1066
|
-
stageSkills([skillEntry]);
|
|
1067
|
-
const result2 = await injectMemoryV2Block({
|
|
1068
|
-
database: db,
|
|
1069
|
-
conversationId: "conv-1",
|
|
1070
|
-
currentTurn: 2,
|
|
1071
|
-
recentTurnPairs: [
|
|
1072
|
-
{ assistantMessage: "ok", userMessage: "more examples" },
|
|
1073
|
-
],
|
|
1074
|
-
nowText: "Now",
|
|
1075
|
-
messageId: "msg-2",
|
|
1076
|
-
config: makeConfig(),
|
|
1077
|
-
});
|
|
1078
|
-
expect(result2.toInject).toEqual([]);
|
|
1079
|
-
expect(result2.block).toBeNull();
|
|
1080
|
-
|
|
1081
|
-
const persisted = await hydrate(db, "conv-1");
|
|
1082
|
-
expect(persisted!.everInjected).toEqual([
|
|
1083
|
-
{ slug: "skills/example-skill-a", turn: 1 },
|
|
1084
|
-
]);
|
|
1085
|
-
});
|
|
1086
|
-
|
|
1087
|
-
test("skill slugs whose entry is missing from the cache are dropped silently", async () => {
|
|
1088
|
-
// The skill ranks into top-K but the in-process cache no longer knows
|
|
1089
|
-
// its content (skill uninstalled mid-run, or a startup race where the
|
|
1090
|
-
// Qdrant row landed before the skill cache was seeded). The render path
|
|
1091
|
-
// drops it without surfacing it as a `missingSlugs` page-missing event —
|
|
1092
|
-
// that status is reserved for on-disk concept pages, not catalog-derived
|
|
1093
|
-
// skill entries.
|
|
1094
|
-
stageTurn([{ slug: "skills/missing-skill", denseScore: 0.9 }]);
|
|
1095
|
-
// No `stageSkills` call — cache stays empty.
|
|
1096
|
-
|
|
1097
|
-
const result = await injectMemoryV2Block({
|
|
1098
|
-
database: db,
|
|
1099
|
-
conversationId: "conv-1",
|
|
1100
|
-
currentTurn: 1,
|
|
1101
|
-
recentTurnPairs: [{ assistantMessage: "", userMessage: "anything" }],
|
|
1102
|
-
nowText: "Now",
|
|
1103
|
-
messageId: "msg-1",
|
|
1104
|
-
config: makeConfig(),
|
|
1105
|
-
});
|
|
1106
|
-
|
|
1107
|
-
// The skill is excluded from `toInject` (and `everInjected`) so future
|
|
1108
|
-
// per-turn runs re-attempt the attach once the cache is populated.
|
|
1109
|
-
// `block` collapses to null because the only candidate was a cache miss.
|
|
1110
|
-
expect(result.toInject).toEqual([]);
|
|
1111
|
-
expect(result.block).toBeNull();
|
|
1112
|
-
|
|
1113
|
-
// Persisted `everInjected` must not record the missing skill — that
|
|
1114
|
-
// would block retry on a later turn until compaction-driven eviction.
|
|
1115
|
-
const persisted = await hydrate(db, "conv-1");
|
|
1116
|
-
expect(persisted!.everInjected).toEqual([]);
|
|
1117
|
-
});
|
|
1118
|
-
|
|
1119
|
-
test("returns null when both concept pages and skills are empty", async () => {
|
|
1120
|
-
stageTurn([]);
|
|
1121
|
-
|
|
1122
|
-
const result = await injectMemoryV2Block({
|
|
1123
|
-
database: db,
|
|
1124
|
-
conversationId: "conv-1",
|
|
1125
|
-
currentTurn: 1,
|
|
1126
|
-
recentTurnPairs: [{ assistantMessage: "", userMessage: "anything" }],
|
|
1127
|
-
nowText: "",
|
|
1128
|
-
messageId: "msg-1",
|
|
1129
|
-
config: makeConfig(),
|
|
1130
|
-
});
|
|
1131
|
-
|
|
1132
|
-
expect(result.toInject).toEqual([]);
|
|
1133
|
-
expect(result.block).toBeNull();
|
|
1134
|
-
});
|
|
1135
|
-
|
|
1136
|
-
// ---------------------------------------------------------------------------
|
|
1137
|
-
// CLI-command synthetic entries — same unified-pool plumbing as skills.
|
|
1138
|
-
// ---------------------------------------------------------------------------
|
|
1139
|
-
|
|
1140
|
-
test("renders a retrieved cli-commands/<name> slug under CLI Commands You Can Use", async () => {
|
|
1141
|
-
stageTurn([{ slug: "cli-commands/attachment", denseScore: 0.9 }]);
|
|
1142
|
-
stageCliCommands([
|
|
1143
|
-
{
|
|
1144
|
-
id: "attachment",
|
|
1145
|
-
description: "Manage file attachments for conversations",
|
|
1146
|
-
content: 'The "assistant attachment" CLI command is available...',
|
|
1147
|
-
},
|
|
1148
|
-
]);
|
|
1149
|
-
|
|
1150
|
-
const result = await injectMemoryV2Block({
|
|
1151
|
-
database: db,
|
|
1152
|
-
conversationId: "conv-1",
|
|
1153
|
-
currentTurn: 1,
|
|
1154
|
-
recentTurnPairs: [
|
|
1155
|
-
{ assistantMessage: "", userMessage: "How do I register a video?" },
|
|
1156
|
-
],
|
|
1157
|
-
nowText: "Now",
|
|
1158
|
-
messageId: "msg-1",
|
|
1159
|
-
config: makeConfig(),
|
|
1160
|
-
});
|
|
1161
|
-
|
|
1162
|
-
expect(result.toInject).toEqual(["cli-commands/attachment"]);
|
|
1163
|
-
expect(result.block).not.toBeNull();
|
|
1164
|
-
const headerIdx = result.block!.indexOf("### CLI Commands You Can Use");
|
|
1165
|
-
const lineIdx = result.block!.indexOf(
|
|
1166
|
-
"- `assistant attachment`: Manage file attachments for conversations",
|
|
1167
|
-
);
|
|
1168
|
-
expect(headerIdx).toBeGreaterThan(-1);
|
|
1169
|
-
expect(lineIdx).toBeGreaterThan(headerIdx);
|
|
1170
|
-
});
|
|
1171
|
-
|
|
1172
|
-
test("renders concepts, skills, then cli-commands in that order in mixed blocks", async () => {
|
|
1173
|
-
stageTurn([
|
|
1174
|
-
{ slug: "alice-vscode", denseScore: 0.95 },
|
|
1175
|
-
{ slug: "skills/example-skill-a", denseScore: 0.85 },
|
|
1176
|
-
{ slug: "cli-commands/config", denseScore: 0.75 },
|
|
1177
|
-
]);
|
|
1178
|
-
stageSkills([
|
|
1179
|
-
{
|
|
1180
|
-
id: "example-skill-a",
|
|
1181
|
-
content:
|
|
1182
|
-
'The "Example Skill A" skill (example-skill-a) is available. Helps with examples.',
|
|
1183
|
-
},
|
|
1184
|
-
]);
|
|
1185
|
-
stageCliCommands([
|
|
1186
|
-
{
|
|
1187
|
-
id: "config",
|
|
1188
|
-
description: "Manage configuration",
|
|
1189
|
-
content: 'The "assistant config" CLI command is available...',
|
|
1190
|
-
},
|
|
1191
|
-
]);
|
|
1192
|
-
|
|
1193
|
-
const result = await injectMemoryV2Block({
|
|
1194
|
-
database: db,
|
|
1195
|
-
conversationId: "conv-1",
|
|
1196
|
-
currentTurn: 1,
|
|
1197
|
-
recentTurnPairs: [{ assistantMessage: "", userMessage: "Help me" }],
|
|
1198
|
-
nowText: "Now",
|
|
1199
|
-
messageId: "msg-1",
|
|
1200
|
-
config: makeConfig(),
|
|
1201
|
-
});
|
|
1202
|
-
|
|
1203
|
-
expect(new Set(result.toInject)).toEqual(
|
|
1204
|
-
new Set([
|
|
1205
|
-
"alice-vscode",
|
|
1206
|
-
"skills/example-skill-a",
|
|
1207
|
-
"cli-commands/config",
|
|
1208
|
-
]),
|
|
1209
|
-
);
|
|
1210
|
-
const conceptIdx = result.block!.indexOf(
|
|
1211
|
-
"# memory/concepts/alice-vscode.md",
|
|
1212
|
-
);
|
|
1213
|
-
const skillsIdx = result.block!.indexOf("### Skills You Can Use");
|
|
1214
|
-
const cliIdx = result.block!.indexOf("### CLI Commands You Can Use");
|
|
1215
|
-
expect(conceptIdx).toBeGreaterThan(-1);
|
|
1216
|
-
expect(skillsIdx).toBeGreaterThan(conceptIdx);
|
|
1217
|
-
expect(cliIdx).toBeGreaterThan(skillsIdx);
|
|
1218
|
-
});
|
|
1219
|
-
|
|
1220
|
-
test("cli-command slugs whose entry is missing from the cache are dropped silently", async () => {
|
|
1221
|
-
stageTurn([{ slug: "cli-commands/missing-command", denseScore: 0.9 }]);
|
|
1222
|
-
|
|
1223
|
-
const result = await injectMemoryV2Block({
|
|
1224
|
-
database: db,
|
|
1225
|
-
conversationId: "conv-1",
|
|
1226
|
-
currentTurn: 1,
|
|
1227
|
-
recentTurnPairs: [{ assistantMessage: "", userMessage: "anything" }],
|
|
1228
|
-
nowText: "Now",
|
|
1229
|
-
messageId: "msg-1",
|
|
1230
|
-
config: makeConfig(),
|
|
1231
|
-
});
|
|
1232
|
-
|
|
1233
|
-
expect(result.toInject).toEqual([]);
|
|
1234
|
-
expect(result.block).toBeNull();
|
|
1235
|
-
|
|
1236
|
-
const persisted = await hydrate(db, "conv-1");
|
|
1237
|
-
expect(persisted!.everInjected).toEqual([]);
|
|
1238
|
-
});
|
|
1239
|
-
|
|
1240
|
-
test("cli-commands participate in everInjected so they dedupe across turns", async () => {
|
|
1241
|
-
const entry = {
|
|
1242
|
-
id: "config",
|
|
1243
|
-
description: "Manage configuration",
|
|
1244
|
-
content: 'The "assistant config" CLI command is available...',
|
|
1245
|
-
};
|
|
1246
|
-
stageTurn([{ slug: "cli-commands/config", denseScore: 0.9 }]);
|
|
1247
|
-
stageCliCommands([entry]);
|
|
1248
|
-
const result1 = await injectMemoryV2Block({
|
|
1249
|
-
database: db,
|
|
1250
|
-
conversationId: "conv-1",
|
|
1251
|
-
currentTurn: 1,
|
|
1252
|
-
recentTurnPairs: [{ assistantMessage: "", userMessage: "config" }],
|
|
1253
|
-
nowText: "Now",
|
|
1254
|
-
messageId: "msg-1",
|
|
1255
|
-
config: makeConfig(),
|
|
1256
|
-
});
|
|
1257
|
-
expect(result1.toInject).toEqual(["cli-commands/config"]);
|
|
1258
|
-
expect(result1.block).toContain("### CLI Commands You Can Use");
|
|
1259
|
-
|
|
1260
|
-
stageTurn([{ slug: "cli-commands/config", denseScore: 0.9 }]);
|
|
1261
|
-
stageCliCommands([entry]);
|
|
1262
|
-
const result2 = await injectMemoryV2Block({
|
|
1263
|
-
database: db,
|
|
1264
|
-
conversationId: "conv-1",
|
|
1265
|
-
currentTurn: 2,
|
|
1266
|
-
recentTurnPairs: [{ assistantMessage: "ok", userMessage: "more config" }],
|
|
1267
|
-
nowText: "Now",
|
|
1268
|
-
messageId: "msg-2",
|
|
1269
|
-
config: makeConfig(),
|
|
1270
|
-
});
|
|
1271
|
-
expect(result2.toInject).toEqual([]);
|
|
1272
|
-
expect(result2.block).toBeNull();
|
|
1273
|
-
|
|
1274
|
-
const persisted = await hydrate(db, "conv-1");
|
|
1275
|
-
expect(persisted!.everInjected).toEqual([
|
|
1276
|
-
{ slug: "cli-commands/config", turn: 1 },
|
|
1277
|
-
]);
|
|
1278
|
-
});
|
|
1279
|
-
|
|
1280
|
-
test("context-load mode renders topNow even when every slug was previously injected", async () => {
|
|
1281
|
-
// Turn 1 (per-turn): seed alice as injected.
|
|
1282
|
-
stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
|
|
1283
|
-
await injectMemoryV2Block({
|
|
1284
|
-
database: db,
|
|
1285
|
-
conversationId: "conv-1",
|
|
1286
|
-
currentTurn: 1,
|
|
1287
|
-
recentTurnPairs: [
|
|
1288
|
-
{ assistantMessage: "", userMessage: "Alice's editor" },
|
|
1289
|
-
],
|
|
1290
|
-
nowText: "Now",
|
|
1291
|
-
messageId: "msg-1",
|
|
1292
|
-
config: makeConfig(),
|
|
1293
|
-
});
|
|
1294
|
-
|
|
1295
|
-
// Subsequent context-load (post-compaction or fresh load): alice is
|
|
1296
|
-
// back in the candidate pool. Per-turn would dedup against everInjected
|
|
1297
|
-
// and produce a null block; context-load must re-render the full top-K
|
|
1298
|
-
// because cached attachments don't exist on a fresh load.
|
|
1299
|
-
stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
|
|
1300
|
-
const result = await injectMemoryV2Block({
|
|
1301
|
-
database: db,
|
|
1302
|
-
conversationId: "conv-1",
|
|
1303
|
-
currentTurn: 2,
|
|
1304
|
-
recentTurnPairs: [
|
|
1305
|
-
{ assistantMessage: "", userMessage: "Reload context" },
|
|
1306
|
-
],
|
|
1307
|
-
nowText: "Now",
|
|
1308
|
-
messageId: "msg-2",
|
|
1309
|
-
mode: "context-load",
|
|
1310
|
-
config: makeConfig(),
|
|
1311
|
-
});
|
|
1312
|
-
|
|
1313
|
-
expect(result.block).not.toBeNull();
|
|
1314
|
-
expect(result.block).toContain("# memory/concepts/alice-vscode.md");
|
|
1315
|
-
// No newly-injected slug — alice was already in everInjected.
|
|
1316
|
-
expect(result.toInject).toEqual([]);
|
|
1317
|
-
|
|
1318
|
-
// everInjected stays a single entry (alice was already there) — context-
|
|
1319
|
-
// load doesn't double-stamp.
|
|
1320
|
-
const persisted = await hydrate(db, "conv-1");
|
|
1321
|
-
expect(persisted!.everInjected).toEqual([
|
|
1322
|
-
{ slug: "alice-vscode", turn: 1 },
|
|
1323
|
-
]);
|
|
1324
|
-
});
|
|
1325
|
-
|
|
1326
|
-
test("context-load mode renders the full top-K on a fresh first turn", async () => {
|
|
1327
|
-
// Turn 1 with no prior state and three candidates. Per-turn and context-
|
|
1328
|
-
// load behave identically when everInjected is empty (toInject == topNow),
|
|
1329
|
-
// but this asserts the contract: a fresh first user message gets the
|
|
1330
|
-
// entire top-K rendered, not just a delta.
|
|
1331
|
-
stageTurn([
|
|
1332
|
-
{ slug: "alice-vscode", denseScore: 0.9 },
|
|
1333
|
-
{ slug: "bob-coffee", denseScore: 0.8 },
|
|
1334
|
-
{ slug: "carol-jazz", denseScore: 0.7 },
|
|
1335
|
-
]);
|
|
1336
|
-
|
|
1337
|
-
const result = await injectMemoryV2Block({
|
|
1338
|
-
database: db,
|
|
1339
|
-
conversationId: "conv-1",
|
|
1340
|
-
currentTurn: 1,
|
|
1341
|
-
recentTurnPairs: [{ assistantMessage: "", userMessage: "hi" }],
|
|
1342
|
-
nowText: "",
|
|
1343
|
-
messageId: "msg-1",
|
|
1344
|
-
mode: "context-load",
|
|
1345
|
-
config: makeConfig({ top_k: 3 }),
|
|
1346
|
-
});
|
|
1347
|
-
|
|
1348
|
-
expect(result.block).not.toBeNull();
|
|
1349
|
-
expect(result.block).toContain("# memory/concepts/alice-vscode.md");
|
|
1350
|
-
expect(result.block).toContain("# memory/concepts/bob-coffee.md");
|
|
1351
|
-
expect(result.block).toContain("# memory/concepts/carol-jazz.md");
|
|
1352
|
-
// The seeded directed edges (alice→bob, bob→alice, frontmatter-demo→alice)
|
|
1353
|
-
// mean alice has two incoming predecessors and bob has one, so directed
|
|
1354
|
-
// spread normalizes alice's activation more aggressively than bob's. The
|
|
1355
|
-
// resulting rank order is bob > carol (no predecessors) > alice.
|
|
1356
|
-
expect(new Set(result.toInject)).toEqual(
|
|
1357
|
-
new Set(["alice-vscode", "bob-coffee", "carol-jazz"]),
|
|
1358
|
-
);
|
|
1359
|
-
expect(result.toInject).toHaveLength(3);
|
|
1360
|
-
|
|
1361
|
-
// All three slugs persisted to everInjected so the next per-turn doesn't
|
|
1362
|
-
// re-attach the same content.
|
|
1363
|
-
const persisted = await hydrate(db, "conv-1");
|
|
1364
|
-
expect(new Set(persisted!.everInjected.map((e) => e.slug))).toEqual(
|
|
1365
|
-
new Set(["alice-vscode", "bob-coffee", "carol-jazz"]),
|
|
1366
|
-
);
|
|
1367
|
-
expect(persisted!.everInjected).toHaveLength(3);
|
|
1368
|
-
});
|
|
1369
|
-
|
|
1370
|
-
// ---------------------------------------------------------------------------
|
|
1371
|
-
// Activation-log telemetry
|
|
1372
|
-
// ---------------------------------------------------------------------------
|
|
1373
|
-
|
|
1374
|
-
test("writes one activation-log row per turn with concept rows partitioned and sorted", async () => {
|
|
1375
|
-
// Turn 1: seed alice as injected so turn 2 has an `in_context` candidate.
|
|
1376
|
-
stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
|
|
1377
|
-
await injectMemoryV2Block({
|
|
1378
|
-
database: db,
|
|
1379
|
-
conversationId: "conv-1",
|
|
1380
|
-
currentTurn: 1,
|
|
1381
|
-
recentTurnPairs: [
|
|
1382
|
-
{ assistantMessage: "", userMessage: "Alice's editor" },
|
|
1383
|
-
],
|
|
1384
|
-
nowText: "Now",
|
|
1385
|
-
messageId: "msg-1",
|
|
1386
|
-
config: makeConfig(),
|
|
1387
|
-
});
|
|
1388
|
-
expect(telemetryState.recordCalls.length).toBe(1);
|
|
1389
|
-
|
|
1390
|
-
// Turn 2: alice carries forward (now `in_context`); carol is freshly
|
|
1391
|
-
// surfaced (`injected`); bob would be a candidate only if it carried
|
|
1392
|
-
// forward, but with no prior bob entry it doesn't appear here.
|
|
1393
|
-
stageTurn([
|
|
1394
|
-
{ slug: "alice-vscode", denseScore: 0.6 },
|
|
1395
|
-
{ slug: "carol-jazz", denseScore: 0.95 },
|
|
1396
|
-
]);
|
|
1397
|
-
await injectMemoryV2Block({
|
|
1398
|
-
database: db,
|
|
1399
|
-
conversationId: "conv-1",
|
|
1400
|
-
currentTurn: 2,
|
|
1401
|
-
recentTurnPairs: [{ assistantMessage: "", userMessage: "Carol's music" }],
|
|
1402
|
-
nowText: "Now",
|
|
1403
|
-
messageId: "msg-2",
|
|
1404
|
-
config: makeConfig(),
|
|
1405
|
-
});
|
|
1406
|
-
|
|
1407
|
-
expect(telemetryState.recordCalls.length).toBe(2);
|
|
1408
|
-
const row = telemetryState.recordCalls[1] as {
|
|
1409
|
-
conversationId: string;
|
|
1410
|
-
turn: number;
|
|
1411
|
-
mode: string;
|
|
1412
|
-
concepts: Array<{
|
|
1413
|
-
slug: string;
|
|
1414
|
-
finalActivation: number;
|
|
1415
|
-
status: string;
|
|
1416
|
-
source: string;
|
|
1417
|
-
}>;
|
|
1418
|
-
config: { top_k: number };
|
|
1419
|
-
};
|
|
1420
|
-
expect(row.conversationId).toBe("conv-1");
|
|
1421
|
-
expect(row.turn).toBe(2);
|
|
1422
|
-
expect(row.mode).toBe("per-turn");
|
|
1423
|
-
expect(row.config.top_k).toBe(25);
|
|
1424
|
-
|
|
1425
|
-
// The candidate set is the union of fromPrior (alice) and fromAnn
|
|
1426
|
-
// (alice + carol) → two concept rows.
|
|
1427
|
-
expect(row.concepts.length).toBe(2);
|
|
1428
|
-
const slugs = row.concepts.map((c) => c.slug);
|
|
1429
|
-
expect(new Set(slugs)).toEqual(new Set(["alice-vscode", "carol-jazz"]));
|
|
1430
|
-
|
|
1431
|
-
// Sorted descending by finalActivation.
|
|
1432
|
-
for (let i = 1; i < row.concepts.length; i++) {
|
|
1433
|
-
expect(row.concepts[i - 1]!.finalActivation).toBeGreaterThanOrEqual(
|
|
1434
|
-
row.concepts[i]!.finalActivation,
|
|
1435
|
-
);
|
|
1436
|
-
}
|
|
1437
|
-
|
|
1438
|
-
const byslug = new Map(row.concepts.map((c) => [c.slug, c]));
|
|
1439
|
-
// Alice was attached on turn 1 → status `in_context` on turn 2.
|
|
1440
|
-
expect(byslug.get("alice-vscode")!.status).toBe("in_context");
|
|
1441
|
-
// Carol is freshly injected on turn 2.
|
|
1442
|
-
expect(byslug.get("carol-jazz")!.status).toBe("injected");
|
|
1443
|
-
});
|
|
1444
|
-
|
|
1445
|
-
test("activation-log concepts include skill rows under the skills/ prefix", async () => {
|
|
1446
|
-
// Skills participate in the unified telemetry list — they live in the
|
|
1447
|
-
// same `concepts` array, identifiable by the `skills/` slug prefix.
|
|
1448
|
-
stageTurn([
|
|
1449
|
-
{ slug: "alice-vscode", denseScore: 0.9 },
|
|
1450
|
-
{ slug: "skills/example-skill-a", denseScore: 0.7 },
|
|
1451
|
-
]);
|
|
1452
|
-
stageSkills([
|
|
1453
|
-
{
|
|
1454
|
-
id: "example-skill-a",
|
|
1455
|
-
content: "skill content",
|
|
1456
|
-
},
|
|
1457
|
-
]);
|
|
1458
|
-
|
|
1459
|
-
await injectMemoryV2Block({
|
|
1460
|
-
database: db,
|
|
1461
|
-
conversationId: "conv-1",
|
|
1462
|
-
currentTurn: 1,
|
|
1463
|
-
recentTurnPairs: [
|
|
1464
|
-
{ assistantMessage: "", userMessage: "Alice's editor" },
|
|
1465
|
-
],
|
|
1466
|
-
nowText: "Now",
|
|
1467
|
-
messageId: "msg-1",
|
|
1468
|
-
config: makeConfig(),
|
|
1469
|
-
});
|
|
1470
|
-
|
|
1471
|
-
expect(telemetryState.recordCalls.length).toBe(1);
|
|
1472
|
-
const row = telemetryState.recordCalls[0] as {
|
|
1473
|
-
concepts: Array<{ slug: string; status: string }>;
|
|
1474
|
-
};
|
|
1475
|
-
const slugs = row.concepts.map((c) => c.slug);
|
|
1476
|
-
expect(new Set(slugs)).toEqual(
|
|
1477
|
-
new Set(["alice-vscode", "skills/example-skill-a"]),
|
|
1478
|
-
);
|
|
1479
|
-
});
|
|
1480
|
-
|
|
1481
|
-
test("context-load mode marks every rendered slug as `injected`, never `in_context`", async () => {
|
|
1482
|
-
// Turn 1 (per-turn): seed alice as injected so the next turn's prior
|
|
1483
|
-
// `everInjected` includes her — the same setup the per-turn telemetry
|
|
1484
|
-
// test uses, so the difference between modes is unambiguous.
|
|
1485
|
-
stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
|
|
1486
|
-
await injectMemoryV2Block({
|
|
1487
|
-
database: db,
|
|
1488
|
-
conversationId: "conv-1",
|
|
1489
|
-
currentTurn: 1,
|
|
1490
|
-
recentTurnPairs: [
|
|
1491
|
-
{ assistantMessage: "", userMessage: "Alice's editor" },
|
|
1492
|
-
],
|
|
1493
|
-
nowText: "Now",
|
|
1494
|
-
messageId: "msg-1",
|
|
1495
|
-
config: makeConfig(),
|
|
1496
|
-
});
|
|
1497
|
-
expect(telemetryState.recordCalls.length).toBe(1);
|
|
1498
|
-
|
|
1499
|
-
// Turn 2 in context-load mode (post-compaction or fresh load). Alice
|
|
1500
|
-
// carries forward AND ranks high again; carol is a brand-new candidate.
|
|
1501
|
-
// Both end up in `topNow` (and therefore in `slugsToRender` since
|
|
1502
|
-
// context-load renders the full top-K). The status field must reflect
|
|
1503
|
-
// that they were physically rendered into the new user message on this
|
|
1504
|
-
// turn — `injected` for both — rather than reading `in_context` for
|
|
1505
|
-
// alice based on stale prior `everInjected` state.
|
|
1506
|
-
stageTurn([
|
|
1507
|
-
{ slug: "alice-vscode", denseScore: 0.6 },
|
|
1508
|
-
{ slug: "carol-jazz", denseScore: 0.95 },
|
|
1509
|
-
]);
|
|
1510
|
-
await injectMemoryV2Block({
|
|
1511
|
-
database: db,
|
|
1512
|
-
conversationId: "conv-1",
|
|
1513
|
-
currentTurn: 2,
|
|
1514
|
-
recentTurnPairs: [
|
|
1515
|
-
{ assistantMessage: "", userMessage: "Reload context" },
|
|
1516
|
-
],
|
|
1517
|
-
nowText: "Now",
|
|
1518
|
-
messageId: "msg-2",
|
|
1519
|
-
mode: "context-load",
|
|
1520
|
-
config: makeConfig(),
|
|
1521
|
-
});
|
|
1522
|
-
|
|
1523
|
-
expect(telemetryState.recordCalls.length).toBe(2);
|
|
1524
|
-
const row = telemetryState.recordCalls[1] as {
|
|
1525
|
-
mode: string;
|
|
1526
|
-
concepts: Array<{ slug: string; status: string }>;
|
|
1527
|
-
};
|
|
1528
|
-
expect(row.mode).toBe("context-load");
|
|
1529
|
-
|
|
1530
|
-
const byslug = new Map(row.concepts.map((c) => [c.slug, c]));
|
|
1531
|
-
// Both rendered slugs read as `injected` — alice especially, even though
|
|
1532
|
-
// she's in prior `everInjected`, because context-load actually rendered
|
|
1533
|
-
// her into the fresh user message on this turn.
|
|
1534
|
-
expect(byslug.get("alice-vscode")!.status).toBe("injected");
|
|
1535
|
-
expect(byslug.get("carol-jazz")!.status).toBe("injected");
|
|
1536
|
-
|
|
1537
|
-
// No slug reads as `in_context` in context-load mode — the cache was
|
|
1538
|
-
// wiped, so there is no prior cached attachment to reference.
|
|
1539
|
-
for (const concept of row.concepts) {
|
|
1540
|
-
expect(concept.status).not.toBe("in_context");
|
|
1541
|
-
}
|
|
1542
|
-
});
|
|
1543
|
-
|
|
1544
|
-
test("context-load mode marks candidates outside `slugsToRender` as `not_injected`", async () => {
|
|
1545
|
-
// Turn 1 (per-turn): seed both alice and bob with positive activation
|
|
1546
|
-
// so they survive into turn 2's prior-state candidate pool.
|
|
1547
|
-
stageTurn([
|
|
1548
|
-
{ slug: "alice-vscode", denseScore: 0.9 },
|
|
1549
|
-
{ slug: "bob-coffee", denseScore: 0.8 },
|
|
1550
|
-
]);
|
|
1551
|
-
await injectMemoryV2Block({
|
|
1552
|
-
database: db,
|
|
1553
|
-
conversationId: "conv-1",
|
|
1554
|
-
currentTurn: 1,
|
|
1555
|
-
recentTurnPairs: [
|
|
1556
|
-
{
|
|
1557
|
-
assistantMessage: "",
|
|
1558
|
-
userMessage: "Alice's editor and Bob's coffee",
|
|
1559
|
-
},
|
|
1560
|
-
],
|
|
1561
|
-
nowText: "Now",
|
|
1562
|
-
messageId: "msg-1",
|
|
1563
|
-
config: makeConfig(),
|
|
1564
|
-
});
|
|
1565
|
-
|
|
1566
|
-
// Turn 2 (context-load) with `top_k: 1`: alice and bob both carry
|
|
1567
|
-
// forward as candidates, but only the top-ranked slug is rendered.
|
|
1568
|
-
// Whichever slug doesn't make the cut must read as `not_injected`.
|
|
1569
|
-
stageTurn([
|
|
1570
|
-
{ slug: "alice-vscode", denseScore: 0.95 },
|
|
1571
|
-
{ slug: "bob-coffee", denseScore: 0.05 },
|
|
1572
|
-
]);
|
|
1573
|
-
await injectMemoryV2Block({
|
|
1574
|
-
database: db,
|
|
1575
|
-
conversationId: "conv-1",
|
|
1576
|
-
currentTurn: 2,
|
|
1577
|
-
recentTurnPairs: [
|
|
1578
|
-
{ assistantMessage: "", userMessage: "Reload context" },
|
|
1579
|
-
],
|
|
1580
|
-
nowText: "Now",
|
|
1581
|
-
messageId: "msg-2",
|
|
1582
|
-
mode: "context-load",
|
|
1583
|
-
config: makeConfig({ top_k: 1 }),
|
|
1584
|
-
});
|
|
1585
|
-
|
|
1586
|
-
expect(telemetryState.recordCalls.length).toBe(2);
|
|
1587
|
-
const row = telemetryState.recordCalls[1] as {
|
|
1588
|
-
mode: string;
|
|
1589
|
-
concepts: Array<{ slug: string; status: string }>;
|
|
1590
|
-
};
|
|
1591
|
-
expect(row.mode).toBe("context-load");
|
|
1592
|
-
|
|
1593
|
-
const byslug = new Map(row.concepts.map((c) => [c.slug, c]));
|
|
1594
|
-
// Alice ranked first → she is in `slugsToRender` → `injected`.
|
|
1595
|
-
expect(byslug.get("alice-vscode")!.status).toBe("injected");
|
|
1596
|
-
// Bob was a candidate but didn't make `top_k: 1` → `not_injected`.
|
|
1597
|
-
expect(byslug.get("bob-coffee")!.status).toBe("not_injected");
|
|
1598
|
-
});
|
|
1599
|
-
|
|
1600
|
-
test("telemetry write failure is non-fatal — injection still returns a normal result", async () => {
|
|
1601
|
-
telemetryState.recordShouldThrow = true;
|
|
1602
|
-
|
|
1603
|
-
stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
|
|
1604
|
-
const result = await injectMemoryV2Block({
|
|
1605
|
-
database: db,
|
|
1606
|
-
conversationId: "conv-1",
|
|
1607
|
-
currentTurn: 1,
|
|
1608
|
-
recentTurnPairs: [
|
|
1609
|
-
{ assistantMessage: "", userMessage: "Alice's editor" },
|
|
1610
|
-
],
|
|
1611
|
-
nowText: "Now",
|
|
1612
|
-
messageId: "msg-1",
|
|
1613
|
-
config: makeConfig(),
|
|
1614
|
-
});
|
|
1615
|
-
|
|
1616
|
-
// No row captured (the throw aborted the push), but the caller still
|
|
1617
|
-
// produced a regular block + toInject result and persisted state.
|
|
1618
|
-
expect(telemetryState.recordCalls.length).toBe(0);
|
|
1619
|
-
expect(result.toInject).toEqual(["alice-vscode"]);
|
|
1620
|
-
expect(result.block).not.toBeNull();
|
|
1621
|
-
expect(result.block).toContain("# memory/concepts/alice-vscode.md");
|
|
1622
|
-
|
|
1623
|
-
const persisted = await hydrate(db, "conv-1");
|
|
1624
|
-
expect(persisted!.everInjected).toEqual([
|
|
1625
|
-
{ slug: "alice-vscode", turn: 1 },
|
|
1626
|
-
]);
|
|
1627
|
-
});
|
|
1628
|
-
|
|
1629
|
-
// ---------------------------------------------------------------------------
|
|
1630
|
-
// Per-page error isolation + on-throw telemetry
|
|
1631
|
-
// ---------------------------------------------------------------------------
|
|
1632
|
-
|
|
1633
|
-
test("one slug's page-read failing isolates the error — other slugs still render and the corrupt slug records `status: corrupt`", async () => {
|
|
1634
|
-
// Two slugs rank into top-K together. Carol's page reads cleanly; alice's
|
|
1635
|
-
// `readPage` throws a ZodError mimicking the real "unrecognized
|
|
1636
|
-
// frontmatter key" failure that motivated this work. Before the fix, the
|
|
1637
|
-
// bare `Promise.all` rejected and the entire turn lost its block AND its
|
|
1638
|
-
// activation log row. With per-page isolation, carol still renders and
|
|
1639
|
-
// the activation log row marks alice as `corrupt` (telemetry remains
|
|
1640
|
-
// observable for triage).
|
|
1641
|
-
const zodErr = z.object({ x: z.string() }).safeParse({ x: 1 }).error!;
|
|
1642
|
-
pageStoreState.failingSlugs.set("alice-vscode", zodErr);
|
|
1643
|
-
stageTurn([
|
|
1644
|
-
{ slug: "alice-vscode", denseScore: 0.95 },
|
|
1645
|
-
{ slug: "carol-jazz", denseScore: 0.9 },
|
|
1646
|
-
]);
|
|
1647
|
-
|
|
1648
|
-
const result = await injectMemoryV2Block({
|
|
1649
|
-
database: db,
|
|
1650
|
-
conversationId: "conv-1",
|
|
1651
|
-
currentTurn: 1,
|
|
1652
|
-
recentTurnPairs: [
|
|
1653
|
-
{ assistantMessage: "", userMessage: "music and editors" },
|
|
1654
|
-
],
|
|
1655
|
-
nowText: "Now",
|
|
1656
|
-
messageId: "msg-1",
|
|
1657
|
-
config: makeConfig(),
|
|
1658
|
-
});
|
|
1659
|
-
|
|
1660
|
-
// (a) Block is non-null and contains content from the OTHER slug; alice
|
|
1661
|
-
// is dropped from the rendered block but does not poison the batch.
|
|
1662
|
-
expect(result.block).not.toBeNull();
|
|
1663
|
-
expect(result.block).toContain("# memory/concepts/carol-jazz.md");
|
|
1664
|
-
expect(result.block).not.toContain("# memory/concepts/alice-vscode.md");
|
|
1665
|
-
|
|
1666
|
-
// (b) Activation log row exists with carol `injected` and alice
|
|
1667
|
-
// `corrupt`. Status `corrupt` is reserved for read-time throws and is
|
|
1668
|
-
// distinct from `page_missing` (which is null-return / file vanished).
|
|
1669
|
-
expect(telemetryState.recordCalls.length).toBe(1);
|
|
1670
|
-
const row = telemetryState.recordCalls[0] as {
|
|
1671
|
-
mode: string;
|
|
1672
|
-
concepts: Array<{ slug: string; status: string }>;
|
|
1673
|
-
};
|
|
1674
|
-
expect(row.mode).toBe("per-turn");
|
|
1675
|
-
const byslug = new Map(row.concepts.map((c) => [c.slug, c]));
|
|
1676
|
-
expect(byslug.get("alice-vscode")!.status).toBe("corrupt");
|
|
1677
|
-
expect(byslug.get("carol-jazz")!.status).toBe("injected");
|
|
1678
|
-
|
|
1679
|
-
// (c) Both slugs land in `toInject` and `everInjected` — same handling
|
|
1680
|
-
// as `page_missing` (see the phantom-slug test): the slug was attempted
|
|
1681
|
-
// this turn, telemetry records the outcome, and we don't keep re-trying
|
|
1682
|
-
// a stale Qdrant / edge-index entry on every subsequent turn.
|
|
1683
|
-
expect(new Set(result.toInject)).toEqual(
|
|
1684
|
-
new Set(["alice-vscode", "carol-jazz"]),
|
|
1685
|
-
);
|
|
1686
|
-
const persisted = await hydrate(db, "conv-1");
|
|
1687
|
-
const everInjectedSlugs = persisted!.everInjected.map((e) => e.slug);
|
|
1688
|
-
expect(new Set(everInjectedSlugs)).toEqual(
|
|
1689
|
-
new Set(["alice-vscode", "carol-jazz"]),
|
|
1690
|
-
);
|
|
1691
|
-
});
|
|
1692
|
-
|
|
1693
|
-
test("a throw before renderInjectionBlock still flushes telemetry as `mode: errored` and re-throws", async () => {
|
|
1694
|
-
// The activation-state save throws — the most realistic non-render
|
|
1695
|
-
// failure mode (transient SQLite write error mid-injection). The
|
|
1696
|
-
// `injectMemoryV2Block` outer try/finally must (a) flush an activation
|
|
1697
|
-
// log row tagged `mode: "errored"` so silent failures stay observable
|
|
1698
|
-
// in the database, and (b) re-throw so callers (e.g. `prepareMemory`'s
|
|
1699
|
-
// outer catch) see the original error and can degrade gracefully.
|
|
1700
|
-
activationStoreState.saveShouldThrow = true;
|
|
1701
|
-
stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
|
|
1702
|
-
|
|
1703
|
-
let threw: unknown = undefined;
|
|
1704
|
-
try {
|
|
1705
|
-
await injectMemoryV2Block({
|
|
1706
|
-
database: db,
|
|
1707
|
-
conversationId: "conv-1",
|
|
1708
|
-
currentTurn: 1,
|
|
1709
|
-
recentTurnPairs: [
|
|
1710
|
-
{ assistantMessage: "", userMessage: "Alice's editor" },
|
|
1711
|
-
],
|
|
1712
|
-
nowText: "Now",
|
|
1713
|
-
messageId: "msg-1",
|
|
1714
|
-
config: makeConfig(),
|
|
1715
|
-
});
|
|
1716
|
-
} catch (err) {
|
|
1717
|
-
threw = err;
|
|
1718
|
-
}
|
|
1719
|
-
|
|
1720
|
-
// The original error propagates to the caller.
|
|
1721
|
-
expect(threw).toBeInstanceOf(Error);
|
|
1722
|
-
expect((threw as Error).message).toContain(
|
|
1723
|
-
"simulated activation-store save failure",
|
|
1724
|
-
);
|
|
1725
|
-
|
|
1726
|
-
// A telemetry row was still written, tagged `errored`. `concepts` is
|
|
1727
|
-
// empty because the throw fired before the row-builder ran — that's
|
|
1728
|
-
// expected and documented as part of the contract.
|
|
1729
|
-
expect(telemetryState.recordCalls.length).toBe(1);
|
|
1730
|
-
const row = telemetryState.recordCalls[0] as {
|
|
1731
|
-
mode: string;
|
|
1732
|
-
conversationId: string;
|
|
1733
|
-
turn: number;
|
|
1734
|
-
concepts: unknown[];
|
|
1735
|
-
};
|
|
1736
|
-
expect(row.mode).toBe("errored");
|
|
1737
|
-
expect(row.conversationId).toBe("conv-1");
|
|
1738
|
-
expect(row.turn).toBe(1);
|
|
1739
|
-
expect(row.concepts).toEqual([]);
|
|
1740
|
-
});
|
|
1741
|
-
|
|
1742
|
-
test("activation pipeline routes through `finalizeInjection` — telemetry shape and config snapshot match the contract", async () => {
|
|
1743
|
-
// Pure-refactor regression check: `injectMemoryV2Block` now delegates the
|
|
1744
|
-
// tail (state save + render + telemetry finalization + log write) to a
|
|
1745
|
-
// private `finalizeInjection` helper. This test asserts the helper is
|
|
1746
|
-
// exercised by verifying `recordMemoryV2ActivationLog` is called with the
|
|
1747
|
-
// same arg shape as before — same conversationId/turn/mode, same config
|
|
1748
|
-
// snapshot, and a fully populated concept row whose status was finalized
|
|
1749
|
-
// to `"injected"` on the freshly-attached slug.
|
|
1750
|
-
stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
|
|
1751
|
-
|
|
1752
|
-
const result = await injectMemoryV2Block({
|
|
1753
|
-
database: db,
|
|
1754
|
-
conversationId: "conv-finalize",
|
|
1755
|
-
currentTurn: 7,
|
|
1756
|
-
recentTurnPairs: [
|
|
1757
|
-
{ assistantMessage: "", userMessage: "Alice's editor" },
|
|
1758
|
-
],
|
|
1759
|
-
nowText: "Now",
|
|
1760
|
-
messageId: "msg-finalize",
|
|
1761
|
-
config: makeConfig(),
|
|
1762
|
-
});
|
|
1763
|
-
|
|
1764
|
-
// The helper rendered + persisted just like the original tail did.
|
|
1765
|
-
expect(result.block).toContain("alice-vscode");
|
|
1766
|
-
expect(result.toInject).toEqual(["alice-vscode"]);
|
|
1767
|
-
|
|
1768
|
-
expect(telemetryState.recordCalls.length).toBe(1);
|
|
1769
|
-
const row = telemetryState.recordCalls[0] as {
|
|
1770
|
-
conversationId: string;
|
|
1771
|
-
turn: number;
|
|
1772
|
-
mode: string;
|
|
1773
|
-
concepts: Array<{
|
|
1774
|
-
slug: string;
|
|
1775
|
-
status: string;
|
|
1776
|
-
finalActivation: number;
|
|
1777
|
-
}>;
|
|
1778
|
-
config: {
|
|
1779
|
-
d: number;
|
|
1780
|
-
c_user: number;
|
|
1781
|
-
c_assistant: number;
|
|
1782
|
-
c_now: number;
|
|
1783
|
-
k: number;
|
|
1784
|
-
hops: number;
|
|
1785
|
-
top_k: number;
|
|
1786
|
-
epsilon: number;
|
|
1787
|
-
};
|
|
1788
|
-
};
|
|
1789
|
-
expect(row.conversationId).toBe("conv-finalize");
|
|
1790
|
-
expect(row.turn).toBe(7);
|
|
1791
|
-
expect(row.mode).toBe("per-turn");
|
|
1792
|
-
// Config snapshot must include all eight tunables — proves the helper is
|
|
1793
|
-
// pulling from `config.memory.v2` rather than synthesizing a partial.
|
|
1794
|
-
expect(Object.keys(row.config).sort()).toEqual(
|
|
1795
|
-
[
|
|
1796
|
-
"c_assistant",
|
|
1797
|
-
"c_now",
|
|
1798
|
-
"c_user",
|
|
1799
|
-
"d",
|
|
1800
|
-
"epsilon",
|
|
1801
|
-
"hops",
|
|
1802
|
-
"k",
|
|
1803
|
-
"top_k",
|
|
1804
|
-
].sort(),
|
|
1805
|
-
);
|
|
1806
|
-
// Status finalization ran inside the helper — alice was selected and
|
|
1807
|
-
// rendered, so its row reads `injected`.
|
|
1808
|
-
const aliceRow = row.concepts.find((c) => c.slug === "alice-vscode");
|
|
1809
|
-
expect(aliceRow?.status).toBe("injected");
|
|
1810
|
-
});
|
|
1811
|
-
|
|
1812
|
-
// ---------------------------------------------------------------------------
|
|
1813
|
-
// Router mode (flag-gated)
|
|
1814
|
-
// ---------------------------------------------------------------------------
|
|
1815
|
-
|
|
1816
|
-
describe("router mode", () => {
|
|
1817
|
-
test("flag-on: router-selected slugs render and append to everInjected", async () => {
|
|
1818
|
-
// Router picks alice. The activation pipeline never runs — we don't
|
|
1819
|
-
// stage any qdrant responses here, and that's intentional. The
|
|
1820
|
-
// candidate set comes straight from the router's `selectedSlugs`.
|
|
1821
|
-
routerState.nextResult = {
|
|
1822
|
-
selectedSlugs: ["alice-vscode"],
|
|
1823
|
-
failureReason: null,
|
|
1824
|
-
};
|
|
1825
|
-
|
|
1826
|
-
const result = await injectMemoryV2Block({
|
|
1827
|
-
database: db,
|
|
1828
|
-
conversationId: "conv-router-1",
|
|
1829
|
-
currentTurn: 1,
|
|
1830
|
-
recentTurnPairs: [
|
|
1831
|
-
{ assistantMessage: "", userMessage: "Tell me about Alice" },
|
|
1832
|
-
],
|
|
1833
|
-
nowText: "Now",
|
|
1834
|
-
messageId: "msg-1",
|
|
1835
|
-
config: makeConfig({ router: { enabled: true } }),
|
|
1836
|
-
});
|
|
1837
|
-
|
|
1838
|
-
expect(routerState.callCount).toBe(1);
|
|
1839
|
-
expect(result.toInject).toEqual(["alice-vscode"]);
|
|
1840
|
-
expect(result.block).not.toBeNull();
|
|
1841
|
-
expect(result.block).toContain("# memory/concepts/alice-vscode.md");
|
|
1842
|
-
|
|
1843
|
-
const persisted = await hydrate(db, "conv-router-1");
|
|
1844
|
-
expect(persisted!.everInjected).toEqual([
|
|
1845
|
-
{ slug: "alice-vscode", turn: 1 },
|
|
1846
|
-
]);
|
|
1847
|
-
// Router mode persists an empty sparse activation map — the router
|
|
1848
|
-
// does not compute spreading-activation scores.
|
|
1849
|
-
expect(persisted!.state).toEqual({});
|
|
1850
|
-
|
|
1851
|
-
// Telemetry: success rows get `mode: "router"` and `source: "router"`,
|
|
1852
|
-
// with all activation fields zeroed.
|
|
1853
|
-
expect(telemetryState.recordCalls.length).toBe(1);
|
|
1854
|
-
const row = telemetryState.recordCalls[0] as {
|
|
1855
|
-
mode: string;
|
|
1856
|
-
concepts: Array<{
|
|
1857
|
-
slug: string;
|
|
1858
|
-
source: string;
|
|
1859
|
-
status: string;
|
|
1860
|
-
finalActivation: number;
|
|
1861
|
-
ownActivation: number;
|
|
1862
|
-
}>;
|
|
1863
|
-
};
|
|
1864
|
-
expect(row.mode).toBe("router");
|
|
1865
|
-
const aliceRow = row.concepts.find((c) => c.slug === "alice-vscode");
|
|
1866
|
-
expect(aliceRow).toBeDefined();
|
|
1867
|
-
// Default-stub provenance is `tier3:0` (single-batch path); see the
|
|
1868
|
-
// runRouter mock for the synthesis rule.
|
|
1869
|
-
expect(aliceRow!.source).toBe("tier3:0");
|
|
1870
|
-
expect(aliceRow!.status).toBe("injected");
|
|
1871
|
-
expect(aliceRow!.finalActivation).toBe(0);
|
|
1872
|
-
expect(aliceRow!.ownActivation).toBe(0);
|
|
1873
|
-
});
|
|
1874
|
-
|
|
1875
|
-
test("flag-on: saturated index (every page already injected) skips the router LLM call", async () => {
|
|
1876
|
-
// Turn 1 — normal router path injects alice.
|
|
1877
|
-
routerState.nextResult = {
|
|
1878
|
-
selectedSlugs: ["alice-vscode"],
|
|
1879
|
-
failureReason: null,
|
|
1880
|
-
};
|
|
1881
|
-
await injectMemoryV2Block({
|
|
1882
|
-
database: db,
|
|
1883
|
-
conversationId: "conv-router-saturated",
|
|
1884
|
-
currentTurn: 1,
|
|
1885
|
-
recentTurnPairs: [
|
|
1886
|
-
{ assistantMessage: "", userMessage: "Tell me about Alice" },
|
|
1887
|
-
],
|
|
1888
|
-
nowText: "Now",
|
|
1889
|
-
messageId: "msg-1",
|
|
1890
|
-
config: makeConfig({ router: { enabled: true } }),
|
|
1891
|
-
});
|
|
1892
|
-
|
|
1893
|
-
// Mark every page in the index as already injected — the state a
|
|
1894
|
-
// small workspace reaches a few turns into any conversation.
|
|
1895
|
-
const { getPageIndex } = await import("../page-index.js");
|
|
1896
|
-
const index = await getPageIndex(tmpWorkspace);
|
|
1897
|
-
const seeded = await hydrate(db, "conv-router-saturated");
|
|
1898
|
-
await save(db, "conv-router-saturated", {
|
|
1899
|
-
...seeded!,
|
|
1900
|
-
everInjected: index.entries.map((e) => ({ slug: e.slug, turn: 1 })),
|
|
1901
|
-
});
|
|
1902
|
-
|
|
1903
|
-
// Turn 2 — the router must not be called: any selection would dedupe
|
|
1904
|
-
// against everInjected and render nothing.
|
|
1905
|
-
const callsBefore = routerState.callCount;
|
|
1906
|
-
routerState.nextResult = {
|
|
1907
|
-
selectedSlugs: ["bob-coffee"],
|
|
1908
|
-
failureReason: null,
|
|
1909
|
-
};
|
|
1910
|
-
const result = await injectMemoryV2Block({
|
|
1911
|
-
database: db,
|
|
1912
|
-
conversationId: "conv-router-saturated",
|
|
1913
|
-
currentTurn: 2,
|
|
1914
|
-
recentTurnPairs: [{ assistantMessage: "ok", userMessage: "and Bob?" }],
|
|
1915
|
-
nowText: "Now",
|
|
1916
|
-
messageId: "msg-2",
|
|
1917
|
-
config: makeConfig({ router: { enabled: true } }),
|
|
1918
|
-
});
|
|
1919
|
-
|
|
1920
|
-
expect(routerState.callCount).toBe(callsBefore);
|
|
1921
|
-
expect(result.block).toBeNull();
|
|
1922
|
-
expect(result.toInject).toEqual([]);
|
|
1923
|
-
|
|
1924
|
-
// State still advanced; everInjected preserved for future dedupe.
|
|
1925
|
-
const persisted = await hydrate(db, "conv-router-saturated");
|
|
1926
|
-
expect(persisted!.currentTurn).toBe(2);
|
|
1927
|
-
expect(persisted!.messageId).toBe("msg-2");
|
|
1928
|
-
expect(persisted!.everInjected.length).toBe(index.entries.length);
|
|
1929
|
-
|
|
1930
|
-
// Telemetry row stays in router mode with every slug carried over.
|
|
1931
|
-
const row = telemetryState.recordCalls.at(-1) as {
|
|
1932
|
-
mode: string;
|
|
1933
|
-
concepts: Array<{ source: string; status: string }>;
|
|
1934
|
-
};
|
|
1935
|
-
expect(row.mode).toBe("router");
|
|
1936
|
-
expect(row.concepts.length).toBe(index.entries.length);
|
|
1937
|
-
for (const concept of row.concepts) {
|
|
1938
|
-
expect(concept.source).toBe("carry_over");
|
|
1939
|
-
// `finalizeInjection` rewrites the placeholder status: slugs already
|
|
1940
|
-
// in everInjected are reported as in_context.
|
|
1941
|
-
expect(concept.status).toBe("in_context");
|
|
1942
|
-
}
|
|
1943
|
-
});
|
|
1944
|
-
|
|
1945
|
-
test("flag-on: router failure logs warn, writes mode:`errored` telemetry, returns null block", async () => {
|
|
1946
|
-
routerState.nextResult = {
|
|
1947
|
-
selectedSlugs: [],
|
|
1948
|
-
failureReason: "api_error",
|
|
1949
|
-
};
|
|
1950
|
-
|
|
1951
|
-
const result = await injectMemoryV2Block({
|
|
1952
|
-
database: db,
|
|
1953
|
-
conversationId: "conv-router-fail",
|
|
1954
|
-
currentTurn: 3,
|
|
1955
|
-
recentTurnPairs: [{ assistantMessage: "ok", userMessage: "anything" }],
|
|
1956
|
-
nowText: "Now",
|
|
1957
|
-
messageId: "msg-fail",
|
|
1958
|
-
config: makeConfig({ router: { enabled: true } }),
|
|
1959
|
-
});
|
|
1960
|
-
|
|
1961
|
-
expect(result.block).toBeNull();
|
|
1962
|
-
expect(result.toInject).toEqual([]);
|
|
1963
|
-
|
|
1964
|
-
// Stub state still advanced.
|
|
1965
|
-
const persisted = await hydrate(db, "conv-router-fail");
|
|
1966
|
-
expect(persisted).not.toBeNull();
|
|
1967
|
-
expect(persisted!.currentTurn).toBe(3);
|
|
1968
|
-
expect(persisted!.messageId).toBe("msg-fail");
|
|
1969
|
-
expect(persisted!.state).toEqual({});
|
|
1970
|
-
expect(persisted!.everInjected).toEqual([]);
|
|
1971
|
-
|
|
1972
|
-
// Single telemetry row with `mode: "errored"` (not `"router"`).
|
|
1973
|
-
expect(telemetryState.recordCalls.length).toBe(1);
|
|
1974
|
-
const row = telemetryState.recordCalls[0] as {
|
|
1975
|
-
mode: string;
|
|
1976
|
-
conversationId: string;
|
|
1977
|
-
turn: number;
|
|
1978
|
-
concepts: unknown[];
|
|
1979
|
-
};
|
|
1980
|
-
expect(row.mode).toBe("errored");
|
|
1981
|
-
expect(row.conversationId).toBe("conv-router-fail");
|
|
1982
|
-
expect(row.turn).toBe(3);
|
|
1983
|
-
expect(row.concepts).toEqual([]);
|
|
1984
|
-
});
|
|
1985
|
-
|
|
1986
|
-
test("flag-on: router-failure path swallows a save() error and returns block:null instead of throwing", async () => {
|
|
1987
|
-
// PR 30176 refactored router-failure handling to delegate to
|
|
1988
|
-
// `finalizeInjection`. That regressed the prior inline log-and-continue
|
|
1989
|
-
// semantics on the router-failure path: a transient SQLite write
|
|
1990
|
-
// throwing during the stub-state save now aborted the whole turn
|
|
1991
|
-
// because `finalizeInjection`'s try/catch re-threw caughtErr at the end.
|
|
1992
|
-
//
|
|
1993
|
-
// This test stages exactly that scenario — router returns
|
|
1994
|
-
// `failureReason: api_error` AND `save()` throws — and asserts the
|
|
1995
|
-
// turn completes with `{ block: null, toInject: [] }` rather than
|
|
1996
|
-
// propagating the SQLite error to `prepareMemory`.
|
|
1997
|
-
routerState.nextResult = {
|
|
1998
|
-
selectedSlugs: [],
|
|
1999
|
-
failureReason: "api_error",
|
|
2000
|
-
};
|
|
2001
|
-
activationStoreState.saveShouldThrow = true;
|
|
2002
|
-
|
|
2003
|
-
let threw: unknown = undefined;
|
|
2004
|
-
let result: Awaited<ReturnType<typeof injectMemoryV2Block>> | undefined;
|
|
2005
|
-
try {
|
|
2006
|
-
result = await injectMemoryV2Block({
|
|
2007
|
-
database: db,
|
|
2008
|
-
conversationId: "conv-router-fail-save-throws",
|
|
2009
|
-
currentTurn: 5,
|
|
2010
|
-
recentTurnPairs: [
|
|
2011
|
-
{ assistantMessage: "ok", userMessage: "anything" },
|
|
2012
|
-
],
|
|
2013
|
-
nowText: "Now",
|
|
2014
|
-
messageId: "msg-fail-save",
|
|
2015
|
-
config: makeConfig({ router: { enabled: true } }),
|
|
2016
|
-
});
|
|
2017
|
-
} catch (err) {
|
|
2018
|
-
threw = err;
|
|
2019
|
-
}
|
|
2020
|
-
|
|
2021
|
-
expect(threw).toBeUndefined();
|
|
2022
|
-
expect(result).toBeDefined();
|
|
2023
|
-
expect(result!.block).toBeNull();
|
|
2024
|
-
expect(result!.toInject).toEqual([]);
|
|
2025
|
-
|
|
2026
|
-
// Telemetry still flushes with `mode: "errored"` so the failure stays
|
|
2027
|
-
// observable — the same row the inline pre-refactor path emitted.
|
|
2028
|
-
expect(telemetryState.recordCalls.length).toBe(1);
|
|
2029
|
-
const row = telemetryState.recordCalls[0] as {
|
|
2030
|
-
mode: string;
|
|
2031
|
-
concepts: unknown[];
|
|
2032
|
-
};
|
|
2033
|
-
expect(row.mode).toBe("errored");
|
|
2034
|
-
expect(row.concepts).toEqual([]);
|
|
2035
|
-
});
|
|
2036
|
-
|
|
2037
|
-
test("flag-on: router abstention (empty selectedSlugs, no failure) writes mode:`router` row with no injected pages", async () => {
|
|
2038
|
-
routerState.nextResult = {
|
|
2039
|
-
selectedSlugs: [],
|
|
2040
|
-
failureReason: null,
|
|
2041
|
-
};
|
|
2042
|
-
|
|
2043
|
-
const result = await injectMemoryV2Block({
|
|
2044
|
-
database: db,
|
|
2045
|
-
conversationId: "conv-router-abstain",
|
|
2046
|
-
currentTurn: 1,
|
|
2047
|
-
recentTurnPairs: [{ assistantMessage: "", userMessage: "small talk" }],
|
|
2048
|
-
nowText: "Now",
|
|
2049
|
-
messageId: "msg-abstain",
|
|
2050
|
-
config: makeConfig({ router: { enabled: true } }),
|
|
2051
|
-
});
|
|
2052
|
-
|
|
2053
|
-
expect(result.block).toBeNull();
|
|
2054
|
-
expect(result.toInject).toEqual([]);
|
|
2055
|
-
|
|
2056
|
-
// No prior everInjected to dedup against, so toInject is empty and
|
|
2057
|
-
// nothing renders. State still advanced.
|
|
2058
|
-
const persisted = await hydrate(db, "conv-router-abstain");
|
|
2059
|
-
expect(persisted!.everInjected).toEqual([]);
|
|
2060
|
-
expect(persisted!.currentTurn).toBe(1);
|
|
2061
|
-
|
|
2062
|
-
// Telemetry: `mode: "router"` row with zero injected pages.
|
|
2063
|
-
expect(telemetryState.recordCalls.length).toBe(1);
|
|
2064
|
-
const row = telemetryState.recordCalls[0] as {
|
|
2065
|
-
mode: string;
|
|
2066
|
-
concepts: Array<{ slug: string; status: string }>;
|
|
2067
|
-
};
|
|
2068
|
-
expect(row.mode).toBe("router");
|
|
2069
|
-
const injectedCount = row.concepts.filter(
|
|
2070
|
-
(c) => c.status === "injected",
|
|
2071
|
-
).length;
|
|
2072
|
-
expect(injectedCount).toBe(0);
|
|
2073
|
-
});
|
|
2074
|
-
|
|
2075
|
-
test("flag-on: router-selected slug whose page is missing on disk records `page_missing` and is NOT added to everInjected", async () => {
|
|
2076
|
-
routerState.nextResult = {
|
|
2077
|
-
selectedSlugs: ["phantom-router-slug"],
|
|
2078
|
-
failureReason: null,
|
|
2079
|
-
};
|
|
2080
|
-
|
|
2081
|
-
const result = await injectMemoryV2Block({
|
|
2082
|
-
database: db,
|
|
2083
|
-
conversationId: "conv-router-missing",
|
|
2084
|
-
currentTurn: 1,
|
|
2085
|
-
recentTurnPairs: [{ assistantMessage: "", userMessage: "phantom" }],
|
|
2086
|
-
nowText: "Now",
|
|
2087
|
-
messageId: "msg-missing",
|
|
2088
|
-
config: makeConfig({ router: { enabled: true } }),
|
|
2089
|
-
});
|
|
2090
|
-
|
|
2091
|
-
// No backing page → block collapses to null.
|
|
2092
|
-
expect(result.block).toBeNull();
|
|
2093
|
-
// toInject mirrors `newlyInjected` from `finalizeInjection` — the
|
|
2094
|
-
// missing slug still flowed through `slugsToRender` so it's recorded
|
|
2095
|
-
// here (matching the activation-mode phantom-slug contract).
|
|
2096
|
-
expect(result.toInject).toEqual(["phantom-router-slug"]);
|
|
2097
|
-
|
|
2098
|
-
// Activation-mode parity: the phantom slug DOES land in everInjected
|
|
2099
|
-
// so we don't infinite-retry it. (This matches the behavior the
|
|
2100
|
-
// existing `returns null block when toInject slugs all reference
|
|
2101
|
-
// missing pages` test asserts for activation mode.)
|
|
2102
|
-
const persisted = await hydrate(db, "conv-router-missing");
|
|
2103
|
-
expect(persisted!.everInjected).toEqual([
|
|
2104
|
-
{ slug: "phantom-router-slug", turn: 1 },
|
|
2105
|
-
]);
|
|
2106
|
-
|
|
2107
|
-
// Telemetry: `status: "page_missing"` for the phantom slug.
|
|
2108
|
-
expect(telemetryState.recordCalls.length).toBe(1);
|
|
2109
|
-
const row = telemetryState.recordCalls[0] as {
|
|
2110
|
-
mode: string;
|
|
2111
|
-
concepts: Array<{ slug: string; status: string; source: string }>;
|
|
2112
|
-
};
|
|
2113
|
-
expect(row.mode).toBe("router");
|
|
2114
|
-
const phantom = row.concepts.find(
|
|
2115
|
-
(c) => c.slug === "phantom-router-slug",
|
|
2116
|
-
);
|
|
2117
|
-
expect(phantom).toBeDefined();
|
|
2118
|
-
expect(phantom!.status).toBe("page_missing");
|
|
2119
|
-
expect(phantom!.source).toBe("tier3:0");
|
|
2120
|
-
});
|
|
2121
|
-
|
|
2122
|
-
test("flag-on: router re-picking a prior-everInjected slug does NOT re-render it; non-overlapping picks render and append to everInjected", async () => {
|
|
2123
|
-
// Turn 1: router picks alice. Standard append.
|
|
2124
|
-
routerState.nextResult = {
|
|
2125
|
-
selectedSlugs: ["alice-vscode"],
|
|
2126
|
-
failureReason: null,
|
|
2127
|
-
};
|
|
2128
|
-
const turn1 = await injectMemoryV2Block({
|
|
2129
|
-
database: db,
|
|
2130
|
-
conversationId: "conv-router-dedup",
|
|
2131
|
-
currentTurn: 1,
|
|
2132
|
-
recentTurnPairs: [
|
|
2133
|
-
{ assistantMessage: "", userMessage: "Tell me about Alice" },
|
|
2134
|
-
],
|
|
2135
|
-
nowText: "Now",
|
|
2136
|
-
messageId: "msg-1",
|
|
2137
|
-
config: makeConfig({ router: { enabled: true } }),
|
|
2138
|
-
});
|
|
2139
|
-
expect(turn1.toInject).toEqual(["alice-vscode"]);
|
|
2140
|
-
|
|
2141
|
-
// Turn 2: router re-picks alice (the "re-anchor" prompt branch) AND
|
|
2142
|
-
// adds bob. The block must NOT contain alice's body — her cached
|
|
2143
|
-
// attachment from turn 1 is still on the prior user message — but
|
|
2144
|
-
// must contain bob's.
|
|
2145
|
-
telemetryState.recordCalls.length = 0;
|
|
2146
|
-
routerState.nextResult = {
|
|
2147
|
-
selectedSlugs: ["alice-vscode", "bob-coffee"],
|
|
2148
|
-
failureReason: null,
|
|
2149
|
-
};
|
|
2150
|
-
const turn2 = await injectMemoryV2Block({
|
|
2151
|
-
database: db,
|
|
2152
|
-
conversationId: "conv-router-dedup",
|
|
2153
|
-
currentTurn: 2,
|
|
2154
|
-
recentTurnPairs: [
|
|
2155
|
-
{ assistantMessage: "Sure", userMessage: "And Bob?" },
|
|
2156
|
-
],
|
|
2157
|
-
nowText: "Now",
|
|
2158
|
-
messageId: "msg-2",
|
|
2159
|
-
config: makeConfig({ router: { enabled: true } }),
|
|
2160
|
-
});
|
|
2161
|
-
|
|
2162
|
-
// Re-picked alice was deduped; only bob is freshly injected.
|
|
2163
|
-
expect(turn2.toInject).toEqual(["bob-coffee"]);
|
|
2164
|
-
expect(turn2.block).not.toBeNull();
|
|
2165
|
-
expect(turn2.block).toContain("# memory/concepts/bob-coffee.md");
|
|
2166
|
-
expect(turn2.block).toContain("Bob takes his coffee");
|
|
2167
|
-
expect(turn2.block).not.toContain("VS Code");
|
|
2168
|
-
expect(turn2.block).not.toContain("# memory/concepts/alice-vscode.md");
|
|
2169
|
-
|
|
2170
|
-
// everInjected only gained bob — alice was already there.
|
|
2171
|
-
const persisted = await hydrate(db, "conv-router-dedup");
|
|
2172
|
-
expect(persisted!.everInjected).toEqual([
|
|
2173
|
-
{ slug: "alice-vscode", turn: 1 },
|
|
2174
|
-
{ slug: "bob-coffee", turn: 2 },
|
|
2175
|
-
]);
|
|
2176
|
-
});
|
|
2177
|
-
|
|
2178
|
-
test("flag-on: telemetry distinguishes `source: router` (router picks) from `source: carry_over` (prior-everInjected slugs the router did not re-pick)", async () => {
|
|
2179
|
-
// Turn 1: seed everInjected with alice.
|
|
2180
|
-
routerState.nextResult = {
|
|
2181
|
-
selectedSlugs: ["alice-vscode"],
|
|
2182
|
-
failureReason: null,
|
|
2183
|
-
};
|
|
2184
|
-
await injectMemoryV2Block({
|
|
2185
|
-
database: db,
|
|
2186
|
-
conversationId: "conv-router-source",
|
|
2187
|
-
currentTurn: 1,
|
|
2188
|
-
recentTurnPairs: [{ assistantMessage: "", userMessage: "Alice" }],
|
|
2189
|
-
nowText: "Now",
|
|
2190
|
-
messageId: "msg-1",
|
|
2191
|
-
config: makeConfig({ router: { enabled: true } }),
|
|
2192
|
-
});
|
|
2193
|
-
telemetryState.recordCalls.length = 0;
|
|
2194
|
-
|
|
2195
|
-
// Turn 2: router picks bob only. alice is still in everInjected but
|
|
2196
|
-
// not re-picked — her telemetry row must read `source: carry_over`,
|
|
2197
|
-
// not `source: router`.
|
|
2198
|
-
routerState.nextResult = {
|
|
2199
|
-
selectedSlugs: ["bob-coffee"],
|
|
2200
|
-
failureReason: null,
|
|
2201
|
-
};
|
|
2202
|
-
await injectMemoryV2Block({
|
|
2203
|
-
database: db,
|
|
2204
|
-
conversationId: "conv-router-source",
|
|
2205
|
-
currentTurn: 2,
|
|
2206
|
-
recentTurnPairs: [{ assistantMessage: "", userMessage: "Bob" }],
|
|
2207
|
-
nowText: "Now",
|
|
2208
|
-
messageId: "msg-2",
|
|
2209
|
-
config: makeConfig({ router: { enabled: true } }),
|
|
2210
|
-
});
|
|
2211
|
-
|
|
2212
|
-
expect(telemetryState.recordCalls.length).toBe(1);
|
|
2213
|
-
const row = telemetryState.recordCalls[0] as {
|
|
2214
|
-
mode: string;
|
|
2215
|
-
concepts: Array<{ slug: string; source: string; status: string }>;
|
|
2216
|
-
};
|
|
2217
|
-
expect(row.mode).toBe("router");
|
|
2218
|
-
const aliceRow = row.concepts.find((c) => c.slug === "alice-vscode");
|
|
2219
|
-
const bobRow = row.concepts.find((c) => c.slug === "bob-coffee");
|
|
2220
|
-
expect(aliceRow).toBeDefined();
|
|
2221
|
-
expect(bobRow).toBeDefined();
|
|
2222
|
-
expect(aliceRow!.source).toBe("carry_over");
|
|
2223
|
-
expect(aliceRow!.status).toBe("in_context");
|
|
2224
|
-
expect(bobRow!.source).toBe("tier3:0");
|
|
2225
|
-
expect(bobRow!.status).toBe("injected");
|
|
2226
|
-
});
|
|
2227
|
-
|
|
2228
|
-
test("flag-off (default): activation pipeline still runs unchanged", async () => {
|
|
2229
|
-
// Regression check — with the router flag explicitly off (the
|
|
2230
|
-
// production default), `runRouter` must never be called and the
|
|
2231
|
-
// activation pipeline drives the selection just like before.
|
|
2232
|
-
stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
|
|
2233
|
-
routerState.nextResult = {
|
|
2234
|
-
selectedSlugs: ["should-not-be-used"],
|
|
2235
|
-
failureReason: null,
|
|
2236
|
-
};
|
|
2237
|
-
|
|
2238
|
-
const result = await injectMemoryV2Block({
|
|
2239
|
-
database: db,
|
|
2240
|
-
conversationId: "conv-flag-off",
|
|
2241
|
-
currentTurn: 1,
|
|
2242
|
-
recentTurnPairs: [
|
|
2243
|
-
{ assistantMessage: "", userMessage: "Alice's editor" },
|
|
2244
|
-
],
|
|
2245
|
-
nowText: "Now",
|
|
2246
|
-
messageId: "msg-1",
|
|
2247
|
-
config: makeConfig({ router: { enabled: false } }),
|
|
2248
|
-
});
|
|
2249
|
-
|
|
2250
|
-
// Router was not called.
|
|
2251
|
-
expect(routerState.callCount).toBe(0);
|
|
2252
|
-
// Activation pipeline produced its normal result.
|
|
2253
|
-
expect(result.toInject).toEqual(["alice-vscode"]);
|
|
2254
|
-
expect(result.block).toContain("# memory/concepts/alice-vscode.md");
|
|
2255
|
-
|
|
2256
|
-
// Telemetry row carries the activation mode, not router.
|
|
2257
|
-
expect(telemetryState.recordCalls.length).toBe(1);
|
|
2258
|
-
const row = telemetryState.recordCalls[0] as { mode: string };
|
|
2259
|
-
expect(row.mode).toBe("per-turn");
|
|
2260
|
-
});
|
|
2261
|
-
|
|
2262
|
-
test("flag-on + mode='context-load': router runs (everInjected was cleared by onCompacted so dedupe is a no-op; abstention is accepted as the trade-off)", async () => {
|
|
2263
|
-
// Context-load is the full top-K bootstrap fired after compaction or
|
|
2264
|
-
// a fresh conversation reload. The earlier worry about the router's
|
|
2265
|
-
// `everInjected` dedupe filtering out post-compaction restorations
|
|
2266
|
-
// doesn't apply: `ConversationGraphMemory.onCompacted` calls
|
|
2267
|
-
// `evictCompactedTurnsV2` which empties the list before this code
|
|
2268
|
-
// runs. Router abstention here means no v2 pages this turn — that's
|
|
2269
|
-
// preferable to letting the activation graph pick something arbitrary.
|
|
2270
|
-
routerState.nextResult = {
|
|
2271
|
-
selectedSlugs: ["alice-vscode"],
|
|
2272
|
-
failureReason: null,
|
|
2273
|
-
};
|
|
2274
|
-
|
|
2275
|
-
const result = await injectMemoryV2Block({
|
|
2276
|
-
database: db,
|
|
2277
|
-
conversationId: "conv-context-load-router-on",
|
|
2278
|
-
currentTurn: 1,
|
|
2279
|
-
recentTurnPairs: [
|
|
2280
|
-
{ assistantMessage: "", userMessage: "Tell me about Alice" },
|
|
2281
|
-
],
|
|
2282
|
-
nowText: "Now",
|
|
2283
|
-
messageId: "msg-1",
|
|
2284
|
-
mode: "context-load",
|
|
2285
|
-
config: makeConfig({ router: { enabled: true } }),
|
|
2286
|
-
});
|
|
2287
|
-
|
|
2288
|
-
// Router was called on context-load too.
|
|
2289
|
-
expect(routerState.callCount).toBe(1);
|
|
2290
|
-
|
|
2291
|
-
// Router's picks were rendered.
|
|
2292
|
-
expect(result.toInject).toEqual(["alice-vscode"]);
|
|
2293
|
-
expect(result.block).toContain("# memory/concepts/alice-vscode.md");
|
|
2294
|
-
|
|
2295
|
-
// Telemetry row reflects the router mode, not the activation mode.
|
|
2296
|
-
expect(telemetryState.recordCalls.length).toBe(1);
|
|
2297
|
-
const row = telemetryState.recordCalls[0] as { mode: string };
|
|
2298
|
-
expect(row.mode).toBe("router");
|
|
2299
|
-
});
|
|
2300
|
-
});
|
|
2301
|
-
});
|