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