@yourgpt/llm-sdk 2.6.0-beta.3 → 2.6.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/LICENSE +21 -0
- package/README.md +46 -10
- package/dist/adapters/index.d.mts +11 -13
- package/dist/adapters/index.d.ts +11 -13
- package/dist/adapters/index.js +327 -100
- package/dist/adapters/index.mjs +327 -100
- package/dist/audio-K-Z3-Bce.d.mts +191 -0
- package/dist/audio-K-Z3-Bce.d.ts +191 -0
- package/dist/{base-BICaQaRS.d.mts → base-6LzczuCg.d.ts} +8 -1
- package/dist/{base-CpRPB8u8.d.ts → base-DySbTP8C.d.mts} +8 -1
- package/dist/decisions-CJzOt87t.d.mts +137 -0
- package/dist/decisions-CJzOt87t.d.ts +137 -0
- package/dist/fallback/index.d.mts +4 -4
- package/dist/fallback/index.d.ts +4 -4
- package/dist/http-BQxUT5A9.d.mts +9 -0
- package/dist/http-BQxUT5A9.d.ts +9 -0
- package/dist/index.d.mts +14 -8
- package/dist/index.d.ts +14 -8
- package/dist/index.js +599 -195
- package/dist/index.mjs +596 -196
- package/dist/providers/anthropic/index.d.mts +7 -4
- package/dist/providers/anthropic/index.d.ts +7 -4
- package/dist/providers/anthropic/index.js +383 -102
- package/dist/providers/anthropic/index.mjs +383 -102
- package/dist/providers/azure/index.d.mts +3 -3
- package/dist/providers/azure/index.d.ts +3 -3
- package/dist/providers/cloudflare/index.d.mts +11 -0
- package/dist/providers/cloudflare/index.d.ts +11 -0
- package/dist/providers/cloudflare/index.js +743 -0
- package/dist/providers/cloudflare/index.mjs +741 -0
- package/dist/providers/fireworks/index.d.mts +3 -3
- package/dist/providers/fireworks/index.d.ts +3 -3
- package/dist/providers/fireworks/index.js +108 -59
- package/dist/providers/fireworks/index.mjs +108 -59
- package/dist/providers/google/index.d.mts +3 -3
- package/dist/providers/google/index.d.ts +3 -3
- package/dist/providers/google/index.js +108 -59
- package/dist/providers/google/index.mjs +108 -59
- package/dist/providers/ollama/index.d.mts +4 -4
- package/dist/providers/ollama/index.d.ts +4 -4
- package/dist/providers/openai/index.d.mts +38 -6
- package/dist/providers/openai/index.d.ts +38 -6
- package/dist/providers/openai/index.js +1378 -84
- package/dist/providers/openai/index.mjs +1376 -85
- package/dist/providers/openrouter/index.d.mts +21 -4
- package/dist/providers/openrouter/index.d.ts +21 -4
- package/dist/providers/openrouter/index.js +967 -130
- package/dist/providers/openrouter/index.mjs +967 -131
- package/dist/providers/togetherai/index.d.mts +3 -3
- package/dist/providers/togetherai/index.d.ts +3 -3
- package/dist/providers/togetherai/index.js +108 -59
- package/dist/providers/togetherai/index.mjs +108 -59
- package/dist/providers/typesafe/index.d.mts +8 -0
- package/dist/providers/typesafe/index.d.ts +8 -0
- package/dist/providers/typesafe/index.js +735 -0
- package/dist/providers/typesafe/index.mjs +733 -0
- package/dist/providers/xai/index.d.mts +3 -3
- package/dist/providers/xai/index.d.ts +3 -3
- package/dist/providers/xai/index.js +108 -59
- package/dist/providers/xai/index.mjs +108 -59
- package/dist/{types-DCFqkJAy.d.ts → types-B0y6VZSQ.d.ts} +1 -1
- package/dist/{types-DHQEMFHA.d.mts → types-BXQMtaCX.d.ts} +17 -3
- package/dist/{types-C3RgRbEC.d.mts → types-BY6BVhFg.d.mts} +1 -1
- package/dist/{types-Dikj3En4.d.ts → types-C7_qVSSd.d.mts} +17 -3
- package/dist/{types-Dg1Bcg1k.d.mts → types-D7lzMMLu.d.mts} +13 -1
- package/dist/{types-Dg1Bcg1k.d.ts → types-D7lzMMLu.d.ts} +13 -1
- package/dist/yourgpt/index.d.mts +1 -1
- package/dist/yourgpt/index.d.ts +1 -1
- package/docs/decisions.md +174 -0
- package/docs/media.md +201 -0
- package/docs/multimodal-and-audio.md +9 -2
- package/package.json +34 -12
- package/dist/audio-BBSwnjo8.d.mts +0 -92
- package/dist/audio-BBSwnjo8.d.ts +0 -92
package/dist/adapters/index.js
CHANGED
|
@@ -103,6 +103,63 @@ function textToolOutput(value, fallback) {
|
|
|
103
103
|
return toolOutputForProvider(value, "unsupported").map((part) => part.text).join("\n");
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
// src/core/anthropic-replay.ts
|
|
107
|
+
function anthropicReplay(content) {
|
|
108
|
+
if (!Array.isArray(content) || !content.some(
|
|
109
|
+
(b) => b?.type === "thinking" || b?.type === "redacted_thinking"
|
|
110
|
+
))
|
|
111
|
+
return void 0;
|
|
112
|
+
const blocks = content.flatMap((block) => {
|
|
113
|
+
if (block?.type === "thinking" && typeof block.thinking === "string" && typeof block.signature === "string")
|
|
114
|
+
return [
|
|
115
|
+
{
|
|
116
|
+
type: "thinking",
|
|
117
|
+
thinking: block.thinking,
|
|
118
|
+
signature: block.signature
|
|
119
|
+
}
|
|
120
|
+
];
|
|
121
|
+
if (block?.type === "redacted_thinking" && typeof block.data === "string")
|
|
122
|
+
return [{ type: "redacted_thinking", data: block.data }];
|
|
123
|
+
if (block?.type === "text" && typeof block.text === "string")
|
|
124
|
+
return [{ type: "text", text: block.text }];
|
|
125
|
+
if (block?.type === "tool_use" && typeof block.id === "string" && typeof block.name === "string")
|
|
126
|
+
return [
|
|
127
|
+
{
|
|
128
|
+
type: "tool_use",
|
|
129
|
+
id: block.id,
|
|
130
|
+
name: block.name,
|
|
131
|
+
input: block.input
|
|
132
|
+
}
|
|
133
|
+
];
|
|
134
|
+
return [];
|
|
135
|
+
});
|
|
136
|
+
return { anthropic: { content: blocks } };
|
|
137
|
+
}
|
|
138
|
+
function anthropicReplayContent(metadata) {
|
|
139
|
+
const state = metadata?.anthropic;
|
|
140
|
+
return anthropicReplay(state?.content)?.anthropic?.content;
|
|
141
|
+
}
|
|
142
|
+
function collectAnthropicContent(blocks, event) {
|
|
143
|
+
if (event.type === "content_block_start")
|
|
144
|
+
blocks[event.index] = { ...event.content_block };
|
|
145
|
+
const block = blocks[event.index];
|
|
146
|
+
if (event.type !== "content_block_delta" || !block) return;
|
|
147
|
+
const delta = event.delta;
|
|
148
|
+
if (delta.type === "thinking_delta")
|
|
149
|
+
block.thinking = (block.thinking ?? "") + delta.thinking;
|
|
150
|
+
else if (delta.type === "signature_delta")
|
|
151
|
+
block.signature = (block.signature ?? "") + delta.signature;
|
|
152
|
+
else if (delta.type === "text_delta")
|
|
153
|
+
block.text = (block.text ?? "") + delta.text;
|
|
154
|
+
else if (delta.type === "input_json_delta") {
|
|
155
|
+
block.partialInput = (block.partialInput ?? "") + delta.partial_json;
|
|
156
|
+
try {
|
|
157
|
+
block.input = JSON.parse(block.partialInput);
|
|
158
|
+
} catch {
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
106
163
|
// src/core/openai-parameters.ts
|
|
107
164
|
function capabilities(model) {
|
|
108
165
|
const gpt = /^gpt-(\d+)(?:\.(\d+))?(?:-(.+))?$/i.exec(model);
|
|
@@ -113,6 +170,19 @@ function capabilities(model) {
|
|
|
113
170
|
const supportsNone = major === 5 && minor >= 1 && !chat || /^gpt-6-(?:sol|luna)(?:-\d{4}-\d{2}-\d{2})?$/i.test(model);
|
|
114
171
|
return { major, minor, reasoning, supportsNone };
|
|
115
172
|
}
|
|
173
|
+
function filterOpenAIResponseInclude(model, include, options = {}) {
|
|
174
|
+
const c = capabilities(model);
|
|
175
|
+
let result = include;
|
|
176
|
+
if (options.parameterPolicy !== "passthrough" && c.reasoning && !(options.reasoningEffort === "none" && c.supportsNone) && include.includes("message.output_text.logprobs")) {
|
|
177
|
+
result = include.filter(
|
|
178
|
+
(value) => value !== "message.output_text.logprobs"
|
|
179
|
+
);
|
|
180
|
+
(options.onWarning ?? console.warn)(
|
|
181
|
+
`[llm-sdk] ${model}: omitted message.output_text.logprobs because reasoning is enabled.`
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
return result.length ? result : void 0;
|
|
185
|
+
}
|
|
116
186
|
function requiresOpenAIResponses(model, baseUrl, options = {}) {
|
|
117
187
|
if (options.parameterPolicy === "passthrough") return false;
|
|
118
188
|
const c = capabilities(model);
|
|
@@ -284,7 +354,22 @@ function stripSchemaKeys(schema, keysToDrop, options = {}) {
|
|
|
284
354
|
)) {
|
|
285
355
|
if (keysToDrop.has(key)) continue;
|
|
286
356
|
const renamed = options.renameKeys?.[key] ?? key;
|
|
287
|
-
|
|
357
|
+
if ([
|
|
358
|
+
"properties",
|
|
359
|
+
"$defs",
|
|
360
|
+
"definitions",
|
|
361
|
+
"patternProperties",
|
|
362
|
+
"dependentSchemas"
|
|
363
|
+
].includes(key) && value && typeof value === "object" && !Array.isArray(value)) {
|
|
364
|
+
out[renamed] = Object.fromEntries(
|
|
365
|
+
Object.entries(value).map(([name, child]) => [
|
|
366
|
+
name,
|
|
367
|
+
stripSchemaKeys(child, keysToDrop, options)
|
|
368
|
+
])
|
|
369
|
+
);
|
|
370
|
+
} else if (["enum", "const", "default", "examples"].includes(key)) {
|
|
371
|
+
out[renamed] = value;
|
|
372
|
+
} else out[renamed] = stripSchemaKeys(value, keysToDrop, options);
|
|
288
373
|
}
|
|
289
374
|
if (options.forceAdditionalPropertiesFalse && out.type === "object") {
|
|
290
375
|
out.additionalProperties = false;
|
|
@@ -305,6 +390,7 @@ function toOpenAIResponseFormat(rf) {
|
|
|
305
390
|
};
|
|
306
391
|
}
|
|
307
392
|
function toOpenAIResponsesTextFormat(rf) {
|
|
393
|
+
if (rf?.type === "json_object") return { type: "json_object" };
|
|
308
394
|
if (!rf || rf.type !== "json_schema") return void 0;
|
|
309
395
|
return {
|
|
310
396
|
type: "json_schema",
|
|
@@ -544,6 +630,14 @@ function formatMessagesForAnthropic(messages, systemPrompt) {
|
|
|
544
630
|
const msg = messages[i];
|
|
545
631
|
if (msg.role === "system") continue;
|
|
546
632
|
if (msg.role === "assistant") {
|
|
633
|
+
const replay = anthropicReplayContent(msg.providerMetadata);
|
|
634
|
+
if (replay) {
|
|
635
|
+
formatted.push({
|
|
636
|
+
role: "assistant",
|
|
637
|
+
content: replay
|
|
638
|
+
});
|
|
639
|
+
continue;
|
|
640
|
+
}
|
|
547
641
|
const content = [];
|
|
548
642
|
if (msg.content) {
|
|
549
643
|
content.push({ type: "text", text: msg.content });
|
|
@@ -634,6 +728,63 @@ function formatMessagesForOpenAI(messages, systemPrompt, preserveProviderMetadat
|
|
|
634
728
|
return formatted;
|
|
635
729
|
}
|
|
636
730
|
|
|
731
|
+
// src/core/provider-error.ts
|
|
732
|
+
function invalidProviderResponse(message) {
|
|
733
|
+
return Object.assign(new Error(message), {
|
|
734
|
+
name: "InvalidProviderResponseError",
|
|
735
|
+
status: 502,
|
|
736
|
+
code: "INVALID_PROVIDER_RESPONSE"
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
function providerErrorEvent(error, code) {
|
|
740
|
+
const details = error ?? {};
|
|
741
|
+
const event = {
|
|
742
|
+
type: "error",
|
|
743
|
+
message: error instanceof Error ? error.message : String(error),
|
|
744
|
+
code,
|
|
745
|
+
...typeof details.status === "number" ? { status: details.status } : {},
|
|
746
|
+
...typeof details.code === "string" ? { providerCode: details.code } : {},
|
|
747
|
+
...typeof details.param === "string" ? { param: details.param } : {},
|
|
748
|
+
...typeof details.request_id === "string" ? { requestId: details.request_id } : {}
|
|
749
|
+
};
|
|
750
|
+
Object.defineProperty(event, "cause", { value: error, enumerable: false });
|
|
751
|
+
return event;
|
|
752
|
+
}
|
|
753
|
+
function throwIfAborted(signal) {
|
|
754
|
+
if (!signal?.aborted) return;
|
|
755
|
+
const error = new Error("The operation was aborted");
|
|
756
|
+
error.name = "AbortError";
|
|
757
|
+
throw error;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
// src/core/tool-validation.ts
|
|
761
|
+
function parseToolArguments(value) {
|
|
762
|
+
let args = value;
|
|
763
|
+
if (typeof value === "string") {
|
|
764
|
+
try {
|
|
765
|
+
args = JSON.parse(value || "{}");
|
|
766
|
+
} catch {
|
|
767
|
+
throw invalidProviderResponse("Tool arguments are not valid JSON");
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
if (args === null || typeof args !== "object" || Array.isArray(args))
|
|
771
|
+
throw invalidProviderResponse("Tool arguments must be a JSON object");
|
|
772
|
+
return args;
|
|
773
|
+
}
|
|
774
|
+
function validateToolCalls(calls) {
|
|
775
|
+
const ids = /* @__PURE__ */ new Set();
|
|
776
|
+
for (const call of calls) {
|
|
777
|
+
if (!call || typeof call.id !== "string" || !call.id || typeof call.name !== "string" || !call.name || ids.has(call.id))
|
|
778
|
+
throw invalidProviderResponse(
|
|
779
|
+
"Tool calls have missing or duplicate identities"
|
|
780
|
+
);
|
|
781
|
+
ids.add(call.id);
|
|
782
|
+
if (typeof call.args === "string")
|
|
783
|
+
throw invalidProviderResponse("Parsed tool arguments must be an object");
|
|
784
|
+
parseToolArguments(call.args);
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
|
|
637
788
|
// src/core/openai-responses.ts
|
|
638
789
|
function resolveOpenAITransport(defaults, overrides) {
|
|
639
790
|
return {
|
|
@@ -740,35 +891,6 @@ function getResponseReplay(metadata) {
|
|
|
740
891
|
return responseReplayMetadata(metadata)?.openai?.response?.output;
|
|
741
892
|
}
|
|
742
893
|
|
|
743
|
-
// src/core/provider-error.ts
|
|
744
|
-
function invalidProviderResponse(message) {
|
|
745
|
-
return Object.assign(new Error(message), {
|
|
746
|
-
name: "InvalidProviderResponseError",
|
|
747
|
-
status: 502,
|
|
748
|
-
code: "INVALID_PROVIDER_RESPONSE"
|
|
749
|
-
});
|
|
750
|
-
}
|
|
751
|
-
function providerErrorEvent(error, code) {
|
|
752
|
-
const details = error ?? {};
|
|
753
|
-
const event = {
|
|
754
|
-
type: "error",
|
|
755
|
-
message: error instanceof Error ? error.message : String(error),
|
|
756
|
-
code,
|
|
757
|
-
...typeof details.status === "number" ? { status: details.status } : {},
|
|
758
|
-
...typeof details.code === "string" ? { providerCode: details.code } : {},
|
|
759
|
-
...typeof details.param === "string" ? { param: details.param } : {},
|
|
760
|
-
...typeof details.request_id === "string" ? { requestId: details.request_id } : {}
|
|
761
|
-
};
|
|
762
|
-
Object.defineProperty(event, "cause", { value: error, enumerable: false });
|
|
763
|
-
return event;
|
|
764
|
-
}
|
|
765
|
-
function throwIfAborted(signal) {
|
|
766
|
-
if (!signal?.aborted) return;
|
|
767
|
-
const error = new Error("The operation was aborted");
|
|
768
|
-
error.name = "AbortError";
|
|
769
|
-
throw error;
|
|
770
|
-
}
|
|
771
|
-
|
|
772
894
|
// src/core/utils.ts
|
|
773
895
|
function generateId(prefix = "id") {
|
|
774
896
|
return `${prefix}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
@@ -802,6 +924,8 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
802
924
|
apiKey: this.config.apiKey,
|
|
803
925
|
baseURL: this.config.baseUrl,
|
|
804
926
|
organization: this.config.organization,
|
|
927
|
+
project: this.config.project,
|
|
928
|
+
timeout: this.config.timeout,
|
|
805
929
|
defaultHeaders: this.config.headers
|
|
806
930
|
});
|
|
807
931
|
}
|
|
@@ -1083,6 +1207,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1083
1207
|
request.config?.responseFormat
|
|
1084
1208
|
);
|
|
1085
1209
|
const modelIdForPayload = request.config?.model || this.model;
|
|
1210
|
+
const include = filterOpenAIResponseInclude(
|
|
1211
|
+
modelIdForPayload,
|
|
1212
|
+
[
|
|
1213
|
+
.../* @__PURE__ */ new Set([
|
|
1214
|
+
...options?.include ?? [],
|
|
1215
|
+
...options?.store === false ? ["reasoning.encrypted_content"] : []
|
|
1216
|
+
])
|
|
1217
|
+
],
|
|
1218
|
+
this.parameterOptions(request)
|
|
1219
|
+
);
|
|
1086
1220
|
const payload = {
|
|
1087
1221
|
model: modelIdForPayload,
|
|
1088
1222
|
instructions: request.systemPrompt,
|
|
@@ -1106,14 +1240,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1106
1240
|
...options?.promptCacheKey !== void 0 ? { prompt_cache_key: options.promptCacheKey } : {},
|
|
1107
1241
|
...options?.promptCacheOptions !== void 0 ? { prompt_cache_options: options.promptCacheOptions } : {},
|
|
1108
1242
|
...options?.promptCacheRetention !== void 0 ? { prompt_cache_retention: options.promptCacheRetention } : {},
|
|
1109
|
-
...
|
|
1110
|
-
include: [
|
|
1111
|
-
.../* @__PURE__ */ new Set([
|
|
1112
|
-
...options?.include ?? [],
|
|
1113
|
-
...options?.store === false ? ["reasoning.encrypted_content"] : []
|
|
1114
|
-
])
|
|
1115
|
-
]
|
|
1116
|
-
} : {},
|
|
1243
|
+
...include ? { include } : {},
|
|
1117
1244
|
...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
|
|
1118
1245
|
stream
|
|
1119
1246
|
};
|
|
@@ -1484,15 +1611,20 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1484
1611
|
}
|
|
1485
1612
|
throwIfAborted(request.signal);
|
|
1486
1613
|
if (!finishReason)
|
|
1487
|
-
throw
|
|
1614
|
+
throw invalidProviderResponse(
|
|
1615
|
+
"OpenAI stream ended without a finish reason"
|
|
1616
|
+
);
|
|
1488
1617
|
if (toolCalls.size && !["tool_calls", "function_call"].includes(finishReason)) {
|
|
1489
|
-
throw
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
if (!call.id || !call.name)
|
|
1493
|
-
throw new Error("OpenAI stream contains an incomplete tool call");
|
|
1494
|
-
JSON.parse(call.arguments || "{}");
|
|
1618
|
+
throw invalidProviderResponse(
|
|
1619
|
+
"OpenAI stream ended with incomplete tool calls"
|
|
1620
|
+
);
|
|
1495
1621
|
}
|
|
1622
|
+
validateToolCalls(
|
|
1623
|
+
[...toolCalls.values()].map((call) => ({
|
|
1624
|
+
...call,
|
|
1625
|
+
args: parseToolArguments(call.arguments)
|
|
1626
|
+
}))
|
|
1627
|
+
);
|
|
1496
1628
|
for (const call of toolCalls.values()) {
|
|
1497
1629
|
yield {
|
|
1498
1630
|
type: "action:start",
|
|
@@ -1576,20 +1708,20 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1576
1708
|
logProviderPayload("openai", "response payload", response, request.debug);
|
|
1577
1709
|
const choice = response.choices?.[0];
|
|
1578
1710
|
const message = choice?.message;
|
|
1711
|
+
const toolCalls = (message?.tool_calls ?? []).map((toolCall) => ({
|
|
1712
|
+
id: toolCall.id,
|
|
1713
|
+
name: toolCall.function?.name,
|
|
1714
|
+
args: parseToolArguments(toolCall.function?.arguments ?? "{}"),
|
|
1715
|
+
...toolCall.extra_content ? { extra_content: toolCall.extra_content } : {}
|
|
1716
|
+
}));
|
|
1717
|
+
validateToolCalls(toolCalls);
|
|
1718
|
+
if (toolCalls.length && choice?.finish_reason && !["tool_calls", "function_call"].includes(choice.finish_reason))
|
|
1719
|
+
throw invalidProviderResponse(
|
|
1720
|
+
"OpenAI response ended with incomplete tool calls"
|
|
1721
|
+
);
|
|
1579
1722
|
return {
|
|
1580
1723
|
content: message?.content ?? "",
|
|
1581
|
-
toolCalls
|
|
1582
|
-
id: toolCall.id ?? generateToolCallId(),
|
|
1583
|
-
name: toolCall.function?.name ?? "",
|
|
1584
|
-
args: (() => {
|
|
1585
|
-
try {
|
|
1586
|
-
return JSON.parse(toolCall.function?.arguments ?? "{}");
|
|
1587
|
-
} catch {
|
|
1588
|
-
return {};
|
|
1589
|
-
}
|
|
1590
|
-
})(),
|
|
1591
|
-
...toolCall.extra_content ? { extra_content: toolCall.extra_content } : {}
|
|
1592
|
-
})) ?? [],
|
|
1724
|
+
toolCalls,
|
|
1593
1725
|
usage: response.usage ? {
|
|
1594
1726
|
promptTokens: response.usage.prompt_tokens,
|
|
1595
1727
|
completionTokens: response.usage.completion_tokens,
|
|
@@ -1622,6 +1754,52 @@ function createOpenAIAdapter(config) {
|
|
|
1622
1754
|
return new OpenAIAdapter(config);
|
|
1623
1755
|
}
|
|
1624
1756
|
|
|
1757
|
+
// src/core/anthropic-parameters.ts
|
|
1758
|
+
function anthropicMaxTokens(maxTokens, thinking) {
|
|
1759
|
+
return maxTokens ?? Math.max(4096, Number(thinking?.budget_tokens ?? 0) + 1);
|
|
1760
|
+
}
|
|
1761
|
+
function anthropicModelRules(model) {
|
|
1762
|
+
const match = /^claude-(opus|sonnet|haiku)-(\d+)(?:-(\d{1,2})(?=-|$))?(?:-|$)/i.exec(
|
|
1763
|
+
model
|
|
1764
|
+
);
|
|
1765
|
+
const family = match?.[1]?.toLowerCase();
|
|
1766
|
+
const major = Number(match?.[2] ?? 0);
|
|
1767
|
+
const minor = Number(match?.[3] ?? 0);
|
|
1768
|
+
const adaptive = major >= 5 || major === 4 && minor >= 6;
|
|
1769
|
+
return {
|
|
1770
|
+
structured: major >= 5 || major === 4 && minor >= 5,
|
|
1771
|
+
thinking: major >= 4 || /^claude-3-7-/.test(model),
|
|
1772
|
+
adaptive,
|
|
1773
|
+
rejectsSampling: major >= 5 || family === "opus" && major === 4 && minor >= 7
|
|
1774
|
+
};
|
|
1775
|
+
}
|
|
1776
|
+
function anthropicInputTokens(usage) {
|
|
1777
|
+
return (usage?.input_tokens ?? 0) + (usage?.cache_creation_input_tokens ?? 0) + (usage?.cache_read_input_tokens ?? 0);
|
|
1778
|
+
}
|
|
1779
|
+
function anthropicThinking(model, thinking) {
|
|
1780
|
+
if (!thinking) return void 0;
|
|
1781
|
+
if (thinking.type === "enabled") {
|
|
1782
|
+
if (anthropicModelRules(model).adaptive) {
|
|
1783
|
+
console.warn(
|
|
1784
|
+
`[llm-sdk] ${model}: using adaptive thinking instead of a legacy token budget.`
|
|
1785
|
+
);
|
|
1786
|
+
return { type: "adaptive" };
|
|
1787
|
+
}
|
|
1788
|
+
return { type: "enabled", budget_tokens: thinking.budgetTokens ?? 1e4 };
|
|
1789
|
+
}
|
|
1790
|
+
return { ...thinking };
|
|
1791
|
+
}
|
|
1792
|
+
function anthropicTemperature(model, temperature, thinking = false) {
|
|
1793
|
+
if (temperature === void 0) return {};
|
|
1794
|
+
if (thinking || anthropicModelRules(model).rejectsSampling) {
|
|
1795
|
+
console.warn(
|
|
1796
|
+
`[llm-sdk] ${model}: omitted temperature because this model or thinking mode does not support it.`
|
|
1797
|
+
);
|
|
1798
|
+
return {};
|
|
1799
|
+
}
|
|
1800
|
+
return { temperature };
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1625
1803
|
// src/adapters/anthropic.ts
|
|
1626
1804
|
var AnthropicAdapter = class {
|
|
1627
1805
|
constructor(config) {
|
|
@@ -1633,7 +1811,10 @@ var AnthropicAdapter = class {
|
|
|
1633
1811
|
if (!this.client) {
|
|
1634
1812
|
const { default: Anthropic } = await import('@anthropic-ai/sdk');
|
|
1635
1813
|
this.client = new Anthropic({
|
|
1636
|
-
apiKey: this.config.apiKey
|
|
1814
|
+
apiKey: this.config.apiKey,
|
|
1815
|
+
baseURL: this.config.baseUrl,
|
|
1816
|
+
timeout: this.config.timeout,
|
|
1817
|
+
defaultHeaders: this.config.headers
|
|
1637
1818
|
});
|
|
1638
1819
|
}
|
|
1639
1820
|
return this.client;
|
|
@@ -1670,6 +1851,15 @@ var AnthropicAdapter = class {
|
|
|
1670
1851
|
lastToolCallIds = [];
|
|
1671
1852
|
toolResultIndex = 0;
|
|
1672
1853
|
}
|
|
1854
|
+
const replay = anthropicReplayContent(
|
|
1855
|
+
msg.providerMetadata
|
|
1856
|
+
);
|
|
1857
|
+
if (replay) {
|
|
1858
|
+
messages.push({ role: "assistant", content: replay });
|
|
1859
|
+
lastToolCallIds = replay.filter((b) => b.type === "tool_use").map((b) => b.id);
|
|
1860
|
+
toolResultIndex = 0;
|
|
1861
|
+
continue;
|
|
1862
|
+
}
|
|
1673
1863
|
const content = [];
|
|
1674
1864
|
if (msg.content && typeof msg.content === "string" && msg.content.trim()) {
|
|
1675
1865
|
content.push({ type: "text", text: msg.content });
|
|
@@ -1845,7 +2035,7 @@ var AnthropicAdapter = class {
|
|
|
1845
2035
|
*/
|
|
1846
2036
|
buildRequestOptions(request) {
|
|
1847
2037
|
const responseFormat = request.config?.responseFormat;
|
|
1848
|
-
const jsonObjectSuffix = responseFormat?.type === "json_object" ? "\n\nRespond with a single JSON object and no other text." : "";
|
|
2038
|
+
const jsonObjectSuffix = responseFormat?.type === "json_object" ? "\n\nRespond with a single JSON object and no other text. Do not include Markdown code fences." : "";
|
|
1849
2039
|
let systemMessage;
|
|
1850
2040
|
let messages;
|
|
1851
2041
|
if (request.rawMessages && request.rawMessages.length > 0) {
|
|
@@ -1867,7 +2057,17 @@ var AnthropicAdapter = class {
|
|
|
1867
2057
|
const tools = anthropicNativeSearch?.enabled ? this.buildNativeSearchTools(
|
|
1868
2058
|
request.toolDefinitions ?? [],
|
|
1869
2059
|
anthropicNativeSearch.variant
|
|
1870
|
-
) : request.
|
|
2060
|
+
) : request.toolDefinitions?.length ? request.toolDefinitions.filter((tool) => tool.available !== false).map((tool) => ({
|
|
2061
|
+
name: tool.name,
|
|
2062
|
+
description: tool.description,
|
|
2063
|
+
// Keep the original schema. Legacy ActionParameter conversion
|
|
2064
|
+
// cannot represent unions, null, or nested required constraints.
|
|
2065
|
+
input_schema: tool.inputSchema ?? {
|
|
2066
|
+
type: "object",
|
|
2067
|
+
properties: {},
|
|
2068
|
+
required: []
|
|
2069
|
+
}
|
|
2070
|
+
})) : request.actions?.map((action) => ({
|
|
1871
2071
|
name: action.name,
|
|
1872
2072
|
description: action.description,
|
|
1873
2073
|
input_schema: {
|
|
@@ -1909,12 +2109,25 @@ var AnthropicAdapter = class {
|
|
|
1909
2109
|
};
|
|
1910
2110
|
}
|
|
1911
2111
|
}
|
|
2112
|
+
const thinking = anthropicThinking(
|
|
2113
|
+
request.config?.model || this.model,
|
|
2114
|
+
this.config.thinking
|
|
2115
|
+
);
|
|
1912
2116
|
const options = {
|
|
1913
2117
|
model: request.config?.model || this.model,
|
|
1914
|
-
max_tokens:
|
|
2118
|
+
max_tokens: anthropicMaxTokens(
|
|
2119
|
+
request.config?.maxTokens ?? this.config.maxTokens,
|
|
2120
|
+
thinking
|
|
2121
|
+
),
|
|
1915
2122
|
system: systemMessage,
|
|
1916
2123
|
messages,
|
|
1917
|
-
tools: tools.length ? tools : void 0
|
|
2124
|
+
tools: tools.length ? tools : void 0,
|
|
2125
|
+
...this.config.cacheControl ? { cache_control: { type: "ephemeral" } } : {},
|
|
2126
|
+
...anthropicTemperature(
|
|
2127
|
+
request.config?.model || this.model,
|
|
2128
|
+
request.config?.temperature ?? this.config.temperature,
|
|
2129
|
+
!!this.config.thinking && this.config.thinking.type !== "disabled"
|
|
2130
|
+
)
|
|
1918
2131
|
};
|
|
1919
2132
|
const anthropicToolOptions = request.providerToolOptions?.anthropic;
|
|
1920
2133
|
if (tools.length > 0 && anthropicToolOptions) {
|
|
@@ -1933,15 +2146,13 @@ var AnthropicAdapter = class {
|
|
|
1933
2146
|
options.server_tool_configuration = serverToolConfiguration;
|
|
1934
2147
|
}
|
|
1935
2148
|
const outputConfig = toAnthropicOutputConfig(responseFormat);
|
|
1936
|
-
if (outputConfig) {
|
|
1937
|
-
options.output_config =
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
options.thinking = {
|
|
1941
|
-
type: "enabled",
|
|
1942
|
-
budget_tokens: this.config.thinking.budgetTokens || 1e4
|
|
2149
|
+
if (outputConfig || this.config.effort) {
|
|
2150
|
+
options.output_config = {
|
|
2151
|
+
...outputConfig,
|
|
2152
|
+
...this.config.effort ? { effort: this.config.effort } : {}
|
|
1943
2153
|
};
|
|
1944
2154
|
}
|
|
2155
|
+
if (thinking) options.thinking = thinking;
|
|
1945
2156
|
return { options, messages };
|
|
1946
2157
|
}
|
|
1947
2158
|
/**
|
|
@@ -1961,7 +2172,9 @@ var AnthropicAdapter = class {
|
|
|
1961
2172
|
nonStreamingOptions,
|
|
1962
2173
|
request.debug
|
|
1963
2174
|
);
|
|
1964
|
-
const response = await client.messages.create(nonStreamingOptions
|
|
2175
|
+
const response = await client.messages.create(nonStreamingOptions, {
|
|
2176
|
+
signal: request.signal
|
|
2177
|
+
});
|
|
1965
2178
|
logProviderPayload(
|
|
1966
2179
|
"anthropic",
|
|
1967
2180
|
"response payload",
|
|
@@ -1984,14 +2197,20 @@ var AnthropicAdapter = class {
|
|
|
1984
2197
|
});
|
|
1985
2198
|
}
|
|
1986
2199
|
}
|
|
2200
|
+
validateToolCalls(toolCalls);
|
|
2201
|
+
if (toolCalls.length && response.stop_reason !== "tool_use")
|
|
2202
|
+
throw invalidProviderResponse(
|
|
2203
|
+
"Anthropic response ended with incomplete tool calls"
|
|
2204
|
+
);
|
|
1987
2205
|
return {
|
|
1988
2206
|
content,
|
|
2207
|
+
providerMetadata: anthropicReplay(response.content),
|
|
1989
2208
|
toolCalls,
|
|
1990
2209
|
thinking: thinking || void 0,
|
|
1991
2210
|
usage: response.usage ? {
|
|
1992
|
-
promptTokens: response.usage
|
|
2211
|
+
promptTokens: anthropicInputTokens(response.usage),
|
|
1993
2212
|
completionTokens: response.usage.output_tokens ?? 0,
|
|
1994
|
-
totalTokens: (response.usage
|
|
2213
|
+
totalTokens: anthropicInputTokens(response.usage) + (response.usage.output_tokens ?? 0)
|
|
1995
2214
|
} : void 0,
|
|
1996
2215
|
rawResponse: response
|
|
1997
2216
|
};
|
|
@@ -2011,28 +2230,33 @@ var AnthropicAdapter = class {
|
|
|
2011
2230
|
options,
|
|
2012
2231
|
request.debug
|
|
2013
2232
|
);
|
|
2014
|
-
const stream = await client.messages.stream(options
|
|
2233
|
+
const stream = await client.messages.stream(options, {
|
|
2234
|
+
signal: request.signal
|
|
2235
|
+
});
|
|
2015
2236
|
let currentToolUse = null;
|
|
2016
2237
|
let isInThinkingBlock = false;
|
|
2238
|
+
const content = [];
|
|
2239
|
+
const toolCalls = [];
|
|
2240
|
+
let stopReason;
|
|
2017
2241
|
const collectedCitations = [];
|
|
2018
2242
|
let citationIndex = 0;
|
|
2019
2243
|
let usage;
|
|
2020
2244
|
for await (const event of stream) {
|
|
2245
|
+
collectAnthropicContent(content, event);
|
|
2021
2246
|
logProviderPayload("anthropic", "stream event", event, request.debug);
|
|
2022
|
-
|
|
2023
|
-
break;
|
|
2024
|
-
}
|
|
2247
|
+
throwIfAborted(request.signal);
|
|
2025
2248
|
switch (event.type) {
|
|
2026
2249
|
case "message_start":
|
|
2027
2250
|
if (event.message?.usage) {
|
|
2028
2251
|
usage = {
|
|
2029
|
-
prompt_tokens: event.message.usage
|
|
2252
|
+
prompt_tokens: anthropicInputTokens(event.message.usage),
|
|
2030
2253
|
completion_tokens: 0,
|
|
2031
|
-
total_tokens: event.message.usage
|
|
2254
|
+
total_tokens: anthropicInputTokens(event.message.usage)
|
|
2032
2255
|
};
|
|
2033
2256
|
}
|
|
2034
2257
|
break;
|
|
2035
2258
|
case "message_delta":
|
|
2259
|
+
if (event.delta?.stop_reason) stopReason = event.delta.stop_reason;
|
|
2036
2260
|
if (event.usage && usage) {
|
|
2037
2261
|
usage.completion_tokens = event.usage.output_tokens;
|
|
2038
2262
|
usage.total_tokens = usage.prompt_tokens + event.usage.output_tokens;
|
|
@@ -2045,13 +2269,6 @@ var AnthropicAdapter = class {
|
|
|
2045
2269
|
name: event.content_block.name,
|
|
2046
2270
|
input: ""
|
|
2047
2271
|
};
|
|
2048
|
-
if (currentToolUse.name !== "web_search") {
|
|
2049
|
-
yield {
|
|
2050
|
-
type: "action:start",
|
|
2051
|
-
id: currentToolUse.id,
|
|
2052
|
-
name: currentToolUse.name
|
|
2053
|
-
};
|
|
2054
|
-
}
|
|
2055
2272
|
} else if (event.content_block.type === "web_search_tool_result") {
|
|
2056
2273
|
const webSearchResult = event.content_block;
|
|
2057
2274
|
if (webSearchResult.content && Array.isArray(webSearchResult.content)) {
|
|
@@ -2100,16 +2317,11 @@ var AnthropicAdapter = class {
|
|
|
2100
2317
|
case "content_block_stop":
|
|
2101
2318
|
if (currentToolUse) {
|
|
2102
2319
|
if (currentToolUse.name !== "web_search") {
|
|
2103
|
-
|
|
2104
|
-
type: "action:args",
|
|
2105
|
-
id: currentToolUse.id,
|
|
2106
|
-
args: currentToolUse.input
|
|
2107
|
-
};
|
|
2108
|
-
yield {
|
|
2109
|
-
type: "action:end",
|
|
2320
|
+
toolCalls.push({
|
|
2110
2321
|
id: currentToolUse.id,
|
|
2111
|
-
name: currentToolUse.name
|
|
2112
|
-
|
|
2322
|
+
name: currentToolUse.name,
|
|
2323
|
+
args: parseToolArguments(currentToolUse.input)
|
|
2324
|
+
});
|
|
2113
2325
|
}
|
|
2114
2326
|
currentToolUse = null;
|
|
2115
2327
|
}
|
|
@@ -2122,18 +2334,33 @@ var AnthropicAdapter = class {
|
|
|
2122
2334
|
break;
|
|
2123
2335
|
}
|
|
2124
2336
|
}
|
|
2337
|
+
throwIfAborted(request.signal);
|
|
2338
|
+
if (!stopReason || currentToolUse)
|
|
2339
|
+
throw invalidProviderResponse(
|
|
2340
|
+
"Anthropic stream ended before its turn completed"
|
|
2341
|
+
);
|
|
2342
|
+
validateToolCalls(toolCalls);
|
|
2343
|
+
if (toolCalls.length && stopReason !== "tool_use")
|
|
2344
|
+
throw invalidProviderResponse(
|
|
2345
|
+
"Anthropic stream ended with incomplete tool calls"
|
|
2346
|
+
);
|
|
2347
|
+
for (const call of toolCalls) {
|
|
2348
|
+
yield { type: "action:start", id: call.id, name: call.name };
|
|
2349
|
+
yield {
|
|
2350
|
+
type: "action:args",
|
|
2351
|
+
id: call.id,
|
|
2352
|
+
args: JSON.stringify(call.args)
|
|
2353
|
+
};
|
|
2354
|
+
yield { type: "action:end", id: call.id, name: call.name };
|
|
2355
|
+
}
|
|
2125
2356
|
if (collectedCitations.length > 0) {
|
|
2126
2357
|
const uniqueCitations = deduplicateCitations2(collectedCitations);
|
|
2127
2358
|
yield { type: "citation", citations: uniqueCitations };
|
|
2128
2359
|
}
|
|
2129
2360
|
yield { type: "message:end" };
|
|
2130
|
-
yield { type: "done", usage };
|
|
2361
|
+
yield { type: "done", usage, providerMetadata: anthropicReplay(content) };
|
|
2131
2362
|
} catch (error) {
|
|
2132
|
-
yield
|
|
2133
|
-
type: "error",
|
|
2134
|
-
message: error instanceof Error ? error.message : "Unknown error",
|
|
2135
|
-
code: "ANTHROPIC_ERROR"
|
|
2136
|
-
};
|
|
2363
|
+
yield providerErrorEvent(error, "ANTHROPIC_ERROR");
|
|
2137
2364
|
}
|
|
2138
2365
|
}
|
|
2139
2366
|
};
|