@standardagents/builder 0.40.5-next.3b25e2a → 0.40.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/runtime.js CHANGED
@@ -1,11 +1,13 @@
1
1
  import { getProviderModelPricing } from '@standardagents/provider-pricing';
2
2
  import { jsonPathReader } from '@formkit/jsonreader';
3
3
  import { ProviderError, mapReasoningLevel, THREAD_STREAM_REASONING_PARAM, isUserEndpoint } from '@standardagents/spec';
4
- export { ProviderError, belongsToPackage, defineAgent, defineHook, defineModel, definePrompt, defineTool, isPacked, isVisibleInNamespace, mapReasoningLevel } from '@standardagents/spec';
4
+ export { ProviderError, belongsToPackage, defineAgent, defineHook, defineModel, definePrompt, defineProvider, defineTool, isPacked, isVisibleInNamespace, mapReasoningLevel, providerConst, providerEnv, providerValue } from '@standardagents/spec';
5
5
  import 'virtual:@standardagents-providers';
6
6
  import { z } from 'zod';
7
7
  import { transform, collect } from '@standardagents/sip';
8
8
  import { DurableObject, WorkerEntrypoint } from 'cloudflare:workers';
9
+ import 'fs';
10
+ import 'path';
9
11
 
10
12
  var __defProp = Object.defineProperty;
11
13
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -454,8 +456,8 @@ async function readCompletedArg(partialJson, argName) {
454
456
  controller.close();
455
457
  }
456
458
  }).getReader();
457
- for await (const [value, path] of jsonPathReader(reader, [argName])) {
458
- if (path === argName) {
459
+ for await (const [value, path2] of jsonPathReader(reader, [argName])) {
460
+ if (path2 === argName) {
459
461
  return typeof value === "string" ? value : void 0;
460
462
  }
461
463
  }
@@ -1535,11 +1537,11 @@ function stripBase64FromMessages(messages, imagePathMap) {
1535
1537
  const data = part.data;
1536
1538
  if (typeof data === "string") {
1537
1539
  if (data.startsWith("data:") || data.length > 1e3) {
1538
- const path = imagePathMap?.get(data);
1540
+ const path2 = imagePathMap?.get(data);
1539
1541
  return {
1540
1542
  ...part,
1541
1543
  data: "[base64 omitted]",
1542
- ...path ? { path } : {}
1544
+ ...path2 ? { path: path2 } : {}
1543
1545
  };
1544
1546
  }
1545
1547
  }
@@ -2105,14 +2107,14 @@ var init_LLMRequest = __esm({
2105
2107
  */
2106
2108
  static async callModel(modelId, context, state, logId) {
2107
2109
  const { ProviderRegistry: ProviderRegistry2 } = await Promise.resolve().then(() => (init_providers(), providers_exports));
2108
- const providerEnv = await ProviderRegistry2.buildThreadScopedEnv(state);
2110
+ const providerEnv2 = await ProviderRegistry2.buildThreadScopedEnv(state);
2109
2111
  const getThreadState = async () => {
2110
2112
  const { ThreadStateImpl: ThreadStateImpl2 } = await Promise.resolve().then(() => (init_ThreadStateImpl(), ThreadStateImpl_exports));
2111
2113
  return ThreadStateImpl2.fromFlowState(state);
2112
2114
  };
2113
2115
  const { provider, modelName, modelDef, viaPlatform, platformProxyOrigin } = await ProviderRegistry2.getProvider(
2114
2116
  modelId,
2115
- providerEnv,
2117
+ providerEnv2,
2116
2118
  state.thread.instance,
2117
2119
  getThreadState
2118
2120
  );
@@ -2755,11 +2757,11 @@ var init_LLMRequest = __esm({
2755
2757
  ...choice.message,
2756
2758
  images: choice.message?.images?.map(
2757
2759
  (img) => {
2758
- const path = img._id ? imagePathMap.get(img._id) : void 0;
2759
- if (path) {
2760
+ const path2 = img._id ? imagePathMap.get(img._id) : void 0;
2761
+ if (path2) {
2760
2762
  return {
2761
2763
  type: img.type,
2762
- image_url: { url: path }
2764
+ image_url: { url: path2 }
2763
2765
  };
2764
2766
  }
2765
2767
  return img;
@@ -3286,20 +3288,20 @@ function detectStorageBackend(location) {
3286
3288
  return "url";
3287
3289
  return "local";
3288
3290
  }
3289
- function basename(path) {
3290
- const parts = path.split("/").filter(Boolean);
3291
+ function basename(path2) {
3292
+ const parts = path2.split("/").filter(Boolean);
3291
3293
  return parts[parts.length - 1] || "";
3292
3294
  }
3293
- function normalizePath(path) {
3294
- let normalized = path.replace(/\/+/g, "/");
3295
+ function normalizePath(path2) {
3296
+ let normalized = path2.replace(/\/+/g, "/");
3295
3297
  if (!normalized.startsWith("/")) normalized = "/" + normalized;
3296
3298
  if (normalized.length > 1 && normalized.endsWith("/")) {
3297
3299
  normalized = normalized.slice(0, -1);
3298
3300
  }
3299
3301
  return normalized;
3300
3302
  }
3301
- function dirname(path) {
3302
- const normalized = normalizePath(path);
3303
+ function dirname(path2) {
3304
+ const normalized = normalizePath(path2);
3303
3305
  const lastSlash = normalized.lastIndexOf("/");
3304
3306
  if (lastSlash <= 0) return "/";
3305
3307
  return normalized.slice(0, lastSlash);
@@ -3317,7 +3319,7 @@ function validateMovePaths(source, destination, isDirectory) {
3317
3319
  );
3318
3320
  }
3319
3321
  }
3320
- function resolveRenameDestination(path, newName) {
3322
+ function resolveRenameDestination(path2, newName) {
3321
3323
  if (typeof newName !== "string" || newName.length === 0) {
3322
3324
  throw new Error("New name must be a non-empty string");
3323
3325
  }
@@ -3327,7 +3329,7 @@ function resolveRenameDestination(path, newName) {
3327
3329
  if (newName === "." || newName === "..") {
3328
3330
  throw new Error("New name must not be '.' or '..'");
3329
3331
  }
3330
- const normalized = normalizePath(path);
3332
+ const normalized = normalizePath(path2);
3331
3333
  const parent = dirname(normalized);
3332
3334
  return parent === "/" ? `/${newName}` : `${parent}/${newName}`;
3333
3335
  }
@@ -3451,8 +3453,8 @@ var init_files = __esm({
3451
3453
  * Write a file to storage.
3452
3454
  * Files > CHUNK_SIZE are automatically chunked into file_chunks table.
3453
3455
  */
3454
- async writeFile(path, data, mimeType, options) {
3455
- const normalizedPath = normalizePath(path);
3456
+ async writeFile(path2, data, mimeType, options) {
3457
+ const normalizedPath = normalizePath(path2);
3456
3458
  const name = basename(normalizedPath);
3457
3459
  const isText = isTextMimeType(mimeType);
3458
3460
  const now = Date.now();
@@ -3564,8 +3566,8 @@ var init_files = __esm({
3564
3566
  /**
3565
3567
  * Link to an external file (URL, S3, R2)
3566
3568
  */
3567
- async linkFile(path, location, options) {
3568
- const normalizedPath = normalizePath(path);
3569
+ async linkFile(path2, location, options) {
3570
+ const normalizedPath = normalizePath(path2);
3569
3571
  const name = basename(normalizedPath);
3570
3572
  const storage = detectStorageBackend(location);
3571
3573
  const now = Date.now();
@@ -3604,8 +3606,8 @@ var init_files = __esm({
3604
3606
  * WARNING: For large chunked files, this loads the entire file into memory.
3605
3607
  * Use streamFile() for memory-efficient access to large files.
3606
3608
  */
3607
- async readFile(path) {
3608
- const normalizedPath = normalizePath(path);
3609
+ async readFile(path2) {
3610
+ const normalizedPath = normalizePath(path2);
3609
3611
  const cursor = await this.sql.exec(
3610
3612
  `SELECT data, content, storage, is_chunked, chunk_count FROM files WHERE path = ? AND is_directory = 0`,
3611
3613
  normalizedPath
@@ -3657,8 +3659,8 @@ var init_files = __esm({
3657
3659
  * Memory-efficient way to read large chunked files.
3658
3660
  * Yields one chunk at a time for streaming HTTP responses.
3659
3661
  */
3660
- async *streamFile(path) {
3661
- const normalizedPath = normalizePath(path);
3662
+ async *streamFile(path2) {
3663
+ const normalizedPath = normalizePath(path2);
3662
3664
  const cursor = await this.sql.exec(
3663
3665
  `SELECT data, content, storage, is_chunked, chunk_count FROM files WHERE path = ? AND is_directory = 0`,
3664
3666
  normalizedPath
@@ -3692,8 +3694,8 @@ var init_files = __esm({
3692
3694
  /**
3693
3695
  * Read text file content
3694
3696
  */
3695
- async readTextFile(path) {
3696
- const normalizedPath = normalizePath(path);
3697
+ async readTextFile(path2) {
3698
+ const normalizedPath = normalizePath(path2);
3697
3699
  const cursor = await this.sql.exec(
3698
3700
  `SELECT content, data, storage FROM files WHERE path = ? AND is_directory = 0`,
3699
3701
  normalizedPath
@@ -3711,8 +3713,8 @@ var init_files = __esm({
3711
3713
  /**
3712
3714
  * Get file metadata (stat)
3713
3715
  */
3714
- async stat(path) {
3715
- const normalizedPath = normalizePath(path);
3716
+ async stat(path2) {
3717
+ const normalizedPath = normalizePath(path2);
3716
3718
  const cursor = await this.sql.exec(
3717
3719
  `SELECT path, name, mime_type, storage, location, size, metadata, is_directory, created_at, width, height, is_chunked, chunk_count
3718
3720
  FROM files WHERE path = ?`,
@@ -3725,8 +3727,8 @@ var init_files = __esm({
3725
3727
  /**
3726
3728
  * Check if file or directory exists
3727
3729
  */
3728
- async exists(path) {
3729
- const normalizedPath = normalizePath(path);
3730
+ async exists(path2) {
3731
+ const normalizedPath = normalizePath(path2);
3730
3732
  const cursor = await this.sql.exec(
3731
3733
  `SELECT COUNT(*) as count FROM files WHERE path = ?`,
3732
3734
  normalizedPath
@@ -3736,8 +3738,8 @@ var init_files = __esm({
3736
3738
  /**
3737
3739
  * Delete a file
3738
3740
  */
3739
- async unlink(path) {
3740
- const normalizedPath = normalizePath(path);
3741
+ async unlink(path2) {
3742
+ const normalizedPath = normalizePath(path2);
3741
3743
  await this.sql.exec(
3742
3744
  `DELETE FROM files WHERE path = ? AND is_directory = 0`,
3743
3745
  normalizedPath
@@ -3747,8 +3749,8 @@ var init_files = __esm({
3747
3749
  /**
3748
3750
  * Create a directory marker
3749
3751
  */
3750
- async mkdir(path) {
3751
- const normalizedPath = normalizePath(path);
3752
+ async mkdir(path2) {
3753
+ const normalizedPath = normalizePath(path2);
3752
3754
  const name = basename(normalizedPath);
3753
3755
  const now = Date.now();
3754
3756
  await this.sql.exec(
@@ -3773,8 +3775,8 @@ var init_files = __esm({
3773
3775
  /**
3774
3776
  * List directory contents
3775
3777
  */
3776
- async readdir(path) {
3777
- const normalizedPath = normalizePath(path);
3778
+ async readdir(path2) {
3779
+ const normalizedPath = normalizePath(path2);
3778
3780
  const prefix = normalizedPath === "/" ? "/" : normalizedPath + "/";
3779
3781
  const cursor = await this.sql.exec(
3780
3782
  `SELECT path, name, mime_type, storage, location, size, metadata, is_directory, created_at
@@ -3792,8 +3794,8 @@ var init_files = __esm({
3792
3794
  /**
3793
3795
  * Remove empty directory
3794
3796
  */
3795
- async rmdir(path) {
3796
- const normalizedPath = normalizePath(path);
3797
+ async rmdir(path2) {
3798
+ const normalizedPath = normalizePath(path2);
3797
3799
  const prefix = normalizedPath + "/";
3798
3800
  const cursor = await this.sql.exec(
3799
3801
  `SELECT COUNT(*) as count FROM files WHERE path LIKE ? || '%'`,
@@ -3891,9 +3893,9 @@ var init_files = __esm({
3891
3893
  * Rename a file or directory in place, keeping it in the same parent
3892
3894
  * directory. `newName` must be a bare file name with no path separators.
3893
3895
  */
3894
- async rename(path, newName) {
3895
- const destination = resolveRenameDestination(path, newName);
3896
- return this.move(normalizePath(path), destination);
3896
+ async rename(path2, newName) {
3897
+ const destination = resolveRenameDestination(path2, newName);
3898
+ return this.move(normalizePath(path2), destination);
3897
3899
  }
3898
3900
  /**
3899
3901
  * Get storage statistics
@@ -3923,8 +3925,8 @@ var init_files = __esm({
3923
3925
  /**
3924
3926
  * Get thumbnail for an image
3925
3927
  */
3926
- async getThumbnail(path) {
3927
- const normalizedPath = normalizePath(path);
3928
+ async getThumbnail(path2) {
3929
+ const normalizedPath = normalizePath(path2);
3928
3930
  const cursor = await this.sql.exec(
3929
3931
  `SELECT thumbnail FROM files WHERE path = ? AND is_directory = 0`,
3930
3932
  normalizedPath
@@ -4375,8 +4377,8 @@ var init_ToolExecutor = __esm({
4375
4377
  const validation = argsSchema.safeParse(args);
4376
4378
  if (!validation.success) {
4377
4379
  const errorMessage = validation.error.issues.map((issue) => {
4378
- const path = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
4379
- return `[${path}] ${issue.message}`;
4380
+ const path2 = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
4381
+ return `[${path2}] ${issue.message}`;
4380
4382
  }).join("; ");
4381
4383
  return {
4382
4384
  status: "error",
@@ -5074,9 +5076,7 @@ Message one with subagent_message(referenceId, message).`
5074
5076
  if (resumable) {
5075
5077
  await this.settleResumableChildAfterRun(
5076
5078
  state,
5077
- stub,
5078
- childThreadId,
5079
- childResult
5079
+ childThreadId
5080
5080
  );
5081
5081
  } else if (stub.terminateThread) {
5082
5082
  await stub.terminateThread(childThreadId);
@@ -5088,7 +5088,7 @@ Message one with subagent_message(referenceId, message).`
5088
5088
  attachments: copiedAttachments,
5089
5089
  subagent_id: childThreadId
5090
5090
  };
5091
- return resumable && !this.isTerminalSubagentResult(childResult) ? this.withReferenceInToolResult(toolResult, childThreadId) : toolResult;
5091
+ return resumable ? this.withReferenceInToolResult(toolResult, childThreadId) : toolResult;
5092
5092
  }
5093
5093
  const backgroundRun = (async () => {
5094
5094
  try {
@@ -5123,9 +5123,7 @@ Message one with subagent_message(referenceId, message).`
5123
5123
  if (resumable) {
5124
5124
  await this.settleResumableChildAfterRun(
5125
5125
  state,
5126
- stub,
5127
- childThreadId,
5128
- childResult
5126
+ childThreadId
5129
5127
  );
5130
5128
  } else if (stub.terminateThread) {
5131
5129
  await stub.terminateThread(childThreadId);
@@ -5374,13 +5372,13 @@ Message one with subagent_message(referenceId, message).`
5374
5372
  new Set(
5375
5373
  issues.map(
5376
5374
  (issue) => Array.isArray(issue.path) ? issue.path.map(String).join(".") : String(issue.path ?? "")
5377
- ).filter((path) => path.length > 0)
5375
+ ).filter((path2) => path2.length > 0)
5378
5376
  )
5379
5377
  );
5380
5378
  const detail = issues.map((issue) => {
5381
- const path = Array.isArray(issue.path) ? issue.path.map(String).join(".") : "";
5379
+ const path2 = Array.isArray(issue.path) ? issue.path.map(String).join(".") : "";
5382
5380
  const message = typeof issue.message === "string" ? issue.message : "invalid value";
5383
- return path ? `${path}: ${message}` : message;
5381
+ return path2 ? `${path2}: ${message}` : message;
5384
5382
  }).join("; ") || parsed.error.message || "invalid arguments";
5385
5383
  const agentLabel = agentDef.title || agentDef.name || options.agentName || qualifiedPromptName;
5386
5384
  return {
@@ -5520,18 +5518,8 @@ Message one with subagent_message(referenceId, message).`
5520
5518
  JSON.stringify(next)
5521
5519
  );
5522
5520
  }
5523
- static isTerminalSubagentResult(result) {
5524
- return result.terminal === true;
5525
- }
5526
- static async settleResumableChildAfterRun(state, childThread, reference, result) {
5527
- if (!this.isTerminalSubagentResult(result)) {
5528
- await this.updateChildStatus(state, reference, "idle");
5529
- return;
5530
- }
5531
- await this.updateChildStatus(state, reference, "terminated");
5532
- if (typeof childThread.terminateThread === "function") {
5533
- await childThread.terminateThread(reference);
5534
- }
5521
+ static async settleResumableChildAfterRun(state, reference) {
5522
+ await this.updateChildStatus(state, reference, "idle");
5535
5523
  }
5536
5524
  static async buildChildInvocationMessages(state, childThread, content, receivesMessages, parentAttachments, initialArguments) {
5537
5525
  const copiedAttachments = await this.copyAttachmentsBetweenThreads(
@@ -5739,8 +5727,8 @@ Reference: ${referenceId}` : `Reference: ${referenceId}`;
5739
5727
  }
5740
5728
  return [];
5741
5729
  }
5742
- static inferMimeTypeFromPath(path) {
5743
- const normalized = path.toLowerCase();
5730
+ static inferMimeTypeFromPath(path2) {
5731
+ const normalized = path2.toLowerCase();
5744
5732
  if (normalized.endsWith(".png")) return "image/png";
5745
5733
  if (normalized.endsWith(".jpg") || normalized.endsWith(".jpeg")) return "image/jpeg";
5746
5734
  if (normalized.endsWith(".webp")) return "image/webp";
@@ -5779,7 +5767,7 @@ Reference: ${referenceId}` : `Reference: ${referenceId}`;
5779
5767
  ext: value.slice(lastDot + 1).toLowerCase()
5780
5768
  };
5781
5769
  }
5782
- static resolveAttachmentMimeType(sourceMimeType, fallbackMimeType, path) {
5770
+ static resolveAttachmentMimeType(sourceMimeType, fallbackMimeType, path2) {
5783
5771
  const source = sourceMimeType?.trim();
5784
5772
  if (source && source !== "application/octet-stream") {
5785
5773
  return source;
@@ -5788,7 +5776,7 @@ Reference: ${referenceId}` : `Reference: ${referenceId}`;
5788
5776
  if (fallback && fallback !== "application/octet-stream") {
5789
5777
  return fallback;
5790
5778
  }
5791
- return this.inferMimeTypeFromPath(path) ?? source ?? fallback ?? "application/octet-stream";
5779
+ return this.inferMimeTypeFromPath(path2) ?? source ?? fallback ?? "application/octet-stream";
5792
5780
  }
5793
5781
  static buildAttachmentTargetPath(preferredName, mimeType, sourcePath) {
5794
5782
  const safeName = this.sanitizeFilename(preferredName);
@@ -5885,8 +5873,8 @@ Reference: ${referenceId}` : `Reference: ${referenceId}`;
5885
5873
  }
5886
5874
  return copied;
5887
5875
  }
5888
- static async readAttachmentDataFromSource(sourceThread, path, sourceFile, allowedAttachmentFetchHosts) {
5889
- const sourceData = await sourceThread.readFile(path);
5876
+ static async readAttachmentDataFromSource(sourceThread, path2, sourceFile, allowedAttachmentFetchHosts) {
5877
+ const sourceData = await sourceThread.readFile(path2);
5890
5878
  if (sourceData.success && sourceData.data) {
5891
5879
  return sourceData.data;
5892
5880
  }
@@ -5923,7 +5911,7 @@ Reference: ${referenceId}` : `Reference: ${referenceId}`;
5923
5911
  if (!attachments || attachments.length === 0) {
5924
5912
  return "";
5925
5913
  }
5926
- const paths = attachments.map((attachment) => attachment.path).filter((path) => typeof path === "string" && path.length > 0);
5914
+ const paths = attachments.map((attachment) => attachment.path).filter((path2) => typeof path2 === "string" && path2.length > 0);
5927
5915
  if (paths.length === 0) {
5928
5916
  return "";
5929
5917
  }
@@ -6220,7 +6208,7 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
6220
6208
  mappedAttachmentValue
6221
6209
  );
6222
6210
  const resolvedPaths = new Set(mappedRefs.map((ref) => ref.path));
6223
- const missingPaths = candidatePaths.filter((path) => !resolvedPaths.has(path));
6211
+ const missingPaths = candidatePaths.filter((path2) => !resolvedPaths.has(path2));
6224
6212
  if (candidatePaths.length === 0 || missingPaths.length > 0) {
6225
6213
  processedResult = {
6226
6214
  status: "error",
@@ -6402,8 +6390,8 @@ ${attachmentPaths}`;
6402
6390
  if (mimeType.startsWith("image/")) {
6403
6391
  return true;
6404
6392
  }
6405
- const path = ref.path.toLowerCase();
6406
- return path.endsWith(".png") || path.endsWith(".jpg") || path.endsWith(".jpeg") || path.endsWith(".webp") || path.endsWith(".gif") || path.endsWith(".bmp") || path.endsWith(".svg");
6393
+ const path2 = ref.path.toLowerCase();
6394
+ return path2.endsWith(".png") || path2.endsWith(".jpg") || path2.endsWith(".jpeg") || path2.endsWith(".webp") || path2.endsWith(".gif") || path2.endsWith(".bmp") || path2.endsWith(".svg");
6407
6395
  });
6408
6396
  if (imageRefs.length === 0) {
6409
6397
  return;
@@ -6469,27 +6457,27 @@ ${attachmentPaths}`;
6469
6457
  */
6470
6458
  static async processToolAttachments(attachments, state) {
6471
6459
  const { FileStorage: FileStorage2 } = await Promise.resolve().then(() => (init_files(), files_exports));
6472
- const fs = new FileStorage2(state.storage.sql);
6460
+ const fs2 = new FileStorage2(state.storage.sql);
6473
6461
  const refs = [];
6474
6462
  for (const attachment of attachments) {
6475
6463
  try {
6476
6464
  const attachmentId = crypto.randomUUID();
6477
6465
  const timestamp = Date.now();
6478
6466
  const ext = attachment.mimeType === "image/png" ? "png" : attachment.mimeType === "image/jpeg" ? "jpg" : attachment.mimeType === "image/gif" ? "gif" : attachment.mimeType === "image/webp" ? "webp" : attachment.name.split(".").pop() || "bin";
6479
- const path = `/attachments/${timestamp}-${attachmentId.slice(0, 8)}.${ext}`;
6467
+ const path2 = `/attachments/${timestamp}-${attachmentId.slice(0, 8)}.${ext}`;
6480
6468
  const binaryString = atob(attachment.data);
6481
6469
  const dataBuffer = new Uint8Array(binaryString.length);
6482
6470
  for (let i = 0; i < binaryString.length; i++) {
6483
6471
  dataBuffer[i] = binaryString.charCodeAt(i);
6484
6472
  }
6485
- await fs.writeFile(path, dataBuffer.buffer, attachment.mimeType, {
6473
+ await fs2.writeFile(path2, dataBuffer.buffer, attachment.mimeType, {
6486
6474
  width: attachment.width,
6487
6475
  height: attachment.height
6488
6476
  });
6489
6477
  const ref = {
6490
6478
  id: attachmentId,
6491
6479
  type: "file",
6492
- path,
6480
+ path: path2,
6493
6481
  name: attachment.name,
6494
6482
  mimeType: attachment.mimeType,
6495
6483
  size: dataBuffer.byteLength
@@ -10852,20 +10840,20 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
10852
10840
  continue;
10853
10841
  }
10854
10842
  const attachmentId = crypto.randomUUID();
10855
- const path = `/attachments/${Date.now()}-${attachmentId.slice(0, 8)}.${ext}`;
10843
+ const path2 = `/attachments/${Date.now()}-${attachmentId.slice(0, 8)}.${ext}`;
10856
10844
  try {
10857
- const written = await state.thread.instance.writeFile(path, base64Data, mimeType);
10845
+ const written = await state.thread.instance.writeFile(path2, base64Data, mimeType);
10858
10846
  if (written && written.success === false) {
10859
10847
  console.error("[FlowEngine] Generated image write failed:", written.error);
10860
10848
  continue;
10861
10849
  }
10862
10850
  if (image.id) {
10863
- imagePathMap.set(image.id, path);
10851
+ imagePathMap.set(image.id, path2);
10864
10852
  }
10865
10853
  refs.push({
10866
10854
  id: attachmentId,
10867
10855
  type: "file",
10868
- path,
10856
+ path: path2,
10869
10857
  name: `generated-${attachmentId}.${ext}`,
10870
10858
  mimeType,
10871
10859
  size: Math.ceil(base64Data.length * 3 / 4)
@@ -10930,9 +10918,9 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
10930
10918
  continue;
10931
10919
  }
10932
10920
  const attachmentId = crypto.randomUUID();
10933
- const path = `/attachments/${Date.now()}-${attachmentId.slice(0, 8)}.${ext}`;
10921
+ const path2 = `/attachments/${Date.now()}-${attachmentId.slice(0, 8)}.${ext}`;
10934
10922
  try {
10935
- const written = await state.thread.instance.writeFile(path, base64Data, mimeType);
10923
+ const written = await state.thread.instance.writeFile(path2, base64Data, mimeType);
10936
10924
  if (written && written.success === false) {
10937
10925
  console.error(`[FlowEngine] ${toolName} image write failed:`, written.error);
10938
10926
  continue;
@@ -10940,7 +10928,7 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
10940
10928
  const attachmentRef = {
10941
10929
  id: attachmentId,
10942
10930
  type: "file",
10943
- path,
10931
+ path: path2,
10944
10932
  name: `generated-${attachmentId}.${ext}`,
10945
10933
  mimeType,
10946
10934
  size: Math.ceil(base64Data.length * 3 / 4)
@@ -11003,7 +10991,7 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
11003
10991
  content: "Image generated successfully",
11004
10992
  status: "success",
11005
10993
  timestamp: Date.now(),
11006
- attachment_path: path
10994
+ attachment_path: path2
11007
10995
  });
11008
10996
  await state.storage.sql.exec(
11009
10997
  `UPDATE logs SET tool_results = ?1 WHERE id = ?2`,
@@ -11025,7 +11013,7 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
11025
11013
  }
11026
11014
  }
11027
11015
  if (image.id) {
11028
- imagePathMap.set(image.id, path);
11016
+ imagePathMap.set(image.id, path2);
11029
11017
  }
11030
11018
  } catch (error) {
11031
11019
  console.error(`[FlowEngine] Failed to store provider tool result for ${toolName}:`, error);
@@ -11890,7 +11878,7 @@ async function updateThread(thread, params) {
11890
11878
  }
11891
11879
  return result.thread;
11892
11880
  }
11893
- async function writeFile(flow, path, data, mimeType, options) {
11881
+ async function writeFile(flow, path2, data, mimeType, options) {
11894
11882
  const instance = flow.thread.instance;
11895
11883
  let base64Data;
11896
11884
  if (typeof data === "string") {
@@ -11912,7 +11900,7 @@ async function writeFile(flow, path, data, mimeType, options) {
11912
11900
  }
11913
11901
  base64Thumbnail = btoa(binary);
11914
11902
  }
11915
- const result = await instance.writeFile(path, base64Data, mimeType, {
11903
+ const result = await instance.writeFile(path2, base64Data, mimeType, {
11916
11904
  metadata: options?.metadata,
11917
11905
  thumbnail: base64Thumbnail
11918
11906
  });
@@ -11921,20 +11909,20 @@ async function writeFile(flow, path, data, mimeType, options) {
11921
11909
  }
11922
11910
  return result.file;
11923
11911
  }
11924
- async function writeImage(flow, path, data, mimeType, options) {
11925
- return writeFile(flow, path, data, mimeType, options);
11912
+ async function writeImage(flow, path2, data, mimeType, options) {
11913
+ return writeFile(flow, path2, data, mimeType, options);
11926
11914
  }
11927
- async function linkFile(flow, path, location, options) {
11915
+ async function linkFile(flow, path2, location, options) {
11928
11916
  const instance = flow.thread.instance;
11929
- const result = await instance.linkFile(path, location, options);
11917
+ const result = await instance.linkFile(path2, location, options);
11930
11918
  if (!result.success) {
11931
11919
  throw new Error(result.error || "Failed to link file");
11932
11920
  }
11933
11921
  return result.file;
11934
11922
  }
11935
- async function readFile(flow, path) {
11923
+ async function readFile(flow, path2) {
11936
11924
  const instance = flow.thread.instance;
11937
- const result = await instance.readFile(path);
11925
+ const result = await instance.readFile(path2);
11938
11926
  if (!result.success) {
11939
11927
  return null;
11940
11928
  }
@@ -11945,45 +11933,45 @@ async function readFile(flow, path) {
11945
11933
  }
11946
11934
  return bytes.buffer;
11947
11935
  }
11948
- async function stat(flow, path) {
11936
+ async function stat(flow, path2) {
11949
11937
  const instance = flow.thread.instance;
11950
- const result = await instance.statFile(path);
11938
+ const result = await instance.statFile(path2);
11951
11939
  if (!result.success) {
11952
11940
  return null;
11953
11941
  }
11954
11942
  return result.file;
11955
11943
  }
11956
- async function exists(flow, path) {
11944
+ async function exists(flow, path2) {
11957
11945
  const instance = flow.thread.instance;
11958
- const result = await instance.fileExists(path);
11946
+ const result = await instance.fileExists(path2);
11959
11947
  return result.success && result.exists;
11960
11948
  }
11961
- async function unlink(flow, path) {
11949
+ async function unlink(flow, path2) {
11962
11950
  const instance = flow.thread.instance;
11963
- const result = await instance.unlinkFile(path);
11951
+ const result = await instance.unlinkFile(path2);
11964
11952
  if (!result.success) {
11965
11953
  throw new Error(result.error || "Failed to delete file");
11966
11954
  }
11967
11955
  }
11968
- async function mkdir(flow, path) {
11956
+ async function mkdir(flow, path2) {
11969
11957
  const instance = flow.thread.instance;
11970
- const result = await instance.mkdirFile(path);
11958
+ const result = await instance.mkdirFile(path2);
11971
11959
  if (!result.success) {
11972
11960
  throw new Error(result.error || "Failed to create directory");
11973
11961
  }
11974
11962
  return result.directory;
11975
11963
  }
11976
- async function readdir(flow, path) {
11964
+ async function readdir(flow, path2) {
11977
11965
  const instance = flow.thread.instance;
11978
- const result = await instance.readdirFile(path);
11966
+ const result = await instance.readdirFile(path2);
11979
11967
  if (!result.success) {
11980
11968
  throw new Error(result.error || "Failed to read directory");
11981
11969
  }
11982
11970
  return result.files;
11983
11971
  }
11984
- async function rmdir(flow, path) {
11972
+ async function rmdir(flow, path2) {
11985
11973
  const instance = flow.thread.instance;
11986
- const result = await instance.rmdirFile(path);
11974
+ const result = await instance.rmdirFile(path2);
11987
11975
  if (!result.success) {
11988
11976
  throw new Error(result.error || "Failed to remove directory");
11989
11977
  }
@@ -11996,9 +11984,9 @@ async function move(flow, sourcePath, destinationPath) {
11996
11984
  }
11997
11985
  return result.file;
11998
11986
  }
11999
- async function rename(flow, path, newName) {
11987
+ async function rename(flow, path2, newName) {
12000
11988
  const instance = flow.thread.instance;
12001
- const result = await instance.renameFile(path, newName);
11989
+ const result = await instance.renameFile(path2, newName);
12002
11990
  if (!result.success) {
12003
11991
  throw new Error(result.error || "Failed to rename file");
12004
11992
  }
@@ -12012,9 +12000,9 @@ async function getFileStats(flow) {
12012
12000
  }
12013
12001
  return result.stats;
12014
12002
  }
12015
- async function getThumbnail(flow, path) {
12003
+ async function getThumbnail(flow, path2) {
12016
12004
  const instance = flow.thread.instance;
12017
- const result = await instance.getFileThumbnail(path);
12005
+ const result = await instance.getFileThumbnail(path2);
12018
12006
  if (!result.success) {
12019
12007
  return null;
12020
12008
  }
@@ -12025,22 +12013,22 @@ async function getThumbnail(flow, path) {
12025
12013
  }
12026
12014
  return bytes.buffer;
12027
12015
  }
12028
- async function cat(flow, path) {
12016
+ async function cat(flow, path2) {
12029
12017
  const instance = flow.thread.instance;
12030
- const result = await instance.readTextFile(path);
12018
+ const result = await instance.readTextFile(path2);
12031
12019
  if (!result.success) {
12032
12020
  return null;
12033
12021
  }
12034
12022
  return result.content;
12035
12023
  }
12036
- async function head(flow, path, lines = 10) {
12037
- const content = await cat(flow, path);
12024
+ async function head(flow, path2, lines = 10) {
12025
+ const content = await cat(flow, path2);
12038
12026
  if (content === null) return null;
12039
12027
  const allLines = content.split("\n");
12040
12028
  return allLines.slice(0, lines).join("\n");
12041
12029
  }
12042
- async function tail(flow, path, lines = 10) {
12043
- const content = await cat(flow, path);
12030
+ async function tail(flow, path2, lines = 10) {
12031
+ const content = await cat(flow, path2);
12044
12032
  if (content === null) return null;
12045
12033
  const allLines = content.split("\n");
12046
12034
  return allLines.slice(-lines).join("\n");
@@ -12579,32 +12567,32 @@ function prepareBridge(options, reports, logs) {
12579
12567
  logs
12580
12568
  };
12581
12569
  }
12582
- function prepareNamespaceRecord(value, path, functions) {
12570
+ function prepareNamespaceRecord(value, path2, functions) {
12583
12571
  const out = {};
12584
12572
  for (const [key, namespace] of Object.entries(value)) {
12585
- out[key] = prepareValueRecord(namespace, `${path}.${key}`, functions);
12573
+ out[key] = prepareValueRecord(namespace, `${path2}.${key}`, functions);
12586
12574
  }
12587
12575
  return out;
12588
12576
  }
12589
- function prepareValueRecord(value, path, functions) {
12577
+ function prepareValueRecord(value, path2, functions) {
12590
12578
  const out = {};
12591
12579
  for (const [key, item] of Object.entries(value)) {
12592
- out[key] = prepareBridgeValue(item, `${path}.${key}`, functions);
12580
+ out[key] = prepareBridgeValue(item, `${path2}.${key}`, functions);
12593
12581
  }
12594
12582
  return out;
12595
12583
  }
12596
- function prepareBridgeValue(value, path, functions) {
12584
+ function prepareBridgeValue(value, path2, functions) {
12597
12585
  if (typeof value === "function") {
12598
- functions.set(path, value);
12599
- return { __agentbuilderType: "function", id: path };
12586
+ functions.set(path2, value);
12587
+ return { __agentbuilderType: "function", id: path2 };
12600
12588
  }
12601
12589
  if (isThenable(value)) {
12602
- const promiseId = `${path}.__promise`;
12590
+ const promiseId = `${path2}.__promise`;
12603
12591
  functions.set(promiseId, async () => value);
12604
12592
  return { __agentbuilderType: "promise", id: promiseId };
12605
12593
  }
12606
12594
  if (Array.isArray(value)) {
12607
- return value.map((item, index) => prepareBridgeValue(item, `${path}.${index}`, functions));
12595
+ return value.map((item, index) => prepareBridgeValue(item, `${path2}.${index}`, functions));
12608
12596
  }
12609
12597
  if (value && typeof value === "object") {
12610
12598
  if (value instanceof Date || value instanceof Map || value instanceof Set || ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {
@@ -12615,7 +12603,7 @@ function prepareBridgeValue(value, path, functions) {
12615
12603
  }
12616
12604
  const out = {};
12617
12605
  for (const [key, item] of Object.entries(value)) {
12618
- out[key] = prepareBridgeValue(item, `${path}.${key}`, functions);
12606
+ out[key] = prepareBridgeValue(item, `${path2}.${key}`, functions);
12619
12607
  }
12620
12608
  return out;
12621
12609
  }
@@ -13490,12 +13478,12 @@ function normalizeVirtualModulePath(basePath, specifier) {
13490
13478
  }
13491
13479
  return normalized;
13492
13480
  }
13493
- function dirnameModulePath(path) {
13494
- const index = path.lastIndexOf("/");
13495
- return index <= 0 ? "" : path.slice(0, index);
13481
+ function dirnameModulePath(path2) {
13482
+ const index = path2.lastIndexOf("/");
13483
+ return index <= 0 ? "" : path2.slice(0, index);
13496
13484
  }
13497
- function hasModuleExtension(path) {
13498
- return /\.[A-Za-z0-9]+$/.test(path);
13485
+ function hasModuleExtension(path2) {
13486
+ return /\.[A-Za-z0-9]+$/.test(path2);
13499
13487
  }
13500
13488
  function resolveGraphModuleSpecifier(fromPath, specifier, modulePaths) {
13501
13489
  const base = normalizeVirtualModulePath(dirnameModulePath(fromPath), specifier);
@@ -13852,9 +13840,9 @@ function isPlainObject2(value) {
13852
13840
  const prototype = Object.getPrototypeOf(value);
13853
13841
  return prototype === Object.prototype || prototype === null;
13854
13842
  }
13855
- function findUntransferableOption(value, path, seen = /* @__PURE__ */ new WeakSet()) {
13843
+ function findUntransferableOption(value, path2, seen = /* @__PURE__ */ new WeakSet()) {
13856
13844
  if (typeof value === "function" || typeof value === "symbol") {
13857
- return path;
13845
+ return path2;
13858
13846
  }
13859
13847
  if (!value || typeof value !== "object") {
13860
13848
  return null;
@@ -13868,7 +13856,7 @@ function findUntransferableOption(value, path, seen = /* @__PURE__ */ new WeakSe
13868
13856
  seen.add(value);
13869
13857
  if (Array.isArray(value)) {
13870
13858
  for (const [index, item] of value.entries()) {
13871
- const found = findUntransferableOption(item, `${path}.${index}`, seen);
13859
+ const found = findUntransferableOption(item, `${path2}.${index}`, seen);
13872
13860
  if (found) return found;
13873
13861
  }
13874
13862
  return null;
@@ -13876,9 +13864,9 @@ function findUntransferableOption(value, path, seen = /* @__PURE__ */ new WeakSe
13876
13864
  if (value instanceof Map) {
13877
13865
  let index = 0;
13878
13866
  for (const [key, item] of value.entries()) {
13879
- const foundKey = findUntransferableOption(key, `${path}.mapKey${index}`, seen);
13867
+ const foundKey = findUntransferableOption(key, `${path2}.mapKey${index}`, seen);
13880
13868
  if (foundKey) return foundKey;
13881
- const foundValue = findUntransferableOption(item, `${path}.mapValue${index}`, seen);
13869
+ const foundValue = findUntransferableOption(item, `${path2}.mapValue${index}`, seen);
13882
13870
  if (foundValue) return foundValue;
13883
13871
  index += 1;
13884
13872
  }
@@ -13887,17 +13875,17 @@ function findUntransferableOption(value, path, seen = /* @__PURE__ */ new WeakSe
13887
13875
  if (value instanceof Set) {
13888
13876
  let index = 0;
13889
13877
  for (const item of value.values()) {
13890
- const found = findUntransferableOption(item, `${path}.setValue${index}`, seen);
13878
+ const found = findUntransferableOption(item, `${path2}.setValue${index}`, seen);
13891
13879
  if (found) return found;
13892
13880
  index += 1;
13893
13881
  }
13894
13882
  return null;
13895
13883
  }
13896
13884
  if (!isPlainObject2(value)) {
13897
- return path;
13885
+ return path2;
13898
13886
  }
13899
13887
  for (const [key, item] of Object.entries(value)) {
13900
- const found = findUntransferableOption(item, `${path}.${key}`, seen);
13888
+ const found = findUntransferableOption(item, `${path2}.${key}`, seen);
13901
13889
  if (found) return found;
13902
13890
  }
13903
13891
  return null;
@@ -14727,27 +14715,51 @@ var init_ThreadStateImpl = __esm({
14727
14715
  const withWake = (threadId) => wakeUserId ? { ...request, wake: { threadId, userId: wakeUserId } } : request;
14728
14716
  const local = await instance.openClientStream(withWake(this._metadata.id));
14729
14717
  if (local.ok || !this.isNoClient(local)) return local;
14730
- const env = this._threadInstance.env;
14731
- if (!env?.AGENT_BUILDER_THREAD) return local;
14718
+ if (typeof instance.createProxyStreamReceiver !== "function" || typeof instance.proxyStreamReceive !== "function") {
14719
+ return local;
14720
+ }
14721
+ let abortRemote = null;
14722
+ const receiver = instance.createProxyStreamReceiver((error) => abortRemote?.(error));
14723
+ const discardReceiver = async (error) => {
14724
+ await instance.proxyStreamReceive(receiver.id, { type: "abort", error });
14725
+ };
14726
+ const namespace = instance.env.AGENT_BUILDER_THREAD;
14732
14727
  const seen = /* @__PURE__ */ new Set([this._metadata.id]);
14733
14728
  let parentId = await this.resolveParentThreadId(this._metadata.id);
14734
14729
  while (parentId && !seen.has(parentId)) {
14735
14730
  seen.add(parentId);
14736
14731
  try {
14737
- const stub = env.AGENT_BUILDER_THREAD.get(env.AGENT_BUILDER_THREAD.idFromName(parentId));
14732
+ const stub = namespace.get(namespace.idFromName(parentId));
14738
14733
  if (typeof stub.proxyStreamOpen === "function") {
14739
- const opened = await stub.proxyStreamOpen(withWake(parentId));
14734
+ const opened = await stub.proxyStreamOpen(withWake(parentId), {
14735
+ threadId: this._metadata.id,
14736
+ receiverId: receiver.id
14737
+ });
14740
14738
  if (opened.ok && opened.id) {
14739
+ if (opened.eventDriven !== true) {
14740
+ await stub.proxyStreamAbort(opened.id).catch(() => {
14741
+ });
14742
+ await discardReceiver("The ancestor runtime does not support event-driven streams.");
14743
+ return {
14744
+ ok: false,
14745
+ error: "The ancestor runtime does not support event-driven streams.",
14746
+ data: { code: "unsupported" }
14747
+ };
14748
+ }
14749
+ abortRemote = (error) => {
14750
+ void stub.proxyStreamAbort(opened.id).catch(() => {
14751
+ });
14752
+ if (error) {
14753
+ void instance.proxyStreamReceive(receiver.id, { type: "abort", error });
14754
+ }
14755
+ };
14741
14756
  return {
14742
14757
  ok: true,
14743
- duplex: this.buildProxyDuplex(
14744
- stub,
14745
- opened.id,
14746
- opened.parkedPull === true
14747
- )
14758
+ duplex: this.buildEventProxyDuplex(stub, opened.id, receiver, instance)
14748
14759
  };
14749
14760
  }
14750
14761
  if (opened.error && !opened.noClient) {
14762
+ await discardReceiver(opened.error);
14751
14763
  return {
14752
14764
  ok: false,
14753
14765
  error: opened.error,
@@ -14759,69 +14771,21 @@ var init_ThreadStateImpl = __esm({
14759
14771
  }
14760
14772
  parentId = await this.resolveParentThreadId(parentId);
14761
14773
  }
14774
+ await discardReceiver(local.error ?? "No execution-owner bridge is available.");
14762
14775
  return local;
14763
14776
  }
14764
14777
  /**
14765
14778
  * Build a client duplex that bridges to a stream opened on an ancestor DO
14766
- * (the bridge holder) via chunk-pull RPCs. `readable` issues PARKED pulls —
14767
- * a current ancestor holds one `proxyStreamPull` until bytes, completion,
14768
- * error, or abort, so an idle open stream performs zero repeated pulls.
14769
- * Older ancestors use the bounded long-pull compatibility path. `writable`
14770
- * forwards each chunk with `proxyStreamWrite`; teardown calls
14771
- * `proxyStreamAbort`.
14779
+ * (the bridge holder). The readable is the receiver registered on this DO;
14780
+ * writes and terminal actions are the only child-to-ancestor RPCs.
14772
14781
  */
14773
- static PROXY_PULL_MAX_WAIT_MS = 2e4;
14774
- buildProxyDuplex(stub, id, supportsParkedPull = false) {
14775
- let settleDone;
14776
- const done = new Promise((r) => settleDone = r);
14782
+ buildEventProxyDuplex(stub, id, receiver, instance) {
14777
14783
  let closed = false;
14778
- let settled = false;
14779
- const settle = (result) => {
14780
- if (settled) return;
14781
- settled = true;
14782
- settleDone(result);
14784
+ const settleLocal = (error) => {
14785
+ if (typeof instance.proxyStreamReceive !== "function") return;
14786
+ const frame = error ? { type: "abort", error } : { type: "end" };
14787
+ void instance.proxyStreamReceive(receiver.id, frame);
14783
14788
  };
14784
- const readable = new ReadableStream({
14785
- async pull(controller) {
14786
- while (!closed) {
14787
- const pullStartedAt = Date.now();
14788
- let res;
14789
- try {
14790
- res = await stub.proxyStreamPull(
14791
- id,
14792
- supportsParkedPull ? void 0 : _ThreadStateImpl.PROXY_PULL_MAX_WAIT_MS
14793
- );
14794
- } catch (error) {
14795
- controller.error(error instanceof Error ? error : new Error(String(error)));
14796
- settle({ ok: false, error: "proxy stream pull failed" });
14797
- return;
14798
- }
14799
- for (const chunk of res.chunks) {
14800
- controller.enqueue(decodeStreamChunk(chunk));
14801
- }
14802
- if (res.done) {
14803
- controller.close();
14804
- settle(res.error ? { ok: false, error: res.error } : { ok: true });
14805
- return;
14806
- }
14807
- if (res.chunks.length > 0) return;
14808
- if (supportsParkedPull) {
14809
- controller.error(new Error("parked proxy pull returned without data"));
14810
- settle({ ok: false, error: "parked proxy pull returned without data" });
14811
- return;
14812
- }
14813
- if (Date.now() - pullStartedAt < 250) {
14814
- await new Promise((r) => setTimeout(r, 250));
14815
- }
14816
- }
14817
- },
14818
- cancel() {
14819
- closed = true;
14820
- void stub.proxyStreamAbort(id).catch(() => {
14821
- });
14822
- settle({ ok: false, error: "proxy stream reader canceled" });
14823
- }
14824
- });
14825
14789
  const writable = new WritableStream({
14826
14790
  async write(chunk) {
14827
14791
  await stub.proxyStreamWrite(id, encodeStreamChunk(chunk));
@@ -14834,20 +14798,20 @@ var init_ThreadStateImpl = __esm({
14834
14798
  closed = true;
14835
14799
  void stub.proxyStreamAbort(id).catch(() => {
14836
14800
  });
14837
- settle({ ok: false, error: "proxy stream writer aborted" });
14801
+ settleLocal("The proxy stream writer was aborted.");
14838
14802
  }
14839
14803
  });
14840
14804
  return {
14841
- readable,
14805
+ readable: receiver.readable,
14842
14806
  writable,
14843
14807
  close: (error) => {
14844
14808
  if (closed) return;
14845
14809
  closed = true;
14846
14810
  void stub.proxyStreamAbort(id).catch(() => {
14847
14811
  });
14848
- settle(error ? { ok: false, error } : { ok: true });
14812
+ settleLocal(error);
14849
14813
  },
14850
- done
14814
+ done: receiver.done
14851
14815
  };
14852
14816
  }
14853
14817
  isNoClient(res) {
@@ -14873,7 +14837,7 @@ var init_ThreadStateImpl = __esm({
14873
14837
  // ─────────────────────────────────────────────────────────────────────────
14874
14838
  // File System
14875
14839
  // ─────────────────────────────────────────────────────────────────────────
14876
- async writeFile(path, data, mimeType, options) {
14840
+ async writeFile(path2, data, mimeType, options) {
14877
14841
  const isText = this._isTextMimeType(mimeType);
14878
14842
  if (isText) {
14879
14843
  let textContent;
@@ -14882,7 +14846,7 @@ var init_ThreadStateImpl = __esm({
14882
14846
  } else {
14883
14847
  textContent = new TextDecoder().decode(data);
14884
14848
  }
14885
- const result = await this._threadInstance.writeTextFile(path, textContent, mimeType, options);
14849
+ const result = await this._threadInstance.writeTextFile(path2, textContent, mimeType, options);
14886
14850
  return this._mapFileRecord(result.file);
14887
14851
  } else {
14888
14852
  let base64Data;
@@ -14902,7 +14866,7 @@ var init_ThreadStateImpl = __esm({
14902
14866
  }
14903
14867
  base64Data = btoa(binary);
14904
14868
  }
14905
- const result = await this._threadInstance.writeFile(path, base64Data, mimeType, options);
14869
+ const result = await this._threadInstance.writeFile(path2, base64Data, mimeType, options);
14906
14870
  return this._mapFileRecord(result.file);
14907
14871
  }
14908
14872
  }
@@ -14974,8 +14938,8 @@ var init_ThreadStateImpl = __esm({
14974
14938
  (type) => mimeType === type || mimeType.startsWith(type + ";")
14975
14939
  );
14976
14940
  }
14977
- async readFile(path) {
14978
- const result = await this._threadInstance.readFile(path);
14941
+ async readFile(path2) {
14942
+ const result = await this._threadInstance.readFile(path2);
14979
14943
  if (!result.success || !result.data) {
14980
14944
  return null;
14981
14945
  }
@@ -14986,8 +14950,8 @@ var init_ThreadStateImpl = __esm({
14986
14950
  }
14987
14951
  return bytes.buffer;
14988
14952
  }
14989
- async readFileStream(path, options) {
14990
- const fileInfo = this._unwrapStatRecord(await this._threadInstance.statFile(path));
14953
+ async readFileStream(path2, options) {
14954
+ const fileInfo = this._unwrapStatRecord(await this._threadInstance.statFile(path2));
14991
14955
  if (!fileInfo) {
14992
14956
  return null;
14993
14957
  }
@@ -15002,7 +14966,7 @@ var init_ThreadStateImpl = __esm({
15002
14966
  return {
15003
14967
  [Symbol.asyncIterator]: async function* () {
15004
14968
  if (!isChunked) {
15005
- const result = await threadInstance.readFile(path);
14969
+ const result = await threadInstance.readFile(path2);
15006
14970
  if (!result.success || !result.data) {
15007
14971
  return;
15008
14972
  }
@@ -15023,7 +14987,7 @@ var init_ThreadStateImpl = __esm({
15023
14987
  if (signal?.aborted) {
15024
14988
  return;
15025
14989
  }
15026
- const result = await threadInstance.readFileChunk(path, i);
14990
+ const result = await threadInstance.readFileChunk(path2, i);
15027
14991
  if (!result.success || !result.data) {
15028
14992
  throw new Error(result.error || `Failed to read chunk ${i}`);
15029
14993
  }
@@ -15056,31 +15020,31 @@ var init_ThreadStateImpl = __esm({
15056
15020
  if (!("path" in record) && !("name" in record)) return null;
15057
15021
  return record;
15058
15022
  }
15059
- async statFile(path) {
15060
- const record = this._unwrapStatRecord(await this._threadInstance.statFile(path));
15023
+ async statFile(path2) {
15024
+ const record = this._unwrapStatRecord(await this._threadInstance.statFile(path2));
15061
15025
  return record ? this._mapFileRecord(record) : null;
15062
15026
  }
15063
- async readdirFile(path) {
15064
- const result = await this._threadInstance.readdirFile(path);
15027
+ async readdirFile(path2) {
15028
+ const result = await this._threadInstance.readdirFile(path2);
15065
15029
  const entries = Array.isArray(result) ? result : result?.files;
15066
15030
  if (!Array.isArray(entries)) {
15067
15031
  throw new Error(
15068
- result?.error || `Could not list directory: ${path}`
15032
+ result?.error || `Could not list directory: ${path2}`
15069
15033
  );
15070
15034
  }
15071
15035
  return {
15072
15036
  entries: entries.map((e) => this._mapFileRecord(e))
15073
15037
  };
15074
15038
  }
15075
- async unlinkFile(path) {
15076
- await this._threadInstance.unlinkFile(path);
15039
+ async unlinkFile(path2) {
15040
+ await this._threadInstance.unlinkFile(path2);
15077
15041
  }
15078
- async mkdirFile(path) {
15079
- const result = await this._threadInstance.mkdirFile(path);
15042
+ async mkdirFile(path2) {
15043
+ const result = await this._threadInstance.mkdirFile(path2);
15080
15044
  return this._mapFileRecord(result);
15081
15045
  }
15082
- async rmdirFile(path) {
15083
- await this._threadInstance.rmdirFile(path);
15046
+ async rmdirFile(path2) {
15047
+ await this._threadInstance.rmdirFile(path2);
15084
15048
  }
15085
15049
  async moveFile(sourcePath, destinationPath) {
15086
15050
  const result = await this._threadInstance.moveFile(sourcePath, destinationPath);
@@ -15089,8 +15053,8 @@ var init_ThreadStateImpl = __esm({
15089
15053
  }
15090
15054
  return this._mapFileRecord(result.file);
15091
15055
  }
15092
- async renameFile(path, newName) {
15093
- const result = await this._threadInstance.renameFile(path, newName);
15056
+ async renameFile(path2, newName) {
15057
+ const result = await this._threadInstance.renameFile(path2, newName);
15094
15058
  if (!result.success || !result.file) {
15095
15059
  throw new Error(result.error || "Failed to rename file");
15096
15060
  }
@@ -15117,8 +15081,8 @@ var init_ThreadStateImpl = __esm({
15117
15081
  paths: Array.isArray(results) ? results : results.paths || []
15118
15082
  };
15119
15083
  }
15120
- async getFileThumbnail(path) {
15121
- return this._threadInstance.getFileThumbnail(path);
15084
+ async getFileThumbnail(path2) {
15085
+ return this._threadInstance.getFileThumbnail(path2);
15122
15086
  }
15123
15087
  // ─────────────────────────────────────────────────────────────────────────
15124
15088
  // Execution State
@@ -15423,7 +15387,7 @@ var init_ThreadStateImpl = __esm({
15423
15387
  const skillMd = await stub.getSkillFile(scope, name, "SKILL.md") ?? "";
15424
15388
  return { metadata, skillMd };
15425
15389
  },
15426
- readFile: (name, path) => stub.getSkillFile(scope, name, path),
15390
+ readFile: (name, path2) => stub.getSkillFile(scope, name, path2),
15427
15391
  install: async (files) => {
15428
15392
  await requireMutationAdmin();
15429
15393
  return stub.upsertSkill(scope, files);
@@ -15710,7 +15674,14 @@ function isHostedInstance(env) {
15710
15674
  }
15711
15675
  return Boolean(value);
15712
15676
  }
15713
- function isTrustedLocalDevelopmentRequest(request, env) {
15677
+ function compiledTrustedDevHosts() {
15678
+ try {
15679
+ return typeof __STANDARD_AGENTS_TRUSTED_DEV_HOSTS__ !== "undefined" && Array.isArray(__STANDARD_AGENTS_TRUSTED_DEV_HOSTS__) ? __STANDARD_AGENTS_TRUSTED_DEV_HOSTS__ : [];
15680
+ } catch {
15681
+ return [];
15682
+ }
15683
+ }
15684
+ function isTrustedLocalDevelopmentRequest(request, env, trustedDevHosts = compiledTrustedDevHosts()) {
15714
15685
  if (isHostedInstance(env)) return false;
15715
15686
  let hostname;
15716
15687
  try {
@@ -15718,7 +15689,7 @@ function isTrustedLocalDevelopmentRequest(request, env) {
15718
15689
  } catch {
15719
15690
  return false;
15720
15691
  }
15721
- return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname.endsWith(".localhost") || hostname.endsWith(".orb.local");
15692
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname.endsWith(".localhost") || hostname.endsWith(".orb.local") || trustedDevHosts.some((trusted) => trusted.trim().toLowerCase() === hostname);
15722
15693
  }
15723
15694
  function isPublicApiRoute(routePath, request, env) {
15724
15695
  if (PUBLIC_ROUTES.has(routePath)) return true;
@@ -19013,10 +18984,10 @@ var DurableAgentBuilder = class extends DurableObject {
19013
18984
  for (const entry of value) {
19014
18985
  if (!entry || typeof entry !== "object") continue;
19015
18986
  const attachment = entry;
19016
- const path = typeof attachment.path === "string" ? attachment.path.trim() : "";
19017
- if (!path) continue;
18987
+ const path2 = typeof attachment.path === "string" ? attachment.path.trim() : "";
18988
+ if (!path2) continue;
19018
18989
  output.push({
19019
- path,
18990
+ path: path2,
19020
18991
  name: typeof attachment.name === "string" ? attachment.name : void 0,
19021
18992
  mimeType: typeof attachment.mimeType === "string" ? attachment.mimeType : void 0,
19022
18993
  size: typeof attachment.size === "number" ? attachment.size : void 0,
@@ -19033,8 +19004,8 @@ var DurableAgentBuilder = class extends DurableObject {
19033
19004
  const trimmed = sanitized.replace(/^[-.]+|[-.]+$/g, "");
19034
19005
  return trimmed || "attachment";
19035
19006
  }
19036
- inferMimeTypeFromPath(path) {
19037
- const normalized = path.toLowerCase();
19007
+ inferMimeTypeFromPath(path2) {
19008
+ const normalized = path2.toLowerCase();
19038
19009
  if (normalized.endsWith(".png")) return "image/png";
19039
19010
  if (normalized.endsWith(".jpg") || normalized.endsWith(".jpeg")) return "image/jpeg";
19040
19011
  if (normalized.endsWith(".webp")) return "image/webp";
@@ -19072,7 +19043,7 @@ var DurableAgentBuilder = class extends DurableObject {
19072
19043
  if (!attachments || attachments.length === 0) {
19073
19044
  return "";
19074
19045
  }
19075
- const paths = attachments.map((attachment) => attachment.path).filter((path) => typeof path === "string" && path.length > 0);
19046
+ const paths = attachments.map((attachment) => attachment.path).filter((path2) => typeof path2 === "string" && path2.length > 0);
19076
19047
  if (paths.length === 0) {
19077
19048
  return "";
19078
19049
  }
@@ -20474,12 +20445,9 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
20474
20445
  await parentThread.updateChildRegistryStatus(
20475
20446
  params.parent_thread_id,
20476
20447
  childThread.id,
20477
- childResult.terminal ? "terminated" : "idle"
20448
+ "idle"
20478
20449
  );
20479
20450
  }
20480
- if (childResult.terminal && typeof childThreadStub.terminateThread === "function") {
20481
- await childThreadStub.terminateThread(childThread.id);
20482
- }
20483
20451
  } else if (typeof childThreadStub.terminateThread === "function") {
20484
20452
  await childThreadStub.terminateThread(childThread.id);
20485
20453
  }
@@ -21752,7 +21720,7 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
21752
21720
  for (const row of cursor.toArray()) {
21753
21721
  if (skills.has(row.name)) continue;
21754
21722
  const parsedFiles = row.files ? JSON.parse(row.files) : [];
21755
- const files = Array.isArray(parsedFiles) ? parsedFiles.filter((path) => typeof path === "string").sort() : [];
21723
+ const files = Array.isArray(parsedFiles) ? parsedFiles.filter((path2) => typeof path2 === "string").sort() : [];
21756
21724
  skills.set(row.name, {
21757
21725
  name: row.name,
21758
21726
  description: row.description,
@@ -21770,7 +21738,7 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
21770
21738
  return all.find((s) => s.name === name) ?? null;
21771
21739
  }
21772
21740
  /** One bundled file's text (null when the skill or file is missing). */
21773
- async getSkillFile(scope, name, path) {
21741
+ async getSkillFile(scope, name, path2) {
21774
21742
  await this.ensureMigrated();
21775
21743
  const cursor = await this.ctx.storage.sql.exec(
21776
21744
  `SELECT f.content FROM skill_files f
@@ -21780,7 +21748,7 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
21780
21748
  ORDER BY CASE WHEN f.owner_id = ? THEN 0 ELSE 1 END
21781
21749
  LIMIT 1`,
21782
21750
  name,
21783
- path.replace(/^\.\//, ""),
21751
+ path2.replace(/^\.\//, ""),
21784
21752
  scope.ownerId,
21785
21753
  scope.includeShared ? 1 : 0,
21786
21754
  scope.ownerId
@@ -22075,12 +22043,12 @@ async function authorizesToolDelivery(pending, proof) {
22075
22043
  return matchesToolDeliveryOwner(pending, proof) && await matchesToolDeliveryToken(pending.delivery_token_hash, proof.token);
22076
22044
  }
22077
22045
  var RUNTIME_STORAGE_PREFIX = "__agentbuilder_runtime_storage__:";
22078
- function normalizeEndpointThreadPath(path) {
22079
- if (!path || /^[A-Za-z][A-Za-z\d+\-.]*:/.test(path)) {
22046
+ function normalizeEndpointThreadPath(path2) {
22047
+ if (!path2 || /^[A-Za-z][A-Za-z\d+\-.]*:/.test(path2)) {
22080
22048
  throw new Error("Use a relative thread filesystem path");
22081
22049
  }
22082
22050
  const parts = [];
22083
- for (const part of path.replace(/\\/g, "/").split("/")) {
22051
+ for (const part of path2.replace(/\\/g, "/").split("/")) {
22084
22052
  if (!part || part === ".") continue;
22085
22053
  if (part === "..") {
22086
22054
  if (parts.length === 0) throw new Error("Path cannot escape the thread filesystem root");
@@ -22130,12 +22098,12 @@ function createEndpointFetchBridge() {
22130
22098
  function createEndpointFsBridge(state) {
22131
22099
  const decoder = new TextDecoder();
22132
22100
  return {
22133
- readFile: async (path) => {
22134
- const data = await state.readFile(normalizeEndpointThreadPath(path));
22101
+ readFile: async (path2) => {
22102
+ const data = await state.readFile(normalizeEndpointThreadPath(path2));
22135
22103
  return data ? decoder.decode(data) : null;
22136
22104
  },
22137
- writeFile: async (path, content, mimeType = "text/plain") => {
22138
- return state.writeFile(normalizeEndpointThreadPath(path), content, mimeType);
22105
+ writeFile: async (path2, content, mimeType = "text/plain") => {
22106
+ return state.writeFile(normalizeEndpointThreadPath(path2), content, mimeType);
22139
22107
  }
22140
22108
  };
22141
22109
  }
@@ -22204,24 +22172,24 @@ function createEndpointThreadStateBridge(state) {
22204
22172
  emit: (event, data) => state.emit(event, data),
22205
22173
  getValue: (key) => state.getValue(key),
22206
22174
  setValue: (key, value) => state.setValue(key, value),
22207
- readFile: (path) => state.readFile(normalizeEndpointThreadPath(path)),
22208
- writeFile: (path, data, mimeType = "application/octet-stream", options) => {
22209
- return state.writeFile(normalizeEndpointThreadPath(path), data, mimeType, options);
22175
+ readFile: (path2) => state.readFile(normalizeEndpointThreadPath(path2)),
22176
+ writeFile: (path2, data, mimeType = "application/octet-stream", options) => {
22177
+ return state.writeFile(normalizeEndpointThreadPath(path2), data, mimeType, options);
22210
22178
  },
22211
- statFile: (path) => state.statFile(normalizeEndpointThreadPath(path)),
22212
- readdirFile: (path) => state.readdirFile(normalizeEndpointThreadPath(path)),
22213
- unlinkFile: (path) => state.unlinkFile(normalizeEndpointThreadPath(path)),
22214
- mkdirFile: (path) => state.mkdirFile(normalizeEndpointThreadPath(path)),
22215
- rmdirFile: (path) => state.rmdirFile(normalizeEndpointThreadPath(path)),
22179
+ statFile: (path2) => state.statFile(normalizeEndpointThreadPath(path2)),
22180
+ readdirFile: (path2) => state.readdirFile(normalizeEndpointThreadPath(path2)),
22181
+ unlinkFile: (path2) => state.unlinkFile(normalizeEndpointThreadPath(path2)),
22182
+ mkdirFile: (path2) => state.mkdirFile(normalizeEndpointThreadPath(path2)),
22183
+ rmdirFile: (path2) => state.rmdirFile(normalizeEndpointThreadPath(path2)),
22216
22184
  moveFile: (sourcePath, destinationPath) => state.moveFile(
22217
22185
  normalizeEndpointThreadPath(sourcePath),
22218
22186
  normalizeEndpointThreadPath(destinationPath)
22219
22187
  ),
22220
- renameFile: (path, newName) => state.renameFile(normalizeEndpointThreadPath(path), newName),
22188
+ renameFile: (path2, newName) => state.renameFile(normalizeEndpointThreadPath(path2), newName),
22221
22189
  getFileStats: () => state.getFileStats(),
22222
22190
  grepFiles: (pattern) => state.grepFiles(pattern),
22223
22191
  findFiles: (pattern) => state.findFiles(pattern),
22224
- getFileThumbnail: (path) => state.getFileThumbnail(normalizeEndpointThreadPath(path))
22192
+ getFileThumbnail: (path2) => state.getFileThumbnail(normalizeEndpointThreadPath(path2))
22225
22193
  };
22226
22194
  }
22227
22195
  function routeBridgeClientFrame(socket, message, handlers) {
@@ -22274,6 +22242,8 @@ var DurableThread = class _DurableThread extends DurableObject {
22274
22242
  // opened on and dies with it. Streams are in-memory only — they exist solely
22275
22243
  // while the client is attached and never park durably.
22276
22244
  clientStreams = /* @__PURE__ */ new Map();
22245
+ proxyStreamReceivers = /* @__PURE__ */ new Map();
22246
+ eventProxyStreams = /* @__PURE__ */ new Map();
22277
22247
  alarmQueue;
22278
22248
  runtimeSafety;
22279
22249
  alarmQueueRearmed = false;
@@ -22385,6 +22355,10 @@ var DurableThread = class _DurableThread extends DurableObject {
22385
22355
  clientName: typeof attachment.clientName === "string" ? attachment.clientName : null,
22386
22356
  clientKind: typeof attachment.clientKind === "string" ? attachment.clientKind : null
22387
22357
  });
22358
+ const interrupted = this.parseProxyStreamAttachments(attachment.proxyStreams);
22359
+ if (interrupted.length > 0) {
22360
+ this.recoverInterruptedProxyStreams(ws, interrupted);
22361
+ }
22388
22362
  }
22389
22363
  }
22390
22364
  }
@@ -22973,7 +22947,7 @@ var DurableThread = class _DurableThread extends DurableObject {
22973
22947
  this.assertJsonSerializableThreadValue(value, "$", /* @__PURE__ */ new WeakSet());
22974
22948
  return JSON.stringify(value);
22975
22949
  }
22976
- assertJsonSerializableThreadValue(value, path, seen) {
22950
+ assertJsonSerializableThreadValue(value, path2, seen) {
22977
22951
  if (value === null) {
22978
22952
  return;
22979
22953
  }
@@ -22983,36 +22957,36 @@ var DurableThread = class _DurableThread extends DurableObject {
22983
22957
  return;
22984
22958
  case "number":
22985
22959
  if (!Number.isFinite(value)) {
22986
- throw new Error(`Thread value at ${path} must be a finite number`);
22960
+ throw new Error(`Thread value at ${path2} must be a finite number`);
22987
22961
  }
22988
22962
  return;
22989
22963
  case "object": {
22990
22964
  if (seen.has(value)) {
22991
- throw new Error(`Thread value at ${path} cannot contain circular references`);
22965
+ throw new Error(`Thread value at ${path2} cannot contain circular references`);
22992
22966
  }
22993
22967
  seen.add(value);
22994
22968
  if (Array.isArray(value)) {
22995
22969
  for (let i = 0; i < value.length; i += 1) {
22996
- this.assertJsonSerializableThreadValue(value[i], `${path}[${i}]`, seen);
22970
+ this.assertJsonSerializableThreadValue(value[i], `${path2}[${i}]`, seen);
22997
22971
  }
22998
22972
  seen.delete(value);
22999
22973
  return;
23000
22974
  }
23001
22975
  const prototype = Object.getPrototypeOf(value);
23002
22976
  if (prototype !== Object.prototype && prototype !== null) {
23003
- throw new Error(`Thread value at ${path} must be a JSON object, array, or primitive`);
22977
+ throw new Error(`Thread value at ${path2} must be a JSON object, array, or primitive`);
23004
22978
  }
23005
22979
  if (Object.getOwnPropertySymbols(value).length > 0) {
23006
- throw new Error(`Thread value at ${path} cannot contain symbol keys`);
22980
+ throw new Error(`Thread value at ${path2} cannot contain symbol keys`);
23007
22981
  }
23008
22982
  for (const [entryKey, entryValue] of Object.entries(value)) {
23009
- this.assertJsonSerializableThreadValue(entryValue, `${path}.${entryKey}`, seen);
22983
+ this.assertJsonSerializableThreadValue(entryValue, `${path2}.${entryKey}`, seen);
23010
22984
  }
23011
22985
  seen.delete(value);
23012
22986
  return;
23013
22987
  }
23014
22988
  default:
23015
- throw new Error(`Thread value at ${path} must be JSON-serializable`);
22989
+ throw new Error(`Thread value at ${path2} must be JSON-serializable`);
23016
22990
  }
23017
22991
  }
23018
22992
  // ============================================================
@@ -24213,8 +24187,8 @@ var DurableThread = class _DurableThread extends DurableObject {
24213
24187
  );
24214
24188
  return terminalCursor.toArray()[0] ?? null;
24215
24189
  }
24216
- inferMimeTypeFromPath(path) {
24217
- const normalized = path.toLowerCase();
24190
+ inferMimeTypeFromPath(path2) {
24191
+ const normalized = path2.toLowerCase();
24218
24192
  if (normalized.endsWith(".png")) return "image/png";
24219
24193
  if (normalized.endsWith(".jpg") || normalized.endsWith(".jpeg")) return "image/jpeg";
24220
24194
  if (normalized.endsWith(".webp")) return "image/webp";
@@ -24253,7 +24227,7 @@ var DurableThread = class _DurableThread extends DurableObject {
24253
24227
  ext: value.slice(lastDot + 1).toLowerCase()
24254
24228
  };
24255
24229
  }
24256
- resolveAttachmentMimeType(sourceMimeType, fallbackMimeType, path) {
24230
+ resolveAttachmentMimeType(sourceMimeType, fallbackMimeType, path2) {
24257
24231
  const source = sourceMimeType?.trim();
24258
24232
  if (source && source !== "application/octet-stream") {
24259
24233
  return source;
@@ -24262,7 +24236,7 @@ var DurableThread = class _DurableThread extends DurableObject {
24262
24236
  if (fallback && fallback !== "application/octet-stream") {
24263
24237
  return fallback;
24264
24238
  }
24265
- return this.inferMimeTypeFromPath(path) ?? source ?? fallback ?? "application/octet-stream";
24239
+ return this.inferMimeTypeFromPath(path2) ?? source ?? fallback ?? "application/octet-stream";
24266
24240
  }
24267
24241
  buildAttachmentTargetPath(preferredName, mimeType, sourcePath) {
24268
24242
  const safeName = this.sanitizeFilename(preferredName);
@@ -24357,8 +24331,8 @@ var DurableThread = class _DurableThread extends DurableObject {
24357
24331
  }
24358
24332
  return copied;
24359
24333
  }
24360
- async readAttachmentDataFromSource(path, sourceFile) {
24361
- const sourceData = await this.readFile(path);
24334
+ async readAttachmentDataFromSource(path2, sourceFile) {
24335
+ const sourceData = await this.readFile(path2);
24362
24336
  if (sourceData.success && sourceData.data) {
24363
24337
  return sourceData.data;
24364
24338
  }
@@ -24395,7 +24369,7 @@ var DurableThread = class _DurableThread extends DurableObject {
24395
24369
  if (!attachments || attachments.length === 0) {
24396
24370
  return "";
24397
24371
  }
24398
- const paths = attachments.map((attachment) => attachment.path).filter((path) => typeof path === "string" && path.length > 0);
24372
+ const paths = attachments.map((attachment) => attachment.path).filter((path2) => typeof path2 === "string" && path2.length > 0);
24399
24373
  if (paths.length === 0) {
24400
24374
  return "";
24401
24375
  }
@@ -24475,11 +24449,13 @@ ${paths.join("\n")}`;
24475
24449
  try {
24476
24450
  const parentId = this.env.AGENT_BUILDER_THREAD.idFromName(parentThreadId);
24477
24451
  const parentStub = this.env.AGENT_BUILDER_THREAD.get(parentId);
24478
- const parentCommunication = await this.getParentCommunicationModeForChild(
24452
+ const childRegistryEntry = await this.getParentRegistryEntryForChild(
24479
24453
  parentStub,
24480
24454
  parentThreadId,
24481
24455
  threadId
24482
24456
  );
24457
+ const parentCommunication = childRegistryEntry?.parentCommunication === "explicit" ? "explicit" : "implicit";
24458
+ const resumableChild = childRegistryEntry?.resumable === true;
24483
24459
  const copiedRefs = await this.copyAttachmentRefsToThread(
24484
24460
  refs,
24485
24461
  parentStub,
@@ -24502,10 +24478,11 @@ ${resultContent}${attachmentSummary}`;
24502
24478
  });
24503
24479
  }
24504
24480
  const terminalChildRun = sessionStopped || hasTerminalSessionTools;
24481
+ const terminateChildThread = terminalChildRun && !resumableChild;
24505
24482
  await parentStub.updateChildRegistryStatus(
24506
24483
  parentThreadId,
24507
24484
  threadId,
24508
- terminalChildRun ? "terminated" : "idle"
24485
+ terminateChildThread ? "terminated" : "idle"
24509
24486
  );
24510
24487
  if (parentCommunication !== "explicit") {
24511
24488
  await this.persistParentHandoffStatusMessage(
@@ -24513,23 +24490,22 @@ ${resultContent}${attachmentSummary}`;
24513
24490
  isErrorTerminal ? "failure" : "result"
24514
24491
  );
24515
24492
  }
24516
- if (terminalChildRun) {
24493
+ if (terminateChildThread) {
24517
24494
  await this.terminateThread(threadId);
24518
24495
  }
24519
24496
  } catch (error) {
24520
24497
  console.error("[DurableThread] Failed to deliver subagent completion to parent:", error);
24521
24498
  }
24522
24499
  }
24523
- async getParentCommunicationModeForChild(parentStub, parentThreadId, childThreadId) {
24500
+ async getParentRegistryEntryForChild(parentStub, parentThreadId, childThreadId) {
24524
24501
  if (typeof parentStub.getChildrenRegistry !== "function") {
24525
- return "implicit";
24502
+ return void 0;
24526
24503
  }
24527
24504
  try {
24528
24505
  const entries = await parentStub.getChildrenRegistry(parentThreadId);
24529
- const childEntry = entries.find((entry) => entry.reference === childThreadId);
24530
- return childEntry?.parentCommunication === "explicit" ? "explicit" : "implicit";
24506
+ return entries.find((entry) => entry.reference === childThreadId);
24531
24507
  } catch {
24532
- return "implicit";
24508
+ return void 0;
24533
24509
  }
24534
24510
  }
24535
24511
  /**
@@ -26077,7 +26053,7 @@ ${resultContent}${attachmentSummary}`;
26077
26053
  void 0,
26078
26054
  INTERNAL_TOOL_DELIVERY
26079
26055
  );
26080
- if (delivered?.resume) sides.add(delivered.side);
26056
+ if (delivered) sides.add(delivered.side);
26081
26057
  }
26082
26058
  if (threadId) {
26083
26059
  for (const side of sides) {
@@ -26379,17 +26355,14 @@ ${resultContent}${attachmentSummary}`;
26379
26355
  deliveredResultWaiters = /* @__PURE__ */ new Map();
26380
26356
  notifyDeliveredResultWaiters(toolCallId) {
26381
26357
  const waiters = this.deliveredResultWaiters?.get(toolCallId);
26382
- if (!waiters || waiters.size === 0) return false;
26358
+ if (!waiters) return;
26383
26359
  this.deliveredResultWaiters.delete(toolCallId);
26384
- let notified = false;
26385
26360
  for (const wake of waiters) {
26386
26361
  try {
26387
26362
  wake();
26388
- notified = true;
26389
26363
  } catch {
26390
26364
  }
26391
26365
  }
26392
- return notified;
26393
26366
  }
26394
26367
  /**
26395
26368
  * Await a parked forwarded call's delivered result: one immediate read,
@@ -26534,46 +26507,37 @@ ${resultContent}${attachmentSummary}`;
26534
26507
  const side = pending.side === "b" ? "b" : "a";
26535
26508
  const content = ok ? result ?? "" : `Error: ${error ?? "tool failed"}`;
26536
26509
  const toolStatus = ok ? "success" : "error";
26537
- const resultMessageId = crypto.randomUUID();
26538
- const resultCreatedAt = Date.now() * TIMESTAMP_MULTIPLIER;
26539
- const accepted = this.ctx.storage.transactionSync(() => {
26540
- const claimed = this.ctx.storage.sql.exec(
26541
- `UPDATE pending_client_calls
26542
- SET status = 'resolved'
26543
- WHERE tool_call_id = ? AND status = 'pending'`,
26510
+ await this.ctx.storage.sql.exec(
26511
+ `UPDATE messages SET content = ?, tool_status = ? WHERE tool_call_id = ? AND role = 'tool'`,
26512
+ content,
26513
+ toolStatus,
26514
+ toolCallId
26515
+ );
26516
+ const updated = await this.ctx.storage.sql.exec(
26517
+ `SELECT COUNT(*) AS total FROM messages WHERE tool_call_id = ? AND role = 'tool'`,
26518
+ toolCallId
26519
+ );
26520
+ if (Number(updated.toArray()[0]?.total ?? 0) === 0) {
26521
+ const toolRow = await this.ctx.storage.sql.exec(
26522
+ `SELECT tool FROM pending_client_calls WHERE tool_call_id = ? LIMIT 1`,
26544
26523
  toolCallId
26545
26524
  );
26546
- if (claimed.rowsWritten !== 1) return false;
26547
- this.ctx.storage.sql.exec(
26548
- `UPDATE messages SET content = ?, tool_status = ? WHERE tool_call_id = ? AND role = 'tool'`,
26525
+ await this.ctx.storage.sql.exec(
26526
+ `INSERT INTO messages (id, role, content, name, tool_call_id, tool_status, created_at, status, prompt)
26527
+ VALUES (?, 'tool', ?, ?, ?, ?, ?, 'completed', NULL)`,
26528
+ crypto.randomUUID(),
26549
26529
  content,
26530
+ toolRow.toArray()[0]?.tool ?? null,
26531
+ toolCallId,
26550
26532
  toolStatus,
26551
- toolCallId
26552
- );
26553
- const updated = this.ctx.storage.sql.exec(
26554
- `SELECT COUNT(*) AS total FROM messages WHERE tool_call_id = ? AND role = 'tool'`,
26555
- toolCallId
26533
+ Date.now() * TIMESTAMP_MULTIPLIER
26556
26534
  );
26557
- if (Number(updated.toArray()[0]?.total ?? 0) === 0) {
26558
- const toolRow = this.ctx.storage.sql.exec(
26559
- `SELECT tool FROM pending_client_calls WHERE tool_call_id = ? LIMIT 1`,
26560
- toolCallId
26561
- );
26562
- this.ctx.storage.sql.exec(
26563
- `INSERT INTO messages (id, role, content, name, tool_call_id, tool_status, created_at, status, prompt)
26564
- VALUES (?, 'tool', ?, ?, ?, ?, ?, 'completed', NULL)`,
26565
- resultMessageId,
26566
- content,
26567
- toolRow.toArray()[0]?.tool ?? null,
26568
- toolCallId,
26569
- toolStatus,
26570
- resultCreatedAt
26571
- );
26572
- }
26573
- return true;
26574
- });
26575
- if (!accepted) return null;
26576
- const resumedInline = this.notifyDeliveredResultWaiters(toolCallId);
26535
+ }
26536
+ await this.ctx.storage.sql.exec(
26537
+ `UPDATE pending_client_calls SET status = 'resolved' WHERE tool_call_id = ?`,
26538
+ toolCallId
26539
+ );
26540
+ this.notifyDeliveredResultWaiters(toolCallId);
26577
26541
  try {
26578
26542
  const msgCursor = await this.ctx.storage.sql.exec(
26579
26543
  `SELECT id, role, content, name, tool_call_id, tool_status, created_at, depth
@@ -26584,7 +26548,7 @@ ${resultContent}${attachmentSummary}`;
26584
26548
  if (msg) this.broadcastMessage(msg);
26585
26549
  } catch {
26586
26550
  }
26587
- return { side, resume: !resumedInline };
26551
+ return { side };
26588
26552
  }
26589
26553
  // ─── Runtime byte streams ──────────────────────────────────────────────────
26590
26554
  // The existing bridge frames carry opaque capability metadata and bytes
@@ -26650,8 +26614,138 @@ ${resultContent}${attachmentSummary}`;
26650
26614
  });
26651
26615
  }
26652
26616
  }
26617
+ parseProxyStreamAttachments(value) {
26618
+ if (!Array.isArray(value)) return [];
26619
+ const parsed = [];
26620
+ for (const item of value) {
26621
+ if (!item || typeof item !== "object") continue;
26622
+ const candidate = item;
26623
+ if (typeof candidate.id === "string" && candidate.target && typeof candidate.target.threadId === "string" && typeof candidate.target.receiverId === "string") {
26624
+ parsed.push({
26625
+ id: candidate.id,
26626
+ target: {
26627
+ threadId: candidate.target.threadId,
26628
+ receiverId: candidate.target.receiverId
26629
+ }
26630
+ });
26631
+ }
26632
+ }
26633
+ return parsed;
26634
+ }
26635
+ /** Keep live proxy routes on the hibernating bridge socket for restart cleanup. */
26636
+ updateBridgeProxyAttachment(socket) {
26637
+ if (typeof socket.serializeAttachment !== "function") return;
26638
+ let attachment = { type: "bridge" };
26639
+ try {
26640
+ const current = socket.deserializeAttachment();
26641
+ if (current && typeof current === "object") {
26642
+ attachment = { ...current };
26643
+ }
26644
+ } catch {
26645
+ }
26646
+ const proxyStreams = Array.from(this.clientStreams.entries()).filter(([, state]) => state.socket === socket && state.proxyTarget !== null).map(([id, state]) => ({ id, target: state.proxyTarget }));
26647
+ try {
26648
+ socket.serializeAttachment({ ...attachment, proxyStreams });
26649
+ } catch {
26650
+ }
26651
+ }
26652
+ async deliverProxyStreamFrame(target, frame) {
26653
+ try {
26654
+ const namespace = this.env.AGENT_BUILDER_THREAD;
26655
+ const stub = namespace.get(namespace.idFromName(target.threadId));
26656
+ return await stub.proxyStreamReceive(target.receiverId, frame);
26657
+ } catch {
26658
+ return false;
26659
+ }
26660
+ }
26661
+ /** Abort live proxy routes restored without their in-memory stream state. */
26662
+ recoverInterruptedProxyStreams(socket, streams) {
26663
+ const error = "The stream ended because its runtime restarted.";
26664
+ for (const stream of streams) {
26665
+ try {
26666
+ if (socket.readyState === WebSocket.OPEN) {
26667
+ socket.send(JSON.stringify({ type: "stream_abort", id: stream.id, error }));
26668
+ }
26669
+ } catch {
26670
+ }
26671
+ this.ctx.waitUntil(
26672
+ this.deliverProxyStreamFrame(stream.target, { type: "abort", error }).then(() => {
26673
+ })
26674
+ );
26675
+ }
26676
+ this.updateBridgeProxyAttachment(socket);
26677
+ }
26678
+ /** Register the child side before any ancestor opens an owner stream. */
26679
+ createProxyStreamReceiver(onCancel) {
26680
+ const id = crypto.randomUUID();
26681
+ let controller = null;
26682
+ let settleDone;
26683
+ const done = new Promise((resolve) => {
26684
+ settleDone = resolve;
26685
+ });
26686
+ const readable = new ReadableStream({
26687
+ start(value) {
26688
+ controller = value;
26689
+ },
26690
+ cancel: (reason) => {
26691
+ const receiver2 = this.proxyStreamReceivers.get(id);
26692
+ if (!receiver2 || receiver2.settled) return;
26693
+ const error = reason instanceof Error ? reason.message : typeof reason === "string" ? reason : "The proxy stream reader was canceled.";
26694
+ receiver2.settle({ ok: false, error });
26695
+ receiver2.onCancel(error);
26696
+ }
26697
+ });
26698
+ const receiver = {
26699
+ controller,
26700
+ settle: (result) => {
26701
+ if (receiver.settled) return;
26702
+ receiver.settled = true;
26703
+ this.proxyStreamReceivers.delete(id);
26704
+ settleDone(result);
26705
+ },
26706
+ onCancel,
26707
+ settled: false
26708
+ };
26709
+ this.proxyStreamReceivers.set(id, receiver);
26710
+ return { id, readable, done };
26711
+ }
26712
+ async proxyStreamReceiverExists(receiverId) {
26713
+ return this.proxyStreamReceivers.has(receiverId);
26714
+ }
26715
+ async proxyStreamReceive(receiverId, frame) {
26716
+ const receiver = this.proxyStreamReceivers.get(receiverId);
26717
+ if (!receiver || receiver.settled) return false;
26718
+ if (frame.type === "data") {
26719
+ try {
26720
+ receiver.controller?.enqueue(decodeStreamChunk(frame.data));
26721
+ } catch (error2) {
26722
+ const message = error2 instanceof Error ? error2.message : String(error2);
26723
+ try {
26724
+ receiver.controller?.error(error2 instanceof Error ? error2 : new Error(message));
26725
+ } catch {
26726
+ }
26727
+ receiver.settle({ ok: false, error: message });
26728
+ }
26729
+ return true;
26730
+ }
26731
+ if (frame.type === "end") {
26732
+ try {
26733
+ receiver.controller?.close();
26734
+ } catch {
26735
+ }
26736
+ receiver.settle({ ok: true });
26737
+ return true;
26738
+ }
26739
+ const error = frame.error ?? "The proxied client stream was aborted.";
26740
+ try {
26741
+ receiver.controller?.error(new Error(error));
26742
+ } catch {
26743
+ }
26744
+ receiver.settle({ ok: false, error });
26745
+ return true;
26746
+ }
26653
26747
  /** Open a bidirectional byte stream to the connected owner client. */
26654
- async openClientStream(request) {
26748
+ async openClientStream(request, proxyTarget = null) {
26655
26749
  const owner = await this.getExecutionOwner();
26656
26750
  let socket = this.getOpenBridgeSocket(owner?.client_id ?? null);
26657
26751
  if (!socket && owner) {
@@ -26684,9 +26778,12 @@ ${resultContent}${attachmentSummary}`;
26684
26778
  opened: null,
26685
26779
  openTimer: null,
26686
26780
  settleDone,
26687
- settled: false
26781
+ settled: false,
26782
+ proxyTarget,
26783
+ delivery: Promise.resolve()
26688
26784
  };
26689
26785
  this.clientStreams.set(id, state);
26786
+ this.updateBridgeProxyAttachment(socket);
26690
26787
  this.bridgeLastSeen.set(socket, Date.now());
26691
26788
  const openResult = await new Promise((resolve) => {
26692
26789
  state.opened = resolve;
@@ -26722,6 +26819,7 @@ ${resultContent}${attachmentSummary}`;
26722
26819
  }
26723
26820
  if (!openResult.ok) {
26724
26821
  this.clientStreams.delete(id);
26822
+ this.updateBridgeProxyAttachment(socket);
26725
26823
  state.settled = true;
26726
26824
  settleDone({ ok: false, error: openResult.error });
26727
26825
  return {
@@ -26763,14 +26861,28 @@ ${resultContent}${attachmentSummary}`;
26763
26861
  };
26764
26862
  return { ok: true, duplex };
26765
26863
  }
26766
- // ─── Subagent stream proxy-up (chunk-pull, no cross-DO ReadableStream) ─────
26767
- // A subagent (child thread, no bridge) proxies its whole stream request UP to
26768
- // this bridge-holding root. We open the client stream locally, then buffer
26769
- // incoming bytes so the child can drain them over plain request/response RPCs
26770
- // — sidestepping the unproven DO-to-DO ReadableStream return.
26771
- proxyStreams = /* @__PURE__ */ new Map();
26772
- async proxyStreamOpen(request) {
26773
- const opened = await this.openClientStream(request);
26864
+ // ─── Event-driven subagent stream proxy ──────────────────────────────────
26865
+ // A child registers a local receiver before the bridge-holding ancestor
26866
+ // opens the client stream. The ancestor invokes that receiver only for real
26867
+ // data/end/abort events; there is no pull loop or permanently outstanding
26868
+ // cross-DO RPC while the stream is idle.
26869
+ async proxyStreamOpen(request, target) {
26870
+ const namespace = this.env.AGENT_BUILDER_THREAD;
26871
+ let receiverExists = false;
26872
+ try {
26873
+ const destination = namespace.get(namespace.idFromName(target.threadId));
26874
+ receiverExists = await destination.proxyStreamReceiverExists(target.receiverId);
26875
+ } catch {
26876
+ receiverExists = false;
26877
+ }
26878
+ if (!receiverExists) {
26879
+ return {
26880
+ ok: false,
26881
+ error: "The destination stream receiver is unavailable.",
26882
+ code: "unavailable"
26883
+ };
26884
+ }
26885
+ const opened = await this.openClientStream(request, target);
26774
26886
  if (!opened.ok) {
26775
26887
  const failureData = opened.data;
26776
26888
  const noClient = failureData?.noClient === true;
@@ -26782,82 +26894,23 @@ ${resultContent}${attachmentSummary}`;
26782
26894
  };
26783
26895
  }
26784
26896
  const id = crypto.randomUUID();
26785
- const duplex = opened.duplex;
26786
- const reader = duplex.readable.getReader();
26787
- const writer = duplex.writable.getWriter();
26788
- const entry = {
26789
- writer,
26790
- reader,
26791
- buffer: [],
26792
- done: false,
26793
- error: void 0,
26794
- pump: Promise.resolve(),
26795
- close: (error) => duplex.close(error),
26796
- waiter: null,
26797
- notify: () => {
26798
- const waiter = entry.waiter;
26799
- entry.waiter = null;
26800
- waiter?.();
26801
- }
26802
- };
26803
- entry.pump = (async () => {
26804
- try {
26805
- while (true) {
26806
- const { value, done } = await reader.read();
26807
- if (done) break;
26808
- if (value) {
26809
- entry.buffer.push(value);
26810
- entry.notify();
26811
- }
26812
- }
26813
- } catch (error) {
26814
- entry.error = error instanceof Error ? error.message : String(error);
26815
- } finally {
26816
- entry.done = true;
26817
- entry.notify();
26818
- }
26819
- })();
26820
- void duplex.done.then((d) => {
26821
- entry.done = true;
26822
- if (!d.ok && !entry.error) entry.error = d.error;
26823
- entry.notify();
26897
+ this.eventProxyStreams.set(id, {
26898
+ writer: opened.duplex.writable.getWriter(),
26899
+ close: (error) => opened.duplex.close(error),
26900
+ target
26824
26901
  });
26825
- this.proxyStreams.set(id, entry);
26826
- return { ok: true, id, parkedPull: true };
26902
+ return { ok: true, id, eventDriven: true };
26827
26903
  }
26828
26904
  async proxyStreamWrite(id, dataB64) {
26829
- const entry = this.proxyStreams.get(id);
26905
+ const entry = this.eventProxyStreams.get(id);
26830
26906
  if (!entry) return;
26831
26907
  try {
26832
26908
  await entry.writer.write(decodeStreamChunk(dataB64));
26833
26909
  } catch {
26834
26910
  }
26835
26911
  }
26836
- async proxyStreamPull(id, maxWaitMs) {
26837
- const entry = this.proxyStreams.get(id);
26838
- if (!entry) return { chunks: [], done: true, error: "unknown proxy stream" };
26839
- if (entry.buffer.length === 0 && !entry.done) {
26840
- await new Promise((resolve) => {
26841
- const deadline = typeof maxWaitMs === "number" && maxWaitMs > 0 ? setTimeout(() => {
26842
- if (entry.waiter === wake) entry.waiter = null;
26843
- resolve();
26844
- }, maxWaitMs) : null;
26845
- const wake = () => {
26846
- if (deadline) clearTimeout(deadline);
26847
- resolve();
26848
- };
26849
- entry.waiter = wake;
26850
- });
26851
- }
26852
- const chunks = entry.buffer.splice(0).map((b) => encodeStreamChunk(b));
26853
- if (entry.done && entry.buffer.length === 0) {
26854
- this.proxyStreams.delete(id);
26855
- return { chunks, done: true, error: entry.error };
26856
- }
26857
- return { chunks, done: false };
26858
- }
26859
26912
  async proxyStreamEnd(id) {
26860
- const entry = this.proxyStreams.get(id);
26913
+ const entry = this.eventProxyStreams.get(id);
26861
26914
  if (!entry) return;
26862
26915
  try {
26863
26916
  await entry.writer.close();
@@ -26865,30 +26918,49 @@ ${resultContent}${attachmentSummary}`;
26865
26918
  }
26866
26919
  }
26867
26920
  async proxyStreamAbort(id) {
26868
- const entry = this.proxyStreams.get(id);
26921
+ const entry = this.eventProxyStreams.get(id);
26869
26922
  if (!entry) return;
26870
- this.proxyStreams.delete(id);
26871
- entry.done = true;
26872
- if (!entry.error) entry.error = "aborted";
26873
- entry.notify();
26923
+ this.eventProxyStreams.delete(id);
26874
26924
  try {
26875
26925
  entry.close("aborted");
26876
26926
  } catch {
26877
26927
  }
26878
26928
  }
26929
+ forgetEventProxyStream(clientStreamId, target) {
26930
+ const matchesTarget = (candidate) => candidate.threadId === target.threadId && candidate.receiverId === target.receiverId;
26931
+ for (const [id, entry] of Array.from(this.eventProxyStreams.entries())) {
26932
+ if (id !== clientStreamId && !matchesTarget(entry.target)) continue;
26933
+ this.eventProxyStreams.delete(id);
26934
+ try {
26935
+ entry.writer.releaseLock();
26936
+ } catch {
26937
+ }
26938
+ }
26939
+ }
26879
26940
  /** Settle and remove a client stream exactly once. */
26880
26941
  settleClientStream(id, result, openCode) {
26881
26942
  const state = this.clientStreams.get(id);
26882
26943
  if (!state) return;
26883
26944
  this.clientStreams.delete(id);
26945
+ this.updateBridgeProxyAttachment(state.socket);
26884
26946
  if (state.openTimer) clearTimeout(state.openTimer);
26885
26947
  if (state.opened) state.opened({ ok: false, error: result.error ?? "Stream closed.", code: openCode });
26886
26948
  if (!state.settled) {
26887
26949
  state.settled = true;
26888
- try {
26889
- if (result.ok) state.controller?.close();
26890
- else state.controller?.error(new Error(result.error ?? "Client stream aborted."));
26891
- } catch {
26950
+ if (state.proxyTarget) {
26951
+ const target = state.proxyTarget;
26952
+ const frame = result.ok ? { type: "end" } : { type: "abort", error: result.error ?? "Client stream aborted." };
26953
+ state.delivery = state.delivery.then(async () => {
26954
+ await this.deliverProxyStreamFrame(target, frame);
26955
+ });
26956
+ this.ctx.waitUntil(state.delivery);
26957
+ this.forgetEventProxyStream(id, target);
26958
+ } else {
26959
+ try {
26960
+ if (result.ok) state.controller?.close();
26961
+ else state.controller?.error(new Error(result.error ?? "Client stream aborted."));
26962
+ } catch {
26963
+ }
26892
26964
  }
26893
26965
  state.settleDone(result);
26894
26966
  }
@@ -26931,6 +27003,18 @@ ${resultContent}${attachmentSummary}`;
26931
27003
  }
26932
27004
  case "stream_data": {
26933
27005
  if (typeof parsed.data !== "string") return;
27006
+ if (state.proxyTarget) {
27007
+ const target = state.proxyTarget;
27008
+ const frame = { type: "data", data: parsed.data };
27009
+ state.delivery = state.delivery.then(async () => {
27010
+ const delivered = await this.deliverProxyStreamFrame(target, frame);
27011
+ if (!delivered && this.clientStreams.get(id) === state) {
27012
+ this.abortClientStream(id, "The destination stream receiver is unavailable.");
27013
+ }
27014
+ });
27015
+ this.ctx.waitUntil(state.delivery);
27016
+ return;
27017
+ }
26934
27018
  try {
26935
27019
  state.controller?.enqueue(decodeStreamChunk(parsed.data));
26936
27020
  } catch {
@@ -27758,11 +27842,12 @@ ${resultContent}${attachmentSummary}`;
27758
27842
  if (!parentThreadId) return;
27759
27843
  const parentId = this.env.AGENT_BUILDER_THREAD.idFromName(parentThreadId);
27760
27844
  const parentStub = this.env.AGENT_BUILDER_THREAD.get(parentId);
27761
- const parentCommunication = await this.getParentCommunicationModeForChild(
27845
+ const childRegistryEntry = await this.getParentRegistryEntryForChild(
27762
27846
  parentStub,
27763
27847
  parentThreadId,
27764
27848
  threadId
27765
27849
  );
27850
+ const parentCommunication = childRegistryEntry?.parentCommunication === "explicit" ? "explicit" : "implicit";
27766
27851
  if (parentCommunication !== "explicit") {
27767
27852
  await parentStub.queueMessage(parentThreadId, {
27768
27853
  role: "user",
@@ -28521,11 +28606,11 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
28521
28606
  /**
28522
28607
  * Write a file to storage (RPC method)
28523
28608
  */
28524
- async writeFile(path, data, mimeType, options) {
28609
+ async writeFile(path2, data, mimeType, options) {
28525
28610
  await this.ensureMigrated();
28526
28611
  try {
28527
- const fs = this.getFileStorage();
28528
- const existingFile = await fs.stat(path);
28612
+ const fs2 = this.getFileStorage();
28613
+ const existingFile = await fs2.stat(path2);
28529
28614
  const isUpdate = existingFile !== null;
28530
28615
  const binaryString = atob(data);
28531
28616
  const dataBuffer = new Uint8Array(binaryString.length);
@@ -28547,12 +28632,12 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
28547
28632
  }
28548
28633
  }
28549
28634
  }
28550
- const record = await fs.writeFile(path, dataBuffer, mimeType, {
28635
+ const record = await fs2.writeFile(path2, dataBuffer, mimeType, {
28551
28636
  metadata: options?.metadata,
28552
28637
  thumbnail: thumbnailBuffer
28553
28638
  });
28554
28639
  this.broadcastEvent(isUpdate ? "file_updated" : "file_created", {
28555
- path,
28640
+ path: path2,
28556
28641
  file: record
28557
28642
  });
28558
28643
  return { success: true, file: record };
@@ -28564,15 +28649,15 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
28564
28649
  /**
28565
28650
  * Write a text file to storage (RPC method)
28566
28651
  */
28567
- async writeTextFile(path, content, mimeType = "text/plain", options) {
28652
+ async writeTextFile(path2, content, mimeType = "text/plain", options) {
28568
28653
  await this.ensureMigrated();
28569
28654
  try {
28570
- const fs = this.getFileStorage();
28571
- const existingFile = await fs.stat(path);
28655
+ const fs2 = this.getFileStorage();
28656
+ const existingFile = await fs2.stat(path2);
28572
28657
  const isUpdate = existingFile !== null;
28573
- const record = await fs.writeFile(path, content, mimeType, options);
28658
+ const record = await fs2.writeFile(path2, content, mimeType, options);
28574
28659
  this.broadcastEvent(isUpdate ? "file_updated" : "file_created", {
28575
- path,
28660
+ path: path2,
28576
28661
  file: record
28577
28662
  });
28578
28663
  return { success: true, file: record };
@@ -28609,11 +28694,11 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
28609
28694
  /**
28610
28695
  * Link to an external file (RPC method)
28611
28696
  */
28612
- async linkFile(path, location, options) {
28697
+ async linkFile(path2, location, options) {
28613
28698
  await this.ensureMigrated();
28614
28699
  try {
28615
- const fs = this.getFileStorage();
28616
- const record = await fs.linkFile(path, location, options);
28700
+ const fs2 = this.getFileStorage();
28701
+ const record = await fs2.linkFile(path2, location, options);
28617
28702
  return { success: true, file: record };
28618
28703
  } catch (error) {
28619
28704
  console.error("Error in linkFile:", error);
@@ -28624,11 +28709,11 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
28624
28709
  * Read a file from storage (RPC method)
28625
28710
  * Returns base64-encoded data
28626
28711
  */
28627
- async readFile(path) {
28712
+ async readFile(path2) {
28628
28713
  await this.ensureMigrated();
28629
28714
  try {
28630
- const fs = this.getFileStorage();
28631
- const data = await fs.readFile(path);
28715
+ const fs2 = this.getFileStorage();
28716
+ const data = await fs2.readFile(path2);
28632
28717
  if (data === null) {
28633
28718
  return { success: false, error: "File not found or external" };
28634
28719
  }
@@ -28647,11 +28732,11 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
28647
28732
  /**
28648
28733
  * Read a text file from storage (RPC method)
28649
28734
  */
28650
- async readTextFile(path) {
28735
+ async readTextFile(path2) {
28651
28736
  await this.ensureMigrated();
28652
28737
  try {
28653
- const fs = this.getFileStorage();
28654
- const content = await fs.readTextFile(path);
28738
+ const fs2 = this.getFileStorage();
28739
+ const content = await fs2.readTextFile(path2);
28655
28740
  if (content === null) {
28656
28741
  return { success: false, error: "File not found or external" };
28657
28742
  }
@@ -28664,11 +28749,11 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
28664
28749
  /**
28665
28750
  * Get file metadata (RPC method)
28666
28751
  */
28667
- async statFile(path) {
28752
+ async statFile(path2) {
28668
28753
  await this.ensureMigrated();
28669
28754
  try {
28670
- const fs = this.getFileStorage();
28671
- const record = await fs.stat(path);
28755
+ const fs2 = this.getFileStorage();
28756
+ const record = await fs2.stat(path2);
28672
28757
  if (record === null) {
28673
28758
  return { success: false, error: "File not found" };
28674
28759
  }
@@ -28681,11 +28766,11 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
28681
28766
  /**
28682
28767
  * Check if file exists (RPC method)
28683
28768
  */
28684
- async fileExists(path) {
28769
+ async fileExists(path2) {
28685
28770
  await this.ensureMigrated();
28686
28771
  try {
28687
- const fs = this.getFileStorage();
28688
- const exists2 = await fs.exists(path);
28772
+ const fs2 = this.getFileStorage();
28773
+ const exists2 = await fs2.exists(path2);
28689
28774
  return { success: true, exists: exists2 };
28690
28775
  } catch (error) {
28691
28776
  console.error("Error in fileExists:", error);
@@ -28695,12 +28780,12 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
28695
28780
  /**
28696
28781
  * Delete a file (RPC method)
28697
28782
  */
28698
- async unlinkFile(path) {
28783
+ async unlinkFile(path2) {
28699
28784
  await this.ensureMigrated();
28700
28785
  try {
28701
- const fs = this.getFileStorage();
28702
- await fs.unlink(path);
28703
- this.broadcastEvent("file_deleted", { path });
28786
+ const fs2 = this.getFileStorage();
28787
+ await fs2.unlink(path2);
28788
+ this.broadcastEvent("file_deleted", { path: path2 });
28704
28789
  return { success: true };
28705
28790
  } catch (error) {
28706
28791
  console.error("Error in unlinkFile:", error);
@@ -28710,12 +28795,12 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
28710
28795
  /**
28711
28796
  * Create a directory (RPC method)
28712
28797
  */
28713
- async mkdirFile(path) {
28798
+ async mkdirFile(path2) {
28714
28799
  await this.ensureMigrated();
28715
28800
  try {
28716
- const fs = this.getFileStorage();
28717
- const record = await fs.mkdir(path);
28718
- this.broadcastEvent("file_created", { path, file: record });
28801
+ const fs2 = this.getFileStorage();
28802
+ const record = await fs2.mkdir(path2);
28803
+ this.broadcastEvent("file_created", { path: path2, file: record });
28719
28804
  return { success: true, directory: record };
28720
28805
  } catch (error) {
28721
28806
  console.error("Error in mkdirFile:", error);
@@ -28725,11 +28810,11 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
28725
28810
  /**
28726
28811
  * List directory contents (RPC method)
28727
28812
  */
28728
- async readdirFile(path) {
28813
+ async readdirFile(path2) {
28729
28814
  await this.ensureMigrated();
28730
28815
  try {
28731
- const fs = this.getFileStorage();
28732
- const files = await fs.readdir(path);
28816
+ const fs2 = this.getFileStorage();
28817
+ const files = await fs2.readdir(path2);
28733
28818
  return { success: true, files };
28734
28819
  } catch (error) {
28735
28820
  console.error("Error in readdirFile:", error);
@@ -28739,12 +28824,12 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
28739
28824
  /**
28740
28825
  * Remove empty directory (RPC method)
28741
28826
  */
28742
- async rmdirFile(path) {
28827
+ async rmdirFile(path2) {
28743
28828
  await this.ensureMigrated();
28744
28829
  try {
28745
- const fs = this.getFileStorage();
28746
- await fs.rmdir(path);
28747
- this.broadcastEvent("file_deleted", { path });
28830
+ const fs2 = this.getFileStorage();
28831
+ await fs2.rmdir(path2);
28832
+ this.broadcastEvent("file_deleted", { path: path2 });
28748
28833
  return { success: true };
28749
28834
  } catch (error) {
28750
28835
  console.error("Error in rmdirFile:", error);
@@ -28759,9 +28844,9 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
28759
28844
  await this.ensureMigrated();
28760
28845
  try {
28761
28846
  const { normalizePath: normalizePath2 } = await Promise.resolve().then(() => (init_files(), files_exports));
28762
- const fs = this.getFileStorage();
28847
+ const fs2 = this.getFileStorage();
28763
28848
  const from = normalizePath2(sourcePath);
28764
- const record = await fs.move(sourcePath, destinationPath);
28849
+ const record = await fs2.move(sourcePath, destinationPath);
28765
28850
  this.broadcastEvent("file_moved", { from, path: record.path, file: record });
28766
28851
  this.broadcastEvent("file_deleted", { path: from });
28767
28852
  this.broadcastEvent("file_created", { path: record.path, file: record });
@@ -28774,13 +28859,13 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
28774
28859
  /**
28775
28860
  * Rename a file or directory in place (RPC method).
28776
28861
  */
28777
- async renameFile(path, newName) {
28862
+ async renameFile(path2, newName) {
28778
28863
  await this.ensureMigrated();
28779
28864
  try {
28780
28865
  const { normalizePath: normalizePath2 } = await Promise.resolve().then(() => (init_files(), files_exports));
28781
- const fs = this.getFileStorage();
28782
- const from = normalizePath2(path);
28783
- const record = await fs.rename(path, newName);
28866
+ const fs2 = this.getFileStorage();
28867
+ const from = normalizePath2(path2);
28868
+ const record = await fs2.rename(path2, newName);
28784
28869
  this.broadcastEvent("file_moved", { from, path: record.path, file: record });
28785
28870
  this.broadcastEvent("file_deleted", { path: from });
28786
28871
  this.broadcastEvent("file_created", { path: record.path, file: record });
@@ -28796,8 +28881,8 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
28796
28881
  async getFileStats() {
28797
28882
  await this.ensureMigrated();
28798
28883
  try {
28799
- const fs = this.getFileStorage();
28800
- const stats = await fs.getFileStats();
28884
+ const fs2 = this.getFileStorage();
28885
+ const stats = await fs2.getFileStats();
28801
28886
  return { success: true, stats };
28802
28887
  } catch (error) {
28803
28888
  console.error("Error in getFileStats:", error);
@@ -28808,11 +28893,11 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
28808
28893
  * Get thumbnail for an image (RPC method)
28809
28894
  * Returns base64-encoded data
28810
28895
  */
28811
- async getFileThumbnail(path) {
28896
+ async getFileThumbnail(path2) {
28812
28897
  await this.ensureMigrated();
28813
28898
  try {
28814
- const fs = this.getFileStorage();
28815
- const data = await fs.getThumbnail(path);
28899
+ const fs2 = this.getFileStorage();
28900
+ const data = await fs2.getThumbnail(path2);
28816
28901
  if (data === null) {
28817
28902
  return { success: false, error: "Thumbnail not found" };
28818
28903
  }
@@ -28834,8 +28919,8 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
28834
28919
  async grepFiles(pattern, options) {
28835
28920
  await this.ensureMigrated();
28836
28921
  try {
28837
- const fs = this.getFileStorage();
28838
- const results = await fs.grep(pattern, options);
28922
+ const fs2 = this.getFileStorage();
28923
+ const results = await fs2.grep(pattern, options);
28839
28924
  return { success: true, results };
28840
28925
  } catch (error) {
28841
28926
  console.error("Error in grepFiles:", error);
@@ -28848,8 +28933,8 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
28848
28933
  async findFiles(pattern, options) {
28849
28934
  await this.ensureMigrated();
28850
28935
  try {
28851
- const fs = this.getFileStorage();
28852
- const files = await fs.find(pattern, options);
28936
+ const fs2 = this.getFileStorage();
28937
+ const files = await fs2.find(pattern, options);
28853
28938
  return { success: true, files };
28854
28939
  } catch (error) {
28855
28940
  console.error("Error in findFiles:", error);
@@ -28864,11 +28949,11 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
28864
28949
  * Creates file record with is_chunked=1 and chunk_count=null.
28865
28950
  * Caller should then use writeFileChunk() to write chunks.
28866
28951
  */
28867
- async startChunkedUpload(path, totalSize, mimeType, options) {
28952
+ async startChunkedUpload(path2, totalSize, mimeType, options) {
28868
28953
  await this.ensureMigrated();
28869
28954
  try {
28870
28955
  const { CHUNK_SIZE: CHUNK_SIZE2, normalizePath: normalizePath2, basename: basename2 } = await Promise.resolve().then(() => (init_files(), files_exports));
28871
- const normalizedPath = normalizePath2(path);
28956
+ const normalizedPath = normalizePath2(path2);
28872
28957
  const name = basename2(normalizedPath);
28873
28958
  const now = Date.now();
28874
28959
  const expectedChunks = Math.ceil(totalSize / CHUNK_SIZE2);
@@ -28905,11 +28990,11 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
28905
28990
  * @param chunkIndex - 0-based chunk index
28906
28991
  * @param data - Base64 encoded chunk data
28907
28992
  */
28908
- async writeFileChunk(path, chunkIndex, data) {
28993
+ async writeFileChunk(path2, chunkIndex, data) {
28909
28994
  await this.ensureMigrated();
28910
28995
  try {
28911
28996
  const { normalizePath: normalizePath2 } = await Promise.resolve().then(() => (init_files(), files_exports));
28912
- const normalizedPath = normalizePath2(path);
28997
+ const normalizedPath = normalizePath2(path2);
28913
28998
  const binaryString = atob(data);
28914
28999
  const dataBuffer = new Uint8Array(binaryString.length);
28915
29000
  for (let i = 0; i < binaryString.length; i++) {
@@ -28931,12 +29016,12 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
28931
29016
  * Complete a chunked file upload.
28932
29017
  * Validates all chunks are present and sets chunk_count.
28933
29018
  */
28934
- async completeChunkedUpload(path, expectedChunks, options) {
29019
+ async completeChunkedUpload(path2, expectedChunks, options) {
28935
29020
  await this.ensureMigrated();
28936
29021
  try {
28937
29022
  const { normalizePath: normalizePath2 } = await Promise.resolve().then(() => (init_files(), files_exports));
28938
- const fs = this.getFileStorage();
28939
- const normalizedPath = normalizePath2(path);
29023
+ const fs2 = this.getFileStorage();
29024
+ const normalizedPath = normalizePath2(path2);
28940
29025
  const countResult = await this.ctx.storage.sql.exec(
28941
29026
  `SELECT COUNT(*) as count FROM file_chunks WHERE file_path = ?`,
28942
29027
  normalizedPath
@@ -28962,7 +29047,7 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
28962
29047
  thumbnailBuffer || null,
28963
29048
  normalizedPath
28964
29049
  );
28965
- const file = await fs.stat(normalizedPath);
29050
+ const file = await fs2.stat(normalizedPath);
28966
29051
  if (file) {
28967
29052
  this.broadcastEvent("file_created", { path: normalizedPath, file });
28968
29053
  }
@@ -28976,11 +29061,11 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
28976
29061
  * Read a single chunk of a file.
28977
29062
  * Use for streaming large files to client.
28978
29063
  */
28979
- async readFileChunk(path, chunkIndex) {
29064
+ async readFileChunk(path2, chunkIndex) {
28980
29065
  await this.ensureMigrated();
28981
29066
  try {
28982
29067
  const { normalizePath: normalizePath2 } = await Promise.resolve().then(() => (init_files(), files_exports));
28983
- const normalizedPath = normalizePath2(path);
29068
+ const normalizedPath = normalizePath2(path2);
28984
29069
  const cursor = await this.ctx.storage.sql.exec(
28985
29070
  `SELECT data FROM file_chunks WHERE file_path = ? AND chunk_index = ?`,
28986
29071
  normalizedPath,
@@ -29005,11 +29090,11 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
29005
29090
  /**
29006
29091
  * Get file info including chunking metadata.
29007
29092
  */
29008
- async getFileInfo(path) {
29093
+ async getFileInfo(path2) {
29009
29094
  await this.ensureMigrated();
29010
29095
  try {
29011
- const fs = this.getFileStorage();
29012
- const file = await fs.stat(path);
29096
+ const fs2 = this.getFileStorage();
29097
+ const file = await fs2.stat(path2);
29013
29098
  if (!file) {
29014
29099
  return { success: false, error: "File not found" };
29015
29100
  }
@@ -29227,16 +29312,16 @@ function parseUserRouteKey(key) {
29227
29312
  }
29228
29313
  return { key, method, segments, dynamism };
29229
29314
  }
29230
- function matchSegments(route, path) {
29315
+ function matchSegments(route, path2) {
29231
29316
  const params = {};
29232
29317
  for (let i = 0; i < route.length; i++) {
29233
29318
  const seg = route[i];
29234
29319
  if (seg === "[*]") {
29235
29320
  if (i !== route.length - 1) return null;
29236
- params["*"] = path.slice(i).join("/");
29321
+ params["*"] = path2.slice(i).join("/");
29237
29322
  return params;
29238
29323
  }
29239
- const value = path[i];
29324
+ const value = path2[i];
29240
29325
  if (value === void 0) return null;
29241
29326
  if (seg.startsWith("[") && seg.endsWith("]")) {
29242
29327
  params[seg.slice(1, -1)] = value;
@@ -29244,16 +29329,16 @@ function matchSegments(route, path) {
29244
29329
  return null;
29245
29330
  }
29246
29331
  }
29247
- return path.length === route.length ? params : null;
29332
+ return path2.length === route.length ? params : null;
29248
29333
  }
29249
29334
  function matchUserRoute(keys, method, endpointPath) {
29250
- const path = endpointPath.split("/").filter((s) => s.length > 0);
29335
+ const path2 = endpointPath.split("/").filter((s) => s.length > 0);
29251
29336
  const wanted = method.toUpperCase();
29252
29337
  let best = null;
29253
29338
  for (const key of keys) {
29254
29339
  const route = parseUserRouteKey(key);
29255
29340
  if (route.method !== wanted) continue;
29256
- const params = matchSegments(route.segments, path);
29341
+ const params = matchSegments(route.segments, path2);
29257
29342
  if (!params) continue;
29258
29343
  if (!best || route.dynamism < best.route.dynamism) {
29259
29344
  best = { route, params };