@agents24/node 0.5.7 → 0.5.9

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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "contractHash": "18daf9ff1f2875f3945f292d0e188804259b35cf98eccd2662f9902e17beb42d",
2
+ "contractHash": "c8dfce18f633a53461f27cd14d0af66526765ad321dd98cb50d79288a6ef54f0",
3
3
  "contractVersion": "0.3.0",
4
4
  "corpus": "conformance/v1/corpus.json",
5
5
  "generatedBy": "@agents24/sdk-contract",
@@ -19,7 +19,7 @@
19
19
  "runtime": "run-stream.v3"
20
20
  },
21
21
  "@agents24/node": {
22
- "contract": "18daf9ff1f2875f3945f292d0e188804259b35cf98eccd2662f9902e17beb42d",
22
+ "contract": "c8dfce18f633a53461f27cd14d0af66526765ad321dd98cb50d79288a6ef54f0",
23
23
  "node": "^22.0.0 || ^24.0.0"
24
24
  },
25
25
  "@agents24/react": {
@@ -31,7 +31,7 @@
31
31
  "protocolOwner": "@agents24/client"
32
32
  },
33
33
  "agents24": {
34
- "contract": "18daf9ff1f2875f3945f292d0e188804259b35cf98eccd2662f9902e17beb42d",
34
+ "contract": "c8dfce18f633a53461f27cd14d0af66526765ad321dd98cb50d79288a6ef54f0",
35
35
  "python": ">=3.10"
36
36
  }
37
37
  },
@@ -48,7 +48,7 @@
48
48
  "schemaVersion": "agents24.compatibility.v1",
49
49
  "targetOperationCounts": {
50
50
  "client": 22,
51
- "node": 106,
52
- "python": 99
51
+ "node": 107,
52
+ "python": 100
53
53
  }
54
54
  }
package/dist/bff.cjs CHANGED
@@ -98,38 +98,59 @@ function publicError(status, code, message, retryable = false, violations) {
98
98
  headers: { "Cache-Control": "no-store", "Content-Type": "application/json; charset=utf-8" }
99
99
  });
100
100
  }
101
- function safeResourcePolicyError(details) {
101
+ var FAILURE_CATEGORIES = /* @__PURE__ */ new Set([
102
+ "validation",
103
+ "authentication",
104
+ "authorization",
105
+ "not_found",
106
+ "policy",
107
+ "conflict",
108
+ "billing",
109
+ "quota",
110
+ "rate_limit",
111
+ "capacity",
112
+ "dependency",
113
+ "protocol",
114
+ "timeout",
115
+ "internal"
116
+ ]);
117
+ var SAFE_VIOLATION_KEYS = /* @__PURE__ */ new Set([
118
+ "field",
119
+ "code",
120
+ "message",
121
+ "policy_subject_type",
122
+ "rule_type",
123
+ "aggregation_scope",
124
+ "resource_type",
125
+ "resource_name",
126
+ "quota_unit",
127
+ "quota_window",
128
+ "limit",
129
+ "remaining",
130
+ "resets_at"
131
+ ]);
132
+ function safeFailure(details) {
102
133
  if (!details || typeof details !== "object" || Array.isArray(details)) return null;
103
134
  const outer = details;
104
135
  const candidate = outer.schema_version === "agents24.failure.v1" ? outer : outer.detail && typeof outer.detail === "object" && !Array.isArray(outer.detail) ? outer.detail : outer;
105
- const code = typeof candidate.code === "string" ? candidate.code : "";
106
- if (!["RESOURCE_POLICY_ACCESS_DENIED", "RESOURCE_POLICY_QUOTA_EXCEEDED", "RESOURCE_POLICY_CONFIGURATION_ERROR"].includes(code)) return null;
136
+ if (candidate.schema_version !== "agents24.failure.v1") return null;
137
+ const code = typeof candidate.code === "string" && /^[A-Z0-9_]{2,128}$/.test(candidate.code) ? candidate.code : "";
138
+ const category = typeof candidate.category === "string" && FAILURE_CATEGORIES.has(candidate.category) ? candidate.category : "";
139
+ if (!code || !category) return null;
107
140
  const failureId = typeof candidate.failure_id === "string" && candidate.failure_id.trim() ? candidate.failure_id : "";
108
141
  if (!failureId) return null;
109
- const message = typeof candidate.message === "string" && candidate.message.trim() ? candidate.message.trim() : "The resource policy prevented this request.";
110
- const allowedViolationKeys = /* @__PURE__ */ new Set([
111
- "policy_subject_type",
112
- "rule_type",
113
- "aggregation_scope",
114
- "resource_type",
115
- "resource_name",
116
- "quota_unit",
117
- "quota_window",
118
- "limit",
119
- "remaining",
120
- "resets_at"
121
- ]);
142
+ const message = typeof candidate.message === "string" && candidate.message.trim() && candidate.message.length <= 1e3 ? candidate.message.trim() : "The Agent request failed.";
122
143
  const candidateDetails = candidate.details && typeof candidate.details === "object" ? candidate.details : candidate;
123
144
  const violations = Array.isArray(candidateDetails.violations) ? candidateDetails.violations.flatMap((item) => {
124
145
  if (!item || typeof item !== "object" || Array.isArray(item)) return [];
125
146
  return [Object.fromEntries(
126
- Object.entries(item).filter(([key, value]) => allowedViolationKeys.has(key) && ["string", "number"].includes(typeof value))
147
+ Object.entries(item).filter(([key, value]) => SAFE_VIOLATION_KEYS.has(key) && ["string", "number", "boolean"].includes(typeof value))
127
148
  )];
128
149
  }).filter((item) => Object.keys(item).length > 0).slice(0, 20) : void 0;
129
150
  return {
130
151
  failureId,
131
152
  code,
132
- category: code === "RESOURCE_POLICY_QUOTA_EXCEEDED" ? "quota" : "policy",
153
+ category,
133
154
  message,
134
155
  requestId: typeof candidate.request_id === "string" ? candidate.request_id : null,
135
156
  retryable: candidate.retryable === true,
@@ -137,7 +158,8 @@ function safeResourcePolicyError(details) {
137
158
  ...violations?.length ? { violations } : {}
138
159
  };
139
160
  }
140
- function resourcePolicyFailureResponse(status, failure) {
161
+ function upstreamFailureResponse(status, failure) {
162
+ const candidateDetails = failure.violations?.length ? { violations: failure.violations } : {};
141
163
  return Response.json({
142
164
  schema_version: "agents24.failure.v1",
143
165
  failure_id: failure.failureId,
@@ -147,7 +169,7 @@ function resourcePolicyFailureResponse(status, failure) {
147
169
  retryable: failure.retryable,
148
170
  request_id: failure.requestId,
149
171
  retry_after_ms: failure.retryAfterMs,
150
- details: failure.violations?.length ? { violations: failure.violations } : {}
172
+ details: candidateDetails
151
173
  }, {
152
174
  status,
153
175
  headers: { "Cache-Control": "no-store", "Content-Type": "application/json; charset=utf-8" }
@@ -158,13 +180,41 @@ function errorResponse(error) {
158
180
  if (isSdkError) {
159
181
  const sdkError = error;
160
182
  const status = sdkError.status && sdkError.status >= 400 && sdkError.status <= 599 ? sdkError.status : 502;
161
- const policyError = safeResourcePolicyError(sdkError.failure);
162
- if (policyError) return resourcePolicyFailureResponse(status, policyError);
183
+ const upstreamFailure = safeFailure(sdkError.failure);
184
+ if (upstreamFailure) return upstreamFailureResponse(status, upstreamFailure);
163
185
  return publicError(status, `UPSTREAM_${status}`, "The Agent request failed.", status >= 500);
164
186
  }
165
187
  return publicError(500, "BFF_REQUEST_FAILED", "The Agent request could not be completed.", true);
166
188
  }
167
189
 
190
+ // src/bff-diagnostics.ts
191
+ function emitDiagnostic(callback, diagnostic) {
192
+ void Promise.resolve(callback(diagnostic)).catch(() => void 0);
193
+ }
194
+ function reportFailureResponse(callback, request, operation, response) {
195
+ if (!callback || response.status < 400) return response;
196
+ void response.clone().json().then((payload) => {
197
+ const row = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
198
+ const clean2 = (value, pattern) => typeof value === "string" && pattern.test(value) ? value : void 0;
199
+ emitDiagnostic(callback, {
200
+ operation,
201
+ method: request.method,
202
+ path: new URL(request.url).pathname,
203
+ status: response.status,
204
+ ...clean2(row.failure_id, /^[A-Za-z0-9_-]{1,128}$/) ? { failureId: String(row.failure_id) } : {},
205
+ ...clean2(row.request_id, /^[A-Za-z0-9_.:-]{1,128}$/) ? { requestId: String(row.request_id) } : {},
206
+ ...clean2(row.code, /^[A-Z0-9_]{2,128}$/) ? { code: String(row.code) } : {},
207
+ ...clean2(row.category, /^[a-z_]{2,64}$/) ? { category: String(row.category) } : {}
208
+ });
209
+ }).catch(() => emitDiagnostic(callback, {
210
+ operation,
211
+ method: request.method,
212
+ path: new URL(request.url).pathname,
213
+ status: response.status
214
+ }));
215
+ return response;
216
+ }
217
+
168
218
  // src/bff.ts
169
219
  var JSON_LIMIT_BYTES = 1048576;
170
220
  var MAX_INPUT_LENGTH = 2e5;
@@ -289,7 +339,7 @@ function sseHeaders(headers) {
289
339
  result.set("X-Accel-Buffering", "no");
290
340
  return result;
291
341
  }
292
- function sseResponse(execute, headers, failurePayload) {
342
+ function sseResponse(execute, headers, failurePayload, onFailure) {
293
343
  const stream = new TransformStream();
294
344
  const writer = stream.writable.getWriter();
295
345
  const encoder = new TextEncoder();
@@ -297,6 +347,7 @@ function sseResponse(execute, headers, failurePayload) {
297
347
 
298
348
  `));
299
349
  void execute(write).catch(async (error) => {
350
+ onFailure?.(error);
300
351
  if (failurePayload) {
301
352
  await write(failurePayload(error)).catch(() => void 0);
302
353
  return;
@@ -344,6 +395,9 @@ function createAgents24BffHandlerWithResolver(options, resolveCustomerIdentity)
344
395
  if (runtimeTarget === "draft" && agentVersionId) throw new Error("agentVersionId cannot be used with draft runtimeTarget.");
345
396
  const basePath = normalizeBasePath(options.basePath);
346
397
  const embed = options.client.embed;
398
+ const streamFailure = (request, operation) => (error) => {
399
+ reportFailureResponse(options.onDiagnostic, request, operation, errorResponse(error));
400
+ };
347
401
  return async (request) => {
348
402
  const url = new URL(request.url);
349
403
  if (url.pathname !== basePath && !url.pathname.startsWith(`${basePath}/`)) {
@@ -412,7 +466,7 @@ function createAgents24BffHandlerWithResolver(options, resolveCustomerIdentity)
412
466
  metadata: objectValue(body.metadata),
413
467
  client: objectValue(body.client)
414
468
  }, (event) => write(event), { idempotencyKey, signal: request.signal });
415
- });
469
+ }, void 0, void 0, streamFailure(request, "chat.stream"));
416
470
  } else if (request.method === "POST" && /^\/runs\/[^/]+\/attach$/.test(path)) {
417
471
  const runId = routeId(path, /^\/runs\/([^/]+)\/attach$/, "runId");
418
472
  const body = await requestJson(request);
@@ -430,7 +484,7 @@ function createAgents24BffHandlerWithResolver(options, resolveCustomerIdentity)
430
484
  idempotencyKey,
431
485
  signal: request.signal
432
486
  });
433
- });
487
+ }, void 0, void 0, streamFailure(request, "run.attach"));
434
488
  } else if (request.method === "POST" && /^\/runs\/[^/]+\/cancel$/.test(path)) {
435
489
  const runId = routeId(path, /^\/runs\/([^/]+)\/cancel$/, "runId");
436
490
  response = json(await embed.cancelAgentRun(agentId, runId, {
@@ -492,7 +546,7 @@ function createAgents24BffHandlerWithResolver(options, resolveCustomerIdentity)
492
546
  event: "snapshot_required",
493
547
  cursor,
494
548
  reason: "stream_failed"
495
- }));
549
+ }), streamFailure(request, "threads.events"));
496
550
  } else if (/^\/threads\/[^/]+$/.test(path) && request.method === "GET") {
497
551
  const threadId = routeId(path, /^\/threads\/([^/]+)$/, "threadId");
498
552
  const rawBefore = url.searchParams.get("before_turn_index");
@@ -589,9 +643,9 @@ function createAgents24BffHandlerWithResolver(options, resolveCustomerIdentity)
589
643
  return mergeHeaders(response, resolution.responseHeaders);
590
644
  } catch (error) {
591
645
  if (error instanceof BffInputError) {
592
- return mergeHeaders(publicError(error.status, error.code, error.message), resolution.responseHeaders);
646
+ return mergeHeaders(reportFailureResponse(options.onDiagnostic, request, "request", publicError(error.status, error.code, error.message)), resolution.responseHeaders);
593
647
  }
594
- return mergeHeaders(errorResponse(error), resolution.responseHeaders);
648
+ return mergeHeaders(reportFailureResponse(options.onDiagnostic, request, "request", errorResponse(error)), resolution.responseHeaders);
595
649
  }
596
650
  };
597
651
  }
@@ -625,7 +679,8 @@ function createResolvedAgents24BffHandler(options) {
625
679
  integrationName: options.integrationName,
626
680
  basePath: `${basePath}/agents/${encodeURIComponent(agent.agentId)}`,
627
681
  resolvePrincipal: options.resolvePrincipal,
628
- revokePrincipal: options.revokePrincipal
682
+ revokePrincipal: options.revokePrincipal,
683
+ onDiagnostic: options.onDiagnostic
629
684
  }, resolveCustomerIdentity)
630
685
  ]));
631
686
  const agentBySelector = /* @__PURE__ */ new Map();
@@ -748,7 +803,7 @@ function createResolvedAgents24BffHandler(options) {
748
803
  metadata: objectValue(body.metadata),
749
804
  client: objectValue(body.client)
750
805
  }, (event) => write(event), { idempotencyKey: stringValue(request.headers.get("idempotency-key")), signal: request.signal });
751
- }), resolution.responseHeaders);
806
+ }, void 0, void 0, (error) => reportFailureResponse(options.onDiagnostic, request, "chat.stream", errorResponse(error))), resolution.responseHeaders);
752
807
  }
753
808
  if (request.method === "GET" && path === "/threads") {
754
809
  const skip = Number(url.searchParams.get("skip") || 0);
@@ -787,7 +842,7 @@ function createResolvedAgents24BffHandler(options) {
787
842
  event: "snapshot_required",
788
843
  cursor,
789
844
  reason: "stream_failed"
790
- })), resolution.responseHeaders);
845
+ }), (error) => reportFailureResponse(options.onDiagnostic, request, "threads.events", errorResponse(error))), resolution.responseHeaders);
791
846
  }
792
847
  if (/^\/threads\/[^/]+$/.test(path) && request.method === "GET") {
793
848
  const threadId = routeId(path, /^\/threads\/([^/]+)$/, "threadId");
@@ -862,8 +917,8 @@ function createResolvedAgents24BffHandler(options) {
862
917
  }
863
918
  return mergeHeaders(publicError(404, "NOT_FOUND", "The requested BFF route does not exist."), resolution.responseHeaders);
864
919
  } catch (error) {
865
- if (error instanceof BffInputError) return mergeHeaders(publicError(error.status, error.code, error.message), resolution.responseHeaders);
866
- return mergeHeaders(errorResponse(error), resolution.responseHeaders);
920
+ if (error instanceof BffInputError) return mergeHeaders(reportFailureResponse(options.onDiagnostic, request, "request", publicError(error.status, error.code, error.message)), resolution.responseHeaders);
921
+ return mergeHeaders(reportFailureResponse(options.onDiagnostic, request, "request", errorResponse(error)), resolution.responseHeaders);
867
922
  }
868
923
  };
869
924
  }
@@ -883,7 +938,7 @@ function createAgents24BffHandler(options) {
883
938
  return (await resolvedHandler)(request);
884
939
  } catch (error) {
885
940
  resolvedHandler = void 0;
886
- return errorResponse(error);
941
+ return reportFailureResponse(options.onDiagnostic, request, "agent.resolve", errorResponse(error));
887
942
  }
888
943
  };
889
944
  }