stratagate-dsh 0.2.63 → 0.2.64
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 +344 -337
- package/README.md +447 -447
- package/README.zh-CN.md +412 -412
- package/cordis.patch.yml +11 -11
- package/dist/client.d.ts +1 -1
- package/dist/client.js +6 -7
- package/dist/plugin.js +212 -60
- package/dist/plugin.js.map +1 -1
- package/dist/repair-profile.js +0 -0
- package/docs/ARCHITECTURE.md +215 -215
- package/docs/DSH.md +192 -192
- package/docs/DSH.zh-CN.md +189 -189
- package/docs/EVALUATION.md +179 -179
- package/package.json +225 -225
package/dist/plugin.js
CHANGED
|
@@ -2752,6 +2752,7 @@ var StrataGate = class _StrataGate {
|
|
|
2752
2752
|
summaryJobs = /* @__PURE__ */ new Map();
|
|
2753
2753
|
elementProjectionJobs = /* @__PURE__ */ new Map();
|
|
2754
2754
|
graphProjectionJobs = /* @__PURE__ */ new Map();
|
|
2755
|
+
manualRetryRuns = /* @__PURE__ */ new Map();
|
|
2755
2756
|
usageReceipts = /* @__PURE__ */ new Map();
|
|
2756
2757
|
successfulModelResponses = [];
|
|
2757
2758
|
ingestionReceipts = /* @__PURE__ */ new Map();
|
|
@@ -2997,34 +2998,90 @@ var StrataGate = class _StrataGate {
|
|
|
2997
2998
|
listSummaryJobs() {
|
|
2998
2999
|
return [...this.summaryJobs.values()];
|
|
2999
3000
|
}
|
|
3000
|
-
|
|
3001
|
+
runManualRetry(key, operation) {
|
|
3002
|
+
const existing = this.manualRetryRuns.get(key);
|
|
3003
|
+
if (existing) return existing;
|
|
3004
|
+
const run = operation().finally(() => {
|
|
3005
|
+
if (this.manualRetryRuns.get(key) === run) this.manualRetryRuns.delete(key);
|
|
3006
|
+
});
|
|
3007
|
+
this.manualRetryRuns.set(key, run);
|
|
3008
|
+
return run;
|
|
3009
|
+
}
|
|
3010
|
+
/** Give one failed Block Summary job a fresh, user-requested retry budget. */
|
|
3001
3011
|
async retryBlockSummary(id) {
|
|
3002
3012
|
const blockId = id.trim();
|
|
3003
3013
|
if (!blockId) throw new TypeError("Block id must not be empty");
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
throw new Error(`Block ${blockId} Summary
|
|
3014
|
+
return this.runManualRetry(`summary:${blockId}`, async () => {
|
|
3015
|
+
const block = this.blocks.find((candidate) => candidate.id === blockId);
|
|
3016
|
+
if (!block) throw new Error(`Unknown block: ${blockId}`);
|
|
3017
|
+
if (block.processingStatus !== "pending") throw new Error(`Block ${blockId} is already ready`);
|
|
3018
|
+
await this.commitMutation(() => {
|
|
3019
|
+
const job = this.summaryJobs.get(blockId);
|
|
3020
|
+
if (!job) throw new Error(`Missing summary job for block: ${blockId}`);
|
|
3021
|
+
if (job.status !== "failed") throw new Error(`Block ${blockId} Summary is ${job.status}, not failed`);
|
|
3022
|
+
this.summaryJobs.set(blockId, {
|
|
3023
|
+
...job,
|
|
3024
|
+
status: "pending",
|
|
3025
|
+
attempts: 0,
|
|
3026
|
+
lastError: null,
|
|
3027
|
+
nextRetryAt: null,
|
|
3028
|
+
updatedAt: toUtc8Iso(this.now())
|
|
3029
|
+
});
|
|
3030
|
+
});
|
|
3031
|
+
const extractedEvents = await this.processBlock(block, { retryFailed: false });
|
|
3032
|
+
const processed = this.blocks.find((candidate) => candidate.id === blockId);
|
|
3033
|
+
const readyBlocks = processed?.processingStatus === "ready" ? [processed] : [];
|
|
3034
|
+
return { sealedBlocks: [], readyBlocks, extractedEvents, projectedElements: [] };
|
|
3035
|
+
});
|
|
3036
|
+
}
|
|
3037
|
+
/** Retry only Event extraction for one failed Block without rerunning its Summary. */
|
|
3038
|
+
async retryEventExtraction(id) {
|
|
3039
|
+
const blockId = id.trim();
|
|
3040
|
+
if (!blockId) throw new TypeError("Block id must not be empty");
|
|
3041
|
+
return this.runManualRetry(`extraction:${blockId}`, async () => {
|
|
3042
|
+
const block = this.blocks.find((candidate) => candidate.id === blockId);
|
|
3043
|
+
if (!block) throw new Error(`Unknown block: ${blockId}`);
|
|
3044
|
+
if (block.processingStatus !== "pending" || block.shouldExtract !== true) {
|
|
3045
|
+
throw new Error(`Block ${blockId} is not waiting for Event extraction`);
|
|
3012
3046
|
}
|
|
3013
|
-
this.
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3047
|
+
await this.commitMutation(() => {
|
|
3048
|
+
const job = this.extractionJobs.get(blockId);
|
|
3049
|
+
if (!job) throw new Error(`Missing extraction job for block: ${blockId}`);
|
|
3050
|
+
if (job.status !== "failed") throw new Error(`Event extraction ${blockId} is ${job.status}, not failed`);
|
|
3051
|
+
this.extractionJobs.set(blockId, {
|
|
3052
|
+
...job,
|
|
3053
|
+
attempts: 0,
|
|
3054
|
+
lastError: null,
|
|
3055
|
+
nextRetryAt: null,
|
|
3056
|
+
updatedAt: toUtc8Iso(this.now())
|
|
3057
|
+
});
|
|
3020
3058
|
});
|
|
3059
|
+
return await this.extractEligibleBlock({ blockId, retryFailed: true }) ?? [];
|
|
3060
|
+
});
|
|
3061
|
+
}
|
|
3062
|
+
/** Retry exactly one failed Graph projection batch. */
|
|
3063
|
+
async retryGraphProjection(id) {
|
|
3064
|
+
const jobId = id.trim();
|
|
3065
|
+
if (!jobId) throw new TypeError("Graph projection id must not be empty");
|
|
3066
|
+
return this.runManualRetry(`graph:${jobId}`, async () => {
|
|
3067
|
+
if (!this.graphProjector) throw new Error("Graph projector is not configured");
|
|
3068
|
+
await this.commitMutation(() => {
|
|
3069
|
+
const job = this.requireGraphProjectionJob(jobId);
|
|
3070
|
+
if (job.status !== "failed") throw new Error(`Graph projection ${jobId} is ${job.status}, not failed`);
|
|
3071
|
+
job.status = "pending";
|
|
3072
|
+
job.attempts = 0;
|
|
3073
|
+
job.lastError = null;
|
|
3074
|
+
job.updatedAt = toUtc8Iso(this.now());
|
|
3075
|
+
});
|
|
3076
|
+
const batch = await this.claimGraphProjection(jobId);
|
|
3077
|
+
if (!batch) throw new Error(`Graph projection ${jobId} could not be claimed`);
|
|
3078
|
+
try {
|
|
3079
|
+
return await this.completeGraphProjection(jobId, await this.graphProjector(batch));
|
|
3080
|
+
} catch (error) {
|
|
3081
|
+
await this.failGraphProjection(jobId, error);
|
|
3082
|
+
throw error;
|
|
3083
|
+
}
|
|
3021
3084
|
});
|
|
3022
|
-
const extractedEvents = await this.processBlock(block, { retryFailed: false });
|
|
3023
|
-
const processed = this.blocks.find((candidate) => candidate.id === blockId);
|
|
3024
|
-
const readyBlocks = processed?.processingStatus === "ready" ? [processed] : [];
|
|
3025
|
-
const projectedElements = await this.projectEligibleElements() ?? [];
|
|
3026
|
-
await this.projectEligibleGraph();
|
|
3027
|
-
return { sealedBlocks: [], readyBlocks, extractedEvents, projectedElements };
|
|
3028
3085
|
}
|
|
3029
3086
|
listElementProjectionJobs() {
|
|
3030
3087
|
return [...this.elementProjectionJobs.values()];
|
|
@@ -3664,9 +3721,9 @@ var StrataGate = class _StrataGate {
|
|
|
3664
3721
|
job.updatedAt = toUtc8Iso(this.now());
|
|
3665
3722
|
});
|
|
3666
3723
|
}
|
|
3667
|
-
async
|
|
3724
|
+
async claimGraphProjection(jobId) {
|
|
3668
3725
|
return this.commitMutation(() => {
|
|
3669
|
-
const job = [...this.graphProjectionJobs.values()].filter((candidate) => candidate.status === "pending" || candidate.status === "failed").sort((left, right) => right.priority - left.priority || left.createdAt.localeCompare(right.createdAt))[0];
|
|
3726
|
+
const job = [...this.graphProjectionJobs.values()].filter((candidate) => (jobId === void 0 || candidate.id === jobId) && (candidate.status === "pending" || candidate.status === "failed")).sort((left, right) => right.priority - left.priority || left.createdAt.localeCompare(right.createdAt))[0];
|
|
3670
3727
|
if (!job) return null;
|
|
3671
3728
|
const events = job.sourceEventIds.flatMap((id) => this.events.find((event) => event.id === id) ?? []);
|
|
3672
3729
|
if (events.length === 0) throw new Error(`Graph projection ${job.id} has no available source events`);
|
|
@@ -3692,6 +3749,9 @@ var StrataGate = class _StrataGate {
|
|
|
3692
3749
|
};
|
|
3693
3750
|
});
|
|
3694
3751
|
}
|
|
3752
|
+
async claimNextGraphProjection() {
|
|
3753
|
+
return this.claimGraphProjection();
|
|
3754
|
+
}
|
|
3695
3755
|
async completeGraphProjection(jobId, result) {
|
|
3696
3756
|
return this.commitMutation(() => {
|
|
3697
3757
|
const job = this.requireGraphProjectionJob(jobId);
|
|
@@ -5716,6 +5776,7 @@ var StrataGateRuntime = class {
|
|
|
5716
5776
|
pendingSurfaceSync = /* @__PURE__ */ new Map();
|
|
5717
5777
|
adminSnapshotCache = /* @__PURE__ */ new Map();
|
|
5718
5778
|
externalImportRuns = /* @__PURE__ */ new Map();
|
|
5779
|
+
adminJobRetryRuns = /* @__PURE__ */ new Map();
|
|
5719
5780
|
feedbackDrafts = /* @__PURE__ */ new Map();
|
|
5720
5781
|
pendingFeedbackSuggestionSessions = /* @__PURE__ */ new Set();
|
|
5721
5782
|
pendingTurns = /* @__PURE__ */ new Map();
|
|
@@ -6715,34 +6776,53 @@ var StrataGateRuntime = class {
|
|
|
6715
6776
|
});
|
|
6716
6777
|
return update;
|
|
6717
6778
|
}
|
|
6718
|
-
async
|
|
6779
|
+
async adminRetryJob(namespace, kind, id) {
|
|
6719
6780
|
const key = namespace.trim();
|
|
6720
|
-
const
|
|
6781
|
+
const jobId = id.trim();
|
|
6721
6782
|
if (!key) throw new TypeError("StrataGate admin namespace must not be empty");
|
|
6722
|
-
if (!
|
|
6783
|
+
if (!jobId) throw new TypeError("StrataGate job id must not be empty");
|
|
6784
|
+
const retryKey = `${key}\0${kind}\0${jobId}`;
|
|
6785
|
+
const existing = this.adminJobRetryRuns.get(retryKey);
|
|
6786
|
+
if (existing) return existing;
|
|
6723
6787
|
const update = this.settingsTail.catch(() => {
|
|
6724
6788
|
}).then(async () => {
|
|
6725
6789
|
await this.flush();
|
|
6726
6790
|
const { memory, owned } = await this.openAdminMemory(key, { derivation: true });
|
|
6727
6791
|
try {
|
|
6728
6792
|
await this.refreshExternalImportMemory(key, memory);
|
|
6729
|
-
const
|
|
6730
|
-
|
|
6731
|
-
const
|
|
6732
|
-
|
|
6733
|
-
|
|
6793
|
+
const graphJob = kind === "graph-projection" ? memory.listGraphProjectionJobs().find((candidate) => candidate.id === jobId) : void 0;
|
|
6794
|
+
const blockId = kind === "graph-projection" ? graphJob?.sourceEventIds.flatMap((eventId) => memory.listEvents().find(({ id: eventCandidateId }) => eventCandidateId === eventId)?.sourceBlockId ?? [])[0] : jobId;
|
|
6795
|
+
const block = blockId ? memory.listBlocks().find((candidate) => candidate.id === blockId) : void 0;
|
|
6796
|
+
if (kind !== "graph-projection" && !block) throw new Error(`Unknown block: ${jobId}`);
|
|
6797
|
+
if (kind === "graph-projection" && !graphJob) throw new Error(`Unknown graph projection: ${jobId}`);
|
|
6798
|
+
const threadId = block?.threadId ?? `admin-job-retry:${kind}:${jobId}`;
|
|
6799
|
+
const session = block?.threadId ? this.knownSessions.get(block.threadId)?.deref() : void 0;
|
|
6800
|
+
const retry = async () => {
|
|
6801
|
+
if (kind === "block-summary") return memory.retryBlockSummary(jobId);
|
|
6802
|
+
if (kind === "event-extraction") return memory.retryEventExtraction(jobId);
|
|
6803
|
+
return memory.retryGraphProjection(jobId);
|
|
6804
|
+
};
|
|
6805
|
+
const result = session && this.namespaceFor(session) === key ? await this.models.run(session, retry) : await this.models.runDetached(threadId, retry);
|
|
6734
6806
|
await this.persistSuccessfulResponses(memory);
|
|
6735
|
-
|
|
6736
|
-
|
|
6807
|
+
const currentBlock = blockId ? memory.listBlocks().find(({ id: candidateId }) => candidateId === blockId) : void 0;
|
|
6808
|
+
if (kind !== "graph-projection" && currentBlock?.processingStatus === "ready" && currentBlock.threadId) {
|
|
6809
|
+
this.pendingSurfaceSync.set(`${key}\0${currentBlock.id}`, { namespace: key, blockId: currentBlock.id });
|
|
6737
6810
|
if (session && this.namespaceFor(session) === key) await this.syncPendingRetrySurface(session, memory);
|
|
6738
6811
|
}
|
|
6739
|
-
const
|
|
6812
|
+
const job = kind === "block-summary" ? memory.listSummaryJobs().find(({ blockId: candidateId }) => candidateId === jobId) : kind === "event-extraction" ? memory.listExtractionJobs().find(({ blockId: candidateId }) => candidateId === jobId) : memory.listGraphProjectionJobs().find(({ id: candidateId }) => candidateId === jobId);
|
|
6813
|
+
const succeeded = kind === "graph-projection" ? job?.status === "completed" : job?.status === "succeeded" || job?.status === "skipped";
|
|
6814
|
+
if (!succeeded) throw new Error(job?.lastError || `${kind} retry did not complete`);
|
|
6740
6815
|
return {
|
|
6816
|
+
kind,
|
|
6817
|
+
jobId,
|
|
6741
6818
|
blockId,
|
|
6742
|
-
|
|
6743
|
-
|
|
6744
|
-
summaryJob:
|
|
6745
|
-
|
|
6819
|
+
status: job?.status,
|
|
6820
|
+
job: job ?? null,
|
|
6821
|
+
...kind === "block-summary" ? { summaryJob: job ?? null } : {},
|
|
6822
|
+
result,
|
|
6823
|
+
processingStatus: currentBlock?.processingStatus ?? null,
|
|
6824
|
+
ready: currentBlock?.processingStatus === "ready",
|
|
6825
|
+
surfaceUpdated: !blockId || !this.pendingSurfaceSync.has(`${key}\0${blockId}`)
|
|
6746
6826
|
};
|
|
6747
6827
|
} finally {
|
|
6748
6828
|
if (owned) await memory.close();
|
|
@@ -6751,7 +6831,14 @@ var StrataGateRuntime = class {
|
|
|
6751
6831
|
this.settingsTail = update.then(() => {
|
|
6752
6832
|
}, () => {
|
|
6753
6833
|
});
|
|
6754
|
-
|
|
6834
|
+
const tracked = update.finally(() => {
|
|
6835
|
+
if (this.adminJobRetryRuns.get(retryKey) === tracked) this.adminJobRetryRuns.delete(retryKey);
|
|
6836
|
+
});
|
|
6837
|
+
this.adminJobRetryRuns.set(retryKey, tracked);
|
|
6838
|
+
return tracked;
|
|
6839
|
+
}
|
|
6840
|
+
async adminRetryBlockSummary(namespace, id) {
|
|
6841
|
+
return this.adminRetryJob(namespace, "block-summary", id);
|
|
6755
6842
|
}
|
|
6756
6843
|
async applyBlockDecayLambda(value) {
|
|
6757
6844
|
await this.flush();
|
|
@@ -7623,7 +7710,7 @@ function clusterKnowledgeGraph(rawNodes, rawEdges) {
|
|
|
7623
7710
|
}
|
|
7624
7711
|
|
|
7625
7712
|
// src/web.ts
|
|
7626
|
-
var STRATAGATE_DSH_VERSION = "0.2.
|
|
7713
|
+
var STRATAGATE_DSH_VERSION = "0.2.64";
|
|
7627
7714
|
var LEGACY_THREAD_ID = "__legacy__";
|
|
7628
7715
|
var nodeRequire2 = createRequire2(import.meta.url);
|
|
7629
7716
|
function installedPackageVersion(names) {
|
|
@@ -7780,26 +7867,66 @@ async function overview(runtime, cachedEntries) {
|
|
|
7780
7867
|
lastErrorFull: job.lastError,
|
|
7781
7868
|
updatedAt: job.updatedAt,
|
|
7782
7869
|
threadId: block?.threadId ?? null,
|
|
7870
|
+
blockIds: [job.blockId],
|
|
7871
|
+
threadIds: block?.threadId ? [block.threadId] : [],
|
|
7872
|
+
blockDetails: block ? [{
|
|
7873
|
+
id: block.id,
|
|
7874
|
+
sequence: block.sequence,
|
|
7875
|
+
title: block.l0Title ?? null,
|
|
7876
|
+
threadId: block.threadId ?? null,
|
|
7877
|
+
turnRange: [block.startTurn, block.endTurn]
|
|
7878
|
+
}] : [],
|
|
7783
7879
|
sequence: block?.sequence ?? null,
|
|
7784
7880
|
turnRange: block ? [block.startTurn, block.endTurn] : null
|
|
7785
7881
|
};
|
|
7786
7882
|
}),
|
|
7787
|
-
...snapshot.extractionJobs.filter(({ status }) => status === "failed").map((job) =>
|
|
7788
|
-
id
|
|
7789
|
-
|
|
7790
|
-
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
|
|
7794
|
-
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
|
|
7799
|
-
|
|
7800
|
-
|
|
7801
|
-
|
|
7802
|
-
|
|
7883
|
+
...snapshot.extractionJobs.filter(({ status }) => status === "failed").map((job) => {
|
|
7884
|
+
const block = snapshot.blocks.find(({ id }) => id === job.blockId);
|
|
7885
|
+
return {
|
|
7886
|
+
id: job.blockId,
|
|
7887
|
+
kind: "event-extraction",
|
|
7888
|
+
attempts: job.attempts,
|
|
7889
|
+
nextRetryAt: job.nextRetryAt,
|
|
7890
|
+
lastError: job.lastError?.slice(0, 500) ?? null,
|
|
7891
|
+
lastErrorFull: job.lastError,
|
|
7892
|
+
updatedAt: job.updatedAt,
|
|
7893
|
+
blockIds: [job.blockId],
|
|
7894
|
+
threadIds: block?.threadId ? [block.threadId] : [],
|
|
7895
|
+
blockDetails: block ? [{
|
|
7896
|
+
id: block.id,
|
|
7897
|
+
sequence: block.sequence,
|
|
7898
|
+
title: block.l0Title ?? null,
|
|
7899
|
+
threadId: block.threadId ?? null,
|
|
7900
|
+
turnRange: [block.startTurn, block.endTurn]
|
|
7901
|
+
}] : [],
|
|
7902
|
+
sequence: block?.sequence ?? null,
|
|
7903
|
+
turnRange: block ? [block.startTurn, block.endTurn] : null
|
|
7904
|
+
};
|
|
7905
|
+
}),
|
|
7906
|
+
...snapshot.graphProjectionJobs.filter(({ status }) => status === "failed").map((job) => {
|
|
7907
|
+
const blockIds = [...new Set(job.sourceEventIds.flatMap((eventId) => snapshot.events.find(({ id }) => id === eventId)?.sourceBlockId ?? []))];
|
|
7908
|
+
const blocks = blockIds.flatMap((blockId) => snapshot.blocks.find(({ id }) => id === blockId) ?? []);
|
|
7909
|
+
return {
|
|
7910
|
+
id: job.id,
|
|
7911
|
+
kind: "graph-projection",
|
|
7912
|
+
attempts: job.attempts,
|
|
7913
|
+
nextRetryAt: null,
|
|
7914
|
+
lastError: job.lastError?.slice(0, 500) ?? null,
|
|
7915
|
+
lastErrorFull: job.lastError,
|
|
7916
|
+
updatedAt: job.updatedAt,
|
|
7917
|
+
blockIds,
|
|
7918
|
+
threadIds: [...new Set(blocks.flatMap(({ threadId }) => threadId ?? []))],
|
|
7919
|
+
blockDetails: blocks.map((block) => ({
|
|
7920
|
+
id: block.id,
|
|
7921
|
+
sequence: block.sequence,
|
|
7922
|
+
title: block.l0Title ?? null,
|
|
7923
|
+
threadId: block.threadId ?? null,
|
|
7924
|
+
turnRange: [block.startTurn, block.endTurn]
|
|
7925
|
+
})),
|
|
7926
|
+
sequences: blocks.map(({ sequence }) => sequence),
|
|
7927
|
+
sourceEventIds: job.sourceEventIds
|
|
7928
|
+
};
|
|
7929
|
+
})
|
|
7803
7930
|
];
|
|
7804
7931
|
const timestamps = [
|
|
7805
7932
|
...snapshot.blocks.map(({ createdAt }) => createdAt),
|
|
@@ -8345,11 +8472,33 @@ async function retryBlockSummary(runtime, url) {
|
|
|
8345
8472
|
const snapshot = await requiredSnapshot(runtime, namespace);
|
|
8346
8473
|
const job = snapshot.summaryJobs.find(({ blockId: candidateId }) => candidateId === blockId);
|
|
8347
8474
|
if (!job) throw new AdminHttpError(404, `Unknown Block Summary job: ${blockId}`);
|
|
8348
|
-
if (job.status !== "failed"
|
|
8349
|
-
throw new AdminHttpError(409, "Block Summary is not in a terminal failed state");
|
|
8350
|
-
}
|
|
8475
|
+
if (job.status !== "failed") throw new AdminHttpError(409, `Block Summary is ${job.status}, not failed`);
|
|
8351
8476
|
return runtime.adminRetryBlockSummary(namespace, blockId);
|
|
8352
8477
|
}
|
|
8478
|
+
async function retryJob(runtime, url) {
|
|
8479
|
+
const namespace = url.searchParams.get("namespace")?.trim() ?? "";
|
|
8480
|
+
const kind = url.searchParams.get("kind")?.trim() ?? "";
|
|
8481
|
+
const jobId = url.searchParams.get("jobId")?.trim() ?? "";
|
|
8482
|
+
if (!namespace) throw new AdminHttpError(400, "namespace is required");
|
|
8483
|
+
if (!["block-summary", "event-extraction", "graph-projection"].includes(kind)) {
|
|
8484
|
+
throw new AdminHttpError(400, "kind must be block-summary, event-extraction, or graph-projection");
|
|
8485
|
+
}
|
|
8486
|
+
if (!jobId) throw new AdminHttpError(400, "jobId is required");
|
|
8487
|
+
if (jobId.startsWith("virtual:")) throw new AdminHttpError(409, "Recovered legacy fragments cannot be retried");
|
|
8488
|
+
const snapshot = await requiredSnapshot(runtime, namespace);
|
|
8489
|
+
const job = kind === "block-summary" ? snapshot.summaryJobs.find(({ blockId }) => blockId === jobId) : kind === "event-extraction" ? snapshot.extractionJobs.find(({ blockId }) => blockId === jobId) : snapshot.graphProjectionJobs.find(({ id }) => id === jobId);
|
|
8490
|
+
if (!job) throw new AdminHttpError(404, `Unknown ${kind} job: ${jobId}`);
|
|
8491
|
+
if (job.status !== "failed") throw new AdminHttpError(409, `${kind} job is ${job.status}, not failed`);
|
|
8492
|
+
try {
|
|
8493
|
+
return await runtime.adminRetryJob(
|
|
8494
|
+
namespace,
|
|
8495
|
+
kind,
|
|
8496
|
+
jobId
|
|
8497
|
+
);
|
|
8498
|
+
} catch (error) {
|
|
8499
|
+
throw new AdminHttpError(422, error instanceof Error ? error.message : String(error));
|
|
8500
|
+
}
|
|
8501
|
+
}
|
|
8353
8502
|
function receiptSources(snapshot, receipt) {
|
|
8354
8503
|
const events = snapshot.events.filter(({ id }) => receipt.eventIds.includes(id));
|
|
8355
8504
|
const elements = snapshot.elements.filter(({ id }) => receipt.elementIds.includes(id));
|
|
@@ -8465,6 +8614,9 @@ async function handleAdminRequest(runtime, req, res) {
|
|
|
8465
8614
|
} else if (path === "/api/stratagate/blocks/retry-summary") {
|
|
8466
8615
|
if (req.method !== "POST") throw new AdminHttpError(405, "StrataGate Block Summary retry requires POST");
|
|
8467
8616
|
sendJson(res, 200, await retryBlockSummary(runtime, url));
|
|
8617
|
+
} else if (path === "/api/stratagate/jobs/retry") {
|
|
8618
|
+
if (req.method !== "POST") throw new AdminHttpError(405, "StrataGate job retry requires POST");
|
|
8619
|
+
sendJson(res, 200, await retryJob(runtime, url));
|
|
8468
8620
|
} else if (path === "/api/stratagate/import") {
|
|
8469
8621
|
if (req.method === "GET") {
|
|
8470
8622
|
const operation = url.searchParams.get("operation");
|