@remnic/core 10.0.65 → 10.0.67
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 +16 -16
- package/dist/access-authorization-probe.js +17 -17
- package/dist/access-boundary.js +16 -16
- package/dist/access-cli.js +61 -61
- package/dist/access-extraction-force-flush.js +16 -16
- package/dist/access-http-briefing.js +17 -17
- package/dist/access-http-query.js +18 -18
- package/dist/access-http.js +33 -33
- package/dist/access-identity-continuity-surface.js +16 -16
- package/dist/access-lcm-surface.js +16 -16
- package/dist/access-mcp.js +26 -26
- package/dist/access-namespace-preflight.js +16 -16
- package/dist/access-observe-write-surface.js +16 -16
- package/dist/access-operations-batch.js +17 -17
- package/dist/access-operations.js +24 -24
- package/dist/access-recall-concurrency.js +16 -16
- package/dist/access-recall-diagnostics.js +2 -2
- package/dist/access-recall-response.js +16 -16
- package/dist/access-recall-surface.js +16 -16
- package/dist/access-service.js +16 -16
- package/dist/access-surface-catalog.js +18 -18
- package/dist/active-recall.js +3 -3
- package/dist/briefing.js +3 -3
- package/dist/buffer.js +2 -2
- package/dist/causal-consolidation.js +4 -4
- package/dist/{chunk-KISOMGY2.js → chunk-3RHU5MD7.js} +2 -2
- package/dist/{chunk-3LSTL6EY.js → chunk-4MPAKYZU.js} +2 -2
- package/dist/{chunk-OVL5AD3N.js → chunk-4NV7O76Q.js} +2 -2
- package/dist/{chunk-BH7NVSEC.js → chunk-4SOWMA55.js} +3 -3
- package/dist/{chunk-GROHOWR5.js → chunk-5MGKGEL7.js} +2 -2
- package/dist/{chunk-ZPLQ27MY.js → chunk-5UM4H64E.js} +2 -2
- package/dist/{chunk-2DNFRLLL.js → chunk-5Y6VA6X2.js} +2 -2
- package/dist/{chunk-GRAUQXQB.js → chunk-6WKWL53V.js} +13 -13
- package/dist/{chunk-HOR4RMUM.js → chunk-75DCOS6I.js} +24 -24
- package/dist/{chunk-25QK3LR2.js → chunk-7O2MC42R.js} +2 -2
- package/dist/{chunk-7ETWIBTO.js → chunk-ADYP7HXE.js} +3 -3
- package/dist/{chunk-FUDKGJDN.js → chunk-AVGDYYMA.js} +2 -2
- package/dist/{chunk-ECF627KC.js → chunk-AYJQ644F.js} +2 -2
- package/dist/{chunk-T22FBDG3.js → chunk-B3MWELZ3.js} +2 -2
- package/dist/{chunk-DRTSPRWL.js → chunk-B4DXREWC.js} +2 -2
- package/dist/{chunk-5UEGL5BF.js → chunk-CI3MAAIY.js} +2 -2
- package/dist/{chunk-7JYK7NNY.js → chunk-CTH2CQCB.js} +2 -2
- package/dist/{chunk-UVHXLVFJ.js → chunk-EURPSF4Y.js} +2 -2
- package/dist/{chunk-VPEA63FC.js → chunk-EWJZZDRG.js} +2 -2
- package/dist/{chunk-BOZQAUAJ.js → chunk-EXQJMFRF.js} +2 -2
- package/dist/{chunk-UH6ROXFJ.js → chunk-GGD2YDS6.js} +2 -2
- package/dist/{chunk-5JABRT5G.js → chunk-GHHQLSSY.js} +3 -3
- package/dist/{chunk-N4T5FW6U.js → chunk-GJ4HU6LK.js} +2 -2
- package/dist/{chunk-HRRAOTOQ.js → chunk-H5DIRCZP.js} +12 -12
- package/dist/{chunk-434E4BTO.js → chunk-HH73M65H.js} +3 -3
- package/dist/{chunk-LIGZO7XN.js → chunk-HPB5TF55.js} +2 -2
- package/dist/{chunk-E4QIX2OB.js → chunk-IAGVM7EY.js} +2 -2
- package/dist/{chunk-YJQJRXUI.js → chunk-IG3EZ3TF.js} +2 -2
- package/dist/{chunk-KNMSD2MQ.js → chunk-IVUVQPTQ.js} +2 -2
- package/dist/{chunk-XOFIJGB2.js → chunk-IZBIDPMY.js} +2 -2
- package/dist/{chunk-HFEGRMFG.js → chunk-JLGBJ4AX.js} +7 -7
- package/dist/{chunk-BBHKN2CN.js → chunk-JLMOH5JA.js} +2 -2
- package/dist/{chunk-TPCRDPUY.js → chunk-KZSGBWOJ.js} +2 -2
- package/dist/{chunk-SHHZWSSE.js → chunk-KZZ5EZ7O.js} +2 -2
- package/dist/{chunk-2ZSRACNK.js → chunk-LFYEQK45.js} +682 -549
- package/dist/chunk-LFYEQK45.js.map +1 -0
- package/dist/{chunk-FKGLJJVS.js → chunk-LN4X2NDA.js} +2 -2
- package/dist/{chunk-5ZHFPUBC.js → chunk-MOIJWWNA.js} +8 -8
- package/dist/{chunk-KO224R36.js → chunk-NCZGGGWI.js} +2 -2
- package/dist/{chunk-XVQVF2TK.js → chunk-NHWDTOBN.js} +269 -230
- package/dist/chunk-NHWDTOBN.js.map +1 -0
- package/dist/{chunk-7ZTGMEXF.js → chunk-O5ZINWW3.js} +2 -2
- package/dist/{chunk-WWH7GJ42.js → chunk-OCK4D5PC.js} +2 -2
- package/dist/{chunk-G6L3REL3.js → chunk-OPFVXM2D.js} +2 -2
- package/dist/{chunk-FR7PK7ED.js → chunk-P4TV3TQ2.js} +2 -2
- package/dist/{chunk-P2EM5LKH.js → chunk-PMDOGXA2.js} +2 -2
- package/dist/{chunk-NM2II57L.js → chunk-PRKNAIGZ.js} +2 -1
- package/dist/chunk-PRKNAIGZ.js.map +1 -0
- package/dist/{chunk-MRF5V5CD.js → chunk-QGFR73SN.js} +2 -2
- package/dist/{chunk-6D3IWYNY.js → chunk-R2BIVU2Z.js} +354 -292
- package/dist/chunk-R2BIVU2Z.js.map +1 -0
- package/dist/{chunk-HG3CG557.js → chunk-RLVI2M5Q.js} +2 -2
- package/dist/{chunk-HHL4MX3W.js → chunk-SXTVZ6JL.js} +2 -2
- package/dist/{chunk-CLSKGTAT.js → chunk-TECK5IVY.js} +2 -2
- package/dist/{chunk-SNS3DWG6.js → chunk-TVE7W67N.js} +2 -2
- package/dist/{chunk-KYSSUY66.js → chunk-U2CAGMUD.js} +2 -2
- package/dist/{chunk-XLCEFUAU.js → chunk-UVVFPCPX.js} +2 -2
- package/dist/{chunk-KQJUEQ2E.js → chunk-UW6LBFYN.js} +5 -5
- package/dist/{chunk-SEA56G6S.js → chunk-V4XE263I.js} +1 -1
- package/dist/chunk-V4XE263I.js.map +1 -0
- package/dist/{chunk-JL5HXL25.js → chunk-V6SBA5O7.js} +3 -3
- package/dist/{chunk-R7WYAXPO.js → chunk-VHSQU3RO.js} +81 -42
- package/dist/chunk-VHSQU3RO.js.map +1 -0
- package/dist/{chunk-B7VD36TI.js → chunk-WHROVQ5Q.js} +3 -3
- package/dist/{chunk-LDHR465K.js → chunk-Y3XPSGNF.js} +2 -2
- package/dist/{chunk-JPY3RMG2.js → chunk-ZORS5BG5.js} +4 -4
- package/dist/{chunk-KXY4HW2Y.js → chunk-ZXF3O7P4.js} +2 -2
- package/dist/cli.js +47 -47
- package/dist/coding/export-okf-codegraph.js +2 -2
- package/dist/compounding/engine.js +4 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -3
- package/dist/connectors/codex-materialize-runner.js +3 -3
- package/dist/connectors/index.js +3 -3
- package/dist/convergence-refresh.js +5 -5
- package/dist/corpus-watermark.js +5 -5
- package/dist/entity-retrieval.js +3 -3
- package/dist/external-wiki-access.js +17 -17
- package/dist/extraction.js +6 -6
- package/dist/harmonic-retrieval.js +3 -3
- package/dist/index.js +61 -61
- package/dist/location/index.js +5 -5
- package/dist/maintenance/memory-governance.js +3 -3
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
- package/dist/maintenance/rebuild-memory-projection-runner.js +5 -5
- package/dist/maintenance/rebuild-memory-projection.js +4 -4
- package/dist/memory-browse-operations.js +17 -17
- package/dist/namespaces/migrate.js +4 -4
- package/dist/namespaces/storage.js +3 -3
- package/dist/operator-doctor-corpus.js +6 -6
- package/dist/operator-toolkit.js +12 -12
- package/dist/orchestration/buffer-drain-runner.js +61 -61
- package/dist/orchestration/consolidation-run.d.ts.map +1 -1
- package/dist/orchestration/extraction-drain.d.ts +4 -4
- package/dist/orchestration/extraction-drain.d.ts.map +1 -1
- package/dist/orchestration/extraction-persist-deps.d.ts +0 -2
- package/dist/orchestration/extraction-persist-deps.d.ts.map +1 -1
- package/dist/orchestration/extraction-persist.d.ts +10 -4
- package/dist/orchestration/extraction-persist.d.ts.map +1 -1
- package/dist/orchestration/extraction-queue-coordinator.d.ts +67 -33
- package/dist/orchestration/extraction-queue-coordinator.d.ts.map +1 -1
- package/dist/orchestration/extraction-run-helpers.d.ts +3 -2
- package/dist/orchestration/extraction-run-helpers.d.ts.map +1 -1
- package/dist/orchestration/extraction-run.d.ts +4 -14
- package/dist/orchestration/extraction-run.d.ts.map +1 -1
- package/dist/orchestration/fact-dedup-window.d.ts +49 -0
- package/dist/orchestration/fact-dedup-window.d.ts.map +1 -0
- package/dist/orchestration/maintenance.js +13 -13
- package/dist/orchestration/provider-breaker.d.ts +58 -0
- package/dist/orchestration/provider-breaker.d.ts.map +1 -0
- package/dist/orchestrator.d.ts +2 -17
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +61 -61
- 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 +17 -17
- package/dist/recall-navigation.js +16 -16
- 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/resume-bundles.js +4 -4
- package/dist/semantic-consolidation.js +4 -4
- package/dist/semantic-rule-promotion.js +3 -3
- package/dist/semantic-rule-verifier.js +3 -3
- package/dist/source-agent-qualifier.js +5 -5
- package/dist/standup/build.js +3 -3
- package/dist/storage/profile-mutation.d.ts +25 -0
- package/dist/storage/profile-mutation.d.ts.map +1 -0
- package/dist/storage.d.ts +4 -6
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +2 -2
- package/dist/support-passport/index.js +19 -19
- package/dist/threading.d.ts +21 -4
- package/dist/threading.d.ts.map +1 -1
- package/dist/threading.js +1 -1
- package/dist/transfer/export-okf.js +3 -3
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/dist/verified-recall.js +3 -3
- package/dist/who-knows-cli.js +4 -4
- package/dist/who-knows.js +3 -3
- package/package.json +2 -2
- package/src/access-observe-replay-durability.test.ts +1 -1
- package/src/buffer-drain-handover.test.ts +3 -3
- package/src/buffer-drop-extraction-chunk.test.ts +0 -1
- package/src/config.test.ts +12 -0
- package/src/config.ts +2 -0
- package/src/connector-provenance-lifecycle.test.ts +5 -8
- package/src/fact-dedup-window.test.ts +116 -0
- package/src/faithfulness-graph-guard.test.ts +11 -6
- package/src/harmonic-construction.test.ts +16 -10
- package/src/orchestration/consolidation-profile-race.test.ts +178 -0
- package/src/orchestration/consolidation-run.ts +19 -7
- package/src/orchestration/extraction-drain.ts +10 -3
- package/src/orchestration/extraction-persist-deps.ts +0 -2
- package/src/orchestration/extraction-persist.ts +159 -148
- package/src/orchestration/extraction-queue-coordinator.ts +167 -56
- package/src/orchestration/extraction-run-helpers.ts +5 -4
- package/src/orchestration/extraction-run.test.ts +1 -2
- package/src/orchestration/extraction-run.ts +56 -99
- package/src/orchestration/fact-dedup-window.ts +122 -0
- package/src/orchestration/provider-breaker.test.ts +89 -0
- package/src/orchestration/provider-breaker.ts +158 -0
- package/src/orchestration/turn-ingestion.ts +5 -5
- package/src/orchestrator-extraction-queue.test.ts +179 -8
- package/src/orchestrator.ts +7 -23
- package/src/storage/profile-mutation.ts +119 -0
- package/src/storage-append-profile.test.ts +114 -0
- package/src/storage.ts +17 -48
- package/src/testing/orchestrator-lite.ts +1 -1
- package/src/threading.test.ts +153 -0
- package/src/threading.ts +95 -45
- package/src/types.ts +2 -0
- package/dist/chunk-2ZSRACNK.js.map +0 -1
- package/dist/chunk-6D3IWYNY.js.map +0 -1
- package/dist/chunk-NM2II57L.js.map +0 -1
- package/dist/chunk-R7WYAXPO.js.map +0 -1
- package/dist/chunk-SEA56G6S.js.map +0 -1
- package/dist/chunk-XVQVF2TK.js.map +0 -1
- /package/dist/{chunk-KISOMGY2.js.map → chunk-3RHU5MD7.js.map} +0 -0
- /package/dist/{chunk-3LSTL6EY.js.map → chunk-4MPAKYZU.js.map} +0 -0
- /package/dist/{chunk-OVL5AD3N.js.map → chunk-4NV7O76Q.js.map} +0 -0
- /package/dist/{chunk-BH7NVSEC.js.map → chunk-4SOWMA55.js.map} +0 -0
- /package/dist/{chunk-GROHOWR5.js.map → chunk-5MGKGEL7.js.map} +0 -0
- /package/dist/{chunk-ZPLQ27MY.js.map → chunk-5UM4H64E.js.map} +0 -0
- /package/dist/{chunk-2DNFRLLL.js.map → chunk-5Y6VA6X2.js.map} +0 -0
- /package/dist/{chunk-GRAUQXQB.js.map → chunk-6WKWL53V.js.map} +0 -0
- /package/dist/{chunk-HOR4RMUM.js.map → chunk-75DCOS6I.js.map} +0 -0
- /package/dist/{chunk-25QK3LR2.js.map → chunk-7O2MC42R.js.map} +0 -0
- /package/dist/{chunk-7ETWIBTO.js.map → chunk-ADYP7HXE.js.map} +0 -0
- /package/dist/{chunk-FUDKGJDN.js.map → chunk-AVGDYYMA.js.map} +0 -0
- /package/dist/{chunk-ECF627KC.js.map → chunk-AYJQ644F.js.map} +0 -0
- /package/dist/{chunk-T22FBDG3.js.map → chunk-B3MWELZ3.js.map} +0 -0
- /package/dist/{chunk-DRTSPRWL.js.map → chunk-B4DXREWC.js.map} +0 -0
- /package/dist/{chunk-5UEGL5BF.js.map → chunk-CI3MAAIY.js.map} +0 -0
- /package/dist/{chunk-7JYK7NNY.js.map → chunk-CTH2CQCB.js.map} +0 -0
- /package/dist/{chunk-UVHXLVFJ.js.map → chunk-EURPSF4Y.js.map} +0 -0
- /package/dist/{chunk-VPEA63FC.js.map → chunk-EWJZZDRG.js.map} +0 -0
- /package/dist/{chunk-BOZQAUAJ.js.map → chunk-EXQJMFRF.js.map} +0 -0
- /package/dist/{chunk-UH6ROXFJ.js.map → chunk-GGD2YDS6.js.map} +0 -0
- /package/dist/{chunk-5JABRT5G.js.map → chunk-GHHQLSSY.js.map} +0 -0
- /package/dist/{chunk-N4T5FW6U.js.map → chunk-GJ4HU6LK.js.map} +0 -0
- /package/dist/{chunk-HRRAOTOQ.js.map → chunk-H5DIRCZP.js.map} +0 -0
- /package/dist/{chunk-434E4BTO.js.map → chunk-HH73M65H.js.map} +0 -0
- /package/dist/{chunk-LIGZO7XN.js.map → chunk-HPB5TF55.js.map} +0 -0
- /package/dist/{chunk-E4QIX2OB.js.map → chunk-IAGVM7EY.js.map} +0 -0
- /package/dist/{chunk-YJQJRXUI.js.map → chunk-IG3EZ3TF.js.map} +0 -0
- /package/dist/{chunk-KNMSD2MQ.js.map → chunk-IVUVQPTQ.js.map} +0 -0
- /package/dist/{chunk-XOFIJGB2.js.map → chunk-IZBIDPMY.js.map} +0 -0
- /package/dist/{chunk-HFEGRMFG.js.map → chunk-JLGBJ4AX.js.map} +0 -0
- /package/dist/{chunk-BBHKN2CN.js.map → chunk-JLMOH5JA.js.map} +0 -0
- /package/dist/{chunk-TPCRDPUY.js.map → chunk-KZSGBWOJ.js.map} +0 -0
- /package/dist/{chunk-SHHZWSSE.js.map → chunk-KZZ5EZ7O.js.map} +0 -0
- /package/dist/{chunk-FKGLJJVS.js.map → chunk-LN4X2NDA.js.map} +0 -0
- /package/dist/{chunk-5ZHFPUBC.js.map → chunk-MOIJWWNA.js.map} +0 -0
- /package/dist/{chunk-KO224R36.js.map → chunk-NCZGGGWI.js.map} +0 -0
- /package/dist/{chunk-7ZTGMEXF.js.map → chunk-O5ZINWW3.js.map} +0 -0
- /package/dist/{chunk-WWH7GJ42.js.map → chunk-OCK4D5PC.js.map} +0 -0
- /package/dist/{chunk-G6L3REL3.js.map → chunk-OPFVXM2D.js.map} +0 -0
- /package/dist/{chunk-FR7PK7ED.js.map → chunk-P4TV3TQ2.js.map} +0 -0
- /package/dist/{chunk-P2EM5LKH.js.map → chunk-PMDOGXA2.js.map} +0 -0
- /package/dist/{chunk-MRF5V5CD.js.map → chunk-QGFR73SN.js.map} +0 -0
- /package/dist/{chunk-HG3CG557.js.map → chunk-RLVI2M5Q.js.map} +0 -0
- /package/dist/{chunk-HHL4MX3W.js.map → chunk-SXTVZ6JL.js.map} +0 -0
- /package/dist/{chunk-CLSKGTAT.js.map → chunk-TECK5IVY.js.map} +0 -0
- /package/dist/{chunk-SNS3DWG6.js.map → chunk-TVE7W67N.js.map} +0 -0
- /package/dist/{chunk-KYSSUY66.js.map → chunk-U2CAGMUD.js.map} +0 -0
- /package/dist/{chunk-XLCEFUAU.js.map → chunk-UVVFPCPX.js.map} +0 -0
- /package/dist/{chunk-KQJUEQ2E.js.map → chunk-UW6LBFYN.js.map} +0 -0
- /package/dist/{chunk-JL5HXL25.js.map → chunk-V6SBA5O7.js.map} +0 -0
- /package/dist/{chunk-B7VD36TI.js.map → chunk-WHROVQ5Q.js.map} +0 -0
- /package/dist/{chunk-LDHR465K.js.map → chunk-Y3XPSGNF.js.map} +0 -0
- /package/dist/{chunk-JPY3RMG2.js.map → chunk-ZORS5BG5.js.map} +0 -0
- /package/dist/{chunk-KXY4HW2Y.js.map → chunk-ZXF3O7P4.js.map} +0 -0
|
@@ -132,7 +132,7 @@ async function runExtractionPostPersistBestEffort(runDeadlineAware, stage, opera
|
|
|
132
132
|
async function runExtractionDeferRetention(runPostPersistBestEffort, options) {
|
|
133
133
|
await runPostPersistBestEffort("during_defer_retention", async () => {
|
|
134
134
|
if (options.clearBufferAfterExtraction && !options.extractionJudgeShadow) {
|
|
135
|
-
const deferredCount = options.
|
|
135
|
+
const deferredCount = options.deferredCount;
|
|
136
136
|
if (deferredCount > 0 && options.normalizedTurns.length > 0) {
|
|
137
137
|
await options.retainDeferredTurns(options.bufferKey, options.normalizedTurns, 10);
|
|
138
138
|
} else {
|
|
@@ -178,7 +178,7 @@ async function runExtractionPostPersist(options) {
|
|
|
178
178
|
await runExtractionDeferRetention(runBestEffort, {
|
|
179
179
|
clearBufferAfterExtraction: options.clearBufferAfterExtraction,
|
|
180
180
|
extractionJudgeShadow: options.extractionJudgeShadow,
|
|
181
|
-
|
|
181
|
+
deferredCount: options.deferredCount,
|
|
182
182
|
normalizedTurns: options.normalizedTurns,
|
|
183
183
|
bufferKey: options.bufferKey,
|
|
184
184
|
retainDeferredTurns: options.retainDeferredTurns
|
|
@@ -274,6 +274,104 @@ function classifyExtractionOrigin(sourceContext) {
|
|
|
274
274
|
});
|
|
275
275
|
}
|
|
276
276
|
|
|
277
|
+
// src/orchestration/provider-breaker.ts
|
|
278
|
+
var ProviderCircuitBreaker = class {
|
|
279
|
+
consecutiveFailures = 0;
|
|
280
|
+
openUntilMs = 0;
|
|
281
|
+
state = "closed";
|
|
282
|
+
lastReason = "";
|
|
283
|
+
probeHeld = false;
|
|
284
|
+
probeToken = null;
|
|
285
|
+
acquire(now) {
|
|
286
|
+
if (now < this.openUntilMs) return { suppressed: true, probe: false };
|
|
287
|
+
if (this.state === "open") {
|
|
288
|
+
this.state = "half_open";
|
|
289
|
+
this.probeHeld = true;
|
|
290
|
+
const token = { __probeOwner: true };
|
|
291
|
+
this.probeToken = token;
|
|
292
|
+
this.logTransition();
|
|
293
|
+
return { suppressed: false, probe: true, token };
|
|
294
|
+
}
|
|
295
|
+
if (this.state === "half_open") {
|
|
296
|
+
if (this.probeHeld) return { suppressed: true, probe: false };
|
|
297
|
+
this.probeHeld = true;
|
|
298
|
+
const token = { __probeOwner: true };
|
|
299
|
+
this.probeToken = token;
|
|
300
|
+
return { suppressed: false, probe: true, token };
|
|
301
|
+
}
|
|
302
|
+
return { suppressed: false, probe: false };
|
|
303
|
+
}
|
|
304
|
+
/** Release an owned probe on an attempt that exits without a terminal
|
|
305
|
+
* outcome (deadline, abort, throw). Only the matching owner releases;
|
|
306
|
+
* idempotent; state stays half_open so the next attempt re-probes. */
|
|
307
|
+
releaseProbe(token) {
|
|
308
|
+
if (token === void 0 || this.probeToken !== token) return;
|
|
309
|
+
this.probeToken = null;
|
|
310
|
+
this.probeHeld = false;
|
|
311
|
+
}
|
|
312
|
+
failure(cls, now, config, probeToken) {
|
|
313
|
+
const owned = probeToken !== void 0 && this.probeToken === probeToken;
|
|
314
|
+
if (owned) {
|
|
315
|
+
this.probeToken = null;
|
|
316
|
+
this.probeHeld = false;
|
|
317
|
+
}
|
|
318
|
+
this.consecutiveFailures += 1;
|
|
319
|
+
const trip = (
|
|
320
|
+
// An unowned auth_config failure (forced extraction) must not reopen
|
|
321
|
+
// over a held half-open probe — same ownership rule as the threshold
|
|
322
|
+
// term; the auth cooldown still applies once the probe settles.
|
|
323
|
+
cls === "auth_config" && (this.state !== "half_open" || owned) || // A failed half-open probe re-opens immediately (standard breaker
|
|
324
|
+
// semantics). Without this, an auth_config-opened breaker (which trips
|
|
325
|
+
// below the threshold) would get stuck half_open after a transient
|
|
326
|
+
// probe failure and stop suppressing (cursor review).
|
|
327
|
+
owned && this.state === "half_open" || // PRRT_kwDORJXyws6zxG6V: an unowned (forced-extraction) failure must
|
|
328
|
+
// not cross the threshold while another attempt owns the half-open
|
|
329
|
+
// probe — reopening here would strand the owner's token and let the
|
|
330
|
+
// next cooldown mint a second concurrent probe. The failure count and
|
|
331
|
+
// retry bookkeeping still accumulate for when the state leaves
|
|
332
|
+
// half_open.
|
|
333
|
+
this.state !== "half_open" && this.consecutiveFailures >= config.failureThreshold
|
|
334
|
+
);
|
|
335
|
+
if (!trip) return;
|
|
336
|
+
const cooldown = cls === "auth_config" ? config.authCooldownMs : config.cooldownMs;
|
|
337
|
+
this.openUntilMs = now + Math.max(0, cooldown);
|
|
338
|
+
this.lastReason = cls;
|
|
339
|
+
if (this.state !== "open") {
|
|
340
|
+
this.state = "open";
|
|
341
|
+
this.logTransition();
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
success(probeToken) {
|
|
345
|
+
const wasDisturbed = this.state !== "closed" || this.consecutiveFailures > 0 || this.openUntilMs > 0;
|
|
346
|
+
if (!wasDisturbed) return;
|
|
347
|
+
if (this.probeHeld && !(probeToken !== void 0 && this.probeToken === probeToken)) return;
|
|
348
|
+
const wasOpen = this.state !== "closed";
|
|
349
|
+
this.probeToken = null;
|
|
350
|
+
this.probeHeld = false;
|
|
351
|
+
this.consecutiveFailures = 0;
|
|
352
|
+
this.openUntilMs = 0;
|
|
353
|
+
this.lastReason = "";
|
|
354
|
+
this.state = "closed";
|
|
355
|
+
if (wasOpen) this.logTransition();
|
|
356
|
+
}
|
|
357
|
+
snapshot() {
|
|
358
|
+
return {
|
|
359
|
+
state: this.state,
|
|
360
|
+
openUntilMs: this.openUntilMs,
|
|
361
|
+
consecutiveFailures: this.consecutiveFailures,
|
|
362
|
+
lastReason: this.lastReason
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
logTransition() {
|
|
366
|
+
log.warn("extraction: provider circuit breaker transition", {
|
|
367
|
+
state: this.state,
|
|
368
|
+
consecutiveFailures: this.consecutiveFailures,
|
|
369
|
+
lastReason: this.lastReason,
|
|
370
|
+
openUntilMs: this.openUntilMs
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
};
|
|
374
|
+
|
|
277
375
|
// src/orchestration/extraction-run.ts
|
|
278
376
|
var ExtractionDeadlineError = class extends Error {
|
|
279
377
|
stage;
|
|
@@ -298,7 +396,7 @@ var ExtractionRunCoordinator = class {
|
|
|
298
396
|
// backoff still throttles, so a restart can't resurrect the hot loop.
|
|
299
397
|
extractionRetryState = /* @__PURE__ */ new Map();
|
|
300
398
|
hydratedRetryNamespaces = /* @__PURE__ */ new Set();
|
|
301
|
-
providerBreaker =
|
|
399
|
+
providerBreaker = new ProviderCircuitBreaker();
|
|
302
400
|
get config() {
|
|
303
401
|
return this.deps.config;
|
|
304
402
|
}
|
|
@@ -398,51 +496,6 @@ ${normalized}`).digest("hex");
|
|
|
398
496
|
}
|
|
399
497
|
this.extractionRetryState.set(namespace, nsMap);
|
|
400
498
|
}
|
|
401
|
-
logBreakerTransition(state) {
|
|
402
|
-
log.warn("extraction: provider circuit breaker transition", {
|
|
403
|
-
state,
|
|
404
|
-
consecutiveFailures: this.providerBreaker.consecutiveFailures,
|
|
405
|
-
lastReason: this.providerBreaker.lastReason,
|
|
406
|
-
openUntilMs: this.providerBreaker.openUntilMs
|
|
407
|
-
});
|
|
408
|
-
}
|
|
409
|
-
/** True while the breaker suppresses non-forced attempts. Flips an expired
|
|
410
|
-
* `open` breaker to `half_open`, which allows exactly one probe (the next
|
|
411
|
-
* non-forced attempt) because the extraction queue is a serial drain. */
|
|
412
|
-
isProviderBreakerOpen(now) {
|
|
413
|
-
if (now < this.providerBreaker.openUntilMs) return true;
|
|
414
|
-
if (this.providerBreaker.state === "open") {
|
|
415
|
-
this.providerBreaker.state = "half_open";
|
|
416
|
-
this.logBreakerTransition("half_open");
|
|
417
|
-
}
|
|
418
|
-
return false;
|
|
419
|
-
}
|
|
420
|
-
onProviderFailure(cls, now) {
|
|
421
|
-
this.providerBreaker.consecutiveFailures += 1;
|
|
422
|
-
const trip = cls === "auth_config" || // A failed half-open probe re-opens immediately (standard breaker
|
|
423
|
-
// semantics). Without this, an auth_config-opened breaker (which trips
|
|
424
|
-
// below the threshold) would get stuck half_open after a transient
|
|
425
|
-
// probe failure and stop suppressing (cursor review).
|
|
426
|
-
this.providerBreaker.state === "half_open" || this.providerBreaker.consecutiveFailures >= this.config.extractionBreakerFailureThreshold;
|
|
427
|
-
if (!trip) return;
|
|
428
|
-
const cooldown = cls === "auth_config" ? this.config.extractionBreakerAuthCooldownMs : this.config.extractionBreakerCooldownMs;
|
|
429
|
-
this.providerBreaker.openUntilMs = now + Math.max(0, cooldown);
|
|
430
|
-
this.providerBreaker.lastReason = cls;
|
|
431
|
-
if (this.providerBreaker.state !== "open") {
|
|
432
|
-
this.providerBreaker.state = "open";
|
|
433
|
-
this.logBreakerTransition("open");
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
resetProviderBreakerOnSuccess() {
|
|
437
|
-
const wasDisturbed = this.providerBreaker.state !== "closed" || this.providerBreaker.consecutiveFailures > 0 || this.providerBreaker.openUntilMs > 0;
|
|
438
|
-
if (!wasDisturbed) return;
|
|
439
|
-
const wasOpen = this.providerBreaker.state !== "closed";
|
|
440
|
-
this.providerBreaker.consecutiveFailures = 0;
|
|
441
|
-
this.providerBreaker.openUntilMs = 0;
|
|
442
|
-
this.providerBreaker.lastReason = "";
|
|
443
|
-
this.providerBreaker.state = "closed";
|
|
444
|
-
if (wasOpen) this.logBreakerTransition("closed");
|
|
445
|
-
}
|
|
446
499
|
/** Rebuild `meta.extractionRetryState` from the in-memory namespace mirror,
|
|
447
500
|
* bounded to the newest entries, and prune the mirror to match. */
|
|
448
501
|
persistRetryStateToMeta(namespace, meta) {
|
|
@@ -464,10 +517,10 @@ ${normalized}`).digest("hex");
|
|
|
464
517
|
}
|
|
465
518
|
}
|
|
466
519
|
/** Record an extraction failure into per-fingerprint backoff state + breaker, persisting to namespace meta. Fail-open. */
|
|
467
|
-
async recordExtractionFailure(namespace, fingerprint, cls, meta, now) {
|
|
520
|
+
async recordExtractionFailure(namespace, fingerprint, cls, meta, now, probeToken) {
|
|
468
521
|
try {
|
|
469
522
|
this.hydrateRetryStateFromMeta(namespace, meta);
|
|
470
|
-
this.applyExtractionFailureToMemory(namespace, fingerprint, cls, now);
|
|
523
|
+
this.applyExtractionFailureToMemory(namespace, fingerprint, cls, now, probeToken);
|
|
471
524
|
this.persistRetryStateToMeta(namespace, meta);
|
|
472
525
|
} catch (err) {
|
|
473
526
|
log.warn("runExtraction: failed to record extraction retry state (non-fatal)", err);
|
|
@@ -475,7 +528,7 @@ ${normalized}`).digest("hex");
|
|
|
475
528
|
}
|
|
476
529
|
/** Failure backoff into the in-memory mirror + breaker WITHOUT touching meta — the fallback
|
|
477
530
|
* when the locked meta write cannot run: the retry gate reads this mirror, so it stays shut. */
|
|
478
|
-
applyExtractionFailureToMemory(namespace, fingerprint, cls, now) {
|
|
531
|
+
applyExtractionFailureToMemory(namespace, fingerprint, cls, now, probeToken) {
|
|
479
532
|
const nsMap = this.extractionRetryState.get(namespace) ?? /* @__PURE__ */ new Map();
|
|
480
533
|
const prev = nsMap.get(fingerprint);
|
|
481
534
|
const attempts = (prev?.attempts ?? 0) + 1;
|
|
@@ -494,7 +547,11 @@ ${normalized}`).digest("hex");
|
|
|
494
547
|
}
|
|
495
548
|
nsMap.set(fingerprint, { attempts, nextEligibleAtMs, firstFailedAtMs, lastFailureClass: cls });
|
|
496
549
|
this.extractionRetryState.set(namespace, nsMap);
|
|
497
|
-
this.
|
|
550
|
+
this.providerBreaker.failure(cls, now, {
|
|
551
|
+
failureThreshold: this.config.extractionBreakerFailureThreshold,
|
|
552
|
+
cooldownMs: this.config.extractionBreakerCooldownMs,
|
|
553
|
+
authCooldownMs: this.config.extractionBreakerAuthCooldownMs
|
|
554
|
+
}, probeToken);
|
|
498
555
|
}
|
|
499
556
|
/** Delete a fingerprint's retry entry from the mirror + meta. Returns whether
|
|
500
557
|
* meta changed (so the caller can decide to persist). Does not touch the
|
|
@@ -513,12 +570,7 @@ ${normalized}`).digest("hex");
|
|
|
513
570
|
backoffFingerprintCount += nsMap.size;
|
|
514
571
|
}
|
|
515
572
|
return {
|
|
516
|
-
breaker:
|
|
517
|
-
state: this.providerBreaker.state,
|
|
518
|
-
openUntilMs: this.providerBreaker.openUntilMs,
|
|
519
|
-
consecutiveFailures: this.providerBreaker.consecutiveFailures,
|
|
520
|
-
lastReason: this.providerBreaker.lastReason
|
|
521
|
-
},
|
|
573
|
+
breaker: this.providerBreaker.snapshot(),
|
|
522
574
|
backoffFingerprintCount
|
|
523
575
|
};
|
|
524
576
|
}
|
|
@@ -774,13 +826,18 @@ ${normalized}`).digest("hex");
|
|
|
774
826
|
}
|
|
775
827
|
const forcedExtractionAttempt = options.failOnExtractionFailure === true || options.forceExtractionAttempt === true;
|
|
776
828
|
const extractionRetryEnabled = resolveMemoryLifecycleCapabilities(this.config).extractionRetry;
|
|
829
|
+
let extractionProbeOwned = false;
|
|
830
|
+
let extractionProbeToken;
|
|
777
831
|
if (extractionFingerprint && !forcedExtractionAttempt && extractionRetryEnabled) {
|
|
778
832
|
try {
|
|
779
833
|
meta ??= await runDeadlineAware(() => storage.loadMeta(), "during_retry_gate");
|
|
780
834
|
this.hydrateRetryStateFromMeta(selfNamespace, meta);
|
|
781
835
|
const nowMs = Date.now();
|
|
836
|
+
const probeAttempt = this.providerBreaker.acquire(nowMs);
|
|
837
|
+
extractionProbeOwned = probeAttempt.probe;
|
|
838
|
+
extractionProbeToken = probeAttempt.token;
|
|
782
839
|
let suppressReason = null;
|
|
783
|
-
if (
|
|
840
|
+
if (probeAttempt.suppressed) {
|
|
784
841
|
suppressReason = "provider_circuit_open";
|
|
785
842
|
} else {
|
|
786
843
|
const st = this.extractionRetryState.get(selfNamespace)?.get(extractionFingerprint);
|
|
@@ -803,6 +860,7 @@ ${normalized}`).digest("hex");
|
|
|
803
860
|
log.warn("runExtraction: passive correction capture failed on suppressed attempt (non-fatal)", captureErr);
|
|
804
861
|
}
|
|
805
862
|
clearExtractionDeadlineTimer();
|
|
863
|
+
if (extractionProbeOwned) this.providerBreaker.releaseProbe(extractionProbeToken);
|
|
806
864
|
return { status: "skipped", reason: suppressReason, persistedCount: 0, durableOutputCount: 0 };
|
|
807
865
|
}
|
|
808
866
|
} catch (err) {
|
|
@@ -810,268 +868,272 @@ ${normalized}`).digest("hex");
|
|
|
810
868
|
log.warn("runExtraction: extraction retry gate check failed; proceeding (fail-open)", err);
|
|
811
869
|
}
|
|
812
870
|
}
|
|
813
|
-
const existingEntities = await runDeadlineAware(
|
|
814
|
-
() => storage.listEntityNames(),
|
|
815
|
-
"during_list_entity_names"
|
|
816
|
-
);
|
|
817
|
-
let result;
|
|
818
871
|
try {
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
"extraction aborted (during_extract)"
|
|
872
|
+
const existingEntities = await runDeadlineAware(
|
|
873
|
+
() => storage.listEntityNames(),
|
|
874
|
+
"during_list_entity_names"
|
|
823
875
|
);
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
log.warn("runExtraction: extraction returned null/undefined");
|
|
836
|
-
if (options.failOnExtractionFailure) {
|
|
837
|
-
throw new Error("extraction failed: invalid_extraction_result");
|
|
876
|
+
let result;
|
|
877
|
+
try {
|
|
878
|
+
result = await raceRecallAbort(
|
|
879
|
+
this.deps.getExtraction().extract(normalizedTurns, existingEntities, extractionAbortSignal),
|
|
880
|
+
extractionAbortSignal,
|
|
881
|
+
"extraction aborted (during_extract)"
|
|
882
|
+
);
|
|
883
|
+
} catch (error) {
|
|
884
|
+
clearExtractionDeadlineTimer();
|
|
885
|
+
if (deadlineMs !== void 0 && Date.now() >= deadlineMs) {
|
|
886
|
+
throw new ExtractionDeadlineError("during_extract");
|
|
838
887
|
}
|
|
839
|
-
|
|
840
|
-
return {
|
|
841
|
-
status: "skipped",
|
|
842
|
-
reason: "invalid_extraction_result",
|
|
843
|
-
persistedCount: 0,
|
|
844
|
-
durableOutputCount: 0
|
|
845
|
-
};
|
|
888
|
+
throw error;
|
|
846
889
|
}
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
890
|
+
try {
|
|
891
|
+
throwIfDeadlineExceeded("before_persist");
|
|
892
|
+
throwIfAborted("before_persist");
|
|
893
|
+
if (!result) {
|
|
894
|
+
log.warn("runExtraction: extraction returned null/undefined");
|
|
895
|
+
if (options.failOnExtractionFailure) {
|
|
896
|
+
throw new Error("extraction failed: invalid_extraction_result");
|
|
897
|
+
}
|
|
898
|
+
await clearBuffer();
|
|
899
|
+
return {
|
|
900
|
+
status: "skipped",
|
|
901
|
+
reason: "invalid_extraction_result",
|
|
902
|
+
persistedCount: 0,
|
|
903
|
+
durableOutputCount: 0
|
|
904
|
+
};
|
|
860
905
|
}
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
906
|
+
const invalidExtractionResultFields = [
|
|
907
|
+
["facts", result.facts],
|
|
908
|
+
["entities", result.entities],
|
|
909
|
+
["questions", result.questions],
|
|
910
|
+
["profileUpdates", result.profileUpdates]
|
|
911
|
+
].filter(([, value]) => !Array.isArray(value)).map(([field]) => field);
|
|
912
|
+
if (invalidExtractionResultFields.length > 0) {
|
|
913
|
+
log.warn("runExtraction: extraction returned invalid collection fields", {
|
|
914
|
+
invalidFields: invalidExtractionResultFields,
|
|
915
|
+
resultKeys: typeof result === "object" && result !== null ? Object.keys(result) : []
|
|
916
|
+
});
|
|
917
|
+
if (options.failOnExtractionFailure) {
|
|
918
|
+
throw new Error("extraction failed: invalid_extraction_result");
|
|
919
|
+
}
|
|
920
|
+
await clearBuffer();
|
|
921
|
+
return {
|
|
922
|
+
status: "skipped",
|
|
923
|
+
reason: "invalid_extraction_result",
|
|
924
|
+
persistedCount: 0,
|
|
925
|
+
durableOutputCount: 0
|
|
926
|
+
};
|
|
927
|
+
}
|
|
928
|
+
const extractionFailure = typeof result.extractionFailure === "string" && result.extractionFailure.trim().length > 0 ? result.extractionFailure : void 0;
|
|
879
929
|
if (extractionFailure) {
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
930
|
+
recordExtractionLlmFailure(extractionFailure);
|
|
931
|
+
emitExtractionLlmFailureError(extractionFailure, result.extractionFailureClass);
|
|
932
|
+
} else if (result.extractionSkippedReason !== void 0) {
|
|
933
|
+
} else {
|
|
934
|
+
recordExtractionLlmSuccess();
|
|
935
|
+
}
|
|
936
|
+
let recordedRetryFailure = false;
|
|
937
|
+
if (extractionFingerprint && extractionRetryEnabled) {
|
|
938
|
+
if (extractionFailure) {
|
|
939
|
+
const failureClass = result.extractionFailureClass ?? "provider_retryable";
|
|
940
|
+
try {
|
|
941
|
+
await runDeadlineAware(
|
|
942
|
+
() => storage.updateMeta(
|
|
943
|
+
(freshMeta) => this.recordExtractionFailure(selfNamespace, extractionFingerprint, failureClass, freshMeta, Date.now(), extractionProbeToken)
|
|
944
|
+
),
|
|
945
|
+
"during_retry_bookkeeping_save",
|
|
946
|
+
false
|
|
947
|
+
);
|
|
948
|
+
recordedRetryFailure = true;
|
|
949
|
+
} catch (err) {
|
|
950
|
+
if (err instanceof ExtractionDeadlineError) throw err;
|
|
951
|
+
if (err instanceof Error && err.message.includes("meta.json.lock not acquired"))
|
|
952
|
+
this.applyExtractionFailureToMemory(selfNamespace, extractionFingerprint, failureClass, Date.now(), extractionProbeToken);
|
|
953
|
+
recordedRetryFailure = true;
|
|
954
|
+
log.warn("runExtraction: retry state kept in memory; meta persist will catch up", err);
|
|
955
|
+
}
|
|
956
|
+
} else if (result.extractionSkippedReason === void 0) {
|
|
957
|
+
this.providerBreaker.success(extractionProbeToken);
|
|
958
|
+
try {
|
|
959
|
+
await runDeadlineAware(
|
|
960
|
+
() => storage.updateMeta((freshMeta) => {
|
|
961
|
+
this.hydrateRetryStateFromMeta(selfNamespace, freshMeta);
|
|
962
|
+
return this.clearExtractionRetryEntry(selfNamespace, extractionFingerprint, freshMeta);
|
|
963
|
+
}),
|
|
964
|
+
"during_retry_bookkeeping_save",
|
|
965
|
+
false
|
|
966
|
+
);
|
|
967
|
+
} catch (err) {
|
|
968
|
+
if (err instanceof ExtractionDeadlineError) throw err;
|
|
969
|
+
log.warn("runExtraction: failed to persist cleared retry state (non-fatal)", err);
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
if (options.failOnExtractionFailure && extractionFailure) {
|
|
974
|
+
throw new Error(`extraction failed: ${extractionFailure}`);
|
|
975
|
+
}
|
|
976
|
+
if (result.facts.length === 0 && result.entities.length === 0 && result.questions.length === 0 && result.profileUpdates.length === 0) {
|
|
977
|
+
log.debug("runExtraction: extraction produced no durable outputs; skipping persistence");
|
|
978
|
+
if (extractionFailure) {
|
|
979
|
+
log.warn(
|
|
980
|
+
"runExtraction: extraction reported failure with no durable outputs; not marking fingerprint processed",
|
|
981
|
+
{ extractionFailure }
|
|
888
982
|
);
|
|
889
|
-
recordedRetryFailure = true;
|
|
890
|
-
} catch (err) {
|
|
891
|
-
if (err instanceof ExtractionDeadlineError) throw err;
|
|
892
|
-
if (err instanceof Error && err.message.includes("meta.json.lock not acquired"))
|
|
893
|
-
this.applyExtractionFailureToMemory(selfNamespace, extractionFingerprint, failureClass, Date.now());
|
|
894
|
-
recordedRetryFailure = true;
|
|
895
|
-
log.warn("runExtraction: retry state kept in memory; meta persist will catch up", err);
|
|
896
983
|
}
|
|
897
|
-
|
|
898
|
-
|
|
984
|
+
const emptySuccessCommit = {
|
|
985
|
+
storage,
|
|
986
|
+
extractionFingerprint,
|
|
987
|
+
shouldPersistProcessedFingerprint,
|
|
988
|
+
hasExtractionFailure: Boolean(extractionFailure),
|
|
989
|
+
extractionSkippedReason: result.extractionSkippedReason,
|
|
990
|
+
recordProcessedExtractionFingerprint: this.deps.recordProcessedExtractionFingerprint,
|
|
991
|
+
runDeadlineAware,
|
|
992
|
+
isDeadlineError: (error) => error instanceof ExtractionDeadlineError
|
|
993
|
+
};
|
|
994
|
+
if (shouldPersistProcessedFingerprint) {
|
|
995
|
+
await commitEmptySuccessExtraction(emptySuccessCommit);
|
|
996
|
+
}
|
|
997
|
+
await runPassiveCapture(normalizedTurns, {
|
|
998
|
+
sessionKey,
|
|
999
|
+
principal,
|
|
1000
|
+
namespace: selfNamespace,
|
|
1001
|
+
bufferKey,
|
|
1002
|
+
isLiveSession: clearBufferAfterExtraction
|
|
1003
|
+
});
|
|
1004
|
+
if (recordedRetryFailure) {
|
|
1005
|
+
log.debug("runExtraction: retaining buffer for backoff retry after failure");
|
|
1006
|
+
} else {
|
|
1007
|
+
await clearBuffer();
|
|
1008
|
+
}
|
|
1009
|
+
if (!shouldPersistProcessedFingerprint) {
|
|
1010
|
+
await commitEmptySuccessExtraction(emptySuccessCommit);
|
|
1011
|
+
}
|
|
1012
|
+
return emptyExtractionResult(recordedRetryFailure, result.extractionFailureClass);
|
|
1013
|
+
}
|
|
1014
|
+
let threadIdForExtraction = null;
|
|
1015
|
+
if (resolvePresentationCapabilities(this.config).threading && turns.length > 0) {
|
|
1016
|
+
const lastTurn = turns[turns.length - 1];
|
|
899
1017
|
try {
|
|
900
|
-
await runDeadlineAware(
|
|
901
|
-
() =>
|
|
902
|
-
|
|
903
|
-
return this.clearExtractionRetryEntry(selfNamespace, extractionFingerprint, freshMeta);
|
|
904
|
-
}),
|
|
905
|
-
"during_retry_bookkeeping_save",
|
|
906
|
-
false
|
|
1018
|
+
threadIdForExtraction = await runDeadlineAware(
|
|
1019
|
+
() => this.deps.getThreading().processTurn(lastTurn, []),
|
|
1020
|
+
"during_threading"
|
|
907
1021
|
);
|
|
908
1022
|
} catch (err) {
|
|
909
1023
|
if (err instanceof ExtractionDeadlineError) throw err;
|
|
910
|
-
log.warn("
|
|
1024
|
+
log.warn("[threading] processTurn failed before persistence (non-fatal)", err);
|
|
911
1025
|
}
|
|
912
1026
|
}
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
1027
|
+
const originContext = deriveExtractionOriginContext(targetTurns, result.sourceConnector);
|
|
1028
|
+
options.onBeforePersist?.();
|
|
1029
|
+
throwIfDeadlineExceeded("before_persist");
|
|
1030
|
+
throwIfAborted("before_persist");
|
|
1031
|
+
const { persistedIds, deferredCount, pendingReviewIds } = await this.deps.persistExtraction(
|
|
1032
|
+
result,
|
|
1033
|
+
storage,
|
|
1034
|
+
threadIdForExtraction,
|
|
1035
|
+
{ sessionKey, principal, validAt: sourceValidAt, ...originContext },
|
|
1036
|
+
// Pass the KNOWN base namespace (NHIdx) so the catalog write touch records the
|
|
1037
|
+
// real namespace rather than a guess decoded from the storage dir.
|
|
1038
|
+
selfNamespace,
|
|
1039
|
+
scopeProfileWritePlan,
|
|
1040
|
+
// Verbatim source turns for the faithfulness gate (#1576) so it can
|
|
1041
|
+
// locate a quote per fact when #1575 spans are absent.
|
|
1042
|
+
normalizedTurns.map((t) => t.content).join("\n\n")
|
|
1043
|
+
);
|
|
1044
|
+
const durableOutputCount = result.facts.length + result.entities.length + result.questions.length + result.profileUpdates.length;
|
|
1045
|
+
try {
|
|
1046
|
+
options.onDurableCommit?.();
|
|
1047
|
+
} catch (error) {
|
|
1048
|
+
log.warn("runExtraction: durable-commit callback failed", error);
|
|
924
1049
|
}
|
|
925
|
-
const
|
|
1050
|
+
const runPostPersistBestEffort = runExtractionPostPersistBestEffort.bind(null, runDeadlineAware);
|
|
1051
|
+
await tagPersistedMemories(storage, persistedIds, this.config);
|
|
1052
|
+
const postPersist = await runExtractionPostPersist({
|
|
1053
|
+
result,
|
|
926
1054
|
storage,
|
|
927
|
-
extractionFingerprint,
|
|
1055
|
+
extractionFingerprint: extractionFingerprint ?? void 0,
|
|
928
1056
|
shouldPersistProcessedFingerprint,
|
|
929
|
-
hasExtractionFailure: Boolean(extractionFailure),
|
|
930
|
-
extractionSkippedReason: result.extractionSkippedReason,
|
|
931
1057
|
recordProcessedExtractionFingerprint: this.deps.recordProcessedExtractionFingerprint,
|
|
932
1058
|
runDeadlineAware,
|
|
933
|
-
isDeadlineError: (error) => error instanceof ExtractionDeadlineError
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
namespace: selfNamespace,
|
|
1059
|
+
isDeadlineError: (error) => error instanceof ExtractionDeadlineError,
|
|
1060
|
+
createDeadlineError: (stage) => new ExtractionDeadlineError(stage),
|
|
1061
|
+
deadlineMs,
|
|
1062
|
+
clearBufferAfterExtraction,
|
|
1063
|
+
runPostPersistBestEffort,
|
|
1064
|
+
extractionJudgeShadow: this.config.extractionJudgeShadow,
|
|
1065
|
+
deferredCount,
|
|
1066
|
+
normalizedTurns,
|
|
942
1067
|
bufferKey,
|
|
943
|
-
|
|
1068
|
+
retainDeferredTurns: (key, retainedTurns, max) => this.deps.getBuffer().retainDeferredTurns(key, retainedTurns, max, options.retentionWindow ?? turns),
|
|
1069
|
+
clearBuffer,
|
|
1070
|
+
failOnExtractionFailure: options.failOnExtractionFailure === true
|
|
944
1071
|
});
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
1072
|
+
const postPersistMetadataFailed = postPersist.metadataFailed;
|
|
1073
|
+
await runPostPersistBestEffort(
|
|
1074
|
+
"during_post_persist_passive_capture",
|
|
1075
|
+
() => runPassiveCapture(normalizedTurns, {
|
|
1076
|
+
sessionKey,
|
|
1077
|
+
principal,
|
|
1078
|
+
namespace: selfNamespace,
|
|
1079
|
+
bufferKey,
|
|
1080
|
+
isLiveSession: clearBufferAfterExtraction,
|
|
1081
|
+
abortSignal: extractionAbortSignal
|
|
1082
|
+
})
|
|
1083
|
+
);
|
|
1084
|
+
if (resolvePresentationCapabilities(this.config).memoryBoxes && persistedIds.length > 0) {
|
|
1085
|
+
const extractionTopics = deriveTopicsFromExtraction(result);
|
|
1086
|
+
const firstUserTurn = turns.find((t) => t.role === "user");
|
|
1087
|
+
const boxGoal = firstUserTurn?.content?.slice(0, 100)?.trim() || void 0;
|
|
1088
|
+
await runPostPersistBestEffort(
|
|
1089
|
+
"during_memory_box",
|
|
1090
|
+
() => this.deps.boxBuilderFor(storage).onExtraction({
|
|
1091
|
+
topics: extractionTopics,
|
|
1092
|
+
memoryIds: persistedIds,
|
|
1093
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1094
|
+
goal: boxGoal
|
|
1095
|
+
})
|
|
1096
|
+
);
|
|
1097
|
+
}
|
|
1098
|
+
if (resolvePresentationCapabilities(this.config).threading && threadIdForExtraction && persistedIds.length > 0) {
|
|
1099
|
+
await runPostPersistBestEffort(
|
|
1100
|
+
"during_thread_episode_append",
|
|
1101
|
+
() => this.deps.appendPersistedThreadEpisodes(threadIdForExtraction, persistedIds, pendingReviewIds)
|
|
1102
|
+
);
|
|
949
1103
|
}
|
|
950
|
-
if (
|
|
951
|
-
|
|
1104
|
+
if (resolvePresentationCapabilities(this.config).threading && threadIdForExtraction) {
|
|
1105
|
+
const conversationContent = turns.map((t) => t.content).join(" ");
|
|
1106
|
+
await runPostPersistBestEffort(
|
|
1107
|
+
"during_thread_title_update",
|
|
1108
|
+
() => this.deps.getThreading().updateThreadTitle(threadIdForExtraction, conversationContent)
|
|
1109
|
+
);
|
|
952
1110
|
}
|
|
953
|
-
|
|
954
|
-
}
|
|
955
|
-
let threadIdForExtraction = null;
|
|
956
|
-
if (resolvePresentationCapabilities(this.config).threading && turns.length > 0) {
|
|
957
|
-
const lastTurn = turns[turns.length - 1];
|
|
1111
|
+
const nonZeroExtraction = durableOutputCount > 0;
|
|
958
1112
|
try {
|
|
959
|
-
|
|
960
|
-
() => this.deps.getThreading().processTurn(lastTurn, []),
|
|
961
|
-
"during_threading"
|
|
962
|
-
);
|
|
1113
|
+
this.deps.maybeScheduleConsolidation(nonZeroExtraction);
|
|
963
1114
|
} catch (err) {
|
|
964
|
-
|
|
965
|
-
|
|
1115
|
+
log.warn("runExtraction: consolidation scheduling failed after persistence (non-fatal)", err);
|
|
1116
|
+
}
|
|
1117
|
+
try {
|
|
1118
|
+
this.deps.requestQmdMaintenance();
|
|
1119
|
+
} catch (err) {
|
|
1120
|
+
log.warn("runExtraction: QMD maintenance scheduling failed after persistence (non-fatal)", err);
|
|
966
1121
|
}
|
|
967
|
-
}
|
|
968
|
-
const originContext = deriveExtractionOriginContext(targetTurns, result.sourceConnector);
|
|
969
|
-
options.onBeforePersist?.();
|
|
970
|
-
throwIfDeadlineExceeded("before_persist");
|
|
971
|
-
throwIfAborted("before_persist");
|
|
972
|
-
const { persistedIds } = await this.deps.persistExtraction(
|
|
973
|
-
result,
|
|
974
|
-
storage,
|
|
975
|
-
threadIdForExtraction,
|
|
976
|
-
{ sessionKey, principal, validAt: sourceValidAt, ...originContext },
|
|
977
|
-
// Pass the KNOWN base namespace (NHIdx) so the catalog write touch records the
|
|
978
|
-
// real namespace rather than a guess decoded from the storage dir.
|
|
979
|
-
selfNamespace,
|
|
980
|
-
scopeProfileWritePlan,
|
|
981
|
-
// Verbatim source turns for the faithfulness gate (#1576) so it can
|
|
982
|
-
// locate a quote per fact when #1575 spans are absent.
|
|
983
|
-
normalizedTurns.map((t) => t.content).join("\n\n")
|
|
984
|
-
);
|
|
985
|
-
const durableOutputCount = result.facts.length + result.entities.length + result.questions.length + result.profileUpdates.length;
|
|
986
|
-
try {
|
|
987
|
-
options.onDurableCommit?.();
|
|
988
|
-
} catch (error) {
|
|
989
|
-
log.warn("runExtraction: durable-commit callback failed", error);
|
|
990
|
-
}
|
|
991
|
-
const runPostPersistBestEffort = runExtractionPostPersistBestEffort.bind(null, runDeadlineAware);
|
|
992
|
-
await tagPersistedMemories(storage, persistedIds, this.config);
|
|
993
|
-
const postPersist = await runExtractionPostPersist({
|
|
994
|
-
result,
|
|
995
|
-
storage,
|
|
996
|
-
extractionFingerprint: extractionFingerprint ?? void 0,
|
|
997
|
-
shouldPersistProcessedFingerprint,
|
|
998
|
-
recordProcessedExtractionFingerprint: this.deps.recordProcessedExtractionFingerprint,
|
|
999
|
-
runDeadlineAware,
|
|
1000
|
-
isDeadlineError: (error) => error instanceof ExtractionDeadlineError,
|
|
1001
|
-
createDeadlineError: (stage) => new ExtractionDeadlineError(stage),
|
|
1002
|
-
deadlineMs,
|
|
1003
|
-
clearBufferAfterExtraction,
|
|
1004
|
-
runPostPersistBestEffort,
|
|
1005
|
-
extractionJudgeShadow: this.config.extractionJudgeShadow,
|
|
1006
|
-
getDeferredCount: () => this.deps.getLastPersistExtractionDeferredCount(),
|
|
1007
|
-
normalizedTurns,
|
|
1008
|
-
bufferKey,
|
|
1009
|
-
retainDeferredTurns: (key, retainedTurns, max) => this.deps.getBuffer().retainDeferredTurns(key, retainedTurns, max, options.retentionWindow ?? turns),
|
|
1010
|
-
clearBuffer,
|
|
1011
|
-
failOnExtractionFailure: options.failOnExtractionFailure === true
|
|
1012
|
-
});
|
|
1013
|
-
const postPersistMetadataFailed = postPersist.metadataFailed;
|
|
1014
|
-
await runPostPersistBestEffort(
|
|
1015
|
-
"during_post_persist_passive_capture",
|
|
1016
|
-
() => runPassiveCapture(normalizedTurns, {
|
|
1017
|
-
sessionKey,
|
|
1018
|
-
principal,
|
|
1019
|
-
namespace: selfNamespace,
|
|
1020
|
-
bufferKey,
|
|
1021
|
-
isLiveSession: clearBufferAfterExtraction,
|
|
1022
|
-
abortSignal: extractionAbortSignal
|
|
1023
|
-
})
|
|
1024
|
-
);
|
|
1025
|
-
if (resolvePresentationCapabilities(this.config).memoryBoxes && persistedIds.length > 0) {
|
|
1026
|
-
const extractionTopics = deriveTopicsFromExtraction(result);
|
|
1027
|
-
const firstUserTurn = turns.find((t) => t.role === "user");
|
|
1028
|
-
const boxGoal = firstUserTurn?.content?.slice(0, 100)?.trim() || void 0;
|
|
1029
|
-
await runPostPersistBestEffort(
|
|
1030
|
-
"during_memory_box",
|
|
1031
|
-
() => this.deps.boxBuilderFor(storage).onExtraction({
|
|
1032
|
-
topics: extractionTopics,
|
|
1033
|
-
memoryIds: persistedIds,
|
|
1034
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1035
|
-
goal: boxGoal
|
|
1036
|
-
})
|
|
1037
|
-
);
|
|
1038
|
-
}
|
|
1039
|
-
if (resolvePresentationCapabilities(this.config).threading && threadIdForExtraction && persistedIds.length > 0) {
|
|
1040
|
-
await runPostPersistBestEffort(
|
|
1041
|
-
"during_thread_episode_append",
|
|
1042
|
-
() => this.deps.appendPersistedThreadEpisodes(threadIdForExtraction, persistedIds)
|
|
1043
|
-
);
|
|
1044
|
-
}
|
|
1045
|
-
if (resolvePresentationCapabilities(this.config).threading && threadIdForExtraction) {
|
|
1046
|
-
const conversationContent = turns.map((t) => t.content).join(" ");
|
|
1047
1122
|
await runPostPersistBestEffort(
|
|
1048
|
-
"
|
|
1049
|
-
() => this.deps.
|
|
1123
|
+
"during_tier_migration",
|
|
1124
|
+
() => this.deps.runTierMigrationCycle(storage, "extraction")
|
|
1050
1125
|
);
|
|
1126
|
+
return {
|
|
1127
|
+
status: "completed",
|
|
1128
|
+
persistedCount: persistedIds.length,
|
|
1129
|
+
durableOutputCount,
|
|
1130
|
+
postPersistMetadataFailed
|
|
1131
|
+
};
|
|
1132
|
+
} finally {
|
|
1133
|
+
clearExtractionDeadlineTimer();
|
|
1051
1134
|
}
|
|
1052
|
-
const nonZeroExtraction = durableOutputCount > 0;
|
|
1053
|
-
try {
|
|
1054
|
-
this.deps.maybeScheduleConsolidation(nonZeroExtraction);
|
|
1055
|
-
} catch (err) {
|
|
1056
|
-
log.warn("runExtraction: consolidation scheduling failed after persistence (non-fatal)", err);
|
|
1057
|
-
}
|
|
1058
|
-
try {
|
|
1059
|
-
this.deps.requestQmdMaintenance();
|
|
1060
|
-
} catch (err) {
|
|
1061
|
-
log.warn("runExtraction: QMD maintenance scheduling failed after persistence (non-fatal)", err);
|
|
1062
|
-
}
|
|
1063
|
-
await runPostPersistBestEffort(
|
|
1064
|
-
"during_tier_migration",
|
|
1065
|
-
() => this.deps.runTierMigrationCycle(storage, "extraction")
|
|
1066
|
-
);
|
|
1067
|
-
return {
|
|
1068
|
-
status: "completed",
|
|
1069
|
-
persistedCount: persistedIds.length,
|
|
1070
|
-
durableOutputCount,
|
|
1071
|
-
postPersistMetadataFailed
|
|
1072
|
-
};
|
|
1073
1135
|
} finally {
|
|
1074
|
-
|
|
1136
|
+
if (extractionProbeOwned) this.providerBreaker.releaseProbe(extractionProbeToken);
|
|
1075
1137
|
}
|
|
1076
1138
|
}
|
|
1077
1139
|
};
|
|
@@ -1083,4 +1145,4 @@ export {
|
|
|
1083
1145
|
ExtractionDeadlineError,
|
|
1084
1146
|
ExtractionRunCoordinator
|
|
1085
1147
|
};
|
|
1086
|
-
//# sourceMappingURL=chunk-
|
|
1148
|
+
//# sourceMappingURL=chunk-R2BIVU2Z.js.map
|