@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.cjs +1530 -266
- package/dist/index.d.cts +174 -6
- package/dist/index.d.ts +174 -6
- package/dist/index.js +1474 -244
- package/package.json +3 -3
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
|
|
57
|
-
import { AppErrorCode as
|
|
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
|
|
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
|
-
|
|
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
|
|
73
|
-
|
|
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
|
|
162
|
-
code:
|
|
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
|
|
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
|
|
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
|
|
189
|
-
code:
|
|
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
|
|
199
|
-
import { AppErrorCode as
|
|
200
|
-
import { AppError as
|
|
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
|
|
218
|
-
code:
|
|
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
|
|
227
|
-
code:
|
|
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
|
|
238
|
-
code:
|
|
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 =
|
|
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
|
|
252
|
-
import { AppError as
|
|
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
|
|
258
|
-
code:
|
|
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
|
|
561
|
+
import { AppError as AppError7 } from "@assemble-dev/shared-utils/errors";
|
|
285
562
|
|
|
286
563
|
// src/provider-retry.ts
|
|
287
|
-
import { AppErrorCode as
|
|
288
|
-
import { AppError as
|
|
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
|
-
|
|
294
|
-
|
|
295
|
-
|
|
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
|
|
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
|
|
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
|
|
356
|
-
import { AppError as
|
|
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
|
|
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
|
|
368
|
-
code:
|
|
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
|
|
652
|
+
return AppErrorCode7.BadRequest;
|
|
376
653
|
}
|
|
377
654
|
if (providerStatus === 401) {
|
|
378
|
-
return
|
|
655
|
+
return AppErrorCode7.Unauthorized;
|
|
379
656
|
}
|
|
380
657
|
if (providerStatus === 403) {
|
|
381
|
-
return
|
|
658
|
+
return AppErrorCode7.Forbidden;
|
|
382
659
|
}
|
|
383
660
|
if (providerStatus === 404) {
|
|
384
|
-
return
|
|
661
|
+
return AppErrorCode7.NotFound;
|
|
385
662
|
}
|
|
386
663
|
if (providerStatus === 429) {
|
|
387
|
-
return
|
|
664
|
+
return AppErrorCode7.RateLimited;
|
|
388
665
|
}
|
|
389
|
-
return
|
|
666
|
+
return AppErrorCode7.InternalServerError;
|
|
390
667
|
}
|
|
391
668
|
function mapAppErrorCodeToStatusCode(code) {
|
|
392
|
-
if (code ===
|
|
669
|
+
if (code === AppErrorCode7.BadRequest) {
|
|
393
670
|
return 400;
|
|
394
671
|
}
|
|
395
|
-
if (code ===
|
|
672
|
+
if (code === AppErrorCode7.Unauthorized) {
|
|
396
673
|
return 401;
|
|
397
674
|
}
|
|
398
|
-
if (code ===
|
|
675
|
+
if (code === AppErrorCode7.Forbidden) {
|
|
399
676
|
return 403;
|
|
400
677
|
}
|
|
401
|
-
if (code ===
|
|
678
|
+
if (code === AppErrorCode7.NotFound) {
|
|
402
679
|
return 404;
|
|
403
680
|
}
|
|
404
|
-
if (code ===
|
|
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 =
|
|
413
|
-
id:
|
|
414
|
-
function:
|
|
415
|
-
name:
|
|
416
|
-
arguments:
|
|
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 =
|
|
420
|
-
choices:
|
|
421
|
-
|
|
422
|
-
message:
|
|
423
|
-
content:
|
|
424
|
-
tool_calls:
|
|
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:
|
|
703
|
+
finish_reason: z4.string().nullable().optional()
|
|
427
704
|
})
|
|
428
705
|
).min(1),
|
|
429
|
-
usage:
|
|
430
|
-
prompt_tokens:
|
|
431
|
-
completion_tokens:
|
|
432
|
-
total_tokens:
|
|
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
|
|
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
|
|
555
|
-
code:
|
|
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
|
|
578
|
-
code:
|
|
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
|
|
799
|
-
import { AppErrorCode as
|
|
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
|
|
802
|
-
var AnthropicUsageSchema =
|
|
803
|
-
input_tokens:
|
|
804
|
-
output_tokens:
|
|
805
|
-
cache_creation_input_tokens:
|
|
806
|
-
cache_read_input_tokens:
|
|
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 =
|
|
809
|
-
|
|
810
|
-
type:
|
|
811
|
-
text:
|
|
1084
|
+
var AnthropicContentBlockSchema = z5.discriminatedUnion("type", [
|
|
1085
|
+
z5.object({
|
|
1086
|
+
type: z5.literal("text"),
|
|
1087
|
+
text: z5.string()
|
|
812
1088
|
}),
|
|
813
|
-
|
|
814
|
-
type:
|
|
815
|
-
id:
|
|
816
|
-
name:
|
|
1089
|
+
z5.object({
|
|
1090
|
+
type: z5.literal("tool_use"),
|
|
1091
|
+
id: z5.string(),
|
|
1092
|
+
name: z5.string(),
|
|
817
1093
|
input: JsonValueSchema4
|
|
818
1094
|
}),
|
|
819
|
-
|
|
820
|
-
type:
|
|
821
|
-
thinking:
|
|
822
|
-
signature:
|
|
1095
|
+
z5.object({
|
|
1096
|
+
type: z5.literal("thinking"),
|
|
1097
|
+
thinking: z5.string().optional(),
|
|
1098
|
+
signature: z5.string().optional()
|
|
823
1099
|
}),
|
|
824
|
-
|
|
825
|
-
type:
|
|
826
|
-
data:
|
|
1100
|
+
z5.object({
|
|
1101
|
+
type: z5.literal("redacted_thinking"),
|
|
1102
|
+
data: z5.string().optional()
|
|
827
1103
|
})
|
|
828
1104
|
]);
|
|
829
|
-
var AnthropicMessagesResponseSchema =
|
|
830
|
-
content:
|
|
831
|
-
stop_reason:
|
|
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
|
|
862
|
-
code:
|
|
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
|
|
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
|
|
1184
|
+
import { AppError as AppError11 } from "@assemble-dev/shared-utils/errors";
|
|
902
1185
|
|
|
903
1186
|
// src/anthropic-stream-events.ts
|
|
904
|
-
import { z as
|
|
905
|
-
var AnthropicStreamEventSchema =
|
|
906
|
-
|
|
907
|
-
type:
|
|
908
|
-
message:
|
|
909
|
-
usage:
|
|
910
|
-
input_tokens:
|
|
911
|
-
output_tokens:
|
|
912
|
-
cache_creation_input_tokens:
|
|
913
|
-
cache_read_input_tokens:
|
|
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
|
-
|
|
918
|
-
type:
|
|
919
|
-
index:
|
|
920
|
-
content_block:
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
type:
|
|
924
|
-
|
|
925
|
-
|
|
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
|
-
|
|
930
|
-
type:
|
|
931
|
-
index:
|
|
932
|
-
delta:
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
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
|
-
|
|
941
|
-
|
|
942
|
-
type:
|
|
943
|
-
delta:
|
|
944
|
-
usage:
|
|
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
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
type:
|
|
950
|
-
error:
|
|
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
|
|
1044
|
-
code:
|
|
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
|
|
1160
|
-
code:
|
|
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(
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
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
|
|
1306
|
-
import { AppErrorCode as
|
|
1307
|
-
import { AppError as
|
|
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 =
|
|
1310
|
-
candidates:
|
|
1311
|
-
|
|
1312
|
-
content:
|
|
1313
|
-
parts:
|
|
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:
|
|
1318
|
-
promptTokenCount:
|
|
1319
|
-
candidatesTokenCount:
|
|
1320
|
-
totalTokenCount:
|
|
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(
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
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
|
|
1434
|
-
code:
|
|
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.
|
|
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
|
|
1483
|
-
code:
|
|
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
|
|
1503
|
-
import { AppError as
|
|
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
|
|
1584
|
-
code:
|
|
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
|
|
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
|
|
2110
|
+
import { AppError as AppError15 } from "@assemble-dev/shared-utils/errors";
|
|
1675
2111
|
|
|
1676
2112
|
// src/anthropic-batch-structured.ts
|
|
1677
|
-
import { AppErrorCode as
|
|
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
|
|
1680
|
-
var anthropicBatchJsonOnlySystemInstruction =
|
|
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
|
|
1689
|
-
code:
|
|
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
|
|
1881
|
-
var AnthropicMessageBatchResponseSchema =
|
|
1882
|
-
id:
|
|
1883
|
-
processing_status:
|
|
1884
|
-
request_counts:
|
|
1885
|
-
processing:
|
|
1886
|
-
succeeded:
|
|
1887
|
-
errored:
|
|
1888
|
-
canceled:
|
|
1889
|
-
expired:
|
|
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:
|
|
1892
|
-
created_at:
|
|
1893
|
-
ended_at:
|
|
2341
|
+
results_url: z8.string().nullable(),
|
|
2342
|
+
created_at: z8.string(),
|
|
2343
|
+
ended_at: z8.string().nullable()
|
|
1894
2344
|
});
|
|
1895
|
-
var AnthropicBatchContentBlockSchema =
|
|
1896
|
-
|
|
1897
|
-
type:
|
|
1898
|
-
text:
|
|
2345
|
+
var AnthropicBatchContentBlockSchema = z8.discriminatedUnion("type", [
|
|
2346
|
+
z8.object({
|
|
2347
|
+
type: z8.literal("text"),
|
|
2348
|
+
text: z8.string()
|
|
1899
2349
|
}),
|
|
1900
|
-
|
|
1901
|
-
type:
|
|
1902
|
-
thinking:
|
|
1903
|
-
signature:
|
|
2350
|
+
z8.object({
|
|
2351
|
+
type: z8.literal("thinking"),
|
|
2352
|
+
thinking: z8.string().optional(),
|
|
2353
|
+
signature: z8.string().optional()
|
|
1904
2354
|
}),
|
|
1905
|
-
|
|
1906
|
-
type:
|
|
1907
|
-
data:
|
|
2355
|
+
z8.object({
|
|
2356
|
+
type: z8.literal("redacted_thinking"),
|
|
2357
|
+
data: z8.string().optional()
|
|
1908
2358
|
})
|
|
1909
2359
|
]);
|
|
1910
|
-
var AnthropicBatchResultLineSchema =
|
|
1911
|
-
custom_id:
|
|
1912
|
-
result:
|
|
1913
|
-
|
|
1914
|
-
type:
|
|
1915
|
-
message:
|
|
1916
|
-
content:
|
|
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
|
-
|
|
1921
|
-
type:
|
|
1922
|
-
error:
|
|
1923
|
-
type:
|
|
1924
|
-
message:
|
|
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
|
-
|
|
1928
|
-
|
|
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
|
|
2079
|
-
code:
|
|
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
|
|
2141
|
-
code:
|
|
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
|
-
|
|
3426
|
+
sanitizeJsonSchemaForAnthropicStructuredOutput,
|
|
3427
|
+
sanitizeJsonSchemaForGeminiResponseSchema,
|
|
3428
|
+
sanitizeJsonSchemaForOpenAiStructuredOutput,
|
|
3429
|
+
signAwsRequestWithSigV4,
|
|
3430
|
+
streamAnthropicChatCompletion,
|
|
3431
|
+
streamAzureOpenAiChatCompletion,
|
|
3432
|
+
structuredOutputJsonOnlySystemInstruction,
|
|
3433
|
+
structuredOutputJsonOnlySystemMessage
|
|
2204
3434
|
};
|