@standardagents/builder 0.25.5 → 0.25.7
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 +27 -2
- package/dist/built-in-routes.js.map +1 -1
- package/dist/index.js +114 -10
- package/dist/index.js.map +1 -1
- package/dist/runtime.d.ts +8 -0
- package/dist/runtime.js +114 -10
- 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();
|
|
@@ -7804,6 +7807,25 @@ This usually points to something I can't fix from here \u2014 for example the wo
|
|
|
7804
7807
|
return null;
|
|
7805
7808
|
}
|
|
7806
7809
|
}
|
|
7810
|
+
/**
|
|
7811
|
+
* Registry entries the model may see (and therefore manage). Hidden
|
|
7812
|
+
* subagent relationships (`SubagentToolConfig.hidden` — infrastructure
|
|
7813
|
+
* children like background compaction) are excluded from the injected
|
|
7814
|
+
* "Active subagent instances" message: a listed instance reads as the
|
|
7815
|
+
* model's to clean up, and terminate_subagent on an infrastructure child
|
|
7816
|
+
* kills work the runtime depends on. Static and pure for direct testing.
|
|
7817
|
+
*/
|
|
7818
|
+
static filterModelVisibleSubagents(registry, promptTools) {
|
|
7819
|
+
if (registry.length === 0) return registry;
|
|
7820
|
+
const hidden = /* @__PURE__ */ new Set();
|
|
7821
|
+
for (const config of promptTools ?? []) {
|
|
7822
|
+
if (typeof config === "object" && config !== null && "name" in config && config.hidden === true) {
|
|
7823
|
+
hidden.add(config.name);
|
|
7824
|
+
}
|
|
7825
|
+
}
|
|
7826
|
+
if (hidden.size === 0) return registry;
|
|
7827
|
+
return registry.filter((entry) => !hidden.has(entry.name));
|
|
7828
|
+
}
|
|
7807
7829
|
static async getSubagentRegistry(state) {
|
|
7808
7830
|
if (typeof state.thread.instance.getChildrenRegistry === "function") {
|
|
7809
7831
|
try {
|
|
@@ -8062,7 +8084,10 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
8062
8084
|
});
|
|
8063
8085
|
}
|
|
8064
8086
|
}
|
|
8065
|
-
const subagentRegistry =
|
|
8087
|
+
const subagentRegistry = _FlowEngine.filterModelVisibleSubagents(
|
|
8088
|
+
await this.getSubagentRegistry(state),
|
|
8089
|
+
state.prompt?._tools
|
|
8090
|
+
);
|
|
8066
8091
|
if (subagentRegistry.length > 0) {
|
|
8067
8092
|
const fallbackNameMap = await this.resolveRegistryThreadNameMap(state, subagentRegistry);
|
|
8068
8093
|
const lines = subagentRegistry.map((entry) => {
|
|
@@ -15038,6 +15063,38 @@ var AlarmQueue = class {
|
|
|
15038
15063
|
async ensureAlarmScheduled() {
|
|
15039
15064
|
await this.rescheduleAlarm();
|
|
15040
15065
|
}
|
|
15066
|
+
/**
|
|
15067
|
+
* Recover queue items orphaned in 'processing' by a dead predecessor
|
|
15068
|
+
* instance.
|
|
15069
|
+
*
|
|
15070
|
+
* processNext marks an item 'processing' before executing it. If the DO is
|
|
15071
|
+
* evicted or a deploy restarts it mid-execution, that row used to stay
|
|
15072
|
+
* 'processing' FOREVER — only 'pending' rows are ever picked up again — so
|
|
15073
|
+
* queued subagent executions, queued messages, and scheduled effects that
|
|
15074
|
+
* were mid-flight at a restart were silently lost (a subagent that "just
|
|
15075
|
+
* died half way through" with nothing to revive it).
|
|
15076
|
+
*
|
|
15077
|
+
* MUST ONLY be called from the once-per-instance wake path (DurableThread's
|
|
15078
|
+
* alarmQueueRearmed guard): at that moment this fresh instance is executing
|
|
15079
|
+
* nothing, so ANY 'processing' row provably belongs to a dead predecessor.
|
|
15080
|
+
* Calling it at any other time would re-queue items that are legitimately
|
|
15081
|
+
* mid-execution on this very instance.
|
|
15082
|
+
*/
|
|
15083
|
+
async recoverOrphanedProcessing(maxAttempts = 3) {
|
|
15084
|
+
const now = Date.now() * 1e3;
|
|
15085
|
+
await this.sql.exec(
|
|
15086
|
+
`UPDATE alarm_queue
|
|
15087
|
+
SET status = 'failed',
|
|
15088
|
+
error = 'Lost mid-execution (the executor restarted) and retry attempts were exhausted.',
|
|
15089
|
+
completed_at = ?
|
|
15090
|
+
WHERE status = 'processing' AND attempts >= ?`,
|
|
15091
|
+
now,
|
|
15092
|
+
maxAttempts
|
|
15093
|
+
);
|
|
15094
|
+
await this.sql.exec(
|
|
15095
|
+
`UPDATE alarm_queue SET status = 'pending' WHERE status = 'processing'`
|
|
15096
|
+
);
|
|
15097
|
+
}
|
|
15041
15098
|
// ============================================================
|
|
15042
15099
|
// Effect-specific Methods
|
|
15043
15100
|
// ============================================================
|
|
@@ -16960,6 +17017,9 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
16960
17017
|
}
|
|
16961
17018
|
this.migratedToVersion = LATEST_SCHEMA_VERSION;
|
|
16962
17019
|
if (!this.alarmQueueRearmed && typeof this.alarmQueue.ensureAlarmScheduled === "function") {
|
|
17020
|
+
if (typeof this.alarmQueue.recoverOrphanedProcessing === "function") {
|
|
17021
|
+
await this.alarmQueue.recoverOrphanedProcessing();
|
|
17022
|
+
}
|
|
16963
17023
|
await this.alarmQueue.ensureAlarmScheduled();
|
|
16964
17024
|
this.alarmQueueRearmed = true;
|
|
16965
17025
|
}
|
|
@@ -19665,14 +19725,14 @@ ${resultContent}${attachmentSummary}`;
|
|
|
19665
19725
|
`SELECT id FROM logs WHERE is_complete = 0`
|
|
19666
19726
|
)).toArray();
|
|
19667
19727
|
let incomplete = await readIncomplete();
|
|
19728
|
+
const ceiling = resolveWatchdogStaleCeilingMs(this.env);
|
|
19729
|
+
const silenceMs = this.lastProgressAt === 0 ? Number.POSITIVE_INFINITY : Date.now() - this.lastProgressAt;
|
|
19668
19730
|
if (this.isExecuting) {
|
|
19669
19731
|
if (incomplete.length === 0) {
|
|
19670
19732
|
this.watchdogWedgeStrikes = 0;
|
|
19671
19733
|
await rearm();
|
|
19672
19734
|
return;
|
|
19673
19735
|
}
|
|
19674
|
-
const ceiling = resolveWatchdogStaleCeilingMs(this.env);
|
|
19675
|
-
const silenceMs = Date.now() - this.lastProgressAt;
|
|
19676
19736
|
if (silenceMs <= ceiling) {
|
|
19677
19737
|
this.watchdogWedgeStrikes = 0;
|
|
19678
19738
|
await rearm();
|
|
@@ -19681,20 +19741,23 @@ ${resultContent}${attachmentSummary}`;
|
|
|
19681
19741
|
this.watchdogWedgeStrikes++;
|
|
19682
19742
|
if (this.watchdogWedgeStrikes < 2) {
|
|
19683
19743
|
console.warn(
|
|
19684
|
-
`[DurableThread] Watchdog: execution silent for ${Math.round(silenceMs / 1e3)}s (ceiling ${Math.round(ceiling / 1e3)}s) \u2014
|
|
19744
|
+
`[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
19745
|
);
|
|
19686
|
-
try {
|
|
19687
|
-
this.currentAbortController?.abort();
|
|
19688
|
-
} catch {
|
|
19689
|
-
}
|
|
19690
19746
|
await rearm();
|
|
19691
19747
|
return;
|
|
19692
19748
|
}
|
|
19693
19749
|
console.error(
|
|
19694
|
-
|
|
19750
|
+
`[DurableThread] Watchdog: wedged execution (${Math.round(silenceMs / 1e3)}s silent across two cycles) \u2014 forcing takeover`
|
|
19695
19751
|
);
|
|
19752
|
+
try {
|
|
19753
|
+
this.currentAbortController?.abort();
|
|
19754
|
+
} catch {
|
|
19755
|
+
}
|
|
19696
19756
|
this.isExecuting = false;
|
|
19697
19757
|
this.currentAbortController = null;
|
|
19758
|
+
} else if (incomplete.length > 0 && silenceMs <= ceiling) {
|
|
19759
|
+
await rearm();
|
|
19760
|
+
return;
|
|
19698
19761
|
}
|
|
19699
19762
|
incomplete = await readIncomplete();
|
|
19700
19763
|
if (this.isExecuting) {
|
|
@@ -19722,6 +19785,7 @@ ${resultContent}${attachmentSummary}`;
|
|
|
19722
19785
|
console.error(
|
|
19723
19786
|
`[DurableThread] Watchdog: resume budget exhausted for thread ${threadId} \u2014 leaving thread stopped`
|
|
19724
19787
|
);
|
|
19788
|
+
await this.notifyParentOfLostExecution(threadId);
|
|
19725
19789
|
}
|
|
19726
19790
|
await this.disarmExecutionWatchdog();
|
|
19727
19791
|
} catch (error) {
|
|
@@ -19749,6 +19813,46 @@ ${resultContent}${attachmentSummary}`;
|
|
|
19749
19813
|
});
|
|
19750
19814
|
}
|
|
19751
19815
|
}
|
|
19816
|
+
/**
|
|
19817
|
+
* A subagent whose execution the watchdog gave up on leaves its parent
|
|
19818
|
+
* waiting forever for a completion message. Deliver the failure the same way
|
|
19819
|
+
* a sessionFail would, so the parent's turn wakes and can route around it.
|
|
19820
|
+
* Explicit-communication children (e.g. the compaction agent) stay quiet by
|
|
19821
|
+
* contract — only the registry status updates for those.
|
|
19822
|
+
*/
|
|
19823
|
+
async notifyParentOfLostExecution(threadId) {
|
|
19824
|
+
try {
|
|
19825
|
+
const agentBuilderId = this.env.AGENT_BUILDER.idFromName("singleton");
|
|
19826
|
+
const agentBuilder = this.env.AGENT_BUILDER.get(agentBuilderId);
|
|
19827
|
+
const meta = await agentBuilder.getThread(threadId);
|
|
19828
|
+
const parentThreadId = meta?.parent ?? null;
|
|
19829
|
+
if (!parentThreadId) return;
|
|
19830
|
+
const parentId = this.env.AGENT_BUILDER_THREAD.idFromName(parentThreadId);
|
|
19831
|
+
const parentStub = this.env.AGENT_BUILDER_THREAD.get(parentId);
|
|
19832
|
+
const parentCommunication = await this.getParentCommunicationModeForChild(
|
|
19833
|
+
parentStub,
|
|
19834
|
+
parentThreadId,
|
|
19835
|
+
threadId
|
|
19836
|
+
);
|
|
19837
|
+
if (parentCommunication !== "explicit") {
|
|
19838
|
+
await parentStub.queueMessage(parentThreadId, {
|
|
19839
|
+
role: "user",
|
|
19840
|
+
content: `Subagent (reference: ${threadId}) has reported a failure:
|
|
19841
|
+
|
|
19842
|
+
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.`,
|
|
19843
|
+
attachments: [],
|
|
19844
|
+
silent: true,
|
|
19845
|
+
metadata: { subagent_id: threadId }
|
|
19846
|
+
});
|
|
19847
|
+
}
|
|
19848
|
+
await parentStub.updateChildRegistryStatus(parentThreadId, threadId, "idle");
|
|
19849
|
+
} catch (error) {
|
|
19850
|
+
console.error(
|
|
19851
|
+
"[DurableThread] Watchdog: failed to notify parent of lost execution (non-fatal):",
|
|
19852
|
+
error
|
|
19853
|
+
);
|
|
19854
|
+
}
|
|
19855
|
+
}
|
|
19752
19856
|
/** At most N auto-resumes per rolling window, tracked durably. */
|
|
19753
19857
|
async consumeWatchdogResumeBudget() {
|
|
19754
19858
|
const now = Date.now();
|