@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
|
@@ -87,6 +87,120 @@ function toolOutputForProvider(value, provider) {
|
|
|
87
87
|
});
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
// src/core/provider-error.ts
|
|
91
|
+
function invalidProviderResponse(message) {
|
|
92
|
+
return Object.assign(new Error(message), {
|
|
93
|
+
name: "InvalidProviderResponseError",
|
|
94
|
+
status: 502,
|
|
95
|
+
code: "INVALID_PROVIDER_RESPONSE"
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
function providerErrorEvent(error, code) {
|
|
99
|
+
const details = error ?? {};
|
|
100
|
+
const event = {
|
|
101
|
+
type: "error",
|
|
102
|
+
message: error instanceof Error ? error.message : String(error),
|
|
103
|
+
code,
|
|
104
|
+
...typeof details.status === "number" ? { status: details.status } : {},
|
|
105
|
+
...typeof details.code === "string" ? { providerCode: details.code } : {},
|
|
106
|
+
...typeof details.param === "string" ? { param: details.param } : {},
|
|
107
|
+
...typeof details.request_id === "string" ? { requestId: details.request_id } : {}
|
|
108
|
+
};
|
|
109
|
+
Object.defineProperty(event, "cause", { value: error, enumerable: false });
|
|
110
|
+
return event;
|
|
111
|
+
}
|
|
112
|
+
function throwIfAborted(signal) {
|
|
113
|
+
if (!signal?.aborted) return;
|
|
114
|
+
const error = new Error("The operation was aborted");
|
|
115
|
+
error.name = "AbortError";
|
|
116
|
+
throw error;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// src/core/tool-validation.ts
|
|
120
|
+
function parseToolArguments(value) {
|
|
121
|
+
let args = value;
|
|
122
|
+
if (typeof value === "string") {
|
|
123
|
+
try {
|
|
124
|
+
args = JSON.parse(value || "{}");
|
|
125
|
+
} catch {
|
|
126
|
+
throw invalidProviderResponse("Tool arguments are not valid JSON");
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (args === null || typeof args !== "object" || Array.isArray(args))
|
|
130
|
+
throw invalidProviderResponse("Tool arguments must be a JSON object");
|
|
131
|
+
return args;
|
|
132
|
+
}
|
|
133
|
+
function validateToolCalls(calls) {
|
|
134
|
+
const ids = /* @__PURE__ */ new Set();
|
|
135
|
+
for (const call of calls) {
|
|
136
|
+
if (!call || typeof call.id !== "string" || !call.id || typeof call.name !== "string" || !call.name || ids.has(call.id))
|
|
137
|
+
throw invalidProviderResponse(
|
|
138
|
+
"Tool calls have missing or duplicate identities"
|
|
139
|
+
);
|
|
140
|
+
ids.add(call.id);
|
|
141
|
+
if (typeof call.args === "string")
|
|
142
|
+
throw invalidProviderResponse("Parsed tool arguments must be an object");
|
|
143
|
+
parseToolArguments(call.args);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// src/core/anthropic-replay.ts
|
|
148
|
+
function anthropicReplay(content) {
|
|
149
|
+
if (!Array.isArray(content) || !content.some(
|
|
150
|
+
(b) => b?.type === "thinking" || b?.type === "redacted_thinking"
|
|
151
|
+
))
|
|
152
|
+
return void 0;
|
|
153
|
+
const blocks = content.flatMap((block) => {
|
|
154
|
+
if (block?.type === "thinking" && typeof block.thinking === "string" && typeof block.signature === "string")
|
|
155
|
+
return [
|
|
156
|
+
{
|
|
157
|
+
type: "thinking",
|
|
158
|
+
thinking: block.thinking,
|
|
159
|
+
signature: block.signature
|
|
160
|
+
}
|
|
161
|
+
];
|
|
162
|
+
if (block?.type === "redacted_thinking" && typeof block.data === "string")
|
|
163
|
+
return [{ type: "redacted_thinking", data: block.data }];
|
|
164
|
+
if (block?.type === "text" && typeof block.text === "string")
|
|
165
|
+
return [{ type: "text", text: block.text }];
|
|
166
|
+
if (block?.type === "tool_use" && typeof block.id === "string" && typeof block.name === "string")
|
|
167
|
+
return [
|
|
168
|
+
{
|
|
169
|
+
type: "tool_use",
|
|
170
|
+
id: block.id,
|
|
171
|
+
name: block.name,
|
|
172
|
+
input: block.input
|
|
173
|
+
}
|
|
174
|
+
];
|
|
175
|
+
return [];
|
|
176
|
+
});
|
|
177
|
+
return { anthropic: { content: blocks } };
|
|
178
|
+
}
|
|
179
|
+
function anthropicReplayContent(metadata) {
|
|
180
|
+
const state = metadata?.anthropic;
|
|
181
|
+
return anthropicReplay(state?.content)?.anthropic?.content;
|
|
182
|
+
}
|
|
183
|
+
function collectAnthropicContent(blocks, event) {
|
|
184
|
+
if (event.type === "content_block_start")
|
|
185
|
+
blocks[event.index] = { ...event.content_block };
|
|
186
|
+
const block = blocks[event.index];
|
|
187
|
+
if (event.type !== "content_block_delta" || !block) return;
|
|
188
|
+
const delta = event.delta;
|
|
189
|
+
if (delta.type === "thinking_delta")
|
|
190
|
+
block.thinking = (block.thinking ?? "") + delta.thinking;
|
|
191
|
+
else if (delta.type === "signature_delta")
|
|
192
|
+
block.signature = (block.signature ?? "") + delta.signature;
|
|
193
|
+
else if (delta.type === "text_delta")
|
|
194
|
+
block.text = (block.text ?? "") + delta.text;
|
|
195
|
+
else if (delta.type === "input_json_delta") {
|
|
196
|
+
block.partialInput = (block.partialInput ?? "") + delta.partial_json;
|
|
197
|
+
try {
|
|
198
|
+
block.input = JSON.parse(block.partialInput);
|
|
199
|
+
} catch {
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
90
204
|
// src/adapters/base.ts
|
|
91
205
|
function stringifyForDebug(value) {
|
|
92
206
|
return JSON.stringify(
|
|
@@ -165,7 +279,22 @@ function stripSchemaKeys(schema, keysToDrop, options = {}) {
|
|
|
165
279
|
)) {
|
|
166
280
|
if (keysToDrop.has(key)) continue;
|
|
167
281
|
const renamed = options.renameKeys?.[key] ?? key;
|
|
168
|
-
|
|
282
|
+
if ([
|
|
283
|
+
"properties",
|
|
284
|
+
"$defs",
|
|
285
|
+
"definitions",
|
|
286
|
+
"patternProperties",
|
|
287
|
+
"dependentSchemas"
|
|
288
|
+
].includes(key) && value && typeof value === "object" && !Array.isArray(value)) {
|
|
289
|
+
out[renamed] = Object.fromEntries(
|
|
290
|
+
Object.entries(value).map(([name, child]) => [
|
|
291
|
+
name,
|
|
292
|
+
stripSchemaKeys(child, keysToDrop, options)
|
|
293
|
+
])
|
|
294
|
+
);
|
|
295
|
+
} else if (["enum", "const", "default", "examples"].includes(key)) {
|
|
296
|
+
out[renamed] = value;
|
|
297
|
+
} else out[renamed] = stripSchemaKeys(value, keysToDrop, options);
|
|
169
298
|
}
|
|
170
299
|
if (options.forceAdditionalPropertiesFalse && out.type === "object") {
|
|
171
300
|
out.additionalProperties = false;
|
|
@@ -312,6 +441,14 @@ function formatMessagesForAnthropic(messages, systemPrompt) {
|
|
|
312
441
|
const msg = messages[i];
|
|
313
442
|
if (msg.role === "system") continue;
|
|
314
443
|
if (msg.role === "assistant") {
|
|
444
|
+
const replay = anthropicReplayContent(msg.providerMetadata);
|
|
445
|
+
if (replay) {
|
|
446
|
+
formatted.push({
|
|
447
|
+
role: "assistant",
|
|
448
|
+
content: replay
|
|
449
|
+
});
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
315
452
|
const content = [];
|
|
316
453
|
if (msg.content) {
|
|
317
454
|
content.push({ type: "text", text: msg.content });
|
|
@@ -366,6 +503,52 @@ function formatMessagesForAnthropic(messages, systemPrompt) {
|
|
|
366
503
|
};
|
|
367
504
|
}
|
|
368
505
|
|
|
506
|
+
// src/core/anthropic-parameters.ts
|
|
507
|
+
function anthropicMaxTokens(maxTokens, thinking) {
|
|
508
|
+
return maxTokens ?? Math.max(4096, Number(thinking?.budget_tokens ?? 0) + 1);
|
|
509
|
+
}
|
|
510
|
+
function anthropicModelRules(model) {
|
|
511
|
+
const match = /^claude-(opus|sonnet|haiku)-(\d+)(?:-(\d{1,2})(?=-|$))?(?:-|$)/i.exec(
|
|
512
|
+
model
|
|
513
|
+
);
|
|
514
|
+
const family = match?.[1]?.toLowerCase();
|
|
515
|
+
const major = Number(match?.[2] ?? 0);
|
|
516
|
+
const minor = Number(match?.[3] ?? 0);
|
|
517
|
+
const adaptive = major >= 5 || major === 4 && minor >= 6;
|
|
518
|
+
return {
|
|
519
|
+
structured: major >= 5 || major === 4 && minor >= 5,
|
|
520
|
+
thinking: major >= 4 || /^claude-3-7-/.test(model),
|
|
521
|
+
adaptive,
|
|
522
|
+
rejectsSampling: major >= 5 || family === "opus" && major === 4 && minor >= 7
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
function anthropicInputTokens(usage) {
|
|
526
|
+
return (usage?.input_tokens ?? 0) + (usage?.cache_creation_input_tokens ?? 0) + (usage?.cache_read_input_tokens ?? 0);
|
|
527
|
+
}
|
|
528
|
+
function anthropicThinking(model, thinking) {
|
|
529
|
+
if (!thinking) return void 0;
|
|
530
|
+
if (thinking.type === "enabled") {
|
|
531
|
+
if (anthropicModelRules(model).adaptive) {
|
|
532
|
+
console.warn(
|
|
533
|
+
`[llm-sdk] ${model}: using adaptive thinking instead of a legacy token budget.`
|
|
534
|
+
);
|
|
535
|
+
return { type: "adaptive" };
|
|
536
|
+
}
|
|
537
|
+
return { type: "enabled", budget_tokens: thinking.budgetTokens ?? 1e4 };
|
|
538
|
+
}
|
|
539
|
+
return { ...thinking };
|
|
540
|
+
}
|
|
541
|
+
function anthropicTemperature(model, temperature, thinking = false) {
|
|
542
|
+
if (temperature === void 0) return {};
|
|
543
|
+
if (thinking || anthropicModelRules(model).rejectsSampling) {
|
|
544
|
+
console.warn(
|
|
545
|
+
`[llm-sdk] ${model}: omitted temperature because this model or thinking mode does not support it.`
|
|
546
|
+
);
|
|
547
|
+
return {};
|
|
548
|
+
}
|
|
549
|
+
return { temperature };
|
|
550
|
+
}
|
|
551
|
+
|
|
369
552
|
// src/providers/anthropic/provider.ts
|
|
370
553
|
var ANTHROPIC_MODELS = {
|
|
371
554
|
// Claude 4 series
|
|
@@ -475,6 +658,10 @@ function anthropic(modelId, options = {}) {
|
|
|
475
658
|
return client;
|
|
476
659
|
}
|
|
477
660
|
const modelConfig = ANTHROPIC_MODELS[modelId] ?? ANTHROPIC_MODELS["claude-3-5-sonnet-latest"];
|
|
661
|
+
const thinking = anthropicThinking(
|
|
662
|
+
modelId,
|
|
663
|
+
options.thinking && ("enabled" in options.thinking ? options.thinking.enabled ? { type: "enabled", budgetTokens: options.thinking.budgetTokens } : void 0 : options.thinking)
|
|
664
|
+
);
|
|
478
665
|
return {
|
|
479
666
|
provider: "anthropic",
|
|
480
667
|
modelId,
|
|
@@ -482,8 +669,8 @@ function anthropic(modelId, options = {}) {
|
|
|
482
669
|
supportsVision: modelConfig.vision,
|
|
483
670
|
supportsTools: modelConfig.tools,
|
|
484
671
|
supportsStreaming: true,
|
|
485
|
-
supportsJsonMode:
|
|
486
|
-
supportsThinking: modelConfig.thinking,
|
|
672
|
+
supportsJsonMode: anthropicModelRules(modelId).structured,
|
|
673
|
+
supportsThinking: modelConfig.thinking || anthropicModelRules(modelId).thinking,
|
|
487
674
|
supportsPDF: modelConfig.pdf,
|
|
488
675
|
maxTokens: modelConfig.maxTokens,
|
|
489
676
|
supportedImageTypes: modelConfig.vision ? ["image/png", "image/jpeg", "image/gif", "image/webp"] : []
|
|
@@ -493,25 +680,34 @@ function anthropic(modelId, options = {}) {
|
|
|
493
680
|
const { system, messages } = formatMessagesForAnthropic2(params.messages);
|
|
494
681
|
const requestOptions = {
|
|
495
682
|
model: modelId,
|
|
496
|
-
max_tokens: params.maxTokens
|
|
683
|
+
max_tokens: anthropicMaxTokens(params.maxTokens, thinking),
|
|
497
684
|
system: system || void 0,
|
|
498
685
|
messages,
|
|
499
|
-
tools: params.tools
|
|
686
|
+
tools: params.tools,
|
|
687
|
+
...options.cacheControl ? { cache_control: { type: "ephemeral" } } : {}
|
|
500
688
|
};
|
|
501
|
-
|
|
502
|
-
requestOptions
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
type
|
|
507
|
-
|
|
508
|
-
|
|
689
|
+
Object.assign(
|
|
690
|
+
requestOptions,
|
|
691
|
+
anthropicTemperature(
|
|
692
|
+
modelId,
|
|
693
|
+
params.temperature,
|
|
694
|
+
!!thinking && thinking.type !== "disabled"
|
|
695
|
+
)
|
|
696
|
+
);
|
|
697
|
+
if (params.responseFormat?.type === "json_object") {
|
|
698
|
+
requestOptions.system = (system || "") + "\n\nRespond with a single JSON object and no other text. Do not include Markdown code fences.";
|
|
509
699
|
}
|
|
700
|
+
if (thinking) requestOptions.thinking = thinking;
|
|
510
701
|
const outputConfig = toAnthropicOutputConfig(params.responseFormat);
|
|
511
|
-
if (outputConfig) {
|
|
512
|
-
requestOptions.output_config =
|
|
702
|
+
if (outputConfig || options.effort) {
|
|
703
|
+
requestOptions.output_config = {
|
|
704
|
+
...outputConfig,
|
|
705
|
+
...options.effort ? { effort: options.effort } : {}
|
|
706
|
+
};
|
|
513
707
|
}
|
|
514
|
-
const response = await client2.messages.create(requestOptions
|
|
708
|
+
const response = await client2.messages.create(requestOptions, {
|
|
709
|
+
signal: params.signal
|
|
710
|
+
});
|
|
515
711
|
let text = "";
|
|
516
712
|
const toolCalls = [];
|
|
517
713
|
for (const block of response.content) {
|
|
@@ -525,14 +721,21 @@ function anthropic(modelId, options = {}) {
|
|
|
525
721
|
});
|
|
526
722
|
}
|
|
527
723
|
}
|
|
724
|
+
validateToolCalls(toolCalls);
|
|
725
|
+
if (toolCalls.length && response.stop_reason !== "tool_use")
|
|
726
|
+
throw invalidProviderResponse(
|
|
727
|
+
"Anthropic response ended with incomplete tool calls"
|
|
728
|
+
);
|
|
528
729
|
return {
|
|
529
730
|
text,
|
|
731
|
+
reasoningText: response.content.filter((b) => b.type === "thinking").map((b) => b.thinking).join("") || void 0,
|
|
732
|
+
providerMetadata: anthropicReplay(response.content),
|
|
530
733
|
toolCalls,
|
|
531
734
|
finishReason: mapFinishReason(response.stop_reason),
|
|
532
735
|
usage: {
|
|
533
|
-
promptTokens: response.usage
|
|
736
|
+
promptTokens: anthropicInputTokens(response.usage),
|
|
534
737
|
completionTokens: response.usage?.output_tokens ?? 0,
|
|
535
|
-
totalTokens: (response.usage
|
|
738
|
+
totalTokens: anthropicInputTokens(response.usage) + (response.usage?.output_tokens ?? 0)
|
|
536
739
|
},
|
|
537
740
|
rawResponse: response
|
|
538
741
|
};
|
|
@@ -542,37 +745,47 @@ function anthropic(modelId, options = {}) {
|
|
|
542
745
|
const { system, messages } = formatMessagesForAnthropic2(params.messages);
|
|
543
746
|
const requestOptions = {
|
|
544
747
|
model: modelId,
|
|
545
|
-
max_tokens: params.maxTokens
|
|
748
|
+
max_tokens: anthropicMaxTokens(params.maxTokens, thinking),
|
|
546
749
|
system: system || void 0,
|
|
547
750
|
messages,
|
|
548
|
-
tools: params.tools
|
|
751
|
+
tools: params.tools,
|
|
752
|
+
...options.cacheControl ? { cache_control: { type: "ephemeral" } } : {}
|
|
549
753
|
};
|
|
550
|
-
|
|
551
|
-
requestOptions
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
type
|
|
556
|
-
|
|
557
|
-
|
|
754
|
+
Object.assign(
|
|
755
|
+
requestOptions,
|
|
756
|
+
anthropicTemperature(
|
|
757
|
+
modelId,
|
|
758
|
+
params.temperature,
|
|
759
|
+
!!thinking && thinking.type !== "disabled"
|
|
760
|
+
)
|
|
761
|
+
);
|
|
762
|
+
if (params.responseFormat?.type === "json_object") {
|
|
763
|
+
requestOptions.system = (system || "") + "\n\nRespond with a single JSON object and no other text. Do not include Markdown code fences.";
|
|
558
764
|
}
|
|
765
|
+
if (thinking) requestOptions.thinking = thinking;
|
|
559
766
|
const outputConfig = toAnthropicOutputConfig(params.responseFormat);
|
|
560
|
-
if (outputConfig) {
|
|
561
|
-
requestOptions.output_config =
|
|
767
|
+
if (outputConfig || options.effort) {
|
|
768
|
+
requestOptions.output_config = {
|
|
769
|
+
...outputConfig,
|
|
770
|
+
...options.effort ? { effort: options.effort } : {}
|
|
771
|
+
};
|
|
562
772
|
}
|
|
563
|
-
const stream = await client2.messages.stream(requestOptions
|
|
773
|
+
const stream = await client2.messages.stream(requestOptions, {
|
|
774
|
+
signal: params.signal
|
|
775
|
+
});
|
|
564
776
|
let currentToolUse = null;
|
|
565
777
|
let inputTokens = 0;
|
|
566
778
|
let outputTokens = 0;
|
|
779
|
+
const content = [];
|
|
780
|
+
const toolCalls = [];
|
|
781
|
+
let stopReason;
|
|
567
782
|
for await (const event of stream) {
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
return;
|
|
571
|
-
}
|
|
783
|
+
collectAnthropicContent(content, event);
|
|
784
|
+
throwIfAborted(params.signal);
|
|
572
785
|
switch (event.type) {
|
|
573
786
|
case "message_start":
|
|
574
787
|
if (event.message?.usage) {
|
|
575
|
-
inputTokens = event.message.usage
|
|
788
|
+
inputTokens = anthropicInputTokens(event.message.usage);
|
|
576
789
|
}
|
|
577
790
|
break;
|
|
578
791
|
case "content_block_start":
|
|
@@ -587,20 +800,19 @@ function anthropic(modelId, options = {}) {
|
|
|
587
800
|
case "content_block_delta":
|
|
588
801
|
if (event.delta?.type === "text_delta") {
|
|
589
802
|
yield { type: "text-delta", text: event.delta.text };
|
|
803
|
+
} else if (event.delta?.type === "thinking_delta") {
|
|
804
|
+
yield { type: "reasoning-delta", text: event.delta.thinking };
|
|
590
805
|
} else if (event.delta?.type === "input_json_delta" && currentToolUse) {
|
|
591
806
|
currentToolUse.input += event.delta.partial_json;
|
|
592
807
|
}
|
|
593
808
|
break;
|
|
594
809
|
case "content_block_stop":
|
|
595
810
|
if (currentToolUse) {
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
args: JSON.parse(currentToolUse.input || "{}")
|
|
602
|
-
}
|
|
603
|
-
};
|
|
811
|
+
toolCalls.push({
|
|
812
|
+
id: currentToolUse.id,
|
|
813
|
+
name: currentToolUse.name,
|
|
814
|
+
args: parseToolArguments(currentToolUse.input)
|
|
815
|
+
});
|
|
604
816
|
currentToolUse = null;
|
|
605
817
|
}
|
|
606
818
|
break;
|
|
@@ -609,19 +821,32 @@ function anthropic(modelId, options = {}) {
|
|
|
609
821
|
outputTokens = event.usage.output_tokens ?? 0;
|
|
610
822
|
}
|
|
611
823
|
if (event.delta?.stop_reason) {
|
|
612
|
-
|
|
613
|
-
type: "finish",
|
|
614
|
-
finishReason: mapFinishReason(event.delta.stop_reason),
|
|
615
|
-
usage: {
|
|
616
|
-
promptTokens: inputTokens,
|
|
617
|
-
completionTokens: outputTokens,
|
|
618
|
-
totalTokens: inputTokens + outputTokens
|
|
619
|
-
}
|
|
620
|
-
};
|
|
824
|
+
stopReason = event.delta.stop_reason;
|
|
621
825
|
}
|
|
622
826
|
break;
|
|
623
827
|
}
|
|
624
828
|
}
|
|
829
|
+
throwIfAborted(params.signal);
|
|
830
|
+
if (!stopReason || currentToolUse)
|
|
831
|
+
throw invalidProviderResponse(
|
|
832
|
+
"Anthropic stream ended before its turn completed"
|
|
833
|
+
);
|
|
834
|
+
validateToolCalls(toolCalls);
|
|
835
|
+
if (toolCalls.length && stopReason !== "tool_use")
|
|
836
|
+
throw invalidProviderResponse(
|
|
837
|
+
"Anthropic stream ended with incomplete tool calls"
|
|
838
|
+
);
|
|
839
|
+
for (const toolCall of toolCalls) yield { type: "tool-call", toolCall };
|
|
840
|
+
yield {
|
|
841
|
+
type: "finish",
|
|
842
|
+
finishReason: mapFinishReason(stopReason),
|
|
843
|
+
providerMetadata: anthropicReplay(content),
|
|
844
|
+
usage: {
|
|
845
|
+
promptTokens: inputTokens,
|
|
846
|
+
completionTokens: outputTokens,
|
|
847
|
+
totalTokens: inputTokens + outputTokens
|
|
848
|
+
}
|
|
849
|
+
};
|
|
625
850
|
}
|
|
626
851
|
};
|
|
627
852
|
}
|
|
@@ -639,7 +864,7 @@ function mapFinishReason(reason) {
|
|
|
639
864
|
}
|
|
640
865
|
}
|
|
641
866
|
function formatMessagesForAnthropic2(messages) {
|
|
642
|
-
|
|
867
|
+
const system = extractAnthropicSystemPrompt(messages);
|
|
643
868
|
const formatted = [];
|
|
644
869
|
const pendingToolResults = [];
|
|
645
870
|
const flushToolResults = () => {
|
|
@@ -665,7 +890,6 @@ function formatMessagesForAnthropic2(messages) {
|
|
|
665
890
|
};
|
|
666
891
|
for (const msg of messages) {
|
|
667
892
|
if (msg.role === "system") {
|
|
668
|
-
system += (system ? "\n" : "") + msg.content;
|
|
669
893
|
continue;
|
|
670
894
|
}
|
|
671
895
|
if (msg.role === "assistant" && pendingToolResults.length > 0) {
|
|
@@ -703,6 +927,11 @@ function formatMessagesForAnthropic2(messages) {
|
|
|
703
927
|
formatted.push({ role: "user", content });
|
|
704
928
|
}
|
|
705
929
|
} else if (msg.role === "assistant") {
|
|
930
|
+
const replay = anthropicReplayContent(msg.providerMetadata);
|
|
931
|
+
if (replay) {
|
|
932
|
+
formatted.push({ role: "assistant", content: replay });
|
|
933
|
+
continue;
|
|
934
|
+
}
|
|
706
935
|
const content = [];
|
|
707
936
|
if (msg.content) {
|
|
708
937
|
content.push({ type: "text", text: msg.content });
|
|
@@ -758,7 +987,10 @@ var AnthropicAdapter = class {
|
|
|
758
987
|
if (!this.client) {
|
|
759
988
|
const { default: Anthropic } = await import('@anthropic-ai/sdk');
|
|
760
989
|
this.client = new Anthropic({
|
|
761
|
-
apiKey: this.config.apiKey
|
|
990
|
+
apiKey: this.config.apiKey,
|
|
991
|
+
baseURL: this.config.baseUrl,
|
|
992
|
+
timeout: this.config.timeout,
|
|
993
|
+
defaultHeaders: this.config.headers
|
|
762
994
|
});
|
|
763
995
|
}
|
|
764
996
|
return this.client;
|
|
@@ -795,6 +1027,15 @@ var AnthropicAdapter = class {
|
|
|
795
1027
|
lastToolCallIds = [];
|
|
796
1028
|
toolResultIndex = 0;
|
|
797
1029
|
}
|
|
1030
|
+
const replay = anthropicReplayContent(
|
|
1031
|
+
msg.providerMetadata
|
|
1032
|
+
);
|
|
1033
|
+
if (replay) {
|
|
1034
|
+
messages.push({ role: "assistant", content: replay });
|
|
1035
|
+
lastToolCallIds = replay.filter((b) => b.type === "tool_use").map((b) => b.id);
|
|
1036
|
+
toolResultIndex = 0;
|
|
1037
|
+
continue;
|
|
1038
|
+
}
|
|
798
1039
|
const content = [];
|
|
799
1040
|
if (msg.content && typeof msg.content === "string" && msg.content.trim()) {
|
|
800
1041
|
content.push({ type: "text", text: msg.content });
|
|
@@ -970,7 +1211,7 @@ var AnthropicAdapter = class {
|
|
|
970
1211
|
*/
|
|
971
1212
|
buildRequestOptions(request) {
|
|
972
1213
|
const responseFormat = request.config?.responseFormat;
|
|
973
|
-
const jsonObjectSuffix = responseFormat?.type === "json_object" ? "\n\nRespond with a single JSON object and no other text." : "";
|
|
1214
|
+
const jsonObjectSuffix = responseFormat?.type === "json_object" ? "\n\nRespond with a single JSON object and no other text. Do not include Markdown code fences." : "";
|
|
974
1215
|
let systemMessage;
|
|
975
1216
|
let messages;
|
|
976
1217
|
if (request.rawMessages && request.rawMessages.length > 0) {
|
|
@@ -992,7 +1233,17 @@ var AnthropicAdapter = class {
|
|
|
992
1233
|
const tools = anthropicNativeSearch?.enabled ? this.buildNativeSearchTools(
|
|
993
1234
|
request.toolDefinitions ?? [],
|
|
994
1235
|
anthropicNativeSearch.variant
|
|
995
|
-
) : request.
|
|
1236
|
+
) : request.toolDefinitions?.length ? request.toolDefinitions.filter((tool) => tool.available !== false).map((tool) => ({
|
|
1237
|
+
name: tool.name,
|
|
1238
|
+
description: tool.description,
|
|
1239
|
+
// Keep the original schema. Legacy ActionParameter conversion
|
|
1240
|
+
// cannot represent unions, null, or nested required constraints.
|
|
1241
|
+
input_schema: tool.inputSchema ?? {
|
|
1242
|
+
type: "object",
|
|
1243
|
+
properties: {},
|
|
1244
|
+
required: []
|
|
1245
|
+
}
|
|
1246
|
+
})) : request.actions?.map((action) => ({
|
|
996
1247
|
name: action.name,
|
|
997
1248
|
description: action.description,
|
|
998
1249
|
input_schema: {
|
|
@@ -1034,12 +1285,25 @@ var AnthropicAdapter = class {
|
|
|
1034
1285
|
};
|
|
1035
1286
|
}
|
|
1036
1287
|
}
|
|
1288
|
+
const thinking = anthropicThinking(
|
|
1289
|
+
request.config?.model || this.model,
|
|
1290
|
+
this.config.thinking
|
|
1291
|
+
);
|
|
1037
1292
|
const options = {
|
|
1038
1293
|
model: request.config?.model || this.model,
|
|
1039
|
-
max_tokens:
|
|
1294
|
+
max_tokens: anthropicMaxTokens(
|
|
1295
|
+
request.config?.maxTokens ?? this.config.maxTokens,
|
|
1296
|
+
thinking
|
|
1297
|
+
),
|
|
1040
1298
|
system: systemMessage,
|
|
1041
1299
|
messages,
|
|
1042
|
-
tools: tools.length ? tools : void 0
|
|
1300
|
+
tools: tools.length ? tools : void 0,
|
|
1301
|
+
...this.config.cacheControl ? { cache_control: { type: "ephemeral" } } : {},
|
|
1302
|
+
...anthropicTemperature(
|
|
1303
|
+
request.config?.model || this.model,
|
|
1304
|
+
request.config?.temperature ?? this.config.temperature,
|
|
1305
|
+
!!this.config.thinking && this.config.thinking.type !== "disabled"
|
|
1306
|
+
)
|
|
1043
1307
|
};
|
|
1044
1308
|
const anthropicToolOptions = request.providerToolOptions?.anthropic;
|
|
1045
1309
|
if (tools.length > 0 && anthropicToolOptions) {
|
|
@@ -1058,15 +1322,13 @@ var AnthropicAdapter = class {
|
|
|
1058
1322
|
options.server_tool_configuration = serverToolConfiguration;
|
|
1059
1323
|
}
|
|
1060
1324
|
const outputConfig = toAnthropicOutputConfig(responseFormat);
|
|
1061
|
-
if (outputConfig) {
|
|
1062
|
-
options.output_config =
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
options.thinking = {
|
|
1066
|
-
type: "enabled",
|
|
1067
|
-
budget_tokens: this.config.thinking.budgetTokens || 1e4
|
|
1325
|
+
if (outputConfig || this.config.effort) {
|
|
1326
|
+
options.output_config = {
|
|
1327
|
+
...outputConfig,
|
|
1328
|
+
...this.config.effort ? { effort: this.config.effort } : {}
|
|
1068
1329
|
};
|
|
1069
1330
|
}
|
|
1331
|
+
if (thinking) options.thinking = thinking;
|
|
1070
1332
|
return { options, messages };
|
|
1071
1333
|
}
|
|
1072
1334
|
/**
|
|
@@ -1086,7 +1348,9 @@ var AnthropicAdapter = class {
|
|
|
1086
1348
|
nonStreamingOptions,
|
|
1087
1349
|
request.debug
|
|
1088
1350
|
);
|
|
1089
|
-
const response = await client.messages.create(nonStreamingOptions
|
|
1351
|
+
const response = await client.messages.create(nonStreamingOptions, {
|
|
1352
|
+
signal: request.signal
|
|
1353
|
+
});
|
|
1090
1354
|
logProviderPayload(
|
|
1091
1355
|
"anthropic",
|
|
1092
1356
|
"response payload",
|
|
@@ -1109,14 +1373,20 @@ var AnthropicAdapter = class {
|
|
|
1109
1373
|
});
|
|
1110
1374
|
}
|
|
1111
1375
|
}
|
|
1376
|
+
validateToolCalls(toolCalls);
|
|
1377
|
+
if (toolCalls.length && response.stop_reason !== "tool_use")
|
|
1378
|
+
throw invalidProviderResponse(
|
|
1379
|
+
"Anthropic response ended with incomplete tool calls"
|
|
1380
|
+
);
|
|
1112
1381
|
return {
|
|
1113
1382
|
content,
|
|
1383
|
+
providerMetadata: anthropicReplay(response.content),
|
|
1114
1384
|
toolCalls,
|
|
1115
1385
|
thinking: thinking || void 0,
|
|
1116
1386
|
usage: response.usage ? {
|
|
1117
|
-
promptTokens: response.usage
|
|
1387
|
+
promptTokens: anthropicInputTokens(response.usage),
|
|
1118
1388
|
completionTokens: response.usage.output_tokens ?? 0,
|
|
1119
|
-
totalTokens: (response.usage
|
|
1389
|
+
totalTokens: anthropicInputTokens(response.usage) + (response.usage.output_tokens ?? 0)
|
|
1120
1390
|
} : void 0,
|
|
1121
1391
|
rawResponse: response
|
|
1122
1392
|
};
|
|
@@ -1136,28 +1406,33 @@ var AnthropicAdapter = class {
|
|
|
1136
1406
|
options,
|
|
1137
1407
|
request.debug
|
|
1138
1408
|
);
|
|
1139
|
-
const stream = await client.messages.stream(options
|
|
1409
|
+
const stream = await client.messages.stream(options, {
|
|
1410
|
+
signal: request.signal
|
|
1411
|
+
});
|
|
1140
1412
|
let currentToolUse = null;
|
|
1141
1413
|
let isInThinkingBlock = false;
|
|
1414
|
+
const content = [];
|
|
1415
|
+
const toolCalls = [];
|
|
1416
|
+
let stopReason;
|
|
1142
1417
|
const collectedCitations = [];
|
|
1143
1418
|
let citationIndex = 0;
|
|
1144
1419
|
let usage;
|
|
1145
1420
|
for await (const event of stream) {
|
|
1421
|
+
collectAnthropicContent(content, event);
|
|
1146
1422
|
logProviderPayload("anthropic", "stream event", event, request.debug);
|
|
1147
|
-
|
|
1148
|
-
break;
|
|
1149
|
-
}
|
|
1423
|
+
throwIfAborted(request.signal);
|
|
1150
1424
|
switch (event.type) {
|
|
1151
1425
|
case "message_start":
|
|
1152
1426
|
if (event.message?.usage) {
|
|
1153
1427
|
usage = {
|
|
1154
|
-
prompt_tokens: event.message.usage
|
|
1428
|
+
prompt_tokens: anthropicInputTokens(event.message.usage),
|
|
1155
1429
|
completion_tokens: 0,
|
|
1156
|
-
total_tokens: event.message.usage
|
|
1430
|
+
total_tokens: anthropicInputTokens(event.message.usage)
|
|
1157
1431
|
};
|
|
1158
1432
|
}
|
|
1159
1433
|
break;
|
|
1160
1434
|
case "message_delta":
|
|
1435
|
+
if (event.delta?.stop_reason) stopReason = event.delta.stop_reason;
|
|
1161
1436
|
if (event.usage && usage) {
|
|
1162
1437
|
usage.completion_tokens = event.usage.output_tokens;
|
|
1163
1438
|
usage.total_tokens = usage.prompt_tokens + event.usage.output_tokens;
|
|
@@ -1170,13 +1445,6 @@ var AnthropicAdapter = class {
|
|
|
1170
1445
|
name: event.content_block.name,
|
|
1171
1446
|
input: ""
|
|
1172
1447
|
};
|
|
1173
|
-
if (currentToolUse.name !== "web_search") {
|
|
1174
|
-
yield {
|
|
1175
|
-
type: "action:start",
|
|
1176
|
-
id: currentToolUse.id,
|
|
1177
|
-
name: currentToolUse.name
|
|
1178
|
-
};
|
|
1179
|
-
}
|
|
1180
1448
|
} else if (event.content_block.type === "web_search_tool_result") {
|
|
1181
1449
|
const webSearchResult = event.content_block;
|
|
1182
1450
|
if (webSearchResult.content && Array.isArray(webSearchResult.content)) {
|
|
@@ -1225,16 +1493,11 @@ var AnthropicAdapter = class {
|
|
|
1225
1493
|
case "content_block_stop":
|
|
1226
1494
|
if (currentToolUse) {
|
|
1227
1495
|
if (currentToolUse.name !== "web_search") {
|
|
1228
|
-
|
|
1229
|
-
type: "action:args",
|
|
1496
|
+
toolCalls.push({
|
|
1230
1497
|
id: currentToolUse.id,
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
type: "action:end",
|
|
1235
|
-
id: currentToolUse.id,
|
|
1236
|
-
name: currentToolUse.name
|
|
1237
|
-
};
|
|
1498
|
+
name: currentToolUse.name,
|
|
1499
|
+
args: parseToolArguments(currentToolUse.input)
|
|
1500
|
+
});
|
|
1238
1501
|
}
|
|
1239
1502
|
currentToolUse = null;
|
|
1240
1503
|
}
|
|
@@ -1247,18 +1510,33 @@ var AnthropicAdapter = class {
|
|
|
1247
1510
|
break;
|
|
1248
1511
|
}
|
|
1249
1512
|
}
|
|
1513
|
+
throwIfAborted(request.signal);
|
|
1514
|
+
if (!stopReason || currentToolUse)
|
|
1515
|
+
throw invalidProviderResponse(
|
|
1516
|
+
"Anthropic stream ended before its turn completed"
|
|
1517
|
+
);
|
|
1518
|
+
validateToolCalls(toolCalls);
|
|
1519
|
+
if (toolCalls.length && stopReason !== "tool_use")
|
|
1520
|
+
throw invalidProviderResponse(
|
|
1521
|
+
"Anthropic stream ended with incomplete tool calls"
|
|
1522
|
+
);
|
|
1523
|
+
for (const call of toolCalls) {
|
|
1524
|
+
yield { type: "action:start", id: call.id, name: call.name };
|
|
1525
|
+
yield {
|
|
1526
|
+
type: "action:args",
|
|
1527
|
+
id: call.id,
|
|
1528
|
+
args: JSON.stringify(call.args)
|
|
1529
|
+
};
|
|
1530
|
+
yield { type: "action:end", id: call.id, name: call.name };
|
|
1531
|
+
}
|
|
1250
1532
|
if (collectedCitations.length > 0) {
|
|
1251
1533
|
const uniqueCitations = deduplicateCitations(collectedCitations);
|
|
1252
1534
|
yield { type: "citation", citations: uniqueCitations };
|
|
1253
1535
|
}
|
|
1254
1536
|
yield { type: "message:end" };
|
|
1255
|
-
yield { type: "done", usage };
|
|
1537
|
+
yield { type: "done", usage, providerMetadata: anthropicReplay(content) };
|
|
1256
1538
|
} catch (error) {
|
|
1257
|
-
yield
|
|
1258
|
-
type: "error",
|
|
1259
|
-
message: error instanceof Error ? error.message : "Unknown error",
|
|
1260
|
-
code: "ANTHROPIC_ERROR"
|
|
1261
|
-
};
|
|
1539
|
+
yield providerErrorEvent(error, "ANTHROPIC_ERROR");
|
|
1262
1540
|
}
|
|
1263
1541
|
}
|
|
1264
1542
|
};
|
|
@@ -1374,7 +1652,11 @@ function createAnthropic(config = {}) {
|
|
|
1374
1652
|
apiKey,
|
|
1375
1653
|
model: modelId,
|
|
1376
1654
|
baseUrl: config.baseUrl,
|
|
1377
|
-
|
|
1655
|
+
timeout: config.timeout,
|
|
1656
|
+
headers: config.headers,
|
|
1657
|
+
cacheControl: config.cacheControl,
|
|
1658
|
+
thinking: config.thinking ?? (config.thinkingBudget ? { type: "enabled", budgetTokens: config.thinkingBudget } : void 0),
|
|
1659
|
+
effort: config.effort
|
|
1378
1660
|
});
|
|
1379
1661
|
};
|
|
1380
1662
|
const getCapabilities = (modelId) => {
|
|
@@ -1382,7 +1664,7 @@ function createAnthropic(config = {}) {
|
|
|
1382
1664
|
return {
|
|
1383
1665
|
supportsVision: model.vision,
|
|
1384
1666
|
supportsTools: model.tools,
|
|
1385
|
-
supportsThinking:
|
|
1667
|
+
supportsThinking: anthropicModelRules(modelId).thinking,
|
|
1386
1668
|
supportsStreaming: true,
|
|
1387
1669
|
supportsPDF: true,
|
|
1388
1670
|
supportsAudio: false,
|
|
@@ -1394,8 +1676,7 @@ function createAnthropic(config = {}) {
|
|
|
1394
1676
|
"image/gif",
|
|
1395
1677
|
"image/webp"
|
|
1396
1678
|
],
|
|
1397
|
-
|
|
1398
|
-
supportsJsonMode: true,
|
|
1679
|
+
supportsJsonMode: anthropicModelRules(modelId).structured,
|
|
1399
1680
|
supportsSystemMessages: true
|
|
1400
1681
|
};
|
|
1401
1682
|
};
|