@remnic/core 9.3.728 → 9.3.729
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-boundary.d.ts +2 -2
- package/dist/access-cli.js +1 -1
- package/dist/access-http.d.ts +2 -2
- package/dist/access-mcp.d.ts +2 -2
- package/dist/access-operations.d.ts +7 -7
- package/dist/access-schema.d.ts +42 -42
- package/dist/{access-service-Bgpjxo4f.d.ts → access-service-BXMJqkTA.d.ts} +1 -1
- package/dist/access-service.d.ts +2 -2
- package/dist/access-surface-catalog.d.ts +2 -2
- package/dist/bootstrap.d.ts +1 -1
- package/dist/{chunk-QNEUZIAH.js → chunk-HEDZUSCS.js} +136 -66
- package/dist/chunk-HEDZUSCS.js.map +1 -0
- package/dist/{cli-BLME420h.d.ts → cli-DmAiDd8A.d.ts} +2 -2
- package/dist/cli.d.ts +3 -3
- package/dist/explicit-capture.d.ts +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1 -1
- package/dist/mcp-memory-inspector-app.d.ts +2 -2
- package/dist/{orchestrator-DqPAz8ot.d.ts → orchestrator-BR0sGsME.d.ts} +104 -26
- package/dist/orchestrator.d.ts +1 -1
- package/dist/orchestrator.js +1 -1
- package/dist/schemas.d.ts +52 -52
- package/dist/shared-context/manager.d.ts +2 -2
- package/dist/transfer/types.d.ts +24 -24
- package/package.json +2 -2
- package/src/orchestration/extraction-queue-coordinator.ts +175 -0
- package/src/orchestrator-extraction-queue.test.ts +26 -38
- package/src/orchestrator-flush.test.ts +10 -15
- package/src/orchestrator.ts +14 -78
- package/dist/chunk-QNEUZIAH.js.map +0 -1
|
@@ -746,6 +746,130 @@ var TierMigrationCoordinator = class {
|
|
|
746
746
|
}
|
|
747
747
|
};
|
|
748
748
|
|
|
749
|
+
// src/orchestration/extraction-queue-coordinator.ts
|
|
750
|
+
var ExtractionQueueCoordinator = class {
|
|
751
|
+
/**
|
|
752
|
+
* Background serial queue for extractions (agent_end optimization).
|
|
753
|
+
* Queue stores tasks that resolve when extraction should run.
|
|
754
|
+
*/
|
|
755
|
+
queue = [];
|
|
756
|
+
/** Whether the serial drain loop is currently running. */
|
|
757
|
+
processing = false;
|
|
758
|
+
/** Current queue depth (idle-wait + test seam). */
|
|
759
|
+
get length() {
|
|
760
|
+
return this.queue.length;
|
|
761
|
+
}
|
|
762
|
+
/** Whether the serial drain loop is currently running (idle-wait + test seam). */
|
|
763
|
+
get isProcessing() {
|
|
764
|
+
return this.processing;
|
|
765
|
+
}
|
|
766
|
+
/**
|
|
767
|
+
* Enqueue a task and start the serial processor if it is idle. This is
|
|
768
|
+
* the production entry point — the orchestrator's `queueBufferedExtraction`
|
|
769
|
+
* builds each task closure and hands it here.
|
|
770
|
+
*/
|
|
771
|
+
enqueue(task) {
|
|
772
|
+
this.queue.push(task);
|
|
773
|
+
if (!this.processing) {
|
|
774
|
+
this.processing = true;
|
|
775
|
+
this.processQueue().catch((err) => {
|
|
776
|
+
this.logExtractionQueueFailure(err, "processor");
|
|
777
|
+
this.processing = false;
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
/**
|
|
782
|
+
* Background serial queue processor.
|
|
783
|
+
* Processes extractions one at a time to avoid race conditions.
|
|
784
|
+
* Called automatically when items are queued via `enqueue`; also exposed
|
|
785
|
+
* for the characterization tests that push raw tasks and assert drain
|
|
786
|
+
* semantics directly.
|
|
787
|
+
*/
|
|
788
|
+
async processQueue() {
|
|
789
|
+
while (this.queue.length > 0) {
|
|
790
|
+
const task = this.queue.shift();
|
|
791
|
+
if (task) {
|
|
792
|
+
try {
|
|
793
|
+
await task();
|
|
794
|
+
} catch (err) {
|
|
795
|
+
this.logExtractionQueueFailure(err, "task");
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
this.processing = false;
|
|
800
|
+
}
|
|
801
|
+
/**
|
|
802
|
+
* Classify + log a failure from either the per-task catch inside
|
|
803
|
+
* `processQueue()` or the outer `processQueue().catch(...)` in
|
|
804
|
+
* `enqueue()`. Issue #549: `throwIfRecallAborted`
|
|
805
|
+
* (used throughout `runExtraction`) raises an Error whose `name` is
|
|
806
|
+
* `"AbortError"`. That path fires when `before_reset` aborts a
|
|
807
|
+
* queued task to avoid duplicate extraction — it is intentional
|
|
808
|
+
* cancellation, not a failure. Downgrading the log to debug
|
|
809
|
+
* prevents spurious `error`-level lines that routinely appear
|
|
810
|
+
* right next to a successful `persisted: N facts, M entities` log
|
|
811
|
+
* and that confuse operators into thinking extraction is broken.
|
|
812
|
+
* Genuine extraction failures (network, parse, I/O) still log at
|
|
813
|
+
* `error`.
|
|
814
|
+
*
|
|
815
|
+
* Source differentiates the two call sites so the log message
|
|
816
|
+
* names the right layer (`task` vs `processor`).
|
|
817
|
+
*/
|
|
818
|
+
logExtractionQueueFailure(err, source) {
|
|
819
|
+
const aborted = source === "task" ? "background extraction task aborted (session transition)" : "background extraction queue processor aborted (session transition)";
|
|
820
|
+
const failed = source === "task" ? "background extraction task failed" : "background extraction queue processor failed";
|
|
821
|
+
if (isAbortError(err)) {
|
|
822
|
+
log.debug(aborted);
|
|
823
|
+
} else {
|
|
824
|
+
log.error(failed, err);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
/**
|
|
828
|
+
* Wait until the extraction queue is fully drained (no tasks queued, no
|
|
829
|
+
* drain in flight) or `timeoutMs` elapses. Used by bootstrap (after a
|
|
830
|
+
* dry-run import) and by tests that need to assert extraction settled.
|
|
831
|
+
* Returns false on timeout, true once idle.
|
|
832
|
+
*/
|
|
833
|
+
async waitForIdle(timeoutMs = 6e4) {
|
|
834
|
+
const started = Date.now();
|
|
835
|
+
while (this.processing || this.queue.length > 0) {
|
|
836
|
+
if (Date.now() - started > timeoutMs) {
|
|
837
|
+
log.warn(`waitForExtractionIdle timed out after ${timeoutMs}ms`);
|
|
838
|
+
return false;
|
|
839
|
+
}
|
|
840
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
841
|
+
setTimeout(resolve, 50);
|
|
842
|
+
await promise;
|
|
843
|
+
}
|
|
844
|
+
return true;
|
|
845
|
+
}
|
|
846
|
+
// ── Test seams ─────────────────────────────────────────────────────────
|
|
847
|
+
// Mirror the pre-extraction `orchestrator.extractionQueue` /
|
|
848
|
+
// `orchestrator.queueProcessing` direct-field access the characterization
|
|
849
|
+
// and flush deadline tests relied on. Each is a thin, well-named handle
|
|
850
|
+
// onto the coordinator's private state — no behavior change.
|
|
851
|
+
/**
|
|
852
|
+
* Push a raw task WITHOUT auto-starting the processor, matching the
|
|
853
|
+
* pre-extraction `this.extractionQueue.push(...)` used by the
|
|
854
|
+
* characterization tests that drive the drain manually via `processQueue`.
|
|
855
|
+
*/
|
|
856
|
+
pushRaw(task) {
|
|
857
|
+
this.queue.push(task);
|
|
858
|
+
}
|
|
859
|
+
/** Remove + return the front task (test seam for the flush deadline tests). */
|
|
860
|
+
shift() {
|
|
861
|
+
return this.queue.shift();
|
|
862
|
+
}
|
|
863
|
+
/**
|
|
864
|
+
* Force the processor-busy flag so `enqueue` does not auto-start the
|
|
865
|
+
* drain — used by the flush deadline test to simulate a busy queue and
|
|
866
|
+
* assert a queued task's deadline expires while it waits.
|
|
867
|
+
*/
|
|
868
|
+
setProcessingForTest(value) {
|
|
869
|
+
this.processing = value;
|
|
870
|
+
}
|
|
871
|
+
};
|
|
872
|
+
|
|
749
873
|
// src/maintenance/pattern-reinforcement.ts
|
|
750
874
|
function patternReinforcementKey(content) {
|
|
751
875
|
return content.trim().toLowerCase().replace(/\s+/g, " ").slice(0, 200);
|
|
@@ -2998,10 +3122,14 @@ var Orchestrator = class _Orchestrator {
|
|
|
2998
3122
|
passiveCorrectionDedup = /* @__PURE__ */ new Set();
|
|
2999
3123
|
_passiveCorrectionService = null;
|
|
3000
3124
|
passiveCorrectionTelemetry = { detected: 0, queued: 0, autoApplied: 0, suppressedReasonCounts: {} };
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3125
|
+
/**
|
|
3126
|
+
* Background serial extraction queue coordinator (issue #1526 — moved
|
|
3127
|
+
* from inline `extractionQueue`/`queueProcessing` fields). Owns queue
|
|
3128
|
+
* state + scheduling + the serial drain + failure classification; the
|
|
3129
|
+
* orchestrator builds each task closure in `queueBufferedExtraction` and
|
|
3130
|
+
* hands it to `enqueue`.
|
|
3131
|
+
*/
|
|
3132
|
+
extractionQueueCoordinator;
|
|
3005
3133
|
heartbeatObserverChains = /* @__PURE__ */ new Map();
|
|
3006
3134
|
recentExtractionFingerprints = /* @__PURE__ */ new Map();
|
|
3007
3135
|
consolidationObservers = /* @__PURE__ */ new Set();
|
|
@@ -3706,6 +3834,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
3706
3834
|
namespaceSearchRouter: this.namespaceSearchRouter,
|
|
3707
3835
|
namespaceCatalog: this.namespaceCatalog
|
|
3708
3836
|
});
|
|
3837
|
+
this.extractionQueueCoordinator = new ExtractionQueueCoordinator();
|
|
3709
3838
|
const conversationIndexRuntime = createConversationIndexRuntime(config, {
|
|
3710
3839
|
getQmd: () => this.conversationQmd,
|
|
3711
3840
|
getFaiss: () => this.conversationFaiss
|
|
@@ -4928,15 +5057,7 @@ ${doc.content}` : doc.content,
|
|
|
4928
5057
|
return result;
|
|
4929
5058
|
}
|
|
4930
5059
|
async waitForExtractionIdle(timeoutMs = 6e4) {
|
|
4931
|
-
|
|
4932
|
-
while (this.queueProcessing || this.extractionQueue.length > 0) {
|
|
4933
|
-
if (Date.now() - started > timeoutMs) {
|
|
4934
|
-
log.warn(`waitForExtractionIdle timed out after ${timeoutMs}ms`);
|
|
4935
|
-
return false;
|
|
4936
|
-
}
|
|
4937
|
-
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
4938
|
-
}
|
|
4939
|
-
return true;
|
|
5060
|
+
return this.extractionQueueCoordinator.waitForIdle(timeoutMs);
|
|
4940
5061
|
}
|
|
4941
5062
|
async waitForConsolidationIdle(timeoutMs = 6e4) {
|
|
4942
5063
|
const started = Date.now();
|
|
@@ -11161,7 +11282,7 @@ _Context: ${topQuestion.context}_`
|
|
|
11161
11282
|
settleTask(new Error("replay extraction deadline exceeded (queue_wait)"));
|
|
11162
11283
|
}, remainingMs);
|
|
11163
11284
|
}
|
|
11164
|
-
this.
|
|
11285
|
+
this.extractionQueueCoordinator.enqueue(async () => {
|
|
11165
11286
|
if (settled) return;
|
|
11166
11287
|
if (typeof extractionDeadlineMs === "number" && extractionDeadlineMs <= Date.now()) {
|
|
11167
11288
|
settleTask(new Error("replay extraction deadline exceeded (queue_wait)"));
|
|
@@ -11187,13 +11308,6 @@ _Context: ${topQuestion.context}_`
|
|
|
11187
11308
|
}
|
|
11188
11309
|
}
|
|
11189
11310
|
});
|
|
11190
|
-
if (!this.queueProcessing) {
|
|
11191
|
-
this.queueProcessing = true;
|
|
11192
|
-
this.processQueue().catch((err) => {
|
|
11193
|
-
this.logExtractionQueueFailure(err, "processor");
|
|
11194
|
-
this.queueProcessing = false;
|
|
11195
|
-
});
|
|
11196
|
-
}
|
|
11197
11311
|
log.debug(`queued extraction from ${reason}`);
|
|
11198
11312
|
}
|
|
11199
11313
|
normalizeExtractionFingerprintTurns(turns) {
|
|
@@ -11237,50 +11351,6 @@ ${normalized}`).digest("hex");
|
|
|
11237
11351
|
}
|
|
11238
11352
|
return true;
|
|
11239
11353
|
}
|
|
11240
|
-
/**
|
|
11241
|
-
* Background serial queue processor.
|
|
11242
|
-
* Processes extractions one at a time to avoid race conditions.
|
|
11243
|
-
* Called automatically when items are queued.
|
|
11244
|
-
*/
|
|
11245
|
-
async processQueue() {
|
|
11246
|
-
while (this.extractionQueue.length > 0) {
|
|
11247
|
-
const task = this.extractionQueue.shift();
|
|
11248
|
-
if (task) {
|
|
11249
|
-
try {
|
|
11250
|
-
await task();
|
|
11251
|
-
} catch (err) {
|
|
11252
|
-
this.logExtractionQueueFailure(err, "task");
|
|
11253
|
-
}
|
|
11254
|
-
}
|
|
11255
|
-
}
|
|
11256
|
-
this.queueProcessing = false;
|
|
11257
|
-
}
|
|
11258
|
-
/**
|
|
11259
|
-
* Classify + log a failure from either the per-task catch inside
|
|
11260
|
-
* `processQueue()` or the outer `processQueue().catch(...)` in
|
|
11261
|
-
* `queueBufferedExtraction()`. Issue #549: `throwIfRecallAborted`
|
|
11262
|
-
* (used throughout `runExtraction`) raises an Error whose `name` is
|
|
11263
|
-
* `"AbortError"`. That path fires when `before_reset` aborts a
|
|
11264
|
-
* queued task to avoid duplicate extraction — it is intentional
|
|
11265
|
-
* cancellation, not a failure. Downgrading the log to debug
|
|
11266
|
-
* prevents spurious `error`-level lines that routinely appear
|
|
11267
|
-
* right next to a successful `persisted: N facts, M entities` log
|
|
11268
|
-
* and that confuse operators into thinking extraction is broken.
|
|
11269
|
-
* Genuine extraction failures (network, parse, I/O) still log at
|
|
11270
|
-
* `error`.
|
|
11271
|
-
*
|
|
11272
|
-
* Source differentiates the two call sites so the log message
|
|
11273
|
-
* names the right layer (`task` vs `processor`).
|
|
11274
|
-
*/
|
|
11275
|
-
logExtractionQueueFailure(err, source) {
|
|
11276
|
-
const aborted = source === "task" ? "background extraction task aborted (session transition)" : "background extraction queue processor aborted (session transition)";
|
|
11277
|
-
const failed = source === "task" ? "background extraction task failed" : "background extraction queue processor failed";
|
|
11278
|
-
if (isAbortError(err)) {
|
|
11279
|
-
log.debug(aborted);
|
|
11280
|
-
} else {
|
|
11281
|
-
log.error(failed, err);
|
|
11282
|
-
}
|
|
11283
|
-
}
|
|
11284
11354
|
/**
|
|
11285
11355
|
* Passive correction capture (issue #1581) — detects corrections expressed
|
|
11286
11356
|
* passively in conversation turns and routes them to the Correction Contract
|
|
@@ -16322,4 +16392,4 @@ export {
|
|
|
16322
16392
|
resolvePersistedMemoryRelativePath,
|
|
16323
16393
|
Orchestrator
|
|
16324
16394
|
};
|
|
16325
|
-
//# sourceMappingURL=chunk-
|
|
16395
|
+
//# sourceMappingURL=chunk-HEDZUSCS.js.map
|