@remnic/core 9.6.1 → 9.6.2
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 +7 -8
- package/dist/access-admin-ops-surface.js +8 -8
- package/dist/access-boundary.d.ts +9 -8
- package/dist/access-boundary.js +9 -9
- package/dist/access-cli.js +40 -40
- package/dist/access-http.d.ts +47 -16
- package/dist/access-http.js +13 -13
- package/dist/access-identity-continuity-surface.d.ts +6 -7
- package/dist/access-identity-continuity-surface.js +8 -8
- package/dist/access-lcm-surface.d.ts +7 -8
- package/dist/access-lcm-surface.js +8 -8
- package/dist/access-mcp.d.ts +13 -8
- package/dist/access-mcp.js +12 -12
- package/dist/access-observe-write-surface.d.ts +7 -8
- package/dist/access-observe-write-surface.js +8 -8
- package/dist/access-operations-batch.js +10 -10
- package/dist/access-operations.d.ts +8 -9
- package/dist/access-operations.js +11 -11
- package/dist/access-recall-surface.d.ts +7 -8
- package/dist/access-recall-surface.js +8 -8
- package/dist/access-schema.d.ts +6 -6
- package/dist/{access-service-CXJaql3A.d.ts → access-service-B_sc1w_k.d.ts} +9 -9
- package/dist/access-service.d.ts +7 -8
- package/dist/access-service.js +8 -8
- package/dist/access-surface-catalog.d.ts +7 -8
- package/dist/action-confidence.d.ts +1 -2
- package/dist/active-memory-bridge.d.ts +1 -2
- package/dist/active-recall.d.ts +1 -2
- package/dist/behavior-learner.d.ts +1 -2
- package/dist/behavior-signals.d.ts +1 -2
- package/dist/bootstrap.d.ts +6 -7
- package/dist/briefing.d.ts +2 -3
- package/dist/briefing.js +3 -3
- package/dist/buffer-surprise-report.d.ts +1 -2
- package/dist/buffer.d.ts +2 -3
- package/dist/buffer.js +1 -1
- package/dist/bulk-import/index.d.ts +3 -3
- package/dist/bulk-import/index.js +2 -2
- package/dist/calibration.d.ts +1 -2
- package/dist/capabilities.d.ts +1 -2
- package/dist/{catalog-C9cu67Ig.d.ts → catalog-9WanSGtt.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -2
- package/dist/causal-consolidation.d.ts +1 -2
- package/dist/causal-consolidation.js +4 -4
- package/dist/causal-trajectory-graph.d.ts +1 -2
- package/dist/{chunk-PNLFN2PZ.js → chunk-23G3T2Q5.js} +2 -2
- package/dist/{chunk-SIRPLF54.js → chunk-2K3OSLHE.js} +2 -2
- package/dist/{chunk-JS2HKKOK.js → chunk-3AC5UYKI.js} +1 -1
- package/dist/{chunk-JS2HKKOK.js.map → chunk-3AC5UYKI.js.map} +1 -1
- package/dist/{chunk-FKCRGLRD.js → chunk-4WRKKRTD.js} +266 -160
- package/dist/chunk-4WRKKRTD.js.map +1 -0
- package/dist/{chunk-LQHDIS7L.js → chunk-54BGIBCR.js} +2 -2
- package/dist/{chunk-PVUJ6WVV.js → chunk-5MH5NF3U.js} +5 -5
- package/dist/{chunk-PCLIWBGD.js → chunk-7ARV32PI.js} +8 -6
- package/dist/chunk-7ARV32PI.js.map +1 -0
- package/dist/{chunk-Y7UNNAZD.js → chunk-7ZYBDQ7V.js} +2 -2
- package/dist/{chunk-2PRQG7PV.js → chunk-AJVLDJU6.js} +1 -1
- package/dist/chunk-AJVLDJU6.js.map +1 -0
- package/dist/{chunk-LR5DZ56F.js → chunk-AXALUFAH.js} +2 -2
- package/dist/{chunk-AYZJID4S.js → chunk-B5GBWBCZ.js} +2 -2
- package/dist/{chunk-TLUDFPZL.js → chunk-CAZ3Z5M6.js} +2 -2
- package/dist/{chunk-RGK27ELN.js → chunk-DEKIXXIG.js} +2 -2
- package/dist/{chunk-2KK5WNQB.js → chunk-DQ42IQSK.js} +2 -2
- package/dist/{chunk-UFUKHGZD.js → chunk-F4I5NYBI.js} +89 -33
- package/dist/chunk-F4I5NYBI.js.map +1 -0
- package/dist/{chunk-HOJZMQ4J.js → chunk-FGDKJJZS.js} +2 -2
- package/dist/{chunk-ABP6QMVM.js → chunk-FQ7HAWWC.js} +2 -2
- package/dist/{chunk-CYWA2CXR.js → chunk-FVTLSFWU.js} +2 -2
- package/dist/{chunk-JJEJJ7RK.js → chunk-FXZTL7F7.js} +2 -2
- package/dist/{chunk-LADFWYHY.js → chunk-GOEV7CYF.js} +6 -6
- package/dist/chunk-GOEV7CYF.js.map +1 -0
- package/dist/{chunk-DANV2HTH.js → chunk-GQGDRLDM.js} +3 -3
- package/dist/{chunk-7F7Z6MOS.js → chunk-H4CKS5B2.js} +2 -2
- package/dist/{chunk-SVOHGUMI.js → chunk-H4FHR4UM.js} +174 -197
- package/dist/chunk-H4FHR4UM.js.map +1 -0
- package/dist/{chunk-CKITWVWJ.js → chunk-HSSERO3E.js} +2 -2
- package/dist/{chunk-23JFRB73.js → chunk-JODHPNLN.js} +2 -2
- package/dist/{chunk-DS7MM2ES.js → chunk-JZKR6ZAV.js} +2 -2
- package/dist/{chunk-BEM4D2QG.js → chunk-KJIJNLXT.js} +3 -3
- package/dist/{chunk-JSNVWNGX.js → chunk-KVSVVKHA.js} +2 -2
- package/dist/{chunk-4GNEDXDI.js → chunk-M67TLMP6.js} +2 -2
- package/dist/chunk-M67TLMP6.js.map +1 -0
- package/dist/{chunk-MC4FJXPA.js → chunk-MMACM5G2.js} +2 -2
- package/dist/{chunk-OUELRE5E.js → chunk-NOUJNHWG.js} +1 -1
- package/dist/chunk-NOUJNHWG.js.map +1 -0
- package/dist/{chunk-3XIY7MDQ.js → chunk-O6YI4CVI.js} +2 -2
- package/dist/{chunk-F53UF7CI.js → chunk-QLVLW7UD.js} +6 -2
- package/dist/{chunk-F53UF7CI.js.map → chunk-QLVLW7UD.js.map} +1 -1
- package/dist/{chunk-XCL57M6Q.js → chunk-RRKPLLCC.js} +21 -20
- package/dist/chunk-RRKPLLCC.js.map +1 -0
- package/dist/{chunk-72WG5QKN.js → chunk-SDAXPXER.js} +2 -2
- package/dist/{chunk-4LV23CHK.js → chunk-VHJARF5R.js} +2 -2
- package/dist/{chunk-H2DXDQCQ.js → chunk-VRJG3HIZ.js} +46 -42
- package/dist/chunk-VRJG3HIZ.js.map +1 -0
- package/dist/{chunk-6MMONPHM.js → chunk-W2AHSCKY.js} +2 -2
- package/dist/{chunk-P454KXD6.js → chunk-YAWJMR3Y.js} +21 -21
- package/dist/{chunk-K5LLP4CY.js → chunk-ZGPDSEKG.js} +20 -9
- package/dist/chunk-ZGPDSEKG.js.map +1 -0
- package/dist/{cli-CqdPA6z9.d.ts → cli-CnRsWREp.d.ts} +4 -5
- package/dist/cli.d.ts +9 -10
- package/dist/cli.js +32 -32
- package/dist/compounding/engine.d.ts +2 -3
- package/dist/compounding/engine.js +3 -3
- package/dist/compounding/preference-consolidator.d.ts +1 -2
- package/dist/compression-optimizer.d.ts +1 -2
- package/dist/config.d.ts +1 -2
- package/dist/connectors/codex-materialize-runner.d.ts +1 -2
- package/dist/connectors/codex-materialize-runner.js +3 -3
- package/dist/connectors/codex-materialize.d.ts +1 -2
- package/dist/connectors/index.d.ts +1 -2
- package/dist/connectors/index.js +3 -3
- package/dist/consolidation-provenance-check.d.ts +2 -3
- package/dist/consolidation-undo.d.ts +2 -3
- package/dist/contradiction/index.d.ts +3 -4
- package/dist/conversation-index/backend.d.ts +1 -2
- package/dist/conversation-index/chunker.d.ts +1 -2
- package/dist/conversation-index/faiss-adapter.d.ts +1 -2
- package/dist/conversation-index/indexer.d.ts +1 -2
- package/dist/conversation-index/search.d.ts +1 -2
- package/dist/day-summary.d.ts +1 -2
- package/dist/delinearize.d.ts +1 -2
- package/dist/direct-answer-wiring.d.ts +1 -2
- package/dist/direct-answer.d.ts +1 -2
- package/dist/embedding-fallback.d.ts +1 -2
- package/dist/enrichment/index.d.ts +1 -2
- package/dist/entity-retrieval.d.ts +2 -3
- package/dist/entity-retrieval.js +3 -3
- package/dist/entity-schema.d.ts +1 -2
- package/dist/explicit-capture.d.ts +8 -7
- package/dist/explicit-capture.js +1 -1
- package/dist/extraction-faithfulness.d.ts +1 -2
- package/dist/extraction-judge-telemetry.d.ts +1 -2
- package/dist/extraction-judge-training.d.ts +1 -2
- package/dist/extraction-judge.d.ts +1 -2
- package/dist/extraction.d.ts +1 -2
- package/dist/fallback-llm.d.ts +1 -2
- package/dist/graph-dashboard-diff.d.ts +1 -2
- package/dist/graph-dashboard-key.d.ts +1 -2
- package/dist/graph-dashboard-parser.d.ts +1 -2
- package/dist/graph-edge-reinforcement.d.ts +1 -2
- package/dist/graph-snapshot.d.ts +1 -2
- package/dist/graph.d.ts +1 -2
- package/dist/identity-continuity.d.ts +1 -2
- package/dist/importance.d.ts +1 -2
- package/dist/importers/index.d.ts +1 -1
- package/dist/importers/index.js +2 -2
- package/dist/index.d.ts +14 -15
- package/dist/index.js +40 -40
- package/dist/intent.d.ts +1 -2
- package/dist/lcm/engine.d.ts +1 -2
- package/dist/lcm/index.d.ts +1 -2
- package/dist/lcm/tools.d.ts +1 -2
- package/dist/lifecycle.d.ts +1 -2
- package/dist/live-connectors-runner.d.ts +1 -2
- package/dist/local-llm.d.ts +1 -2
- package/dist/local-model-endpoint.d.ts +1 -2
- package/dist/maintenance/memory-governance.d.ts +1 -2
- package/dist/maintenance/memory-governance.js +3 -3
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
- package/dist/maintenance/rebuild-memory-projection.js +4 -4
- package/dist/mcp-memory-inspector-app.d.ts +7 -8
- package/dist/memory-action-policy.d.ts +1 -2
- package/dist/memory-cache.d.ts +1 -2
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -2
- package/dist/memory-projection-store.d.ts +1 -2
- package/dist/memory-provenance.d.ts +1 -2
- package/dist/memory-worth-outcomes.d.ts +2 -3
- package/dist/models-json.d.ts +1 -2
- package/dist/namespaces/migrate.d.ts +3 -4
- package/dist/namespaces/migrate.js +4 -4
- package/dist/namespaces/principal.d.ts +1 -2
- package/dist/namespaces/search.d.ts +1 -2
- package/dist/namespaces/storage.d.ts +3 -4
- package/dist/namespaces/storage.js +3 -3
- package/dist/native-knowledge.d.ts +1 -2
- package/dist/operator-toolkit.d.ts +2 -3
- package/dist/operator-toolkit.js +7 -7
- package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -3
- package/dist/orchestration/maintenance.d.ts +2 -3
- package/dist/orchestration/maintenance.js +5 -5
- package/dist/{orchestrator-CWFrT8AF.d.ts → orchestrator-NRLVXPpH.d.ts} +40 -15
- package/dist/orchestrator.d.ts +6 -7
- package/dist/orchestrator.js +40 -40
- package/dist/patterns-cli.d.ts +1 -2
- package/dist/{pipeline-DmqtvION.d.ts → pipeline-CiD86zIk.d.ts} +1 -1
- package/dist/policy-runtime.d.ts +1 -2
- package/dist/provenance.d.ts +1 -2
- package/dist/{qmd--fnPMK60.d.ts → qmd-Bef7DDuQ.d.ts} +1 -1
- package/dist/qmd-preflight.d.ts +2 -3
- package/dist/qmd-recall-cache.d.ts +1 -2
- package/dist/qmd.d.ts +2 -3
- package/dist/recall-disclosure-escalation.d.ts +1 -2
- package/dist/recall-explain-renderer.d.ts +1 -2
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-planner-llm.d.ts +1 -2
- package/dist/recall-state.d.ts +1 -2
- package/dist/recall-tag-filter.d.ts +1 -2
- package/dist/recall-timings.d.ts +1 -2
- package/dist/recall-xray-cli.d.ts +1 -2
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +1 -2
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +1 -2
- package/dist/recall-xray.js +2 -2
- package/dist/replay/normalizers/chatgpt.d.ts +1 -0
- package/dist/replay/normalizers/chatgpt.js +3 -3
- package/dist/replay/normalizers/claude.d.ts +1 -0
- package/dist/replay/normalizers/claude.js +3 -3
- package/dist/replay/normalizers/openclaw.d.ts +1 -0
- package/dist/replay/normalizers/openclaw.js +3 -3
- package/dist/replay/normalizers/shared.d.ts +1 -0
- package/dist/replay/normalizers/shared.js +2 -2
- package/dist/replay/runner.d.ts +1 -0
- package/dist/replay/runner.js +2 -2
- package/dist/replay/types.d.ts +2 -1
- package/dist/replay/types.js +1 -1
- package/dist/resolve-auth-token.d.ts +1 -2
- package/dist/retrieval-agents.d.ts +2 -3
- package/dist/retrieval-tiers.d.ts +1 -2
- package/dist/routing/engine.d.ts +1 -2
- package/dist/routing/store.d.ts +1 -2
- package/dist/schemas.d.ts +22 -22
- package/dist/search/embed-helper.d.ts +1 -2
- package/dist/search/factory.d.ts +1 -2
- package/dist/search/index.d.ts +1 -2
- package/dist/search/lancedb-backend.d.ts +1 -2
- package/dist/search/meilisearch-backend.d.ts +1 -2
- package/dist/search/noop-backend.d.ts +1 -2
- package/dist/search/orama-backend.d.ts +1 -2
- package/dist/search/port.d.ts +1 -2
- package/dist/search/remote-backend.d.ts +1 -2
- package/dist/{semantic-DJR8_DMQ.d.ts → semantic-TddhF0y7.d.ts} +17 -1
- package/dist/{semantic-consolidation-O5lMZ4LG.d.ts → semantic-consolidation-BTShF2Fo.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -3
- package/dist/semantic-consolidation.js +4 -4
- package/dist/semantic-rule-promotion.js +3 -3
- package/dist/semantic-rule-verifier.d.ts +1 -2
- package/dist/semantic-rule-verifier.js +3 -3
- package/dist/session-observer-bands.d.ts +1 -2
- package/dist/session-observer-state.d.ts +1 -2
- package/dist/shared-context/manager.d.ts +3 -4
- package/dist/signal.d.ts +1 -2
- package/dist/{storage-C1maCNbc.d.ts → storage-DxPDAiU9.d.ts} +5 -1
- package/dist/storage.d.ts +2 -3
- package/dist/storage.js +2 -2
- package/dist/summarizer.d.ts +1 -2
- package/dist/summary-snapshot.d.ts +1 -2
- package/dist/temporal-supersession.d.ts +2 -3
- package/dist/temporal-validity.d.ts +1 -2
- package/dist/threading.d.ts +1 -2
- package/dist/tier-migration.d.ts +2 -3
- package/dist/tier-routing.d.ts +1 -2
- package/dist/topics.d.ts +1 -2
- package/dist/transcript.d.ts +1 -2
- package/dist/trust-score-stage.d.ts +1 -2
- package/dist/trust-score.d.ts +1 -2
- package/dist/{types-CGgcNWCG.d.ts → types-DDUDgd7T.d.ts} +93 -4
- package/dist/types.d.ts +1 -2
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +1 -2
- package/dist/verified-recall.js +3 -3
- package/package.json +2 -2
- package/src/access-admin-ops-surface.ts +1 -0
- package/src/access-boundary.ts +2 -0
- package/src/access-http.test.ts +129 -0
- package/src/access-http.ts +92 -23
- package/src/access-mcp.ts +11 -2
- package/src/access-observe-write-surface.ts +87 -113
- package/src/access-operations-batch.ts +2 -2
- package/src/access-operations.ts +17 -16
- package/src/access-service.ts +11 -3
- package/src/admin/admin-surfaces.ts +2 -0
- package/src/buffer.ts +6 -1
- package/src/bulk-import/types.ts +2 -1
- package/src/coding/architecture-surfaces.test.ts +79 -5
- package/src/coding/architecture-surfaces.ts +7 -1
- package/src/coding/decision-surfaces.test.ts +1 -0
- package/src/coding/decision-surfaces.ts +4 -0
- package/src/connector-provenance-lifecycle.test.ts +618 -0
- package/src/connector-provenance.test.ts +219 -0
- package/src/dedup/semantic.test.ts +105 -0
- package/src/dedup/semantic.ts +69 -1
- package/src/explicit-capture.ts +21 -4
- package/src/orchestration/extraction-persist.ts +154 -6
- package/src/orchestration/extraction-run.ts +138 -228
- package/src/orchestration/persistence-index.ts +40 -5
- package/src/orchestration/turn-ingestion.ts +16 -9
- package/src/orchestrator-connector-dedup.test.ts +1082 -0
- package/src/orchestrator.ts +7 -11
- package/src/replay/types.ts +2 -1
- package/src/storage.ts +426 -553
- package/src/types.ts +11 -2
- package/src/utils/yaml-scalar.ts +20 -0
- package/dist/chunk-2PRQG7PV.js.map +0 -1
- package/dist/chunk-4GNEDXDI.js.map +0 -1
- package/dist/chunk-FKCRGLRD.js.map +0 -1
- package/dist/chunk-H2DXDQCQ.js.map +0 -1
- package/dist/chunk-K5LLP4CY.js.map +0 -1
- package/dist/chunk-LADFWYHY.js.map +0 -1
- package/dist/chunk-OUELRE5E.js.map +0 -1
- package/dist/chunk-PCLIWBGD.js.map +0 -1
- package/dist/chunk-SVOHGUMI.js.map +0 -1
- package/dist/chunk-UFUKHGZD.js.map +0 -1
- package/dist/chunk-XCL57M6Q.js.map +0 -1
- package/dist/types-gb_SNtjR.d.ts +0 -85
- /package/dist/{chunk-PNLFN2PZ.js.map → chunk-23G3T2Q5.js.map} +0 -0
- /package/dist/{chunk-SIRPLF54.js.map → chunk-2K3OSLHE.js.map} +0 -0
- /package/dist/{chunk-LQHDIS7L.js.map → chunk-54BGIBCR.js.map} +0 -0
- /package/dist/{chunk-PVUJ6WVV.js.map → chunk-5MH5NF3U.js.map} +0 -0
- /package/dist/{chunk-Y7UNNAZD.js.map → chunk-7ZYBDQ7V.js.map} +0 -0
- /package/dist/{chunk-LR5DZ56F.js.map → chunk-AXALUFAH.js.map} +0 -0
- /package/dist/{chunk-AYZJID4S.js.map → chunk-B5GBWBCZ.js.map} +0 -0
- /package/dist/{chunk-TLUDFPZL.js.map → chunk-CAZ3Z5M6.js.map} +0 -0
- /package/dist/{chunk-RGK27ELN.js.map → chunk-DEKIXXIG.js.map} +0 -0
- /package/dist/{chunk-2KK5WNQB.js.map → chunk-DQ42IQSK.js.map} +0 -0
- /package/dist/{chunk-HOJZMQ4J.js.map → chunk-FGDKJJZS.js.map} +0 -0
- /package/dist/{chunk-ABP6QMVM.js.map → chunk-FQ7HAWWC.js.map} +0 -0
- /package/dist/{chunk-CYWA2CXR.js.map → chunk-FVTLSFWU.js.map} +0 -0
- /package/dist/{chunk-JJEJJ7RK.js.map → chunk-FXZTL7F7.js.map} +0 -0
- /package/dist/{chunk-DANV2HTH.js.map → chunk-GQGDRLDM.js.map} +0 -0
- /package/dist/{chunk-7F7Z6MOS.js.map → chunk-H4CKS5B2.js.map} +0 -0
- /package/dist/{chunk-CKITWVWJ.js.map → chunk-HSSERO3E.js.map} +0 -0
- /package/dist/{chunk-23JFRB73.js.map → chunk-JODHPNLN.js.map} +0 -0
- /package/dist/{chunk-DS7MM2ES.js.map → chunk-JZKR6ZAV.js.map} +0 -0
- /package/dist/{chunk-BEM4D2QG.js.map → chunk-KJIJNLXT.js.map} +0 -0
- /package/dist/{chunk-JSNVWNGX.js.map → chunk-KVSVVKHA.js.map} +0 -0
- /package/dist/{chunk-MC4FJXPA.js.map → chunk-MMACM5G2.js.map} +0 -0
- /package/dist/{chunk-3XIY7MDQ.js.map → chunk-O6YI4CVI.js.map} +0 -0
- /package/dist/{chunk-72WG5QKN.js.map → chunk-SDAXPXER.js.map} +0 -0
- /package/dist/{chunk-4LV23CHK.js.map → chunk-VHJARF5R.js.map} +0 -0
- /package/dist/{chunk-6MMONPHM.js.map → chunk-W2AHSCKY.js.map} +0 -0
- /package/dist/{chunk-P454KXD6.js.map → chunk-YAWJMR3Y.js.map} +0 -0
|
@@ -28,14 +28,8 @@ import type { ExtractionEngine } from "../extraction.js";
|
|
|
28
28
|
import type { SmartBuffer } from "../buffer.js";
|
|
29
29
|
import type { ThreadingManager } from "../threading.js";
|
|
30
30
|
import type { BoxBuilder } from "../boxes.js";
|
|
31
|
-
import {
|
|
32
|
-
|
|
33
|
-
defaultNamespaceForPrincipal,
|
|
34
|
-
} from "../namespaces/principal.js";
|
|
35
|
-
import {
|
|
36
|
-
resolveScopeProfilePlan,
|
|
37
|
-
type ResolvedScopeProfilePlan,
|
|
38
|
-
} from "../namespaces/scope-profiles.js";
|
|
31
|
+
import { resolvePrincipal, defaultNamespaceForPrincipal } from "../namespaces/principal.js";
|
|
32
|
+
import { resolveScopeProfilePlan, type ResolvedScopeProfilePlan } from "../namespaces/scope-profiles.js";
|
|
39
33
|
import { resolveCodingNamespaceOverlay } from "../coding/coding-namespace.js";
|
|
40
34
|
import type { CodingContext } from "../types.js";
|
|
41
35
|
import {
|
|
@@ -46,11 +40,7 @@ import {
|
|
|
46
40
|
} from "../capabilities.js";
|
|
47
41
|
import { parseFlexibleIsoTimestamp } from "../utils/iso-timestamp.js";
|
|
48
42
|
import { log } from "../logger.js";
|
|
49
|
-
import type {
|
|
50
|
-
PluginConfig,
|
|
51
|
-
BufferTurn,
|
|
52
|
-
ExtractionResult,
|
|
53
|
-
} from "../types.js";
|
|
43
|
+
import type { PluginConfig, BufferTurn, ExtractionResult } from "../types.js";
|
|
54
44
|
import type { TierMigrationCycleSummary } from "../recall-state.js";
|
|
55
45
|
|
|
56
46
|
export interface ExtractionRunResult {
|
|
@@ -67,20 +57,20 @@ export interface ExtractionRunResult {
|
|
|
67
57
|
export interface ExtractionRunCoordinatorDeps {
|
|
68
58
|
config: PluginConfig;
|
|
69
59
|
getBuffer: () => SmartBuffer;
|
|
70
|
-
getExtraction: () => ExtractionEngine
|
|
71
|
-
getStorageRouter: () => NamespaceStorageRouter
|
|
72
|
-
getThreading: () => ThreadingManager
|
|
60
|
+
getExtraction: () => Pick<ExtractionEngine, "extract">;
|
|
61
|
+
getStorageRouter: () => Pick<NamespaceStorageRouter, "storageFor">;
|
|
62
|
+
getThreading: () => Pick<ThreadingManager, "processTurn" | "updateThreadTitle">;
|
|
73
63
|
|
|
74
64
|
persistExtraction: (
|
|
75
65
|
result: ExtractionResult,
|
|
76
66
|
storage: StorageManager,
|
|
77
67
|
threadIdForExtraction?: string | null,
|
|
78
|
-
sourceContext?: { sessionKey?: string; principal?: string; validAt?: string },
|
|
68
|
+
sourceContext?: { sessionKey?: string; principal?: string; validAt?: string; sourceConnector?: string },
|
|
79
69
|
baseNamespace?: string,
|
|
80
70
|
scopeProfileWritePlan?: ResolvedScopeProfilePlan | null,
|
|
81
71
|
sourceText?: string,
|
|
82
72
|
graphCaps?: GraphConstructionCapabilitySet,
|
|
83
|
-
lifecycleCaps?: MemoryLifecycleCapabilitySet
|
|
73
|
+
lifecycleCaps?: MemoryLifecycleCapabilitySet
|
|
84
74
|
) => Promise<string[]>;
|
|
85
75
|
|
|
86
76
|
maybeCapturePassiveCorrections: (
|
|
@@ -91,17 +81,14 @@ export interface ExtractionRunCoordinatorDeps {
|
|
|
91
81
|
namespace: string;
|
|
92
82
|
bufferKey: string;
|
|
93
83
|
isLiveSession: boolean;
|
|
94
|
-
}
|
|
84
|
+
}
|
|
95
85
|
) => Promise<void>;
|
|
96
86
|
|
|
97
87
|
resolveSelfNamespace: (sessionKey?: string) => string;
|
|
98
88
|
getCodingContextForSession: (sessionKey: string) => CodingContext | null;
|
|
99
89
|
applyCodingNamespaceOverlay: (sessionKey: string, namespace: string) => string;
|
|
100
|
-
boxBuilderFor: (storage: StorageManager) => BoxBuilder
|
|
101
|
-
appendPersistedThreadEpisodes: (
|
|
102
|
-
threadId: string,
|
|
103
|
-
ids: string[],
|
|
104
|
-
) => Promise<void>;
|
|
90
|
+
boxBuilderFor: (storage: StorageManager) => Pick<BoxBuilder, "onExtraction">;
|
|
91
|
+
appendPersistedThreadEpisodes: (threadId: string, ids: string[]) => Promise<void>;
|
|
105
92
|
maybeScheduleConsolidation: (nonZero: boolean) => void;
|
|
106
93
|
requestQmdMaintenance: () => void;
|
|
107
94
|
runTierMigrationCycle: (
|
|
@@ -111,13 +98,13 @@ export interface ExtractionRunCoordinatorDeps {
|
|
|
111
98
|
dryRun?: boolean;
|
|
112
99
|
limitOverride?: number;
|
|
113
100
|
force?: boolean;
|
|
114
|
-
}
|
|
101
|
+
}
|
|
115
102
|
) => Promise<TierMigrationCycleSummary>;
|
|
116
103
|
getLastPersistExtractionDeferredCount: () => number;
|
|
117
104
|
recordProcessedExtractionFingerprint: (
|
|
118
105
|
storage: StorageManager,
|
|
119
106
|
fingerprint: string,
|
|
120
|
-
preloadedMeta?: Awaited<ReturnType<StorageManager["loadMeta"]
|
|
107
|
+
preloadedMeta?: Awaited<ReturnType<StorageManager["loadMeta"]>>
|
|
121
108
|
) => Promise<void>;
|
|
122
109
|
}
|
|
123
110
|
|
|
@@ -151,9 +138,7 @@ export function deriveTopicsFromExtraction(result: ExtractionResult): string[] {
|
|
|
151
138
|
export class ExtractionRunCoordinator {
|
|
152
139
|
private readonly recentExtractionFingerprints = new Map<string, number>();
|
|
153
140
|
|
|
154
|
-
constructor(
|
|
155
|
-
private readonly deps: ExtractionRunCoordinatorDeps,
|
|
156
|
-
) {}
|
|
141
|
+
constructor(private readonly deps: ExtractionRunCoordinatorDeps) {}
|
|
157
142
|
|
|
158
143
|
private get config(): PluginConfig {
|
|
159
144
|
return this.deps.config;
|
|
@@ -177,7 +162,6 @@ export class ExtractionRunCoordinator {
|
|
|
177
162
|
return latestMs === null ? undefined : new Date(latestMs).toISOString();
|
|
178
163
|
}
|
|
179
164
|
|
|
180
|
-
|
|
181
165
|
// -------------------------------------------------------------------------
|
|
182
166
|
// Extraction dedupe fingerprint helpers
|
|
183
167
|
// -------------------------------------------------------------------------
|
|
@@ -187,10 +171,7 @@ export class ExtractionRunCoordinator {
|
|
|
187
171
|
return turns
|
|
188
172
|
.filter((turn) => turn.role === "user" || turn.role === "assistant")
|
|
189
173
|
.map((turn) => {
|
|
190
|
-
if (
|
|
191
|
-
typeof turn.turnFingerprint === "string" &&
|
|
192
|
-
turn.turnFingerprint.length > 0
|
|
193
|
-
) {
|
|
174
|
+
if (typeof turn.turnFingerprint === "string" && turn.turnFingerprint.length > 0) {
|
|
194
175
|
return `fp:${turn.turnFingerprint}`;
|
|
195
176
|
}
|
|
196
177
|
return `${turn.role}:${(turn.content ?? "").replace(/\s+/g, " ").trim().slice(0, this.config.extractionMaxTurnChars)}`;
|
|
@@ -198,24 +179,13 @@ export class ExtractionRunCoordinator {
|
|
|
198
179
|
.filter((value) => value.length > 0);
|
|
199
180
|
}
|
|
200
181
|
|
|
201
|
-
|
|
202
|
-
buildExtractionFingerprint(
|
|
203
|
-
turns: BufferTurn[],
|
|
204
|
-
bufferKey: string,
|
|
205
|
-
): string | null {
|
|
182
|
+
buildExtractionFingerprint(turns: BufferTurn[], bufferKey: string): string | null {
|
|
206
183
|
const normalized = this.normalizeExtractionFingerprintTurns(turns).join("\n");
|
|
207
184
|
if (!normalized) return null;
|
|
208
|
-
return createHash("sha256")
|
|
209
|
-
.update(`${bufferKey}\n${normalized}`)
|
|
210
|
-
.digest("hex");
|
|
185
|
+
return createHash("sha256").update(`${bufferKey}\n${normalized}`).digest("hex");
|
|
211
186
|
}
|
|
212
187
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
shouldQueueExtraction(
|
|
216
|
-
turns: BufferTurn[],
|
|
217
|
-
options: { commit?: boolean; bufferKey?: string } = {},
|
|
218
|
-
): boolean {
|
|
188
|
+
shouldQueueExtraction(turns: BufferTurn[], options: { commit?: boolean; bufferKey?: string } = {}): boolean {
|
|
219
189
|
const lifecycleCaps = resolveMemoryLifecycleCapabilities(this.config);
|
|
220
190
|
if (!lifecycleCaps.extractionDedupe) return true;
|
|
221
191
|
if (!Array.isArray(turns) || turns.length === 0) return false;
|
|
@@ -234,13 +204,8 @@ export class ExtractionRunCoordinator {
|
|
|
234
204
|
this.recentExtractionFingerprints.set(fingerprint, now);
|
|
235
205
|
}
|
|
236
206
|
// Keep this cache bounded to avoid unbounded growth.
|
|
237
|
-
if (
|
|
238
|
-
|
|
239
|
-
this.recentExtractionFingerprints.size > 200
|
|
240
|
-
) {
|
|
241
|
-
const entries = Array.from(
|
|
242
|
-
this.recentExtractionFingerprints.entries(),
|
|
243
|
-
).sort((a, b) => a[1] - b[1]);
|
|
207
|
+
if (options.commit !== false && this.recentExtractionFingerprints.size > 200) {
|
|
208
|
+
const entries = Array.from(this.recentExtractionFingerprints.entries()).sort((a, b) => a[1] - b[1]);
|
|
244
209
|
for (const [key] of entries.slice(0, entries.length - 200)) {
|
|
245
210
|
this.recentExtractionFingerprints.delete(key);
|
|
246
211
|
}
|
|
@@ -249,7 +214,6 @@ export class ExtractionRunCoordinator {
|
|
|
249
214
|
return true;
|
|
250
215
|
}
|
|
251
216
|
|
|
252
|
-
|
|
253
217
|
// -------------------------------------------------------------------------
|
|
254
218
|
// Processed-fingerprint recording
|
|
255
219
|
// -------------------------------------------------------------------------
|
|
@@ -257,15 +221,12 @@ export class ExtractionRunCoordinator {
|
|
|
257
221
|
async recordProcessedExtractionFingerprint(
|
|
258
222
|
storage: StorageManager,
|
|
259
223
|
fingerprint: string,
|
|
260
|
-
preloadedMeta?: Awaited<ReturnType<StorageManager["loadMeta"]
|
|
224
|
+
preloadedMeta?: Awaited<ReturnType<StorageManager["loadMeta"]>>
|
|
261
225
|
): Promise<void> {
|
|
262
226
|
const meta = preloadedMeta ?? (await storage.loadMeta());
|
|
263
227
|
const observedAt = new Date().toISOString();
|
|
264
228
|
const seen = new Map(
|
|
265
|
-
(meta.processedExtractionFingerprints ?? []).map((entry) => [
|
|
266
|
-
entry.fingerprint,
|
|
267
|
-
entry.observedAt,
|
|
268
|
-
]),
|
|
229
|
+
(meta.processedExtractionFingerprints ?? []).map((entry) => [entry.fingerprint, entry.observedAt])
|
|
269
230
|
);
|
|
270
231
|
seen.set(fingerprint, observedAt);
|
|
271
232
|
meta.processedExtractionFingerprints = Array.from(seen.entries())
|
|
@@ -277,7 +238,6 @@ export class ExtractionRunCoordinator {
|
|
|
277
238
|
}
|
|
278
239
|
}
|
|
279
240
|
|
|
280
|
-
|
|
281
241
|
// -------------------------------------------------------------------------
|
|
282
242
|
// Main extraction pipeline
|
|
283
243
|
// -------------------------------------------------------------------------
|
|
@@ -308,18 +268,14 @@ export class ExtractionRunCoordinator {
|
|
|
308
268
|
* (un-prefixed) key and storage is pinned via `writeNamespaceOverride`.
|
|
309
269
|
*/
|
|
310
270
|
principalOverride?: string;
|
|
311
|
-
} = {}
|
|
271
|
+
} = {}
|
|
312
272
|
): Promise<ExtractionRunResult> {
|
|
313
273
|
log.debug(`running extraction on ${turns.length} turns`);
|
|
314
|
-
const clearBufferAfterExtraction =
|
|
315
|
-
options.clearBufferAfterExtraction ?? true;
|
|
274
|
+
const clearBufferAfterExtraction = options.clearBufferAfterExtraction ?? true;
|
|
316
275
|
const skipCharThreshold = options.skipCharThreshold ?? false;
|
|
317
276
|
const skipUserTurnThreshold = options.skipUserTurnThreshold ?? false;
|
|
318
277
|
const deadlineMs =
|
|
319
|
-
typeof options.deadlineMs === "number" &&
|
|
320
|
-
Number.isFinite(options.deadlineMs)
|
|
321
|
-
? options.deadlineMs
|
|
322
|
-
: undefined;
|
|
278
|
+
typeof options.deadlineMs === "number" && Number.isFinite(options.deadlineMs) ? options.deadlineMs : undefined;
|
|
323
279
|
const bufferKey = options.bufferKey ?? turns[0]?.sessionKey ?? "default";
|
|
324
280
|
const throwIfDeadlineExceeded = (stage: string): void => {
|
|
325
281
|
if (typeof deadlineMs === "number" && Date.now() > deadlineMs) {
|
|
@@ -352,25 +308,25 @@ export class ExtractionRunCoordinator {
|
|
|
352
308
|
}
|
|
353
309
|
|
|
354
310
|
const normalizedTurns = turns
|
|
355
|
-
.filter(
|
|
356
|
-
(t) =>
|
|
357
|
-
(t.role === "user" || t.role === "assistant") &&
|
|
358
|
-
typeof t.content === "string",
|
|
359
|
-
)
|
|
311
|
+
.filter((t) => (t.role === "user" || t.role === "assistant") && typeof t.content === "string")
|
|
360
312
|
.map((t) => ({
|
|
361
313
|
...t,
|
|
362
314
|
content: t.content.trim().slice(0, this.config.extractionMaxTurnChars),
|
|
363
315
|
}))
|
|
364
316
|
.filter((t) => t.content.length > 0);
|
|
365
|
-
const targetTurns = normalizedTurns.filter(
|
|
366
|
-
(turn) => turn.extractionContextOnly !== true,
|
|
367
|
-
);
|
|
317
|
+
const targetTurns = normalizedTurns.filter((turn) => turn.extractionContextOnly !== true);
|
|
368
318
|
if (targetTurns.length === 0) {
|
|
369
319
|
log.debug("skipping extraction: no non-context turns after normalization");
|
|
370
320
|
// Context-only turns may still contain corrections (review: "context-only
|
|
371
321
|
// turns skip capture"). Scan normalizedTurns before clearing the buffer.
|
|
372
322
|
if (normalizedTurns.length > 0) {
|
|
373
|
-
await this.deps.maybeCapturePassiveCorrections(normalizedTurns as BufferTurn[], {
|
|
323
|
+
await this.deps.maybeCapturePassiveCorrections(normalizedTurns as BufferTurn[], {
|
|
324
|
+
sessionKey,
|
|
325
|
+
principal: resolvePrincipal(sessionKey, this.config),
|
|
326
|
+
namespace: this.deps.resolveSelfNamespace(sessionKey),
|
|
327
|
+
bufferKey,
|
|
328
|
+
isLiveSession: clearBufferAfterExtraction,
|
|
329
|
+
});
|
|
374
330
|
}
|
|
375
331
|
await clearBuffer();
|
|
376
332
|
return { status: "skipped", reason: "empty_normalized_turns", persistedCount: 0, durableOutputCount: 0 };
|
|
@@ -380,18 +336,11 @@ export class ExtractionRunCoordinator {
|
|
|
380
336
|
throwIfAborted("before_extract");
|
|
381
337
|
|
|
382
338
|
const userTurns = targetTurns.filter((t) => t.role === "user");
|
|
383
|
-
const totalChars = targetTurns.reduce(
|
|
384
|
-
(sum, t) => sum + t.content.length,
|
|
385
|
-
0,
|
|
386
|
-
);
|
|
339
|
+
const totalChars = targetTurns.reduce((sum, t) => sum + t.content.length, 0);
|
|
387
340
|
const belowCharThreshold = totalChars < this.config.extractionMinChars;
|
|
388
|
-
const belowUserTurnThreshold =
|
|
389
|
-
!skipUserTurnThreshold &&
|
|
390
|
-
userTurns.length < this.config.extractionMinUserTurns;
|
|
341
|
+
const belowUserTurnThreshold = !skipUserTurnThreshold && userTurns.length < this.config.extractionMinUserTurns;
|
|
391
342
|
if ((!skipCharThreshold && belowCharThreshold) || belowUserTurnThreshold) {
|
|
392
|
-
log.debug(
|
|
393
|
-
`skipping extraction: below threshold (totalChars=${totalChars}, userTurns=${userTurns.length})`,
|
|
394
|
-
);
|
|
343
|
+
log.debug(`skipping extraction: below threshold (totalChars=${totalChars}, userTurns=${userTurns.length})`);
|
|
395
344
|
await clearBuffer();
|
|
396
345
|
// Passive correction capture runs even when extraction is skipped for
|
|
397
346
|
// being below the char/user-turn threshold (review: "skipped extraction
|
|
@@ -407,14 +356,30 @@ export class ExtractionRunCoordinator {
|
|
|
407
356
|
typeof options.principalOverride === "string" && options.principalOverride.length > 0
|
|
408
357
|
? options.principalOverride
|
|
409
358
|
: resolvePrincipal(sessionKey, this.config);
|
|
410
|
-
const captureWO =
|
|
411
|
-
|
|
359
|
+
const captureWO =
|
|
360
|
+
typeof options.writeNamespaceOverride === "string" && options.writeNamespaceOverride.length > 0
|
|
361
|
+
? options.writeNamespaceOverride
|
|
362
|
+
: undefined;
|
|
412
363
|
const captureCodingCtx = sessionKey ? this.deps.getCodingContextForSession(sessionKey) : null;
|
|
413
|
-
const captureCodingOv = resolveCodingNamespaceOverlay(
|
|
414
|
-
|
|
415
|
-
|
|
364
|
+
const captureCodingOv = resolveCodingNamespaceOverlay(
|
|
365
|
+
captureCodingCtx,
|
|
366
|
+
this.config.codingMode,
|
|
367
|
+
this.config.defaultNamespace
|
|
368
|
+
);
|
|
369
|
+
const captureScopePlan = resolveScopeProfilePlan({
|
|
370
|
+
config: this.config,
|
|
371
|
+
principal: capturePrincipal,
|
|
372
|
+
codingContext: captureCodingCtx,
|
|
373
|
+
codingOverlay: captureCodingOv,
|
|
374
|
+
});
|
|
375
|
+
const captureNamespace =
|
|
376
|
+
captureWO ?? captureScopePlan?.writeNamespace ?? this.deps.resolveSelfNamespace(sessionKey);
|
|
416
377
|
await this.deps.maybeCapturePassiveCorrections(normalizedTurns as BufferTurn[], {
|
|
417
|
-
sessionKey,
|
|
378
|
+
sessionKey,
|
|
379
|
+
principal: capturePrincipal,
|
|
380
|
+
namespace: captureNamespace,
|
|
381
|
+
bufferKey,
|
|
382
|
+
isLiveSession: clearBufferAfterExtraction,
|
|
418
383
|
});
|
|
419
384
|
}
|
|
420
385
|
return {
|
|
@@ -433,8 +398,7 @@ export class ExtractionRunCoordinator {
|
|
|
433
398
|
// namespace-prefixed key would collapse to `default`. The ORIGINAL,
|
|
434
399
|
// un-prefixed session key still drives threading.
|
|
435
400
|
const principal =
|
|
436
|
-
typeof options.principalOverride === "string" &&
|
|
437
|
-
options.principalOverride.length > 0
|
|
401
|
+
typeof options.principalOverride === "string" && options.principalOverride.length > 0
|
|
438
402
|
? options.principalOverride
|
|
439
403
|
: resolvePrincipal(sessionKey, this.config);
|
|
440
404
|
// Write path — explicit callers still win. Otherwise, an active hosted
|
|
@@ -442,17 +406,14 @@ export class ExtractionRunCoordinator {
|
|
|
442
406
|
// in the same layer that profile recall searches. Without a profile, preserve
|
|
443
407
|
// the existing coding-agent overlay behavior (issue #569).
|
|
444
408
|
const explicitWriteNamespace =
|
|
445
|
-
typeof options.writeNamespaceOverride === "string" &&
|
|
446
|
-
options.writeNamespaceOverride.length > 0
|
|
409
|
+
typeof options.writeNamespaceOverride === "string" && options.writeNamespaceOverride.length > 0
|
|
447
410
|
? options.writeNamespaceOverride
|
|
448
411
|
: undefined;
|
|
449
|
-
const codingContextForWrite = sessionKey
|
|
450
|
-
? this.deps.getCodingContextForSession(sessionKey)
|
|
451
|
-
: null;
|
|
412
|
+
const codingContextForWrite = sessionKey ? this.deps.getCodingContextForSession(sessionKey) : null;
|
|
452
413
|
const codingOverlayForWrite = resolveCodingNamespaceOverlay(
|
|
453
414
|
codingContextForWrite,
|
|
454
415
|
this.config.codingMode,
|
|
455
|
-
this.config.defaultNamespace
|
|
416
|
+
this.config.defaultNamespace
|
|
456
417
|
);
|
|
457
418
|
const scopeProfileGatePlan = resolveScopeProfilePlan({
|
|
458
419
|
config: this.config,
|
|
@@ -462,15 +423,13 @@ export class ExtractionRunCoordinator {
|
|
|
462
423
|
});
|
|
463
424
|
const scopeProfileWritePlan = explicitWriteNamespace ? null : scopeProfileGatePlan;
|
|
464
425
|
if (scopeProfileWritePlan) {
|
|
465
|
-
const selectedLayer = scopeProfileWritePlan.layers.find(
|
|
466
|
-
(layer) => layer.id === scopeProfileWritePlan.writeLayer,
|
|
467
|
-
);
|
|
426
|
+
const selectedLayer = scopeProfileWritePlan.layers.find((layer) => layer.id === scopeProfileWritePlan.writeLayer);
|
|
468
427
|
const writeNamespaceReadable = scopeProfileWritePlan.readNamespaces.includes(
|
|
469
|
-
scopeProfileWritePlan.writeNamespace
|
|
428
|
+
scopeProfileWritePlan.writeNamespace
|
|
470
429
|
);
|
|
471
430
|
if (!selectedLayer?.writable || !writeNamespaceReadable) {
|
|
472
431
|
log.warn(
|
|
473
|
-
`runExtraction: skipping scope profile ${scopeProfileWritePlan.profileId} because write layer ${scopeProfileWritePlan.writeLayer} is not writable inside the profile read stack
|
|
432
|
+
`runExtraction: skipping scope profile ${scopeProfileWritePlan.profileId} because write layer ${scopeProfileWritePlan.writeLayer} is not writable inside the profile read stack`
|
|
474
433
|
);
|
|
475
434
|
await clearBuffer();
|
|
476
435
|
return {
|
|
@@ -484,32 +443,17 @@ export class ExtractionRunCoordinator {
|
|
|
484
443
|
const selfNamespace =
|
|
485
444
|
explicitWriteNamespace ??
|
|
486
445
|
scopeProfileWritePlan?.writeNamespace ??
|
|
487
|
-
this.deps.applyCodingNamespaceOverlay(
|
|
488
|
-
sessionKey,
|
|
489
|
-
defaultNamespaceForPrincipal(principal, this.config),
|
|
490
|
-
);
|
|
446
|
+
this.deps.applyCodingNamespaceOverlay(sessionKey, defaultNamespaceForPrincipal(principal, this.config));
|
|
491
447
|
const storage = await this.deps.getStorageRouter().storageFor(selfNamespace);
|
|
492
|
-
const shouldPersistProcessedFingerprint = targetTurns.some(
|
|
493
|
-
|
|
494
|
-
);
|
|
495
|
-
const extractionFingerprint = this.buildExtractionFingerprint(
|
|
496
|
-
targetTurns,
|
|
497
|
-
bufferKey,
|
|
498
|
-
);
|
|
499
|
-
let meta =
|
|
500
|
-
extractionFingerprint && shouldPersistProcessedFingerprint
|
|
501
|
-
? await storage.loadMeta()
|
|
502
|
-
: null;
|
|
448
|
+
const shouldPersistProcessedFingerprint = targetTurns.some((turn) => turn.persistProcessedFingerprint === true);
|
|
449
|
+
const extractionFingerprint = this.buildExtractionFingerprint(targetTurns, bufferKey);
|
|
450
|
+
let meta = extractionFingerprint && shouldPersistProcessedFingerprint ? await storage.loadMeta() : null;
|
|
503
451
|
if (
|
|
504
452
|
extractionFingerprint &&
|
|
505
453
|
shouldPersistProcessedFingerprint &&
|
|
506
|
-
(meta?.processedExtractionFingerprints ?? []).some(
|
|
507
|
-
(entry) => entry.fingerprint === extractionFingerprint,
|
|
508
|
-
)
|
|
454
|
+
(meta?.processedExtractionFingerprints ?? []).some((entry) => entry.fingerprint === extractionFingerprint)
|
|
509
455
|
) {
|
|
510
|
-
log.debug(
|
|
511
|
-
`runExtraction: skipping already-processed extraction fingerprint for ${bufferKey}`,
|
|
512
|
-
);
|
|
456
|
+
log.debug(`runExtraction: skipping already-processed extraction fingerprint for ${bufferKey}`);
|
|
513
457
|
await clearBuffer();
|
|
514
458
|
return {
|
|
515
459
|
status: "skipped",
|
|
@@ -522,12 +466,9 @@ export class ExtractionRunCoordinator {
|
|
|
522
466
|
// Pass existing entity names so the LLM can reuse them instead of inventing variants
|
|
523
467
|
const existingEntities = await storage.listEntityNames();
|
|
524
468
|
const result = await raceRecallAbort(
|
|
525
|
-
this.deps.getExtraction().extract(
|
|
526
|
-
normalizedTurns,
|
|
527
|
-
existingEntities,
|
|
528
|
-
),
|
|
469
|
+
this.deps.getExtraction().extract(normalizedTurns, existingEntities),
|
|
529
470
|
options.abortSignal,
|
|
530
|
-
"extraction aborted (during_extract)"
|
|
471
|
+
"extraction aborted (during_extract)"
|
|
531
472
|
);
|
|
532
473
|
throwIfDeadlineExceeded("before_persist");
|
|
533
474
|
throwIfAborted("before_persist");
|
|
@@ -557,16 +498,10 @@ export class ExtractionRunCoordinator {
|
|
|
557
498
|
.filter(([, value]) => !Array.isArray(value))
|
|
558
499
|
.map(([field]) => field);
|
|
559
500
|
if (invalidExtractionResultFields.length > 0) {
|
|
560
|
-
log.warn(
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
resultKeys:
|
|
565
|
-
typeof result === "object" && result !== null
|
|
566
|
-
? Object.keys(result)
|
|
567
|
-
: [],
|
|
568
|
-
},
|
|
569
|
-
);
|
|
501
|
+
log.warn("runExtraction: extraction returned invalid collection fields", {
|
|
502
|
+
invalidFields: invalidExtractionResultFields,
|
|
503
|
+
resultKeys: typeof result === "object" && result !== null ? Object.keys(result) : [],
|
|
504
|
+
});
|
|
570
505
|
if (options.failOnExtractionFailure) {
|
|
571
506
|
throw new Error("extraction failed: invalid_extraction_result");
|
|
572
507
|
}
|
|
@@ -579,8 +514,7 @@ export class ExtractionRunCoordinator {
|
|
|
579
514
|
};
|
|
580
515
|
}
|
|
581
516
|
const extractionFailure =
|
|
582
|
-
typeof result.extractionFailure === "string" &&
|
|
583
|
-
result.extractionFailure.trim().length > 0
|
|
517
|
+
typeof result.extractionFailure === "string" && result.extractionFailure.trim().length > 0
|
|
584
518
|
? result.extractionFailure
|
|
585
519
|
: undefined;
|
|
586
520
|
if (options.failOnExtractionFailure && extractionFailure) {
|
|
@@ -592,26 +526,16 @@ export class ExtractionRunCoordinator {
|
|
|
592
526
|
result.questions.length === 0 &&
|
|
593
527
|
result.profileUpdates.length === 0
|
|
594
528
|
) {
|
|
595
|
-
log.debug(
|
|
596
|
-
"runExtraction: extraction produced no durable outputs; skipping persistence",
|
|
597
|
-
);
|
|
529
|
+
log.debug("runExtraction: extraction produced no durable outputs; skipping persistence");
|
|
598
530
|
if (extractionFailure) {
|
|
599
531
|
log.warn(
|
|
600
532
|
"runExtraction: extraction reported failure with no durable outputs; not marking fingerprint processed",
|
|
601
|
-
{ extractionFailure }
|
|
533
|
+
{ extractionFailure }
|
|
602
534
|
);
|
|
603
535
|
}
|
|
604
|
-
if (
|
|
605
|
-
extractionFingerprint &&
|
|
606
|
-
shouldPersistProcessedFingerprint &&
|
|
607
|
-
!extractionFailure
|
|
608
|
-
) {
|
|
536
|
+
if (extractionFingerprint && shouldPersistProcessedFingerprint && !extractionFailure) {
|
|
609
537
|
meta ??= await storage.loadMeta();
|
|
610
|
-
await this.deps.recordProcessedExtractionFingerprint(
|
|
611
|
-
storage,
|
|
612
|
-
extractionFingerprint,
|
|
613
|
-
meta,
|
|
614
|
-
);
|
|
538
|
+
await this.deps.recordProcessedExtractionFingerprint(storage, extractionFingerprint, meta);
|
|
615
539
|
meta.extractionCount += 1;
|
|
616
540
|
meta.lastExtractionAt = new Date().toISOString();
|
|
617
541
|
await storage.saveMeta(meta);
|
|
@@ -619,7 +543,13 @@ export class ExtractionRunCoordinator {
|
|
|
619
543
|
// Correction-only turns that meet char/user-turn thresholds but yield
|
|
620
544
|
// zero facts still need passive capture (review: "empty extraction skips
|
|
621
545
|
// capture"). selfNamespace/principal already resolved above.
|
|
622
|
-
await this.deps.maybeCapturePassiveCorrections(normalizedTurns as BufferTurn[], {
|
|
546
|
+
await this.deps.maybeCapturePassiveCorrections(normalizedTurns as BufferTurn[], {
|
|
547
|
+
sessionKey,
|
|
548
|
+
principal,
|
|
549
|
+
namespace: selfNamespace,
|
|
550
|
+
bufferKey,
|
|
551
|
+
isLiveSession: clearBufferAfterExtraction,
|
|
552
|
+
});
|
|
623
553
|
await clearBuffer();
|
|
624
554
|
return { status: "skipped", reason: "empty_extraction_result", persistedCount: 0, durableOutputCount: 0 };
|
|
625
555
|
}
|
|
@@ -631,10 +561,7 @@ export class ExtractionRunCoordinator {
|
|
|
631
561
|
threadIdForExtraction = await this.deps.getThreading().processTurn(lastTurn, []);
|
|
632
562
|
} catch (err) {
|
|
633
563
|
// Fail-open: threading errors must not block memory persistence.
|
|
634
|
-
log.warn(
|
|
635
|
-
"[threading] processTurn failed before persistence (non-fatal)",
|
|
636
|
-
err,
|
|
637
|
-
);
|
|
564
|
+
log.warn("[threading] processTurn failed before persistence (non-fatal)", err);
|
|
638
565
|
}
|
|
639
566
|
}
|
|
640
567
|
|
|
@@ -642,28 +569,26 @@ export class ExtractionRunCoordinator {
|
|
|
642
569
|
result,
|
|
643
570
|
storage,
|
|
644
571
|
threadIdForExtraction,
|
|
645
|
-
{ sessionKey, principal, validAt: sourceValidAt },
|
|
572
|
+
{ sessionKey, principal, validAt: sourceValidAt, sourceConnector: deriveSourceConnector(targetTurns as BufferTurn[]) },
|
|
646
573
|
// Pass the KNOWN base namespace (NHIdx) so the catalog write touch records the
|
|
647
574
|
// real namespace rather than a guess decoded from the storage dir.
|
|
648
575
|
selfNamespace,
|
|
649
576
|
scopeProfileGatePlan,
|
|
650
577
|
// Verbatim source turns for the faithfulness gate (#1576) so it can
|
|
651
578
|
// locate a quote per fact when #1575 spans are absent.
|
|
652
|
-
normalizedTurns
|
|
579
|
+
normalizedTurns
|
|
580
|
+
.map((t) => t.content)
|
|
581
|
+
.join("\n\n")
|
|
653
582
|
);
|
|
654
583
|
let postPersistMetadataFailed = false;
|
|
655
584
|
meta ??= await storage.loadMeta();
|
|
656
585
|
if (extractionFingerprint && shouldPersistProcessedFingerprint) {
|
|
657
586
|
try {
|
|
658
|
-
await this.deps.recordProcessedExtractionFingerprint(
|
|
659
|
-
storage,
|
|
660
|
-
extractionFingerprint,
|
|
661
|
-
meta,
|
|
662
|
-
);
|
|
587
|
+
await this.deps.recordProcessedExtractionFingerprint(storage, extractionFingerprint, meta);
|
|
663
588
|
} catch (error) {
|
|
664
589
|
log.warn(
|
|
665
590
|
"runExtraction: failed to persist processed extraction fingerprint; continuing with buffer clear",
|
|
666
|
-
error
|
|
591
|
+
error
|
|
667
592
|
);
|
|
668
593
|
postPersistMetadataFailed = true;
|
|
669
594
|
}
|
|
@@ -675,27 +600,20 @@ export class ExtractionRunCoordinator {
|
|
|
675
600
|
// would duplicate them.
|
|
676
601
|
meta.extractionCount += 1;
|
|
677
602
|
meta.lastExtractionAt = new Date().toISOString();
|
|
678
|
-
meta.totalMemories += Array.isArray(result?.facts)
|
|
679
|
-
|
|
680
|
-
: 0;
|
|
681
|
-
meta.totalEntities += Array.isArray(result?.entities)
|
|
682
|
-
? result.entities.length
|
|
683
|
-
: 0;
|
|
603
|
+
meta.totalMemories += Array.isArray(result?.facts) ? result.facts.length : 0;
|
|
604
|
+
meta.totalEntities += Array.isArray(result?.entities) ? result.entities.length : 0;
|
|
684
605
|
try {
|
|
685
606
|
await storage.saveMeta(meta);
|
|
686
607
|
} catch (error) {
|
|
687
608
|
log.warn(
|
|
688
609
|
"runExtraction: failed to save extraction metadata after durable persistence; continuing with buffer clear",
|
|
689
|
-
error
|
|
610
|
+
error
|
|
690
611
|
);
|
|
691
612
|
postPersistMetadataFailed = true;
|
|
692
613
|
}
|
|
693
614
|
|
|
694
615
|
const durableOutputCount =
|
|
695
|
-
result.facts.length +
|
|
696
|
-
result.entities.length +
|
|
697
|
-
result.questions.length +
|
|
698
|
-
result.profileUpdates.length;
|
|
616
|
+
result.facts.length + result.entities.length + result.questions.length + result.profileUpdates.length;
|
|
699
617
|
|
|
700
618
|
// Buffer retention for defer verdicts (issue #562, PR 2). When the judge
|
|
701
619
|
// deferred at least one candidate, retain the tail of the current turn
|
|
@@ -713,17 +631,10 @@ export class ExtractionRunCoordinator {
|
|
|
713
631
|
// waste buffer space and cause the same facts to re-enter the
|
|
714
632
|
// pipeline on the next pass.
|
|
715
633
|
try {
|
|
716
|
-
if (
|
|
717
|
-
clearBufferAfterExtraction &&
|
|
718
|
-
!this.config.extractionJudgeShadow
|
|
719
|
-
) {
|
|
634
|
+
if (clearBufferAfterExtraction && !this.config.extractionJudgeShadow) {
|
|
720
635
|
const deferredCount = this.deps.getLastPersistExtractionDeferredCount();
|
|
721
636
|
if (deferredCount > 0 && normalizedTurns.length > 0) {
|
|
722
|
-
await this.deps.getBuffer().retainDeferredTurns(
|
|
723
|
-
bufferKey,
|
|
724
|
-
normalizedTurns as BufferTurn[],
|
|
725
|
-
10,
|
|
726
|
-
);
|
|
637
|
+
await this.deps.getBuffer().retainDeferredTurns(bufferKey, normalizedTurns as BufferTurn[], 10);
|
|
727
638
|
} else {
|
|
728
639
|
await this.deps.getBuffer().retainDeferredTurns(bufferKey, [], 0);
|
|
729
640
|
}
|
|
@@ -732,7 +643,7 @@ export class ExtractionRunCoordinator {
|
|
|
732
643
|
// Fail-open: retention is a nice-to-have. If it fails the judge will
|
|
733
644
|
// still cap deferrals and convert to reject on the next pass.
|
|
734
645
|
log.debug(
|
|
735
|
-
`extraction-judge: defer retention failed (non-fatal): ${err instanceof Error ? err.message : String(err)}
|
|
646
|
+
`extraction-judge: defer retention failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`
|
|
736
647
|
);
|
|
737
648
|
}
|
|
738
649
|
|
|
@@ -759,46 +670,31 @@ export class ExtractionRunCoordinator {
|
|
|
759
670
|
const extractionTopics = deriveTopicsFromExtraction(result);
|
|
760
671
|
// Derive episodic metadata from buffer turns (REMem-inspired)
|
|
761
672
|
const firstUserTurn = turns.find((t) => t.role === "user");
|
|
762
|
-
const boxGoal =
|
|
763
|
-
|
|
764
|
-
|
|
673
|
+
const boxGoal = firstUserTurn?.content?.slice(0, 100)?.trim() || undefined;
|
|
674
|
+
await this.deps
|
|
675
|
+
.boxBuilderFor(storage)
|
|
765
676
|
.onExtraction({
|
|
766
677
|
topics: extractionTopics,
|
|
767
678
|
memoryIds: persistedIds,
|
|
768
679
|
timestamp: new Date().toISOString(),
|
|
769
680
|
goal: boxGoal,
|
|
770
681
|
})
|
|
771
|
-
.catch((err) =>
|
|
772
|
-
log.warn("[boxes] onExtraction failed (non-fatal)", err),
|
|
773
|
-
);
|
|
682
|
+
.catch((err) => log.warn("[boxes] onExtraction failed (non-fatal)", err));
|
|
774
683
|
}
|
|
775
684
|
|
|
776
685
|
// Batch-append persisted IDs so non-fact memories (entities/questions) are
|
|
777
686
|
// always attached to the thread. The helper excludes pending_review ids (#1635).
|
|
778
|
-
if (
|
|
779
|
-
|
|
780
|
-
threadIdForExtraction &&
|
|
781
|
-
persistedIds.length > 0
|
|
782
|
-
) {
|
|
783
|
-
await this.deps.appendPersistedThreadEpisodes(
|
|
784
|
-
threadIdForExtraction,
|
|
785
|
-
persistedIds,
|
|
786
|
-
);
|
|
687
|
+
if (resolvePresentationCapabilities(this.config).threading && threadIdForExtraction && persistedIds.length > 0) {
|
|
688
|
+
await this.deps.appendPersistedThreadEpisodes(threadIdForExtraction, persistedIds);
|
|
787
689
|
}
|
|
788
690
|
|
|
789
691
|
// Thread title update for the already-established thread context.
|
|
790
692
|
if (resolvePresentationCapabilities(this.config).threading && threadIdForExtraction) {
|
|
791
693
|
const conversationContent = turns.map((t) => t.content).join(" ");
|
|
792
694
|
try {
|
|
793
|
-
await this.deps.getThreading().updateThreadTitle(
|
|
794
|
-
threadIdForExtraction,
|
|
795
|
-
conversationContent,
|
|
796
|
-
);
|
|
695
|
+
await this.deps.getThreading().updateThreadTitle(threadIdForExtraction, conversationContent);
|
|
797
696
|
} catch (err) {
|
|
798
|
-
log.warn(
|
|
799
|
-
"[threading] updateThreadTitle failed after persistence (non-fatal)",
|
|
800
|
-
err,
|
|
801
|
-
);
|
|
697
|
+
log.warn("[threading] updateThreadTitle failed after persistence (non-fatal)", err);
|
|
802
698
|
}
|
|
803
699
|
}
|
|
804
700
|
|
|
@@ -809,28 +705,19 @@ export class ExtractionRunCoordinator {
|
|
|
809
705
|
// the scheduler with the rest of the cadence state (issue #1526 PR1).
|
|
810
706
|
this.deps.maybeScheduleConsolidation(nonZeroExtraction);
|
|
811
707
|
} catch (err) {
|
|
812
|
-
log.warn(
|
|
813
|
-
"runExtraction: consolidation scheduling failed after persistence (non-fatal)",
|
|
814
|
-
err,
|
|
815
|
-
);
|
|
708
|
+
log.warn("runExtraction: consolidation scheduling failed after persistence (non-fatal)", err);
|
|
816
709
|
}
|
|
817
710
|
|
|
818
711
|
try {
|
|
819
712
|
this.deps.requestQmdMaintenance();
|
|
820
713
|
} catch (err) {
|
|
821
|
-
log.warn(
|
|
822
|
-
"runExtraction: QMD maintenance scheduling failed after persistence (non-fatal)",
|
|
823
|
-
err,
|
|
824
|
-
);
|
|
714
|
+
log.warn("runExtraction: QMD maintenance scheduling failed after persistence (non-fatal)", err);
|
|
825
715
|
}
|
|
826
716
|
|
|
827
717
|
try {
|
|
828
718
|
await this.deps.runTierMigrationCycle(storage, "extraction");
|
|
829
719
|
} catch (err) {
|
|
830
|
-
log.warn(
|
|
831
|
-
"runExtraction: tier migration failed after persistence (non-fatal)",
|
|
832
|
-
err,
|
|
833
|
-
);
|
|
720
|
+
log.warn("runExtraction: tier migration failed after persistence (non-fatal)", err);
|
|
834
721
|
}
|
|
835
722
|
|
|
836
723
|
return {
|
|
@@ -842,3 +729,26 @@ export class ExtractionRunCoordinator {
|
|
|
842
729
|
}
|
|
843
730
|
}
|
|
844
731
|
|
|
732
|
+
/**
|
|
733
|
+
* Derive a single `sourceConnector` from a batch of turns.
|
|
734
|
+
* Returns the connector ONLY when ALL turns carry the same connector.
|
|
735
|
+
* Mixed tagged/untagged batches return undefined — extraction facts are
|
|
736
|
+
* persisted at batch level, so attributing them to the single tagged
|
|
737
|
+
* connector would falsely label facts from untagged turns.
|
|
738
|
+
* Conflicting connectors (different values) also return undefined.
|
|
739
|
+
*/
|
|
740
|
+
export function deriveSourceConnector(turns: readonly BufferTurn[]): string | undefined {
|
|
741
|
+
if (turns.length === 0) return undefined;
|
|
742
|
+
const connectors = new Set<string>();
|
|
743
|
+
let untaggedCount = 0;
|
|
744
|
+
for (const turn of turns) {
|
|
745
|
+
if (typeof turn.sourceConnector === "string" && turn.sourceConnector.length > 0) {
|
|
746
|
+
connectors.add(turn.sourceConnector);
|
|
747
|
+
} else {
|
|
748
|
+
untaggedCount += 1;
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
// All turns must agree on the same connector — no untagged turns mixed in.
|
|
752
|
+
if (untaggedCount > 0) return undefined;
|
|
753
|
+
return connectors.size === 1 ? [...connectors][0] : undefined;
|
|
754
|
+
}
|