@assemble-dev/providers 0.1.0 → 0.3.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.
package/dist/index.js CHANGED
@@ -28,12 +28,16 @@ var ModelToolCallSchema = z.object({
28
28
  toolName: z.string(),
29
29
  input: JsonValueSchema
30
30
  });
31
+ var ChatMessageCacheControlSchema = z.object({
32
+ ttl: z.enum(["5m", "1h"]).optional()
33
+ });
31
34
  var ChatMessageSchema = z.object({
32
35
  role: ChatMessageRoleSchema,
33
36
  content: z.union([z.string(), z.array(MessageContentBlockSchema)]),
34
37
  toolName: z.string().optional(),
35
38
  toolCallId: z.string().optional(),
36
- toolCalls: z.array(ModelToolCallSchema).optional()
39
+ toolCalls: z.array(ModelToolCallSchema).optional(),
40
+ cacheControl: ChatMessageCacheControlSchema.optional()
37
41
  });
38
42
  var ChatStopReasonSchema = z.enum([
39
43
  "end_turn",
@@ -49,14 +53,222 @@ function extractMessageText(message) {
49
53
  }
50
54
 
51
55
  // src/openai-adapter.ts
52
- import { z as z3 } from "zod";
53
- import { AppErrorCode as AppErrorCode7 } from "@assemble-dev/shared-types/errors";
56
+ import { z as z4 } from "zod";
57
+ import { AppErrorCode as AppErrorCode8 } from "@assemble-dev/shared-types/errors";
54
58
  import { JsonValueSchema as JsonValueSchema3 } from "@assemble-dev/shared-types/json";
55
- import { AppError as AppError8 } from "@assemble-dev/shared-utils/errors";
59
+ import { AppError as AppError9 } from "@assemble-dev/shared-utils/errors";
56
60
 
57
61
  // src/openai-request-mapping.ts
62
+ import { AppErrorCode as AppErrorCode2 } from "@assemble-dev/shared-types/errors";
63
+ import { AppError as AppError2 } from "@assemble-dev/shared-utils/errors";
64
+
65
+ // src/structured-output-json-schema.ts
66
+ import { z as z2 } from "zod";
58
67
  import { AppErrorCode } from "@assemble-dev/shared-types/errors";
68
+ import { JsonObjectSchema } from "@assemble-dev/shared-types/json";
59
69
  import { AppError } from "@assemble-dev/shared-utils/errors";
70
+
71
+ // src/json-schema-tree.ts
72
+ var schemaMapKeywords = ["properties", "$defs"];
73
+ var schemaListKeywords = ["anyOf", "oneOf", "allOf", "prefixItems"];
74
+ var schemaValueKeywords = [
75
+ "items",
76
+ "additionalProperties",
77
+ "not",
78
+ "if",
79
+ "then",
80
+ "else",
81
+ "contains",
82
+ "propertyNames"
83
+ ];
84
+ function isJsonObject(value) {
85
+ return typeof value === "object" && value !== null && !Array.isArray(value);
86
+ }
87
+ function transformJsonSchemaNode(node, transformNode) {
88
+ const result = { ...transformNode({ ...node }) };
89
+ for (const keyword of schemaMapKeywords) {
90
+ const mapValue = result[keyword];
91
+ if (mapValue !== void 0 && isJsonObject(mapValue)) {
92
+ result[keyword] = transformJsonSchemaMap(mapValue, transformNode);
93
+ }
94
+ }
95
+ for (const keyword of schemaListKeywords) {
96
+ const listValue = result[keyword];
97
+ if (Array.isArray(listValue)) {
98
+ result[keyword] = listValue.map(
99
+ (entry) => isJsonObject(entry) ? transformJsonSchemaNode(entry, transformNode) : entry
100
+ );
101
+ }
102
+ }
103
+ for (const keyword of schemaValueKeywords) {
104
+ const schemaValue = result[keyword];
105
+ if (schemaValue !== void 0 && isJsonObject(schemaValue)) {
106
+ result[keyword] = transformJsonSchemaNode(schemaValue, transformNode);
107
+ }
108
+ }
109
+ return result;
110
+ }
111
+ function transformJsonSchemaMap(schemaMap, transformNode) {
112
+ const result = {};
113
+ for (const [schemaName, schemaValue] of Object.entries(schemaMap)) {
114
+ result[schemaName] = isJsonObject(schemaValue) ? transformJsonSchemaNode(schemaValue, transformNode) : schemaValue;
115
+ }
116
+ return result;
117
+ }
118
+ function inlineJsonSchemaReferences(root) {
119
+ const rootDefinitions = root["$defs"];
120
+ const definitions = rootDefinitions !== void 0 && isJsonObject(rootDefinitions) ? rootDefinitions : {};
121
+ const resolvedRoot = resolveJsonSchemaReferences(
122
+ root,
123
+ definitions,
124
+ /* @__PURE__ */ new Set()
125
+ );
126
+ return isJsonObject(resolvedRoot) ? resolvedRoot : {};
127
+ }
128
+ function resolveJsonSchemaReferences(value, definitions, activeReferences) {
129
+ if (Array.isArray(value)) {
130
+ return value.map(
131
+ (entry) => resolveJsonSchemaReferences(entry, definitions, activeReferences)
132
+ );
133
+ }
134
+ if (!isJsonObject(value)) {
135
+ return value;
136
+ }
137
+ const referenceTarget = value["$ref"];
138
+ if (typeof referenceTarget === "string") {
139
+ return resolveJsonSchemaReferenceTarget(
140
+ referenceTarget,
141
+ definitions,
142
+ activeReferences
143
+ );
144
+ }
145
+ const result = {};
146
+ for (const [key, entryValue] of Object.entries(value)) {
147
+ if (key !== "$defs") {
148
+ result[key] = resolveJsonSchemaReferences(
149
+ entryValue,
150
+ definitions,
151
+ activeReferences
152
+ );
153
+ }
154
+ }
155
+ return result;
156
+ }
157
+ function resolveJsonSchemaReferenceTarget(referenceTarget, definitions, activeReferences) {
158
+ if (activeReferences.has(referenceTarget)) {
159
+ return {};
160
+ }
161
+ const definitionsPrefix = "#/$defs/";
162
+ if (!referenceTarget.startsWith(definitionsPrefix)) {
163
+ return {};
164
+ }
165
+ const definition = definitions[referenceTarget.slice(definitionsPrefix.length)];
166
+ if (definition === void 0 || !isJsonObject(definition)) {
167
+ return {};
168
+ }
169
+ return resolveJsonSchemaReferences(
170
+ definition,
171
+ definitions,
172
+ /* @__PURE__ */ new Set([...activeReferences, referenceTarget])
173
+ );
174
+ }
175
+ function removeJsonSchemaKeywords(node, keywords) {
176
+ const result = {};
177
+ for (const [key, value] of Object.entries(node)) {
178
+ if (!keywords.includes(key)) {
179
+ result[key] = value;
180
+ }
181
+ }
182
+ return result;
183
+ }
184
+
185
+ // src/structured-output-json-schema.ts
186
+ var openAiStructuredOutputSchemaName = "structured_output";
187
+ var schemaMetadataKeywords = ["$schema", "$id"];
188
+ var anthropicUnsupportedSchemaKeywords = [
189
+ ...schemaMetadataKeywords,
190
+ "minimum",
191
+ "maximum",
192
+ "exclusiveMinimum",
193
+ "exclusiveMaximum",
194
+ "minLength",
195
+ "maxLength",
196
+ "multipleOf"
197
+ ];
198
+ var openAiUnsupportedSchemaKeywords = [
199
+ ...anthropicUnsupportedSchemaKeywords,
200
+ "pattern",
201
+ "format",
202
+ "minItems",
203
+ "maxItems",
204
+ "uniqueItems",
205
+ "default"
206
+ ];
207
+ function convertZodSchemaToJsonSchema(schema) {
208
+ try {
209
+ return JsonObjectSchema.parse(z2.toJSONSchema(schema, { io: "input" }));
210
+ } catch (error) {
211
+ throw new AppError({
212
+ code: AppErrorCode.BadRequest,
213
+ message: "Structured output schema could not be converted to JSON Schema",
214
+ statusCode: 400,
215
+ cause: error instanceof Error ? error : void 0
216
+ });
217
+ }
218
+ }
219
+ function buildAnthropicStructuredOutputJsonSchema(schema) {
220
+ return sanitizeJsonSchemaForAnthropicStructuredOutput(
221
+ convertZodSchemaToJsonSchema(schema)
222
+ );
223
+ }
224
+ function sanitizeJsonSchemaForAnthropicStructuredOutput(jsonSchema) {
225
+ return transformJsonSchemaNode(
226
+ inlineJsonSchemaReferences(jsonSchema),
227
+ sanitizeAnthropicSchemaNode
228
+ );
229
+ }
230
+ function buildOpenAiStructuredOutputJsonSchema(schema) {
231
+ return sanitizeJsonSchemaForOpenAiStructuredOutput(
232
+ convertZodSchemaToJsonSchema(schema)
233
+ );
234
+ }
235
+ function sanitizeJsonSchemaForOpenAiStructuredOutput(jsonSchema) {
236
+ return transformJsonSchemaNode(jsonSchema, sanitizeOpenAiSchemaNode);
237
+ }
238
+ function sanitizeAnthropicSchemaNode(node) {
239
+ const sanitized = removeJsonSchemaKeywords(
240
+ node,
241
+ anthropicUnsupportedSchemaKeywords
242
+ );
243
+ if (sanitized["type"] === "object") {
244
+ sanitized["additionalProperties"] = false;
245
+ }
246
+ return sanitized;
247
+ }
248
+ function sanitizeOpenAiSchemaNode(node) {
249
+ const sanitized = removeJsonSchemaKeywords(
250
+ node,
251
+ openAiUnsupportedSchemaKeywords
252
+ );
253
+ if (sanitized["type"] !== "object") {
254
+ return sanitized;
255
+ }
256
+ sanitized["additionalProperties"] = false;
257
+ const propertyNames = listSchemaPropertyNames(sanitized);
258
+ if (propertyNames.length > 0) {
259
+ sanitized["required"] = propertyNames;
260
+ }
261
+ return sanitized;
262
+ }
263
+ function listSchemaPropertyNames(node) {
264
+ const properties = node["properties"];
265
+ if (properties === void 0 || !isJsonObject(properties)) {
266
+ return [];
267
+ }
268
+ return Object.keys(properties);
269
+ }
270
+
271
+ // src/openai-request-mapping.ts
60
272
  function buildOpenAiRequestBody(model, input) {
61
273
  const requestBody = {
62
274
  model,
@@ -68,7 +280,16 @@ function buildOpenAiRequestBody(model, input) {
68
280
  if (input.maxOutputTokens !== void 0) {
69
281
  requestBody.max_tokens = input.maxOutputTokens;
70
282
  }
71
- if (input.requireJsonObjectResponse) {
283
+ if (input.structuredOutputJsonSchema !== void 0) {
284
+ requestBody.response_format = {
285
+ type: "json_schema",
286
+ json_schema: {
287
+ name: openAiStructuredOutputSchemaName,
288
+ strict: true,
289
+ schema: input.structuredOutputJsonSchema
290
+ }
291
+ };
292
+ } else if (input.requireJsonObjectResponse === true) {
72
293
  requestBody.response_format = { type: "json_object" };
73
294
  }
74
295
  if (input.tools !== void 0 && input.tools.length > 0) {
@@ -154,17 +375,17 @@ function mapMessageContentBlockToOpenAiContentPart(contentBlock) {
154
375
  }
155
376
  };
156
377
  }
157
- throw new AppError({
158
- code: AppErrorCode.ValidationFailed,
378
+ throw new AppError2({
379
+ code: AppErrorCode2.ValidationFailed,
159
380
  message: "OpenAI adapter does not support document content blocks in chat messages",
160
381
  statusCode: 400
161
382
  });
162
383
  }
163
384
 
164
385
  // src/parse-structured-json.ts
165
- import { AppErrorCode as AppErrorCode2 } from "@assemble-dev/shared-types/errors";
386
+ import { AppErrorCode as AppErrorCode3 } from "@assemble-dev/shared-types/errors";
166
387
  import { JsonValueSchema as JsonValueSchema2 } from "@assemble-dev/shared-types/json";
167
- import { AppError as AppError2 } from "@assemble-dev/shared-utils/errors";
388
+ import { AppError as AppError3 } from "@assemble-dev/shared-utils/errors";
168
389
  var markdownCodeFencePattern = /^```[A-Za-z]*\s*\n?([\s\S]*?)\n?```$/;
169
390
  function parseStructuredJsonText(text, schema) {
170
391
  return schema.parse(parseJsonText(stripMarkdownCodeFences(text)));
@@ -181,8 +402,8 @@ function parseJsonText(text) {
181
402
  try {
182
403
  return JsonValueSchema2.parse(JSON.parse(text));
183
404
  } catch (error) {
184
- throw new AppError2({
185
- code: AppErrorCode2.ValidationFailed,
405
+ throw new AppError3({
406
+ code: AppErrorCode3.ValidationFailed,
186
407
  message: "Structured output was not valid JSON",
187
408
  statusCode: 422,
188
409
  cause: error instanceof Error ? error : void 0
@@ -191,9 +412,9 @@ function parseJsonText(text) {
191
412
  }
192
413
 
193
414
  // src/provider-api-key.ts
194
- import { z as z2 } from "zod";
195
- import { AppErrorCode as AppErrorCode3 } from "@assemble-dev/shared-types/errors";
196
- import { AppError as AppError3 } from "@assemble-dev/shared-utils/errors";
415
+ import { z as z3 } from "zod";
416
+ import { AppErrorCode as AppErrorCode4 } from "@assemble-dev/shared-types/errors";
417
+ import { AppError as AppError4 } from "@assemble-dev/shared-utils/errors";
197
418
  import {
198
419
  buildNamedApiKeyEnvVarName,
199
420
  expectedProviderApiKeyNameFormat,
@@ -210,8 +431,8 @@ function resolveProviderApiKey(input) {
210
431
  }
211
432
  function resolveNamedProviderApiKeyFromEnv(input, apiKeyName) {
212
433
  if (!validateProviderApiKeyName(apiKeyName)) {
213
- throw new AppError3({
214
- code: AppErrorCode3.BadRequest,
434
+ throw new AppError4({
435
+ code: AppErrorCode4.BadRequest,
215
436
  message: `Invalid ${input.providerLabel} apiKeyName "${apiKeyName}". Expected ${expectedProviderApiKeyNameFormat}.`,
216
437
  statusCode: 400
217
438
  });
@@ -219,8 +440,8 @@ function resolveNamedProviderApiKeyFromEnv(input, apiKeyName) {
219
440
  const envVarName = buildNamedApiKeyEnvVarName(input.baseEnvVarName, apiKeyName);
220
441
  const envApiKey = readEnvironmentVariable(envVarName);
221
442
  if (envApiKey === void 0 || envApiKey.length === 0) {
222
- throw new AppError3({
223
- code: AppErrorCode3.Unauthorized,
443
+ throw new AppError4({
444
+ code: AppErrorCode4.Unauthorized,
224
445
  message: `${input.providerLabel} API key named "${apiKeyName}" is missing. Set the ${envVarName} environment variable or pass apiKey to ${input.adapterFunctionName}.`,
225
446
  statusCode: 401
226
447
  });
@@ -230,8 +451,8 @@ function resolveNamedProviderApiKeyFromEnv(input, apiKeyName) {
230
451
  function resolveBaseProviderApiKeyFromEnv(input) {
231
452
  const envApiKey = readEnvironmentVariable(input.baseEnvVarName);
232
453
  if (envApiKey === void 0 || envApiKey.length === 0) {
233
- throw new AppError3({
234
- code: AppErrorCode3.Unauthorized,
454
+ throw new AppError4({
455
+ code: AppErrorCode4.Unauthorized,
235
456
  message: `${input.providerLabel} API key is missing. Pass apiKey to ${input.adapterFunctionName} or set the ${input.baseEnvVarName} environment variable.`,
236
457
  statusCode: 401
237
458
  });
@@ -239,19 +460,19 @@ function resolveBaseProviderApiKeyFromEnv(input) {
239
460
  return envApiKey;
240
461
  }
241
462
  function readEnvironmentVariable(envVarName) {
242
- const parsedEnv = z2.object({ [envVarName]: z2.string().optional() }).parse(process.env);
463
+ const parsedEnv = z3.object({ [envVarName]: z3.string().optional() }).parse(process.env);
243
464
  return parsedEnv[envVarName];
244
465
  }
245
466
 
246
467
  // src/provider-cancellation.ts
247
- import { AppErrorCode as AppErrorCode4 } from "@assemble-dev/shared-types/errors";
248
- import { AppError as AppError4 } from "@assemble-dev/shared-utils/errors";
468
+ import { AppErrorCode as AppErrorCode5 } from "@assemble-dev/shared-types/errors";
469
+ import { AppError as AppError5 } from "@assemble-dev/shared-utils/errors";
249
470
  function isAbortError(error) {
250
471
  return error.name === "AbortError";
251
472
  }
252
473
  function buildProviderCanceledError(providerLabel) {
253
- return new AppError4({
254
- code: AppErrorCode4.Canceled,
474
+ return new AppError5({
475
+ code: AppErrorCode5.Canceled,
255
476
  message: `${providerLabel} request was canceled`,
256
477
  statusCode: 499
257
478
  });
@@ -267,19 +488,28 @@ async function executeAbortableProviderFetch(providerLabel, performFetch) {
267
488
  }
268
489
  }
269
490
 
491
+ // src/provider-extra-body.ts
492
+ function mergeProviderRequestExtraBody(requestBody, adapterExtraBody, requestExtraBody) {
493
+ return {
494
+ ...requestBody,
495
+ ...adapterExtraBody ?? {},
496
+ ...requestExtraBody ?? {}
497
+ };
498
+ }
499
+
270
500
  // src/provider-fallback.ts
271
- import { AppError as AppError6 } from "@assemble-dev/shared-utils/errors";
501
+ import { AppError as AppError7 } from "@assemble-dev/shared-utils/errors";
272
502
 
273
503
  // src/provider-retry.ts
274
- import { AppErrorCode as AppErrorCode5 } from "@assemble-dev/shared-types/errors";
275
- import { AppError as AppError5 } from "@assemble-dev/shared-utils/errors";
504
+ import { AppErrorCode as AppErrorCode6 } from "@assemble-dev/shared-types/errors";
505
+ import { AppError as AppError6 } from "@assemble-dev/shared-utils/errors";
276
506
  var defaultProviderRetryMaxAttempts = 3;
277
507
  var defaultProviderRetryInitialDelayMs = 500;
278
508
  var defaultProviderRetryMaxDelayMs = 8e3;
279
509
  var retryableAppErrorCodes = /* @__PURE__ */ new Set([
280
- AppErrorCode5.RateLimited,
281
- AppErrorCode5.ServiceUnavailable,
282
- AppErrorCode5.InternalServerError
510
+ AppErrorCode6.RateLimited,
511
+ AppErrorCode6.ServiceUnavailable,
512
+ AppErrorCode6.InternalServerError
283
513
  ]);
284
514
  function isRetryableProviderAppError(appError) {
285
515
  return retryableAppErrorCodes.has(appError.code);
@@ -294,7 +524,7 @@ async function executeProviderCallWithRetry(retryOptions, executeCall, waitFor)
294
524
  try {
295
525
  return await executeCall();
296
526
  } catch (error) {
297
- if (error instanceof AppError5 && !isRetryableProviderAppError(error)) {
527
+ if (error instanceof AppError6 && !isRetryableProviderAppError(error)) {
298
528
  throw error;
299
529
  }
300
530
  if (error instanceof Error && isAbortError(error)) {
@@ -328,7 +558,7 @@ async function executeProviderCallWithModelFallback(fallbackModel, executePrimar
328
558
  if (fallbackModel === void 0) {
329
559
  throw error;
330
560
  }
331
- if (error instanceof AppError6 && !isRetryableProviderAppError(error)) {
561
+ if (error instanceof AppError7 && !isRetryableProviderAppError(error)) {
332
562
  throw error;
333
563
  }
334
564
  if (error instanceof Error && isAbortError(error)) {
@@ -339,11 +569,11 @@ async function executeProviderCallWithModelFallback(fallbackModel, executePrimar
339
569
  }
340
570
 
341
571
  // src/provider-status-error.ts
342
- import { AppErrorCode as AppErrorCode6 } from "@assemble-dev/shared-types/errors";
343
- import { AppError as AppError7 } from "@assemble-dev/shared-utils/errors";
572
+ import { AppErrorCode as AppErrorCode7 } from "@assemble-dev/shared-types/errors";
573
+ import { AppError as AppError8 } from "@assemble-dev/shared-utils/errors";
344
574
  function buildProviderStatusError(providerLabel, providerStatus) {
345
575
  const code = mapProviderStatusToAppErrorCode(providerStatus);
346
- return new AppError7({
576
+ return new AppError8({
347
577
  code,
348
578
  message: `${providerLabel} request failed with status ${String(providerStatus)}`,
349
579
  statusCode: mapAppErrorCodeToStatusCode(code),
@@ -351,44 +581,44 @@ function buildProviderStatusError(providerLabel, providerStatus) {
351
581
  });
352
582
  }
353
583
  function buildProviderInvalidResponseError(providerLabel, expectedShapeDescription) {
354
- return new AppError7({
355
- code: AppErrorCode6.ValidationFailed,
584
+ return new AppError8({
585
+ code: AppErrorCode7.ValidationFailed,
356
586
  message: `${providerLabel} response did not match the expected ${expectedShapeDescription} shape`,
357
587
  statusCode: 502
358
588
  });
359
589
  }
360
590
  function mapProviderStatusToAppErrorCode(providerStatus) {
361
591
  if (providerStatus === 400) {
362
- return AppErrorCode6.BadRequest;
592
+ return AppErrorCode7.BadRequest;
363
593
  }
364
594
  if (providerStatus === 401) {
365
- return AppErrorCode6.Unauthorized;
595
+ return AppErrorCode7.Unauthorized;
366
596
  }
367
597
  if (providerStatus === 403) {
368
- return AppErrorCode6.Forbidden;
598
+ return AppErrorCode7.Forbidden;
369
599
  }
370
600
  if (providerStatus === 404) {
371
- return AppErrorCode6.NotFound;
601
+ return AppErrorCode7.NotFound;
372
602
  }
373
603
  if (providerStatus === 429) {
374
- return AppErrorCode6.RateLimited;
604
+ return AppErrorCode7.RateLimited;
375
605
  }
376
- return AppErrorCode6.InternalServerError;
606
+ return AppErrorCode7.InternalServerError;
377
607
  }
378
608
  function mapAppErrorCodeToStatusCode(code) {
379
- if (code === AppErrorCode6.BadRequest) {
609
+ if (code === AppErrorCode7.BadRequest) {
380
610
  return 400;
381
611
  }
382
- if (code === AppErrorCode6.Unauthorized) {
612
+ if (code === AppErrorCode7.Unauthorized) {
383
613
  return 401;
384
614
  }
385
- if (code === AppErrorCode6.Forbidden) {
615
+ if (code === AppErrorCode7.Forbidden) {
386
616
  return 403;
387
617
  }
388
- if (code === AppErrorCode6.NotFound) {
618
+ if (code === AppErrorCode7.NotFound) {
389
619
  return 404;
390
620
  }
391
- if (code === AppErrorCode6.RateLimited) {
621
+ if (code === AppErrorCode7.RateLimited) {
392
622
  return 429;
393
623
  }
394
624
  return 500;
@@ -396,33 +626,29 @@ function mapAppErrorCodeToStatusCode(code) {
396
626
 
397
627
  // src/openai-adapter.ts
398
628
  var defaultOpenAiBaseUrl = "https://api.openai.com/v1";
399
- var OpenAiResponseToolCallSchema = z3.object({
400
- id: z3.string(),
401
- function: z3.object({
402
- name: z3.string(),
403
- arguments: z3.string()
629
+ var OpenAiResponseToolCallSchema = z4.object({
630
+ id: z4.string(),
631
+ function: z4.object({
632
+ name: z4.string(),
633
+ arguments: z4.string()
404
634
  })
405
635
  });
406
- var OpenAiChatCompletionResponseSchema = z3.object({
407
- choices: z3.array(
408
- z3.object({
409
- message: z3.object({
410
- content: z3.string().nullable(),
411
- tool_calls: z3.array(OpenAiResponseToolCallSchema).optional()
636
+ var OpenAiChatCompletionResponseSchema = z4.object({
637
+ choices: z4.array(
638
+ z4.object({
639
+ message: z4.object({
640
+ content: z4.string().nullable(),
641
+ tool_calls: z4.array(OpenAiResponseToolCallSchema).optional()
412
642
  }),
413
- finish_reason: z3.string().nullable().optional()
643
+ finish_reason: z4.string().nullable().optional()
414
644
  })
415
645
  ).min(1),
416
- usage: z3.object({
417
- prompt_tokens: z3.number().int().nonnegative(),
418
- completion_tokens: z3.number().int().nonnegative(),
419
- total_tokens: z3.number().int().nonnegative()
646
+ usage: z4.object({
647
+ prompt_tokens: z4.number().int().nonnegative(),
648
+ completion_tokens: z4.number().int().nonnegative(),
649
+ total_tokens: z4.number().int().nonnegative()
420
650
  })
421
651
  });
422
- var structuredOutputSystemMessage = {
423
- role: "system",
424
- content: "Respond with a single JSON object that satisfies the caller's requested structure. Output only valid JSON with no surrounding text."
425
- };
426
652
  function openai(options) {
427
653
  return {
428
654
  name: `openai:${options.model}`,
@@ -431,18 +657,20 @@ function openai(options) {
431
657
  messages: request.messages,
432
658
  temperature: request.temperature ?? options.temperature,
433
659
  maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
434
- requireJsonObjectResponse: false,
435
660
  tools: request.tools,
436
661
  toolChoice: request.toolChoice,
437
- abortSignal: request.abortSignal
662
+ abortSignal: request.abortSignal,
663
+ extraBody: request.extraBody
438
664
  });
439
665
  },
440
666
  async generateStructuredOutput(request) {
441
667
  const completion = await executeOpenAiAdapterCall(options, {
442
- messages: [structuredOutputSystemMessage, ...request.messages],
668
+ messages: request.messages,
443
669
  temperature: request.temperature ?? options.temperature,
444
670
  maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
445
- requireJsonObjectResponse: true,
671
+ structuredOutputJsonSchema: buildOpenAiStructuredOutputJsonSchema(
672
+ request.schema
673
+ ),
446
674
  abortSignal: request.abortSignal
447
675
  });
448
676
  return {
@@ -476,7 +704,11 @@ async function requestOpenAiChatCompletion(options, input) {
476
704
  });
477
705
  const fetchImplementation = options.fetchImplementation ?? fetch;
478
706
  const baseUrl = options.baseURL ?? defaultOpenAiBaseUrl;
479
- const requestBody = buildOpenAiRequestBody(options.model, input);
707
+ const requestBody = mergeProviderRequestExtraBody(
708
+ buildOpenAiRequestBody(options.model, input),
709
+ options.extraBody,
710
+ input.extraBody
711
+ );
480
712
  const startedAt = Date.now();
481
713
  const response = await executeAbortableProviderFetch(
482
714
  "OpenAI",
@@ -533,8 +765,8 @@ function parseOpenAiToolArgumentsJson(argumentsJsonText) {
533
765
  try {
534
766
  return JsonValueSchema3.parse(JSON.parse(argumentsJsonText));
535
767
  } catch (error) {
536
- throw new AppError8({
537
- code: AppErrorCode7.ValidationFailed,
768
+ throw new AppError9({
769
+ code: AppErrorCode8.ValidationFailed,
538
770
  message: "OpenAI tool call arguments were not valid JSON",
539
771
  statusCode: 502,
540
772
  cause: error instanceof Error ? error : void 0
@@ -556,8 +788,8 @@ function extractOpenAiMessageContent(response, allowEmptyContent) {
556
788
  if (allowEmptyContent) {
557
789
  return "";
558
790
  }
559
- throw new AppError8({
560
- code: AppErrorCode7.ValidationFailed,
791
+ throw new AppError9({
792
+ code: AppErrorCode8.ValidationFailed,
561
793
  message: "OpenAI response contained no message content",
562
794
  statusCode: 502
563
795
  });
@@ -572,6 +804,36 @@ function mapOpenAiUsageToTokenUsage(response) {
572
804
  };
573
805
  }
574
806
 
807
+ // src/anthropic-cache-control.ts
808
+ function resolveAnthropicPromptCachingSettings(promptCaching) {
809
+ if (promptCaching === void 0) {
810
+ return { mode: "off" };
811
+ }
812
+ if (typeof promptCaching === "string") {
813
+ return { mode: promptCaching };
814
+ }
815
+ return promptCaching;
816
+ }
817
+ function buildAnthropicCacheControl(ttl) {
818
+ if (ttl === void 0) {
819
+ return { type: "ephemeral" };
820
+ }
821
+ return { type: "ephemeral", ttl };
822
+ }
823
+ function applyCacheControlToLastContentBlock(requestMessage, cacheControl) {
824
+ if (typeof requestMessage.content === "string") {
825
+ if (requestMessage.content.length === 0) {
826
+ return;
827
+ }
828
+ requestMessage.content = [{ type: "text", text: requestMessage.content }];
829
+ }
830
+ const lastContentBlock = requestMessage.content[requestMessage.content.length - 1];
831
+ if (lastContentBlock === void 0) {
832
+ return;
833
+ }
834
+ lastContentBlock.cache_control = cacheControl;
835
+ }
836
+
575
837
  // src/anthropic-request-mapping.ts
576
838
  function buildAnthropicRequestBody(settings, input) {
577
839
  const requestBody = {
@@ -581,6 +843,7 @@ function buildAnthropicRequestBody(settings, input) {
581
843
  };
582
844
  applyAnthropicSystemField(requestBody, settings, input);
583
845
  applyAnthropicToolFields(requestBody, settings, input);
846
+ applyAnthropicMessageCacheBreakpoints(requestBody, settings, input);
584
847
  if (input.temperature !== void 0) {
585
848
  requestBody.temperature = input.temperature;
586
849
  }
@@ -590,21 +853,54 @@ function buildAnthropicRequestBody(settings, input) {
590
853
  budget_tokens: settings.thinking.budgetTokens
591
854
  };
592
855
  }
856
+ if (input.structuredOutputJsonSchema !== void 0) {
857
+ requestBody.output_config = {
858
+ format: { type: "json_schema", schema: input.structuredOutputJsonSchema }
859
+ };
860
+ }
593
861
  return requestBody;
594
862
  }
595
863
  function applyAnthropicSystemField(requestBody, settings, input) {
864
+ const caching = resolveAnthropicPromptCachingSettings(settings.promptCaching);
596
865
  const systemText = joinSystemMessageText(input.messages);
597
866
  if (systemText.length === 0) {
598
867
  return;
599
868
  }
600
- if (settings.promptCaching !== "auto") {
869
+ if (caching.mode === "off") {
601
870
  requestBody.system = systemText;
602
871
  return;
603
872
  }
604
873
  requestBody.system = [
605
- { type: "text", text: systemText, cache_control: { type: "ephemeral" } }
874
+ {
875
+ type: "text",
876
+ text: systemText,
877
+ cache_control: buildAnthropicCacheControl(caching.ttl)
878
+ }
606
879
  ];
607
880
  }
881
+ function applyAnthropicMessageCacheBreakpoints(requestBody, settings, input) {
882
+ const caching = resolveAnthropicPromptCachingSettings(settings.promptCaching);
883
+ const finalRequestMessage = requestBody.messages[requestBody.messages.length - 1];
884
+ if (caching.mode === "messages" && finalRequestMessage !== void 0) {
885
+ applyCacheControlToLastContentBlock(
886
+ finalRequestMessage,
887
+ buildAnthropicCacheControl(caching.ttl)
888
+ );
889
+ }
890
+ const nonSystemMessages = input.messages.filter(
891
+ (message) => message.role !== "system"
892
+ );
893
+ nonSystemMessages.forEach((message, messageIndex) => {
894
+ const requestMessage = requestBody.messages[messageIndex];
895
+ if (message.cacheControl === void 0 || requestMessage === void 0) {
896
+ return;
897
+ }
898
+ applyCacheControlToLastContentBlock(
899
+ requestMessage,
900
+ buildAnthropicCacheControl(message.cacheControl.ttl ?? caching.ttl)
901
+ );
902
+ });
903
+ }
608
904
  function applyAnthropicToolFields(requestBody, settings, input) {
609
905
  if (input.tools !== void 0 && input.tools.length > 0) {
610
906
  requestBody.tools = mapModelToolDefinitionsToAnthropicTools(
@@ -619,14 +915,15 @@ function applyAnthropicToolFields(requestBody, settings, input) {
619
915
  }
620
916
  }
621
917
  function mapModelToolDefinitionsToAnthropicTools(tools, promptCaching) {
918
+ const caching = resolveAnthropicPromptCachingSettings(promptCaching);
622
919
  return tools.map((tool, toolIndex) => {
623
920
  const anthropicTool = {
624
921
  name: tool.name,
625
922
  description: tool.description,
626
923
  input_schema: tool.inputJsonSchema
627
924
  };
628
- if (promptCaching === "auto" && toolIndex === tools.length - 1) {
629
- anthropicTool.cache_control = { type: "ephemeral" };
925
+ if (caching.mode !== "off" && toolIndex === tools.length - 1) {
926
+ anthropicTool.cache_control = buildAnthropicCacheControl(caching.ttl);
630
927
  }
631
928
  return anthropicTool;
632
929
  });
@@ -717,44 +1014,45 @@ function mapMessageContentBlockToAnthropic(contentBlock) {
717
1014
  }
718
1015
 
719
1016
  // src/anthropic-response-parsing.ts
720
- import { z as z4 } from "zod";
721
- import { AppErrorCode as AppErrorCode8 } from "@assemble-dev/shared-types/errors";
1017
+ import { z as z5 } from "zod";
1018
+ import { AppErrorCode as AppErrorCode9 } from "@assemble-dev/shared-types/errors";
722
1019
  import { JsonValueSchema as JsonValueSchema4 } from "@assemble-dev/shared-types/json";
723
- import { AppError as AppError9 } from "@assemble-dev/shared-utils/errors";
724
- var AnthropicUsageSchema = z4.object({
725
- input_tokens: z4.number().int().nonnegative(),
726
- output_tokens: z4.number().int().nonnegative(),
727
- cache_creation_input_tokens: z4.number().int().nonnegative().optional(),
728
- cache_read_input_tokens: z4.number().int().nonnegative().optional()
1020
+ import { AppError as AppError10 } from "@assemble-dev/shared-utils/errors";
1021
+ var AnthropicUsageSchema = z5.object({
1022
+ input_tokens: z5.number().int().nonnegative(),
1023
+ output_tokens: z5.number().int().nonnegative(),
1024
+ cache_creation_input_tokens: z5.number().int().nonnegative().optional(),
1025
+ cache_read_input_tokens: z5.number().int().nonnegative().optional()
729
1026
  });
730
- var AnthropicContentBlockSchema = z4.discriminatedUnion("type", [
731
- z4.object({
732
- type: z4.literal("text"),
733
- text: z4.string()
1027
+ var AnthropicContentBlockSchema = z5.discriminatedUnion("type", [
1028
+ z5.object({
1029
+ type: z5.literal("text"),
1030
+ text: z5.string()
734
1031
  }),
735
- z4.object({
736
- type: z4.literal("tool_use"),
737
- id: z4.string(),
738
- name: z4.string(),
1032
+ z5.object({
1033
+ type: z5.literal("tool_use"),
1034
+ id: z5.string(),
1035
+ name: z5.string(),
739
1036
  input: JsonValueSchema4
740
1037
  }),
741
- z4.object({
742
- type: z4.literal("thinking"),
743
- thinking: z4.string().optional(),
744
- signature: z4.string().optional()
1038
+ z5.object({
1039
+ type: z5.literal("thinking"),
1040
+ thinking: z5.string().optional(),
1041
+ signature: z5.string().optional()
745
1042
  }),
746
- z4.object({
747
- type: z4.literal("redacted_thinking"),
748
- data: z4.string().optional()
1043
+ z5.object({
1044
+ type: z5.literal("redacted_thinking"),
1045
+ data: z5.string().optional()
749
1046
  })
750
1047
  ]);
751
- var AnthropicMessagesResponseSchema = z4.object({
752
- content: z4.array(AnthropicContentBlockSchema),
753
- stop_reason: z4.string().nullable().optional(),
1048
+ var AnthropicMessagesResponseSchema = z5.object({
1049
+ content: z5.array(AnthropicContentBlockSchema),
1050
+ stop_reason: z5.string().nullable().optional(),
754
1051
  usage: AnthropicUsageSchema
755
1052
  });
756
1053
  function mapAnthropicResponseToChatCompletionResult(response, latencyMs) {
757
1054
  const toolCalls = extractAnthropicToolCalls(response);
1055
+ const thinkingText = extractAnthropicThinkingText(response);
758
1056
  const result = {
759
1057
  content: extractAnthropicTextContent(response, toolCalls.length > 0),
760
1058
  tokenUsage: mapAnthropicUsageToTokenUsage(response.usage),
@@ -763,6 +1061,9 @@ function mapAnthropicResponseToChatCompletionResult(response, latencyMs) {
763
1061
  if (toolCalls.length > 0) {
764
1062
  result.toolCalls = toolCalls;
765
1063
  }
1064
+ if (thinkingText.length > 0) {
1065
+ result.thinkingText = thinkingText;
1066
+ }
766
1067
  if (response.stop_reason !== null && response.stop_reason !== void 0) {
767
1068
  result.stopReason = normalizeAnthropicStopReason(response.stop_reason);
768
1069
  }
@@ -775,13 +1076,16 @@ function extractAnthropicToolCalls(response) {
775
1076
  input: contentBlock.input
776
1077
  }));
777
1078
  }
1079
+ function extractAnthropicThinkingText(response) {
1080
+ return response.content.filter((contentBlock) => contentBlock.type === "thinking").map((contentBlock) => contentBlock.thinking ?? "").join("");
1081
+ }
778
1082
  function extractAnthropicTextContent(response, allowEmptyText) {
779
1083
  const textBlocks = response.content.filter(
780
1084
  (contentBlock) => contentBlock.type === "text"
781
1085
  );
782
1086
  if (textBlocks.length === 0 && !allowEmptyText) {
783
- throw new AppError9({
784
- code: AppErrorCode8.ValidationFailed,
1087
+ throw new AppError10({
1088
+ code: AppErrorCode9.ValidationFailed,
785
1089
  message: "Anthropic response contained no text content",
786
1090
  statusCode: 502
787
1091
  });
@@ -818,58 +1122,68 @@ function mapAnthropicUsageToTokenUsage(usage) {
818
1122
  }
819
1123
 
820
1124
  // src/anthropic-stream.ts
821
- import { AppErrorCode as AppErrorCode9 } from "@assemble-dev/shared-types/errors";
1125
+ import { AppErrorCode as AppErrorCode10 } from "@assemble-dev/shared-types/errors";
822
1126
  import { JsonValueSchema as JsonValueSchema5 } from "@assemble-dev/shared-types/json";
823
- import { AppError as AppError10 } from "@assemble-dev/shared-utils/errors";
1127
+ import { AppError as AppError11 } from "@assemble-dev/shared-utils/errors";
824
1128
 
825
1129
  // src/anthropic-stream-events.ts
826
- import { z as z5 } from "zod";
827
- var AnthropicStreamEventSchema = z5.discriminatedUnion("type", [
828
- z5.object({
829
- type: z5.literal("message_start"),
830
- message: z5.object({
831
- usage: z5.object({
832
- input_tokens: z5.number().int().nonnegative(),
833
- output_tokens: z5.number().int().nonnegative().optional(),
834
- cache_creation_input_tokens: z5.number().int().nonnegative().optional(),
835
- cache_read_input_tokens: z5.number().int().nonnegative().optional()
1130
+ import { z as z6 } from "zod";
1131
+ var AnthropicStreamEventSchema = z6.discriminatedUnion("type", [
1132
+ z6.object({
1133
+ type: z6.literal("message_start"),
1134
+ message: z6.object({
1135
+ usage: z6.object({
1136
+ input_tokens: z6.number().int().nonnegative(),
1137
+ output_tokens: z6.number().int().nonnegative().optional(),
1138
+ cache_creation_input_tokens: z6.number().int().nonnegative().optional(),
1139
+ cache_read_input_tokens: z6.number().int().nonnegative().optional()
836
1140
  })
837
1141
  })
838
1142
  }),
839
- z5.object({
840
- type: z5.literal("content_block_start"),
841
- index: z5.number().int().nonnegative(),
842
- content_block: z5.discriminatedUnion("type", [
843
- z5.object({ type: z5.literal("text"), text: z5.string().optional() }),
844
- z5.object({
845
- type: z5.literal("tool_use"),
846
- id: z5.string(),
847
- name: z5.string()
1143
+ z6.object({
1144
+ type: z6.literal("content_block_start"),
1145
+ index: z6.number().int().nonnegative(),
1146
+ content_block: z6.discriminatedUnion("type", [
1147
+ z6.object({ type: z6.literal("text"), text: z6.string().optional() }),
1148
+ z6.object({
1149
+ type: z6.literal("thinking"),
1150
+ thinking: z6.string().optional()
1151
+ }),
1152
+ z6.object({
1153
+ type: z6.literal("redacted_thinking"),
1154
+ data: z6.string().optional()
1155
+ }),
1156
+ z6.object({
1157
+ type: z6.literal("tool_use"),
1158
+ id: z6.string(),
1159
+ name: z6.string()
848
1160
  })
849
1161
  ])
850
1162
  }),
851
- z5.object({
852
- type: z5.literal("content_block_delta"),
853
- index: z5.number().int().nonnegative(),
854
- delta: z5.discriminatedUnion("type", [
855
- z5.object({ type: z5.literal("text_delta"), text: z5.string() }),
856
- z5.object({
857
- type: z5.literal("input_json_delta"),
858
- partial_json: z5.string()
1163
+ z6.object({
1164
+ type: z6.literal("content_block_delta"),
1165
+ index: z6.number().int().nonnegative(),
1166
+ delta: z6.discriminatedUnion("type", [
1167
+ z6.object({ type: z6.literal("text_delta"), text: z6.string() }),
1168
+ z6.object({ type: z6.literal("thinking_delta"), thinking: z6.string() }),
1169
+ z6.object({ type: z6.literal("signature_delta"), signature: z6.string() }),
1170
+ z6.object({
1171
+ type: z6.literal("input_json_delta"),
1172
+ partial_json: z6.string()
859
1173
  })
860
1174
  ])
861
1175
  }),
862
- z5.object({ type: z5.literal("content_block_stop") }),
863
- z5.object({
864
- type: z5.literal("message_delta"),
865
- delta: z5.object({ stop_reason: z5.string().nullable().optional() }),
866
- usage: z5.object({ output_tokens: z5.number().int().nonnegative() }).optional()
1176
+ z6.object({ type: z6.literal("content_block_stop") }),
1177
+ z6.object({
1178
+ type: z6.literal("message_delta"),
1179
+ delta: z6.object({ stop_reason: z6.string().nullable().optional() }),
1180
+ usage: z6.object({ output_tokens: z6.number().int().nonnegative() }).optional()
867
1181
  }),
868
- z5.object({ type: z5.literal("message_stop") }),
869
- z5.object({ type: z5.literal("ping") }),
870
- z5.object({
871
- type: z5.literal("error"),
872
- error: z5.object({ message: z5.string() })
1182
+ z6.object({ type: z6.literal("message_stop") }),
1183
+ z6.object({ type: z6.literal("ping") }),
1184
+ z6.object({
1185
+ type: z6.literal("error"),
1186
+ error: z6.object({ message: z6.string() })
873
1187
  })
874
1188
  ]);
875
1189
 
@@ -955,6 +1269,7 @@ async function* readServerSentEventDataLines(body, abortSignal) {
955
1269
  function createAnthropicStreamAccumulator() {
956
1270
  return {
957
1271
  contentText: "",
1272
+ thinkingText: "",
958
1273
  toolCallsByBlockIndex: /* @__PURE__ */ new Map(),
959
1274
  inputTokens: 0,
960
1275
  outputTokens: 0
@@ -962,8 +1277,8 @@ function createAnthropicStreamAccumulator() {
962
1277
  }
963
1278
  function* applyAnthropicStreamEvent(event, accumulator) {
964
1279
  if (event.type === "error") {
965
- throw new AppError10({
966
- code: AppErrorCode9.InternalServerError,
1280
+ throw new AppError11({
1281
+ code: AppErrorCode10.InternalServerError,
967
1282
  message: `Anthropic stream reported an error: ${event.error.message}`,
968
1283
  statusCode: 502
969
1284
  });
@@ -999,6 +1314,17 @@ function* applyAnthropicContentBlockStart(event, accumulator) {
999
1314
  }
1000
1315
  return;
1001
1316
  }
1317
+ if (event.content_block.type === "thinking") {
1318
+ const initialThinkingText = event.content_block.thinking ?? "";
1319
+ if (initialThinkingText.length > 0) {
1320
+ accumulator.thinkingText += initialThinkingText;
1321
+ yield { type: "thinking_delta", text: initialThinkingText };
1322
+ }
1323
+ return;
1324
+ }
1325
+ if (event.content_block.type === "redacted_thinking") {
1326
+ return;
1327
+ }
1002
1328
  accumulator.toolCallsByBlockIndex.set(event.index, {
1003
1329
  id: event.content_block.id,
1004
1330
  toolName: event.content_block.name,
@@ -1016,6 +1342,14 @@ function* applyAnthropicContentBlockDelta(event, accumulator) {
1016
1342
  yield { type: "text_delta", text: event.delta.text };
1017
1343
  return;
1018
1344
  }
1345
+ if (event.delta.type === "thinking_delta") {
1346
+ accumulator.thinkingText += event.delta.thinking;
1347
+ yield { type: "thinking_delta", text: event.delta.thinking };
1348
+ return;
1349
+ }
1350
+ if (event.delta.type === "signature_delta") {
1351
+ return;
1352
+ }
1019
1353
  const toolCallAccumulation = accumulator.toolCallsByBlockIndex.get(
1020
1354
  event.index
1021
1355
  );
@@ -1062,6 +1396,9 @@ function buildAnthropicStreamResult(accumulator, latencyMs) {
1062
1396
  if (accumulator.stopReason !== void 0) {
1063
1397
  result.stopReason = accumulator.stopReason;
1064
1398
  }
1399
+ if (accumulator.thinkingText.length > 0) {
1400
+ result.thinkingText = accumulator.thinkingText;
1401
+ }
1065
1402
  return result;
1066
1403
  }
1067
1404
  function mapAccumulatedToolCallToModelToolCall(toolCallAccumulation) {
@@ -1078,8 +1415,8 @@ function parseAnthropicToolInputJson(inputJsonText) {
1078
1415
  try {
1079
1416
  return JsonValueSchema5.parse(JSON.parse(inputJsonText));
1080
1417
  } catch (error) {
1081
- throw new AppError10({
1082
- code: AppErrorCode9.ValidationFailed,
1418
+ throw new AppError11({
1419
+ code: AppErrorCode10.ValidationFailed,
1083
1420
  message: "Anthropic tool input was not valid JSON",
1084
1421
  statusCode: 502,
1085
1422
  cause: error instanceof Error ? error : void 0
@@ -1091,10 +1428,6 @@ function parseAnthropicToolInputJson(inputJsonText) {
1091
1428
  var defaultAnthropicBaseUrl = "https://api.anthropic.com";
1092
1429
  var defaultAnthropicMaxOutputTokens = 1024;
1093
1430
  var anthropicApiVersion = "2023-06-01";
1094
- var structuredOutputSystemMessage2 = {
1095
- role: "system",
1096
- content: "Respond with a single JSON object that satisfies the caller's requested structure. Output only valid JSON with no surrounding text."
1097
- };
1098
1431
  function anthropic(options) {
1099
1432
  return {
1100
1433
  name: `anthropic:${options.model}`,
@@ -1106,9 +1439,12 @@ function anthropic(options) {
1106
1439
  },
1107
1440
  async generateStructuredOutput(request) {
1108
1441
  const completion = await executeAnthropicAdapterCall(options, {
1109
- messages: [structuredOutputSystemMessage2, ...request.messages],
1442
+ messages: request.messages,
1110
1443
  temperature: request.temperature ?? options.temperature,
1111
1444
  maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
1445
+ structuredOutputJsonSchema: buildAnthropicStructuredOutputJsonSchema(
1446
+ request.schema
1447
+ ),
1112
1448
  abortSignal: request.abortSignal
1113
1449
  });
1114
1450
  return {
@@ -1131,7 +1467,8 @@ function buildAnthropicCallInput(options, request) {
1131
1467
  maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
1132
1468
  tools: request.tools,
1133
1469
  toolChoice: request.toolChoice,
1134
- abortSignal: request.abortSignal
1470
+ abortSignal: request.abortSignal,
1471
+ extraBody: request.extraBody
1135
1472
  };
1136
1473
  }
1137
1474
  async function executeAnthropicAdapterCall(options, input) {
@@ -1148,9 +1485,10 @@ async function executeAnthropicAdapterCall(options, input) {
1148
1485
  );
1149
1486
  }
1150
1487
  async function requestAnthropicMessages(options, input) {
1151
- const requestBody = buildAnthropicRequestBody(
1152
- buildAnthropicRequestSettings(options),
1153
- input
1488
+ const requestBody = mergeProviderRequestExtraBody(
1489
+ buildAnthropicRequestBody(buildAnthropicRequestSettings(options), input),
1490
+ options.extraBody,
1491
+ input.extraBody
1154
1492
  );
1155
1493
  const startedAt = Date.now();
1156
1494
  const response = await executeAbortableProviderFetch(
@@ -1179,9 +1517,10 @@ async function requestAnthropicMessages(options, input) {
1179
1517
  }
1180
1518
  function buildAnthropicStreamInput(options, request) {
1181
1519
  const input = buildAnthropicCallInput(options, request);
1182
- const requestBody = buildAnthropicRequestBody(
1183
- buildAnthropicRequestSettings(options),
1184
- input
1520
+ const requestBody = mergeProviderRequestExtraBody(
1521
+ buildAnthropicRequestBody(buildAnthropicRequestSettings(options), input),
1522
+ options.extraBody,
1523
+ input.extraBody
1185
1524
  );
1186
1525
  return {
1187
1526
  url: `${resolveAnthropicBaseUrl(options)}/v1/messages`,
@@ -1221,28 +1560,116 @@ function resolveAnthropicFetch(options) {
1221
1560
  }
1222
1561
 
1223
1562
  // src/gemini-adapter.ts
1224
- import { z as z6 } from "zod";
1225
- import { AppErrorCode as AppErrorCode10 } from "@assemble-dev/shared-types/errors";
1226
- import { AppError as AppError11 } from "@assemble-dev/shared-utils/errors";
1563
+ import { z as z7 } from "zod";
1564
+ import { AppErrorCode as AppErrorCode11 } from "@assemble-dev/shared-types/errors";
1565
+ import { AppError as AppError12 } from "@assemble-dev/shared-utils/errors";
1566
+
1567
+ // src/gemini-response-schema.ts
1568
+ var geminiAllowedSchemaKeywords = [
1569
+ "type",
1570
+ "format",
1571
+ "description",
1572
+ "nullable",
1573
+ "enum",
1574
+ "properties",
1575
+ "required",
1576
+ "items",
1577
+ "minItems",
1578
+ "maxItems",
1579
+ "anyOf"
1580
+ ];
1581
+ var geminiAllowedFormats = [
1582
+ "date-time",
1583
+ "int32",
1584
+ "int64",
1585
+ "float",
1586
+ "double"
1587
+ ];
1588
+ function buildGeminiResponseSchema(schema) {
1589
+ return sanitizeJsonSchemaForGeminiResponseSchema(
1590
+ convertZodSchemaToJsonSchema(schema)
1591
+ );
1592
+ }
1593
+ function sanitizeJsonSchemaForGeminiResponseSchema(jsonSchema) {
1594
+ return transformJsonSchemaNode(
1595
+ inlineJsonSchemaReferences(jsonSchema),
1596
+ sanitizeGeminiSchemaNode
1597
+ );
1598
+ }
1599
+ function sanitizeGeminiSchemaNode(node) {
1600
+ const normalized = normalizeGeminiNullableType(
1601
+ mergeNullUnionIntoNullableNode(node)
1602
+ );
1603
+ const sanitized = {};
1604
+ for (const [key, value] of Object.entries(normalized)) {
1605
+ if (geminiAllowedSchemaKeywords.includes(key)) {
1606
+ sanitized[key] = value;
1607
+ }
1608
+ }
1609
+ return removeUnsupportedGeminiFormat(sanitized);
1610
+ }
1611
+ function mergeNullUnionIntoNullableNode(node) {
1612
+ const unionKeyword = Array.isArray(node["anyOf"]) ? "anyOf" : "oneOf";
1613
+ const unionMembers = node[unionKeyword];
1614
+ if (!Array.isArray(unionMembers)) {
1615
+ return node;
1616
+ }
1617
+ const nonNullMembers = unionMembers.filter(
1618
+ (member) => !isNullTypeSchemaNode(member)
1619
+ );
1620
+ if (nonNullMembers.length === unionMembers.length) {
1621
+ return node;
1622
+ }
1623
+ const merged = { ...node };
1624
+ delete merged[unionKeyword];
1625
+ const singleMember = nonNullMembers.length === 1 ? nonNullMembers[0] : void 0;
1626
+ if (singleMember !== void 0 && isJsonObject(singleMember)) {
1627
+ return { ...merged, ...singleMember, nullable: true };
1628
+ }
1629
+ return { ...merged, anyOf: nonNullMembers, nullable: true };
1630
+ }
1631
+ function normalizeGeminiNullableType(node) {
1632
+ const typeValue = node["type"];
1633
+ if (!Array.isArray(typeValue)) {
1634
+ return node;
1635
+ }
1636
+ const nonNullTypes = typeValue.filter((typeName) => typeName !== "null");
1637
+ const normalized = { ...node };
1638
+ if (nonNullTypes.length < typeValue.length) {
1639
+ normalized["nullable"] = true;
1640
+ }
1641
+ normalized["type"] = nonNullTypes[0] ?? "string";
1642
+ return normalized;
1643
+ }
1644
+ function removeUnsupportedGeminiFormat(node) {
1645
+ const formatValue = node["format"];
1646
+ if (typeof formatValue === "string" && !geminiAllowedFormats.includes(formatValue)) {
1647
+ const withoutFormat = { ...node };
1648
+ delete withoutFormat["format"];
1649
+ return withoutFormat;
1650
+ }
1651
+ return node;
1652
+ }
1653
+ function isNullTypeSchemaNode(value) {
1654
+ return isJsonObject(value) && value["type"] === "null";
1655
+ }
1656
+
1657
+ // src/gemini-adapter.ts
1227
1658
  var defaultGeminiBaseUrl = "https://generativelanguage.googleapis.com";
1228
- var GeminiGenerateContentResponseSchema = z6.object({
1229
- candidates: z6.array(
1230
- z6.object({
1231
- content: z6.object({
1232
- parts: z6.array(z6.object({ text: z6.string() }))
1659
+ var GeminiGenerateContentResponseSchema = z7.object({
1660
+ candidates: z7.array(
1661
+ z7.object({
1662
+ content: z7.object({
1663
+ parts: z7.array(z7.object({ text: z7.string() }))
1233
1664
  })
1234
1665
  })
1235
1666
  ).optional(),
1236
- usageMetadata: z6.object({
1237
- promptTokenCount: z6.number().int().nonnegative().optional(),
1238
- candidatesTokenCount: z6.number().int().nonnegative().optional(),
1239
- totalTokenCount: z6.number().int().nonnegative().optional()
1667
+ usageMetadata: z7.object({
1668
+ promptTokenCount: z7.number().int().nonnegative().optional(),
1669
+ candidatesTokenCount: z7.number().int().nonnegative().optional(),
1670
+ totalTokenCount: z7.number().int().nonnegative().optional()
1240
1671
  }).optional()
1241
1672
  });
1242
- var structuredOutputSystemMessage3 = {
1243
- role: "system",
1244
- content: "Respond with a single JSON object that satisfies the caller's requested structure. Output only valid JSON with no surrounding text."
1245
- };
1246
1673
  function gemini(options) {
1247
1674
  return {
1248
1675
  name: `gemini:${options.model}`,
@@ -1252,16 +1679,16 @@ function gemini(options) {
1252
1679
  messages: request.messages,
1253
1680
  temperature: request.temperature ?? options.temperature,
1254
1681
  maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
1255
- requireJsonResponse: false,
1256
- abortSignal: request.abortSignal
1682
+ abortSignal: request.abortSignal,
1683
+ extraBody: request.extraBody
1257
1684
  });
1258
1685
  },
1259
1686
  async generateStructuredOutput(request) {
1260
1687
  const completion = await executeGeminiAdapterCall(options, {
1261
- messages: [structuredOutputSystemMessage3, ...request.messages],
1688
+ messages: request.messages,
1262
1689
  temperature: request.temperature ?? options.temperature,
1263
1690
  maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
1264
- requireJsonResponse: true,
1691
+ responseSchema: buildGeminiResponseSchema(request.schema),
1265
1692
  abortSignal: request.abortSignal
1266
1693
  });
1267
1694
  return {
@@ -1295,7 +1722,11 @@ async function requestGeminiGenerateContent(options, input) {
1295
1722
  });
1296
1723
  const fetchImplementation = options.fetchImplementation ?? fetch;
1297
1724
  const baseUrl = options.baseURL ?? defaultGeminiBaseUrl;
1298
- const requestBody = buildGeminiRequestBody(input);
1725
+ const requestBody = mergeProviderRequestExtraBody(
1726
+ buildGeminiRequestBody(input),
1727
+ options.extraBody,
1728
+ input.extraBody
1729
+ );
1299
1730
  const requestUrl = `${baseUrl}/v1beta/models/${options.model}:generateContent`;
1300
1731
  const startedAt = Date.now();
1301
1732
  const response = await executeAbortableProviderFetch(
@@ -1344,8 +1775,8 @@ function ensureGeminiRequestHasNoTools(request) {
1344
1775
  if (request.tools === void 0 || request.tools.length === 0) {
1345
1776
  return;
1346
1777
  }
1347
- throw new AppError11({
1348
- code: AppErrorCode10.ValidationFailed,
1778
+ throw new AppError12({
1779
+ code: AppErrorCode11.ValidationFailed,
1349
1780
  message: "gemini adapter does not support model-driven tool use; remove tools from the request or use another adapter",
1350
1781
  statusCode: 400
1351
1782
  });
@@ -1382,8 +1813,9 @@ function buildGeminiGenerationConfig(input) {
1382
1813
  if (input.maxOutputTokens !== void 0) {
1383
1814
  generationConfig.maxOutputTokens = input.maxOutputTokens;
1384
1815
  }
1385
- if (input.requireJsonResponse) {
1816
+ if (input.responseSchema !== void 0) {
1386
1817
  generationConfig.responseMimeType = "application/json";
1818
+ generationConfig.responseSchema = input.responseSchema;
1387
1819
  }
1388
1820
  if (Object.keys(generationConfig).length === 0) {
1389
1821
  return void 0;
@@ -1393,8 +1825,8 @@ function buildGeminiGenerationConfig(input) {
1393
1825
  function extractGeminiCandidateText(response) {
1394
1826
  const firstCandidate = response.candidates?.[0];
1395
1827
  if (firstCandidate === void 0) {
1396
- throw new AppError11({
1397
- code: AppErrorCode10.ValidationFailed,
1828
+ throw new AppError12({
1829
+ code: AppErrorCode11.ValidationFailed,
1398
1830
  message: "Gemini response contained no candidates",
1399
1831
  statusCode: 502
1400
1832
  });
@@ -1413,8 +1845,8 @@ function mapGeminiUsageToTokenUsage(response) {
1413
1845
  }
1414
1846
 
1415
1847
  // src/mock-adapter.ts
1416
- import { AppErrorCode as AppErrorCode11 } from "@assemble-dev/shared-types/errors";
1417
- import { AppError as AppError12 } from "@assemble-dev/shared-utils/errors";
1848
+ import { AppErrorCode as AppErrorCode12 } from "@assemble-dev/shared-types/errors";
1849
+ import { AppError as AppError13 } from "@assemble-dev/shared-utils/errors";
1418
1850
  var mockStreamChunkCount = 3;
1419
1851
  function mockModel(options = {}) {
1420
1852
  const remainingScriptedResponses = [...options.scriptedResponses ?? []];
@@ -1494,8 +1926,8 @@ function resolveNextMockResponseText(request, remainingScriptedResponses, respon
1494
1926
  if (respond !== void 0) {
1495
1927
  return respond(request);
1496
1928
  }
1497
- throw new AppError12({
1498
- code: AppErrorCode11.BadRequest,
1929
+ throw new AppError13({
1930
+ code: AppErrorCode12.BadRequest,
1499
1931
  message: "Mock model has no scripted responses left and no respond function was provided",
1500
1932
  statusCode: 400
1501
1933
  });
@@ -1583,60 +2015,277 @@ function calculateModelCallCostUsd(pricing, tokenUsage) {
1583
2015
  }
1584
2016
 
1585
2017
  // src/anthropic-batch.ts
1586
- import { AppErrorCode as AppErrorCode12 } from "@assemble-dev/shared-types/errors";
2018
+ import { AppErrorCode as AppErrorCode14 } from "@assemble-dev/shared-types/errors";
2019
+ import { JsonValueSchema as JsonValueSchema7 } from "@assemble-dev/shared-types/json";
2020
+ import { AppError as AppError15 } from "@assemble-dev/shared-utils/errors";
2021
+
2022
+ // src/anthropic-batch-structured.ts
2023
+ import { AppErrorCode as AppErrorCode13 } from "@assemble-dev/shared-types/errors";
1587
2024
  import { JsonValueSchema as JsonValueSchema6 } from "@assemble-dev/shared-types/json";
1588
- import { AppError as AppError13 } from "@assemble-dev/shared-utils/errors";
2025
+ import { AppError as AppError14 } from "@assemble-dev/shared-utils/errors";
2026
+ var anthropicBatchJsonOnlySystemInstruction = "Respond with a single JSON object that satisfies the caller's requested structure. Output only valid JSON with no surrounding text.";
2027
+ function parseAnthropicBatchStructuredContent(content, schema) {
2028
+ const jsonValue = parseStructuredJsonText(
2029
+ content,
2030
+ JsonValueSchema6
2031
+ );
2032
+ const validationResult = schema.safeParse(jsonValue);
2033
+ if (!validationResult.success) {
2034
+ throw new AppError14({
2035
+ code: AppErrorCode13.ValidationFailed,
2036
+ message: "Anthropic batch structured output did not match the expected schema",
2037
+ statusCode: 422,
2038
+ details: { validationErrorMessage: validationResult.error.message }
2039
+ });
2040
+ }
2041
+ return validationResult.data;
2042
+ }
1589
2043
 
1590
- // src/anthropic-batch-types.ts
1591
- import { z as z7 } from "zod";
1592
- var AnthropicMessageBatchResponseSchema = z7.object({
1593
- id: z7.string(),
1594
- processing_status: z7.enum(["in_progress", "canceling", "ended"]),
1595
- request_counts: z7.object({
1596
- processing: z7.number().int().nonnegative(),
1597
- succeeded: z7.number().int().nonnegative(),
1598
- errored: z7.number().int().nonnegative(),
1599
- canceled: z7.number().int().nonnegative(),
1600
- expired: z7.number().int().nonnegative()
1601
- }),
1602
- results_url: z7.string().nullable(),
1603
- created_at: z7.string(),
1604
- ended_at: z7.string().nullable()
1605
- });
1606
- var AnthropicBatchContentBlockSchema = z7.discriminatedUnion("type", [
1607
- z7.object({
1608
- type: z7.literal("text"),
1609
- text: z7.string()
1610
- }),
1611
- z7.object({
1612
- type: z7.literal("thinking"),
1613
- thinking: z7.string().optional(),
1614
- signature: z7.string().optional()
1615
- }),
1616
- z7.object({
1617
- type: z7.literal("redacted_thinking"),
1618
- data: z7.string().optional()
1619
- })
1620
- ]);
1621
- var AnthropicBatchResultLineSchema = z7.object({
1622
- custom_id: z7.string(),
1623
- result: z7.discriminatedUnion("type", [
1624
- z7.object({
1625
- type: z7.literal("succeeded"),
1626
- message: z7.object({
1627
- content: z7.array(AnthropicBatchContentBlockSchema),
1628
- usage: AnthropicUsageSchema
1629
- })
1630
- }),
1631
- z7.object({
1632
- type: z7.literal("errored"),
1633
- error: z7.object({
1634
- type: z7.string(),
1635
- message: z7.string()
2044
+ // src/anthropic-batch-request.ts
2045
+ function mapBatchMessageRequestToApiBatchRequest(request) {
2046
+ const params = {
2047
+ model: request.model,
2048
+ max_tokens: request.maxOutputTokens ?? defaultAnthropicMaxOutputTokens,
2049
+ messages: request.messages.filter((message) => message.role !== "system").map(mapChatMessageToBatchApiRequestMessage)
2050
+ };
2051
+ applyBatchSystemField(params, request);
2052
+ applyBatchStructuredOutputConfig(params, request);
2053
+ if (request.temperature !== void 0) {
2054
+ params.temperature = request.temperature;
2055
+ }
2056
+ return { custom_id: request.customId, params };
2057
+ }
2058
+ function applyBatchStructuredOutputConfig(params, request) {
2059
+ if (request.structuredOutputJsonSchema === void 0) {
2060
+ return;
2061
+ }
2062
+ params.output_config = {
2063
+ format: {
2064
+ type: "json_schema",
2065
+ schema: sanitizeJsonSchemaForAnthropicStructuredOutput(
2066
+ request.structuredOutputJsonSchema
2067
+ )
2068
+ }
2069
+ };
2070
+ }
2071
+ function applyBatchSystemField(params, request) {
2072
+ const systemText = buildBatchSystemText(request);
2073
+ if (systemText.length === 0) {
2074
+ return;
2075
+ }
2076
+ if (request.promptCaching !== "auto") {
2077
+ params.system = systemText;
2078
+ return;
2079
+ }
2080
+ params.system = [
2081
+ { type: "text", text: systemText, cache_control: { type: "ephemeral" } }
2082
+ ];
2083
+ }
2084
+ function buildBatchSystemText(request) {
2085
+ const joinedSystemText = joinBatchSystemMessageText(request.messages);
2086
+ if (request.requireJsonResponse !== true || request.structuredOutputJsonSchema !== void 0) {
2087
+ return joinedSystemText;
2088
+ }
2089
+ if (joinedSystemText.length === 0) {
2090
+ return anthropicBatchJsonOnlySystemInstruction;
2091
+ }
2092
+ return `${anthropicBatchJsonOnlySystemInstruction}
2093
+
2094
+ ${joinedSystemText}`;
2095
+ }
2096
+ function joinBatchSystemMessageText(messages) {
2097
+ return messages.filter((message) => message.role === "system").map(extractMessageText).join("\n\n");
2098
+ }
2099
+ function mapChatMessageToBatchApiRequestMessage(message) {
2100
+ if (message.role === "assistant") {
2101
+ return { role: "assistant", content: extractMessageText(message) };
2102
+ }
2103
+ if (message.role === "tool") {
2104
+ return { role: "user", content: buildBatchToolResultText(message) };
2105
+ }
2106
+ return { role: "user", content: extractMessageText(message) };
2107
+ }
2108
+ function buildBatchToolResultText(message) {
2109
+ if (message.toolName === void 0) {
2110
+ return `Tool result: ${extractMessageText(message)}`;
2111
+ }
2112
+ return `Tool result (${message.toolName}): ${extractMessageText(message)}`;
2113
+ }
2114
+
2115
+ // src/anthropic-batch-trace-events.ts
2116
+ import {
2117
+ generateRunId,
2118
+ generateTraceEventId
2119
+ } from "@assemble-dev/shared-utils/ids";
2120
+ var anthropicBatchTraceWorkflowName = "anthropic-message-batch";
2121
+ function createAnthropicBatchTraceEmitter(input) {
2122
+ if (input.onTraceEvent === void 0) {
2123
+ return createNoopAnthropicBatchTraceEmitter();
2124
+ }
2125
+ const onTraceEvent = input.onTraceEvent;
2126
+ const runId = generateRunId();
2127
+ const completedBatchIds = /* @__PURE__ */ new Set();
2128
+ const submittedEventIdByBatchId = /* @__PURE__ */ new Map();
2129
+ const modelByBatchScopedCustomId = /* @__PURE__ */ new Map();
2130
+ function buildBatchTraceEventBase(parentEventId) {
2131
+ return {
2132
+ id: generateTraceEventId(),
2133
+ runId,
2134
+ workflowName: anthropicBatchTraceWorkflowName,
2135
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2136
+ parentEventId,
2137
+ redacted: false
2138
+ };
2139
+ }
2140
+ function stampMetadataOntoEvent(event) {
2141
+ if (input.metadata === void 0) {
2142
+ return event;
2143
+ }
2144
+ return { ...event, metadata: input.metadata };
2145
+ }
2146
+ function emitBatchSubmittedEvent(batch, requestSummaries) {
2147
+ const submittedEvent = {
2148
+ ...buildBatchTraceEventBase(null),
2149
+ type: "batch.submitted",
2150
+ batchId: batch.id,
2151
+ requestCount: requestSummaries.length,
2152
+ models: requestSummaries.map((requestSummary) => requestSummary.model)
2153
+ };
2154
+ submittedEventIdByBatchId.set(batch.id, submittedEvent.id);
2155
+ for (const requestSummary of requestSummaries) {
2156
+ modelByBatchScopedCustomId.set(
2157
+ buildBatchScopedCustomIdKey(batch.id, requestSummary.customId),
2158
+ requestSummary.model
2159
+ );
2160
+ }
2161
+ onTraceEvent(stampMetadataOntoEvent(submittedEvent));
2162
+ }
2163
+ function emitBatchCompletedEventOnce(batch) {
2164
+ if (batch.processingStatus !== "ended" || completedBatchIds.has(batch.id)) {
2165
+ return;
2166
+ }
2167
+ completedBatchIds.add(batch.id);
2168
+ const completedEvent = {
2169
+ ...buildBatchTraceEventBase(
2170
+ submittedEventIdByBatchId.get(batch.id) ?? null
2171
+ ),
2172
+ type: "batch.completed",
2173
+ batchId: batch.id,
2174
+ requestCounts: batch.requestCounts,
2175
+ latencyMs: calculateBatchLatencyMs(batch)
2176
+ };
2177
+ onTraceEvent(stampMetadataOntoEvent(completedEvent));
2178
+ }
2179
+ function emitBatchResultEvent(batchId, result) {
2180
+ const resultEvent = buildBatchResultEvent(
2181
+ buildBatchTraceEventBase(submittedEventIdByBatchId.get(batchId) ?? null),
2182
+ batchId,
2183
+ result,
2184
+ modelByBatchScopedCustomId.get(
2185
+ buildBatchScopedCustomIdKey(batchId, result.customId)
2186
+ )
2187
+ );
2188
+ onTraceEvent(stampMetadataOntoEvent(resultEvent));
2189
+ }
2190
+ return {
2191
+ emitBatchSubmittedEvent,
2192
+ emitBatchCompletedEventOnce,
2193
+ emitBatchResultEvent
2194
+ };
2195
+ }
2196
+ function createNoopAnthropicBatchTraceEmitter() {
2197
+ return {
2198
+ emitBatchSubmittedEvent() {
2199
+ },
2200
+ emitBatchCompletedEventOnce() {
2201
+ },
2202
+ emitBatchResultEvent() {
2203
+ }
2204
+ };
2205
+ }
2206
+ function buildBatchScopedCustomIdKey(batchId, customId) {
2207
+ return `${batchId}:${customId}`;
2208
+ }
2209
+ function calculateBatchLatencyMs(batch) {
2210
+ const createdAtMs = Date.parse(batch.createdAt);
2211
+ const endedAtMs = batch.endedAt === null ? Date.now() : Date.parse(batch.endedAt);
2212
+ if (Number.isNaN(createdAtMs) || Number.isNaN(endedAtMs)) {
2213
+ return 0;
2214
+ }
2215
+ return Math.max(0, endedAtMs - createdAtMs);
2216
+ }
2217
+ function buildBatchResultEvent(eventBase, batchId, result, modelName) {
2218
+ if (result.outcome.type !== "succeeded") {
2219
+ return {
2220
+ ...eventBase,
2221
+ type: "batch.result",
2222
+ batchId,
2223
+ customId: result.customId,
2224
+ outcomeType: result.outcome.type,
2225
+ costUsd: null
2226
+ };
2227
+ }
2228
+ return {
2229
+ ...eventBase,
2230
+ type: "batch.result",
2231
+ batchId,
2232
+ customId: result.customId,
2233
+ outcomeType: "succeeded",
2234
+ tokenUsage: result.outcome.tokenUsage,
2235
+ costUsd: modelName === void 0 ? null : estimateModelCallCostUsd(modelName, result.outcome.tokenUsage)
2236
+ };
2237
+ }
2238
+
2239
+ // src/anthropic-batch-types.ts
2240
+ import { z as z8 } from "zod";
2241
+ var AnthropicMessageBatchResponseSchema = z8.object({
2242
+ id: z8.string(),
2243
+ processing_status: z8.enum(["in_progress", "canceling", "ended"]),
2244
+ request_counts: z8.object({
2245
+ processing: z8.number().int().nonnegative(),
2246
+ succeeded: z8.number().int().nonnegative(),
2247
+ errored: z8.number().int().nonnegative(),
2248
+ canceled: z8.number().int().nonnegative(),
2249
+ expired: z8.number().int().nonnegative()
2250
+ }),
2251
+ results_url: z8.string().nullable(),
2252
+ created_at: z8.string(),
2253
+ ended_at: z8.string().nullable()
2254
+ });
2255
+ var AnthropicBatchContentBlockSchema = z8.discriminatedUnion("type", [
2256
+ z8.object({
2257
+ type: z8.literal("text"),
2258
+ text: z8.string()
2259
+ }),
2260
+ z8.object({
2261
+ type: z8.literal("thinking"),
2262
+ thinking: z8.string().optional(),
2263
+ signature: z8.string().optional()
2264
+ }),
2265
+ z8.object({
2266
+ type: z8.literal("redacted_thinking"),
2267
+ data: z8.string().optional()
2268
+ })
2269
+ ]);
2270
+ var AnthropicBatchResultLineSchema = z8.object({
2271
+ custom_id: z8.string(),
2272
+ result: z8.discriminatedUnion("type", [
2273
+ z8.object({
2274
+ type: z8.literal("succeeded"),
2275
+ message: z8.object({
2276
+ content: z8.array(AnthropicBatchContentBlockSchema),
2277
+ usage: AnthropicUsageSchema
2278
+ })
2279
+ }),
2280
+ z8.object({
2281
+ type: z8.literal("errored"),
2282
+ error: z8.object({
2283
+ type: z8.string(),
2284
+ message: z8.string()
1636
2285
  })
1637
2286
  }),
1638
- z7.object({ type: z7.literal("canceled") }),
1639
- z7.object({ type: z7.literal("expired") })
2287
+ z8.object({ type: z8.literal("canceled") }),
2288
+ z8.object({ type: z8.literal("expired") })
1640
2289
  ])
1641
2290
  });
1642
2291
  function mapAnthropicMessageBatchResponseToMessageBatch(response) {
@@ -1690,19 +2339,26 @@ var defaultAnthropicBatchPollIntervalMs = 5e3;
1690
2339
  var defaultAnthropicBatchTimeoutMs = 36e5;
1691
2340
  var anthropicBatchApiVersion = "2023-06-01";
1692
2341
  function createAnthropicBatchClient(options) {
2342
+ const clientContext = {
2343
+ options,
2344
+ traceEmitter: createAnthropicBatchTraceEmitter({
2345
+ onTraceEvent: options.onTraceEvent,
2346
+ metadata: options.metadata
2347
+ })
2348
+ };
1693
2349
  return {
1694
2350
  async submitMessageBatch(requests) {
1695
- return await submitAnthropicMessageBatch(options, requests);
2351
+ return await submitAnthropicMessageBatch(clientContext, requests);
1696
2352
  },
1697
2353
  async fetchMessageBatch(batchId) {
1698
- return await fetchAnthropicMessageBatch(options, batchId);
2354
+ return await fetchAnthropicMessageBatch(clientContext, batchId);
1699
2355
  },
1700
2356
  async listMessageBatchResults(batchId) {
1701
- return await listAnthropicMessageBatchResults(options, batchId);
2357
+ return await listAnthropicMessageBatchResults(clientContext, batchId);
1702
2358
  },
1703
2359
  async waitForMessageBatchCompletion(batchId, waitOptions) {
1704
2360
  return await waitForAnthropicMessageBatchCompletion(
1705
- options,
2361
+ clientContext,
1706
2362
  batchId,
1707
2363
  waitOptions
1708
2364
  );
@@ -1729,8 +2385,8 @@ function buildAnthropicBatchRequestHeaders(apiKey) {
1729
2385
  "anthropic-version": anthropicBatchApiVersion
1730
2386
  };
1731
2387
  }
1732
- async function submitAnthropicMessageBatch(options, requests) {
1733
- const context = resolveAnthropicBatchRequestContext(options);
2388
+ async function submitAnthropicMessageBatch(clientContext, requests) {
2389
+ const context = resolveAnthropicBatchRequestContext(clientContext.options);
1734
2390
  const response = await context.fetchImplementation(
1735
2391
  `${context.baseUrl}/v1/messages/batches`,
1736
2392
  {
@@ -1741,10 +2397,18 @@ async function submitAnthropicMessageBatch(options, requests) {
1741
2397
  })
1742
2398
  }
1743
2399
  );
1744
- return await parseAnthropicMessageBatchHttpResponse(response);
2400
+ const batch = await parseAnthropicMessageBatchHttpResponse(response);
2401
+ clientContext.traceEmitter.emitBatchSubmittedEvent(
2402
+ batch,
2403
+ requests.map((request) => ({
2404
+ customId: request.customId,
2405
+ model: request.model
2406
+ }))
2407
+ );
2408
+ return batch;
1745
2409
  }
1746
- async function fetchAnthropicMessageBatch(options, batchId) {
1747
- const context = resolveAnthropicBatchRequestContext(options);
2410
+ async function fetchAnthropicMessageBatch(clientContext, batchId) {
2411
+ const context = resolveAnthropicBatchRequestContext(clientContext.options);
1748
2412
  const response = await context.fetchImplementation(
1749
2413
  `${context.baseUrl}/v1/messages/batches/${batchId}`,
1750
2414
  {
@@ -1752,7 +2416,9 @@ async function fetchAnthropicMessageBatch(options, batchId) {
1752
2416
  headers: buildAnthropicBatchRequestHeaders(context.apiKey)
1753
2417
  }
1754
2418
  );
1755
- return await parseAnthropicMessageBatchHttpResponse(response);
2419
+ const batch = await parseAnthropicMessageBatchHttpResponse(response);
2420
+ clientContext.traceEmitter.emitBatchCompletedEventOnce(batch);
2421
+ return batch;
1756
2422
  }
1757
2423
  async function parseAnthropicMessageBatchHttpResponse(response) {
1758
2424
  if (!response.ok) {
@@ -1766,17 +2432,17 @@ async function parseAnthropicMessageBatchHttpResponse(response) {
1766
2432
  }
1767
2433
  return mapAnthropicMessageBatchResponseToMessageBatch(parseResult.data);
1768
2434
  }
1769
- async function listAnthropicMessageBatchResults(options, batchId) {
1770
- const batch = await fetchAnthropicMessageBatch(options, batchId);
2435
+ async function listAnthropicMessageBatchResults(clientContext, batchId) {
2436
+ const batch = await fetchAnthropicMessageBatch(clientContext, batchId);
1771
2437
  if (batch.resultsUrl === null) {
1772
- throw new AppError13({
1773
- code: AppErrorCode12.Conflict,
2438
+ throw new AppError15({
2439
+ code: AppErrorCode14.Conflict,
1774
2440
  message: `Anthropic message batch ${batchId} has no results because processing has not ended`,
1775
2441
  statusCode: 409,
1776
2442
  details: { batchId, processingStatus: batch.processingStatus }
1777
2443
  });
1778
2444
  }
1779
- const context = resolveAnthropicBatchRequestContext(options);
2445
+ const context = resolveAnthropicBatchRequestContext(clientContext.options);
1780
2446
  const response = await context.fetchImplementation(batch.resultsUrl, {
1781
2447
  method: "GET",
1782
2448
  headers: buildAnthropicBatchRequestHeaders(context.apiKey)
@@ -1784,7 +2450,11 @@ async function listAnthropicMessageBatchResults(options, batchId) {
1784
2450
  if (!response.ok) {
1785
2451
  throw buildProviderStatusError("Anthropic", response.status);
1786
2452
  }
1787
- return parseAnthropicBatchResultsJsonl(await response.text());
2453
+ const results = parseAnthropicBatchResultsJsonl(await response.text());
2454
+ for (const result of results) {
2455
+ clientContext.traceEmitter.emitBatchResultEvent(batchId, result);
2456
+ }
2457
+ return results;
1788
2458
  }
1789
2459
  function parseAnthropicBatchResultsJsonl(jsonlText) {
1790
2460
  return jsonlText.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map(parseAnthropicBatchResultLine);
@@ -1803,7 +2473,7 @@ function parseAnthropicBatchResultLine(line) {
1803
2473
  }
1804
2474
  function parseAnthropicBatchResultLineJson(line) {
1805
2475
  try {
1806
- return JsonValueSchema6.parse(JSON.parse(line));
2476
+ return JsonValueSchema7.parse(JSON.parse(line));
1807
2477
  } catch {
1808
2478
  throw buildProviderInvalidResponseError(
1809
2479
  "Anthropic",
@@ -1811,80 +2481,810 @@ function parseAnthropicBatchResultLineJson(line) {
1811
2481
  );
1812
2482
  }
1813
2483
  }
1814
- async function waitForAnthropicMessageBatchCompletion(options, batchId, waitOptions) {
2484
+ async function waitForAnthropicMessageBatchCompletion(clientContext, batchId, waitOptions) {
1815
2485
  const pollIntervalMs = waitOptions?.pollIntervalMs ?? defaultAnthropicBatchPollIntervalMs;
1816
2486
  const timeoutMs = waitOptions?.timeoutMs ?? defaultAnthropicBatchTimeoutMs;
1817
2487
  const waitFor = waitOptions?.waitFor ?? waitForMilliseconds;
1818
2488
  const startedAt = Date.now();
1819
- let batch = await fetchAnthropicMessageBatch(options, batchId);
2489
+ let batch = await fetchAnthropicMessageBatch(clientContext, batchId);
1820
2490
  while (batch.processingStatus !== "ended") {
1821
2491
  if (Date.now() - startedAt >= timeoutMs) {
1822
2492
  throw buildAnthropicBatchTimeoutError(batchId, timeoutMs);
1823
2493
  }
1824
2494
  await waitFor(pollIntervalMs);
1825
- batch = await fetchAnthropicMessageBatch(options, batchId);
2495
+ batch = await fetchAnthropicMessageBatch(clientContext, batchId);
1826
2496
  }
1827
2497
  return batch;
1828
2498
  }
1829
2499
  function buildAnthropicBatchTimeoutError(batchId, timeoutMs) {
1830
- return new AppError13({
1831
- code: AppErrorCode12.ServiceUnavailable,
2500
+ return new AppError15({
2501
+ code: AppErrorCode14.ServiceUnavailable,
1832
2502
  message: `Anthropic message batch ${batchId} did not complete within ${String(timeoutMs)}ms`,
1833
2503
  statusCode: 504,
1834
2504
  details: { batchId, timeoutMs }
1835
2505
  });
1836
2506
  }
1837
- function mapBatchMessageRequestToApiBatchRequest(request) {
1838
- const params = {
1839
- model: request.model,
1840
- max_tokens: request.maxOutputTokens ?? defaultAnthropicMaxOutputTokens,
1841
- messages: request.messages.filter((message) => message.role !== "system").map(mapChatMessageToBatchApiRequestMessage)
2507
+
2508
+ // src/azure-openai-adapter.ts
2509
+ import { AppErrorCode as AppErrorCode16 } from "@assemble-dev/shared-types/errors";
2510
+ import { AppError as AppError17 } from "@assemble-dev/shared-utils/errors";
2511
+
2512
+ // src/azure-openai-response-parsing.ts
2513
+ import { z as z9 } from "zod";
2514
+ import { AppErrorCode as AppErrorCode15 } from "@assemble-dev/shared-types/errors";
2515
+ import { JsonValueSchema as JsonValueSchema8 } from "@assemble-dev/shared-types/json";
2516
+ import { AppError as AppError16 } from "@assemble-dev/shared-utils/errors";
2517
+ var AzureOpenAiUsageSchema = z9.object({
2518
+ prompt_tokens: z9.number().int().nonnegative(),
2519
+ completion_tokens: z9.number().int().nonnegative(),
2520
+ total_tokens: z9.number().int().nonnegative()
2521
+ });
2522
+ var AzureOpenAiResponseToolCallSchema = z9.object({
2523
+ id: z9.string(),
2524
+ function: z9.object({
2525
+ name: z9.string(),
2526
+ arguments: z9.string()
2527
+ })
2528
+ });
2529
+ var AzureOpenAiChatCompletionResponseSchema = z9.object({
2530
+ choices: z9.array(
2531
+ z9.object({
2532
+ message: z9.object({
2533
+ content: z9.string().nullable(),
2534
+ tool_calls: z9.array(AzureOpenAiResponseToolCallSchema).optional()
2535
+ }),
2536
+ finish_reason: z9.string().nullable().optional()
2537
+ })
2538
+ ).min(1),
2539
+ usage: AzureOpenAiUsageSchema
2540
+ });
2541
+ function mapAzureOpenAiResponseToChatCompletionResult(response, latencyMs) {
2542
+ const toolCalls = extractAzureOpenAiToolCalls(response);
2543
+ const result = {
2544
+ content: extractAzureOpenAiMessageContent(response, toolCalls.length > 0),
2545
+ tokenUsage: mapAzureOpenAiUsageToTokenUsage(response.usage),
2546
+ latencyMs
1842
2547
  };
1843
- const systemText = joinBatchSystemMessageText(request.messages);
1844
- if (systemText.length > 0) {
1845
- params.system = systemText;
2548
+ const finishReason = response.choices[0]?.finish_reason;
2549
+ if (toolCalls.length > 0) {
2550
+ result.toolCalls = toolCalls;
1846
2551
  }
1847
- if (request.temperature !== void 0) {
1848
- params.temperature = request.temperature;
2552
+ if (finishReason !== null && finishReason !== void 0) {
2553
+ result.stopReason = normalizeAzureOpenAiFinishReason(finishReason);
1849
2554
  }
1850
- return { custom_id: request.customId, params };
2555
+ return result;
1851
2556
  }
1852
- function joinBatchSystemMessageText(messages) {
1853
- return messages.filter((message) => message.role === "system").map(extractMessageText).join("\n\n");
2557
+ function extractAzureOpenAiToolCalls(response) {
2558
+ const responseToolCalls = response.choices[0]?.message.tool_calls ?? [];
2559
+ return responseToolCalls.map((responseToolCall) => ({
2560
+ id: responseToolCall.id,
2561
+ toolName: responseToolCall.function.name,
2562
+ input: parseAzureOpenAiToolArgumentsJson(responseToolCall.function.arguments)
2563
+ }));
1854
2564
  }
1855
- function mapChatMessageToBatchApiRequestMessage(message) {
1856
- if (message.role === "assistant") {
1857
- return { role: "assistant", content: extractMessageText(message) };
2565
+ function parseAzureOpenAiToolArgumentsJson(argumentsJsonText) {
2566
+ if (argumentsJsonText.trim().length === 0) {
2567
+ return {};
1858
2568
  }
1859
- if (message.role === "tool") {
1860
- return { role: "user", content: buildBatchToolResultText(message) };
2569
+ try {
2570
+ return JsonValueSchema8.parse(JSON.parse(argumentsJsonText));
2571
+ } catch (error) {
2572
+ throw new AppError16({
2573
+ code: AppErrorCode15.ValidationFailed,
2574
+ message: "Azure OpenAI tool call arguments were not valid JSON",
2575
+ statusCode: 502,
2576
+ cause: error instanceof Error ? error : void 0
2577
+ });
1861
2578
  }
1862
- return { role: "user", content: extractMessageText(message) };
1863
2579
  }
1864
- function buildBatchToolResultText(message) {
1865
- if (message.toolName === void 0) {
1866
- return `Tool result: ${extractMessageText(message)}`;
2580
+ function normalizeAzureOpenAiFinishReason(finishReason) {
2581
+ if (finishReason === "tool_calls") {
2582
+ return "tool_use";
1867
2583
  }
1868
- return `Tool result (${message.toolName}): ${extractMessageText(message)}`;
2584
+ if (finishReason === "length") {
2585
+ return "max_tokens";
2586
+ }
2587
+ return "end_turn";
2588
+ }
2589
+ function extractAzureOpenAiMessageContent(response, allowEmptyContent) {
2590
+ const content = response.choices[0]?.message.content;
2591
+ if (content === void 0 || content === null) {
2592
+ if (allowEmptyContent) {
2593
+ return "";
2594
+ }
2595
+ throw new AppError16({
2596
+ code: AppErrorCode15.ValidationFailed,
2597
+ message: "Azure OpenAI response contained no message content",
2598
+ statusCode: 502
2599
+ });
2600
+ }
2601
+ return content;
2602
+ }
2603
+ function mapAzureOpenAiUsageToTokenUsage(usage) {
2604
+ return {
2605
+ inputTokens: usage.prompt_tokens,
2606
+ outputTokens: usage.completion_tokens,
2607
+ totalTokens: usage.total_tokens
2608
+ };
2609
+ }
2610
+
2611
+ // src/azure-openai-stream.ts
2612
+ import { z as z10 } from "zod";
2613
+ var AzureOpenAiStreamToolCallDeltaSchema = z10.object({
2614
+ index: z10.number().int().nonnegative(),
2615
+ id: z10.string().optional(),
2616
+ function: z10.object({
2617
+ name: z10.string().optional(),
2618
+ arguments: z10.string().optional()
2619
+ }).optional()
2620
+ });
2621
+ var AzureOpenAiStreamChunkSchema = z10.object({
2622
+ choices: z10.array(
2623
+ z10.object({
2624
+ delta: z10.object({
2625
+ content: z10.string().nullable().optional(),
2626
+ tool_calls: z10.array(AzureOpenAiStreamToolCallDeltaSchema).optional()
2627
+ }).optional(),
2628
+ finish_reason: z10.string().nullable().optional()
2629
+ })
2630
+ ).optional(),
2631
+ usage: AzureOpenAiUsageSchema.nullable().optional()
2632
+ });
2633
+ async function* streamAzureOpenAiChatCompletion(input) {
2634
+ const startedAt = Date.now();
2635
+ const response = await establishAzureOpenAiStreamResponse(input);
2636
+ if (response.body === null) {
2637
+ throw buildProviderInvalidResponseError("Azure OpenAI", "stream body");
2638
+ }
2639
+ yield* parseAzureOpenAiStreamEvents(
2640
+ response.body,
2641
+ startedAt,
2642
+ input.abortSignal
2643
+ );
2644
+ }
2645
+ async function establishAzureOpenAiStreamResponse(input) {
2646
+ return await executeProviderCallWithRetry(input.retry, async () => {
2647
+ const response = await executeAbortableProviderFetch(
2648
+ "Azure OpenAI",
2649
+ async () => await input.fetchImplementation(input.url, {
2650
+ method: "POST",
2651
+ headers: input.headers,
2652
+ body: JSON.stringify(input.body),
2653
+ signal: input.abortSignal
2654
+ })
2655
+ );
2656
+ if (!response.ok) {
2657
+ throw buildProviderStatusError("Azure OpenAI", response.status);
2658
+ }
2659
+ return response;
2660
+ });
2661
+ }
2662
+ async function* parseAzureOpenAiStreamEvents(body, startedAt, abortSignal) {
2663
+ const accumulator = createAzureOpenAiStreamAccumulator();
2664
+ for await (const dataText of readServerSentEventDataLines2(body, abortSignal)) {
2665
+ if (dataText === "[DONE]") {
2666
+ yield {
2667
+ type: "completed",
2668
+ result: buildAzureOpenAiStreamResult(
2669
+ accumulator,
2670
+ Date.now() - startedAt
2671
+ )
2672
+ };
2673
+ return;
2674
+ }
2675
+ const parsedChunk = AzureOpenAiStreamChunkSchema.safeParse(
2676
+ JSON.parse(dataText)
2677
+ );
2678
+ if (!parsedChunk.success) {
2679
+ continue;
2680
+ }
2681
+ yield* applyAzureOpenAiStreamChunk(parsedChunk.data, accumulator);
2682
+ }
2683
+ throw buildProviderInvalidResponseError("Azure OpenAI", "stream termination");
2684
+ }
2685
+ async function* readServerSentEventDataLines2(body, abortSignal) {
2686
+ const reader = body.getReader();
2687
+ const decoder = new TextDecoder();
2688
+ let bufferedText = "";
2689
+ try {
2690
+ for (; ; ) {
2691
+ if (abortSignal?.aborted === true) {
2692
+ await reader.cancel();
2693
+ throw buildProviderCanceledError("Azure OpenAI");
2694
+ }
2695
+ const readResult = await reader.read();
2696
+ if (readResult.done) {
2697
+ return;
2698
+ }
2699
+ bufferedText += decoder.decode(readResult.value, { stream: true });
2700
+ const lines = bufferedText.split("\n");
2701
+ bufferedText = lines.pop() ?? "";
2702
+ for (const line of lines) {
2703
+ if (line.startsWith("data:")) {
2704
+ const dataText = line.slice("data:".length).trim();
2705
+ if (dataText.length > 0) {
2706
+ yield dataText;
2707
+ }
2708
+ }
2709
+ }
2710
+ }
2711
+ } catch (error) {
2712
+ if (error instanceof Error && isAbortError(error)) {
2713
+ throw buildProviderCanceledError("Azure OpenAI");
2714
+ }
2715
+ throw error;
2716
+ }
2717
+ }
2718
+ function createAzureOpenAiStreamAccumulator() {
2719
+ return {
2720
+ contentText: "",
2721
+ toolCallsByIndex: /* @__PURE__ */ new Map()
2722
+ };
2723
+ }
2724
+ function* applyAzureOpenAiStreamChunk(chunk, accumulator) {
2725
+ if (chunk.usage !== null && chunk.usage !== void 0) {
2726
+ accumulator.usage = chunk.usage;
2727
+ }
2728
+ const choice = chunk.choices?.[0];
2729
+ if (choice === void 0) {
2730
+ return;
2731
+ }
2732
+ if (choice.finish_reason !== null && choice.finish_reason !== void 0) {
2733
+ accumulator.finishReason = choice.finish_reason;
2734
+ }
2735
+ if (choice.delta === void 0) {
2736
+ return;
2737
+ }
2738
+ const contentDelta = choice.delta.content;
2739
+ if (contentDelta !== null && contentDelta !== void 0 && contentDelta.length > 0) {
2740
+ accumulator.contentText += contentDelta;
2741
+ yield { type: "text_delta", text: contentDelta };
2742
+ }
2743
+ for (const toolCallDelta of choice.delta.tool_calls ?? []) {
2744
+ yield* applyAzureOpenAiToolCallDelta(toolCallDelta, accumulator);
2745
+ }
2746
+ }
2747
+ function* applyAzureOpenAiToolCallDelta(toolCallDelta, accumulator) {
2748
+ const existingToolCall = accumulator.toolCallsByIndex.get(toolCallDelta.index);
2749
+ if (existingToolCall === void 0) {
2750
+ yield* startAzureOpenAiToolCallAccumulation(toolCallDelta, accumulator);
2751
+ return;
2752
+ }
2753
+ const argumentsDelta = toolCallDelta.function?.arguments;
2754
+ if (argumentsDelta !== void 0 && argumentsDelta.length > 0) {
2755
+ existingToolCall.argumentsJsonText += argumentsDelta;
2756
+ yield {
2757
+ type: "tool_call_input_delta",
2758
+ id: existingToolCall.id,
2759
+ inputJsonText: argumentsDelta
2760
+ };
2761
+ }
2762
+ }
2763
+ function* startAzureOpenAiToolCallAccumulation(toolCallDelta, accumulator) {
2764
+ const toolName = toolCallDelta.function?.name;
2765
+ if (toolCallDelta.id === void 0 || toolName === void 0) {
2766
+ throw buildProviderInvalidResponseError(
2767
+ "Azure OpenAI",
2768
+ "stream tool call start"
2769
+ );
2770
+ }
2771
+ const startedToolCall = {
2772
+ id: toolCallDelta.id,
2773
+ toolName,
2774
+ argumentsJsonText: toolCallDelta.function?.arguments ?? ""
2775
+ };
2776
+ accumulator.toolCallsByIndex.set(toolCallDelta.index, startedToolCall);
2777
+ yield {
2778
+ type: "tool_call_started",
2779
+ id: startedToolCall.id,
2780
+ toolName: startedToolCall.toolName
2781
+ };
2782
+ if (startedToolCall.argumentsJsonText.length > 0) {
2783
+ yield {
2784
+ type: "tool_call_input_delta",
2785
+ id: startedToolCall.id,
2786
+ inputJsonText: startedToolCall.argumentsJsonText
2787
+ };
2788
+ }
2789
+ }
2790
+ function buildAzureOpenAiStreamResult(accumulator, latencyMs) {
2791
+ const result = {
2792
+ content: accumulator.contentText,
2793
+ tokenUsage: mapAzureOpenAiUsageToTokenUsage(
2794
+ accumulator.usage ?? {
2795
+ prompt_tokens: 0,
2796
+ completion_tokens: 0,
2797
+ total_tokens: 0
2798
+ }
2799
+ ),
2800
+ latencyMs
2801
+ };
2802
+ const toolCalls = [...accumulator.toolCallsByIndex.values()].map(
2803
+ mapAccumulatedToolCallToModelToolCall2
2804
+ );
2805
+ if (toolCalls.length > 0) {
2806
+ result.toolCalls = toolCalls;
2807
+ }
2808
+ if (accumulator.finishReason !== void 0) {
2809
+ result.stopReason = normalizeAzureOpenAiFinishReason(
2810
+ accumulator.finishReason
2811
+ );
2812
+ }
2813
+ return result;
2814
+ }
2815
+ function mapAccumulatedToolCallToModelToolCall2(toolCallAccumulation) {
2816
+ return {
2817
+ id: toolCallAccumulation.id,
2818
+ toolName: toolCallAccumulation.toolName,
2819
+ input: parseAzureOpenAiToolArgumentsJson(
2820
+ toolCallAccumulation.argumentsJsonText
2821
+ )
2822
+ };
2823
+ }
2824
+
2825
+ // src/azure-openai-adapter.ts
2826
+ var defaultAzureOpenAiApiVersion = "2024-10-21";
2827
+ var azureDeploymentModelPlaceholder = "azure-deployment";
2828
+ function azureOpenai(options) {
2829
+ return {
2830
+ name: `azure-openai:${options.deployment}`,
2831
+ async generateChatCompletion(request) {
2832
+ return await executeAzureOpenAiAdapterCall(options, {
2833
+ messages: request.messages,
2834
+ temperature: request.temperature ?? options.temperature,
2835
+ maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
2836
+ tools: request.tools,
2837
+ toolChoice: request.toolChoice,
2838
+ abortSignal: request.abortSignal,
2839
+ extraBody: request.extraBody
2840
+ });
2841
+ },
2842
+ async generateStructuredOutput(request) {
2843
+ const completion = await executeAzureOpenAiAdapterCall(options, {
2844
+ messages: request.messages,
2845
+ temperature: request.temperature ?? options.temperature,
2846
+ maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
2847
+ structuredOutputJsonSchema: buildOpenAiStructuredOutputJsonSchema(
2848
+ request.schema
2849
+ ),
2850
+ abortSignal: request.abortSignal
2851
+ });
2852
+ return {
2853
+ value: parseStructuredJsonText(completion.content, request.schema),
2854
+ tokenUsage: completion.tokenUsage,
2855
+ latencyMs: completion.latencyMs
2856
+ };
2857
+ },
2858
+ streamChatCompletion(request) {
2859
+ return streamAzureOpenAiChatCompletion(
2860
+ buildAzureOpenAiStreamInput(options, request)
2861
+ );
2862
+ }
2863
+ };
2864
+ }
2865
+ function buildAzureOpenAiChatCompletionsUrl(options) {
2866
+ const endpoint = resolveAzureOpenAiEndpoint(options);
2867
+ const apiVersion = options.apiVersion ?? defaultAzureOpenAiApiVersion;
2868
+ return `${endpoint}/openai/deployments/${encodeURIComponent(options.deployment)}/chat/completions?api-version=${encodeURIComponent(apiVersion)}`;
2869
+ }
2870
+ function resolveAzureOpenAiEndpoint(options) {
2871
+ if (options.baseURL !== void 0 && options.baseURL.length > 0) {
2872
+ return options.baseURL.replace(/\/+$/, "");
2873
+ }
2874
+ if (options.resourceName !== void 0 && options.resourceName.length > 0) {
2875
+ return `https://${options.resourceName}.openai.azure.com`;
2876
+ }
2877
+ throw new AppError17({
2878
+ code: AppErrorCode16.BadRequest,
2879
+ message: "Azure OpenAI endpoint is missing. Pass resourceName or baseURL to azureOpenai().",
2880
+ statusCode: 400
2881
+ });
2882
+ }
2883
+ function buildAzureOpenAiRequestHeaders(options) {
2884
+ return {
2885
+ "content-type": "application/json",
2886
+ "api-key": resolveProviderApiKey({
2887
+ providerLabel: "Azure OpenAI",
2888
+ adapterFunctionName: "azureOpenai()",
2889
+ baseEnvVarName: "AZURE_OPENAI_API_KEY",
2890
+ apiKey: options.apiKey,
2891
+ apiKeyName: options.apiKeyName
2892
+ })
2893
+ };
2894
+ }
2895
+ function buildAzureOpenAiChatRequestBody(input) {
2896
+ const requestBody = buildOpenAiRequestBody(
2897
+ azureDeploymentModelPlaceholder,
2898
+ input
2899
+ );
2900
+ const { model: ignoredModel, ...requestBodyWithoutModel } = requestBody;
2901
+ void ignoredModel;
2902
+ return requestBodyWithoutModel;
2903
+ }
2904
+ async function executeAzureOpenAiAdapterCall(options, input) {
2905
+ return await executeProviderCallWithRetry(
2906
+ options.retry,
2907
+ async () => await requestAzureOpenAiChatCompletion(options, input)
2908
+ );
2909
+ }
2910
+ async function requestAzureOpenAiChatCompletion(options, input) {
2911
+ const fetchImplementation = options.fetchImplementation ?? fetch;
2912
+ const requestBody = mergeProviderRequestExtraBody(
2913
+ buildAzureOpenAiChatRequestBody(input),
2914
+ options.extraBody,
2915
+ input.extraBody
2916
+ );
2917
+ const startedAt = Date.now();
2918
+ const response = await executeAbortableProviderFetch(
2919
+ "Azure OpenAI",
2920
+ async () => await fetchImplementation(buildAzureOpenAiChatCompletionsUrl(options), {
2921
+ method: "POST",
2922
+ headers: buildAzureOpenAiRequestHeaders(options),
2923
+ body: JSON.stringify(requestBody),
2924
+ signal: input.abortSignal
2925
+ })
2926
+ );
2927
+ const latencyMs = Date.now() - startedAt;
2928
+ if (!response.ok) {
2929
+ throw buildProviderStatusError("Azure OpenAI", response.status);
2930
+ }
2931
+ const parseResult = AzureOpenAiChatCompletionResponseSchema.safeParse(
2932
+ await response.json()
2933
+ );
2934
+ if (!parseResult.success) {
2935
+ throw buildProviderInvalidResponseError("Azure OpenAI", "chat completion");
2936
+ }
2937
+ return mapAzureOpenAiResponseToChatCompletionResult(
2938
+ parseResult.data,
2939
+ latencyMs
2940
+ );
2941
+ }
2942
+ function buildAzureOpenAiStreamInput(options, request) {
2943
+ const requestBody = mergeProviderRequestExtraBody(
2944
+ buildAzureOpenAiChatRequestBody({
2945
+ messages: request.messages,
2946
+ temperature: request.temperature ?? options.temperature,
2947
+ maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
2948
+ tools: request.tools,
2949
+ toolChoice: request.toolChoice,
2950
+ abortSignal: request.abortSignal,
2951
+ extraBody: request.extraBody
2952
+ }),
2953
+ options.extraBody,
2954
+ request.extraBody
2955
+ );
2956
+ return {
2957
+ url: buildAzureOpenAiChatCompletionsUrl(options),
2958
+ headers: buildAzureOpenAiRequestHeaders(options),
2959
+ body: {
2960
+ ...requestBody,
2961
+ stream: true,
2962
+ stream_options: { include_usage: true }
2963
+ },
2964
+ fetchImplementation: options.fetchImplementation ?? fetch,
2965
+ retry: options.retry,
2966
+ abortSignal: request.abortSignal
2967
+ };
2968
+ }
2969
+
2970
+ // src/bedrock-adapter.ts
2971
+ import { z as z11 } from "zod";
2972
+ import { AppErrorCode as AppErrorCode17 } from "@assemble-dev/shared-types/errors";
2973
+ import { AppError as AppError18 } from "@assemble-dev/shared-utils/errors";
2974
+
2975
+ // src/bedrock-sigv4.ts
2976
+ var awsSigV4Algorithm = "AWS4-HMAC-SHA256";
2977
+ async function signAwsRequestWithSigV4(input) {
2978
+ const amzDate = formatAmzDateTime(input.signingDate ?? /* @__PURE__ */ new Date());
2979
+ const dateStamp = amzDate.slice(0, 8);
2980
+ const headersToSign = buildHeadersToSign(input, amzDate);
2981
+ const canonicalHeaderEntries = buildCanonicalHeaderEntries(headersToSign);
2982
+ const signedHeaderNames = canonicalHeaderEntries.map(([headerName]) => headerName).join(";");
2983
+ const credentialScope = `${dateStamp}/${input.region}/${input.service}/aws4_request`;
2984
+ const signatureHex = await computeAwsSigV4Signature(
2985
+ input,
2986
+ amzDate,
2987
+ credentialScope,
2988
+ canonicalHeaderEntries,
2989
+ signedHeaderNames
2990
+ );
2991
+ return {
2992
+ ...headersToSign,
2993
+ authorization: `${awsSigV4Algorithm} Credential=${input.credentials.accessKeyId}/${credentialScope}, SignedHeaders=${signedHeaderNames}, Signature=${signatureHex}`
2994
+ };
2995
+ }
2996
+ async function computeAwsSigV4Signature(input, amzDate, credentialScope, canonicalHeaderEntries, signedHeaderNames) {
2997
+ const canonicalRequest = await buildCanonicalRequest(
2998
+ input,
2999
+ canonicalHeaderEntries,
3000
+ signedHeaderNames
3001
+ );
3002
+ const stringToSign = [
3003
+ awsSigV4Algorithm,
3004
+ amzDate,
3005
+ credentialScope,
3006
+ await hashSha256Hex(canonicalRequest)
3007
+ ].join("\n");
3008
+ const signingKey = await deriveAwsSigningKey(
3009
+ input.credentials.secretAccessKey,
3010
+ amzDate.slice(0, 8),
3011
+ input.region,
3012
+ input.service
3013
+ );
3014
+ return bytesToHex(await computeHmacSha256(signingKey, stringToSign));
3015
+ }
3016
+ function buildHeadersToSign(input, amzDate) {
3017
+ const headersToSign = {};
3018
+ for (const [headerName, headerValue] of Object.entries(input.headers)) {
3019
+ headersToSign[headerName.toLowerCase()] = headerValue;
3020
+ }
3021
+ headersToSign.host = input.url.host;
3022
+ headersToSign["x-amz-date"] = amzDate;
3023
+ if (input.credentials.sessionToken !== void 0) {
3024
+ headersToSign["x-amz-security-token"] = input.credentials.sessionToken;
3025
+ }
3026
+ return headersToSign;
3027
+ }
3028
+ function buildCanonicalHeaderEntries(headersToSign) {
3029
+ return Object.entries(headersToSign).map(([headerName, headerValue]) => [
3030
+ headerName.toLowerCase(),
3031
+ headerValue.trim().replace(/\s+/g, " ")
3032
+ ]).sort(([leftName], [rightName]) => leftName.localeCompare(rightName));
3033
+ }
3034
+ async function buildCanonicalRequest(input, canonicalHeaderEntries, signedHeaderNames) {
3035
+ const canonicalHeadersText = canonicalHeaderEntries.map(([headerName, headerValue]) => `${headerName}:${headerValue}`).join("\n");
3036
+ return [
3037
+ input.method.toUpperCase(),
3038
+ buildCanonicalUri(input.url.pathname),
3039
+ buildCanonicalQueryString(input.url.searchParams),
3040
+ `${canonicalHeadersText}
3041
+ `,
3042
+ signedHeaderNames,
3043
+ await hashSha256Hex(input.bodyText)
3044
+ ].join("\n");
3045
+ }
3046
+ function buildCanonicalUri(pathname) {
3047
+ if (pathname.length === 0) {
3048
+ return "/";
3049
+ }
3050
+ return pathname.split("/").map(encodeRfc3986UriComponent).join("/");
3051
+ }
3052
+ function buildCanonicalQueryString(searchParams) {
3053
+ const encodedEntries = [];
3054
+ searchParams.forEach((parameterValue, parameterName) => {
3055
+ encodedEntries.push([
3056
+ encodeRfc3986UriComponent(parameterName),
3057
+ encodeRfc3986UriComponent(parameterValue)
3058
+ ]);
3059
+ });
3060
+ return encodedEntries.sort(
3061
+ ([leftName, leftValue], [rightName, rightValue]) => leftName.localeCompare(rightName) || leftValue.localeCompare(rightValue)
3062
+ ).map(([parameterName, parameterValue]) => `${parameterName}=${parameterValue}`).join("&");
3063
+ }
3064
+ function encodeRfc3986UriComponent(value) {
3065
+ return encodeURIComponent(value).replace(
3066
+ /[!'()*]/g,
3067
+ (character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`
3068
+ );
3069
+ }
3070
+ function formatAmzDateTime(date) {
3071
+ return date.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
3072
+ }
3073
+ async function deriveAwsSigningKey(secretAccessKey, dateStamp, region, service) {
3074
+ const dateKey = await computeHmacSha256(
3075
+ new TextEncoder().encode(`AWS4${secretAccessKey}`),
3076
+ dateStamp
3077
+ );
3078
+ const regionKey = await computeHmacSha256(dateKey, region);
3079
+ const serviceKey = await computeHmacSha256(regionKey, service);
3080
+ return await computeHmacSha256(serviceKey, "aws4_request");
3081
+ }
3082
+ async function hashSha256Hex(text) {
3083
+ const digest = await crypto.subtle.digest(
3084
+ "SHA-256",
3085
+ new TextEncoder().encode(text)
3086
+ );
3087
+ return bytesToHex(new Uint8Array(digest));
3088
+ }
3089
+ async function computeHmacSha256(keyBytes, text) {
3090
+ const hmacKey = await crypto.subtle.importKey(
3091
+ "raw",
3092
+ keyBytes,
3093
+ { name: "HMAC", hash: "SHA-256" },
3094
+ false,
3095
+ ["sign"]
3096
+ );
3097
+ const signature = await crypto.subtle.sign(
3098
+ "HMAC",
3099
+ hmacKey,
3100
+ new TextEncoder().encode(text)
3101
+ );
3102
+ return new Uint8Array(signature);
3103
+ }
3104
+ function bytesToHex(bytes) {
3105
+ return Array.from(bytes).map((byteValue) => byteValue.toString(16).padStart(2, "0")).join("");
3106
+ }
3107
+
3108
+ // src/bedrock-adapter.ts
3109
+ var bedrockAnthropicVersion = "bedrock-2023-05-31";
3110
+ var defaultBedrockMaxOutputTokens = 1024;
3111
+ var bedrockSigningServiceName = "bedrock";
3112
+ var bedrockModelPlaceholder = "bedrock-invoke-model";
3113
+ var BedrockEnvCredentialsSchema = z11.object({
3114
+ AWS_ACCESS_KEY_ID: z11.string().optional(),
3115
+ AWS_SECRET_ACCESS_KEY: z11.string().optional(),
3116
+ AWS_SESSION_TOKEN: z11.string().optional()
3117
+ });
3118
+ function bedrock(options) {
3119
+ return {
3120
+ name: `bedrock:${options.modelId}`,
3121
+ async generateChatCompletion(request) {
3122
+ return await executeBedrockAdapterCall(options, {
3123
+ messages: request.messages,
3124
+ temperature: request.temperature ?? options.temperature,
3125
+ maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
3126
+ tools: request.tools,
3127
+ toolChoice: request.toolChoice,
3128
+ abortSignal: request.abortSignal,
3129
+ extraBody: request.extraBody
3130
+ });
3131
+ },
3132
+ async generateStructuredOutput(request) {
3133
+ const completion = await executeBedrockAdapterCall(options, {
3134
+ messages: [
3135
+ buildBedrockStructuredOutputSystemMessage(request.schema),
3136
+ ...request.messages
3137
+ ],
3138
+ temperature: request.temperature ?? options.temperature,
3139
+ maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
3140
+ abortSignal: request.abortSignal
3141
+ });
3142
+ return {
3143
+ value: parseStructuredJsonText(completion.content, request.schema),
3144
+ tokenUsage: completion.tokenUsage,
3145
+ latencyMs: completion.latencyMs
3146
+ };
3147
+ }
3148
+ };
3149
+ }
3150
+ function buildBedrockInvokeModelUrl(region, modelId) {
3151
+ return `https://bedrock-runtime.${region}.amazonaws.com/model/${encodeURIComponent(modelId)}/invoke`;
3152
+ }
3153
+ function resolveBedrockCredentials(options) {
3154
+ if (options.credentials !== void 0) {
3155
+ return options.credentials;
3156
+ }
3157
+ const parsedEnv = BedrockEnvCredentialsSchema.parse(process.env);
3158
+ const accessKeyId = parsedEnv.AWS_ACCESS_KEY_ID;
3159
+ const secretAccessKey = parsedEnv.AWS_SECRET_ACCESS_KEY;
3160
+ if (accessKeyId === void 0 || accessKeyId.length === 0 || secretAccessKey === void 0 || secretAccessKey.length === 0) {
3161
+ throw new AppError18({
3162
+ code: AppErrorCode17.Unauthorized,
3163
+ message: "AWS credentials are missing. Pass credentials to bedrock() or set the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables.",
3164
+ statusCode: 401
3165
+ });
3166
+ }
3167
+ const credentials = { accessKeyId, secretAccessKey };
3168
+ const sessionToken = parsedEnv.AWS_SESSION_TOKEN;
3169
+ if (sessionToken !== void 0 && sessionToken.length > 0) {
3170
+ credentials.sessionToken = sessionToken;
3171
+ }
3172
+ return credentials;
3173
+ }
3174
+ async function executeBedrockAdapterCall(options, input) {
3175
+ return await executeProviderCallWithRetry(
3176
+ options.retry,
3177
+ async () => await requestBedrockInvokeModel(options, input)
3178
+ );
3179
+ }
3180
+ async function requestBedrockInvokeModel(options, input) {
3181
+ const credentials = resolveBedrockCredentials(options);
3182
+ const fetchImplementation = options.fetchImplementation ?? fetch;
3183
+ const requestBody = mergeProviderRequestExtraBody(
3184
+ buildBedrockInvokeModelRequestBody(input),
3185
+ options.extraBody,
3186
+ input.extraBody
3187
+ );
3188
+ const bodyText = JSON.stringify(requestBody);
3189
+ const url = new URL(buildBedrockInvokeModelUrl(options.region, options.modelId));
3190
+ const signedHeaders = await signAwsRequestWithSigV4({
3191
+ method: "POST",
3192
+ url,
3193
+ headers: { "content-type": "application/json" },
3194
+ bodyText,
3195
+ region: options.region,
3196
+ service: bedrockSigningServiceName,
3197
+ credentials
3198
+ });
3199
+ const startedAt = Date.now();
3200
+ const response = await executeAbortableProviderFetch(
3201
+ "Bedrock",
3202
+ async () => await fetchImplementation(url.toString(), {
3203
+ method: "POST",
3204
+ headers: signedHeaders,
3205
+ body: bodyText,
3206
+ signal: input.abortSignal
3207
+ })
3208
+ );
3209
+ const latencyMs = Date.now() - startedAt;
3210
+ if (!response.ok) {
3211
+ throw buildProviderStatusError("Bedrock", response.status);
3212
+ }
3213
+ const parseResult = AnthropicMessagesResponseSchema.safeParse(
3214
+ await response.json()
3215
+ );
3216
+ if (!parseResult.success) {
3217
+ throw buildProviderInvalidResponseError("Bedrock", "invoke model");
3218
+ }
3219
+ return mapAnthropicResponseToChatCompletionResult(parseResult.data, latencyMs);
3220
+ }
3221
+ function buildBedrockInvokeModelRequestBody(input) {
3222
+ const anthropicRequestBody = buildAnthropicRequestBody(
3223
+ {
3224
+ model: bedrockModelPlaceholder,
3225
+ defaultMaxOutputTokens: defaultBedrockMaxOutputTokens
3226
+ },
3227
+ input
3228
+ );
3229
+ const {
3230
+ model: ignoredModel,
3231
+ stream: ignoredStream,
3232
+ ...requestBodyWithoutModel
3233
+ } = anthropicRequestBody;
3234
+ void ignoredModel;
3235
+ void ignoredStream;
3236
+ return {
3237
+ ...requestBodyWithoutModel,
3238
+ anthropic_version: bedrockAnthropicVersion
3239
+ };
3240
+ }
3241
+ function buildBedrockStructuredOutputSystemMessage(schema) {
3242
+ return {
3243
+ role: "system",
3244
+ content: `Respond with a single JSON object that satisfies the following JSON Schema. Output only valid JSON with no surrounding text.
3245
+
3246
+ JSON Schema:
3247
+ ${JSON.stringify(convertZodSchemaToJsonSchema(schema))}`
3248
+ };
1869
3249
  }
1870
3250
  export {
1871
3251
  AnthropicMessagesResponseSchema,
1872
3252
  AnthropicStreamEventSchema,
3253
+ AzureOpenAiChatCompletionResponseSchema,
3254
+ ChatMessageCacheControlSchema,
1873
3255
  ChatMessageRoleSchema,
1874
3256
  ChatMessageSchema,
1875
3257
  ChatStopReasonSchema,
1876
3258
  MessageContentBlockSchema,
1877
3259
  ModelToolCallSchema,
1878
3260
  anthropic,
3261
+ anthropicBatchJsonOnlySystemInstruction,
3262
+ anthropicBatchTraceWorkflowName,
3263
+ applyCacheControlToLastContentBlock,
3264
+ awsSigV4Algorithm,
3265
+ azureOpenai,
3266
+ bedrock,
3267
+ bedrockAnthropicVersion,
3268
+ buildAnthropicCacheControl,
1879
3269
  buildAnthropicRequestBody,
3270
+ buildAnthropicStructuredOutputJsonSchema,
3271
+ buildAzureOpenAiChatCompletionsUrl,
3272
+ buildAzureOpenAiChatRequestBody,
3273
+ buildBedrockInvokeModelRequestBody,
3274
+ buildBedrockInvokeModelUrl,
3275
+ buildGeminiResponseSchema,
1880
3276
  buildOpenAiRequestBody,
3277
+ buildOpenAiStructuredOutputJsonSchema,
1881
3278
  buildProviderCanceledError,
1882
3279
  calculateProviderRetryDelayMs,
3280
+ convertZodSchemaToJsonSchema,
1883
3281
  createAnthropicBatchClient,
1884
3282
  defaultAnthropicBaseUrl,
1885
3283
  defaultAnthropicBatchPollIntervalMs,
1886
3284
  defaultAnthropicBatchTimeoutMs,
1887
3285
  defaultAnthropicMaxOutputTokens,
3286
+ defaultAzureOpenAiApiVersion,
3287
+ defaultBedrockMaxOutputTokens,
1888
3288
  defaultGeminiBaseUrl,
1889
3289
  defaultOpenAiBaseUrl,
1890
3290
  defaultProviderRetryInitialDelayMs,
@@ -1895,6 +3295,7 @@ export {
1895
3295
  executeProviderCallWithModelFallback,
1896
3296
  executeProviderCallWithRetry,
1897
3297
  extractAnthropicTextContent,
3298
+ extractAnthropicThinkingText,
1898
3299
  extractAnthropicToolCalls,
1899
3300
  extractMessageText,
1900
3301
  gemini,
@@ -1903,17 +3304,32 @@ export {
1903
3304
  joinSystemMessageText,
1904
3305
  mapAnthropicResponseToChatCompletionResult,
1905
3306
  mapAnthropicUsageToTokenUsage,
3307
+ mapAzureOpenAiResponseToChatCompletionResult,
3308
+ mapAzureOpenAiUsageToTokenUsage,
1906
3309
  mapChatMessageToAnthropicRequestMessage,
1907
3310
  mapChatMessageToOpenAiRequestMessage,
1908
3311
  mapModelToolChoiceToAnthropicToolChoice,
1909
3312
  mapModelToolChoiceToOpenAiToolChoice,
1910
3313
  mapModelToolDefinitionToOpenAiTool,
1911
3314
  mapModelToolDefinitionsToAnthropicTools,
3315
+ mergeProviderRequestExtraBody,
1912
3316
  mockModel,
1913
3317
  normalizeAnthropicStopReason,
3318
+ normalizeAzureOpenAiFinishReason,
3319
+ openAiStructuredOutputSchemaName,
1914
3320
  openai,
3321
+ parseAnthropicBatchStructuredContent,
1915
3322
  parseAnthropicStreamEvents,
1916
3323
  parseAnthropicToolInputJson,
3324
+ parseAzureOpenAiStreamEvents,
3325
+ parseAzureOpenAiToolArgumentsJson,
3326
+ resolveAnthropicPromptCachingSettings,
3327
+ resolveBedrockCredentials,
1917
3328
  resolveProviderApiKey,
1918
- streamAnthropicChatCompletion
3329
+ sanitizeJsonSchemaForAnthropicStructuredOutput,
3330
+ sanitizeJsonSchemaForGeminiResponseSchema,
3331
+ sanitizeJsonSchemaForOpenAiStructuredOutput,
3332
+ signAwsRequestWithSigV4,
3333
+ streamAnthropicChatCompletion,
3334
+ streamAzureOpenAiChatCompletion
1919
3335
  };