@remnic/core 10.0.90 → 10.0.92
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.js +92 -92
- package/dist/access-authorization-probe.js +93 -93
- package/dist/access-boundary.js +92 -92
- package/dist/access-cli.js +200 -199
- package/dist/access-cli.js.map +1 -1
- package/dist/access-extraction-force-flush.js +92 -92
- package/dist/access-http-admission.d.ts +14 -0
- package/dist/access-http-admission.d.ts.map +1 -0
- package/dist/access-http-admission.js +9 -0
- package/dist/access-http-briefing.js +93 -93
- package/dist/access-http-query.js +94 -94
- package/dist/access-http-types.d.ts +145 -0
- package/dist/access-http-types.d.ts.map +1 -0
- package/dist/access-http-types.js +1 -0
- package/dist/access-http.d.ts +3 -142
- package/dist/access-http.d.ts.map +1 -1
- package/dist/access-http.js +121 -120
- package/dist/access-identity-continuity-surface.js +92 -92
- package/dist/access-lcm-surface.js +92 -92
- package/dist/access-mcp.d.ts.map +1 -1
- package/dist/access-mcp.js +108 -108
- package/dist/access-namespace-preflight.js +92 -92
- package/dist/access-observe-write-category.js +12 -12
- package/dist/access-observe-write-surface.js +92 -92
- package/dist/access-offline-manifest.js +17 -17
- package/dist/access-operations-batch.js +96 -96
- package/dist/access-operations.js +103 -103
- package/dist/access-recall-concurrency.js +92 -92
- package/dist/access-recall-diagnostics.js +7 -7
- package/dist/access-recall-response.js +92 -92
- package/dist/access-recall-surface.js +92 -92
- package/dist/access-schema.js +8 -8
- package/dist/access-service.d.ts +1 -0
- package/dist/access-service.d.ts.map +1 -1
- package/dist/access-service.js +92 -92
- package/dist/access-surface-catalog.js +94 -94
- package/dist/active-memory-bridge.js +6 -6
- package/dist/active-recall.js +43 -43
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/auto-sync-3AZW7MXI.js +3 -3
- package/dist/briefing.js +31 -31
- package/dist/buffer-admission.d.ts +9 -0
- package/dist/buffer-admission.d.ts.map +1 -1
- package/dist/buffer-admission.js +3 -1
- package/dist/buffer.js +14 -14
- package/dist/calibration.js +5 -5
- package/dist/causal-behavior.js +2 -2
- package/dist/causal-chain.js +2 -2
- package/dist/causal-consolidation.js +36 -36
- package/dist/causal-retrieval.js +2 -2
- package/dist/causal-trajectory-graph.js +2 -2
- package/dist/causal-trajectory.js +1 -1
- package/dist/{chunk-4XYAWK5H.js → chunk-25BUV3TU.js} +2 -2
- package/dist/{chunk-QKES7GU6.js → chunk-2FGLEF7C.js} +2 -2
- package/dist/{chunk-3NF4QUNZ.js → chunk-2JSDPUKD.js} +5 -5
- package/dist/{chunk-AJHNXIQU.js → chunk-2LCRG2YV.js} +2 -2
- package/dist/{chunk-YRZPBN46.js → chunk-3RLK65ZK.js} +2 -2
- package/dist/{chunk-V4XE263I.js → chunk-43AA5FVD.js} +1 -1
- package/dist/chunk-43AA5FVD.js.map +1 -0
- package/dist/{chunk-GCBIXUPT.js → chunk-47F6WWLQ.js} +2 -2
- package/dist/{chunk-TSS3D7ZY.js → chunk-4CJTQHEG.js} +3 -3
- package/dist/{chunk-QD5R6U5J.js → chunk-4J363OAA.js} +2 -2
- package/dist/{chunk-C2HORX76.js → chunk-4WR2OD7K.js} +2 -2
- package/dist/{chunk-4X7HQKAG.js → chunk-4XINO77L.js} +2 -2
- package/dist/{chunk-OXQ7F45O.js → chunk-5HFXGXE5.js} +6 -6
- package/dist/{chunk-ELHJK7LM.js → chunk-5IYOKDM4.js} +12 -12
- package/dist/{chunk-LEEAO2TX.js → chunk-5M5M22GW.js} +3 -3
- package/dist/{chunk-52II7PB6.js → chunk-645WOU5I.js} +4 -4
- package/dist/{chunk-QEZ3DW5O.js → chunk-65AUYLU3.js} +5 -5
- package/dist/{chunk-B56LORLY.js → chunk-6F42QONS.js} +2 -2
- package/dist/{chunk-ADYP7HXE.js → chunk-6F5MJFXY.js} +3 -3
- package/dist/{chunk-GOZXQNIM.js → chunk-6P7U3HWG.js} +3 -3
- package/dist/{chunk-SBRUTD5O.js → chunk-6SRYCJ5I.js} +10 -10
- package/dist/{chunk-JM2YZKCQ.js → chunk-7GLJMDEQ.js} +6 -6
- package/dist/{chunk-BLSHFIR6.js → chunk-7HTUYFR3.js} +5 -5
- package/dist/{chunk-SYKJBS7S.js → chunk-7W3RXOIG.js} +24 -24
- package/dist/{chunk-J6GZ2254.js → chunk-AL3TCNSJ.js} +4 -4
- package/dist/{chunk-BIVKPQ6Q.js → chunk-AP6NCP3V.js} +8 -8
- package/dist/{chunk-32YX7EJ3.js → chunk-ATPWZ4F7.js} +13 -13
- package/dist/{chunk-4GMI5HFH.js → chunk-B4QYQFGY.js} +26 -23
- package/dist/chunk-B4QYQFGY.js.map +1 -0
- package/dist/{chunk-HXFIILGF.js → chunk-BFPF5N3H.js} +4 -4
- package/dist/{chunk-LHGPU6DQ.js → chunk-BJRTMNCB.js} +6 -6
- package/dist/{chunk-F74G4KIH.js → chunk-BLJT6JP2.js} +2 -2
- package/dist/{chunk-3TKX2RYK.js → chunk-BQZEGOZ4.js} +2 -2
- package/dist/{chunk-HLN2HOXX.js → chunk-BRLXOZLM.js} +6 -6
- package/dist/{chunk-5UBXIV3N.js → chunk-BSACVS6R.js} +14 -14
- package/dist/{chunk-4Q26RNSR.js → chunk-CD4BCCNP.js} +2 -2
- package/dist/{chunk-5SOSQTVE.js → chunk-CIEEYVUB.js} +2 -2
- package/dist/{chunk-SO4DZIVF.js → chunk-DKAA2IHQ.js} +38 -36
- package/dist/chunk-DKAA2IHQ.js.map +1 -0
- package/dist/{chunk-G54BOKZ6.js → chunk-E3A7ELSG.js} +9 -9
- package/dist/{chunk-OL553AWT.js → chunk-E4IRW2FG.js} +12 -12
- package/dist/{chunk-TFEHSPGQ.js → chunk-E5PPE4VA.js} +4 -4
- package/dist/{chunk-3UZ2VMKD.js → chunk-E6M225BJ.js} +6 -6
- package/dist/{chunk-TIGYOZBU.js → chunk-E6Z4FBX6.js} +4 -4
- package/dist/{chunk-2XOFVTTT.js → chunk-E7YZXWIS.js} +2 -2
- package/dist/{chunk-QKERFEJS.js → chunk-EFYN5I7Z.js} +2 -2
- package/dist/{chunk-M3BEJJNV.js → chunk-ENQCH3SW.js} +8 -1
- package/dist/chunk-ENQCH3SW.js.map +1 -0
- package/dist/{chunk-D5EV6Y2L.js → chunk-ETZLQOUR.js} +2 -2
- package/dist/{chunk-IBDWYRDR.js → chunk-EXHXJETE.js} +2 -2
- package/dist/{chunk-APYY5CX3.js → chunk-F55YQP7N.js} +5 -4
- package/dist/chunk-F55YQP7N.js.map +1 -0
- package/dist/{chunk-S45INSV3.js → chunk-FF6N7BXC.js} +4 -4
- package/dist/{chunk-N7EKND7S.js → chunk-FLRP63GU.js} +175 -173
- package/dist/chunk-FLRP63GU.js.map +1 -0
- package/dist/{chunk-77PDJ4OE.js → chunk-FNXQZGUS.js} +2 -2
- package/dist/{chunk-H3WAT6BR.js → chunk-FQKBJJYB.js} +2 -2
- package/dist/{chunk-CC4V7HNP.js → chunk-FSO3G4JJ.js} +53 -53
- package/dist/{chunk-ZOJUWVAU.js → chunk-GKL6QYZO.js} +1 -1
- package/dist/{chunk-2U4LMSEX.js → chunk-GVGAO3WV.js} +3 -3
- package/dist/{chunk-DT7SNJH6.js → chunk-HF3BKUVV.js} +4 -4
- package/dist/{chunk-TRMZHGIX.js → chunk-HH5LY6RR.js} +15 -15
- package/dist/{chunk-Q5XJYCFE.js → chunk-HVX4LPNY.js} +2 -2
- package/dist/chunk-I3V3JJS7.js +24 -0
- package/dist/chunk-I3V3JJS7.js.map +1 -0
- package/dist/{chunk-5MF6LMUY.js → chunk-ID6JGIMD.js} +2 -2
- package/dist/{chunk-YLTU2DC4.js → chunk-IHCXMYSE.js} +2 -2
- package/dist/{chunk-2G4TV2ML.js → chunk-IPT2OY4B.js} +4 -4
- package/dist/{chunk-ZANNIXXE.js → chunk-IQMDQJCD.js} +3 -3
- package/dist/{chunk-S7GJNA3K.js → chunk-IQWUACVG.js} +2 -2
- package/dist/{chunk-QNSZYTSG.js → chunk-ITHZFHST.js} +2 -2
- package/dist/{chunk-QUMKDRCF.js → chunk-JDY34KBL.js} +4 -4
- package/dist/{chunk-2N4OUSIA.js → chunk-JV4S6VDH.js} +2 -2
- package/dist/{chunk-7LCGFUMB.js → chunk-KQAFEZQX.js} +4 -4
- package/dist/{chunk-ARRTLPRC.js → chunk-LUJCQQ3L.js} +3 -3
- package/dist/{chunk-DC55RIEZ.js → chunk-M4IEZGCK.js} +4 -4
- package/dist/{chunk-TNW6BOMM.js → chunk-MB6ZJDN6.js} +2 -2
- package/dist/{chunk-GGRRF4PZ.js → chunk-MDPT6QFK.js} +1 -1
- package/dist/{chunk-GGRRF4PZ.js.map → chunk-MDPT6QFK.js.map} +1 -1
- package/dist/{chunk-UWRHHRDK.js → chunk-MKRYQROF.js} +5 -5
- package/dist/{chunk-P452SEKO.js → chunk-MXHMNKWG.js} +2 -2
- package/dist/{chunk-IPD5GC7C.js → chunk-N4KAE2NB.js} +2 -2
- package/dist/{chunk-BCCG7VWM.js → chunk-NBH6K6G5.js} +63 -9
- package/dist/chunk-NBH6K6G5.js.map +1 -0
- package/dist/{chunk-25Q52SOT.js → chunk-NTRUKAAE.js} +3 -3
- package/dist/{chunk-3DAWHP5K.js → chunk-NZSRRVJQ.js} +5 -5
- package/dist/{chunk-ROGO7FRA.js → chunk-O55EKIEC.js} +2 -2
- package/dist/{chunk-J5WI4QRP.js → chunk-OIGJZHDU.js} +4 -4
- package/dist/{chunk-K3FH3LAQ.js → chunk-OJXK5C6Z.js} +4 -4
- package/dist/{chunk-EA2LA5RI.js → chunk-P4WNBSTW.js} +2 -2
- package/dist/{chunk-EURPSF4Y.js → chunk-PH5ZQM35.js} +2 -2
- package/dist/{chunk-3ICAWZUU.js → chunk-PLCYKAWH.js} +4 -4
- package/dist/{chunk-3Y5X6YFH.js → chunk-PMJFRDJI.js} +2 -2
- package/dist/{chunk-PDOOUXCS.js → chunk-PPCLZ4JU.js} +2 -2
- package/dist/{chunk-VKILERSL.js → chunk-PWXPRVLK.js} +2 -2
- package/dist/{chunk-G6HWNPZA.js → chunk-QJPJXCS4.js} +2 -2
- package/dist/{chunk-YMJRLT7S.js → chunk-R2DOFBG4.js} +3 -3
- package/dist/{chunk-PKZ274PI.js → chunk-R2LBF4HH.js} +3 -3
- package/dist/{chunk-NQP4ZYGG.js → chunk-RGUUBAT5.js} +3 -3
- package/dist/{chunk-EWJZZDRG.js → chunk-RHQLIHMB.js} +2 -2
- package/dist/{chunk-CYCEROPR.js → chunk-RIMK327Y.js} +7 -7
- package/dist/{chunk-P4JED3ZL.js → chunk-RMXS4I66.js} +2 -2
- package/dist/{chunk-TX6EHB2Q.js → chunk-RRJBDXAQ.js} +2 -2
- package/dist/{chunk-MTTYIXSU.js → chunk-RRTVGD3J.js} +9 -9
- package/dist/{chunk-OZNBZJ3S.js → chunk-SLDRXK37.js} +8 -8
- package/dist/{chunk-NIVKG3DS.js → chunk-SUSW74WU.js} +6 -6
- package/dist/{chunk-G67EUQAB.js → chunk-TG3R2SID.js} +4 -4
- package/dist/{chunk-3PJEDHLD.js → chunk-U6UNF5ZS.js} +3 -3
- package/dist/{chunk-YAVIBVCU.js → chunk-UA2NDTIU.js} +4 -4
- package/dist/{chunk-KVSOEVAF.js → chunk-UE6RRXMF.js} +2 -2
- package/dist/{chunk-TAUHAP5J.js → chunk-UXPXOVJI.js} +9 -9
- package/dist/{chunk-KZSGBWOJ.js → chunk-V2KGDESV.js} +2 -2
- package/dist/{chunk-UH3FPX3L.js → chunk-W7K5BP3M.js} +2 -2
- package/dist/{chunk-TQ4SCPGQ.js → chunk-WRT7GJ2D.js} +3 -3
- package/dist/{chunk-IHJZSRDM.js → chunk-X562NQFA.js} +90 -89
- package/dist/chunk-X562NQFA.js.map +1 -0
- package/dist/{chunk-M5O2ANZD.js → chunk-XDSCJOH7.js} +24 -22
- package/dist/chunk-XDSCJOH7.js.map +1 -0
- package/dist/{chunk-CN7Q3T2J.js → chunk-XNI3URDR.js} +2 -2
- package/dist/{chunk-7O2MC42R.js → chunk-XNRLRNQF.js} +2 -2
- package/dist/{chunk-64S6X4IU.js → chunk-XTN54NML.js} +4 -4
- package/dist/{chunk-ZBFLV657.js → chunk-XYKBWTWI.js} +2 -2
- package/dist/{chunk-PWPIERBM.js → chunk-YCNIGRRF.js} +4 -4
- package/dist/{chunk-EZ25VE3G.js → chunk-YNDLCWXS.js} +4 -4
- package/dist/{chunk-DZ7DPDVW.js → chunk-YODUDA6R.js} +15 -15
- package/dist/{chunk-2K3AUDH7.js → chunk-YYOMGOHB.js} +4 -4
- package/dist/{chunk-ROKDHO74.js → chunk-Z7JIZ42P.js} +4 -4
- package/dist/{chunk-ATWFYXEN.js → chunk-ZTTCDQ4I.js} +146 -143
- package/dist/chunk-ZTTCDQ4I.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +154 -153
- package/dist/coding/export-okf-codegraph.js +30 -30
- package/dist/coding/pre-action-gate.js +2 -2
- package/dist/compounding/engine.js +32 -32
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +43 -43
- package/dist/connectors/codex-materialize-runner.js +33 -33
- package/dist/connectors/codex-materialize.js +2 -2
- package/dist/connectors/index.js +36 -36
- package/dist/connectors/live/framework.d.ts +7 -0
- package/dist/connectors/live/framework.d.ts.map +1 -1
- package/dist/connectors/live/google-drive.d.ts +15 -3
- package/dist/connectors/live/google-drive.d.ts.map +1 -1
- package/dist/consolidation-provenance-check.js +2 -2
- package/dist/contradiction/index.js +6 -6
- package/dist/{contradiction-scan-P7KXB5R4.js → contradiction-scan-P2MHYFVG.js} +5 -5
- package/dist/convergence-refresh.js +33 -33
- package/dist/corpus-watermark.js +33 -33
- package/dist/dashboard-runtime.js +2 -2
- package/dist/deep-recall-http-glue.js +9 -9
- package/dist/deep-recall.js +2 -2
- package/dist/embedding-fallback.js +3 -3
- package/dist/entity-retrieval.js +32 -32
- package/dist/event-order-recall.js +3 -3
- package/dist/explicit-capture.js +10 -10
- package/dist/external-wiki-access.js +93 -93
- package/dist/extraction-evidence-class.js +2 -2
- package/dist/extraction-normalization.js +1 -1
- package/dist/extraction-source-grounding.js +3 -3
- package/dist/extraction.js +47 -47
- package/dist/{first-start-migration-A6PHIBUQ.js → first-start-migration-QFI7B5SH.js} +7 -7
- package/dist/{graph-edge-decay-EKWXRBWF.js → graph-edge-decay-OEX5OGMI.js} +6 -6
- package/dist/graph-jsonl.js +3 -3
- package/dist/graph-snapshot.js +3 -3
- package/dist/graph.js +2 -2
- package/dist/harmonic-retrieval.js +30 -30
- package/dist/index.js +309 -308
- package/dist/lcm/engine.js +3 -3
- package/dist/lcm/index.js +8 -8
- package/dist/live-connectors-runner.d.ts +2 -0
- package/dist/live-connectors-runner.d.ts.map +1 -1
- package/dist/live-connectors-runner.js +3 -3
- package/dist/local-llm-config.js +1 -1
- package/dist/local-llm.js +2 -2
- package/dist/location/index.js +33 -33
- package/dist/maintenance/memory-governance.js +31 -31
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +30 -30
- package/dist/maintenance/rebuild-memory-projection-runner.js +33 -33
- package/dist/maintenance/rebuild-memory-projection.js +32 -32
- package/dist/memory-browse-operations.js +93 -93
- package/dist/memory-browse.js +10 -10
- package/dist/memory-subject.js +1 -1
- package/dist/namespaces/migrate.js +32 -32
- package/dist/namespaces/search.js +7 -7
- package/dist/namespaces/storage.js +31 -31
- package/dist/offline-sync-changeset-generations.js +4 -4
- package/dist/offline-sync-embedding-generation.js +3 -3
- package/dist/offline-sync-impression-drain.js +3 -3
- package/dist/offline-sync-snapshot-stream.js +6 -6
- package/dist/offline-sync.js +7 -7
- package/dist/operator-doctor-corpus.js +34 -34
- package/dist/operator-toolkit.js +58 -58
- package/dist/orchestration/backlog-scheduler.js +201 -200
- package/dist/orchestration/backlog-scheduler.js.map +1 -1
- package/dist/orchestration/buffer-drain-runner.js +201 -200
- package/dist/orchestration/maintenance.js +48 -48
- package/dist/orchestration/turn-ingestion.d.ts +2 -2
- package/dist/orchestration/turn-ingestion.d.ts.map +1 -1
- package/dist/orchestrator.d.ts +2 -0
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +201 -200
- package/dist/provenance.js +2 -2
- package/dist/qmd.js +6 -6
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-navigate-access.js +2 -2
- package/dist/recall-navigate-disclosure.js +2 -2
- package/dist/recall-navigate.js +2 -2
- package/dist/recall-navigation-operations.js +93 -93
- package/dist/recall-navigation.js +92 -92
- package/dist/recall-state-view-admission.js +7 -7
- package/dist/recall-why-service.js +14 -14
- package/dist/recall-why.js +5 -5
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.js +2 -2
- package/dist/reconcile/cursor.js +2 -2
- package/dist/reconcile/manifest.js +6 -6
- package/dist/reconcile/plan.js +2 -2
- package/dist/{resolution-23ZBDM6A.js → resolution-N7H3F2E4.js} +7 -7
- package/dist/resolution-N7H3F2E4.js.map +1 -0
- package/dist/resume-bundles.js +45 -45
- package/dist/salvage-envelope.js +1 -1
- package/dist/search/factory.js +6 -6
- package/dist/search/index.js +10 -10
- package/dist/semantic-consolidation.js +39 -39
- package/dist/semantic-rule-promotion.js +30 -30
- package/dist/semantic-rule-verifier.js +30 -30
- package/dist/source-agent-qualifier.js +43 -43
- package/dist/standup/build.js +30 -30
- package/dist/{state-store-I5HLZTZT.js → state-store-EEAX2MBS.js} +2 -2
- package/dist/state-store-EEAX2MBS.js.map +1 -0
- package/dist/storage.js +29 -29
- package/dist/subject-config.js +1 -1
- package/dist/summarizer.js +5 -5
- package/dist/support-passport/index.js +108 -108
- package/dist/tier-routing.js +3 -3
- package/dist/{tier-stats-C3IAMS4X.js → tier-stats-FQGQSFET.js} +7 -7
- package/dist/transfer/capsule-export.js +2 -2
- package/dist/transfer/capsule-import.js +2 -2
- package/dist/transfer/export-okf.js +30 -30
- package/dist/types.d.ts +10 -10
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/dist/verified-recall.js +30 -30
- package/dist/who-knows-cli.js +31 -31
- package/dist/who-knows.js +30 -30
- package/dist/write-envelope.js +1 -1
- package/package.json +2 -2
- package/src/access-http-admission.ts +33 -0
- package/src/access-http-types.ts +153 -0
- package/src/access-http.test.ts +63 -1
- package/src/access-http.ts +26 -148
- package/src/access-mcp.test.ts +24 -0
- package/src/access-mcp.ts +3 -0
- package/src/access-observe-replay-durability.test.ts +4 -1
- package/src/access-service-observe-idempotency.test.ts +44 -0
- package/src/access-service.ts +3 -0
- package/src/buffer-admission.ts +13 -0
- package/src/cli.ts +1 -2
- package/src/config.test.ts +17 -0
- package/src/config.ts +25 -7
- package/src/connectors/live/framework.ts +8 -0
- package/src/connectors/live/google-drive.test.ts +35 -0
- package/src/connectors/live/google-drive.ts +108 -10
- package/src/live-connectors-runner.ts +3 -0
- package/src/live-connectors-secretref.test.ts +126 -0
- package/src/orchestration/turn-ingestion.ts +3 -3
- package/src/orchestrator.ts +5 -5
- package/src/types.ts +10 -10
- package/dist/chunk-4GMI5HFH.js.map +0 -1
- package/dist/chunk-APYY5CX3.js.map +0 -1
- package/dist/chunk-ATWFYXEN.js.map +0 -1
- package/dist/chunk-BCCG7VWM.js.map +0 -1
- package/dist/chunk-IHJZSRDM.js.map +0 -1
- package/dist/chunk-M3BEJJNV.js.map +0 -1
- package/dist/chunk-M5O2ANZD.js.map +0 -1
- package/dist/chunk-N7EKND7S.js.map +0 -1
- package/dist/chunk-SO4DZIVF.js.map +0 -1
- package/dist/chunk-V4XE263I.js.map +0 -1
- /package/dist/{contradiction-scan-P7KXB5R4.js.map → access-http-admission.js.map} +0 -0
- /package/dist/{graph-edge-decay-EKWXRBWF.js.map → access-http-types.js.map} +0 -0
- /package/dist/{chunk-4XYAWK5H.js.map → chunk-25BUV3TU.js.map} +0 -0
- /package/dist/{chunk-QKES7GU6.js.map → chunk-2FGLEF7C.js.map} +0 -0
- /package/dist/{chunk-3NF4QUNZ.js.map → chunk-2JSDPUKD.js.map} +0 -0
- /package/dist/{chunk-AJHNXIQU.js.map → chunk-2LCRG2YV.js.map} +0 -0
- /package/dist/{chunk-YRZPBN46.js.map → chunk-3RLK65ZK.js.map} +0 -0
- /package/dist/{chunk-GCBIXUPT.js.map → chunk-47F6WWLQ.js.map} +0 -0
- /package/dist/{chunk-TSS3D7ZY.js.map → chunk-4CJTQHEG.js.map} +0 -0
- /package/dist/{chunk-QD5R6U5J.js.map → chunk-4J363OAA.js.map} +0 -0
- /package/dist/{chunk-C2HORX76.js.map → chunk-4WR2OD7K.js.map} +0 -0
- /package/dist/{chunk-4X7HQKAG.js.map → chunk-4XINO77L.js.map} +0 -0
- /package/dist/{chunk-OXQ7F45O.js.map → chunk-5HFXGXE5.js.map} +0 -0
- /package/dist/{chunk-ELHJK7LM.js.map → chunk-5IYOKDM4.js.map} +0 -0
- /package/dist/{chunk-LEEAO2TX.js.map → chunk-5M5M22GW.js.map} +0 -0
- /package/dist/{chunk-52II7PB6.js.map → chunk-645WOU5I.js.map} +0 -0
- /package/dist/{chunk-QEZ3DW5O.js.map → chunk-65AUYLU3.js.map} +0 -0
- /package/dist/{chunk-B56LORLY.js.map → chunk-6F42QONS.js.map} +0 -0
- /package/dist/{chunk-ADYP7HXE.js.map → chunk-6F5MJFXY.js.map} +0 -0
- /package/dist/{chunk-GOZXQNIM.js.map → chunk-6P7U3HWG.js.map} +0 -0
- /package/dist/{chunk-SBRUTD5O.js.map → chunk-6SRYCJ5I.js.map} +0 -0
- /package/dist/{chunk-JM2YZKCQ.js.map → chunk-7GLJMDEQ.js.map} +0 -0
- /package/dist/{chunk-BLSHFIR6.js.map → chunk-7HTUYFR3.js.map} +0 -0
- /package/dist/{chunk-SYKJBS7S.js.map → chunk-7W3RXOIG.js.map} +0 -0
- /package/dist/{chunk-J6GZ2254.js.map → chunk-AL3TCNSJ.js.map} +0 -0
- /package/dist/{chunk-BIVKPQ6Q.js.map → chunk-AP6NCP3V.js.map} +0 -0
- /package/dist/{chunk-32YX7EJ3.js.map → chunk-ATPWZ4F7.js.map} +0 -0
- /package/dist/{chunk-HXFIILGF.js.map → chunk-BFPF5N3H.js.map} +0 -0
- /package/dist/{chunk-LHGPU6DQ.js.map → chunk-BJRTMNCB.js.map} +0 -0
- /package/dist/{chunk-F74G4KIH.js.map → chunk-BLJT6JP2.js.map} +0 -0
- /package/dist/{chunk-3TKX2RYK.js.map → chunk-BQZEGOZ4.js.map} +0 -0
- /package/dist/{chunk-HLN2HOXX.js.map → chunk-BRLXOZLM.js.map} +0 -0
- /package/dist/{chunk-5UBXIV3N.js.map → chunk-BSACVS6R.js.map} +0 -0
- /package/dist/{chunk-4Q26RNSR.js.map → chunk-CD4BCCNP.js.map} +0 -0
- /package/dist/{chunk-5SOSQTVE.js.map → chunk-CIEEYVUB.js.map} +0 -0
- /package/dist/{chunk-G54BOKZ6.js.map → chunk-E3A7ELSG.js.map} +0 -0
- /package/dist/{chunk-OL553AWT.js.map → chunk-E4IRW2FG.js.map} +0 -0
- /package/dist/{chunk-TFEHSPGQ.js.map → chunk-E5PPE4VA.js.map} +0 -0
- /package/dist/{chunk-3UZ2VMKD.js.map → chunk-E6M225BJ.js.map} +0 -0
- /package/dist/{chunk-TIGYOZBU.js.map → chunk-E6Z4FBX6.js.map} +0 -0
- /package/dist/{chunk-2XOFVTTT.js.map → chunk-E7YZXWIS.js.map} +0 -0
- /package/dist/{chunk-QKERFEJS.js.map → chunk-EFYN5I7Z.js.map} +0 -0
- /package/dist/{chunk-D5EV6Y2L.js.map → chunk-ETZLQOUR.js.map} +0 -0
- /package/dist/{chunk-IBDWYRDR.js.map → chunk-EXHXJETE.js.map} +0 -0
- /package/dist/{chunk-S45INSV3.js.map → chunk-FF6N7BXC.js.map} +0 -0
- /package/dist/{chunk-77PDJ4OE.js.map → chunk-FNXQZGUS.js.map} +0 -0
- /package/dist/{chunk-H3WAT6BR.js.map → chunk-FQKBJJYB.js.map} +0 -0
- /package/dist/{chunk-CC4V7HNP.js.map → chunk-FSO3G4JJ.js.map} +0 -0
- /package/dist/{chunk-ZOJUWVAU.js.map → chunk-GKL6QYZO.js.map} +0 -0
- /package/dist/{chunk-2U4LMSEX.js.map → chunk-GVGAO3WV.js.map} +0 -0
- /package/dist/{chunk-DT7SNJH6.js.map → chunk-HF3BKUVV.js.map} +0 -0
- /package/dist/{chunk-TRMZHGIX.js.map → chunk-HH5LY6RR.js.map} +0 -0
- /package/dist/{chunk-Q5XJYCFE.js.map → chunk-HVX4LPNY.js.map} +0 -0
- /package/dist/{chunk-5MF6LMUY.js.map → chunk-ID6JGIMD.js.map} +0 -0
- /package/dist/{chunk-YLTU2DC4.js.map → chunk-IHCXMYSE.js.map} +0 -0
- /package/dist/{chunk-2G4TV2ML.js.map → chunk-IPT2OY4B.js.map} +0 -0
- /package/dist/{chunk-ZANNIXXE.js.map → chunk-IQMDQJCD.js.map} +0 -0
- /package/dist/{chunk-S7GJNA3K.js.map → chunk-IQWUACVG.js.map} +0 -0
- /package/dist/{chunk-QNSZYTSG.js.map → chunk-ITHZFHST.js.map} +0 -0
- /package/dist/{chunk-QUMKDRCF.js.map → chunk-JDY34KBL.js.map} +0 -0
- /package/dist/{chunk-2N4OUSIA.js.map → chunk-JV4S6VDH.js.map} +0 -0
- /package/dist/{chunk-7LCGFUMB.js.map → chunk-KQAFEZQX.js.map} +0 -0
- /package/dist/{chunk-ARRTLPRC.js.map → chunk-LUJCQQ3L.js.map} +0 -0
- /package/dist/{chunk-DC55RIEZ.js.map → chunk-M4IEZGCK.js.map} +0 -0
- /package/dist/{chunk-TNW6BOMM.js.map → chunk-MB6ZJDN6.js.map} +0 -0
- /package/dist/{chunk-UWRHHRDK.js.map → chunk-MKRYQROF.js.map} +0 -0
- /package/dist/{chunk-P452SEKO.js.map → chunk-MXHMNKWG.js.map} +0 -0
- /package/dist/{chunk-IPD5GC7C.js.map → chunk-N4KAE2NB.js.map} +0 -0
- /package/dist/{chunk-25Q52SOT.js.map → chunk-NTRUKAAE.js.map} +0 -0
- /package/dist/{chunk-3DAWHP5K.js.map → chunk-NZSRRVJQ.js.map} +0 -0
- /package/dist/{chunk-ROGO7FRA.js.map → chunk-O55EKIEC.js.map} +0 -0
- /package/dist/{chunk-J5WI4QRP.js.map → chunk-OIGJZHDU.js.map} +0 -0
- /package/dist/{chunk-K3FH3LAQ.js.map → chunk-OJXK5C6Z.js.map} +0 -0
- /package/dist/{chunk-EA2LA5RI.js.map → chunk-P4WNBSTW.js.map} +0 -0
- /package/dist/{chunk-EURPSF4Y.js.map → chunk-PH5ZQM35.js.map} +0 -0
- /package/dist/{chunk-3ICAWZUU.js.map → chunk-PLCYKAWH.js.map} +0 -0
- /package/dist/{chunk-3Y5X6YFH.js.map → chunk-PMJFRDJI.js.map} +0 -0
- /package/dist/{chunk-PDOOUXCS.js.map → chunk-PPCLZ4JU.js.map} +0 -0
- /package/dist/{chunk-VKILERSL.js.map → chunk-PWXPRVLK.js.map} +0 -0
- /package/dist/{chunk-G6HWNPZA.js.map → chunk-QJPJXCS4.js.map} +0 -0
- /package/dist/{chunk-YMJRLT7S.js.map → chunk-R2DOFBG4.js.map} +0 -0
- /package/dist/{chunk-PKZ274PI.js.map → chunk-R2LBF4HH.js.map} +0 -0
- /package/dist/{chunk-NQP4ZYGG.js.map → chunk-RGUUBAT5.js.map} +0 -0
- /package/dist/{chunk-EWJZZDRG.js.map → chunk-RHQLIHMB.js.map} +0 -0
- /package/dist/{chunk-CYCEROPR.js.map → chunk-RIMK327Y.js.map} +0 -0
- /package/dist/{chunk-P4JED3ZL.js.map → chunk-RMXS4I66.js.map} +0 -0
- /package/dist/{chunk-TX6EHB2Q.js.map → chunk-RRJBDXAQ.js.map} +0 -0
- /package/dist/{chunk-MTTYIXSU.js.map → chunk-RRTVGD3J.js.map} +0 -0
- /package/dist/{chunk-OZNBZJ3S.js.map → chunk-SLDRXK37.js.map} +0 -0
- /package/dist/{chunk-NIVKG3DS.js.map → chunk-SUSW74WU.js.map} +0 -0
- /package/dist/{chunk-G67EUQAB.js.map → chunk-TG3R2SID.js.map} +0 -0
- /package/dist/{chunk-3PJEDHLD.js.map → chunk-U6UNF5ZS.js.map} +0 -0
- /package/dist/{chunk-YAVIBVCU.js.map → chunk-UA2NDTIU.js.map} +0 -0
- /package/dist/{chunk-KVSOEVAF.js.map → chunk-UE6RRXMF.js.map} +0 -0
- /package/dist/{chunk-TAUHAP5J.js.map → chunk-UXPXOVJI.js.map} +0 -0
- /package/dist/{chunk-KZSGBWOJ.js.map → chunk-V2KGDESV.js.map} +0 -0
- /package/dist/{chunk-UH3FPX3L.js.map → chunk-W7K5BP3M.js.map} +0 -0
- /package/dist/{chunk-TQ4SCPGQ.js.map → chunk-WRT7GJ2D.js.map} +0 -0
- /package/dist/{chunk-CN7Q3T2J.js.map → chunk-XNI3URDR.js.map} +0 -0
- /package/dist/{chunk-7O2MC42R.js.map → chunk-XNRLRNQF.js.map} +0 -0
- /package/dist/{chunk-64S6X4IU.js.map → chunk-XTN54NML.js.map} +0 -0
- /package/dist/{chunk-ZBFLV657.js.map → chunk-XYKBWTWI.js.map} +0 -0
- /package/dist/{chunk-PWPIERBM.js.map → chunk-YCNIGRRF.js.map} +0 -0
- /package/dist/{chunk-EZ25VE3G.js.map → chunk-YNDLCWXS.js.map} +0 -0
- /package/dist/{chunk-DZ7DPDVW.js.map → chunk-YODUDA6R.js.map} +0 -0
- /package/dist/{chunk-2K3AUDH7.js.map → chunk-YYOMGOHB.js.map} +0 -0
- /package/dist/{chunk-ROKDHO74.js.map → chunk-Z7JIZ42P.js.map} +0 -0
- /package/dist/{resolution-23ZBDM6A.js.map → contradiction-scan-P2MHYFVG.js.map} +0 -0
- /package/dist/{first-start-migration-A6PHIBUQ.js.map → first-start-migration-QFI7B5SH.js.map} +0 -0
- /package/dist/{state-store-I5HLZTZT.js.map → graph-edge-decay-OEX5OGMI.js.map} +0 -0
- /package/dist/{tier-stats-C3IAMS4X.js.map → tier-stats-FQGQSFET.js.map} +0 -0
|
@@ -1600,7 +1600,10 @@ test("#3251 namespaced buffered admission without writeNamespaceOverride or plan
|
|
|
1600
1600
|
[makeReplayTurn("no-target-sess", "capture without target")],
|
|
1601
1601
|
bufferedObserveOptions({ sessionOwnerPrincipal: "alice" }),
|
|
1602
1602
|
),
|
|
1603
|
-
|
|
1603
|
+
(err: Error) =>
|
|
1604
|
+
err.name === "StorageTargetRequiredError" &&
|
|
1605
|
+
/requires an explicit storage target/.test(err.message),
|
|
1606
|
+
"the missing-target refusal must be its own non-retryable class, never ReplayAdmissionRefusedError",
|
|
1604
1607
|
);
|
|
1605
1608
|
assert.equal(lcmCalls.length, 0, "zero LCM archival on rejected admission");
|
|
1606
1609
|
assert.equal(queued.length, 0, "zero extraction queued on rejected admission");
|
|
@@ -22,6 +22,7 @@ import { EngramAccessService } from "./access-service.js";
|
|
|
22
22
|
import { EngramAccessInputError } from "./access-service.js";
|
|
23
23
|
import { initLogger } from "./logger.js";
|
|
24
24
|
import { Orchestrator } from "./orchestrator.js";
|
|
25
|
+
import { ReplayAdmissionRefusedError } from "./orchestration/turn-ingestion.js";
|
|
25
26
|
import type { EngramAccessObserveRequest } from "./access-service.js";
|
|
26
27
|
import type { CodingContext, PluginConfig } from "./types.js";
|
|
27
28
|
|
|
@@ -328,6 +329,49 @@ test("#2206 project-scope-off ignores ambient coding context in observe idempote
|
|
|
328
329
|
}
|
|
329
330
|
});
|
|
330
331
|
|
|
332
|
+
test("#1649 a capacity-refused observe does not consume its idempotencyKey", async () => {
|
|
333
|
+
const memoryDir = mkdtempSync(join(tmpdir(), "remnic-observe-cap-idem-"));
|
|
334
|
+
try {
|
|
335
|
+
const probe = makeObserveProbe(memoryDir);
|
|
336
|
+
const service = new EngramAccessService(probe.orch);
|
|
337
|
+
const orch: Orchestrator = probe.orch;
|
|
338
|
+
const realIngest = orch.ingestReplayBatch.bind(orch);
|
|
339
|
+
type IngestFn = Orchestrator["ingestReplayBatch"];
|
|
340
|
+
let armed = true;
|
|
341
|
+
orch.ingestReplayBatch = async (...args: Parameters<IngestFn>): Promise<void> => {
|
|
342
|
+
if (armed) {
|
|
343
|
+
armed = false;
|
|
344
|
+
throw new ReplayAdmissionRefusedError(
|
|
345
|
+
"durable observe capture refused: extraction buffer at entry capacity for batch containing pi-geek:abc123",
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
return realIngest(...args);
|
|
349
|
+
};
|
|
350
|
+
const key = "observe-capacity-pi-geek-abc123-#1";
|
|
351
|
+
|
|
352
|
+
// First attempt refuses at entry capacity — the key must stay unused.
|
|
353
|
+
await assert.rejects(
|
|
354
|
+
service.observe(observeRequest({ idempotencyKey: key })),
|
|
355
|
+
(err: Error) => err instanceof ReplayAdmissionRefusedError,
|
|
356
|
+
"the seeded first attempt must refuse with the capacity backpressure error",
|
|
357
|
+
);
|
|
358
|
+
assert.equal(probe.extractionCalls.length, 0, "refused attempt must not ingest");
|
|
359
|
+
|
|
360
|
+
// Identical retry, same key: a REAL miss once capacity exists, not a replay
|
|
361
|
+
// of a response that never happened.
|
|
362
|
+
const retry = await service.observe(observeRequest({ idempotencyKey: key }));
|
|
363
|
+
assert.equal(retry.idempotencyReplay, undefined, "refusal must not have cached a response");
|
|
364
|
+
assert.equal(probe.extractionCalls.length, 1, "retry is admitted exactly once");
|
|
365
|
+
|
|
366
|
+
// Third identical request replays — the success bound the key, not the refusal.
|
|
367
|
+
const replay = await service.observe(observeRequest({ idempotencyKey: key }));
|
|
368
|
+
assert.equal(replay.idempotencyReplay, true, "post-success identical request replays");
|
|
369
|
+
assert.equal(probe.extractionCalls.length, 1, "replay must not ingest again");
|
|
370
|
+
} finally {
|
|
371
|
+
rmSync(memoryDir, { recursive: true, force: true });
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
|
|
331
375
|
test("#1649 review fix: projectTag observe replays correctly despite scope resolution side effects", async () => {
|
|
332
376
|
// The fingerprint folds in the RESOLVED writeNamespace (not the raw ambient
|
|
333
377
|
// context). resolveMemoryScopePlan seeds the session context from projectTag
|
package/src/access-service.ts
CHANGED
|
@@ -1365,6 +1365,7 @@ export class EngramAccessService extends SupportPassportAccessServiceBase {
|
|
|
1365
1365
|
}
|
|
1366
1366
|
private readonly extractionLivenessWarn = new ExtractionLivenessWarnThrottle();
|
|
1367
1367
|
|
|
1368
|
+
private readonly secretRefResolver: ResolveSecretRefFn | null;
|
|
1368
1369
|
constructor(
|
|
1369
1370
|
private readonly orchestrator: Orchestrator,
|
|
1370
1371
|
options: {
|
|
@@ -1375,6 +1376,7 @@ export class EngramAccessService extends SupportPassportAccessServiceBase {
|
|
|
1375
1376
|
) {
|
|
1376
1377
|
super();
|
|
1377
1378
|
this.idempotency = new AccessIdempotencyStore(orchestrator.config.memoryDir);
|
|
1379
|
+
this.secretRefResolver = options.resolveSecretRef ?? null;
|
|
1378
1380
|
// Peer SecretRef tokens resolve at poll time through the host resolver, the
|
|
1379
1381
|
// same indirection as agentAccessHttp.authToken (review round 1). Absent a
|
|
1380
1382
|
// resolver, string/${ENV} tokens still work and a SecretRef degrades to a
|
|
@@ -3721,6 +3723,7 @@ export class EngramAccessService extends SupportPassportAccessServiceBase {
|
|
|
3721
3723
|
this.writableNamespaceFor(undefined, undefined, request.authenticatedPrincipal ?? principal);
|
|
3722
3724
|
return this.orchestrator.runLiveConnectors({
|
|
3723
3725
|
force: request.force === true,
|
|
3726
|
+
resolveSecretRef: this.secretRefResolver,
|
|
3724
3727
|
});
|
|
3725
3728
|
}
|
|
3726
3729
|
|
package/src/buffer-admission.ts
CHANGED
|
@@ -26,6 +26,19 @@ export class ReplayAdmissionRefusedError extends Error {
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Durable observe capture rejected because the request resolves to no storage
|
|
31
|
+
* target (namespaces ON with neither writeNamespaceOverride nor a plan's
|
|
32
|
+
* writeNamespace). A property of the request — retrying cannot fix it — so it
|
|
33
|
+
* must never be classified as retryable backpressure.
|
|
34
|
+
*/
|
|
35
|
+
export class StorageTargetRequiredError extends Error {
|
|
36
|
+
constructor(message: string) {
|
|
37
|
+
super(message);
|
|
38
|
+
this.name = "StorageTargetRequiredError";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
29
42
|
/**
|
|
30
43
|
* Live-admission bound (#1908 policy, backlog-safe): a NEW session enters
|
|
31
44
|
* only while under the cap or when an EMPTY entry can be reclaimed. Buffered
|
package/src/cli.ts
CHANGED
|
@@ -6107,8 +6107,7 @@ export function registerCli(
|
|
|
6107
6107
|
priorState: state,
|
|
6108
6108
|
syncFn: (cursor) =>
|
|
6109
6109
|
connector.syncIncremental({
|
|
6110
|
-
cursor,
|
|
6111
|
-
config: validatedCfg,
|
|
6110
|
+
cursor, config: validatedCfg, resolveSecretRef: hostSecretRefResolver(registerOptions),
|
|
6112
6111
|
}),
|
|
6113
6112
|
ingestFn: sharedIngestFn,
|
|
6114
6113
|
writeCursorFn: makeWriteCursorFn(name),
|
package/src/config.test.ts
CHANGED
|
@@ -1891,6 +1891,23 @@ test("parseConfig connectors.googleDrive accepts valid overrides", () => {
|
|
|
1891
1891
|
]);
|
|
1892
1892
|
});
|
|
1893
1893
|
|
|
1894
|
+
test("parseConfig connectors.googleDrive keeps a SecretRef credential verbatim", () => {
|
|
1895
|
+
const secretRef = { source: "keychain", id: "projects/drive-secret" };
|
|
1896
|
+
const result = parseConfig({
|
|
1897
|
+
openaiApiKey: "sk-test",
|
|
1898
|
+
connectors: {
|
|
1899
|
+
googleDrive: {
|
|
1900
|
+
enabled: true,
|
|
1901
|
+
clientId: "synthetic-client",
|
|
1902
|
+
clientSecret: secretRef,
|
|
1903
|
+
refreshToken: "synthetic-token",
|
|
1904
|
+
},
|
|
1905
|
+
},
|
|
1906
|
+
});
|
|
1907
|
+
assert.deepEqual(result.connectors.googleDrive.clientSecret, secretRef);
|
|
1908
|
+
assert.equal(result.connectors.googleDrive.clientId, "synthetic-client");
|
|
1909
|
+
});
|
|
1910
|
+
|
|
1894
1911
|
test("parseConfig rejects malformed connectors top-level", () => {
|
|
1895
1912
|
assert.throws(
|
|
1896
1913
|
() => parseConfig({ openaiApiKey: "sk-test", connectors: "nope" }),
|
package/src/config.ts
CHANGED
|
@@ -19,6 +19,7 @@ import type {
|
|
|
19
19
|
RecallSectionConfig,
|
|
20
20
|
ReasoningEffort,
|
|
21
21
|
SemanticChunkingConfigShape,
|
|
22
|
+
SecretRef,
|
|
22
23
|
SessionObserverBandConfig,
|
|
23
24
|
SlotBehaviorConfig,
|
|
24
25
|
SlotMismatchMode,
|
|
@@ -3719,16 +3720,33 @@ export function parseConfig(
|
|
|
3719
3720
|
? (rawConnectors.googleDrive as Record<string, unknown>)
|
|
3720
3721
|
: {};
|
|
3721
3722
|
const driveEnabled = coerceBool(rawDrive.enabled) === true;
|
|
3723
|
+
const driveClientIdRaw = rawDrive.clientId;
|
|
3724
|
+
// SAFETY: a string value is a string; an object with a string source is a SecretRef, kept verbatim.
|
|
3722
3725
|
const driveClientId =
|
|
3723
|
-
|
|
3726
|
+
Object.prototype.toString.call(driveClientIdRaw) === "[object String]"
|
|
3727
|
+
? (driveClientIdRaw as string)
|
|
3728
|
+
: Object.prototype.toString.call(driveClientIdRaw) === "[object Object]" &&
|
|
3729
|
+
Object.prototype.toString.call((driveClientIdRaw as { source?: object }).source) === "[object String]"
|
|
3730
|
+
? (driveClientIdRaw as SecretRef)
|
|
3731
|
+
: "";
|
|
3732
|
+
const driveClientSecretRaw = rawDrive[CLIENT_SECRET_FIELD];
|
|
3733
|
+
// SAFETY: a string value is a string; an object with a string source is a SecretRef, kept verbatim.
|
|
3724
3734
|
const driveClientSecret =
|
|
3725
|
-
|
|
3726
|
-
?
|
|
3727
|
-
: ""
|
|
3735
|
+
Object.prototype.toString.call(driveClientSecretRaw) === "[object String]"
|
|
3736
|
+
? (driveClientSecretRaw as string)
|
|
3737
|
+
: Object.prototype.toString.call(driveClientSecretRaw) === "[object Object]" &&
|
|
3738
|
+
Object.prototype.toString.call((driveClientSecretRaw as { source?: object }).source) === "[object String]"
|
|
3739
|
+
? (driveClientSecretRaw as SecretRef)
|
|
3740
|
+
: "";
|
|
3741
|
+
const driveRefreshTokenRaw = rawDrive[REFRESH_TOKEN_FIELD];
|
|
3742
|
+
// SAFETY: a string value is a string; an object with a string source is a SecretRef, kept verbatim.
|
|
3728
3743
|
const driveRefreshToken =
|
|
3729
|
-
|
|
3730
|
-
?
|
|
3731
|
-
: ""
|
|
3744
|
+
Object.prototype.toString.call(driveRefreshTokenRaw) === "[object String]"
|
|
3745
|
+
? (driveRefreshTokenRaw as string)
|
|
3746
|
+
: Object.prototype.toString.call(driveRefreshTokenRaw) === "[object Object]" &&
|
|
3747
|
+
Object.prototype.toString.call((driveRefreshTokenRaw as { source?: object }).source) === "[object String]"
|
|
3748
|
+
? (driveRefreshTokenRaw as SecretRef)
|
|
3749
|
+
: "";
|
|
3732
3750
|
const drivePollCoerced = coerceNumber(rawDrive.pollIntervalMs);
|
|
3733
3751
|
let drivePollIntervalMs = 300_000;
|
|
3734
3752
|
if (drivePollCoerced !== undefined) {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { ResolveSecretRefFn } from "../../resolve-auth-token.js";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* @remnic/core — Live Connectors Framework (issue #683 PR 1/N)
|
|
3
5
|
*
|
|
@@ -139,6 +141,12 @@ export interface SyncIncrementalArgs {
|
|
|
139
141
|
readonly config: ConnectorConfig;
|
|
140
142
|
/** Optional abort signal. Connectors SHOULD honor it for cooperative cancellation. */
|
|
141
143
|
readonly abortSignal?: AbortSignal;
|
|
144
|
+
/**
|
|
145
|
+
* Host resolver for credential fields that hold a SecretRef. A connector
|
|
146
|
+
* resolves those at poll time. Absent a resolver, a plain string still works
|
|
147
|
+
* and a SecretRef fails that connector only.
|
|
148
|
+
*/
|
|
149
|
+
readonly resolveSecretRef?: ResolveSecretRefFn | null;
|
|
142
150
|
}
|
|
143
151
|
|
|
144
152
|
/**
|
|
@@ -88,6 +88,41 @@ test("validateGoogleDriveConfig accepts a minimal valid config", () => {
|
|
|
88
88
|
assert.deepEqual([...cfg.folderIds], []);
|
|
89
89
|
});
|
|
90
90
|
|
|
91
|
+
test("a SecretRef credential resolves at poll time and never reaches the persisted config", async () => {
|
|
92
|
+
const client = makeMockClient({});
|
|
93
|
+
let seenSecret = "";
|
|
94
|
+
const factory: GoogleDriveClientFactory = async (config) => {
|
|
95
|
+
seenSecret = config.clientSecret;
|
|
96
|
+
return client;
|
|
97
|
+
};
|
|
98
|
+
const connector = createGoogleDriveConnector({ clientFactory: factory });
|
|
99
|
+
const ref = { source: "keychain", id: "projects/drive-secret" };
|
|
100
|
+
const config: ConnectorConfig = { ...SYNTHETIC_CREDS, clientSecret: ref };
|
|
101
|
+
await connector.syncIncremental({
|
|
102
|
+
cursor: null,
|
|
103
|
+
config,
|
|
104
|
+
resolveSecretRef: async () => "resolved-drive-secret",
|
|
105
|
+
});
|
|
106
|
+
assert.equal(seenSecret, "resolved-drive-secret");
|
|
107
|
+
const persisted = JSON.stringify(connector.persistConfig?.(config) ?? {});
|
|
108
|
+
assert.equal(persisted.includes("resolved-drive-secret"), false);
|
|
109
|
+
assert.equal(persisted.includes("projects/drive-secret"), false);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("a SecretRef with no resolver fails the connector and hides the reference", async () => {
|
|
113
|
+
const connector = createGoogleDriveConnector({ clientFactory: makeFactory(makeMockClient({})) });
|
|
114
|
+
const config: ConnectorConfig = { ...SYNTHETIC_CREDS, clientSecret: { source: "keychain", id: "projects/drive-secret" } };
|
|
115
|
+
let message = "";
|
|
116
|
+
try {
|
|
117
|
+
await connector.syncIncremental({ cursor: null, config });
|
|
118
|
+
} catch (err) {
|
|
119
|
+
message = err instanceof Error ? err.message : "";
|
|
120
|
+
}
|
|
121
|
+
assert.match(message, /clientSecret is a secret reference but no resolver is configured/);
|
|
122
|
+
assert.equal(message.includes("projects/drive-secret"), false);
|
|
123
|
+
assert.equal(message.includes("keychain"), false);
|
|
124
|
+
});
|
|
125
|
+
|
|
91
126
|
test("validateGoogleDriveConfig rejects non-object input", () => {
|
|
92
127
|
assert.throws(() => validateGoogleDriveConfig(null), /must be an object/);
|
|
93
128
|
assert.throws(() => validateGoogleDriveConfig([]), /must be an object/);
|
|
@@ -65,6 +65,8 @@ import type {
|
|
|
65
65
|
} from "./framework.js";
|
|
66
66
|
import { isTransientHttpError } from "./transient-errors.js";
|
|
67
67
|
import { throwIfAborted } from "../../abort-error.js";
|
|
68
|
+
import type { ResolveSecretRefFn } from "../../resolve-auth-token.js";
|
|
69
|
+
import type { SecretRef } from "../../types.js";
|
|
68
70
|
|
|
69
71
|
/**
|
|
70
72
|
* Stable connector id. Lives in the registry under this exact string.
|
|
@@ -122,15 +124,40 @@ const FOLDER_ID_PATTERN = /^[A-Za-z0-9_-]{8,256}$/;
|
|
|
122
124
|
* Validated, frozen view of `connectors.googleDrive.*`.
|
|
123
125
|
*/
|
|
124
126
|
export interface GoogleDriveConnectorConfig {
|
|
127
|
+
readonly clientId: DriveCredential;
|
|
128
|
+
readonly clientSecret: DriveCredential;
|
|
129
|
+
readonly refreshToken: DriveCredential;
|
|
130
|
+
/** Poll interval surfaced to the scheduler. */
|
|
131
|
+
readonly pollIntervalMs: number;
|
|
132
|
+
/** Folder ids to scope import to. Empty = "all accessible". */
|
|
133
|
+
readonly folderIds: readonly string[];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** A credential field as configured: a plain string, or a SecretRef resolved at poll time. */
|
|
137
|
+
type DriveCredential = string | SecretRef;
|
|
138
|
+
|
|
139
|
+
interface DriveCredentialFields {
|
|
140
|
+
clientId: DriveCredential;
|
|
141
|
+
clientSecret: DriveCredential;
|
|
142
|
+
refreshToken: DriveCredential;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** Resolved credentials passed to the Drive client. Always plain strings. */
|
|
146
|
+
interface GoogleDriveResolvedConfig {
|
|
125
147
|
readonly clientId: string;
|
|
126
148
|
readonly clientSecret: string;
|
|
127
149
|
readonly refreshToken: string;
|
|
128
|
-
/** Poll interval surfaced to the scheduler. */
|
|
129
150
|
readonly pollIntervalMs: number;
|
|
130
|
-
/** Folder ids to scope import to. Empty = "all accessible". */
|
|
131
151
|
readonly folderIds: readonly string[];
|
|
132
152
|
}
|
|
133
153
|
|
|
154
|
+
/** Disk form of a Drive config. A SecretRef clientId is omitted, never written. */
|
|
155
|
+
interface PersistedGoogleDriveConfig {
|
|
156
|
+
pollIntervalMs: number;
|
|
157
|
+
folderIds: readonly string[];
|
|
158
|
+
clientId?: string;
|
|
159
|
+
}
|
|
160
|
+
|
|
134
161
|
/**
|
|
135
162
|
* Optional injection point for tests. The real connector dynamically imports
|
|
136
163
|
* `googleapis`; tests pass a stub here to avoid the optional-peer-dep
|
|
@@ -139,7 +166,7 @@ export interface GoogleDriveConnectorConfig {
|
|
|
139
166
|
* The shape only covers the tiny slice of the SDK we actually use.
|
|
140
167
|
*/
|
|
141
168
|
export interface GoogleDriveClientFactory {
|
|
142
|
-
(config:
|
|
169
|
+
(config: GoogleDriveResolvedConfig): Promise<GoogleDriveClient>;
|
|
143
170
|
}
|
|
144
171
|
|
|
145
172
|
/**
|
|
@@ -243,9 +270,30 @@ export function validateGoogleDriveConfig(raw: unknown): GoogleDriveConnectorCon
|
|
|
243
270
|
);
|
|
244
271
|
}
|
|
245
272
|
const r = raw as Record<string, unknown>;
|
|
246
|
-
const
|
|
247
|
-
const
|
|
248
|
-
|
|
273
|
+
const credentialKeys = ["clientId", CLIENT_SECRET_FIELD, REFRESH_TOKEN_FIELD] as const;
|
|
274
|
+
const credentials: DriveCredentialFields = {
|
|
275
|
+
clientId: "",
|
|
276
|
+
clientSecret: "",
|
|
277
|
+
refreshToken: "",
|
|
278
|
+
};
|
|
279
|
+
for (const key of credentialKeys) {
|
|
280
|
+
const value = r[key];
|
|
281
|
+
if (Object.prototype.toString.call(value) === "[object Object]") {
|
|
282
|
+
// SAFETY: the toString check proves value is a non-null object.
|
|
283
|
+
const source = (value as { source?: object }).source;
|
|
284
|
+
if (Object.prototype.toString.call(source) === "[object String]") {
|
|
285
|
+
// SAFETY: a string `source` on this object is the SecretRef discriminator.
|
|
286
|
+
credentials[key] = value as SecretRef;
|
|
287
|
+
} else {
|
|
288
|
+
credentials[key] = requireNonEmptyString(value, key);
|
|
289
|
+
}
|
|
290
|
+
} else {
|
|
291
|
+
credentials[key] = requireNonEmptyString(value, key);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
const clientId = credentials.clientId;
|
|
295
|
+
const clientSecret = credentials.clientSecret;
|
|
296
|
+
const refreshToken = credentials.refreshToken;
|
|
249
297
|
|
|
250
298
|
let pollIntervalMs: number;
|
|
251
299
|
if (r.pollIntervalMs === undefined) {
|
|
@@ -321,6 +369,51 @@ function requireNonEmptyString(value: unknown, key: string): string {
|
|
|
321
369
|
return trimmed;
|
|
322
370
|
}
|
|
323
371
|
|
|
372
|
+
|
|
373
|
+
async function resolveCredential(
|
|
374
|
+
value: DriveCredential,
|
|
375
|
+
key: string,
|
|
376
|
+
resolver: ResolveSecretRefFn | null | undefined,
|
|
377
|
+
): Promise<string> {
|
|
378
|
+
if (Object.prototype.toString.call(value) !== "[object Object]") {
|
|
379
|
+
// SAFETY: a DriveCredential that is not an object is the plain string form.
|
|
380
|
+
return value as string;
|
|
381
|
+
}
|
|
382
|
+
// SAFETY: the toString check proves value is a non-null object, so it is a SecretRef.
|
|
383
|
+
const ref = value as SecretRef;
|
|
384
|
+
if (resolver == null) {
|
|
385
|
+
throw new Error(`googleDrive: ${key} is a secret reference but no resolver is configured`);
|
|
386
|
+
}
|
|
387
|
+
let resolved: unknown;
|
|
388
|
+
try {
|
|
389
|
+
resolved = await resolver(ref);
|
|
390
|
+
} catch {
|
|
391
|
+
throw new Error(`googleDrive: ${key} secret reference could not be resolved`);
|
|
392
|
+
}
|
|
393
|
+
if (Object.prototype.toString.call(resolved) !== "[object String]") {
|
|
394
|
+
throw new Error(`googleDrive: ${key} secret reference resolved to a non-string value`);
|
|
395
|
+
}
|
|
396
|
+
// SAFETY: the toString check above proves `resolved` is a string.
|
|
397
|
+
const text = (resolved as string).trim();
|
|
398
|
+
if (text.length === 0) {
|
|
399
|
+
throw new Error(`googleDrive: ${key} secret reference resolved to an empty value`);
|
|
400
|
+
}
|
|
401
|
+
return text;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
async function resolveGoogleDriveConfig(
|
|
405
|
+
stored: GoogleDriveConnectorConfig,
|
|
406
|
+
resolver: ResolveSecretRefFn | null | undefined,
|
|
407
|
+
): Promise<GoogleDriveResolvedConfig> {
|
|
408
|
+
return {
|
|
409
|
+
clientId: await resolveCredential(stored.clientId, "clientId", resolver),
|
|
410
|
+
[CLIENT_SECRET_FIELD]: await resolveCredential(stored[CLIENT_SECRET_FIELD], CLIENT_SECRET_FIELD, resolver),
|
|
411
|
+
[REFRESH_TOKEN_FIELD]: await resolveCredential(stored[REFRESH_TOKEN_FIELD], REFRESH_TOKEN_FIELD, resolver),
|
|
412
|
+
pollIntervalMs: stored.pollIntervalMs,
|
|
413
|
+
folderIds: stored.folderIds,
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
|
|
324
417
|
/**
|
|
325
418
|
* Decide whether a Drive `change` corresponds to an importable text file
|
|
326
419
|
* scoped to (optionally) the configured folder set.
|
|
@@ -405,16 +498,21 @@ export function createGoogleDriveConnector(
|
|
|
405
498
|
|
|
406
499
|
persistConfig(validated: ConnectorConfig): ConnectorConfig {
|
|
407
500
|
const config = validateGoogleDriveConfig(validated);
|
|
408
|
-
|
|
409
|
-
clientId: config.clientId,
|
|
501
|
+
const persisted: PersistedGoogleDriveConfig = {
|
|
410
502
|
pollIntervalMs: config.pollIntervalMs,
|
|
411
503
|
folderIds: config.folderIds,
|
|
412
|
-
}
|
|
504
|
+
};
|
|
505
|
+
if (Object.prototype.toString.call(config.clientId) === "[object String]") {
|
|
506
|
+
// SAFETY: the toString check proves clientId is a string, not a SecretRef.
|
|
507
|
+
persisted.clientId = config.clientId as string;
|
|
508
|
+
}
|
|
509
|
+
return Object.freeze(persisted);
|
|
510
|
+
|
|
413
511
|
},
|
|
414
512
|
|
|
415
513
|
async syncIncremental(args: SyncIncrementalArgs): Promise<SyncIncrementalResult> {
|
|
416
514
|
// Re-validate on every pass: a JS caller could mutate it between passes.
|
|
417
|
-
const config = validateGoogleDriveConfig(args.config);
|
|
515
|
+
const config = await resolveGoogleDriveConfig(validateGoogleDriveConfig(args.config), args.resolveSecretRef);
|
|
418
516
|
throwIfAborted(args.abortSignal, "googleDrive: sync aborted");
|
|
419
517
|
|
|
420
518
|
const client = await clientFactory(config);
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
} from "./connectors/live/index.js";
|
|
32
32
|
import { abortError } from "./abort-error.js";
|
|
33
33
|
import type { LiveConnectorsConfig } from "./types.js";
|
|
34
|
+
import type { ResolveSecretRefFn } from "./resolve-auth-token.js";
|
|
34
35
|
|
|
35
36
|
export type LiveConnectorSkipReason =
|
|
36
37
|
| "disabled"
|
|
@@ -138,6 +139,7 @@ export async function runLiveConnectorsOnce(options: {
|
|
|
138
139
|
now?: LiveConnectorsNow;
|
|
139
140
|
abortSignal?: AbortSignal;
|
|
140
141
|
definitions?: LiveConnectorDefinition[];
|
|
142
|
+
resolveSecretRef?: ResolveSecretRefFn | null;
|
|
141
143
|
}): Promise<LiveConnectorsRunSummary> {
|
|
142
144
|
const ranAt = resolveNow(options.now);
|
|
143
145
|
const force = options.force === true;
|
|
@@ -228,6 +230,7 @@ export async function runLiveConnectorsOnce(options: {
|
|
|
228
230
|
cursor,
|
|
229
231
|
config: validatedConfig,
|
|
230
232
|
abortSignal: pollAbortSignal,
|
|
233
|
+
resolveSecretRef: options.resolveSecretRef,
|
|
231
234
|
}),
|
|
232
235
|
ingestFn: async (docs) => {
|
|
233
236
|
throwIfAborted(pollAbortSignal);
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { mkdtemp, readFile, rm } from "node:fs/promises";
|
|
6
|
+
|
|
7
|
+
import { parseConfig } from "./config.js";
|
|
8
|
+
import {
|
|
9
|
+
builtInLiveConnectorDefinitions,
|
|
10
|
+
runLiveConnectorsOnce,
|
|
11
|
+
} from "./live-connectors-runner.js";
|
|
12
|
+
import {
|
|
13
|
+
GOOGLE_DRIVE_CONNECTOR_ID,
|
|
14
|
+
NOTION_CONNECTOR_ID,
|
|
15
|
+
createGoogleDriveConnector,
|
|
16
|
+
type GoogleDriveClient,
|
|
17
|
+
} from "./connectors/live/index.js";
|
|
18
|
+
import type { LiveConnector } from "./connectors/live/framework.js";
|
|
19
|
+
|
|
20
|
+
const RESOLVED_SECRET = "resolved-drive-secret";
|
|
21
|
+
const SECRET_REF = { source: "keychain", id: "projects/drive-secret" };
|
|
22
|
+
|
|
23
|
+
function driveConfig() {
|
|
24
|
+
return {
|
|
25
|
+
openaiApiKey: "sk-test",
|
|
26
|
+
connectors: {
|
|
27
|
+
googleDrive: {
|
|
28
|
+
enabled: true,
|
|
29
|
+
clientId: "synthetic-client",
|
|
30
|
+
clientSecret: SECRET_REF,
|
|
31
|
+
refreshToken: "synthetic-token",
|
|
32
|
+
},
|
|
33
|
+
notion: { enabled: true, token: "secret_synthetic_notion_token" },
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function notionStub(): LiveConnector {
|
|
39
|
+
return {
|
|
40
|
+
id: NOTION_CONNECTOR_ID,
|
|
41
|
+
displayName: "Notion",
|
|
42
|
+
validateConfig: () => ({}),
|
|
43
|
+
async syncIncremental() {
|
|
44
|
+
return { newDocs: [], nextCursor: { kind: "notion", value: "cursor-1", updatedAt: "2026-11-11T00:00:00.000Z" } };
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
test("a Drive SecretRef resolves through parseConfig and the runner, and stays out of the state file", async () => {
|
|
50
|
+
const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-drive-secretref-"));
|
|
51
|
+
try {
|
|
52
|
+
const parsed = parseConfig(driveConfig());
|
|
53
|
+
const definitions = builtInLiveConnectorDefinitions(parsed.connectors);
|
|
54
|
+
let seenSecret = "";
|
|
55
|
+
const client: GoogleDriveClient = {
|
|
56
|
+
async getStartPageToken() {
|
|
57
|
+
return { startPageToken: "seed-token" };
|
|
58
|
+
},
|
|
59
|
+
async listChanges() {
|
|
60
|
+
return { changes: [], newStartPageToken: "next-token" };
|
|
61
|
+
},
|
|
62
|
+
async exportFile() {
|
|
63
|
+
return "";
|
|
64
|
+
},
|
|
65
|
+
async getFileMedia() {
|
|
66
|
+
return "";
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
for (const definition of definitions) {
|
|
70
|
+
if (definition.id === GOOGLE_DRIVE_CONNECTOR_ID) {
|
|
71
|
+
definition.createConnector = () =>
|
|
72
|
+
createGoogleDriveConnector({
|
|
73
|
+
clientFactory: async (config) => {
|
|
74
|
+
seenSecret = config.clientSecret;
|
|
75
|
+
return client;
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
if (definition.id === NOTION_CONNECTOR_ID) {
|
|
80
|
+
definition.createConnector = notionStub;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const summary = await runLiveConnectorsOnce({
|
|
84
|
+
memoryDir,
|
|
85
|
+
connectors: parsed.connectors,
|
|
86
|
+
definitions,
|
|
87
|
+
force: true,
|
|
88
|
+
resolveSecretRef: async () => RESOLVED_SECRET,
|
|
89
|
+
ingestDocuments: async () => {},
|
|
90
|
+
});
|
|
91
|
+
assert.equal(seenSecret, RESOLVED_SECRET);
|
|
92
|
+
const drive = summary.results.find((item) => item.id === GOOGLE_DRIVE_CONNECTOR_ID);
|
|
93
|
+
assert.equal(drive?.ran, true);
|
|
94
|
+
const statePath = path.join(memoryDir, "state", "connectors", `${GOOGLE_DRIVE_CONNECTOR_ID}.json`);
|
|
95
|
+
const stateText = await readFile(statePath, "utf-8");
|
|
96
|
+
assert.equal(stateText.includes(RESOLVED_SECRET), false);
|
|
97
|
+
assert.equal(stateText.includes(SECRET_REF.id), false);
|
|
98
|
+
} finally {
|
|
99
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test("a Drive SecretRef with no resolver fails that connector and the others still run", async () => {
|
|
104
|
+
const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-drive-secretref-"));
|
|
105
|
+
try {
|
|
106
|
+
const parsed = parseConfig(driveConfig());
|
|
107
|
+
const definitions = builtInLiveConnectorDefinitions(parsed.connectors);
|
|
108
|
+
for (const definition of definitions) {
|
|
109
|
+
if (definition.id === NOTION_CONNECTOR_ID) definition.createConnector = notionStub;
|
|
110
|
+
}
|
|
111
|
+
const summary = await runLiveConnectorsOnce({
|
|
112
|
+
memoryDir,
|
|
113
|
+
connectors: parsed.connectors,
|
|
114
|
+
definitions,
|
|
115
|
+
force: true,
|
|
116
|
+
ingestDocuments: async () => {},
|
|
117
|
+
});
|
|
118
|
+
const drive = summary.results.find((item) => item.id === GOOGLE_DRIVE_CONNECTOR_ID);
|
|
119
|
+
const notion = summary.results.find((item) => item.id === NOTION_CONNECTOR_ID);
|
|
120
|
+
assert.match(drive?.error ?? "", /clientSecret is a secret reference but no resolver is configured/);
|
|
121
|
+
assert.equal((drive?.error ?? "").includes(SECRET_REF.id), false);
|
|
122
|
+
assert.equal(notion?.ran, true);
|
|
123
|
+
} finally {
|
|
124
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
125
|
+
}
|
|
126
|
+
});
|
|
@@ -59,8 +59,8 @@ import {
|
|
|
59
59
|
|
|
60
60
|
// The class lives in ../buffer-admission.js next to BufferAdmissionRefusedError;
|
|
61
61
|
// re-exported here so existing importers keep their import path.
|
|
62
|
-
import { ReplayAdmissionRefusedError } from "../buffer-admission.js";
|
|
63
|
-
export { ReplayAdmissionRefusedError };
|
|
62
|
+
import { ReplayAdmissionRefusedError, StorageTargetRequiredError } from "../buffer-admission.js";
|
|
63
|
+
export { ReplayAdmissionRefusedError, StorageTargetRequiredError };
|
|
64
64
|
|
|
65
65
|
export interface TurnIngestionDeps {
|
|
66
66
|
readonly buffer: SmartBuffer;
|
|
@@ -428,7 +428,7 @@ export class TurnIngestionCoordinator {
|
|
|
428
428
|
? options.scopeProfileWritePlan?.writeNamespace
|
|
429
429
|
: this.deps.config.defaultNamespace);
|
|
430
430
|
if (!resolvedWriteTarget) {
|
|
431
|
-
throw new
|
|
431
|
+
throw new StorageTargetRequiredError(
|
|
432
432
|
"accepted capture requires an explicit storage target (writeNamespaceOverride or scopeProfileWritePlan.writeNamespace)",
|
|
433
433
|
);
|
|
434
434
|
}
|
package/src/orchestrator.ts
CHANGED
|
@@ -236,6 +236,7 @@ import {
|
|
|
236
236
|
runLiveConnectorsOnce,
|
|
237
237
|
type LiveConnectorsRunSummary,
|
|
238
238
|
} from "./live-connectors-runner.js";
|
|
239
|
+
import type { ResolveSecretRefFn } from "./resolve-auth-token.js";
|
|
239
240
|
import {
|
|
240
241
|
runPatternReinforcement,
|
|
241
242
|
type PatternReinforcementResult,
|
|
@@ -2116,20 +2117,19 @@ export class Orchestrator {
|
|
|
2116
2117
|
async runLiveConnectors(options: {
|
|
2117
2118
|
force?: boolean;
|
|
2118
2119
|
abortSignal?: AbortSignal;
|
|
2120
|
+
resolveSecretRef?: ResolveSecretRefFn | null;
|
|
2119
2121
|
} = {}): Promise<LiveConnectorsRunSummary> {
|
|
2120
2122
|
return runLiveConnectorsOnce({
|
|
2121
2123
|
memoryDir: this.config.memoryDir,
|
|
2122
2124
|
connectors: this.config.connectors,
|
|
2123
2125
|
force: options.force === true,
|
|
2124
2126
|
abortSignal: options.abortSignal,
|
|
2127
|
+
resolveSecretRef: options.resolveSecretRef,
|
|
2125
2128
|
ingestDocuments: async (docs) => {
|
|
2126
2129
|
const fetchedAt = new Date().toISOString();
|
|
2127
2130
|
const turns = docs.map((doc) => ({
|
|
2128
|
-
role: "assistant" as const,
|
|
2129
|
-
content: doc.title
|
|
2130
|
-
? `# ${doc.title}\n\n${doc.content}`
|
|
2131
|
-
: doc.content,
|
|
2132
|
-
timestamp: fetchedAt,
|
|
2131
|
+
role: "assistant" as const, timestamp: fetchedAt,
|
|
2132
|
+
content: doc.title ? `# ${doc.title}\n\n${doc.content}` : doc.content,
|
|
2133
2133
|
}));
|
|
2134
2134
|
await this.ingestBulkImportBatch(turns);
|
|
2135
2135
|
},
|