@standardagents/builder 0.37.4 → 0.37.5
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 +160 -79
- package/dist/built-in-routes.js.map +1 -1
- package/dist/client/{ApiKeysView-BhuT3pIF.js → ApiKeysView-Pk5oljVU.js} +1 -1
- package/dist/client/CenteredContentView-HGpMGAQj.js +1 -0
- package/dist/client/CompositionView-DN8dTOCO.js +32 -0
- package/dist/client/{ConfirmDialog.vue_vue_type_script_setup_true_lang-BqwwsXWJ.js → ConfirmDialog.vue_vue_type_script_setup_true_lang--j_hnMZ0.js} +1 -1
- package/dist/client/{CopyButton.vue_vue_type_script_setup_true_lang-Cqm3Vt3E.js → CopyButton.vue_vue_type_script_setup_true_lang-CpJDcbZx.js} +1 -1
- package/dist/client/{DataTable.vue_vue_type_script_setup_true_lang-CA5qgsty.js → DataTable.vue_vue_type_script_setup_true_lang-unLrY-PY.js} +1 -1
- package/dist/client/{JsonViewer-ByQKCShF.js → JsonViewer-BYj_yrGB.js} +1 -1
- package/dist/client/{LoginView-J4qtHbQK.js → LoginView-CfVqItZV.js} +1 -1
- package/dist/client/{MarketplaceView-CshdWDqp.js → MarketplaceView-Cidt0nLf.js} +1 -1
- package/dist/client/{Modal.vue_vue_type_script_setup_true_lang-DKdB9A8Z.js → Modal.vue_vue_type_script_setup_true_lang-C1dmm1HX.js} +1 -1
- package/dist/client/ModelModal.vue_vue_type_script_setup_true_lang-DIKLuPXT.js +1 -0
- package/dist/client/{ModelsView-B_n306yk.js → ModelsView-DH6wNe38.js} +1 -1
- package/dist/client/{PromptEditView-C85qRgsE.js → PromptEditView-D_VjoAa-.js} +1 -1
- package/dist/client/{PromptModal-PNpoJfqD.js → PromptModal-a9LTOWNt.js} +1 -1
- package/dist/client/{PromptsView-BKnfThIF.js → PromptsView-BCCCryKR.js} +1 -1
- package/dist/client/{ProvidersView-Df41VhHD.js → ProvidersView-CF4x5F6G.js} +2 -2
- package/dist/client/ThreadInspectorPane.vue_vue_type_script_setup_true_lang-D5VDoQiK.js +22 -0
- package/dist/client/ThreadsView-BzscU1l2.js +1 -0
- package/dist/client/{ToolsView-C0MH9x3N.js → ToolsView-CeEtxDZV.js} +1 -1
- package/dist/client/{UiCodeBlock.vue_vue_type_script_setup_true_lang-DjDQOYjB.js → UiCodeBlock.vue_vue_type_script_setup_true_lang-BdyzSxZZ.js} +1 -1
- package/dist/client/{UsersView--TQiJYP7.js → UsersView-Di5cmUYL.js} +1 -1
- package/dist/client/{VariablesView-BO3UljZu.js → VariablesView-CXUr05jD.js} +1 -1
- package/dist/client/assets/{CompositionView-nJBKoNx4.css → CompositionView-0qQUWuc1.css} +1 -1
- package/dist/client/{check-DeHZQcv4.js → check-YKi1o6p6.js} +1 -1
- package/dist/client/{chevron-right-C8Mb0B59.js → chevron-right-T0zzq_GX.js} +1 -1
- package/dist/client/{copy-BxJsl-KZ.js → copy-C_gUGAj1.js} +1 -1
- package/dist/client/{formkit-0eyyCEP_.js → formkit-CE26dtFp.js} +1 -1
- package/dist/client/index-BMqXblce.js +6 -0
- package/dist/client/index.html +3 -3
- package/dist/client/{package-B9czwyIu.js → package-B70IFSDB.js} +1 -1
- package/dist/client/{plus-DqtuqJFm.js → plus-BN9IHYdt.js} +1 -1
- package/dist/client/{timeAgo-CDt-vAhI.js → timeAgo-G1ovbWPH.js} +1 -1
- package/dist/client/{useActionFeedback-B6UfBJ7l.js → useActionFeedback-7pfPjKMi.js} +1 -1
- package/dist/client/{vue-Dw7WLX4c.js → vue-CZ-ORfS3.js} +1 -1
- package/dist/{index-DceFbLG9.d.ts → index-Lfan8QMN.d.ts} +46 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +279 -23
- package/dist/index.js.map +1 -1
- package/dist/plugin.js +6 -0
- package/dist/plugin.js.map +1 -1
- package/dist/runtime.d.ts +45 -5
- package/dist/runtime.js +273 -23
- package/dist/runtime.js.map +1 -1
- package/dist/test.d.ts +1 -1
- package/package.json +5 -5
- package/dist/client/CenteredContentView-CfgX3Ao3.js +0 -1
- package/dist/client/CompositionView-B9FfWMHd.js +0 -32
- package/dist/client/ModelModal.vue_vue_type_script_setup_true_lang-BAxaBZsx.js +0 -1
- package/dist/client/ThreadInspectorPane.vue_vue_type_script_setup_true_lang-CtIBWHUR.js +0 -22
- package/dist/client/ThreadsView-sjo5Rrcm.js +0 -1
- package/dist/client/index-BgZnQr8X.js +0 -6
package/dist/runtime.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { i as AuthContext, e as ThreadEnv, v as Agent, x as ThreadMetadata, y as ToolResult, M as Message, n as ClientToolRequest, o as ClientToolResponse, p as ClientStreamRequest, q as ClientStreamResponse, G as FileRecord, F as FlowState, K as FileStats, J as GrepResult, H as AttachmentRef, Q as MessageContent, E as Env, w as ThreadInstance } from './index-
|
|
2
|
-
export { A as AuthUser, f as BuilderThreadEndpointHandler, C as CLIENT_STREAM_CHUNK_BYTES, t as ClientDuplex, u as ClientForwarding, B as Controller, a as ControllerContext, z as FlowResult, O as ImageContentPart, I as ImageMetadata, L as LLMResponse, P as MultimodalContent, R as RequestContext, S as StorageBackend, D as TelemetryEvent, N as TextContentPart, b as ThreadEndpointContext, T as ToolCall, g as authenticate, j as callClient, k as callClientStream, c as createThreadEndpointHandler, m as decodeStreamChunk, d as defineController, l as encodeStreamChunk, h as requireAdmin, r as requireAuth, s as supportsClientForwarding } from './index-
|
|
1
|
+
import { i as AuthContext, e as ThreadEnv, v as Agent, x as ThreadMetadata, y as ToolResult, M as Message, n as ClientToolRequest, o as ClientToolResponse, p as ClientStreamRequest, q as ClientStreamResponse, G as FileRecord, F as FlowState, K as FileStats, J as GrepResult, H as AttachmentRef, Q as MessageContent, E as Env, w as ThreadInstance } from './index-Lfan8QMN.js';
|
|
2
|
+
export { A as AuthUser, f as BuilderThreadEndpointHandler, C as CLIENT_STREAM_CHUNK_BYTES, t as ClientDuplex, u as ClientForwarding, B as Controller, a as ControllerContext, z as FlowResult, O as ImageContentPart, I as ImageMetadata, L as LLMResponse, P as MultimodalContent, R as RequestContext, S as StorageBackend, D as TelemetryEvent, N as TextContentPart, b as ThreadEndpointContext, T as ToolCall, g as authenticate, j as callClient, k as callClientStream, c as createThreadEndpointHandler, m as decodeStreamChunk, d as defineController, l as encodeStreamChunk, h as requireAdmin, r as requireAuth, s as supportsClientForwarding } from './index-Lfan8QMN.js';
|
|
3
3
|
import { CodeExecutionOptions, CodeExecutionResult, SubagentRegistryEntry, InjectMessageInput, QueueMessageInput, CredentialGrant, SkillMetadata, SkillFileInput, ModelDefinition as ModelDefinition$1, ToolArgs, PromptTextPart, PromptEnvPart, VariableDefinition, SubpromptConfig as SubpromptConfig$1, PromptToolConfig as PromptToolConfig$1, SubagentToolConfig as SubagentToolConfig$1, ReasoningConfig, SideConfig as SideConfig$1, LLMProviderInterface, ContentPart, TextPart, ImagePart, FilePart, ThreadState, NamespaceContext, DefinitionLoader } from '@standardagents/spec';
|
|
4
4
|
export { AgentType, DefinitionLoader, GlobalNamespaceContext, HookSignatures, ImageContent, ModelCapabilities, ModelProvider, NamespaceContext, PackageSignature, PackedExports, PackedMeta, PackedMetadata, PackedNamespaceContext, PromptInput, PromptTextPart, ProviderAssistantMessage, ProviderError, ProviderErrorCode, ProviderFactory, ProviderFactoryConfig, ProviderFinishReason, ProviderGeneratedImage, ProviderMessage, ProviderMessageContent, ModelCapabilities as ProviderModelCapabilities, ProviderReasoningDetail, ProviderRequest, ProviderResponse, ProviderStreamChunk, ProviderSystemMessage, ProviderTool, ProviderToolCallPart, ProviderToolMessage, ProviderToolResultContent, ProviderUsage, ProviderUserMessage, ReasoningConfig, StructuredPrompt, TextContent, Tool, ToolArgs, ToolArgsNode, ToolArgsRawShape, ToolContent, belongsToPackage, defineAgent, defineHook, defineModel, definePrompt, defineTool, isPacked, isVisibleInNamespace, mapReasoningLevel } from '@standardagents/spec';
|
|
5
5
|
import { DurableObject, WorkerEntrypoint } from 'cloudflare:workers';
|
|
@@ -224,6 +224,15 @@ declare class DurableThread<Env extends ThreadEnv = ThreadEnv> extends DurableOb
|
|
|
224
224
|
private alarmQueueRearmed;
|
|
225
225
|
private currentAbortController;
|
|
226
226
|
private isExecuting;
|
|
227
|
+
/**
|
|
228
|
+
* In-memory waiters parked until the running flow finishes (AB-09): the
|
|
229
|
+
* executeFlow busy-guard awaits this signal instead of re-checking
|
|
230
|
+
* isExecuting every 500ms. Every isExecuting=false transition (execution
|
|
231
|
+
* finallys and the watchdog takeover) notifies. In-memory only — a DO
|
|
232
|
+
* restart drops waiters together with the busy caller.
|
|
233
|
+
*/
|
|
234
|
+
private executionIdleWaiters;
|
|
235
|
+
private notifyExecutionIdleWaiters;
|
|
227
236
|
private lastProgressAt;
|
|
228
237
|
private watchdogWedgeStrikes;
|
|
229
238
|
private readonly watchdogIntervalMs;
|
|
@@ -1160,6 +1169,25 @@ declare class DurableThread<Env extends ThreadEnv = ThreadEnv> extends DurableOb
|
|
|
1160
1169
|
* permission level covers the call) otherwise race the placeholder into
|
|
1161
1170
|
* stored history, leaving the model blind to its own tool outcomes.
|
|
1162
1171
|
*/
|
|
1172
|
+
/**
|
|
1173
|
+
* In-memory waiters parked on a forwarded call's result delivery (AB-09).
|
|
1174
|
+
* `deliverClientToolResult` resolves them so the approval grace-wait reads
|
|
1175
|
+
* delivered state exactly once instead of re-polling it every 150ms.
|
|
1176
|
+
* In-memory only: a DO restart drops waiters along with the caller that
|
|
1177
|
+
* registered them, and the durable park path still resumes the turn.
|
|
1178
|
+
*/
|
|
1179
|
+
private deliveredResultWaiters;
|
|
1180
|
+
private notifyDeliveredResultWaiters;
|
|
1181
|
+
/**
|
|
1182
|
+
* Await a parked forwarded call's delivered result: one immediate read,
|
|
1183
|
+
* then a single parked wait resolved by result delivery, bounded by one
|
|
1184
|
+
* hard deadline, then one final read. Replaces the caller-side 150ms
|
|
1185
|
+
* re-poll of {@link getDeliveredClientToolResult}.
|
|
1186
|
+
*/
|
|
1187
|
+
awaitDeliveredClientToolResult(toolCallId: string, maxWaitMs: number): Promise<{
|
|
1188
|
+
content: string;
|
|
1189
|
+
toolStatus: string | null;
|
|
1190
|
+
} | null>;
|
|
1163
1191
|
getDeliveredClientToolResult(toolCallId: string): Promise<{
|
|
1164
1192
|
content: string;
|
|
1165
1193
|
toolStatus: string | null;
|
|
@@ -1185,8 +1213,14 @@ declare class DurableThread<Env extends ThreadEnv = ThreadEnv> extends DurableOb
|
|
|
1185
1213
|
} | null>;
|
|
1186
1214
|
/** Default time to wait for the client to accept a stream open. */
|
|
1187
1215
|
private static readonly CLIENT_STREAM_OPEN_TIMEOUT_MS;
|
|
1188
|
-
/**
|
|
1189
|
-
|
|
1216
|
+
/**
|
|
1217
|
+
* In-memory waiters parked on the owner's bridge socket returning (AB-09).
|
|
1218
|
+
* Resolved by bridge attach and by execution-owner changes; each waiter
|
|
1219
|
+
* re-evaluates against the CURRENT owner on wake. In-memory only: a DO
|
|
1220
|
+
* restart drops waiters with the stream-open call that registered them.
|
|
1221
|
+
*/
|
|
1222
|
+
private ownerBridgeWaiters;
|
|
1223
|
+
private notifyOwnerBridgeWaiters;
|
|
1190
1224
|
/**
|
|
1191
1225
|
* The thread HAS an elected execution owner, but its bridge socket is gone
|
|
1192
1226
|
* (daemon restart, network blip, DO handoff). Summon the owning machine
|
|
@@ -1195,6 +1229,11 @@ declare class DurableThread<Env extends ThreadEnv = ThreadEnv> extends DurableOb
|
|
|
1195
1229
|
* Sama One turns with "workspace unavailable" whenever a slow tool/approval
|
|
1196
1230
|
* outlived the socket. Threads with NO recorded owner (subagent children)
|
|
1197
1231
|
* still fail fast so ancestor walk-up routing stays immediate.
|
|
1232
|
+
*
|
|
1233
|
+
* The wait parks on bridge-attach/owner-change signals under ONE hard
|
|
1234
|
+
* deadline — no re-poll cadence. Each wake re-reads the owner because the
|
|
1235
|
+
* returning daemon may reclaim with a new generation, and the socket must
|
|
1236
|
+
* match the CURRENT owner.
|
|
1198
1237
|
*/
|
|
1199
1238
|
private awaitOwnerBridgeSocket;
|
|
1200
1239
|
/** Open a bidirectional byte stream to the connected owner client. */
|
|
@@ -1205,10 +1244,11 @@ declare class DurableThread<Env extends ThreadEnv = ThreadEnv> extends DurableOb
|
|
|
1205
1244
|
id?: string;
|
|
1206
1245
|
error?: string;
|
|
1207
1246
|
noClient?: boolean;
|
|
1247
|
+
parkedPull?: boolean;
|
|
1208
1248
|
code?: 'unsupported' | 'unavailable' | 'refused' | 'timeout';
|
|
1209
1249
|
}>;
|
|
1210
1250
|
proxyStreamWrite(id: string, dataB64: string): Promise<void>;
|
|
1211
|
-
proxyStreamPull(id: string): Promise<{
|
|
1251
|
+
proxyStreamPull(id: string, maxWaitMs?: number): Promise<{
|
|
1212
1252
|
chunks: string[];
|
|
1213
1253
|
done: boolean;
|
|
1214
1254
|
error?: string;
|
package/dist/runtime.js
CHANGED
|
@@ -13729,8 +13729,25 @@ var init_ThreadStateImpl = __esm({
|
|
|
13729
13729
|
const mustParkForApproval = await this.forwardedCallNeedsApproval(request);
|
|
13730
13730
|
if (mustParkForApproval && canPark && toolCallId && typeof instance.hasBridge === "function" && await instance.hasBridge()) {
|
|
13731
13731
|
await instance.dispatchClientTool(request, toolCallId, side);
|
|
13732
|
-
const
|
|
13733
|
-
if (typeof
|
|
13732
|
+
const withDelivery = instance;
|
|
13733
|
+
if (typeof withDelivery.awaitDeliveredClientToolResult === "function") {
|
|
13734
|
+
try {
|
|
13735
|
+
const delivered = await withDelivery.awaitDeliveredClientToolResult.call(
|
|
13736
|
+
instance,
|
|
13737
|
+
toolCallId,
|
|
13738
|
+
4e3
|
|
13739
|
+
);
|
|
13740
|
+
if (delivered) {
|
|
13741
|
+
return {
|
|
13742
|
+
ok: delivered.toolStatus !== "error",
|
|
13743
|
+
result: delivered.content,
|
|
13744
|
+
data: { toolCallId }
|
|
13745
|
+
};
|
|
13746
|
+
}
|
|
13747
|
+
} catch {
|
|
13748
|
+
}
|
|
13749
|
+
} else if (typeof withDelivery.getDeliveredClientToolResult === "function") {
|
|
13750
|
+
const getDelivered = withDelivery.getDeliveredClientToolResult;
|
|
13734
13751
|
const graceDeadline = Date.now() + 4e3;
|
|
13735
13752
|
while (Date.now() < graceDeadline) {
|
|
13736
13753
|
await new Promise((r) => setTimeout(r, 150));
|
|
@@ -13820,7 +13837,14 @@ var init_ThreadStateImpl = __esm({
|
|
|
13820
13837
|
if (typeof stub.proxyStreamOpen === "function") {
|
|
13821
13838
|
const opened = await stub.proxyStreamOpen(withWake(parentId));
|
|
13822
13839
|
if (opened.ok && opened.id) {
|
|
13823
|
-
return {
|
|
13840
|
+
return {
|
|
13841
|
+
ok: true,
|
|
13842
|
+
duplex: this.buildProxyDuplex(
|
|
13843
|
+
stub,
|
|
13844
|
+
opened.id,
|
|
13845
|
+
opened.parkedPull === true
|
|
13846
|
+
)
|
|
13847
|
+
};
|
|
13824
13848
|
}
|
|
13825
13849
|
if (opened.error && !opened.noClient) {
|
|
13826
13850
|
return {
|
|
@@ -13838,11 +13862,15 @@ var init_ThreadStateImpl = __esm({
|
|
|
13838
13862
|
}
|
|
13839
13863
|
/**
|
|
13840
13864
|
* Build a client duplex that bridges to a stream opened on an ancestor DO
|
|
13841
|
-
* (the bridge holder) via chunk-pull RPCs. `readable`
|
|
13842
|
-
*
|
|
13865
|
+
* (the bridge holder) via chunk-pull RPCs. `readable` issues PARKED pulls —
|
|
13866
|
+
* a current ancestor holds one `proxyStreamPull` until bytes, completion,
|
|
13867
|
+
* error, or abort, so an idle open stream performs zero repeated pulls.
|
|
13868
|
+
* Older ancestors use the bounded long-pull compatibility path. `writable`
|
|
13869
|
+
* forwards each chunk with `proxyStreamWrite`; teardown calls
|
|
13843
13870
|
* `proxyStreamAbort`.
|
|
13844
13871
|
*/
|
|
13845
|
-
|
|
13872
|
+
static PROXY_PULL_MAX_WAIT_MS = 2e4;
|
|
13873
|
+
buildProxyDuplex(stub, id, supportsParkedPull = false) {
|
|
13846
13874
|
let settleDone;
|
|
13847
13875
|
const done = new Promise((r) => settleDone = r);
|
|
13848
13876
|
let closed = false;
|
|
@@ -13855,9 +13883,13 @@ var init_ThreadStateImpl = __esm({
|
|
|
13855
13883
|
const readable = new ReadableStream({
|
|
13856
13884
|
async pull(controller) {
|
|
13857
13885
|
while (!closed) {
|
|
13886
|
+
const pullStartedAt = Date.now();
|
|
13858
13887
|
let res;
|
|
13859
13888
|
try {
|
|
13860
|
-
res = await stub.proxyStreamPull(
|
|
13889
|
+
res = await stub.proxyStreamPull(
|
|
13890
|
+
id,
|
|
13891
|
+
supportsParkedPull ? void 0 : _ThreadStateImpl.PROXY_PULL_MAX_WAIT_MS
|
|
13892
|
+
);
|
|
13861
13893
|
} catch (error) {
|
|
13862
13894
|
controller.error(error instanceof Error ? error : new Error(String(error)));
|
|
13863
13895
|
settle({ ok: false, error: "proxy stream pull failed" });
|
|
@@ -13872,7 +13904,14 @@ var init_ThreadStateImpl = __esm({
|
|
|
13872
13904
|
return;
|
|
13873
13905
|
}
|
|
13874
13906
|
if (res.chunks.length > 0) return;
|
|
13875
|
-
|
|
13907
|
+
if (supportsParkedPull) {
|
|
13908
|
+
controller.error(new Error("parked proxy pull returned without data"));
|
|
13909
|
+
settle({ ok: false, error: "parked proxy pull returned without data" });
|
|
13910
|
+
return;
|
|
13911
|
+
}
|
|
13912
|
+
if (Date.now() - pullStartedAt < 250) {
|
|
13913
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
13914
|
+
}
|
|
13876
13915
|
}
|
|
13877
13916
|
},
|
|
13878
13917
|
cancel() {
|
|
@@ -15991,6 +16030,9 @@ var AlarmQueue = class {
|
|
|
15991
16030
|
options.sourceLogId ?? null
|
|
15992
16031
|
);
|
|
15993
16032
|
await this.rescheduleAlarm();
|
|
16033
|
+
if (method === "runEffect") {
|
|
16034
|
+
await this.emitEffectRunChange(id);
|
|
16035
|
+
}
|
|
15994
16036
|
return id;
|
|
15995
16037
|
}
|
|
15996
16038
|
/**
|
|
@@ -16029,6 +16071,9 @@ var AlarmQueue = class {
|
|
|
16029
16071
|
`UPDATE alarm_queue SET status = 'processing', attempts = attempts + 1 WHERE id = ?`,
|
|
16030
16072
|
item.id
|
|
16031
16073
|
);
|
|
16074
|
+
if (item.method === "runEffect") {
|
|
16075
|
+
await this.emitEffectRunChange(item.id);
|
|
16076
|
+
}
|
|
16032
16077
|
try {
|
|
16033
16078
|
const args = JSON.parse(item.args);
|
|
16034
16079
|
await this.executeMethod(item.method, args, item.id);
|
|
@@ -16082,6 +16127,7 @@ var AlarmQueue = class {
|
|
|
16082
16127
|
now,
|
|
16083
16128
|
id
|
|
16084
16129
|
);
|
|
16130
|
+
await this.emitEffectRunChange(id);
|
|
16085
16131
|
}
|
|
16086
16132
|
/**
|
|
16087
16133
|
* Mark an item as failed but keep it for 24 hours for debugging
|
|
@@ -16101,6 +16147,7 @@ var AlarmQueue = class {
|
|
|
16101
16147
|
now,
|
|
16102
16148
|
id
|
|
16103
16149
|
);
|
|
16150
|
+
await this.emitEffectRunChange(id);
|
|
16104
16151
|
}
|
|
16105
16152
|
/**
|
|
16106
16153
|
* Clean up failed items older than 24 hours
|
|
@@ -16190,6 +16237,10 @@ var AlarmQueue = class {
|
|
|
16190
16237
|
*/
|
|
16191
16238
|
async recoverOrphanedProcessing(maxAttempts = 3) {
|
|
16192
16239
|
const now = Date.now() * 1e3;
|
|
16240
|
+
const orphanedEffectsCursor = await this.sql.exec(
|
|
16241
|
+
`SELECT id FROM alarm_queue WHERE status = 'processing' AND method = 'runEffect'`
|
|
16242
|
+
);
|
|
16243
|
+
const orphanedEffectIds = orphanedEffectsCursor.toArray().map((row) => row.id);
|
|
16193
16244
|
await this.sql.exec(
|
|
16194
16245
|
`UPDATE alarm_queue
|
|
16195
16246
|
SET status = 'failed',
|
|
@@ -16202,6 +16253,9 @@ var AlarmQueue = class {
|
|
|
16202
16253
|
await this.sql.exec(
|
|
16203
16254
|
`UPDATE alarm_queue SET status = 'pending' WHERE status = 'processing'`
|
|
16204
16255
|
);
|
|
16256
|
+
for (const id of orphanedEffectIds) {
|
|
16257
|
+
await this.emitEffectRunChange(id);
|
|
16258
|
+
}
|
|
16205
16259
|
}
|
|
16206
16260
|
// ============================================================
|
|
16207
16261
|
// Effect-specific Methods
|
|
@@ -16380,6 +16434,7 @@ var AlarmQueue = class {
|
|
|
16380
16434
|
const canceled = changesRows.length > 0 && changesRows[0].changes > 0;
|
|
16381
16435
|
if (canceled) {
|
|
16382
16436
|
await this.rescheduleAlarm();
|
|
16437
|
+
await this.emitEffectRunChange(id);
|
|
16383
16438
|
}
|
|
16384
16439
|
return canceled;
|
|
16385
16440
|
}
|
|
@@ -16454,6 +16509,7 @@ var AlarmQueue = class {
|
|
|
16454
16509
|
if (!changed) {
|
|
16455
16510
|
throw new Error(`Effect run ${item.id} is no longer pending`);
|
|
16456
16511
|
}
|
|
16512
|
+
await this.emitEffectRunChange(item.id);
|
|
16457
16513
|
try {
|
|
16458
16514
|
await this.executeMethod(item.method, JSON.parse(item.args), item.id);
|
|
16459
16515
|
await this.complete(item.id, item.method);
|
|
@@ -16465,6 +16521,45 @@ var AlarmQueue = class {
|
|
|
16465
16521
|
await this.rescheduleAlarm();
|
|
16466
16522
|
}
|
|
16467
16523
|
}
|
|
16524
|
+
/**
|
|
16525
|
+
* Read one effect row and hand its bounded projection (no args payload) to
|
|
16526
|
+
* the change listener. Self-filtering: operational (non-effect) rows and
|
|
16527
|
+
* already-deleted rows emit nothing, and a listener failure must never
|
|
16528
|
+
* disturb queue processing.
|
|
16529
|
+
*/
|
|
16530
|
+
async emitEffectRunChange(id) {
|
|
16531
|
+
const listener = this.options.onEffectRunChanged;
|
|
16532
|
+
if (!listener) return;
|
|
16533
|
+
try {
|
|
16534
|
+
const cursor = await this.sql.exec(
|
|
16535
|
+
`
|
|
16536
|
+
SELECT id, args, scheduled_at, created_at, status, attempts, error, completed_at, manual_run, manual_run_at, replayed_from
|
|
16537
|
+
FROM alarm_queue
|
|
16538
|
+
WHERE id = ? AND method = 'runEffect'
|
|
16539
|
+
LIMIT 1
|
|
16540
|
+
`,
|
|
16541
|
+
id
|
|
16542
|
+
);
|
|
16543
|
+
const row = cursor.toArray()[0];
|
|
16544
|
+
if (!row) return;
|
|
16545
|
+
const { effectName } = this.parseEffectPayload(row.args);
|
|
16546
|
+
listener({
|
|
16547
|
+
id: row.id,
|
|
16548
|
+
name: effectName,
|
|
16549
|
+
scheduledAt: row.scheduled_at,
|
|
16550
|
+
createdAt: row.created_at,
|
|
16551
|
+
status: row.status,
|
|
16552
|
+
attempts: row.attempts,
|
|
16553
|
+
error: row.error,
|
|
16554
|
+
completedAt: row.completed_at,
|
|
16555
|
+
manualRun: row.manual_run === 1,
|
|
16556
|
+
manualRunAt: row.manual_run_at,
|
|
16557
|
+
replayedFrom: row.replayed_from
|
|
16558
|
+
});
|
|
16559
|
+
} catch (error) {
|
|
16560
|
+
console.error(`[AlarmQueue] Failed to emit effect run change for ${id}:`, error);
|
|
16561
|
+
}
|
|
16562
|
+
}
|
|
16468
16563
|
normalizeOffset(value) {
|
|
16469
16564
|
const parsed = typeof value === "number" ? Math.trunc(value) : Number.NaN;
|
|
16470
16565
|
if (!Number.isFinite(parsed)) return 0;
|
|
@@ -20935,6 +21030,25 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
20935
21030
|
alarmQueueRearmed = false;
|
|
20936
21031
|
currentAbortController = null;
|
|
20937
21032
|
isExecuting = false;
|
|
21033
|
+
/**
|
|
21034
|
+
* In-memory waiters parked until the running flow finishes (AB-09): the
|
|
21035
|
+
* executeFlow busy-guard awaits this signal instead of re-checking
|
|
21036
|
+
* isExecuting every 500ms. Every isExecuting=false transition (execution
|
|
21037
|
+
* finallys and the watchdog takeover) notifies. In-memory only — a DO
|
|
21038
|
+
* restart drops waiters together with the busy caller.
|
|
21039
|
+
*/
|
|
21040
|
+
executionIdleWaiters = /* @__PURE__ */ new Set();
|
|
21041
|
+
notifyExecutionIdleWaiters() {
|
|
21042
|
+
if (!this.executionIdleWaiters || this.executionIdleWaiters.size === 0) return;
|
|
21043
|
+
const waiters = Array.from(this.executionIdleWaiters);
|
|
21044
|
+
this.executionIdleWaiters.clear();
|
|
21045
|
+
for (const wake of waiters) {
|
|
21046
|
+
try {
|
|
21047
|
+
wake();
|
|
21048
|
+
} catch {
|
|
21049
|
+
}
|
|
21050
|
+
}
|
|
21051
|
+
}
|
|
20938
21052
|
// ── Execution watchdog state (see watchdogCheck) ─────────────────────────
|
|
20939
21053
|
// In-memory heartbeat: bumped by noteExecutionProgress() on every streamed
|
|
20940
21054
|
// chunk and request attempt. Deliberately NOT persisted — after a DO restart
|
|
@@ -20959,7 +21073,11 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
20959
21073
|
this.alarmQueue = new AlarmQueue(ctx, {
|
|
20960
21074
|
retentionEnabled: env.AGENT_BUILDER_ALARM_RETENTION_ENABLED !== "false",
|
|
20961
21075
|
isForensicHold: async () => (await this.runtimeSafety.getStatus()).forensicHold,
|
|
20962
|
-
invocationSqlLimits: { rowsRead: 1e6, rowsWritten: 1e4 }
|
|
21076
|
+
invocationSqlLimits: { rowsRead: 1e6, rowsWritten: 1e4 },
|
|
21077
|
+
// Effect lifecycle transitions broadcast on the thread event channel so
|
|
21078
|
+
// inspectors stay live from the already-open message socket instead of
|
|
21079
|
+
// polling the effects list.
|
|
21080
|
+
onEffectRunChanged: (change) => this.broadcastEvent("effect_changed", change)
|
|
20963
21081
|
});
|
|
20964
21082
|
this.alarmQueue.setExecutor(
|
|
20965
21083
|
async (method, args, itemId) => {
|
|
@@ -21518,6 +21636,7 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
21518
21636
|
if (value === null || value === void 0) {
|
|
21519
21637
|
await this.ctx.storage.sql.exec(`DELETE FROM thread_values WHERE key = ?`, key);
|
|
21520
21638
|
this.broadcastLog({ type: "kv_data", key, deleted: true, updated_at: updatedAt });
|
|
21639
|
+
this.broadcastEvent("kv_changed", { key, deleted: true, updated_at: updatedAt });
|
|
21521
21640
|
return;
|
|
21522
21641
|
}
|
|
21523
21642
|
const serialized = this.serializeThreadValue(value);
|
|
@@ -21534,6 +21653,7 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
21534
21653
|
updatedAt
|
|
21535
21654
|
);
|
|
21536
21655
|
this.broadcastLog({ type: "kv_data", key, deleted: false, updated_at: updatedAt });
|
|
21656
|
+
this.broadcastEvent("kv_changed", { key, deleted: false, updated_at: updatedAt });
|
|
21537
21657
|
}
|
|
21538
21658
|
async listValues(options = {}) {
|
|
21539
21659
|
await this.ensureMigrated();
|
|
@@ -24554,6 +24674,7 @@ ${resultContent}${attachmentSummary}`;
|
|
|
24554
24674
|
if (isOwner) {
|
|
24555
24675
|
void this.resendPendingClientCalls(server);
|
|
24556
24676
|
}
|
|
24677
|
+
this.notifyOwnerBridgeWaiters();
|
|
24557
24678
|
return new Response(null, {
|
|
24558
24679
|
status: 101,
|
|
24559
24680
|
webSocket: client
|
|
@@ -24589,6 +24710,7 @@ ${resultContent}${attachmentSummary}`;
|
|
|
24589
24710
|
/** Persist + cache the execution-owner record (null releases ownership). */
|
|
24590
24711
|
async setExecutionOwner(owner) {
|
|
24591
24712
|
await this.setValue(EXECUTION_OWNER_KEY, owner);
|
|
24713
|
+
this.notifyOwnerBridgeWaiters();
|
|
24592
24714
|
}
|
|
24593
24715
|
/** Whether the given client id has an open bridge socket (excluding `except`).
|
|
24594
24716
|
* Idle bridge heartbeats are handled by Cloudflare without waking this object,
|
|
@@ -24946,6 +25068,55 @@ ${resultContent}${attachmentSummary}`;
|
|
|
24946
25068
|
* permission level covers the call) otherwise race the placeholder into
|
|
24947
25069
|
* stored history, leaving the model blind to its own tool outcomes.
|
|
24948
25070
|
*/
|
|
25071
|
+
/**
|
|
25072
|
+
* In-memory waiters parked on a forwarded call's result delivery (AB-09).
|
|
25073
|
+
* `deliverClientToolResult` resolves them so the approval grace-wait reads
|
|
25074
|
+
* delivered state exactly once instead of re-polling it every 150ms.
|
|
25075
|
+
* In-memory only: a DO restart drops waiters along with the caller that
|
|
25076
|
+
* registered them, and the durable park path still resumes the turn.
|
|
25077
|
+
*/
|
|
25078
|
+
deliveredResultWaiters = /* @__PURE__ */ new Map();
|
|
25079
|
+
notifyDeliveredResultWaiters(toolCallId) {
|
|
25080
|
+
const waiters = this.deliveredResultWaiters?.get(toolCallId);
|
|
25081
|
+
if (!waiters) return;
|
|
25082
|
+
this.deliveredResultWaiters.delete(toolCallId);
|
|
25083
|
+
for (const wake of waiters) {
|
|
25084
|
+
try {
|
|
25085
|
+
wake();
|
|
25086
|
+
} catch {
|
|
25087
|
+
}
|
|
25088
|
+
}
|
|
25089
|
+
}
|
|
25090
|
+
/**
|
|
25091
|
+
* Await a parked forwarded call's delivered result: one immediate read,
|
|
25092
|
+
* then a single parked wait resolved by result delivery, bounded by one
|
|
25093
|
+
* hard deadline, then one final read. Replaces the caller-side 150ms
|
|
25094
|
+
* re-poll of {@link getDeliveredClientToolResult}.
|
|
25095
|
+
*/
|
|
25096
|
+
async awaitDeliveredClientToolResult(toolCallId, maxWaitMs) {
|
|
25097
|
+
const immediate = await this.getDeliveredClientToolResult(toolCallId);
|
|
25098
|
+
if (immediate) return immediate;
|
|
25099
|
+
if (!(maxWaitMs > 0)) return null;
|
|
25100
|
+
await new Promise((resolve) => {
|
|
25101
|
+
let waiters = this.deliveredResultWaiters.get(toolCallId);
|
|
25102
|
+
if (!waiters) {
|
|
25103
|
+
waiters = /* @__PURE__ */ new Set();
|
|
25104
|
+
this.deliveredResultWaiters.set(toolCallId, waiters);
|
|
25105
|
+
}
|
|
25106
|
+
const registered = waiters;
|
|
25107
|
+
const deadline = setTimeout(() => {
|
|
25108
|
+
registered.delete(wake);
|
|
25109
|
+
if (registered.size === 0) this.deliveredResultWaiters.delete(toolCallId);
|
|
25110
|
+
resolve();
|
|
25111
|
+
}, maxWaitMs);
|
|
25112
|
+
const wake = () => {
|
|
25113
|
+
clearTimeout(deadline);
|
|
25114
|
+
resolve();
|
|
25115
|
+
};
|
|
25116
|
+
registered.add(wake);
|
|
25117
|
+
});
|
|
25118
|
+
return this.getDeliveredClientToolResult(toolCallId);
|
|
25119
|
+
}
|
|
24949
25120
|
async getDeliveredClientToolResult(toolCallId) {
|
|
24950
25121
|
await this.ensureMigrated();
|
|
24951
25122
|
await this.ensurePendingClientTable();
|
|
@@ -25081,6 +25252,7 @@ ${resultContent}${attachmentSummary}`;
|
|
|
25081
25252
|
`UPDATE pending_client_calls SET status = 'resolved' WHERE tool_call_id = ?`,
|
|
25082
25253
|
toolCallId
|
|
25083
25254
|
);
|
|
25255
|
+
this.notifyDeliveredResultWaiters(toolCallId);
|
|
25084
25256
|
try {
|
|
25085
25257
|
const msgCursor = await this.ctx.storage.sql.exec(
|
|
25086
25258
|
`SELECT id, role, content, name, tool_call_id, tool_status, created_at, depth
|
|
@@ -25099,8 +25271,24 @@ ${resultContent}${attachmentSummary}`;
|
|
|
25099
25271
|
// they are bound to one bridge socket and never park.
|
|
25100
25272
|
/** Default time to wait for the client to accept a stream open. */
|
|
25101
25273
|
static CLIENT_STREAM_OPEN_TIMEOUT_MS = 3e4;
|
|
25102
|
-
/**
|
|
25103
|
-
|
|
25274
|
+
/**
|
|
25275
|
+
* In-memory waiters parked on the owner's bridge socket returning (AB-09).
|
|
25276
|
+
* Resolved by bridge attach and by execution-owner changes; each waiter
|
|
25277
|
+
* re-evaluates against the CURRENT owner on wake. In-memory only: a DO
|
|
25278
|
+
* restart drops waiters with the stream-open call that registered them.
|
|
25279
|
+
*/
|
|
25280
|
+
ownerBridgeWaiters = /* @__PURE__ */ new Set();
|
|
25281
|
+
notifyOwnerBridgeWaiters() {
|
|
25282
|
+
if (!this.ownerBridgeWaiters || this.ownerBridgeWaiters.size === 0) return;
|
|
25283
|
+
const waiters = Array.from(this.ownerBridgeWaiters);
|
|
25284
|
+
this.ownerBridgeWaiters.clear();
|
|
25285
|
+
for (const wake of waiters) {
|
|
25286
|
+
try {
|
|
25287
|
+
wake();
|
|
25288
|
+
} catch {
|
|
25289
|
+
}
|
|
25290
|
+
}
|
|
25291
|
+
}
|
|
25104
25292
|
/**
|
|
25105
25293
|
* The thread HAS an elected execution owner, but its bridge socket is gone
|
|
25106
25294
|
* (daemon restart, network blip, DO handoff). Summon the owning machine
|
|
@@ -25109,6 +25297,11 @@ ${resultContent}${attachmentSummary}`;
|
|
|
25109
25297
|
* Sama One turns with "workspace unavailable" whenever a slow tool/approval
|
|
25110
25298
|
* outlived the socket. Threads with NO recorded owner (subagent children)
|
|
25111
25299
|
* still fail fast so ancestor walk-up routing stays immediate.
|
|
25300
|
+
*
|
|
25301
|
+
* The wait parks on bridge-attach/owner-change signals under ONE hard
|
|
25302
|
+
* deadline — no re-poll cadence. Each wake re-reads the owner because the
|
|
25303
|
+
* returning daemon may reclaim with a new generation, and the socket must
|
|
25304
|
+
* match the CURRENT owner.
|
|
25112
25305
|
*/
|
|
25113
25306
|
async awaitOwnerBridgeSocket(request) {
|
|
25114
25307
|
if (request.wake?.userId) {
|
|
@@ -25116,15 +25309,25 @@ ${resultContent}${attachmentSummary}`;
|
|
|
25116
25309
|
}
|
|
25117
25310
|
const timeoutMs = typeof request.timeoutMs === "number" && request.timeoutMs > 0 ? request.timeoutMs : _DurableThread.CLIENT_STREAM_OPEN_TIMEOUT_MS;
|
|
25118
25311
|
const deadline = Date.now() + timeoutMs;
|
|
25119
|
-
|
|
25120
|
-
|
|
25121
|
-
(resolve) => setTimeout(resolve, _DurableThread.OWNER_REATTACH_POLL_MS)
|
|
25122
|
-
);
|
|
25312
|
+
this.ownerBridgeWaiters ??= /* @__PURE__ */ new Set();
|
|
25313
|
+
while (true) {
|
|
25123
25314
|
const owner = await this.getExecutionOwner();
|
|
25124
25315
|
const socket = this.getOpenBridgeSocket(owner?.client_id ?? null);
|
|
25125
25316
|
if (socket) return socket;
|
|
25317
|
+
const remainingMs = deadline - Date.now();
|
|
25318
|
+
if (remainingMs <= 0) return null;
|
|
25319
|
+
await new Promise((resolve) => {
|
|
25320
|
+
const timer = setTimeout(() => {
|
|
25321
|
+
this.ownerBridgeWaiters.delete(wake);
|
|
25322
|
+
resolve();
|
|
25323
|
+
}, remainingMs);
|
|
25324
|
+
const wake = () => {
|
|
25325
|
+
clearTimeout(timer);
|
|
25326
|
+
resolve();
|
|
25327
|
+
};
|
|
25328
|
+
this.ownerBridgeWaiters.add(wake);
|
|
25329
|
+
});
|
|
25126
25330
|
}
|
|
25127
|
-
return null;
|
|
25128
25331
|
}
|
|
25129
25332
|
/** Open a bidirectional byte stream to the connected owner client. */
|
|
25130
25333
|
async openClientStream(request) {
|
|
@@ -25268,27 +25471,38 @@ ${resultContent}${attachmentSummary}`;
|
|
|
25268
25471
|
done: false,
|
|
25269
25472
|
error: void 0,
|
|
25270
25473
|
pump: Promise.resolve(),
|
|
25271
|
-
close: (error) => duplex.close(error)
|
|
25474
|
+
close: (error) => duplex.close(error),
|
|
25475
|
+
waiter: null,
|
|
25476
|
+
notify: () => {
|
|
25477
|
+
const waiter = entry.waiter;
|
|
25478
|
+
entry.waiter = null;
|
|
25479
|
+
waiter?.();
|
|
25480
|
+
}
|
|
25272
25481
|
};
|
|
25273
25482
|
entry.pump = (async () => {
|
|
25274
25483
|
try {
|
|
25275
25484
|
while (true) {
|
|
25276
25485
|
const { value, done } = await reader.read();
|
|
25277
25486
|
if (done) break;
|
|
25278
|
-
if (value)
|
|
25487
|
+
if (value) {
|
|
25488
|
+
entry.buffer.push(value);
|
|
25489
|
+
entry.notify();
|
|
25490
|
+
}
|
|
25279
25491
|
}
|
|
25280
25492
|
} catch (error) {
|
|
25281
25493
|
entry.error = error instanceof Error ? error.message : String(error);
|
|
25282
25494
|
} finally {
|
|
25283
25495
|
entry.done = true;
|
|
25496
|
+
entry.notify();
|
|
25284
25497
|
}
|
|
25285
25498
|
})();
|
|
25286
25499
|
void duplex.done.then((d) => {
|
|
25287
25500
|
entry.done = true;
|
|
25288
25501
|
if (!d.ok && !entry.error) entry.error = d.error;
|
|
25502
|
+
entry.notify();
|
|
25289
25503
|
});
|
|
25290
25504
|
this.proxyStreams.set(id, entry);
|
|
25291
|
-
return { ok: true, id };
|
|
25505
|
+
return { ok: true, id, parkedPull: true };
|
|
25292
25506
|
}
|
|
25293
25507
|
async proxyStreamWrite(id, dataB64) {
|
|
25294
25508
|
const entry = this.proxyStreams.get(id);
|
|
@@ -25298,9 +25512,22 @@ ${resultContent}${attachmentSummary}`;
|
|
|
25298
25512
|
} catch {
|
|
25299
25513
|
}
|
|
25300
25514
|
}
|
|
25301
|
-
async proxyStreamPull(id) {
|
|
25515
|
+
async proxyStreamPull(id, maxWaitMs) {
|
|
25302
25516
|
const entry = this.proxyStreams.get(id);
|
|
25303
25517
|
if (!entry) return { chunks: [], done: true, error: "unknown proxy stream" };
|
|
25518
|
+
if (entry.buffer.length === 0 && !entry.done) {
|
|
25519
|
+
await new Promise((resolve) => {
|
|
25520
|
+
const deadline = typeof maxWaitMs === "number" && maxWaitMs > 0 ? setTimeout(() => {
|
|
25521
|
+
if (entry.waiter === wake) entry.waiter = null;
|
|
25522
|
+
resolve();
|
|
25523
|
+
}, maxWaitMs) : null;
|
|
25524
|
+
const wake = () => {
|
|
25525
|
+
if (deadline) clearTimeout(deadline);
|
|
25526
|
+
resolve();
|
|
25527
|
+
};
|
|
25528
|
+
entry.waiter = wake;
|
|
25529
|
+
});
|
|
25530
|
+
}
|
|
25304
25531
|
const chunks = entry.buffer.splice(0).map((b) => encodeStreamChunk(b));
|
|
25305
25532
|
if (entry.done && entry.buffer.length === 0) {
|
|
25306
25533
|
this.proxyStreams.delete(id);
|
|
@@ -25320,6 +25547,9 @@ ${resultContent}${attachmentSummary}`;
|
|
|
25320
25547
|
const entry = this.proxyStreams.get(id);
|
|
25321
25548
|
if (!entry) return;
|
|
25322
25549
|
this.proxyStreams.delete(id);
|
|
25550
|
+
entry.done = true;
|
|
25551
|
+
if (!entry.error) entry.error = "aborted";
|
|
25552
|
+
entry.notify();
|
|
25323
25553
|
try {
|
|
25324
25554
|
entry.close("aborted");
|
|
25325
25555
|
} catch {
|
|
@@ -25675,6 +25905,7 @@ ${resultContent}${attachmentSummary}`;
|
|
|
25675
25905
|
this.broadcastEvent(type, data);
|
|
25676
25906
|
}
|
|
25677
25907
|
broadcastEvent(type, data) {
|
|
25908
|
+
if (!this.messageSockets || this.messageSockets.size === 0) return;
|
|
25678
25909
|
const payload = JSON.stringify({
|
|
25679
25910
|
type: "event",
|
|
25680
25911
|
eventType: type,
|
|
@@ -26101,6 +26332,7 @@ ${resultContent}${attachmentSummary}`;
|
|
|
26101
26332
|
} catch {
|
|
26102
26333
|
}
|
|
26103
26334
|
this.isExecuting = false;
|
|
26335
|
+
this.notifyExecutionIdleWaiters();
|
|
26104
26336
|
this.currentAbortController = null;
|
|
26105
26337
|
await this.recordRegistryActivity(threadId, false);
|
|
26106
26338
|
tookOver = true;
|
|
@@ -26293,9 +26525,22 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
26293
26525
|
await this.assertNotTerminated();
|
|
26294
26526
|
if (this.isExecuting) {
|
|
26295
26527
|
const busyWaitBudgetMs = 3e4;
|
|
26296
|
-
const
|
|
26297
|
-
|
|
26298
|
-
|
|
26528
|
+
const deadline = Date.now() + busyWaitBudgetMs;
|
|
26529
|
+
this.executionIdleWaiters ??= /* @__PURE__ */ new Set();
|
|
26530
|
+
while (this.isExecuting) {
|
|
26531
|
+
const remainingMs = deadline - Date.now();
|
|
26532
|
+
if (remainingMs <= 0) break;
|
|
26533
|
+
await new Promise((resolve) => {
|
|
26534
|
+
const timer = setTimeout(() => {
|
|
26535
|
+
this.executionIdleWaiters.delete(wake);
|
|
26536
|
+
resolve();
|
|
26537
|
+
}, remainingMs);
|
|
26538
|
+
const wake = () => {
|
|
26539
|
+
clearTimeout(timer);
|
|
26540
|
+
resolve();
|
|
26541
|
+
};
|
|
26542
|
+
this.executionIdleWaiters.add(wake);
|
|
26543
|
+
});
|
|
26299
26544
|
}
|
|
26300
26545
|
if (this.isExecuting) {
|
|
26301
26546
|
throw new Error(
|
|
@@ -26434,6 +26679,7 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
26434
26679
|
return flowResult;
|
|
26435
26680
|
} finally {
|
|
26436
26681
|
this.isExecuting = false;
|
|
26682
|
+
this.notifyExecutionIdleWaiters();
|
|
26437
26683
|
this.currentAbortController = null;
|
|
26438
26684
|
await this.disarmExecutionWatchdog(threadId);
|
|
26439
26685
|
await this.recordRegistryActivity(threadId, false);
|
|
@@ -26647,6 +26893,7 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
26647
26893
|
}, true);
|
|
26648
26894
|
} finally {
|
|
26649
26895
|
this.isExecuting = false;
|
|
26896
|
+
this.notifyExecutionIdleWaiters();
|
|
26650
26897
|
this.currentAbortController = null;
|
|
26651
26898
|
await this.disarmExecutionWatchdog(threadId);
|
|
26652
26899
|
await this.recordRegistryActivity(threadId, false);
|
|
@@ -26773,6 +27020,7 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
26773
27020
|
);
|
|
26774
27021
|
} finally {
|
|
26775
27022
|
this.isExecuting = false;
|
|
27023
|
+
this.notifyExecutionIdleWaiters();
|
|
26776
27024
|
this.currentAbortController = null;
|
|
26777
27025
|
await this.disarmExecutionWatchdog(threadId);
|
|
26778
27026
|
await this.recordRegistryActivity(threadId, false);
|
|
@@ -27199,6 +27447,7 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
27199
27447
|
const fs = this.getFileStorage();
|
|
27200
27448
|
const from = normalizePath2(sourcePath);
|
|
27201
27449
|
const record = await fs.move(sourcePath, destinationPath);
|
|
27450
|
+
this.broadcastEvent("file_moved", { from, path: record.path, file: record });
|
|
27202
27451
|
this.broadcastEvent("file_deleted", { path: from });
|
|
27203
27452
|
this.broadcastEvent("file_created", { path: record.path, file: record });
|
|
27204
27453
|
return { success: true, file: record };
|
|
@@ -27217,6 +27466,7 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
27217
27466
|
const fs = this.getFileStorage();
|
|
27218
27467
|
const from = normalizePath2(path);
|
|
27219
27468
|
const record = await fs.rename(path, newName);
|
|
27469
|
+
this.broadcastEvent("file_moved", { from, path: record.path, file: record });
|
|
27220
27470
|
this.broadcastEvent("file_deleted", { path: from });
|
|
27221
27471
|
this.broadcastEvent("file_created", { path: record.path, file: record });
|
|
27222
27472
|
return { success: true, file: record };
|