@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
package/src/threading.ts
CHANGED
|
@@ -85,10 +85,56 @@ function parseConversationThread(raw: string): ConversationThread | null {
|
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
/** One session's thread-run state: its current thread and last turn time. */
|
|
89
|
+
interface ThreadingRunState {
|
|
90
|
+
currentThreadId: string | null;
|
|
91
|
+
lastTurnTimestamp: number | null;
|
|
92
|
+
}
|
|
93
|
+
|
|
88
94
|
export class ThreadingManager {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
95
|
+
/**
|
|
96
|
+
* Per-session thread-run state. One global slot let two concurrent
|
|
97
|
+
* extractions (bounded-parallel queue) interleave sessions and attach
|
|
98
|
+
* turns to the wrong thread, so the run state is keyed by session.
|
|
99
|
+
* Bounded: a long-lived daemon sees one entry per active session.
|
|
100
|
+
*/
|
|
101
|
+
private readonly runStateBySession = new Map<string, ThreadingRunState>();
|
|
102
|
+
/**
|
|
103
|
+
* Run states with a processTurn awaiting inside them. A session parked on
|
|
104
|
+
* `saveThread` can watch 512 other sessions insert and evict; dropping its
|
|
105
|
+
* state mid-await loses its thread id and forks its thread, so eviction
|
|
106
|
+
* never takes an in-flight state (the cap may be exceeded briefly by the
|
|
107
|
+
* number of in-flight extractions, which is bounded by the queue).
|
|
108
|
+
*/
|
|
109
|
+
private readonly inFlightRunStates = new Set<ThreadingRunState>();
|
|
110
|
+
private static readonly RUN_STATE_MAX_SESSIONS = 512;
|
|
111
|
+
|
|
112
|
+
private runStateFor(turn: BufferTurn): ThreadingRunState {
|
|
113
|
+
const key = turn.sessionKey ?? "";
|
|
114
|
+
let state = this.runStateBySession.get(key);
|
|
115
|
+
if (state) {
|
|
116
|
+
// Refresh recency: Map iteration is insertion-ordered, so re-putting a
|
|
117
|
+
// touched session makes eviction true LRU instead of first-in-first-out —
|
|
118
|
+
// an active session must not be the oldest entry just because it started
|
|
119
|
+
// first.
|
|
120
|
+
this.runStateBySession.delete(key);
|
|
121
|
+
this.runStateBySession.set(key, state);
|
|
122
|
+
} else {
|
|
123
|
+
state = { currentThreadId: null, lastTurnTimestamp: null };
|
|
124
|
+
this.runStateBySession.set(key, state);
|
|
125
|
+
if (this.runStateBySession.size > ThreadingManager.RUN_STATE_MAX_SESSIONS) {
|
|
126
|
+
for (const [oldestKey, oldest] of this.runStateBySession) {
|
|
127
|
+
// Never evict the state being inserted: before the caller registers
|
|
128
|
+
// it in-flight, every older entry can be in flight and the loop
|
|
129
|
+
// would otherwise delete this turn's own state and fork the thread.
|
|
130
|
+
if (oldest === state || this.inFlightRunStates.has(oldest)) continue;
|
|
131
|
+
this.runStateBySession.delete(oldestKey);
|
|
132
|
+
if (this.runStateBySession.size <= ThreadingManager.RUN_STATE_MAX_SESSIONS) break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return state;
|
|
137
|
+
}
|
|
92
138
|
|
|
93
139
|
constructor(
|
|
94
140
|
private readonly threadsDir: string,
|
|
@@ -164,18 +210,16 @@ export class ThreadingManager {
|
|
|
164
210
|
|
|
165
211
|
/**
|
|
166
212
|
* Check if we should start a new thread based on session key and time gap.
|
|
213
|
+
* State is per session, so the cross-session check the shared slot needed
|
|
214
|
+
* is gone: different sessions never share run state at all.
|
|
167
215
|
*/
|
|
168
216
|
shouldStartNewThread(turn: BufferTurn): boolean {
|
|
169
217
|
const turnTime = new Date(turn.timestamp).getTime();
|
|
170
|
-
|
|
171
|
-
// Different session key = new thread
|
|
172
|
-
if (turn.sessionKey && this.lastSessionKey && turn.sessionKey !== this.lastSessionKey) {
|
|
173
|
-
return true;
|
|
174
|
-
}
|
|
218
|
+
const state = this.runStateFor(turn);
|
|
175
219
|
|
|
176
220
|
// Time gap > threshold = new thread
|
|
177
|
-
if (
|
|
178
|
-
const gapMs = turnTime -
|
|
221
|
+
if (state.lastTurnTimestamp) {
|
|
222
|
+
const gapMs = turnTime - state.lastTurnTimestamp;
|
|
179
223
|
const gapMinutes = gapMs / (1000 * 60);
|
|
180
224
|
if (gapMinutes > this.gapMinutes) {
|
|
181
225
|
return true;
|
|
@@ -183,7 +227,7 @@ export class ThreadingManager {
|
|
|
183
227
|
}
|
|
184
228
|
|
|
185
229
|
// No current thread = new thread
|
|
186
|
-
if (!
|
|
230
|
+
if (!state.currentThreadId) {
|
|
187
231
|
return true;
|
|
188
232
|
}
|
|
189
233
|
|
|
@@ -198,41 +242,45 @@ export class ThreadingManager {
|
|
|
198
242
|
await this.ensureDirectory();
|
|
199
243
|
|
|
200
244
|
const turnTime = new Date(turn.timestamp).getTime();
|
|
245
|
+
const state = this.runStateFor(turn);
|
|
246
|
+
this.inFlightRunStates.add(state);
|
|
247
|
+
try {
|
|
248
|
+
if (this.shouldStartNewThread(turn)) {
|
|
249
|
+
// Create new thread
|
|
250
|
+
const threadId = `thread-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
|
|
251
|
+
const thread: ConversationThread = {
|
|
252
|
+
id: threadId,
|
|
253
|
+
title: "New Thread", // Will be updated later with keywords
|
|
254
|
+
createdAt: turn.timestamp,
|
|
255
|
+
updatedAt: turn.timestamp,
|
|
256
|
+
sessionKey: turn.sessionKey,
|
|
257
|
+
episodeIds: [...episodeIds],
|
|
258
|
+
linkedThreadIds: [],
|
|
259
|
+
};
|
|
201
260
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
await this.saveThread(thread);
|
|
216
|
-
this.currentThreadId = threadId;
|
|
217
|
-
log.debug(`created new thread ${threadId}`);
|
|
218
|
-
} else if (this.currentThreadId) {
|
|
219
|
-
// Add episodes to current thread
|
|
220
|
-
const thread = await this.loadThread(this.currentThreadId);
|
|
221
|
-
if (thread) {
|
|
222
|
-
for (const id of episodeIds) {
|
|
223
|
-
if (!thread.episodeIds.includes(id)) {
|
|
224
|
-
thread.episodeIds.push(id);
|
|
261
|
+
await this.saveThread(thread);
|
|
262
|
+
state.currentThreadId = threadId;
|
|
263
|
+
log.debug(`created new thread ${threadId}`);
|
|
264
|
+
} else if (state.currentThreadId) {
|
|
265
|
+
// Add episodes to current thread
|
|
266
|
+
const thread = await this.loadThread(state.currentThreadId);
|
|
267
|
+
if (thread) {
|
|
268
|
+
for (const id of episodeIds) {
|
|
269
|
+
if (!thread.episodeIds.includes(id)) {
|
|
270
|
+
thread.episodeIds.push(id);
|
|
271
|
+
}
|
|
225
272
|
}
|
|
273
|
+
thread.updatedAt = turn.timestamp;
|
|
274
|
+
await this.saveThread(thread);
|
|
226
275
|
}
|
|
227
|
-
thread.updatedAt = turn.timestamp;
|
|
228
|
-
await this.saveThread(thread);
|
|
229
276
|
}
|
|
230
|
-
}
|
|
231
277
|
|
|
232
|
-
|
|
233
|
-
this.lastSessionKey = turn.sessionKey ?? null;
|
|
278
|
+
state.lastTurnTimestamp = turnTime;
|
|
234
279
|
|
|
235
|
-
|
|
280
|
+
return state.currentThreadId!;
|
|
281
|
+
} finally {
|
|
282
|
+
this.inFlightRunStates.delete(state);
|
|
283
|
+
}
|
|
236
284
|
}
|
|
237
285
|
|
|
238
286
|
/**
|
|
@@ -378,18 +426,20 @@ export class ThreadingManager {
|
|
|
378
426
|
}
|
|
379
427
|
|
|
380
428
|
/**
|
|
381
|
-
* Get the current thread ID (if any).
|
|
429
|
+
* Get the current thread ID (if any). With per-session run state there is
|
|
430
|
+
* no single current thread; null unless exactly one session is tracked.
|
|
382
431
|
*/
|
|
383
432
|
getCurrentThreadId(): string | null {
|
|
384
|
-
|
|
433
|
+
if (this.runStateBySession.size === 1) {
|
|
434
|
+
return this.runStateBySession.values().next().value?.currentThreadId ?? null;
|
|
435
|
+
}
|
|
436
|
+
return null;
|
|
385
437
|
}
|
|
386
438
|
|
|
387
439
|
/**
|
|
388
440
|
* Reset threading state (e.g., on plugin restart).
|
|
389
441
|
*/
|
|
390
442
|
reset(): void {
|
|
391
|
-
this.
|
|
392
|
-
this.lastTurnTimestamp = null;
|
|
393
|
-
this.lastSessionKey = null;
|
|
443
|
+
this.runStateBySession.clear();
|
|
394
444
|
}
|
|
395
445
|
}
|
package/src/types.ts
CHANGED
|
@@ -722,6 +722,8 @@ export interface PluginConfig
|
|
|
722
722
|
/** Distinct sessions the extraction buffer admits before backpressure (#3303). */
|
|
723
723
|
bufferMaxSessions: number;
|
|
724
724
|
bufferMaxMinutes: number;
|
|
725
|
+
/** Queue depth cap; default 1 = serial queue, same-buffer tasks never overlap. Applies at daemon start. */
|
|
726
|
+
extractionQueueConcurrency: number;
|
|
725
727
|
/**
|
|
726
728
|
* Debounce window (ms) for persisting the smart buffer to `state/buffer.json`
|
|
727
729
|
* (issue #1909). Steady-state buffering coalesces the whole-state serialize
|