@standardagents/builder 0.25.5 → 0.25.6
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/built-in-routes.js +4 -1
- package/dist/built-in-routes.js.map +1 -1
- package/dist/index.js +91 -9
- package/dist/index.js.map +1 -1
- package/dist/runtime.d.ts +8 -0
- package/dist/runtime.js +91 -9
- package/dist/runtime.js.map +1 -1
- package/package.json +5 -5
package/dist/runtime.d.ts
CHANGED
|
@@ -1098,6 +1098,14 @@ declare class DurableThread<Env extends ThreadEnv = ThreadEnv> extends DurableOb
|
|
|
1098
1098
|
private watchdogCheck;
|
|
1099
1099
|
/** Mark logs the dead executor abandoned, and tell connected clients. */
|
|
1100
1100
|
private finalizeLostExecutionLogs;
|
|
1101
|
+
/**
|
|
1102
|
+
* A subagent whose execution the watchdog gave up on leaves its parent
|
|
1103
|
+
* waiting forever for a completion message. Deliver the failure the same way
|
|
1104
|
+
* a sessionFail would, so the parent's turn wakes and can route around it.
|
|
1105
|
+
* Explicit-communication children (e.g. the compaction agent) stay quiet by
|
|
1106
|
+
* contract — only the registry status updates for those.
|
|
1107
|
+
*/
|
|
1108
|
+
private notifyParentOfLostExecution;
|
|
1101
1109
|
/** At most N auto-resumes per rolling window, tracked durably. */
|
|
1102
1110
|
private consumeWatchdogResumeBudget;
|
|
1103
1111
|
private normalizePlainRecord;
|
package/dist/runtime.js
CHANGED
|
@@ -2385,8 +2385,11 @@ var init_LLMRequest = __esm({
|
|
|
2385
2385
|
*/
|
|
2386
2386
|
static async logError(state, error, errorType, modelId, startTime, existingLogId) {
|
|
2387
2387
|
try {
|
|
2388
|
-
|
|
2388
|
+
let rawErrorMessage = error instanceof Error ? error.message : String(error);
|
|
2389
2389
|
const errorStack = error instanceof Error ? error.stack : void 0;
|
|
2390
|
+
if (error instanceof Error && error.name === "AbortError" && /operation was aborted/i.test(rawErrorMessage)) {
|
|
2391
|
+
rawErrorMessage = state.abortController?.signal?.aborted ? "Aborted: the execution this request belonged to was cancelled (user stop, watchdog takeover, or a restart) \u2014 retries and fallbacks of a cancelled execution fail immediately." : "Aborted: the request's connection was cancelled mid-flight (provider disconnect or executor restart).";
|
|
2392
|
+
}
|
|
2390
2393
|
let errorMessage = rawErrorMessage;
|
|
2391
2394
|
let parsedProviderBody = null;
|
|
2392
2395
|
const trimmedRaw = rawErrorMessage.trim();
|
|
@@ -15038,6 +15041,38 @@ var AlarmQueue = class {
|
|
|
15038
15041
|
async ensureAlarmScheduled() {
|
|
15039
15042
|
await this.rescheduleAlarm();
|
|
15040
15043
|
}
|
|
15044
|
+
/**
|
|
15045
|
+
* Recover queue items orphaned in 'processing' by a dead predecessor
|
|
15046
|
+
* instance.
|
|
15047
|
+
*
|
|
15048
|
+
* processNext marks an item 'processing' before executing it. If the DO is
|
|
15049
|
+
* evicted or a deploy restarts it mid-execution, that row used to stay
|
|
15050
|
+
* 'processing' FOREVER — only 'pending' rows are ever picked up again — so
|
|
15051
|
+
* queued subagent executions, queued messages, and scheduled effects that
|
|
15052
|
+
* were mid-flight at a restart were silently lost (a subagent that "just
|
|
15053
|
+
* died half way through" with nothing to revive it).
|
|
15054
|
+
*
|
|
15055
|
+
* MUST ONLY be called from the once-per-instance wake path (DurableThread's
|
|
15056
|
+
* alarmQueueRearmed guard): at that moment this fresh instance is executing
|
|
15057
|
+
* nothing, so ANY 'processing' row provably belongs to a dead predecessor.
|
|
15058
|
+
* Calling it at any other time would re-queue items that are legitimately
|
|
15059
|
+
* mid-execution on this very instance.
|
|
15060
|
+
*/
|
|
15061
|
+
async recoverOrphanedProcessing(maxAttempts = 3) {
|
|
15062
|
+
const now = Date.now() * 1e3;
|
|
15063
|
+
await this.sql.exec(
|
|
15064
|
+
`UPDATE alarm_queue
|
|
15065
|
+
SET status = 'failed',
|
|
15066
|
+
error = 'Lost mid-execution (the executor restarted) and retry attempts were exhausted.',
|
|
15067
|
+
completed_at = ?
|
|
15068
|
+
WHERE status = 'processing' AND attempts >= ?`,
|
|
15069
|
+
now,
|
|
15070
|
+
maxAttempts
|
|
15071
|
+
);
|
|
15072
|
+
await this.sql.exec(
|
|
15073
|
+
`UPDATE alarm_queue SET status = 'pending' WHERE status = 'processing'`
|
|
15074
|
+
);
|
|
15075
|
+
}
|
|
15041
15076
|
// ============================================================
|
|
15042
15077
|
// Effect-specific Methods
|
|
15043
15078
|
// ============================================================
|
|
@@ -16960,6 +16995,9 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
16960
16995
|
}
|
|
16961
16996
|
this.migratedToVersion = LATEST_SCHEMA_VERSION;
|
|
16962
16997
|
if (!this.alarmQueueRearmed && typeof this.alarmQueue.ensureAlarmScheduled === "function") {
|
|
16998
|
+
if (typeof this.alarmQueue.recoverOrphanedProcessing === "function") {
|
|
16999
|
+
await this.alarmQueue.recoverOrphanedProcessing();
|
|
17000
|
+
}
|
|
16963
17001
|
await this.alarmQueue.ensureAlarmScheduled();
|
|
16964
17002
|
this.alarmQueueRearmed = true;
|
|
16965
17003
|
}
|
|
@@ -19665,14 +19703,14 @@ ${resultContent}${attachmentSummary}`;
|
|
|
19665
19703
|
`SELECT id FROM logs WHERE is_complete = 0`
|
|
19666
19704
|
)).toArray();
|
|
19667
19705
|
let incomplete = await readIncomplete();
|
|
19706
|
+
const ceiling = resolveWatchdogStaleCeilingMs(this.env);
|
|
19707
|
+
const silenceMs = this.lastProgressAt === 0 ? Number.POSITIVE_INFINITY : Date.now() - this.lastProgressAt;
|
|
19668
19708
|
if (this.isExecuting) {
|
|
19669
19709
|
if (incomplete.length === 0) {
|
|
19670
19710
|
this.watchdogWedgeStrikes = 0;
|
|
19671
19711
|
await rearm();
|
|
19672
19712
|
return;
|
|
19673
19713
|
}
|
|
19674
|
-
const ceiling = resolveWatchdogStaleCeilingMs(this.env);
|
|
19675
|
-
const silenceMs = Date.now() - this.lastProgressAt;
|
|
19676
19714
|
if (silenceMs <= ceiling) {
|
|
19677
19715
|
this.watchdogWedgeStrikes = 0;
|
|
19678
19716
|
await rearm();
|
|
@@ -19681,20 +19719,23 @@ ${resultContent}${attachmentSummary}`;
|
|
|
19681
19719
|
this.watchdogWedgeStrikes++;
|
|
19682
19720
|
if (this.watchdogWedgeStrikes < 2) {
|
|
19683
19721
|
console.warn(
|
|
19684
|
-
`[DurableThread] Watchdog: execution silent for ${Math.round(silenceMs / 1e3)}s (ceiling ${Math.round(ceiling / 1e3)}s) \u2014
|
|
19722
|
+
`[DurableThread] Watchdog: execution silent for ${Math.round(silenceMs / 1e3)}s (ceiling ${Math.round(ceiling / 1e3)}s) \u2014 observing; takeover next cycle if still silent`
|
|
19685
19723
|
);
|
|
19686
|
-
try {
|
|
19687
|
-
this.currentAbortController?.abort();
|
|
19688
|
-
} catch {
|
|
19689
|
-
}
|
|
19690
19724
|
await rearm();
|
|
19691
19725
|
return;
|
|
19692
19726
|
}
|
|
19693
19727
|
console.error(
|
|
19694
|
-
|
|
19728
|
+
`[DurableThread] Watchdog: wedged execution (${Math.round(silenceMs / 1e3)}s silent across two cycles) \u2014 forcing takeover`
|
|
19695
19729
|
);
|
|
19730
|
+
try {
|
|
19731
|
+
this.currentAbortController?.abort();
|
|
19732
|
+
} catch {
|
|
19733
|
+
}
|
|
19696
19734
|
this.isExecuting = false;
|
|
19697
19735
|
this.currentAbortController = null;
|
|
19736
|
+
} else if (incomplete.length > 0 && silenceMs <= ceiling) {
|
|
19737
|
+
await rearm();
|
|
19738
|
+
return;
|
|
19698
19739
|
}
|
|
19699
19740
|
incomplete = await readIncomplete();
|
|
19700
19741
|
if (this.isExecuting) {
|
|
@@ -19722,6 +19763,7 @@ ${resultContent}${attachmentSummary}`;
|
|
|
19722
19763
|
console.error(
|
|
19723
19764
|
`[DurableThread] Watchdog: resume budget exhausted for thread ${threadId} \u2014 leaving thread stopped`
|
|
19724
19765
|
);
|
|
19766
|
+
await this.notifyParentOfLostExecution(threadId);
|
|
19725
19767
|
}
|
|
19726
19768
|
await this.disarmExecutionWatchdog();
|
|
19727
19769
|
} catch (error) {
|
|
@@ -19749,6 +19791,46 @@ ${resultContent}${attachmentSummary}`;
|
|
|
19749
19791
|
});
|
|
19750
19792
|
}
|
|
19751
19793
|
}
|
|
19794
|
+
/**
|
|
19795
|
+
* A subagent whose execution the watchdog gave up on leaves its parent
|
|
19796
|
+
* waiting forever for a completion message. Deliver the failure the same way
|
|
19797
|
+
* a sessionFail would, so the parent's turn wakes and can route around it.
|
|
19798
|
+
* Explicit-communication children (e.g. the compaction agent) stay quiet by
|
|
19799
|
+
* contract — only the registry status updates for those.
|
|
19800
|
+
*/
|
|
19801
|
+
async notifyParentOfLostExecution(threadId) {
|
|
19802
|
+
try {
|
|
19803
|
+
const agentBuilderId = this.env.AGENT_BUILDER.idFromName("singleton");
|
|
19804
|
+
const agentBuilder = this.env.AGENT_BUILDER.get(agentBuilderId);
|
|
19805
|
+
const meta = await agentBuilder.getThread(threadId);
|
|
19806
|
+
const parentThreadId = meta?.parent ?? null;
|
|
19807
|
+
if (!parentThreadId) return;
|
|
19808
|
+
const parentId = this.env.AGENT_BUILDER_THREAD.idFromName(parentThreadId);
|
|
19809
|
+
const parentStub = this.env.AGENT_BUILDER_THREAD.get(parentId);
|
|
19810
|
+
const parentCommunication = await this.getParentCommunicationModeForChild(
|
|
19811
|
+
parentStub,
|
|
19812
|
+
parentThreadId,
|
|
19813
|
+
threadId
|
|
19814
|
+
);
|
|
19815
|
+
if (parentCommunication !== "explicit") {
|
|
19816
|
+
await parentStub.queueMessage(parentThreadId, {
|
|
19817
|
+
role: "user",
|
|
19818
|
+
content: `Subagent (reference: ${threadId}) has reported a failure:
|
|
19819
|
+
|
|
19820
|
+
Its execution was lost (the executor restarted or hung) and automatic recovery was exhausted. Treat this subagent's task as failed \u2014 do not wait for it; retry the work another way or report the failure.`,
|
|
19821
|
+
attachments: [],
|
|
19822
|
+
silent: true,
|
|
19823
|
+
metadata: { subagent_id: threadId }
|
|
19824
|
+
});
|
|
19825
|
+
}
|
|
19826
|
+
await parentStub.updateChildRegistryStatus(parentThreadId, threadId, "idle");
|
|
19827
|
+
} catch (error) {
|
|
19828
|
+
console.error(
|
|
19829
|
+
"[DurableThread] Watchdog: failed to notify parent of lost execution (non-fatal):",
|
|
19830
|
+
error
|
|
19831
|
+
);
|
|
19832
|
+
}
|
|
19833
|
+
}
|
|
19752
19834
|
/** At most N auto-resumes per rolling window, tracked durably. */
|
|
19753
19835
|
async consumeWatchdogResumeBudget() {
|
|
19754
19836
|
const now = Date.now();
|