@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/index.js
CHANGED
|
@@ -2394,8 +2394,11 @@ var init_LLMRequest = __esm({
|
|
|
2394
2394
|
*/
|
|
2395
2395
|
static async logError(state, error, errorType, modelId, startTime, existingLogId) {
|
|
2396
2396
|
try {
|
|
2397
|
-
|
|
2397
|
+
let rawErrorMessage = error instanceof Error ? error.message : String(error);
|
|
2398
2398
|
const errorStack = error instanceof Error ? error.stack : void 0;
|
|
2399
|
+
if (error instanceof Error && error.name === "AbortError" && /operation was aborted/i.test(rawErrorMessage)) {
|
|
2400
|
+
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).";
|
|
2401
|
+
}
|
|
2399
2402
|
let errorMessage = rawErrorMessage;
|
|
2400
2403
|
let parsedProviderBody = null;
|
|
2401
2404
|
const trimmedRaw = rawErrorMessage.trim();
|
|
@@ -7813,6 +7816,25 @@ This usually points to something I can't fix from here \u2014 for example the wo
|
|
|
7813
7816
|
return null;
|
|
7814
7817
|
}
|
|
7815
7818
|
}
|
|
7819
|
+
/**
|
|
7820
|
+
* Registry entries the model may see (and therefore manage). Hidden
|
|
7821
|
+
* subagent relationships (`SubagentToolConfig.hidden` — infrastructure
|
|
7822
|
+
* children like background compaction) are excluded from the injected
|
|
7823
|
+
* "Active subagent instances" message: a listed instance reads as the
|
|
7824
|
+
* model's to clean up, and terminate_subagent on an infrastructure child
|
|
7825
|
+
* kills work the runtime depends on. Static and pure for direct testing.
|
|
7826
|
+
*/
|
|
7827
|
+
static filterModelVisibleSubagents(registry, promptTools) {
|
|
7828
|
+
if (registry.length === 0) return registry;
|
|
7829
|
+
const hidden = /* @__PURE__ */ new Set();
|
|
7830
|
+
for (const config of promptTools ?? []) {
|
|
7831
|
+
if (typeof config === "object" && config !== null && "name" in config && config.hidden === true) {
|
|
7832
|
+
hidden.add(config.name);
|
|
7833
|
+
}
|
|
7834
|
+
}
|
|
7835
|
+
if (hidden.size === 0) return registry;
|
|
7836
|
+
return registry.filter((entry) => !hidden.has(entry.name));
|
|
7837
|
+
}
|
|
7816
7838
|
static async getSubagentRegistry(state) {
|
|
7817
7839
|
if (typeof state.thread.instance.getChildrenRegistry === "function") {
|
|
7818
7840
|
try {
|
|
@@ -8071,7 +8093,10 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
8071
8093
|
});
|
|
8072
8094
|
}
|
|
8073
8095
|
}
|
|
8074
|
-
const subagentRegistry =
|
|
8096
|
+
const subagentRegistry = _FlowEngine.filterModelVisibleSubagents(
|
|
8097
|
+
await this.getSubagentRegistry(state),
|
|
8098
|
+
state.prompt?._tools
|
|
8099
|
+
);
|
|
8075
8100
|
if (subagentRegistry.length > 0) {
|
|
8076
8101
|
const fallbackNameMap = await this.resolveRegistryThreadNameMap(state, subagentRegistry);
|
|
8077
8102
|
const lines = subagentRegistry.map((entry) => {
|
|
@@ -23329,6 +23354,38 @@ var AlarmQueue = class {
|
|
|
23329
23354
|
async ensureAlarmScheduled() {
|
|
23330
23355
|
await this.rescheduleAlarm();
|
|
23331
23356
|
}
|
|
23357
|
+
/**
|
|
23358
|
+
* Recover queue items orphaned in 'processing' by a dead predecessor
|
|
23359
|
+
* instance.
|
|
23360
|
+
*
|
|
23361
|
+
* processNext marks an item 'processing' before executing it. If the DO is
|
|
23362
|
+
* evicted or a deploy restarts it mid-execution, that row used to stay
|
|
23363
|
+
* 'processing' FOREVER — only 'pending' rows are ever picked up again — so
|
|
23364
|
+
* queued subagent executions, queued messages, and scheduled effects that
|
|
23365
|
+
* were mid-flight at a restart were silently lost (a subagent that "just
|
|
23366
|
+
* died half way through" with nothing to revive it).
|
|
23367
|
+
*
|
|
23368
|
+
* MUST ONLY be called from the once-per-instance wake path (DurableThread's
|
|
23369
|
+
* alarmQueueRearmed guard): at that moment this fresh instance is executing
|
|
23370
|
+
* nothing, so ANY 'processing' row provably belongs to a dead predecessor.
|
|
23371
|
+
* Calling it at any other time would re-queue items that are legitimately
|
|
23372
|
+
* mid-execution on this very instance.
|
|
23373
|
+
*/
|
|
23374
|
+
async recoverOrphanedProcessing(maxAttempts = 3) {
|
|
23375
|
+
const now = Date.now() * 1e3;
|
|
23376
|
+
await this.sql.exec(
|
|
23377
|
+
`UPDATE alarm_queue
|
|
23378
|
+
SET status = 'failed',
|
|
23379
|
+
error = 'Lost mid-execution (the executor restarted) and retry attempts were exhausted.',
|
|
23380
|
+
completed_at = ?
|
|
23381
|
+
WHERE status = 'processing' AND attempts >= ?`,
|
|
23382
|
+
now,
|
|
23383
|
+
maxAttempts
|
|
23384
|
+
);
|
|
23385
|
+
await this.sql.exec(
|
|
23386
|
+
`UPDATE alarm_queue SET status = 'pending' WHERE status = 'processing'`
|
|
23387
|
+
);
|
|
23388
|
+
}
|
|
23332
23389
|
// ============================================================
|
|
23333
23390
|
// Effect-specific Methods
|
|
23334
23391
|
// ============================================================
|
|
@@ -25251,6 +25308,9 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
25251
25308
|
}
|
|
25252
25309
|
this.migratedToVersion = LATEST_SCHEMA_VERSION;
|
|
25253
25310
|
if (!this.alarmQueueRearmed && typeof this.alarmQueue.ensureAlarmScheduled === "function") {
|
|
25311
|
+
if (typeof this.alarmQueue.recoverOrphanedProcessing === "function") {
|
|
25312
|
+
await this.alarmQueue.recoverOrphanedProcessing();
|
|
25313
|
+
}
|
|
25254
25314
|
await this.alarmQueue.ensureAlarmScheduled();
|
|
25255
25315
|
this.alarmQueueRearmed = true;
|
|
25256
25316
|
}
|
|
@@ -27956,14 +28016,14 @@ ${resultContent}${attachmentSummary}`;
|
|
|
27956
28016
|
`SELECT id FROM logs WHERE is_complete = 0`
|
|
27957
28017
|
)).toArray();
|
|
27958
28018
|
let incomplete = await readIncomplete();
|
|
28019
|
+
const ceiling = resolveWatchdogStaleCeilingMs(this.env);
|
|
28020
|
+
const silenceMs = this.lastProgressAt === 0 ? Number.POSITIVE_INFINITY : Date.now() - this.lastProgressAt;
|
|
27959
28021
|
if (this.isExecuting) {
|
|
27960
28022
|
if (incomplete.length === 0) {
|
|
27961
28023
|
this.watchdogWedgeStrikes = 0;
|
|
27962
28024
|
await rearm();
|
|
27963
28025
|
return;
|
|
27964
28026
|
}
|
|
27965
|
-
const ceiling = resolveWatchdogStaleCeilingMs(this.env);
|
|
27966
|
-
const silenceMs = Date.now() - this.lastProgressAt;
|
|
27967
28027
|
if (silenceMs <= ceiling) {
|
|
27968
28028
|
this.watchdogWedgeStrikes = 0;
|
|
27969
28029
|
await rearm();
|
|
@@ -27972,20 +28032,23 @@ ${resultContent}${attachmentSummary}`;
|
|
|
27972
28032
|
this.watchdogWedgeStrikes++;
|
|
27973
28033
|
if (this.watchdogWedgeStrikes < 2) {
|
|
27974
28034
|
console.warn(
|
|
27975
|
-
`[DurableThread] Watchdog: execution silent for ${Math.round(silenceMs / 1e3)}s (ceiling ${Math.round(ceiling / 1e3)}s) \u2014
|
|
28035
|
+
`[DurableThread] Watchdog: execution silent for ${Math.round(silenceMs / 1e3)}s (ceiling ${Math.round(ceiling / 1e3)}s) \u2014 observing; takeover next cycle if still silent`
|
|
27976
28036
|
);
|
|
27977
|
-
try {
|
|
27978
|
-
this.currentAbortController?.abort();
|
|
27979
|
-
} catch {
|
|
27980
|
-
}
|
|
27981
28037
|
await rearm();
|
|
27982
28038
|
return;
|
|
27983
28039
|
}
|
|
27984
28040
|
console.error(
|
|
27985
|
-
|
|
28041
|
+
`[DurableThread] Watchdog: wedged execution (${Math.round(silenceMs / 1e3)}s silent across two cycles) \u2014 forcing takeover`
|
|
27986
28042
|
);
|
|
28043
|
+
try {
|
|
28044
|
+
this.currentAbortController?.abort();
|
|
28045
|
+
} catch {
|
|
28046
|
+
}
|
|
27987
28047
|
this.isExecuting = false;
|
|
27988
28048
|
this.currentAbortController = null;
|
|
28049
|
+
} else if (incomplete.length > 0 && silenceMs <= ceiling) {
|
|
28050
|
+
await rearm();
|
|
28051
|
+
return;
|
|
27989
28052
|
}
|
|
27990
28053
|
incomplete = await readIncomplete();
|
|
27991
28054
|
if (this.isExecuting) {
|
|
@@ -28013,6 +28076,7 @@ ${resultContent}${attachmentSummary}`;
|
|
|
28013
28076
|
console.error(
|
|
28014
28077
|
`[DurableThread] Watchdog: resume budget exhausted for thread ${threadId} \u2014 leaving thread stopped`
|
|
28015
28078
|
);
|
|
28079
|
+
await this.notifyParentOfLostExecution(threadId);
|
|
28016
28080
|
}
|
|
28017
28081
|
await this.disarmExecutionWatchdog();
|
|
28018
28082
|
} catch (error) {
|
|
@@ -28040,6 +28104,46 @@ ${resultContent}${attachmentSummary}`;
|
|
|
28040
28104
|
});
|
|
28041
28105
|
}
|
|
28042
28106
|
}
|
|
28107
|
+
/**
|
|
28108
|
+
* A subagent whose execution the watchdog gave up on leaves its parent
|
|
28109
|
+
* waiting forever for a completion message. Deliver the failure the same way
|
|
28110
|
+
* a sessionFail would, so the parent's turn wakes and can route around it.
|
|
28111
|
+
* Explicit-communication children (e.g. the compaction agent) stay quiet by
|
|
28112
|
+
* contract — only the registry status updates for those.
|
|
28113
|
+
*/
|
|
28114
|
+
async notifyParentOfLostExecution(threadId) {
|
|
28115
|
+
try {
|
|
28116
|
+
const agentBuilderId = this.env.AGENT_BUILDER.idFromName("singleton");
|
|
28117
|
+
const agentBuilder = this.env.AGENT_BUILDER.get(agentBuilderId);
|
|
28118
|
+
const meta = await agentBuilder.getThread(threadId);
|
|
28119
|
+
const parentThreadId = meta?.parent ?? null;
|
|
28120
|
+
if (!parentThreadId) return;
|
|
28121
|
+
const parentId = this.env.AGENT_BUILDER_THREAD.idFromName(parentThreadId);
|
|
28122
|
+
const parentStub = this.env.AGENT_BUILDER_THREAD.get(parentId);
|
|
28123
|
+
const parentCommunication = await this.getParentCommunicationModeForChild(
|
|
28124
|
+
parentStub,
|
|
28125
|
+
parentThreadId,
|
|
28126
|
+
threadId
|
|
28127
|
+
);
|
|
28128
|
+
if (parentCommunication !== "explicit") {
|
|
28129
|
+
await parentStub.queueMessage(parentThreadId, {
|
|
28130
|
+
role: "user",
|
|
28131
|
+
content: `Subagent (reference: ${threadId}) has reported a failure:
|
|
28132
|
+
|
|
28133
|
+
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.`,
|
|
28134
|
+
attachments: [],
|
|
28135
|
+
silent: true,
|
|
28136
|
+
metadata: { subagent_id: threadId }
|
|
28137
|
+
});
|
|
28138
|
+
}
|
|
28139
|
+
await parentStub.updateChildRegistryStatus(parentThreadId, threadId, "idle");
|
|
28140
|
+
} catch (error) {
|
|
28141
|
+
console.error(
|
|
28142
|
+
"[DurableThread] Watchdog: failed to notify parent of lost execution (non-fatal):",
|
|
28143
|
+
error
|
|
28144
|
+
);
|
|
28145
|
+
}
|
|
28146
|
+
}
|
|
28043
28147
|
/** At most N auto-resumes per rolling window, tracked durably. */
|
|
28044
28148
|
async consumeWatchdogResumeBudget() {
|
|
28045
28149
|
const now = Date.now();
|