stratagate-dsh 0.2.55 → 0.2.57
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/CHANGELOG.md +100 -90
- package/README.md +44 -43
- package/dist/client.js +3 -3
- package/dist/index.js +149 -14
- package/dist/index.js.map +1 -1
- package/package.json +181 -181
package/dist/index.js
CHANGED
|
@@ -2986,6 +2986,35 @@ var StrataGate = class _StrataGate {
|
|
|
2986
2986
|
listSummaryJobs() {
|
|
2987
2987
|
return [...this.summaryJobs.values()];
|
|
2988
2988
|
}
|
|
2989
|
+
/** Give one terminally failed Block Summary job a fresh, user-requested retry budget. */
|
|
2990
|
+
async retryBlockSummary(id) {
|
|
2991
|
+
const blockId = id.trim();
|
|
2992
|
+
if (!blockId) throw new TypeError("Block id must not be empty");
|
|
2993
|
+
const block = this.blocks.find((candidate) => candidate.id === blockId);
|
|
2994
|
+
if (!block) throw new Error(`Unknown block: ${blockId}`);
|
|
2995
|
+
if (block.processingStatus !== "pending") throw new Error(`Block ${blockId} is already ready`);
|
|
2996
|
+
await this.commitMutation(() => {
|
|
2997
|
+
const job = this.summaryJobs.get(blockId);
|
|
2998
|
+
if (!job) throw new Error(`Missing summary job for block: ${blockId}`);
|
|
2999
|
+
if (job.status !== "failed" || job.nextRetryAt !== null) {
|
|
3000
|
+
throw new Error(`Block ${blockId} Summary has not exhausted automatic retries`);
|
|
3001
|
+
}
|
|
3002
|
+
this.summaryJobs.set(blockId, {
|
|
3003
|
+
...job,
|
|
3004
|
+
status: "pending",
|
|
3005
|
+
attempts: 0,
|
|
3006
|
+
lastError: null,
|
|
3007
|
+
nextRetryAt: null,
|
|
3008
|
+
updatedAt: toUtc8Iso(this.now())
|
|
3009
|
+
});
|
|
3010
|
+
});
|
|
3011
|
+
const extractedEvents = await this.processBlock(block, { retryFailed: false });
|
|
3012
|
+
const processed = this.blocks.find((candidate) => candidate.id === blockId);
|
|
3013
|
+
const readyBlocks = processed?.processingStatus === "ready" ? [processed] : [];
|
|
3014
|
+
const projectedElements = await this.projectEligibleElements() ?? [];
|
|
3015
|
+
await this.projectEligibleGraph();
|
|
3016
|
+
return { sealedBlocks: [], readyBlocks, extractedEvents, projectedElements };
|
|
3017
|
+
}
|
|
2989
3018
|
listElementProjectionJobs() {
|
|
2990
3019
|
return [...this.elementProjectionJobs.values()];
|
|
2991
3020
|
}
|
|
@@ -5566,6 +5595,8 @@ var StrataGateRuntime = class {
|
|
|
5566
5595
|
migrationTimers = /* @__PURE__ */ new Map();
|
|
5567
5596
|
derivationTimers = /* @__PURE__ */ new Map();
|
|
5568
5597
|
derivationRuns = /* @__PURE__ */ new Map();
|
|
5598
|
+
knownSessions = /* @__PURE__ */ new Map();
|
|
5599
|
+
pendingSurfaceSync = /* @__PURE__ */ new Map();
|
|
5569
5600
|
adminSnapshotCache = /* @__PURE__ */ new Map();
|
|
5570
5601
|
externalImportRuns = /* @__PURE__ */ new Map();
|
|
5571
5602
|
feedbackDrafts = /* @__PURE__ */ new Map();
|
|
@@ -5936,6 +5967,33 @@ var StrataGateRuntime = class {
|
|
|
5936
5967
|
}
|
|
5937
5968
|
return changed;
|
|
5938
5969
|
}
|
|
5970
|
+
/** Finish native-surface replacement when an admin retry ran without the target session loaded. */
|
|
5971
|
+
async syncPendingRetrySurface(session, memory) {
|
|
5972
|
+
const namespace = this.namespaceFor(session);
|
|
5973
|
+
const threadId = String(session.id);
|
|
5974
|
+
const pending = [...this.pendingSurfaceSync.entries()].filter(([, item]) => item.namespace === namespace);
|
|
5975
|
+
if (pending.length === 0) return;
|
|
5976
|
+
const contexts = new Map(memory.getBlockContext(threadId).map((context) => [context.id, context]));
|
|
5977
|
+
const existing = currentBlockSurfaceMessages(session);
|
|
5978
|
+
let changed = false;
|
|
5979
|
+
for (const [key, { blockId }] of pending) {
|
|
5980
|
+
if (existing.has(blockId)) {
|
|
5981
|
+
this.pendingSurfaceSync.delete(key);
|
|
5982
|
+
continue;
|
|
5983
|
+
}
|
|
5984
|
+
const block = memory.listBlocks().find((candidate) => candidate.id === blockId && candidate.threadId === threadId);
|
|
5985
|
+
const context = contexts.get(blockId);
|
|
5986
|
+
if (!block || block.processingStatus !== "ready" || !context) continue;
|
|
5987
|
+
try {
|
|
5988
|
+
this.replaceSealedSurface(session, block, context, dshTurnAtBlockEnd(session, block));
|
|
5989
|
+
this.pendingSurfaceSync.delete(key);
|
|
5990
|
+
changed = true;
|
|
5991
|
+
} catch (error) {
|
|
5992
|
+
this.onIngestError(error);
|
|
5993
|
+
}
|
|
5994
|
+
}
|
|
5995
|
+
if (changed) await this.flushNativeSession(session);
|
|
5996
|
+
}
|
|
5939
5997
|
// Keep the ingestion error for callers that explicitly require a flushed run.
|
|
5940
5998
|
async settleIngestion() {
|
|
5941
5999
|
await this.ingestTail;
|
|
@@ -6455,6 +6513,44 @@ var StrataGateRuntime = class {
|
|
|
6455
6513
|
});
|
|
6456
6514
|
return update;
|
|
6457
6515
|
}
|
|
6516
|
+
async adminRetryBlockSummary(namespace, id) {
|
|
6517
|
+
const key = namespace.trim();
|
|
6518
|
+
const blockId = id.trim();
|
|
6519
|
+
if (!key) throw new TypeError("StrataGate admin namespace must not be empty");
|
|
6520
|
+
if (!blockId) throw new TypeError("Block id must not be empty");
|
|
6521
|
+
const update = this.settingsTail.catch(() => {
|
|
6522
|
+
}).then(async () => {
|
|
6523
|
+
await this.flush();
|
|
6524
|
+
const { memory, owned } = await this.openAdminMemory(key, { derivation: true });
|
|
6525
|
+
try {
|
|
6526
|
+
await this.refreshExternalImportMemory(key, memory);
|
|
6527
|
+
const block = memory.listBlocks().find((candidate) => candidate.id === blockId);
|
|
6528
|
+
if (!block) throw new Error(`Unknown block: ${blockId}`);
|
|
6529
|
+
const threadId = block.threadId ?? `admin-summary-retry:${blockId}`;
|
|
6530
|
+
const session = block.threadId ? this.knownSessions.get(block.threadId)?.deref() : void 0;
|
|
6531
|
+
const resumed = session && this.namespaceFor(session) === key ? await this.models.run(session, () => memory.retryBlockSummary(blockId)) : await this.models.runDetached(threadId, () => memory.retryBlockSummary(blockId));
|
|
6532
|
+
await this.persistSuccessfulResponses(memory);
|
|
6533
|
+
if (resumed.readyBlocks.some(({ id: readyId }) => readyId === blockId) && block.threadId) {
|
|
6534
|
+
this.pendingSurfaceSync.set(`${key}\0${blockId}`, { namespace: key, blockId });
|
|
6535
|
+
if (session && this.namespaceFor(session) === key) await this.syncPendingRetrySurface(session, memory);
|
|
6536
|
+
}
|
|
6537
|
+
const summaryJob = memory.listSummaryJobs().find(({ blockId: candidateId }) => candidateId === blockId);
|
|
6538
|
+
return {
|
|
6539
|
+
blockId,
|
|
6540
|
+
processingStatus: block.processingStatus,
|
|
6541
|
+
ready: block.processingStatus === "ready",
|
|
6542
|
+
summaryJob: summaryJob ?? null,
|
|
6543
|
+
surfaceUpdated: !this.pendingSurfaceSync.has(`${key}\0${blockId}`)
|
|
6544
|
+
};
|
|
6545
|
+
} finally {
|
|
6546
|
+
if (owned) await memory.close();
|
|
6547
|
+
}
|
|
6548
|
+
});
|
|
6549
|
+
this.settingsTail = update.then(() => {
|
|
6550
|
+
}, () => {
|
|
6551
|
+
});
|
|
6552
|
+
return update;
|
|
6553
|
+
}
|
|
6458
6554
|
async applyBlockDecayLambda(value) {
|
|
6459
6555
|
await this.flush();
|
|
6460
6556
|
this.blockDecayLambda = value;
|
|
@@ -6517,8 +6613,9 @@ var StrataGateRuntime = class {
|
|
|
6517
6613
|
}
|
|
6518
6614
|
}
|
|
6519
6615
|
}
|
|
6520
|
-
space(session) {
|
|
6616
|
+
async space(session) {
|
|
6521
6617
|
const namespace = this.namespaceFor(session);
|
|
6618
|
+
this.knownSessions.set(String(session.id), new WeakRef(session));
|
|
6522
6619
|
this.rememberWorkspace(namespace, session.header.cwd);
|
|
6523
6620
|
let opening = this.spaces.get(namespace);
|
|
6524
6621
|
if (!opening) {
|
|
@@ -6531,20 +6628,20 @@ var StrataGateRuntime = class {
|
|
|
6531
6628
|
extractor: this.models.extractor,
|
|
6532
6629
|
graphProjector: this.models.graphProjector,
|
|
6533
6630
|
disableElementProjection: true
|
|
6534
|
-
}).then(async (
|
|
6631
|
+
}).then(async (memory2) => {
|
|
6535
6632
|
try {
|
|
6536
6633
|
try {
|
|
6537
|
-
await
|
|
6538
|
-
const contexts =
|
|
6634
|
+
await memory2.resumePendingWork({ deferDerivation: true, threadId: String(session.id) });
|
|
6635
|
+
const contexts = memory2.getBlockContext(String(session.id));
|
|
6539
6636
|
this.syncDecayedBlockSurface(session, contexts);
|
|
6540
6637
|
} finally {
|
|
6541
|
-
await this.persistSuccessfulResponses(
|
|
6638
|
+
await this.persistSuccessfulResponses(memory2);
|
|
6542
6639
|
}
|
|
6543
|
-
this.scheduleGraphMigration(session,
|
|
6544
|
-
this.scheduleBlockDerivation(session,
|
|
6545
|
-
return
|
|
6640
|
+
this.scheduleGraphMigration(session, memory2);
|
|
6641
|
+
this.scheduleBlockDerivation(session, memory2);
|
|
6642
|
+
return memory2;
|
|
6546
6643
|
} catch (error) {
|
|
6547
|
-
await
|
|
6644
|
+
await memory2.close().catch(() => {
|
|
6548
6645
|
});
|
|
6549
6646
|
throw error;
|
|
6550
6647
|
}
|
|
@@ -6554,7 +6651,9 @@ var StrataGateRuntime = class {
|
|
|
6554
6651
|
if (this.spaces.get(namespace) === opening) this.spaces.delete(namespace);
|
|
6555
6652
|
});
|
|
6556
6653
|
}
|
|
6557
|
-
|
|
6654
|
+
const memory = await opening;
|
|
6655
|
+
await this.syncPendingRetrySurface(session, memory);
|
|
6656
|
+
return memory;
|
|
6558
6657
|
}
|
|
6559
6658
|
async searchGraph(session, query, limit = 8) {
|
|
6560
6659
|
await this.flush();
|
|
@@ -6658,7 +6757,7 @@ var StrataGateRuntime = class {
|
|
|
6658
6757
|
noteNewCoreJobFailures(session, before, memory) {
|
|
6659
6758
|
if ([...this.failedCoreJobs(memory)].some((failure) => !before.has(failure))) this.notePluginError(session);
|
|
6660
6759
|
}
|
|
6661
|
-
async openAdminMemory(namespace) {
|
|
6760
|
+
async openAdminMemory(namespace, options = {}) {
|
|
6662
6761
|
const active = this.spaces.get(namespace);
|
|
6663
6762
|
if (active) return { memory: await active, owned: false };
|
|
6664
6763
|
if (this.config.database === ":memory:" || !existsSync(this.config.database)) {
|
|
@@ -6670,6 +6769,10 @@ var StrataGateRuntime = class {
|
|
|
6670
6769
|
namespace,
|
|
6671
6770
|
blockTurnSize: this.blockTurnSize,
|
|
6672
6771
|
blockDecayLambda: this.blockDecayLambda,
|
|
6772
|
+
...options.derivation ? {
|
|
6773
|
+
summarizer: this.models.summarizer,
|
|
6774
|
+
extractor: this.models.extractor
|
|
6775
|
+
} : {},
|
|
6673
6776
|
graphProjector: this.models.graphProjector,
|
|
6674
6777
|
disableElementProjection: true
|
|
6675
6778
|
}),
|
|
@@ -7315,7 +7418,7 @@ function clusterKnowledgeGraph(rawNodes, rawEdges) {
|
|
|
7315
7418
|
}
|
|
7316
7419
|
|
|
7317
7420
|
// src/web.ts
|
|
7318
|
-
var STRATAGATE_DSH_VERSION = "0.2.
|
|
7421
|
+
var STRATAGATE_DSH_VERSION = "0.2.57";
|
|
7319
7422
|
var LEGACY_THREAD_ID = "__legacy__";
|
|
7320
7423
|
var nodeRequire = createRequire(import.meta.url);
|
|
7321
7424
|
function installedPackageVersion(names) {
|
|
@@ -7458,9 +7561,24 @@ async function overview(runtime, cachedEntries) {
|
|
|
7458
7561
|
const rows = [];
|
|
7459
7562
|
for (const { namespace, snapshot } of entries) {
|
|
7460
7563
|
if (!snapshot) continue;
|
|
7461
|
-
const failedJobs = snapshot.extractionJobs.filter(({ status }) => status === "failed").length + snapshot.graphProjectionJobs.filter(({ status }) => status === "failed").length;
|
|
7564
|
+
const failedJobs = snapshot.summaryJobs.filter(({ status }) => status === "failed").length + snapshot.extractionJobs.filter(({ status }) => status === "failed").length + snapshot.graphProjectionJobs.filter(({ status }) => status === "failed").length;
|
|
7462
7565
|
const processingJobs = snapshot.summaryJobs.filter(({ status, nextRetryAt }) => status === "pending" || status === "running" || status === "failed" && nextRetryAt !== null).length + snapshot.extractionJobs.filter(({ status, nextRetryAt }) => status === "running" || status === "failed" && nextRetryAt !== null).length + snapshot.graphProjectionJobs.filter(({ status }) => status === "pending" || status === "running").length;
|
|
7463
7566
|
const failedJobDetails = [
|
|
7567
|
+
...snapshot.summaryJobs.filter(({ status }) => status === "failed").map((job) => {
|
|
7568
|
+
const block = snapshot.blocks.find(({ id }) => id === job.blockId);
|
|
7569
|
+
return {
|
|
7570
|
+
id: job.blockId,
|
|
7571
|
+
kind: "block-summary",
|
|
7572
|
+
attempts: job.attempts,
|
|
7573
|
+
nextRetryAt: job.nextRetryAt,
|
|
7574
|
+
lastError: job.lastError?.slice(0, 500) ?? null,
|
|
7575
|
+
lastErrorFull: job.lastError,
|
|
7576
|
+
updatedAt: job.updatedAt,
|
|
7577
|
+
threadId: block?.threadId ?? null,
|
|
7578
|
+
sequence: block?.sequence ?? null,
|
|
7579
|
+
turnRange: block ? [block.startTurn, block.endTurn] : null
|
|
7580
|
+
};
|
|
7581
|
+
}),
|
|
7464
7582
|
...snapshot.extractionJobs.filter(({ status }) => status === "failed").map((job) => ({
|
|
7465
7583
|
id: job.blockId,
|
|
7466
7584
|
kind: "event-extraction",
|
|
@@ -7855,7 +7973,7 @@ async function memories(runtime, url) {
|
|
|
7855
7973
|
const failedProjection = projections.find(({ status: status2 }) => status2 === "failed");
|
|
7856
7974
|
const pendingProjection = projections.some(({ status: status2 }) => status2 === "pending" || status2 === "running");
|
|
7857
7975
|
const needsExtraction = source.shouldExtract === true;
|
|
7858
|
-
const status = extraction?.status === "failed" || failedProjection ? "failed" : extraction?.status === "succeeded" || extraction?.status === "skipped" ? pendingProjection ? "processing" : "organized" : needsExtraction ? "waiting" : "organized";
|
|
7976
|
+
const status = summary?.status === "failed" ? "failed" : summary?.status === "pending" || summary?.status === "running" || !summary && source.processingStatus === "pending" ? "processing" : extraction?.status === "failed" || failedProjection ? "failed" : extraction?.status === "succeeded" || extraction?.status === "skipped" ? pendingProjection ? "processing" : "organized" : needsExtraction ? "waiting" : "organized";
|
|
7859
7977
|
const blockPosition = scopedBlocks.findIndex(({ id }) => id === block.id) + 1;
|
|
7860
7978
|
const latestBlockPosition = scopedBlocks.length;
|
|
7861
7979
|
const currentLevel = getDecayedBlockLevel(
|
|
@@ -8013,6 +8131,20 @@ async function expandBlock(runtime, url) {
|
|
|
8013
8131
|
if (!/^L?[0-5]$/i.test(target)) throw new AdminHttpError(400, "level must be L0 through L5");
|
|
8014
8132
|
return runtime.adminExpandBlock(namespace, blockId, target);
|
|
8015
8133
|
}
|
|
8134
|
+
async function retryBlockSummary(runtime, url) {
|
|
8135
|
+
const namespace = url.searchParams.get("namespace")?.trim() ?? "";
|
|
8136
|
+
const blockId = url.searchParams.get("blockId")?.trim() ?? "";
|
|
8137
|
+
if (!namespace) throw new AdminHttpError(400, "namespace is required");
|
|
8138
|
+
if (!blockId) throw new AdminHttpError(400, "blockId is required");
|
|
8139
|
+
if (blockId.startsWith("virtual:")) throw new AdminHttpError(409, "Recovered legacy fragments cannot be retried");
|
|
8140
|
+
const snapshot = await requiredSnapshot(runtime, namespace);
|
|
8141
|
+
const job = snapshot.summaryJobs.find(({ blockId: candidateId }) => candidateId === blockId);
|
|
8142
|
+
if (!job) throw new AdminHttpError(404, `Unknown Block Summary job: ${blockId}`);
|
|
8143
|
+
if (job.status !== "failed" || job.nextRetryAt !== null) {
|
|
8144
|
+
throw new AdminHttpError(409, "Block Summary is not in a terminal failed state");
|
|
8145
|
+
}
|
|
8146
|
+
return runtime.adminRetryBlockSummary(namespace, blockId);
|
|
8147
|
+
}
|
|
8016
8148
|
function receiptSources(snapshot, receipt) {
|
|
8017
8149
|
const events = snapshot.events.filter(({ id }) => receipt.eventIds.includes(id));
|
|
8018
8150
|
const elements = snapshot.elements.filter(({ id }) => receipt.elementIds.includes(id));
|
|
@@ -8125,6 +8257,9 @@ async function handleAdminRequest(runtime, req, res) {
|
|
|
8125
8257
|
} else if (path === "/api/stratagate/blocks/expand") {
|
|
8126
8258
|
if (req.method !== "PATCH") throw new AdminHttpError(405, "StrataGate Block expansion requires PATCH");
|
|
8127
8259
|
sendJson(res, 200, await expandBlock(runtime, url));
|
|
8260
|
+
} else if (path === "/api/stratagate/blocks/retry-summary") {
|
|
8261
|
+
if (req.method !== "POST") throw new AdminHttpError(405, "StrataGate Block Summary retry requires POST");
|
|
8262
|
+
sendJson(res, 200, await retryBlockSummary(runtime, url));
|
|
8128
8263
|
} else if (path === "/api/stratagate/import") {
|
|
8129
8264
|
if (req.method === "GET") {
|
|
8130
8265
|
const operation = url.searchParams.get("operation");
|