@remnic/core 9.50.0 → 9.50.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 +10 -10
- package/dist/access-admin-ops-surface.js +17 -17
- package/dist/access-authorization-probe.d.ts +10 -10
- package/dist/access-authorization-probe.js +18 -18
- package/dist/access-boundary.d.ts +10 -10
- package/dist/access-boundary.js +17 -17
- package/dist/access-cli.js +42 -42
- package/dist/access-coding-context-resolution.d.ts +1 -1
- package/dist/access-extraction-force-flush.d.ts +10 -10
- package/dist/access-extraction-force-flush.js +17 -17
- package/dist/access-health-types.d.ts +1 -1
- package/dist/access-http-lcm-compaction.d.ts +10 -10
- package/dist/access-http-lifecycle-flush.d.ts +10 -10
- package/dist/access-http-offline-stream.d.ts +10 -10
- package/dist/access-http-query.js +17 -17
- package/dist/access-http.d.ts +10 -10
- package/dist/access-http.js +23 -23
- package/dist/access-identity-continuity-surface.d.ts +8 -8
- package/dist/access-identity-continuity-surface.js +17 -17
- package/dist/access-lcm-surface.d.ts +10 -10
- package/dist/access-lcm-surface.js +17 -17
- package/dist/access-mcp.d.ts +10 -10
- package/dist/access-mcp.js +21 -21
- package/dist/access-memory-search-fanout.d.ts +2 -2
- package/dist/{access-namespace-preflight-DuDU301-.d.ts → access-namespace-preflight-Dj2QolFE.d.ts} +1 -1
- package/dist/access-namespace-preflight.d.ts +3 -3
- package/dist/access-namespace-preflight.js +17 -17
- package/dist/access-observe-write-surface.d.ts +10 -10
- package/dist/access-observe-write-surface.js +17 -17
- package/dist/access-offline-manifest.d.ts +8 -8
- package/dist/access-operations-batch.js +18 -18
- package/dist/access-operations.d.ts +10 -10
- package/dist/access-operations.js +20 -20
- package/dist/access-recall-concurrency.d.ts +10 -10
- package/dist/access-recall-concurrency.js +17 -17
- package/dist/access-recall-response.d.ts +10 -10
- package/dist/access-recall-response.js +17 -17
- package/dist/access-recall-surface.d.ts +10 -10
- package/dist/access-recall-surface.js +17 -17
- package/dist/{access-service--_3T_v23.d.ts → access-service-DesbnTSa.d.ts} +7 -7
- package/dist/access-service-helpers.d.ts +10 -10
- package/dist/access-service.d.ts +10 -10
- package/dist/access-service.js +17 -17
- package/dist/access-surface-catalog.d.ts +10 -10
- package/dist/access-wearables-meetings-surface.d.ts +3 -3
- package/dist/action-confidence.d.ts +1 -1
- package/dist/active-memory-bridge.d.ts +1 -1
- package/dist/active-recall.d.ts +1 -1
- package/dist/ambient-provenance.d.ts +1 -1
- package/dist/artifact-search.d.ts +1 -1
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +8 -8
- package/dist/briefing.d.ts +2 -2
- package/dist/briefing.js +6 -6
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer-turn-helpers.d.ts +1 -1
- package/dist/buffer.d.ts +2 -2
- package/dist/bulk-import/index.d.ts +3 -3
- package/dist/calibration.d.ts +1 -1
- package/dist/capabilities.d.ts +1 -1
- package/dist/{capsule-merge-KXTRZ23Z.js → capsule-merge-XMFBXVDP.js} +4 -4
- package/dist/{catalog-DjUmUIal.d.ts → catalog-D-G7RgXR.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +7 -7
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/{chunk-N3CXAYPJ.js → chunk-2HGUDBRJ.js} +2 -2
- package/dist/{chunk-FV7YQTN3.js → chunk-2S72LWKX.js} +2 -2
- package/dist/{chunk-NKL25FCF.js → chunk-4MBPIL4V.js} +2 -2
- package/dist/{chunk-PWIMF7LP.js → chunk-5C2HNJMO.js} +12 -12
- package/dist/{chunk-ZN4EYMKJ.js → chunk-67QG75MJ.js} +2 -2
- package/dist/{chunk-JI62YGPI.js → chunk-6QPHF6RR.js} +2 -2
- package/dist/{chunk-4EABKPZS.js → chunk-75XOWNRS.js} +4 -4
- package/dist/{chunk-O76MWTVS.js → chunk-7BAYBYY5.js} +2 -2
- package/dist/{chunk-4JWJMRPJ.js → chunk-7PKFPLLZ.js} +2 -2
- package/dist/{chunk-24BKGKGO.js → chunk-BOFVT6P3.js} +5 -5
- package/dist/{chunk-SHYIMIX5.js → chunk-ESG7Z255.js} +2 -2
- package/dist/{chunk-P26YHAQH.js → chunk-EWMTOVMY.js} +51 -27
- package/dist/chunk-EWMTOVMY.js.map +1 -0
- package/dist/{chunk-WPZX7MEA.js → chunk-FXX6RQYC.js} +3 -3
- package/dist/{chunk-S75UQ3T3.js → chunk-GDDGZVFI.js} +2 -2
- package/dist/{chunk-S2SJEOTM.js → chunk-GFIKG4FR.js} +2 -2
- package/dist/{chunk-7NDM2PNK.js → chunk-GZICBRWK.js} +2 -2
- package/dist/{chunk-X4IDNPOS.js → chunk-HAEU3ZW7.js} +2 -2
- package/dist/{chunk-RBPH3GZV.js → chunk-IK6X5QPO.js} +26 -29
- package/dist/chunk-IK6X5QPO.js.map +1 -0
- package/dist/{chunk-GKEYXXKX.js → chunk-IXXABW5A.js} +2 -2
- package/dist/{chunk-GGBSF2X7.js → chunk-JB6D7EFB.js} +2 -2
- package/dist/{chunk-E633OXMH.js → chunk-JPHEOE6Z.js} +8 -8
- package/dist/{chunk-6XGEBQ3R.js → chunk-KDG2KTWW.js} +3 -3
- package/dist/{chunk-7BLWBSRL.js → chunk-LEJPSMKM.js} +2 -2
- package/dist/{chunk-JDCQK3C5.js → chunk-M4A44LUA.js} +2 -2
- package/dist/{chunk-ZDAYWJV6.js → chunk-NO37MR45.js} +3 -3
- package/dist/{chunk-PWLB4TRK.js → chunk-OQAL6SIR.js} +2 -2
- package/dist/{chunk-QWLW3VQH.js → chunk-PLKFO2HJ.js} +2 -2
- package/dist/{chunk-EURCX6PS.js → chunk-PWN32TAG.js} +2 -2
- package/dist/{chunk-ELQCS47S.js → chunk-PYKKWQZ2.js} +3 -3
- package/dist/{chunk-P4QOYG52.js → chunk-QN7NTKRC.js} +1 -1
- package/dist/{chunk-7VWZ4LRW.js → chunk-QW3WFHKU.js} +2 -2
- package/dist/{chunk-PNRA7FAD.js → chunk-RZRUV6N2.js} +104 -62
- package/dist/chunk-RZRUV6N2.js.map +1 -0
- package/dist/{chunk-3LD4N2TF.js → chunk-S3AYIQCU.js} +68 -82
- package/dist/chunk-S3AYIQCU.js.map +1 -0
- package/dist/{chunk-ZJIFYUJI.js → chunk-SV3PSA7Y.js} +2 -2
- package/dist/{chunk-LQKXVQZR.js → chunk-TQFHQPWD.js} +5 -5
- package/dist/{chunk-GSEPRIZC.js → chunk-TS4AJ2GI.js} +2 -2
- package/dist/{chunk-VFS3MK5F.js → chunk-V5H6OJCR.js} +2 -2
- package/dist/{chunk-T35UJI5R.js → chunk-V7X767RT.js} +18 -18
- package/dist/{chunk-4S3ECH3U.js → chunk-VJXY5ZCT.js} +2 -2
- package/dist/{chunk-PLCHU56K.js → chunk-YQ4IQ2GA.js} +2 -2
- package/dist/{chunk-LTOAJXZB.js → chunk-Z3RHPGSY.js} +3 -3
- package/dist/{chunk-5XCN4XBU.js → chunk-ZQOCRIGA.js} +3 -3
- package/dist/{cli-BLNmNEMT.d.ts → cli-D4vvtxjY.d.ts} +5 -5
- package/dist/cli.d.ts +12 -12
- package/dist/cli.js +34 -34
- package/dist/coding/pre-action-gate.d.ts +1 -1
- package/dist/compounding/engine.d.ts +2 -2
- package/dist/compounding/engine.js +6 -6
- package/dist/compounding/preference-consolidator.d.ts +1 -1
- package/dist/compression-optimizer.d.ts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +6 -6
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +2 -1
- package/dist/connectors/index.js +7 -7
- package/dist/consolidation-provenance-check.d.ts +2 -2
- package/dist/consolidation-provenance-check.js +4 -4
- package/dist/consolidation-undo.d.ts +2 -2
- package/dist/consolidation-undo.js +3 -3
- package/dist/contradiction/index.d.ts +2 -2
- package/dist/converge-config.d.ts +1 -1
- package/dist/convergence-refresh.d.ts +2 -2
- package/dist/convergence-refresh.js +8 -8
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/chunker.d.ts +1 -1
- package/dist/conversation-index/faiss-adapter.d.ts +1 -1
- package/dist/conversation-index/indexer.d.ts +1 -1
- package/dist/conversation-index/search.d.ts +1 -1
- package/dist/corpus-watermark.d.ts +1 -1
- package/dist/corpus-watermark.js +8 -8
- package/dist/day-summary.d.ts +1 -1
- package/dist/delinearize.d.ts +1 -1
- package/dist/dependency-propagation-config.d.ts +1 -1
- package/dist/direct-answer-wiring.d.ts +1 -1
- package/dist/direct-answer.d.ts +1 -1
- package/dist/embedding-fallback.d.ts +1 -1
- package/dist/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +2 -2
- package/dist/entity-retrieval.js +6 -6
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +8 -8
- package/dist/explicit-capture.js +4 -4
- package/dist/external-wiki-access.d.ts +10 -10
- package/dist/external-wiki-access.js +18 -18
- package/dist/external-wiki-collection-registration.d.ts +1 -1
- package/dist/external-wiki-collection.d.ts +1 -1
- package/dist/external-wiki-mcp-tools.d.ts +10 -10
- package/dist/extraction-error-classification.d.ts +1 -1
- package/dist/extraction-faithfulness.d.ts +1 -1
- package/dist/extraction-judge-telemetry.d.ts +1 -1
- package/dist/extraction-judge-training.d.ts +1 -1
- package/dist/extraction-judge.d.ts +1 -1
- package/dist/extraction-liveness.d.ts +1 -1
- package/dist/extraction-normalization.d.ts +1 -1
- package/dist/extraction-prompt.d.ts +1 -1
- package/dist/extraction-source-grounding-rules.d.ts +1 -1
- package/dist/extraction-source-grounding.d.ts +1 -1
- package/dist/extraction.d.ts +17 -18
- package/dist/extraction.js +10 -10
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/{forget-GJ42LCBW.js → forget-UJDJHG6R.js} +2 -2
- package/dist/graph-dashboard-diff.d.ts +1 -1
- package/dist/graph-dashboard-key.d.ts +1 -1
- package/dist/graph-dashboard-parser.d.ts +1 -1
- package/dist/graph-edge-reinforcement.d.ts +1 -1
- package/dist/graph-snapshot.d.ts +1 -1
- package/dist/graph.d.ts +1 -1
- package/dist/harmonic-retrieval.js +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/importers/index.d.ts +1 -1
- package/dist/in-flight-reads.d.ts +1 -1
- package/dist/index.d.ts +19 -19
- package/dist/index.js +42 -42
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/tools.d.ts +1 -1
- package/dist/lifecycle.d.ts +1 -1
- package/dist/live-connectors-runner.d.ts +1 -1
- package/dist/local-llm.d.ts +1 -1
- package/dist/local-model-endpoint.d.ts +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +6 -6
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +6 -6
- package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-projection.js +7 -7
- package/dist/{maintenance-DKbKZi3u.d.ts → maintenance-ClmUVpGI.d.ts} +3 -3
- package/dist/mcp-memory-inspector-app.d.ts +10 -10
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/memory-provenance.d.ts +1 -1
- package/dist/memory-snapshot.d.ts +1 -1
- package/dist/memory-worth-outcomes.d.ts +2 -2
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +3 -3
- package/dist/namespaces/migrate.js +7 -7
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/storage.d.ts +3 -3
- package/dist/namespaces/storage.js +6 -6
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/offline-sync-impression-drain.d.ts +1 -1
- package/dist/operator-doctor-corpus.d.ts +1 -1
- package/dist/operator-doctor-corpus.js +9 -9
- package/dist/operator-doctor-replica.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +3 -3
- package/dist/operator-toolkit.js +14 -14
- package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
- package/dist/orchestration/maintenance.d.ts +4 -4
- package/dist/orchestration/maintenance.js +11 -11
- package/dist/{orchestrator-BRwD7ceU.d.ts → orchestrator-qJ07zI8H.d.ts} +8 -12
- package/dist/orchestrator.d.ts +8 -8
- package/dist/orchestrator.js +42 -42
- package/dist/page-versioning.js +3 -3
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/{pipeline-DC-1C9T8.d.ts → pipeline-WFCxhHOn.d.ts} +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/proactive-contention.d.ts +1 -1
- package/dist/provenance.d.ts +1 -1
- package/dist/{qmd-DdeCEZdb.d.ts → qmd-5tzkQ44y.d.ts} +1 -1
- package/dist/qmd-preflight.d.ts +2 -2
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +2 -2
- package/dist/recall-concurrency-config.d.ts +1 -1
- package/dist/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -1
- package/dist/recall-memory-map.d.ts +1 -1
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-state.d.ts +1 -1
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-timings.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray.d.ts +1 -1
- package/dist/reconcile/cursor.d.ts +1 -1
- package/dist/reconcile/manifest.d.ts +1 -1
- package/dist/reconcile/plan.d.ts +1 -1
- package/dist/replay/normalizers/chatgpt.d.ts +1 -1
- package/dist/replay/normalizers/claude.d.ts +1 -1
- package/dist/replay/normalizers/openclaw.d.ts +1 -1
- package/dist/replay/normalizers/shared.d.ts +1 -1
- package/dist/replay/runner.d.ts +1 -1
- package/dist/replay/types.d.ts +1 -1
- package/dist/replica-divergence.d.ts +1 -1
- package/dist/replica-peers-config.d.ts +1 -1
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/retrieval-agents.d.ts +2 -2
- package/dist/retrieval-tiers.d.ts +1 -1
- package/dist/routing/engine.d.ts +1 -1
- package/dist/routing/store.d.ts +1 -1
- package/dist/salvage-envelope.d.ts +1 -1
- package/dist/{scope-profiles-BXVq4Jv0.d.ts → scope-profiles--vfXPl3X.d.ts} +1 -1
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/index.d.ts +1 -1
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/port.d.ts +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-consolidation-CGYxfa8F.d.ts → semantic-consolidation-BBDuP9nJ.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +7 -7
- package/dist/semantic-rule-promotion.js +6 -6
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +6 -6
- package/dist/{service-CBDBQFCN.d.ts → service-B8DtbpCM.d.ts} +2 -2
- package/dist/session-observer-bands.d.ts +1 -1
- package/dist/session-observer-state.d.ts +1 -1
- package/dist/shared-context/manager.d.ts +1 -1
- package/dist/signal.d.ts +1 -1
- package/dist/source-agent-qualifier.d.ts +1 -1
- package/dist/source-agent-qualifier.js +9 -9
- package/dist/{storage-V--MQi7w.d.ts → storage-BkYN1RIy.d.ts} +1 -1
- package/dist/storage.d.ts +2 -2
- package/dist/storage.js +5 -5
- package/dist/summarizer.d.ts +1 -1
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/temporal-supersession.d.ts +2 -2
- package/dist/temporal-supersession.js +1 -1
- package/dist/temporal-timeline-recall.d.ts +1 -1
- package/dist/temporal-validity.d.ts +1 -1
- package/dist/threading.d.ts +1 -1
- package/dist/tier-migration.d.ts +2 -2
- package/dist/tier-routing.d.ts +1 -1
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/capsule-import.js +4 -4
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-D_a6Sqjz.d.ts → types-u2s9j1uD.d.ts} +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +6 -6
- package/dist/write-envelope.d.ts +1 -1
- package/package.json +2 -2
- package/src/connectors/index.ts +40 -112
- package/src/dependency-revalidation-routing.test.ts +165 -0
- package/src/extraction.ts +46 -31
- package/src/orchestration/dependency-propagation.test.ts +89 -8
- package/src/orchestration/dependency-propagation.ts +60 -27
- package/src/orchestration/dependency-revalidation.test.ts +119 -0
- package/src/orchestration/dependency-revalidation.ts +31 -82
- package/src/orchestrator.ts +5 -7
- package/src/runtime/daemon-health.ts +53 -0
- package/src/runtime/http-transport.ts +25 -0
- package/src/testing/subjects/dependency-propagation.test.ts +367 -0
- package/dist/chunk-3LD4N2TF.js.map +0 -1
- package/dist/chunk-P26YHAQH.js.map +0 -1
- package/dist/chunk-PNRA7FAD.js.map +0 -1
- package/dist/chunk-RBPH3GZV.js.map +0 -1
- /package/dist/{capsule-merge-KXTRZ23Z.js.map → capsule-merge-XMFBXVDP.js.map} +0 -0
- /package/dist/{chunk-N3CXAYPJ.js.map → chunk-2HGUDBRJ.js.map} +0 -0
- /package/dist/{chunk-FV7YQTN3.js.map → chunk-2S72LWKX.js.map} +0 -0
- /package/dist/{chunk-NKL25FCF.js.map → chunk-4MBPIL4V.js.map} +0 -0
- /package/dist/{chunk-PWIMF7LP.js.map → chunk-5C2HNJMO.js.map} +0 -0
- /package/dist/{chunk-ZN4EYMKJ.js.map → chunk-67QG75MJ.js.map} +0 -0
- /package/dist/{chunk-JI62YGPI.js.map → chunk-6QPHF6RR.js.map} +0 -0
- /package/dist/{chunk-4EABKPZS.js.map → chunk-75XOWNRS.js.map} +0 -0
- /package/dist/{chunk-O76MWTVS.js.map → chunk-7BAYBYY5.js.map} +0 -0
- /package/dist/{chunk-4JWJMRPJ.js.map → chunk-7PKFPLLZ.js.map} +0 -0
- /package/dist/{chunk-24BKGKGO.js.map → chunk-BOFVT6P3.js.map} +0 -0
- /package/dist/{chunk-SHYIMIX5.js.map → chunk-ESG7Z255.js.map} +0 -0
- /package/dist/{chunk-WPZX7MEA.js.map → chunk-FXX6RQYC.js.map} +0 -0
- /package/dist/{chunk-S75UQ3T3.js.map → chunk-GDDGZVFI.js.map} +0 -0
- /package/dist/{chunk-S2SJEOTM.js.map → chunk-GFIKG4FR.js.map} +0 -0
- /package/dist/{chunk-7NDM2PNK.js.map → chunk-GZICBRWK.js.map} +0 -0
- /package/dist/{chunk-X4IDNPOS.js.map → chunk-HAEU3ZW7.js.map} +0 -0
- /package/dist/{chunk-GKEYXXKX.js.map → chunk-IXXABW5A.js.map} +0 -0
- /package/dist/{chunk-GGBSF2X7.js.map → chunk-JB6D7EFB.js.map} +0 -0
- /package/dist/{chunk-E633OXMH.js.map → chunk-JPHEOE6Z.js.map} +0 -0
- /package/dist/{chunk-6XGEBQ3R.js.map → chunk-KDG2KTWW.js.map} +0 -0
- /package/dist/{chunk-7BLWBSRL.js.map → chunk-LEJPSMKM.js.map} +0 -0
- /package/dist/{chunk-JDCQK3C5.js.map → chunk-M4A44LUA.js.map} +0 -0
- /package/dist/{chunk-ZDAYWJV6.js.map → chunk-NO37MR45.js.map} +0 -0
- /package/dist/{chunk-PWLB4TRK.js.map → chunk-OQAL6SIR.js.map} +0 -0
- /package/dist/{chunk-QWLW3VQH.js.map → chunk-PLKFO2HJ.js.map} +0 -0
- /package/dist/{chunk-EURCX6PS.js.map → chunk-PWN32TAG.js.map} +0 -0
- /package/dist/{chunk-ELQCS47S.js.map → chunk-PYKKWQZ2.js.map} +0 -0
- /package/dist/{chunk-P4QOYG52.js.map → chunk-QN7NTKRC.js.map} +0 -0
- /package/dist/{chunk-7VWZ4LRW.js.map → chunk-QW3WFHKU.js.map} +0 -0
- /package/dist/{chunk-ZJIFYUJI.js.map → chunk-SV3PSA7Y.js.map} +0 -0
- /package/dist/{chunk-LQKXVQZR.js.map → chunk-TQFHQPWD.js.map} +0 -0
- /package/dist/{chunk-GSEPRIZC.js.map → chunk-TS4AJ2GI.js.map} +0 -0
- /package/dist/{chunk-VFS3MK5F.js.map → chunk-V5H6OJCR.js.map} +0 -0
- /package/dist/{chunk-T35UJI5R.js.map → chunk-V7X767RT.js.map} +0 -0
- /package/dist/{chunk-4S3ECH3U.js.map → chunk-VJXY5ZCT.js.map} +0 -0
- /package/dist/{chunk-PLCHU56K.js.map → chunk-YQ4IQ2GA.js.map} +0 -0
- /package/dist/{chunk-LTOAJXZB.js.map → chunk-Z3RHPGSY.js.map} +0 -0
- /package/dist/{chunk-5XCN4XBU.js.map → chunk-ZQOCRIGA.js.map} +0 -0
- /package/dist/{forget-GJ42LCBW.js.map → forget-UJDJHG6R.js.map} +0 -0
package/src/connectors/index.ts
CHANGED
|
@@ -12,10 +12,10 @@ import { createRequire } from "node:module";
|
|
|
12
12
|
import { fileURLToPath } from "node:url";
|
|
13
13
|
|
|
14
14
|
import { generateToken, revokeToken, buildTokenEntry, commitTokenEntry, loadTokenStore, saveTokenStore } from "../tokens.js";
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
15
|
+
import { checkDaemonHealth } from "../runtime/daemon-health.js";
|
|
16
|
+
import { readEnvVar, resolveHomeDir } from "../runtime/env.js";
|
|
17
17
|
import { expandTildePath } from "../utils/path.js";
|
|
18
|
-
import { coerceInstallExtension } from "./coerce.js";
|
|
18
|
+
import { coerceBool, coerceInstallExtension } from "./coerce.js";
|
|
19
19
|
import {
|
|
20
20
|
assertConfigComponentsNotSymlinked,
|
|
21
21
|
hermesShimPath,
|
|
@@ -988,10 +988,12 @@ export function installConnector(options: InstallOptions): InstallResult {
|
|
|
988
988
|
let hermesSavedProfile: string | undefined;
|
|
989
989
|
let hermesSavedHost: string | undefined;
|
|
990
990
|
let hermesSavedPort: number | undefined;
|
|
991
|
+
let hermesSavedAllowInsecureHttp: boolean | undefined;
|
|
991
992
|
// Resolved values (used both in resolvedConfig and in the YAML update below)
|
|
992
993
|
let hermesResolvedProfile: string | undefined;
|
|
993
994
|
let hermesResolvedHost: string | undefined;
|
|
994
995
|
let hermesResolvedPort: number | undefined;
|
|
996
|
+
let hermesResolvedAllowInsecureHttp = false;
|
|
995
997
|
if (options.connectorId === "hermes") {
|
|
996
998
|
if (fs.existsSync(configPath)) {
|
|
997
999
|
try {
|
|
@@ -1022,6 +1024,9 @@ export function installConnector(options: InstallOptions): InstallResult {
|
|
|
1022
1024
|
// Invalid saved port — fall through to default
|
|
1023
1025
|
}
|
|
1024
1026
|
}
|
|
1027
|
+
if (prev?.allow_insecure_http != null) {
|
|
1028
|
+
hermesSavedAllowInsecureHttp = coerceBool(prev.allow_insecure_http, "allow_insecure_http");
|
|
1029
|
+
}
|
|
1025
1030
|
} catch {
|
|
1026
1031
|
// Could not read existing config — fall through to defaults
|
|
1027
1032
|
}
|
|
@@ -1030,6 +1035,7 @@ export function installConnector(options: InstallOptions): InstallResult {
|
|
|
1030
1035
|
// and applied in the sanitization block below (single point of validation).
|
|
1031
1036
|
hermesResolvedProfile = hermesSavedProfile ?? "default";
|
|
1032
1037
|
hermesResolvedHost = hermesSavedHost ?? "127.0.0.1";
|
|
1038
|
+
hermesResolvedAllowInsecureHttp = hermesSavedAllowInsecureHttp ?? false;
|
|
1033
1039
|
|
|
1034
1040
|
// Issue C: wrap sanitizeHermesPort (and profile/host) in try-catch so
|
|
1035
1041
|
// that invalid user-supplied values return a clean error result.
|
|
@@ -1071,6 +1077,17 @@ export function installConnector(options: InstallOptions): InstallResult {
|
|
|
1071
1077
|
};
|
|
1072
1078
|
}
|
|
1073
1079
|
}
|
|
1080
|
+
if (options.config?.allow_insecure_http !== undefined) {
|
|
1081
|
+
const allowInsecureHttp = coerceBool(options.config.allow_insecure_http, "allow_insecure_http");
|
|
1082
|
+
if (allowInsecureHttp === undefined) {
|
|
1083
|
+
return {
|
|
1084
|
+
connectorId: options.connectorId,
|
|
1085
|
+
status: "error",
|
|
1086
|
+
message: "Invalid Hermes config: allow_insecure_http must be true or false",
|
|
1087
|
+
};
|
|
1088
|
+
}
|
|
1089
|
+
hermesResolvedAllowInsecureHttp = allowInsecureHttp;
|
|
1090
|
+
}
|
|
1074
1091
|
}
|
|
1075
1092
|
|
|
1076
1093
|
// Generate a per-connector auth token so the daemon can authenticate
|
|
@@ -1182,6 +1199,7 @@ export function installConnector(options: InstallOptions): InstallResult {
|
|
|
1182
1199
|
profile: hermesResolvedProfile,
|
|
1183
1200
|
host: hermesResolvedHost,
|
|
1184
1201
|
port: hermesResolvedPort,
|
|
1202
|
+
allow_insecure_http: hermesResolvedAllowInsecureHttp,
|
|
1185
1203
|
} : {}),
|
|
1186
1204
|
};
|
|
1187
1205
|
|
|
@@ -1260,6 +1278,7 @@ export function installConnector(options: InstallOptions): InstallResult {
|
|
|
1260
1278
|
host: hermesHost,
|
|
1261
1279
|
port: hermesPort,
|
|
1262
1280
|
token: tokenEntry.token,
|
|
1281
|
+
allowInsecureHttp: hermesResolvedAllowInsecureHttp,
|
|
1263
1282
|
});
|
|
1264
1283
|
} catch (err) {
|
|
1265
1284
|
// upsertHermesConfig threw — old token preserved, connector.json unchanged.
|
|
@@ -1458,6 +1477,7 @@ export function installConnector(options: InstallOptions): InstallResult {
|
|
|
1458
1477
|
host: hermesHost,
|
|
1459
1478
|
port: hermesPort,
|
|
1460
1479
|
token: tokenEntry.token,
|
|
1480
|
+
allowInsecureHttp: hermesResolvedAllowInsecureHttp,
|
|
1461
1481
|
});
|
|
1462
1482
|
if (refresh.updated) {
|
|
1463
1483
|
hermesPriorConfigMutations.push({ mutatedPath: priorConfigPath, priorContent: beforeRefresh });
|
|
@@ -1756,7 +1776,12 @@ export function installConnector(options: InstallOptions): InstallResult {
|
|
|
1756
1776
|
// (we returned early on failure above) but the explicit guard is kept for
|
|
1757
1777
|
// clarity and future robustness.
|
|
1758
1778
|
if (committed && tokenEntry) {
|
|
1759
|
-
const daemonOk = checkDaemonHealth(
|
|
1779
|
+
const daemonOk = checkDaemonHealth(
|
|
1780
|
+
hermesHost,
|
|
1781
|
+
hermesPort,
|
|
1782
|
+
tokenEntry.token,
|
|
1783
|
+
hermesResolvedAllowInsecureHttp,
|
|
1784
|
+
);
|
|
1760
1785
|
if (daemonOk) {
|
|
1761
1786
|
notes.push("Daemon health check: OK");
|
|
1762
1787
|
} else {
|
|
@@ -2883,6 +2908,7 @@ export function upsertHermesConfig(opts: {
|
|
|
2883
2908
|
host: string;
|
|
2884
2909
|
port: number;
|
|
2885
2910
|
token: string;
|
|
2911
|
+
allowInsecureHttp?: boolean;
|
|
2886
2912
|
}): HermesConfigResult {
|
|
2887
2913
|
return upsertHermesConfigAt(hermesConfigPath(opts.profile), opts);
|
|
2888
2914
|
}
|
|
@@ -2895,7 +2921,7 @@ export function upsertHermesConfig(opts: {
|
|
|
2895
2921
|
*/
|
|
2896
2922
|
function upsertHermesConfigAt(
|
|
2897
2923
|
cfgPath: string,
|
|
2898
|
-
opts: { host: string; port: number; token: string },
|
|
2924
|
+
opts: { host: string; port: number; token: string; allowInsecureHttp?: boolean },
|
|
2899
2925
|
): HermesConfigResult {
|
|
2900
2926
|
// Symlinked components below the Hermes root must not redirect the
|
|
2901
2927
|
// token-bearing write (Codex P1 on PR #1938, round 19).
|
|
@@ -2907,6 +2933,7 @@ function upsertHermesConfigAt(
|
|
|
2907
2933
|
// that could break out of the scalar context.
|
|
2908
2934
|
const safeHost = sanitizeHermesHost(opts.host);
|
|
2909
2935
|
const safePort = sanitizeHermesPort(opts.port);
|
|
2936
|
+
const allowInsecureHttp = opts.allowInsecureHttp ?? false;
|
|
2910
2937
|
// Token is generated by randomBytes + a fixed alphabetic prefix, so it's
|
|
2911
2938
|
// already safe for YAML scalar interpolation. We still guard against an
|
|
2912
2939
|
// unexpectedly malformed token reaching this function.
|
|
@@ -2928,6 +2955,7 @@ function upsertHermesConfigAt(
|
|
|
2928
2955
|
` host: "${safeHost}"`,
|
|
2929
2956
|
` port: ${safePort}`,
|
|
2930
2957
|
` token: "${opts.token}"`,
|
|
2958
|
+
` allow_insecure_http: ${allowInsecureHttp}`,
|
|
2931
2959
|
].join("\n");
|
|
2932
2960
|
|
|
2933
2961
|
if (!fs.existsSync(cfgPath)) {
|
|
@@ -2973,7 +3001,7 @@ function upsertHermesConfigAt(
|
|
|
2973
3001
|
let blockWritten = false;
|
|
2974
3002
|
|
|
2975
3003
|
// Track which sub-keys we've emitted
|
|
2976
|
-
const written = { host: false, port: false, token: false };
|
|
3004
|
+
const written = { host: false, port: false, token: false, allowInsecureHttp: false };
|
|
2977
3005
|
|
|
2978
3006
|
for (let i = 0; i < lines.length; i++) {
|
|
2979
3007
|
const line = lines[i];
|
|
@@ -2993,13 +3021,14 @@ function upsertHermesConfigAt(
|
|
|
2993
3021
|
if (!written.host) newLines.push(` host: "${safeHost}"`);
|
|
2994
3022
|
if (!written.port) newLines.push(` port: ${safePort}`);
|
|
2995
3023
|
if (!written.token) newLines.push(` token: "${opts.token}"`);
|
|
3024
|
+
if (!written.allowInsecureHttp) newLines.push(` allow_insecure_http: ${allowInsecureHttp}`);
|
|
2996
3025
|
blockWritten = true;
|
|
2997
3026
|
inRemnicBlock = false;
|
|
2998
3027
|
newLines.push(line);
|
|
2999
3028
|
continue;
|
|
3000
3029
|
}
|
|
3001
3030
|
|
|
3002
|
-
// Replace
|
|
3031
|
+
// Replace managed transport fields and preserve other sub-keys.
|
|
3003
3032
|
if (/^\s+host:/.test(line)) {
|
|
3004
3033
|
newLines.push(` host: "${safeHost}"`);
|
|
3005
3034
|
written.host = true;
|
|
@@ -3009,6 +3038,9 @@ function upsertHermesConfigAt(
|
|
|
3009
3038
|
} else if (/^\s+token:/.test(line)) {
|
|
3010
3039
|
newLines.push(` token: "${opts.token}"`);
|
|
3011
3040
|
written.token = true;
|
|
3041
|
+
} else if (/^\s+allow_insecure_http:/.test(line)) {
|
|
3042
|
+
newLines.push(` allow_insecure_http: ${allowInsecureHttp}`);
|
|
3043
|
+
written.allowInsecureHttp = true;
|
|
3012
3044
|
} else {
|
|
3013
3045
|
newLines.push(line);
|
|
3014
3046
|
}
|
|
@@ -3023,6 +3055,7 @@ function upsertHermesConfigAt(
|
|
|
3023
3055
|
if (!written.host) newLines.push(` host: "${safeHost}"`);
|
|
3024
3056
|
if (!written.port) newLines.push(` port: ${safePort}`);
|
|
3025
3057
|
if (!written.token) newLines.push(` token: "${opts.token}"`);
|
|
3058
|
+
if (!written.allowInsecureHttp) newLines.push(` allow_insecure_http: ${allowInsecureHttp}`);
|
|
3026
3059
|
}
|
|
3027
3060
|
|
|
3028
3061
|
// Always write exactly one trailing newline, matching the create and append paths.
|
|
@@ -3207,111 +3240,6 @@ function removeHermesConfigFile(cfgPath: string): HermesConfigResult {
|
|
|
3207
3240
|
return { updated: true, skipped: false, configPath: cfgPath };
|
|
3208
3241
|
}
|
|
3209
3242
|
|
|
3210
|
-
// ── Daemon health check (synchronous, non-fatal) ────────────────────────────
|
|
3211
|
-
|
|
3212
|
-
/**
|
|
3213
|
-
* Probe exit-code contract (used by checkDaemonHealth):
|
|
3214
|
-
* 0 — HTTP 200 (healthy)
|
|
3215
|
-
* 2 — HTTP 401 (token cache miss: retry after TTL)
|
|
3216
|
-
* 1 — any other HTTP status or network error
|
|
3217
|
-
*/
|
|
3218
|
-
const HEALTH_EXIT_OK = 0;
|
|
3219
|
-
const HEALTH_EXIT_UNAUTHORIZED = 2;
|
|
3220
|
-
|
|
3221
|
-
/**
|
|
3222
|
-
* Ping /engram/v1/health synchronously.
|
|
3223
|
-
* Returns true if the daemon responds with HTTP 200, false otherwise.
|
|
3224
|
-
* Uses a synchronous helper to run a one-liner Node script so that the existing
|
|
3225
|
-
* installConnector() flow does not need to become async.
|
|
3226
|
-
*
|
|
3227
|
-
* Data (host, port, token) are passed via environment variables — NOT
|
|
3228
|
-
* interpolated into the script string — to prevent injection from
|
|
3229
|
-
* user-supplied config values.
|
|
3230
|
-
*
|
|
3231
|
-
* /engram/v1/health is protected by bearer auth in the access HTTP server,
|
|
3232
|
-
* so the caller must pass the connector token (or the configured server
|
|
3233
|
-
* token) or the probe will always return 401 and report the daemon as
|
|
3234
|
-
* unreachable even when it is running.
|
|
3235
|
-
*
|
|
3236
|
-
* 401 handling: the daemon caches valid tokens with a 5-second TTL
|
|
3237
|
-
* (getAllValidTokensCached). A freshly-rotated token may not appear in the
|
|
3238
|
-
* cache for up to 5 s after rotation. We tolerate a single 401 by sleeping
|
|
3239
|
-
* one cache TTL (6000 ms = 5 s TTL + 1 s buffer) and retrying exactly once.
|
|
3240
|
-
*/
|
|
3241
|
-
function checkDaemonHealth(host: string, port: number, authToken?: string): boolean {
|
|
3242
|
-
try {
|
|
3243
|
-
// Validate port: must be an integer in [1, 65535].
|
|
3244
|
-
// This guards against user config supplying a non-numeric string.
|
|
3245
|
-
const safePort = Math.trunc(Number(port));
|
|
3246
|
-
if (!Number.isFinite(safePort) || safePort < 1 || safePort > 65535) {
|
|
3247
|
-
return false;
|
|
3248
|
-
}
|
|
3249
|
-
// Finding 7 fix: Node's http.get({ host }) expects an unbracketed IPv6
|
|
3250
|
-
// literal (e.g. "::1"), but sanitizeHermesHost permits bracketed form
|
|
3251
|
-
// "[::1]" (required for URL contexts). Strip the brackets here so that
|
|
3252
|
-
// http.get receives the bare address and doesn't fail to connect.
|
|
3253
|
-
// IPv4 and hostname strings are unaffected (no brackets to strip).
|
|
3254
|
-
const bareHost = host.startsWith("[") && host.endsWith("]")
|
|
3255
|
-
? host.slice(1, -1)
|
|
3256
|
-
: host;
|
|
3257
|
-
|
|
3258
|
-
// Data (host, port, token) are passed via env vars, never interpolated
|
|
3259
|
-
// into the script string, preventing any code-injection from malformed
|
|
3260
|
-
// config values.
|
|
3261
|
-
// Exit codes: 0 = 200 OK, 2 = 401 Unauthorized, 1 = other error.
|
|
3262
|
-
const script = [
|
|
3263
|
-
"const http = require('http');",
|
|
3264
|
-
"const env = process['env'];",
|
|
3265
|
-
"const headers = {};",
|
|
3266
|
-
"if (env.REMNIC_HEALTH_TOKEN) {",
|
|
3267
|
-
" headers['authorization'] = 'Bearer ' + env.REMNIC_HEALTH_TOKEN;",
|
|
3268
|
-
"}",
|
|
3269
|
-
"const req = http.get({",
|
|
3270
|
-
" host: env.REMNIC_HEALTH_HOST,",
|
|
3271
|
-
" port: parseInt(env.REMNIC_HEALTH_PORT, 10),",
|
|
3272
|
-
" path: '/engram/v1/health',",
|
|
3273
|
-
" headers,",
|
|
3274
|
-
" timeout: 3000,",
|
|
3275
|
-
"}, (res) => { process.exit(res.statusCode === 200 ? 0 : res.statusCode === 401 ? 2 : 1); });",
|
|
3276
|
-
"req.on('error', () => process.exit(1));",
|
|
3277
|
-
"req.on('timeout', () => { req.destroy(); process.exit(1); });",
|
|
3278
|
-
].join("\n");
|
|
3279
|
-
const env: NodeJS.ProcessEnv = mergeEnv({
|
|
3280
|
-
REMNIC_HEALTH_HOST: bareHost,
|
|
3281
|
-
REMNIC_HEALTH_PORT: String(safePort),
|
|
3282
|
-
});
|
|
3283
|
-
if (authToken) {
|
|
3284
|
-
env.REMNIC_HEALTH_TOKEN = authToken;
|
|
3285
|
-
}
|
|
3286
|
-
const processPath = process.execPath;
|
|
3287
|
-
const launchOptions = { timeout: 4000, env };
|
|
3288
|
-
const result = launchProcessSync(processPath, ["-e", script], launchOptions);
|
|
3289
|
-
|
|
3290
|
-
if (result.status === HEALTH_EXIT_OK) {
|
|
3291
|
-
return true;
|
|
3292
|
-
}
|
|
3293
|
-
|
|
3294
|
-
if (result.status === HEALTH_EXIT_UNAUTHORIZED) {
|
|
3295
|
-
// The daemon's token cache (5 s TTL) has not yet picked up the freshly
|
|
3296
|
-
// rotated token. Sleep one TTL + buffer and retry exactly once.
|
|
3297
|
-
console.error(
|
|
3298
|
-
"[remnic/connectors] health probe got 401 — retrying after token cache TTL...",
|
|
3299
|
-
);
|
|
3300
|
-
// Synchronous sleep without making the caller async.
|
|
3301
|
-
launchProcessSync(processPath, ["-e", "setTimeout(() => {}, 6000)"], {
|
|
3302
|
-
timeout: 7000,
|
|
3303
|
-
env: {},
|
|
3304
|
-
});
|
|
3305
|
-
const retry = launchProcessSync(processPath, ["-e", script], launchOptions);
|
|
3306
|
-
return retry.status === HEALTH_EXIT_OK;
|
|
3307
|
-
}
|
|
3308
|
-
|
|
3309
|
-
return false;
|
|
3310
|
-
} catch {
|
|
3311
|
-
return false;
|
|
3312
|
-
}
|
|
3313
|
-
}
|
|
3314
|
-
|
|
3315
3243
|
// ── Doctor ────────────────────────────────────────────────────────────────────
|
|
3316
3244
|
|
|
3317
3245
|
export async function doctorConnector(connectorId: string): Promise<DoctorResult> {
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { parseConfig } from "./config.js";
|
|
4
|
+
import { ExtractionEngine } from "./extraction.js";
|
|
5
|
+
|
|
6
|
+
type TestMessage = { role: "system" | "user" | "assistant"; content: string };
|
|
7
|
+
type TestOptions = { maxTokens?: number; signal?: AbortSignal };
|
|
8
|
+
|
|
9
|
+
const superseded = { id: "support-old", content: "The service uses port 4000." };
|
|
10
|
+
const replacement = { id: "support-new", content: "The service uses port 5000." };
|
|
11
|
+
const dependents = [{ id: "dependent", category: "fact", content: "Port 4000 must be open." }];
|
|
12
|
+
const response = {
|
|
13
|
+
content: JSON.stringify({
|
|
14
|
+
verdicts: [{ memoryId: "dependent", verdict: "invalidated", reason: "The port changed." }],
|
|
15
|
+
}),
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
function assertInvalidated(result: Awaited<ReturnType<ExtractionEngine["revalidateDependents"]>>): void {
|
|
19
|
+
assert.deepEqual(result, {
|
|
20
|
+
verdicts: [{ memoryId: "dependent", verdict: "invalidated", reason: "The port changed." }],
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
test("revalidation keeps the official OpenAI base URL on the Responses API", async () => {
|
|
25
|
+
const engine = new ExtractionEngine(
|
|
26
|
+
parseConfig({ openaiApiKey: "fixture-key", openaiBaseUrl: "https://api.openai.com/v1" }),
|
|
27
|
+
);
|
|
28
|
+
const signal = new AbortController().signal;
|
|
29
|
+
let calls = 0;
|
|
30
|
+
let request: Record<string, unknown> | undefined;
|
|
31
|
+
let requestOptions: { signal?: AbortSignal } | undefined;
|
|
32
|
+
Reflect.set(engine, "client", {
|
|
33
|
+
baseURL: "https://api.openai.com/v1",
|
|
34
|
+
responses: {
|
|
35
|
+
async create(body: Record<string, unknown>, options: { signal?: AbortSignal }) {
|
|
36
|
+
calls += 1;
|
|
37
|
+
request = body;
|
|
38
|
+
requestOptions = options;
|
|
39
|
+
return { output_text: response.content };
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
assertInvalidated(await engine.revalidateDependents(superseded, replacement, dependents, signal));
|
|
44
|
+
assert.equal(calls, 1);
|
|
45
|
+
assert.equal(request?.model, "gpt-5.5");
|
|
46
|
+
assert.equal(request?.max_output_tokens, 1024);
|
|
47
|
+
assert.match(String(request?.instructions), /revalidate dependent memory claims/i);
|
|
48
|
+
assert.match(String(request?.input), /SUPERSEDED MEMORY.*support-old/s);
|
|
49
|
+
assert.equal(requestOptions?.signal, signal);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("revalidation uses the client's effective custom base URL", async () => {
|
|
53
|
+
const engine = new ExtractionEngine(
|
|
54
|
+
parseConfig({
|
|
55
|
+
openaiApiKey: "fixture-key",
|
|
56
|
+
openaiBaseUrl: "https://api.openai.com/v1",
|
|
57
|
+
}),
|
|
58
|
+
);
|
|
59
|
+
const signal = new AbortController().signal;
|
|
60
|
+
let chatRequest: Record<string, unknown> | undefined;
|
|
61
|
+
let chatOptions: { signal?: AbortSignal } | undefined;
|
|
62
|
+
let responsesCalls = 0;
|
|
63
|
+
Reflect.set(engine, "client", {
|
|
64
|
+
baseURL: "https://inference.example.test/v1",
|
|
65
|
+
chat: {
|
|
66
|
+
completions: {
|
|
67
|
+
async create(body: Record<string, unknown>, options: { signal?: AbortSignal }) {
|
|
68
|
+
chatRequest = body;
|
|
69
|
+
chatOptions = options;
|
|
70
|
+
return { choices: [{ message: response }] };
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
responses: {
|
|
75
|
+
async create() {
|
|
76
|
+
responsesCalls += 1;
|
|
77
|
+
throw new Error("custom endpoint does not implement /responses");
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
assertInvalidated(await engine.revalidateDependents(superseded, replacement, dependents, signal));
|
|
83
|
+
assert.equal(responsesCalls, 0);
|
|
84
|
+
assert.equal(chatRequest?.model, "gpt-5.5");
|
|
85
|
+
assert.equal(chatRequest?.max_tokens, 1024);
|
|
86
|
+
assert.ok(Array.isArray(chatRequest?.messages));
|
|
87
|
+
assert.equal(chatOptions?.signal, signal);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("revalidation falls back to the direct route when the injected fast route rejects", async () => {
|
|
91
|
+
const engine = new ExtractionEngine(
|
|
92
|
+
parseConfig({ openaiApiKey: "fixture-key", openaiBaseUrl: "https://api.openai.com/v1" }),
|
|
93
|
+
undefined,
|
|
94
|
+
undefined,
|
|
95
|
+
undefined,
|
|
96
|
+
undefined,
|
|
97
|
+
async () => null,
|
|
98
|
+
);
|
|
99
|
+
const signal = new AbortController().signal;
|
|
100
|
+
let fastCalls = 0;
|
|
101
|
+
let directCalls = 0;
|
|
102
|
+
let fastMessages: TestMessage[] | undefined;
|
|
103
|
+
let fastOptions: TestOptions | undefined;
|
|
104
|
+
let request: Record<string, unknown> | undefined;
|
|
105
|
+
let requestOptions: { signal?: AbortSignal } | undefined;
|
|
106
|
+
Reflect.set(engine, "fastChatCompletion", async (messages: TestMessage[], options: TestOptions) => {
|
|
107
|
+
fastCalls += 1;
|
|
108
|
+
fastMessages = messages;
|
|
109
|
+
fastOptions = options;
|
|
110
|
+
throw new Error("fast route unavailable");
|
|
111
|
+
});
|
|
112
|
+
Reflect.set(engine, "client", {
|
|
113
|
+
baseURL: "https://api.openai.com/v1",
|
|
114
|
+
responses: {
|
|
115
|
+
async create(body: Record<string, unknown>, options: { signal?: AbortSignal }) {
|
|
116
|
+
directCalls += 1;
|
|
117
|
+
request = body;
|
|
118
|
+
requestOptions = options;
|
|
119
|
+
return { output_text: response.content };
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
assertInvalidated(await engine.revalidateDependents(superseded, replacement, dependents, signal));
|
|
125
|
+
assert.equal(fastCalls, 1);
|
|
126
|
+
assert.equal(directCalls, 1);
|
|
127
|
+
assert.equal(fastMessages?.[0]?.role, "system");
|
|
128
|
+
assert.match(fastMessages?.[1]?.content ?? "", /support-new/);
|
|
129
|
+
assert.equal(fastOptions?.maxTokens, 1024);
|
|
130
|
+
assert.equal(fastOptions?.signal, signal);
|
|
131
|
+
assert.equal(request?.max_output_tokens, 1024);
|
|
132
|
+
assert.equal(requestOptions?.signal, signal);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("revalidation preserves the gateway fallback route for the legacy constructor", async () => {
|
|
136
|
+
const engine = new ExtractionEngine(parseConfig({ modelSource: "gateway" }));
|
|
137
|
+
const signal = new AbortController().signal;
|
|
138
|
+
let fastCalls = 0;
|
|
139
|
+
let fallbackCalls = 0;
|
|
140
|
+
let fallbackMessages: TestMessage[] | undefined;
|
|
141
|
+
let fallbackOptions: TestOptions | undefined;
|
|
142
|
+
Reflect.set(engine, "fastChatCompletion", async () => {
|
|
143
|
+
fastCalls += 1;
|
|
144
|
+
return null;
|
|
145
|
+
});
|
|
146
|
+
Reflect.set(engine, "fallbackLlm", {
|
|
147
|
+
async chatCompletion(
|
|
148
|
+
messages: TestMessage[],
|
|
149
|
+
options: TestOptions,
|
|
150
|
+
) {
|
|
151
|
+
fallbackCalls += 1;
|
|
152
|
+
fallbackMessages = messages;
|
|
153
|
+
fallbackOptions = options;
|
|
154
|
+
return response;
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
assertInvalidated(await engine.revalidateDependents(superseded, replacement, dependents, signal));
|
|
159
|
+
assert.equal(fastCalls, 1);
|
|
160
|
+
assert.equal(fallbackCalls, 1);
|
|
161
|
+
assert.equal(fallbackMessages?.[0]?.role, "system");
|
|
162
|
+
assert.match(fallbackMessages?.[1]?.content ?? "", /dependent/);
|
|
163
|
+
assert.equal(fallbackOptions?.maxTokens, 1024);
|
|
164
|
+
assert.equal(fallbackOptions?.signal, signal);
|
|
165
|
+
});
|
package/src/extraction.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import OpenAI from "openai";
|
|
2
|
+
import { isAbortError } from "./abort-error.js";
|
|
2
3
|
import { log } from "./logger.js";
|
|
3
4
|
import { delinearize } from "./delinearize.js";
|
|
4
5
|
import { LocalLlmClient } from "./local-llm.js";
|
|
5
6
|
import { shouldRunProactivePass } from "./proactive-contention.js";
|
|
6
7
|
import { FallbackLlmClient, fallbackLlmRuntimeContextFromConfig, gatewayTaskChainOptions } from "./fallback-llm.js";
|
|
7
|
-
import { revalidateDependentsViaLlm } from "./orchestration/dependency-revalidation.js";
|
|
8
|
+
import { revalidateDependentsViaLlm, type RevalidationFastChatCompletion } from "./orchestration/dependency-revalidation.js";
|
|
8
9
|
import {
|
|
9
10
|
ExtractionResultSchema,
|
|
10
11
|
ConsolidationResultSchema,
|
|
@@ -79,7 +80,6 @@ const CONSOLIDATION_RESPONSE_SCHEMA = `{
|
|
|
79
80
|
"entityUpdates": [{"name": "person-jane-doe", "type": "person", "facts": ["Now leads the backend team", "Recently migrated the user service to TypeScript"]}]
|
|
80
81
|
}`;
|
|
81
82
|
|
|
82
|
-
|
|
83
83
|
function extractionEntityType(value: unknown): ExtractedEntityResult["type"] | undefined {
|
|
84
84
|
const type = extractionText(value);
|
|
85
85
|
if (
|
|
@@ -152,6 +152,7 @@ export class ExtractionEngine {
|
|
|
152
152
|
localLlm?: LocalLlmClient,
|
|
153
153
|
gatewayConfig?: GatewayConfig,
|
|
154
154
|
modelRegistry?: ModelRegistry,
|
|
155
|
+
private readonly fastChatCompletion?: RevalidationFastChatCompletion,
|
|
155
156
|
) {
|
|
156
157
|
this.profiler = profilerArg ?? new ProfilingCollector({ enabled: false, storageDir: "/tmp/engram-profiler-disabled", maxTraces: 0 });
|
|
157
158
|
if (config.openaiApiKey) {
|
|
@@ -186,26 +187,14 @@ export class ExtractionEngine {
|
|
|
186
187
|
}
|
|
187
188
|
}
|
|
188
189
|
|
|
189
|
-
/**
|
|
190
|
-
* Whether LLM calls should be routed through the gateway model chain
|
|
191
|
-
* instead of the plugin's own local/OpenAI clients.
|
|
192
|
-
*/
|
|
193
190
|
private get useGatewayModelSource(): boolean {
|
|
194
191
|
return this.config.modelSource === "gateway";
|
|
195
192
|
}
|
|
196
193
|
|
|
197
|
-
/**
|
|
198
|
-
* Whether the local LLM path should be attempted.
|
|
199
|
-
* Disabled when gateway model source is active (gateway chain replaces local).
|
|
200
|
-
*/
|
|
201
194
|
private get shouldUseLocalLlm(): boolean {
|
|
202
195
|
return resolveLocalLlmCapabilities(this.config).localLlm && !this.useGatewayModelSource;
|
|
203
196
|
}
|
|
204
197
|
|
|
205
|
-
/**
|
|
206
|
-
* Whether the direct OpenAI client should be used.
|
|
207
|
-
* Disabled when gateway model source is active.
|
|
208
|
-
*/
|
|
209
198
|
private get shouldUseDirectClient(): boolean {
|
|
210
199
|
return !this.useGatewayModelSource && this.client !== null;
|
|
211
200
|
}
|
|
@@ -2453,29 +2442,55 @@ Respond with valid JSON matching this schema:
|
|
|
2453
2442
|
reason?: string;
|
|
2454
2443
|
}>;
|
|
2455
2444
|
}> {
|
|
2445
|
+
const complete: RevalidationFastChatCompletion = async (messages, options) => {
|
|
2446
|
+
try {
|
|
2447
|
+
const fast = await this.fastChatCompletion?.(messages, options);
|
|
2448
|
+
if (fast) return fast;
|
|
2449
|
+
} catch (error) {
|
|
2450
|
+
if (isAbortError(error) || options.signal?.aborted) throw error;
|
|
2451
|
+
log.warn(`dependency revalidation fast route failed: ${error}`);
|
|
2452
|
+
}
|
|
2453
|
+
if (this.shouldUseLocalLlm) {
|
|
2454
|
+
try {
|
|
2455
|
+
const local = await this.localLlm.chatCompletion(messages, options);
|
|
2456
|
+
if (local || !this.config.localLlmFallback) return local;
|
|
2457
|
+
} catch (error) {
|
|
2458
|
+
if (!this.config.localLlmFallback) throw error;
|
|
2459
|
+
}
|
|
2460
|
+
}
|
|
2461
|
+
if (!this.shouldUseDirectClient) {
|
|
2462
|
+
return this.fallbackLlm.chatCompletion(messages, this.withGatewayAgent(options));
|
|
2463
|
+
}
|
|
2464
|
+
const client = this.client;
|
|
2465
|
+
if (!client) return null;
|
|
2466
|
+
if (!shouldAssumeOpenAiChatCompletions(client.baseURL ?? this.config.openaiBaseUrl)) {
|
|
2467
|
+
const response = await client.chat.completions.create(
|
|
2468
|
+
{
|
|
2469
|
+
model: this.config.model,
|
|
2470
|
+
messages,
|
|
2471
|
+
max_tokens: options.maxTokens,
|
|
2472
|
+
},
|
|
2473
|
+
{ signal: options.signal },
|
|
2474
|
+
);
|
|
2475
|
+
const content = response.choices[0]?.message?.content;
|
|
2476
|
+
return typeof content === "string" ? { content } : null;
|
|
2477
|
+
}
|
|
2478
|
+
const response = await client.responses.create({
|
|
2479
|
+
model: this.config.model,
|
|
2480
|
+
instructions: messages.find((message) => message.role === "system")?.content,
|
|
2481
|
+
input: messages.filter((message) => message.role !== "system").map((message) => message.content).join("\n\n"),
|
|
2482
|
+
max_output_tokens: options.maxTokens,
|
|
2483
|
+
}, { signal: options.signal });
|
|
2484
|
+
return typeof response.output_text === "string" ? { content: response.output_text } : null;
|
|
2485
|
+
};
|
|
2456
2486
|
return revalidateDependentsViaLlm(
|
|
2457
|
-
{
|
|
2458
|
-
shouldUseLocalLlm: this.shouldUseLocalLlm,
|
|
2459
|
-
shouldUseDirectClient: this.shouldUseDirectClient,
|
|
2460
|
-
localLlm: this.localLlm,
|
|
2461
|
-
fallbackLlm: this.fallbackLlm,
|
|
2462
|
-
client: this.client,
|
|
2463
|
-
config: this.config,
|
|
2464
|
-
withGatewayAgent: this.withGatewayAgent.bind(this),
|
|
2465
|
-
parseJsonObject: this.parseJsonObject,
|
|
2466
|
-
},
|
|
2487
|
+
{ fastChatCompletion: complete, parseJsonObject: this.parseJsonObject },
|
|
2467
2488
|
superseded,
|
|
2468
2489
|
replacement,
|
|
2469
2490
|
dependents,
|
|
2470
|
-
signal,
|
|
2491
|
+
{ signal, timeoutMs: this.config.dependencyPropagation.timeoutMs },
|
|
2471
2492
|
);
|
|
2472
2493
|
}
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
/**
|
|
2476
|
-
* Suggest links between a new memory and existing memories (Phase 3A).
|
|
2477
|
-
* Called during extraction to build the knowledge graph.
|
|
2478
|
-
*/
|
|
2479
2494
|
async suggestLinks(
|
|
2480
2495
|
newMemory: { content: string; category: string },
|
|
2481
2496
|
candidateMemories: Array<{ id: string; content: string; category: string }>,
|