@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.
Files changed (74) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +46 -10
  3. package/dist/adapters/index.d.mts +11 -13
  4. package/dist/adapters/index.d.ts +11 -13
  5. package/dist/adapters/index.js +327 -100
  6. package/dist/adapters/index.mjs +327 -100
  7. package/dist/audio-K-Z3-Bce.d.mts +191 -0
  8. package/dist/audio-K-Z3-Bce.d.ts +191 -0
  9. package/dist/{base-BICaQaRS.d.mts → base-6LzczuCg.d.ts} +8 -1
  10. package/dist/{base-CpRPB8u8.d.ts → base-DySbTP8C.d.mts} +8 -1
  11. package/dist/decisions-CJzOt87t.d.mts +137 -0
  12. package/dist/decisions-CJzOt87t.d.ts +137 -0
  13. package/dist/fallback/index.d.mts +4 -4
  14. package/dist/fallback/index.d.ts +4 -4
  15. package/dist/http-BQxUT5A9.d.mts +9 -0
  16. package/dist/http-BQxUT5A9.d.ts +9 -0
  17. package/dist/index.d.mts +14 -8
  18. package/dist/index.d.ts +14 -8
  19. package/dist/index.js +599 -195
  20. package/dist/index.mjs +596 -196
  21. package/dist/providers/anthropic/index.d.mts +7 -4
  22. package/dist/providers/anthropic/index.d.ts +7 -4
  23. package/dist/providers/anthropic/index.js +383 -102
  24. package/dist/providers/anthropic/index.mjs +383 -102
  25. package/dist/providers/azure/index.d.mts +3 -3
  26. package/dist/providers/azure/index.d.ts +3 -3
  27. package/dist/providers/cloudflare/index.d.mts +11 -0
  28. package/dist/providers/cloudflare/index.d.ts +11 -0
  29. package/dist/providers/cloudflare/index.js +743 -0
  30. package/dist/providers/cloudflare/index.mjs +741 -0
  31. package/dist/providers/fireworks/index.d.mts +3 -3
  32. package/dist/providers/fireworks/index.d.ts +3 -3
  33. package/dist/providers/fireworks/index.js +108 -59
  34. package/dist/providers/fireworks/index.mjs +108 -59
  35. package/dist/providers/google/index.d.mts +3 -3
  36. package/dist/providers/google/index.d.ts +3 -3
  37. package/dist/providers/google/index.js +108 -59
  38. package/dist/providers/google/index.mjs +108 -59
  39. package/dist/providers/ollama/index.d.mts +4 -4
  40. package/dist/providers/ollama/index.d.ts +4 -4
  41. package/dist/providers/openai/index.d.mts +38 -6
  42. package/dist/providers/openai/index.d.ts +38 -6
  43. package/dist/providers/openai/index.js +1378 -84
  44. package/dist/providers/openai/index.mjs +1376 -85
  45. package/dist/providers/openrouter/index.d.mts +21 -4
  46. package/dist/providers/openrouter/index.d.ts +21 -4
  47. package/dist/providers/openrouter/index.js +967 -130
  48. package/dist/providers/openrouter/index.mjs +967 -131
  49. package/dist/providers/togetherai/index.d.mts +3 -3
  50. package/dist/providers/togetherai/index.d.ts +3 -3
  51. package/dist/providers/togetherai/index.js +108 -59
  52. package/dist/providers/togetherai/index.mjs +108 -59
  53. package/dist/providers/typesafe/index.d.mts +8 -0
  54. package/dist/providers/typesafe/index.d.ts +8 -0
  55. package/dist/providers/typesafe/index.js +735 -0
  56. package/dist/providers/typesafe/index.mjs +733 -0
  57. package/dist/providers/xai/index.d.mts +3 -3
  58. package/dist/providers/xai/index.d.ts +3 -3
  59. package/dist/providers/xai/index.js +108 -59
  60. package/dist/providers/xai/index.mjs +108 -59
  61. package/dist/{types-DCFqkJAy.d.ts → types-B0y6VZSQ.d.ts} +1 -1
  62. package/dist/{types-DHQEMFHA.d.mts → types-BXQMtaCX.d.ts} +17 -3
  63. package/dist/{types-C3RgRbEC.d.mts → types-BY6BVhFg.d.mts} +1 -1
  64. package/dist/{types-Dikj3En4.d.ts → types-C7_qVSSd.d.mts} +17 -3
  65. package/dist/{types-Dg1Bcg1k.d.mts → types-D7lzMMLu.d.mts} +13 -1
  66. package/dist/{types-Dg1Bcg1k.d.ts → types-D7lzMMLu.d.ts} +13 -1
  67. package/dist/yourgpt/index.d.mts +1 -1
  68. package/dist/yourgpt/index.d.ts +1 -1
  69. package/docs/decisions.md +174 -0
  70. package/docs/media.md +201 -0
  71. package/docs/multimodal-and-audio.md +9 -2
  72. package/package.json +34 -12
  73. package/dist/audio-BBSwnjo8.d.mts +0 -92
  74. package/dist/audio-BBSwnjo8.d.ts +0 -92
@@ -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
- out[renamed] = stripSchemaKeys(value, keysToDrop, options);
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
- ...options?.store === false || options?.include ? {
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 new Error("OpenAI stream ended without a finish reason");
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 new Error("OpenAI stream ended with incomplete tool calls");
1488
- }
1489
- for (const call of toolCalls.values()) {
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: message?.tool_calls?.map((toolCall) => ({
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.actions?.map((action) => ({
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: request.config?.maxTokens || this.config.maxTokens || 4096,
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 = outputConfig;
1936
- }
1937
- if (this.config.thinking?.type === "enabled") {
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.input_tokens ?? 0,
2209
+ promptTokens: anthropicInputTokens(response.usage),
1991
2210
  completionTokens: response.usage.output_tokens ?? 0,
1992
- totalTokens: (response.usage.input_tokens ?? 0) + (response.usage.output_tokens ?? 0)
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
- if (request.signal?.aborted) {
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.input_tokens,
2250
+ prompt_tokens: anthropicInputTokens(event.message.usage),
2028
2251
  completion_tokens: 0,
2029
- total_tokens: event.message.usage.input_tokens
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
- yield {
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
  };