@remnic/core 9.65.7 → 9.65.8
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-admin-ops-surface.d.ts +15 -13
- package/dist/access-admin-ops-surface.js +42 -42
- package/dist/access-authorization-probe.d.ts +15 -13
- package/dist/access-authorization-probe.js +43 -43
- package/dist/access-boundary.d.ts +15 -13
- package/dist/access-boundary.js +42 -42
- package/dist/access-cli.js +143 -140
- package/dist/access-cli.js.map +1 -1
- package/dist/access-coding-context-resolution.d.ts +2 -1
- package/dist/access-extraction-force-flush.d.ts +15 -13
- package/dist/access-extraction-force-flush.js +42 -42
- package/dist/access-health-types.d.ts +2 -1
- package/dist/access-http-lcm-compaction.d.ts +15 -13
- package/dist/access-http-lifecycle-flush.d.ts +15 -13
- package/dist/access-http-offline-stream.d.ts +15 -13
- package/dist/access-http-query.d.ts +3 -2
- package/dist/access-http-query.js +44 -44
- package/dist/access-http.d.ts +16 -14
- package/dist/access-http.js +59 -59
- package/dist/access-identity-continuity-surface.d.ts +13 -11
- package/dist/access-identity-continuity-surface.js +42 -42
- package/dist/access-lcm-surface.d.ts +15 -13
- package/dist/access-lcm-surface.js +42 -42
- package/dist/access-mcp.d.ts +15 -13
- package/dist/access-mcp.js +49 -49
- package/dist/access-memory-search-fanout.d.ts +3 -2
- package/dist/{access-namespace-preflight-8VYKmRX0.d.ts → access-namespace-preflight-CpAOrS-9.d.ts} +1 -1
- package/dist/access-namespace-preflight.d.ts +4 -3
- package/dist/access-namespace-preflight.js +42 -42
- package/dist/access-observe-write-surface.d.ts +15 -13
- package/dist/access-observe-write-surface.js +42 -42
- package/dist/access-offline-manifest.d.ts +13 -11
- package/dist/access-offline-manifest.js +6 -6
- package/dist/access-operations-batch.js +45 -45
- package/dist/access-operations.d.ts +20 -18
- package/dist/access-operations.js +48 -48
- package/dist/access-recall-concurrency.d.ts +15 -13
- package/dist/access-recall-concurrency.js +42 -42
- package/dist/access-recall-response.d.ts +15 -13
- package/dist/access-recall-response.js +42 -42
- package/dist/access-recall-surface.d.ts +15 -13
- package/dist/access-recall-surface.js +42 -42
- package/dist/access-schema.d.ts +83 -83
- package/dist/{access-service-Crk__Git.d.ts → access-service-Diu61Cfv.d.ts} +71 -71
- package/dist/access-service-helpers.d.ts +15 -13
- package/dist/access-service.d.ts +15 -13
- package/dist/access-service.js +42 -42
- package/dist/access-surface-catalog.d.ts +15 -13
- package/dist/access-surface-catalog.js +44 -44
- package/dist/access-wearables-meetings-surface.d.ts +6 -3
- package/dist/action-confidence.d.ts +2 -1
- package/dist/active-context-config.d.ts +27 -0
- package/dist/active-context-config.js +14 -0
- package/dist/active-context-transform.d.ts +267 -0
- package/dist/active-context-transform.js +31 -0
- package/dist/active-context-transform.js.map +1 -0
- package/dist/active-memory-bridge.d.ts +2 -1
- package/dist/active-recall.d.ts +2 -1
- package/dist/active-recall.js +10 -9
- package/dist/active-recall.js.map +1 -1
- package/dist/adapters/index.js +7 -7
- package/dist/adapters/registry.js +3 -3
- package/dist/ambient-provenance.d.ts +2 -1
- package/dist/artifact-search.d.ts +2 -1
- package/dist/{auto-sync-XVMLL2RH.js → auto-sync-2YPITIWN.js} +6 -6
- package/dist/behavior-learner.d.ts +2 -1
- package/dist/behavior-signals.d.ts +2 -1
- package/dist/bootstrap.d.ts +13 -11
- package/dist/briefing-window.d.ts +5 -2
- package/dist/briefing.d.ts +5 -2
- package/dist/briefing.js +23 -23
- package/dist/buffer-surprise-report.d.ts +2 -1
- package/dist/buffer-turn-helpers.d.ts +2 -1
- package/dist/buffer.d.ts +5 -2
- package/dist/buffer.js +6 -6
- package/dist/bulk-import/index.d.ts +4 -3
- package/dist/calibration.d.ts +2 -1
- package/dist/capabilities.d.ts +2 -1
- package/dist/{catalog-DybwVNW3.d.ts → catalog-9f-vEQLS.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +4 -3
- package/dist/causal-consolidation.d.ts +2 -1
- package/dist/causal-consolidation.js +24 -24
- package/dist/causal-trajectory-graph.d.ts +2 -1
- package/dist/{chunk-JBPKEARU.js → chunk-2QSZNTDO.js} +7 -7
- package/dist/{chunk-S3K2CIK5.js → chunk-3A2NJP2U.js} +2 -2
- package/dist/{chunk-OPGL46PX.js → chunk-3PKAS6VL.js} +2 -2
- package/dist/{chunk-GTSVEEP3.js → chunk-3SZD4CYO.js} +3 -3
- package/dist/chunk-43HUVDTD.js +114 -0
- package/dist/chunk-43HUVDTD.js.map +1 -0
- package/dist/{chunk-YKWFK7XA.js → chunk-4F4AQFWL.js} +7 -7
- package/dist/{chunk-RGCF4XNH.js → chunk-4QEYREAV.js} +9 -9
- package/dist/{chunk-46WM6JX2.js → chunk-4ZWCQJNM.js} +5 -5
- package/dist/{chunk-DVYRD4HY.js → chunk-5ACCD4L7.js} +30 -1
- package/dist/chunk-5ACCD4L7.js.map +1 -0
- package/dist/{chunk-3RI5Y7KU.js → chunk-5DHKCO52.js} +2 -2
- package/dist/{chunk-VKCAHCBI.js → chunk-5RWZH6PH.js} +2 -2
- package/dist/{chunk-52II7PB6.js → chunk-645WOU5I.js} +4 -4
- package/dist/{chunk-A32YEQAM.js → chunk-76DIF5KT.js} +2 -2
- package/dist/{chunk-OPPBTPUU.js → chunk-7KQB4EBS.js} +4 -4
- package/dist/{chunk-I2HTKOOP.js → chunk-7VZFRUQU.js} +3 -3
- package/dist/{chunk-D4QVPP3G.js → chunk-7WOWGRAU.js} +10 -6
- package/dist/chunk-7WOWGRAU.js.map +1 -0
- package/dist/{chunk-JCWY73FK.js → chunk-AHPIFKNG.js} +2 -2
- package/dist/{chunk-IP4ZNT4U.js → chunk-AZMLH5UT.js} +2 -2
- package/dist/chunk-B32WYRXX.js +77 -0
- package/dist/chunk-B32WYRXX.js.map +1 -0
- package/dist/{chunk-JOEJG4SD.js → chunk-BEC4YBNA.js} +4 -4
- package/dist/{chunk-VXVZ2GM3.js → chunk-CAMNRAJF.js} +2 -2
- package/dist/{chunk-C24UZSFW.js → chunk-CEH2AFXG.js} +6 -6
- package/dist/{chunk-YOXVZJFM.js → chunk-CFVTRUR3.js} +2 -2
- package/dist/{chunk-SVSRPG6M.js → chunk-CPA5NBHN.js} +2 -2
- package/dist/{chunk-7BEPVIH3.js → chunk-CRML27CO.js} +3 -3
- package/dist/{chunk-IY7UXD3J.js → chunk-DA7ITC5Z.js} +2 -2
- package/dist/{chunk-AFR6AIM4.js → chunk-DEACDKE3.js} +3 -3
- package/dist/{chunk-NG3MBQV4.js → chunk-DPCXDG7G.js} +2 -2
- package/dist/{chunk-HZNYJN77.js → chunk-F3NVYTTA.js} +2 -2
- package/dist/{chunk-PDDSFELN.js → chunk-F7XUD3PL.js} +2 -2
- package/dist/{chunk-YWSQD2IB.js → chunk-GTO56JY5.js} +2 -2
- package/dist/{chunk-RAIUTAZZ.js → chunk-H2YSH3DG.js} +2 -2
- package/dist/{chunk-F6QHHRWP.js → chunk-HMZKGHMD.js} +2 -2
- package/dist/{chunk-ZIJDI4CP.js → chunk-HRHO3ZNG.js} +2 -2
- package/dist/{chunk-SDEPLF7V.js → chunk-IBJ6U753.js} +2 -2
- package/dist/{chunk-T3JQTCCO.js → chunk-JI7U6AS3.js} +4 -4
- package/dist/{chunk-TR7DGXGI.js → chunk-JOZUBF4A.js} +5 -5
- package/dist/{chunk-I7EX6KSH.js → chunk-JYSN42VN.js} +55 -55
- package/dist/{chunk-ZPUIRTIZ.js → chunk-KOLJJN5G.js} +12 -75
- package/dist/chunk-KOLJJN5G.js.map +1 -0
- package/dist/{chunk-FMQ4MOQO.js → chunk-KZIF6XHX.js} +14 -14
- package/dist/chunk-LB7WCZHY.js +553 -0
- package/dist/chunk-LB7WCZHY.js.map +1 -0
- package/dist/{chunk-RIAM7DND.js → chunk-LDKPDODJ.js} +2 -2
- package/dist/{chunk-227UFSEQ.js → chunk-LEPOP46W.js} +4 -4
- package/dist/{chunk-LLQCM2U2.js → chunk-LKYIOCWL.js} +101 -101
- package/dist/{chunk-5S4LQOPE.js → chunk-LOXHYCVS.js} +2 -2
- package/dist/{chunk-ANJXPFRS.js → chunk-LPNCR4QK.js} +8 -8
- package/dist/{chunk-GEPACVWN.js → chunk-MDD2RINF.js} +2 -2
- package/dist/{chunk-H63EDPFJ.js → chunk-MI2OTWV5.js} +15 -2
- package/dist/{chunk-H63EDPFJ.js.map → chunk-MI2OTWV5.js.map} +1 -1
- package/dist/{chunk-LBFFNDFM.js → chunk-MINHJ55X.js} +1 -1
- package/dist/chunk-MINHJ55X.js.map +1 -0
- package/dist/{chunk-6CPUQ5D6.js → chunk-MY2BC6UE.js} +13 -13
- package/dist/{chunk-CFGU52XJ.js → chunk-NPFUNWNX.js} +2 -2
- package/dist/{chunk-MFOSZUIT.js → chunk-NPIBN2VL.js} +2 -2
- package/dist/{chunk-5DH6PG4B.js → chunk-OA2O2GJ4.js} +3 -3
- package/dist/{chunk-JAQXUGLN.js → chunk-ODU2CNNX.js} +2 -2
- package/dist/{chunk-RQE4TITU.js → chunk-OXRRJXPR.js} +32 -32
- package/dist/{chunk-SEA6M7SS.js → chunk-P36Z4JRA.js} +2 -2
- package/dist/{chunk-Z4U3UN56.js → chunk-PU56CXZA.js} +6 -6
- package/dist/{chunk-5VPQSRQO.js → chunk-S5XOSTYM.js} +3 -3
- package/dist/{chunk-SVVIASVX.js → chunk-SEEJOGQX.js} +5 -5
- package/dist/{chunk-7TCGNUVP.js → chunk-SNOIKAHM.js} +2 -2
- package/dist/{chunk-7F27PCSN.js → chunk-T6ILXUAH.js} +2 -2
- package/dist/{chunk-EOHKUWXW.js → chunk-T7XP6IZE.js} +2 -2
- package/dist/{chunk-7WR462EM.js → chunk-TFR3HG4K.js} +3 -3
- package/dist/{chunk-YRVAKONL.js → chunk-TUHBYJXL.js} +1 -1
- package/dist/{chunk-F635GAL7.js → chunk-U7EW2W4W.js} +10 -10
- package/dist/{chunk-VFYRYFLL.js → chunk-UEBDCMOO.js} +2 -2
- package/dist/{chunk-WTOZBZNN.js → chunk-UENKPWCS.js} +4 -4
- package/dist/{chunk-AAXJNINV.js → chunk-UL4MKZHI.js} +2 -2
- package/dist/{chunk-R2MZCYA6.js → chunk-UNUMFURP.js} +3 -3
- package/dist/{chunk-ACOC27BB.js → chunk-UPFNQJC7.js} +2 -2
- package/dist/{chunk-W4BMEGQA.js → chunk-UTQUEHC7.js} +2 -2
- package/dist/{chunk-I32NKXE2.js → chunk-V4IDF3EZ.js} +2 -2
- package/dist/{chunk-BJTHRFFC.js → chunk-W2BAGGEW.js} +51 -19
- package/dist/chunk-W2BAGGEW.js.map +1 -0
- package/dist/{chunk-ZAOHJDKH.js → chunk-WNXYT4MK.js} +3 -3
- package/dist/{chunk-T42L3S6A.js → chunk-XBGHAAKR.js} +2 -2
- package/dist/{chunk-I4343FIA.js → chunk-XNWXSGHS.js} +4 -4
- package/dist/{chunk-THG4GYIE.js → chunk-YEUXERJ6.js} +5 -5
- package/dist/{chunk-EZ25VE3G.js → chunk-YNDLCWXS.js} +4 -4
- package/dist/{chunk-5HERQ5FX.js → chunk-Z3YEGSR4.js} +10 -10
- package/dist/{cli-B322UMvB.d.ts → cli-O3F-ht3i.d.ts} +5 -5
- package/dist/cli.d.ts +17 -15
- package/dist/cli.js +92 -91
- package/dist/coding/pre-action-gate.d.ts +2 -1
- package/dist/compounding/engine.d.ts +5 -2
- package/dist/compounding/engine.js +24 -24
- package/dist/compounding/preference-consolidator.d.ts +4 -3
- package/dist/compression-optimizer.d.ts +2 -1
- package/dist/config-security.js +2 -2
- package/dist/config.d.ts +2 -1
- package/dist/config.js +10 -9
- package/dist/connectors/codex-materialize-runner.d.ts +2 -1
- package/dist/connectors/codex-materialize-runner.js +23 -23
- package/dist/connectors/codex-materialize.d.ts +2 -1
- package/dist/connectors/index.d.ts +2 -1
- package/dist/connectors/index.js +23 -23
- package/dist/consolidation-provenance-check.d.ts +5 -2
- package/dist/consolidation-provenance-check.js +2 -2
- package/dist/consolidation-undo.d.ts +5 -2
- package/dist/context-summary.d.ts +43 -0
- package/dist/context-summary.js +14 -0
- package/dist/context-summary.js.map +1 -0
- package/dist/contradiction/index.d.ts +6 -3
- package/dist/contradiction/index.js +5 -5
- package/dist/converge-config.d.ts +2 -1
- package/dist/convergence-refresh.d.ts +5 -2
- package/dist/convergence-refresh.js +26 -26
- package/dist/conversation-index/backend.d.ts +2 -1
- package/dist/conversation-index/backend.js +2 -2
- package/dist/conversation-index/chunker.d.ts +2 -1
- package/dist/conversation-index/faiss-adapter.d.ts +2 -1
- package/dist/conversation-index/indexer.d.ts +2 -1
- package/dist/conversation-index/search.d.ts +2 -1
- package/dist/corpus-watermark.d.ts +2 -1
- package/dist/corpus-watermark.js +25 -25
- package/dist/cross-lingual-recall.d.ts +2 -1
- package/dist/dashboard-runtime.js +2 -2
- package/dist/day-summary.d.ts +2 -1
- package/dist/delinearize.d.ts +2 -1
- package/dist/dependency-propagation-config.d.ts +2 -1
- package/dist/{dependency-propagation-delivery-BGcNairQ.d.ts → dependency-propagation-delivery-CL6RWXTA.d.ts} +1 -1
- package/dist/direct-answer-wiring.d.ts +2 -1
- package/dist/direct-answer.d.ts +2 -1
- package/dist/embedding-fallback.d.ts +2 -1
- package/dist/enrichment/index.d.ts +2 -1
- package/dist/entity-origin-fields.d.ts +2 -1
- package/dist/entity-retrieval.d.ts +5 -2
- package/dist/entity-retrieval.js +24 -24
- package/dist/entity-schema.d.ts +2 -1
- package/dist/episodic-context.d.ts +2 -1
- package/dist/eval-trajectory-contracts.d.ts +2 -1
- package/dist/eval-trajectory-store.d.ts +2 -1
- package/dist/eval-trajectory.d.ts +2 -1
- package/dist/event-order-recall.js +3 -3
- package/dist/explicit-capture.d.ts +13 -11
- package/dist/explicit-capture.js +6 -6
- package/dist/external-wiki-access.d.ts +15 -13
- package/dist/external-wiki-access.js +43 -43
- package/dist/external-wiki-collection-registration.d.ts +2 -1
- package/dist/external-wiki-collection.d.ts +2 -1
- package/dist/external-wiki-mcp-tools.d.ts +15 -13
- package/dist/extraction-error-classification.d.ts +2 -1
- package/dist/extraction-faithfulness.d.ts +2 -1
- package/dist/extraction-judge-telemetry.d.ts +2 -1
- package/dist/extraction-judge-training.d.ts +2 -1
- package/dist/extraction-judge.d.ts +2 -1
- package/dist/extraction-liveness.d.ts +2 -1
- package/dist/extraction-normalization.d.ts +2 -1
- package/dist/extraction-prompt.d.ts +2 -1
- package/dist/extraction-source-grounding-rules.d.ts +2 -1
- package/dist/extraction-source-grounding.d.ts +2 -1
- package/dist/extraction.d.ts +2 -1
- package/dist/extraction.js +31 -31
- package/dist/fallback-llm.d.ts +2 -1
- package/dist/{forget-SZ2BXDGF.js → forget-2AE4MDK3.js} +3 -3
- package/dist/graph-dashboard-diff.d.ts +2 -1
- package/dist/graph-dashboard-key.d.ts +2 -1
- package/dist/graph-dashboard-parser.d.ts +2 -1
- package/dist/graph-edge-reinforcement.d.ts +2 -1
- package/dist/graph-path-reconstruction.d.ts +2 -1
- package/dist/graph-path-scoring.d.ts +2 -1
- package/dist/graph-snapshot.d.ts +2 -1
- package/dist/graph.d.ts +2 -1
- package/dist/harmonic-retrieval.js +1 -1
- package/dist/importance.d.ts +2 -1
- package/dist/importers/index.d.ts +2 -1
- package/dist/in-flight-reads.d.ts +2 -1
- package/dist/{index-By2QUAMh.d.ts → index-C7Xep6S9.d.ts} +2 -2
- package/dist/index.d.ts +703 -701
- package/dist/index.js +225 -196
- package/dist/intent.d.ts +2 -1
- package/dist/lcm/engine.d.ts +3 -2
- package/dist/lcm/engine.js +5 -4
- package/dist/lcm/index.d.ts +4 -2
- package/dist/lcm/index.js +12 -11
- package/dist/lcm/summarizer.d.ts +4 -6
- package/dist/lcm/summarizer.js +2 -1
- package/dist/lcm/tools.d.ts +4 -3
- package/dist/lifecycle.d.ts +2 -1
- package/dist/live-connectors-runner.d.ts +2 -1
- package/dist/local-llm.d.ts +2 -1
- package/dist/local-model-endpoint.d.ts +2 -1
- package/dist/maintenance/memory-governance.d.ts +2 -1
- package/dist/maintenance/memory-governance.js +24 -24
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +5 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +23 -23
- package/dist/maintenance/rebuild-memory-projection.d.ts +5 -2
- package/dist/maintenance/rebuild-memory-projection.js +25 -25
- package/dist/{maintenance-Dm2McrIx.d.ts → maintenance-CJ-xqFp0.d.ts} +3 -3
- package/dist/mcp-memory-inspector-app.d.ts +15 -13
- package/dist/memory-action-policy.d.ts +18 -2
- package/dist/memory-action-policy.js +3 -1
- package/dist/memory-cache.d.ts +2 -1
- package/dist/memory-controller.d.ts +2 -1
- package/dist/memory-controller.js +2 -2
- package/dist/memory-lifecycle-ledger-utils.d.ts +2 -1
- package/dist/memory-projection-store.d.ts +2 -1
- package/dist/memory-provenance.d.ts +2 -1
- package/dist/memory-snapshot.d.ts +2 -1
- package/dist/memory-subject-cli.d.ts +15 -13
- package/dist/memory-subject.d.ts +15 -13
- package/dist/memory-subject.js +3 -3
- package/dist/memory-worth-outcomes.d.ts +5 -2
- package/dist/models-json.d.ts +2 -1
- package/dist/namespaces/migrate.d.ts +6 -3
- package/dist/namespaces/migrate.js +24 -24
- package/dist/namespaces/principal.d.ts +2 -1
- package/dist/namespaces/search.d.ts +2 -1
- package/dist/namespaces/search.js +9 -9
- package/dist/namespaces/storage.d.ts +6 -3
- package/dist/namespaces/storage.js +23 -23
- package/dist/native-knowledge.d.ts +2 -1
- package/dist/offline-sync-impression-drain.d.ts +2 -1
- package/dist/offline-sync-impression-drain.js +2 -2
- package/dist/operator-doctor-corpus.d.ts +2 -1
- package/dist/operator-doctor-corpus.js +26 -26
- package/dist/operator-doctor-replica.d.ts +2 -1
- package/dist/operator-toolkit.d.ts +6 -3
- package/dist/operator-toolkit.js +38 -37
- package/dist/orchestration/compression-guideline-coordinator.d.ts +5 -2
- package/dist/orchestration/maintenance.d.ts +7 -4
- package/dist/orchestration/maintenance.js +31 -31
- package/dist/{orchestrator-Co1DyfuP.d.ts → orchestrator-BsntWxLy.d.ts} +8 -8
- package/dist/orchestrator.d.ts +13 -11
- package/dist/orchestrator.js +143 -140
- package/dist/patterns-cli.d.ts +2 -1
- package/dist/{pipeline-DotMnb6y.d.ts → pipeline-CVoysPm2.d.ts} +1 -1
- package/dist/policy-runtime.d.ts +2 -1
- package/dist/proactive-contention.d.ts +2 -1
- package/dist/provenance.d.ts +2 -1
- package/dist/{public-http-PJRtnSi-.d.ts → public-http-CuOxlTC2.d.ts} +1 -1
- package/dist/{qmd-BP0n11fR.d.ts → qmd-DWMAGA5l.d.ts} +1 -1
- package/dist/qmd-preflight.d.ts +3 -2
- package/dist/qmd-recall-cache.d.ts +2 -1
- package/dist/qmd.d.ts +3 -2
- package/dist/qmd.js +4 -4
- package/dist/recall-concurrency-config.d.ts +2 -1
- package/dist/recall-disclosure-escalation.d.ts +2 -1
- package/dist/recall-explain-renderer.d.ts +2 -1
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-memory-map.d.ts +2 -1
- package/dist/recall-planner-llm.d.ts +2 -1
- package/dist/recall-state.d.ts +2 -1
- package/dist/recall-tag-filter.d.ts +2 -1
- package/dist/recall-timings.d.ts +2 -1
- package/dist/recall-xray-cli.d.ts +2 -1
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +2 -1
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +2 -1
- package/dist/recall-xray.js +2 -2
- package/dist/reconcile/cursor.d.ts +2 -1
- package/dist/reconcile/manifest.d.ts +2 -1
- package/dist/reconcile/manifest.js +3 -3
- package/dist/reconcile/plan.d.ts +2 -1
- package/dist/replay/normalizers/chatgpt.d.ts +2 -1
- package/dist/replay/normalizers/claude.d.ts +2 -1
- package/dist/replay/normalizers/openclaw.d.ts +2 -1
- package/dist/replay/normalizers/shared.d.ts +2 -1
- package/dist/replay/runner.d.ts +2 -1
- package/dist/replay/types.d.ts +2 -1
- package/dist/replica-divergence.d.ts +2 -1
- package/dist/replica-peers-config.d.ts +2 -1
- package/dist/{resolution-4552BNRV.js → resolution-XWBPKYFB.js} +6 -6
- package/dist/resolution-XWBPKYFB.js.map +1 -0
- package/dist/resolve-auth-token.d.ts +2 -1
- package/dist/resume-bundles.js +11 -10
- package/dist/retrieval-agents.d.ts +3 -2
- package/dist/retrieval-tiers.d.ts +2 -1
- package/dist/routing/engine.d.ts +2 -1
- package/dist/routing/store.d.ts +2 -1
- package/dist/salvage-envelope.d.ts +2 -1
- package/dist/salvage-envelope.js +5 -5
- package/dist/schemas.d.ts +124 -124
- package/dist/{scope-profiles-6ChZKTy-.d.ts → scope-profiles-CPWkW_dI.d.ts} +1 -1
- package/dist/search/embed-helper.d.ts +2 -1
- package/dist/search/factory.d.ts +2 -1
- package/dist/search/factory.js +8 -8
- package/dist/search/index.d.ts +2 -1
- package/dist/search/index.js +14 -14
- package/dist/search/lancedb-backend.d.ts +2 -1
- package/dist/search/meilisearch-backend.d.ts +2 -1
- package/dist/search/noop-backend.d.ts +2 -1
- package/dist/search/orama-backend.d.ts +2 -1
- package/dist/search/port.d.ts +2 -1
- package/dist/search/remote-backend.d.ts +2 -1
- package/dist/{semantic-consolidation-DziYcW5J.d.ts → semantic-consolidation-CNFVBXFc.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +3 -2
- package/dist/semantic-consolidation.js +29 -29
- package/dist/semantic-rule-promotion.js +23 -23
- package/dist/semantic-rule-verifier.d.ts +2 -1
- package/dist/semantic-rule-verifier.js +23 -23
- package/dist/{service-C7rIBuK_.d.ts → service-Bb-JIdQ0.d.ts} +2 -2
- package/dist/session-observer-bands.d.ts +2 -1
- package/dist/session-observer-state.d.ts +2 -1
- package/dist/shared-context/manager.d.ts +8 -7
- package/dist/signal.d.ts +2 -1
- package/dist/source-agent-qualifier.d.ts +2 -1
- package/dist/source-agent-qualifier.js +27 -27
- package/dist/{storage-B1hEx8Xg.d.ts → storage-CukrlNKk.d.ts} +4 -1
- package/dist/storage.d.ts +5 -2
- package/dist/storage.js +22 -22
- package/dist/subject-config.d.ts +2 -1
- package/dist/subject-config.js +4 -4
- package/dist/summarizer.d.ts +2 -1
- package/dist/summary-snapshot.d.ts +2 -1
- package/dist/support-passport/index.d.ts +18 -16
- package/dist/support-passport/index.js +45 -45
- package/dist/temporal-supersession.d.ts +3 -2
- package/dist/temporal-timeline-recall.d.ts +2 -1
- package/dist/temporal-validity.d.ts +2 -1
- package/dist/threading.d.ts +2 -1
- package/dist/tier-migration.d.ts +5 -2
- package/dist/tier-routing.d.ts +2 -1
- package/dist/topics.d.ts +2 -1
- package/dist/transcript.d.ts +2 -1
- package/dist/transfer/types.d.ts +78 -78
- package/dist/trust-score-stage.d.ts +2 -1
- package/dist/trust-score.d.ts +2 -1
- package/dist/{types-BHDNxGTT.d.ts → types-djxQlxJ7.d.ts} +2 -1
- package/dist/types.d.ts +2 -1
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +2 -1
- package/dist/verified-recall.js +23 -23
- package/dist/who-knows-cli.d.ts +15 -13
- package/dist/who-knows-cli.js +24 -24
- package/dist/who-knows.d.ts +15 -13
- package/dist/who-knows.js +23 -23
- package/dist/write-envelope.d.ts +2 -1
- package/dist/write-envelope.js +4 -4
- package/package.json +22 -2
- package/src/active-context-config.ts +98 -0
- package/src/active-context-transform.test.ts +533 -0
- package/src/active-context-transform.ts +981 -0
- package/src/config.ts +3 -5
- package/src/context-summary.ts +182 -0
- package/src/index.ts +4 -11
- package/src/lcm/summarizer.ts +14 -93
- package/src/memory-action-policy.ts +28 -0
- package/src/storage/context-transform-ledger.ts +39 -0
- package/src/storage/secure-line-reader.ts +50 -1
- package/src/storage.ts +4 -1
- package/src/types.ts +2 -3
- package/dist/chunk-BJTHRFFC.js.map +0 -1
- package/dist/chunk-D4QVPP3G.js.map +0 -1
- package/dist/chunk-DVYRD4HY.js.map +0 -1
- package/dist/chunk-LBFFNDFM.js.map +0 -1
- package/dist/chunk-ZPUIRTIZ.js.map +0 -1
- /package/dist/{resolution-4552BNRV.js.map → active-context-config.js.map} +0 -0
- /package/dist/{auto-sync-XVMLL2RH.js.map → auto-sync-2YPITIWN.js.map} +0 -0
- /package/dist/{chunk-JBPKEARU.js.map → chunk-2QSZNTDO.js.map} +0 -0
- /package/dist/{chunk-S3K2CIK5.js.map → chunk-3A2NJP2U.js.map} +0 -0
- /package/dist/{chunk-OPGL46PX.js.map → chunk-3PKAS6VL.js.map} +0 -0
- /package/dist/{chunk-GTSVEEP3.js.map → chunk-3SZD4CYO.js.map} +0 -0
- /package/dist/{chunk-YKWFK7XA.js.map → chunk-4F4AQFWL.js.map} +0 -0
- /package/dist/{chunk-RGCF4XNH.js.map → chunk-4QEYREAV.js.map} +0 -0
- /package/dist/{chunk-46WM6JX2.js.map → chunk-4ZWCQJNM.js.map} +0 -0
- /package/dist/{chunk-3RI5Y7KU.js.map → chunk-5DHKCO52.js.map} +0 -0
- /package/dist/{chunk-VKCAHCBI.js.map → chunk-5RWZH6PH.js.map} +0 -0
- /package/dist/{chunk-52II7PB6.js.map → chunk-645WOU5I.js.map} +0 -0
- /package/dist/{chunk-A32YEQAM.js.map → chunk-76DIF5KT.js.map} +0 -0
- /package/dist/{chunk-OPPBTPUU.js.map → chunk-7KQB4EBS.js.map} +0 -0
- /package/dist/{chunk-I2HTKOOP.js.map → chunk-7VZFRUQU.js.map} +0 -0
- /package/dist/{chunk-JCWY73FK.js.map → chunk-AHPIFKNG.js.map} +0 -0
- /package/dist/{chunk-IP4ZNT4U.js.map → chunk-AZMLH5UT.js.map} +0 -0
- /package/dist/{chunk-JOEJG4SD.js.map → chunk-BEC4YBNA.js.map} +0 -0
- /package/dist/{chunk-VXVZ2GM3.js.map → chunk-CAMNRAJF.js.map} +0 -0
- /package/dist/{chunk-C24UZSFW.js.map → chunk-CEH2AFXG.js.map} +0 -0
- /package/dist/{chunk-YOXVZJFM.js.map → chunk-CFVTRUR3.js.map} +0 -0
- /package/dist/{chunk-SVSRPG6M.js.map → chunk-CPA5NBHN.js.map} +0 -0
- /package/dist/{chunk-7BEPVIH3.js.map → chunk-CRML27CO.js.map} +0 -0
- /package/dist/{chunk-IY7UXD3J.js.map → chunk-DA7ITC5Z.js.map} +0 -0
- /package/dist/{chunk-AFR6AIM4.js.map → chunk-DEACDKE3.js.map} +0 -0
- /package/dist/{chunk-NG3MBQV4.js.map → chunk-DPCXDG7G.js.map} +0 -0
- /package/dist/{chunk-HZNYJN77.js.map → chunk-F3NVYTTA.js.map} +0 -0
- /package/dist/{chunk-PDDSFELN.js.map → chunk-F7XUD3PL.js.map} +0 -0
- /package/dist/{chunk-YWSQD2IB.js.map → chunk-GTO56JY5.js.map} +0 -0
- /package/dist/{chunk-RAIUTAZZ.js.map → chunk-H2YSH3DG.js.map} +0 -0
- /package/dist/{chunk-F6QHHRWP.js.map → chunk-HMZKGHMD.js.map} +0 -0
- /package/dist/{chunk-ZIJDI4CP.js.map → chunk-HRHO3ZNG.js.map} +0 -0
- /package/dist/{chunk-SDEPLF7V.js.map → chunk-IBJ6U753.js.map} +0 -0
- /package/dist/{chunk-T3JQTCCO.js.map → chunk-JI7U6AS3.js.map} +0 -0
- /package/dist/{chunk-TR7DGXGI.js.map → chunk-JOZUBF4A.js.map} +0 -0
- /package/dist/{chunk-I7EX6KSH.js.map → chunk-JYSN42VN.js.map} +0 -0
- /package/dist/{chunk-FMQ4MOQO.js.map → chunk-KZIF6XHX.js.map} +0 -0
- /package/dist/{chunk-RIAM7DND.js.map → chunk-LDKPDODJ.js.map} +0 -0
- /package/dist/{chunk-227UFSEQ.js.map → chunk-LEPOP46W.js.map} +0 -0
- /package/dist/{chunk-LLQCM2U2.js.map → chunk-LKYIOCWL.js.map} +0 -0
- /package/dist/{chunk-5S4LQOPE.js.map → chunk-LOXHYCVS.js.map} +0 -0
- /package/dist/{chunk-ANJXPFRS.js.map → chunk-LPNCR4QK.js.map} +0 -0
- /package/dist/{chunk-GEPACVWN.js.map → chunk-MDD2RINF.js.map} +0 -0
- /package/dist/{chunk-6CPUQ5D6.js.map → chunk-MY2BC6UE.js.map} +0 -0
- /package/dist/{chunk-CFGU52XJ.js.map → chunk-NPFUNWNX.js.map} +0 -0
- /package/dist/{chunk-MFOSZUIT.js.map → chunk-NPIBN2VL.js.map} +0 -0
- /package/dist/{chunk-5DH6PG4B.js.map → chunk-OA2O2GJ4.js.map} +0 -0
- /package/dist/{chunk-JAQXUGLN.js.map → chunk-ODU2CNNX.js.map} +0 -0
- /package/dist/{chunk-RQE4TITU.js.map → chunk-OXRRJXPR.js.map} +0 -0
- /package/dist/{chunk-SEA6M7SS.js.map → chunk-P36Z4JRA.js.map} +0 -0
- /package/dist/{chunk-Z4U3UN56.js.map → chunk-PU56CXZA.js.map} +0 -0
- /package/dist/{chunk-5VPQSRQO.js.map → chunk-S5XOSTYM.js.map} +0 -0
- /package/dist/{chunk-SVVIASVX.js.map → chunk-SEEJOGQX.js.map} +0 -0
- /package/dist/{chunk-7TCGNUVP.js.map → chunk-SNOIKAHM.js.map} +0 -0
- /package/dist/{chunk-7F27PCSN.js.map → chunk-T6ILXUAH.js.map} +0 -0
- /package/dist/{chunk-EOHKUWXW.js.map → chunk-T7XP6IZE.js.map} +0 -0
- /package/dist/{chunk-7WR462EM.js.map → chunk-TFR3HG4K.js.map} +0 -0
- /package/dist/{chunk-YRVAKONL.js.map → chunk-TUHBYJXL.js.map} +0 -0
- /package/dist/{chunk-F635GAL7.js.map → chunk-U7EW2W4W.js.map} +0 -0
- /package/dist/{chunk-VFYRYFLL.js.map → chunk-UEBDCMOO.js.map} +0 -0
- /package/dist/{chunk-WTOZBZNN.js.map → chunk-UENKPWCS.js.map} +0 -0
- /package/dist/{chunk-AAXJNINV.js.map → chunk-UL4MKZHI.js.map} +0 -0
- /package/dist/{chunk-R2MZCYA6.js.map → chunk-UNUMFURP.js.map} +0 -0
- /package/dist/{chunk-ACOC27BB.js.map → chunk-UPFNQJC7.js.map} +0 -0
- /package/dist/{chunk-W4BMEGQA.js.map → chunk-UTQUEHC7.js.map} +0 -0
- /package/dist/{chunk-I32NKXE2.js.map → chunk-V4IDF3EZ.js.map} +0 -0
- /package/dist/{chunk-ZAOHJDKH.js.map → chunk-WNXYT4MK.js.map} +0 -0
- /package/dist/{chunk-T42L3S6A.js.map → chunk-XBGHAAKR.js.map} +0 -0
- /package/dist/{chunk-I4343FIA.js.map → chunk-XNWXSGHS.js.map} +0 -0
- /package/dist/{chunk-THG4GYIE.js.map → chunk-YEUXERJ6.js.map} +0 -0
- /package/dist/{chunk-EZ25VE3G.js.map → chunk-YNDLCWXS.js.map} +0 -0
- /package/dist/{chunk-5HERQ5FX.js.map → chunk-Z3YEGSR4.js.map} +0 -0
- /package/dist/{forget-SZ2BXDGF.js.map → forget-2AE4MDK3.js.map} +0 -0
|
@@ -0,0 +1,981 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-agnostic active-context SUMMARY/FILTER plans (issue #2347).
|
|
3
|
+
*
|
|
4
|
+
* Core receives a short message list, checks the trusted scope first,
|
|
5
|
+
* then IDs and limits, and returns a content-addressed plan. Core never
|
|
6
|
+
* mutates host state or saved memory: the host adapter owns save, apply,
|
|
7
|
+
* and undo; it reports back through {@link ActiveContextApplyReceipt}.
|
|
8
|
+
* Plans and telemetry carry hashes and counts only — never raw message
|
|
9
|
+
* text, keep rules, or summary output.
|
|
10
|
+
*
|
|
11
|
+
* Paper basis: AgeMem (arXiv:2601.01885v3) §3.1/A.1 eq. (14) Summary and
|
|
12
|
+
* eq. (15) Filter. Selection is host-bounded (explicit IDs or one closed
|
|
13
|
+
* span); `all` / last-N spans are never inferred. Filter keeps messages
|
|
14
|
+
* with `score >= threshold` using a caller-supplied fixed score rule — an
|
|
15
|
+
* LLM never picks drop IDs. Event counts back the design; no ship claim.
|
|
16
|
+
*/
|
|
17
|
+
import { createHash } from "node:crypto";
|
|
18
|
+
import { DEFAULT_ACTIVE_CONTEXT_CAPS, type ActiveContextCapabilitySet } from "./active-context-config.js";
|
|
19
|
+
import {
|
|
20
|
+
ContextSummaryUnavailableError,
|
|
21
|
+
summarizeContextPure,
|
|
22
|
+
type SummarizeFn,
|
|
23
|
+
} from "./context-summary.js";
|
|
24
|
+
import { evaluateActiveContextTransformPolicy } from "./memory-action-policy.js";
|
|
25
|
+
|
|
26
|
+
export const ACTIVE_CONTEXT_ALGORITHM_VERSION = "active-context-transform/1";
|
|
27
|
+
export const ACTIVE_CONTEXT_SNAPSHOT_SCHEMA_VERSION = 1;
|
|
28
|
+
export const ACTIVE_CONTEXT_PLAN_SCHEMA_VERSION = 1;
|
|
29
|
+
export const ACTIVE_CONTEXT_RECEIPT_SCHEMA_VERSION = 1;
|
|
30
|
+
export const ACTIVE_CONTEXT_RECORD_SCHEMA_VERSION = 1;
|
|
31
|
+
|
|
32
|
+
export type ActiveContextOperation = "SUMMARY" | "FILTER";
|
|
33
|
+
export type ActiveContextPhase = "plan" | "prepare";
|
|
34
|
+
export type ActiveContextMessageRole = "system" | "developer" | "user" | "assistant" | "tool";
|
|
35
|
+
|
|
36
|
+
export type ActiveContextErrorCode =
|
|
37
|
+
| "feature_disabled"
|
|
38
|
+
| "scope_mismatch"
|
|
39
|
+
| "invalid_request"
|
|
40
|
+
| "stale_context"
|
|
41
|
+
| "plan_conflict"
|
|
42
|
+
| "preserve_conflict"
|
|
43
|
+
| "filter_unavailable"
|
|
44
|
+
| "summary_unavailable"
|
|
45
|
+
| "unsupported"
|
|
46
|
+
| "retention_unavailable"
|
|
47
|
+
| "retention_expired"
|
|
48
|
+
| "invalid_receipt"
|
|
49
|
+
| "host_error";
|
|
50
|
+
|
|
51
|
+
/** Roles that can never be removed by any operation or selector. */
|
|
52
|
+
const PROTECTED_ROLES: Record<string, true> = { system: true, developer: true };
|
|
53
|
+
|
|
54
|
+
export interface ActiveContextMessage {
|
|
55
|
+
id: string;
|
|
56
|
+
/** Snapshot order; plans sort by it and never reorder sources. */
|
|
57
|
+
ordinal: number;
|
|
58
|
+
role: ActiveContextMessageRole;
|
|
59
|
+
content: string;
|
|
60
|
+
/** Caller-marked protection; equivalent to a preserve-listed ID. */
|
|
61
|
+
protected?: boolean;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface ActiveContextSnapshot {
|
|
65
|
+
schemaVersion: 1;
|
|
66
|
+
sessionKey: string;
|
|
67
|
+
/** Data routing only — never authorization. */
|
|
68
|
+
namespace: string;
|
|
69
|
+
/** Host revision/turn identifier the plan binds as a precondition. */
|
|
70
|
+
revision: string | number;
|
|
71
|
+
messages: ActiveContextMessage[];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Trusted scope resolved by the access layer BEFORE any plan work
|
|
76
|
+
* (mirrors `ResolvedIdentity` from adapters/types.ts). Core never treats
|
|
77
|
+
* `snapshot.namespace` as auth.
|
|
78
|
+
*/
|
|
79
|
+
export interface ActiveContextResolvedScope {
|
|
80
|
+
sessionKey: string;
|
|
81
|
+
namespace: string;
|
|
82
|
+
principal: string;
|
|
83
|
+
adapterId: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Fixed, caller-supplied score rule. Must return a finite score in [0,1]. */
|
|
87
|
+
export type ActiveContextScoreMessageFn = (message: ActiveContextMessage) => number | undefined;
|
|
88
|
+
|
|
89
|
+
export interface ActiveContextTransformDeps {
|
|
90
|
+
resolvedScope: ActiveContextResolvedScope;
|
|
91
|
+
/** Filter score rule — required for FILTER plans. */
|
|
92
|
+
scoreMessage?: ActiveContextScoreMessageFn;
|
|
93
|
+
/** Model seam for SUMMARY; the same pure seam LCM uses. */
|
|
94
|
+
summarize?: SummarizeFn;
|
|
95
|
+
/** Config-projected caps; defaults are conservative (see capabilities.ts). */
|
|
96
|
+
caps?: ActiveContextCapabilitySet;
|
|
97
|
+
/** Gate override; defaults to `caps.activeContextTransforms`. */
|
|
98
|
+
actionsEnabled?: boolean;
|
|
99
|
+
/** Clock seam for deterministic expiry tests. */
|
|
100
|
+
now?: () => Date;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface ActiveContextSpanSelector {
|
|
104
|
+
/** Closed span: inclusive start (by snapshot order). */
|
|
105
|
+
startMessageId: string;
|
|
106
|
+
/** Closed span: inclusive end (by snapshot order). */
|
|
107
|
+
endMessageId: string;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface ActiveContextTransformRequest {
|
|
111
|
+
schemaVersion: 1;
|
|
112
|
+
operation: ActiveContextOperation;
|
|
113
|
+
phase: ActiveContextPhase;
|
|
114
|
+
snapshot: ActiveContextSnapshot;
|
|
115
|
+
/** Exactly one of `messageIds` or `span`. */
|
|
116
|
+
selector: { messageIds?: string[]; span?: ActiveContextSpanSelector };
|
|
117
|
+
preserve?: {
|
|
118
|
+
messageIds?: string[];
|
|
119
|
+
roles?: ActiveContextMessageRole[];
|
|
120
|
+
minRetainedMessages?: number;
|
|
121
|
+
};
|
|
122
|
+
summary?: { method: "deterministic" | "llm" | "auto"; targetTokens?: number };
|
|
123
|
+
filter?: { keepCriterion: string; threshold: number };
|
|
124
|
+
expectedRevision?: string | number;
|
|
125
|
+
requestId?: string;
|
|
126
|
+
sourcePromptHash?: string;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export interface ActiveContextScoreRow {
|
|
130
|
+
messageId: string;
|
|
131
|
+
score: number;
|
|
132
|
+
decision: "keep" | "drop";
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export interface ActiveContextPlanReplacement {
|
|
136
|
+
messageId: string;
|
|
137
|
+
/** Filled by prepare — plans never carry raw text. */
|
|
138
|
+
contentHash?: string;
|
|
139
|
+
sourceMessageIds: string[];
|
|
140
|
+
method: "deterministic" | "llm";
|
|
141
|
+
/** Whether prepare may degrade to deterministic output (auto mode only). */
|
|
142
|
+
fallbackPolicy: "allowed" | "none";
|
|
143
|
+
targetTokens: number;
|
|
144
|
+
modelUsed?: string;
|
|
145
|
+
fallback?: boolean;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export interface ActiveContextTransformPlan {
|
|
149
|
+
schemaVersion: 1;
|
|
150
|
+
planId: string;
|
|
151
|
+
planHash: string;
|
|
152
|
+
operation: ActiveContextOperation;
|
|
153
|
+
status: "ready" | "rejected";
|
|
154
|
+
errorCode?: ActiveContextErrorCode;
|
|
155
|
+
precondition: {
|
|
156
|
+
principal: string;
|
|
157
|
+
sessionKey: string;
|
|
158
|
+
namespace: string;
|
|
159
|
+
adapterId: string;
|
|
160
|
+
snapshotRevision: string | number;
|
|
161
|
+
expiresAt: string;
|
|
162
|
+
};
|
|
163
|
+
/** Selected sources in snapshot order. */
|
|
164
|
+
selectedMessageIds: string[];
|
|
165
|
+
/** Messages that stay after the plan applies. */
|
|
166
|
+
retainedMessageIds: string[];
|
|
167
|
+
/** Removable IDs the plan proposes to drop or fold into a replacement. */
|
|
168
|
+
proposedRemovalIds: string[];
|
|
169
|
+
scoreRows?: ActiveContextScoreRow[];
|
|
170
|
+
replacement?: ActiveContextPlanReplacement;
|
|
171
|
+
preserve: { protectedMessageIds: string[]; minimumRetainedMessages: number };
|
|
172
|
+
inverse: {
|
|
173
|
+
kind: "restore-source-message-ids";
|
|
174
|
+
sourceMessageIds: string[];
|
|
175
|
+
removeReplacementMessageId?: string;
|
|
176
|
+
expectedAppliedPlanHash?: string;
|
|
177
|
+
};
|
|
178
|
+
retention: {
|
|
179
|
+
planId: string;
|
|
180
|
+
mode: "adapter-local";
|
|
181
|
+
expiresAt: string;
|
|
182
|
+
maxBytes: number;
|
|
183
|
+
snapshotContentHash: string;
|
|
184
|
+
};
|
|
185
|
+
provenance: {
|
|
186
|
+
algorithmVersion: string;
|
|
187
|
+
selectorHash: string;
|
|
188
|
+
snapshotContentHash: string;
|
|
189
|
+
criterionHash?: string;
|
|
190
|
+
sourcePromptHash?: string;
|
|
191
|
+
generatedAt: string;
|
|
192
|
+
};
|
|
193
|
+
policy: { decision: "allow" | "deny"; rationale: string };
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export interface ActiveContextHostCapability {
|
|
197
|
+
capabilityId: string;
|
|
198
|
+
trustedScope: ActiveContextResolvedScope;
|
|
199
|
+
hostRevision: string | number;
|
|
200
|
+
operations: ActiveContextOperation[];
|
|
201
|
+
expiresAt: string;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export interface ActiveContextApplyReceipt {
|
|
205
|
+
schemaVersion: 1;
|
|
206
|
+
planId: string;
|
|
207
|
+
planHash: string;
|
|
208
|
+
adapterId: string;
|
|
209
|
+
outcome: "applied" | "skipped" | "failed";
|
|
210
|
+
errorCode?: ActiveContextErrorCode;
|
|
211
|
+
hostRevisionBefore?: string | number;
|
|
212
|
+
hostRevisionAfter?: string | number;
|
|
213
|
+
appliedMessageIds?: string[];
|
|
214
|
+
removedMessageIds?: string[];
|
|
215
|
+
replacementMessageId?: string;
|
|
216
|
+
retentionExpiresAt?: string;
|
|
217
|
+
appliedAt: string;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** Discriminated ledger record appended to `state/memory-actions.jsonl`. */
|
|
221
|
+
export interface ContextTransformTelemetryRecord {
|
|
222
|
+
recordKind: "context_transform";
|
|
223
|
+
schemaVersion: 1;
|
|
224
|
+
timestamp: string;
|
|
225
|
+
/** Plan ID doubles as the record action ID. */
|
|
226
|
+
actionId: string;
|
|
227
|
+
action: "summarize_context" | "filter_context";
|
|
228
|
+
outcome: "applied" | "skipped" | "failed";
|
|
229
|
+
status: "validated" | "applied" | "rejected";
|
|
230
|
+
actor?: string;
|
|
231
|
+
subsystem: string;
|
|
232
|
+
namespace: string;
|
|
233
|
+
sourceSessionKey: string;
|
|
234
|
+
planHash: string;
|
|
235
|
+
snapshotRevision: string | number;
|
|
236
|
+
adapterId?: string;
|
|
237
|
+
algorithmVersion?: string;
|
|
238
|
+
selectedCount: number;
|
|
239
|
+
retainedCount: number;
|
|
240
|
+
proposedRemovalCount: number;
|
|
241
|
+
receiptOutcome?: "applied" | "skipped" | "failed";
|
|
242
|
+
selectorHash: string;
|
|
243
|
+
snapshotContentHash: string;
|
|
244
|
+
criterionHash?: string;
|
|
245
|
+
sourcePromptHash?: string;
|
|
246
|
+
replacementContentHash?: string;
|
|
247
|
+
policyDecision?: "allow" | "defer" | "deny";
|
|
248
|
+
policyRationale?: string;
|
|
249
|
+
telemetryRecorded?: boolean;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export interface ActiveContextPreparedReplacement {
|
|
253
|
+
messageId: string;
|
|
254
|
+
text: string;
|
|
255
|
+
contentHash: string;
|
|
256
|
+
method: "deterministic" | "llm";
|
|
257
|
+
modelUsed?: string;
|
|
258
|
+
fallback: boolean;
|
|
259
|
+
sourceMessageIds: string[];
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export interface ActiveContextPreparedTransform {
|
|
263
|
+
status: "ready" | "rejected" | "failed";
|
|
264
|
+
plan: ActiveContextTransformPlan;
|
|
265
|
+
replacement?: ActiveContextPreparedReplacement;
|
|
266
|
+
errorCode?: ActiveContextErrorCode;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ── hashing ────────────────────────────────────────────────────────────────
|
|
270
|
+
|
|
271
|
+
function sha256Hex(value: string): string {
|
|
272
|
+
return createHash("sha256").update(value, "utf8").digest("hex");
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/** Deterministic JSON: sorted keys, so field order never changes a hash. */
|
|
276
|
+
function canonicalJson(value: unknown): string {
|
|
277
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
278
|
+
if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
|
|
279
|
+
const entries = Object.entries(value as Record<string, unknown>)
|
|
280
|
+
.filter(([, v]) => v !== undefined)
|
|
281
|
+
.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
|
|
282
|
+
.map(([k, v]) => `${JSON.stringify(k)}:${canonicalJson(v)}`);
|
|
283
|
+
return `{${entries.join(",")}}`;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function hashSnapshot(snapshot: ActiveContextSnapshot): string {
|
|
287
|
+
return sha256Hex(
|
|
288
|
+
canonicalJson({
|
|
289
|
+
namespace: snapshot.namespace,
|
|
290
|
+
revision: snapshot.revision,
|
|
291
|
+
sessionKey: snapshot.sessionKey,
|
|
292
|
+
messages: snapshot.messages.map((m) => ({
|
|
293
|
+
contentHash: sha256Hex(m.content),
|
|
294
|
+
id: m.id,
|
|
295
|
+
ordinal: m.ordinal,
|
|
296
|
+
role: m.role,
|
|
297
|
+
})),
|
|
298
|
+
}),
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// ── shared validation ──────────────────────────────────────────────────────
|
|
303
|
+
|
|
304
|
+
interface PlanContext {
|
|
305
|
+
caps: ActiveContextCapabilitySet;
|
|
306
|
+
scope: ActiveContextResolvedScope;
|
|
307
|
+
snapshotRevision: string | number;
|
|
308
|
+
byId: Map<string, ActiveContextMessage>;
|
|
309
|
+
ordered: ActiveContextMessage[];
|
|
310
|
+
snapshotContentHash: string;
|
|
311
|
+
generatedAt: string;
|
|
312
|
+
expiresAt: string;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const VALID_PHASES: Record<string, true> = { plan: true, prepare: true };
|
|
316
|
+
const VALID_ROLES: Record<string, true> = {
|
|
317
|
+
system: true,
|
|
318
|
+
developer: true,
|
|
319
|
+
user: true,
|
|
320
|
+
assistant: true,
|
|
321
|
+
tool: true,
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
function rejectedPlan(
|
|
325
|
+
operation: ActiveContextOperation,
|
|
326
|
+
errorCode: ActiveContextErrorCode,
|
|
327
|
+
context: PlanContext | null,
|
|
328
|
+
policy: { decision: "allow" | "deny"; rationale: string },
|
|
329
|
+
): ActiveContextTransformPlan {
|
|
330
|
+
const planId = `actx-rejected-${sha256Hex(`${operation}:${errorCode}:${policy.rationale}`).slice(0, 12)}`;
|
|
331
|
+
return {
|
|
332
|
+
schemaVersion: ACTIVE_CONTEXT_PLAN_SCHEMA_VERSION,
|
|
333
|
+
planId,
|
|
334
|
+
planHash: sha256Hex(canonicalJson({ planId, errorCode, operation })),
|
|
335
|
+
operation,
|
|
336
|
+
status: "rejected",
|
|
337
|
+
errorCode,
|
|
338
|
+
precondition: context
|
|
339
|
+
? {
|
|
340
|
+
principal: context.scope.principal,
|
|
341
|
+
sessionKey: context.scope.sessionKey,
|
|
342
|
+
namespace: context.scope.namespace,
|
|
343
|
+
adapterId: context.scope.adapterId,
|
|
344
|
+
snapshotRevision: context.snapshotRevision,
|
|
345
|
+
expiresAt: context.expiresAt,
|
|
346
|
+
}
|
|
347
|
+
: {
|
|
348
|
+
principal: "",
|
|
349
|
+
sessionKey: "",
|
|
350
|
+
namespace: "",
|
|
351
|
+
adapterId: "",
|
|
352
|
+
snapshotRevision: "",
|
|
353
|
+
expiresAt: "",
|
|
354
|
+
},
|
|
355
|
+
selectedMessageIds: [],
|
|
356
|
+
retainedMessageIds: [],
|
|
357
|
+
proposedRemovalIds: [],
|
|
358
|
+
preserve: { protectedMessageIds: [], minimumRetainedMessages: 0 },
|
|
359
|
+
inverse: { kind: "restore-source-message-ids", sourceMessageIds: [] },
|
|
360
|
+
retention: {
|
|
361
|
+
planId,
|
|
362
|
+
mode: "adapter-local",
|
|
363
|
+
expiresAt: "",
|
|
364
|
+
maxBytes: 0,
|
|
365
|
+
snapshotContentHash: context?.snapshotContentHash ?? "",
|
|
366
|
+
},
|
|
367
|
+
provenance: {
|
|
368
|
+
algorithmVersion: ACTIVE_CONTEXT_ALGORITHM_VERSION,
|
|
369
|
+
selectorHash: "",
|
|
370
|
+
snapshotContentHash: context?.snapshotContentHash ?? "",
|
|
371
|
+
generatedAt: context?.generatedAt ?? new Date().toISOString(),
|
|
372
|
+
},
|
|
373
|
+
policy,
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/** Scope + snapshot validation shared by plan and prepare. Throws PlanReject. */
|
|
378
|
+
class PlanReject extends Error {
|
|
379
|
+
constructor(readonly code: ActiveContextErrorCode) {
|
|
380
|
+
super(code);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
function buildContext(
|
|
385
|
+
request: ActiveContextTransformRequest,
|
|
386
|
+
deps: ActiveContextTransformDeps,
|
|
387
|
+
): PlanContext {
|
|
388
|
+
const caps = deps.caps ?? {
|
|
389
|
+
...DEFAULT_ACTIVE_CONTEXT_CAPS,
|
|
390
|
+
activeContextTransforms: true,
|
|
391
|
+
activeContextLlm: false,
|
|
392
|
+
};
|
|
393
|
+
const scope = deps.resolvedScope;
|
|
394
|
+
if (!scope || !scope.sessionKey || !scope.namespace || !scope.principal || !scope.adapterId) {
|
|
395
|
+
throw new PlanReject("scope_mismatch");
|
|
396
|
+
}
|
|
397
|
+
// Trusted-scope checks run before any ID selection or model work.
|
|
398
|
+
if (request.snapshot.sessionKey !== scope.sessionKey) throw new PlanReject("scope_mismatch");
|
|
399
|
+
if (request.snapshot.namespace !== scope.namespace) throw new PlanReject("scope_mismatch");
|
|
400
|
+
|
|
401
|
+
const snapshot = request.snapshot;
|
|
402
|
+
if (snapshot.schemaVersion !== ACTIVE_CONTEXT_SNAPSHOT_SCHEMA_VERSION) {
|
|
403
|
+
throw new PlanReject("invalid_request");
|
|
404
|
+
}
|
|
405
|
+
if (!Array.isArray(snapshot.messages) || snapshot.messages.length === 0) {
|
|
406
|
+
throw new PlanReject("invalid_request");
|
|
407
|
+
}
|
|
408
|
+
const byId = new Map<string, ActiveContextMessage>();
|
|
409
|
+
let totalChars = 0;
|
|
410
|
+
for (const message of snapshot.messages) {
|
|
411
|
+
if (
|
|
412
|
+
typeof message?.id !== "string" ||
|
|
413
|
+
message.id.length === 0 ||
|
|
414
|
+
typeof message.content !== "string" ||
|
|
415
|
+
VALID_ROLES[message.role] !== true
|
|
416
|
+
) {
|
|
417
|
+
throw new PlanReject("invalid_request");
|
|
418
|
+
}
|
|
419
|
+
if (byId.has(message.id)) throw new PlanReject("invalid_request"); // duplicate IDs
|
|
420
|
+
byId.set(message.id, message);
|
|
421
|
+
totalChars += message.content.length;
|
|
422
|
+
}
|
|
423
|
+
if (snapshot.messages.length > caps.activeContextMaxMessages) throw new PlanReject("invalid_request");
|
|
424
|
+
if (totalChars > caps.activeContextMaxSnapshotChars) throw new PlanReject("invalid_request");
|
|
425
|
+
|
|
426
|
+
const now = (deps.now ?? (() => new Date()))();
|
|
427
|
+
const generatedAt = now.toISOString();
|
|
428
|
+
const expiresAt = new Date(now.getTime() + caps.activeContextPlanTtlMinutes * 60_000).toISOString();
|
|
429
|
+
return {
|
|
430
|
+
caps,
|
|
431
|
+
scope,
|
|
432
|
+
snapshotRevision: snapshot.revision,
|
|
433
|
+
byId,
|
|
434
|
+
ordered: [...snapshot.messages].sort((a, b) => a.ordinal - b.ordinal || a.id.localeCompare(b.id)),
|
|
435
|
+
snapshotContentHash: hashSnapshot(snapshot),
|
|
436
|
+
generatedAt,
|
|
437
|
+
expiresAt,
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/** Resolve the selector to ordered source messages. Exactly one form allowed. */
|
|
442
|
+
function resolveSelection(
|
|
443
|
+
request: ActiveContextTransformRequest,
|
|
444
|
+
context: PlanContext,
|
|
445
|
+
): ActiveContextMessage[] {
|
|
446
|
+
const messageIds = request.selector?.messageIds;
|
|
447
|
+
const span = request.selector?.span;
|
|
448
|
+
const hasIds = Array.isArray(messageIds) && messageIds.length > 0;
|
|
449
|
+
if (hasIds === (span !== undefined)) throw new PlanReject("invalid_request"); // both or neither
|
|
450
|
+
|
|
451
|
+
if (hasIds && messageIds) {
|
|
452
|
+
const seen = new Set<string>();
|
|
453
|
+
const picked: ActiveContextMessage[] = [];
|
|
454
|
+
for (const id of messageIds) {
|
|
455
|
+
if (seen.has(id)) throw new PlanReject("invalid_request"); // duplicate IDs
|
|
456
|
+
seen.add(id);
|
|
457
|
+
const message = context.byId.get(id);
|
|
458
|
+
if (!message) throw new PlanReject("invalid_request"); // unknown IDs
|
|
459
|
+
picked.push(message);
|
|
460
|
+
}
|
|
461
|
+
return picked.sort((a, b) => a.ordinal - b.ordinal || a.id.localeCompare(b.id)); // snapshot order
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (!span) throw new PlanReject("invalid_request");
|
|
465
|
+
const { startMessageId, endMessageId } = span;
|
|
466
|
+
const start = context.byId.get(startMessageId);
|
|
467
|
+
const end = context.byId.get(endMessageId);
|
|
468
|
+
if (!start || !end) throw new PlanReject("invalid_request");
|
|
469
|
+
if (start.ordinal > end.ordinal) throw new PlanReject("invalid_request"); // inverted span
|
|
470
|
+
const inSpan = context.ordered.filter(
|
|
471
|
+
(m) => m.ordinal >= start.ordinal && m.ordinal <= end.ordinal, // closed and full
|
|
472
|
+
);
|
|
473
|
+
if (inSpan.length === 0) throw new PlanReject("invalid_request"); // empty span
|
|
474
|
+
return inSpan;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function protectedIdSet(
|
|
478
|
+
request: ActiveContextTransformRequest,
|
|
479
|
+
context: PlanContext,
|
|
480
|
+
): Set<string> {
|
|
481
|
+
const protectedIds = new Set<string>();
|
|
482
|
+
for (const message of context.ordered) {
|
|
483
|
+
if (PROTECTED_ROLES[message.role] === true || message.protected === true) {
|
|
484
|
+
protectedIds.add(message.id);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
for (const role of request.preserve?.roles ?? []) {
|
|
488
|
+
if (PROTECTED_ROLES[role] === true) continue;
|
|
489
|
+
for (const message of context.ordered) {
|
|
490
|
+
if (message.role === role) protectedIds.add(message.id);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
for (const id of request.preserve?.messageIds ?? []) {
|
|
494
|
+
if (context.byId.has(id)) protectedIds.add(id);
|
|
495
|
+
}
|
|
496
|
+
return protectedIds;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// ── plan ───────────────────────────────────────────────────────────────────
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Build one bounded, content-addressed SUMMARY or FILTER plan. Returns a
|
|
503
|
+
* rejected plan (with a stable error code) instead of throwing on bad
|
|
504
|
+
* input — bad input is never hidden behind a no-op. `planHash` binds the
|
|
505
|
+
* scope, revision, and every selected/removal/replacement ID; replay
|
|
506
|
+
* across principal, session, namespace, adapter, or revision therefore
|
|
507
|
+
* fails the adapter's comparisons before retain, apply, or undo.
|
|
508
|
+
*/
|
|
509
|
+
export function planActiveContextTransform(
|
|
510
|
+
request: ActiveContextTransformRequest,
|
|
511
|
+
deps: ActiveContextTransformDeps,
|
|
512
|
+
): ActiveContextTransformPlan {
|
|
513
|
+
const caps =
|
|
514
|
+
deps.caps ?? { ...DEFAULT_ACTIVE_CONTEXT_CAPS, activeContextTransforms: true, activeContextLlm: false };
|
|
515
|
+
const policy = evaluateActiveContextTransformPolicy({
|
|
516
|
+
actionsEnabled: deps.actionsEnabled ?? caps.activeContextTransforms,
|
|
517
|
+
operation: request.operation,
|
|
518
|
+
});
|
|
519
|
+
if (policy.decision === "deny") {
|
|
520
|
+
// feature_disabled — evaluated before scope or selection work.
|
|
521
|
+
return rejectedPlan(request.operation, "feature_disabled", null, policy);
|
|
522
|
+
}
|
|
523
|
+
let context: PlanContext | null = null;
|
|
524
|
+
try {
|
|
525
|
+
if (request.schemaVersion !== ACTIVE_CONTEXT_SNAPSHOT_SCHEMA_VERSION) {
|
|
526
|
+
throw new PlanReject("invalid_request");
|
|
527
|
+
}
|
|
528
|
+
if (request.operation !== "SUMMARY" && request.operation !== "FILTER") {
|
|
529
|
+
throw new PlanReject("invalid_request");
|
|
530
|
+
}
|
|
531
|
+
if (VALID_PHASES[request.phase] !== true) throw new PlanReject("invalid_request");
|
|
532
|
+
context = buildContext(request, deps);
|
|
533
|
+
|
|
534
|
+
if (
|
|
535
|
+
request.expectedRevision !== undefined &&
|
|
536
|
+
request.expectedRevision !== request.snapshot.revision
|
|
537
|
+
) {
|
|
538
|
+
throw new PlanReject("stale_context");
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
const selected = resolveSelection(request, context);
|
|
542
|
+
const protectedIds = protectedIdSet(request, context);
|
|
543
|
+
const removable = selected.filter((m) => !protectedIds.has(m.id));
|
|
544
|
+
if (removable.length === 0) {
|
|
545
|
+
throw new PlanReject("preserve_conflict"); // nothing chosen is removable
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
const minimumRetained = Math.max(
|
|
549
|
+
1,
|
|
550
|
+
request.preserve?.minRetainedMessages ?? caps.activeContextMinRetainedMessages,
|
|
551
|
+
);
|
|
552
|
+
const idList = (messages: ActiveContextMessage[]) => messages.map((m) => m.id);
|
|
553
|
+
const allIds = idList(context.ordered);
|
|
554
|
+
const selectorHash = sha256Hex(canonicalJson(request.selector ?? {}));
|
|
555
|
+
|
|
556
|
+
if (request.operation === "FILTER") {
|
|
557
|
+
return buildFilterPlan(request, deps, context, {
|
|
558
|
+
selected,
|
|
559
|
+
removable,
|
|
560
|
+
protectedIds,
|
|
561
|
+
minimumRetained,
|
|
562
|
+
allIds,
|
|
563
|
+
selectorHash,
|
|
564
|
+
policy,
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
return buildSummaryPlan(request, deps, context, {
|
|
568
|
+
selected,
|
|
569
|
+
removable,
|
|
570
|
+
protectedIds,
|
|
571
|
+
minimumRetained,
|
|
572
|
+
allIds,
|
|
573
|
+
selectorHash,
|
|
574
|
+
policy,
|
|
575
|
+
});
|
|
576
|
+
} catch (err) {
|
|
577
|
+
if (err instanceof PlanReject) {
|
|
578
|
+
return rejectedPlan(request.operation, err.code, context, policy);
|
|
579
|
+
}
|
|
580
|
+
throw err;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
interface SelectionBundle {
|
|
585
|
+
selected: ActiveContextMessage[];
|
|
586
|
+
removable: ActiveContextMessage[];
|
|
587
|
+
protectedIds: Set<string>;
|
|
588
|
+
minimumRetained: number;
|
|
589
|
+
allIds: string[];
|
|
590
|
+
selectorHash: string;
|
|
591
|
+
policy: { decision: "allow" | "deny"; rationale: string };
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
function finalizePlan(
|
|
595
|
+
operation: ActiveContextOperation,
|
|
596
|
+
context: PlanContext,
|
|
597
|
+
bundle: SelectionBundle,
|
|
598
|
+
proposedRemovalIds: string[],
|
|
599
|
+
extras: {
|
|
600
|
+
scoreRows?: ActiveContextScoreRow[];
|
|
601
|
+
replacement?: ActiveContextPlanReplacement;
|
|
602
|
+
criterionHash?: string;
|
|
603
|
+
sourcePromptHash?: string;
|
|
604
|
+
},
|
|
605
|
+
): ActiveContextTransformPlan {
|
|
606
|
+
const retainedIds = bundle.allIds.filter((id) => !proposedRemovalIds.includes(id));
|
|
607
|
+
if (retainedIds.length < bundle.minimumRetained) {
|
|
608
|
+
throw new PlanReject("preserve_conflict"); // below keep floor / no safe message left
|
|
609
|
+
}
|
|
610
|
+
const sourceMessageIds = bundle.removable.map((m) => m.id);
|
|
611
|
+
const precondition = {
|
|
612
|
+
principal: context.scope.principal,
|
|
613
|
+
sessionKey: context.scope.sessionKey,
|
|
614
|
+
namespace: context.scope.namespace,
|
|
615
|
+
adapterId: context.scope.adapterId,
|
|
616
|
+
snapshotRevision: context.snapshotRevision,
|
|
617
|
+
expiresAt: context.expiresAt,
|
|
618
|
+
};
|
|
619
|
+
const provenance = {
|
|
620
|
+
algorithmVersion: ACTIVE_CONTEXT_ALGORITHM_VERSION,
|
|
621
|
+
selectorHash: bundle.selectorHash,
|
|
622
|
+
snapshotContentHash: context.snapshotContentHash,
|
|
623
|
+
...(extras.criterionHash ? { criterionHash: extras.criterionHash } : {}),
|
|
624
|
+
...(extras.sourcePromptHash ? { sourcePromptHash: extras.sourcePromptHash } : {}),
|
|
625
|
+
generatedAt: context.generatedAt,
|
|
626
|
+
};
|
|
627
|
+
const planId = `actx-${sha256Hex(
|
|
628
|
+
canonicalJson({
|
|
629
|
+
adapterId: precondition.adapterId,
|
|
630
|
+
criterionHash: extras.criterionHash,
|
|
631
|
+
namespace: precondition.namespace,
|
|
632
|
+
operation,
|
|
633
|
+
principal: precondition.principal,
|
|
634
|
+
selectorHash: bundle.selectorHash,
|
|
635
|
+
sessionKey: precondition.sessionKey,
|
|
636
|
+
snapshotContentHash: context.snapshotContentHash,
|
|
637
|
+
}),
|
|
638
|
+
).slice(0, 16)}`;
|
|
639
|
+
const planBody = {
|
|
640
|
+
operation,
|
|
641
|
+
planId,
|
|
642
|
+
precondition,
|
|
643
|
+
proposedRemovalIds,
|
|
644
|
+
replacementMessageId: extras.replacement?.messageId,
|
|
645
|
+
replacementSourceIds: extras.replacement?.sourceMessageIds,
|
|
646
|
+
retainedIds,
|
|
647
|
+
selectedIds: bundle.selected.map((m) => m.id),
|
|
648
|
+
};
|
|
649
|
+
const planHash = sha256Hex(canonicalJson(planBody));
|
|
650
|
+
return {
|
|
651
|
+
schemaVersion: ACTIVE_CONTEXT_PLAN_SCHEMA_VERSION,
|
|
652
|
+
planId,
|
|
653
|
+
planHash,
|
|
654
|
+
operation,
|
|
655
|
+
status: "ready",
|
|
656
|
+
precondition,
|
|
657
|
+
selectedMessageIds: planBody.selectedIds,
|
|
658
|
+
retainedMessageIds: retainedIds,
|
|
659
|
+
proposedRemovalIds,
|
|
660
|
+
...(extras.scoreRows ? { scoreRows: extras.scoreRows } : {}),
|
|
661
|
+
...(extras.replacement ? { replacement: extras.replacement } : {}),
|
|
662
|
+
preserve: {
|
|
663
|
+
protectedMessageIds: [...bundle.protectedIds],
|
|
664
|
+
minimumRetainedMessages: bundle.minimumRetained,
|
|
665
|
+
},
|
|
666
|
+
inverse: {
|
|
667
|
+
kind: "restore-source-message-ids",
|
|
668
|
+
sourceMessageIds,
|
|
669
|
+
...(extras.replacement ? { removeReplacementMessageId: extras.replacement.messageId } : {}),
|
|
670
|
+
expectedAppliedPlanHash: planHash,
|
|
671
|
+
},
|
|
672
|
+
retention: {
|
|
673
|
+
planId,
|
|
674
|
+
mode: "adapter-local",
|
|
675
|
+
expiresAt: context.expiresAt,
|
|
676
|
+
maxBytes: context.caps.activeContextRetentionMaxBytes,
|
|
677
|
+
snapshotContentHash: context.snapshotContentHash,
|
|
678
|
+
},
|
|
679
|
+
provenance,
|
|
680
|
+
policy: bundle.policy,
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
function buildFilterPlan(
|
|
685
|
+
request: ActiveContextTransformRequest,
|
|
686
|
+
deps: ActiveContextTransformDeps,
|
|
687
|
+
context: PlanContext,
|
|
688
|
+
bundle: SelectionBundle,
|
|
689
|
+
): ActiveContextTransformPlan {
|
|
690
|
+
const filter = request.filter;
|
|
691
|
+
if (!filter || typeof filter.keepCriterion !== "string" || filter.keepCriterion.length === 0) {
|
|
692
|
+
throw new PlanReject("invalid_request"); // Filter needs keepCriterion
|
|
693
|
+
}
|
|
694
|
+
const threshold = filter.threshold;
|
|
695
|
+
if (typeof threshold !== "number" || !Number.isFinite(threshold) || threshold < 0 || threshold > 1) {
|
|
696
|
+
throw new PlanReject("invalid_request"); // fixed limit in [0,1], never defaulted
|
|
697
|
+
}
|
|
698
|
+
if (!deps.scoreMessage) {
|
|
699
|
+
throw new PlanReject("filter_unavailable"); // Filter needs a score function
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
const scoreRows: ActiveContextScoreRow[] = [];
|
|
703
|
+
const removalIds: string[] = [];
|
|
704
|
+
for (const message of bundle.removable) {
|
|
705
|
+
const score = deps.scoreMessage(message);
|
|
706
|
+
if (typeof score !== "number" || !Number.isFinite(score) || score < 0 || score > 1) {
|
|
707
|
+
throw new PlanReject("filter_unavailable"); // missing / NaN / out of range
|
|
708
|
+
}
|
|
709
|
+
const decision = score >= threshold ? "keep" : "drop"; // fixed keep rule
|
|
710
|
+
scoreRows.push({ messageId: message.id, score, decision });
|
|
711
|
+
if (decision === "drop") removalIds.push(message.id);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
return finalizePlan("FILTER", context, bundle, removalIds, {
|
|
715
|
+
scoreRows,
|
|
716
|
+
criterionHash: sha256Hex(filter.keepCriterion), // hash, never the rule text
|
|
717
|
+
sourcePromptHash: request.sourcePromptHash,
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
function buildSummaryPlan(
|
|
722
|
+
request: ActiveContextTransformRequest,
|
|
723
|
+
deps: ActiveContextTransformDeps,
|
|
724
|
+
context: PlanContext,
|
|
725
|
+
bundle: SelectionBundle,
|
|
726
|
+
): ActiveContextTransformPlan {
|
|
727
|
+
const requested = request.summary?.method ?? "deterministic";
|
|
728
|
+
const llmEnabled = context.caps.activeContextLlm;
|
|
729
|
+
let method: "deterministic" | "llm";
|
|
730
|
+
let fallbackPolicy: "allowed" | "none";
|
|
731
|
+
if (requested === "deterministic") {
|
|
732
|
+
method = "deterministic";
|
|
733
|
+
fallbackPolicy = "none";
|
|
734
|
+
} else if (requested === "llm") {
|
|
735
|
+
if (!llmEnabled) throw new PlanReject("unsupported"); // explicit llm behind a closed gate
|
|
736
|
+
method = "llm";
|
|
737
|
+
fallbackPolicy = "none"; // fallback only in auto mode
|
|
738
|
+
} else {
|
|
739
|
+
// auto: prefer the LLM seam when allowed; deterministic otherwise.
|
|
740
|
+
method = llmEnabled && deps.summarize ? "llm" : "deterministic";
|
|
741
|
+
fallbackPolicy = method === "llm" ? "allowed" : "none";
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
const requestedTokens = request.summary?.targetTokens ?? context.caps.activeContextSummaryMaxTokens;
|
|
745
|
+
if (
|
|
746
|
+
typeof requestedTokens !== "number" ||
|
|
747
|
+
!Number.isFinite(requestedTokens) ||
|
|
748
|
+
requestedTokens <= 0 ||
|
|
749
|
+
requestedTokens > context.caps.activeContextSummaryMaxTokens
|
|
750
|
+
) {
|
|
751
|
+
throw new PlanReject("invalid_request");
|
|
752
|
+
}
|
|
753
|
+
const targetTokens = Math.floor(requestedTokens);
|
|
754
|
+
|
|
755
|
+
// planId is derived inside finalizePlan; the replacement ID must be stable
|
|
756
|
+
// relative to it, so derive from the same stable inputs.
|
|
757
|
+
const replacementSeed = sha256Hex(
|
|
758
|
+
canonicalJson({
|
|
759
|
+
operation: "SUMMARY",
|
|
760
|
+
selectorHash: bundle.selectorHash,
|
|
761
|
+
snapshotContentHash: context.snapshotContentHash,
|
|
762
|
+
sessionKey: context.scope.sessionKey,
|
|
763
|
+
namespace: context.scope.namespace,
|
|
764
|
+
principal: context.scope.principal,
|
|
765
|
+
adapterId: context.scope.adapterId,
|
|
766
|
+
}),
|
|
767
|
+
);
|
|
768
|
+
const replacement: ActiveContextPlanReplacement = {
|
|
769
|
+
messageId: `actxr-${replacementSeed.slice(0, 16)}`,
|
|
770
|
+
sourceMessageIds: bundle.removable.map((m) => m.id),
|
|
771
|
+
method,
|
|
772
|
+
fallbackPolicy,
|
|
773
|
+
targetTokens,
|
|
774
|
+
};
|
|
775
|
+
|
|
776
|
+
const plan = finalizePlan("SUMMARY", context, bundle, [...replacement.sourceMessageIds], {
|
|
777
|
+
replacement,
|
|
778
|
+
sourcePromptHash: request.sourcePromptHash,
|
|
779
|
+
});
|
|
780
|
+
return plan;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// ── prepare ────────────────────────────────────────────────────────────────
|
|
784
|
+
|
|
785
|
+
/**
|
|
786
|
+
* Produce the SUMMARY replacement text for a ready plan through the pure
|
|
787
|
+
* summary seam (context-summary.ts). Never calls `LcmSummarizer`. FILTER
|
|
788
|
+
* plans pass through unchanged after revalidation. The caller must supply
|
|
789
|
+
* the same snapshot the plan was built from; a changed transcript fence
|
|
790
|
+
* rejects with `plan_conflict`.
|
|
791
|
+
*/
|
|
792
|
+
export async function prepareActiveContextTransform(
|
|
793
|
+
plan: ActiveContextTransformPlan,
|
|
794
|
+
deps: ActiveContextTransformDeps & { snapshot: ActiveContextSnapshot },
|
|
795
|
+
): Promise<ActiveContextPreparedTransform> {
|
|
796
|
+
if (plan.status !== "ready") {
|
|
797
|
+
return { status: "rejected", plan, errorCode: plan.errorCode ?? "invalid_request" };
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
const scope = deps.resolvedScope;
|
|
801
|
+
const p = plan.precondition;
|
|
802
|
+
if (
|
|
803
|
+
!scope ||
|
|
804
|
+
scope.principal !== p.principal ||
|
|
805
|
+
scope.sessionKey !== p.sessionKey ||
|
|
806
|
+
scope.namespace !== p.namespace ||
|
|
807
|
+
scope.adapterId !== p.adapterId
|
|
808
|
+
) {
|
|
809
|
+
return { status: "rejected", plan, errorCode: "scope_mismatch" };
|
|
810
|
+
}
|
|
811
|
+
const now = deps.now?.() ?? new Date();
|
|
812
|
+
if (now.getTime() >= new Date(plan.retention.expiresAt).getTime()) {
|
|
813
|
+
return { status: "rejected", plan, errorCode: "stale_context" }; // expired plan
|
|
814
|
+
}
|
|
815
|
+
if (deps.snapshot.sessionKey !== p.sessionKey || deps.snapshot.namespace !== p.namespace) {
|
|
816
|
+
return { status: "rejected", plan, errorCode: "scope_mismatch" };
|
|
817
|
+
}
|
|
818
|
+
const fenceHash = hashSnapshot(deps.snapshot);
|
|
819
|
+
if (fenceHash !== plan.provenance.snapshotContentHash) {
|
|
820
|
+
return { status: "rejected", plan, errorCode: "plan_conflict" }; // changed fence
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
if (plan.operation === "FILTER") {
|
|
824
|
+
return { status: "ready", plan };
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
const replacement = plan.replacement;
|
|
828
|
+
if (!replacement) {
|
|
829
|
+
return { status: "failed", plan, errorCode: "invalid_request" };
|
|
830
|
+
}
|
|
831
|
+
const byId = new Map(deps.snapshot.messages.map((m) => [m.id, m] as const));
|
|
832
|
+
const sourceText = replacement.sourceMessageIds
|
|
833
|
+
.map((id) => byId.get(id))
|
|
834
|
+
.filter((m): m is ActiveContextMessage => m !== undefined)
|
|
835
|
+
.sort((a, b) => a.ordinal - b.ordinal || a.id.localeCompare(b.id))
|
|
836
|
+
.map((m) => m.content)
|
|
837
|
+
.join("\n\n"); // exact order, exact text
|
|
838
|
+
|
|
839
|
+
const method =
|
|
840
|
+
replacement.method === "deterministic"
|
|
841
|
+
? "deterministic"
|
|
842
|
+
: replacement.fallbackPolicy === "allowed"
|
|
843
|
+
? "auto"
|
|
844
|
+
: "llm";
|
|
845
|
+
try {
|
|
846
|
+
const result = await summarizeContextPure(sourceText, replacement.targetTokens, method, {
|
|
847
|
+
llm: deps.summarize,
|
|
848
|
+
deterministicMaxTokens: deps.caps?.activeContextSummaryMaxTokens ?? replacement.targetTokens,
|
|
849
|
+
});
|
|
850
|
+
if (result.text.trim().length === 0) {
|
|
851
|
+
return { status: "failed", plan, errorCode: "summary_unavailable" }; // bad model text
|
|
852
|
+
}
|
|
853
|
+
return {
|
|
854
|
+
status: "ready",
|
|
855
|
+
plan,
|
|
856
|
+
replacement: {
|
|
857
|
+
messageId: replacement.messageId,
|
|
858
|
+
text: result.text,
|
|
859
|
+
contentHash: sha256Hex(result.text),
|
|
860
|
+
method: result.method,
|
|
861
|
+
...(result.modelUsed ? { modelUsed: result.modelUsed } : {}),
|
|
862
|
+
fallback: result.fallback,
|
|
863
|
+
sourceMessageIds: replacement.sourceMessageIds,
|
|
864
|
+
},
|
|
865
|
+
};
|
|
866
|
+
} catch (err) {
|
|
867
|
+
if (err instanceof ContextSummaryUnavailableError) {
|
|
868
|
+
return { status: "failed", plan, errorCode: "summary_unavailable" };
|
|
869
|
+
}
|
|
870
|
+
throw err;
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
// ── receipts and telemetry ─────────────────────────────────────────────────
|
|
875
|
+
|
|
876
|
+
/**
|
|
877
|
+
* Validate a host receipt against the plan's bindings and append one
|
|
878
|
+
* context record to the ledger. Order of checks: scope → hash → revision →
|
|
879
|
+
* shape. One-time use is enforced by the adapter's persisted apply/undo
|
|
880
|
+
* markers (retention store); this recorder appends only. A ledger write
|
|
881
|
+
* failure returns `recorded: false` and never fabricates an apply.
|
|
882
|
+
*/
|
|
883
|
+
export async function recordActiveContextApplyReceipt(
|
|
884
|
+
plan: ActiveContextTransformPlan,
|
|
885
|
+
receipt: ActiveContextApplyReceipt,
|
|
886
|
+
trustedScope: ActiveContextResolvedScope,
|
|
887
|
+
recorder: {
|
|
888
|
+
append(record: ContextTransformTelemetryRecord): Promise<boolean>;
|
|
889
|
+
},
|
|
890
|
+
): Promise<{ recorded: boolean; event: ContextTransformTelemetryRecord }> {
|
|
891
|
+
const p = plan.precondition;
|
|
892
|
+
const scopeMatch =
|
|
893
|
+
trustedScope.principal === p.principal &&
|
|
894
|
+
trustedScope.sessionKey === p.sessionKey &&
|
|
895
|
+
trustedScope.namespace === p.namespace &&
|
|
896
|
+
trustedScope.adapterId === p.adapterId &&
|
|
897
|
+
receipt.adapterId === trustedScope.adapterId;
|
|
898
|
+
if (!scopeMatch) throw new PlanReject("scope_mismatch");
|
|
899
|
+
if (receipt.planHash !== plan.planHash) throw new PlanReject("plan_conflict"); // bad hash
|
|
900
|
+
if (receipt.hostRevisionBefore === undefined || receipt.hostRevisionBefore !== p.snapshotRevision) {
|
|
901
|
+
throw new PlanReject("stale_context"); // old plan / bad revision
|
|
902
|
+
}
|
|
903
|
+
const shapeOk =
|
|
904
|
+
receipt.schemaVersion === ACTIVE_CONTEXT_RECEIPT_SCHEMA_VERSION &&
|
|
905
|
+
receipt.planId === plan.planId &&
|
|
906
|
+
(receipt.outcome === "applied" || receipt.outcome === "skipped" || receipt.outcome === "failed") &&
|
|
907
|
+
typeof receipt.appliedAt === "string" &&
|
|
908
|
+
!Number.isNaN(Date.parse(receipt.appliedAt));
|
|
909
|
+
if (!shapeOk) throw new PlanReject("invalid_receipt");
|
|
910
|
+
|
|
911
|
+
const event: ContextTransformTelemetryRecord = {
|
|
912
|
+
recordKind: "context_transform",
|
|
913
|
+
schemaVersion: ACTIVE_CONTEXT_RECORD_SCHEMA_VERSION,
|
|
914
|
+
timestamp: receipt.appliedAt,
|
|
915
|
+
actionId: plan.planId,
|
|
916
|
+
action: plan.operation === "SUMMARY" ? "summarize_context" : "filter_context",
|
|
917
|
+
outcome: receipt.outcome,
|
|
918
|
+
status: receipt.outcome === "applied" ? "applied" : receipt.outcome === "failed" ? "rejected" : "validated",
|
|
919
|
+
subsystem: "active-context",
|
|
920
|
+
namespace: p.namespace,
|
|
921
|
+
sourceSessionKey: p.sessionKey,
|
|
922
|
+
planHash: plan.planHash,
|
|
923
|
+
snapshotRevision: p.snapshotRevision,
|
|
924
|
+
adapterId: receipt.adapterId,
|
|
925
|
+
algorithmVersion: plan.provenance.algorithmVersion,
|
|
926
|
+
selectedCount: plan.selectedMessageIds.length,
|
|
927
|
+
retainedCount: plan.retainedMessageIds.length,
|
|
928
|
+
proposedRemovalCount: plan.proposedRemovalIds.length,
|
|
929
|
+
receiptOutcome: receipt.outcome,
|
|
930
|
+
selectorHash: plan.provenance.selectorHash,
|
|
931
|
+
snapshotContentHash: plan.provenance.snapshotContentHash,
|
|
932
|
+
...(plan.provenance.criterionHash ? { criterionHash: plan.provenance.criterionHash } : {}),
|
|
933
|
+
...(plan.provenance.sourcePromptHash ? { sourcePromptHash: plan.provenance.sourcePromptHash } : {}),
|
|
934
|
+
policyDecision: plan.policy.decision,
|
|
935
|
+
policyRationale: plan.policy.rationale,
|
|
936
|
+
};
|
|
937
|
+
|
|
938
|
+
let recorded = false;
|
|
939
|
+
try {
|
|
940
|
+
recorded = await recorder.append(event);
|
|
941
|
+
} catch {
|
|
942
|
+
recorded = false; // ledger errors surface in the result, never as an apply
|
|
943
|
+
}
|
|
944
|
+
return { recorded, event: { ...event, telemetryRecorded: recorded } };
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
/**
|
|
948
|
+
* Build a plan-stage ledger record (plan produced, rejected, skipped, or
|
|
949
|
+
* failed before host apply). Receipt-backed applies use
|
|
950
|
+
* {@link recordActiveContextApplyReceipt} instead.
|
|
951
|
+
*/
|
|
952
|
+
export function buildContextTransformPlanEvent(
|
|
953
|
+
plan: ActiveContextTransformPlan,
|
|
954
|
+
outcome: "skipped" | "failed",
|
|
955
|
+
): ContextTransformTelemetryRecord {
|
|
956
|
+
return {
|
|
957
|
+
recordKind: "context_transform",
|
|
958
|
+
schemaVersion: ACTIVE_CONTEXT_RECORD_SCHEMA_VERSION,
|
|
959
|
+
timestamp: plan.provenance.generatedAt,
|
|
960
|
+
actionId: plan.planId,
|
|
961
|
+
action: plan.operation === "SUMMARY" ? "summarize_context" : "filter_context",
|
|
962
|
+
outcome,
|
|
963
|
+
status: plan.status === "ready" ? "validated" : "rejected",
|
|
964
|
+
subsystem: "active-context",
|
|
965
|
+
namespace: plan.precondition.namespace,
|
|
966
|
+
sourceSessionKey: plan.precondition.sessionKey,
|
|
967
|
+
planHash: plan.planHash,
|
|
968
|
+
snapshotRevision: plan.precondition.snapshotRevision,
|
|
969
|
+
algorithmVersion: plan.provenance.algorithmVersion,
|
|
970
|
+
selectedCount: plan.selectedMessageIds.length,
|
|
971
|
+
retainedCount: plan.retainedMessageIds.length,
|
|
972
|
+
proposedRemovalCount: plan.proposedRemovalIds.length,
|
|
973
|
+
selectorHash: plan.provenance.selectorHash,
|
|
974
|
+
snapshotContentHash: plan.provenance.snapshotContentHash,
|
|
975
|
+
...(plan.provenance.criterionHash ? { criterionHash: plan.provenance.criterionHash } : {}),
|
|
976
|
+
...(plan.provenance.sourcePromptHash ? { sourcePromptHash: plan.provenance.sourcePromptHash } : {}),
|
|
977
|
+
policyDecision: plan.policy.decision,
|
|
978
|
+
policyRationale: plan.policy.rationale,
|
|
979
|
+
telemetryRecorded: true,
|
|
980
|
+
};
|
|
981
|
+
}
|