@remnic/core 9.3.712 → 9.3.714
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/dist/access-boundary.d.ts +6 -6
- package/dist/access-boundary.js +17 -16
- package/dist/access-cli.js +40 -39
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +5 -5
- package/dist/access-http.js +24 -23
- package/dist/access-mcp.d.ts +18 -5
- package/dist/access-mcp.js +21 -20
- package/dist/access-operations-batch.js +18 -17
- package/dist/access-operations.d.ts +6 -5
- package/dist/access-operations.js +20 -19
- package/dist/access-schema.d.ts +10 -0
- package/dist/access-schema.js +1 -1
- package/dist/{access-service-Dx2rSJjH.d.ts → access-service-lddjZoRh.d.ts} +20 -5
- package/dist/access-service.d.ts +5 -5
- package/dist/access-service.js +16 -15
- package/dist/access-surface-catalog.d.ts +5 -5
- package/dist/access-surface-catalog.js +6 -1
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/action-confidence.d.ts +1 -1
- package/dist/active-memory-bridge.d.ts +3 -1
- package/dist/active-memory-bridge.js +2 -1
- package/dist/active-recall.d.ts +1 -1
- package/dist/active-recall.js +4 -3
- package/dist/active-recall.js.map +1 -1
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +4 -4
- package/dist/briefing.d.ts +1 -1
- package/dist/briefing.js +8 -7
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer.d.ts +1 -1
- package/dist/calibration.d.ts +1 -1
- package/dist/capabilities.d.ts +1 -1
- package/dist/{catalog-CadPvH29.d.ts → catalog-CbR0CsUw.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +9 -8
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/{chunk-OMSTU233.js → chunk-2KAYTPPT.js} +4 -4
- package/dist/{chunk-VYZNWH4J.js → chunk-2SXMCQEQ.js} +3 -3
- package/dist/{chunk-NXL5CVE7.js → chunk-2Y6LMOQQ.js} +2 -2
- package/dist/{chunk-AMXOCZHE.js → chunk-3VUPWDSE.js} +15 -3
- package/dist/{chunk-AMXOCZHE.js.map → chunk-3VUPWDSE.js.map} +1 -1
- package/dist/{chunk-FVQJYWH7.js → chunk-5GKPFL3S.js} +1 -1
- package/dist/{chunk-FVQJYWH7.js.map → chunk-5GKPFL3S.js.map} +1 -1
- package/dist/{chunk-LQ4J7ELC.js → chunk-67HG7KFE.js} +2 -2
- package/dist/{chunk-ZBG4K36I.js → chunk-6FUJ2VYY.js} +3 -3
- package/dist/{chunk-GMRNKPWO.js → chunk-6QUPUTT7.js} +2 -2
- package/dist/{chunk-Z56IHRVV.js → chunk-6UU43ZGD.js} +2 -2
- package/dist/{chunk-APJQ6UEA.js → chunk-AGNBY3VG.js} +4 -4
- package/dist/{chunk-OWOKOFXK.js → chunk-AJOIM6UR.js} +2 -2
- package/dist/{chunk-JBPKEARU.js → chunk-AU7Q3LSC.js} +4 -4
- package/dist/{chunk-YVWZW37D.js → chunk-BNOAB5HH.js} +62 -12
- package/dist/{chunk-YVWZW37D.js.map → chunk-BNOAB5HH.js.map} +1 -1
- package/dist/{chunk-A2R5NV6O.js → chunk-CTAHKIG6.js} +205 -29
- package/dist/chunk-CTAHKIG6.js.map +1 -0
- package/dist/{chunk-K22IJO4R.js → chunk-CTOQEZSN.js} +2 -2
- package/dist/{chunk-SINGJCUR.js → chunk-CX77GNMB.js} +14 -3
- package/dist/chunk-CX77GNMB.js.map +1 -0
- package/dist/{chunk-HSDJCT3V.js → chunk-DXGS5YOQ.js} +3 -3
- package/dist/{chunk-HV57RHMD.js → chunk-EH5ED3C6.js} +2 -2
- package/dist/{chunk-NUWZFSKC.js → chunk-FVZ2ISIX.js} +9 -1
- package/dist/chunk-FVZ2ISIX.js.map +1 -0
- package/dist/{chunk-GKPIY7EQ.js → chunk-FXZKXW7C.js} +117 -46
- package/dist/chunk-FXZKXW7C.js.map +1 -0
- package/dist/{chunk-7NDYFAJS.js → chunk-GM3BMWKR.js} +2 -2
- package/dist/{chunk-ZVDRL6SK.js → chunk-HHLWSWWF.js} +2 -2
- package/dist/chunk-HHLWSWWF.js.map +1 -0
- package/dist/{chunk-5QUS24F7.js → chunk-I56LKMF7.js} +2 -2
- package/dist/{chunk-Z3B2YW56.js → chunk-IHMT6XTY.js} +9 -5
- package/dist/chunk-IHMT6XTY.js.map +1 -0
- package/dist/chunk-JAKIDQB2.js +173 -0
- package/dist/chunk-JAKIDQB2.js.map +1 -0
- package/dist/{chunk-35YJ6KCV.js → chunk-JEIROMLX.js} +2 -2
- package/dist/{chunk-SKQCFAYU.js → chunk-JVEMUX6L.js} +2 -2
- package/dist/{chunk-CXMXAC5R.js → chunk-K44MIN6D.js} +3 -3
- package/dist/{chunk-5KQCOIPW.js → chunk-MECU6WSH.js} +188 -31
- package/dist/chunk-MECU6WSH.js.map +1 -0
- package/dist/{chunk-BQCFXAMN.js → chunk-MPHDVHIB.js} +2 -2
- package/dist/{chunk-BOGENF7P.js → chunk-MSVSP5VO.js} +1 -1
- package/dist/chunk-MSVSP5VO.js.map +1 -0
- package/dist/{chunk-QXNFQKWU.js → chunk-MTHNJCOJ.js} +2 -2
- package/dist/{chunk-3TCRU4JA.js → chunk-O62P2LFL.js} +2 -2
- package/dist/{chunk-JSDZMOT7.js → chunk-OC56UWV5.js} +11 -11
- package/dist/{chunk-7IBEWQLG.js → chunk-QOIONSOI.js} +2 -2
- package/dist/{chunk-4P5UAL3C.js → chunk-RBHANGVX.js} +6 -6
- package/dist/{chunk-SK2CR6MW.js → chunk-RVLB4E6N.js} +2 -2
- package/dist/{chunk-I3BT2IDW.js → chunk-SYDHFFAW.js} +1110 -28
- package/dist/chunk-SYDHFFAW.js.map +1 -0
- package/dist/{chunk-VILEUJXC.js → chunk-UC4YOAC2.js} +74 -2
- package/dist/{chunk-VILEUJXC.js.map → chunk-UC4YOAC2.js.map} +1 -1
- package/dist/{chunk-CNVIWMQI.js → chunk-UY4JMEAK.js} +2 -2
- package/dist/{chunk-S6FQLQGH.js → chunk-V7GDTQ6I.js} +2 -2
- package/dist/{chunk-JNOYYWCA.js → chunk-VO4UICII.js} +3 -3
- package/dist/{chunk-54TI5GLV.js → chunk-WI4QX7GH.js} +3 -3
- package/dist/{chunk-3XHD3XGK.js → chunk-XCTDHF7U.js} +30 -2
- package/dist/chunk-XCTDHF7U.js.map +1 -0
- package/dist/{chunk-XKU4YE6Z.js → chunk-XZTUMWKQ.js} +2 -2
- package/dist/{cli-DTWRoJEI.d.ts → cli-iAiVkbYJ.d.ts} +3 -3
- package/dist/cli.d.ts +6 -6
- package/dist/cli.js +43 -42
- package/dist/compounding/engine.d.ts +1 -1
- package/dist/compounding/engine.js +8 -7
- package/dist/compounding/preference-consolidator.d.ts +1 -1
- package/dist/compression-optimizer.d.ts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +4 -3
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +8 -7
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +9 -8
- package/dist/consolidation-provenance-check.d.ts +1 -1
- package/dist/consolidation-undo.d.ts +1 -1
- package/dist/contradiction/index.d.ts +1 -1
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/chunker.d.ts +1 -1
- package/dist/conversation-index/faiss-adapter.d.ts +1 -1
- package/dist/conversation-index/indexer.d.ts +1 -1
- package/dist/conversation-index/search.d.ts +1 -1
- package/dist/day-summary.d.ts +1 -1
- package/dist/delinearize.d.ts +1 -1
- package/dist/direct-answer-wiring.d.ts +1 -1
- package/dist/direct-answer.d.ts +1 -1
- package/dist/embedding-fallback.d.ts +1 -1
- package/dist/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +1 -1
- package/dist/entity-retrieval.js +8 -7
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +4 -4
- package/dist/explicit-capture.js +3 -2
- package/dist/extraction-faithfulness.d.ts +1 -1
- package/dist/extraction-judge-telemetry.d.ts +1 -1
- package/dist/extraction-judge-training.d.ts +1 -1
- package/dist/extraction-judge.d.ts +1 -1
- package/dist/extraction.d.ts +1 -1
- package/dist/extraction.js +4 -3
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/identity-continuity.d.ts +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/index.d.ts +9 -9
- package/dist/index.js +62 -61
- package/dist/index.js.map +1 -1
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/index.js +3 -3
- package/dist/lcm/tools.d.ts +1 -1
- package/dist/lifecycle.d.ts +1 -1
- package/dist/live-connectors-runner.d.ts +1 -1
- package/dist/local-llm.d.ts +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +8 -7
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +8 -7
- package/dist/maintenance/rebuild-memory-projection.js +9 -8
- package/dist/mcp-memory-inspector-app.d.ts +5 -5
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/memory-provenance.d.ts +1 -1
- package/dist/memory-worth-outcomes.d.ts +1 -1
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +2 -2
- package/dist/namespaces/migrate.js +12 -11
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +3 -3
- package/dist/namespaces/storage.d.ts +2 -2
- package/dist/namespaces/storage.js +8 -7
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +1 -1
- package/dist/operator-toolkit.js +17 -16
- package/dist/orchestration/maintenance.d.ts +2 -2
- package/dist/orchestration/maintenance.js +10 -9
- package/dist/{orchestrator-B1iVjEyc.d.ts → orchestrator-iVZWi8aW.d.ts} +21 -4
- package/dist/orchestrator.d.ts +4 -4
- package/dist/orchestrator.js +32 -31
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/provenance.d.ts +1 -1
- package/dist/provenance.js +3 -2
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +1 -1
- package/dist/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -1
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-handles.d.ts +228 -0
- package/dist/recall-handles.js +42 -0
- package/dist/recall-handles.js.map +1 -0
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-state.d.ts +40 -2
- package/dist/recall-state.js +3 -1
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +1 -1
- package/dist/recall-xray.js +2 -2
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/resume-bundles.js +5 -4
- package/dist/retrieval-agents.d.ts +1 -1
- package/dist/retrieval-tiers.d.ts +1 -1
- package/dist/routing/engine.d.ts +1 -1
- package/dist/routing/store.d.ts +1 -1
- package/dist/sanitize.d.ts +2 -0
- package/dist/sanitize.js +6 -2
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/factory.js +2 -2
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +4 -4
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/port.d.ts +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-consolidation-CY8uVRNJ.d.ts → semantic-consolidation-DSjMDZ1u.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +9 -8
- package/dist/semantic-rule-promotion.js +8 -7
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +8 -7
- package/dist/session-observer-bands.d.ts +1 -1
- package/dist/session-observer-state.d.ts +1 -1
- package/dist/shared-context/manager.d.ts +3 -3
- package/dist/signal.d.ts +1 -1
- package/dist/storage.d.ts +1 -1
- package/dist/storage.js +7 -6
- package/dist/summarizer.d.ts +1 -1
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/temporal-supersession.d.ts +1 -1
- package/dist/temporal-validity.d.ts +1 -1
- package/dist/threading.d.ts +1 -1
- package/dist/tier-migration.d.ts +1 -1
- package/dist/tier-routing.d.ts +1 -1
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/import-sqlite.js +2 -2
- package/dist/{types-Dr0Cw3L9.d.ts → types-D9dwzU_x.d.ts} +25 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +8 -7
- package/package.json +2 -2
- package/src/access-boundary.ts +4 -1
- package/src/access-http.ts +78 -20
- package/src/access-mcp.test.ts +29 -0
- package/src/access-mcp.ts +99 -17
- package/src/access-operations-batch.ts +14 -0
- package/src/access-operations.ts +5 -0
- package/src/access-schema.ts +8 -0
- package/src/access-service-observe-idempotency.test.ts +308 -0
- package/src/access-service.ts +106 -5
- package/src/access-surface-catalog.test.ts +4 -2
- package/src/access-surface-catalog.ts +5 -0
- package/src/active-memory-bridge.test.ts +72 -0
- package/src/active-memory-bridge.ts +21 -2
- package/src/chat/chat-cli.test.ts +142 -0
- package/src/chat/chat-cli.ts +206 -0
- package/src/chat/chat-config.ts +57 -0
- package/src/chat/chat-engine.test.ts +272 -0
- package/src/chat/chat-engine.ts +518 -0
- package/src/chat/chat-executor.ts +133 -0
- package/src/chat/chat-factory.ts +161 -0
- package/src/chat/chat-http.test.ts +197 -0
- package/src/chat/chat-http.ts +222 -0
- package/src/chat/chat-llm.ts +229 -0
- package/src/chat/chat-mcp.test.ts +135 -0
- package/src/chat/chat-security.test.ts +491 -0
- package/src/chat/chat-session.ts +296 -0
- package/src/chat/chat-system-prompt.ts +76 -0
- package/src/chat/chat-tools.ts +255 -0
- package/src/chat/chat-types.ts +167 -0
- package/src/cli.ts +20 -0
- package/src/config.ts +9 -0
- package/src/orchestrator.ts +106 -5
- package/src/recall-handles-wiring.test.ts +477 -0
- package/src/recall-handles.test.ts +283 -0
- package/src/recall-handles.ts +414 -0
- package/src/recall-state.ts +99 -0
- package/src/sanitize.ts +6 -0
- package/src/types.ts +29 -0
- package/dist/chunk-3XHD3XGK.js.map +0 -1
- package/dist/chunk-5KQCOIPW.js.map +0 -1
- package/dist/chunk-A2R5NV6O.js.map +0 -1
- package/dist/chunk-BOGENF7P.js.map +0 -1
- package/dist/chunk-GKPIY7EQ.js.map +0 -1
- package/dist/chunk-I3BT2IDW.js.map +0 -1
- package/dist/chunk-NUWZFSKC.js.map +0 -1
- package/dist/chunk-SINGJCUR.js.map +0 -1
- package/dist/chunk-Z3B2YW56.js.map +0 -1
- package/dist/chunk-ZVDRL6SK.js.map +0 -1
- /package/dist/{chunk-OMSTU233.js.map → chunk-2KAYTPPT.js.map} +0 -0
- /package/dist/{chunk-VYZNWH4J.js.map → chunk-2SXMCQEQ.js.map} +0 -0
- /package/dist/{chunk-NXL5CVE7.js.map → chunk-2Y6LMOQQ.js.map} +0 -0
- /package/dist/{chunk-LQ4J7ELC.js.map → chunk-67HG7KFE.js.map} +0 -0
- /package/dist/{chunk-ZBG4K36I.js.map → chunk-6FUJ2VYY.js.map} +0 -0
- /package/dist/{chunk-GMRNKPWO.js.map → chunk-6QUPUTT7.js.map} +0 -0
- /package/dist/{chunk-Z56IHRVV.js.map → chunk-6UU43ZGD.js.map} +0 -0
- /package/dist/{chunk-APJQ6UEA.js.map → chunk-AGNBY3VG.js.map} +0 -0
- /package/dist/{chunk-OWOKOFXK.js.map → chunk-AJOIM6UR.js.map} +0 -0
- /package/dist/{chunk-JBPKEARU.js.map → chunk-AU7Q3LSC.js.map} +0 -0
- /package/dist/{chunk-K22IJO4R.js.map → chunk-CTOQEZSN.js.map} +0 -0
- /package/dist/{chunk-HSDJCT3V.js.map → chunk-DXGS5YOQ.js.map} +0 -0
- /package/dist/{chunk-HV57RHMD.js.map → chunk-EH5ED3C6.js.map} +0 -0
- /package/dist/{chunk-7NDYFAJS.js.map → chunk-GM3BMWKR.js.map} +0 -0
- /package/dist/{chunk-5QUS24F7.js.map → chunk-I56LKMF7.js.map} +0 -0
- /package/dist/{chunk-35YJ6KCV.js.map → chunk-JEIROMLX.js.map} +0 -0
- /package/dist/{chunk-SKQCFAYU.js.map → chunk-JVEMUX6L.js.map} +0 -0
- /package/dist/{chunk-CXMXAC5R.js.map → chunk-K44MIN6D.js.map} +0 -0
- /package/dist/{chunk-BQCFXAMN.js.map → chunk-MPHDVHIB.js.map} +0 -0
- /package/dist/{chunk-QXNFQKWU.js.map → chunk-MTHNJCOJ.js.map} +0 -0
- /package/dist/{chunk-3TCRU4JA.js.map → chunk-O62P2LFL.js.map} +0 -0
- /package/dist/{chunk-JSDZMOT7.js.map → chunk-OC56UWV5.js.map} +0 -0
- /package/dist/{chunk-7IBEWQLG.js.map → chunk-QOIONSOI.js.map} +0 -0
- /package/dist/{chunk-4P5UAL3C.js.map → chunk-RBHANGVX.js.map} +0 -0
- /package/dist/{chunk-SK2CR6MW.js.map → chunk-RVLB4E6N.js.map} +0 -0
- /package/dist/{chunk-CNVIWMQI.js.map → chunk-UY4JMEAK.js.map} +0 -0
- /package/dist/{chunk-S6FQLQGH.js.map → chunk-V7GDTQ6I.js.map} +0 -0
- /package/dist/{chunk-JNOYYWCA.js.map → chunk-VO4UICII.js.map} +0 -0
- /package/dist/{chunk-54TI5GLV.js.map → chunk-WI4QX7GH.js.map} +0 -0
- /package/dist/{chunk-XKU4YE6Z.js.map → chunk-XZTUMWKQ.js.map} +0 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for the conversational memory chat engine (issue #1583).
|
|
3
|
+
*
|
|
4
|
+
* The chat engine is a deliberately bounded tool-loop agent — NOT a general
|
|
5
|
+
* assistant. It exposes a fixed set of read-only and (confirmation-gated)
|
|
6
|
+
* mutating tools, each a thin adapter over an existing access-service method.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// LLM adapter — production signature (rule 33), stubbable for tests
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A single chat message in the LLM conversation.
|
|
15
|
+
*/
|
|
16
|
+
export interface ChatLlmMessage {
|
|
17
|
+
role: "system" | "user" | "assistant" | "tool";
|
|
18
|
+
content: string;
|
|
19
|
+
/** Tool-call id when role === "tool" (correlates the result back). */
|
|
20
|
+
toolCallId?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* A tool-call request emitted by the LLM. The engine parses these from the
|
|
25
|
+
* LLM response and dispatches them through the tool registry.
|
|
26
|
+
*/
|
|
27
|
+
export interface ChatLlmToolCall {
|
|
28
|
+
id: string;
|
|
29
|
+
name: string;
|
|
30
|
+
arguments: Record<string, unknown>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Structured LLM response — either a text reply or a set of tool calls.
|
|
35
|
+
* The adapter (stub or production) is responsible for parsing the raw model
|
|
36
|
+
* output into this shape.
|
|
37
|
+
*/
|
|
38
|
+
export interface ChatLlmResponse {
|
|
39
|
+
/** Assistant text reply (empty when only tool calls are present). */
|
|
40
|
+
content: string;
|
|
41
|
+
/** Tool calls to execute (empty for a final text reply). */
|
|
42
|
+
toolCalls: ChatLlmToolCall[];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Production-grade LLM adapter interface. The stub implementation used in
|
|
47
|
+
* tests drives scripted sequences; the production implementation wraps the
|
|
48
|
+
* existing FallbackLlmClient routing chain so local Ollama/vLLM models are
|
|
49
|
+
* fully supported (gotcha 1).
|
|
50
|
+
*/
|
|
51
|
+
export interface ChatLlmAdapter {
|
|
52
|
+
/**
|
|
53
|
+
* Send the conversation so far to the LLM and receive the next response.
|
|
54
|
+
* Returns `null` when no model is available or the request fails (rule 13).
|
|
55
|
+
*/
|
|
56
|
+
complete(
|
|
57
|
+
messages: ChatLlmMessage[],
|
|
58
|
+
options: {
|
|
59
|
+
tools: ChatToolSchema[];
|
|
60
|
+
model?: string;
|
|
61
|
+
signal?: AbortSignal;
|
|
62
|
+
},
|
|
63
|
+
): Promise<ChatLlmResponse | null>;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// Tool schema + execution
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* JSON-Schema description of a chat tool, sent to the LLM so it knows what
|
|
72
|
+
* tools are available and how to call them.
|
|
73
|
+
*/
|
|
74
|
+
export interface ChatToolSchema {
|
|
75
|
+
type: "function";
|
|
76
|
+
function: {
|
|
77
|
+
name: string;
|
|
78
|
+
description: string;
|
|
79
|
+
parameters: Record<string, unknown>;
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Result of executing a chat tool. Read-only tools return data; mutating
|
|
85
|
+
* tools go through the confirmation protocol before they reach the executor.
|
|
86
|
+
*/
|
|
87
|
+
export interface ChatToolResult {
|
|
88
|
+
/** Structured payload returned to the LLM as a tool message. */
|
|
89
|
+
content: string;
|
|
90
|
+
/** Whether the tool call was intercepted by the confirmation protocol. */
|
|
91
|
+
pendingConfirmation?: boolean;
|
|
92
|
+
/** Plan preview when pendingConfirmation is true. */
|
|
93
|
+
planPreview?: string;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
// Chat session — transcript + pending-plan state
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* A single line in the persisted chat transcript (JSONL).
|
|
102
|
+
*/
|
|
103
|
+
export interface ChatTranscriptEntry {
|
|
104
|
+
/** Monotonic sequence number within the session. */
|
|
105
|
+
seq: number;
|
|
106
|
+
/** ISO 8601 timestamp. */
|
|
107
|
+
ts: string;
|
|
108
|
+
role: "user" | "assistant" | "tool" | "system";
|
|
109
|
+
content: string;
|
|
110
|
+
/** Tool-call id for tool messages. */
|
|
111
|
+
toolCallId?: string;
|
|
112
|
+
/** Tool name for tool messages. */
|
|
113
|
+
toolName?: string;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* In-memory session state, backed by the JSONL transcript on disk.
|
|
118
|
+
*/
|
|
119
|
+
export interface ChatSessionState {
|
|
120
|
+
id: string;
|
|
121
|
+
/** Caller principal bound at creation (rule 42). */
|
|
122
|
+
principal?: string;
|
|
123
|
+
/** Session key for namespace resolution. */
|
|
124
|
+
sessionKey?: string;
|
|
125
|
+
/** Namespace override. */
|
|
126
|
+
namespace?: string;
|
|
127
|
+
/** Transcript entries loaded from disk. */
|
|
128
|
+
transcript: ChatTranscriptEntry[];
|
|
129
|
+
/** Plan ids confirmed by the user for exactly one apply. */
|
|
130
|
+
confirmedPlanIds: Set<string>;
|
|
131
|
+
/** The pending plan awaiting confirmation (if any). */
|
|
132
|
+
pendingPlanId?: string;
|
|
133
|
+
/** The pending memory-promotion memory id awaiting confirmation (if any). */
|
|
134
|
+
pendingPromotionId?: string;
|
|
135
|
+
/** Creation timestamp. */
|
|
136
|
+
createdAt: string;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ---------------------------------------------------------------------------
|
|
140
|
+
// Engine turn result
|
|
141
|
+
// ---------------------------------------------------------------------------
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* What the engine returns for a single user message.
|
|
145
|
+
*/
|
|
146
|
+
export interface ChatTurnResult {
|
|
147
|
+
/** The assistant's text reply (may be partial on budget exhaustion). */
|
|
148
|
+
reply: string;
|
|
149
|
+
/** The chat session id (existing or newly created). */
|
|
150
|
+
chatSessionId: string;
|
|
151
|
+
/** A pending plan awaiting user confirmation, if surfaced. */
|
|
152
|
+
pendingPlan?: {
|
|
153
|
+
planId: string;
|
|
154
|
+
preview: string;
|
|
155
|
+
};
|
|
156
|
+
/** Tool calls that were skipped due to budget exhaustion. */
|
|
157
|
+
skippedTools?: string[];
|
|
158
|
+
/** Whether the reply is a tagged error (rule 13). */
|
|
159
|
+
error?: string;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// ---------------------------------------------------------------------------
|
|
163
|
+
// Chat config — re-exported from types.ts (canonical definition).
|
|
164
|
+
// DEFAULT_CHAT_CONFIG lives in chat-config.ts.
|
|
165
|
+
// ---------------------------------------------------------------------------
|
|
166
|
+
|
|
167
|
+
export type { ChatConfig } from "../types.js";
|
package/src/cli.ts
CHANGED
|
@@ -95,6 +95,7 @@ import { WebDavServer } from "./network/webdav.js";
|
|
|
95
95
|
import { GraphDashboardServer, type DashboardStatus } from "./dashboard-runtime.js";
|
|
96
96
|
import { EngramAccessService } from "./access-service.js";
|
|
97
97
|
import { EngramAccessHttpServer } from "./access-http.js";
|
|
98
|
+
import { runChatCli } from "./chat/chat-cli.js";
|
|
98
99
|
import {
|
|
99
100
|
buildActionConfidenceInputFromOptions,
|
|
100
101
|
evaluateActionConfidence,
|
|
@@ -2807,6 +2808,7 @@ export async function runAccessMcpServeCliCommand(
|
|
|
2807
2808
|
architectureCardVisible: service.architectureCardSurfaceVisible,
|
|
2808
2809
|
codegraphVisible: service.codegraphSurfaceVisible,
|
|
2809
2810
|
sessionDeltaVisible: service.sessionDeltaSurfaceVisible,
|
|
2811
|
+
chatVisible: service.configRef?.chat?.enabled === true,
|
|
2810
2812
|
correctionVisible: service.correctionSurfaceVisible,
|
|
2811
2813
|
});
|
|
2812
2814
|
await server.runStdio(options.stdin ?? process.stdin, options.stdout ?? process.stdout);
|
|
@@ -9336,6 +9338,24 @@ export function registerCli(
|
|
|
9336
9338
|
}
|
|
9337
9339
|
}
|
|
9338
9340
|
});
|
|
9341
|
+
// ── Chat — conversational memory inspection + correction (#1583) ────
|
|
9342
|
+
cmd
|
|
9343
|
+
.command("chat")
|
|
9344
|
+
.description("Conversational memory inspection and correction (issue #1583)")
|
|
9345
|
+
.option("--session <id>", "Resume an existing chat session")
|
|
9346
|
+
.option("--once", "Process a single message from stdin and exit (non-TTY/scripting)")
|
|
9347
|
+
.option("--principal <principal>", "Trusted principal (defaults to config/env)")
|
|
9348
|
+
.action(async (...args: unknown[]) => {
|
|
9349
|
+
const options = (args[0] ?? {}) as Record<string, unknown>;
|
|
9350
|
+
await runChatCli({
|
|
9351
|
+
service: new EngramAccessService(orchestrator),
|
|
9352
|
+
config: orchestrator.config?.chat,
|
|
9353
|
+
memoryDir: orchestrator.config.memoryDir,
|
|
9354
|
+
principal: resolveAccessPrincipalOverride(options.principal, orchestrator.config.agentAccessHttp.principal),
|
|
9355
|
+
...(typeof options.session === "string" ? { sessionId: options.session } : {}),
|
|
9356
|
+
...(options.once === true ? { once: true } : {}),
|
|
9357
|
+
});
|
|
9358
|
+
});
|
|
9339
9359
|
},
|
|
9340
9360
|
{ commands: ["engram"] },
|
|
9341
9361
|
);
|
package/src/config.ts
CHANGED
|
@@ -47,6 +47,7 @@ import {
|
|
|
47
47
|
import { parseWearablesConfig } from "./wearables/config.js";
|
|
48
48
|
import { parseProvenanceConfig } from "./provenance.js";
|
|
49
49
|
import { parseCodingKnowledgeConfig } from "./coding/coding-knowledge-config.js";
|
|
50
|
+
import { parseChatConfig } from "./chat/chat-config.js";
|
|
50
51
|
const DEFAULT_MEMORY_DIR = path.join(
|
|
51
52
|
resolveHomeDir(),
|
|
52
53
|
".openclaw",
|
|
@@ -2507,6 +2508,7 @@ export function parseConfig(
|
|
|
2507
2508
|
slotBehavior,
|
|
2508
2509
|
codexCompat,
|
|
2509
2510
|
codingKnowledge: parseCodingKnowledgeConfig(cfg.codingKnowledge),
|
|
2511
|
+
chat: parseChatConfig(cfg.chat),
|
|
2510
2512
|
// Hourly summaries
|
|
2511
2513
|
hourlySummariesEnabled: cfg.hourlySummariesEnabled !== false, // default: true
|
|
2512
2514
|
daySummaryEnabled: cfg.daySummaryEnabled !== false, // default: true
|
|
@@ -3246,6 +3248,13 @@ export function parseConfig(
|
|
|
3246
3248
|
// Issue #564 PR 3: off by default; enable explicitly after bench validation.
|
|
3247
3249
|
recallReasoningTraceBoostEnabled:
|
|
3248
3250
|
coerceBool(cfg.recallReasoningTraceBoostEnabled) ?? false,
|
|
3251
|
+
// Issue #1582: off by default — handles are byte-additive at injection time.
|
|
3252
|
+
recallMemoryHandles: coerceBool(cfg.recallMemoryHandles) ?? false,
|
|
3253
|
+
recallHandleSnapshotDepth:
|
|
3254
|
+
typeof cfg.recallHandleSnapshotDepth === "number" &&
|
|
3255
|
+
Number.isFinite(cfg.recallHandleSnapshotDepth)
|
|
3256
|
+
? Math.max(1, Math.min(50, Math.floor(cfg.recallHandleSnapshotDepth)))
|
|
3257
|
+
: 5,
|
|
3249
3258
|
qmdRecallCacheTtlMs:
|
|
3250
3259
|
typeof cfg.qmdRecallCacheTtlMs === "number" ? Math.max(0, Math.floor(cfg.qmdRecallCacheTtlMs)) : 60_000,
|
|
3251
3260
|
qmdRecallCacheStaleTtlMs:
|
package/src/orchestrator.ts
CHANGED
|
@@ -126,6 +126,7 @@ import { RelevanceStore } from "./relevance.js";
|
|
|
126
126
|
import { NegativeExampleStore } from "./negative.js";
|
|
127
127
|
import {
|
|
128
128
|
LastRecallStore,
|
|
129
|
+
RecallHandleHistoryStore,
|
|
129
130
|
type LastRecallBudgetSummary,
|
|
130
131
|
TierMigrationStatusStore,
|
|
131
132
|
clampGraphRecallExpandedEntries,
|
|
@@ -134,6 +135,14 @@ import {
|
|
|
134
135
|
type TierMigrationCycleSummary,
|
|
135
136
|
type TierMigrationStatusSnapshot,
|
|
136
137
|
} from "./recall-state.js";
|
|
138
|
+
import {
|
|
139
|
+
buildHandleIndexForResults,
|
|
140
|
+
MEMORY_ID_PATTERN,
|
|
141
|
+
parseIdOrHandle,
|
|
142
|
+
resolveHandle,
|
|
143
|
+
stripHandles,
|
|
144
|
+
type RecallSnapshotIds,
|
|
145
|
+
} from "./recall-handles.js";
|
|
137
146
|
import {
|
|
138
147
|
buildXraySnapshot,
|
|
139
148
|
type RecallFilterTrace,
|
|
@@ -1872,6 +1881,7 @@ export class Orchestrator {
|
|
|
1872
1881
|
readonly relevance: RelevanceStore;
|
|
1873
1882
|
readonly negatives: NegativeExampleStore;
|
|
1874
1883
|
readonly lastRecall: LastRecallStore;
|
|
1884
|
+
readonly handleHistory: RecallHandleHistoryStore;
|
|
1875
1885
|
readonly tierMigrationStatus: TierMigrationStatusStore;
|
|
1876
1886
|
/**
|
|
1877
1887
|
* In-memory X-ray snapshot from the most recent `recall()` call that
|
|
@@ -2797,6 +2807,9 @@ export class Orchestrator {
|
|
|
2797
2807
|
this.relevance = new RelevanceStore(config.memoryDir);
|
|
2798
2808
|
this.negatives = new NegativeExampleStore(config.memoryDir);
|
|
2799
2809
|
this.lastRecall = new LastRecallStore(config.memoryDir);
|
|
2810
|
+
this.handleHistory = new RecallHandleHistoryStore(config.memoryDir, {
|
|
2811
|
+
maxDepth: config.recallHandleSnapshotDepth,
|
|
2812
|
+
});
|
|
2800
2813
|
this.tierMigrationStatus = new TierMigrationStatusStore(config.memoryDir);
|
|
2801
2814
|
this.sessionObserver = new SessionObserverState({
|
|
2802
2815
|
memoryDir: config.memoryDir,
|
|
@@ -3241,6 +3254,7 @@ export class Orchestrator {
|
|
|
3241
3254
|
await this.relevance.load();
|
|
3242
3255
|
await this.negatives.load();
|
|
3243
3256
|
await this.lastRecall.load();
|
|
3257
|
+
await this.handleHistory.load();
|
|
3244
3258
|
await this.tierMigrationStatus.load();
|
|
3245
3259
|
await this.sessionObserver.load();
|
|
3246
3260
|
this.runtimePolicyValues = await this.policyRuntime.loadRuntimeValues();
|
|
@@ -11299,7 +11313,7 @@ export class Orchestrator {
|
|
|
11299
11313
|
this.appendRecallSection(
|
|
11300
11314
|
sectionBuckets,
|
|
11301
11315
|
"workspace-context",
|
|
11302
|
-
this.formatQmdResults("Workspace Context", globalResults),
|
|
11316
|
+
this.formatQmdResults("Workspace Context", globalResults, sessionKey),
|
|
11303
11317
|
);
|
|
11304
11318
|
}
|
|
11305
11319
|
|
|
@@ -12073,6 +12087,22 @@ export class Orchestrator {
|
|
|
12073
12087
|
backendDegradations.length > 0 ? backendDegradations : undefined,
|
|
12074
12088
|
})
|
|
12075
12089
|
.catch((err) => log.debug(`last recall record failed: ${err}`));
|
|
12090
|
+
// Issue #1582 — record the admitted memory-id set for handle resolution.
|
|
12091
|
+
// Only when handles are enabled: if injection is off, no handle is ever
|
|
12092
|
+
// rendered, so there is nothing to resolve and we skip the write.
|
|
12093
|
+
if (this.config.recallMemoryHandles && recalledMemoryIds.length > 0) {
|
|
12094
|
+
// Only handle-eligible ids aid resolution; filter out non-memory .md
|
|
12095
|
+
// basenames (entity reconstructions) so the resolver never records a
|
|
12096
|
+
// citation target that cannot be loaded.
|
|
12097
|
+
const handleEligibleIds = recalledMemoryIds.filter((id) =>
|
|
12098
|
+
MEMORY_ID_PATTERN.test(id),
|
|
12099
|
+
);
|
|
12100
|
+
if (handleEligibleIds.length > 0) {
|
|
12101
|
+
this.handleHistory
|
|
12102
|
+
.record(sessionKey, handleEligibleIds)
|
|
12103
|
+
.catch((err) => log.debug(`handle history record failed: ${err}`));
|
|
12104
|
+
}
|
|
12105
|
+
}
|
|
12076
12106
|
}
|
|
12077
12107
|
if (sessionKey) {
|
|
12078
12108
|
this.queueEvalShadowRecall({
|
|
@@ -12165,9 +12195,17 @@ export class Orchestrator {
|
|
|
12165
12195
|
? sessionKey
|
|
12166
12196
|
: "default";
|
|
12167
12197
|
const captureTimestamp = new Date().toISOString();
|
|
12198
|
+
// Issue #1582 hygiene §2 — strip any echoed `[m:xxxx]` handle before the
|
|
12199
|
+
// turn enters the extraction buffer so handles never become memory content
|
|
12200
|
+
// or get QMD-indexed (rule 23). Gated on the feature flag: when handles are
|
|
12201
|
+
// off none are ever injected, so there is nothing to strip and the buffer
|
|
12202
|
+
// stays byte-identical to the pre-#1582 path.
|
|
12203
|
+
const bufferedContent = this.config.recallMemoryHandles
|
|
12204
|
+
? stripHandles(content)
|
|
12205
|
+
: content;
|
|
12168
12206
|
const turn: BufferTurn = {
|
|
12169
12207
|
role,
|
|
12170
|
-
content,
|
|
12208
|
+
content: bufferedContent,
|
|
12171
12209
|
timestamp: captureTimestamp,
|
|
12172
12210
|
// #1578: anchor live-capture turns to wall-clock when bi-temporal is on;
|
|
12173
12211
|
// replay/import turns carry sourceValidAt explicitly (codex P1).
|
|
@@ -17455,13 +17493,28 @@ export class Orchestrator {
|
|
|
17455
17493
|
}
|
|
17456
17494
|
}
|
|
17457
17495
|
|
|
17458
|
-
private formatQmdResults(
|
|
17496
|
+
private formatQmdResults(
|
|
17497
|
+
title: string,
|
|
17498
|
+
results: QmdSearchResult[],
|
|
17499
|
+
sessionKey?: string,
|
|
17500
|
+
): string {
|
|
17501
|
+
// Issue #1582 — handles are only rendered when a session key is available:
|
|
17502
|
+
// resolution requires the handle history to have been recorded for this
|
|
17503
|
+
// session, which only happens when sessionKey is present. Rendering handles
|
|
17504
|
+
// without recording would show tokens a user can never resolve (cursor
|
|
17505
|
+
// review). The rendering logic itself lives in the pure handles module.
|
|
17506
|
+
const handleByIndex = buildHandleIndexForResults(
|
|
17507
|
+
results,
|
|
17508
|
+
this.config.recallMemoryHandles === true && sessionKey != null,
|
|
17509
|
+
);
|
|
17459
17510
|
const lines = results.map((r, i) => {
|
|
17460
17511
|
const snippet = r.snippet
|
|
17461
17512
|
? r.snippet.slice(0, 500).replace(/\n/g, " ")
|
|
17462
17513
|
: "(no preview)";
|
|
17463
17514
|
const source = typeof r.line === "number" ? `${r.path}:${r.line}` : r.path;
|
|
17464
|
-
|
|
17515
|
+
const head = `[${i + 1}] ${source} (score: ${r.score.toFixed(3)})\n${snippet}`;
|
|
17516
|
+
const handle = handleByIndex.get(i);
|
|
17517
|
+
return handle ? `${head.replace(/\s+$/, "")} ${handle}` : head;
|
|
17465
17518
|
});
|
|
17466
17519
|
return `## ${title}\n\n${lines.join("\n\n")}`;
|
|
17467
17520
|
}
|
|
@@ -17826,7 +17879,7 @@ export class Orchestrator {
|
|
|
17826
17879
|
this.appendRecallSection(
|
|
17827
17880
|
options.sectionBuckets,
|
|
17828
17881
|
sectionId,
|
|
17829
|
-
this.formatQmdResults(options.title, options.results),
|
|
17882
|
+
this.formatQmdResults(options.title, options.results, options.sessionKey),
|
|
17830
17883
|
);
|
|
17831
17884
|
}
|
|
17832
17885
|
|
|
@@ -19661,6 +19714,54 @@ export class Orchestrator {
|
|
|
19661
19714
|
return this.lastRecall.get(sessionKey);
|
|
19662
19715
|
}
|
|
19663
19716
|
|
|
19717
|
+
/**
|
|
19718
|
+
* Issue #1582 — resolve a memory handle (`[m:4f2a]` / bare hex) to its memory
|
|
19719
|
+
* id against THIS session's recent recall history. Returns the id on a unique
|
|
19720
|
+
* hit, `null` on a miss, and throws on ambiguity (callers must disambiguate —
|
|
19721
|
+
* rule 34/51). Resolution is per-session and snapshot-scoped; there is no
|
|
19722
|
+
* global handle→id map (rule 42).
|
|
19723
|
+
*/
|
|
19724
|
+
resolveMemoryHandle(handle: string, sessionKey: string): string | null {
|
|
19725
|
+
if (!sessionKey) return null;
|
|
19726
|
+
const depth = this.config.recallHandleSnapshotDepth;
|
|
19727
|
+
const snapshots: RecallSnapshotIds[] = this.handleHistory
|
|
19728
|
+
.recent(sessionKey, depth)
|
|
19729
|
+
.map((ids) => ({ memoryIds: ids }));
|
|
19730
|
+
const result = resolveHandle(handle, snapshots, depth);
|
|
19731
|
+
if (result.ok) return result.memoryId;
|
|
19732
|
+
if (result.reason === "ambiguous") {
|
|
19733
|
+
throw new Error(
|
|
19734
|
+
`Memory handle ${handle} is ambiguous in session ${sessionKey}: ` +
|
|
19735
|
+
`${result.candidates.join(", ")}. Cite a unique memory id instead.`,
|
|
19736
|
+
);
|
|
19737
|
+
}
|
|
19738
|
+
return null;
|
|
19739
|
+
}
|
|
19740
|
+
|
|
19741
|
+
/**
|
|
19742
|
+
* Issue #1582 — resolve a caller reference that may be EITHER a memory id or
|
|
19743
|
+
* a handle to a concrete memory id. Handles resolve against the session's
|
|
19744
|
+
* recall history; raw ids pass through unchanged. The single shared helper
|
|
19745
|
+
* every surface (memory_get / feedback / outcome / correction targetIds)
|
|
19746
|
+
* calls so handle resolution has one path (rule 22).
|
|
19747
|
+
*/
|
|
19748
|
+
resolveMemoryIdOrHandle(ref: string, sessionKey?: string): string {
|
|
19749
|
+
const parsed = parseIdOrHandle(ref);
|
|
19750
|
+
if (!parsed.isHandle) return parsed.value;
|
|
19751
|
+
if (!sessionKey) {
|
|
19752
|
+
throw new Error(
|
|
19753
|
+
`Memory handle ${ref} cannot be resolved without a session key.`,
|
|
19754
|
+
);
|
|
19755
|
+
}
|
|
19756
|
+
const resolved = this.resolveMemoryHandle(parsed.value, sessionKey);
|
|
19757
|
+
if (resolved === null) {
|
|
19758
|
+
throw new Error(
|
|
19759
|
+
`Memory handle ${ref} was not found in the recent recall history for session ${sessionKey}.`,
|
|
19760
|
+
);
|
|
19761
|
+
}
|
|
19762
|
+
return resolved;
|
|
19763
|
+
}
|
|
19764
|
+
|
|
19664
19765
|
/**
|
|
19665
19766
|
* Check if a new memory contradicts an existing one.
|
|
19666
19767
|
* Uses QMD to find similar memories, then LLM to verify contradiction.
|