@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.cjs
CHANGED
|
@@ -22,6 +22,7 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
AnthropicMessagesResponseSchema: () => AnthropicMessagesResponseSchema,
|
|
24
24
|
AnthropicStreamEventSchema: () => AnthropicStreamEventSchema,
|
|
25
|
+
AzureOpenAiChatCompletionResponseSchema: () => AzureOpenAiChatCompletionResponseSchema,
|
|
25
26
|
ChatMessageCacheControlSchema: () => ChatMessageCacheControlSchema,
|
|
26
27
|
ChatMessageRoleSchema: () => ChatMessageRoleSchema,
|
|
27
28
|
ChatMessageSchema: () => ChatMessageSchema,
|
|
@@ -32,16 +33,30 @@ __export(index_exports, {
|
|
|
32
33
|
anthropicBatchJsonOnlySystemInstruction: () => anthropicBatchJsonOnlySystemInstruction,
|
|
33
34
|
anthropicBatchTraceWorkflowName: () => anthropicBatchTraceWorkflowName,
|
|
34
35
|
applyCacheControlToLastContentBlock: () => applyCacheControlToLastContentBlock,
|
|
36
|
+
awsSigV4Algorithm: () => awsSigV4Algorithm,
|
|
37
|
+
azureOpenai: () => azureOpenai,
|
|
38
|
+
bedrock: () => bedrock,
|
|
39
|
+
bedrockAnthropicVersion: () => bedrockAnthropicVersion,
|
|
35
40
|
buildAnthropicCacheControl: () => buildAnthropicCacheControl,
|
|
36
41
|
buildAnthropicRequestBody: () => buildAnthropicRequestBody,
|
|
42
|
+
buildAnthropicStructuredOutputJsonSchema: () => buildAnthropicStructuredOutputJsonSchema,
|
|
43
|
+
buildAzureOpenAiChatCompletionsUrl: () => buildAzureOpenAiChatCompletionsUrl,
|
|
44
|
+
buildAzureOpenAiChatRequestBody: () => buildAzureOpenAiChatRequestBody,
|
|
45
|
+
buildBedrockInvokeModelRequestBody: () => buildBedrockInvokeModelRequestBody,
|
|
46
|
+
buildBedrockInvokeModelUrl: () => buildBedrockInvokeModelUrl,
|
|
47
|
+
buildGeminiResponseSchema: () => buildGeminiResponseSchema,
|
|
37
48
|
buildOpenAiRequestBody: () => buildOpenAiRequestBody,
|
|
49
|
+
buildOpenAiStructuredOutputJsonSchema: () => buildOpenAiStructuredOutputJsonSchema,
|
|
38
50
|
buildProviderCanceledError: () => buildProviderCanceledError,
|
|
39
51
|
calculateProviderRetryDelayMs: () => calculateProviderRetryDelayMs,
|
|
52
|
+
convertZodSchemaToJsonSchema: () => convertZodSchemaToJsonSchema,
|
|
40
53
|
createAnthropicBatchClient: () => createAnthropicBatchClient,
|
|
41
54
|
defaultAnthropicBaseUrl: () => defaultAnthropicBaseUrl,
|
|
42
55
|
defaultAnthropicBatchPollIntervalMs: () => defaultAnthropicBatchPollIntervalMs,
|
|
43
56
|
defaultAnthropicBatchTimeoutMs: () => defaultAnthropicBatchTimeoutMs,
|
|
44
57
|
defaultAnthropicMaxOutputTokens: () => defaultAnthropicMaxOutputTokens,
|
|
58
|
+
defaultAzureOpenAiApiVersion: () => defaultAzureOpenAiApiVersion,
|
|
59
|
+
defaultBedrockMaxOutputTokens: () => defaultBedrockMaxOutputTokens,
|
|
45
60
|
defaultGeminiBaseUrl: () => defaultGeminiBaseUrl,
|
|
46
61
|
defaultOpenAiBaseUrl: () => defaultOpenAiBaseUrl,
|
|
47
62
|
defaultProviderRetryInitialDelayMs: () => defaultProviderRetryInitialDelayMs,
|
|
@@ -52,14 +67,19 @@ __export(index_exports, {
|
|
|
52
67
|
executeProviderCallWithModelFallback: () => executeProviderCallWithModelFallback,
|
|
53
68
|
executeProviderCallWithRetry: () => executeProviderCallWithRetry,
|
|
54
69
|
extractAnthropicTextContent: () => extractAnthropicTextContent,
|
|
70
|
+
extractAnthropicThinkingText: () => extractAnthropicThinkingText,
|
|
55
71
|
extractAnthropicToolCalls: () => extractAnthropicToolCalls,
|
|
56
72
|
extractMessageText: () => extractMessageText,
|
|
57
73
|
gemini: () => gemini,
|
|
58
74
|
isAbortError: () => isAbortError,
|
|
75
|
+
isOpenAiReasoningModel: () => isOpenAiReasoningModel,
|
|
59
76
|
isRetryableProviderAppError: () => isRetryableProviderAppError,
|
|
77
|
+
isZodV4Schema: () => isZodV4Schema,
|
|
60
78
|
joinSystemMessageText: () => joinSystemMessageText,
|
|
61
79
|
mapAnthropicResponseToChatCompletionResult: () => mapAnthropicResponseToChatCompletionResult,
|
|
62
80
|
mapAnthropicUsageToTokenUsage: () => mapAnthropicUsageToTokenUsage,
|
|
81
|
+
mapAzureOpenAiResponseToChatCompletionResult: () => mapAzureOpenAiResponseToChatCompletionResult,
|
|
82
|
+
mapAzureOpenAiUsageToTokenUsage: () => mapAzureOpenAiUsageToTokenUsage,
|
|
63
83
|
mapChatMessageToAnthropicRequestMessage: () => mapChatMessageToAnthropicRequestMessage,
|
|
64
84
|
mapChatMessageToOpenAiRequestMessage: () => mapChatMessageToOpenAiRequestMessage,
|
|
65
85
|
mapModelToolChoiceToAnthropicToolChoice: () => mapModelToolChoiceToAnthropicToolChoice,
|
|
@@ -69,13 +89,27 @@ __export(index_exports, {
|
|
|
69
89
|
mergeProviderRequestExtraBody: () => mergeProviderRequestExtraBody,
|
|
70
90
|
mockModel: () => mockModel,
|
|
71
91
|
normalizeAnthropicStopReason: () => normalizeAnthropicStopReason,
|
|
92
|
+
normalizeAzureOpenAiFinishReason: () => normalizeAzureOpenAiFinishReason,
|
|
93
|
+
openAiStructuredOutputSchemaName: () => openAiStructuredOutputSchemaName,
|
|
72
94
|
openai: () => openai,
|
|
73
95
|
parseAnthropicBatchStructuredContent: () => parseAnthropicBatchStructuredContent,
|
|
74
96
|
parseAnthropicStreamEvents: () => parseAnthropicStreamEvents,
|
|
75
97
|
parseAnthropicToolInputJson: () => parseAnthropicToolInputJson,
|
|
98
|
+
parseAzureOpenAiStreamEvents: () => parseAzureOpenAiStreamEvents,
|
|
99
|
+
parseAzureOpenAiToolArgumentsJson: () => parseAzureOpenAiToolArgumentsJson,
|
|
100
|
+
prependStructuredOutputJsonOnlySystemMessage: () => prependStructuredOutputJsonOnlySystemMessage,
|
|
76
101
|
resolveAnthropicPromptCachingSettings: () => resolveAnthropicPromptCachingSettings,
|
|
102
|
+
resolveBedrockCredentials: () => resolveBedrockCredentials,
|
|
103
|
+
resolveOpenAiStructuredOutputMode: () => resolveOpenAiStructuredOutputMode,
|
|
77
104
|
resolveProviderApiKey: () => resolveProviderApiKey,
|
|
78
|
-
|
|
105
|
+
sanitizeJsonSchemaForAnthropicStructuredOutput: () => sanitizeJsonSchemaForAnthropicStructuredOutput,
|
|
106
|
+
sanitizeJsonSchemaForGeminiResponseSchema: () => sanitizeJsonSchemaForGeminiResponseSchema,
|
|
107
|
+
sanitizeJsonSchemaForOpenAiStructuredOutput: () => sanitizeJsonSchemaForOpenAiStructuredOutput,
|
|
108
|
+
signAwsRequestWithSigV4: () => signAwsRequestWithSigV4,
|
|
109
|
+
streamAnthropicChatCompletion: () => streamAnthropicChatCompletion,
|
|
110
|
+
streamAzureOpenAiChatCompletion: () => streamAzureOpenAiChatCompletion,
|
|
111
|
+
structuredOutputJsonOnlySystemInstruction: () => structuredOutputJsonOnlySystemInstruction,
|
|
112
|
+
structuredOutputJsonOnlySystemMessage: () => structuredOutputJsonOnlySystemMessage
|
|
79
113
|
});
|
|
80
114
|
module.exports = __toCommonJS(index_exports);
|
|
81
115
|
|
|
@@ -134,28 +168,306 @@ function extractMessageText(message) {
|
|
|
134
168
|
}
|
|
135
169
|
|
|
136
170
|
// src/openai-adapter.ts
|
|
137
|
-
var
|
|
138
|
-
var
|
|
139
|
-
var
|
|
140
|
-
var
|
|
171
|
+
var import_zod4 = require("zod");
|
|
172
|
+
var import_errors16 = require("@assemble-dev/shared-types/errors");
|
|
173
|
+
var import_json4 = require("@assemble-dev/shared-types/json");
|
|
174
|
+
var import_errors17 = require("@assemble-dev/shared-utils/errors");
|
|
141
175
|
|
|
142
176
|
// src/openai-request-mapping.ts
|
|
177
|
+
var import_errors3 = require("@assemble-dev/shared-types/errors");
|
|
178
|
+
var import_errors4 = require("@assemble-dev/shared-utils/errors");
|
|
179
|
+
|
|
180
|
+
// src/structured-output-json-schema.ts
|
|
181
|
+
var import_zod2 = require("zod");
|
|
143
182
|
var import_errors = require("@assemble-dev/shared-types/errors");
|
|
183
|
+
var import_json2 = require("@assemble-dev/shared-types/json");
|
|
144
184
|
var import_errors2 = require("@assemble-dev/shared-utils/errors");
|
|
185
|
+
|
|
186
|
+
// src/json-schema-tree.ts
|
|
187
|
+
var schemaMapKeywords = ["properties", "$defs"];
|
|
188
|
+
var schemaListKeywords = ["anyOf", "oneOf", "allOf", "prefixItems"];
|
|
189
|
+
var schemaValueKeywords = [
|
|
190
|
+
"items",
|
|
191
|
+
"additionalProperties",
|
|
192
|
+
"not",
|
|
193
|
+
"if",
|
|
194
|
+
"then",
|
|
195
|
+
"else",
|
|
196
|
+
"contains",
|
|
197
|
+
"propertyNames"
|
|
198
|
+
];
|
|
199
|
+
function isJsonObject(value) {
|
|
200
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
201
|
+
}
|
|
202
|
+
function transformJsonSchemaNode(node, transformNode) {
|
|
203
|
+
const result = { ...transformNode({ ...node }) };
|
|
204
|
+
for (const keyword of schemaMapKeywords) {
|
|
205
|
+
const mapValue = result[keyword];
|
|
206
|
+
if (mapValue !== void 0 && isJsonObject(mapValue)) {
|
|
207
|
+
result[keyword] = transformJsonSchemaMap(mapValue, transformNode);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
for (const keyword of schemaListKeywords) {
|
|
211
|
+
const listValue = result[keyword];
|
|
212
|
+
if (Array.isArray(listValue)) {
|
|
213
|
+
result[keyword] = listValue.map(
|
|
214
|
+
(entry) => isJsonObject(entry) ? transformJsonSchemaNode(entry, transformNode) : entry
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
for (const keyword of schemaValueKeywords) {
|
|
219
|
+
const schemaValue = result[keyword];
|
|
220
|
+
if (schemaValue !== void 0 && isJsonObject(schemaValue)) {
|
|
221
|
+
result[keyword] = transformJsonSchemaNode(schemaValue, transformNode);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return result;
|
|
225
|
+
}
|
|
226
|
+
function transformJsonSchemaMap(schemaMap, transformNode) {
|
|
227
|
+
const result = {};
|
|
228
|
+
for (const [schemaName, schemaValue] of Object.entries(schemaMap)) {
|
|
229
|
+
result[schemaName] = isJsonObject(schemaValue) ? transformJsonSchemaNode(schemaValue, transformNode) : schemaValue;
|
|
230
|
+
}
|
|
231
|
+
return result;
|
|
232
|
+
}
|
|
233
|
+
function inlineJsonSchemaReferences(root) {
|
|
234
|
+
const rootDefinitions = root["$defs"];
|
|
235
|
+
const definitions = rootDefinitions !== void 0 && isJsonObject(rootDefinitions) ? rootDefinitions : {};
|
|
236
|
+
const resolvedRoot = resolveJsonSchemaReferences(
|
|
237
|
+
root,
|
|
238
|
+
definitions,
|
|
239
|
+
/* @__PURE__ */ new Set()
|
|
240
|
+
);
|
|
241
|
+
return isJsonObject(resolvedRoot) ? resolvedRoot : {};
|
|
242
|
+
}
|
|
243
|
+
function resolveJsonSchemaReferences(value, definitions, activeReferences) {
|
|
244
|
+
if (Array.isArray(value)) {
|
|
245
|
+
return value.map(
|
|
246
|
+
(entry) => resolveJsonSchemaReferences(entry, definitions, activeReferences)
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
if (!isJsonObject(value)) {
|
|
250
|
+
return value;
|
|
251
|
+
}
|
|
252
|
+
const referenceTarget = value["$ref"];
|
|
253
|
+
if (typeof referenceTarget === "string") {
|
|
254
|
+
return resolveJsonSchemaReferenceTarget(
|
|
255
|
+
referenceTarget,
|
|
256
|
+
definitions,
|
|
257
|
+
activeReferences
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
const result = {};
|
|
261
|
+
for (const [key, entryValue] of Object.entries(value)) {
|
|
262
|
+
if (key !== "$defs") {
|
|
263
|
+
result[key] = resolveJsonSchemaReferences(
|
|
264
|
+
entryValue,
|
|
265
|
+
definitions,
|
|
266
|
+
activeReferences
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return result;
|
|
271
|
+
}
|
|
272
|
+
function resolveJsonSchemaReferenceTarget(referenceTarget, definitions, activeReferences) {
|
|
273
|
+
if (activeReferences.has(referenceTarget)) {
|
|
274
|
+
return {};
|
|
275
|
+
}
|
|
276
|
+
const definitionsPrefix = "#/$defs/";
|
|
277
|
+
if (!referenceTarget.startsWith(definitionsPrefix)) {
|
|
278
|
+
return {};
|
|
279
|
+
}
|
|
280
|
+
const definition = definitions[referenceTarget.slice(definitionsPrefix.length)];
|
|
281
|
+
if (definition === void 0 || !isJsonObject(definition)) {
|
|
282
|
+
return {};
|
|
283
|
+
}
|
|
284
|
+
return resolveJsonSchemaReferences(
|
|
285
|
+
definition,
|
|
286
|
+
definitions,
|
|
287
|
+
/* @__PURE__ */ new Set([...activeReferences, referenceTarget])
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
function removeJsonSchemaKeywords(node, keywords) {
|
|
291
|
+
const result = {};
|
|
292
|
+
for (const [key, value] of Object.entries(node)) {
|
|
293
|
+
if (!keywords.includes(key)) {
|
|
294
|
+
result[key] = value;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return result;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// src/structured-output-json-schema.ts
|
|
301
|
+
var openAiStructuredOutputSchemaName = "structured_output";
|
|
302
|
+
var schemaMetadataKeywords = ["$schema", "$id"];
|
|
303
|
+
var anthropicUnsupportedSchemaKeywords = [
|
|
304
|
+
...schemaMetadataKeywords,
|
|
305
|
+
"minimum",
|
|
306
|
+
"maximum",
|
|
307
|
+
"exclusiveMinimum",
|
|
308
|
+
"exclusiveMaximum",
|
|
309
|
+
"minLength",
|
|
310
|
+
"maxLength",
|
|
311
|
+
"multipleOf"
|
|
312
|
+
];
|
|
313
|
+
var openAiUnsupportedSchemaKeywords = [
|
|
314
|
+
...anthropicUnsupportedSchemaKeywords,
|
|
315
|
+
"pattern",
|
|
316
|
+
"format",
|
|
317
|
+
"minItems",
|
|
318
|
+
"maxItems",
|
|
319
|
+
"uniqueItems",
|
|
320
|
+
"default"
|
|
321
|
+
];
|
|
322
|
+
function isZodV4Schema(schema) {
|
|
323
|
+
return "_zod" in schema;
|
|
324
|
+
}
|
|
325
|
+
function convertZodSchemaToJsonSchema(schema) {
|
|
326
|
+
try {
|
|
327
|
+
return import_json2.JsonObjectSchema.parse(import_zod2.z.toJSONSchema(schema, { io: "input" }));
|
|
328
|
+
} catch (error) {
|
|
329
|
+
throw new import_errors2.AppError({
|
|
330
|
+
code: import_errors.AppErrorCode.BadRequest,
|
|
331
|
+
message: "Structured output schema could not be converted to JSON Schema",
|
|
332
|
+
statusCode: 400,
|
|
333
|
+
cause: error instanceof Error ? error : void 0
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
function buildAnthropicStructuredOutputJsonSchema(schema) {
|
|
338
|
+
return sanitizeJsonSchemaForAnthropicStructuredOutput(
|
|
339
|
+
convertZodSchemaToJsonSchema(schema)
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
function sanitizeJsonSchemaForAnthropicStructuredOutput(jsonSchema) {
|
|
343
|
+
return transformJsonSchemaNode(
|
|
344
|
+
inlineJsonSchemaReferences(jsonSchema),
|
|
345
|
+
sanitizeAnthropicSchemaNode
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
function buildOpenAiStructuredOutputJsonSchema(schema) {
|
|
349
|
+
return sanitizeJsonSchemaForOpenAiStructuredOutput(
|
|
350
|
+
convertZodSchemaToJsonSchema(schema)
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
function sanitizeJsonSchemaForOpenAiStructuredOutput(jsonSchema) {
|
|
354
|
+
return transformJsonSchemaNode(jsonSchema, sanitizeOpenAiSchemaNode);
|
|
355
|
+
}
|
|
356
|
+
function sanitizeAnthropicSchemaNode(node) {
|
|
357
|
+
const sanitized = removeJsonSchemaKeywords(
|
|
358
|
+
node,
|
|
359
|
+
anthropicUnsupportedSchemaKeywords
|
|
360
|
+
);
|
|
361
|
+
if (sanitized["type"] === "object") {
|
|
362
|
+
sanitized["additionalProperties"] = false;
|
|
363
|
+
}
|
|
364
|
+
return sanitized;
|
|
365
|
+
}
|
|
366
|
+
function sanitizeOpenAiSchemaNode(node) {
|
|
367
|
+
const sanitized = removeJsonSchemaKeywords(
|
|
368
|
+
node,
|
|
369
|
+
openAiUnsupportedSchemaKeywords
|
|
370
|
+
);
|
|
371
|
+
if (sanitized["type"] !== "object") {
|
|
372
|
+
return sanitized;
|
|
373
|
+
}
|
|
374
|
+
sanitized["additionalProperties"] = false;
|
|
375
|
+
const propertyNames = listSchemaPropertyNames(sanitized);
|
|
376
|
+
if (propertyNames.length > 0) {
|
|
377
|
+
sanitized["required"] = propertyNames;
|
|
378
|
+
}
|
|
379
|
+
return sanitized;
|
|
380
|
+
}
|
|
381
|
+
function listSchemaPropertyNames(node) {
|
|
382
|
+
const properties = node["properties"];
|
|
383
|
+
if (properties === void 0 || !isJsonObject(properties)) {
|
|
384
|
+
return [];
|
|
385
|
+
}
|
|
386
|
+
return Object.keys(properties);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// src/structured-output-fallback.ts
|
|
390
|
+
var structuredOutputJsonOnlySystemInstruction = "Respond with a single JSON object that satisfies the caller's requested structure. Output only valid JSON with no surrounding text.";
|
|
391
|
+
var structuredOutputJsonOnlySystemMessage = {
|
|
392
|
+
role: "system",
|
|
393
|
+
content: structuredOutputJsonOnlySystemInstruction
|
|
394
|
+
};
|
|
395
|
+
function prependStructuredOutputJsonOnlySystemMessage(messages) {
|
|
396
|
+
return [structuredOutputJsonOnlySystemMessage, ...messages];
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// src/openai-request-mapping.ts
|
|
400
|
+
var openAiReasoningModelNamePrefixes = [
|
|
401
|
+
"gpt-5",
|
|
402
|
+
"o1",
|
|
403
|
+
"o3",
|
|
404
|
+
"o4"
|
|
405
|
+
];
|
|
406
|
+
function isOpenAiReasoningModel(model) {
|
|
407
|
+
return openAiReasoningModelNamePrefixes.some(
|
|
408
|
+
(prefix) => matchesOpenAiModelNamePrefix(model, prefix)
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
function matchesOpenAiModelNamePrefix(model, prefix) {
|
|
412
|
+
if (!model.startsWith(prefix)) {
|
|
413
|
+
return false;
|
|
414
|
+
}
|
|
415
|
+
const boundaryCharacter = model.charAt(prefix.length);
|
|
416
|
+
return boundaryCharacter === "" || boundaryCharacter === "-" || boundaryCharacter === ".";
|
|
417
|
+
}
|
|
418
|
+
function resolveOpenAiStructuredOutputMode(messages, schema) {
|
|
419
|
+
if (isZodV4Schema(schema)) {
|
|
420
|
+
return {
|
|
421
|
+
messages,
|
|
422
|
+
structuredOutputJsonSchema: buildOpenAiStructuredOutputJsonSchema(schema)
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
return {
|
|
426
|
+
messages: prependStructuredOutputJsonOnlySystemMessage(messages),
|
|
427
|
+
requireJsonObjectResponse: true
|
|
428
|
+
};
|
|
429
|
+
}
|
|
145
430
|
function buildOpenAiRequestBody(model, input) {
|
|
146
431
|
const requestBody = {
|
|
147
432
|
model,
|
|
148
433
|
messages: input.messages.map(mapChatMessageToOpenAiRequestMessage)
|
|
149
434
|
};
|
|
150
|
-
|
|
435
|
+
applyOpenAiGenerationSettings(requestBody, model, input);
|
|
436
|
+
applyOpenAiResponseFormat(requestBody, input);
|
|
437
|
+
applyOpenAiToolFields(requestBody, input);
|
|
438
|
+
return requestBody;
|
|
439
|
+
}
|
|
440
|
+
function applyOpenAiGenerationSettings(requestBody, model, input) {
|
|
441
|
+
const reasoningModel = input.reasoningModel ?? isOpenAiReasoningModel(model);
|
|
442
|
+
if (input.temperature !== void 0 && !reasoningModel) {
|
|
151
443
|
requestBody.temperature = input.temperature;
|
|
152
444
|
}
|
|
153
|
-
if (input.maxOutputTokens
|
|
154
|
-
|
|
445
|
+
if (input.maxOutputTokens === void 0) {
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
if (reasoningModel) {
|
|
449
|
+
requestBody.max_completion_tokens = input.maxOutputTokens;
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
requestBody.max_tokens = input.maxOutputTokens;
|
|
453
|
+
}
|
|
454
|
+
function applyOpenAiResponseFormat(requestBody, input) {
|
|
455
|
+
if (input.structuredOutputJsonSchema !== void 0) {
|
|
456
|
+
requestBody.response_format = {
|
|
457
|
+
type: "json_schema",
|
|
458
|
+
json_schema: {
|
|
459
|
+
name: openAiStructuredOutputSchemaName,
|
|
460
|
+
strict: true,
|
|
461
|
+
schema: input.structuredOutputJsonSchema
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
return;
|
|
155
465
|
}
|
|
156
|
-
if (input.requireJsonObjectResponse) {
|
|
466
|
+
if (input.requireJsonObjectResponse === true) {
|
|
157
467
|
requestBody.response_format = { type: "json_object" };
|
|
158
468
|
}
|
|
469
|
+
}
|
|
470
|
+
function applyOpenAiToolFields(requestBody, input) {
|
|
159
471
|
if (input.tools !== void 0 && input.tools.length > 0) {
|
|
160
472
|
requestBody.tools = input.tools.map(mapModelToolDefinitionToOpenAiTool);
|
|
161
473
|
}
|
|
@@ -164,7 +476,6 @@ function buildOpenAiRequestBody(model, input) {
|
|
|
164
476
|
input.toolChoice
|
|
165
477
|
);
|
|
166
478
|
}
|
|
167
|
-
return requestBody;
|
|
168
479
|
}
|
|
169
480
|
function mapModelToolDefinitionToOpenAiTool(tool) {
|
|
170
481
|
return {
|
|
@@ -239,17 +550,17 @@ function mapMessageContentBlockToOpenAiContentPart(contentBlock) {
|
|
|
239
550
|
}
|
|
240
551
|
};
|
|
241
552
|
}
|
|
242
|
-
throw new
|
|
243
|
-
code:
|
|
553
|
+
throw new import_errors4.AppError({
|
|
554
|
+
code: import_errors3.AppErrorCode.ValidationFailed,
|
|
244
555
|
message: "OpenAI adapter does not support document content blocks in chat messages",
|
|
245
556
|
statusCode: 400
|
|
246
557
|
});
|
|
247
558
|
}
|
|
248
559
|
|
|
249
560
|
// src/parse-structured-json.ts
|
|
250
|
-
var
|
|
251
|
-
var
|
|
252
|
-
var
|
|
561
|
+
var import_errors5 = require("@assemble-dev/shared-types/errors");
|
|
562
|
+
var import_json3 = require("@assemble-dev/shared-types/json");
|
|
563
|
+
var import_errors6 = require("@assemble-dev/shared-utils/errors");
|
|
253
564
|
var markdownCodeFencePattern = /^```[A-Za-z]*\s*\n?([\s\S]*?)\n?```$/;
|
|
254
565
|
function parseStructuredJsonText(text, schema) {
|
|
255
566
|
return schema.parse(parseJsonText(stripMarkdownCodeFences(text)));
|
|
@@ -264,10 +575,10 @@ function stripMarkdownCodeFences(text) {
|
|
|
264
575
|
}
|
|
265
576
|
function parseJsonText(text) {
|
|
266
577
|
try {
|
|
267
|
-
return
|
|
578
|
+
return import_json3.JsonValueSchema.parse(JSON.parse(text));
|
|
268
579
|
} catch (error) {
|
|
269
|
-
throw new
|
|
270
|
-
code:
|
|
580
|
+
throw new import_errors6.AppError({
|
|
581
|
+
code: import_errors5.AppErrorCode.ValidationFailed,
|
|
271
582
|
message: "Structured output was not valid JSON",
|
|
272
583
|
statusCode: 422,
|
|
273
584
|
cause: error instanceof Error ? error : void 0
|
|
@@ -276,9 +587,9 @@ function parseJsonText(text) {
|
|
|
276
587
|
}
|
|
277
588
|
|
|
278
589
|
// src/provider-api-key.ts
|
|
279
|
-
var
|
|
280
|
-
var
|
|
281
|
-
var
|
|
590
|
+
var import_zod3 = require("zod");
|
|
591
|
+
var import_errors7 = require("@assemble-dev/shared-types/errors");
|
|
592
|
+
var import_errors8 = require("@assemble-dev/shared-utils/errors");
|
|
282
593
|
var import_provider_keys = require("@assemble-dev/shared-utils/provider-keys");
|
|
283
594
|
function resolveProviderApiKey(input) {
|
|
284
595
|
if (input.apiKey !== void 0 && input.apiKey.length > 0) {
|
|
@@ -291,8 +602,8 @@ function resolveProviderApiKey(input) {
|
|
|
291
602
|
}
|
|
292
603
|
function resolveNamedProviderApiKeyFromEnv(input, apiKeyName) {
|
|
293
604
|
if (!(0, import_provider_keys.validateProviderApiKeyName)(apiKeyName)) {
|
|
294
|
-
throw new
|
|
295
|
-
code:
|
|
605
|
+
throw new import_errors8.AppError({
|
|
606
|
+
code: import_errors7.AppErrorCode.BadRequest,
|
|
296
607
|
message: `Invalid ${input.providerLabel} apiKeyName "${apiKeyName}". Expected ${import_provider_keys.expectedProviderApiKeyNameFormat}.`,
|
|
297
608
|
statusCode: 400
|
|
298
609
|
});
|
|
@@ -300,8 +611,8 @@ function resolveNamedProviderApiKeyFromEnv(input, apiKeyName) {
|
|
|
300
611
|
const envVarName = (0, import_provider_keys.buildNamedApiKeyEnvVarName)(input.baseEnvVarName, apiKeyName);
|
|
301
612
|
const envApiKey = readEnvironmentVariable(envVarName);
|
|
302
613
|
if (envApiKey === void 0 || envApiKey.length === 0) {
|
|
303
|
-
throw new
|
|
304
|
-
code:
|
|
614
|
+
throw new import_errors8.AppError({
|
|
615
|
+
code: import_errors7.AppErrorCode.Unauthorized,
|
|
305
616
|
message: `${input.providerLabel} API key named "${apiKeyName}" is missing. Set the ${envVarName} environment variable or pass apiKey to ${input.adapterFunctionName}.`,
|
|
306
617
|
statusCode: 401
|
|
307
618
|
});
|
|
@@ -311,8 +622,8 @@ function resolveNamedProviderApiKeyFromEnv(input, apiKeyName) {
|
|
|
311
622
|
function resolveBaseProviderApiKeyFromEnv(input) {
|
|
312
623
|
const envApiKey = readEnvironmentVariable(input.baseEnvVarName);
|
|
313
624
|
if (envApiKey === void 0 || envApiKey.length === 0) {
|
|
314
|
-
throw new
|
|
315
|
-
code:
|
|
625
|
+
throw new import_errors8.AppError({
|
|
626
|
+
code: import_errors7.AppErrorCode.Unauthorized,
|
|
316
627
|
message: `${input.providerLabel} API key is missing. Pass apiKey to ${input.adapterFunctionName} or set the ${input.baseEnvVarName} environment variable.`,
|
|
317
628
|
statusCode: 401
|
|
318
629
|
});
|
|
@@ -320,19 +631,19 @@ function resolveBaseProviderApiKeyFromEnv(input) {
|
|
|
320
631
|
return envApiKey;
|
|
321
632
|
}
|
|
322
633
|
function readEnvironmentVariable(envVarName) {
|
|
323
|
-
const parsedEnv =
|
|
634
|
+
const parsedEnv = import_zod3.z.object({ [envVarName]: import_zod3.z.string().optional() }).parse(process.env);
|
|
324
635
|
return parsedEnv[envVarName];
|
|
325
636
|
}
|
|
326
637
|
|
|
327
638
|
// src/provider-cancellation.ts
|
|
328
|
-
var
|
|
329
|
-
var
|
|
639
|
+
var import_errors9 = require("@assemble-dev/shared-types/errors");
|
|
640
|
+
var import_errors10 = require("@assemble-dev/shared-utils/errors");
|
|
330
641
|
function isAbortError(error) {
|
|
331
642
|
return error.name === "AbortError";
|
|
332
643
|
}
|
|
333
644
|
function buildProviderCanceledError(providerLabel) {
|
|
334
|
-
return new
|
|
335
|
-
code:
|
|
645
|
+
return new import_errors10.AppError({
|
|
646
|
+
code: import_errors9.AppErrorCode.Canceled,
|
|
336
647
|
message: `${providerLabel} request was canceled`,
|
|
337
648
|
statusCode: 499
|
|
338
649
|
});
|
|
@@ -358,18 +669,18 @@ function mergeProviderRequestExtraBody(requestBody, adapterExtraBody, requestExt
|
|
|
358
669
|
}
|
|
359
670
|
|
|
360
671
|
// src/provider-fallback.ts
|
|
361
|
-
var
|
|
672
|
+
var import_errors13 = require("@assemble-dev/shared-utils/errors");
|
|
362
673
|
|
|
363
674
|
// src/provider-retry.ts
|
|
364
|
-
var
|
|
365
|
-
var
|
|
675
|
+
var import_errors11 = require("@assemble-dev/shared-types/errors");
|
|
676
|
+
var import_errors12 = require("@assemble-dev/shared-utils/errors");
|
|
366
677
|
var defaultProviderRetryMaxAttempts = 3;
|
|
367
678
|
var defaultProviderRetryInitialDelayMs = 500;
|
|
368
679
|
var defaultProviderRetryMaxDelayMs = 8e3;
|
|
369
680
|
var retryableAppErrorCodes = /* @__PURE__ */ new Set([
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
681
|
+
import_errors11.AppErrorCode.RateLimited,
|
|
682
|
+
import_errors11.AppErrorCode.ServiceUnavailable,
|
|
683
|
+
import_errors11.AppErrorCode.InternalServerError
|
|
373
684
|
]);
|
|
374
685
|
function isRetryableProviderAppError(appError) {
|
|
375
686
|
return retryableAppErrorCodes.has(appError.code);
|
|
@@ -384,7 +695,7 @@ async function executeProviderCallWithRetry(retryOptions, executeCall, waitFor)
|
|
|
384
695
|
try {
|
|
385
696
|
return await executeCall();
|
|
386
697
|
} catch (error) {
|
|
387
|
-
if (error instanceof
|
|
698
|
+
if (error instanceof import_errors12.AppError && !isRetryableProviderAppError(error)) {
|
|
388
699
|
throw error;
|
|
389
700
|
}
|
|
390
701
|
if (error instanceof Error && isAbortError(error)) {
|
|
@@ -418,7 +729,7 @@ async function executeProviderCallWithModelFallback(fallbackModel, executePrimar
|
|
|
418
729
|
if (fallbackModel === void 0) {
|
|
419
730
|
throw error;
|
|
420
731
|
}
|
|
421
|
-
if (error instanceof
|
|
732
|
+
if (error instanceof import_errors13.AppError && !isRetryableProviderAppError(error)) {
|
|
422
733
|
throw error;
|
|
423
734
|
}
|
|
424
735
|
if (error instanceof Error && isAbortError(error)) {
|
|
@@ -429,11 +740,11 @@ async function executeProviderCallWithModelFallback(fallbackModel, executePrimar
|
|
|
429
740
|
}
|
|
430
741
|
|
|
431
742
|
// src/provider-status-error.ts
|
|
432
|
-
var
|
|
433
|
-
var
|
|
743
|
+
var import_errors14 = require("@assemble-dev/shared-types/errors");
|
|
744
|
+
var import_errors15 = require("@assemble-dev/shared-utils/errors");
|
|
434
745
|
function buildProviderStatusError(providerLabel, providerStatus) {
|
|
435
746
|
const code = mapProviderStatusToAppErrorCode(providerStatus);
|
|
436
|
-
return new
|
|
747
|
+
return new import_errors15.AppError({
|
|
437
748
|
code,
|
|
438
749
|
message: `${providerLabel} request failed with status ${String(providerStatus)}`,
|
|
439
750
|
statusCode: mapAppErrorCodeToStatusCode(code),
|
|
@@ -441,44 +752,44 @@ function buildProviderStatusError(providerLabel, providerStatus) {
|
|
|
441
752
|
});
|
|
442
753
|
}
|
|
443
754
|
function buildProviderInvalidResponseError(providerLabel, expectedShapeDescription) {
|
|
444
|
-
return new
|
|
445
|
-
code:
|
|
755
|
+
return new import_errors15.AppError({
|
|
756
|
+
code: import_errors14.AppErrorCode.ValidationFailed,
|
|
446
757
|
message: `${providerLabel} response did not match the expected ${expectedShapeDescription} shape`,
|
|
447
758
|
statusCode: 502
|
|
448
759
|
});
|
|
449
760
|
}
|
|
450
761
|
function mapProviderStatusToAppErrorCode(providerStatus) {
|
|
451
762
|
if (providerStatus === 400) {
|
|
452
|
-
return
|
|
763
|
+
return import_errors14.AppErrorCode.BadRequest;
|
|
453
764
|
}
|
|
454
765
|
if (providerStatus === 401) {
|
|
455
|
-
return
|
|
766
|
+
return import_errors14.AppErrorCode.Unauthorized;
|
|
456
767
|
}
|
|
457
768
|
if (providerStatus === 403) {
|
|
458
|
-
return
|
|
769
|
+
return import_errors14.AppErrorCode.Forbidden;
|
|
459
770
|
}
|
|
460
771
|
if (providerStatus === 404) {
|
|
461
|
-
return
|
|
772
|
+
return import_errors14.AppErrorCode.NotFound;
|
|
462
773
|
}
|
|
463
774
|
if (providerStatus === 429) {
|
|
464
|
-
return
|
|
775
|
+
return import_errors14.AppErrorCode.RateLimited;
|
|
465
776
|
}
|
|
466
|
-
return
|
|
777
|
+
return import_errors14.AppErrorCode.InternalServerError;
|
|
467
778
|
}
|
|
468
779
|
function mapAppErrorCodeToStatusCode(code) {
|
|
469
|
-
if (code ===
|
|
780
|
+
if (code === import_errors14.AppErrorCode.BadRequest) {
|
|
470
781
|
return 400;
|
|
471
782
|
}
|
|
472
|
-
if (code ===
|
|
783
|
+
if (code === import_errors14.AppErrorCode.Unauthorized) {
|
|
473
784
|
return 401;
|
|
474
785
|
}
|
|
475
|
-
if (code ===
|
|
786
|
+
if (code === import_errors14.AppErrorCode.Forbidden) {
|
|
476
787
|
return 403;
|
|
477
788
|
}
|
|
478
|
-
if (code ===
|
|
789
|
+
if (code === import_errors14.AppErrorCode.NotFound) {
|
|
479
790
|
return 404;
|
|
480
791
|
}
|
|
481
|
-
if (code ===
|
|
792
|
+
if (code === import_errors14.AppErrorCode.RateLimited) {
|
|
482
793
|
return 429;
|
|
483
794
|
}
|
|
484
795
|
return 500;
|
|
@@ -486,33 +797,29 @@ function mapAppErrorCodeToStatusCode(code) {
|
|
|
486
797
|
|
|
487
798
|
// src/openai-adapter.ts
|
|
488
799
|
var defaultOpenAiBaseUrl = "https://api.openai.com/v1";
|
|
489
|
-
var OpenAiResponseToolCallSchema =
|
|
490
|
-
id:
|
|
491
|
-
function:
|
|
492
|
-
name:
|
|
493
|
-
arguments:
|
|
800
|
+
var OpenAiResponseToolCallSchema = import_zod4.z.object({
|
|
801
|
+
id: import_zod4.z.string(),
|
|
802
|
+
function: import_zod4.z.object({
|
|
803
|
+
name: import_zod4.z.string(),
|
|
804
|
+
arguments: import_zod4.z.string()
|
|
494
805
|
})
|
|
495
806
|
});
|
|
496
|
-
var OpenAiChatCompletionResponseSchema =
|
|
497
|
-
choices:
|
|
498
|
-
|
|
499
|
-
message:
|
|
500
|
-
content:
|
|
501
|
-
tool_calls:
|
|
807
|
+
var OpenAiChatCompletionResponseSchema = import_zod4.z.object({
|
|
808
|
+
choices: import_zod4.z.array(
|
|
809
|
+
import_zod4.z.object({
|
|
810
|
+
message: import_zod4.z.object({
|
|
811
|
+
content: import_zod4.z.string().nullable(),
|
|
812
|
+
tool_calls: import_zod4.z.array(OpenAiResponseToolCallSchema).optional()
|
|
502
813
|
}),
|
|
503
|
-
finish_reason:
|
|
814
|
+
finish_reason: import_zod4.z.string().nullable().optional()
|
|
504
815
|
})
|
|
505
816
|
).min(1),
|
|
506
|
-
usage:
|
|
507
|
-
prompt_tokens:
|
|
508
|
-
completion_tokens:
|
|
509
|
-
total_tokens:
|
|
817
|
+
usage: import_zod4.z.object({
|
|
818
|
+
prompt_tokens: import_zod4.z.number().int().nonnegative(),
|
|
819
|
+
completion_tokens: import_zod4.z.number().int().nonnegative(),
|
|
820
|
+
total_tokens: import_zod4.z.number().int().nonnegative()
|
|
510
821
|
})
|
|
511
822
|
});
|
|
512
|
-
var structuredOutputSystemMessage = {
|
|
513
|
-
role: "system",
|
|
514
|
-
content: "Respond with a single JSON object that satisfies the caller's requested structure. Output only valid JSON with no surrounding text."
|
|
515
|
-
};
|
|
516
823
|
function openai(options) {
|
|
517
824
|
return {
|
|
518
825
|
name: `openai:${options.model}`,
|
|
@@ -521,7 +828,6 @@ function openai(options) {
|
|
|
521
828
|
messages: request.messages,
|
|
522
829
|
temperature: request.temperature ?? options.temperature,
|
|
523
830
|
maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
|
|
524
|
-
requireJsonObjectResponse: false,
|
|
525
831
|
tools: request.tools,
|
|
526
832
|
toolChoice: request.toolChoice,
|
|
527
833
|
abortSignal: request.abortSignal,
|
|
@@ -530,10 +836,9 @@ function openai(options) {
|
|
|
530
836
|
},
|
|
531
837
|
async generateStructuredOutput(request) {
|
|
532
838
|
const completion = await executeOpenAiAdapterCall(options, {
|
|
533
|
-
messages
|
|
839
|
+
...resolveOpenAiStructuredOutputMode(request.messages, request.schema),
|
|
534
840
|
temperature: request.temperature ?? options.temperature,
|
|
535
841
|
maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
|
|
536
|
-
requireJsonObjectResponse: true,
|
|
537
842
|
abortSignal: request.abortSignal
|
|
538
843
|
});
|
|
539
844
|
return {
|
|
@@ -626,10 +931,10 @@ function parseOpenAiToolArgumentsJson(argumentsJsonText) {
|
|
|
626
931
|
return {};
|
|
627
932
|
}
|
|
628
933
|
try {
|
|
629
|
-
return
|
|
934
|
+
return import_json4.JsonValueSchema.parse(JSON.parse(argumentsJsonText));
|
|
630
935
|
} catch (error) {
|
|
631
|
-
throw new
|
|
632
|
-
code:
|
|
936
|
+
throw new import_errors17.AppError({
|
|
937
|
+
code: import_errors16.AppErrorCode.ValidationFailed,
|
|
633
938
|
message: "OpenAI tool call arguments were not valid JSON",
|
|
634
939
|
statusCode: 502,
|
|
635
940
|
cause: error instanceof Error ? error : void 0
|
|
@@ -651,8 +956,8 @@ function extractOpenAiMessageContent(response, allowEmptyContent) {
|
|
|
651
956
|
if (allowEmptyContent) {
|
|
652
957
|
return "";
|
|
653
958
|
}
|
|
654
|
-
throw new
|
|
655
|
-
code:
|
|
959
|
+
throw new import_errors17.AppError({
|
|
960
|
+
code: import_errors16.AppErrorCode.ValidationFailed,
|
|
656
961
|
message: "OpenAI response contained no message content",
|
|
657
962
|
statusCode: 502
|
|
658
963
|
});
|
|
@@ -716,6 +1021,11 @@ function buildAnthropicRequestBody(settings, input) {
|
|
|
716
1021
|
budget_tokens: settings.thinking.budgetTokens
|
|
717
1022
|
};
|
|
718
1023
|
}
|
|
1024
|
+
if (input.structuredOutputJsonSchema !== void 0) {
|
|
1025
|
+
requestBody.output_config = {
|
|
1026
|
+
format: { type: "json_schema", schema: input.structuredOutputJsonSchema }
|
|
1027
|
+
};
|
|
1028
|
+
}
|
|
719
1029
|
return requestBody;
|
|
720
1030
|
}
|
|
721
1031
|
function applyAnthropicSystemField(requestBody, settings, input) {
|
|
@@ -872,44 +1182,45 @@ function mapMessageContentBlockToAnthropic(contentBlock) {
|
|
|
872
1182
|
}
|
|
873
1183
|
|
|
874
1184
|
// src/anthropic-response-parsing.ts
|
|
875
|
-
var
|
|
876
|
-
var
|
|
877
|
-
var
|
|
878
|
-
var
|
|
879
|
-
var AnthropicUsageSchema =
|
|
880
|
-
input_tokens:
|
|
881
|
-
output_tokens:
|
|
882
|
-
cache_creation_input_tokens:
|
|
883
|
-
cache_read_input_tokens:
|
|
1185
|
+
var import_zod5 = require("zod");
|
|
1186
|
+
var import_errors18 = require("@assemble-dev/shared-types/errors");
|
|
1187
|
+
var import_json5 = require("@assemble-dev/shared-types/json");
|
|
1188
|
+
var import_errors19 = require("@assemble-dev/shared-utils/errors");
|
|
1189
|
+
var AnthropicUsageSchema = import_zod5.z.object({
|
|
1190
|
+
input_tokens: import_zod5.z.number().int().nonnegative(),
|
|
1191
|
+
output_tokens: import_zod5.z.number().int().nonnegative(),
|
|
1192
|
+
cache_creation_input_tokens: import_zod5.z.number().int().nonnegative().optional(),
|
|
1193
|
+
cache_read_input_tokens: import_zod5.z.number().int().nonnegative().optional()
|
|
884
1194
|
});
|
|
885
|
-
var AnthropicContentBlockSchema =
|
|
886
|
-
|
|
887
|
-
type:
|
|
888
|
-
text:
|
|
1195
|
+
var AnthropicContentBlockSchema = import_zod5.z.discriminatedUnion("type", [
|
|
1196
|
+
import_zod5.z.object({
|
|
1197
|
+
type: import_zod5.z.literal("text"),
|
|
1198
|
+
text: import_zod5.z.string()
|
|
889
1199
|
}),
|
|
890
|
-
|
|
891
|
-
type:
|
|
892
|
-
id:
|
|
893
|
-
name:
|
|
894
|
-
input:
|
|
1200
|
+
import_zod5.z.object({
|
|
1201
|
+
type: import_zod5.z.literal("tool_use"),
|
|
1202
|
+
id: import_zod5.z.string(),
|
|
1203
|
+
name: import_zod5.z.string(),
|
|
1204
|
+
input: import_json5.JsonValueSchema
|
|
895
1205
|
}),
|
|
896
|
-
|
|
897
|
-
type:
|
|
898
|
-
thinking:
|
|
899
|
-
signature:
|
|
1206
|
+
import_zod5.z.object({
|
|
1207
|
+
type: import_zod5.z.literal("thinking"),
|
|
1208
|
+
thinking: import_zod5.z.string().optional(),
|
|
1209
|
+
signature: import_zod5.z.string().optional()
|
|
900
1210
|
}),
|
|
901
|
-
|
|
902
|
-
type:
|
|
903
|
-
data:
|
|
1211
|
+
import_zod5.z.object({
|
|
1212
|
+
type: import_zod5.z.literal("redacted_thinking"),
|
|
1213
|
+
data: import_zod5.z.string().optional()
|
|
904
1214
|
})
|
|
905
1215
|
]);
|
|
906
|
-
var AnthropicMessagesResponseSchema =
|
|
907
|
-
content:
|
|
908
|
-
stop_reason:
|
|
1216
|
+
var AnthropicMessagesResponseSchema = import_zod5.z.object({
|
|
1217
|
+
content: import_zod5.z.array(AnthropicContentBlockSchema),
|
|
1218
|
+
stop_reason: import_zod5.z.string().nullable().optional(),
|
|
909
1219
|
usage: AnthropicUsageSchema
|
|
910
1220
|
});
|
|
911
1221
|
function mapAnthropicResponseToChatCompletionResult(response, latencyMs) {
|
|
912
1222
|
const toolCalls = extractAnthropicToolCalls(response);
|
|
1223
|
+
const thinkingText = extractAnthropicThinkingText(response);
|
|
913
1224
|
const result = {
|
|
914
1225
|
content: extractAnthropicTextContent(response, toolCalls.length > 0),
|
|
915
1226
|
tokenUsage: mapAnthropicUsageToTokenUsage(response.usage),
|
|
@@ -918,6 +1229,9 @@ function mapAnthropicResponseToChatCompletionResult(response, latencyMs) {
|
|
|
918
1229
|
if (toolCalls.length > 0) {
|
|
919
1230
|
result.toolCalls = toolCalls;
|
|
920
1231
|
}
|
|
1232
|
+
if (thinkingText.length > 0) {
|
|
1233
|
+
result.thinkingText = thinkingText;
|
|
1234
|
+
}
|
|
921
1235
|
if (response.stop_reason !== null && response.stop_reason !== void 0) {
|
|
922
1236
|
result.stopReason = normalizeAnthropicStopReason(response.stop_reason);
|
|
923
1237
|
}
|
|
@@ -930,13 +1244,16 @@ function extractAnthropicToolCalls(response) {
|
|
|
930
1244
|
input: contentBlock.input
|
|
931
1245
|
}));
|
|
932
1246
|
}
|
|
1247
|
+
function extractAnthropicThinkingText(response) {
|
|
1248
|
+
return response.content.filter((contentBlock) => contentBlock.type === "thinking").map((contentBlock) => contentBlock.thinking ?? "").join("");
|
|
1249
|
+
}
|
|
933
1250
|
function extractAnthropicTextContent(response, allowEmptyText) {
|
|
934
1251
|
const textBlocks = response.content.filter(
|
|
935
1252
|
(contentBlock) => contentBlock.type === "text"
|
|
936
1253
|
);
|
|
937
1254
|
if (textBlocks.length === 0 && !allowEmptyText) {
|
|
938
|
-
throw new
|
|
939
|
-
code:
|
|
1255
|
+
throw new import_errors19.AppError({
|
|
1256
|
+
code: import_errors18.AppErrorCode.ValidationFailed,
|
|
940
1257
|
message: "Anthropic response contained no text content",
|
|
941
1258
|
statusCode: 502
|
|
942
1259
|
});
|
|
@@ -973,58 +1290,68 @@ function mapAnthropicUsageToTokenUsage(usage) {
|
|
|
973
1290
|
}
|
|
974
1291
|
|
|
975
1292
|
// src/anthropic-stream.ts
|
|
976
|
-
var
|
|
977
|
-
var
|
|
978
|
-
var
|
|
1293
|
+
var import_errors20 = require("@assemble-dev/shared-types/errors");
|
|
1294
|
+
var import_json6 = require("@assemble-dev/shared-types/json");
|
|
1295
|
+
var import_errors21 = require("@assemble-dev/shared-utils/errors");
|
|
979
1296
|
|
|
980
1297
|
// src/anthropic-stream-events.ts
|
|
981
|
-
var
|
|
982
|
-
var AnthropicStreamEventSchema =
|
|
983
|
-
|
|
984
|
-
type:
|
|
985
|
-
message:
|
|
986
|
-
usage:
|
|
987
|
-
input_tokens:
|
|
988
|
-
output_tokens:
|
|
989
|
-
cache_creation_input_tokens:
|
|
990
|
-
cache_read_input_tokens:
|
|
1298
|
+
var import_zod6 = require("zod");
|
|
1299
|
+
var AnthropicStreamEventSchema = import_zod6.z.discriminatedUnion("type", [
|
|
1300
|
+
import_zod6.z.object({
|
|
1301
|
+
type: import_zod6.z.literal("message_start"),
|
|
1302
|
+
message: import_zod6.z.object({
|
|
1303
|
+
usage: import_zod6.z.object({
|
|
1304
|
+
input_tokens: import_zod6.z.number().int().nonnegative(),
|
|
1305
|
+
output_tokens: import_zod6.z.number().int().nonnegative().optional(),
|
|
1306
|
+
cache_creation_input_tokens: import_zod6.z.number().int().nonnegative().optional(),
|
|
1307
|
+
cache_read_input_tokens: import_zod6.z.number().int().nonnegative().optional()
|
|
991
1308
|
})
|
|
992
1309
|
})
|
|
993
1310
|
}),
|
|
994
|
-
|
|
995
|
-
type:
|
|
996
|
-
index:
|
|
997
|
-
content_block:
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
type:
|
|
1001
|
-
|
|
1002
|
-
|
|
1311
|
+
import_zod6.z.object({
|
|
1312
|
+
type: import_zod6.z.literal("content_block_start"),
|
|
1313
|
+
index: import_zod6.z.number().int().nonnegative(),
|
|
1314
|
+
content_block: import_zod6.z.discriminatedUnion("type", [
|
|
1315
|
+
import_zod6.z.object({ type: import_zod6.z.literal("text"), text: import_zod6.z.string().optional() }),
|
|
1316
|
+
import_zod6.z.object({
|
|
1317
|
+
type: import_zod6.z.literal("thinking"),
|
|
1318
|
+
thinking: import_zod6.z.string().optional()
|
|
1319
|
+
}),
|
|
1320
|
+
import_zod6.z.object({
|
|
1321
|
+
type: import_zod6.z.literal("redacted_thinking"),
|
|
1322
|
+
data: import_zod6.z.string().optional()
|
|
1323
|
+
}),
|
|
1324
|
+
import_zod6.z.object({
|
|
1325
|
+
type: import_zod6.z.literal("tool_use"),
|
|
1326
|
+
id: import_zod6.z.string(),
|
|
1327
|
+
name: import_zod6.z.string()
|
|
1003
1328
|
})
|
|
1004
1329
|
])
|
|
1005
1330
|
}),
|
|
1006
|
-
|
|
1007
|
-
type:
|
|
1008
|
-
index:
|
|
1009
|
-
delta:
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1331
|
+
import_zod6.z.object({
|
|
1332
|
+
type: import_zod6.z.literal("content_block_delta"),
|
|
1333
|
+
index: import_zod6.z.number().int().nonnegative(),
|
|
1334
|
+
delta: import_zod6.z.discriminatedUnion("type", [
|
|
1335
|
+
import_zod6.z.object({ type: import_zod6.z.literal("text_delta"), text: import_zod6.z.string() }),
|
|
1336
|
+
import_zod6.z.object({ type: import_zod6.z.literal("thinking_delta"), thinking: import_zod6.z.string() }),
|
|
1337
|
+
import_zod6.z.object({ type: import_zod6.z.literal("signature_delta"), signature: import_zod6.z.string() }),
|
|
1338
|
+
import_zod6.z.object({
|
|
1339
|
+
type: import_zod6.z.literal("input_json_delta"),
|
|
1340
|
+
partial_json: import_zod6.z.string()
|
|
1014
1341
|
})
|
|
1015
1342
|
])
|
|
1016
1343
|
}),
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
type:
|
|
1020
|
-
delta:
|
|
1021
|
-
usage:
|
|
1344
|
+
import_zod6.z.object({ type: import_zod6.z.literal("content_block_stop") }),
|
|
1345
|
+
import_zod6.z.object({
|
|
1346
|
+
type: import_zod6.z.literal("message_delta"),
|
|
1347
|
+
delta: import_zod6.z.object({ stop_reason: import_zod6.z.string().nullable().optional() }),
|
|
1348
|
+
usage: import_zod6.z.object({ output_tokens: import_zod6.z.number().int().nonnegative() }).optional()
|
|
1022
1349
|
}),
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
type:
|
|
1027
|
-
error:
|
|
1350
|
+
import_zod6.z.object({ type: import_zod6.z.literal("message_stop") }),
|
|
1351
|
+
import_zod6.z.object({ type: import_zod6.z.literal("ping") }),
|
|
1352
|
+
import_zod6.z.object({
|
|
1353
|
+
type: import_zod6.z.literal("error"),
|
|
1354
|
+
error: import_zod6.z.object({ message: import_zod6.z.string() })
|
|
1028
1355
|
})
|
|
1029
1356
|
]);
|
|
1030
1357
|
|
|
@@ -1110,6 +1437,7 @@ async function* readServerSentEventDataLines(body, abortSignal) {
|
|
|
1110
1437
|
function createAnthropicStreamAccumulator() {
|
|
1111
1438
|
return {
|
|
1112
1439
|
contentText: "",
|
|
1440
|
+
thinkingText: "",
|
|
1113
1441
|
toolCallsByBlockIndex: /* @__PURE__ */ new Map(),
|
|
1114
1442
|
inputTokens: 0,
|
|
1115
1443
|
outputTokens: 0
|
|
@@ -1117,8 +1445,8 @@ function createAnthropicStreamAccumulator() {
|
|
|
1117
1445
|
}
|
|
1118
1446
|
function* applyAnthropicStreamEvent(event, accumulator) {
|
|
1119
1447
|
if (event.type === "error") {
|
|
1120
|
-
throw new
|
|
1121
|
-
code:
|
|
1448
|
+
throw new import_errors21.AppError({
|
|
1449
|
+
code: import_errors20.AppErrorCode.InternalServerError,
|
|
1122
1450
|
message: `Anthropic stream reported an error: ${event.error.message}`,
|
|
1123
1451
|
statusCode: 502
|
|
1124
1452
|
});
|
|
@@ -1154,6 +1482,17 @@ function* applyAnthropicContentBlockStart(event, accumulator) {
|
|
|
1154
1482
|
}
|
|
1155
1483
|
return;
|
|
1156
1484
|
}
|
|
1485
|
+
if (event.content_block.type === "thinking") {
|
|
1486
|
+
const initialThinkingText = event.content_block.thinking ?? "";
|
|
1487
|
+
if (initialThinkingText.length > 0) {
|
|
1488
|
+
accumulator.thinkingText += initialThinkingText;
|
|
1489
|
+
yield { type: "thinking_delta", text: initialThinkingText };
|
|
1490
|
+
}
|
|
1491
|
+
return;
|
|
1492
|
+
}
|
|
1493
|
+
if (event.content_block.type === "redacted_thinking") {
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1157
1496
|
accumulator.toolCallsByBlockIndex.set(event.index, {
|
|
1158
1497
|
id: event.content_block.id,
|
|
1159
1498
|
toolName: event.content_block.name,
|
|
@@ -1171,6 +1510,14 @@ function* applyAnthropicContentBlockDelta(event, accumulator) {
|
|
|
1171
1510
|
yield { type: "text_delta", text: event.delta.text };
|
|
1172
1511
|
return;
|
|
1173
1512
|
}
|
|
1513
|
+
if (event.delta.type === "thinking_delta") {
|
|
1514
|
+
accumulator.thinkingText += event.delta.thinking;
|
|
1515
|
+
yield { type: "thinking_delta", text: event.delta.thinking };
|
|
1516
|
+
return;
|
|
1517
|
+
}
|
|
1518
|
+
if (event.delta.type === "signature_delta") {
|
|
1519
|
+
return;
|
|
1520
|
+
}
|
|
1174
1521
|
const toolCallAccumulation = accumulator.toolCallsByBlockIndex.get(
|
|
1175
1522
|
event.index
|
|
1176
1523
|
);
|
|
@@ -1217,6 +1564,9 @@ function buildAnthropicStreamResult(accumulator, latencyMs) {
|
|
|
1217
1564
|
if (accumulator.stopReason !== void 0) {
|
|
1218
1565
|
result.stopReason = accumulator.stopReason;
|
|
1219
1566
|
}
|
|
1567
|
+
if (accumulator.thinkingText.length > 0) {
|
|
1568
|
+
result.thinkingText = accumulator.thinkingText;
|
|
1569
|
+
}
|
|
1220
1570
|
return result;
|
|
1221
1571
|
}
|
|
1222
1572
|
function mapAccumulatedToolCallToModelToolCall(toolCallAccumulation) {
|
|
@@ -1231,10 +1581,10 @@ function parseAnthropicToolInputJson(inputJsonText) {
|
|
|
1231
1581
|
return {};
|
|
1232
1582
|
}
|
|
1233
1583
|
try {
|
|
1234
|
-
return
|
|
1584
|
+
return import_json6.JsonValueSchema.parse(JSON.parse(inputJsonText));
|
|
1235
1585
|
} catch (error) {
|
|
1236
|
-
throw new
|
|
1237
|
-
code:
|
|
1586
|
+
throw new import_errors21.AppError({
|
|
1587
|
+
code: import_errors20.AppErrorCode.ValidationFailed,
|
|
1238
1588
|
message: "Anthropic tool input was not valid JSON",
|
|
1239
1589
|
statusCode: 502,
|
|
1240
1590
|
cause: error instanceof Error ? error : void 0
|
|
@@ -1246,10 +1596,6 @@ function parseAnthropicToolInputJson(inputJsonText) {
|
|
|
1246
1596
|
var defaultAnthropicBaseUrl = "https://api.anthropic.com";
|
|
1247
1597
|
var defaultAnthropicMaxOutputTokens = 1024;
|
|
1248
1598
|
var anthropicApiVersion = "2023-06-01";
|
|
1249
|
-
var structuredOutputSystemMessage2 = {
|
|
1250
|
-
role: "system",
|
|
1251
|
-
content: "Respond with a single JSON object that satisfies the caller's requested structure. Output only valid JSON with no surrounding text."
|
|
1252
|
-
};
|
|
1253
1599
|
function anthropic(options) {
|
|
1254
1600
|
return {
|
|
1255
1601
|
name: `anthropic:${options.model}`,
|
|
@@ -1260,12 +1606,10 @@ function anthropic(options) {
|
|
|
1260
1606
|
);
|
|
1261
1607
|
},
|
|
1262
1608
|
async generateStructuredOutput(request) {
|
|
1263
|
-
const completion = await executeAnthropicAdapterCall(
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
abortSignal: request.abortSignal
|
|
1268
|
-
});
|
|
1609
|
+
const completion = await executeAnthropicAdapterCall(
|
|
1610
|
+
options,
|
|
1611
|
+
buildAnthropicStructuredOutputInput(options, request)
|
|
1612
|
+
);
|
|
1269
1613
|
return {
|
|
1270
1614
|
value: parseStructuredJsonText(completion.content, request.schema),
|
|
1271
1615
|
tokenUsage: completion.tokenUsage,
|
|
@@ -1279,6 +1623,26 @@ function anthropic(options) {
|
|
|
1279
1623
|
}
|
|
1280
1624
|
};
|
|
1281
1625
|
}
|
|
1626
|
+
function buildAnthropicStructuredOutputInput(options, request) {
|
|
1627
|
+
const baseInput = {
|
|
1628
|
+
messages: request.messages,
|
|
1629
|
+
temperature: request.temperature ?? options.temperature,
|
|
1630
|
+
maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
|
|
1631
|
+
abortSignal: request.abortSignal
|
|
1632
|
+
};
|
|
1633
|
+
if (isZodV4Schema(request.schema)) {
|
|
1634
|
+
return {
|
|
1635
|
+
...baseInput,
|
|
1636
|
+
structuredOutputJsonSchema: buildAnthropicStructuredOutputJsonSchema(
|
|
1637
|
+
request.schema
|
|
1638
|
+
)
|
|
1639
|
+
};
|
|
1640
|
+
}
|
|
1641
|
+
return {
|
|
1642
|
+
...baseInput,
|
|
1643
|
+
messages: prependStructuredOutputJsonOnlySystemMessage(request.messages)
|
|
1644
|
+
};
|
|
1645
|
+
}
|
|
1282
1646
|
function buildAnthropicCallInput(options, request) {
|
|
1283
1647
|
return {
|
|
1284
1648
|
messages: request.messages,
|
|
@@ -1379,28 +1743,116 @@ function resolveAnthropicFetch(options) {
|
|
|
1379
1743
|
}
|
|
1380
1744
|
|
|
1381
1745
|
// src/gemini-adapter.ts
|
|
1382
|
-
var
|
|
1383
|
-
var
|
|
1384
|
-
var
|
|
1746
|
+
var import_zod7 = require("zod");
|
|
1747
|
+
var import_errors22 = require("@assemble-dev/shared-types/errors");
|
|
1748
|
+
var import_errors23 = require("@assemble-dev/shared-utils/errors");
|
|
1749
|
+
|
|
1750
|
+
// src/gemini-response-schema.ts
|
|
1751
|
+
var geminiAllowedSchemaKeywords = [
|
|
1752
|
+
"type",
|
|
1753
|
+
"format",
|
|
1754
|
+
"description",
|
|
1755
|
+
"nullable",
|
|
1756
|
+
"enum",
|
|
1757
|
+
"properties",
|
|
1758
|
+
"required",
|
|
1759
|
+
"items",
|
|
1760
|
+
"minItems",
|
|
1761
|
+
"maxItems",
|
|
1762
|
+
"anyOf"
|
|
1763
|
+
];
|
|
1764
|
+
var geminiAllowedFormats = [
|
|
1765
|
+
"date-time",
|
|
1766
|
+
"int32",
|
|
1767
|
+
"int64",
|
|
1768
|
+
"float",
|
|
1769
|
+
"double"
|
|
1770
|
+
];
|
|
1771
|
+
function buildGeminiResponseSchema(schema) {
|
|
1772
|
+
return sanitizeJsonSchemaForGeminiResponseSchema(
|
|
1773
|
+
convertZodSchemaToJsonSchema(schema)
|
|
1774
|
+
);
|
|
1775
|
+
}
|
|
1776
|
+
function sanitizeJsonSchemaForGeminiResponseSchema(jsonSchema) {
|
|
1777
|
+
return transformJsonSchemaNode(
|
|
1778
|
+
inlineJsonSchemaReferences(jsonSchema),
|
|
1779
|
+
sanitizeGeminiSchemaNode
|
|
1780
|
+
);
|
|
1781
|
+
}
|
|
1782
|
+
function sanitizeGeminiSchemaNode(node) {
|
|
1783
|
+
const normalized = normalizeGeminiNullableType(
|
|
1784
|
+
mergeNullUnionIntoNullableNode(node)
|
|
1785
|
+
);
|
|
1786
|
+
const sanitized = {};
|
|
1787
|
+
for (const [key, value] of Object.entries(normalized)) {
|
|
1788
|
+
if (geminiAllowedSchemaKeywords.includes(key)) {
|
|
1789
|
+
sanitized[key] = value;
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
return removeUnsupportedGeminiFormat(sanitized);
|
|
1793
|
+
}
|
|
1794
|
+
function mergeNullUnionIntoNullableNode(node) {
|
|
1795
|
+
const unionKeyword = Array.isArray(node["anyOf"]) ? "anyOf" : "oneOf";
|
|
1796
|
+
const unionMembers = node[unionKeyword];
|
|
1797
|
+
if (!Array.isArray(unionMembers)) {
|
|
1798
|
+
return node;
|
|
1799
|
+
}
|
|
1800
|
+
const nonNullMembers = unionMembers.filter(
|
|
1801
|
+
(member) => !isNullTypeSchemaNode(member)
|
|
1802
|
+
);
|
|
1803
|
+
if (nonNullMembers.length === unionMembers.length) {
|
|
1804
|
+
return node;
|
|
1805
|
+
}
|
|
1806
|
+
const merged = { ...node };
|
|
1807
|
+
delete merged[unionKeyword];
|
|
1808
|
+
const singleMember = nonNullMembers.length === 1 ? nonNullMembers[0] : void 0;
|
|
1809
|
+
if (singleMember !== void 0 && isJsonObject(singleMember)) {
|
|
1810
|
+
return { ...merged, ...singleMember, nullable: true };
|
|
1811
|
+
}
|
|
1812
|
+
return { ...merged, anyOf: nonNullMembers, nullable: true };
|
|
1813
|
+
}
|
|
1814
|
+
function normalizeGeminiNullableType(node) {
|
|
1815
|
+
const typeValue = node["type"];
|
|
1816
|
+
if (!Array.isArray(typeValue)) {
|
|
1817
|
+
return node;
|
|
1818
|
+
}
|
|
1819
|
+
const nonNullTypes = typeValue.filter((typeName) => typeName !== "null");
|
|
1820
|
+
const normalized = { ...node };
|
|
1821
|
+
if (nonNullTypes.length < typeValue.length) {
|
|
1822
|
+
normalized["nullable"] = true;
|
|
1823
|
+
}
|
|
1824
|
+
normalized["type"] = nonNullTypes[0] ?? "string";
|
|
1825
|
+
return normalized;
|
|
1826
|
+
}
|
|
1827
|
+
function removeUnsupportedGeminiFormat(node) {
|
|
1828
|
+
const formatValue = node["format"];
|
|
1829
|
+
if (typeof formatValue === "string" && !geminiAllowedFormats.includes(formatValue)) {
|
|
1830
|
+
const withoutFormat = { ...node };
|
|
1831
|
+
delete withoutFormat["format"];
|
|
1832
|
+
return withoutFormat;
|
|
1833
|
+
}
|
|
1834
|
+
return node;
|
|
1835
|
+
}
|
|
1836
|
+
function isNullTypeSchemaNode(value) {
|
|
1837
|
+
return isJsonObject(value) && value["type"] === "null";
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
// src/gemini-adapter.ts
|
|
1385
1841
|
var defaultGeminiBaseUrl = "https://generativelanguage.googleapis.com";
|
|
1386
|
-
var GeminiGenerateContentResponseSchema =
|
|
1387
|
-
candidates:
|
|
1388
|
-
|
|
1389
|
-
content:
|
|
1390
|
-
parts:
|
|
1842
|
+
var GeminiGenerateContentResponseSchema = import_zod7.z.object({
|
|
1843
|
+
candidates: import_zod7.z.array(
|
|
1844
|
+
import_zod7.z.object({
|
|
1845
|
+
content: import_zod7.z.object({
|
|
1846
|
+
parts: import_zod7.z.array(import_zod7.z.object({ text: import_zod7.z.string() }))
|
|
1391
1847
|
})
|
|
1392
1848
|
})
|
|
1393
1849
|
).optional(),
|
|
1394
|
-
usageMetadata:
|
|
1395
|
-
promptTokenCount:
|
|
1396
|
-
candidatesTokenCount:
|
|
1397
|
-
totalTokenCount:
|
|
1850
|
+
usageMetadata: import_zod7.z.object({
|
|
1851
|
+
promptTokenCount: import_zod7.z.number().int().nonnegative().optional(),
|
|
1852
|
+
candidatesTokenCount: import_zod7.z.number().int().nonnegative().optional(),
|
|
1853
|
+
totalTokenCount: import_zod7.z.number().int().nonnegative().optional()
|
|
1398
1854
|
}).optional()
|
|
1399
1855
|
});
|
|
1400
|
-
var structuredOutputSystemMessage3 = {
|
|
1401
|
-
role: "system",
|
|
1402
|
-
content: "Respond with a single JSON object that satisfies the caller's requested structure. Output only valid JSON with no surrounding text."
|
|
1403
|
-
};
|
|
1404
1856
|
function gemini(options) {
|
|
1405
1857
|
return {
|
|
1406
1858
|
name: `gemini:${options.model}`,
|
|
@@ -1410,19 +1862,15 @@ function gemini(options) {
|
|
|
1410
1862
|
messages: request.messages,
|
|
1411
1863
|
temperature: request.temperature ?? options.temperature,
|
|
1412
1864
|
maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
|
|
1413
|
-
requireJsonResponse: false,
|
|
1414
1865
|
abortSignal: request.abortSignal,
|
|
1415
1866
|
extraBody: request.extraBody
|
|
1416
1867
|
});
|
|
1417
1868
|
},
|
|
1418
1869
|
async generateStructuredOutput(request) {
|
|
1419
|
-
const completion = await executeGeminiAdapterCall(
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
requireJsonResponse: true,
|
|
1424
|
-
abortSignal: request.abortSignal
|
|
1425
|
-
});
|
|
1870
|
+
const completion = await executeGeminiAdapterCall(
|
|
1871
|
+
options,
|
|
1872
|
+
buildGeminiStructuredOutputInput(options, request)
|
|
1873
|
+
);
|
|
1426
1874
|
return {
|
|
1427
1875
|
value: parseStructuredJsonText(completion.content, request.schema),
|
|
1428
1876
|
tokenUsage: completion.tokenUsage,
|
|
@@ -1431,16 +1879,35 @@ function gemini(options) {
|
|
|
1431
1879
|
}
|
|
1432
1880
|
};
|
|
1433
1881
|
}
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1882
|
+
function buildGeminiStructuredOutputInput(options, request) {
|
|
1883
|
+
const baseInput = {
|
|
1884
|
+
messages: request.messages,
|
|
1885
|
+
temperature: request.temperature ?? options.temperature,
|
|
1886
|
+
maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
|
|
1887
|
+
abortSignal: request.abortSignal
|
|
1888
|
+
};
|
|
1889
|
+
if (isZodV4Schema(request.schema)) {
|
|
1890
|
+
return {
|
|
1891
|
+
...baseInput,
|
|
1892
|
+
responseSchema: buildGeminiResponseSchema(request.schema)
|
|
1893
|
+
};
|
|
1894
|
+
}
|
|
1895
|
+
return {
|
|
1896
|
+
...baseInput,
|
|
1897
|
+
messages: prependStructuredOutputJsonOnlySystemMessage(request.messages),
|
|
1898
|
+
requireJsonResponse: true
|
|
1899
|
+
};
|
|
1900
|
+
}
|
|
1901
|
+
async function executeGeminiAdapterCall(options, input) {
|
|
1902
|
+
return await executeProviderCallWithModelFallback(
|
|
1903
|
+
options.fallbackModel,
|
|
1904
|
+
async () => await executeProviderCallWithRetry(
|
|
1905
|
+
options.retry,
|
|
1906
|
+
async () => await requestGeminiGenerateContent(options, input)
|
|
1907
|
+
),
|
|
1908
|
+
async (fallbackModelId) => await requestGeminiGenerateContent(
|
|
1909
|
+
{ ...options, model: fallbackModelId },
|
|
1910
|
+
input
|
|
1444
1911
|
)
|
|
1445
1912
|
);
|
|
1446
1913
|
}
|
|
@@ -1507,8 +1974,8 @@ function ensureGeminiRequestHasNoTools(request) {
|
|
|
1507
1974
|
if (request.tools === void 0 || request.tools.length === 0) {
|
|
1508
1975
|
return;
|
|
1509
1976
|
}
|
|
1510
|
-
throw new
|
|
1511
|
-
code:
|
|
1977
|
+
throw new import_errors23.AppError({
|
|
1978
|
+
code: import_errors22.AppErrorCode.ValidationFailed,
|
|
1512
1979
|
message: "gemini adapter does not support model-driven tool use; remove tools from the request or use another adapter",
|
|
1513
1980
|
statusCode: 400
|
|
1514
1981
|
});
|
|
@@ -1545,7 +2012,10 @@ function buildGeminiGenerationConfig(input) {
|
|
|
1545
2012
|
if (input.maxOutputTokens !== void 0) {
|
|
1546
2013
|
generationConfig.maxOutputTokens = input.maxOutputTokens;
|
|
1547
2014
|
}
|
|
1548
|
-
if (input.
|
|
2015
|
+
if (input.responseSchema !== void 0) {
|
|
2016
|
+
generationConfig.responseMimeType = "application/json";
|
|
2017
|
+
generationConfig.responseSchema = input.responseSchema;
|
|
2018
|
+
} else if (input.requireJsonResponse === true) {
|
|
1549
2019
|
generationConfig.responseMimeType = "application/json";
|
|
1550
2020
|
}
|
|
1551
2021
|
if (Object.keys(generationConfig).length === 0) {
|
|
@@ -1556,8 +2026,8 @@ function buildGeminiGenerationConfig(input) {
|
|
|
1556
2026
|
function extractGeminiCandidateText(response) {
|
|
1557
2027
|
const firstCandidate = response.candidates?.[0];
|
|
1558
2028
|
if (firstCandidate === void 0) {
|
|
1559
|
-
throw new
|
|
1560
|
-
code:
|
|
2029
|
+
throw new import_errors23.AppError({
|
|
2030
|
+
code: import_errors22.AppErrorCode.ValidationFailed,
|
|
1561
2031
|
message: "Gemini response contained no candidates",
|
|
1562
2032
|
statusCode: 502
|
|
1563
2033
|
});
|
|
@@ -1576,8 +2046,8 @@ function mapGeminiUsageToTokenUsage(response) {
|
|
|
1576
2046
|
}
|
|
1577
2047
|
|
|
1578
2048
|
// src/mock-adapter.ts
|
|
1579
|
-
var
|
|
1580
|
-
var
|
|
2049
|
+
var import_errors24 = require("@assemble-dev/shared-types/errors");
|
|
2050
|
+
var import_errors25 = require("@assemble-dev/shared-utils/errors");
|
|
1581
2051
|
var mockStreamChunkCount = 3;
|
|
1582
2052
|
function mockModel(options = {}) {
|
|
1583
2053
|
const remainingScriptedResponses = [...options.scriptedResponses ?? []];
|
|
@@ -1657,8 +2127,8 @@ function resolveNextMockResponseText(request, remainingScriptedResponses, respon
|
|
|
1657
2127
|
if (respond !== void 0) {
|
|
1658
2128
|
return respond(request);
|
|
1659
2129
|
}
|
|
1660
|
-
throw new
|
|
1661
|
-
code:
|
|
2130
|
+
throw new import_errors25.AppError({
|
|
2131
|
+
code: import_errors24.AppErrorCode.BadRequest,
|
|
1662
2132
|
message: "Mock model has no scripted responses left and no respond function was provided",
|
|
1663
2133
|
statusCode: 400
|
|
1664
2134
|
});
|
|
@@ -1746,24 +2216,24 @@ function calculateModelCallCostUsd(pricing, tokenUsage) {
|
|
|
1746
2216
|
}
|
|
1747
2217
|
|
|
1748
2218
|
// src/anthropic-batch.ts
|
|
2219
|
+
var import_errors28 = require("@assemble-dev/shared-types/errors");
|
|
2220
|
+
var import_json8 = require("@assemble-dev/shared-types/json");
|
|
2221
|
+
var import_errors29 = require("@assemble-dev/shared-utils/errors");
|
|
2222
|
+
|
|
2223
|
+
// src/anthropic-batch-structured.ts
|
|
1749
2224
|
var import_errors26 = require("@assemble-dev/shared-types/errors");
|
|
1750
2225
|
var import_json7 = require("@assemble-dev/shared-types/json");
|
|
1751
2226
|
var import_errors27 = require("@assemble-dev/shared-utils/errors");
|
|
1752
|
-
|
|
1753
|
-
// src/anthropic-batch-structured.ts
|
|
1754
|
-
var import_errors24 = require("@assemble-dev/shared-types/errors");
|
|
1755
|
-
var import_json6 = require("@assemble-dev/shared-types/json");
|
|
1756
|
-
var import_errors25 = require("@assemble-dev/shared-utils/errors");
|
|
1757
|
-
var anthropicBatchJsonOnlySystemInstruction = "Respond with a single JSON object that satisfies the caller's requested structure. Output only valid JSON with no surrounding text.";
|
|
2227
|
+
var anthropicBatchJsonOnlySystemInstruction = structuredOutputJsonOnlySystemInstruction;
|
|
1758
2228
|
function parseAnthropicBatchStructuredContent(content, schema) {
|
|
1759
2229
|
const jsonValue = parseStructuredJsonText(
|
|
1760
2230
|
content,
|
|
1761
|
-
|
|
2231
|
+
import_json7.JsonValueSchema
|
|
1762
2232
|
);
|
|
1763
2233
|
const validationResult = schema.safeParse(jsonValue);
|
|
1764
2234
|
if (!validationResult.success) {
|
|
1765
|
-
throw new
|
|
1766
|
-
code:
|
|
2235
|
+
throw new import_errors27.AppError({
|
|
2236
|
+
code: import_errors26.AppErrorCode.ValidationFailed,
|
|
1767
2237
|
message: "Anthropic batch structured output did not match the expected schema",
|
|
1768
2238
|
statusCode: 422,
|
|
1769
2239
|
details: { validationErrorMessage: validationResult.error.message }
|
|
@@ -1780,11 +2250,25 @@ function mapBatchMessageRequestToApiBatchRequest(request) {
|
|
|
1780
2250
|
messages: request.messages.filter((message) => message.role !== "system").map(mapChatMessageToBatchApiRequestMessage)
|
|
1781
2251
|
};
|
|
1782
2252
|
applyBatchSystemField(params, request);
|
|
2253
|
+
applyBatchStructuredOutputConfig(params, request);
|
|
1783
2254
|
if (request.temperature !== void 0) {
|
|
1784
2255
|
params.temperature = request.temperature;
|
|
1785
2256
|
}
|
|
1786
2257
|
return { custom_id: request.customId, params };
|
|
1787
2258
|
}
|
|
2259
|
+
function applyBatchStructuredOutputConfig(params, request) {
|
|
2260
|
+
if (request.structuredOutputJsonSchema === void 0) {
|
|
2261
|
+
return;
|
|
2262
|
+
}
|
|
2263
|
+
params.output_config = {
|
|
2264
|
+
format: {
|
|
2265
|
+
type: "json_schema",
|
|
2266
|
+
schema: sanitizeJsonSchemaForAnthropicStructuredOutput(
|
|
2267
|
+
request.structuredOutputJsonSchema
|
|
2268
|
+
)
|
|
2269
|
+
}
|
|
2270
|
+
};
|
|
2271
|
+
}
|
|
1788
2272
|
function applyBatchSystemField(params, request) {
|
|
1789
2273
|
const systemText = buildBatchSystemText(request);
|
|
1790
2274
|
if (systemText.length === 0) {
|
|
@@ -1800,7 +2284,7 @@ function applyBatchSystemField(params, request) {
|
|
|
1800
2284
|
}
|
|
1801
2285
|
function buildBatchSystemText(request) {
|
|
1802
2286
|
const joinedSystemText = joinBatchSystemMessageText(request.messages);
|
|
1803
|
-
if (request.requireJsonResponse !== true) {
|
|
2287
|
+
if (request.requireJsonResponse !== true || request.structuredOutputJsonSchema !== void 0) {
|
|
1804
2288
|
return joinedSystemText;
|
|
1805
2289
|
}
|
|
1806
2290
|
if (joinedSystemText.length === 0) {
|
|
@@ -1951,55 +2435,55 @@ function buildBatchResultEvent(eventBase, batchId, result, modelName) {
|
|
|
1951
2435
|
}
|
|
1952
2436
|
|
|
1953
2437
|
// src/anthropic-batch-types.ts
|
|
1954
|
-
var
|
|
1955
|
-
var AnthropicMessageBatchResponseSchema =
|
|
1956
|
-
id:
|
|
1957
|
-
processing_status:
|
|
1958
|
-
request_counts:
|
|
1959
|
-
processing:
|
|
1960
|
-
succeeded:
|
|
1961
|
-
errored:
|
|
1962
|
-
canceled:
|
|
1963
|
-
expired:
|
|
2438
|
+
var import_zod8 = require("zod");
|
|
2439
|
+
var AnthropicMessageBatchResponseSchema = import_zod8.z.object({
|
|
2440
|
+
id: import_zod8.z.string(),
|
|
2441
|
+
processing_status: import_zod8.z.enum(["in_progress", "canceling", "ended"]),
|
|
2442
|
+
request_counts: import_zod8.z.object({
|
|
2443
|
+
processing: import_zod8.z.number().int().nonnegative(),
|
|
2444
|
+
succeeded: import_zod8.z.number().int().nonnegative(),
|
|
2445
|
+
errored: import_zod8.z.number().int().nonnegative(),
|
|
2446
|
+
canceled: import_zod8.z.number().int().nonnegative(),
|
|
2447
|
+
expired: import_zod8.z.number().int().nonnegative()
|
|
1964
2448
|
}),
|
|
1965
|
-
results_url:
|
|
1966
|
-
created_at:
|
|
1967
|
-
ended_at:
|
|
2449
|
+
results_url: import_zod8.z.string().nullable(),
|
|
2450
|
+
created_at: import_zod8.z.string(),
|
|
2451
|
+
ended_at: import_zod8.z.string().nullable()
|
|
1968
2452
|
});
|
|
1969
|
-
var AnthropicBatchContentBlockSchema =
|
|
1970
|
-
|
|
1971
|
-
type:
|
|
1972
|
-
text:
|
|
2453
|
+
var AnthropicBatchContentBlockSchema = import_zod8.z.discriminatedUnion("type", [
|
|
2454
|
+
import_zod8.z.object({
|
|
2455
|
+
type: import_zod8.z.literal("text"),
|
|
2456
|
+
text: import_zod8.z.string()
|
|
1973
2457
|
}),
|
|
1974
|
-
|
|
1975
|
-
type:
|
|
1976
|
-
thinking:
|
|
1977
|
-
signature:
|
|
2458
|
+
import_zod8.z.object({
|
|
2459
|
+
type: import_zod8.z.literal("thinking"),
|
|
2460
|
+
thinking: import_zod8.z.string().optional(),
|
|
2461
|
+
signature: import_zod8.z.string().optional()
|
|
1978
2462
|
}),
|
|
1979
|
-
|
|
1980
|
-
type:
|
|
1981
|
-
data:
|
|
2463
|
+
import_zod8.z.object({
|
|
2464
|
+
type: import_zod8.z.literal("redacted_thinking"),
|
|
2465
|
+
data: import_zod8.z.string().optional()
|
|
1982
2466
|
})
|
|
1983
2467
|
]);
|
|
1984
|
-
var AnthropicBatchResultLineSchema =
|
|
1985
|
-
custom_id:
|
|
1986
|
-
result:
|
|
1987
|
-
|
|
1988
|
-
type:
|
|
1989
|
-
message:
|
|
1990
|
-
content:
|
|
2468
|
+
var AnthropicBatchResultLineSchema = import_zod8.z.object({
|
|
2469
|
+
custom_id: import_zod8.z.string(),
|
|
2470
|
+
result: import_zod8.z.discriminatedUnion("type", [
|
|
2471
|
+
import_zod8.z.object({
|
|
2472
|
+
type: import_zod8.z.literal("succeeded"),
|
|
2473
|
+
message: import_zod8.z.object({
|
|
2474
|
+
content: import_zod8.z.array(AnthropicBatchContentBlockSchema),
|
|
1991
2475
|
usage: AnthropicUsageSchema
|
|
1992
2476
|
})
|
|
1993
2477
|
}),
|
|
1994
|
-
|
|
1995
|
-
type:
|
|
1996
|
-
error:
|
|
1997
|
-
type:
|
|
1998
|
-
message:
|
|
2478
|
+
import_zod8.z.object({
|
|
2479
|
+
type: import_zod8.z.literal("errored"),
|
|
2480
|
+
error: import_zod8.z.object({
|
|
2481
|
+
type: import_zod8.z.string(),
|
|
2482
|
+
message: import_zod8.z.string()
|
|
1999
2483
|
})
|
|
2000
2484
|
}),
|
|
2001
|
-
|
|
2002
|
-
|
|
2485
|
+
import_zod8.z.object({ type: import_zod8.z.literal("canceled") }),
|
|
2486
|
+
import_zod8.z.object({ type: import_zod8.z.literal("expired") })
|
|
2003
2487
|
])
|
|
2004
2488
|
});
|
|
2005
2489
|
function mapAnthropicMessageBatchResponseToMessageBatch(response) {
|
|
@@ -2149,8 +2633,8 @@ async function parseAnthropicMessageBatchHttpResponse(response) {
|
|
|
2149
2633
|
async function listAnthropicMessageBatchResults(clientContext, batchId) {
|
|
2150
2634
|
const batch = await fetchAnthropicMessageBatch(clientContext, batchId);
|
|
2151
2635
|
if (batch.resultsUrl === null) {
|
|
2152
|
-
throw new
|
|
2153
|
-
code:
|
|
2636
|
+
throw new import_errors29.AppError({
|
|
2637
|
+
code: import_errors28.AppErrorCode.Conflict,
|
|
2154
2638
|
message: `Anthropic message batch ${batchId} has no results because processing has not ended`,
|
|
2155
2639
|
statusCode: 409,
|
|
2156
2640
|
details: { batchId, processingStatus: batch.processingStatus }
|
|
@@ -2187,7 +2671,7 @@ function parseAnthropicBatchResultLine(line) {
|
|
|
2187
2671
|
}
|
|
2188
2672
|
function parseAnthropicBatchResultLineJson(line) {
|
|
2189
2673
|
try {
|
|
2190
|
-
return
|
|
2674
|
+
return import_json8.JsonValueSchema.parse(JSON.parse(line));
|
|
2191
2675
|
} catch {
|
|
2192
2676
|
throw buildProviderInvalidResponseError(
|
|
2193
2677
|
"Anthropic",
|
|
@@ -2211,17 +2695,764 @@ async function waitForAnthropicMessageBatchCompletion(clientContext, batchId, wa
|
|
|
2211
2695
|
return batch;
|
|
2212
2696
|
}
|
|
2213
2697
|
function buildAnthropicBatchTimeoutError(batchId, timeoutMs) {
|
|
2214
|
-
return new
|
|
2215
|
-
code:
|
|
2698
|
+
return new import_errors29.AppError({
|
|
2699
|
+
code: import_errors28.AppErrorCode.ServiceUnavailable,
|
|
2216
2700
|
message: `Anthropic message batch ${batchId} did not complete within ${String(timeoutMs)}ms`,
|
|
2217
2701
|
statusCode: 504,
|
|
2218
2702
|
details: { batchId, timeoutMs }
|
|
2219
2703
|
});
|
|
2220
2704
|
}
|
|
2705
|
+
|
|
2706
|
+
// src/azure-openai-adapter.ts
|
|
2707
|
+
var import_errors32 = require("@assemble-dev/shared-types/errors");
|
|
2708
|
+
var import_errors33 = require("@assemble-dev/shared-utils/errors");
|
|
2709
|
+
|
|
2710
|
+
// src/azure-openai-response-parsing.ts
|
|
2711
|
+
var import_zod9 = require("zod");
|
|
2712
|
+
var import_errors30 = require("@assemble-dev/shared-types/errors");
|
|
2713
|
+
var import_json9 = require("@assemble-dev/shared-types/json");
|
|
2714
|
+
var import_errors31 = require("@assemble-dev/shared-utils/errors");
|
|
2715
|
+
var AzureOpenAiUsageSchema = import_zod9.z.object({
|
|
2716
|
+
prompt_tokens: import_zod9.z.number().int().nonnegative(),
|
|
2717
|
+
completion_tokens: import_zod9.z.number().int().nonnegative(),
|
|
2718
|
+
total_tokens: import_zod9.z.number().int().nonnegative()
|
|
2719
|
+
});
|
|
2720
|
+
var AzureOpenAiResponseToolCallSchema = import_zod9.z.object({
|
|
2721
|
+
id: import_zod9.z.string(),
|
|
2722
|
+
function: import_zod9.z.object({
|
|
2723
|
+
name: import_zod9.z.string(),
|
|
2724
|
+
arguments: import_zod9.z.string()
|
|
2725
|
+
})
|
|
2726
|
+
});
|
|
2727
|
+
var AzureOpenAiChatCompletionResponseSchema = import_zod9.z.object({
|
|
2728
|
+
choices: import_zod9.z.array(
|
|
2729
|
+
import_zod9.z.object({
|
|
2730
|
+
message: import_zod9.z.object({
|
|
2731
|
+
content: import_zod9.z.string().nullable(),
|
|
2732
|
+
tool_calls: import_zod9.z.array(AzureOpenAiResponseToolCallSchema).optional()
|
|
2733
|
+
}),
|
|
2734
|
+
finish_reason: import_zod9.z.string().nullable().optional()
|
|
2735
|
+
})
|
|
2736
|
+
).min(1),
|
|
2737
|
+
usage: AzureOpenAiUsageSchema
|
|
2738
|
+
});
|
|
2739
|
+
function mapAzureOpenAiResponseToChatCompletionResult(response, latencyMs) {
|
|
2740
|
+
const toolCalls = extractAzureOpenAiToolCalls(response);
|
|
2741
|
+
const result = {
|
|
2742
|
+
content: extractAzureOpenAiMessageContent(response, toolCalls.length > 0),
|
|
2743
|
+
tokenUsage: mapAzureOpenAiUsageToTokenUsage(response.usage),
|
|
2744
|
+
latencyMs
|
|
2745
|
+
};
|
|
2746
|
+
const finishReason = response.choices[0]?.finish_reason;
|
|
2747
|
+
if (toolCalls.length > 0) {
|
|
2748
|
+
result.toolCalls = toolCalls;
|
|
2749
|
+
}
|
|
2750
|
+
if (finishReason !== null && finishReason !== void 0) {
|
|
2751
|
+
result.stopReason = normalizeAzureOpenAiFinishReason(finishReason);
|
|
2752
|
+
}
|
|
2753
|
+
return result;
|
|
2754
|
+
}
|
|
2755
|
+
function extractAzureOpenAiToolCalls(response) {
|
|
2756
|
+
const responseToolCalls = response.choices[0]?.message.tool_calls ?? [];
|
|
2757
|
+
return responseToolCalls.map((responseToolCall) => ({
|
|
2758
|
+
id: responseToolCall.id,
|
|
2759
|
+
toolName: responseToolCall.function.name,
|
|
2760
|
+
input: parseAzureOpenAiToolArgumentsJson(responseToolCall.function.arguments)
|
|
2761
|
+
}));
|
|
2762
|
+
}
|
|
2763
|
+
function parseAzureOpenAiToolArgumentsJson(argumentsJsonText) {
|
|
2764
|
+
if (argumentsJsonText.trim().length === 0) {
|
|
2765
|
+
return {};
|
|
2766
|
+
}
|
|
2767
|
+
try {
|
|
2768
|
+
return import_json9.JsonValueSchema.parse(JSON.parse(argumentsJsonText));
|
|
2769
|
+
} catch (error) {
|
|
2770
|
+
throw new import_errors31.AppError({
|
|
2771
|
+
code: import_errors30.AppErrorCode.ValidationFailed,
|
|
2772
|
+
message: "Azure OpenAI tool call arguments were not valid JSON",
|
|
2773
|
+
statusCode: 502,
|
|
2774
|
+
cause: error instanceof Error ? error : void 0
|
|
2775
|
+
});
|
|
2776
|
+
}
|
|
2777
|
+
}
|
|
2778
|
+
function normalizeAzureOpenAiFinishReason(finishReason) {
|
|
2779
|
+
if (finishReason === "tool_calls") {
|
|
2780
|
+
return "tool_use";
|
|
2781
|
+
}
|
|
2782
|
+
if (finishReason === "length") {
|
|
2783
|
+
return "max_tokens";
|
|
2784
|
+
}
|
|
2785
|
+
return "end_turn";
|
|
2786
|
+
}
|
|
2787
|
+
function extractAzureOpenAiMessageContent(response, allowEmptyContent) {
|
|
2788
|
+
const content = response.choices[0]?.message.content;
|
|
2789
|
+
if (content === void 0 || content === null) {
|
|
2790
|
+
if (allowEmptyContent) {
|
|
2791
|
+
return "";
|
|
2792
|
+
}
|
|
2793
|
+
throw new import_errors31.AppError({
|
|
2794
|
+
code: import_errors30.AppErrorCode.ValidationFailed,
|
|
2795
|
+
message: "Azure OpenAI response contained no message content",
|
|
2796
|
+
statusCode: 502
|
|
2797
|
+
});
|
|
2798
|
+
}
|
|
2799
|
+
return content;
|
|
2800
|
+
}
|
|
2801
|
+
function mapAzureOpenAiUsageToTokenUsage(usage) {
|
|
2802
|
+
return {
|
|
2803
|
+
inputTokens: usage.prompt_tokens,
|
|
2804
|
+
outputTokens: usage.completion_tokens,
|
|
2805
|
+
totalTokens: usage.total_tokens
|
|
2806
|
+
};
|
|
2807
|
+
}
|
|
2808
|
+
|
|
2809
|
+
// src/azure-openai-stream.ts
|
|
2810
|
+
var import_zod10 = require("zod");
|
|
2811
|
+
var AzureOpenAiStreamToolCallDeltaSchema = import_zod10.z.object({
|
|
2812
|
+
index: import_zod10.z.number().int().nonnegative(),
|
|
2813
|
+
id: import_zod10.z.string().optional(),
|
|
2814
|
+
function: import_zod10.z.object({
|
|
2815
|
+
name: import_zod10.z.string().optional(),
|
|
2816
|
+
arguments: import_zod10.z.string().optional()
|
|
2817
|
+
}).optional()
|
|
2818
|
+
});
|
|
2819
|
+
var AzureOpenAiStreamChunkSchema = import_zod10.z.object({
|
|
2820
|
+
choices: import_zod10.z.array(
|
|
2821
|
+
import_zod10.z.object({
|
|
2822
|
+
delta: import_zod10.z.object({
|
|
2823
|
+
content: import_zod10.z.string().nullable().optional(),
|
|
2824
|
+
tool_calls: import_zod10.z.array(AzureOpenAiStreamToolCallDeltaSchema).optional()
|
|
2825
|
+
}).optional(),
|
|
2826
|
+
finish_reason: import_zod10.z.string().nullable().optional()
|
|
2827
|
+
})
|
|
2828
|
+
).optional(),
|
|
2829
|
+
usage: AzureOpenAiUsageSchema.nullable().optional()
|
|
2830
|
+
});
|
|
2831
|
+
async function* streamAzureOpenAiChatCompletion(input) {
|
|
2832
|
+
const startedAt = Date.now();
|
|
2833
|
+
const response = await establishAzureOpenAiStreamResponse(input);
|
|
2834
|
+
if (response.body === null) {
|
|
2835
|
+
throw buildProviderInvalidResponseError("Azure OpenAI", "stream body");
|
|
2836
|
+
}
|
|
2837
|
+
yield* parseAzureOpenAiStreamEvents(
|
|
2838
|
+
response.body,
|
|
2839
|
+
startedAt,
|
|
2840
|
+
input.abortSignal
|
|
2841
|
+
);
|
|
2842
|
+
}
|
|
2843
|
+
async function establishAzureOpenAiStreamResponse(input) {
|
|
2844
|
+
return await executeProviderCallWithRetry(input.retry, async () => {
|
|
2845
|
+
const response = await executeAbortableProviderFetch(
|
|
2846
|
+
"Azure OpenAI",
|
|
2847
|
+
async () => await input.fetchImplementation(input.url, {
|
|
2848
|
+
method: "POST",
|
|
2849
|
+
headers: input.headers,
|
|
2850
|
+
body: JSON.stringify(input.body),
|
|
2851
|
+
signal: input.abortSignal
|
|
2852
|
+
})
|
|
2853
|
+
);
|
|
2854
|
+
if (!response.ok) {
|
|
2855
|
+
throw buildProviderStatusError("Azure OpenAI", response.status);
|
|
2856
|
+
}
|
|
2857
|
+
return response;
|
|
2858
|
+
});
|
|
2859
|
+
}
|
|
2860
|
+
async function* parseAzureOpenAiStreamEvents(body, startedAt, abortSignal) {
|
|
2861
|
+
const accumulator = createAzureOpenAiStreamAccumulator();
|
|
2862
|
+
for await (const dataText of readServerSentEventDataLines2(body, abortSignal)) {
|
|
2863
|
+
if (dataText === "[DONE]") {
|
|
2864
|
+
yield {
|
|
2865
|
+
type: "completed",
|
|
2866
|
+
result: buildAzureOpenAiStreamResult(
|
|
2867
|
+
accumulator,
|
|
2868
|
+
Date.now() - startedAt
|
|
2869
|
+
)
|
|
2870
|
+
};
|
|
2871
|
+
return;
|
|
2872
|
+
}
|
|
2873
|
+
const parsedChunk = AzureOpenAiStreamChunkSchema.safeParse(
|
|
2874
|
+
JSON.parse(dataText)
|
|
2875
|
+
);
|
|
2876
|
+
if (!parsedChunk.success) {
|
|
2877
|
+
continue;
|
|
2878
|
+
}
|
|
2879
|
+
yield* applyAzureOpenAiStreamChunk(parsedChunk.data, accumulator);
|
|
2880
|
+
}
|
|
2881
|
+
throw buildProviderInvalidResponseError("Azure OpenAI", "stream termination");
|
|
2882
|
+
}
|
|
2883
|
+
async function* readServerSentEventDataLines2(body, abortSignal) {
|
|
2884
|
+
const reader = body.getReader();
|
|
2885
|
+
const decoder = new TextDecoder();
|
|
2886
|
+
let bufferedText = "";
|
|
2887
|
+
try {
|
|
2888
|
+
for (; ; ) {
|
|
2889
|
+
if (abortSignal?.aborted === true) {
|
|
2890
|
+
await reader.cancel();
|
|
2891
|
+
throw buildProviderCanceledError("Azure OpenAI");
|
|
2892
|
+
}
|
|
2893
|
+
const readResult = await reader.read();
|
|
2894
|
+
if (readResult.done) {
|
|
2895
|
+
return;
|
|
2896
|
+
}
|
|
2897
|
+
bufferedText += decoder.decode(readResult.value, { stream: true });
|
|
2898
|
+
const lines = bufferedText.split("\n");
|
|
2899
|
+
bufferedText = lines.pop() ?? "";
|
|
2900
|
+
for (const line of lines) {
|
|
2901
|
+
if (line.startsWith("data:")) {
|
|
2902
|
+
const dataText = line.slice("data:".length).trim();
|
|
2903
|
+
if (dataText.length > 0) {
|
|
2904
|
+
yield dataText;
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
}
|
|
2908
|
+
}
|
|
2909
|
+
} catch (error) {
|
|
2910
|
+
if (error instanceof Error && isAbortError(error)) {
|
|
2911
|
+
throw buildProviderCanceledError("Azure OpenAI");
|
|
2912
|
+
}
|
|
2913
|
+
throw error;
|
|
2914
|
+
}
|
|
2915
|
+
}
|
|
2916
|
+
function createAzureOpenAiStreamAccumulator() {
|
|
2917
|
+
return {
|
|
2918
|
+
contentText: "",
|
|
2919
|
+
toolCallsByIndex: /* @__PURE__ */ new Map()
|
|
2920
|
+
};
|
|
2921
|
+
}
|
|
2922
|
+
function* applyAzureOpenAiStreamChunk(chunk, accumulator) {
|
|
2923
|
+
if (chunk.usage !== null && chunk.usage !== void 0) {
|
|
2924
|
+
accumulator.usage = chunk.usage;
|
|
2925
|
+
}
|
|
2926
|
+
const choice = chunk.choices?.[0];
|
|
2927
|
+
if (choice === void 0) {
|
|
2928
|
+
return;
|
|
2929
|
+
}
|
|
2930
|
+
if (choice.finish_reason !== null && choice.finish_reason !== void 0) {
|
|
2931
|
+
accumulator.finishReason = choice.finish_reason;
|
|
2932
|
+
}
|
|
2933
|
+
if (choice.delta === void 0) {
|
|
2934
|
+
return;
|
|
2935
|
+
}
|
|
2936
|
+
const contentDelta = choice.delta.content;
|
|
2937
|
+
if (contentDelta !== null && contentDelta !== void 0 && contentDelta.length > 0) {
|
|
2938
|
+
accumulator.contentText += contentDelta;
|
|
2939
|
+
yield { type: "text_delta", text: contentDelta };
|
|
2940
|
+
}
|
|
2941
|
+
for (const toolCallDelta of choice.delta.tool_calls ?? []) {
|
|
2942
|
+
yield* applyAzureOpenAiToolCallDelta(toolCallDelta, accumulator);
|
|
2943
|
+
}
|
|
2944
|
+
}
|
|
2945
|
+
function* applyAzureOpenAiToolCallDelta(toolCallDelta, accumulator) {
|
|
2946
|
+
const existingToolCall = accumulator.toolCallsByIndex.get(toolCallDelta.index);
|
|
2947
|
+
if (existingToolCall === void 0) {
|
|
2948
|
+
yield* startAzureOpenAiToolCallAccumulation(toolCallDelta, accumulator);
|
|
2949
|
+
return;
|
|
2950
|
+
}
|
|
2951
|
+
const argumentsDelta = toolCallDelta.function?.arguments;
|
|
2952
|
+
if (argumentsDelta !== void 0 && argumentsDelta.length > 0) {
|
|
2953
|
+
existingToolCall.argumentsJsonText += argumentsDelta;
|
|
2954
|
+
yield {
|
|
2955
|
+
type: "tool_call_input_delta",
|
|
2956
|
+
id: existingToolCall.id,
|
|
2957
|
+
inputJsonText: argumentsDelta
|
|
2958
|
+
};
|
|
2959
|
+
}
|
|
2960
|
+
}
|
|
2961
|
+
function* startAzureOpenAiToolCallAccumulation(toolCallDelta, accumulator) {
|
|
2962
|
+
const toolName = toolCallDelta.function?.name;
|
|
2963
|
+
if (toolCallDelta.id === void 0 || toolName === void 0) {
|
|
2964
|
+
throw buildProviderInvalidResponseError(
|
|
2965
|
+
"Azure OpenAI",
|
|
2966
|
+
"stream tool call start"
|
|
2967
|
+
);
|
|
2968
|
+
}
|
|
2969
|
+
const startedToolCall = {
|
|
2970
|
+
id: toolCallDelta.id,
|
|
2971
|
+
toolName,
|
|
2972
|
+
argumentsJsonText: toolCallDelta.function?.arguments ?? ""
|
|
2973
|
+
};
|
|
2974
|
+
accumulator.toolCallsByIndex.set(toolCallDelta.index, startedToolCall);
|
|
2975
|
+
yield {
|
|
2976
|
+
type: "tool_call_started",
|
|
2977
|
+
id: startedToolCall.id,
|
|
2978
|
+
toolName: startedToolCall.toolName
|
|
2979
|
+
};
|
|
2980
|
+
if (startedToolCall.argumentsJsonText.length > 0) {
|
|
2981
|
+
yield {
|
|
2982
|
+
type: "tool_call_input_delta",
|
|
2983
|
+
id: startedToolCall.id,
|
|
2984
|
+
inputJsonText: startedToolCall.argumentsJsonText
|
|
2985
|
+
};
|
|
2986
|
+
}
|
|
2987
|
+
}
|
|
2988
|
+
function buildAzureOpenAiStreamResult(accumulator, latencyMs) {
|
|
2989
|
+
const result = {
|
|
2990
|
+
content: accumulator.contentText,
|
|
2991
|
+
tokenUsage: mapAzureOpenAiUsageToTokenUsage(
|
|
2992
|
+
accumulator.usage ?? {
|
|
2993
|
+
prompt_tokens: 0,
|
|
2994
|
+
completion_tokens: 0,
|
|
2995
|
+
total_tokens: 0
|
|
2996
|
+
}
|
|
2997
|
+
),
|
|
2998
|
+
latencyMs
|
|
2999
|
+
};
|
|
3000
|
+
const toolCalls = [...accumulator.toolCallsByIndex.values()].map(
|
|
3001
|
+
mapAccumulatedToolCallToModelToolCall2
|
|
3002
|
+
);
|
|
3003
|
+
if (toolCalls.length > 0) {
|
|
3004
|
+
result.toolCalls = toolCalls;
|
|
3005
|
+
}
|
|
3006
|
+
if (accumulator.finishReason !== void 0) {
|
|
3007
|
+
result.stopReason = normalizeAzureOpenAiFinishReason(
|
|
3008
|
+
accumulator.finishReason
|
|
3009
|
+
);
|
|
3010
|
+
}
|
|
3011
|
+
return result;
|
|
3012
|
+
}
|
|
3013
|
+
function mapAccumulatedToolCallToModelToolCall2(toolCallAccumulation) {
|
|
3014
|
+
return {
|
|
3015
|
+
id: toolCallAccumulation.id,
|
|
3016
|
+
toolName: toolCallAccumulation.toolName,
|
|
3017
|
+
input: parseAzureOpenAiToolArgumentsJson(
|
|
3018
|
+
toolCallAccumulation.argumentsJsonText
|
|
3019
|
+
)
|
|
3020
|
+
};
|
|
3021
|
+
}
|
|
3022
|
+
|
|
3023
|
+
// src/azure-openai-adapter.ts
|
|
3024
|
+
var defaultAzureOpenAiApiVersion = "2024-10-21";
|
|
3025
|
+
var azureDeploymentModelPlaceholder = "azure-deployment";
|
|
3026
|
+
function azureOpenai(options) {
|
|
3027
|
+
return {
|
|
3028
|
+
name: `azure-openai:${options.deployment}`,
|
|
3029
|
+
async generateChatCompletion(request) {
|
|
3030
|
+
return await executeAzureOpenAiAdapterCall(options, {
|
|
3031
|
+
messages: request.messages,
|
|
3032
|
+
temperature: request.temperature ?? options.temperature,
|
|
3033
|
+
maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
|
|
3034
|
+
reasoningModel: options.reasoningModel,
|
|
3035
|
+
tools: request.tools,
|
|
3036
|
+
toolChoice: request.toolChoice,
|
|
3037
|
+
abortSignal: request.abortSignal,
|
|
3038
|
+
extraBody: request.extraBody
|
|
3039
|
+
});
|
|
3040
|
+
},
|
|
3041
|
+
async generateStructuredOutput(request) {
|
|
3042
|
+
const completion = await executeAzureOpenAiAdapterCall(options, {
|
|
3043
|
+
...resolveOpenAiStructuredOutputMode(request.messages, request.schema),
|
|
3044
|
+
temperature: request.temperature ?? options.temperature,
|
|
3045
|
+
maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
|
|
3046
|
+
reasoningModel: options.reasoningModel,
|
|
3047
|
+
abortSignal: request.abortSignal
|
|
3048
|
+
});
|
|
3049
|
+
return {
|
|
3050
|
+
value: parseStructuredJsonText(completion.content, request.schema),
|
|
3051
|
+
tokenUsage: completion.tokenUsage,
|
|
3052
|
+
latencyMs: completion.latencyMs
|
|
3053
|
+
};
|
|
3054
|
+
},
|
|
3055
|
+
streamChatCompletion(request) {
|
|
3056
|
+
return streamAzureOpenAiChatCompletion(
|
|
3057
|
+
buildAzureOpenAiStreamInput(options, request)
|
|
3058
|
+
);
|
|
3059
|
+
}
|
|
3060
|
+
};
|
|
3061
|
+
}
|
|
3062
|
+
function buildAzureOpenAiChatCompletionsUrl(options) {
|
|
3063
|
+
const endpoint = resolveAzureOpenAiEndpoint(options);
|
|
3064
|
+
const apiVersion = options.apiVersion ?? defaultAzureOpenAiApiVersion;
|
|
3065
|
+
return `${endpoint}/openai/deployments/${encodeURIComponent(options.deployment)}/chat/completions?api-version=${encodeURIComponent(apiVersion)}`;
|
|
3066
|
+
}
|
|
3067
|
+
function resolveAzureOpenAiEndpoint(options) {
|
|
3068
|
+
if (options.baseURL !== void 0 && options.baseURL.length > 0) {
|
|
3069
|
+
return options.baseURL.replace(/\/+$/, "");
|
|
3070
|
+
}
|
|
3071
|
+
if (options.resourceName !== void 0 && options.resourceName.length > 0) {
|
|
3072
|
+
return `https://${options.resourceName}.openai.azure.com`;
|
|
3073
|
+
}
|
|
3074
|
+
throw new import_errors33.AppError({
|
|
3075
|
+
code: import_errors32.AppErrorCode.BadRequest,
|
|
3076
|
+
message: "Azure OpenAI endpoint is missing. Pass resourceName or baseURL to azureOpenai().",
|
|
3077
|
+
statusCode: 400
|
|
3078
|
+
});
|
|
3079
|
+
}
|
|
3080
|
+
function buildAzureOpenAiRequestHeaders(options) {
|
|
3081
|
+
return {
|
|
3082
|
+
"content-type": "application/json",
|
|
3083
|
+
"api-key": resolveProviderApiKey({
|
|
3084
|
+
providerLabel: "Azure OpenAI",
|
|
3085
|
+
adapterFunctionName: "azureOpenai()",
|
|
3086
|
+
baseEnvVarName: "AZURE_OPENAI_API_KEY",
|
|
3087
|
+
apiKey: options.apiKey,
|
|
3088
|
+
apiKeyName: options.apiKeyName
|
|
3089
|
+
})
|
|
3090
|
+
};
|
|
3091
|
+
}
|
|
3092
|
+
function buildAzureOpenAiChatRequestBody(input) {
|
|
3093
|
+
const requestBody = buildOpenAiRequestBody(
|
|
3094
|
+
azureDeploymentModelPlaceholder,
|
|
3095
|
+
input
|
|
3096
|
+
);
|
|
3097
|
+
const { model: ignoredModel, ...requestBodyWithoutModel } = requestBody;
|
|
3098
|
+
void ignoredModel;
|
|
3099
|
+
return requestBodyWithoutModel;
|
|
3100
|
+
}
|
|
3101
|
+
async function executeAzureOpenAiAdapterCall(options, input) {
|
|
3102
|
+
return await executeProviderCallWithRetry(
|
|
3103
|
+
options.retry,
|
|
3104
|
+
async () => await requestAzureOpenAiChatCompletion(options, input)
|
|
3105
|
+
);
|
|
3106
|
+
}
|
|
3107
|
+
async function requestAzureOpenAiChatCompletion(options, input) {
|
|
3108
|
+
const fetchImplementation = options.fetchImplementation ?? fetch;
|
|
3109
|
+
const requestBody = mergeProviderRequestExtraBody(
|
|
3110
|
+
buildAzureOpenAiChatRequestBody(input),
|
|
3111
|
+
options.extraBody,
|
|
3112
|
+
input.extraBody
|
|
3113
|
+
);
|
|
3114
|
+
const startedAt = Date.now();
|
|
3115
|
+
const response = await executeAbortableProviderFetch(
|
|
3116
|
+
"Azure OpenAI",
|
|
3117
|
+
async () => await fetchImplementation(buildAzureOpenAiChatCompletionsUrl(options), {
|
|
3118
|
+
method: "POST",
|
|
3119
|
+
headers: buildAzureOpenAiRequestHeaders(options),
|
|
3120
|
+
body: JSON.stringify(requestBody),
|
|
3121
|
+
signal: input.abortSignal
|
|
3122
|
+
})
|
|
3123
|
+
);
|
|
3124
|
+
const latencyMs = Date.now() - startedAt;
|
|
3125
|
+
if (!response.ok) {
|
|
3126
|
+
throw buildProviderStatusError("Azure OpenAI", response.status);
|
|
3127
|
+
}
|
|
3128
|
+
const parseResult = AzureOpenAiChatCompletionResponseSchema.safeParse(
|
|
3129
|
+
await response.json()
|
|
3130
|
+
);
|
|
3131
|
+
if (!parseResult.success) {
|
|
3132
|
+
throw buildProviderInvalidResponseError("Azure OpenAI", "chat completion");
|
|
3133
|
+
}
|
|
3134
|
+
return mapAzureOpenAiResponseToChatCompletionResult(
|
|
3135
|
+
parseResult.data,
|
|
3136
|
+
latencyMs
|
|
3137
|
+
);
|
|
3138
|
+
}
|
|
3139
|
+
function buildAzureOpenAiStreamInput(options, request) {
|
|
3140
|
+
const requestBody = mergeProviderRequestExtraBody(
|
|
3141
|
+
buildAzureOpenAiChatRequestBody({
|
|
3142
|
+
messages: request.messages,
|
|
3143
|
+
temperature: request.temperature ?? options.temperature,
|
|
3144
|
+
maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
|
|
3145
|
+
reasoningModel: options.reasoningModel,
|
|
3146
|
+
tools: request.tools,
|
|
3147
|
+
toolChoice: request.toolChoice,
|
|
3148
|
+
abortSignal: request.abortSignal,
|
|
3149
|
+
extraBody: request.extraBody
|
|
3150
|
+
}),
|
|
3151
|
+
options.extraBody,
|
|
3152
|
+
request.extraBody
|
|
3153
|
+
);
|
|
3154
|
+
return {
|
|
3155
|
+
url: buildAzureOpenAiChatCompletionsUrl(options),
|
|
3156
|
+
headers: buildAzureOpenAiRequestHeaders(options),
|
|
3157
|
+
body: {
|
|
3158
|
+
...requestBody,
|
|
3159
|
+
stream: true,
|
|
3160
|
+
stream_options: { include_usage: true }
|
|
3161
|
+
},
|
|
3162
|
+
fetchImplementation: options.fetchImplementation ?? fetch,
|
|
3163
|
+
retry: options.retry,
|
|
3164
|
+
abortSignal: request.abortSignal
|
|
3165
|
+
};
|
|
3166
|
+
}
|
|
3167
|
+
|
|
3168
|
+
// src/bedrock-adapter.ts
|
|
3169
|
+
var import_zod11 = require("zod");
|
|
3170
|
+
var import_errors34 = require("@assemble-dev/shared-types/errors");
|
|
3171
|
+
var import_errors35 = require("@assemble-dev/shared-utils/errors");
|
|
3172
|
+
|
|
3173
|
+
// src/bedrock-sigv4.ts
|
|
3174
|
+
var awsSigV4Algorithm = "AWS4-HMAC-SHA256";
|
|
3175
|
+
async function signAwsRequestWithSigV4(input) {
|
|
3176
|
+
const amzDate = formatAmzDateTime(input.signingDate ?? /* @__PURE__ */ new Date());
|
|
3177
|
+
const dateStamp = amzDate.slice(0, 8);
|
|
3178
|
+
const headersToSign = buildHeadersToSign(input, amzDate);
|
|
3179
|
+
const canonicalHeaderEntries = buildCanonicalHeaderEntries(headersToSign);
|
|
3180
|
+
const signedHeaderNames = canonicalHeaderEntries.map(([headerName]) => headerName).join(";");
|
|
3181
|
+
const credentialScope = `${dateStamp}/${input.region}/${input.service}/aws4_request`;
|
|
3182
|
+
const signatureHex = await computeAwsSigV4Signature(
|
|
3183
|
+
input,
|
|
3184
|
+
amzDate,
|
|
3185
|
+
credentialScope,
|
|
3186
|
+
canonicalHeaderEntries,
|
|
3187
|
+
signedHeaderNames
|
|
3188
|
+
);
|
|
3189
|
+
return {
|
|
3190
|
+
...headersToSign,
|
|
3191
|
+
authorization: `${awsSigV4Algorithm} Credential=${input.credentials.accessKeyId}/${credentialScope}, SignedHeaders=${signedHeaderNames}, Signature=${signatureHex}`
|
|
3192
|
+
};
|
|
3193
|
+
}
|
|
3194
|
+
async function computeAwsSigV4Signature(input, amzDate, credentialScope, canonicalHeaderEntries, signedHeaderNames) {
|
|
3195
|
+
const canonicalRequest = await buildCanonicalRequest(
|
|
3196
|
+
input,
|
|
3197
|
+
canonicalHeaderEntries,
|
|
3198
|
+
signedHeaderNames
|
|
3199
|
+
);
|
|
3200
|
+
const stringToSign = [
|
|
3201
|
+
awsSigV4Algorithm,
|
|
3202
|
+
amzDate,
|
|
3203
|
+
credentialScope,
|
|
3204
|
+
await hashSha256Hex(canonicalRequest)
|
|
3205
|
+
].join("\n");
|
|
3206
|
+
const signingKey = await deriveAwsSigningKey(
|
|
3207
|
+
input.credentials.secretAccessKey,
|
|
3208
|
+
amzDate.slice(0, 8),
|
|
3209
|
+
input.region,
|
|
3210
|
+
input.service
|
|
3211
|
+
);
|
|
3212
|
+
return bytesToHex(await computeHmacSha256(signingKey, stringToSign));
|
|
3213
|
+
}
|
|
3214
|
+
function buildHeadersToSign(input, amzDate) {
|
|
3215
|
+
const headersToSign = {};
|
|
3216
|
+
for (const [headerName, headerValue] of Object.entries(input.headers)) {
|
|
3217
|
+
headersToSign[headerName.toLowerCase()] = headerValue;
|
|
3218
|
+
}
|
|
3219
|
+
headersToSign.host = input.url.host;
|
|
3220
|
+
headersToSign["x-amz-date"] = amzDate;
|
|
3221
|
+
if (input.credentials.sessionToken !== void 0) {
|
|
3222
|
+
headersToSign["x-amz-security-token"] = input.credentials.sessionToken;
|
|
3223
|
+
}
|
|
3224
|
+
return headersToSign;
|
|
3225
|
+
}
|
|
3226
|
+
function buildCanonicalHeaderEntries(headersToSign) {
|
|
3227
|
+
return Object.entries(headersToSign).map(([headerName, headerValue]) => [
|
|
3228
|
+
headerName.toLowerCase(),
|
|
3229
|
+
headerValue.trim().replace(/\s+/g, " ")
|
|
3230
|
+
]).sort(([leftName], [rightName]) => leftName.localeCompare(rightName));
|
|
3231
|
+
}
|
|
3232
|
+
async function buildCanonicalRequest(input, canonicalHeaderEntries, signedHeaderNames) {
|
|
3233
|
+
const canonicalHeadersText = canonicalHeaderEntries.map(([headerName, headerValue]) => `${headerName}:${headerValue}`).join("\n");
|
|
3234
|
+
return [
|
|
3235
|
+
input.method.toUpperCase(),
|
|
3236
|
+
buildCanonicalUri(input.url.pathname),
|
|
3237
|
+
buildCanonicalQueryString(input.url.searchParams),
|
|
3238
|
+
`${canonicalHeadersText}
|
|
3239
|
+
`,
|
|
3240
|
+
signedHeaderNames,
|
|
3241
|
+
await hashSha256Hex(input.bodyText)
|
|
3242
|
+
].join("\n");
|
|
3243
|
+
}
|
|
3244
|
+
function buildCanonicalUri(pathname) {
|
|
3245
|
+
if (pathname.length === 0) {
|
|
3246
|
+
return "/";
|
|
3247
|
+
}
|
|
3248
|
+
return pathname.split("/").map(encodeRfc3986UriComponent).join("/");
|
|
3249
|
+
}
|
|
3250
|
+
function buildCanonicalQueryString(searchParams) {
|
|
3251
|
+
const encodedEntries = [];
|
|
3252
|
+
searchParams.forEach((parameterValue, parameterName) => {
|
|
3253
|
+
encodedEntries.push([
|
|
3254
|
+
encodeRfc3986UriComponent(parameterName),
|
|
3255
|
+
encodeRfc3986UriComponent(parameterValue)
|
|
3256
|
+
]);
|
|
3257
|
+
});
|
|
3258
|
+
return encodedEntries.sort(
|
|
3259
|
+
([leftName, leftValue], [rightName, rightValue]) => leftName.localeCompare(rightName) || leftValue.localeCompare(rightValue)
|
|
3260
|
+
).map(([parameterName, parameterValue]) => `${parameterName}=${parameterValue}`).join("&");
|
|
3261
|
+
}
|
|
3262
|
+
function encodeRfc3986UriComponent(value) {
|
|
3263
|
+
return encodeURIComponent(value).replace(
|
|
3264
|
+
/[!'()*]/g,
|
|
3265
|
+
(character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`
|
|
3266
|
+
);
|
|
3267
|
+
}
|
|
3268
|
+
function formatAmzDateTime(date) {
|
|
3269
|
+
return date.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
|
|
3270
|
+
}
|
|
3271
|
+
async function deriveAwsSigningKey(secretAccessKey, dateStamp, region, service) {
|
|
3272
|
+
const dateKey = await computeHmacSha256(
|
|
3273
|
+
new TextEncoder().encode(`AWS4${secretAccessKey}`),
|
|
3274
|
+
dateStamp
|
|
3275
|
+
);
|
|
3276
|
+
const regionKey = await computeHmacSha256(dateKey, region);
|
|
3277
|
+
const serviceKey = await computeHmacSha256(regionKey, service);
|
|
3278
|
+
return await computeHmacSha256(serviceKey, "aws4_request");
|
|
3279
|
+
}
|
|
3280
|
+
async function hashSha256Hex(text) {
|
|
3281
|
+
const digest = await crypto.subtle.digest(
|
|
3282
|
+
"SHA-256",
|
|
3283
|
+
new TextEncoder().encode(text)
|
|
3284
|
+
);
|
|
3285
|
+
return bytesToHex(new Uint8Array(digest));
|
|
3286
|
+
}
|
|
3287
|
+
async function computeHmacSha256(keyBytes, text) {
|
|
3288
|
+
const hmacKey = await crypto.subtle.importKey(
|
|
3289
|
+
"raw",
|
|
3290
|
+
keyBytes,
|
|
3291
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
3292
|
+
false,
|
|
3293
|
+
["sign"]
|
|
3294
|
+
);
|
|
3295
|
+
const signature = await crypto.subtle.sign(
|
|
3296
|
+
"HMAC",
|
|
3297
|
+
hmacKey,
|
|
3298
|
+
new TextEncoder().encode(text)
|
|
3299
|
+
);
|
|
3300
|
+
return new Uint8Array(signature);
|
|
3301
|
+
}
|
|
3302
|
+
function bytesToHex(bytes) {
|
|
3303
|
+
return Array.from(bytes).map((byteValue) => byteValue.toString(16).padStart(2, "0")).join("");
|
|
3304
|
+
}
|
|
3305
|
+
|
|
3306
|
+
// src/bedrock-adapter.ts
|
|
3307
|
+
var bedrockAnthropicVersion = "bedrock-2023-05-31";
|
|
3308
|
+
var defaultBedrockMaxOutputTokens = 1024;
|
|
3309
|
+
var bedrockSigningServiceName = "bedrock";
|
|
3310
|
+
var bedrockModelPlaceholder = "bedrock-invoke-model";
|
|
3311
|
+
var BedrockEnvCredentialsSchema = import_zod11.z.object({
|
|
3312
|
+
AWS_ACCESS_KEY_ID: import_zod11.z.string().optional(),
|
|
3313
|
+
AWS_SECRET_ACCESS_KEY: import_zod11.z.string().optional(),
|
|
3314
|
+
AWS_SESSION_TOKEN: import_zod11.z.string().optional()
|
|
3315
|
+
});
|
|
3316
|
+
function bedrock(options) {
|
|
3317
|
+
return {
|
|
3318
|
+
name: `bedrock:${options.modelId}`,
|
|
3319
|
+
async generateChatCompletion(request) {
|
|
3320
|
+
return await executeBedrockAdapterCall(options, {
|
|
3321
|
+
messages: request.messages,
|
|
3322
|
+
temperature: request.temperature ?? options.temperature,
|
|
3323
|
+
maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
|
|
3324
|
+
tools: request.tools,
|
|
3325
|
+
toolChoice: request.toolChoice,
|
|
3326
|
+
abortSignal: request.abortSignal,
|
|
3327
|
+
extraBody: request.extraBody
|
|
3328
|
+
});
|
|
3329
|
+
},
|
|
3330
|
+
async generateStructuredOutput(request) {
|
|
3331
|
+
const completion = await executeBedrockAdapterCall(options, {
|
|
3332
|
+
messages: [
|
|
3333
|
+
buildBedrockStructuredOutputSystemMessage(request.schema),
|
|
3334
|
+
...request.messages
|
|
3335
|
+
],
|
|
3336
|
+
temperature: request.temperature ?? options.temperature,
|
|
3337
|
+
maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
|
|
3338
|
+
abortSignal: request.abortSignal
|
|
3339
|
+
});
|
|
3340
|
+
return {
|
|
3341
|
+
value: parseStructuredJsonText(completion.content, request.schema),
|
|
3342
|
+
tokenUsage: completion.tokenUsage,
|
|
3343
|
+
latencyMs: completion.latencyMs
|
|
3344
|
+
};
|
|
3345
|
+
}
|
|
3346
|
+
};
|
|
3347
|
+
}
|
|
3348
|
+
function buildBedrockInvokeModelUrl(region, modelId) {
|
|
3349
|
+
return `https://bedrock-runtime.${region}.amazonaws.com/model/${encodeURIComponent(modelId)}/invoke`;
|
|
3350
|
+
}
|
|
3351
|
+
function resolveBedrockCredentials(options) {
|
|
3352
|
+
if (options.credentials !== void 0) {
|
|
3353
|
+
return options.credentials;
|
|
3354
|
+
}
|
|
3355
|
+
const parsedEnv = BedrockEnvCredentialsSchema.parse(process.env);
|
|
3356
|
+
const accessKeyId = parsedEnv.AWS_ACCESS_KEY_ID;
|
|
3357
|
+
const secretAccessKey = parsedEnv.AWS_SECRET_ACCESS_KEY;
|
|
3358
|
+
if (accessKeyId === void 0 || accessKeyId.length === 0 || secretAccessKey === void 0 || secretAccessKey.length === 0) {
|
|
3359
|
+
throw new import_errors35.AppError({
|
|
3360
|
+
code: import_errors34.AppErrorCode.Unauthorized,
|
|
3361
|
+
message: "AWS credentials are missing. Pass credentials to bedrock() or set the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables.",
|
|
3362
|
+
statusCode: 401
|
|
3363
|
+
});
|
|
3364
|
+
}
|
|
3365
|
+
const credentials = { accessKeyId, secretAccessKey };
|
|
3366
|
+
const sessionToken = parsedEnv.AWS_SESSION_TOKEN;
|
|
3367
|
+
if (sessionToken !== void 0 && sessionToken.length > 0) {
|
|
3368
|
+
credentials.sessionToken = sessionToken;
|
|
3369
|
+
}
|
|
3370
|
+
return credentials;
|
|
3371
|
+
}
|
|
3372
|
+
async function executeBedrockAdapterCall(options, input) {
|
|
3373
|
+
return await executeProviderCallWithRetry(
|
|
3374
|
+
options.retry,
|
|
3375
|
+
async () => await requestBedrockInvokeModel(options, input)
|
|
3376
|
+
);
|
|
3377
|
+
}
|
|
3378
|
+
async function requestBedrockInvokeModel(options, input) {
|
|
3379
|
+
const credentials = resolveBedrockCredentials(options);
|
|
3380
|
+
const fetchImplementation = options.fetchImplementation ?? fetch;
|
|
3381
|
+
const requestBody = mergeProviderRequestExtraBody(
|
|
3382
|
+
buildBedrockInvokeModelRequestBody(input),
|
|
3383
|
+
options.extraBody,
|
|
3384
|
+
input.extraBody
|
|
3385
|
+
);
|
|
3386
|
+
const bodyText = JSON.stringify(requestBody);
|
|
3387
|
+
const url = new URL(buildBedrockInvokeModelUrl(options.region, options.modelId));
|
|
3388
|
+
const signedHeaders = await signAwsRequestWithSigV4({
|
|
3389
|
+
method: "POST",
|
|
3390
|
+
url,
|
|
3391
|
+
headers: { "content-type": "application/json" },
|
|
3392
|
+
bodyText,
|
|
3393
|
+
region: options.region,
|
|
3394
|
+
service: bedrockSigningServiceName,
|
|
3395
|
+
credentials
|
|
3396
|
+
});
|
|
3397
|
+
const startedAt = Date.now();
|
|
3398
|
+
const response = await executeAbortableProviderFetch(
|
|
3399
|
+
"Bedrock",
|
|
3400
|
+
async () => await fetchImplementation(url.toString(), {
|
|
3401
|
+
method: "POST",
|
|
3402
|
+
headers: signedHeaders,
|
|
3403
|
+
body: bodyText,
|
|
3404
|
+
signal: input.abortSignal
|
|
3405
|
+
})
|
|
3406
|
+
);
|
|
3407
|
+
const latencyMs = Date.now() - startedAt;
|
|
3408
|
+
if (!response.ok) {
|
|
3409
|
+
throw buildProviderStatusError("Bedrock", response.status);
|
|
3410
|
+
}
|
|
3411
|
+
const parseResult = AnthropicMessagesResponseSchema.safeParse(
|
|
3412
|
+
await response.json()
|
|
3413
|
+
);
|
|
3414
|
+
if (!parseResult.success) {
|
|
3415
|
+
throw buildProviderInvalidResponseError("Bedrock", "invoke model");
|
|
3416
|
+
}
|
|
3417
|
+
return mapAnthropicResponseToChatCompletionResult(parseResult.data, latencyMs);
|
|
3418
|
+
}
|
|
3419
|
+
function buildBedrockInvokeModelRequestBody(input) {
|
|
3420
|
+
const anthropicRequestBody = buildAnthropicRequestBody(
|
|
3421
|
+
{
|
|
3422
|
+
model: bedrockModelPlaceholder,
|
|
3423
|
+
defaultMaxOutputTokens: defaultBedrockMaxOutputTokens
|
|
3424
|
+
},
|
|
3425
|
+
input
|
|
3426
|
+
);
|
|
3427
|
+
const {
|
|
3428
|
+
model: ignoredModel,
|
|
3429
|
+
stream: ignoredStream,
|
|
3430
|
+
...requestBodyWithoutModel
|
|
3431
|
+
} = anthropicRequestBody;
|
|
3432
|
+
void ignoredModel;
|
|
3433
|
+
void ignoredStream;
|
|
3434
|
+
return {
|
|
3435
|
+
...requestBodyWithoutModel,
|
|
3436
|
+
anthropic_version: bedrockAnthropicVersion
|
|
3437
|
+
};
|
|
3438
|
+
}
|
|
3439
|
+
function buildBedrockStructuredOutputSystemMessage(schema) {
|
|
3440
|
+
if (!isZodV4Schema(schema)) {
|
|
3441
|
+
return structuredOutputJsonOnlySystemMessage;
|
|
3442
|
+
}
|
|
3443
|
+
return {
|
|
3444
|
+
role: "system",
|
|
3445
|
+
content: `Respond with a single JSON object that satisfies the following JSON Schema. Output only valid JSON with no surrounding text.
|
|
3446
|
+
|
|
3447
|
+
JSON Schema:
|
|
3448
|
+
${JSON.stringify(convertZodSchemaToJsonSchema(schema))}`
|
|
3449
|
+
};
|
|
3450
|
+
}
|
|
2221
3451
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2222
3452
|
0 && (module.exports = {
|
|
2223
3453
|
AnthropicMessagesResponseSchema,
|
|
2224
3454
|
AnthropicStreamEventSchema,
|
|
3455
|
+
AzureOpenAiChatCompletionResponseSchema,
|
|
2225
3456
|
ChatMessageCacheControlSchema,
|
|
2226
3457
|
ChatMessageRoleSchema,
|
|
2227
3458
|
ChatMessageSchema,
|
|
@@ -2232,16 +3463,30 @@ function buildAnthropicBatchTimeoutError(batchId, timeoutMs) {
|
|
|
2232
3463
|
anthropicBatchJsonOnlySystemInstruction,
|
|
2233
3464
|
anthropicBatchTraceWorkflowName,
|
|
2234
3465
|
applyCacheControlToLastContentBlock,
|
|
3466
|
+
awsSigV4Algorithm,
|
|
3467
|
+
azureOpenai,
|
|
3468
|
+
bedrock,
|
|
3469
|
+
bedrockAnthropicVersion,
|
|
2235
3470
|
buildAnthropicCacheControl,
|
|
2236
3471
|
buildAnthropicRequestBody,
|
|
3472
|
+
buildAnthropicStructuredOutputJsonSchema,
|
|
3473
|
+
buildAzureOpenAiChatCompletionsUrl,
|
|
3474
|
+
buildAzureOpenAiChatRequestBody,
|
|
3475
|
+
buildBedrockInvokeModelRequestBody,
|
|
3476
|
+
buildBedrockInvokeModelUrl,
|
|
3477
|
+
buildGeminiResponseSchema,
|
|
2237
3478
|
buildOpenAiRequestBody,
|
|
3479
|
+
buildOpenAiStructuredOutputJsonSchema,
|
|
2238
3480
|
buildProviderCanceledError,
|
|
2239
3481
|
calculateProviderRetryDelayMs,
|
|
3482
|
+
convertZodSchemaToJsonSchema,
|
|
2240
3483
|
createAnthropicBatchClient,
|
|
2241
3484
|
defaultAnthropicBaseUrl,
|
|
2242
3485
|
defaultAnthropicBatchPollIntervalMs,
|
|
2243
3486
|
defaultAnthropicBatchTimeoutMs,
|
|
2244
3487
|
defaultAnthropicMaxOutputTokens,
|
|
3488
|
+
defaultAzureOpenAiApiVersion,
|
|
3489
|
+
defaultBedrockMaxOutputTokens,
|
|
2245
3490
|
defaultGeminiBaseUrl,
|
|
2246
3491
|
defaultOpenAiBaseUrl,
|
|
2247
3492
|
defaultProviderRetryInitialDelayMs,
|
|
@@ -2252,14 +3497,19 @@ function buildAnthropicBatchTimeoutError(batchId, timeoutMs) {
|
|
|
2252
3497
|
executeProviderCallWithModelFallback,
|
|
2253
3498
|
executeProviderCallWithRetry,
|
|
2254
3499
|
extractAnthropicTextContent,
|
|
3500
|
+
extractAnthropicThinkingText,
|
|
2255
3501
|
extractAnthropicToolCalls,
|
|
2256
3502
|
extractMessageText,
|
|
2257
3503
|
gemini,
|
|
2258
3504
|
isAbortError,
|
|
3505
|
+
isOpenAiReasoningModel,
|
|
2259
3506
|
isRetryableProviderAppError,
|
|
3507
|
+
isZodV4Schema,
|
|
2260
3508
|
joinSystemMessageText,
|
|
2261
3509
|
mapAnthropicResponseToChatCompletionResult,
|
|
2262
3510
|
mapAnthropicUsageToTokenUsage,
|
|
3511
|
+
mapAzureOpenAiResponseToChatCompletionResult,
|
|
3512
|
+
mapAzureOpenAiUsageToTokenUsage,
|
|
2263
3513
|
mapChatMessageToAnthropicRequestMessage,
|
|
2264
3514
|
mapChatMessageToOpenAiRequestMessage,
|
|
2265
3515
|
mapModelToolChoiceToAnthropicToolChoice,
|
|
@@ -2269,11 +3519,25 @@ function buildAnthropicBatchTimeoutError(batchId, timeoutMs) {
|
|
|
2269
3519
|
mergeProviderRequestExtraBody,
|
|
2270
3520
|
mockModel,
|
|
2271
3521
|
normalizeAnthropicStopReason,
|
|
3522
|
+
normalizeAzureOpenAiFinishReason,
|
|
3523
|
+
openAiStructuredOutputSchemaName,
|
|
2272
3524
|
openai,
|
|
2273
3525
|
parseAnthropicBatchStructuredContent,
|
|
2274
3526
|
parseAnthropicStreamEvents,
|
|
2275
3527
|
parseAnthropicToolInputJson,
|
|
3528
|
+
parseAzureOpenAiStreamEvents,
|
|
3529
|
+
parseAzureOpenAiToolArgumentsJson,
|
|
3530
|
+
prependStructuredOutputJsonOnlySystemMessage,
|
|
2276
3531
|
resolveAnthropicPromptCachingSettings,
|
|
3532
|
+
resolveBedrockCredentials,
|
|
3533
|
+
resolveOpenAiStructuredOutputMode,
|
|
2277
3534
|
resolveProviderApiKey,
|
|
2278
|
-
|
|
3535
|
+
sanitizeJsonSchemaForAnthropicStructuredOutput,
|
|
3536
|
+
sanitizeJsonSchemaForGeminiResponseSchema,
|
|
3537
|
+
sanitizeJsonSchemaForOpenAiStructuredOutput,
|
|
3538
|
+
signAwsRequestWithSigV4,
|
|
3539
|
+
streamAnthropicChatCompletion,
|
|
3540
|
+
streamAzureOpenAiChatCompletion,
|
|
3541
|
+
structuredOutputJsonOnlySystemInstruction,
|
|
3542
|
+
structuredOutputJsonOnlySystemMessage
|
|
2279
3543
|
});
|