nlm-memory 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/plugins/marketplace.json +20 -0
- package/.github/workflows/ci.yml +30 -0
- package/LICENSE +151 -0
- package/README.md +119 -0
- package/dist/cli/classify-parity.d.ts +48 -0
- package/dist/cli/classify-parity.js +182 -0
- package/dist/cli/classify-parity.js.map +1 -0
- package/dist/cli/launchctl-helpers.d.ts +26 -0
- package/dist/cli/launchctl-helpers.js +42 -0
- package/dist/cli/launchctl-helpers.js.map +1 -0
- package/dist/cli/nlm.d.ts +25 -0
- package/dist/cli/nlm.js +832 -0
- package/dist/cli/nlm.js.map +1 -0
- package/dist/core/actions/actions-log.d.ts +40 -0
- package/dist/core/actions/actions-log.js +72 -0
- package/dist/core/actions/actions-log.js.map +1 -0
- package/dist/core/actions/overlay.d.ts +30 -0
- package/dist/core/actions/overlay.js +101 -0
- package/dist/core/actions/overlay.js.map +1 -0
- package/dist/core/adapters/aider.d.ts +33 -0
- package/dist/core/adapters/aider.js +167 -0
- package/dist/core/adapters/aider.js.map +1 -0
- package/dist/core/adapters/claude-code.d.ts +32 -0
- package/dist/core/adapters/claude-code.js +270 -0
- package/dist/core/adapters/claude-code.js.map +1 -0
- package/dist/core/adapters/common.d.ts +20 -0
- package/dist/core/adapters/common.js +60 -0
- package/dist/core/adapters/common.js.map +1 -0
- package/dist/core/adapters/from-source.d.ts +11 -0
- package/dist/core/adapters/from-source.js +55 -0
- package/dist/core/adapters/from-source.js.map +1 -0
- package/dist/core/adapters/hermes-agent.d.ts +34 -0
- package/dist/core/adapters/hermes-agent.js +192 -0
- package/dist/core/adapters/hermes-agent.js.map +1 -0
- package/dist/core/adapters/hermes.d.ts +31 -0
- package/dist/core/adapters/hermes.js +247 -0
- package/dist/core/adapters/hermes.js.map +1 -0
- package/dist/core/adapters/jsonl-generic.d.ts +56 -0
- package/dist/core/adapters/jsonl-generic.js +185 -0
- package/dist/core/adapters/jsonl-generic.js.map +1 -0
- package/dist/core/adapters/opencode.d.ts +36 -0
- package/dist/core/adapters/opencode.js +213 -0
- package/dist/core/adapters/opencode.js.map +1 -0
- package/dist/core/adapters/pi.d.ts +32 -0
- package/dist/core/adapters/pi.js +233 -0
- package/dist/core/adapters/pi.js.map +1 -0
- package/dist/core/classifier/prompt.d.ts +60 -0
- package/dist/core/classifier/prompt.js +178 -0
- package/dist/core/classifier/prompt.js.map +1 -0
- package/dist/core/dataset/build-dataset.d.ts +87 -0
- package/dist/core/dataset/build-dataset.js +335 -0
- package/dist/core/dataset/build-dataset.js.map +1 -0
- package/dist/core/embedding/chunk-body.d.ts +30 -0
- package/dist/core/embedding/chunk-body.js +60 -0
- package/dist/core/embedding/chunk-body.js.map +1 -0
- package/dist/core/embedding/embed-backfill.d.ts +36 -0
- package/dist/core/embedding/embed-backfill.js +168 -0
- package/dist/core/embedding/embed-backfill.js.map +1 -0
- package/dist/core/embedding/embed-normalize.d.ts +28 -0
- package/dist/core/embedding/embed-normalize.js +98 -0
- package/dist/core/embedding/embed-normalize.js.map +1 -0
- package/dist/core/facts/backfill-facts.d.ts +58 -0
- package/dist/core/facts/backfill-facts.js +169 -0
- package/dist/core/facts/backfill-facts.js.map +1 -0
- package/dist/core/facts/extract-facts.d.ts +20 -0
- package/dist/core/facts/extract-facts.js +37 -0
- package/dist/core/facts/extract-facts.js.map +1 -0
- package/dist/core/hook/citation-detect.d.ts +32 -0
- package/dist/core/hook/citation-detect.js +105 -0
- package/dist/core/hook/citation-detect.js.map +1 -0
- package/dist/core/hook/cite-memo.d.ts +20 -0
- package/dist/core/hook/cite-memo.js +68 -0
- package/dist/core/hook/cite-memo.js.map +1 -0
- package/dist/core/hook/claude-settings.d.ts +34 -0
- package/dist/core/hook/claude-settings.js +117 -0
- package/dist/core/hook/claude-settings.js.map +1 -0
- package/dist/core/hook/gate.d.ts +11 -0
- package/dist/core/hook/gate.js +19 -0
- package/dist/core/hook/gate.js.map +1 -0
- package/dist/core/hook/hook-log.d.ts +25 -0
- package/dist/core/hook/hook-log.js +28 -0
- package/dist/core/hook/hook-log.js.map +1 -0
- package/dist/core/hook/memo-sweep.d.ts +55 -0
- package/dist/core/hook/memo-sweep.js +134 -0
- package/dist/core/hook/memo-sweep.js.map +1 -0
- package/dist/core/hook/memo.d.ts +20 -0
- package/dist/core/hook/memo.js +66 -0
- package/dist/core/hook/memo.js.map +1 -0
- package/dist/core/hook/pointer-block.d.ts +14 -0
- package/dist/core/hook/pointer-block.js +19 -0
- package/dist/core/hook/pointer-block.js.map +1 -0
- package/dist/core/hook/select.d.ts +21 -0
- package/dist/core/hook/select.js +15 -0
- package/dist/core/hook/select.js.map +1 -0
- package/dist/core/hook/transcript.d.ts +31 -0
- package/dist/core/hook/transcript.js +103 -0
- package/dist/core/hook/transcript.js.map +1 -0
- package/dist/core/ingest/ingest-session.d.ts +40 -0
- package/dist/core/ingest/ingest-session.js +71 -0
- package/dist/core/ingest/ingest-session.js.map +1 -0
- package/dist/core/providers/provider-models.d.ts +24 -0
- package/dist/core/providers/provider-models.js +72 -0
- package/dist/core/providers/provider-models.js.map +1 -0
- package/dist/core/providers/provider-registry.d.ts +62 -0
- package/dist/core/providers/provider-registry.js +143 -0
- package/dist/core/providers/provider-registry.js.map +1 -0
- package/dist/core/recall/citation-log.d.ts +28 -0
- package/dist/core/recall/citation-log.js +90 -0
- package/dist/core/recall/citation-log.js.map +1 -0
- package/dist/core/recall/filter.d.ts +11 -0
- package/dist/core/recall/filter.js +20 -0
- package/dist/core/recall/filter.js.map +1 -0
- package/dist/core/recall/index.d.ts +6 -0
- package/dist/core/recall/index.js +5 -0
- package/dist/core/recall/index.js.map +1 -0
- package/dist/core/recall/match-fields.d.ts +10 -0
- package/dist/core/recall/match-fields.js +37 -0
- package/dist/core/recall/match-fields.js.map +1 -0
- package/dist/core/recall/query-log.d.ts +36 -0
- package/dist/core/recall/query-log.js +112 -0
- package/dist/core/recall/query-log.js.map +1 -0
- package/dist/core/recall/query-shape.d.ts +22 -0
- package/dist/core/recall/query-shape.js +64 -0
- package/dist/core/recall/query-shape.js.map +1 -0
- package/dist/core/recall/recall-service.d.ts +19 -0
- package/dist/core/recall/recall-service.js +252 -0
- package/dist/core/recall/recall-service.js.map +1 -0
- package/dist/core/recall/recent-log.d.ts +16 -0
- package/dist/core/recall/recent-log.js +46 -0
- package/dist/core/recall/recent-log.js.map +1 -0
- package/dist/core/recall/tokenize.d.ts +7 -0
- package/dist/core/recall/tokenize.js +18 -0
- package/dist/core/recall/tokenize.js.map +1 -0
- package/dist/core/recall/useful-scan.d.ts +52 -0
- package/dist/core/recall/useful-scan.js +300 -0
- package/dist/core/recall/useful-scan.js.map +1 -0
- package/dist/core/recall-facts/fact-query-log.d.ts +42 -0
- package/dist/core/recall-facts/fact-query-log.js +115 -0
- package/dist/core/recall-facts/fact-query-log.js.map +1 -0
- package/dist/core/recall-facts/fact-recall-service.d.ts +34 -0
- package/dist/core/recall-facts/fact-recall-service.js +246 -0
- package/dist/core/recall-facts/fact-recall-service.js.map +1 -0
- package/dist/core/scheduler/scan-once.d.ts +32 -0
- package/dist/core/scheduler/scan-once.js +100 -0
- package/dist/core/scheduler/scan-once.js.map +1 -0
- package/dist/core/scheduler/scheduler.d.ts +59 -0
- package/dist/core/scheduler/scheduler.js +158 -0
- package/dist/core/scheduler/scheduler.js.map +1 -0
- package/dist/core/sources/source-registry.d.ts +68 -0
- package/dist/core/sources/source-registry.js +208 -0
- package/dist/core/sources/source-registry.js.map +1 -0
- package/dist/core/storage/db-restore.d.ts +53 -0
- package/dist/core/storage/db-restore.js +113 -0
- package/dist/core/storage/db-restore.js.map +1 -0
- package/dist/core/storage/live-status.d.ts +15 -0
- package/dist/core/storage/live-status.js +43 -0
- package/dist/core/storage/live-status.js.map +1 -0
- package/dist/core/storage/migrate.d.ts +14 -0
- package/dist/core/storage/migrate.js +52 -0
- package/dist/core/storage/migrate.js.map +1 -0
- package/dist/core/storage/sqlite-fact-store.d.ts +50 -0
- package/dist/core/storage/sqlite-fact-store.js +256 -0
- package/dist/core/storage/sqlite-fact-store.js.map +1 -0
- package/dist/core/storage/sqlite-session-store.d.ts +152 -0
- package/dist/core/storage/sqlite-session-store.js +587 -0
- package/dist/core/storage/sqlite-session-store.js.map +1 -0
- package/dist/hook/pre-compact-hook.d.ts +26 -0
- package/dist/hook/pre-compact-hook.js +94 -0
- package/dist/hook/pre-compact-hook.js.map +1 -0
- package/dist/hook/prompt-recall-hook.d.ts +23 -0
- package/dist/hook/prompt-recall-hook.js +141 -0
- package/dist/hook/prompt-recall-hook.js.map +1 -0
- package/dist/hook/session-end-hook.d.ts +18 -0
- package/dist/hook/session-end-hook.js +67 -0
- package/dist/hook/session-end-hook.js.map +1 -0
- package/dist/hook/session-start-hook.d.ts +25 -0
- package/dist/hook/session-start-hook.js +129 -0
- package/dist/hook/session-start-hook.js.map +1 -0
- package/dist/hook/stop-hook.d.ts +38 -0
- package/dist/hook/stop-hook.js +171 -0
- package/dist/hook/stop-hook.js.map +1 -0
- package/dist/hook/subagent-start-hook.d.ts +30 -0
- package/dist/hook/subagent-start-hook.js +108 -0
- package/dist/hook/subagent-start-hook.js.map +1 -0
- package/dist/http/app.d.ts +65 -0
- package/dist/http/app.js +1009 -0
- package/dist/http/app.js.map +1 -0
- package/dist/install/claude-code.d.ts +57 -0
- package/dist/install/claude-code.js +76 -0
- package/dist/install/claude-code.js.map +1 -0
- package/dist/install/codex.d.ts +82 -0
- package/dist/install/codex.js +277 -0
- package/dist/install/codex.js.map +1 -0
- package/dist/install/hermes-agent.d.ts +35 -0
- package/dist/install/hermes-agent.js +48 -0
- package/dist/install/hermes-agent.js.map +1 -0
- package/dist/install/hermes.d.ts +29 -0
- package/dist/install/hermes.js +52 -0
- package/dist/install/hermes.js.map +1 -0
- package/dist/install/ollama.d.ts +54 -0
- package/dist/install/ollama.js +178 -0
- package/dist/install/ollama.js.map +1 -0
- package/dist/install/setup.d.ts +37 -0
- package/dist/install/setup.js +339 -0
- package/dist/install/setup.js.map +1 -0
- package/dist/llm/classifier-box.d.ts +29 -0
- package/dist/llm/classifier-box.js +43 -0
- package/dist/llm/classifier-box.js.map +1 -0
- package/dist/llm/deepseek-client.d.ts +40 -0
- package/dist/llm/deepseek-client.js +114 -0
- package/dist/llm/deepseek-client.js.map +1 -0
- package/dist/llm/env-autoload.d.ts +8 -0
- package/dist/llm/env-autoload.js +54 -0
- package/dist/llm/env-autoload.js.map +1 -0
- package/dist/llm/ollama-client.d.ts +47 -0
- package/dist/llm/ollama-client.js +156 -0
- package/dist/llm/ollama-client.js.map +1 -0
- package/dist/mcp/server.d.ts +64 -0
- package/dist/mcp/server.js +430 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/ports/fact-store.d.ts +82 -0
- package/dist/ports/fact-store.js +16 -0
- package/dist/ports/fact-store.js.map +1 -0
- package/dist/ports/llm-client.d.ts +42 -0
- package/dist/ports/llm-client.js +14 -0
- package/dist/ports/llm-client.js.map +1 -0
- package/dist/ports/logger.d.ts +13 -0
- package/dist/ports/logger.js +8 -0
- package/dist/ports/logger.js.map +1 -0
- package/dist/ports/session-store.d.ts +29 -0
- package/dist/ports/session-store.js +9 -0
- package/dist/ports/session-store.js.map +1 -0
- package/dist/ports/transcript-adapter.d.ts +48 -0
- package/dist/ports/transcript-adapter.js +15 -0
- package/dist/ports/transcript-adapter.js.map +1 -0
- package/dist/shared/types.d.ts +129 -0
- package/dist/shared/types.js +6 -0
- package/dist/shared/types.js.map +1 -0
- package/dist/ui/assets/index-BA6IpU8g.css +1 -0
- package/dist/ui/assets/index-B_qIVV0k.js +69 -0
- package/dist/ui/index.html +13 -0
- package/docs/methodology/re-derivation-rate.md +112 -0
- package/docs/methodology/useful-hit-rate.md +79 -0
- package/docs/plans/2026-05-20-fts5-lexical-recall.md +1088 -0
- package/docs/plans/2026-05-20-recall-daemon-wedge-fix.md +662 -0
- package/docs/plans/2026-05-20-recall-hook-design.md +131 -0
- package/docs/plans/2026-05-20-recall-hook-implementation.md +1222 -0
- package/docs/plans/desktop-product.md +69 -0
- package/docs/plans/factstore-design.md +236 -0
- package/logs/CHANGELOG/CHANGELOG-2026.md +1389 -0
- package/logs/CHANGELOG/CHANGELOG.md +320 -0
- package/migrations/000_initial_schema.sql +174 -0
- package/migrations/001_entity_type_rename.sql +17 -0
- package/migrations/002_adapter_state_extend.sql +12 -0
- package/migrations/003_session_embeddings.sql +11 -0
- package/migrations/004_facts.sql +46 -0
- package/migrations/005_sources.sql +31 -0
- package/migrations/006_providers.sql +33 -0
- package/migrations/007_source_tokens.sql +17 -0
- package/migrations/008_fts_rebuild.sql +9 -0
- package/migrations/009_session_embedding_chunks.sql +46 -0
- package/migrations/010_sources_opencode.sql +30 -0
- package/migrations/011_sources_hermes_agent.sql +30 -0
- package/migrations/012_sources_aider.sql +30 -0
- package/migrations/013_adapter_state_failure_count.sql +12 -0
- package/package.json +56 -0
- package/plugin/.codex-plugin/plugin.json +22 -0
- package/plugin/.mcp.json +8 -0
- package/plugin/README.md +51 -0
- package/plugin/hooks/hooks.json +25 -0
- package/plugin/scripts/prompt-recall-hook.mjs +202 -0
- package/plugin/scripts/stop-hook.mjs +306 -0
- package/plugin-hermes-agent/README.md +49 -0
- package/plugin-hermes-agent/__init__.py +75 -0
- package/plugin-hermes-agent/plugin.yaml +15 -0
- package/scripts/backfill-citations.mjs +0 -0
- package/scripts/build-codex-plugin.mjs +61 -0
- package/scripts/deepseek-probe.mjs +67 -0
- package/scripts/extract-triples.mjs +207 -0
- package/scripts/longmemeval/embedding-cache.ts +77 -0
- package/scripts/longmemeval/fetch-dataset.sh +25 -0
- package/scripts/longmemeval/run-harness.ts +315 -0
- package/scripts/longmemeval/scorer.ts +99 -0
- package/scripts/longmemeval/tsconfig.json +9 -0
- package/scripts/longmemeval/types.ts +35 -0
- package/scripts/nlm-daily-digest.py +239 -0
- package/scripts/nlm-daily-digest.sh +28 -0
- package/src/cli/classify-parity.ts +257 -0
- package/src/cli/launchctl-helpers.ts +49 -0
- package/src/cli/nlm.ts +885 -0
- package/src/core/actions/actions-log.ts +118 -0
- package/src/core/actions/overlay.ts +117 -0
- package/src/core/adapters/aider.ts +205 -0
- package/src/core/adapters/claude-code.ts +293 -0
- package/src/core/adapters/common.ts +54 -0
- package/src/core/adapters/from-source.ts +57 -0
- package/src/core/adapters/hermes-agent.ts +240 -0
- package/src/core/adapters/hermes.ts +277 -0
- package/src/core/adapters/jsonl-generic.ts +208 -0
- package/src/core/adapters/opencode.ts +281 -0
- package/src/core/adapters/pi.ts +264 -0
- package/src/core/classifier/prompt.ts +200 -0
- package/src/core/dataset/build-dataset.ts +463 -0
- package/src/core/embedding/chunk-body.ts +76 -0
- package/src/core/embedding/embed-backfill.ts +210 -0
- package/src/core/embedding/embed-normalize.ts +135 -0
- package/src/core/facts/backfill-facts.ts +254 -0
- package/src/core/facts/extract-facts.ts +50 -0
- package/src/core/hook/citation-detect.ts +124 -0
- package/src/core/hook/cite-memo.ts +68 -0
- package/src/core/hook/claude-settings.ts +166 -0
- package/src/core/hook/gate.ts +25 -0
- package/src/core/hook/hook-log.ts +41 -0
- package/src/core/hook/memo-sweep.ts +164 -0
- package/src/core/hook/memo.ts +67 -0
- package/src/core/hook/pointer-block.ts +26 -0
- package/src/core/hook/select.ts +32 -0
- package/src/core/hook/transcript.ts +121 -0
- package/src/core/ingest/ingest-session.ts +111 -0
- package/src/core/providers/provider-models.ts +100 -0
- package/src/core/providers/provider-registry.ts +196 -0
- package/src/core/recall/citation-log.ts +108 -0
- package/src/core/recall/filter.ts +27 -0
- package/src/core/recall/index.ts +6 -0
- package/src/core/recall/match-fields.ts +40 -0
- package/src/core/recall/query-log.ts +149 -0
- package/src/core/recall/query-shape.ts +66 -0
- package/src/core/recall/recall-service.ts +320 -0
- package/src/core/recall/recent-log.ts +59 -0
- package/src/core/recall/tokenize.ts +18 -0
- package/src/core/recall/useful-scan.ts +336 -0
- package/src/core/recall-facts/fact-query-log.ts +150 -0
- package/src/core/recall-facts/fact-recall-service.ts +327 -0
- package/src/core/scheduler/scan-once.ts +142 -0
- package/src/core/scheduler/scheduler.ts +225 -0
- package/src/core/sources/source-registry.ts +260 -0
- package/src/core/storage/db-restore.ts +133 -0
- package/src/core/storage/live-status.ts +45 -0
- package/src/core/storage/migrate.ts +72 -0
- package/src/core/storage/sqlite-fact-store.ts +304 -0
- package/src/core/storage/sqlite-session-store.ts +765 -0
- package/src/hook/prompt-recall-hook.ts +174 -0
- package/src/hook/session-end-hook.ts +81 -0
- package/src/hook/session-start-hook.ts +165 -0
- package/src/hook/stop-hook.ts +236 -0
- package/src/http/app.ts +1114 -0
- package/src/install/claude-code.ts +128 -0
- package/src/install/codex.ts +367 -0
- package/src/install/hermes-agent.ts +76 -0
- package/src/install/hermes.ts +78 -0
- package/src/install/ollama.ts +208 -0
- package/src/install/setup.ts +368 -0
- package/src/llm/classifier-box.ts +64 -0
- package/src/llm/deepseek-client.ts +150 -0
- package/src/llm/env-autoload.ts +55 -0
- package/src/llm/ollama-client.ts +189 -0
- package/src/mcp/server.ts +534 -0
- package/src/ports/fact-store.ts +102 -0
- package/src/ports/llm-client.ts +52 -0
- package/src/ports/logger.ts +16 -0
- package/src/ports/session-store.ts +45 -0
- package/src/ports/transcript-adapter.ts +55 -0
- package/src/shared/types.ts +145 -0
- package/src/ui/App.tsx +58 -0
- package/src/ui/components/PromoteOpenButton.tsx +65 -0
- package/src/ui/components/SessionDrawer.tsx +136 -0
- package/src/ui/components/SideNav.tsx +162 -0
- package/src/ui/components/Skeleton.tsx +107 -0
- package/src/ui/index.html +13 -0
- package/src/ui/lib/actions.ts +30 -0
- package/src/ui/lib/api.ts +92 -0
- package/src/ui/lib/dataset.ts +141 -0
- package/src/ui/lib/registries.ts +155 -0
- package/src/ui/lib/view-settings.ts +41 -0
- package/src/ui/main.tsx +15 -0
- package/src/ui/pages/Live.tsx +229 -0
- package/src/ui/pages/Pulse.tsx +415 -0
- package/src/ui/pages/Recall.tsx +190 -0
- package/src/ui/pages/River.tsx +308 -0
- package/src/ui/pages/Search.tsx +93 -0
- package/src/ui/pages/Stub.tsx +9 -0
- package/src/ui/pages/Thread.tsx +262 -0
- package/src/ui/pages/settings/Classifier.tsx +227 -0
- package/src/ui/pages/settings/Data.tsx +190 -0
- package/src/ui/pages/settings/Index.tsx +65 -0
- package/src/ui/pages/settings/Labels.tsx +224 -0
- package/src/ui/pages/settings/Providers.tsx +305 -0
- package/src/ui/pages/settings/SettingsSubnav.tsx +28 -0
- package/src/ui/pages/settings/Sources.tsx +326 -0
- package/src/ui/pages/settings/Views.tsx +96 -0
- package/src/ui/styles.css +1766 -0
- package/src/ui/tsconfig.json +21 -0
- package/src/ui/vite.config.ts +19 -0
- package/tests/fixtures/claude_code/short_session.jsonl +2 -0
- package/tests/fixtures/claude_code/standard_iso.jsonl +4 -0
- package/tests/fixtures/claude_code/tool_heavy.jsonl +8 -0
- package/tests/fixtures/claude_code/with_subagent.jsonl +7 -0
- package/tests/fixtures/facts.ts +17 -0
- package/tests/fixtures/golden-corpus.ts +85 -0
- package/tests/fixtures/hermes/paired_request_dump.json +24 -0
- package/tests/fixtures/hermes/paired_session.json +23 -0
- package/tests/fixtures/hermes/request_dump.json +28 -0
- package/tests/fixtures/hermes/session_iso.json +38 -0
- package/tests/fixtures/hermes/session_unix.json +38 -0
- package/tests/fixtures/hermes/system_only.json +18 -0
- package/tests/fixtures/pi/error-connection-abort.jsonl +8 -0
- package/tests/fixtures/pi/short-successful.jsonl +5 -0
- package/tests/fixtures/pi/with-custom-message.jsonl +6 -0
- package/tests/fixtures/sessions.ts +22 -0
- package/tests/integration/backfill-facts.test.ts +362 -0
- package/tests/integration/citation-explicit.test.ts +111 -0
- package/tests/integration/cite-event.test.ts +169 -0
- package/tests/integration/cite-memo.test.ts +87 -0
- package/tests/integration/db-restore.test.ts +153 -0
- package/tests/integration/embed-backfill.test.ts +176 -0
- package/tests/integration/fact-supersedence.test.ts +313 -0
- package/tests/integration/fts-index.test.ts +60 -0
- package/tests/integration/getbyids-sqlite.test.ts +60 -0
- package/tests/integration/hermes-agent-hooks.test.ts +248 -0
- package/tests/integration/hook-claude-settings.test.ts +205 -0
- package/tests/integration/hook-log.test.ts +54 -0
- package/tests/integration/hook-memo.test.ts +68 -0
- package/tests/integration/hook-pre-compact.test.ts +105 -0
- package/tests/integration/hook-subagent-start.test.ts +102 -0
- package/tests/integration/http.test.ts +401 -0
- package/tests/integration/keyword-search-fts.test.ts +66 -0
- package/tests/integration/mcp-recall-logging.test.ts +88 -0
- package/tests/integration/mcp.test.ts +248 -0
- package/tests/integration/memo-sweep.test.ts +91 -0
- package/tests/integration/prompt-recall-hook.test.ts +88 -0
- package/tests/integration/provider-registry.test.ts +107 -0
- package/tests/integration/recall-golden.test.ts +59 -0
- package/tests/integration/recall-sqlite.test.ts +169 -0
- package/tests/integration/scheduler.test.ts +391 -0
- package/tests/integration/session-end-hook.test.ts +48 -0
- package/tests/integration/session-start-hook.test.ts +126 -0
- package/tests/integration/source-registry.test.ts +120 -0
- package/tests/integration/sqlite-fact-store.test.ts +346 -0
- package/tests/integration/stop-hook.test.ts +560 -0
- package/tests/integration/wal-checkpoint.test.ts +49 -0
- package/tests/unit/cli/launchctl-helpers.test.ts +60 -0
- package/tests/unit/core/adapters/aider.test.ts +230 -0
- package/tests/unit/core/adapters/claude-code.test.ts +118 -0
- package/tests/unit/core/adapters/hermes-agent.test.ts +329 -0
- package/tests/unit/core/adapters/hermes.test.ts +81 -0
- package/tests/unit/core/adapters/jsonl-generic.test.ts +142 -0
- package/tests/unit/core/adapters/opencode.test.ts +354 -0
- package/tests/unit/core/adapters/pi.test.ts +110 -0
- package/tests/unit/core/classifier/prompt.test.ts +126 -0
- package/tests/unit/core/embedding/chunk-body.test.ts +100 -0
- package/tests/unit/core/facts/extract-facts.test.ts +117 -0
- package/tests/unit/core/filter.test.ts +40 -0
- package/tests/unit/core/hook/citation-detect-cite-session.test.ts +96 -0
- package/tests/unit/core/hook/citation-detect.test.ts +124 -0
- package/tests/unit/core/hook/gate.test.ts +29 -0
- package/tests/unit/core/hook/pointer-block.test.ts +22 -0
- package/tests/unit/core/hook/select.test.ts +66 -0
- package/tests/unit/core/match-fields.test.ts +39 -0
- package/tests/unit/core/mcp-cite-session.test.ts +51 -0
- package/tests/unit/core/providers/provider-models.test.ts +101 -0
- package/tests/unit/core/query-shape.test.ts +92 -0
- package/tests/unit/core/recall-facts/fact-recall-service.test.ts +258 -0
- package/tests/unit/core/recall-service.test.ts +200 -0
- package/tests/unit/core/storage/live-status.test.ts +54 -0
- package/tests/unit/core/tokenize.test.ts +32 -0
- package/tests/unit/core/useful-scan.test.ts +537 -0
- package/tests/unit/llm/embed.test.ts +93 -0
- package/tests/unit/llm/ollama-client.test.ts +124 -0
- package/tests/unit/scripts/longmemeval-scorer.test.ts +114 -0
- package/tsconfig.json +31 -0
- package/tsconfig.test.json +11 -0
- package/vitest.config.ts +22 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider model discovery — runtime lookup of available models.
|
|
3
|
+
*
|
|
4
|
+
* Per-kind strategy:
|
|
5
|
+
* - ollama: GET {baseUrl}/api/tags
|
|
6
|
+
* - openai: GET {baseUrl}/models with Bearer key
|
|
7
|
+
* - openrouter: GET {baseUrl}/models with Bearer key
|
|
8
|
+
* - openai-compatible: GET {baseUrl}/models, key optional
|
|
9
|
+
* - deepseek: hardcoded (no public list endpoint)
|
|
10
|
+
* - anthropic: hardcoded (their /v1/models exists but
|
|
11
|
+
* requires beta header + returns subsets;
|
|
12
|
+
* a hardcoded list is more reliable)
|
|
13
|
+
*
|
|
14
|
+
* Returns a flat `string[]`. Errors throw — callers (the HTTP endpoint
|
|
15
|
+
* and connection-test) catch and surface to the user.
|
|
16
|
+
*/
|
|
17
|
+
const HARDCODED_MODELS = {
|
|
18
|
+
deepseek: ["deepseek-v4-flash", "deepseek-v4-pro", "deepseek-chat"],
|
|
19
|
+
anthropic: [
|
|
20
|
+
"claude-opus-4-7",
|
|
21
|
+
"claude-sonnet-4-6",
|
|
22
|
+
"claude-haiku-4-5-20251001",
|
|
23
|
+
],
|
|
24
|
+
};
|
|
25
|
+
export async function listModels(provider, opts = {}) {
|
|
26
|
+
const hardcoded = HARDCODED_MODELS[provider.kind];
|
|
27
|
+
if (hardcoded)
|
|
28
|
+
return [...hardcoded];
|
|
29
|
+
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
30
|
+
const timeoutMs = opts.timeoutMs ?? 10_000;
|
|
31
|
+
const baseUrl = (provider.baseUrl ?? "").replace(/\/+$/, "");
|
|
32
|
+
if (!baseUrl)
|
|
33
|
+
throw new Error(`${provider.name}: baseUrl not configured`);
|
|
34
|
+
if (provider.kind === "ollama") {
|
|
35
|
+
return fetchOllamaModels(baseUrl, fetchImpl, timeoutMs);
|
|
36
|
+
}
|
|
37
|
+
return fetchOpenAIModels(baseUrl, opts.apiKey ?? null, fetchImpl, timeoutMs);
|
|
38
|
+
}
|
|
39
|
+
async function fetchOllamaModels(baseUrl, fetchImpl, timeoutMs) {
|
|
40
|
+
const controller = new AbortController();
|
|
41
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
42
|
+
try {
|
|
43
|
+
const res = await fetchImpl(`${baseUrl}/api/tags`, { signal: controller.signal });
|
|
44
|
+
if (!res.ok)
|
|
45
|
+
throw new Error(`Ollama returned ${res.status}`);
|
|
46
|
+
const data = (await res.json());
|
|
47
|
+
const names = (data.models ?? []).map((m) => m.name).filter((n) => typeof n === "string");
|
|
48
|
+
return names.sort();
|
|
49
|
+
}
|
|
50
|
+
finally {
|
|
51
|
+
clearTimeout(timer);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async function fetchOpenAIModels(baseUrl, apiKey, fetchImpl, timeoutMs) {
|
|
55
|
+
const controller = new AbortController();
|
|
56
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
57
|
+
try {
|
|
58
|
+
const headers = {};
|
|
59
|
+
if (apiKey)
|
|
60
|
+
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
61
|
+
const res = await fetchImpl(`${baseUrl}/models`, { signal: controller.signal, headers });
|
|
62
|
+
if (!res.ok)
|
|
63
|
+
throw new Error(`${res.status} ${res.statusText}`);
|
|
64
|
+
const data = (await res.json());
|
|
65
|
+
const ids = (data.data ?? []).map((m) => m.id).filter((s) => typeof s === "string");
|
|
66
|
+
return ids.sort();
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
clearTimeout(timer);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=provider-models.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-models.js","sourceRoot":"","sources":["../../../src/core/providers/provider-models.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ProviderRegistry — CRUD over the `providers` table.
|
|
3
|
+
*
|
|
4
|
+
* One row per LLM endpoint the user has configured. The classifier reads
|
|
5
|
+
* this at boot to pick a provider/model; the UI lets users add their own.
|
|
6
|
+
*
|
|
7
|
+
* API keys live in the `api_key` column today. Phase 2 (Tauri shell)
|
|
8
|
+
* migrates them to the OS keychain; the API shape stays identical so this
|
|
9
|
+
* module's consumers don't change.
|
|
10
|
+
*
|
|
11
|
+
* `redact()` strips secrets on the way out — every HTTP response sends
|
|
12
|
+
* redacted rows, with the key only retrievable via getSecret() inside the
|
|
13
|
+
* daemon process.
|
|
14
|
+
*/
|
|
15
|
+
import type Database from "better-sqlite3";
|
|
16
|
+
export type ProviderKind = "deepseek" | "ollama" | "openai" | "anthropic" | "openrouter" | "openai-compatible";
|
|
17
|
+
export interface ProviderRow {
|
|
18
|
+
readonly id: number;
|
|
19
|
+
readonly kind: ProviderKind;
|
|
20
|
+
readonly name: string;
|
|
21
|
+
readonly baseUrl: string | null;
|
|
22
|
+
/** Always `null` on rows returned by `list()` / `get()`. Use `getSecret()`. */
|
|
23
|
+
readonly apiKey: string | null;
|
|
24
|
+
readonly hasApiKey: boolean;
|
|
25
|
+
readonly defaultModel: string | null;
|
|
26
|
+
readonly enabled: boolean;
|
|
27
|
+
readonly createdAt: string;
|
|
28
|
+
readonly updatedAt: string;
|
|
29
|
+
}
|
|
30
|
+
export interface ProviderInsert {
|
|
31
|
+
readonly kind: ProviderKind;
|
|
32
|
+
readonly name: string;
|
|
33
|
+
readonly baseUrl?: string | null;
|
|
34
|
+
readonly apiKey?: string | null;
|
|
35
|
+
readonly defaultModel?: string | null;
|
|
36
|
+
readonly enabled?: boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface ProviderUpdate {
|
|
39
|
+
readonly name?: string;
|
|
40
|
+
readonly baseUrl?: string | null;
|
|
41
|
+
readonly apiKey?: string | null;
|
|
42
|
+
readonly defaultModel?: string | null;
|
|
43
|
+
readonly enabled?: boolean;
|
|
44
|
+
}
|
|
45
|
+
export declare class ProviderRegistry {
|
|
46
|
+
private readonly db;
|
|
47
|
+
constructor(db: Database.Database);
|
|
48
|
+
list(): ProviderRow[];
|
|
49
|
+
get(id: number): ProviderRow | null;
|
|
50
|
+
getByName(name: string): ProviderRow | null;
|
|
51
|
+
/** Returns the secret. Use only inside the daemon — never echo to HTTP. */
|
|
52
|
+
getSecret(id: number): string | null;
|
|
53
|
+
insert(input: ProviderInsert): ProviderRow;
|
|
54
|
+
update(id: number, patch: ProviderUpdate): ProviderRow | null;
|
|
55
|
+
delete(id: number): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Seed defaults on an empty registry. Bridges from the legacy env-var
|
|
58
|
+
* setup: if DEEPSEEK_API_KEY is present, the DeepSeek row carries it
|
|
59
|
+
* forward; Ollama is always seeded since it needs no key.
|
|
60
|
+
*/
|
|
61
|
+
seedDefaults(): void;
|
|
62
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ProviderRegistry — CRUD over the `providers` table.
|
|
3
|
+
*
|
|
4
|
+
* One row per LLM endpoint the user has configured. The classifier reads
|
|
5
|
+
* this at boot to pick a provider/model; the UI lets users add their own.
|
|
6
|
+
*
|
|
7
|
+
* API keys live in the `api_key` column today. Phase 2 (Tauri shell)
|
|
8
|
+
* migrates them to the OS keychain; the API shape stays identical so this
|
|
9
|
+
* module's consumers don't change.
|
|
10
|
+
*
|
|
11
|
+
* `redact()` strips secrets on the way out — every HTTP response sends
|
|
12
|
+
* redacted rows, with the key only retrievable via getSecret() inside the
|
|
13
|
+
* daemon process.
|
|
14
|
+
*/
|
|
15
|
+
function rowFromDb(r, includeSecret) {
|
|
16
|
+
return {
|
|
17
|
+
id: r.id,
|
|
18
|
+
kind: r.kind,
|
|
19
|
+
name: r.name,
|
|
20
|
+
baseUrl: r.base_url,
|
|
21
|
+
apiKey: includeSecret ? r.api_key : null,
|
|
22
|
+
hasApiKey: r.api_key !== null && r.api_key.length > 0,
|
|
23
|
+
defaultModel: r.default_model,
|
|
24
|
+
enabled: r.enabled === 1,
|
|
25
|
+
createdAt: r.created_at,
|
|
26
|
+
updatedAt: r.updated_at,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const DEFAULT_BASE_URLS = {
|
|
30
|
+
deepseek: "https://api.deepseek.com",
|
|
31
|
+
ollama: "http://localhost:11434",
|
|
32
|
+
openai: "https://api.openai.com/v1",
|
|
33
|
+
anthropic: "https://api.anthropic.com",
|
|
34
|
+
openrouter: "https://openrouter.ai/api/v1",
|
|
35
|
+
"openai-compatible": null,
|
|
36
|
+
};
|
|
37
|
+
const DEFAULT_MODELS = {
|
|
38
|
+
deepseek: "deepseek-v4-flash",
|
|
39
|
+
ollama: "phi4-mini:latest",
|
|
40
|
+
openai: "gpt-4o-mini",
|
|
41
|
+
anthropic: "claude-haiku-4-5-20251001",
|
|
42
|
+
openrouter: "anthropic/claude-haiku-4-5",
|
|
43
|
+
"openai-compatible": null,
|
|
44
|
+
};
|
|
45
|
+
export class ProviderRegistry {
|
|
46
|
+
db;
|
|
47
|
+
constructor(db) {
|
|
48
|
+
this.db = db;
|
|
49
|
+
}
|
|
50
|
+
list() {
|
|
51
|
+
const rows = this.db.prepare(`SELECT * FROM providers ORDER BY id ASC`).all();
|
|
52
|
+
return rows.map((r) => rowFromDb(r, false));
|
|
53
|
+
}
|
|
54
|
+
get(id) {
|
|
55
|
+
const row = this.db.prepare(`SELECT * FROM providers WHERE id = ?`).get(id);
|
|
56
|
+
return row ? rowFromDb(row, false) : null;
|
|
57
|
+
}
|
|
58
|
+
getByName(name) {
|
|
59
|
+
const row = this.db.prepare(`SELECT * FROM providers WHERE name = ?`).get(name);
|
|
60
|
+
return row ? rowFromDb(row, false) : null;
|
|
61
|
+
}
|
|
62
|
+
/** Returns the secret. Use only inside the daemon — never echo to HTTP. */
|
|
63
|
+
getSecret(id) {
|
|
64
|
+
const row = this.db.prepare(`SELECT * FROM providers WHERE id = ?`).get(id);
|
|
65
|
+
return row?.api_key ?? null;
|
|
66
|
+
}
|
|
67
|
+
insert(input) {
|
|
68
|
+
const baseUrl = input.baseUrl ?? DEFAULT_BASE_URLS[input.kind];
|
|
69
|
+
const defaultModel = input.defaultModel ?? DEFAULT_MODELS[input.kind];
|
|
70
|
+
const result = this.db.prepare(`
|
|
71
|
+
INSERT INTO providers (kind, name, base_url, api_key, default_model, enabled)
|
|
72
|
+
VALUES (@kind, @name, @base_url, @api_key, @default_model, @enabled)
|
|
73
|
+
`).run({
|
|
74
|
+
kind: input.kind,
|
|
75
|
+
name: input.name,
|
|
76
|
+
base_url: baseUrl ?? null,
|
|
77
|
+
api_key: input.apiKey ?? null,
|
|
78
|
+
default_model: defaultModel ?? null,
|
|
79
|
+
enabled: input.enabled === false ? 0 : 1,
|
|
80
|
+
});
|
|
81
|
+
const id = Number(result.lastInsertRowid);
|
|
82
|
+
const row = this.get(id);
|
|
83
|
+
if (!row)
|
|
84
|
+
throw new Error(`ProviderRegistry.insert: row ${id} not found after insert`);
|
|
85
|
+
return row;
|
|
86
|
+
}
|
|
87
|
+
update(id, patch) {
|
|
88
|
+
const fields = [];
|
|
89
|
+
const params = { id };
|
|
90
|
+
if (patch.name !== undefined) {
|
|
91
|
+
fields.push("name = @name");
|
|
92
|
+
params["name"] = patch.name;
|
|
93
|
+
}
|
|
94
|
+
if (patch.baseUrl !== undefined) {
|
|
95
|
+
fields.push("base_url = @url");
|
|
96
|
+
params["url"] = patch.baseUrl;
|
|
97
|
+
}
|
|
98
|
+
if (patch.apiKey !== undefined) {
|
|
99
|
+
fields.push("api_key = @key");
|
|
100
|
+
params["key"] = patch.apiKey;
|
|
101
|
+
}
|
|
102
|
+
if (patch.defaultModel !== undefined) {
|
|
103
|
+
fields.push("default_model = @m");
|
|
104
|
+
params["m"] = patch.defaultModel;
|
|
105
|
+
}
|
|
106
|
+
if (patch.enabled !== undefined) {
|
|
107
|
+
fields.push("enabled = @en");
|
|
108
|
+
params["en"] = patch.enabled ? 1 : 0;
|
|
109
|
+
}
|
|
110
|
+
if (fields.length === 0)
|
|
111
|
+
return this.get(id);
|
|
112
|
+
fields.push("updated_at = datetime('now')");
|
|
113
|
+
this.db.prepare(`UPDATE providers SET ${fields.join(", ")} WHERE id = @id`).run(params);
|
|
114
|
+
return this.get(id);
|
|
115
|
+
}
|
|
116
|
+
delete(id) {
|
|
117
|
+
const result = this.db.prepare(`DELETE FROM providers WHERE id = ?`).run(id);
|
|
118
|
+
return result.changes > 0;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Seed defaults on an empty registry. Bridges from the legacy env-var
|
|
122
|
+
* setup: if DEEPSEEK_API_KEY is present, the DeepSeek row carries it
|
|
123
|
+
* forward; Ollama is always seeded since it needs no key.
|
|
124
|
+
*/
|
|
125
|
+
seedDefaults() {
|
|
126
|
+
const count = this.db.prepare(`SELECT COUNT(*) AS c FROM providers`).get();
|
|
127
|
+
if ((count?.c ?? 0) > 0)
|
|
128
|
+
return;
|
|
129
|
+
this.insert({
|
|
130
|
+
kind: "ollama",
|
|
131
|
+
name: "Ollama (local)",
|
|
132
|
+
baseUrl: process.env["NLM_OLLAMA_URL"] ?? "http://localhost:11434",
|
|
133
|
+
});
|
|
134
|
+
const deepseekKey = process.env["DEEPSEEK_API_KEY"];
|
|
135
|
+
this.insert({
|
|
136
|
+
kind: "deepseek",
|
|
137
|
+
name: "DeepSeek",
|
|
138
|
+
apiKey: deepseekKey ?? null,
|
|
139
|
+
enabled: Boolean(deepseekKey),
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=provider-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-registry.js","sourceRoot":"","sources":["../../../src/core/providers/provider-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Append-only JSONL citation log. One line per (conversationId, citedId)
|
|
3
|
+
* that the Stop hook detected. This is the training-data substrate for the
|
|
4
|
+
* future learned reranker: each row is a (query, returned_id, was_cited)
|
|
5
|
+
* triple once joined against ~/.nlm/query_log.jsonl by conversationId.
|
|
6
|
+
*
|
|
7
|
+
* Path defaults to ~/.nlm/citation-log.jsonl, overridable via
|
|
8
|
+
* NLM_CITATION_LOG. Telemetry path — never raises.
|
|
9
|
+
*/
|
|
10
|
+
export type CitationKind = "tool_use" | "prose";
|
|
11
|
+
export interface CitationEntry {
|
|
12
|
+
readonly conversationId: string;
|
|
13
|
+
readonly citedId: string;
|
|
14
|
+
readonly kind?: CitationKind;
|
|
15
|
+
readonly responsePreview?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface CitationStats {
|
|
18
|
+
readonly days: number;
|
|
19
|
+
readonly total: number;
|
|
20
|
+
readonly distinct_ids: number;
|
|
21
|
+
readonly top_ids: ReadonlyArray<{
|
|
22
|
+
readonly id: string;
|
|
23
|
+
readonly count: number;
|
|
24
|
+
}>;
|
|
25
|
+
readonly log_present: boolean;
|
|
26
|
+
}
|
|
27
|
+
export declare function appendCitation(entry: CitationEntry, logPath?: string): Promise<void>;
|
|
28
|
+
export declare function citationStats(days: number, logPath?: string): Promise<CitationStats>;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Append-only JSONL citation log. One line per (conversationId, citedId)
|
|
3
|
+
* that the Stop hook detected. This is the training-data substrate for the
|
|
4
|
+
* future learned reranker: each row is a (query, returned_id, was_cited)
|
|
5
|
+
* triple once joined against ~/.nlm/query_log.jsonl by conversationId.
|
|
6
|
+
*
|
|
7
|
+
* Path defaults to ~/.nlm/citation-log.jsonl, overridable via
|
|
8
|
+
* NLM_CITATION_LOG. Telemetry path — never raises.
|
|
9
|
+
*/
|
|
10
|
+
import { appendFile, mkdir, readFile, stat } from "node:fs/promises";
|
|
11
|
+
import { dirname, join } from "node:path";
|
|
12
|
+
import { homedir } from "node:os";
|
|
13
|
+
function defaultLogPath() {
|
|
14
|
+
return process.env["NLM_CITATION_LOG"] ?? join(homedir(), ".nlm", "citation-log.jsonl");
|
|
15
|
+
}
|
|
16
|
+
export async function appendCitation(entry, logPath = defaultLogPath()) {
|
|
17
|
+
try {
|
|
18
|
+
await mkdir(dirname(logPath), { recursive: true });
|
|
19
|
+
const payload = {
|
|
20
|
+
ts: new Date().toISOString(),
|
|
21
|
+
conversation_id: entry.conversationId,
|
|
22
|
+
cited_id: entry.citedId,
|
|
23
|
+
...(entry.kind !== undefined ? { kind: entry.kind } : {}),
|
|
24
|
+
...(entry.responsePreview !== undefined
|
|
25
|
+
? { response_preview: entry.responsePreview }
|
|
26
|
+
: {}),
|
|
27
|
+
};
|
|
28
|
+
await appendFile(logPath, JSON.stringify(payload) + "\n", "utf8");
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// Telemetry failure must never break the call path.
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export async function citationStats(days, logPath = defaultLogPath()) {
|
|
35
|
+
const base = {
|
|
36
|
+
days,
|
|
37
|
+
total: 0,
|
|
38
|
+
distinct_ids: 0,
|
|
39
|
+
top_ids: [],
|
|
40
|
+
log_present: false,
|
|
41
|
+
};
|
|
42
|
+
try {
|
|
43
|
+
await stat(logPath);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return base;
|
|
47
|
+
}
|
|
48
|
+
let raw;
|
|
49
|
+
try {
|
|
50
|
+
raw = await readFile(logPath, "utf8");
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return { ...base, log_present: true };
|
|
54
|
+
}
|
|
55
|
+
const cutoff = Date.now() - days * 24 * 60 * 60 * 1000;
|
|
56
|
+
const counts = new Map();
|
|
57
|
+
let total = 0;
|
|
58
|
+
for (const line of raw.split("\n")) {
|
|
59
|
+
const trimmed = line.trim();
|
|
60
|
+
if (!trimmed)
|
|
61
|
+
continue;
|
|
62
|
+
let entry;
|
|
63
|
+
try {
|
|
64
|
+
entry = JSON.parse(trimmed);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const tsRaw = entry["ts"];
|
|
70
|
+
if (typeof tsRaw !== "string")
|
|
71
|
+
continue;
|
|
72
|
+
const ts = Date.parse(tsRaw);
|
|
73
|
+
if (!Number.isFinite(ts) || ts < cutoff)
|
|
74
|
+
continue;
|
|
75
|
+
const id = entry["cited_id"];
|
|
76
|
+
if (typeof id !== "string" || !id)
|
|
77
|
+
continue;
|
|
78
|
+
total += 1;
|
|
79
|
+
counts.set(id, (counts.get(id) ?? 0) + 1);
|
|
80
|
+
}
|
|
81
|
+
const sorted = [...counts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 20);
|
|
82
|
+
return {
|
|
83
|
+
days,
|
|
84
|
+
total,
|
|
85
|
+
distinct_ids: counts.size,
|
|
86
|
+
top_ids: sorted.map(([id, count]) => ({ id, count })),
|
|
87
|
+
log_present: true,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=citation-log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"citation-log.js","sourceRoot":"","sources":["../../../src/core/recall/citation-log.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session-list filters used before scoring.
|
|
3
|
+
*
|
|
4
|
+
* Pure function over a session array. Mirrors recall.py:_apply_filters.
|
|
5
|
+
*/
|
|
6
|
+
import type { Session, RecallKindFilter } from "../../shared/types.js";
|
|
7
|
+
export interface RecallFilter {
|
|
8
|
+
readonly entity?: string;
|
|
9
|
+
readonly kind?: RecallKindFilter;
|
|
10
|
+
}
|
|
11
|
+
export declare function applyFilter(sessions: ReadonlyArray<Session>, filter: RecallFilter): ReadonlyArray<Session>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session-list filters used before scoring.
|
|
3
|
+
*
|
|
4
|
+
* Pure function over a session array. Mirrors recall.py:_apply_filters.
|
|
5
|
+
*/
|
|
6
|
+
export function applyFilter(sessions, filter) {
|
|
7
|
+
const { entity, kind } = filter;
|
|
8
|
+
if (!entity && !kind)
|
|
9
|
+
return sessions;
|
|
10
|
+
return sessions.filter((s) => {
|
|
11
|
+
if (entity && !s.entities.includes(entity))
|
|
12
|
+
return false;
|
|
13
|
+
if (kind === "decision" && s.decisions.length === 0)
|
|
14
|
+
return false;
|
|
15
|
+
if (kind === "open" && s.open.length === 0)
|
|
16
|
+
return false;
|
|
17
|
+
return true;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter.js","sourceRoot":"","sources":["../../../src/core/recall/filter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,MAAM,UAAU,WAAW,CACzB,QAAgC,EAChC,MAAoB;IAEpB,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC;IAChC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI;QAAE,OAAO,QAAQ,CAAC;IAEtC,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QAC3B,IAAI,MAAM,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,OAAO,KAAK,CAAC;QACzD,IAAI,IAAI,KAAK,UAAU,IAAI,CAAC,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QAClE,IAAI,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QACzD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { RecallService } from "./recall-service.js";
|
|
2
|
+
export type { RecallServiceDeps } from "./recall-service.js";
|
|
3
|
+
export { keywordMatchFields } from "./match-fields.js";
|
|
4
|
+
export { applyFilter } from "./filter.js";
|
|
5
|
+
export type { RecallFilter } from "./filter.js";
|
|
6
|
+
export { tokenize, tokenSet } from "./tokenize.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/recall/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Computes which session fields a keyword query matched, for the `matchedIn`
|
|
3
|
+
* badge on a RecallHit. Pure function — no DB, no I/O. FTS5 BM25 ranks the
|
|
4
|
+
* whole row; this recovers per-field attribution from the resolved Session,
|
|
5
|
+
* including decisions/open which live in the markers table (not in FTS).
|
|
6
|
+
*/
|
|
7
|
+
import type { MatchField, Session } from "../../shared/types.js";
|
|
8
|
+
type SessionFields = Pick<Session, "label" | "summary" | "decisions" | "open">;
|
|
9
|
+
export declare function keywordMatchFields(session: SessionFields, queryTokens: ReadonlySet<string>): ReadonlyArray<MatchField>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Computes which session fields a keyword query matched, for the `matchedIn`
|
|
3
|
+
* badge on a RecallHit. Pure function — no DB, no I/O. FTS5 BM25 ranks the
|
|
4
|
+
* whole row; this recovers per-field attribution from the resolved Session,
|
|
5
|
+
* including decisions/open which live in the markers table (not in FTS).
|
|
6
|
+
*/
|
|
7
|
+
import { tokenSet } from "./tokenize.js";
|
|
8
|
+
export function keywordMatchFields(session, queryTokens) {
|
|
9
|
+
if (queryTokens.size === 0)
|
|
10
|
+
return [];
|
|
11
|
+
const fields = [];
|
|
12
|
+
if (overlaps(queryTokens, tokenSet(session.label)))
|
|
13
|
+
fields.push("label");
|
|
14
|
+
if (overlaps(queryTokens, joinedTokens(session.decisions)))
|
|
15
|
+
fields.push("decisions");
|
|
16
|
+
if (overlaps(queryTokens, joinedTokens(session.open)))
|
|
17
|
+
fields.push("open");
|
|
18
|
+
if (overlaps(queryTokens, tokenSet(session.summary)))
|
|
19
|
+
fields.push("summary");
|
|
20
|
+
return fields;
|
|
21
|
+
}
|
|
22
|
+
function joinedTokens(values) {
|
|
23
|
+
const out = new Set();
|
|
24
|
+
for (const v of values) {
|
|
25
|
+
for (const t of tokenSet(v))
|
|
26
|
+
out.add(t);
|
|
27
|
+
}
|
|
28
|
+
return out;
|
|
29
|
+
}
|
|
30
|
+
function overlaps(a, b) {
|
|
31
|
+
const [small, large] = a.size <= b.size ? [a, b] : [b, a];
|
|
32
|
+
for (const item of small)
|
|
33
|
+
if (large.has(item))
|
|
34
|
+
return true;
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=match-fields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"match-fields.js","sourceRoot":"","sources":["../../../src/core/recall/match-fields.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAIzC,MAAM,UAAU,kBAAkB,CAChC,OAAsB,EACtB,WAAgC;IAEhC,IAAI,WAAW,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACtC,MAAM,MAAM,GAAiB,EAAE,CAAC;IAEhC,IAAI,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzE,IAAI,QAAQ,CAAC,WAAW,EAAE,YAAY,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACrF,IAAI,QAAQ,CAAC,WAAW,EAAE,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3E,IAAI,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAE7E,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,YAAY,CAAC,MAA6B;IACjD,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC;YAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,QAAQ,CAAC,CAAsB,EAAE,CAAsB;IAC9D,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1D,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;IAC3D,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query log + stats aggregation. Mirrors recall.py's log_query() / stats().
|
|
3
|
+
*
|
|
4
|
+
* Telemetry path — never raises. The HTTP recall handler calls logQuery()
|
|
5
|
+
* after each /api/recall response; /api/recall/stats reads the same file
|
|
6
|
+
* back to drive the Pulse agent-recall observability panel.
|
|
7
|
+
*
|
|
8
|
+
* File format: one JSON object per line at $NLM_QUERY_LOG or
|
|
9
|
+
* ~/.nlm/query_log.jsonl. Append-only.
|
|
10
|
+
*/
|
|
11
|
+
import type { RecallKindFilter, RecallMode } from "../../shared/types.js";
|
|
12
|
+
export interface LogEntry {
|
|
13
|
+
readonly source: string;
|
|
14
|
+
readonly query: string | null;
|
|
15
|
+
readonly entity: string | null;
|
|
16
|
+
readonly kind: RecallKindFilter | null;
|
|
17
|
+
readonly mode: RecallMode;
|
|
18
|
+
readonly limit: number;
|
|
19
|
+
readonly nResults: number;
|
|
20
|
+
readonly returnedIds: ReadonlyArray<string>;
|
|
21
|
+
}
|
|
22
|
+
export interface StatsResult {
|
|
23
|
+
readonly days: number;
|
|
24
|
+
readonly total: number;
|
|
25
|
+
readonly with_results: number;
|
|
26
|
+
readonly hit_rate: number;
|
|
27
|
+
readonly useful_hit_rate: number | null;
|
|
28
|
+
readonly by_source: Record<string, number>;
|
|
29
|
+
readonly top_queries: ReadonlyArray<{
|
|
30
|
+
readonly query: string;
|
|
31
|
+
readonly count: number;
|
|
32
|
+
}>;
|
|
33
|
+
readonly log_present: boolean;
|
|
34
|
+
}
|
|
35
|
+
export declare function logQuery(entry: LogEntry, logPath?: string): Promise<void>;
|
|
36
|
+
export declare function recallStats(days: number, logPath?: string, usefulHitLogPath?: string): Promise<StatsResult>;
|