@assemble-dev/providers 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +361 -71
- package/dist/index.d.cts +94 -15
- package/dist/index.d.ts +94 -15
- package/dist/index.js +356 -71
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -28,12 +28,16 @@ var ModelToolCallSchema = z.object({
|
|
|
28
28
|
toolName: z.string(),
|
|
29
29
|
input: JsonValueSchema
|
|
30
30
|
});
|
|
31
|
+
var ChatMessageCacheControlSchema = z.object({
|
|
32
|
+
ttl: z.enum(["5m", "1h"]).optional()
|
|
33
|
+
});
|
|
31
34
|
var ChatMessageSchema = z.object({
|
|
32
35
|
role: ChatMessageRoleSchema,
|
|
33
36
|
content: z.union([z.string(), z.array(MessageContentBlockSchema)]),
|
|
34
37
|
toolName: z.string().optional(),
|
|
35
38
|
toolCallId: z.string().optional(),
|
|
36
|
-
toolCalls: z.array(ModelToolCallSchema).optional()
|
|
39
|
+
toolCalls: z.array(ModelToolCallSchema).optional(),
|
|
40
|
+
cacheControl: ChatMessageCacheControlSchema.optional()
|
|
37
41
|
});
|
|
38
42
|
var ChatStopReasonSchema = z.enum([
|
|
39
43
|
"end_turn",
|
|
@@ -267,6 +271,15 @@ async function executeAbortableProviderFetch(providerLabel, performFetch) {
|
|
|
267
271
|
}
|
|
268
272
|
}
|
|
269
273
|
|
|
274
|
+
// src/provider-extra-body.ts
|
|
275
|
+
function mergeProviderRequestExtraBody(requestBody, adapterExtraBody, requestExtraBody) {
|
|
276
|
+
return {
|
|
277
|
+
...requestBody,
|
|
278
|
+
...adapterExtraBody ?? {},
|
|
279
|
+
...requestExtraBody ?? {}
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
|
|
270
283
|
// src/provider-fallback.ts
|
|
271
284
|
import { AppError as AppError6 } from "@assemble-dev/shared-utils/errors";
|
|
272
285
|
|
|
@@ -434,7 +447,8 @@ function openai(options) {
|
|
|
434
447
|
requireJsonObjectResponse: false,
|
|
435
448
|
tools: request.tools,
|
|
436
449
|
toolChoice: request.toolChoice,
|
|
437
|
-
abortSignal: request.abortSignal
|
|
450
|
+
abortSignal: request.abortSignal,
|
|
451
|
+
extraBody: request.extraBody
|
|
438
452
|
});
|
|
439
453
|
},
|
|
440
454
|
async generateStructuredOutput(request) {
|
|
@@ -476,7 +490,11 @@ async function requestOpenAiChatCompletion(options, input) {
|
|
|
476
490
|
});
|
|
477
491
|
const fetchImplementation = options.fetchImplementation ?? fetch;
|
|
478
492
|
const baseUrl = options.baseURL ?? defaultOpenAiBaseUrl;
|
|
479
|
-
const requestBody =
|
|
493
|
+
const requestBody = mergeProviderRequestExtraBody(
|
|
494
|
+
buildOpenAiRequestBody(options.model, input),
|
|
495
|
+
options.extraBody,
|
|
496
|
+
input.extraBody
|
|
497
|
+
);
|
|
480
498
|
const startedAt = Date.now();
|
|
481
499
|
const response = await executeAbortableProviderFetch(
|
|
482
500
|
"OpenAI",
|
|
@@ -572,6 +590,36 @@ function mapOpenAiUsageToTokenUsage(response) {
|
|
|
572
590
|
};
|
|
573
591
|
}
|
|
574
592
|
|
|
593
|
+
// src/anthropic-cache-control.ts
|
|
594
|
+
function resolveAnthropicPromptCachingSettings(promptCaching) {
|
|
595
|
+
if (promptCaching === void 0) {
|
|
596
|
+
return { mode: "off" };
|
|
597
|
+
}
|
|
598
|
+
if (typeof promptCaching === "string") {
|
|
599
|
+
return { mode: promptCaching };
|
|
600
|
+
}
|
|
601
|
+
return promptCaching;
|
|
602
|
+
}
|
|
603
|
+
function buildAnthropicCacheControl(ttl) {
|
|
604
|
+
if (ttl === void 0) {
|
|
605
|
+
return { type: "ephemeral" };
|
|
606
|
+
}
|
|
607
|
+
return { type: "ephemeral", ttl };
|
|
608
|
+
}
|
|
609
|
+
function applyCacheControlToLastContentBlock(requestMessage, cacheControl) {
|
|
610
|
+
if (typeof requestMessage.content === "string") {
|
|
611
|
+
if (requestMessage.content.length === 0) {
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
requestMessage.content = [{ type: "text", text: requestMessage.content }];
|
|
615
|
+
}
|
|
616
|
+
const lastContentBlock = requestMessage.content[requestMessage.content.length - 1];
|
|
617
|
+
if (lastContentBlock === void 0) {
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
lastContentBlock.cache_control = cacheControl;
|
|
621
|
+
}
|
|
622
|
+
|
|
575
623
|
// src/anthropic-request-mapping.ts
|
|
576
624
|
function buildAnthropicRequestBody(settings, input) {
|
|
577
625
|
const requestBody = {
|
|
@@ -581,6 +629,7 @@ function buildAnthropicRequestBody(settings, input) {
|
|
|
581
629
|
};
|
|
582
630
|
applyAnthropicSystemField(requestBody, settings, input);
|
|
583
631
|
applyAnthropicToolFields(requestBody, settings, input);
|
|
632
|
+
applyAnthropicMessageCacheBreakpoints(requestBody, settings, input);
|
|
584
633
|
if (input.temperature !== void 0) {
|
|
585
634
|
requestBody.temperature = input.temperature;
|
|
586
635
|
}
|
|
@@ -593,18 +642,46 @@ function buildAnthropicRequestBody(settings, input) {
|
|
|
593
642
|
return requestBody;
|
|
594
643
|
}
|
|
595
644
|
function applyAnthropicSystemField(requestBody, settings, input) {
|
|
645
|
+
const caching = resolveAnthropicPromptCachingSettings(settings.promptCaching);
|
|
596
646
|
const systemText = joinSystemMessageText(input.messages);
|
|
597
647
|
if (systemText.length === 0) {
|
|
598
648
|
return;
|
|
599
649
|
}
|
|
600
|
-
if (
|
|
650
|
+
if (caching.mode === "off") {
|
|
601
651
|
requestBody.system = systemText;
|
|
602
652
|
return;
|
|
603
653
|
}
|
|
604
654
|
requestBody.system = [
|
|
605
|
-
{
|
|
655
|
+
{
|
|
656
|
+
type: "text",
|
|
657
|
+
text: systemText,
|
|
658
|
+
cache_control: buildAnthropicCacheControl(caching.ttl)
|
|
659
|
+
}
|
|
606
660
|
];
|
|
607
661
|
}
|
|
662
|
+
function applyAnthropicMessageCacheBreakpoints(requestBody, settings, input) {
|
|
663
|
+
const caching = resolveAnthropicPromptCachingSettings(settings.promptCaching);
|
|
664
|
+
const finalRequestMessage = requestBody.messages[requestBody.messages.length - 1];
|
|
665
|
+
if (caching.mode === "messages" && finalRequestMessage !== void 0) {
|
|
666
|
+
applyCacheControlToLastContentBlock(
|
|
667
|
+
finalRequestMessage,
|
|
668
|
+
buildAnthropicCacheControl(caching.ttl)
|
|
669
|
+
);
|
|
670
|
+
}
|
|
671
|
+
const nonSystemMessages = input.messages.filter(
|
|
672
|
+
(message) => message.role !== "system"
|
|
673
|
+
);
|
|
674
|
+
nonSystemMessages.forEach((message, messageIndex) => {
|
|
675
|
+
const requestMessage = requestBody.messages[messageIndex];
|
|
676
|
+
if (message.cacheControl === void 0 || requestMessage === void 0) {
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
applyCacheControlToLastContentBlock(
|
|
680
|
+
requestMessage,
|
|
681
|
+
buildAnthropicCacheControl(message.cacheControl.ttl ?? caching.ttl)
|
|
682
|
+
);
|
|
683
|
+
});
|
|
684
|
+
}
|
|
608
685
|
function applyAnthropicToolFields(requestBody, settings, input) {
|
|
609
686
|
if (input.tools !== void 0 && input.tools.length > 0) {
|
|
610
687
|
requestBody.tools = mapModelToolDefinitionsToAnthropicTools(
|
|
@@ -619,14 +696,15 @@ function applyAnthropicToolFields(requestBody, settings, input) {
|
|
|
619
696
|
}
|
|
620
697
|
}
|
|
621
698
|
function mapModelToolDefinitionsToAnthropicTools(tools, promptCaching) {
|
|
699
|
+
const caching = resolveAnthropicPromptCachingSettings(promptCaching);
|
|
622
700
|
return tools.map((tool, toolIndex) => {
|
|
623
701
|
const anthropicTool = {
|
|
624
702
|
name: tool.name,
|
|
625
703
|
description: tool.description,
|
|
626
704
|
input_schema: tool.inputJsonSchema
|
|
627
705
|
};
|
|
628
|
-
if (
|
|
629
|
-
anthropicTool.cache_control =
|
|
706
|
+
if (caching.mode !== "off" && toolIndex === tools.length - 1) {
|
|
707
|
+
anthropicTool.cache_control = buildAnthropicCacheControl(caching.ttl);
|
|
630
708
|
}
|
|
631
709
|
return anthropicTool;
|
|
632
710
|
});
|
|
@@ -1131,7 +1209,8 @@ function buildAnthropicCallInput(options, request) {
|
|
|
1131
1209
|
maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
|
|
1132
1210
|
tools: request.tools,
|
|
1133
1211
|
toolChoice: request.toolChoice,
|
|
1134
|
-
abortSignal: request.abortSignal
|
|
1212
|
+
abortSignal: request.abortSignal,
|
|
1213
|
+
extraBody: request.extraBody
|
|
1135
1214
|
};
|
|
1136
1215
|
}
|
|
1137
1216
|
async function executeAnthropicAdapterCall(options, input) {
|
|
@@ -1148,9 +1227,10 @@ async function executeAnthropicAdapterCall(options, input) {
|
|
|
1148
1227
|
);
|
|
1149
1228
|
}
|
|
1150
1229
|
async function requestAnthropicMessages(options, input) {
|
|
1151
|
-
const requestBody =
|
|
1152
|
-
buildAnthropicRequestSettings(options),
|
|
1153
|
-
|
|
1230
|
+
const requestBody = mergeProviderRequestExtraBody(
|
|
1231
|
+
buildAnthropicRequestBody(buildAnthropicRequestSettings(options), input),
|
|
1232
|
+
options.extraBody,
|
|
1233
|
+
input.extraBody
|
|
1154
1234
|
);
|
|
1155
1235
|
const startedAt = Date.now();
|
|
1156
1236
|
const response = await executeAbortableProviderFetch(
|
|
@@ -1179,9 +1259,10 @@ async function requestAnthropicMessages(options, input) {
|
|
|
1179
1259
|
}
|
|
1180
1260
|
function buildAnthropicStreamInput(options, request) {
|
|
1181
1261
|
const input = buildAnthropicCallInput(options, request);
|
|
1182
|
-
const requestBody =
|
|
1183
|
-
buildAnthropicRequestSettings(options),
|
|
1184
|
-
|
|
1262
|
+
const requestBody = mergeProviderRequestExtraBody(
|
|
1263
|
+
buildAnthropicRequestBody(buildAnthropicRequestSettings(options), input),
|
|
1264
|
+
options.extraBody,
|
|
1265
|
+
input.extraBody
|
|
1185
1266
|
);
|
|
1186
1267
|
return {
|
|
1187
1268
|
url: `${resolveAnthropicBaseUrl(options)}/v1/messages`,
|
|
@@ -1253,7 +1334,8 @@ function gemini(options) {
|
|
|
1253
1334
|
temperature: request.temperature ?? options.temperature,
|
|
1254
1335
|
maxOutputTokens: request.maxOutputTokens ?? options.maxOutputTokens,
|
|
1255
1336
|
requireJsonResponse: false,
|
|
1256
|
-
abortSignal: request.abortSignal
|
|
1337
|
+
abortSignal: request.abortSignal,
|
|
1338
|
+
extraBody: request.extraBody
|
|
1257
1339
|
});
|
|
1258
1340
|
},
|
|
1259
1341
|
async generateStructuredOutput(request) {
|
|
@@ -1295,7 +1377,11 @@ async function requestGeminiGenerateContent(options, input) {
|
|
|
1295
1377
|
});
|
|
1296
1378
|
const fetchImplementation = options.fetchImplementation ?? fetch;
|
|
1297
1379
|
const baseUrl = options.baseURL ?? defaultGeminiBaseUrl;
|
|
1298
|
-
const requestBody =
|
|
1380
|
+
const requestBody = mergeProviderRequestExtraBody(
|
|
1381
|
+
buildGeminiRequestBody(input),
|
|
1382
|
+
options.extraBody,
|
|
1383
|
+
input.extraBody
|
|
1384
|
+
);
|
|
1299
1385
|
const requestUrl = `${baseUrl}/v1beta/models/${options.model}:generateContent`;
|
|
1300
1386
|
const startedAt = Date.now();
|
|
1301
1387
|
const response = await executeAbortableProviderFetch(
|
|
@@ -1583,9 +1669,212 @@ function calculateModelCallCostUsd(pricing, tokenUsage) {
|
|
|
1583
1669
|
}
|
|
1584
1670
|
|
|
1585
1671
|
// src/anthropic-batch.ts
|
|
1672
|
+
import { AppErrorCode as AppErrorCode13 } from "@assemble-dev/shared-types/errors";
|
|
1673
|
+
import { JsonValueSchema as JsonValueSchema7 } from "@assemble-dev/shared-types/json";
|
|
1674
|
+
import { AppError as AppError14 } from "@assemble-dev/shared-utils/errors";
|
|
1675
|
+
|
|
1676
|
+
// src/anthropic-batch-structured.ts
|
|
1586
1677
|
import { AppErrorCode as AppErrorCode12 } from "@assemble-dev/shared-types/errors";
|
|
1587
1678
|
import { JsonValueSchema as JsonValueSchema6 } from "@assemble-dev/shared-types/json";
|
|
1588
1679
|
import { AppError as AppError13 } from "@assemble-dev/shared-utils/errors";
|
|
1680
|
+
var anthropicBatchJsonOnlySystemInstruction = "Respond with a single JSON object that satisfies the caller's requested structure. Output only valid JSON with no surrounding text.";
|
|
1681
|
+
function parseAnthropicBatchStructuredContent(content, schema) {
|
|
1682
|
+
const jsonValue = parseStructuredJsonText(
|
|
1683
|
+
content,
|
|
1684
|
+
JsonValueSchema6
|
|
1685
|
+
);
|
|
1686
|
+
const validationResult = schema.safeParse(jsonValue);
|
|
1687
|
+
if (!validationResult.success) {
|
|
1688
|
+
throw new AppError13({
|
|
1689
|
+
code: AppErrorCode12.ValidationFailed,
|
|
1690
|
+
message: "Anthropic batch structured output did not match the expected schema",
|
|
1691
|
+
statusCode: 422,
|
|
1692
|
+
details: { validationErrorMessage: validationResult.error.message }
|
|
1693
|
+
});
|
|
1694
|
+
}
|
|
1695
|
+
return validationResult.data;
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
// src/anthropic-batch-request.ts
|
|
1699
|
+
function mapBatchMessageRequestToApiBatchRequest(request) {
|
|
1700
|
+
const params = {
|
|
1701
|
+
model: request.model,
|
|
1702
|
+
max_tokens: request.maxOutputTokens ?? defaultAnthropicMaxOutputTokens,
|
|
1703
|
+
messages: request.messages.filter((message) => message.role !== "system").map(mapChatMessageToBatchApiRequestMessage)
|
|
1704
|
+
};
|
|
1705
|
+
applyBatchSystemField(params, request);
|
|
1706
|
+
if (request.temperature !== void 0) {
|
|
1707
|
+
params.temperature = request.temperature;
|
|
1708
|
+
}
|
|
1709
|
+
return { custom_id: request.customId, params };
|
|
1710
|
+
}
|
|
1711
|
+
function applyBatchSystemField(params, request) {
|
|
1712
|
+
const systemText = buildBatchSystemText(request);
|
|
1713
|
+
if (systemText.length === 0) {
|
|
1714
|
+
return;
|
|
1715
|
+
}
|
|
1716
|
+
if (request.promptCaching !== "auto") {
|
|
1717
|
+
params.system = systemText;
|
|
1718
|
+
return;
|
|
1719
|
+
}
|
|
1720
|
+
params.system = [
|
|
1721
|
+
{ type: "text", text: systemText, cache_control: { type: "ephemeral" } }
|
|
1722
|
+
];
|
|
1723
|
+
}
|
|
1724
|
+
function buildBatchSystemText(request) {
|
|
1725
|
+
const joinedSystemText = joinBatchSystemMessageText(request.messages);
|
|
1726
|
+
if (request.requireJsonResponse !== true) {
|
|
1727
|
+
return joinedSystemText;
|
|
1728
|
+
}
|
|
1729
|
+
if (joinedSystemText.length === 0) {
|
|
1730
|
+
return anthropicBatchJsonOnlySystemInstruction;
|
|
1731
|
+
}
|
|
1732
|
+
return `${anthropicBatchJsonOnlySystemInstruction}
|
|
1733
|
+
|
|
1734
|
+
${joinedSystemText}`;
|
|
1735
|
+
}
|
|
1736
|
+
function joinBatchSystemMessageText(messages) {
|
|
1737
|
+
return messages.filter((message) => message.role === "system").map(extractMessageText).join("\n\n");
|
|
1738
|
+
}
|
|
1739
|
+
function mapChatMessageToBatchApiRequestMessage(message) {
|
|
1740
|
+
if (message.role === "assistant") {
|
|
1741
|
+
return { role: "assistant", content: extractMessageText(message) };
|
|
1742
|
+
}
|
|
1743
|
+
if (message.role === "tool") {
|
|
1744
|
+
return { role: "user", content: buildBatchToolResultText(message) };
|
|
1745
|
+
}
|
|
1746
|
+
return { role: "user", content: extractMessageText(message) };
|
|
1747
|
+
}
|
|
1748
|
+
function buildBatchToolResultText(message) {
|
|
1749
|
+
if (message.toolName === void 0) {
|
|
1750
|
+
return `Tool result: ${extractMessageText(message)}`;
|
|
1751
|
+
}
|
|
1752
|
+
return `Tool result (${message.toolName}): ${extractMessageText(message)}`;
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
// src/anthropic-batch-trace-events.ts
|
|
1756
|
+
import {
|
|
1757
|
+
generateRunId,
|
|
1758
|
+
generateTraceEventId
|
|
1759
|
+
} from "@assemble-dev/shared-utils/ids";
|
|
1760
|
+
var anthropicBatchTraceWorkflowName = "anthropic-message-batch";
|
|
1761
|
+
function createAnthropicBatchTraceEmitter(input) {
|
|
1762
|
+
if (input.onTraceEvent === void 0) {
|
|
1763
|
+
return createNoopAnthropicBatchTraceEmitter();
|
|
1764
|
+
}
|
|
1765
|
+
const onTraceEvent = input.onTraceEvent;
|
|
1766
|
+
const runId = generateRunId();
|
|
1767
|
+
const completedBatchIds = /* @__PURE__ */ new Set();
|
|
1768
|
+
const submittedEventIdByBatchId = /* @__PURE__ */ new Map();
|
|
1769
|
+
const modelByBatchScopedCustomId = /* @__PURE__ */ new Map();
|
|
1770
|
+
function buildBatchTraceEventBase(parentEventId) {
|
|
1771
|
+
return {
|
|
1772
|
+
id: generateTraceEventId(),
|
|
1773
|
+
runId,
|
|
1774
|
+
workflowName: anthropicBatchTraceWorkflowName,
|
|
1775
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1776
|
+
parentEventId,
|
|
1777
|
+
redacted: false
|
|
1778
|
+
};
|
|
1779
|
+
}
|
|
1780
|
+
function stampMetadataOntoEvent(event) {
|
|
1781
|
+
if (input.metadata === void 0) {
|
|
1782
|
+
return event;
|
|
1783
|
+
}
|
|
1784
|
+
return { ...event, metadata: input.metadata };
|
|
1785
|
+
}
|
|
1786
|
+
function emitBatchSubmittedEvent(batch, requestSummaries) {
|
|
1787
|
+
const submittedEvent = {
|
|
1788
|
+
...buildBatchTraceEventBase(null),
|
|
1789
|
+
type: "batch.submitted",
|
|
1790
|
+
batchId: batch.id,
|
|
1791
|
+
requestCount: requestSummaries.length,
|
|
1792
|
+
models: requestSummaries.map((requestSummary) => requestSummary.model)
|
|
1793
|
+
};
|
|
1794
|
+
submittedEventIdByBatchId.set(batch.id, submittedEvent.id);
|
|
1795
|
+
for (const requestSummary of requestSummaries) {
|
|
1796
|
+
modelByBatchScopedCustomId.set(
|
|
1797
|
+
buildBatchScopedCustomIdKey(batch.id, requestSummary.customId),
|
|
1798
|
+
requestSummary.model
|
|
1799
|
+
);
|
|
1800
|
+
}
|
|
1801
|
+
onTraceEvent(stampMetadataOntoEvent(submittedEvent));
|
|
1802
|
+
}
|
|
1803
|
+
function emitBatchCompletedEventOnce(batch) {
|
|
1804
|
+
if (batch.processingStatus !== "ended" || completedBatchIds.has(batch.id)) {
|
|
1805
|
+
return;
|
|
1806
|
+
}
|
|
1807
|
+
completedBatchIds.add(batch.id);
|
|
1808
|
+
const completedEvent = {
|
|
1809
|
+
...buildBatchTraceEventBase(
|
|
1810
|
+
submittedEventIdByBatchId.get(batch.id) ?? null
|
|
1811
|
+
),
|
|
1812
|
+
type: "batch.completed",
|
|
1813
|
+
batchId: batch.id,
|
|
1814
|
+
requestCounts: batch.requestCounts,
|
|
1815
|
+
latencyMs: calculateBatchLatencyMs(batch)
|
|
1816
|
+
};
|
|
1817
|
+
onTraceEvent(stampMetadataOntoEvent(completedEvent));
|
|
1818
|
+
}
|
|
1819
|
+
function emitBatchResultEvent(batchId, result) {
|
|
1820
|
+
const resultEvent = buildBatchResultEvent(
|
|
1821
|
+
buildBatchTraceEventBase(submittedEventIdByBatchId.get(batchId) ?? null),
|
|
1822
|
+
batchId,
|
|
1823
|
+
result,
|
|
1824
|
+
modelByBatchScopedCustomId.get(
|
|
1825
|
+
buildBatchScopedCustomIdKey(batchId, result.customId)
|
|
1826
|
+
)
|
|
1827
|
+
);
|
|
1828
|
+
onTraceEvent(stampMetadataOntoEvent(resultEvent));
|
|
1829
|
+
}
|
|
1830
|
+
return {
|
|
1831
|
+
emitBatchSubmittedEvent,
|
|
1832
|
+
emitBatchCompletedEventOnce,
|
|
1833
|
+
emitBatchResultEvent
|
|
1834
|
+
};
|
|
1835
|
+
}
|
|
1836
|
+
function createNoopAnthropicBatchTraceEmitter() {
|
|
1837
|
+
return {
|
|
1838
|
+
emitBatchSubmittedEvent() {
|
|
1839
|
+
},
|
|
1840
|
+
emitBatchCompletedEventOnce() {
|
|
1841
|
+
},
|
|
1842
|
+
emitBatchResultEvent() {
|
|
1843
|
+
}
|
|
1844
|
+
};
|
|
1845
|
+
}
|
|
1846
|
+
function buildBatchScopedCustomIdKey(batchId, customId) {
|
|
1847
|
+
return `${batchId}:${customId}`;
|
|
1848
|
+
}
|
|
1849
|
+
function calculateBatchLatencyMs(batch) {
|
|
1850
|
+
const createdAtMs = Date.parse(batch.createdAt);
|
|
1851
|
+
const endedAtMs = batch.endedAt === null ? Date.now() : Date.parse(batch.endedAt);
|
|
1852
|
+
if (Number.isNaN(createdAtMs) || Number.isNaN(endedAtMs)) {
|
|
1853
|
+
return 0;
|
|
1854
|
+
}
|
|
1855
|
+
return Math.max(0, endedAtMs - createdAtMs);
|
|
1856
|
+
}
|
|
1857
|
+
function buildBatchResultEvent(eventBase, batchId, result, modelName) {
|
|
1858
|
+
if (result.outcome.type !== "succeeded") {
|
|
1859
|
+
return {
|
|
1860
|
+
...eventBase,
|
|
1861
|
+
type: "batch.result",
|
|
1862
|
+
batchId,
|
|
1863
|
+
customId: result.customId,
|
|
1864
|
+
outcomeType: result.outcome.type,
|
|
1865
|
+
costUsd: null
|
|
1866
|
+
};
|
|
1867
|
+
}
|
|
1868
|
+
return {
|
|
1869
|
+
...eventBase,
|
|
1870
|
+
type: "batch.result",
|
|
1871
|
+
batchId,
|
|
1872
|
+
customId: result.customId,
|
|
1873
|
+
outcomeType: "succeeded",
|
|
1874
|
+
tokenUsage: result.outcome.tokenUsage,
|
|
1875
|
+
costUsd: modelName === void 0 ? null : estimateModelCallCostUsd(modelName, result.outcome.tokenUsage)
|
|
1876
|
+
};
|
|
1877
|
+
}
|
|
1589
1878
|
|
|
1590
1879
|
// src/anthropic-batch-types.ts
|
|
1591
1880
|
import { z as z7 } from "zod";
|
|
@@ -1690,19 +1979,26 @@ var defaultAnthropicBatchPollIntervalMs = 5e3;
|
|
|
1690
1979
|
var defaultAnthropicBatchTimeoutMs = 36e5;
|
|
1691
1980
|
var anthropicBatchApiVersion = "2023-06-01";
|
|
1692
1981
|
function createAnthropicBatchClient(options) {
|
|
1982
|
+
const clientContext = {
|
|
1983
|
+
options,
|
|
1984
|
+
traceEmitter: createAnthropicBatchTraceEmitter({
|
|
1985
|
+
onTraceEvent: options.onTraceEvent,
|
|
1986
|
+
metadata: options.metadata
|
|
1987
|
+
})
|
|
1988
|
+
};
|
|
1693
1989
|
return {
|
|
1694
1990
|
async submitMessageBatch(requests) {
|
|
1695
|
-
return await submitAnthropicMessageBatch(
|
|
1991
|
+
return await submitAnthropicMessageBatch(clientContext, requests);
|
|
1696
1992
|
},
|
|
1697
1993
|
async fetchMessageBatch(batchId) {
|
|
1698
|
-
return await fetchAnthropicMessageBatch(
|
|
1994
|
+
return await fetchAnthropicMessageBatch(clientContext, batchId);
|
|
1699
1995
|
},
|
|
1700
1996
|
async listMessageBatchResults(batchId) {
|
|
1701
|
-
return await listAnthropicMessageBatchResults(
|
|
1997
|
+
return await listAnthropicMessageBatchResults(clientContext, batchId);
|
|
1702
1998
|
},
|
|
1703
1999
|
async waitForMessageBatchCompletion(batchId, waitOptions) {
|
|
1704
2000
|
return await waitForAnthropicMessageBatchCompletion(
|
|
1705
|
-
|
|
2001
|
+
clientContext,
|
|
1706
2002
|
batchId,
|
|
1707
2003
|
waitOptions
|
|
1708
2004
|
);
|
|
@@ -1729,8 +2025,8 @@ function buildAnthropicBatchRequestHeaders(apiKey) {
|
|
|
1729
2025
|
"anthropic-version": anthropicBatchApiVersion
|
|
1730
2026
|
};
|
|
1731
2027
|
}
|
|
1732
|
-
async function submitAnthropicMessageBatch(
|
|
1733
|
-
const context = resolveAnthropicBatchRequestContext(options);
|
|
2028
|
+
async function submitAnthropicMessageBatch(clientContext, requests) {
|
|
2029
|
+
const context = resolveAnthropicBatchRequestContext(clientContext.options);
|
|
1734
2030
|
const response = await context.fetchImplementation(
|
|
1735
2031
|
`${context.baseUrl}/v1/messages/batches`,
|
|
1736
2032
|
{
|
|
@@ -1741,10 +2037,18 @@ async function submitAnthropicMessageBatch(options, requests) {
|
|
|
1741
2037
|
})
|
|
1742
2038
|
}
|
|
1743
2039
|
);
|
|
1744
|
-
|
|
2040
|
+
const batch = await parseAnthropicMessageBatchHttpResponse(response);
|
|
2041
|
+
clientContext.traceEmitter.emitBatchSubmittedEvent(
|
|
2042
|
+
batch,
|
|
2043
|
+
requests.map((request) => ({
|
|
2044
|
+
customId: request.customId,
|
|
2045
|
+
model: request.model
|
|
2046
|
+
}))
|
|
2047
|
+
);
|
|
2048
|
+
return batch;
|
|
1745
2049
|
}
|
|
1746
|
-
async function fetchAnthropicMessageBatch(
|
|
1747
|
-
const context = resolveAnthropicBatchRequestContext(options);
|
|
2050
|
+
async function fetchAnthropicMessageBatch(clientContext, batchId) {
|
|
2051
|
+
const context = resolveAnthropicBatchRequestContext(clientContext.options);
|
|
1748
2052
|
const response = await context.fetchImplementation(
|
|
1749
2053
|
`${context.baseUrl}/v1/messages/batches/${batchId}`,
|
|
1750
2054
|
{
|
|
@@ -1752,7 +2056,9 @@ async function fetchAnthropicMessageBatch(options, batchId) {
|
|
|
1752
2056
|
headers: buildAnthropicBatchRequestHeaders(context.apiKey)
|
|
1753
2057
|
}
|
|
1754
2058
|
);
|
|
1755
|
-
|
|
2059
|
+
const batch = await parseAnthropicMessageBatchHttpResponse(response);
|
|
2060
|
+
clientContext.traceEmitter.emitBatchCompletedEventOnce(batch);
|
|
2061
|
+
return batch;
|
|
1756
2062
|
}
|
|
1757
2063
|
async function parseAnthropicMessageBatchHttpResponse(response) {
|
|
1758
2064
|
if (!response.ok) {
|
|
@@ -1766,17 +2072,17 @@ async function parseAnthropicMessageBatchHttpResponse(response) {
|
|
|
1766
2072
|
}
|
|
1767
2073
|
return mapAnthropicMessageBatchResponseToMessageBatch(parseResult.data);
|
|
1768
2074
|
}
|
|
1769
|
-
async function listAnthropicMessageBatchResults(
|
|
1770
|
-
const batch = await fetchAnthropicMessageBatch(
|
|
2075
|
+
async function listAnthropicMessageBatchResults(clientContext, batchId) {
|
|
2076
|
+
const batch = await fetchAnthropicMessageBatch(clientContext, batchId);
|
|
1771
2077
|
if (batch.resultsUrl === null) {
|
|
1772
|
-
throw new
|
|
1773
|
-
code:
|
|
2078
|
+
throw new AppError14({
|
|
2079
|
+
code: AppErrorCode13.Conflict,
|
|
1774
2080
|
message: `Anthropic message batch ${batchId} has no results because processing has not ended`,
|
|
1775
2081
|
statusCode: 409,
|
|
1776
2082
|
details: { batchId, processingStatus: batch.processingStatus }
|
|
1777
2083
|
});
|
|
1778
2084
|
}
|
|
1779
|
-
const context = resolveAnthropicBatchRequestContext(options);
|
|
2085
|
+
const context = resolveAnthropicBatchRequestContext(clientContext.options);
|
|
1780
2086
|
const response = await context.fetchImplementation(batch.resultsUrl, {
|
|
1781
2087
|
method: "GET",
|
|
1782
2088
|
headers: buildAnthropicBatchRequestHeaders(context.apiKey)
|
|
@@ -1784,7 +2090,11 @@ async function listAnthropicMessageBatchResults(options, batchId) {
|
|
|
1784
2090
|
if (!response.ok) {
|
|
1785
2091
|
throw buildProviderStatusError("Anthropic", response.status);
|
|
1786
2092
|
}
|
|
1787
|
-
|
|
2093
|
+
const results = parseAnthropicBatchResultsJsonl(await response.text());
|
|
2094
|
+
for (const result of results) {
|
|
2095
|
+
clientContext.traceEmitter.emitBatchResultEvent(batchId, result);
|
|
2096
|
+
}
|
|
2097
|
+
return results;
|
|
1788
2098
|
}
|
|
1789
2099
|
function parseAnthropicBatchResultsJsonl(jsonlText) {
|
|
1790
2100
|
return jsonlText.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map(parseAnthropicBatchResultLine);
|
|
@@ -1803,7 +2113,7 @@ function parseAnthropicBatchResultLine(line) {
|
|
|
1803
2113
|
}
|
|
1804
2114
|
function parseAnthropicBatchResultLineJson(line) {
|
|
1805
2115
|
try {
|
|
1806
|
-
return
|
|
2116
|
+
return JsonValueSchema7.parse(JSON.parse(line));
|
|
1807
2117
|
} catch {
|
|
1808
2118
|
throw buildProviderInvalidResponseError(
|
|
1809
2119
|
"Anthropic",
|
|
@@ -1811,71 +2121,43 @@ function parseAnthropicBatchResultLineJson(line) {
|
|
|
1811
2121
|
);
|
|
1812
2122
|
}
|
|
1813
2123
|
}
|
|
1814
|
-
async function waitForAnthropicMessageBatchCompletion(
|
|
2124
|
+
async function waitForAnthropicMessageBatchCompletion(clientContext, batchId, waitOptions) {
|
|
1815
2125
|
const pollIntervalMs = waitOptions?.pollIntervalMs ?? defaultAnthropicBatchPollIntervalMs;
|
|
1816
2126
|
const timeoutMs = waitOptions?.timeoutMs ?? defaultAnthropicBatchTimeoutMs;
|
|
1817
2127
|
const waitFor = waitOptions?.waitFor ?? waitForMilliseconds;
|
|
1818
2128
|
const startedAt = Date.now();
|
|
1819
|
-
let batch = await fetchAnthropicMessageBatch(
|
|
2129
|
+
let batch = await fetchAnthropicMessageBatch(clientContext, batchId);
|
|
1820
2130
|
while (batch.processingStatus !== "ended") {
|
|
1821
2131
|
if (Date.now() - startedAt >= timeoutMs) {
|
|
1822
2132
|
throw buildAnthropicBatchTimeoutError(batchId, timeoutMs);
|
|
1823
2133
|
}
|
|
1824
2134
|
await waitFor(pollIntervalMs);
|
|
1825
|
-
batch = await fetchAnthropicMessageBatch(
|
|
2135
|
+
batch = await fetchAnthropicMessageBatch(clientContext, batchId);
|
|
1826
2136
|
}
|
|
1827
2137
|
return batch;
|
|
1828
2138
|
}
|
|
1829
2139
|
function buildAnthropicBatchTimeoutError(batchId, timeoutMs) {
|
|
1830
|
-
return new
|
|
1831
|
-
code:
|
|
2140
|
+
return new AppError14({
|
|
2141
|
+
code: AppErrorCode13.ServiceUnavailable,
|
|
1832
2142
|
message: `Anthropic message batch ${batchId} did not complete within ${String(timeoutMs)}ms`,
|
|
1833
2143
|
statusCode: 504,
|
|
1834
2144
|
details: { batchId, timeoutMs }
|
|
1835
2145
|
});
|
|
1836
2146
|
}
|
|
1837
|
-
function mapBatchMessageRequestToApiBatchRequest(request) {
|
|
1838
|
-
const params = {
|
|
1839
|
-
model: request.model,
|
|
1840
|
-
max_tokens: request.maxOutputTokens ?? defaultAnthropicMaxOutputTokens,
|
|
1841
|
-
messages: request.messages.filter((message) => message.role !== "system").map(mapChatMessageToBatchApiRequestMessage)
|
|
1842
|
-
};
|
|
1843
|
-
const systemText = joinBatchSystemMessageText(request.messages);
|
|
1844
|
-
if (systemText.length > 0) {
|
|
1845
|
-
params.system = systemText;
|
|
1846
|
-
}
|
|
1847
|
-
if (request.temperature !== void 0) {
|
|
1848
|
-
params.temperature = request.temperature;
|
|
1849
|
-
}
|
|
1850
|
-
return { custom_id: request.customId, params };
|
|
1851
|
-
}
|
|
1852
|
-
function joinBatchSystemMessageText(messages) {
|
|
1853
|
-
return messages.filter((message) => message.role === "system").map(extractMessageText).join("\n\n");
|
|
1854
|
-
}
|
|
1855
|
-
function mapChatMessageToBatchApiRequestMessage(message) {
|
|
1856
|
-
if (message.role === "assistant") {
|
|
1857
|
-
return { role: "assistant", content: extractMessageText(message) };
|
|
1858
|
-
}
|
|
1859
|
-
if (message.role === "tool") {
|
|
1860
|
-
return { role: "user", content: buildBatchToolResultText(message) };
|
|
1861
|
-
}
|
|
1862
|
-
return { role: "user", content: extractMessageText(message) };
|
|
1863
|
-
}
|
|
1864
|
-
function buildBatchToolResultText(message) {
|
|
1865
|
-
if (message.toolName === void 0) {
|
|
1866
|
-
return `Tool result: ${extractMessageText(message)}`;
|
|
1867
|
-
}
|
|
1868
|
-
return `Tool result (${message.toolName}): ${extractMessageText(message)}`;
|
|
1869
|
-
}
|
|
1870
2147
|
export {
|
|
1871
2148
|
AnthropicMessagesResponseSchema,
|
|
1872
2149
|
AnthropicStreamEventSchema,
|
|
2150
|
+
ChatMessageCacheControlSchema,
|
|
1873
2151
|
ChatMessageRoleSchema,
|
|
1874
2152
|
ChatMessageSchema,
|
|
1875
2153
|
ChatStopReasonSchema,
|
|
1876
2154
|
MessageContentBlockSchema,
|
|
1877
2155
|
ModelToolCallSchema,
|
|
1878
2156
|
anthropic,
|
|
2157
|
+
anthropicBatchJsonOnlySystemInstruction,
|
|
2158
|
+
anthropicBatchTraceWorkflowName,
|
|
2159
|
+
applyCacheControlToLastContentBlock,
|
|
2160
|
+
buildAnthropicCacheControl,
|
|
1879
2161
|
buildAnthropicRequestBody,
|
|
1880
2162
|
buildOpenAiRequestBody,
|
|
1881
2163
|
buildProviderCanceledError,
|
|
@@ -1909,11 +2191,14 @@ export {
|
|
|
1909
2191
|
mapModelToolChoiceToOpenAiToolChoice,
|
|
1910
2192
|
mapModelToolDefinitionToOpenAiTool,
|
|
1911
2193
|
mapModelToolDefinitionsToAnthropicTools,
|
|
2194
|
+
mergeProviderRequestExtraBody,
|
|
1912
2195
|
mockModel,
|
|
1913
2196
|
normalizeAnthropicStopReason,
|
|
1914
2197
|
openai,
|
|
2198
|
+
parseAnthropicBatchStructuredContent,
|
|
1915
2199
|
parseAnthropicStreamEvents,
|
|
1916
2200
|
parseAnthropicToolInputJson,
|
|
2201
|
+
resolveAnthropicPromptCachingSettings,
|
|
1917
2202
|
resolveProviderApiKey,
|
|
1918
2203
|
streamAnthropicChatCompletion
|
|
1919
2204
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assemble-dev/providers",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"license": "Elastic-2.0",
|
|
5
5
|
"description": "Model provider adapters for the Assemble SDK",
|
|
6
6
|
"repository": {
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"zod": "^4.1.13",
|
|
30
|
-
"@assemble-dev/shared-types": "0.
|
|
31
|
-
"@assemble-dev/shared-utils": "0.
|
|
30
|
+
"@assemble-dev/shared-types": "0.2.0",
|
|
31
|
+
"@assemble-dev/shared-utils": "0.2.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/node": "^20.19.0",
|