@assemble-dev/providers 0.2.0 → 0.3.1

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
@@ -53,28 +53,306 @@ function extractMessageText(message) {
53
53
  }
54
54
 
55
55
  // src/openai-adapter.ts
56
- import { z as z3 } from "zod";
57
- 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";
58
58
  import { JsonValueSchema as JsonValueSchema3 } from "@assemble-dev/shared-types/json";
59
- import { AppError as AppError8 } from "@assemble-dev/shared-utils/errors";
59
+ import { AppError as AppError9 } from "@assemble-dev/shared-utils/errors";
60
60
 
61
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";
62
67
  import { AppErrorCode } from "@assemble-dev/shared-types/errors";
68
+ import { JsonObjectSchema } from "@assemble-dev/shared-types/json";
63
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 isZodV4Schema(schema) {
208
+ return "_zod" in schema;
209
+ }
210
+ function convertZodSchemaToJsonSchema(schema) {
211
+ try {
212
+ return JsonObjectSchema.parse(z2.toJSONSchema(schema, { io: "input" }));
213
+ } catch (error) {
214
+ throw new AppError({
215
+ code: AppErrorCode.BadRequest,
216
+ message: "Structured output schema could not be converted to JSON Schema",
217
+ statusCode: 400,
218
+ cause: error instanceof Error ? error : void 0
219
+ });
220
+ }
221
+ }
222
+ function buildAnthropicStructuredOutputJsonSchema(schema) {
223
+ return sanitizeJsonSchemaForAnthropicStructuredOutput(
224
+ convertZodSchemaToJsonSchema(schema)
225
+ );
226
+ }
227
+ function sanitizeJsonSchemaForAnthropicStructuredOutput(jsonSchema) {
228
+ return transformJsonSchemaNode(
229
+ inlineJsonSchemaReferences(jsonSchema),
230
+ sanitizeAnthropicSchemaNode
231
+ );
232
+ }
233
+ function buildOpenAiStructuredOutputJsonSchema(schema) {
234
+ return sanitizeJsonSchemaForOpenAiStructuredOutput(
235
+ convertZodSchemaToJsonSchema(schema)
236
+ );
237
+ }
238
+ function sanitizeJsonSchemaForOpenAiStructuredOutput(jsonSchema) {
239
+ return transformJsonSchemaNode(jsonSchema, sanitizeOpenAiSchemaNode);
240
+ }
241
+ function sanitizeAnthropicSchemaNode(node) {
242
+ const sanitized = removeJsonSchemaKeywords(
243
+ node,
244
+ anthropicUnsupportedSchemaKeywords
245
+ );
246
+ if (sanitized["type"] === "object") {
247
+ sanitized["additionalProperties"] = false;
248
+ }
249
+ return sanitized;
250
+ }
251
+ function sanitizeOpenAiSchemaNode(node) {
252
+ const sanitized = removeJsonSchemaKeywords(
253
+ node,
254
+ openAiUnsupportedSchemaKeywords
255
+ );
256
+ if (sanitized["type"] !== "object") {
257
+ return sanitized;
258
+ }
259
+ sanitized["additionalProperties"] = false;
260
+ const propertyNames = listSchemaPropertyNames(sanitized);
261
+ if (propertyNames.length > 0) {
262
+ sanitized["required"] = propertyNames;
263
+ }
264
+ return sanitized;
265
+ }
266
+ function listSchemaPropertyNames(node) {
267
+ const properties = node["properties"];
268
+ if (properties === void 0 || !isJsonObject(properties)) {
269
+ return [];
270
+ }
271
+ return Object.keys(properties);
272
+ }
273
+
274
+ // src/structured-output-fallback.ts
275
+ var structuredOutputJsonOnlySystemInstruction = "Respond with a single JSON object that satisfies the caller's requested structure. Output only valid JSON with no surrounding text.";
276
+ var structuredOutputJsonOnlySystemMessage = {
277
+ role: "system",
278
+ content: structuredOutputJsonOnlySystemInstruction
279
+ };
280
+ function prependStructuredOutputJsonOnlySystemMessage(messages) {
281
+ return [structuredOutputJsonOnlySystemMessage, ...messages];
282
+ }
283
+
284
+ // src/openai-request-mapping.ts
285
+ var openAiReasoningModelNamePrefixes = [
286
+ "gpt-5",
287
+ "o1",
288
+ "o3",
289
+ "o4"
290
+ ];
291
+ function isOpenAiReasoningModel(model) {
292
+ return openAiReasoningModelNamePrefixes.some(
293
+ (prefix) => matchesOpenAiModelNamePrefix(model, prefix)
294
+ );
295
+ }
296
+ function matchesOpenAiModelNamePrefix(model, prefix) {
297
+ if (!model.startsWith(prefix)) {
298
+ return false;
299
+ }
300
+ const boundaryCharacter = model.charAt(prefix.length);
301
+ return boundaryCharacter === "" || boundaryCharacter === "-" || boundaryCharacter === ".";
302
+ }
303
+ function resolveOpenAiStructuredOutputMode(messages, schema) {
304
+ if (isZodV4Schema(schema)) {
305
+ return {
306
+ messages,
307
+ structuredOutputJsonSchema: buildOpenAiStructuredOutputJsonSchema(schema)
308
+ };
309
+ }
310
+ return {
311
+ messages: prependStructuredOutputJsonOnlySystemMessage(messages),
312
+ requireJsonObjectResponse: true
313
+ };
314
+ }
64
315
  function buildOpenAiRequestBody(model, input) {
65
316
  const requestBody = {
66
317
  model,
67
318
  messages: input.messages.map(mapChatMessageToOpenAiRequestMessage)
68
319
  };
69
- if (input.temperature !== void 0) {
320
+ applyOpenAiGenerationSettings(requestBody, model, input);
321
+ applyOpenAiResponseFormat(requestBody, input);
322
+ applyOpenAiToolFields(requestBody, input);
323
+ return requestBody;
324
+ }
325
+ function applyOpenAiGenerationSettings(requestBody, model, input) {
326
+ const reasoningModel = input.reasoningModel ?? isOpenAiReasoningModel(model);
327
+ if (input.temperature !== void 0 && !reasoningModel) {
70
328
  requestBody.temperature = input.temperature;
71
329
  }
72
- if (input.maxOutputTokens !== void 0) {
73
- requestBody.max_tokens = input.maxOutputTokens;
330
+ if (input.maxOutputTokens === void 0) {
331
+ return;
332
+ }
333
+ if (reasoningModel) {
334
+ requestBody.max_completion_tokens = input.maxOutputTokens;
335
+ return;
336
+ }
337
+ requestBody.max_tokens = input.maxOutputTokens;
338
+ }
339
+ function applyOpenAiResponseFormat(requestBody, input) {
340
+ if (input.structuredOutputJsonSchema !== void 0) {
341
+ requestBody.response_format = {
342
+ type: "json_schema",
343
+ json_schema: {
344
+ name: openAiStructuredOutputSchemaName,
345
+ strict: true,
346
+ schema: input.structuredOutputJsonSchema
347
+ }
348
+ };
349
+ return;
74
350
  }
75
- if (input.requireJsonObjectResponse) {
351
+ if (input.requireJsonObjectResponse === true) {
76
352
  requestBody.response_format = { type: "json_object" };
77
353
  }
354
+ }
355
+ function applyOpenAiToolFields(requestBody, input) {
78
356
  if (input.tools !== void 0 && input.tools.length > 0) {
79
357
  requestBody.tools = input.tools.map(mapModelToolDefinitionToOpenAiTool);
80
358
  }
@@ -83,7 +361,6 @@ function buildOpenAiRequestBody(model, input) {
83
361
  input.toolChoice
84
362
  );
85
363
  }
86
- return requestBody;
87
364
  }
88
365
  function mapModelToolDefinitionToOpenAiTool(tool) {
89
366
  return {
@@ -158,17 +435,17 @@ function mapMessageContentBlockToOpenAiContentPart(contentBlock) {
158
435
  }
159
436
  };
160
437
  }
161
- throw new AppError({
162
- code: AppErrorCode.ValidationFailed,
438
+ throw new AppError2({
439
+ code: AppErrorCode2.ValidationFailed,
163
440
  message: "OpenAI adapter does not support document content blocks in chat messages",
164
441
  statusCode: 400
165
442
  });
166
443
  }
167
444
 
168
445
  // src/parse-structured-json.ts
169
- import { AppErrorCode as AppErrorCode2 } from "@assemble-dev/shared-types/errors";
446
+ import { AppErrorCode as AppErrorCode3 } from "@assemble-dev/shared-types/errors";
170
447
  import { JsonValueSchema as JsonValueSchema2 } from "@assemble-dev/shared-types/json";
171
- import { AppError as AppError2 } from "@assemble-dev/shared-utils/errors";
448
+ import { AppError as AppError3 } from "@assemble-dev/shared-utils/errors";
172
449
  var markdownCodeFencePattern = /^```[A-Za-z]*\s*\n?([\s\S]*?)\n?```$/;
173
450
  function parseStructuredJsonText(text, schema) {
174
451
  return schema.parse(parseJsonText(stripMarkdownCodeFences(text)));
@@ -185,8 +462,8 @@ function parseJsonText(text) {
185
462
  try {
186
463
  return JsonValueSchema2.parse(JSON.parse(text));
187
464
  } catch (error) {
188
- throw new AppError2({
189
- code: AppErrorCode2.ValidationFailed,
465
+ throw new AppError3({
466
+ code: AppErrorCode3.ValidationFailed,
190
467
  message: "Structured output was not valid JSON",
191
468
  statusCode: 422,
192
469
  cause: error instanceof Error ? error : void 0
@@ -195,9 +472,9 @@ function parseJsonText(text) {
195
472
  }
196
473
 
197
474
  // src/provider-api-key.ts
198
- import { z as z2 } from "zod";
199
- import { AppErrorCode as AppErrorCode3 } from "@assemble-dev/shared-types/errors";
200
- import { AppError as AppError3 } from "@assemble-dev/shared-utils/errors";
475
+ import { z as z3 } from "zod";
476
+ import { AppErrorCode as AppErrorCode4 } from "@assemble-dev/shared-types/errors";
477
+ import { AppError as AppError4 } from "@assemble-dev/shared-utils/errors";
201
478
  import {
202
479
  buildNamedApiKeyEnvVarName,
203
480
  expectedProviderApiKeyNameFormat,
@@ -214,8 +491,8 @@ function resolveProviderApiKey(input) {
214
491
  }
215
492
  function resolveNamedProviderApiKeyFromEnv(input, apiKeyName) {
216
493
  if (!validateProviderApiKeyName(apiKeyName)) {
217
- throw new AppError3({
218
- code: AppErrorCode3.BadRequest,
494
+ throw new AppError4({
495
+ code: AppErrorCode4.BadRequest,
219
496
  message: `Invalid ${input.providerLabel} apiKeyName "${apiKeyName}". Expected ${expectedProviderApiKeyNameFormat}.`,
220
497
  statusCode: 400
221
498
  });
@@ -223,8 +500,8 @@ function resolveNamedProviderApiKeyFromEnv(input, apiKeyName) {
223
500
  const envVarName = buildNamedApiKeyEnvVarName(input.baseEnvVarName, apiKeyName);
224
501
  const envApiKey = readEnvironmentVariable(envVarName);
225
502
  if (envApiKey === void 0 || envApiKey.length === 0) {
226
- throw new AppError3({
227
- code: AppErrorCode3.Unauthorized,
503
+ throw new AppError4({
504
+ code: AppErrorCode4.Unauthorized,
228
505
  message: `${input.providerLabel} API key named "${apiKeyName}" is missing. Set the ${envVarName} environment variable or pass apiKey to ${input.adapterFunctionName}.`,
229
506
  statusCode: 401
230
507
  });
@@ -234,8 +511,8 @@ function resolveNamedProviderApiKeyFromEnv(input, apiKeyName) {
234
511
  function resolveBaseProviderApiKeyFromEnv(input) {
235
512
  const envApiKey = readEnvironmentVariable(input.baseEnvVarName);
236
513
  if (envApiKey === void 0 || envApiKey.length === 0) {
237
- throw new AppError3({
238
- code: AppErrorCode3.Unauthorized,
514
+ throw new AppError4({
515
+ code: AppErrorCode4.Unauthorized,
239
516
  message: `${input.providerLabel} API key is missing. Pass apiKey to ${input.adapterFunctionName} or set the ${input.baseEnvVarName} environment variable.`,
240
517
  statusCode: 401
241
518
  });
@@ -243,19 +520,19 @@ function resolveBaseProviderApiKeyFromEnv(input) {
243
520
  return envApiKey;
244
521
  }
245
522
  function readEnvironmentVariable(envVarName) {
246
- const parsedEnv = z2.object({ [envVarName]: z2.string().optional() }).parse(process.env);
523
+ const parsedEnv = z3.object({ [envVarName]: z3.string().optional() }).parse(process.env);
247
524
  return parsedEnv[envVarName];
248
525
  }
249
526
 
250
527
  // src/provider-cancellation.ts
251
- import { AppErrorCode as AppErrorCode4 } from "@assemble-dev/shared-types/errors";
252
- import { AppError as AppError4 } from "@assemble-dev/shared-utils/errors";
528
+ import { AppErrorCode as AppErrorCode5 } from "@assemble-dev/shared-types/errors";
529
+ import { AppError as AppError5 } from "@assemble-dev/shared-utils/errors";
253
530
  function isAbortError(error) {
254
531
  return error.name === "AbortError";
255
532
  }
256
533
  function buildProviderCanceledError(providerLabel) {
257
- return new AppError4({
258
- code: AppErrorCode4.Canceled,
534
+ return new AppError5({
535
+ code: AppErrorCode5.Canceled,
259
536
  message: `${providerLabel} request was canceled`,
260
537
  statusCode: 499
261
538
  });
@@ -281,18 +558,18 @@ function mergeProviderRequestExtraBody(requestBody, adapterExtraBody, requestExt
281
558
  }
282
559
 
283
560
  // src/provider-fallback.ts
284
- import { AppError as AppError6 } from "@assemble-dev/shared-utils/errors";
561
+ import { AppError as AppError7 } from "@assemble-dev/shared-utils/errors";
285
562
 
286
563
  // src/provider-retry.ts
287
- import { AppErrorCode as AppErrorCode5 } from "@assemble-dev/shared-types/errors";
288
- import { AppError as AppError5 } from "@assemble-dev/shared-utils/errors";
564
+ import { AppErrorCode as AppErrorCode6 } from "@assemble-dev/shared-types/errors";
565
+ import { AppError as AppError6 } from "@assemble-dev/shared-utils/errors";
289
566
  var defaultProviderRetryMaxAttempts = 3;
290
567
  var defaultProviderRetryInitialDelayMs = 500;
291
568
  var defaultProviderRetryMaxDelayMs = 8e3;
292
569
  var retryableAppErrorCodes = /* @__PURE__ */ new Set([
293
- AppErrorCode5.RateLimited,
294
- AppErrorCode5.ServiceUnavailable,
295
- AppErrorCode5.InternalServerError
570
+ AppErrorCode6.RateLimited,
571
+ AppErrorCode6.ServiceUnavailable,
572
+ AppErrorCode6.InternalServerError
296
573
  ]);
297
574
  function isRetryableProviderAppError(appError) {
298
575
  return retryableAppErrorCodes.has(appError.code);
@@ -307,7 +584,7 @@ async function executeProviderCallWithRetry(retryOptions, executeCall, waitFor)
307
584
  try {
308
585
  return await executeCall();
309
586
  } catch (error) {
310
- if (error instanceof AppError5 && !isRetryableProviderAppError(error)) {
587
+ if (error instanceof AppError6 && !isRetryableProviderAppError(error)) {
311
588
  throw error;
312
589
  }
313
590
  if (error instanceof Error && isAbortError(error)) {
@@ -341,7 +618,7 @@ async function executeProviderCallWithModelFallback(fallbackModel, executePrimar
341
618
  if (fallbackModel === void 0) {
342
619
  throw error;
343
620
  }
344
- if (error instanceof AppError6 && !isRetryableProviderAppError(error)) {
621
+ if (error instanceof AppError7 && !isRetryableProviderAppError(error)) {
345
622
  throw error;
346
623
  }
347
624
  if (error instanceof Error && isAbortError(error)) {
@@ -352,11 +629,11 @@ async function executeProviderCallWithModelFallback(fallbackModel, executePrimar
352
629
  }
353
630
 
354
631
  // src/provider-status-error.ts
355
- import { AppErrorCode as AppErrorCode6 } from "@assemble-dev/shared-types/errors";
356
- import { AppError as AppError7 } from "@assemble-dev/shared-utils/errors";
632
+ import { AppErrorCode as AppErrorCode7 } from "@assemble-dev/shared-types/errors";
633
+ import { AppError as AppError8 } from "@assemble-dev/shared-utils/errors";
357
634
  function buildProviderStatusError(providerLabel, providerStatus) {
358
635
  const code = mapProviderStatusToAppErrorCode(providerStatus);
359
- return new AppError7({
636
+ return new AppError8({
360
637
  code,
361
638
  message: `${providerLabel} request failed with status ${String(providerStatus)}`,
362
639
  statusCode: mapAppErrorCodeToStatusCode(code),
@@ -364,44 +641,44 @@ function buildProviderStatusError(providerLabel, providerStatus) {
364
641
  });
365
642
  }
366
643
  function buildProviderInvalidResponseError(providerLabel, expectedShapeDescription) {
367
- return new AppError7({
368
- code: AppErrorCode6.ValidationFailed,
644
+ return new AppError8({
645
+ code: AppErrorCode7.ValidationFailed,
369
646
  message: `${providerLabel} response did not match the expected ${expectedShapeDescription} shape`,
370
647
  statusCode: 502
371
648
  });
372
649
  }
373
650
  function mapProviderStatusToAppErrorCode(providerStatus) {
374
651
  if (providerStatus === 400) {
375
- return AppErrorCode6.BadRequest;
652
+ return AppErrorCode7.BadRequest;
376
653
  }
377
654
  if (providerStatus === 401) {
378
- return AppErrorCode6.Unauthorized;
655
+ return AppErrorCode7.Unauthorized;
379
656
  }
380
657
  if (providerStatus === 403) {
381
- return AppErrorCode6.Forbidden;
658
+ return AppErrorCode7.Forbidden;
382
659
  }
383
660
  if (providerStatus === 404) {
384
- return AppErrorCode6.NotFound;
661
+ return AppErrorCode7.NotFound;
385
662
  }
386
663
  if (providerStatus === 429) {
387
- return AppErrorCode6.RateLimited;
664
+ return AppErrorCode7.RateLimited;
388
665
  }
389
- return AppErrorCode6.InternalServerError;
666
+ return AppErrorCode7.InternalServerError;
390
667
  }
391
668
  function mapAppErrorCodeToStatusCode(code) {
392
- if (code === AppErrorCode6.BadRequest) {
669
+ if (code === AppErrorCode7.BadRequest) {
393
670
  return 400;
394
671
  }
395
- if (code === AppErrorCode6.Unauthorized) {
672
+ if (code === AppErrorCode7.Unauthorized) {
396
673
  return 401;
397
674
  }
398
- if (code === AppErrorCode6.Forbidden) {
675
+ if (code === AppErrorCode7.Forbidden) {
399
676
  return 403;
400
677
  }
401
- if (code === AppErrorCode6.NotFound) {
678
+ if (code === AppErrorCode7.NotFound) {
402
679
  return 404;
403
680
  }
404
- if (code === AppErrorCode6.RateLimited) {
681
+ if (code === AppErrorCode7.RateLimited) {
405
682
  return 429;
406
683
  }
407
684
  return 500;
@@ -409,33 +686,29 @@ function mapAppErrorCodeToStatusCode(code) {
409
686
 
410
687
  // src/openai-adapter.ts
411
688
  var defaultOpenAiBaseUrl = "https://api.openai.com/v1";
412
- var OpenAiResponseToolCallSchema = z3.object({
413
- id: z3.string(),
414
- function: z3.object({
415
- name: z3.string(),
416
- arguments: z3.string()
689
+ var OpenAiResponseToolCallSchema = z4.object({
690
+ id: z4.string(),
691
+ function: z4.object({
692
+ name: z4.string(),
693
+ arguments: z4.string()
417
694
  })
418
695
  });
419
- var OpenAiChatCompletionResponseSchema = z3.object({
420
- choices: z3.array(
421
- z3.object({
422
- message: z3.object({
423
- content: z3.string().nullable(),
424
- tool_calls: z3.array(OpenAiResponseToolCallSchema).optional()
696
+ var OpenAiChatCompletionResponseSchema = z4.object({
697
+ choices: z4.array(
698
+ z4.object({
699
+ message: z4.object({
700
+ content: z4.string().nullable(),
701
+ tool_calls: z4.array(OpenAiResponseToolCallSchema).optional()
425
702
  }),
426
- finish_reason: z3.string().nullable().optional()
703
+ finish_reason: z4.string().nullable().optional()
427
704
  })
428
705
  ).min(1),
429
- usage: z3.object({
430
- prompt_tokens: z3.number().int().nonnegative(),
431
- completion_tokens: z3.number().int().nonnegative(),
432
- total_tokens: z3.number().int().nonnegative()
706
+ usage: z4.object({
707
+ prompt_tokens: z4.number().int().nonnegative(),
708
+ completion_tokens: z4.number().int().nonnegative(),
709
+ total_tokens: z4.number().int().nonnegative()
433
710
  })
434
711
  });
435
- var structuredOutputSystemMessage = {
436
- role: "system",
437
- content: "Respond with a single JSON object that satisfies the caller's requested structure. Output only valid JSON with no surrounding text."
438
- };
439
712
  function openai(options) {
440
713
  return {
441
714
  name: `openai:${options.model}`,
@@ -444,7 +717,6 @@ function openai(options) {
444
717
  messages: request.messages,
445
718
  temperature: request.temperature ?? options.temperature,
446
719
  maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
447
- requireJsonObjectResponse: false,
448
720
  tools: request.tools,
449
721
  toolChoice: request.toolChoice,
450
722
  abortSignal: request.abortSignal,
@@ -453,10 +725,9 @@ function openai(options) {
453
725
  },
454
726
  async generateStructuredOutput(request) {
455
727
  const completion = await executeOpenAiAdapterCall(options, {
456
- messages: [structuredOutputSystemMessage, ...request.messages],
728
+ ...resolveOpenAiStructuredOutputMode(request.messages, request.schema),
457
729
  temperature: request.temperature ?? options.temperature,
458
730
  maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
459
- requireJsonObjectResponse: true,
460
731
  abortSignal: request.abortSignal
461
732
  });
462
733
  return {
@@ -551,8 +822,8 @@ function parseOpenAiToolArgumentsJson(argumentsJsonText) {
551
822
  try {
552
823
  return JsonValueSchema3.parse(JSON.parse(argumentsJsonText));
553
824
  } catch (error) {
554
- throw new AppError8({
555
- code: AppErrorCode7.ValidationFailed,
825
+ throw new AppError9({
826
+ code: AppErrorCode8.ValidationFailed,
556
827
  message: "OpenAI tool call arguments were not valid JSON",
557
828
  statusCode: 502,
558
829
  cause: error instanceof Error ? error : void 0
@@ -574,8 +845,8 @@ function extractOpenAiMessageContent(response, allowEmptyContent) {
574
845
  if (allowEmptyContent) {
575
846
  return "";
576
847
  }
577
- throw new AppError8({
578
- code: AppErrorCode7.ValidationFailed,
848
+ throw new AppError9({
849
+ code: AppErrorCode8.ValidationFailed,
579
850
  message: "OpenAI response contained no message content",
580
851
  statusCode: 502
581
852
  });
@@ -639,6 +910,11 @@ function buildAnthropicRequestBody(settings, input) {
639
910
  budget_tokens: settings.thinking.budgetTokens
640
911
  };
641
912
  }
913
+ if (input.structuredOutputJsonSchema !== void 0) {
914
+ requestBody.output_config = {
915
+ format: { type: "json_schema", schema: input.structuredOutputJsonSchema }
916
+ };
917
+ }
642
918
  return requestBody;
643
919
  }
644
920
  function applyAnthropicSystemField(requestBody, settings, input) {
@@ -795,44 +1071,45 @@ function mapMessageContentBlockToAnthropic(contentBlock) {
795
1071
  }
796
1072
 
797
1073
  // src/anthropic-response-parsing.ts
798
- import { z as z4 } from "zod";
799
- import { AppErrorCode as AppErrorCode8 } from "@assemble-dev/shared-types/errors";
1074
+ import { z as z5 } from "zod";
1075
+ import { AppErrorCode as AppErrorCode9 } from "@assemble-dev/shared-types/errors";
800
1076
  import { JsonValueSchema as JsonValueSchema4 } from "@assemble-dev/shared-types/json";
801
- import { AppError as AppError9 } from "@assemble-dev/shared-utils/errors";
802
- var AnthropicUsageSchema = z4.object({
803
- input_tokens: z4.number().int().nonnegative(),
804
- output_tokens: z4.number().int().nonnegative(),
805
- cache_creation_input_tokens: z4.number().int().nonnegative().optional(),
806
- cache_read_input_tokens: z4.number().int().nonnegative().optional()
1077
+ import { AppError as AppError10 } from "@assemble-dev/shared-utils/errors";
1078
+ var AnthropicUsageSchema = z5.object({
1079
+ input_tokens: z5.number().int().nonnegative(),
1080
+ output_tokens: z5.number().int().nonnegative(),
1081
+ cache_creation_input_tokens: z5.number().int().nonnegative().optional(),
1082
+ cache_read_input_tokens: z5.number().int().nonnegative().optional()
807
1083
  });
808
- var AnthropicContentBlockSchema = z4.discriminatedUnion("type", [
809
- z4.object({
810
- type: z4.literal("text"),
811
- text: z4.string()
1084
+ var AnthropicContentBlockSchema = z5.discriminatedUnion("type", [
1085
+ z5.object({
1086
+ type: z5.literal("text"),
1087
+ text: z5.string()
812
1088
  }),
813
- z4.object({
814
- type: z4.literal("tool_use"),
815
- id: z4.string(),
816
- name: z4.string(),
1089
+ z5.object({
1090
+ type: z5.literal("tool_use"),
1091
+ id: z5.string(),
1092
+ name: z5.string(),
817
1093
  input: JsonValueSchema4
818
1094
  }),
819
- z4.object({
820
- type: z4.literal("thinking"),
821
- thinking: z4.string().optional(),
822
- signature: z4.string().optional()
1095
+ z5.object({
1096
+ type: z5.literal("thinking"),
1097
+ thinking: z5.string().optional(),
1098
+ signature: z5.string().optional()
823
1099
  }),
824
- z4.object({
825
- type: z4.literal("redacted_thinking"),
826
- data: z4.string().optional()
1100
+ z5.object({
1101
+ type: z5.literal("redacted_thinking"),
1102
+ data: z5.string().optional()
827
1103
  })
828
1104
  ]);
829
- var AnthropicMessagesResponseSchema = z4.object({
830
- content: z4.array(AnthropicContentBlockSchema),
831
- stop_reason: z4.string().nullable().optional(),
1105
+ var AnthropicMessagesResponseSchema = z5.object({
1106
+ content: z5.array(AnthropicContentBlockSchema),
1107
+ stop_reason: z5.string().nullable().optional(),
832
1108
  usage: AnthropicUsageSchema
833
1109
  });
834
1110
  function mapAnthropicResponseToChatCompletionResult(response, latencyMs) {
835
1111
  const toolCalls = extractAnthropicToolCalls(response);
1112
+ const thinkingText = extractAnthropicThinkingText(response);
836
1113
  const result = {
837
1114
  content: extractAnthropicTextContent(response, toolCalls.length > 0),
838
1115
  tokenUsage: mapAnthropicUsageToTokenUsage(response.usage),
@@ -841,6 +1118,9 @@ function mapAnthropicResponseToChatCompletionResult(response, latencyMs) {
841
1118
  if (toolCalls.length > 0) {
842
1119
  result.toolCalls = toolCalls;
843
1120
  }
1121
+ if (thinkingText.length > 0) {
1122
+ result.thinkingText = thinkingText;
1123
+ }
844
1124
  if (response.stop_reason !== null && response.stop_reason !== void 0) {
845
1125
  result.stopReason = normalizeAnthropicStopReason(response.stop_reason);
846
1126
  }
@@ -853,13 +1133,16 @@ function extractAnthropicToolCalls(response) {
853
1133
  input: contentBlock.input
854
1134
  }));
855
1135
  }
1136
+ function extractAnthropicThinkingText(response) {
1137
+ return response.content.filter((contentBlock) => contentBlock.type === "thinking").map((contentBlock) => contentBlock.thinking ?? "").join("");
1138
+ }
856
1139
  function extractAnthropicTextContent(response, allowEmptyText) {
857
1140
  const textBlocks = response.content.filter(
858
1141
  (contentBlock) => contentBlock.type === "text"
859
1142
  );
860
1143
  if (textBlocks.length === 0 && !allowEmptyText) {
861
- throw new AppError9({
862
- code: AppErrorCode8.ValidationFailed,
1144
+ throw new AppError10({
1145
+ code: AppErrorCode9.ValidationFailed,
863
1146
  message: "Anthropic response contained no text content",
864
1147
  statusCode: 502
865
1148
  });
@@ -896,58 +1179,68 @@ function mapAnthropicUsageToTokenUsage(usage) {
896
1179
  }
897
1180
 
898
1181
  // src/anthropic-stream.ts
899
- import { AppErrorCode as AppErrorCode9 } from "@assemble-dev/shared-types/errors";
1182
+ import { AppErrorCode as AppErrorCode10 } from "@assemble-dev/shared-types/errors";
900
1183
  import { JsonValueSchema as JsonValueSchema5 } from "@assemble-dev/shared-types/json";
901
- import { AppError as AppError10 } from "@assemble-dev/shared-utils/errors";
1184
+ import { AppError as AppError11 } from "@assemble-dev/shared-utils/errors";
902
1185
 
903
1186
  // src/anthropic-stream-events.ts
904
- import { z as z5 } from "zod";
905
- var AnthropicStreamEventSchema = z5.discriminatedUnion("type", [
906
- z5.object({
907
- type: z5.literal("message_start"),
908
- message: z5.object({
909
- usage: z5.object({
910
- input_tokens: z5.number().int().nonnegative(),
911
- output_tokens: z5.number().int().nonnegative().optional(),
912
- cache_creation_input_tokens: z5.number().int().nonnegative().optional(),
913
- cache_read_input_tokens: z5.number().int().nonnegative().optional()
1187
+ import { z as z6 } from "zod";
1188
+ var AnthropicStreamEventSchema = z6.discriminatedUnion("type", [
1189
+ z6.object({
1190
+ type: z6.literal("message_start"),
1191
+ message: z6.object({
1192
+ usage: z6.object({
1193
+ input_tokens: z6.number().int().nonnegative(),
1194
+ output_tokens: z6.number().int().nonnegative().optional(),
1195
+ cache_creation_input_tokens: z6.number().int().nonnegative().optional(),
1196
+ cache_read_input_tokens: z6.number().int().nonnegative().optional()
914
1197
  })
915
1198
  })
916
1199
  }),
917
- z5.object({
918
- type: z5.literal("content_block_start"),
919
- index: z5.number().int().nonnegative(),
920
- content_block: z5.discriminatedUnion("type", [
921
- z5.object({ type: z5.literal("text"), text: z5.string().optional() }),
922
- z5.object({
923
- type: z5.literal("tool_use"),
924
- id: z5.string(),
925
- name: z5.string()
1200
+ z6.object({
1201
+ type: z6.literal("content_block_start"),
1202
+ index: z6.number().int().nonnegative(),
1203
+ content_block: z6.discriminatedUnion("type", [
1204
+ z6.object({ type: z6.literal("text"), text: z6.string().optional() }),
1205
+ z6.object({
1206
+ type: z6.literal("thinking"),
1207
+ thinking: z6.string().optional()
1208
+ }),
1209
+ z6.object({
1210
+ type: z6.literal("redacted_thinking"),
1211
+ data: z6.string().optional()
1212
+ }),
1213
+ z6.object({
1214
+ type: z6.literal("tool_use"),
1215
+ id: z6.string(),
1216
+ name: z6.string()
926
1217
  })
927
1218
  ])
928
1219
  }),
929
- z5.object({
930
- type: z5.literal("content_block_delta"),
931
- index: z5.number().int().nonnegative(),
932
- delta: z5.discriminatedUnion("type", [
933
- z5.object({ type: z5.literal("text_delta"), text: z5.string() }),
934
- z5.object({
935
- type: z5.literal("input_json_delta"),
936
- partial_json: z5.string()
1220
+ z6.object({
1221
+ type: z6.literal("content_block_delta"),
1222
+ index: z6.number().int().nonnegative(),
1223
+ delta: z6.discriminatedUnion("type", [
1224
+ z6.object({ type: z6.literal("text_delta"), text: z6.string() }),
1225
+ z6.object({ type: z6.literal("thinking_delta"), thinking: z6.string() }),
1226
+ z6.object({ type: z6.literal("signature_delta"), signature: z6.string() }),
1227
+ z6.object({
1228
+ type: z6.literal("input_json_delta"),
1229
+ partial_json: z6.string()
937
1230
  })
938
1231
  ])
939
1232
  }),
940
- z5.object({ type: z5.literal("content_block_stop") }),
941
- z5.object({
942
- type: z5.literal("message_delta"),
943
- delta: z5.object({ stop_reason: z5.string().nullable().optional() }),
944
- usage: z5.object({ output_tokens: z5.number().int().nonnegative() }).optional()
1233
+ z6.object({ type: z6.literal("content_block_stop") }),
1234
+ z6.object({
1235
+ type: z6.literal("message_delta"),
1236
+ delta: z6.object({ stop_reason: z6.string().nullable().optional() }),
1237
+ usage: z6.object({ output_tokens: z6.number().int().nonnegative() }).optional()
945
1238
  }),
946
- z5.object({ type: z5.literal("message_stop") }),
947
- z5.object({ type: z5.literal("ping") }),
948
- z5.object({
949
- type: z5.literal("error"),
950
- error: z5.object({ message: z5.string() })
1239
+ z6.object({ type: z6.literal("message_stop") }),
1240
+ z6.object({ type: z6.literal("ping") }),
1241
+ z6.object({
1242
+ type: z6.literal("error"),
1243
+ error: z6.object({ message: z6.string() })
951
1244
  })
952
1245
  ]);
953
1246
 
@@ -1033,6 +1326,7 @@ async function* readServerSentEventDataLines(body, abortSignal) {
1033
1326
  function createAnthropicStreamAccumulator() {
1034
1327
  return {
1035
1328
  contentText: "",
1329
+ thinkingText: "",
1036
1330
  toolCallsByBlockIndex: /* @__PURE__ */ new Map(),
1037
1331
  inputTokens: 0,
1038
1332
  outputTokens: 0
@@ -1040,8 +1334,8 @@ function createAnthropicStreamAccumulator() {
1040
1334
  }
1041
1335
  function* applyAnthropicStreamEvent(event, accumulator) {
1042
1336
  if (event.type === "error") {
1043
- throw new AppError10({
1044
- code: AppErrorCode9.InternalServerError,
1337
+ throw new AppError11({
1338
+ code: AppErrorCode10.InternalServerError,
1045
1339
  message: `Anthropic stream reported an error: ${event.error.message}`,
1046
1340
  statusCode: 502
1047
1341
  });
@@ -1077,6 +1371,17 @@ function* applyAnthropicContentBlockStart(event, accumulator) {
1077
1371
  }
1078
1372
  return;
1079
1373
  }
1374
+ if (event.content_block.type === "thinking") {
1375
+ const initialThinkingText = event.content_block.thinking ?? "";
1376
+ if (initialThinkingText.length > 0) {
1377
+ accumulator.thinkingText += initialThinkingText;
1378
+ yield { type: "thinking_delta", text: initialThinkingText };
1379
+ }
1380
+ return;
1381
+ }
1382
+ if (event.content_block.type === "redacted_thinking") {
1383
+ return;
1384
+ }
1080
1385
  accumulator.toolCallsByBlockIndex.set(event.index, {
1081
1386
  id: event.content_block.id,
1082
1387
  toolName: event.content_block.name,
@@ -1094,6 +1399,14 @@ function* applyAnthropicContentBlockDelta(event, accumulator) {
1094
1399
  yield { type: "text_delta", text: event.delta.text };
1095
1400
  return;
1096
1401
  }
1402
+ if (event.delta.type === "thinking_delta") {
1403
+ accumulator.thinkingText += event.delta.thinking;
1404
+ yield { type: "thinking_delta", text: event.delta.thinking };
1405
+ return;
1406
+ }
1407
+ if (event.delta.type === "signature_delta") {
1408
+ return;
1409
+ }
1097
1410
  const toolCallAccumulation = accumulator.toolCallsByBlockIndex.get(
1098
1411
  event.index
1099
1412
  );
@@ -1140,6 +1453,9 @@ function buildAnthropicStreamResult(accumulator, latencyMs) {
1140
1453
  if (accumulator.stopReason !== void 0) {
1141
1454
  result.stopReason = accumulator.stopReason;
1142
1455
  }
1456
+ if (accumulator.thinkingText.length > 0) {
1457
+ result.thinkingText = accumulator.thinkingText;
1458
+ }
1143
1459
  return result;
1144
1460
  }
1145
1461
  function mapAccumulatedToolCallToModelToolCall(toolCallAccumulation) {
@@ -1156,8 +1472,8 @@ function parseAnthropicToolInputJson(inputJsonText) {
1156
1472
  try {
1157
1473
  return JsonValueSchema5.parse(JSON.parse(inputJsonText));
1158
1474
  } catch (error) {
1159
- throw new AppError10({
1160
- code: AppErrorCode9.ValidationFailed,
1475
+ throw new AppError11({
1476
+ code: AppErrorCode10.ValidationFailed,
1161
1477
  message: "Anthropic tool input was not valid JSON",
1162
1478
  statusCode: 502,
1163
1479
  cause: error instanceof Error ? error : void 0
@@ -1169,10 +1485,6 @@ function parseAnthropicToolInputJson(inputJsonText) {
1169
1485
  var defaultAnthropicBaseUrl = "https://api.anthropic.com";
1170
1486
  var defaultAnthropicMaxOutputTokens = 1024;
1171
1487
  var anthropicApiVersion = "2023-06-01";
1172
- var structuredOutputSystemMessage2 = {
1173
- role: "system",
1174
- content: "Respond with a single JSON object that satisfies the caller's requested structure. Output only valid JSON with no surrounding text."
1175
- };
1176
1488
  function anthropic(options) {
1177
1489
  return {
1178
1490
  name: `anthropic:${options.model}`,
@@ -1183,12 +1495,10 @@ function anthropic(options) {
1183
1495
  );
1184
1496
  },
1185
1497
  async generateStructuredOutput(request) {
1186
- const completion = await executeAnthropicAdapterCall(options, {
1187
- messages: [structuredOutputSystemMessage2, ...request.messages],
1188
- temperature: request.temperature ?? options.temperature,
1189
- maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
1190
- abortSignal: request.abortSignal
1191
- });
1498
+ const completion = await executeAnthropicAdapterCall(
1499
+ options,
1500
+ buildAnthropicStructuredOutputInput(options, request)
1501
+ );
1192
1502
  return {
1193
1503
  value: parseStructuredJsonText(completion.content, request.schema),
1194
1504
  tokenUsage: completion.tokenUsage,
@@ -1202,6 +1512,26 @@ function anthropic(options) {
1202
1512
  }
1203
1513
  };
1204
1514
  }
1515
+ function buildAnthropicStructuredOutputInput(options, request) {
1516
+ const baseInput = {
1517
+ messages: request.messages,
1518
+ temperature: request.temperature ?? options.temperature,
1519
+ maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
1520
+ abortSignal: request.abortSignal
1521
+ };
1522
+ if (isZodV4Schema(request.schema)) {
1523
+ return {
1524
+ ...baseInput,
1525
+ structuredOutputJsonSchema: buildAnthropicStructuredOutputJsonSchema(
1526
+ request.schema
1527
+ )
1528
+ };
1529
+ }
1530
+ return {
1531
+ ...baseInput,
1532
+ messages: prependStructuredOutputJsonOnlySystemMessage(request.messages)
1533
+ };
1534
+ }
1205
1535
  function buildAnthropicCallInput(options, request) {
1206
1536
  return {
1207
1537
  messages: request.messages,
@@ -1302,28 +1632,116 @@ function resolveAnthropicFetch(options) {
1302
1632
  }
1303
1633
 
1304
1634
  // src/gemini-adapter.ts
1305
- import { z as z6 } from "zod";
1306
- import { AppErrorCode as AppErrorCode10 } from "@assemble-dev/shared-types/errors";
1307
- import { AppError as AppError11 } from "@assemble-dev/shared-utils/errors";
1635
+ import { z as z7 } from "zod";
1636
+ import { AppErrorCode as AppErrorCode11 } from "@assemble-dev/shared-types/errors";
1637
+ import { AppError as AppError12 } from "@assemble-dev/shared-utils/errors";
1638
+
1639
+ // src/gemini-response-schema.ts
1640
+ var geminiAllowedSchemaKeywords = [
1641
+ "type",
1642
+ "format",
1643
+ "description",
1644
+ "nullable",
1645
+ "enum",
1646
+ "properties",
1647
+ "required",
1648
+ "items",
1649
+ "minItems",
1650
+ "maxItems",
1651
+ "anyOf"
1652
+ ];
1653
+ var geminiAllowedFormats = [
1654
+ "date-time",
1655
+ "int32",
1656
+ "int64",
1657
+ "float",
1658
+ "double"
1659
+ ];
1660
+ function buildGeminiResponseSchema(schema) {
1661
+ return sanitizeJsonSchemaForGeminiResponseSchema(
1662
+ convertZodSchemaToJsonSchema(schema)
1663
+ );
1664
+ }
1665
+ function sanitizeJsonSchemaForGeminiResponseSchema(jsonSchema) {
1666
+ return transformJsonSchemaNode(
1667
+ inlineJsonSchemaReferences(jsonSchema),
1668
+ sanitizeGeminiSchemaNode
1669
+ );
1670
+ }
1671
+ function sanitizeGeminiSchemaNode(node) {
1672
+ const normalized = normalizeGeminiNullableType(
1673
+ mergeNullUnionIntoNullableNode(node)
1674
+ );
1675
+ const sanitized = {};
1676
+ for (const [key, value] of Object.entries(normalized)) {
1677
+ if (geminiAllowedSchemaKeywords.includes(key)) {
1678
+ sanitized[key] = value;
1679
+ }
1680
+ }
1681
+ return removeUnsupportedGeminiFormat(sanitized);
1682
+ }
1683
+ function mergeNullUnionIntoNullableNode(node) {
1684
+ const unionKeyword = Array.isArray(node["anyOf"]) ? "anyOf" : "oneOf";
1685
+ const unionMembers = node[unionKeyword];
1686
+ if (!Array.isArray(unionMembers)) {
1687
+ return node;
1688
+ }
1689
+ const nonNullMembers = unionMembers.filter(
1690
+ (member) => !isNullTypeSchemaNode(member)
1691
+ );
1692
+ if (nonNullMembers.length === unionMembers.length) {
1693
+ return node;
1694
+ }
1695
+ const merged = { ...node };
1696
+ delete merged[unionKeyword];
1697
+ const singleMember = nonNullMembers.length === 1 ? nonNullMembers[0] : void 0;
1698
+ if (singleMember !== void 0 && isJsonObject(singleMember)) {
1699
+ return { ...merged, ...singleMember, nullable: true };
1700
+ }
1701
+ return { ...merged, anyOf: nonNullMembers, nullable: true };
1702
+ }
1703
+ function normalizeGeminiNullableType(node) {
1704
+ const typeValue = node["type"];
1705
+ if (!Array.isArray(typeValue)) {
1706
+ return node;
1707
+ }
1708
+ const nonNullTypes = typeValue.filter((typeName) => typeName !== "null");
1709
+ const normalized = { ...node };
1710
+ if (nonNullTypes.length < typeValue.length) {
1711
+ normalized["nullable"] = true;
1712
+ }
1713
+ normalized["type"] = nonNullTypes[0] ?? "string";
1714
+ return normalized;
1715
+ }
1716
+ function removeUnsupportedGeminiFormat(node) {
1717
+ const formatValue = node["format"];
1718
+ if (typeof formatValue === "string" && !geminiAllowedFormats.includes(formatValue)) {
1719
+ const withoutFormat = { ...node };
1720
+ delete withoutFormat["format"];
1721
+ return withoutFormat;
1722
+ }
1723
+ return node;
1724
+ }
1725
+ function isNullTypeSchemaNode(value) {
1726
+ return isJsonObject(value) && value["type"] === "null";
1727
+ }
1728
+
1729
+ // src/gemini-adapter.ts
1308
1730
  var defaultGeminiBaseUrl = "https://generativelanguage.googleapis.com";
1309
- var GeminiGenerateContentResponseSchema = z6.object({
1310
- candidates: z6.array(
1311
- z6.object({
1312
- content: z6.object({
1313
- parts: z6.array(z6.object({ text: z6.string() }))
1731
+ var GeminiGenerateContentResponseSchema = z7.object({
1732
+ candidates: z7.array(
1733
+ z7.object({
1734
+ content: z7.object({
1735
+ parts: z7.array(z7.object({ text: z7.string() }))
1314
1736
  })
1315
1737
  })
1316
1738
  ).optional(),
1317
- usageMetadata: z6.object({
1318
- promptTokenCount: z6.number().int().nonnegative().optional(),
1319
- candidatesTokenCount: z6.number().int().nonnegative().optional(),
1320
- totalTokenCount: z6.number().int().nonnegative().optional()
1739
+ usageMetadata: z7.object({
1740
+ promptTokenCount: z7.number().int().nonnegative().optional(),
1741
+ candidatesTokenCount: z7.number().int().nonnegative().optional(),
1742
+ totalTokenCount: z7.number().int().nonnegative().optional()
1321
1743
  }).optional()
1322
1744
  });
1323
- var structuredOutputSystemMessage3 = {
1324
- role: "system",
1325
- content: "Respond with a single JSON object that satisfies the caller's requested structure. Output only valid JSON with no surrounding text."
1326
- };
1327
1745
  function gemini(options) {
1328
1746
  return {
1329
1747
  name: `gemini:${options.model}`,
@@ -1333,19 +1751,15 @@ function gemini(options) {
1333
1751
  messages: request.messages,
1334
1752
  temperature: request.temperature ?? options.temperature,
1335
1753
  maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
1336
- requireJsonResponse: false,
1337
1754
  abortSignal: request.abortSignal,
1338
1755
  extraBody: request.extraBody
1339
1756
  });
1340
1757
  },
1341
1758
  async generateStructuredOutput(request) {
1342
- const completion = await executeGeminiAdapterCall(options, {
1343
- messages: [structuredOutputSystemMessage3, ...request.messages],
1344
- temperature: request.temperature ?? options.temperature,
1345
- maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
1346
- requireJsonResponse: true,
1347
- abortSignal: request.abortSignal
1348
- });
1759
+ const completion = await executeGeminiAdapterCall(
1760
+ options,
1761
+ buildGeminiStructuredOutputInput(options, request)
1762
+ );
1349
1763
  return {
1350
1764
  value: parseStructuredJsonText(completion.content, request.schema),
1351
1765
  tokenUsage: completion.tokenUsage,
@@ -1354,6 +1768,25 @@ function gemini(options) {
1354
1768
  }
1355
1769
  };
1356
1770
  }
1771
+ function buildGeminiStructuredOutputInput(options, request) {
1772
+ const baseInput = {
1773
+ messages: request.messages,
1774
+ temperature: request.temperature ?? options.temperature,
1775
+ maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
1776
+ abortSignal: request.abortSignal
1777
+ };
1778
+ if (isZodV4Schema(request.schema)) {
1779
+ return {
1780
+ ...baseInput,
1781
+ responseSchema: buildGeminiResponseSchema(request.schema)
1782
+ };
1783
+ }
1784
+ return {
1785
+ ...baseInput,
1786
+ messages: prependStructuredOutputJsonOnlySystemMessage(request.messages),
1787
+ requireJsonResponse: true
1788
+ };
1789
+ }
1357
1790
  async function executeGeminiAdapterCall(options, input) {
1358
1791
  return await executeProviderCallWithModelFallback(
1359
1792
  options.fallbackModel,
@@ -1430,8 +1863,8 @@ function ensureGeminiRequestHasNoTools(request) {
1430
1863
  if (request.tools === void 0 || request.tools.length === 0) {
1431
1864
  return;
1432
1865
  }
1433
- throw new AppError11({
1434
- code: AppErrorCode10.ValidationFailed,
1866
+ throw new AppError12({
1867
+ code: AppErrorCode11.ValidationFailed,
1435
1868
  message: "gemini adapter does not support model-driven tool use; remove tools from the request or use another adapter",
1436
1869
  statusCode: 400
1437
1870
  });
@@ -1468,7 +1901,10 @@ function buildGeminiGenerationConfig(input) {
1468
1901
  if (input.maxOutputTokens !== void 0) {
1469
1902
  generationConfig.maxOutputTokens = input.maxOutputTokens;
1470
1903
  }
1471
- if (input.requireJsonResponse) {
1904
+ if (input.responseSchema !== void 0) {
1905
+ generationConfig.responseMimeType = "application/json";
1906
+ generationConfig.responseSchema = input.responseSchema;
1907
+ } else if (input.requireJsonResponse === true) {
1472
1908
  generationConfig.responseMimeType = "application/json";
1473
1909
  }
1474
1910
  if (Object.keys(generationConfig).length === 0) {
@@ -1479,8 +1915,8 @@ function buildGeminiGenerationConfig(input) {
1479
1915
  function extractGeminiCandidateText(response) {
1480
1916
  const firstCandidate = response.candidates?.[0];
1481
1917
  if (firstCandidate === void 0) {
1482
- throw new AppError11({
1483
- code: AppErrorCode10.ValidationFailed,
1918
+ throw new AppError12({
1919
+ code: AppErrorCode11.ValidationFailed,
1484
1920
  message: "Gemini response contained no candidates",
1485
1921
  statusCode: 502
1486
1922
  });
@@ -1499,8 +1935,8 @@ function mapGeminiUsageToTokenUsage(response) {
1499
1935
  }
1500
1936
 
1501
1937
  // src/mock-adapter.ts
1502
- import { AppErrorCode as AppErrorCode11 } from "@assemble-dev/shared-types/errors";
1503
- import { AppError as AppError12 } from "@assemble-dev/shared-utils/errors";
1938
+ import { AppErrorCode as AppErrorCode12 } from "@assemble-dev/shared-types/errors";
1939
+ import { AppError as AppError13 } from "@assemble-dev/shared-utils/errors";
1504
1940
  var mockStreamChunkCount = 3;
1505
1941
  function mockModel(options = {}) {
1506
1942
  const remainingScriptedResponses = [...options.scriptedResponses ?? []];
@@ -1580,8 +2016,8 @@ function resolveNextMockResponseText(request, remainingScriptedResponses, respon
1580
2016
  if (respond !== void 0) {
1581
2017
  return respond(request);
1582
2018
  }
1583
- throw new AppError12({
1584
- code: AppErrorCode11.BadRequest,
2019
+ throw new AppError13({
2020
+ code: AppErrorCode12.BadRequest,
1585
2021
  message: "Mock model has no scripted responses left and no respond function was provided",
1586
2022
  statusCode: 400
1587
2023
  });
@@ -1669,15 +2105,15 @@ function calculateModelCallCostUsd(pricing, tokenUsage) {
1669
2105
  }
1670
2106
 
1671
2107
  // src/anthropic-batch.ts
1672
- import { AppErrorCode as AppErrorCode13 } from "@assemble-dev/shared-types/errors";
2108
+ import { AppErrorCode as AppErrorCode14 } from "@assemble-dev/shared-types/errors";
1673
2109
  import { JsonValueSchema as JsonValueSchema7 } from "@assemble-dev/shared-types/json";
1674
- import { AppError as AppError14 } from "@assemble-dev/shared-utils/errors";
2110
+ import { AppError as AppError15 } from "@assemble-dev/shared-utils/errors";
1675
2111
 
1676
2112
  // src/anthropic-batch-structured.ts
1677
- import { AppErrorCode as AppErrorCode12 } from "@assemble-dev/shared-types/errors";
2113
+ import { AppErrorCode as AppErrorCode13 } from "@assemble-dev/shared-types/errors";
1678
2114
  import { JsonValueSchema as JsonValueSchema6 } from "@assemble-dev/shared-types/json";
1679
- import { AppError as AppError13 } from "@assemble-dev/shared-utils/errors";
1680
- var anthropicBatchJsonOnlySystemInstruction = "Respond with a single JSON object that satisfies the caller's requested structure. Output only valid JSON with no surrounding text.";
2115
+ import { AppError as AppError14 } from "@assemble-dev/shared-utils/errors";
2116
+ var anthropicBatchJsonOnlySystemInstruction = structuredOutputJsonOnlySystemInstruction;
1681
2117
  function parseAnthropicBatchStructuredContent(content, schema) {
1682
2118
  const jsonValue = parseStructuredJsonText(
1683
2119
  content,
@@ -1685,8 +2121,8 @@ function parseAnthropicBatchStructuredContent(content, schema) {
1685
2121
  );
1686
2122
  const validationResult = schema.safeParse(jsonValue);
1687
2123
  if (!validationResult.success) {
1688
- throw new AppError13({
1689
- code: AppErrorCode12.ValidationFailed,
2124
+ throw new AppError14({
2125
+ code: AppErrorCode13.ValidationFailed,
1690
2126
  message: "Anthropic batch structured output did not match the expected schema",
1691
2127
  statusCode: 422,
1692
2128
  details: { validationErrorMessage: validationResult.error.message }
@@ -1703,11 +2139,25 @@ function mapBatchMessageRequestToApiBatchRequest(request) {
1703
2139
  messages: request.messages.filter((message) => message.role !== "system").map(mapChatMessageToBatchApiRequestMessage)
1704
2140
  };
1705
2141
  applyBatchSystemField(params, request);
2142
+ applyBatchStructuredOutputConfig(params, request);
1706
2143
  if (request.temperature !== void 0) {
1707
2144
  params.temperature = request.temperature;
1708
2145
  }
1709
2146
  return { custom_id: request.customId, params };
1710
2147
  }
2148
+ function applyBatchStructuredOutputConfig(params, request) {
2149
+ if (request.structuredOutputJsonSchema === void 0) {
2150
+ return;
2151
+ }
2152
+ params.output_config = {
2153
+ format: {
2154
+ type: "json_schema",
2155
+ schema: sanitizeJsonSchemaForAnthropicStructuredOutput(
2156
+ request.structuredOutputJsonSchema
2157
+ )
2158
+ }
2159
+ };
2160
+ }
1711
2161
  function applyBatchSystemField(params, request) {
1712
2162
  const systemText = buildBatchSystemText(request);
1713
2163
  if (systemText.length === 0) {
@@ -1723,7 +2173,7 @@ function applyBatchSystemField(params, request) {
1723
2173
  }
1724
2174
  function buildBatchSystemText(request) {
1725
2175
  const joinedSystemText = joinBatchSystemMessageText(request.messages);
1726
- if (request.requireJsonResponse !== true) {
2176
+ if (request.requireJsonResponse !== true || request.structuredOutputJsonSchema !== void 0) {
1727
2177
  return joinedSystemText;
1728
2178
  }
1729
2179
  if (joinedSystemText.length === 0) {
@@ -1877,55 +2327,55 @@ function buildBatchResultEvent(eventBase, batchId, result, modelName) {
1877
2327
  }
1878
2328
 
1879
2329
  // src/anthropic-batch-types.ts
1880
- import { z as z7 } from "zod";
1881
- var AnthropicMessageBatchResponseSchema = z7.object({
1882
- id: z7.string(),
1883
- processing_status: z7.enum(["in_progress", "canceling", "ended"]),
1884
- request_counts: z7.object({
1885
- processing: z7.number().int().nonnegative(),
1886
- succeeded: z7.number().int().nonnegative(),
1887
- errored: z7.number().int().nonnegative(),
1888
- canceled: z7.number().int().nonnegative(),
1889
- expired: z7.number().int().nonnegative()
2330
+ import { z as z8 } from "zod";
2331
+ var AnthropicMessageBatchResponseSchema = z8.object({
2332
+ id: z8.string(),
2333
+ processing_status: z8.enum(["in_progress", "canceling", "ended"]),
2334
+ request_counts: z8.object({
2335
+ processing: z8.number().int().nonnegative(),
2336
+ succeeded: z8.number().int().nonnegative(),
2337
+ errored: z8.number().int().nonnegative(),
2338
+ canceled: z8.number().int().nonnegative(),
2339
+ expired: z8.number().int().nonnegative()
1890
2340
  }),
1891
- results_url: z7.string().nullable(),
1892
- created_at: z7.string(),
1893
- ended_at: z7.string().nullable()
2341
+ results_url: z8.string().nullable(),
2342
+ created_at: z8.string(),
2343
+ ended_at: z8.string().nullable()
1894
2344
  });
1895
- var AnthropicBatchContentBlockSchema = z7.discriminatedUnion("type", [
1896
- z7.object({
1897
- type: z7.literal("text"),
1898
- text: z7.string()
2345
+ var AnthropicBatchContentBlockSchema = z8.discriminatedUnion("type", [
2346
+ z8.object({
2347
+ type: z8.literal("text"),
2348
+ text: z8.string()
1899
2349
  }),
1900
- z7.object({
1901
- type: z7.literal("thinking"),
1902
- thinking: z7.string().optional(),
1903
- signature: z7.string().optional()
2350
+ z8.object({
2351
+ type: z8.literal("thinking"),
2352
+ thinking: z8.string().optional(),
2353
+ signature: z8.string().optional()
1904
2354
  }),
1905
- z7.object({
1906
- type: z7.literal("redacted_thinking"),
1907
- data: z7.string().optional()
2355
+ z8.object({
2356
+ type: z8.literal("redacted_thinking"),
2357
+ data: z8.string().optional()
1908
2358
  })
1909
2359
  ]);
1910
- var AnthropicBatchResultLineSchema = z7.object({
1911
- custom_id: z7.string(),
1912
- result: z7.discriminatedUnion("type", [
1913
- z7.object({
1914
- type: z7.literal("succeeded"),
1915
- message: z7.object({
1916
- content: z7.array(AnthropicBatchContentBlockSchema),
2360
+ var AnthropicBatchResultLineSchema = z8.object({
2361
+ custom_id: z8.string(),
2362
+ result: z8.discriminatedUnion("type", [
2363
+ z8.object({
2364
+ type: z8.literal("succeeded"),
2365
+ message: z8.object({
2366
+ content: z8.array(AnthropicBatchContentBlockSchema),
1917
2367
  usage: AnthropicUsageSchema
1918
2368
  })
1919
2369
  }),
1920
- z7.object({
1921
- type: z7.literal("errored"),
1922
- error: z7.object({
1923
- type: z7.string(),
1924
- message: z7.string()
2370
+ z8.object({
2371
+ type: z8.literal("errored"),
2372
+ error: z8.object({
2373
+ type: z8.string(),
2374
+ message: z8.string()
1925
2375
  })
1926
2376
  }),
1927
- z7.object({ type: z7.literal("canceled") }),
1928
- z7.object({ type: z7.literal("expired") })
2377
+ z8.object({ type: z8.literal("canceled") }),
2378
+ z8.object({ type: z8.literal("expired") })
1929
2379
  ])
1930
2380
  });
1931
2381
  function mapAnthropicMessageBatchResponseToMessageBatch(response) {
@@ -2075,8 +2525,8 @@ async function parseAnthropicMessageBatchHttpResponse(response) {
2075
2525
  async function listAnthropicMessageBatchResults(clientContext, batchId) {
2076
2526
  const batch = await fetchAnthropicMessageBatch(clientContext, batchId);
2077
2527
  if (batch.resultsUrl === null) {
2078
- throw new AppError14({
2079
- code: AppErrorCode13.Conflict,
2528
+ throw new AppError15({
2529
+ code: AppErrorCode14.Conflict,
2080
2530
  message: `Anthropic message batch ${batchId} has no results because processing has not ended`,
2081
2531
  statusCode: 409,
2082
2532
  details: { batchId, processingStatus: batch.processingStatus }
@@ -2137,16 +2587,763 @@ async function waitForAnthropicMessageBatchCompletion(clientContext, batchId, wa
2137
2587
  return batch;
2138
2588
  }
2139
2589
  function buildAnthropicBatchTimeoutError(batchId, timeoutMs) {
2140
- return new AppError14({
2141
- code: AppErrorCode13.ServiceUnavailable,
2590
+ return new AppError15({
2591
+ code: AppErrorCode14.ServiceUnavailable,
2142
2592
  message: `Anthropic message batch ${batchId} did not complete within ${String(timeoutMs)}ms`,
2143
2593
  statusCode: 504,
2144
2594
  details: { batchId, timeoutMs }
2145
2595
  });
2146
2596
  }
2597
+
2598
+ // src/azure-openai-adapter.ts
2599
+ import { AppErrorCode as AppErrorCode16 } from "@assemble-dev/shared-types/errors";
2600
+ import { AppError as AppError17 } from "@assemble-dev/shared-utils/errors";
2601
+
2602
+ // src/azure-openai-response-parsing.ts
2603
+ import { z as z9 } from "zod";
2604
+ import { AppErrorCode as AppErrorCode15 } from "@assemble-dev/shared-types/errors";
2605
+ import { JsonValueSchema as JsonValueSchema8 } from "@assemble-dev/shared-types/json";
2606
+ import { AppError as AppError16 } from "@assemble-dev/shared-utils/errors";
2607
+ var AzureOpenAiUsageSchema = z9.object({
2608
+ prompt_tokens: z9.number().int().nonnegative(),
2609
+ completion_tokens: z9.number().int().nonnegative(),
2610
+ total_tokens: z9.number().int().nonnegative()
2611
+ });
2612
+ var AzureOpenAiResponseToolCallSchema = z9.object({
2613
+ id: z9.string(),
2614
+ function: z9.object({
2615
+ name: z9.string(),
2616
+ arguments: z9.string()
2617
+ })
2618
+ });
2619
+ var AzureOpenAiChatCompletionResponseSchema = z9.object({
2620
+ choices: z9.array(
2621
+ z9.object({
2622
+ message: z9.object({
2623
+ content: z9.string().nullable(),
2624
+ tool_calls: z9.array(AzureOpenAiResponseToolCallSchema).optional()
2625
+ }),
2626
+ finish_reason: z9.string().nullable().optional()
2627
+ })
2628
+ ).min(1),
2629
+ usage: AzureOpenAiUsageSchema
2630
+ });
2631
+ function mapAzureOpenAiResponseToChatCompletionResult(response, latencyMs) {
2632
+ const toolCalls = extractAzureOpenAiToolCalls(response);
2633
+ const result = {
2634
+ content: extractAzureOpenAiMessageContent(response, toolCalls.length > 0),
2635
+ tokenUsage: mapAzureOpenAiUsageToTokenUsage(response.usage),
2636
+ latencyMs
2637
+ };
2638
+ const finishReason = response.choices[0]?.finish_reason;
2639
+ if (toolCalls.length > 0) {
2640
+ result.toolCalls = toolCalls;
2641
+ }
2642
+ if (finishReason !== null && finishReason !== void 0) {
2643
+ result.stopReason = normalizeAzureOpenAiFinishReason(finishReason);
2644
+ }
2645
+ return result;
2646
+ }
2647
+ function extractAzureOpenAiToolCalls(response) {
2648
+ const responseToolCalls = response.choices[0]?.message.tool_calls ?? [];
2649
+ return responseToolCalls.map((responseToolCall) => ({
2650
+ id: responseToolCall.id,
2651
+ toolName: responseToolCall.function.name,
2652
+ input: parseAzureOpenAiToolArgumentsJson(responseToolCall.function.arguments)
2653
+ }));
2654
+ }
2655
+ function parseAzureOpenAiToolArgumentsJson(argumentsJsonText) {
2656
+ if (argumentsJsonText.trim().length === 0) {
2657
+ return {};
2658
+ }
2659
+ try {
2660
+ return JsonValueSchema8.parse(JSON.parse(argumentsJsonText));
2661
+ } catch (error) {
2662
+ throw new AppError16({
2663
+ code: AppErrorCode15.ValidationFailed,
2664
+ message: "Azure OpenAI tool call arguments were not valid JSON",
2665
+ statusCode: 502,
2666
+ cause: error instanceof Error ? error : void 0
2667
+ });
2668
+ }
2669
+ }
2670
+ function normalizeAzureOpenAiFinishReason(finishReason) {
2671
+ if (finishReason === "tool_calls") {
2672
+ return "tool_use";
2673
+ }
2674
+ if (finishReason === "length") {
2675
+ return "max_tokens";
2676
+ }
2677
+ return "end_turn";
2678
+ }
2679
+ function extractAzureOpenAiMessageContent(response, allowEmptyContent) {
2680
+ const content = response.choices[0]?.message.content;
2681
+ if (content === void 0 || content === null) {
2682
+ if (allowEmptyContent) {
2683
+ return "";
2684
+ }
2685
+ throw new AppError16({
2686
+ code: AppErrorCode15.ValidationFailed,
2687
+ message: "Azure OpenAI response contained no message content",
2688
+ statusCode: 502
2689
+ });
2690
+ }
2691
+ return content;
2692
+ }
2693
+ function mapAzureOpenAiUsageToTokenUsage(usage) {
2694
+ return {
2695
+ inputTokens: usage.prompt_tokens,
2696
+ outputTokens: usage.completion_tokens,
2697
+ totalTokens: usage.total_tokens
2698
+ };
2699
+ }
2700
+
2701
+ // src/azure-openai-stream.ts
2702
+ import { z as z10 } from "zod";
2703
+ var AzureOpenAiStreamToolCallDeltaSchema = z10.object({
2704
+ index: z10.number().int().nonnegative(),
2705
+ id: z10.string().optional(),
2706
+ function: z10.object({
2707
+ name: z10.string().optional(),
2708
+ arguments: z10.string().optional()
2709
+ }).optional()
2710
+ });
2711
+ var AzureOpenAiStreamChunkSchema = z10.object({
2712
+ choices: z10.array(
2713
+ z10.object({
2714
+ delta: z10.object({
2715
+ content: z10.string().nullable().optional(),
2716
+ tool_calls: z10.array(AzureOpenAiStreamToolCallDeltaSchema).optional()
2717
+ }).optional(),
2718
+ finish_reason: z10.string().nullable().optional()
2719
+ })
2720
+ ).optional(),
2721
+ usage: AzureOpenAiUsageSchema.nullable().optional()
2722
+ });
2723
+ async function* streamAzureOpenAiChatCompletion(input) {
2724
+ const startedAt = Date.now();
2725
+ const response = await establishAzureOpenAiStreamResponse(input);
2726
+ if (response.body === null) {
2727
+ throw buildProviderInvalidResponseError("Azure OpenAI", "stream body");
2728
+ }
2729
+ yield* parseAzureOpenAiStreamEvents(
2730
+ response.body,
2731
+ startedAt,
2732
+ input.abortSignal
2733
+ );
2734
+ }
2735
+ async function establishAzureOpenAiStreamResponse(input) {
2736
+ return await executeProviderCallWithRetry(input.retry, async () => {
2737
+ const response = await executeAbortableProviderFetch(
2738
+ "Azure OpenAI",
2739
+ async () => await input.fetchImplementation(input.url, {
2740
+ method: "POST",
2741
+ headers: input.headers,
2742
+ body: JSON.stringify(input.body),
2743
+ signal: input.abortSignal
2744
+ })
2745
+ );
2746
+ if (!response.ok) {
2747
+ throw buildProviderStatusError("Azure OpenAI", response.status);
2748
+ }
2749
+ return response;
2750
+ });
2751
+ }
2752
+ async function* parseAzureOpenAiStreamEvents(body, startedAt, abortSignal) {
2753
+ const accumulator = createAzureOpenAiStreamAccumulator();
2754
+ for await (const dataText of readServerSentEventDataLines2(body, abortSignal)) {
2755
+ if (dataText === "[DONE]") {
2756
+ yield {
2757
+ type: "completed",
2758
+ result: buildAzureOpenAiStreamResult(
2759
+ accumulator,
2760
+ Date.now() - startedAt
2761
+ )
2762
+ };
2763
+ return;
2764
+ }
2765
+ const parsedChunk = AzureOpenAiStreamChunkSchema.safeParse(
2766
+ JSON.parse(dataText)
2767
+ );
2768
+ if (!parsedChunk.success) {
2769
+ continue;
2770
+ }
2771
+ yield* applyAzureOpenAiStreamChunk(parsedChunk.data, accumulator);
2772
+ }
2773
+ throw buildProviderInvalidResponseError("Azure OpenAI", "stream termination");
2774
+ }
2775
+ async function* readServerSentEventDataLines2(body, abortSignal) {
2776
+ const reader = body.getReader();
2777
+ const decoder = new TextDecoder();
2778
+ let bufferedText = "";
2779
+ try {
2780
+ for (; ; ) {
2781
+ if (abortSignal?.aborted === true) {
2782
+ await reader.cancel();
2783
+ throw buildProviderCanceledError("Azure OpenAI");
2784
+ }
2785
+ const readResult = await reader.read();
2786
+ if (readResult.done) {
2787
+ return;
2788
+ }
2789
+ bufferedText += decoder.decode(readResult.value, { stream: true });
2790
+ const lines = bufferedText.split("\n");
2791
+ bufferedText = lines.pop() ?? "";
2792
+ for (const line of lines) {
2793
+ if (line.startsWith("data:")) {
2794
+ const dataText = line.slice("data:".length).trim();
2795
+ if (dataText.length > 0) {
2796
+ yield dataText;
2797
+ }
2798
+ }
2799
+ }
2800
+ }
2801
+ } catch (error) {
2802
+ if (error instanceof Error && isAbortError(error)) {
2803
+ throw buildProviderCanceledError("Azure OpenAI");
2804
+ }
2805
+ throw error;
2806
+ }
2807
+ }
2808
+ function createAzureOpenAiStreamAccumulator() {
2809
+ return {
2810
+ contentText: "",
2811
+ toolCallsByIndex: /* @__PURE__ */ new Map()
2812
+ };
2813
+ }
2814
+ function* applyAzureOpenAiStreamChunk(chunk, accumulator) {
2815
+ if (chunk.usage !== null && chunk.usage !== void 0) {
2816
+ accumulator.usage = chunk.usage;
2817
+ }
2818
+ const choice = chunk.choices?.[0];
2819
+ if (choice === void 0) {
2820
+ return;
2821
+ }
2822
+ if (choice.finish_reason !== null && choice.finish_reason !== void 0) {
2823
+ accumulator.finishReason = choice.finish_reason;
2824
+ }
2825
+ if (choice.delta === void 0) {
2826
+ return;
2827
+ }
2828
+ const contentDelta = choice.delta.content;
2829
+ if (contentDelta !== null && contentDelta !== void 0 && contentDelta.length > 0) {
2830
+ accumulator.contentText += contentDelta;
2831
+ yield { type: "text_delta", text: contentDelta };
2832
+ }
2833
+ for (const toolCallDelta of choice.delta.tool_calls ?? []) {
2834
+ yield* applyAzureOpenAiToolCallDelta(toolCallDelta, accumulator);
2835
+ }
2836
+ }
2837
+ function* applyAzureOpenAiToolCallDelta(toolCallDelta, accumulator) {
2838
+ const existingToolCall = accumulator.toolCallsByIndex.get(toolCallDelta.index);
2839
+ if (existingToolCall === void 0) {
2840
+ yield* startAzureOpenAiToolCallAccumulation(toolCallDelta, accumulator);
2841
+ return;
2842
+ }
2843
+ const argumentsDelta = toolCallDelta.function?.arguments;
2844
+ if (argumentsDelta !== void 0 && argumentsDelta.length > 0) {
2845
+ existingToolCall.argumentsJsonText += argumentsDelta;
2846
+ yield {
2847
+ type: "tool_call_input_delta",
2848
+ id: existingToolCall.id,
2849
+ inputJsonText: argumentsDelta
2850
+ };
2851
+ }
2852
+ }
2853
+ function* startAzureOpenAiToolCallAccumulation(toolCallDelta, accumulator) {
2854
+ const toolName = toolCallDelta.function?.name;
2855
+ if (toolCallDelta.id === void 0 || toolName === void 0) {
2856
+ throw buildProviderInvalidResponseError(
2857
+ "Azure OpenAI",
2858
+ "stream tool call start"
2859
+ );
2860
+ }
2861
+ const startedToolCall = {
2862
+ id: toolCallDelta.id,
2863
+ toolName,
2864
+ argumentsJsonText: toolCallDelta.function?.arguments ?? ""
2865
+ };
2866
+ accumulator.toolCallsByIndex.set(toolCallDelta.index, startedToolCall);
2867
+ yield {
2868
+ type: "tool_call_started",
2869
+ id: startedToolCall.id,
2870
+ toolName: startedToolCall.toolName
2871
+ };
2872
+ if (startedToolCall.argumentsJsonText.length > 0) {
2873
+ yield {
2874
+ type: "tool_call_input_delta",
2875
+ id: startedToolCall.id,
2876
+ inputJsonText: startedToolCall.argumentsJsonText
2877
+ };
2878
+ }
2879
+ }
2880
+ function buildAzureOpenAiStreamResult(accumulator, latencyMs) {
2881
+ const result = {
2882
+ content: accumulator.contentText,
2883
+ tokenUsage: mapAzureOpenAiUsageToTokenUsage(
2884
+ accumulator.usage ?? {
2885
+ prompt_tokens: 0,
2886
+ completion_tokens: 0,
2887
+ total_tokens: 0
2888
+ }
2889
+ ),
2890
+ latencyMs
2891
+ };
2892
+ const toolCalls = [...accumulator.toolCallsByIndex.values()].map(
2893
+ mapAccumulatedToolCallToModelToolCall2
2894
+ );
2895
+ if (toolCalls.length > 0) {
2896
+ result.toolCalls = toolCalls;
2897
+ }
2898
+ if (accumulator.finishReason !== void 0) {
2899
+ result.stopReason = normalizeAzureOpenAiFinishReason(
2900
+ accumulator.finishReason
2901
+ );
2902
+ }
2903
+ return result;
2904
+ }
2905
+ function mapAccumulatedToolCallToModelToolCall2(toolCallAccumulation) {
2906
+ return {
2907
+ id: toolCallAccumulation.id,
2908
+ toolName: toolCallAccumulation.toolName,
2909
+ input: parseAzureOpenAiToolArgumentsJson(
2910
+ toolCallAccumulation.argumentsJsonText
2911
+ )
2912
+ };
2913
+ }
2914
+
2915
+ // src/azure-openai-adapter.ts
2916
+ var defaultAzureOpenAiApiVersion = "2024-10-21";
2917
+ var azureDeploymentModelPlaceholder = "azure-deployment";
2918
+ function azureOpenai(options) {
2919
+ return {
2920
+ name: `azure-openai:${options.deployment}`,
2921
+ async generateChatCompletion(request) {
2922
+ return await executeAzureOpenAiAdapterCall(options, {
2923
+ messages: request.messages,
2924
+ temperature: request.temperature ?? options.temperature,
2925
+ maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
2926
+ reasoningModel: options.reasoningModel,
2927
+ tools: request.tools,
2928
+ toolChoice: request.toolChoice,
2929
+ abortSignal: request.abortSignal,
2930
+ extraBody: request.extraBody
2931
+ });
2932
+ },
2933
+ async generateStructuredOutput(request) {
2934
+ const completion = await executeAzureOpenAiAdapterCall(options, {
2935
+ ...resolveOpenAiStructuredOutputMode(request.messages, request.schema),
2936
+ temperature: request.temperature ?? options.temperature,
2937
+ maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
2938
+ reasoningModel: options.reasoningModel,
2939
+ abortSignal: request.abortSignal
2940
+ });
2941
+ return {
2942
+ value: parseStructuredJsonText(completion.content, request.schema),
2943
+ tokenUsage: completion.tokenUsage,
2944
+ latencyMs: completion.latencyMs
2945
+ };
2946
+ },
2947
+ streamChatCompletion(request) {
2948
+ return streamAzureOpenAiChatCompletion(
2949
+ buildAzureOpenAiStreamInput(options, request)
2950
+ );
2951
+ }
2952
+ };
2953
+ }
2954
+ function buildAzureOpenAiChatCompletionsUrl(options) {
2955
+ const endpoint = resolveAzureOpenAiEndpoint(options);
2956
+ const apiVersion = options.apiVersion ?? defaultAzureOpenAiApiVersion;
2957
+ return `${endpoint}/openai/deployments/${encodeURIComponent(options.deployment)}/chat/completions?api-version=${encodeURIComponent(apiVersion)}`;
2958
+ }
2959
+ function resolveAzureOpenAiEndpoint(options) {
2960
+ if (options.baseURL !== void 0 && options.baseURL.length > 0) {
2961
+ return options.baseURL.replace(/\/+$/, "");
2962
+ }
2963
+ if (options.resourceName !== void 0 && options.resourceName.length > 0) {
2964
+ return `https://${options.resourceName}.openai.azure.com`;
2965
+ }
2966
+ throw new AppError17({
2967
+ code: AppErrorCode16.BadRequest,
2968
+ message: "Azure OpenAI endpoint is missing. Pass resourceName or baseURL to azureOpenai().",
2969
+ statusCode: 400
2970
+ });
2971
+ }
2972
+ function buildAzureOpenAiRequestHeaders(options) {
2973
+ return {
2974
+ "content-type": "application/json",
2975
+ "api-key": resolveProviderApiKey({
2976
+ providerLabel: "Azure OpenAI",
2977
+ adapterFunctionName: "azureOpenai()",
2978
+ baseEnvVarName: "AZURE_OPENAI_API_KEY",
2979
+ apiKey: options.apiKey,
2980
+ apiKeyName: options.apiKeyName
2981
+ })
2982
+ };
2983
+ }
2984
+ function buildAzureOpenAiChatRequestBody(input) {
2985
+ const requestBody = buildOpenAiRequestBody(
2986
+ azureDeploymentModelPlaceholder,
2987
+ input
2988
+ );
2989
+ const { model: ignoredModel, ...requestBodyWithoutModel } = requestBody;
2990
+ void ignoredModel;
2991
+ return requestBodyWithoutModel;
2992
+ }
2993
+ async function executeAzureOpenAiAdapterCall(options, input) {
2994
+ return await executeProviderCallWithRetry(
2995
+ options.retry,
2996
+ async () => await requestAzureOpenAiChatCompletion(options, input)
2997
+ );
2998
+ }
2999
+ async function requestAzureOpenAiChatCompletion(options, input) {
3000
+ const fetchImplementation = options.fetchImplementation ?? fetch;
3001
+ const requestBody = mergeProviderRequestExtraBody(
3002
+ buildAzureOpenAiChatRequestBody(input),
3003
+ options.extraBody,
3004
+ input.extraBody
3005
+ );
3006
+ const startedAt = Date.now();
3007
+ const response = await executeAbortableProviderFetch(
3008
+ "Azure OpenAI",
3009
+ async () => await fetchImplementation(buildAzureOpenAiChatCompletionsUrl(options), {
3010
+ method: "POST",
3011
+ headers: buildAzureOpenAiRequestHeaders(options),
3012
+ body: JSON.stringify(requestBody),
3013
+ signal: input.abortSignal
3014
+ })
3015
+ );
3016
+ const latencyMs = Date.now() - startedAt;
3017
+ if (!response.ok) {
3018
+ throw buildProviderStatusError("Azure OpenAI", response.status);
3019
+ }
3020
+ const parseResult = AzureOpenAiChatCompletionResponseSchema.safeParse(
3021
+ await response.json()
3022
+ );
3023
+ if (!parseResult.success) {
3024
+ throw buildProviderInvalidResponseError("Azure OpenAI", "chat completion");
3025
+ }
3026
+ return mapAzureOpenAiResponseToChatCompletionResult(
3027
+ parseResult.data,
3028
+ latencyMs
3029
+ );
3030
+ }
3031
+ function buildAzureOpenAiStreamInput(options, request) {
3032
+ const requestBody = mergeProviderRequestExtraBody(
3033
+ buildAzureOpenAiChatRequestBody({
3034
+ messages: request.messages,
3035
+ temperature: request.temperature ?? options.temperature,
3036
+ maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
3037
+ reasoningModel: options.reasoningModel,
3038
+ tools: request.tools,
3039
+ toolChoice: request.toolChoice,
3040
+ abortSignal: request.abortSignal,
3041
+ extraBody: request.extraBody
3042
+ }),
3043
+ options.extraBody,
3044
+ request.extraBody
3045
+ );
3046
+ return {
3047
+ url: buildAzureOpenAiChatCompletionsUrl(options),
3048
+ headers: buildAzureOpenAiRequestHeaders(options),
3049
+ body: {
3050
+ ...requestBody,
3051
+ stream: true,
3052
+ stream_options: { include_usage: true }
3053
+ },
3054
+ fetchImplementation: options.fetchImplementation ?? fetch,
3055
+ retry: options.retry,
3056
+ abortSignal: request.abortSignal
3057
+ };
3058
+ }
3059
+
3060
+ // src/bedrock-adapter.ts
3061
+ import { z as z11 } from "zod";
3062
+ import { AppErrorCode as AppErrorCode17 } from "@assemble-dev/shared-types/errors";
3063
+ import { AppError as AppError18 } from "@assemble-dev/shared-utils/errors";
3064
+
3065
+ // src/bedrock-sigv4.ts
3066
+ var awsSigV4Algorithm = "AWS4-HMAC-SHA256";
3067
+ async function signAwsRequestWithSigV4(input) {
3068
+ const amzDate = formatAmzDateTime(input.signingDate ?? /* @__PURE__ */ new Date());
3069
+ const dateStamp = amzDate.slice(0, 8);
3070
+ const headersToSign = buildHeadersToSign(input, amzDate);
3071
+ const canonicalHeaderEntries = buildCanonicalHeaderEntries(headersToSign);
3072
+ const signedHeaderNames = canonicalHeaderEntries.map(([headerName]) => headerName).join(";");
3073
+ const credentialScope = `${dateStamp}/${input.region}/${input.service}/aws4_request`;
3074
+ const signatureHex = await computeAwsSigV4Signature(
3075
+ input,
3076
+ amzDate,
3077
+ credentialScope,
3078
+ canonicalHeaderEntries,
3079
+ signedHeaderNames
3080
+ );
3081
+ return {
3082
+ ...headersToSign,
3083
+ authorization: `${awsSigV4Algorithm} Credential=${input.credentials.accessKeyId}/${credentialScope}, SignedHeaders=${signedHeaderNames}, Signature=${signatureHex}`
3084
+ };
3085
+ }
3086
+ async function computeAwsSigV4Signature(input, amzDate, credentialScope, canonicalHeaderEntries, signedHeaderNames) {
3087
+ const canonicalRequest = await buildCanonicalRequest(
3088
+ input,
3089
+ canonicalHeaderEntries,
3090
+ signedHeaderNames
3091
+ );
3092
+ const stringToSign = [
3093
+ awsSigV4Algorithm,
3094
+ amzDate,
3095
+ credentialScope,
3096
+ await hashSha256Hex(canonicalRequest)
3097
+ ].join("\n");
3098
+ const signingKey = await deriveAwsSigningKey(
3099
+ input.credentials.secretAccessKey,
3100
+ amzDate.slice(0, 8),
3101
+ input.region,
3102
+ input.service
3103
+ );
3104
+ return bytesToHex(await computeHmacSha256(signingKey, stringToSign));
3105
+ }
3106
+ function buildHeadersToSign(input, amzDate) {
3107
+ const headersToSign = {};
3108
+ for (const [headerName, headerValue] of Object.entries(input.headers)) {
3109
+ headersToSign[headerName.toLowerCase()] = headerValue;
3110
+ }
3111
+ headersToSign.host = input.url.host;
3112
+ headersToSign["x-amz-date"] = amzDate;
3113
+ if (input.credentials.sessionToken !== void 0) {
3114
+ headersToSign["x-amz-security-token"] = input.credentials.sessionToken;
3115
+ }
3116
+ return headersToSign;
3117
+ }
3118
+ function buildCanonicalHeaderEntries(headersToSign) {
3119
+ return Object.entries(headersToSign).map(([headerName, headerValue]) => [
3120
+ headerName.toLowerCase(),
3121
+ headerValue.trim().replace(/\s+/g, " ")
3122
+ ]).sort(([leftName], [rightName]) => leftName.localeCompare(rightName));
3123
+ }
3124
+ async function buildCanonicalRequest(input, canonicalHeaderEntries, signedHeaderNames) {
3125
+ const canonicalHeadersText = canonicalHeaderEntries.map(([headerName, headerValue]) => `${headerName}:${headerValue}`).join("\n");
3126
+ return [
3127
+ input.method.toUpperCase(),
3128
+ buildCanonicalUri(input.url.pathname),
3129
+ buildCanonicalQueryString(input.url.searchParams),
3130
+ `${canonicalHeadersText}
3131
+ `,
3132
+ signedHeaderNames,
3133
+ await hashSha256Hex(input.bodyText)
3134
+ ].join("\n");
3135
+ }
3136
+ function buildCanonicalUri(pathname) {
3137
+ if (pathname.length === 0) {
3138
+ return "/";
3139
+ }
3140
+ return pathname.split("/").map(encodeRfc3986UriComponent).join("/");
3141
+ }
3142
+ function buildCanonicalQueryString(searchParams) {
3143
+ const encodedEntries = [];
3144
+ searchParams.forEach((parameterValue, parameterName) => {
3145
+ encodedEntries.push([
3146
+ encodeRfc3986UriComponent(parameterName),
3147
+ encodeRfc3986UriComponent(parameterValue)
3148
+ ]);
3149
+ });
3150
+ return encodedEntries.sort(
3151
+ ([leftName, leftValue], [rightName, rightValue]) => leftName.localeCompare(rightName) || leftValue.localeCompare(rightValue)
3152
+ ).map(([parameterName, parameterValue]) => `${parameterName}=${parameterValue}`).join("&");
3153
+ }
3154
+ function encodeRfc3986UriComponent(value) {
3155
+ return encodeURIComponent(value).replace(
3156
+ /[!'()*]/g,
3157
+ (character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`
3158
+ );
3159
+ }
3160
+ function formatAmzDateTime(date) {
3161
+ return date.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
3162
+ }
3163
+ async function deriveAwsSigningKey(secretAccessKey, dateStamp, region, service) {
3164
+ const dateKey = await computeHmacSha256(
3165
+ new TextEncoder().encode(`AWS4${secretAccessKey}`),
3166
+ dateStamp
3167
+ );
3168
+ const regionKey = await computeHmacSha256(dateKey, region);
3169
+ const serviceKey = await computeHmacSha256(regionKey, service);
3170
+ return await computeHmacSha256(serviceKey, "aws4_request");
3171
+ }
3172
+ async function hashSha256Hex(text) {
3173
+ const digest = await crypto.subtle.digest(
3174
+ "SHA-256",
3175
+ new TextEncoder().encode(text)
3176
+ );
3177
+ return bytesToHex(new Uint8Array(digest));
3178
+ }
3179
+ async function computeHmacSha256(keyBytes, text) {
3180
+ const hmacKey = await crypto.subtle.importKey(
3181
+ "raw",
3182
+ keyBytes,
3183
+ { name: "HMAC", hash: "SHA-256" },
3184
+ false,
3185
+ ["sign"]
3186
+ );
3187
+ const signature = await crypto.subtle.sign(
3188
+ "HMAC",
3189
+ hmacKey,
3190
+ new TextEncoder().encode(text)
3191
+ );
3192
+ return new Uint8Array(signature);
3193
+ }
3194
+ function bytesToHex(bytes) {
3195
+ return Array.from(bytes).map((byteValue) => byteValue.toString(16).padStart(2, "0")).join("");
3196
+ }
3197
+
3198
+ // src/bedrock-adapter.ts
3199
+ var bedrockAnthropicVersion = "bedrock-2023-05-31";
3200
+ var defaultBedrockMaxOutputTokens = 1024;
3201
+ var bedrockSigningServiceName = "bedrock";
3202
+ var bedrockModelPlaceholder = "bedrock-invoke-model";
3203
+ var BedrockEnvCredentialsSchema = z11.object({
3204
+ AWS_ACCESS_KEY_ID: z11.string().optional(),
3205
+ AWS_SECRET_ACCESS_KEY: z11.string().optional(),
3206
+ AWS_SESSION_TOKEN: z11.string().optional()
3207
+ });
3208
+ function bedrock(options) {
3209
+ return {
3210
+ name: `bedrock:${options.modelId}`,
3211
+ async generateChatCompletion(request) {
3212
+ return await executeBedrockAdapterCall(options, {
3213
+ messages: request.messages,
3214
+ temperature: request.temperature ?? options.temperature,
3215
+ maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
3216
+ tools: request.tools,
3217
+ toolChoice: request.toolChoice,
3218
+ abortSignal: request.abortSignal,
3219
+ extraBody: request.extraBody
3220
+ });
3221
+ },
3222
+ async generateStructuredOutput(request) {
3223
+ const completion = await executeBedrockAdapterCall(options, {
3224
+ messages: [
3225
+ buildBedrockStructuredOutputSystemMessage(request.schema),
3226
+ ...request.messages
3227
+ ],
3228
+ temperature: request.temperature ?? options.temperature,
3229
+ maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
3230
+ abortSignal: request.abortSignal
3231
+ });
3232
+ return {
3233
+ value: parseStructuredJsonText(completion.content, request.schema),
3234
+ tokenUsage: completion.tokenUsage,
3235
+ latencyMs: completion.latencyMs
3236
+ };
3237
+ }
3238
+ };
3239
+ }
3240
+ function buildBedrockInvokeModelUrl(region, modelId) {
3241
+ return `https://bedrock-runtime.${region}.amazonaws.com/model/${encodeURIComponent(modelId)}/invoke`;
3242
+ }
3243
+ function resolveBedrockCredentials(options) {
3244
+ if (options.credentials !== void 0) {
3245
+ return options.credentials;
3246
+ }
3247
+ const parsedEnv = BedrockEnvCredentialsSchema.parse(process.env);
3248
+ const accessKeyId = parsedEnv.AWS_ACCESS_KEY_ID;
3249
+ const secretAccessKey = parsedEnv.AWS_SECRET_ACCESS_KEY;
3250
+ if (accessKeyId === void 0 || accessKeyId.length === 0 || secretAccessKey === void 0 || secretAccessKey.length === 0) {
3251
+ throw new AppError18({
3252
+ code: AppErrorCode17.Unauthorized,
3253
+ message: "AWS credentials are missing. Pass credentials to bedrock() or set the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables.",
3254
+ statusCode: 401
3255
+ });
3256
+ }
3257
+ const credentials = { accessKeyId, secretAccessKey };
3258
+ const sessionToken = parsedEnv.AWS_SESSION_TOKEN;
3259
+ if (sessionToken !== void 0 && sessionToken.length > 0) {
3260
+ credentials.sessionToken = sessionToken;
3261
+ }
3262
+ return credentials;
3263
+ }
3264
+ async function executeBedrockAdapterCall(options, input) {
3265
+ return await executeProviderCallWithRetry(
3266
+ options.retry,
3267
+ async () => await requestBedrockInvokeModel(options, input)
3268
+ );
3269
+ }
3270
+ async function requestBedrockInvokeModel(options, input) {
3271
+ const credentials = resolveBedrockCredentials(options);
3272
+ const fetchImplementation = options.fetchImplementation ?? fetch;
3273
+ const requestBody = mergeProviderRequestExtraBody(
3274
+ buildBedrockInvokeModelRequestBody(input),
3275
+ options.extraBody,
3276
+ input.extraBody
3277
+ );
3278
+ const bodyText = JSON.stringify(requestBody);
3279
+ const url = new URL(buildBedrockInvokeModelUrl(options.region, options.modelId));
3280
+ const signedHeaders = await signAwsRequestWithSigV4({
3281
+ method: "POST",
3282
+ url,
3283
+ headers: { "content-type": "application/json" },
3284
+ bodyText,
3285
+ region: options.region,
3286
+ service: bedrockSigningServiceName,
3287
+ credentials
3288
+ });
3289
+ const startedAt = Date.now();
3290
+ const response = await executeAbortableProviderFetch(
3291
+ "Bedrock",
3292
+ async () => await fetchImplementation(url.toString(), {
3293
+ method: "POST",
3294
+ headers: signedHeaders,
3295
+ body: bodyText,
3296
+ signal: input.abortSignal
3297
+ })
3298
+ );
3299
+ const latencyMs = Date.now() - startedAt;
3300
+ if (!response.ok) {
3301
+ throw buildProviderStatusError("Bedrock", response.status);
3302
+ }
3303
+ const parseResult = AnthropicMessagesResponseSchema.safeParse(
3304
+ await response.json()
3305
+ );
3306
+ if (!parseResult.success) {
3307
+ throw buildProviderInvalidResponseError("Bedrock", "invoke model");
3308
+ }
3309
+ return mapAnthropicResponseToChatCompletionResult(parseResult.data, latencyMs);
3310
+ }
3311
+ function buildBedrockInvokeModelRequestBody(input) {
3312
+ const anthropicRequestBody = buildAnthropicRequestBody(
3313
+ {
3314
+ model: bedrockModelPlaceholder,
3315
+ defaultMaxOutputTokens: defaultBedrockMaxOutputTokens
3316
+ },
3317
+ input
3318
+ );
3319
+ const {
3320
+ model: ignoredModel,
3321
+ stream: ignoredStream,
3322
+ ...requestBodyWithoutModel
3323
+ } = anthropicRequestBody;
3324
+ void ignoredModel;
3325
+ void ignoredStream;
3326
+ return {
3327
+ ...requestBodyWithoutModel,
3328
+ anthropic_version: bedrockAnthropicVersion
3329
+ };
3330
+ }
3331
+ function buildBedrockStructuredOutputSystemMessage(schema) {
3332
+ if (!isZodV4Schema(schema)) {
3333
+ return structuredOutputJsonOnlySystemMessage;
3334
+ }
3335
+ return {
3336
+ role: "system",
3337
+ content: `Respond with a single JSON object that satisfies the following JSON Schema. Output only valid JSON with no surrounding text.
3338
+
3339
+ JSON Schema:
3340
+ ${JSON.stringify(convertZodSchemaToJsonSchema(schema))}`
3341
+ };
3342
+ }
2147
3343
  export {
2148
3344
  AnthropicMessagesResponseSchema,
2149
3345
  AnthropicStreamEventSchema,
3346
+ AzureOpenAiChatCompletionResponseSchema,
2150
3347
  ChatMessageCacheControlSchema,
2151
3348
  ChatMessageRoleSchema,
2152
3349
  ChatMessageSchema,
@@ -2157,16 +3354,30 @@ export {
2157
3354
  anthropicBatchJsonOnlySystemInstruction,
2158
3355
  anthropicBatchTraceWorkflowName,
2159
3356
  applyCacheControlToLastContentBlock,
3357
+ awsSigV4Algorithm,
3358
+ azureOpenai,
3359
+ bedrock,
3360
+ bedrockAnthropicVersion,
2160
3361
  buildAnthropicCacheControl,
2161
3362
  buildAnthropicRequestBody,
3363
+ buildAnthropicStructuredOutputJsonSchema,
3364
+ buildAzureOpenAiChatCompletionsUrl,
3365
+ buildAzureOpenAiChatRequestBody,
3366
+ buildBedrockInvokeModelRequestBody,
3367
+ buildBedrockInvokeModelUrl,
3368
+ buildGeminiResponseSchema,
2162
3369
  buildOpenAiRequestBody,
3370
+ buildOpenAiStructuredOutputJsonSchema,
2163
3371
  buildProviderCanceledError,
2164
3372
  calculateProviderRetryDelayMs,
3373
+ convertZodSchemaToJsonSchema,
2165
3374
  createAnthropicBatchClient,
2166
3375
  defaultAnthropicBaseUrl,
2167
3376
  defaultAnthropicBatchPollIntervalMs,
2168
3377
  defaultAnthropicBatchTimeoutMs,
2169
3378
  defaultAnthropicMaxOutputTokens,
3379
+ defaultAzureOpenAiApiVersion,
3380
+ defaultBedrockMaxOutputTokens,
2170
3381
  defaultGeminiBaseUrl,
2171
3382
  defaultOpenAiBaseUrl,
2172
3383
  defaultProviderRetryInitialDelayMs,
@@ -2177,14 +3388,19 @@ export {
2177
3388
  executeProviderCallWithModelFallback,
2178
3389
  executeProviderCallWithRetry,
2179
3390
  extractAnthropicTextContent,
3391
+ extractAnthropicThinkingText,
2180
3392
  extractAnthropicToolCalls,
2181
3393
  extractMessageText,
2182
3394
  gemini,
2183
3395
  isAbortError,
3396
+ isOpenAiReasoningModel,
2184
3397
  isRetryableProviderAppError,
3398
+ isZodV4Schema,
2185
3399
  joinSystemMessageText,
2186
3400
  mapAnthropicResponseToChatCompletionResult,
2187
3401
  mapAnthropicUsageToTokenUsage,
3402
+ mapAzureOpenAiResponseToChatCompletionResult,
3403
+ mapAzureOpenAiUsageToTokenUsage,
2188
3404
  mapChatMessageToAnthropicRequestMessage,
2189
3405
  mapChatMessageToOpenAiRequestMessage,
2190
3406
  mapModelToolChoiceToAnthropicToolChoice,
@@ -2194,11 +3410,25 @@ export {
2194
3410
  mergeProviderRequestExtraBody,
2195
3411
  mockModel,
2196
3412
  normalizeAnthropicStopReason,
3413
+ normalizeAzureOpenAiFinishReason,
3414
+ openAiStructuredOutputSchemaName,
2197
3415
  openai,
2198
3416
  parseAnthropicBatchStructuredContent,
2199
3417
  parseAnthropicStreamEvents,
2200
3418
  parseAnthropicToolInputJson,
3419
+ parseAzureOpenAiStreamEvents,
3420
+ parseAzureOpenAiToolArgumentsJson,
3421
+ prependStructuredOutputJsonOnlySystemMessage,
2201
3422
  resolveAnthropicPromptCachingSettings,
3423
+ resolveBedrockCredentials,
3424
+ resolveOpenAiStructuredOutputMode,
2202
3425
  resolveProviderApiKey,
2203
- streamAnthropicChatCompletion
3426
+ sanitizeJsonSchemaForAnthropicStructuredOutput,
3427
+ sanitizeJsonSchemaForGeminiResponseSchema,
3428
+ sanitizeJsonSchemaForOpenAiStructuredOutput,
3429
+ signAwsRequestWithSigV4,
3430
+ streamAnthropicChatCompletion,
3431
+ streamAzureOpenAiChatCompletion,
3432
+ structuredOutputJsonOnlySystemInstruction,
3433
+ structuredOutputJsonOnlySystemMessage
2204
3434
  };