@gea-ai/agent-sdk 0.1.261012-alpha.0 → 0.1.261016-alpha.0

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.
Files changed (68) hide show
  1. package/dist/agent-ai.d.ts +1 -0
  2. package/dist/agent-ai.js +11 -4
  3. package/dist/agent-call.d.ts +175 -3
  4. package/dist/agent-call.js +197 -24
  5. package/dist/agent-channel-api.js +81 -31
  6. package/dist/agent-channel-author-runtime.d.ts +15 -15
  7. package/dist/agent-channel-author-runtime.js +59 -11
  8. package/dist/agent-channel-control.d.ts +4 -0
  9. package/dist/agent-channel-control.js +336 -0
  10. package/dist/agent-channel-receiver.js +24 -8
  11. package/dist/agent-channel-runtime.d.ts +1 -1
  12. package/dist/agent-channel-runtime.js +221 -136
  13. package/dist/agent-channel-session-transport.d.ts +3 -0
  14. package/dist/agent-channel-session-transport.js +26 -0
  15. package/dist/agent-channel-worker.js +2 -1
  16. package/dist/agent-client-tool.d.ts +3 -0
  17. package/dist/agent-client-tool.js +79 -0
  18. package/dist/agent-computer-http.d.ts +6 -2
  19. package/dist/agent-computer-http.js +33 -14
  20. package/dist/agent-computer-protocol.d.ts +8 -0
  21. package/dist/agent-computer-protocol.js +126 -0
  22. package/dist/agent-computer-scope.d.ts +1 -0
  23. package/dist/agent-computer-scope.js +18 -1
  24. package/dist/agent-computer-session.d.ts +5 -0
  25. package/dist/agent-computer-session.js +149 -25
  26. package/dist/agent-core.wasm +0 -0
  27. package/dist/agent-remote-run.d.ts +2 -2
  28. package/dist/agent-run-host.d.ts +10 -7
  29. package/dist/agent-run-host.js +15 -9
  30. package/dist/agent-session-execution.d.ts +33 -1
  31. package/dist/agent-session-execution.js +215 -28
  32. package/dist/agent-session-inbox.d.ts +9 -2
  33. package/dist/agent-session-inbox.js +419 -33
  34. package/dist/agent-session-stale-run.d.ts +33 -0
  35. package/dist/agent-session-stale-run.js +44 -0
  36. package/dist/agent-session.d.ts +24 -0
  37. package/dist/agent-session.js +25 -5
  38. package/dist/agent-stream-coalescing.d.ts +11 -0
  39. package/dist/agent-stream-coalescing.js +159 -0
  40. package/dist/agent-worker-attachments.d.ts +2 -2
  41. package/dist/agent-worker.d.ts +9 -1
  42. package/dist/agent-worker.js +210 -221
  43. package/dist/artifacts.d.ts +4 -4
  44. package/dist/artifacts.js +2 -2
  45. package/dist/channels/index.d.ts +13 -3
  46. package/dist/channels/index.js +3 -0
  47. package/dist/context-runtime.d.ts +1 -0
  48. package/dist/context-runtime.js +1 -0
  49. package/dist/evals.d.ts +8 -0
  50. package/dist/evals.js +96 -2
  51. package/dist/experimental/agent-core-ui.js +1 -0
  52. package/dist/index.d.ts +10 -4
  53. package/dist/index.js +6 -0
  54. package/dist/session-authority.d.ts +6 -1
  55. package/dist/tool-model-output.d.ts +1 -1
  56. package/dist/version.d.ts +1 -1
  57. package/dist/version.js +1 -1
  58. package/package.json +10 -8
  59. package/dist/channels/feishu-codec.d.ts +0 -17
  60. package/dist/channels/feishu-codec.js +0 -108
  61. package/dist/channels/feishu-inbound.d.ts +0 -34
  62. package/dist/channels/feishu-inbound.js +0 -135
  63. package/dist/channels/feishu-output.d.ts +0 -427
  64. package/dist/channels/feishu-output.js +0 -852
  65. package/dist/channels/feishu-websocket.d.ts +0 -4
  66. package/dist/channels/feishu-websocket.js +0 -423
  67. package/dist/channels/feishu.d.ts +0 -145
  68. package/dist/channels/feishu.js +0 -85
@@ -6,4 +6,5 @@ export declare function createAgentAI(input: {
6
6
  modelId: string;
7
7
  signal(): AbortSignal;
8
8
  recordUsage(entry: AgentContextUsage): void;
9
+ startUsage?(callId: string, model: string): Promise<void>;
9
10
  }): AgentAI;
package/dist/agent-ai.js CHANGED
@@ -29,9 +29,9 @@ export function createAgentAI(input) {
29
29
  };
30
30
  // The binding owns the model span. Forward the active SDK parent so generic
31
31
  // native calls and Agent-owned calls share the same trace without two model spans.
32
- const observe = (options, result) => result.then((value) => {
32
+ const observe = (options, result, callId) => result.then((value) => {
33
33
  input.recordUsage({
34
- callId: value.callId,
34
+ callId: callId ?? value.callId,
35
35
  model: value.model,
36
36
  label: options.label,
37
37
  usage: value.usage,
@@ -40,6 +40,7 @@ export function createAgentAI(input) {
40
40
  return value;
41
41
  }, (error) => {
42
42
  input.recordUsage({
43
+ callId,
43
44
  model: options.model,
44
45
  label: options.label,
45
46
  usage: null,
@@ -53,20 +54,26 @@ export function createAgentAI(input) {
53
54
  return {
54
55
  async generateText(options) {
55
56
  const parameters = prepare(options);
57
+ const callId = input.startUsage ? crypto.randomUUID() : undefined;
58
+ if (callId)
59
+ await input.startUsage(callId, parameters.model);
56
60
  return observe(parameters, (async () => {
57
61
  if (!input.binding.generateText)
58
62
  throw new Error("AI generation binding is unavailable. Update Worker Runtime.");
59
63
  return input.binding.generateText(parameters);
60
- })());
64
+ })(), callId);
61
65
  },
62
66
  async streamText(options) {
63
67
  const parameters = prepare(options);
68
+ const callId = input.startUsage ? crypto.randomUUID() : undefined;
69
+ if (callId)
70
+ await input.startUsage(callId, parameters.model);
64
71
  const opened = (async () => {
65
72
  if (!input.binding.streamText)
66
73
  throw new Error("AI generation binding is unavailable. Update Worker Runtime.");
67
74
  return input.binding.streamText(parameters);
68
75
  })();
69
- const result = observe(parameters, opened.then((call) => call.result));
76
+ const result = observe(parameters, opened.then((call) => call.result), callId);
70
77
  result.catch(() => { });
71
78
  const call = await opened;
72
79
  return { stream: call.stream, result };
@@ -1,12 +1,12 @@
1
1
  import { z } from "zod";
2
2
  import { type AgentWorkerToolInitialization } from "@gea-ai/contract/agent-worker-tools";
3
3
  import type { AgentHostBinding } from "./agent-worker.js";
4
- import type { StudioArtifactScope } from "@gea-ai/contract/studio-artifacts";
4
+ import type { BuilderArtifactScope } from "@gea-ai/contract/builder-artifacts";
5
5
  /** Fresh Sessions keep the declared-target rule. A resume only needs sessionId. */
6
6
  export declare function workerAgentToolInputSchema(input: {
7
7
  agents: NonNullable<AgentWorkerToolInitialization["agents"]>;
8
8
  canCopy?: boolean;
9
- artifactScope?: StudioArtifactScope;
9
+ artifactScope?: BuilderArtifactScope;
10
10
  }): z.ZodObject<{
11
11
  sessionId: z.ZodOptional<z.ZodUUID>;
12
12
  target: z.ZodOptional<z.ZodString>;
@@ -31,8 +31,9 @@ export declare function workerAgentToolInputSchema(input: {
31
31
  export declare function createWorkerAgentTool(input: {
32
32
  agents: NonNullable<AgentWorkerToolInitialization["agents"]>;
33
33
  host: AgentHostBinding;
34
+ runId?: string;
34
35
  canCopy?: boolean;
35
- artifactScope?: StudioArtifactScope;
36
+ artifactScope?: BuilderArtifactScope;
36
37
  }): ({
37
38
  deferLoading?: boolean;
38
39
  title?: string;
@@ -146,6 +147,16 @@ export declare function createWorkerAgentTool(input: {
146
147
  } | {
147
148
  error: string;
148
149
  message: string;
150
+ } | {
151
+ code: "UPSTREAM_HTTP_ERROR";
152
+ status: number;
153
+ message: string;
154
+ } | {
155
+ code: string;
156
+ reason: string;
157
+ status: number;
158
+ requestId?: string | undefined;
159
+ message: string;
149
160
  }>;
150
161
  }) => import("@ai-sdk/provider-utils").ToolResultOutput | PromiseLike<import("@ai-sdk/provider-utils").ToolResultOutput>) | undefined;
151
162
  } & {
@@ -168,6 +179,16 @@ export declare function createWorkerAgentTool(input: {
168
179
  } | {
169
180
  error: string;
170
181
  message: string;
182
+ } | {
183
+ code: "UPSTREAM_HTTP_ERROR";
184
+ status: number;
185
+ message: string;
186
+ } | {
187
+ code: string;
188
+ reason: string;
189
+ status: number;
190
+ requestId?: string | undefined;
191
+ message: string;
171
192
  }> | undefined;
172
193
  execute: import("ai").ToolExecuteFunction<{
173
194
  sessionId?: string | undefined;
@@ -207,6 +228,16 @@ export declare function createWorkerAgentTool(input: {
207
228
  } | {
208
229
  error: string;
209
230
  message: string;
231
+ } | {
232
+ code: "UPSTREAM_HTTP_ERROR";
233
+ status: number;
234
+ message: string;
235
+ } | {
236
+ code: string;
237
+ reason: string;
238
+ status: number;
239
+ requestId?: string | undefined;
240
+ message: string;
210
241
  }, NoInfer<import("@ai-sdk/provider-utils").Context>>;
211
242
  } & {
212
243
  description?: string | ((options: {
@@ -281,6 +312,16 @@ export declare function createWorkerAgentTool(input: {
281
312
  } | {
282
313
  error: string;
283
314
  message: string;
315
+ } | {
316
+ code: "UPSTREAM_HTTP_ERROR";
317
+ status: number;
318
+ message: string;
319
+ } | {
320
+ code: string;
321
+ reason: string;
322
+ status: number;
323
+ requestId?: string | undefined;
324
+ message: string;
284
325
  }, NoInfer<import("@ai-sdk/provider-utils").Context>>;
285
326
  }) | ({
286
327
  deferLoading?: boolean;
@@ -395,6 +436,16 @@ export declare function createWorkerAgentTool(input: {
395
436
  } | {
396
437
  error: string;
397
438
  message: string;
439
+ } | {
440
+ code: "UPSTREAM_HTTP_ERROR";
441
+ status: number;
442
+ message: string;
443
+ } | {
444
+ code: string;
445
+ reason: string;
446
+ status: number;
447
+ requestId?: string | undefined;
448
+ message: string;
398
449
  }>;
399
450
  }) => import("@ai-sdk/provider-utils").ToolResultOutput | PromiseLike<import("@ai-sdk/provider-utils").ToolResultOutput>) | undefined;
400
451
  } & {
@@ -417,6 +468,16 @@ export declare function createWorkerAgentTool(input: {
417
468
  } | {
418
469
  error: string;
419
470
  message: string;
471
+ } | {
472
+ code: "UPSTREAM_HTTP_ERROR";
473
+ status: number;
474
+ message: string;
475
+ } | {
476
+ code: string;
477
+ reason: string;
478
+ status: number;
479
+ requestId?: string | undefined;
480
+ message: string;
420
481
  }> | undefined;
421
482
  execute: import("ai").ToolExecuteFunction<{
422
483
  sessionId?: string | undefined;
@@ -456,6 +517,16 @@ export declare function createWorkerAgentTool(input: {
456
517
  } | {
457
518
  error: string;
458
519
  message: string;
520
+ } | {
521
+ code: "UPSTREAM_HTTP_ERROR";
522
+ status: number;
523
+ message: string;
524
+ } | {
525
+ code: string;
526
+ reason: string;
527
+ status: number;
528
+ requestId?: string | undefined;
529
+ message: string;
459
530
  }, NoInfer<import("@ai-sdk/provider-utils").Context>>;
460
531
  } & {
461
532
  description?: string | ((options: {
@@ -530,6 +601,16 @@ export declare function createWorkerAgentTool(input: {
530
601
  } | {
531
602
  error: string;
532
603
  message: string;
604
+ } | {
605
+ code: "UPSTREAM_HTTP_ERROR";
606
+ status: number;
607
+ message: string;
608
+ } | {
609
+ code: string;
610
+ reason: string;
611
+ status: number;
612
+ requestId?: string | undefined;
613
+ message: string;
533
614
  }, NoInfer<import("@ai-sdk/provider-utils").Context>>;
534
615
  }) | ({
535
616
  deferLoading?: boolean;
@@ -644,6 +725,16 @@ export declare function createWorkerAgentTool(input: {
644
725
  } | {
645
726
  error: string;
646
727
  message: string;
728
+ } | {
729
+ code: "UPSTREAM_HTTP_ERROR";
730
+ status: number;
731
+ message: string;
732
+ } | {
733
+ code: string;
734
+ reason: string;
735
+ status: number;
736
+ requestId?: string | undefined;
737
+ message: string;
647
738
  }>;
648
739
  }) => import("@ai-sdk/provider-utils").ToolResultOutput | PromiseLike<import("@ai-sdk/provider-utils").ToolResultOutput>) | undefined;
649
740
  } & {
@@ -666,6 +757,16 @@ export declare function createWorkerAgentTool(input: {
666
757
  } | {
667
758
  error: string;
668
759
  message: string;
760
+ } | {
761
+ code: "UPSTREAM_HTTP_ERROR";
762
+ status: number;
763
+ message: string;
764
+ } | {
765
+ code: string;
766
+ reason: string;
767
+ status: number;
768
+ requestId?: string | undefined;
769
+ message: string;
669
770
  }> | undefined;
670
771
  execute: import("ai").ToolExecuteFunction<{
671
772
  sessionId?: string | undefined;
@@ -705,6 +806,16 @@ export declare function createWorkerAgentTool(input: {
705
806
  } | {
706
807
  error: string;
707
808
  message: string;
809
+ } | {
810
+ code: "UPSTREAM_HTTP_ERROR";
811
+ status: number;
812
+ message: string;
813
+ } | {
814
+ code: string;
815
+ reason: string;
816
+ status: number;
817
+ requestId?: string | undefined;
818
+ message: string;
708
819
  }, NoInfer<import("@ai-sdk/provider-utils").Context>>;
709
820
  } & {
710
821
  type: 'provider';
@@ -755,6 +866,16 @@ export declare function createWorkerAgentTool(input: {
755
866
  } | {
756
867
  error: string;
757
868
  message: string;
869
+ } | {
870
+ code: "UPSTREAM_HTTP_ERROR";
871
+ status: number;
872
+ message: string;
873
+ } | {
874
+ code: string;
875
+ reason: string;
876
+ status: number;
877
+ requestId?: string | undefined;
878
+ message: string;
758
879
  }, NoInfer<import("@ai-sdk/provider-utils").Context>>;
759
880
  }) | ({
760
881
  deferLoading?: boolean;
@@ -869,6 +990,16 @@ export declare function createWorkerAgentTool(input: {
869
990
  } | {
870
991
  error: string;
871
992
  message: string;
993
+ } | {
994
+ code: "UPSTREAM_HTTP_ERROR";
995
+ status: number;
996
+ message: string;
997
+ } | {
998
+ code: string;
999
+ reason: string;
1000
+ status: number;
1001
+ requestId?: string | undefined;
1002
+ message: string;
872
1003
  }>;
873
1004
  }) => import("@ai-sdk/provider-utils").ToolResultOutput | PromiseLike<import("@ai-sdk/provider-utils").ToolResultOutput>) | undefined;
874
1005
  } & {
@@ -891,6 +1022,16 @@ export declare function createWorkerAgentTool(input: {
891
1022
  } | {
892
1023
  error: string;
893
1024
  message: string;
1025
+ } | {
1026
+ code: "UPSTREAM_HTTP_ERROR";
1027
+ status: number;
1028
+ message: string;
1029
+ } | {
1030
+ code: string;
1031
+ reason: string;
1032
+ status: number;
1033
+ requestId?: string | undefined;
1034
+ message: string;
894
1035
  }> | undefined;
895
1036
  execute: import("ai").ToolExecuteFunction<{
896
1037
  sessionId?: string | undefined;
@@ -930,6 +1071,16 @@ export declare function createWorkerAgentTool(input: {
930
1071
  } | {
931
1072
  error: string;
932
1073
  message: string;
1074
+ } | {
1075
+ code: "UPSTREAM_HTTP_ERROR";
1076
+ status: number;
1077
+ message: string;
1078
+ } | {
1079
+ code: string;
1080
+ reason: string;
1081
+ status: number;
1082
+ requestId?: string | undefined;
1083
+ message: string;
933
1084
  }, NoInfer<import("@ai-sdk/provider-utils").Context>>;
934
1085
  } & {
935
1086
  type: 'provider';
@@ -980,6 +1131,16 @@ export declare function createWorkerAgentTool(input: {
980
1131
  } | {
981
1132
  error: string;
982
1133
  message: string;
1134
+ } | {
1135
+ code: "UPSTREAM_HTTP_ERROR";
1136
+ status: number;
1137
+ message: string;
1138
+ } | {
1139
+ code: string;
1140
+ reason: string;
1141
+ status: number;
1142
+ requestId?: string | undefined;
1143
+ message: string;
983
1144
  }, NoInfer<import("@ai-sdk/provider-utils").Context>>;
984
1145
  });
985
1146
  export declare function createWorkerRunCancelTool({ host, }: {
@@ -1251,7 +1412,18 @@ export declare function createWorkerRunCancelTool({ host, }: {
1251
1412
  status: "abort_requested" | "not_running";
1252
1413
  }, NoInfer<import("@ai-sdk/provider-utils").Context>>;
1253
1414
  });
1415
+ export declare function readChildHttpRejection(response: Response): Promise<{
1416
+ body: unknown;
1417
+ bodyPrefix: string;
1418
+ bodyState: string;
1419
+ logReason: string;
1420
+ code: string;
1421
+ reason: string;
1422
+ requestId: string | undefined;
1423
+ }>;
1254
1424
  export declare function readWorkerAgentResponse(response: Response, options?: {
1425
+ runId?: string;
1426
+ requestPath?: string;
1255
1427
  persistedSessionWaiting?: () => Promise<boolean>;
1256
1428
  }): Promise<{
1257
1429
  status: "completed" | "suspended";
@@ -59,9 +59,9 @@ export function createWorkerAgentTool(input) {
59
59
  signal: options.abortSignal,
60
60
  });
61
61
  if (!response.ok) {
62
- const body = await Result.tryPromise(() => response.json());
63
- if (body.isOk()) {
64
- const value = body.value;
62
+ const rejection = await readChildHttpRejection(response);
63
+ if (rejection.body !== undefined) {
64
+ const value = rejection.body;
65
65
  const limit = agentSubagentConcurrencyErrorSchema.safeParse(value);
66
66
  if (limit.success)
67
67
  return {
@@ -95,25 +95,14 @@ export function createWorkerAgentTool(input) {
95
95
  error: "child_busy",
96
96
  message: "This child Session has unfinished work. Wait for its Run before continuing the Session.",
97
97
  };
98
- if (response.status === 403) {
99
- const rejection = z
100
- .object({
101
- error: z
102
- .string()
103
- .max(80)
104
- .regex(/^[A-Za-z0-9_.-]+$/),
105
- })
106
- .safeParse(value);
107
- if (rejection.success) {
108
- console.error("Child run rejected", {
109
- status: 403,
110
- error: rejection.data.error,
111
- });
112
- throw new Error(`Agent invocation was rejected (403 ${rejection.data.error}).`);
113
- }
114
- }
115
98
  }
116
- throw new Error(`Agent invocation was rejected (${response.status}).`);
99
+ logChildHttpRejection(response, rejection, {
100
+ path: "/internal/agent-worker-host/v1/agents/runs",
101
+ ...(input.runId ? { runId: input.runId } : {}),
102
+ });
103
+ // Return the rejection instead of throwing. A thrown tool error is
104
+ // replaced by a generic execution message before it reaches the model.
105
+ return agentToolRejectionResult(response.status, rejection);
117
106
  }
118
107
  return agentRunCallResultSchema.parse(await response.json());
119
108
  },
@@ -149,18 +138,202 @@ function childDiagnosticIdentifier(value) {
149
138
  ? value
150
139
  : undefined;
151
140
  }
141
+ // Only fixed protocol vocabulary may appear outside the shape-redacted prefix.
142
+ // Identifier-shaped strings can still be tokens, so a character regex is insufficient.
143
+ const childHttpLogReasonSchema = z.enum([
144
+ "UPSTREAM_HTTP_ERROR",
145
+ "BAD_REQUEST",
146
+ "UNAUTHORIZED",
147
+ "FORBIDDEN",
148
+ "NOT_FOUND",
149
+ "CONFLICT",
150
+ "NESTED_RESUME_REQUIRES_NEW_SDK",
151
+ "CHILD_SESSION_AUTHORITY_MISMATCH",
152
+ "invalid_request",
153
+ "invalid_child_request",
154
+ "invalid_json",
155
+ "unknown_child_session",
156
+ "child_busy",
157
+ "session_identity_conflict",
158
+ "subagent_concurrency_limit",
159
+ "runtime_unavailable",
160
+ "empty_error_response",
161
+ "invalid_error_response",
162
+ "unreadable_error_response",
163
+ "error_response_too_large",
164
+ "error_response_timeout",
165
+ ]);
166
+ // Both admission and dispatch consume untrusted HTTP failures. Bound diagnostics
167
+ // independently of a streaming Run: a stalled error body must never hold its slot.
168
+ export async function readChildHttpRejection(response) {
169
+ let bodyPrefix = "";
170
+ let reason = "empty_error_response";
171
+ let body;
172
+ if (response.body) {
173
+ reason = "unreadable_error_response";
174
+ const reader = response.body.getReader();
175
+ let timer;
176
+ const read = await Result.tryPromise(() => Promise.race([
177
+ (async () => {
178
+ const chunks = [];
179
+ let size = 0;
180
+ let reads = 0;
181
+ while (true) {
182
+ if (++reads > 8192) {
183
+ reason = "error_response_too_large";
184
+ return undefined;
185
+ }
186
+ const next = await reader.read();
187
+ if (next.done)
188
+ break;
189
+ // Shape-only redaction: arbitrary error text may contain credentials or
190
+ // user content under any key. Never guess which strings are safe.
191
+ const prefix = next.value.subarray(0, Math.max(0, 512 - bodyPrefix.length));
192
+ bodyPrefix += Array.from(prefix, (byte) => [123, 125, 91, 93, 34, 58, 44, 32].includes(byte)
193
+ ? String.fromCharCode(byte)
194
+ : "*").join("");
195
+ size += next.value.byteLength;
196
+ if (size > 8192) {
197
+ reason = "error_response_too_large";
198
+ return undefined;
199
+ }
200
+ chunks.push(next.value);
201
+ }
202
+ if (!size) {
203
+ reason = "empty_error_response";
204
+ return undefined;
205
+ }
206
+ reason = "invalid_error_response";
207
+ const bytes = new Uint8Array(size);
208
+ let offset = 0;
209
+ for (const chunk of chunks) {
210
+ bytes.set(chunk, offset);
211
+ offset += chunk.byteLength;
212
+ }
213
+ const parsed = JSON.parse(new TextDecoder().decode(bytes));
214
+ reason = "complete";
215
+ return parsed;
216
+ })(),
217
+ new Promise((resolve) => {
218
+ timer = setTimeout(() => {
219
+ reason = "error_response_timeout";
220
+ resolve(undefined);
221
+ }, 1000);
222
+ }),
223
+ ]));
224
+ clearTimeout(timer);
225
+ // Do not await a peer's cancellation acknowledgement on the rejection path.
226
+ void reader.cancel().catch(() => { });
227
+ reader.releaseLock();
228
+ if (read.isOk())
229
+ body = read.value;
230
+ }
231
+ const bodyState = reason;
232
+ const identifier = z
233
+ .string()
234
+ .max(80)
235
+ .regex(/^[A-Za-z0-9_.-]+$/);
236
+ const parsed = z
237
+ .object({
238
+ code: identifier.optional(),
239
+ requestId: z.uuid().optional(),
240
+ reason: z.string().max(1000).optional(),
241
+ error: z
242
+ .union([
243
+ identifier,
244
+ z.object({
245
+ code: identifier,
246
+ reason: z.string().max(1000).optional(),
247
+ }),
248
+ ])
249
+ .optional(),
250
+ })
251
+ .safeParse(body);
252
+ if (parsed.success) {
253
+ const error = parsed.data.error;
254
+ const code = typeof error === "string" ? error : (error?.code ?? parsed.data.code);
255
+ const detail = (typeof error === "object" ? error.reason : undefined) ??
256
+ parsed.data.reason;
257
+ if (code || detail)
258
+ return {
259
+ body,
260
+ bodyPrefix,
261
+ bodyState,
262
+ logReason: childHttpLogReasonSchema.safeParse(detail).data ??
263
+ childHttpLogReasonSchema.safeParse(code).data ??
264
+ "unclassified_upstream_error",
265
+ code: code ?? "UPSTREAM_HTTP_ERROR",
266
+ reason: detail ?? code,
267
+ requestId: parsed.data.requestId,
268
+ };
269
+ }
270
+ return {
271
+ body,
272
+ bodyPrefix,
273
+ bodyState,
274
+ logReason: reason === "complete" ? "invalid_error_response" : reason,
275
+ code: "UPSTREAM_HTTP_ERROR",
276
+ reason: reason === "complete" ? "invalid_error_response" : reason,
277
+ requestId: undefined,
278
+ };
279
+ }
280
+ function agentToolRejectionResult(status, rejection) {
281
+ const recognized = rejection.bodyState === "complete" &&
282
+ !(rejection.code === "UPSTREAM_HTTP_ERROR" &&
283
+ rejection.reason === "invalid_error_response");
284
+ if (!recognized) {
285
+ return {
286
+ code: "UPSTREAM_HTTP_ERROR",
287
+ status,
288
+ message: `Agent invocation was rejected (${status}). The server did not return a readable error.`,
289
+ };
290
+ }
291
+ const request = rejection.requestId
292
+ ? ` (request ${rejection.requestId})`
293
+ : "";
294
+ return {
295
+ code: rejection.code,
296
+ reason: rejection.reason,
297
+ status,
298
+ ...(rejection.requestId ? { requestId: rejection.requestId } : {}),
299
+ message: `Agent invocation was rejected (${status}) ${rejection.code}: ${rejection.reason}${request}`,
300
+ };
301
+ }
302
+ function logChildHttpRejection(response, rejection, identity) {
303
+ const requestId = rejection.requestId ??
304
+ z.uuid().safeParse(response.headers.get("x-gea-request-id")).data;
305
+ // JSON stays readable in native console forwarding as well as Node/Nitro.
306
+ console.error(JSON.stringify({
307
+ event: "agent.child_http.rejected",
308
+ ...identity,
309
+ status: response.status,
310
+ bodyState: rejection.bodyState,
311
+ reason: rejection.logReason,
312
+ bodyPrefix: rejection.bodyPrefix,
313
+ ...(requestId ? { requestId } : {}),
314
+ }));
315
+ }
152
316
  export async function readWorkerAgentResponse(response, options) {
153
317
  if (response.status === 409 &&
154
318
  response.headers.get("x-gea-session-execution") === "already-started") {
155
- await response.body?.cancel();
319
+ void response.body?.cancel().catch(() => { });
156
320
  return { status: "suspended", text: "" };
157
321
  }
158
322
  if (!response.ok || !response.body) {
159
- await response.body?.cancel();
323
+ const rejection = await readChildHttpRejection(response);
324
+ logChildHttpRejection(response, rejection, {
325
+ path: response.url
326
+ ? new URL(response.url).pathname
327
+ : (options?.requestPath?.split(/[?#]/, 1)[0] ?? "unknown"),
328
+ ...(options?.runId ? { runId: options.runId } : {}),
329
+ });
160
330
  throw new AgentChildRunResponseError({
161
331
  code: "child_http_error",
162
332
  status: response.status,
163
- message: `Child Agent invocation failed (${response.status}).`,
333
+ data: {
334
+ reason: rejection.logReason,
335
+ },
336
+ message: `Child Agent invocation failed (${response.status}) ${rejection.code}: ${rejection.reason}`,
164
337
  });
165
338
  }
166
339
  let text = "";