@nodetool-ai/runtime 0.7.0-rc.23 → 0.8.1

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 (665) hide show
  1. package/README.md +29 -0
  2. package/dist/.nodetool-build-stamp +1 -0
  3. package/dist/agent-memory.d.ts +118 -0
  4. package/dist/agent-memory.d.ts.map +1 -0
  5. package/dist/agent-memory.js +186 -0
  6. package/dist/agent-memory.js.map +1 -0
  7. package/dist/async-local-storage.d.ts +20 -0
  8. package/dist/async-local-storage.d.ts.map +1 -0
  9. package/dist/async-local-storage.js +28 -0
  10. package/dist/async-local-storage.js.map +1 -0
  11. package/dist/blender-executor.d.ts +93 -0
  12. package/dist/blender-executor.d.ts.map +1 -0
  13. package/dist/blender-executor.js +294 -0
  14. package/dist/blender-executor.js.map +1 -0
  15. package/dist/comfy-executor.d.ts +23 -1
  16. package/dist/comfy-executor.d.ts.map +1 -1
  17. package/dist/comfy-executor.js +234 -55
  18. package/dist/comfy-executor.js.map +1 -1
  19. package/dist/context-packer.d.ts +1 -1
  20. package/dist/context-packer.d.ts.map +1 -1
  21. package/dist/context-packer.js +23 -25
  22. package/dist/context-packer.js.map +1 -1
  23. package/dist/context.d.ts +954 -127
  24. package/dist/context.d.ts.map +1 -1
  25. package/dist/context.js +2424 -513
  26. package/dist/context.js.map +1 -1
  27. package/dist/cost-reconciler.d.ts +32 -0
  28. package/dist/cost-reconciler.d.ts.map +1 -0
  29. package/dist/cost-reconciler.js +21 -0
  30. package/dist/cost-reconciler.js.map +1 -0
  31. package/dist/entities.d.ts +33 -0
  32. package/dist/entities.d.ts.map +1 -0
  33. package/dist/entities.js +43 -0
  34. package/dist/entities.js.map +1 -0
  35. package/dist/external-media-fetch.d.ts +29 -0
  36. package/dist/external-media-fetch.d.ts.map +1 -0
  37. package/dist/external-media-fetch.js +38 -0
  38. package/dist/external-media-fetch.js.map +1 -0
  39. package/dist/generation-receipt.d.ts +86 -0
  40. package/dist/generation-receipt.d.ts.map +1 -0
  41. package/dist/generation-receipt.js +137 -0
  42. package/dist/generation-receipt.js.map +1 -0
  43. package/dist/generation-registry.d.ts +67 -0
  44. package/dist/generation-registry.d.ts.map +1 -0
  45. package/dist/generation-registry.js +126 -0
  46. package/dist/generation-registry.js.map +1 -0
  47. package/dist/google/client.d.ts +196 -0
  48. package/dist/google/client.d.ts.map +1 -0
  49. package/dist/google/client.js +396 -0
  50. package/dist/google/client.js.map +1 -0
  51. package/dist/google/index.d.ts +3 -0
  52. package/dist/google/index.d.ts.map +1 -0
  53. package/dist/google/index.js +3 -0
  54. package/dist/google/index.js.map +1 -0
  55. package/dist/google/token.d.ts +15 -0
  56. package/dist/google/token.d.ts.map +1 -0
  57. package/dist/google/token.js +24 -0
  58. package/dist/google/token.js.map +1 -0
  59. package/dist/host-binaries.d.ts +106 -0
  60. package/dist/host-binaries.d.ts.map +1 -0
  61. package/dist/host-binaries.js +344 -0
  62. package/dist/host-binaries.js.map +1 -0
  63. package/dist/image-codec.d.ts +74 -0
  64. package/dist/image-codec.d.ts.map +1 -0
  65. package/dist/image-codec.js +273 -0
  66. package/dist/image-codec.js.map +1 -0
  67. package/dist/index.d.ts +56 -6
  68. package/dist/index.d.ts.map +1 -1
  69. package/dist/index.js +43 -4
  70. package/dist/index.js.map +1 -1
  71. package/dist/invocation-account.d.ts +43 -0
  72. package/dist/invocation-account.d.ts.map +1 -0
  73. package/dist/invocation-account.js +60 -0
  74. package/dist/invocation-account.js.map +1 -0
  75. package/dist/media-ref-bytes.d.ts +19 -0
  76. package/dist/media-ref-bytes.d.ts.map +1 -0
  77. package/dist/media-ref-bytes.js +181 -0
  78. package/dist/media-ref-bytes.js.map +1 -0
  79. package/dist/node-executor.d.ts +113 -2
  80. package/dist/node-executor.d.ts.map +1 -1
  81. package/dist/permission-gate.d.ts +152 -0
  82. package/dist/permission-gate.d.ts.map +1 -0
  83. package/dist/permission-gate.js +87 -0
  84. package/dist/permission-gate.js.map +1 -0
  85. package/dist/prefixed-storage-adapter.d.ts +33 -0
  86. package/dist/prefixed-storage-adapter.d.ts.map +1 -0
  87. package/dist/prefixed-storage-adapter.js +70 -0
  88. package/dist/prefixed-storage-adapter.js.map +1 -0
  89. package/dist/prompt-asset-refs.d.ts +222 -0
  90. package/dist/prompt-asset-refs.d.ts.map +1 -0
  91. package/dist/prompt-asset-refs.js +751 -0
  92. package/dist/prompt-asset-refs.js.map +1 -0
  93. package/dist/provider-cache.d.ts +3 -0
  94. package/dist/provider-cache.d.ts.map +1 -0
  95. package/dist/provider-cache.js +8 -0
  96. package/dist/provider-cache.js.map +1 -0
  97. package/dist/providers/aki-provider.d.ts +33 -10
  98. package/dist/providers/aki-provider.d.ts.map +1 -1
  99. package/dist/providers/aki-provider.js +84 -77
  100. package/dist/providers/aki-provider.js.map +1 -1
  101. package/dist/providers/alibaba-provider.d.ts +39 -0
  102. package/dist/providers/alibaba-provider.d.ts.map +1 -0
  103. package/dist/providers/alibaba-provider.js +86 -0
  104. package/dist/providers/alibaba-provider.js.map +1 -0
  105. package/dist/providers/anthropic-provider.d.ts +52 -3
  106. package/dist/providers/anthropic-provider.d.ts.map +1 -1
  107. package/dist/providers/anthropic-provider.js +1020 -338
  108. package/dist/providers/anthropic-provider.js.map +1 -1
  109. package/dist/providers/atlascloud-provider.d.ts +101 -0
  110. package/dist/providers/atlascloud-provider.d.ts.map +1 -0
  111. package/dist/providers/atlascloud-provider.js +1009 -0
  112. package/dist/providers/atlascloud-provider.js.map +1 -0
  113. package/dist/providers/atlascloud-transport.d.ts +100 -0
  114. package/dist/providers/atlascloud-transport.d.ts.map +1 -0
  115. package/dist/providers/atlascloud-transport.js +364 -0
  116. package/dist/providers/atlascloud-transport.js.map +1 -0
  117. package/dist/providers/atlascloud-webhook-registry.d.ts +35 -0
  118. package/dist/providers/atlascloud-webhook-registry.d.ts.map +1 -0
  119. package/dist/providers/atlascloud-webhook-registry.js +104 -0
  120. package/dist/providers/atlascloud-webhook-registry.js.map +1 -0
  121. package/dist/providers/audio-mime.d.ts +11 -0
  122. package/dist/providers/audio-mime.d.ts.map +1 -0
  123. package/dist/providers/audio-mime.js +46 -0
  124. package/dist/providers/audio-mime.js.map +1 -0
  125. package/dist/providers/base-provider.d.ts +481 -24
  126. package/dist/providers/base-provider.d.ts.map +1 -1
  127. package/dist/providers/base-provider.js +1259 -42
  128. package/dist/providers/base-provider.js.map +1 -1
  129. package/dist/providers/cassette-provider.d.ts +217 -0
  130. package/dist/providers/cassette-provider.d.ts.map +1 -0
  131. package/dist/providers/cassette-provider.js +502 -0
  132. package/dist/providers/cassette-provider.js.map +1 -0
  133. package/dist/providers/cerebras-provider.d.ts +6 -12
  134. package/dist/providers/cerebras-provider.d.ts.map +1 -1
  135. package/dist/providers/cerebras-provider.js +8 -33
  136. package/dist/providers/cerebras-provider.js.map +1 -1
  137. package/dist/providers/claude-agent-provider.d.ts +131 -68
  138. package/dist/providers/claude-agent-provider.d.ts.map +1 -1
  139. package/dist/providers/claude-agent-provider.js +1095 -515
  140. package/dist/providers/claude-agent-provider.js.map +1 -1
  141. package/dist/providers/codex-provider.d.ts +82 -0
  142. package/dist/providers/codex-provider.d.ts.map +1 -0
  143. package/dist/providers/codex-provider.js +492 -0
  144. package/dist/providers/codex-provider.js.map +1 -0
  145. package/dist/providers/cohere-provider.d.ts +5 -2
  146. package/dist/providers/cohere-provider.d.ts.map +1 -1
  147. package/dist/providers/cohere-provider.js +9 -2
  148. package/dist/providers/cohere-provider.js.map +1 -1
  149. package/dist/providers/comfy-cloud-provider.d.ts +30 -0
  150. package/dist/providers/comfy-cloud-provider.d.ts.map +1 -0
  151. package/dist/providers/comfy-cloud-provider.js +42 -0
  152. package/dist/providers/comfy-cloud-provider.js.map +1 -0
  153. package/dist/providers/content-filter.d.ts +46 -0
  154. package/dist/providers/content-filter.d.ts.map +1 -0
  155. package/dist/providers/content-filter.js +92 -0
  156. package/dist/providers/content-filter.js.map +1 -0
  157. package/dist/providers/context-exceeded.d.ts +37 -0
  158. package/dist/providers/context-exceeded.d.ts.map +1 -0
  159. package/dist/providers/context-exceeded.js +114 -0
  160. package/dist/providers/context-exceeded.js.map +1 -0
  161. package/dist/providers/context-window.d.ts +44 -0
  162. package/dist/providers/context-window.d.ts.map +1 -0
  163. package/dist/providers/context-window.js +145 -0
  164. package/dist/providers/context-window.js.map +1 -0
  165. package/dist/providers/contract/index.d.ts +4 -0
  166. package/dist/providers/contract/index.d.ts.map +1 -0
  167. package/dist/providers/contract/index.js +4 -0
  168. package/dist/providers/contract/index.js.map +1 -0
  169. package/dist/providers/contract/probe-manifest.d.ts +75 -0
  170. package/dist/providers/contract/probe-manifest.d.ts.map +1 -0
  171. package/dist/providers/contract/probe-manifest.js +379 -0
  172. package/dist/providers/contract/probe-manifest.js.map +1 -0
  173. package/dist/providers/contract/probe-runner.d.ts +57 -0
  174. package/dist/providers/contract/probe-runner.d.ts.map +1 -0
  175. package/dist/providers/contract/probe-runner.js +180 -0
  176. package/dist/providers/contract/probe-runner.js.map +1 -0
  177. package/dist/providers/contract/redact.d.ts +29 -0
  178. package/dist/providers/contract/redact.d.ts.map +1 -0
  179. package/dist/providers/contract/redact.js +113 -0
  180. package/dist/providers/contract/redact.js.map +1 -0
  181. package/dist/providers/core-tools.d.ts +74 -0
  182. package/dist/providers/core-tools.d.ts.map +1 -0
  183. package/dist/providers/core-tools.js +127 -0
  184. package/dist/providers/core-tools.js.map +1 -0
  185. package/dist/providers/cost-calculator.d.ts +69 -50
  186. package/dist/providers/cost-calculator.d.ts.map +1 -1
  187. package/dist/providers/cost-calculator.js +207 -397
  188. package/dist/providers/cost-calculator.js.map +1 -1
  189. package/dist/providers/credential-check.d.ts +45 -0
  190. package/dist/providers/credential-check.d.ts.map +1 -0
  191. package/dist/providers/credential-check.js +159 -0
  192. package/dist/providers/credential-check.js.map +1 -0
  193. package/dist/providers/custom-model-kinds.d.ts +33 -0
  194. package/dist/providers/custom-model-kinds.d.ts.map +1 -0
  195. package/dist/providers/custom-model-kinds.js +96 -0
  196. package/dist/providers/custom-model-kinds.js.map +1 -0
  197. package/dist/providers/custom-openai-provider.d.ts +81 -0
  198. package/dist/providers/custom-openai-provider.d.ts.map +1 -0
  199. package/dist/providers/custom-openai-provider.js +182 -0
  200. package/dist/providers/custom-openai-provider.js.map +1 -0
  201. package/dist/providers/custom-provider-registry.d.ts +19 -0
  202. package/dist/providers/custom-provider-registry.d.ts.map +1 -0
  203. package/dist/providers/custom-provider-registry.js +52 -0
  204. package/dist/providers/custom-provider-registry.js.map +1 -0
  205. package/dist/providers/deepseek-provider.d.ts +8 -14
  206. package/dist/providers/deepseek-provider.d.ts.map +1 -1
  207. package/dist/providers/deepseek-provider.js +6 -35
  208. package/dist/providers/deepseek-provider.js.map +1 -1
  209. package/dist/providers/defaults.d.ts +12 -0
  210. package/dist/providers/defaults.d.ts.map +1 -0
  211. package/dist/providers/defaults.js +12 -0
  212. package/dist/providers/defaults.js.map +1 -0
  213. package/dist/providers/elevenlabs-provider.d.ts +49 -0
  214. package/dist/providers/elevenlabs-provider.d.ts.map +1 -0
  215. package/dist/providers/elevenlabs-provider.js +142 -0
  216. package/dist/providers/elevenlabs-provider.js.map +1 -0
  217. package/dist/providers/entity-references.d.ts +31 -0
  218. package/dist/providers/entity-references.d.ts.map +1 -0
  219. package/dist/providers/entity-references.js +113 -0
  220. package/dist/providers/entity-references.js.map +1 -0
  221. package/dist/providers/evolink-provider.d.ts +38 -0
  222. package/dist/providers/evolink-provider.d.ts.map +1 -0
  223. package/dist/providers/evolink-provider.js +304 -0
  224. package/dist/providers/evolink-provider.js.map +1 -0
  225. package/dist/providers/fake-provider.d.ts +72 -1
  226. package/dist/providers/fake-provider.d.ts.map +1 -1
  227. package/dist/providers/fake-provider.js +203 -1
  228. package/dist/providers/fake-provider.js.map +1 -1
  229. package/dist/providers/fal-generations.d.ts +106 -0
  230. package/dist/providers/fal-generations.d.ts.map +1 -0
  231. package/dist/providers/fal-generations.js +286 -0
  232. package/dist/providers/fal-generations.js.map +1 -0
  233. package/dist/providers/fal-provider.d.ts +171 -7
  234. package/dist/providers/fal-provider.d.ts.map +1 -1
  235. package/dist/providers/fal-provider.js +1369 -64
  236. package/dist/providers/fal-provider.js.map +1 -1
  237. package/dist/providers/fal-queue.d.ts +47 -0
  238. package/dist/providers/fal-queue.d.ts.map +1 -0
  239. package/dist/providers/fal-queue.js +231 -0
  240. package/dist/providers/fal-queue.js.map +1 -0
  241. package/dist/providers/gemini-provider.d.ts +148 -8
  242. package/dist/providers/gemini-provider.d.ts.map +1 -1
  243. package/dist/providers/gemini-provider.js +1500 -316
  244. package/dist/providers/gemini-provider.js.map +1 -1
  245. package/dist/providers/gmi-provider.d.ts +21 -0
  246. package/dist/providers/gmi-provider.d.ts.map +1 -0
  247. package/dist/providers/gmi-provider.js +34 -0
  248. package/dist/providers/gmi-provider.js.map +1 -0
  249. package/dist/providers/gpt-image-size.d.ts +3 -0
  250. package/dist/providers/gpt-image-size.d.ts.map +1 -0
  251. package/dist/providers/gpt-image-size.js +37 -0
  252. package/dist/providers/gpt-image-size.js.map +1 -0
  253. package/dist/providers/groq-provider.d.ts +9 -12
  254. package/dist/providers/groq-provider.d.ts.map +1 -1
  255. package/dist/providers/groq-provider.js +19 -33
  256. package/dist/providers/groq-provider.js.map +1 -1
  257. package/dist/providers/groq-request.d.ts +38 -0
  258. package/dist/providers/groq-request.d.ts.map +1 -0
  259. package/dist/providers/groq-request.js +138 -0
  260. package/dist/providers/groq-request.js.map +1 -0
  261. package/dist/providers/higgsfield-provider.d.ts +30 -0
  262. package/dist/providers/higgsfield-provider.d.ts.map +1 -0
  263. package/dist/providers/higgsfield-provider.js +131 -0
  264. package/dist/providers/higgsfield-provider.js.map +1 -0
  265. package/dist/providers/higgsfield-transport.d.ts +106 -0
  266. package/dist/providers/higgsfield-transport.d.ts.map +1 -0
  267. package/dist/providers/higgsfield-transport.js +182 -0
  268. package/dist/providers/higgsfield-transport.js.map +1 -0
  269. package/dist/providers/http-transport.d.ts +74 -0
  270. package/dist/providers/http-transport.d.ts.map +1 -0
  271. package/dist/providers/http-transport.js +152 -0
  272. package/dist/providers/http-transport.js.map +1 -0
  273. package/dist/providers/huggingface-provider.d.ts +71 -3
  274. package/dist/providers/huggingface-provider.d.ts.map +1 -1
  275. package/dist/providers/huggingface-provider.js +230 -34
  276. package/dist/providers/huggingface-provider.js.map +1 -1
  277. package/dist/providers/image-mime.d.ts +39 -0
  278. package/dist/providers/image-mime.d.ts.map +1 -0
  279. package/dist/providers/image-mime.js +111 -0
  280. package/dist/providers/image-mime.js.map +1 -0
  281. package/dist/providers/image-ref.d.ts +21 -0
  282. package/dist/providers/image-ref.d.ts.map +1 -0
  283. package/dist/providers/image-ref.js +44 -0
  284. package/dist/providers/image-ref.js.map +1 -0
  285. package/dist/providers/index.d.ts +84 -8
  286. package/dist/providers/index.d.ts.map +1 -1
  287. package/dist/providers/index.js +239 -56
  288. package/dist/providers/index.js.map +1 -1
  289. package/dist/providers/jina-provider.d.ts +10 -2
  290. package/dist/providers/jina-provider.d.ts.map +1 -1
  291. package/dist/providers/jina-provider.js +16 -7
  292. package/dist/providers/jina-provider.js.map +1 -1
  293. package/dist/providers/kie-provider.d.ts +170 -9
  294. package/dist/providers/kie-provider.d.ts.map +1 -1
  295. package/dist/providers/kie-provider.js +1176 -228
  296. package/dist/providers/kie-provider.js.map +1 -1
  297. package/dist/providers/kie-webhook-registry.d.ts +28 -0
  298. package/dist/providers/kie-webhook-registry.d.ts.map +1 -0
  299. package/dist/providers/kie-webhook-registry.js +91 -0
  300. package/dist/providers/kie-webhook-registry.js.map +1 -0
  301. package/dist/providers/llama-provider.d.ts +21 -37
  302. package/dist/providers/llama-provider.d.ts.map +1 -1
  303. package/dist/providers/llama-provider.js +43 -354
  304. package/dist/providers/llama-provider.js.map +1 -1
  305. package/dist/providers/lmstudio-provider.d.ts +4 -7
  306. package/dist/providers/lmstudio-provider.d.ts.map +1 -1
  307. package/dist/providers/lmstudio-provider.js +24 -15
  308. package/dist/providers/lmstudio-provider.js.map +1 -1
  309. package/dist/providers/manifest-models.d.ts +341 -1
  310. package/dist/providers/manifest-models.d.ts.map +1 -1
  311. package/dist/providers/manifest-models.js +1106 -22
  312. package/dist/providers/manifest-models.js.map +1 -1
  313. package/dist/providers/media-mime.d.ts +14 -0
  314. package/dist/providers/media-mime.d.ts.map +1 -0
  315. package/dist/providers/media-mime.js +35 -0
  316. package/dist/providers/media-mime.js.map +1 -0
  317. package/dist/providers/meshy-provider.d.ts +14 -1
  318. package/dist/providers/meshy-provider.d.ts.map +1 -1
  319. package/dist/providers/meshy-provider.js +76 -46
  320. package/dist/providers/meshy-provider.js.map +1 -1
  321. package/dist/providers/meta-provider.d.ts +22 -0
  322. package/dist/providers/meta-provider.d.ts.map +1 -0
  323. package/dist/providers/meta-provider.js +54 -0
  324. package/dist/providers/meta-provider.js.map +1 -0
  325. package/dist/providers/minimax-provider.d.ts +25 -18
  326. package/dist/providers/minimax-provider.d.ts.map +1 -1
  327. package/dist/providers/minimax-provider.js +211 -72
  328. package/dist/providers/minimax-provider.js.map +1 -1
  329. package/dist/providers/mistral-provider.d.ts +6 -12
  330. package/dist/providers/mistral-provider.d.ts.map +1 -1
  331. package/dist/providers/mistral-provider.js +10 -34
  332. package/dist/providers/mistral-provider.js.map +1 -1
  333. package/dist/providers/moonshot-provider.d.ts +11 -15
  334. package/dist/providers/moonshot-provider.d.ts.map +1 -1
  335. package/dist/providers/moonshot-provider.js +33 -23
  336. package/dist/providers/moonshot-provider.js.map +1 -1
  337. package/dist/providers/node-llama-cpp-provider.d.ts +98 -0
  338. package/dist/providers/node-llama-cpp-provider.d.ts.map +1 -0
  339. package/dist/providers/node-llama-cpp-provider.js +479 -0
  340. package/dist/providers/node-llama-cpp-provider.js.map +1 -0
  341. package/dist/providers/nodetool-provider.d.ts +49 -0
  342. package/dist/providers/nodetool-provider.d.ts.map +1 -0
  343. package/dist/providers/nodetool-provider.js +224 -0
  344. package/dist/providers/nodetool-provider.js.map +1 -0
  345. package/dist/providers/oauth/browser-launcher.d.ts +23 -0
  346. package/dist/providers/oauth/browser-launcher.d.ts.map +1 -0
  347. package/dist/providers/oauth/browser-launcher.js +45 -0
  348. package/dist/providers/oauth/browser-launcher.js.map +1 -0
  349. package/dist/providers/oauth/claude-code-credentials.d.ts +74 -0
  350. package/dist/providers/oauth/claude-code-credentials.d.ts.map +1 -0
  351. package/dist/providers/oauth/claude-code-credentials.js +133 -0
  352. package/dist/providers/oauth/claude-code-credentials.js.map +1 -0
  353. package/dist/providers/oauth/claude-code-login.d.ts +124 -0
  354. package/dist/providers/oauth/claude-code-login.d.ts.map +1 -0
  355. package/dist/providers/oauth/claude-code-login.js +230 -0
  356. package/dist/providers/oauth/claude-code-login.js.map +1 -0
  357. package/dist/providers/oauth/claude-code-oauth-client.d.ts +111 -0
  358. package/dist/providers/oauth/claude-code-oauth-client.d.ts.map +1 -0
  359. package/dist/providers/oauth/claude-code-oauth-client.js +207 -0
  360. package/dist/providers/oauth/claude-code-oauth-client.js.map +1 -0
  361. package/dist/providers/oauth/errors.d.ts +54 -0
  362. package/dist/providers/oauth/errors.d.ts.map +1 -0
  363. package/dist/providers/oauth/errors.js +79 -0
  364. package/dist/providers/oauth/errors.js.map +1 -0
  365. package/dist/providers/oauth/index.d.ts +105 -0
  366. package/dist/providers/oauth/index.d.ts.map +1 -0
  367. package/dist/providers/oauth/index.js +167 -0
  368. package/dist/providers/oauth/index.js.map +1 -0
  369. package/dist/providers/oauth/jwt-claims.d.ts +23 -0
  370. package/dist/providers/oauth/jwt-claims.d.ts.map +1 -0
  371. package/dist/providers/oauth/jwt-claims.js +67 -0
  372. package/dist/providers/oauth/jwt-claims.js.map +1 -0
  373. package/dist/providers/oauth/local-callback-server.d.ts +60 -0
  374. package/dist/providers/oauth/local-callback-server.d.ts.map +1 -0
  375. package/dist/providers/oauth/local-callback-server.js +148 -0
  376. package/dist/providers/oauth/local-callback-server.js.map +1 -0
  377. package/dist/providers/oauth/oauth-client.d.ts +55 -0
  378. package/dist/providers/oauth/oauth-client.d.ts.map +1 -0
  379. package/dist/providers/oauth/oauth-client.js +161 -0
  380. package/dist/providers/oauth/oauth-client.js.map +1 -0
  381. package/dist/providers/oauth/openai-oauth-provider.d.ts +129 -0
  382. package/dist/providers/oauth/openai-oauth-provider.d.ts.map +1 -0
  383. package/dist/providers/oauth/openai-oauth-provider.js +265 -0
  384. package/dist/providers/oauth/openai-oauth-provider.js.map +1 -0
  385. package/dist/providers/oauth/pkce-helper.d.ts +43 -0
  386. package/dist/providers/oauth/pkce-helper.d.ts.map +1 -0
  387. package/dist/providers/oauth/pkce-helper.js +57 -0
  388. package/dist/providers/oauth/pkce-helper.js.map +1 -0
  389. package/dist/providers/oauth/redaction.d.ts +22 -0
  390. package/dist/providers/oauth/redaction.d.ts.map +1 -0
  391. package/dist/providers/oauth/redaction.js +59 -0
  392. package/dist/providers/oauth/redaction.js.map +1 -0
  393. package/dist/providers/oauth/secure-credential-store.d.ts +67 -0
  394. package/dist/providers/oauth/secure-credential-store.d.ts.map +1 -0
  395. package/dist/providers/oauth/secure-credential-store.js +73 -0
  396. package/dist/providers/oauth/secure-credential-store.js.map +1 -0
  397. package/dist/providers/oauth/token-store.d.ts +53 -0
  398. package/dist/providers/oauth/token-store.d.ts.map +1 -0
  399. package/dist/providers/oauth/token-store.js +78 -0
  400. package/dist/providers/oauth/token-store.js.map +1 -0
  401. package/dist/providers/oauth/types.d.ts +64 -0
  402. package/dist/providers/oauth/types.d.ts.map +1 -0
  403. package/dist/providers/oauth/types.js +12 -0
  404. package/dist/providers/oauth/types.js.map +1 -0
  405. package/dist/providers/object-tracking.d.ts +47 -0
  406. package/dist/providers/object-tracking.d.ts.map +1 -0
  407. package/dist/providers/object-tracking.js +46 -0
  408. package/dist/providers/object-tracking.js.map +1 -0
  409. package/dist/providers/offline-model-index.d.ts +20 -0
  410. package/dist/providers/offline-model-index.d.ts.map +1 -0
  411. package/dist/providers/offline-model-index.js +112 -0
  412. package/dist/providers/offline-model-index.js.map +1 -0
  413. package/dist/providers/ollama-provider.d.ts +28 -1
  414. package/dist/providers/ollama-provider.d.ts.map +1 -1
  415. package/dist/providers/ollama-provider.js +193 -43
  416. package/dist/providers/ollama-provider.js.map +1 -1
  417. package/dist/providers/openai-compat/client.d.ts +57 -0
  418. package/dist/providers/openai-compat/client.d.ts.map +1 -0
  419. package/dist/providers/openai-compat/client.js +157 -0
  420. package/dist/providers/openai-compat/client.js.map +1 -0
  421. package/dist/providers/openai-compat/decode.d.ts +36 -0
  422. package/dist/providers/openai-compat/decode.d.ts.map +1 -0
  423. package/dist/providers/openai-compat/decode.js +55 -0
  424. package/dist/providers/openai-compat/decode.js.map +1 -0
  425. package/dist/providers/openai-compat/errors.d.ts +54 -0
  426. package/dist/providers/openai-compat/errors.d.ts.map +1 -0
  427. package/dist/providers/openai-compat/errors.js +144 -0
  428. package/dist/providers/openai-compat/errors.js.map +1 -0
  429. package/dist/providers/openai-compat/index.d.ts +8 -0
  430. package/dist/providers/openai-compat/index.d.ts.map +1 -0
  431. package/dist/providers/openai-compat/index.js +5 -0
  432. package/dist/providers/openai-compat/index.js.map +1 -0
  433. package/dist/providers/openai-compat/sse.d.ts +14 -0
  434. package/dist/providers/openai-compat/sse.d.ts.map +1 -0
  435. package/dist/providers/openai-compat/sse.js +69 -0
  436. package/dist/providers/openai-compat/sse.js.map +1 -0
  437. package/dist/providers/openai-compat/types.d.ts +75 -0
  438. package/dist/providers/openai-compat/types.d.ts.map +1 -0
  439. package/dist/providers/openai-compat/types.js +9 -0
  440. package/dist/providers/openai-compat/types.js.map +1 -0
  441. package/dist/providers/openai-compat-provider.d.ts +90 -0
  442. package/dist/providers/openai-compat-provider.d.ts.map +1 -0
  443. package/dist/providers/openai-compat-provider.js +282 -0
  444. package/dist/providers/openai-compat-provider.js.map +1 -0
  445. package/dist/providers/openai-provider.d.ts +89 -26
  446. package/dist/providers/openai-provider.d.ts.map +1 -1
  447. package/dist/providers/openai-provider.js +990 -105
  448. package/dist/providers/openai-provider.js.map +1 -1
  449. package/dist/providers/openrouter-provider.d.ts +6 -12
  450. package/dist/providers/openrouter-provider.d.ts.map +1 -1
  451. package/dist/providers/openrouter-provider.js +24 -53
  452. package/dist/providers/openrouter-provider.js.map +1 -1
  453. package/dist/providers/provider-call-failure.d.ts +39 -0
  454. package/dist/providers/provider-call-failure.d.ts.map +1 -0
  455. package/dist/providers/provider-call-failure.js +132 -0
  456. package/dist/providers/provider-call-failure.js.map +1 -0
  457. package/dist/providers/provider-error.d.ts +59 -0
  458. package/dist/providers/provider-error.d.ts.map +1 -0
  459. package/dist/providers/provider-error.js +165 -0
  460. package/dist/providers/provider-error.js.map +1 -0
  461. package/dist/providers/provider-generations.d.ts +99 -0
  462. package/dist/providers/provider-generations.d.ts.map +1 -0
  463. package/dist/providers/provider-generations.js +71 -0
  464. package/dist/providers/provider-generations.js.map +1 -0
  465. package/dist/providers/provider-queue.d.ts +62 -0
  466. package/dist/providers/provider-queue.d.ts.map +1 -0
  467. package/dist/providers/provider-queue.js +28 -0
  468. package/dist/providers/provider-queue.js.map +1 -0
  469. package/dist/providers/provider-registry.d.ts +33 -14
  470. package/dist/providers/provider-registry.d.ts.map +1 -1
  471. package/dist/providers/provider-registry.js +85 -68
  472. package/dist/providers/provider-registry.js.map +1 -1
  473. package/dist/providers/provider-request-log.d.ts +53 -0
  474. package/dist/providers/provider-request-log.d.ts.map +1 -0
  475. package/dist/providers/provider-request-log.js +157 -0
  476. package/dist/providers/provider-request-log.js.map +1 -0
  477. package/dist/providers/provider-session.d.ts +3 -0
  478. package/dist/providers/provider-session.d.ts.map +1 -0
  479. package/dist/providers/provider-session.js +10 -0
  480. package/dist/providers/provider-session.js.map +1 -0
  481. package/dist/providers/provider-transport.d.ts +11 -0
  482. package/dist/providers/provider-transport.d.ts.map +1 -0
  483. package/dist/providers/provider-transport.js +11 -0
  484. package/dist/providers/provider-transport.js.map +1 -0
  485. package/dist/providers/python-provider.d.ts +20 -12
  486. package/dist/providers/python-provider.d.ts.map +1 -1
  487. package/dist/providers/python-provider.js +185 -25
  488. package/dist/providers/python-provider.js.map +1 -1
  489. package/dist/providers/replicate-provider.d.ts +89 -7
  490. package/dist/providers/replicate-provider.d.ts.map +1 -1
  491. package/dist/providers/replicate-provider.js +801 -65
  492. package/dist/providers/replicate-provider.js.map +1 -1
  493. package/dist/providers/replicate-retry.d.ts +30 -0
  494. package/dist/providers/replicate-retry.d.ts.map +1 -0
  495. package/dist/providers/replicate-retry.js +97 -0
  496. package/dist/providers/replicate-retry.js.map +1 -0
  497. package/dist/providers/responses-api.d.ts +27 -0
  498. package/dist/providers/responses-api.d.ts.map +1 -0
  499. package/dist/providers/responses-api.js +297 -0
  500. package/dist/providers/responses-api.js.map +1 -0
  501. package/dist/providers/reve-provider.d.ts +45 -0
  502. package/dist/providers/reve-provider.d.ts.map +1 -0
  503. package/dist/providers/reve-provider.js +159 -0
  504. package/dist/providers/reve-provider.js.map +1 -0
  505. package/dist/providers/rodin-provider.d.ts +23 -1
  506. package/dist/providers/rodin-provider.d.ts.map +1 -1
  507. package/dist/providers/rodin-provider.js +89 -51
  508. package/dist/providers/rodin-provider.js.map +1 -1
  509. package/dist/providers/safe-url.d.ts +70 -0
  510. package/dist/providers/safe-url.d.ts.map +1 -0
  511. package/dist/providers/safe-url.js +277 -0
  512. package/dist/providers/safe-url.js.map +1 -0
  513. package/dist/providers/scripted-provider.d.ts +9 -0
  514. package/dist/providers/scripted-provider.d.ts.map +1 -1
  515. package/dist/providers/scripted-provider.js +86 -10
  516. package/dist/providers/scripted-provider.js.map +1 -1
  517. package/dist/providers/structured-output.d.ts +42 -0
  518. package/dist/providers/structured-output.d.ts.map +1 -0
  519. package/dist/providers/structured-output.js +83 -0
  520. package/dist/providers/structured-output.js.map +1 -0
  521. package/dist/providers/together-provider.d.ts +19 -16
  522. package/dist/providers/together-provider.d.ts.map +1 -1
  523. package/dist/providers/together-provider.js +103 -225
  524. package/dist/providers/together-provider.js.map +1 -1
  525. package/dist/providers/topaz-provider.d.ts +44 -0
  526. package/dist/providers/topaz-provider.d.ts.map +1 -0
  527. package/dist/providers/topaz-provider.js +239 -0
  528. package/dist/providers/topaz-provider.js.map +1 -0
  529. package/dist/providers/types.d.ts +603 -4
  530. package/dist/providers/types.d.ts.map +1 -1
  531. package/dist/providers/types.js +81 -1
  532. package/dist/providers/types.js.map +1 -1
  533. package/dist/providers/useapi-provider.d.ts +27 -0
  534. package/dist/providers/useapi-provider.d.ts.map +1 -0
  535. package/dist/providers/useapi-provider.js +266 -0
  536. package/dist/providers/useapi-provider.js.map +1 -0
  537. package/dist/providers/video-duration.d.ts +6 -0
  538. package/dist/providers/video-duration.d.ts.map +1 -0
  539. package/dist/providers/video-duration.js +63 -0
  540. package/dist/providers/video-duration.js.map +1 -0
  541. package/dist/providers/video-frame-fallback.d.ts +39 -0
  542. package/dist/providers/video-frame-fallback.d.ts.map +1 -0
  543. package/dist/providers/video-frame-fallback.js +155 -0
  544. package/dist/providers/video-frame-fallback.js.map +1 -0
  545. package/dist/providers/video-frames.d.ts +61 -0
  546. package/dist/providers/video-frames.d.ts.map +1 -0
  547. package/dist/providers/video-frames.js +208 -0
  548. package/dist/providers/video-frames.js.map +1 -0
  549. package/dist/providers/video-mime.d.ts +14 -0
  550. package/dist/providers/video-mime.d.ts.map +1 -0
  551. package/dist/providers/video-mime.js +44 -0
  552. package/dist/providers/video-mime.js.map +1 -0
  553. package/dist/providers/video-to-audio.d.ts +34 -0
  554. package/dist/providers/video-to-audio.d.ts.map +1 -0
  555. package/dist/providers/video-to-audio.js +62 -0
  556. package/dist/providers/video-to-audio.js.map +1 -0
  557. package/dist/providers/vllm-provider.d.ts +22 -8
  558. package/dist/providers/vllm-provider.d.ts.map +1 -1
  559. package/dist/providers/vllm-provider.js +48 -23
  560. package/dist/providers/vllm-provider.js.map +1 -1
  561. package/dist/providers/voyage-provider.d.ts +10 -2
  562. package/dist/providers/voyage-provider.d.ts.map +1 -1
  563. package/dist/providers/voyage-provider.js +16 -7
  564. package/dist/providers/voyage-provider.js.map +1 -1
  565. package/dist/providers/xai-provider.d.ts +54 -13
  566. package/dist/providers/xai-provider.d.ts.map +1 -1
  567. package/dist/providers/xai-provider.js +299 -22
  568. package/dist/providers/xai-provider.js.map +1 -1
  569. package/dist/python-bridge-base.d.ts +358 -0
  570. package/dist/python-bridge-base.d.ts.map +1 -0
  571. package/dist/python-bridge-base.js +1557 -0
  572. package/dist/python-bridge-base.js.map +1 -0
  573. package/dist/python-bridge-codec.d.ts +28 -0
  574. package/dist/python-bridge-codec.d.ts.map +1 -0
  575. package/dist/python-bridge-codec.js +39 -0
  576. package/dist/python-bridge-codec.js.map +1 -0
  577. package/dist/python-bridge-factory.d.ts +52 -0
  578. package/dist/python-bridge-factory.d.ts.map +1 -0
  579. package/dist/python-bridge-factory.js +69 -0
  580. package/dist/python-bridge-factory.js.map +1 -0
  581. package/dist/python-bridge-framing.d.ts +68 -0
  582. package/dist/python-bridge-framing.d.ts.map +1 -0
  583. package/dist/python-bridge-framing.js +91 -0
  584. package/dist/python-bridge-framing.js.map +1 -0
  585. package/dist/python-bridge-types.d.ts +545 -2
  586. package/dist/python-bridge-types.d.ts.map +1 -1
  587. package/dist/python-bridge-types.js +49 -1
  588. package/dist/python-bridge-types.js.map +1 -1
  589. package/dist/python-graph-resolver.d.ts +57 -0
  590. package/dist/python-graph-resolver.d.ts.map +1 -0
  591. package/dist/python-graph-resolver.js +79 -0
  592. package/dist/python-graph-resolver.js.map +1 -0
  593. package/dist/python-node-executor.d.ts +36 -4
  594. package/dist/python-node-executor.d.ts.map +1 -1
  595. package/dist/python-node-executor.js +177 -86
  596. package/dist/python-node-executor.js.map +1 -1
  597. package/dist/python-stdio-bridge.d.ts +18 -37
  598. package/dist/python-stdio-bridge.d.ts.map +1 -1
  599. package/dist/python-stdio-bridge.js +148 -475
  600. package/dist/python-stdio-bridge.js.map +1 -1
  601. package/dist/python-websocket-bridge.d.ts +140 -0
  602. package/dist/python-websocket-bridge.d.ts.map +1 -0
  603. package/dist/python-websocket-bridge.js +561 -0
  604. package/dist/python-websocket-bridge.js.map +1 -0
  605. package/dist/python-worker-stderr.d.ts +4 -0
  606. package/dist/python-worker-stderr.d.ts.map +1 -0
  607. package/dist/python-worker-stderr.js +24 -0
  608. package/dist/python-worker-stderr.js.map +1 -0
  609. package/dist/recommended-models.d.ts +2 -2
  610. package/dist/recommended-models.d.ts.map +1 -1
  611. package/dist/recommended-models.js +24 -4
  612. package/dist/recommended-models.js.map +1 -1
  613. package/dist/recoverable-node-error.d.ts +31 -0
  614. package/dist/recoverable-node-error.d.ts.map +1 -0
  615. package/dist/recoverable-node-error.js +37 -0
  616. package/dist/recoverable-node-error.js.map +1 -0
  617. package/dist/redact-params.d.ts +13 -0
  618. package/dist/redact-params.d.ts.map +1 -0
  619. package/dist/redact-params.js +57 -0
  620. package/dist/redact-params.js.map +1 -0
  621. package/dist/sandbox-module-catalog.d.ts +43 -0
  622. package/dist/sandbox-module-catalog.d.ts.map +1 -0
  623. package/dist/sandbox-module-catalog.js +25 -0
  624. package/dist/sandbox-module-catalog.js.map +1 -0
  625. package/dist/storage-workspace.d.ts +59 -0
  626. package/dist/storage-workspace.d.ts.map +1 -0
  627. package/dist/storage-workspace.js +426 -0
  628. package/dist/storage-workspace.js.map +1 -0
  629. package/dist/swappable-python-bridge.d.ts +83 -0
  630. package/dist/swappable-python-bridge.d.ts.map +1 -0
  631. package/dist/swappable-python-bridge.js +246 -0
  632. package/dist/swappable-python-bridge.js.map +1 -0
  633. package/dist/telemetry.d.ts +7 -0
  634. package/dist/telemetry.d.ts.map +1 -1
  635. package/dist/telemetry.js +23 -0
  636. package/dist/telemetry.js.map +1 -1
  637. package/dist/testing.d.ts +81 -0
  638. package/dist/testing.d.ts.map +1 -0
  639. package/dist/testing.js +130 -0
  640. package/dist/testing.js.map +1 -0
  641. package/dist/token-counter.d.ts +30 -0
  642. package/dist/token-counter.d.ts.map +1 -0
  643. package/dist/token-counter.js +156 -0
  644. package/dist/token-counter.js.map +1 -0
  645. package/dist/trace-exporters.d.ts +10 -0
  646. package/dist/trace-exporters.d.ts.map +1 -1
  647. package/dist/trace-exporters.js +59 -20
  648. package/dist/trace-exporters.js.map +1 -1
  649. package/dist/tracing-helpers.d.ts +45 -4
  650. package/dist/tracing-helpers.d.ts.map +1 -1
  651. package/dist/tracing-helpers.js +62 -19
  652. package/dist/tracing-helpers.js.map +1 -1
  653. package/dist/turn-budget.d.ts +278 -0
  654. package/dist/turn-budget.d.ts.map +1 -0
  655. package/dist/turn-budget.js +365 -0
  656. package/dist/turn-budget.js.map +1 -0
  657. package/dist/variable-channel.d.ts +48 -0
  658. package/dist/variable-channel.d.ts.map +1 -0
  659. package/dist/variable-channel.js +110 -0
  660. package/dist/variable-channel.js.map +1 -0
  661. package/dist/workspace.d.ts +119 -0
  662. package/dist/workspace.d.ts.map +1 -0
  663. package/dist/workspace.js +112 -0
  664. package/dist/workspace.js.map +1 -0
  665. package/package.json +107 -19
@@ -1,20 +1,277 @@
1
1
  import Anthropic from "@anthropic-ai/sdk";
2
2
  import { createLogger } from "@nodetool-ai/config";
3
3
  import { BaseProvider } from "./base-provider.js";
4
+ import { anthropicContextExceeded } from "./context-exceeded.js";
5
+ import { safeFetch } from "./safe-url.js";
6
+ import { isNumber, isObjectLike, isRecord, isString } from "@nodetool-ai/protocol";
4
7
  const log = createLogger("nodetool.runtime.providers.anthropic");
8
+ import { WEB_SEARCH_TOOL_NAME } from "./types.js";
9
+ const MAX_IMAGE_BYTES = 5 * 1024 * 1024;
10
+ const MAX_PAUSE_TURN_CONTINUATIONS = 5;
11
+ function toRawBlock(block) {
12
+ return Object.fromEntries(Object.entries(block));
13
+ }
14
+ function retryAfterMs(value) {
15
+ if (!value)
16
+ return null;
17
+ const seconds = Number(value);
18
+ if (Number.isFinite(seconds) && seconds >= 0) {
19
+ return Math.min(seconds * 1000, 60_000);
20
+ }
21
+ const date = Date.parse(value);
22
+ if (Number.isNaN(date))
23
+ return null;
24
+ return Math.min(Math.max(date - Date.now(), 0), 60_000);
25
+ }
26
+ function apiErrorStatus(error) {
27
+ if (isObjectLike(error) && "status" in error && isNumber(error.status)) {
28
+ return error.status;
29
+ }
30
+ return undefined;
31
+ }
32
+ function apiErrorRetryAfter(error) {
33
+ if (isObjectLike(error) &&
34
+ "headers" in error &&
35
+ error.headers instanceof Headers) {
36
+ return error.headers.get("retry-after");
37
+ }
38
+ return null;
39
+ }
40
+ function mapCitation(citation) {
41
+ switch (citation.type) {
42
+ case "char_location":
43
+ return {
44
+ type: citation.type,
45
+ citedText: citation.cited_text,
46
+ documentIndex: citation.document_index,
47
+ documentTitle: citation.document_title,
48
+ fileId: citation.file_id,
49
+ startCharIndex: citation.start_char_index,
50
+ endCharIndex: citation.end_char_index
51
+ };
52
+ case "page_location":
53
+ return {
54
+ type: citation.type,
55
+ citedText: citation.cited_text,
56
+ documentIndex: citation.document_index,
57
+ documentTitle: citation.document_title,
58
+ fileId: citation.file_id,
59
+ startPageNumber: citation.start_page_number,
60
+ endPageNumber: citation.end_page_number
61
+ };
62
+ case "content_block_location":
63
+ return {
64
+ type: citation.type,
65
+ citedText: citation.cited_text,
66
+ documentIndex: citation.document_index,
67
+ documentTitle: citation.document_title,
68
+ fileId: citation.file_id,
69
+ startBlockIndex: citation.start_block_index,
70
+ endBlockIndex: citation.end_block_index
71
+ };
72
+ case "web_search_result_location":
73
+ return {
74
+ type: citation.type,
75
+ citedText: citation.cited_text,
76
+ encryptedIndex: citation.encrypted_index,
77
+ url: citation.url,
78
+ title: citation.title
79
+ };
80
+ case "search_result_location":
81
+ return {
82
+ type: citation.type,
83
+ citedText: citation.cited_text,
84
+ searchResultIndex: citation.search_result_index,
85
+ source: citation.source,
86
+ title: citation.title,
87
+ startBlockIndex: citation.start_block_index,
88
+ endBlockIndex: citation.end_block_index
89
+ };
90
+ }
91
+ }
92
+ function textContentFromRawBlocks(blocks) {
93
+ return blocks.flatMap((block) => {
94
+ if (block?.type !== "text" || !isString(block.text))
95
+ return [];
96
+ const citations = Array.isArray(block.citations)
97
+ ? block.citations.map(mapCitation)
98
+ : undefined;
99
+ const content = {
100
+ type: "text",
101
+ text: block.text
102
+ };
103
+ if (citations && citations.length > 0) {
104
+ content.citations = citations;
105
+ }
106
+ return [content];
107
+ });
108
+ }
109
+ function toAnthropicCitation(citation) {
110
+ switch (citation.type) {
111
+ case "char_location":
112
+ return {
113
+ type: citation.type,
114
+ cited_text: citation.citedText,
115
+ document_index: citation.documentIndex,
116
+ document_title: citation.documentTitle ?? null,
117
+ file_id: citation.fileId ?? null,
118
+ start_char_index: citation.startCharIndex,
119
+ end_char_index: citation.endCharIndex
120
+ };
121
+ case "page_location":
122
+ return {
123
+ type: citation.type,
124
+ cited_text: citation.citedText,
125
+ document_index: citation.documentIndex,
126
+ document_title: citation.documentTitle ?? null,
127
+ file_id: citation.fileId ?? null,
128
+ start_page_number: citation.startPageNumber,
129
+ end_page_number: citation.endPageNumber
130
+ };
131
+ case "content_block_location":
132
+ return {
133
+ type: citation.type,
134
+ cited_text: citation.citedText,
135
+ document_index: citation.documentIndex,
136
+ document_title: citation.documentTitle ?? null,
137
+ file_id: citation.fileId ?? null,
138
+ start_block_index: citation.startBlockIndex,
139
+ end_block_index: citation.endBlockIndex
140
+ };
141
+ case "web_search_result_location":
142
+ return {
143
+ type: citation.type,
144
+ cited_text: citation.citedText,
145
+ encrypted_index: citation.encryptedIndex,
146
+ url: citation.url,
147
+ title: citation.title ?? null
148
+ };
149
+ case "search_result_location":
150
+ return {
151
+ type: citation.type,
152
+ cited_text: citation.citedText,
153
+ search_result_index: citation.searchResultIndex,
154
+ source: citation.source,
155
+ title: citation.title ?? null,
156
+ start_block_index: citation.startBlockIndex,
157
+ end_block_index: citation.endBlockIndex
158
+ };
159
+ }
160
+ }
161
+ /**
162
+ * The tool fields Anthropic accepts on every tool form, with each one the
163
+ * caller left unset omitted.
164
+ */
165
+ function sharedToolFields(tool) {
166
+ const fields = {};
167
+ if (tool.cacheControl) {
168
+ fields.cache_control = tool.cacheControl;
169
+ }
170
+ if (tool.strict !== undefined) {
171
+ fields.strict = tool.strict;
172
+ }
173
+ if (tool.deferLoading !== undefined) {
174
+ fields.defer_loading = tool.deferLoading;
175
+ }
176
+ if (tool.allowedCallers) {
177
+ fields.allowed_callers = tool.allowedCallers;
178
+ }
179
+ return fields;
180
+ }
181
+ function toAnthropicTextBlock(part) {
182
+ const block = {
183
+ type: "text",
184
+ text: part.text
185
+ };
186
+ if (part.citations) {
187
+ block.citations = part.citations.map(toAnthropicCitation);
188
+ }
189
+ return block;
190
+ }
191
+ /**
192
+ * Anthropic requires every `tool_result` block for one assistant turn to live
193
+ * in a single user message. `convertMessage` emits one user message per
194
+ * `role: "tool"` message, so parallel tool calls would produce consecutive user
195
+ * messages and a 400. Merge them back into one.
196
+ */
197
+ function mergeToolResultMessages(messages) {
198
+ const isToolResultMessage = (m) => m.role === "user" &&
199
+ Array.isArray(m.content) &&
200
+ m.content.length > 0 &&
201
+ m.content.every((block) => isObjectLike(block) &&
202
+ block.type === "tool_result");
203
+ const merged = [];
204
+ for (const message of messages) {
205
+ const previous = merged[merged.length - 1];
206
+ if (previous &&
207
+ isToolResultMessage(previous) &&
208
+ isToolResultMessage(message)) {
209
+ merged[merged.length - 1] = {
210
+ ...previous,
211
+ content: [
212
+ ...previous.content,
213
+ ...message.content
214
+ ]
215
+ };
216
+ continue;
217
+ }
218
+ merged.push(message);
219
+ }
220
+ return merged;
221
+ }
222
+ function thinkingPolicy(model) {
223
+ const id = model.toLowerCase();
224
+ if (id.includes("claude-fable-5") ||
225
+ id.includes("claude-mythos-5") ||
226
+ id.includes("claude-mythos-preview")) {
227
+ return "adaptive_required";
228
+ }
229
+ if (id.includes("claude-sonnet-5"))
230
+ return "adaptive_default";
231
+ if (id.includes("claude-opus-4-7") || id.includes("claude-opus-4-8")) {
232
+ return "adaptive_optional";
233
+ }
234
+ return "manual";
235
+ }
236
+ function rejectsCustomSampling(model) {
237
+ return thinkingPolicy(model) !== "manual";
238
+ }
5
239
  function isTextContent(content) {
6
240
  return content.type === "text";
7
241
  }
8
242
  function isImageContent(content) {
9
243
  return content.type === "image_url";
10
244
  }
245
+ function isDocumentContent(content) {
246
+ return content.type === "document";
247
+ }
11
248
  function bytesToBase64(data) {
12
249
  if (!data)
13
250
  return "";
14
- if (typeof data === "string")
251
+ if (isString(data))
15
252
  return data;
16
253
  return Buffer.from(data).toString("base64");
17
254
  }
255
+ function assertImageSize(base64) {
256
+ if (Buffer.byteLength(base64, "base64") > MAX_IMAGE_BYTES) {
257
+ throw new Error("Anthropic image exceeds the 5 MB limit");
258
+ }
259
+ }
260
+ /**
261
+ * Anthropic's image block accepts only image/jpeg, image/png, image/gif and
262
+ * image/webp as `media_type`. Strip any Content-Type parameters, normalize the
263
+ * common `image/jpg` alias, and reject unsupported media types.
264
+ */
265
+ function normalizeAnthropicImageMime(mime) {
266
+ const base = mime.split(";")[0].trim().toLowerCase();
267
+ if (base === "image/jpg")
268
+ return "image/jpeg";
269
+ const supported = ["image/jpeg", "image/png", "image/gif", "image/webp"];
270
+ if (!supported.includes(base)) {
271
+ throw new Error(`Anthropic does not support image media type ${base}`);
272
+ }
273
+ return base;
274
+ }
18
275
  function parseDataUri(uri) {
19
276
  const idx = uri.indexOf(",");
20
277
  if (idx < 0) {
@@ -33,30 +290,65 @@ function parseDataUri(uri) {
33
290
  };
34
291
  }
35
292
  export class AnthropicProvider extends BaseProvider {
293
+ /**
294
+ * Anthropic runs web search server-side via the `web_search_20250305` server
295
+ * tool. Gate on the provider id so subclasses that reuse the Anthropic SDK
296
+ * against a different endpoint (gateways that don't implement that server
297
+ * tool) fall back to the SerpAPI WebSearchTool instead of sending an
298
+ * unsupported tool that silently breaks web search.
299
+ */
300
+ get supportsNativeWebSearch() {
301
+ return this.provider === "anthropic";
302
+ }
36
303
  static requiredSecrets() {
37
304
  return ["ANTHROPIC_API_KEY"];
38
305
  }
39
306
  apiKey;
307
+ authToken;
40
308
  _client;
41
309
  _clientFactory;
42
310
  _fetch;
311
+ _clientOptions;
312
+ _cacheControl;
313
+ _betas;
43
314
  constructor(secrets, options = {}) {
44
- super("anthropic");
45
- const apiKey = secrets.ANTHROPIC_API_KEY;
46
- if (!apiKey || !apiKey.trim()) {
47
- throw new Error("ANTHROPIC_API_KEY is not configured");
315
+ super(options.providerId ?? "anthropic");
316
+ const apiKey = secrets.ANTHROPIC_API_KEY?.trim() ?? "";
317
+ const authToken = secrets.ANTHROPIC_AUTH_TOKEN?.trim() ??
318
+ options.clientOptions?.authToken?.trim() ??
319
+ "";
320
+ const hasStructuredAuth = Boolean(options.clientOptions?.credentials ||
321
+ options.clientOptions?.config ||
322
+ options.clientOptions?.profile);
323
+ if (!apiKey && !authToken && !hasStructuredAuth) {
324
+ throw new Error("Anthropic authentication is not configured (API key, auth token, credentials, config, or profile required)");
48
325
  }
49
326
  this.apiKey = apiKey;
327
+ this.authToken = authToken;
50
328
  this._client = options.client ?? null;
329
+ this._clientOptions = options.clientOptions;
330
+ this._cacheControl = options.cacheControl;
331
+ this._betas = options.betas ?? [];
51
332
  this._clientFactory =
52
333
  options.clientFactory ??
53
- ((key) => new Anthropic({
54
- apiKey: key
55
- }));
334
+ ((key) => {
335
+ const clientOptions = { ...this._clientOptions };
336
+ if (key) {
337
+ clientOptions.apiKey = key;
338
+ }
339
+ if (this.authToken) {
340
+ clientOptions.authToken = this.authToken;
341
+ }
342
+ return new Anthropic(clientOptions);
343
+ });
56
344
  this._fetch = options.fetchFn ?? globalThis.fetch.bind(globalThis);
57
345
  }
58
346
  getContainerEnv() {
59
- return { ANTHROPIC_API_KEY: this.apiKey };
347
+ if (this.apiKey)
348
+ return { ANTHROPIC_API_KEY: this.apiKey };
349
+ if (this.authToken)
350
+ return { ANTHROPIC_AUTH_TOKEN: this.authToken };
351
+ return {};
60
352
  }
61
353
  getClient() {
62
354
  if (!this._client) {
@@ -64,217 +356,347 @@ export class AnthropicProvider extends BaseProvider {
64
356
  }
65
357
  return this._client;
66
358
  }
359
+ requestOptions(signal) {
360
+ const options = {};
361
+ if (signal) {
362
+ options.signal = signal;
363
+ }
364
+ if (this._betas.length > 0) {
365
+ options.headers = { "anthropic-beta": this._betas.join(",") };
366
+ }
367
+ return options;
368
+ }
67
369
  async hasToolSupport(_model) {
68
370
  return true;
69
371
  }
372
+ /**
373
+ * `max_input_tokens` from the Models API. The request carries the same
374
+ * `anthropic-beta` header as Messages, so a 1M-context beta reports the 1M
375
+ * window. Null when the endpoint fails, as it does on gateways that reuse
376
+ * this provider without implementing it.
377
+ */
378
+ async getContextWindow(model) {
379
+ try {
380
+ const info = await this.getClient().models.retrieve(model, null, {
381
+ ...this.requestOptions(),
382
+ timeout: 10_000,
383
+ maxRetries: 0
384
+ });
385
+ return info.max_input_tokens ?? null;
386
+ }
387
+ catch (error) {
388
+ log.debug("Anthropic model lookup failed", {
389
+ model,
390
+ error: error instanceof Error ? error.message : String(error)
391
+ });
392
+ return null;
393
+ }
394
+ }
70
395
  async getAvailableLanguageModels() {
71
396
  const maxRetries = 3;
72
- const baseDelay = 1000; // ms
73
- let lastError = null;
74
397
  for (let attempt = 0; attempt < maxRetries; attempt++) {
75
398
  try {
76
- const controller = new AbortController();
77
- const timeout = setTimeout(() => controller.abort(), 10_000); // 10s total timeout
78
- const response = await this._fetch("https://api.anthropic.com/v1/models", {
79
- headers: {
80
- "x-api-key": this.apiKey,
81
- "anthropic-version": "2023-06-01"
82
- },
83
- signal: controller.signal
84
- });
85
- clearTimeout(timeout);
86
- // Don't retry on auth errors
87
- if (response.status === 401 || response.status === 403) {
88
- log.warn("Anthropic API auth error, not retrying", {
89
- status: response.status
90
- });
91
- return [];
92
- }
93
- // Retry on rate limit or server errors
94
- if ([429, 500, 502, 503, 504].includes(response.status)) {
95
- log.warn("Anthropic API error, retrying", {
96
- status: response.status,
97
- attempt: attempt + 1,
98
- maxRetries
399
+ const models = [];
400
+ let afterId;
401
+ do {
402
+ const listParams = {
403
+ limit: 1000
404
+ };
405
+ if (afterId) {
406
+ listParams.after_id = afterId;
407
+ }
408
+ const page = await this.getClient().models.list(listParams, {
409
+ ...this.requestOptions(),
410
+ timeout: 10_000,
411
+ maxRetries: 0
99
412
  });
100
- if (attempt < maxRetries - 1) {
101
- await new Promise((r) => setTimeout(r, baseDelay * 2 ** attempt));
102
- continue;
413
+ models.push(...page.data.map((model) => ({
414
+ id: model.id,
415
+ name: model.display_name,
416
+ provider: "anthropic"
417
+ })));
418
+ if (page.has_more && !page.last_id) {
419
+ throw new Error("Anthropic Models API returned has_more without last_id");
103
420
  }
421
+ afterId = page.has_more ? (page.last_id ?? undefined) : undefined;
422
+ } while (afterId);
423
+ return models;
424
+ }
425
+ catch (error) {
426
+ const status = apiErrorStatus(error);
427
+ if (status === 401 || status === 403)
104
428
  return [];
105
- }
106
- if (!response.ok) {
429
+ if (attempt === maxRetries - 1 ||
430
+ (status !== undefined &&
431
+ ![429, 500, 502, 503, 504, 529].includes(status))) {
107
432
  log.warn("Failed to fetch Anthropic models", {
108
- status: response.status
433
+ error: error instanceof Error ? error.message : String(error),
434
+ status
109
435
  });
110
436
  return [];
111
437
  }
112
- const payload = (await response.json());
113
- return (payload.data ?? [])
114
- .map((m) => m.id ?? m.name)
115
- .filter((id) => typeof id === "string" && id.length > 0)
116
- .map((id) => ({ id, name: id, provider: "anthropic" }));
117
- }
118
- catch (err) {
119
- lastError = err instanceof Error ? err : new Error(String(err));
120
- // AbortError means timeout
121
- if (lastError.name === "AbortError") {
122
- log.warn("Anthropic API timeout", {
123
- attempt: attempt + 1,
124
- maxRetries
125
- });
126
- }
127
- else {
128
- log.warn("Anthropic API connection error", {
129
- error: lastError.message,
130
- attempt: attempt + 1,
131
- maxRetries
132
- });
133
- }
134
- if (attempt < maxRetries - 1) {
135
- await new Promise((r) => setTimeout(r, baseDelay * 2 ** attempt));
136
- }
438
+ const delay = retryAfterMs(apiErrorRetryAfter(error)) ?? 1000 * 2 ** attempt;
439
+ await new Promise((resolve) => setTimeout(resolve, delay));
137
440
  }
138
441
  }
139
- log.error("Failed to fetch Anthropic models after retries", {
140
- error: lastError?.message
141
- });
142
442
  return [];
143
443
  }
144
444
  prepareJsonSchema(schema) {
145
- if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
445
+ if (!isRecord(schema)) {
446
+ // SAFETY: a schema node that is not an object is carried through as it
447
+ // stands — a scalar, a list, or an absent schema.
146
448
  return schema;
147
449
  }
148
- const obj = { ...schema };
450
+ const obj = {
451
+ // SAFETY: the checks above proved `schema` is a plain object of schema
452
+ // members.
453
+ ...schema
454
+ };
149
455
  if (obj.type === "object" && obj.additionalProperties === undefined) {
150
456
  obj.additionalProperties = false;
151
457
  }
152
- if (obj.properties &&
153
- typeof obj.properties === "object" &&
154
- !Array.isArray(obj.properties)) {
155
- obj.properties = Object.fromEntries(Object.entries(obj.properties).map(([k, v]) => [k, this.prepareJsonSchema(v)]));
458
+ if (isRecord(obj.properties)) {
459
+ obj.properties = Object.fromEntries(Object.entries(obj.properties).map(([k, v]) => [
460
+ k,
461
+ this.prepareJsonSchema(v)
462
+ ]));
156
463
  }
157
- if (obj.items && typeof obj.items === "object") {
464
+ if (isObjectLike(obj.items)) {
158
465
  obj.items = this.prepareJsonSchema(obj.items);
159
466
  }
160
467
  for (const defsKey of ["definitions", "$defs"]) {
161
468
  const defs = obj[defsKey];
162
- if (defs && typeof defs === "object" && !Array.isArray(defs)) {
163
- obj[defsKey] = Object.fromEntries(Object.entries(defs).map(([k, v]) => [
164
- k,
165
- this.prepareJsonSchema(v)
166
- ]));
167
- }
168
- }
169
- const unsupported = [
170
- "default",
171
- "minimum",
172
- "maximum",
173
- "exclusiveMinimum",
174
- "exclusiveMaximum",
175
- "multipleOf",
176
- "minLength",
177
- "maxLength",
178
- "minProperties",
179
- "maxProperties",
180
- "minItems",
181
- "maxItems",
182
- "uniqueItems"
183
- ];
184
- for (const key of unsupported) {
185
- delete obj[key];
469
+ if (isRecord(defs)) {
470
+ obj[defsKey] = Object.fromEntries(Object.entries(defs).map(([k, v]) => [k, this.prepareJsonSchema(v)]));
471
+ }
186
472
  }
187
473
  return obj;
188
474
  }
189
- async convertMessage(message) {
475
+ /**
476
+ * Convert a {@link MessageImageContent} part into an Anthropic image block
477
+ * (`{ type: "image", source: { type: "base64", ... } }`), resolving data
478
+ * URIs, raw base64, and remote/storage URIs (which are fetched and encoded).
479
+ */
480
+ async convertImagePart(part, signal) {
481
+ const rawData = bytesToBase64(part.image.data);
482
+ const uri = part.image.uri ?? "";
483
+ let mediaType = part.image.mimeType ?? "image/png";
484
+ let base64;
485
+ if (rawData) {
486
+ if (rawData.startsWith("data:")) {
487
+ const parsed = parseDataUri(rawData);
488
+ if (part.image.mimeType &&
489
+ normalizeAnthropicImageMime(part.image.mimeType) !==
490
+ normalizeAnthropicImageMime(parsed.mime)) {
491
+ throw new Error("Anthropic image data URI MIME mismatch");
492
+ }
493
+ base64 = parsed.base64;
494
+ mediaType = part.image.mimeType ?? parsed.mime;
495
+ }
496
+ else {
497
+ base64 = rawData;
498
+ }
499
+ }
500
+ else if (uri.startsWith("data:")) {
501
+ const parsed = parseDataUri(uri);
502
+ if (part.image.mimeType &&
503
+ normalizeAnthropicImageMime(part.image.mimeType) !==
504
+ normalizeAnthropicImageMime(parsed.mime)) {
505
+ throw new Error("Anthropic image data URI MIME mismatch");
506
+ }
507
+ base64 = parsed.base64;
508
+ mediaType = part.image.mimeType ?? parsed.mime;
509
+ }
510
+ else if (uri) {
511
+ const resolved = await this.resolveUri(uri);
512
+ if (resolved.startsWith("data:")) {
513
+ const parsed = parseDataUri(resolved);
514
+ if (part.image.mimeType &&
515
+ normalizeAnthropicImageMime(part.image.mimeType) !==
516
+ normalizeAnthropicImageMime(parsed.mime)) {
517
+ throw new Error("Anthropic image data URI MIME mismatch");
518
+ }
519
+ base64 = parsed.base64;
520
+ mediaType = part.image.mimeType ?? parsed.mime;
521
+ }
522
+ else {
523
+ const response = await safeFetch(resolved, signal ? { signal } : undefined, 5, this._fetch);
524
+ if (!response.ok) {
525
+ throw new Error(`Failed to fetch URI: ${response.status}`);
526
+ }
527
+ const contentLength = Number(response.headers.get("content-length"));
528
+ if (Number.isFinite(contentLength) && contentLength > MAX_IMAGE_BYTES) {
529
+ throw new Error("Anthropic image exceeds the 5 MB limit");
530
+ }
531
+ mediaType =
532
+ part.image.mimeType ??
533
+ response.headers.get("content-type") ??
534
+ "image/png";
535
+ const bytes = new Uint8Array(await response.arrayBuffer());
536
+ if (bytes.byteLength > MAX_IMAGE_BYTES) {
537
+ throw new Error("Anthropic image exceeds the 5 MB limit");
538
+ }
539
+ base64 = Buffer.from(bytes).toString("base64");
540
+ }
541
+ }
542
+ else {
543
+ throw new Error("Invalid image reference with no uri or data");
544
+ }
545
+ assertImageSize(base64);
546
+ return {
547
+ type: "image",
548
+ source: {
549
+ type: "base64",
550
+ media_type: normalizeAnthropicImageMime(mediaType),
551
+ data: base64
552
+ }
553
+ };
554
+ }
555
+ async convertDocumentPart(part) {
556
+ const { data, uri, mimeType, title } = part.document;
557
+ let source;
558
+ if (data !== undefined) {
559
+ const parsed = isString(data) && data.startsWith("data:")
560
+ ? parseDataUri(data)
561
+ : undefined;
562
+ const effectiveMime = mimeType ?? parsed?.mime ?? "application/pdf";
563
+ if (parsed && mimeType && parsed.mime !== mimeType) {
564
+ throw new Error(`Anthropic document MIME mismatch: ${mimeType} vs ${parsed.mime}`);
565
+ }
566
+ if (effectiveMime === "text/plain") {
567
+ const text = parsed
568
+ ? Buffer.from(parsed.base64, "base64").toString("utf8")
569
+ : isString(data)
570
+ ? data
571
+ : Buffer.from(data).toString("utf8");
572
+ source = { type: "text", media_type: "text/plain", data: text };
573
+ }
574
+ else if (effectiveMime === "application/pdf") {
575
+ const encoded = parsed?.base64 ?? bytesToBase64(data);
576
+ source = {
577
+ type: "base64",
578
+ media_type: "application/pdf",
579
+ data: encoded
580
+ };
581
+ }
582
+ else {
583
+ throw new Error(`Anthropic does not support document media type ${effectiveMime}`);
584
+ }
585
+ }
586
+ else if (uri) {
587
+ const resolved = await this.resolveUri(uri);
588
+ if (/^https:\/\//i.test(resolved)) {
589
+ source = { type: "url", url: resolved };
590
+ }
591
+ else if (!resolved.startsWith("data:")) {
592
+ throw new Error("Anthropic document URI must resolve to PDF data or an HTTPS URL");
593
+ }
594
+ else {
595
+ const parsed = parseDataUri(resolved);
596
+ if (parsed.mime !== "application/pdf") {
597
+ throw new Error(`Anthropic does not support document media type ${parsed.mime}`);
598
+ }
599
+ source = {
600
+ type: "base64",
601
+ media_type: "application/pdf",
602
+ data: parsed.base64
603
+ };
604
+ }
605
+ }
606
+ else {
607
+ throw new Error("Anthropic document content requires PDF/text data or an HTTPS PDF URL");
608
+ }
609
+ const block = {
610
+ type: "document",
611
+ source
612
+ };
613
+ if (title) {
614
+ block.title = title;
615
+ }
616
+ if (part.context) {
617
+ block.context = part.context;
618
+ }
619
+ if (part.citations !== undefined) {
620
+ block.citations = { enabled: part.citations };
621
+ }
622
+ return block;
623
+ }
624
+ async convertMessage(message, signal) {
190
625
  if (message.role === "tool") {
191
626
  if (!message.toolCallId) {
192
627
  throw new Error("Tool call ID must not be None");
193
628
  }
194
- const contentValue = typeof message.content === "string"
195
- ? message.content
196
- : JSON.stringify(message.content ?? null);
629
+ // Anthropic tool_result content may be a string or an array of blocks
630
+ // (text + image). Structured content (e.g. ui_3d_capture_view's
631
+ // screenshot) is converted to blocks so vision models can see it; plain
632
+ // results stay stringified as before.
633
+ let resultContent;
634
+ if (isString(message.content)) {
635
+ resultContent = message.content;
636
+ }
637
+ else if (Array.isArray(message.content)) {
638
+ const blocks = [];
639
+ for (const part of message.content) {
640
+ if (isTextContent(part)) {
641
+ blocks.push(toAnthropicTextBlock(part));
642
+ }
643
+ else if (isImageContent(part)) {
644
+ blocks.push(await this.convertImagePart(part, signal));
645
+ }
646
+ }
647
+ resultContent =
648
+ blocks.length > 0 ? blocks : JSON.stringify(message.content);
649
+ }
650
+ else {
651
+ resultContent = JSON.stringify(message.content ?? null);
652
+ }
653
+ const toolResult = {
654
+ type: "tool_result",
655
+ tool_use_id: message.toolCallId,
656
+ content: resultContent
657
+ };
658
+ if (message.isError) {
659
+ toolResult.is_error = true;
660
+ }
197
661
  return {
198
662
  role: "user",
199
- content: [
200
- {
201
- type: "tool_result",
202
- tool_use_id: message.toolCallId,
203
- content: contentValue
204
- }
205
- ]
663
+ content: [toolResult]
206
664
  };
207
665
  }
208
666
  if (message.role === "system") {
209
- return {
210
- role: "assistant",
211
- content: typeof message.content === "string"
212
- ? message.content
213
- : String(message.content ?? "")
214
- };
667
+ // Anthropic has no `system` role in the messages array (the system prompt
668
+ // is a top-level param). The main generate paths strip system messages
669
+ // before conversion; if one still reaches here, fold it into a user
670
+ // message rather than mislabeling it as assistant text (and avoid
671
+ // String(array) producing "[object Object]").
672
+ const text = isString(message.content)
673
+ ? message.content
674
+ : (message.content ?? [])
675
+ .filter(isTextContent)
676
+ .map((c) => c.text)
677
+ .join("\n");
678
+ return { role: "user", content: text };
215
679
  }
216
680
  if (message.role === "user") {
217
- if (typeof message.content === "string") {
681
+ if (isString(message.content)) {
218
682
  return { role: "user", content: message.content };
219
683
  }
220
684
  const parts = message.content ?? [];
221
685
  const content = [];
222
686
  for (const part of parts) {
223
687
  if (isTextContent(part)) {
224
- content.push({ type: "text", text: part.text });
688
+ content.push(toAnthropicTextBlock(part));
225
689
  continue;
226
690
  }
227
691
  if (isImageContent(part)) {
228
- const rawData = bytesToBase64(part.image.data);
229
- const uri = part.image.uri ?? "";
230
- let mediaType = part.image.mimeType ?? "image/png";
231
- let base64;
232
- if (rawData) {
233
- if (rawData.startsWith("data:")) {
234
- const parsed = parseDataUri(rawData);
235
- base64 = parsed.base64;
236
- mediaType = part.image.mimeType ?? parsed.mime;
237
- }
238
- else {
239
- base64 = rawData;
240
- }
241
- }
242
- else if (uri.startsWith("data:")) {
243
- const parsed = parseDataUri(uri);
244
- base64 = parsed.base64;
245
- mediaType = part.image.mimeType ?? parsed.mime;
246
- }
247
- else if (uri) {
248
- const resolved = await this.resolveUri(uri);
249
- if (resolved.startsWith("data:")) {
250
- const parsed = parseDataUri(resolved);
251
- base64 = parsed.base64;
252
- mediaType = part.image.mimeType ?? parsed.mime;
253
- }
254
- else {
255
- const response = await this._fetch(resolved);
256
- if (!response.ok) {
257
- throw new Error(`Failed to fetch URI: ${response.status}`);
258
- }
259
- mediaType =
260
- part.image.mimeType ??
261
- response.headers.get("content-type") ??
262
- "image/png";
263
- base64 = Buffer.from(new Uint8Array(await response.arrayBuffer())).toString("base64");
264
- }
265
- }
266
- else {
267
- throw new Error("Invalid image reference with no uri or data");
268
- }
269
- content.push({
270
- type: "image",
271
- source: {
272
- type: "base64",
273
- media_type: mediaType,
274
- data: base64
275
- }
276
- });
692
+ content.push(await this.convertImagePart(part, signal));
693
+ continue;
277
694
  }
695
+ if (isDocumentContent(part)) {
696
+ content.push(await this.convertDocumentPart(part));
697
+ continue;
698
+ }
699
+ throw new Error(`Anthropic does not support ${part.type} message content`);
278
700
  }
279
701
  return {
280
702
  role: "user",
@@ -289,14 +711,20 @@ export class AnthropicProvider extends BaseProvider {
289
711
  return null;
290
712
  }
291
713
  if (message.toolCalls && message.toolCalls.length > 0) {
292
- const contentBlocks = [];
293
- if (typeof message.content === "string" && message.content.trim()) {
714
+ const rawBlocks = message.toolCalls.find((toolCall) => toolCall._anthropicContentBlocks)?._anthropicContentBlocks;
715
+ if (rawBlocks) {
716
+ return { role: "assistant", content: rawBlocks };
717
+ }
718
+ const contentBlocks = [
719
+ ...(message._anthropicThinkingBlocks ?? [])
720
+ ];
721
+ if (isString(message.content) && message.content.trim()) {
294
722
  contentBlocks.push({ type: "text", text: message.content });
295
723
  }
296
724
  if (Array.isArray(message.content)) {
297
725
  for (const part of message.content) {
298
726
  if (isTextContent(part) && part.text.trim()) {
299
- contentBlocks.push({ type: "text", text: part.text });
727
+ contentBlocks.push(toAnthropicTextBlock(part));
300
728
  }
301
729
  }
302
730
  }
@@ -313,7 +741,7 @@ export class AnthropicProvider extends BaseProvider {
313
741
  content: contentBlocks
314
742
  };
315
743
  }
316
- if (typeof message.content === "string") {
744
+ if (isString(message.content)) {
317
745
  return { role: "assistant", content: message.content };
318
746
  }
319
747
  if (Array.isArray(message.content)) {
@@ -321,236 +749,490 @@ export class AnthropicProvider extends BaseProvider {
321
749
  role: "assistant",
322
750
  content: message.content
323
751
  .filter((part) => isTextContent(part))
324
- .map((part) => ({
325
- type: "text",
326
- text: part.text
327
- }))
752
+ .map(toAnthropicTextBlock)
328
753
  };
329
754
  }
330
755
  throw new Error(`Unknown message content type ${typeof message.content}`);
331
756
  }
332
757
  formatTools(tools) {
333
- return tools.map((tool) => ({
334
- name: tool.name,
335
- description: tool.description ?? "",
336
- input_schema: this.prepareJsonSchema(tool.inputSchema ?? { type: "object", properties: {} })
337
- }));
758
+ return tools.map((tool) => {
759
+ // The canonical web-search tool is rendered as Anthropic's built-in
760
+ // server tool — the search runs server-side and its result blocks stream
761
+ // back within the same turn (our stream parser ignores them), so the
762
+ // model answers from live web data without a client round-trip.
763
+ // Gated on supportsNativeWebSearch: subclasses that reuse the Anthropic
764
+ // SDK against a different endpoint don't implement this server tool, so
765
+ // for them the tool falls through to the plain function-tool shape below
766
+ // and runs client-side via SerpAPI.
767
+ if (tool.name === WEB_SEARCH_TOOL_NAME && this.supportsNativeWebSearch) {
768
+ return {
769
+ type: "web_search_20250305",
770
+ name: WEB_SEARCH_TOOL_NAME,
771
+ max_uses: 5,
772
+ ...sharedToolFields(tool)
773
+ };
774
+ }
775
+ const base = {
776
+ name: tool.name,
777
+ description: tool.description ?? "",
778
+ input_schema: this.prepareJsonSchema(tool.inputSchema ?? { type: "object", properties: {} })
779
+ };
780
+ const withExamples = tool.inputExamples
781
+ ? { ...base, input_examples: tool.inputExamples }
782
+ : base;
783
+ return { ...withExamples, ...sharedToolFields(tool) };
784
+ });
338
785
  }
339
786
  extractSystemMessage(messages) {
340
- const system = messages.find((m) => m.role === "system");
341
- if (!system) {
787
+ const systemMessages = messages.filter((m) => m.role === "system");
788
+ if (systemMessages.length === 0) {
342
789
  return "You are a helpful assistant.";
343
790
  }
344
- if (typeof system.content === "string") {
345
- return system.content;
346
- }
347
- if (Array.isArray(system.content)) {
348
- return system.content
349
- .filter((part) => isTextContent(part))
350
- .map((part) => part.text)
351
- .join(" ");
352
- }
353
- return String(system.content ?? "You are a helpful assistant.");
791
+ const sections = systemMessages
792
+ .map((message) => {
793
+ if (isString(message.content))
794
+ return message.content;
795
+ if (Array.isArray(message.content)) {
796
+ return message.content
797
+ .filter(isTextContent)
798
+ .map((part) => part.text)
799
+ .join(" ");
800
+ }
801
+ return message.content == null ? "" : String(message.content);
802
+ })
803
+ .filter(Boolean);
804
+ return sections.join("\n\n") || "You are a helpful assistant.";
354
805
  }
355
- async *generateMessages(args) {
356
- const system = this.extractSystemMessage(args.messages);
357
- const converted = await Promise.all(args.messages
358
- .filter((m) => m.role !== "system")
359
- .map((m) => this.convertMessage(m)));
360
- const anthropicMessages = converted.filter((m) => m !== null);
806
+ buildRequest(args) {
361
807
  const formattedTools = args.tools && args.tools.length > 0
362
808
  ? this.formatTools(args.tools)
363
809
  : undefined;
364
- let resolvedToolChoice;
810
+ const policy = thinkingPolicy(args.model);
811
+ // `thinkingBudget` predates the structured config. A model that only takes
812
+ // adaptive thinking has no use for the number, so it degrades to a bare
813
+ // request for thinking.
814
+ const legacyThinking = args.thinkingBudget === undefined
815
+ ? undefined
816
+ : policy === "manual"
817
+ ? { type: "manual", budgetTokens: args.thinkingBudget }
818
+ : { type: "adaptive" };
819
+ const thinking = args.thinking ?? legacyThinking;
820
+ if (thinking?.type === "manual") {
821
+ if (policy !== "manual") {
822
+ throw new Error(`${args.model} requires adaptive thinking; manual budgets are unsupported`);
823
+ }
824
+ if (thinking.budgetTokens < 1024) {
825
+ throw new Error("Anthropic thinking budget must be at least 1024 tokens");
826
+ }
827
+ }
828
+ if (thinking?.type === "disabled" && policy === "adaptive_required") {
829
+ throw new Error(`${args.model} does not allow thinking to be disabled`);
830
+ }
831
+ const explicitThinking = thinking?.type === "adaptive" || thinking?.type === "manual";
832
+ // Policy-default thinking (no caller-supplied config) is implicit: a forced
833
+ // tool choice wins over it and thinking is turned off, so callers that
834
+ // always force a tool can still use adaptive-default models. An explicit
835
+ // thinking request combined with a forced tool choice is a real conflict.
836
+ const implicitThinking = !thinking &&
837
+ (policy === "adaptive_default" || policy === "adaptive_required");
365
838
  if (args.toolChoice) {
366
- resolvedToolChoice =
367
- args.toolChoice === "any"
368
- ? { type: "any" }
369
- : { type: "tool", name: args.toolChoice };
839
+ if (explicitThinking) {
840
+ throw new Error("Anthropic does not allow a forced tool choice while thinking is active");
841
+ }
842
+ if (implicitThinking && policy === "adaptive_required") {
843
+ throw new Error(`${args.model} does not allow thinking to be disabled, so a forced tool choice is unsupported`);
844
+ }
845
+ }
846
+ const thinkingSuppressedByToolChoice = Boolean(args.toolChoice && implicitThinking);
847
+ const thinkingEnabled = explicitThinking || (implicitThinking && !thinkingSuppressedByToolChoice);
848
+ const toolChoice = args.toolChoice
849
+ ? args.toolChoice === "any"
850
+ ? { type: "any" }
851
+ : { type: "tool", name: args.toolChoice }
852
+ : undefined;
853
+ // A manual budget has to fit inside max_tokens, with at least one token
854
+ // left over for the answer.
855
+ const requestedMaxTokens = args.maxTokens ?? 8192;
856
+ const maxTokens = thinking?.type === "manual"
857
+ ? Math.max(requestedMaxTokens, thinking.budgetTokens + 1)
858
+ : requestedMaxTokens;
859
+ // Models on an adaptive thinking policy reject temperature and top_p
860
+ // outright, and once thinking is on the only value Anthropic still accepts
861
+ // is a top_p of 0.95 or above under a manual budget.
862
+ const sampling = {};
863
+ if (!rejectsCustomSampling(args.model)) {
864
+ if (!thinkingEnabled) {
865
+ if (args.temperature != null) {
866
+ sampling.temperature = args.temperature;
867
+ }
868
+ else if (args.topP != null) {
869
+ sampling.top_p = args.topP;
870
+ }
871
+ }
872
+ else if (thinking?.type === "manual" &&
873
+ args.topP != null &&
874
+ args.topP >= 0.95) {
875
+ sampling.top_p = args.topP;
876
+ }
877
+ }
878
+ // The disabled variant carries no `display` field, hence the narrowing.
879
+ const display = thinking && thinking.type !== "disabled" && thinking.display
880
+ ? { display: thinking.display }
881
+ : {};
882
+ let anthropicThinking;
883
+ if (thinking?.type === "adaptive") {
884
+ anthropicThinking = { type: "adaptive", ...display };
885
+ }
886
+ else if (thinking?.type === "manual") {
887
+ anthropicThinking = {
888
+ type: "enabled",
889
+ budget_tokens: thinking.budgetTokens,
890
+ ...display
891
+ };
892
+ }
893
+ else if (thinking?.type === "disabled" ||
894
+ thinkingSuppressedByToolChoice) {
895
+ anthropicThinking = { type: "disabled" };
370
896
  }
371
897
  const request = {
898
+ model: args.model,
899
+ messages: args.messages,
900
+ system: args.system,
901
+ max_tokens: maxTokens
902
+ };
903
+ if (formattedTools) {
904
+ request.tools = formattedTools;
905
+ }
906
+ if (toolChoice) {
907
+ request.tool_choice = toolChoice;
908
+ }
909
+ Object.assign(request, sampling);
910
+ if (anthropicThinking) {
911
+ request.thinking = anthropicThinking;
912
+ }
913
+ if (args.effort) {
914
+ request.output_config = { effort: args.effort };
915
+ }
916
+ if (this._cacheControl) {
917
+ request.cache_control = this._cacheControl;
918
+ }
919
+ return request;
920
+ }
921
+ async *generateMessages(args) {
922
+ const system = this.extractSystemMessage(args.messages);
923
+ const converted = await Promise.all(args.messages
924
+ .filter((m) => m.role !== "system")
925
+ .map((m) => this.convertMessage(m, args.signal)));
926
+ const anthropicMessages = mergeToolResultMessages(converted.filter((m) => m !== null));
927
+ const request = this.buildRequest({
372
928
  model: args.model,
373
929
  messages: anthropicMessages,
374
930
  system,
375
- max_tokens: args.maxTokens ?? 8192,
376
- ...(formattedTools ? { tools: formattedTools } : {}),
377
- ...(resolvedToolChoice ? { tool_choice: resolvedToolChoice } : {}),
378
- ...(args.temperature != null ? { temperature: args.temperature } : {}),
379
- ...(args.topP != null ? { top_p: args.topP } : {}),
380
- ...(args.thinkingBudget != null
381
- ? { thinking: { type: "enabled", budget_tokens: args.thinkingBudget } }
382
- : {})
383
- };
384
- log.debug("Anthropic request", { model: args.model });
385
- const stream = await this.getClient().messages.create({
386
- ...request,
387
- stream: true
931
+ tools: args.tools,
932
+ toolChoice: args.toolChoice,
933
+ maxTokens: args.maxTokens,
934
+ temperature: args.temperature,
935
+ topP: args.topP,
936
+ thinking: args.thinking,
937
+ effort: args.effort,
938
+ thinkingBudget: args.thinkingBudget
388
939
  });
389
- let streamInputTokens = 0;
390
- let streamOutputTokens = 0;
391
- let streamCachedTokens = 0;
392
- // Track in-flight tool_use blocks: index → { id, name, accumulated partial_json }
393
- const activeToolBlocks = new Map();
394
- for await (const event of stream) {
395
- if (event.type === "message_start") {
396
- const usage = event.message.usage;
397
- streamInputTokens += usage.input_tokens ?? 0;
398
- streamCachedTokens += usage.cache_read_input_tokens ?? 0;
399
- }
400
- if (event.type === "message_delta") {
401
- streamOutputTokens += event.usage.output_tokens ?? 0;
402
- }
403
- if (event.type === "message_stop") {
404
- this.trackUsage(args.model, {
405
- inputTokens: streamInputTokens,
406
- outputTokens: streamOutputTokens,
407
- cachedTokens: streamCachedTokens
408
- });
409
- }
410
- // Record the start of a tool_use content block so we can accumulate its JSON.
411
- if (event.type === "content_block_start") {
412
- const block = event.content_block;
413
- if (block.type === "tool_use") {
414
- activeToolBlocks.set(event.index, {
415
- id: String(block.id ?? ""),
416
- name: String(block.name ?? ""),
417
- json: ""
418
- });
940
+ log.debug("Anthropic request", { model: args.model });
941
+ let currentRequest = request;
942
+ for (let continuation = 0; continuation <= MAX_PAUSE_TURN_CONTINUATIONS; continuation++) {
943
+ // SAFETY: the request is assembled field by field as a dictionary, and
944
+ // the SDK's param interface is closed — it declares no index signature,
945
+ // so the two do not overlap.
946
+ const streamRequest = {
947
+ ...currentRequest,
948
+ stream: true
949
+ };
950
+ this.recordRequestPayload(streamRequest);
951
+ const stream = await this.getClient().messages.create(streamRequest, this.requestOptions(args.signal));
952
+ let inputTokens = 0;
953
+ let outputTokens = 0;
954
+ let cachedTokens = 0;
955
+ let cacheWriteTokens = 0;
956
+ let stopReason = null;
957
+ const contentBlocks = [];
958
+ const jsonByIndex = new Map();
959
+ const thinkingBlocks = [];
960
+ const toolCalls = [];
961
+ for await (const event of stream) {
962
+ if (event.type === "message_start") {
963
+ inputTokens = event.message.usage.input_tokens ?? inputTokens;
964
+ cachedTokens =
965
+ event.message.usage.cache_read_input_tokens ?? cachedTokens;
966
+ cacheWriteTokens =
967
+ event.message.usage.cache_creation_input_tokens ?? cacheWriteTokens;
968
+ continue;
419
969
  }
420
- continue;
421
- }
422
- if (event.type === "content_block_delta") {
423
- const delta = event.delta;
424
- if ("thinking" in delta && typeof delta.thinking === "string") {
425
- const chunk = {
426
- type: "chunk",
427
- content: delta.thinking,
428
- done: false,
429
- thinking: true
430
- };
431
- yield chunk;
970
+ if (event.type === "message_delta") {
971
+ outputTokens = event.usage.output_tokens;
972
+ inputTokens = event.usage.input_tokens ?? inputTokens;
973
+ cachedTokens = event.usage.cache_read_input_tokens ?? cachedTokens;
974
+ cacheWriteTokens =
975
+ event.usage.cache_creation_input_tokens ?? cacheWriteTokens;
976
+ stopReason = event.delta?.stop_reason ?? stopReason;
432
977
  continue;
433
978
  }
434
- if ("partial_json" in delta &&
435
- typeof delta.partial_json === "string") {
436
- // Regular tool call: accumulate the JSON into the active block.
437
- const block = activeToolBlocks.get(event.index);
438
- if (block) {
439
- block.json += delta.partial_json;
979
+ if (event.type === "content_block_start") {
980
+ const raw = toRawBlock(event.content_block);
981
+ contentBlocks[event.index] = raw;
982
+ if (event.content_block.type === "tool_use" ||
983
+ event.content_block.type === "server_tool_use") {
984
+ jsonByIndex.set(event.index, "");
985
+ }
986
+ if (event.content_block.type === "thinking") {
987
+ thinkingBlocks.push({
988
+ type: "thinking",
989
+ thinking: event.content_block.thinking,
990
+ signature: event.content_block.signature
991
+ });
992
+ }
993
+ else if (event.content_block.type === "redacted_thinking") {
994
+ thinkingBlocks.push({
995
+ type: "redacted_thinking",
996
+ data: event.content_block.data
997
+ });
440
998
  }
441
999
  continue;
442
1000
  }
443
- if ("text" in delta &&
444
- typeof delta.text === "string") {
445
- const chunk = {
446
- type: "chunk",
447
- content: delta.text,
448
- done: false
449
- };
450
- yield chunk;
1001
+ if (event.type === "content_block_delta") {
1002
+ const index = Number(event.index ?? 0);
1003
+ const raw = contentBlocks[index] ?? {};
1004
+ contentBlocks[index] = raw;
1005
+ const delta = event.delta;
1006
+ if ("thinking" in delta && isString(delta.thinking)) {
1007
+ const thinkingDelta = delta.thinking;
1008
+ raw.thinking = String(raw.thinking ?? "") + thinkingDelta;
1009
+ const thinking = thinkingBlocks.at(-1);
1010
+ if (thinking?.type === "thinking")
1011
+ thinking.thinking += thinkingDelta;
1012
+ yield {
1013
+ type: "chunk",
1014
+ content: thinkingDelta,
1015
+ done: false,
1016
+ thinking: true
1017
+ };
1018
+ }
1019
+ else if ("signature" in delta && isString(delta.signature)) {
1020
+ const signatureDelta = delta.signature;
1021
+ raw.signature = String(raw.signature ?? "") + signatureDelta;
1022
+ const thinking = thinkingBlocks.at(-1);
1023
+ if (thinking?.type === "thinking")
1024
+ thinking.signature += signatureDelta;
1025
+ }
1026
+ else if ("partial_json" in delta && isString(delta.partial_json)) {
1027
+ jsonByIndex.set(index, (jsonByIndex.get(index) ?? "") + delta.partial_json);
1028
+ }
1029
+ else if ("text" in delta && isString(delta.text)) {
1030
+ const textDelta = delta.text;
1031
+ raw.text = String(raw.text ?? "") + textDelta;
1032
+ yield { type: "chunk", content: textDelta, done: false };
1033
+ }
1034
+ else if (delta.type === "citations_delta") {
1035
+ const citations = Array.isArray(raw.citations) ? raw.citations : [];
1036
+ raw.citations = [...citations, delta.citation];
1037
+ }
1038
+ continue;
451
1039
  }
452
- continue;
453
- }
454
- if (event.type === "content_block_stop") {
455
- // content_block_stop does NOT carry the content_block in the raw API event.
456
- // Use the block we recorded from content_block_start + accumulated partial_json.
457
- const index = event.index;
458
- const toolBlock = activeToolBlocks.get(index);
459
- if (toolBlock) {
460
- activeToolBlocks.delete(index);
461
- let parsedArgs = {};
462
- try {
463
- const parsed = JSON.parse(toolBlock.json || "{}");
464
- if (parsed &&
465
- typeof parsed === "object" &&
466
- !Array.isArray(parsed)) {
467
- parsedArgs = parsed;
1040
+ if (event.type === "content_block_stop") {
1041
+ const raw = contentBlocks[event.index];
1042
+ const json = jsonByIndex.get(event.index);
1043
+ if (json !== undefined) {
1044
+ let input;
1045
+ try {
1046
+ input = JSON.parse(json || "{}");
1047
+ }
1048
+ catch {
1049
+ throw new Error("Anthropic returned incomplete tool input JSON");
1050
+ }
1051
+ raw.input = input;
1052
+ jsonByIndex.delete(event.index);
1053
+ if (raw.type === "tool_use") {
1054
+ if (!isRecord(input)) {
1055
+ throw new Error("Anthropic returned non-object tool input");
1056
+ }
1057
+ const toolCall = {
1058
+ id: String(raw.id ?? ""),
1059
+ name: String(raw.name ?? ""),
1060
+ args: Object.fromEntries(Object.entries(input)),
1061
+ _anthropicThinkingBlocks: thinkingBlocks.length > 0 ? [...thinkingBlocks] : undefined
1062
+ };
1063
+ toolCalls.push(toolCall);
468
1064
  }
469
1065
  }
470
- catch {
471
- // malformed JSON — emit empty args
472
- }
473
- const toolCall = {
474
- id: toolBlock.id,
475
- name: toolBlock.name,
476
- args: parsedArgs
477
- };
478
- yield toolCall;
479
1066
  }
1067
+ }
1068
+ const hasServerToolContent = contentBlocks.some((block) => block?.type === "server_tool_use" ||
1069
+ String(block?.type ?? "").endsWith("_tool_result"));
1070
+ if (hasServerToolContent) {
1071
+ for (const toolCall of toolCalls) {
1072
+ toolCall._anthropicContentBlocks = contentBlocks;
1073
+ }
1074
+ }
1075
+ this.trackUsage(args.model, {
1076
+ inputTokens: inputTokens + cachedTokens + cacheWriteTokens,
1077
+ outputTokens,
1078
+ cachedTokens,
1079
+ cacheWriteTokens
1080
+ });
1081
+ if (stopReason === "pause_turn") {
1082
+ if (continuation === MAX_PAUSE_TURN_CONTINUATIONS) {
1083
+ throw new Error("Anthropic pause_turn continuation limit exceeded");
1084
+ }
1085
+ currentRequest = {
1086
+ ...currentRequest,
1087
+ messages: [
1088
+ ...(currentRequest.messages ?? []),
1089
+ { role: "assistant", content: contentBlocks }
1090
+ ]
1091
+ };
480
1092
  continue;
481
1093
  }
482
- if (event.type === "message_stop") {
483
- const chunk = {
484
- type: "chunk",
485
- content: "",
486
- done: true
1094
+ if (stopReason === "max_tokens" ||
1095
+ stopReason === "model_context_window_exceeded") {
1096
+ throw new Error(`Anthropic response was truncated (${stopReason})`);
1097
+ }
1098
+ if (stopReason === "refusal") {
1099
+ throw new Error("Anthropic refused the request");
1100
+ }
1101
+ const textContent = textContentFromRawBlocks(contentBlocks);
1102
+ if (toolCalls.length === 0 &&
1103
+ textContent.some((part) => part.citations?.length)) {
1104
+ yield {
1105
+ type: "message",
1106
+ message: { role: "assistant", content: textContent }
487
1107
  };
488
- yield chunk;
489
1108
  }
1109
+ for (const toolCall of toolCalls)
1110
+ yield toolCall;
1111
+ yield { type: "chunk", content: "", done: true };
1112
+ return;
490
1113
  }
491
1114
  }
492
1115
  async generateMessage(args) {
493
1116
  const system = this.extractSystemMessage(args.messages);
494
1117
  const converted = await Promise.all(args.messages
495
1118
  .filter((m) => m.role !== "system")
496
- .map((m) => this.convertMessage(m)));
497
- const anthropicMessages = converted.filter((m) => m !== null);
498
- const formattedTools = args.tools && args.tools.length > 0
499
- ? this.formatTools(args.tools)
500
- : undefined;
501
- let resolvedToolChoice;
502
- if (args.toolChoice) {
503
- resolvedToolChoice =
504
- args.toolChoice === "any"
505
- ? { type: "any" }
506
- : { type: "tool", name: args.toolChoice };
507
- }
508
- const request = {
1119
+ .map((m) => this.convertMessage(m, args.signal)));
1120
+ const anthropicMessages = mergeToolResultMessages(converted.filter((m) => m !== null));
1121
+ const request = this.buildRequest({
509
1122
  model: args.model,
510
1123
  messages: anthropicMessages,
511
1124
  system,
512
- max_tokens: args.maxTokens ?? 8192,
513
- ...(formattedTools ? { tools: formattedTools } : {}),
514
- ...(resolvedToolChoice ? { tool_choice: resolvedToolChoice } : {}),
515
- ...(args.temperature != null ? { temperature: args.temperature } : {}),
516
- ...(args.topP != null ? { top_p: args.topP } : {}),
517
- ...(args.thinkingBudget != null
518
- ? { thinking: { type: "enabled", budget_tokens: args.thinkingBudget } }
519
- : {})
520
- };
1125
+ tools: args.tools,
1126
+ toolChoice: args.toolChoice,
1127
+ maxTokens: args.maxTokens,
1128
+ temperature: args.temperature,
1129
+ topP: args.topP,
1130
+ thinking: args.thinking,
1131
+ effort: args.effort,
1132
+ thinkingBudget: args.thinkingBudget
1133
+ });
521
1134
  log.debug("Anthropic request", { model: args.model });
522
- const response = await this.getClient().messages.create(request);
523
- if (response.usage) {
524
- this.trackUsage(args.model, {
525
- inputTokens: response.usage.input_tokens ?? 0,
526
- outputTokens: response.usage.output_tokens ?? 0,
527
- cachedTokens: response.usage.cache_read_input_tokens ?? 0
528
- });
1135
+ let currentRequest = request;
1136
+ let response;
1137
+ for (let continuation = 0; continuation <= MAX_PAUSE_TURN_CONTINUATIONS; continuation++) {
1138
+ this.recordRequestPayload(currentRequest);
1139
+ // SAFETY: as above — a dictionary request handed to the SDK's closed
1140
+ // non-streaming param interface.
1141
+ response = await this.getClient().messages.create(currentRequest, this.requestOptions(args.signal));
1142
+ if (response.usage) {
1143
+ const cacheRead = response.usage.cache_read_input_tokens ?? 0;
1144
+ const cacheWrite = response.usage.cache_creation_input_tokens ?? 0;
1145
+ this.trackUsage(args.model, {
1146
+ inputTokens: response.usage.input_tokens + cacheRead + cacheWrite,
1147
+ outputTokens: response.usage.output_tokens,
1148
+ cachedTokens: cacheRead,
1149
+ cacheWriteTokens: cacheWrite
1150
+ });
1151
+ }
1152
+ if (response.stop_reason !== "pause_turn")
1153
+ break;
1154
+ if (continuation === MAX_PAUSE_TURN_CONTINUATIONS) {
1155
+ throw new Error("Anthropic pause_turn continuation limit exceeded");
1156
+ }
1157
+ currentRequest = {
1158
+ ...currentRequest,
1159
+ messages: [
1160
+ ...(currentRequest.messages ?? []),
1161
+ {
1162
+ role: "assistant",
1163
+ content: response.content.map(toRawBlock)
1164
+ }
1165
+ ]
1166
+ };
1167
+ }
1168
+ if (!response)
1169
+ throw new Error("Anthropic returned no response");
1170
+ const stopReason = String(response.stop_reason ?? "");
1171
+ if (stopReason === "max_tokens" ||
1172
+ stopReason === "model_context_window_exceeded") {
1173
+ throw new Error(`Anthropic response was truncated (${stopReason})`);
1174
+ }
1175
+ if (stopReason === "refusal") {
1176
+ throw new Error("Anthropic refused the request");
529
1177
  }
530
1178
  const textParts = [];
531
1179
  const toolCalls = [];
532
- for (const block of response.content ?? []) {
1180
+ const thinkingBlocks = [];
1181
+ const rawContentBlocks = response.content.map(toRawBlock);
1182
+ for (const block of response.content) {
533
1183
  if (block.type === "tool_use") {
534
- toolCalls.push({
1184
+ const toolCall = {
535
1185
  id: String(block.id ?? ""),
536
1186
  name: String(block.name ?? ""),
537
- args: (block.input ?? {})
1187
+ args: Object.fromEntries(Object.entries(block.input ?? {}))
1188
+ };
1189
+ if (rawContentBlocks.some((raw) => raw.type === "server_tool_use" ||
1190
+ String(raw.type ?? "").endsWith("_tool_result"))) {
1191
+ toolCall._anthropicContentBlocks = rawContentBlocks;
1192
+ }
1193
+ toolCalls.push(toolCall);
1194
+ continue;
1195
+ }
1196
+ if (block.type === "thinking") {
1197
+ thinkingBlocks.push({
1198
+ type: "thinking",
1199
+ thinking: block.thinking,
1200
+ signature: block.signature
538
1201
  });
539
1202
  continue;
540
1203
  }
1204
+ if (block.type === "redacted_thinking") {
1205
+ thinkingBlocks.push({ type: "redacted_thinking", data: block.data });
1206
+ continue;
1207
+ }
541
1208
  if (block.type === "text") {
542
- textParts.push(String(block.text ?? ""));
1209
+ const citations = block.citations?.map(mapCitation);
1210
+ const textPart = {
1211
+ type: "text",
1212
+ text: block.text
1213
+ };
1214
+ if (citations && citations.length > 0) {
1215
+ textPart.citations = citations;
1216
+ }
1217
+ textParts.push(textPart);
543
1218
  }
544
1219
  }
1220
+ const hasCitations = textParts.some((part) => part.citations?.length);
545
1221
  return {
546
1222
  role: "assistant",
547
- content: textParts.join("\n"),
548
- toolCalls
1223
+ content: hasCitations
1224
+ ? textParts
1225
+ : textParts.map((part) => part.text).join("\n"),
1226
+ toolCalls,
1227
+ _anthropicThinkingBlocks: thinkingBlocks.length > 0 ? thinkingBlocks : undefined
549
1228
  };
550
1229
  }
551
1230
  asHttpStatusError(error) {
552
1231
  return new Error(String(error));
553
1232
  }
1233
+ isContextExceededError(error) {
1234
+ return anthropicContextExceeded(error) !== null;
1235
+ }
554
1236
  isContextLengthError(error) {
555
1237
  const msg = String(error).toLowerCase();
556
1238
  return (msg.includes("context length") ||