@llumiverse/drivers 1.2.0 → 1.4.0-dev.20260629.090753Z

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 (403) hide show
  1. package/lib/{types/adobe → adobe}/firefly.d.ts +2 -1
  2. package/lib/adobe/firefly.d.ts.map +1 -0
  3. package/lib/adobe/firefly.js +120 -0
  4. package/lib/adobe/firefly.js.map +1 -0
  5. package/lib/anthropic/index.d.ts +23 -0
  6. package/lib/anthropic/index.d.ts.map +1 -0
  7. package/lib/anthropic/index.js +68 -0
  8. package/lib/anthropic/index.js.map +1 -0
  9. package/lib/{types/azure → azure}/azure_foundry.d.ts +9 -7
  10. package/lib/azure/azure_foundry.d.ts.map +1 -0
  11. package/lib/{esm/azure → azure}/azure_foundry.js +138 -124
  12. package/lib/azure/azure_foundry.js.map +1 -0
  13. package/lib/{types/bedrock → bedrock}/converse.d.ts +2 -2
  14. package/lib/bedrock/converse.d.ts.map +1 -0
  15. package/lib/{esm/bedrock → bedrock}/converse.js +86 -79
  16. package/lib/bedrock/converse.js.map +1 -0
  17. package/lib/bedrock/embeddings.d.ts +4 -0
  18. package/lib/bedrock/embeddings.d.ts.map +1 -0
  19. package/lib/bedrock/embeddings.js +359 -0
  20. package/lib/bedrock/embeddings.js.map +1 -0
  21. package/lib/{types/bedrock → bedrock}/index.d.ts +33 -9
  22. package/lib/bedrock/index.d.ts.map +1 -0
  23. package/lib/{esm/bedrock → bedrock}/index.js +599 -324
  24. package/lib/bedrock/index.js.map +1 -0
  25. package/lib/{types/bedrock → bedrock}/nova-image-payload.d.ts +5 -5
  26. package/lib/bedrock/nova-image-payload.d.ts.map +1 -0
  27. package/lib/{esm/bedrock → bedrock}/nova-image-payload.js +31 -36
  28. package/lib/bedrock/nova-image-payload.js.map +1 -0
  29. package/lib/{types/bedrock → bedrock}/payloads.d.ts +1 -1
  30. package/lib/bedrock/payloads.d.ts.map +1 -0
  31. package/lib/{cjs/bedrock → bedrock}/payloads.js.map +1 -1
  32. package/lib/{types/bedrock → bedrock}/s3.d.ts +3 -2
  33. package/lib/bedrock/s3.d.ts.map +1 -0
  34. package/lib/{esm/bedrock → bedrock}/s3.js +27 -23
  35. package/lib/bedrock/s3.js.map +1 -0
  36. package/lib/{types/bedrock → bedrock}/twelvelabs.d.ts +8 -9
  37. package/lib/bedrock/twelvelabs.d.ts.map +1 -0
  38. package/lib/{esm/bedrock → bedrock}/twelvelabs.js +17 -21
  39. package/lib/bedrock/twelvelabs.js.map +1 -0
  40. package/lib/{types/groq → groq}/index.d.ts +6 -4
  41. package/lib/groq/index.d.ts.map +1 -0
  42. package/lib/{esm/groq → groq}/index.js +72 -39
  43. package/lib/groq/index.js.map +1 -0
  44. package/lib/{types/huggingface_ie.d.ts → huggingface_ie.d.ts} +4 -3
  45. package/lib/huggingface_ie.d.ts.map +1 -0
  46. package/lib/{esm/huggingface_ie.js → huggingface_ie.js} +32 -31
  47. package/lib/huggingface_ie.js.map +1 -0
  48. package/lib/index.d.ts +16 -0
  49. package/lib/index.d.ts.map +1 -0
  50. package/lib/index.js +16 -0
  51. package/lib/index.js.map +1 -0
  52. package/lib/{types/mistral → mistral}/index.d.ts +6 -5
  53. package/lib/mistral/index.d.ts.map +1 -0
  54. package/lib/{esm/mistral → mistral}/index.js +66 -38
  55. package/lib/mistral/index.js.map +1 -0
  56. package/lib/{types/mistral → mistral}/types.d.ts +1 -0
  57. package/lib/mistral/types.d.ts.map +1 -0
  58. package/lib/mistral/types.js.map +1 -0
  59. package/lib/{types/openai → openai}/azure_openai.d.ts +5 -4
  60. package/lib/openai/azure_openai.d.ts.map +1 -0
  61. package/lib/{esm/openai → openai}/azure_openai.js +17 -14
  62. package/lib/openai/azure_openai.js.map +1 -0
  63. package/lib/openai/drivers.d.ts +4 -0
  64. package/lib/openai/drivers.d.ts.map +1 -0
  65. package/lib/openai/drivers.js +9 -0
  66. package/lib/openai/drivers.js.map +1 -0
  67. package/lib/{types/openai → openai}/index.d.ts +17 -5
  68. package/lib/openai/index.d.ts.map +1 -0
  69. package/lib/{esm/openai → openai}/index.js +254 -148
  70. package/lib/openai/index.js.map +1 -0
  71. package/lib/{types/openai → openai}/openai.d.ts +3 -3
  72. package/lib/openai/openai.d.ts.map +1 -0
  73. package/lib/openai/openai.js +15 -0
  74. package/lib/openai/openai.js.map +1 -0
  75. package/lib/{types/openai → openai}/openai_compatible.d.ts +3 -3
  76. package/lib/openai/openai_compatible.d.ts.map +1 -0
  77. package/lib/{esm/openai → openai}/openai_compatible.js +14 -11
  78. package/lib/openai/openai_compatible.js.map +1 -0
  79. package/lib/{types/openai → openai}/openai_format.d.ts +3 -2
  80. package/lib/openai/openai_format.d.ts.map +1 -0
  81. package/lib/{esm/openai → openai}/openai_format.js +66 -24
  82. package/lib/openai/openai_format.js.map +1 -0
  83. package/lib/{types/replicate.d.ts → replicate.d.ts} +3 -2
  84. package/lib/replicate.d.ts.map +1 -0
  85. package/lib/{esm/replicate.js → replicate.js} +59 -49
  86. package/lib/replicate.js.map +1 -0
  87. package/lib/shared/claude-messages.d.ts +99 -0
  88. package/lib/shared/claude-messages.d.ts.map +1 -0
  89. package/lib/shared/claude-messages.js +869 -0
  90. package/lib/shared/claude-messages.js.map +1 -0
  91. package/lib/{types/shared → shared}/claude-thinking.d.ts +1 -1
  92. package/lib/shared/claude-thinking.d.ts.map +1 -0
  93. package/lib/{esm/shared → shared}/claude-thinking.js +5 -7
  94. package/lib/shared/claude-thinking.js.map +1 -0
  95. package/lib/shared/debug-prompt.d.ts +5 -0
  96. package/lib/shared/debug-prompt.d.ts.map +1 -0
  97. package/lib/shared/debug-prompt.js +25 -0
  98. package/lib/shared/debug-prompt.js.map +1 -0
  99. package/lib/{types/test-driver → test-driver}/TestErrorCompletionStream.d.ts +1 -1
  100. package/lib/test-driver/TestErrorCompletionStream.d.ts.map +1 -0
  101. package/lib/test-driver/TestErrorCompletionStream.js +16 -0
  102. package/lib/test-driver/TestErrorCompletionStream.js.map +1 -0
  103. package/lib/{types/test-driver → test-driver}/TestValidationErrorCompletionStream.d.ts +1 -1
  104. package/lib/test-driver/TestValidationErrorCompletionStream.d.ts.map +1 -0
  105. package/lib/{esm/test-driver → test-driver}/TestValidationErrorCompletionStream.js +4 -4
  106. package/lib/test-driver/TestValidationErrorCompletionStream.js.map +1 -0
  107. package/lib/{types/test-driver → test-driver}/index.d.ts +3 -3
  108. package/lib/test-driver/index.d.ts.map +1 -0
  109. package/lib/{esm/test-driver → test-driver}/index.js +20 -20
  110. package/lib/test-driver/index.js.map +1 -0
  111. package/lib/{types/test-driver → test-driver}/utils.d.ts +1 -1
  112. package/lib/test-driver/utils.d.ts.map +1 -0
  113. package/lib/{esm/test-driver → test-driver}/utils.js +4 -4
  114. package/lib/test-driver/utils.js.map +1 -0
  115. package/lib/togetherai/index.d.ts +15 -0
  116. package/lib/togetherai/index.d.ts.map +1 -0
  117. package/lib/togetherai/index.js +54 -0
  118. package/lib/togetherai/index.js.map +1 -0
  119. package/lib/{types/togetherai → togetherai}/interfaces.d.ts +1 -1
  120. package/lib/togetherai/interfaces.d.ts.map +1 -0
  121. package/lib/{cjs/watsonx → togetherai}/interfaces.js.map +1 -1
  122. package/lib/vertexai/debug.d.ts +2 -0
  123. package/lib/vertexai/debug.d.ts.map +1 -0
  124. package/lib/{esm/vertexai → vertexai}/debug.js +1 -1
  125. package/lib/vertexai/debug.js.map +1 -0
  126. package/lib/vertexai/embeddings/embed-legacy-multimodal.d.ts +9 -0
  127. package/lib/vertexai/embeddings/embed-legacy-multimodal.d.ts.map +1 -0
  128. package/lib/vertexai/embeddings/embed-legacy-multimodal.js +141 -0
  129. package/lib/vertexai/embeddings/embed-legacy-multimodal.js.map +1 -0
  130. package/lib/vertexai/embeddings/embed.d.ts +13 -0
  131. package/lib/vertexai/embeddings/embed.d.ts.map +1 -0
  132. package/lib/vertexai/embeddings/embed.js +162 -0
  133. package/lib/vertexai/embeddings/embed.js.map +1 -0
  134. package/lib/vertexai/embeddings/source-utils.d.ts +9 -0
  135. package/lib/vertexai/embeddings/source-utils.d.ts.map +1 -0
  136. package/lib/vertexai/embeddings/source-utils.js +18 -0
  137. package/lib/vertexai/embeddings/source-utils.js.map +1 -0
  138. package/lib/{types/vertexai → vertexai}/index.d.ts +31 -19
  139. package/lib/vertexai/index.d.ts.map +1 -0
  140. package/lib/{esm/vertexai → vertexai}/index.js +221 -159
  141. package/lib/vertexai/index.js.map +1 -0
  142. package/lib/vertexai/models/claude.d.ts +16 -0
  143. package/lib/vertexai/models/claude.d.ts.map +1 -0
  144. package/lib/vertexai/models/claude.js +65 -0
  145. package/lib/vertexai/models/claude.js.map +1 -0
  146. package/lib/{types/vertexai → vertexai}/models/gemini.d.ts +29 -5
  147. package/lib/vertexai/models/gemini.d.ts.map +1 -0
  148. package/lib/{esm/vertexai → vertexai}/models/gemini.js +255 -127
  149. package/lib/vertexai/models/gemini.js.map +1 -0
  150. package/lib/{types/vertexai → vertexai}/models/imagen.d.ts +12 -11
  151. package/lib/vertexai/models/imagen.d.ts.map +1 -0
  152. package/lib/{esm/vertexai → vertexai}/models/imagen.js +74 -47
  153. package/lib/vertexai/models/imagen.js.map +1 -0
  154. package/lib/{types/vertexai → vertexai}/models/llama.d.ts +4 -4
  155. package/lib/vertexai/models/llama.d.ts.map +1 -0
  156. package/lib/{esm/vertexai → vertexai}/models/llama.js +37 -33
  157. package/lib/vertexai/models/llama.js.map +1 -0
  158. package/lib/vertexai/models.d.ts +21 -0
  159. package/lib/vertexai/models.d.ts.map +1 -0
  160. package/lib/{esm/vertexai → vertexai}/models.js +12 -9
  161. package/lib/vertexai/models.js.map +1 -0
  162. package/lib/{types/watsonx → watsonx}/index.d.ts +4 -3
  163. package/lib/watsonx/index.d.ts.map +1 -0
  164. package/lib/{esm/watsonx → watsonx}/index.js +69 -41
  165. package/lib/watsonx/index.js.map +1 -0
  166. package/lib/watsonx/interfaces.d.ts.map +1 -0
  167. package/lib/{esm/watsonx → watsonx}/interfaces.js.map +1 -1
  168. package/lib/{types/xai → xai}/index.d.ts +4 -4
  169. package/lib/xai/index.d.ts.map +1 -0
  170. package/lib/{esm/xai → xai}/index.js +22 -18
  171. package/lib/xai/index.js.map +1 -0
  172. package/package.json +88 -36
  173. package/src/adobe/firefly.ts +60 -43
  174. package/src/anthropic/index.ts +121 -0
  175. package/src/azure/azure_foundry.ts +210 -165
  176. package/src/bedrock/converse.ts +124 -101
  177. package/src/bedrock/embeddings.test.ts +508 -0
  178. package/src/bedrock/embeddings.ts +517 -0
  179. package/src/bedrock/error-handling.test.ts +62 -14
  180. package/src/bedrock/index.ts +832 -466
  181. package/src/bedrock/nova-image-payload.ts +98 -91
  182. package/src/bedrock/payloads.ts +9 -9
  183. package/src/bedrock/s3.test.ts +39 -0
  184. package/src/bedrock/s3.ts +57 -38
  185. package/src/bedrock/streaming-tool-use.test.ts +86 -69
  186. package/src/bedrock/twelvelabs.ts +35 -32
  187. package/src/groq/index.ts +143 -60
  188. package/src/http-timeout-wiring.test.ts +263 -0
  189. package/src/huggingface_ie.ts +45 -61
  190. package/src/index.ts +15 -15
  191. package/src/mistral/index.ts +97 -48
  192. package/src/mistral/types.ts +13 -12
  193. package/src/openai/azure_openai.ts +35 -27
  194. package/src/openai/drivers.ts +9 -0
  195. package/src/openai/error-handling.test.ts +308 -113
  196. package/src/openai/index.ts +389 -254
  197. package/src/openai/openai.ts +6 -13
  198. package/src/openai/openai_compatible.ts +35 -25
  199. package/src/openai/openai_format.ts +90 -40
  200. package/src/replicate.ts +108 -86
  201. package/src/shared/claude-messages.test.ts +37 -0
  202. package/src/shared/claude-messages.ts +1085 -0
  203. package/src/shared/claude-thinking.ts +6 -12
  204. package/src/shared/debug-prompt.ts +28 -0
  205. package/src/test-driver/TestErrorCompletionStream.ts +9 -10
  206. package/src/test-driver/TestValidationErrorCompletionStream.ts +9 -10
  207. package/src/test-driver/index.ts +43 -27
  208. package/src/test-driver/utils.ts +8 -8
  209. package/src/togetherai/index.test.ts +32 -0
  210. package/src/togetherai/index.ts +64 -128
  211. package/src/togetherai/interfaces.ts +5 -5
  212. package/src/vertexai/debug.ts +3 -3
  213. package/src/vertexai/embeddings/embed-legacy-multimodal.ts +211 -0
  214. package/src/vertexai/embeddings/embed.ts +206 -0
  215. package/src/vertexai/embeddings/embeddings.test.ts +497 -0
  216. package/src/vertexai/embeddings/source-utils.test.ts +54 -0
  217. package/src/vertexai/embeddings/source-utils.ts +29 -0
  218. package/src/vertexai/index.ts +339 -253
  219. package/src/vertexai/models/claude-error-handling.test.ts +86 -39
  220. package/src/vertexai/models/claude-streaming-spacing.test.ts +82 -75
  221. package/src/vertexai/models/claude.ts +84 -1041
  222. package/src/vertexai/models/gemini-conversation-mutation.test.ts +65 -23
  223. package/src/vertexai/models/gemini-error-handling.test.ts +126 -10
  224. package/src/vertexai/models/gemini-orphaned-tool-result.test.ts +118 -0
  225. package/src/vertexai/models/gemini.ts +372 -182
  226. package/src/vertexai/models/imagen.ts +164 -100
  227. package/src/vertexai/models/llama.ts +70 -48
  228. package/src/vertexai/models.ts +36 -16
  229. package/src/watsonx/index.ts +101 -65
  230. package/src/watsonx/interfaces.ts +10 -15
  231. package/src/xai/index.ts +30 -30
  232. package/lib/cjs/adobe/firefly.js +0 -120
  233. package/lib/cjs/adobe/firefly.js.map +0 -1
  234. package/lib/cjs/azure/azure_foundry.js +0 -432
  235. package/lib/cjs/azure/azure_foundry.js.map +0 -1
  236. package/lib/cjs/bedrock/converse.js +0 -359
  237. package/lib/cjs/bedrock/converse.js.map +0 -1
  238. package/lib/cjs/bedrock/index.js +0 -1508
  239. package/lib/cjs/bedrock/index.js.map +0 -1
  240. package/lib/cjs/bedrock/nova-image-payload.js +0 -207
  241. package/lib/cjs/bedrock/nova-image-payload.js.map +0 -1
  242. package/lib/cjs/bedrock/payloads.js +0 -3
  243. package/lib/cjs/bedrock/s3.js +0 -107
  244. package/lib/cjs/bedrock/s3.js.map +0 -1
  245. package/lib/cjs/bedrock/twelvelabs.js +0 -87
  246. package/lib/cjs/bedrock/twelvelabs.js.map +0 -1
  247. package/lib/cjs/groq/index.js +0 -328
  248. package/lib/cjs/groq/index.js.map +0 -1
  249. package/lib/cjs/huggingface_ie.js +0 -201
  250. package/lib/cjs/huggingface_ie.js.map +0 -1
  251. package/lib/cjs/index.js +0 -31
  252. package/lib/cjs/index.js.map +0 -1
  253. package/lib/cjs/mistral/index.js +0 -176
  254. package/lib/cjs/mistral/index.js.map +0 -1
  255. package/lib/cjs/mistral/types.js +0 -83
  256. package/lib/cjs/mistral/types.js.map +0 -1
  257. package/lib/cjs/openai/azure_openai.js +0 -72
  258. package/lib/cjs/openai/azure_openai.js.map +0 -1
  259. package/lib/cjs/openai/index.js +0 -1129
  260. package/lib/cjs/openai/index.js.map +0 -1
  261. package/lib/cjs/openai/openai.js +0 -21
  262. package/lib/cjs/openai/openai.js.map +0 -1
  263. package/lib/cjs/openai/openai_compatible.js +0 -63
  264. package/lib/cjs/openai/openai_compatible.js.map +0 -1
  265. package/lib/cjs/openai/openai_format.js +0 -131
  266. package/lib/cjs/openai/openai_format.js.map +0 -1
  267. package/lib/cjs/package.json +0 -3
  268. package/lib/cjs/replicate.js +0 -275
  269. package/lib/cjs/replicate.js.map +0 -1
  270. package/lib/cjs/shared/claude-thinking.js +0 -60
  271. package/lib/cjs/shared/claude-thinking.js.map +0 -1
  272. package/lib/cjs/test-driver/TestErrorCompletionStream.js +0 -20
  273. package/lib/cjs/test-driver/TestErrorCompletionStream.js.map +0 -1
  274. package/lib/cjs/test-driver/TestValidationErrorCompletionStream.js +0 -24
  275. package/lib/cjs/test-driver/TestValidationErrorCompletionStream.js.map +0 -1
  276. package/lib/cjs/test-driver/index.js +0 -109
  277. package/lib/cjs/test-driver/index.js.map +0 -1
  278. package/lib/cjs/test-driver/utils.js +0 -30
  279. package/lib/cjs/test-driver/utils.js.map +0 -1
  280. package/lib/cjs/togetherai/index.js +0 -126
  281. package/lib/cjs/togetherai/index.js.map +0 -1
  282. package/lib/cjs/togetherai/interfaces.js +0 -3
  283. package/lib/cjs/togetherai/interfaces.js.map +0 -1
  284. package/lib/cjs/vertexai/debug.js +0 -12
  285. package/lib/cjs/vertexai/debug.js.map +0 -1
  286. package/lib/cjs/vertexai/embeddings/embeddings-image.js +0 -27
  287. package/lib/cjs/vertexai/embeddings/embeddings-image.js.map +0 -1
  288. package/lib/cjs/vertexai/embeddings/embeddings-text.js +0 -23
  289. package/lib/cjs/vertexai/embeddings/embeddings-text.js.map +0 -1
  290. package/lib/cjs/vertexai/index.js +0 -644
  291. package/lib/cjs/vertexai/index.js.map +0 -1
  292. package/lib/cjs/vertexai/models/claude.js +0 -917
  293. package/lib/cjs/vertexai/models/claude.js.map +0 -1
  294. package/lib/cjs/vertexai/models/gemini.js +0 -858
  295. package/lib/cjs/vertexai/models/gemini.js.map +0 -1
  296. package/lib/cjs/vertexai/models/imagen.js +0 -303
  297. package/lib/cjs/vertexai/models/imagen.js.map +0 -1
  298. package/lib/cjs/vertexai/models/llama.js +0 -183
  299. package/lib/cjs/vertexai/models/llama.js.map +0 -1
  300. package/lib/cjs/vertexai/models.js +0 -35
  301. package/lib/cjs/vertexai/models.js.map +0 -1
  302. package/lib/cjs/watsonx/index.js +0 -161
  303. package/lib/cjs/watsonx/index.js.map +0 -1
  304. package/lib/cjs/watsonx/interfaces.js +0 -3
  305. package/lib/cjs/xai/index.js +0 -65
  306. package/lib/cjs/xai/index.js.map +0 -1
  307. package/lib/esm/adobe/firefly.js +0 -116
  308. package/lib/esm/adobe/firefly.js.map +0 -1
  309. package/lib/esm/azure/azure_foundry.js.map +0 -1
  310. package/lib/esm/bedrock/converse.js.map +0 -1
  311. package/lib/esm/bedrock/index.js.map +0 -1
  312. package/lib/esm/bedrock/nova-image-payload.js.map +0 -1
  313. package/lib/esm/bedrock/payloads.js.map +0 -1
  314. package/lib/esm/bedrock/s3.js.map +0 -1
  315. package/lib/esm/bedrock/twelvelabs.js.map +0 -1
  316. package/lib/esm/groq/index.js.map +0 -1
  317. package/lib/esm/huggingface_ie.js.map +0 -1
  318. package/lib/esm/index.js +0 -15
  319. package/lib/esm/index.js.map +0 -1
  320. package/lib/esm/mistral/index.js.map +0 -1
  321. package/lib/esm/mistral/types.js.map +0 -1
  322. package/lib/esm/openai/azure_openai.js.map +0 -1
  323. package/lib/esm/openai/index.js.map +0 -1
  324. package/lib/esm/openai/openai.js +0 -14
  325. package/lib/esm/openai/openai.js.map +0 -1
  326. package/lib/esm/openai/openai_compatible.js.map +0 -1
  327. package/lib/esm/openai/openai_format.js.map +0 -1
  328. package/lib/esm/replicate.js.map +0 -1
  329. package/lib/esm/shared/claude-thinking.js.map +0 -1
  330. package/lib/esm/test-driver/TestErrorCompletionStream.js +0 -16
  331. package/lib/esm/test-driver/TestErrorCompletionStream.js.map +0 -1
  332. package/lib/esm/test-driver/TestValidationErrorCompletionStream.js.map +0 -1
  333. package/lib/esm/test-driver/index.js.map +0 -1
  334. package/lib/esm/test-driver/utils.js.map +0 -1
  335. package/lib/esm/togetherai/index.js +0 -122
  336. package/lib/esm/togetherai/index.js.map +0 -1
  337. package/lib/esm/togetherai/interfaces.js.map +0 -1
  338. package/lib/esm/vertexai/debug.js.map +0 -1
  339. package/lib/esm/vertexai/embeddings/embeddings-image.js +0 -24
  340. package/lib/esm/vertexai/embeddings/embeddings-image.js.map +0 -1
  341. package/lib/esm/vertexai/embeddings/embeddings-text.js +0 -20
  342. package/lib/esm/vertexai/embeddings/embeddings-text.js.map +0 -1
  343. package/lib/esm/vertexai/index.js.map +0 -1
  344. package/lib/esm/vertexai/models/claude.js +0 -906
  345. package/lib/esm/vertexai/models/claude.js.map +0 -1
  346. package/lib/esm/vertexai/models/gemini.js.map +0 -1
  347. package/lib/esm/vertexai/models/imagen.js.map +0 -1
  348. package/lib/esm/vertexai/models/llama.js.map +0 -1
  349. package/lib/esm/vertexai/models.js.map +0 -1
  350. package/lib/esm/watsonx/index.js.map +0 -1
  351. package/lib/esm/xai/index.js.map +0 -1
  352. package/lib/types/adobe/firefly.d.ts.map +0 -1
  353. package/lib/types/azure/azure_foundry.d.ts.map +0 -1
  354. package/lib/types/bedrock/converse.d.ts.map +0 -1
  355. package/lib/types/bedrock/index.d.ts.map +0 -1
  356. package/lib/types/bedrock/nova-image-payload.d.ts.map +0 -1
  357. package/lib/types/bedrock/payloads.d.ts.map +0 -1
  358. package/lib/types/bedrock/s3.d.ts.map +0 -1
  359. package/lib/types/bedrock/twelvelabs.d.ts.map +0 -1
  360. package/lib/types/groq/index.d.ts.map +0 -1
  361. package/lib/types/huggingface_ie.d.ts.map +0 -1
  362. package/lib/types/index.d.ts +0 -15
  363. package/lib/types/index.d.ts.map +0 -1
  364. package/lib/types/mistral/index.d.ts.map +0 -1
  365. package/lib/types/mistral/types.d.ts.map +0 -1
  366. package/lib/types/openai/azure_openai.d.ts.map +0 -1
  367. package/lib/types/openai/index.d.ts.map +0 -1
  368. package/lib/types/openai/openai.d.ts.map +0 -1
  369. package/lib/types/openai/openai_compatible.d.ts.map +0 -1
  370. package/lib/types/openai/openai_format.d.ts.map +0 -1
  371. package/lib/types/replicate.d.ts.map +0 -1
  372. package/lib/types/shared/claude-thinking.d.ts.map +0 -1
  373. package/lib/types/test-driver/TestErrorCompletionStream.d.ts.map +0 -1
  374. package/lib/types/test-driver/TestValidationErrorCompletionStream.d.ts.map +0 -1
  375. package/lib/types/test-driver/index.d.ts.map +0 -1
  376. package/lib/types/test-driver/utils.d.ts.map +0 -1
  377. package/lib/types/togetherai/index.d.ts +0 -23
  378. package/lib/types/togetherai/index.d.ts.map +0 -1
  379. package/lib/types/togetherai/interfaces.d.ts.map +0 -1
  380. package/lib/types/vertexai/debug.d.ts +0 -2
  381. package/lib/types/vertexai/debug.d.ts.map +0 -1
  382. package/lib/types/vertexai/embeddings/embeddings-image.d.ts +0 -11
  383. package/lib/types/vertexai/embeddings/embeddings-image.d.ts.map +0 -1
  384. package/lib/types/vertexai/embeddings/embeddings-text.d.ts +0 -10
  385. package/lib/types/vertexai/embeddings/embeddings-text.d.ts.map +0 -1
  386. package/lib/types/vertexai/index.d.ts.map +0 -1
  387. package/lib/types/vertexai/models/claude.d.ts +0 -119
  388. package/lib/types/vertexai/models/claude.d.ts.map +0 -1
  389. package/lib/types/vertexai/models/gemini.d.ts.map +0 -1
  390. package/lib/types/vertexai/models/imagen.d.ts.map +0 -1
  391. package/lib/types/vertexai/models/llama.d.ts.map +0 -1
  392. package/lib/types/vertexai/models.d.ts +0 -20
  393. package/lib/types/vertexai/models.d.ts.map +0 -1
  394. package/lib/types/watsonx/index.d.ts.map +0 -1
  395. package/lib/types/watsonx/interfaces.d.ts.map +0 -1
  396. package/lib/types/xai/index.d.ts.map +0 -1
  397. package/src/vertexai/embeddings/embeddings-image.ts +0 -52
  398. package/src/vertexai/embeddings/embeddings-text.ts +0 -54
  399. /package/lib/{esm/bedrock → bedrock}/payloads.js +0 -0
  400. /package/lib/{esm/mistral → mistral}/types.js +0 -0
  401. /package/lib/{esm/togetherai → togetherai}/interfaces.js +0 -0
  402. /package/lib/{types/watsonx → watsonx}/interfaces.d.ts +0 -0
  403. /package/lib/{esm/watsonx → watsonx}/interfaces.js +0 -0
@@ -1,72 +1,137 @@
1
1
  import {
2
- Bedrock, CreateModelCustomizationJobCommand, type FoundationModelSummary, GetModelCustomizationJobCommand,
3
- type GetModelCustomizationJobCommandOutput, ModelCustomizationJobStatus, ModelModality, StopModelCustomizationJobCommand
4
- } from "@aws-sdk/client-bedrock";
5
- import { BedrockRuntime, type ContentBlock, type ConverseRequest, type ConverseResponse, type ConverseStreamOutput, type InferenceConfiguration, type Message, type Tool } from "@aws-sdk/client-bedrock-runtime";
6
- import { S3Client } from "@aws-sdk/client-s3";
7
- import type { AwsCredentialIdentity, Provider } from "@aws-sdk/types";
2
+ Bedrock,
3
+ CreateModelCustomizationJobCommand,
4
+ type FoundationModelSummary,
5
+ GetModelCustomizationJobCommand,
6
+ type GetModelCustomizationJobCommandOutput,
7
+ ModelCustomizationJobStatus,
8
+ ModelModality,
9
+ StopModelCustomizationJobCommand,
10
+ } from '@aws-sdk/client-bedrock';
8
11
  import {
9
- AbstractDriver, type AIModel,
12
+ BedrockRuntime,
13
+ type ContentBlock,
14
+ type ConverseRequest,
15
+ type ConverseResponse,
16
+ type ConverseStreamOutput,
17
+ type InferenceConfiguration,
18
+ type InvokeModelCommandOutput,
19
+ type Message,
20
+ type Tool,
21
+ type ToolResultContentBlock,
22
+ } from '@aws-sdk/client-bedrock-runtime';
23
+ import { S3Client } from '@aws-sdk/client-s3';
24
+ import type { AwsCredentialIdentity, Provider } from '@aws-sdk/types';
25
+ import {
26
+ type AIModel,
10
27
  type BedrockClaudeOptions,
11
28
  type BedrockGptOssOptions,
12
29
  type BedrockPalmyraOptions,
13
- type Completion, type CompletionChunkObject,
30
+ type Completion,
31
+ type CompletionChunkObject,
14
32
  type CompletionResult,
15
33
  type DataSource,
16
- deserializeBinaryFromStorage,
17
34
  type DriverOptions,
18
- type EmbeddingsOptions, type EmbeddingsResult,
19
- type ExecutionOptions, type ExecutionTokenUsage,
35
+ deserializeBinaryFromStorage,
36
+ type EmbeddingsOptions,
37
+ type EmbeddingsResult,
38
+ type ExecutionOptions,
39
+ type ExecutionTokenUsage,
20
40
  getConversationMeta,
21
41
  getMaxTokensLimitBedrock,
22
42
  getModelCapabilities,
43
+ type HttpTimeoutOptions,
23
44
  incrementConversationTurn,
24
45
  isClaudeVersionGTE,
25
- LlumiverseError, type LlumiverseErrorContext,
26
- modelModalitiesToArray,
46
+ LlumiverseError,
47
+ type LlumiverseErrorContext,
27
48
  type ModelOptions,
49
+ modelModalitiesToArray,
28
50
  type NovaCanvasOptions,
29
51
  type PromptSegment,
30
52
  type StatelessExecutionOptions,
31
53
  stripBinaryFromConversation,
32
54
  stripHeartbeatsFromConversation,
33
- type TextFallbackOptions, type ToolDefinition, type ToolUse, type TrainingJob, TrainingJobStatus, type TrainingOptions,
34
- truncateLargeTextInConversation
35
- } from "@llumiverse/core";
36
- import { transformAsyncIterator } from "@llumiverse/core/async";
37
- import { formatNovaPrompt, type NovaMessagesPrompt } from "@llumiverse/core/formatters";
38
- import { LRUCache } from "mnemonist";
39
- import { resolveClaudeThinking } from "../shared/claude-thinking.js";
40
- import { converseConcatMessages, converseJSONprefill, converseSystemToMessages, formatConversePrompt } from "./converse.js";
41
- import { formatNovaImageGenerationPayload, NovaImageGenerationTaskType } from "./nova-image-payload.js";
42
- import { forceUploadFile } from "./s3.js";
55
+ type TextFallbackOptions,
56
+ type ToolDefinition,
57
+ type ToolUse,
58
+ type TrainingJob,
59
+ TrainingJobStatus,
60
+ type TrainingOptions,
61
+ truncateLargeTextInConversation,
62
+ } from '@llumiverse/core';
63
+ import { transformAsyncIterator } from '@llumiverse/core/async';
64
+ import { AbstractDriver } from '@llumiverse/core/driver';
65
+ import { formatNovaPrompt, type NovaMessagesPrompt } from '@llumiverse/core/formatters';
66
+ import { mergeDriverHttpTimeoutOptions, resolveDriverHttpTimeouts } from '@llumiverse/core/http-agent';
67
+ import { LRUCache } from 'mnemonist';
68
+ import { resolveClaudeThinking } from '../shared/claude-thinking.js';
69
+ import { truncateBinaryForDebug, uint8ArrayToBase64ForDebug } from '../shared/debug-prompt.js';
43
70
  import {
44
- formatTwelvelabsPegasusPrompt,
45
- type TwelvelabsMarengoRequest,
46
- type TwelvelabsMarengoResponse,
47
- type TwelvelabsPegasusRequest
48
- } from "./twelvelabs.js";
71
+ converseConcatMessages,
72
+ converseJSONprefill,
73
+ converseSystemToMessages,
74
+ formatConversePrompt,
75
+ } from './converse.js';
76
+ import { generateBedrockEmbeddings } from './embeddings.js';
77
+ import { formatNovaImageGenerationPayload, NovaImageGenerationTaskType } from './nova-image-payload.js';
78
+ import { forceUploadFile } from './s3.js';
79
+ import { formatTwelvelabsPegasusPrompt, type TwelvelabsPegasusRequest } from './twelvelabs.js';
49
80
 
50
81
  const supportStreamingCache = new LRUCache<string, boolean>(4096);
51
82
 
52
- enum BedrockModelType {
53
- FoundationModel = "foundation-model",
54
- InferenceProfile = "inference-profile",
55
- CustomModel = "custom-model",
56
- Unknown = "unknown",
83
+ type AwsSdkError = {
84
+ name?: string;
85
+ message?: string;
86
+ $metadata?: {
87
+ httpStatusCode?: number;
88
+ requestId?: string;
89
+ };
90
+ $fault?: string;
91
+ };
92
+ type ReasoningBlockStart = {
93
+ reasoningContent?: {
94
+ redactedContent?: Uint8Array;
95
+ };
96
+ };
97
+ type BedrockRuntimeExecutorScope = {
98
+ executor: BedrockRuntime;
99
+ close(): void;
57
100
  };
58
101
 
102
+ enum BedrockModelType {
103
+ FoundationModel = 'foundation-model',
104
+ InferenceProfile = 'inference-profile',
105
+ CustomModel = 'custom-model',
106
+ Unknown = 'unknown',
107
+ }
108
+
59
109
  function converseFinishReason(reason: string | undefined) {
60
110
  //Possible values:
61
111
  //end_turn | tool_use | max_tokens | stop_sequence | guardrail_intervened | content_filtered
62
112
  if (!reason) return undefined;
63
113
  switch (reason) {
64
- case 'end_turn': return "stop";
65
- case 'max_tokens': return "length";
66
- default: return reason;
114
+ case 'end_turn':
115
+ return 'stop';
116
+ case 'max_tokens':
117
+ return 'length';
118
+ default:
119
+ return reason;
67
120
  }
68
121
  }
69
122
 
123
+ function withBedrockRuntimeScope<T>(iterable: AsyncIterable<T>, scope: BedrockRuntimeExecutorScope): AsyncIterable<T> {
124
+ return {
125
+ async *[Symbol.asyncIterator]() {
126
+ try {
127
+ yield* iterable;
128
+ } finally {
129
+ scope.close();
130
+ }
131
+ },
132
+ };
133
+ }
134
+
70
135
  export interface BedrockModelCapabilities {
71
136
  name: string;
72
137
  canStream: boolean;
@@ -92,13 +157,12 @@ export interface BedrockDriverOptions extends DriverOptions {
92
157
  * The credentials to use to access AWS (IAM access key + secret)
93
158
  */
94
159
  credentials?: AwsCredentialIdentity | Provider<AwsCredentialIdentity>;
95
-
96
160
  }
97
161
 
98
162
  //Used to get a max_token value when not specified in the model options. Claude requires it to be set.
99
163
  function maxTokenFallbackClaude(option: StatelessExecutionOptions): number {
100
164
  const modelOptions = option.model_options as BedrockClaudeOptions | undefined;
101
- if (modelOptions && typeof modelOptions.max_tokens === "number") {
165
+ if (modelOptions && typeof modelOptions.max_tokens === 'number') {
102
166
  return modelOptions.max_tokens;
103
167
  } else {
104
168
  let maxSupportedTokens = getMaxTokensLimitBedrock(option.model) ?? 8192; // Should always return a number for claude, 8192 is to satisfy the TypeScript type checker;
@@ -115,9 +179,173 @@ export type BedrockPrompt = NovaMessagesPrompt | ConverseRequest | TwelvelabsPeg
115
179
  type BedrockSystemBlock = NonNullable<ConverseRequest['system']>[number];
116
180
  type BedrockToolEntry = NonNullable<NonNullable<ConverseRequest['toolConfig']>['tools']>[number];
117
181
 
118
- export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockPrompt> {
182
+ function formatBedrockBytes(bytes: Uint8Array | string | undefined): string | undefined {
183
+ if (bytes instanceof Uint8Array) {
184
+ return truncateBinaryForDebug(uint8ArrayToBase64ForDebug(bytes));
185
+ }
186
+ if (typeof bytes === 'string') {
187
+ return truncateBinaryForDebug(bytes);
188
+ }
189
+ return bytes;
190
+ }
119
191
 
120
- static PROVIDER = "bedrock";
192
+ function formatBedrockBytesForDebug(bytes: Uint8Array | string | undefined): Uint8Array {
193
+ // AWS SDK prompt types require Uint8Array here, but the debug prompt returned to
194
+ // Studio must be JSON-safe. Keep the mismatch contained to this conversion.
195
+ return formatBedrockBytes(bytes) as unknown as Uint8Array;
196
+ }
197
+
198
+ function formatBedrockContentBlockForDebug(block: ContentBlock): ContentBlock {
199
+ if (block.image?.source?.bytes) {
200
+ return {
201
+ ...block,
202
+ image: {
203
+ ...block.image,
204
+ source: {
205
+ ...block.image.source,
206
+ bytes: formatBedrockBytesForDebug(block.image.source.bytes),
207
+ },
208
+ },
209
+ };
210
+ }
211
+ if (block.document?.source?.bytes) {
212
+ return {
213
+ ...block,
214
+ document: {
215
+ ...block.document,
216
+ source: {
217
+ ...block.document.source,
218
+ bytes: formatBedrockBytesForDebug(block.document.source.bytes),
219
+ },
220
+ },
221
+ };
222
+ }
223
+ if (block.video?.source?.bytes) {
224
+ return {
225
+ ...block,
226
+ video: {
227
+ ...block.video,
228
+ source: {
229
+ ...block.video.source,
230
+ bytes: formatBedrockBytesForDebug(block.video.source.bytes),
231
+ },
232
+ },
233
+ };
234
+ }
235
+ if (block.toolResult?.content) {
236
+ return {
237
+ ...block,
238
+ toolResult: {
239
+ ...block.toolResult,
240
+ content: block.toolResult.content.map(formatBedrockToolResultContentBlockForDebug),
241
+ },
242
+ };
243
+ }
244
+ return block;
245
+ }
246
+
247
+ function formatBedrockToolResultContentBlockForDebug(block: ToolResultContentBlock): ToolResultContentBlock {
248
+ if (block.image?.source?.bytes) {
249
+ return {
250
+ ...block,
251
+ image: {
252
+ ...block.image,
253
+ source: {
254
+ ...block.image.source,
255
+ bytes: formatBedrockBytesForDebug(block.image.source.bytes),
256
+ },
257
+ },
258
+ };
259
+ }
260
+ if (block.document?.source?.bytes) {
261
+ return {
262
+ ...block,
263
+ document: {
264
+ ...block.document,
265
+ source: {
266
+ ...block.document.source,
267
+ bytes: formatBedrockBytesForDebug(block.document.source.bytes),
268
+ },
269
+ },
270
+ };
271
+ }
272
+ if (block.video?.source?.bytes) {
273
+ return {
274
+ ...block,
275
+ video: {
276
+ ...block.video,
277
+ source: {
278
+ ...block.video.source,
279
+ bytes: formatBedrockBytesForDebug(block.video.source.bytes),
280
+ },
281
+ },
282
+ };
283
+ }
284
+ return block;
285
+ }
286
+
287
+ function formatConversePromptForDebug(prompt: ConverseRequest): ConverseRequest {
288
+ return {
289
+ ...prompt,
290
+ messages: prompt.messages?.map((message) => ({
291
+ ...message,
292
+ content: message.content?.map(formatBedrockContentBlockForDebug),
293
+ })),
294
+ };
295
+ }
296
+
297
+ function formatNovaPromptForDebug(prompt: NovaMessagesPrompt): NovaMessagesPrompt {
298
+ return {
299
+ ...prompt,
300
+ messages: prompt.messages.map((message) => ({
301
+ ...message,
302
+ content: message.content.map((part) => {
303
+ if (!part.image?.source.bytes && !part.video?.source.bytes) {
304
+ return part;
305
+ }
306
+ return {
307
+ ...part,
308
+ image: part.image
309
+ ? {
310
+ ...part.image,
311
+ source: {
312
+ ...part.image.source,
313
+ bytes: truncateBinaryForDebug(part.image.source.bytes),
314
+ },
315
+ }
316
+ : undefined,
317
+ video: part.video
318
+ ? {
319
+ ...part.video,
320
+ source: {
321
+ ...part.video.source,
322
+ bytes: part.video.source.bytes
323
+ ? truncateBinaryForDebug(part.video.source.bytes)
324
+ : undefined,
325
+ },
326
+ }
327
+ : undefined,
328
+ };
329
+ }),
330
+ })),
331
+ };
332
+ }
333
+
334
+ function formatTwelvelabsPromptForDebug(prompt: TwelvelabsPegasusRequest): TwelvelabsPegasusRequest {
335
+ if (!prompt.mediaSource.base64String) {
336
+ return prompt;
337
+ }
338
+ return {
339
+ ...prompt,
340
+ mediaSource: {
341
+ ...prompt.mediaSource,
342
+ base64String: truncateBinaryForDebug(prompt.mediaSource.base64String),
343
+ },
344
+ };
345
+ }
346
+
347
+ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockPrompt> {
348
+ static PROVIDER = 'bedrock';
121
349
 
122
350
  provider = BedrockDriver.PROVIDER;
123
351
 
@@ -132,21 +360,63 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
132
360
  }
133
361
  }
134
362
 
135
- getExecutor() {
363
+ /**
364
+ * Build a Smithy `requestHandler` config from the driver's
365
+ * `httpTimeout` so AWS SDK calls fail fast on hung upstream Bedrock
366
+ * endpoints instead of using the AWS default (no request timeout).
367
+ * Returns a partial config the SDK merges into its default handler.
368
+ */
369
+ private getBedrockRequestHandlerConfig(httpTimeout?: HttpTimeoutOptions) {
370
+ const timeouts = resolveDriverHttpTimeouts(
371
+ mergeDriverHttpTimeoutOptions(this.options.httpTimeout, httpTimeout),
372
+ );
373
+ return {
374
+ requestTimeout: timeouts.headersTimeout,
375
+ throwOnRequestTimeout: true,
376
+ connectionTimeout: timeouts.connectTimeout,
377
+ socketTimeout: timeouts.bodyTimeout,
378
+ };
379
+ }
380
+
381
+ private createExecutor(httpTimeout?: HttpTimeoutOptions) {
382
+ return new BedrockRuntime({
383
+ region: this.options.region,
384
+ credentials: this.options.credentials,
385
+ requestHandler: this.getBedrockRequestHandlerConfig(httpTimeout),
386
+ });
387
+ }
388
+
389
+ getExecutor(httpTimeout?: HttpTimeoutOptions) {
390
+ if (httpTimeout) {
391
+ return this.createExecutor(httpTimeout);
392
+ }
136
393
  if (!this._executor) {
137
- this._executor = new BedrockRuntime({
138
- region: this.options.region,
139
- credentials: this.options.credentials,
140
- });
394
+ this._executor = this.createExecutor();
141
395
  }
142
396
  return this._executor;
143
397
  }
144
398
 
399
+ private getScopedExecutor(options: Pick<ExecutionOptions, 'httpTimeout'>): BedrockRuntimeExecutorScope {
400
+ if (!options.httpTimeout) {
401
+ return {
402
+ executor: this.getExecutor(),
403
+ close: () => undefined,
404
+ };
405
+ }
406
+
407
+ const executor = this.getExecutor(options.httpTimeout);
408
+ return {
409
+ executor,
410
+ close: () => executor.destroy(),
411
+ };
412
+ }
413
+
145
414
  getService(region: string = this.options.region) {
146
415
  if (!this._service || this._service_region !== region) {
147
416
  this._service = new Bedrock({
148
417
  region: region,
149
418
  credentials: this.options.credentials,
419
+ requestHandler: this.getBedrockRequestHandlerConfig(),
150
420
  });
151
421
  this._service_region = region;
152
422
  }
@@ -154,34 +424,41 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
154
424
  }
155
425
 
156
426
  protected async formatPrompt(segments: PromptSegment[], opts: ExecutionOptions): Promise<BedrockPrompt> {
157
- if (opts.model.includes("canvas")) {
427
+ if (opts.model.includes('canvas')) {
158
428
  return await formatNovaPrompt(segments, opts.result_schema);
159
429
  }
160
- if (opts.model.includes("twelvelabs.pegasus")) {
430
+ if (opts.model.includes('twelvelabs.pegasus')) {
161
431
  return await formatTwelvelabsPegasusPrompt(segments, opts);
162
432
  }
163
433
  return await formatConversePrompt(segments, opts);
164
434
  }
165
435
 
436
+ public formatDebugPrompt(prompt: BedrockPrompt): BedrockPrompt {
437
+ if ('mediaSource' in prompt) {
438
+ return formatTwelvelabsPromptForDebug(prompt);
439
+ }
440
+ if ('modelId' in prompt) {
441
+ return formatConversePromptForDebug(prompt);
442
+ }
443
+ return formatNovaPromptForDebug(prompt);
444
+ }
445
+
166
446
  /**
167
447
  * Format AWS Bedrock errors into LlumiverseError with proper status codes and retryability.
168
- *
448
+ *
169
449
  * AWS SDK errors provide:
170
450
  * - error.name: The exception type (e.g., "ThrottlingException")
171
451
  * - error.$metadata.httpStatusCode: The HTTP status code
172
452
  * - error.$metadata.requestId: The AWS request ID for tracking
173
453
  * - error.$fault: "client" or "server" indicating error category
174
- *
454
+ *
175
455
  * @param error - The AWS SDK error
176
456
  * @param context - Context about where the error occurred
177
457
  * @returns A standardized LlumiverseError
178
458
  */
179
- public formatLlumiverseError(
180
- error: unknown,
181
- context: LlumiverseErrorContext
182
- ): LlumiverseError {
459
+ public formatLlumiverseError(error: unknown, context: LlumiverseErrorContext): LlumiverseError {
183
460
  // Check if it's an AWS SDK error with $metadata
184
- const awsError = error as any;
461
+ const awsError = error as AwsSdkError;
185
462
  const hasMetadata = awsError?.$metadata !== undefined;
186
463
 
187
464
  if (!hasMetadata) {
@@ -232,13 +509,13 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
232
509
  context,
233
510
  error,
234
511
  httpStatusCode, // Only set code if we have numeric status code
235
- errorName // Preserve AWS error name
512
+ errorName, // Preserve AWS error name
236
513
  );
237
514
  }
238
515
 
239
516
  /**
240
517
  * Determine if a Bedrock error is retryable based on error type and status.
241
- *
518
+ *
242
519
  * Retryable errors:
243
520
  * - ThrottlingException: Rate limit exceeded, retry with backoff
244
521
  * - ServiceUnavailableException: Service temporarily down
@@ -246,7 +523,7 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
246
523
  * - ServiceQuotaExceededException: Quota exhausted, may recover
247
524
  * - 5xx status codes: Server errors
248
525
  * - 429, 408 status codes: Rate limit, timeout
249
- *
526
+ *
250
527
  * Non-retryable errors:
251
528
  * - ValidationException: Invalid request parameters
252
529
  * - AccessDeniedException: Authentication/authorization failure
@@ -254,7 +531,7 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
254
531
  * - ConflictException: Resource state conflict
255
532
  * - ResourceInUseException: Resource locked by another operation
256
533
  * - 4xx status codes (except 429, 408): Client errors
257
- *
534
+ *
258
535
  * @param errorName - The AWS error name (e.g., "ThrottlingException")
259
536
  * @param httpStatusCode - The HTTP status code if available
260
537
  * @param fault - The fault type ("client" or "server")
@@ -263,7 +540,7 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
263
540
  private isBedrockErrorRetryable(
264
541
  errorName: string,
265
542
  httpStatusCode: number | undefined,
266
- fault: string | undefined
543
+ fault: string | undefined,
267
544
  ): boolean | undefined {
268
545
  // Check specific AWS error types first
269
546
  switch (errorName) {
@@ -300,9 +577,13 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
300
577
  return undefined;
301
578
  }
302
579
 
303
- getExtractedExecution(result: ConverseResponse, _prompt?: BedrockPrompt, options?: ExecutionOptions): CompletionChunkObject {
304
- let resultText = "";
305
- let reasoning = "";
580
+ getExtractedExecution(
581
+ result: ConverseResponse,
582
+ _prompt?: BedrockPrompt,
583
+ options?: ExecutionOptions,
584
+ ): CompletionChunkObject {
585
+ let resultText = '';
586
+ let reasoning = '';
306
587
 
307
588
  if (result.output?.message?.content) {
308
589
  for (const content of result.output.message.content) {
@@ -323,14 +604,14 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
323
604
  reasoning += `[Redacted thinking: ${redactedData}]`;
324
605
  }
325
606
  } else {
326
- this.logger.info("[Bedrock] Not outputting reasoning content as include_thoughts is false");
607
+ this.logger.info('[Bedrock] Not outputting reasoning content as include_thoughts is false');
327
608
  }
328
609
  } else {
329
610
  // Get content block type
330
611
  const type = Object.keys(content).find(
331
- key => key !== '$unknown' && content[key as keyof typeof content] !== undefined
612
+ (key) => key !== '$unknown' && content[key as keyof typeof content] !== undefined,
332
613
  );
333
- this.logger.info({ type }, "[Bedrock] Unsupported content response type:");
614
+ this.logger.info({ type }, '[Bedrock] Unsupported content response type:');
334
615
  }
335
616
  }
336
617
 
@@ -341,14 +622,18 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
341
622
  }
342
623
 
343
624
  const completionResult: CompletionChunkObject = {
344
- result: reasoning + resultText ? [{ type: "text", value: reasoning + resultText }] : [],
625
+ result: reasoning + resultText ? [{ type: 'text', value: reasoning + resultText }] : [],
345
626
  token_usage: {
346
627
  // Bedrock's inputTokens already excludes cache-read tokens,
347
628
  // so prompt_new is inputTokens directly (no subtraction needed).
348
629
  // prompt is the total including cached + cache_write for consistency
349
630
  // with the Vertex Claude driver.
350
631
  prompt_new: result.usage?.inputTokens,
351
- prompt: result.usage ? (result.usage.inputTokens ?? 0) + (result.usage.cacheReadInputTokens ?? 0) + (result.usage.cacheWriteInputTokens ?? 0) : undefined,
632
+ prompt: result.usage
633
+ ? (result.usage.inputTokens ?? 0) +
634
+ (result.usage.cacheReadInputTokens ?? 0) +
635
+ (result.usage.cacheWriteInputTokens ?? 0)
636
+ : undefined,
352
637
  result: result.usage?.outputTokens,
353
638
  total: result.usage?.totalTokens,
354
639
  prompt_cached: result.usage?.cacheReadInputTokens ?? undefined,
@@ -358,32 +643,46 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
358
643
  };
359
644
 
360
645
  return completionResult;
361
- };
646
+ }
362
647
 
363
- getExtractedStream(result: ConverseStreamOutput, _prompt?: BedrockPrompt, options?: ExecutionOptions, streamingToolBlocks?: Map<number, { id: string; name: string }>): CompletionChunkObject {
364
- let output: string = "";
365
- let reasoning: string = "";
366
- let stop_reason = "";
648
+ getExtractedStream(
649
+ result: ConverseStreamOutput,
650
+ _prompt?: BedrockPrompt,
651
+ options?: ExecutionOptions,
652
+ streamingToolBlocks?: Map<number, { id: string; name: string }>,
653
+ ): CompletionChunkObject {
654
+ let output: string = '';
655
+ let reasoning: string = '';
656
+ let stop_reason = '';
367
657
  let token_usage: ExecutionTokenUsage | undefined;
368
- let tool_use: ToolUse[] | undefined;
658
+ let tool_use: ToolUse<unknown>[] | undefined;
369
659
 
370
660
  // Check if we should include thoughts (always true for reasoning-only models like DeepSeek R1)
371
661
  const isReasoningModel = options?.model?.includes('deepseek') && options?.model?.includes('r1');
372
- const shouldIncludeThoughts = isReasoningModel || (options && (options.model_options as BedrockClaudeOptions)?.include_thoughts);
662
+ const shouldIncludeThoughts =
663
+ isReasoningModel || (options && (options.model_options as BedrockClaudeOptions)?.include_thoughts);
373
664
 
374
665
  // Handle content block start events (for reasoning blocks and tool use)
375
666
  if (result.contentBlockStart) {
376
- if (result.contentBlockStart.start && 'toolUse' in result.contentBlockStart.start && result.contentBlockStart.start.toolUse) {
667
+ if (
668
+ result.contentBlockStart.start &&
669
+ 'toolUse' in result.contentBlockStart.start &&
670
+ result.contentBlockStart.start.toolUse
671
+ ) {
377
672
  // Register new tool call block and emit an initial chunk so the accumulator can track it by id
378
673
  const toolUseStart = result.contentBlockStart.start.toolUse;
379
674
  const blockIndex = result.contentBlockStart.contentBlockIndex ?? -1;
380
675
  const id = toolUseStart.toolUseId ?? '';
381
676
  const name = toolUseStart.name ?? '';
382
677
  streamingToolBlocks?.set(blockIndex, { id, name });
383
- tool_use = [{ id, tool_name: name, tool_input: '' as any }];
384
- } else if (result.contentBlockStart.start && 'reasoningContent' in result.contentBlockStart.start && shouldIncludeThoughts) {
678
+ tool_use = [{ id, tool_name: name, tool_input: '' }];
679
+ } else if (
680
+ result.contentBlockStart.start &&
681
+ 'reasoningContent' in result.contentBlockStart.start &&
682
+ shouldIncludeThoughts
683
+ ) {
385
684
  // Handle redacted content at block start
386
- const reasoningStart = result.contentBlockStart.start as any;
685
+ const reasoningStart = result.contentBlockStart.start as ReasoningBlockStart;
387
686
  if (reasoningStart.reasoningContent?.redactedContent) {
388
687
  const redactedData = new TextDecoder().decode(reasoningStart.reasoningContent.redactedContent);
389
688
  reasoning = `[Redacted thinking: ${redactedData}]`;
@@ -399,7 +698,7 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
399
698
  const blockIndex = result.contentBlockDelta.contentBlockIndex ?? -1;
400
699
  const toolBlock = streamingToolBlocks?.get(blockIndex);
401
700
  if (toolBlock && delta.toolUse.input !== undefined) {
402
- tool_use = [{ id: toolBlock.id, tool_name: '', tool_input: delta.toolUse.input as any }];
701
+ tool_use = [{ id: toolBlock.id, tool_name: '', tool_input: delta.toolUse.input }];
403
702
  }
404
703
  } else if (delta?.text) {
405
704
  output = delta.text;
@@ -411,16 +710,16 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
411
710
  reasoning = `[Redacted thinking: ${redactedData}]`;
412
711
  } else if (delta.reasoningContent.signature) {
413
712
  // Handle signature updates for reasoning content - end of thinking
414
- reasoning = "\n\n";
713
+ reasoning = '\n\n';
415
714
  // Putting logging here so it only triggers once.
416
- this.logger.info("[Bedrock] Not outputting reasoning content as include_thoughts is false");
715
+ this.logger.info('[Bedrock] Not outputting reasoning content as include_thoughts is false');
417
716
  }
418
717
  } else if (delta) {
419
718
  // Get content block type
420
719
  const type = Object.keys(delta).find(
421
- key => key !== '$unknown' && (delta as any)[key] !== undefined
720
+ (key) => key !== '$unknown' && (delta as unknown as Record<string, unknown>)[key] !== undefined,
422
721
  );
423
- this.logger.info({ type }, "[Bedrock] Unsupported content response type:");
722
+ this.logger.info({ type }, '[Bedrock] Unsupported content response type:');
424
723
  }
425
724
  }
426
725
 
@@ -436,29 +735,33 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
436
735
  }
437
736
 
438
737
  if (result.messageStop) {
439
- stop_reason = result.messageStop.stopReason ?? "";
738
+ stop_reason = result.messageStop.stopReason ?? '';
440
739
  }
441
740
 
442
741
  if (result.metadata) {
443
742
  token_usage = {
444
743
  prompt_new: result.metadata.usage?.inputTokens,
445
- prompt: result.metadata.usage ? (result.metadata.usage.inputTokens ?? 0) + (result.metadata.usage.cacheReadInputTokens ?? 0) + (result.metadata.usage.cacheWriteInputTokens ?? 0) : undefined,
744
+ prompt: result.metadata.usage
745
+ ? (result.metadata.usage.inputTokens ?? 0) +
746
+ (result.metadata.usage.cacheReadInputTokens ?? 0) +
747
+ (result.metadata.usage.cacheWriteInputTokens ?? 0)
748
+ : undefined,
446
749
  result: result.metadata.usage?.outputTokens,
447
750
  total: result.metadata.usage?.totalTokens,
448
751
  prompt_cached: result.metadata.usage?.cacheReadInputTokens ?? undefined,
449
752
  prompt_cache_write: result.metadata.usage?.cacheWriteInputTokens ?? undefined,
450
- }
753
+ };
451
754
  }
452
755
 
453
756
  const completionResult: CompletionChunkObject = {
454
- result: reasoning + output ? [{ type: "text", value: reasoning + output }] : [],
757
+ result: reasoning + output ? [{ type: 'text', value: reasoning + output }] : [],
455
758
  token_usage: token_usage,
456
759
  finish_reason: converseFinishReason(stop_reason),
457
760
  tool_use,
458
761
  };
459
762
 
460
763
  return completionResult;
461
- };
764
+ }
462
765
 
463
766
  extractRegion(modelString: string, defaultRegion: string): string {
464
767
  // Match region in full ARN pattern
@@ -468,7 +771,9 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
468
771
  }
469
772
 
470
773
  // Match common AWS regions directly in string
471
- const regionMatch = modelString.match(/(?:us|eu|ap|sa|ca|me|af)[-](east|west|central|south|north|southeast|southwest|northeast|northwest)[-][1-9]/);
774
+ const regionMatch = modelString.match(
775
+ /(?:us|eu|ap|sa|ca|me|af)[-](east|west|central|south|north|southeast|southwest|northeast|northwest)[-][1-9]/,
776
+ );
472
777
  if (regionMatch) {
473
778
  return regionMatch[0];
474
779
  }
@@ -478,12 +783,12 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
478
783
 
479
784
  private async getCanStream(model: string, type: BedrockModelType): Promise<boolean> {
480
785
  let canStream: boolean = false;
481
- let error: any = null;
786
+ let error: unknown = null;
482
787
  const region = this.extractRegion(model, this.options.region);
483
788
  if (type === BedrockModelType.FoundationModel || type === BedrockModelType.Unknown) {
484
789
  try {
485
790
  const response = await this.getService(region).getFoundationModel({
486
- modelIdentifier: model
791
+ modelIdentifier: model,
487
792
  });
488
793
  canStream = response.modelDetails?.responseStreamingSupported ?? false;
489
794
  return canStream;
@@ -494,9 +799,12 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
494
799
  if (type === BedrockModelType.InferenceProfile || type === BedrockModelType.Unknown) {
495
800
  try {
496
801
  const response = await this.getService(region).getInferenceProfile({
497
- inferenceProfileIdentifier: model
802
+ inferenceProfileIdentifier: model,
498
803
  });
499
- canStream = await this.getCanStream(response.models?.[0].modelArn ?? "", BedrockModelType.FoundationModel);
804
+ canStream = await this.getCanStream(
805
+ response.models?.[0].modelArn ?? '',
806
+ BedrockModelType.FoundationModel,
807
+ );
500
808
  return canStream;
501
809
  } catch (e) {
502
810
  error = e;
@@ -505,16 +813,16 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
505
813
  if (type === BedrockModelType.CustomModel || type === BedrockModelType.Unknown) {
506
814
  try {
507
815
  const response = await this.getService(region).getCustomModel({
508
- modelIdentifier: model
816
+ modelIdentifier: model,
509
817
  });
510
- canStream = await this.getCanStream(response.baseModelArn ?? "", BedrockModelType.FoundationModel);
818
+ canStream = await this.getCanStream(response.baseModelArn ?? '', BedrockModelType.FoundationModel);
511
819
  return canStream;
512
820
  } catch (e) {
513
821
  error = e;
514
822
  }
515
823
  }
516
824
  if (error) {
517
- console.warn("Error on canStream check for model: " + model + " region detected: " + region, error);
825
+ console.warn(`Error on canStream check for model: ${model} region detected: ${region}`, error);
518
826
  }
519
827
  return canStream;
520
828
  }
@@ -528,11 +836,11 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
528
836
  let canStream = supportStreamingCache.get(options.model);
529
837
  if (canStream == null) {
530
838
  let type = BedrockModelType.Unknown;
531
- if (options.model.includes("foundation-model")) {
839
+ if (options.model.includes('foundation-model')) {
532
840
  type = BedrockModelType.FoundationModel;
533
- } else if (options.model.includes("inference-profile")) {
841
+ } else if (options.model.includes('inference-profile')) {
534
842
  type = BedrockModelType.InferenceProfile;
535
- } else if (options.model.includes("custom-model")) {
843
+ } else if (options.model.includes('custom-model')) {
536
844
  type = BedrockModelType.CustomModel;
537
845
  }
538
846
  canStream = await this.getCanStream(options.model, type);
@@ -549,10 +857,10 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
549
857
  prompt: BedrockPrompt,
550
858
  result: unknown[],
551
859
  toolUse: unknown[] | undefined,
552
- options: ExecutionOptions
860
+ options: ExecutionOptions,
553
861
  ): ConverseRequest | undefined {
554
862
  // Only handle ConverseRequest prompts (not NovaMessagesPrompt or TwelvelabsPegasusRequest)
555
- if (options.model.includes("canvas") || options.model.includes("twelvelabs.pegasus")) {
863
+ if (options.model.includes('canvas') || options.model.includes('twelvelabs.pegasus')) {
556
864
  return undefined;
557
865
  }
558
866
 
@@ -561,7 +869,7 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
561
869
 
562
870
  // Convert accumulated results to text content for assistant message
563
871
  const textContent = completionResults
564
- .map(r => {
872
+ .map((r) => {
565
873
  switch (r.type) {
566
874
  case 'text':
567
875
  return r.value;
@@ -570,8 +878,10 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
570
878
  case 'image':
571
879
  // Skip images in conversation - they're in the result
572
880
  return '';
573
- default:
574
- return String((r as any).value || '');
881
+ default: {
882
+ const _exhaustive: never = r;
883
+ return String(_exhaustive);
884
+ }
575
885
  }
576
886
  })
577
887
  .join('');
@@ -583,7 +893,7 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
583
893
  let conversation = updateConversation(incomingConversation, conversePrompt);
584
894
 
585
895
  // Build assistant message content
586
- const messageContent: any[] = [];
896
+ const messageContent: ContentBlock[] = [];
587
897
  if (textContent) {
588
898
  messageContent.push({ text: textContent });
589
899
  }
@@ -595,17 +905,19 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
595
905
  toolUseId: tool.id,
596
906
  name: tool.tool_name,
597
907
  input: tool.tool_input,
598
- }
908
+ },
599
909
  });
600
910
  }
601
911
  }
602
912
 
603
913
  // Add assistant message
604
914
  const assistantMessage: ConverseRequest = {
605
- messages: [{
606
- content: messageContent.length > 0 ? messageContent : [{ text: '' }],
607
- role: "assistant"
608
- }],
915
+ messages: [
916
+ {
917
+ content: messageContent.length > 0 ? messageContent : [{ text: '' }],
918
+ role: 'assistant',
919
+ },
920
+ ],
609
921
  modelId: conversePrompt.modelId,
610
922
  };
611
923
  conversation = updateConversation(conversation, assistantMessage);
@@ -618,7 +930,7 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
618
930
  const stripOptions = {
619
931
  keepForTurns: options.stripImagesAfterTurns ?? Infinity,
620
932
  currentTurn,
621
- textMaxTokens: options.stripTextMaxTokens
933
+ textMaxTokens: options.stripTextMaxTokens,
622
934
  };
623
935
  let processedConversation = stripBinaryFromConversation(conversation, stripOptions);
624
936
  processedConversation = truncateLargeTextInConversation(processedConversation, stripOptions);
@@ -632,7 +944,7 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
632
944
 
633
945
  async requestTextCompletion(prompt: BedrockPrompt, options: ExecutionOptions): Promise<Completion> {
634
946
  // Handle Twelvelabs Pegasus models
635
- if (options.model.includes("twelvelabs.pegasus")) {
947
+ if (options.model.includes('twelvelabs.pegasus')) {
636
948
  return this.requestTwelvelabsPegasusCompletion(prompt as TwelvelabsPegasusRequest, options);
637
949
  }
638
950
 
@@ -644,17 +956,22 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
644
956
  let conversation = updateConversation(incomingConversation, conversePrompt);
645
957
 
646
958
  const payload = this.preparePayload(conversation, options);
647
- const executor = this.getExecutor();
959
+ const executorScope = this.getScopedExecutor(options);
648
960
 
649
- const res = await executor.converse({
650
- ...payload,
651
- });
961
+ let res: ConverseResponse;
962
+ try {
963
+ res = await executorScope.executor.converse({
964
+ ...payload,
965
+ });
966
+ } finally {
967
+ executorScope.close();
968
+ }
652
969
 
653
970
  // Strip reasoningContent from assistant messages before storing in conversation
654
971
  // (DeepSeek R1 returns reasoning blocks but rejects them in subsequent user turns)
655
- const assistantMsg = res.output?.message ?? { content: [{ text: "" }], role: "assistant" };
972
+ const assistantMsg = res.output?.message ?? { content: [{ text: '' }], role: 'assistant' };
656
973
  if (assistantMsg.content) {
657
- assistantMsg.content = assistantMsg.content.filter((c: any) => !c.reasoningContent);
974
+ assistantMsg.content = assistantMsg.content.filter((c) => !('reasoningContent' in c));
658
975
  }
659
976
 
660
977
  conversation = updateConversation(conversation, {
@@ -665,15 +982,15 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
665
982
  // Increment turn counter for deferred stripping
666
983
  conversation = incrementConversationTurn(conversation) as ConverseRequest;
667
984
 
668
- let tool_use: ToolUse[] | undefined = undefined;
985
+ let tool_use: ToolUse<unknown>[] | undefined;
669
986
  //Get tool requests, we check tool use regardless of finish reason, as you can hit length and still get a valid response.
670
- tool_use = res.output?.message?.content?.reduce((tools: ToolUse[], c) => {
987
+ tool_use = res.output?.message?.content?.reduce((tools: ToolUse<unknown>[], c) => {
671
988
  if (c.toolUse) {
672
989
  tools.push({
673
- tool_name: c.toolUse.name ?? "",
674
- tool_input: c.toolUse.input as any,
675
- id: c.toolUse.toolUseId ?? "",
676
- } satisfies ToolUse);
990
+ tool_name: c.toolUse.name ?? '',
991
+ tool_input: c.toolUse.input,
992
+ id: c.toolUse.toolUseId ?? '',
993
+ } satisfies ToolUse<unknown>);
677
994
  }
678
995
  return tools;
679
996
  }, []);
@@ -687,7 +1004,7 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
687
1004
  const stripOptions = {
688
1005
  keepForTurns: options.stripImagesAfterTurns ?? Infinity,
689
1006
  currentTurn,
690
- textMaxTokens: options.stripTextMaxTokens
1007
+ textMaxTokens: options.stripTextMaxTokens,
691
1008
  };
692
1009
  let processedConversation = stripBinaryFromConversation(conversation, stripOptions);
693
1010
 
@@ -710,15 +1027,23 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
710
1027
  return completion;
711
1028
  }
712
1029
 
713
- private async requestTwelvelabsPegasusCompletion(prompt: TwelvelabsPegasusRequest, options: ExecutionOptions): Promise<Completion> {
714
- const executor = this.getExecutor();
715
-
716
- const res = await executor.invokeModel({
717
- modelId: options.model,
718
- contentType: "application/json",
719
- accept: "application/json",
720
- body: JSON.stringify(prompt),
721
- });
1030
+ private async requestTwelvelabsPegasusCompletion(
1031
+ prompt: TwelvelabsPegasusRequest,
1032
+ options: ExecutionOptions,
1033
+ ): Promise<Completion> {
1034
+ const executorScope = this.getScopedExecutor(options);
1035
+
1036
+ let res: InvokeModelCommandOutput;
1037
+ try {
1038
+ res = await executorScope.executor.invokeModel({
1039
+ modelId: options.model,
1040
+ contentType: 'application/json',
1041
+ accept: 'application/json',
1042
+ body: JSON.stringify(prompt),
1043
+ });
1044
+ } finally {
1045
+ executorScope.close();
1046
+ }
722
1047
 
723
1048
  const decoder = new TextDecoder();
724
1049
  const body = decoder.decode(res.body);
@@ -727,81 +1052,96 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
727
1052
  // Extract the response according to TwelveLabs Pegasus format
728
1053
  let finishReason: string | undefined;
729
1054
  switch (result.finishReason) {
730
- case "stop":
731
- finishReason = "stop";
1055
+ case 'stop':
1056
+ finishReason = 'stop';
732
1057
  break;
733
- case "length":
734
- finishReason = "length";
1058
+ case 'length':
1059
+ finishReason = 'length';
735
1060
  break;
736
1061
  default:
737
1062
  finishReason = result.finishReason;
738
1063
  }
739
1064
 
740
1065
  return {
741
- result: result.message ? [{ type: "text" as const, value: result.message }] : [],
1066
+ result: result.message ? [{ type: 'text' as const, value: result.message }] : [],
742
1067
  finish_reason: finishReason,
743
1068
  original_response: options.include_original_response ? result : undefined,
744
1069
  };
745
1070
  }
746
1071
 
747
- private async requestTwelvelabsPegasusCompletionStream(prompt: TwelvelabsPegasusRequest, options: ExecutionOptions): Promise<AsyncIterable<CompletionChunkObject>> {
748
- const executor = this.getExecutor();
1072
+ private async requestTwelvelabsPegasusCompletionStream(
1073
+ prompt: TwelvelabsPegasusRequest,
1074
+ options: ExecutionOptions,
1075
+ ): Promise<AsyncIterable<CompletionChunkObject>> {
1076
+ const executorScope = this.getScopedExecutor(options);
1077
+
1078
+ try {
1079
+ const res = await executorScope.executor.invokeModelWithResponseStream({
1080
+ modelId: options.model,
1081
+ contentType: 'application/json',
1082
+ accept: 'application/json',
1083
+ body: JSON.stringify(prompt),
1084
+ });
749
1085
 
750
- const res = await executor.invokeModelWithResponseStream({
751
- modelId: options.model,
752
- contentType: "application/json",
753
- accept: "application/json",
754
- body: JSON.stringify(prompt),
755
- });
1086
+ if (!res.body) {
1087
+ throw new Error('[Bedrock] Stream not found in response');
1088
+ }
756
1089
 
757
- if (!res.body) {
758
- throw new Error("[Bedrock] Stream not found in response");
759
- }
760
-
761
- return transformAsyncIterator(res.body, (chunk: any) => {
762
- if (chunk.chunk?.bytes) {
763
- const decoder = new TextDecoder();
764
- const body = decoder.decode(chunk.chunk.bytes);
765
-
766
- try {
767
- const result = JSON.parse(body);
768
-
769
- // Extract streaming response according to TwelveLabs Pegasus format
770
- let finishReason: string | undefined;
771
- if (result.finishReason) {
772
- switch (result.finishReason) {
773
- case "stop":
774
- finishReason = "stop";
775
- break;
776
- case "length":
777
- finishReason = "length";
778
- break;
779
- default:
780
- finishReason = result.finishReason;
1090
+ const stream = transformAsyncIterator(res.body, (chunk) => {
1091
+ if (chunk.chunk?.bytes) {
1092
+ const decoder = new TextDecoder();
1093
+ const body = decoder.decode(chunk.chunk.bytes);
1094
+
1095
+ try {
1096
+ const result = JSON.parse(body);
1097
+
1098
+ // Extract streaming response according to TwelveLabs Pegasus format
1099
+ let finishReason: string | undefined;
1100
+ if (result.finishReason) {
1101
+ switch (result.finishReason) {
1102
+ case 'stop':
1103
+ finishReason = 'stop';
1104
+ break;
1105
+ case 'length':
1106
+ finishReason = 'length';
1107
+ break;
1108
+ default:
1109
+ finishReason = result.finishReason;
1110
+ }
781
1111
  }
782
- }
783
1112
 
784
- return {
785
- result: result.delta || result.message ? [{ type: "text" as const, value: result.delta || result.message || "" }] : [],
786
- finish_reason: finishReason,
787
- } satisfies CompletionChunkObject;
788
- } catch (error) {
789
- // If JSON parsing fails, return empty chunk
790
- return {
791
- result: [],
792
- } satisfies CompletionChunkObject;
1113
+ return {
1114
+ result:
1115
+ result.delta || result.message
1116
+ ? [{ type: 'text' as const, value: result.delta || result.message || '' }]
1117
+ : [],
1118
+ finish_reason: finishReason,
1119
+ } satisfies CompletionChunkObject;
1120
+ } catch {
1121
+ // If JSON parsing fails, return empty chunk
1122
+ return {
1123
+ result: [],
1124
+ } satisfies CompletionChunkObject;
1125
+ }
793
1126
  }
794
- }
795
1127
 
796
- return {
797
- result: [],
798
- } satisfies CompletionChunkObject;
799
- });
1128
+ return {
1129
+ result: [],
1130
+ } satisfies CompletionChunkObject;
1131
+ });
1132
+ return withBedrockRuntimeScope(stream, executorScope);
1133
+ } catch (err) {
1134
+ executorScope.close();
1135
+ throw err;
1136
+ }
800
1137
  }
801
1138
 
802
- async requestTextCompletionStream(prompt: BedrockPrompt, options: ExecutionOptions): Promise<AsyncIterable<CompletionChunkObject>> {
1139
+ async requestTextCompletionStream(
1140
+ prompt: BedrockPrompt,
1141
+ options: ExecutionOptions,
1142
+ ): Promise<AsyncIterable<CompletionChunkObject>> {
803
1143
  // Handle Twelvelabs Pegasus models
804
- if (options.model.includes("twelvelabs.pegasus")) {
1144
+ if (options.model.includes('twelvelabs.pegasus')) {
805
1145
  return this.requestTwelvelabsPegasusCompletionStream(prompt as TwelvelabsPegasusRequest, options);
806
1146
  }
807
1147
 
@@ -814,49 +1154,58 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
814
1154
  const conversation = updateConversation(incomingConversation, conversePrompt);
815
1155
 
816
1156
  const payload = this.preparePayload(conversation, options);
817
- const executor = this.getExecutor();
818
- return executor.converseStream({
819
- ...payload,
820
- }).then((res) => {
821
- const stream = res.stream;
822
-
823
- if (!stream) {
824
- throw new Error("[Bedrock] Stream not found in response");
825
- }
1157
+ const executorScope = this.getScopedExecutor(options);
1158
+ return executorScope.executor
1159
+ .converseStream({
1160
+ ...payload,
1161
+ })
1162
+ .then((res) => {
1163
+ const stream = res.stream;
826
1164
 
827
- const streamingToolBlocks = new Map<number, { id: string; name: string }>();
828
- return transformAsyncIterator(stream, (streamSegment: ConverseStreamOutput) => {
829
- return this.getExtractedStream(streamSegment, conversePrompt, options, streamingToolBlocks);
830
- });
1165
+ if (!stream) {
1166
+ throw new Error('[Bedrock] Stream not found in response');
1167
+ }
831
1168
 
832
- }).catch((err) => {
833
- this.logger.error({ error: err }, "[Bedrock] Failed to stream");
834
- throw err;
835
- });
1169
+ const streamingToolBlocks = new Map<number, { id: string; name: string }>();
1170
+ const transformedStream = transformAsyncIterator(stream, (streamSegment: ConverseStreamOutput) => {
1171
+ return this.getExtractedStream(streamSegment, conversePrompt, options, streamingToolBlocks);
1172
+ });
1173
+ return withBedrockRuntimeScope(transformedStream, executorScope);
1174
+ })
1175
+ .catch((err) => {
1176
+ executorScope.close();
1177
+ this.logger.error({ error: err }, '[Bedrock] Failed to stream');
1178
+ throw err;
1179
+ });
836
1180
  }
837
1181
 
838
1182
  preparePayload(prompt: ConverseRequest, options: ExecutionOptions) {
839
- const model_options: TextFallbackOptions = options.model_options as TextFallbackOptions ?? { _option_id: "text-fallback" };
1183
+ const model_options: TextFallbackOptions = (options.model_options as TextFallbackOptions) ?? {
1184
+ _option_id: 'text-fallback',
1185
+ };
840
1186
 
841
- let additionalField = {};
1187
+ let additionalField: Record<string, unknown> = {};
842
1188
  let supportsJSONPrefill = false;
843
1189
 
844
1190
  // Resolve thinking, effort, and sampling restrictions using shared Claude helper
845
- const claudeThinking = resolveClaudeThinking(options.model, options.model_options as BedrockClaudeOptions | undefined);
1191
+ const claudeThinking = resolveClaudeThinking(
1192
+ options.model,
1193
+ options.model_options as BedrockClaudeOptions | undefined,
1194
+ );
846
1195
  const hasSamplingRestriction = claudeThinking.hasSamplingRestriction;
847
1196
 
848
- if (options.model.includes("amazon")) {
1197
+ if (options.model.includes('amazon')) {
849
1198
  supportsJSONPrefill = true;
850
1199
  //Titan models also exists but does not support any additional options
851
- if (options.model.includes("nova")) {
1200
+ if (options.model.includes('nova')) {
852
1201
  additionalField = { inferenceConfig: { topK: model_options.top_k } };
853
1202
  }
854
- } else if (options.model.includes("claude")) {
1203
+ } else if (options.model.includes('claude')) {
855
1204
  const claude_options = model_options as ModelOptions as BedrockClaudeOptions;
856
1205
  // Thinking is active when extended (budget set) or adaptive (effort set) thinking is enabled.
857
1206
  // JSON prefill is incompatible with active thinking.
858
- const thinkingActive = claudeThinking.thinking != null && claudeThinking.thinking.type !== "disabled";
859
- supportsJSONPrefill = !thinkingActive
1207
+ const thinkingActive = claudeThinking.thinking != null && claudeThinking.thinking.type !== 'disabled';
1208
+ supportsJSONPrefill = !thinkingActive;
860
1209
 
861
1210
  // Claude 3.7+ supports thinking — use shared helper for reasoning_config
862
1211
  if (claudeThinking.supportsThinking) {
@@ -867,12 +1216,14 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
867
1216
  };
868
1217
  }
869
1218
  // For Claude 3.7 with extended thinking + high output, add beta header
870
- if (claudeThinking.thinking?.type === "enabled" &&
871
- options.model.includes("claude-3-7-sonnet") &&
872
- ((claude_options.max_tokens ?? 0) > 64000 || (claude_options.thinking_budget_tokens ?? 0) > 64000)) {
1219
+ if (
1220
+ claudeThinking.thinking?.type === 'enabled' &&
1221
+ options.model.includes('claude-3-7-sonnet') &&
1222
+ ((claude_options.max_tokens ?? 0) > 64000 || (claude_options.thinking_budget_tokens ?? 0) > 64000)
1223
+ ) {
873
1224
  additionalField = {
874
1225
  ...additionalField,
875
- anthropic_beta: ["output-128k-2025-02-19"]
1226
+ anthropic_beta: ['output-128k-2025-02-19'],
876
1227
  };
877
1228
  }
878
1229
  }
@@ -880,7 +1231,7 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
880
1231
  if (claudeThinking.outputConfig) {
881
1232
  additionalField = {
882
1233
  ...additionalField,
883
- output_config: claudeThinking.outputConfig
1234
+ output_config: claudeThinking.outputConfig,
884
1235
  };
885
1236
  }
886
1237
  // Claude 4.6 and later versions don't support JSON prefill
@@ -895,11 +1246,11 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
895
1246
  if (!hasSamplingRestriction) {
896
1247
  additionalField = { ...additionalField, top_k: model_options.top_k };
897
1248
  }
898
- } else if (options.model.includes("meta")) {
1249
+ } else if (options.model.includes('meta')) {
899
1250
  //LLaMA models support no additional options
900
- } else if (options.model.includes("mistral")) {
1251
+ } else if (options.model.includes('mistral')) {
901
1252
  //7B instruct and 8x7B instruct
902
- if (options.model.includes("7b")) {
1253
+ if (options.model.includes('7b')) {
903
1254
  additionalField = { top_k: model_options.top_k };
904
1255
  //Does not support system messages
905
1256
  if (prompt.system && prompt.system?.length !== 0) {
@@ -911,10 +1262,10 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
911
1262
  //Other models such as Mistral Small,Large and Large 2
912
1263
  //Support no additional fields.
913
1264
  }
914
- } else if (options.model.includes("ai21")) {
1265
+ } else if (options.model.includes('ai21')) {
915
1266
  //Jamba models support no additional options
916
1267
  //Jurassic 2 models do.
917
- if (options.model.includes("j2")) {
1268
+ if (options.model.includes('j2')) {
918
1269
  additionalField = {
919
1270
  presencePenalty: { scale: model_options.presence_penalty },
920
1271
  frequencyPenalty: { scale: model_options.frequency_penalty },
@@ -926,10 +1277,10 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
926
1277
  prompt.messages = converseConcatMessages(prompt.messages);
927
1278
  }
928
1279
  }
929
- } else if (options.model.includes("cohere.command")) {
1280
+ } else if (options.model.includes('cohere.command')) {
930
1281
  // If last message is "```json", remove it.
931
1282
  //Command R and R plus
932
- if (options.model.includes("cohere.command-r")) {
1283
+ if (options.model.includes('cohere.command-r')) {
933
1284
  additionalField = {
934
1285
  k: model_options.top_k,
935
1286
  frequency_penalty: model_options.frequency_penalty,
@@ -945,19 +1296,19 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
945
1296
  prompt.messages = converseConcatMessages(prompt.messages);
946
1297
  }
947
1298
  }
948
- } else if (options.model.includes("palmyra")) {
1299
+ } else if (options.model.includes('palmyra')) {
949
1300
  const palmyraOptions = model_options as ModelOptions as BedrockPalmyraOptions;
950
1301
  additionalField = {
951
1302
  seed: palmyraOptions?.seed,
952
1303
  presence_penalty: palmyraOptions?.presence_penalty,
953
1304
  frequency_penalty: palmyraOptions?.frequency_penalty,
954
1305
  min_tokens: palmyraOptions?.min_tokens,
955
- }
956
- } else if (options.model.includes("deepseek")) {
1306
+ };
1307
+ } else if (options.model.includes('deepseek')) {
957
1308
  // DeepSeek models: no additional options, no stopSequences, only one of temperature/top_p
958
1309
  model_options.stop_sequence = undefined;
959
1310
  model_options.top_p = undefined;
960
- } else if (options.model.includes("gpt-oss")) {
1311
+ } else if (options.model.includes('gpt-oss')) {
961
1312
  const gptOssOptions = model_options as ModelOptions as BedrockGptOssOptions;
962
1313
  additionalField = {
963
1314
  reasoning_effort: gptOssOptions?.reasoning_effort,
@@ -966,12 +1317,12 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
966
1317
 
967
1318
  //If last message is "```json", add corresponding ``` as a stop sequence.
968
1319
  if (prompt.messages && prompt.messages.length > 0) {
969
- if (prompt.messages[prompt.messages.length - 1].content?.[0].text === "```json") {
1320
+ if (prompt.messages[prompt.messages.length - 1].content?.[0].text === '```json') {
970
1321
  const stopSeq = model_options.stop_sequence;
971
1322
  if (!stopSeq) {
972
- model_options.stop_sequence = ["```"];
973
- } else if (!stopSeq.includes("```")) {
974
- stopSeq.push("```");
1323
+ model_options.stop_sequence = ['```'];
1324
+ } else if (!stopSeq.includes('```')) {
1325
+ stopSeq.push('```');
975
1326
  model_options.stop_sequence = stopSeq;
976
1327
  }
977
1328
  }
@@ -990,10 +1341,12 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
990
1341
  // Models with sampling parameter restrictions don't support temperature/top_p - exclude them from inference config
991
1342
  const cleanedModelOptions = removeUndefinedValues({
992
1343
  maxTokens: model_options.max_tokens,
993
- ...(hasSamplingRestriction ? {} : {
994
- temperature: model_options.temperature,
995
- topP: model_options.temperature != null ? undefined : model_options.top_p,
996
- }),
1344
+ ...(hasSamplingRestriction
1345
+ ? {}
1346
+ : {
1347
+ temperature: model_options.temperature,
1348
+ topP: model_options.temperature != null ? undefined : model_options.top_p,
1349
+ }),
997
1350
  stopSequences: model_options.stop_sequence,
998
1351
  } satisfies InferenceConfiguration);
999
1352
 
@@ -1012,17 +1365,18 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
1012
1365
  }
1013
1366
 
1014
1367
  if (Object.keys(cleanedModelOptions).length > 0) {
1015
- request.inferenceConfig = cleanedModelOptions
1368
+ request.inferenceConfig = cleanedModelOptions;
1016
1369
  }
1017
1370
 
1018
1371
  if (Object.keys(cleanedAdditionalFields).length > 0) {
1019
- request.additionalModelRequestFields = cleanedAdditionalFields;
1372
+ request.additionalModelRequestFields =
1373
+ cleanedAdditionalFields as unknown as ConverseRequest['additionalModelRequestFields'];
1020
1374
  }
1021
1375
 
1022
1376
  if (tool_defs?.length) {
1023
1377
  request.toolConfig = {
1024
1378
  tools: tool_defs,
1025
- }
1379
+ };
1026
1380
  } else if (request.messages && messagesContainToolBlocks(request.messages)) {
1027
1381
  // Bedrock requires toolConfig when conversation contains toolUse/toolResult blocks.
1028
1382
  // When no tools are provided (e.g. checkpoint summary calls), convert tool blocks
@@ -1075,37 +1429,51 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
1075
1429
  return request;
1076
1430
  }
1077
1431
 
1078
-
1079
1432
  protected isImageModel(model: string): boolean {
1080
- return model.includes("titan-image") || model.includes("stable-diffusion") || model.includes("nova-canvas");
1433
+ return model.includes('titan-image') || model.includes('stable-diffusion') || model.includes('nova-canvas');
1081
1434
  }
1082
1435
 
1083
1436
  async requestImageGeneration(prompt: NovaMessagesPrompt, options: ExecutionOptions): Promise<Completion> {
1084
- if (options.model_options?._option_id !== undefined && options.model_options?._option_id !== "bedrock-nova-canvas") {
1085
- this.logger.debug({ options: options.model_options }, "Unexpected option id");
1437
+ if (
1438
+ options.model_options?._option_id !== undefined &&
1439
+ options.model_options?._option_id !== 'bedrock-nova-canvas'
1440
+ ) {
1441
+ this.logger.debug({ options: options.model_options }, 'Unexpected option id');
1086
1442
  }
1087
1443
  const model_options = options.model_options as NovaCanvasOptions;
1088
1444
 
1089
- const executor = this.getExecutor();
1090
1445
  const taskType = model_options.taskType ?? NovaImageGenerationTaskType.TEXT_IMAGE;
1091
1446
 
1092
- this.logger.info("Task type: " + taskType);
1447
+ this.logger.info(`Task type: ${taskType}`);
1093
1448
 
1094
- if (typeof prompt === "string") {
1095
- throw new Error("Bad prompt format");
1449
+ if (typeof prompt === 'string') {
1450
+ throw new Error('Bad prompt format');
1096
1451
  }
1097
1452
 
1098
1453
  const payload = await formatNovaImageGenerationPayload(taskType, prompt, options);
1099
-
1100
- const res = await executor.invokeModel({
1101
- modelId: options.model,
1102
- contentType: "application/json",
1103
- accept: "application/json",
1104
- body: JSON.stringify(payload),
1105
- },
1106
- {
1107
- requestTimeout: 60000 * 5
1108
- });
1454
+ const executorScope = this.getScopedExecutor(options);
1455
+
1456
+ let res: InvokeModelCommandOutput;
1457
+ try {
1458
+ const requestTimeout = options.httpTimeout
1459
+ ? resolveDriverHttpTimeouts(
1460
+ mergeDriverHttpTimeoutOptions(this.options.httpTimeout, options.httpTimeout),
1461
+ ).headersTimeout
1462
+ : (this.options.httpTimeout?.headersTimeout ?? 60_000 * 5);
1463
+ res = await executorScope.executor.invokeModel(
1464
+ {
1465
+ modelId: options.model,
1466
+ contentType: 'application/json',
1467
+ accept: 'application/json',
1468
+ body: JSON.stringify(payload),
1469
+ },
1470
+ {
1471
+ requestTimeout,
1472
+ },
1473
+ );
1474
+ } finally {
1475
+ executorScope.close();
1476
+ }
1109
1477
 
1110
1478
  const decoder = new TextDecoder();
1111
1479
  const body = decoder.decode(res.body);
@@ -1113,15 +1481,14 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
1113
1481
 
1114
1482
  return {
1115
1483
  error: bedrockResult.error,
1116
- result: bedrockResult.images.map((image: any) => ({
1117
- type: "image" as const,
1118
- value: image
1119
- }))
1120
- }
1484
+ result: bedrockResult.images.map((image: string) => ({
1485
+ type: 'image' as const,
1486
+ value: image,
1487
+ })),
1488
+ };
1121
1489
  }
1122
1490
 
1123
1491
  async startTraining(dataset: DataSource, options: TrainingOptions): Promise<TrainingJob> {
1124
-
1125
1492
  //convert options.params to Record<string, string>
1126
1493
  const params: Record<string, string> = {};
1127
1494
  for (const [key, value] of Object.entries(options.params || {})) {
@@ -1129,7 +1496,9 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
1129
1496
  }
1130
1497
 
1131
1498
  if (!this.options.training_bucket) {
1132
- throw new Error("Training cannot nbe used since the 'training_bucket' property was not specified in driver options")
1499
+ throw new Error(
1500
+ "Training cannot nbe used since the 'training_bucket' property was not specified in driver options",
1501
+ );
1133
1502
  }
1134
1503
 
1135
1504
  const s3 = new S3Client({ region: this.options.region, credentials: this.options.credentials });
@@ -1137,45 +1506,56 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
1137
1506
  const upload = await forceUploadFile(s3, stream, this.options.training_bucket, dataset.name);
1138
1507
 
1139
1508
  const service = this.getService();
1140
- const response = await service.send(new CreateModelCustomizationJobCommand({
1141
- jobName: options.name + "-job",
1142
- customModelName: options.name,
1143
- roleArn: this.options.training_role_arn || undefined,
1144
- baseModelIdentifier: options.model,
1145
- clientRequestToken: "llumiverse-" + Date.now(),
1146
- trainingDataConfig: {
1147
- s3Uri: `s3://${upload.Bucket}/${upload.Key}`,
1148
- },
1149
- outputDataConfig: undefined,
1150
- hyperParameters: params,
1151
- //TODO not supported?
1152
- //customizationType: "FINE_TUNING",
1153
- }));
1509
+ const response = await service.send(
1510
+ new CreateModelCustomizationJobCommand({
1511
+ jobName: `${options.name}-job`,
1512
+ customModelName: options.name,
1513
+ roleArn: this.options.training_role_arn || undefined,
1514
+ baseModelIdentifier: options.model,
1515
+ clientRequestToken: `llumiverse-${Date.now()}`,
1516
+ trainingDataConfig: {
1517
+ s3Uri: `s3://${upload.Bucket}/${upload.Key}`,
1518
+ },
1519
+ outputDataConfig: undefined,
1520
+ hyperParameters: params,
1521
+ //TODO not supported?
1522
+ //customizationType: "FINE_TUNING",
1523
+ }),
1524
+ );
1154
1525
 
1155
- const job = await service.send(new GetModelCustomizationJobCommand({
1156
- jobIdentifier: response.jobArn
1157
- }));
1526
+ const job = await service.send(
1527
+ new GetModelCustomizationJobCommand({
1528
+ jobIdentifier: response.jobArn,
1529
+ }),
1530
+ );
1158
1531
 
1532
+ // biome-ignore lint/style/noNonNullAssertion: intentional non-null assertion; TS can't prove narrowing here
1159
1533
  return jobInfo(job, response.jobArn!);
1160
1534
  }
1161
1535
 
1162
1536
  async cancelTraining(jobId: string): Promise<TrainingJob> {
1163
1537
  const service = this.getService();
1164
- await service.send(new StopModelCustomizationJobCommand({
1165
- jobIdentifier: jobId
1166
- }));
1167
- const job = await service.send(new GetModelCustomizationJobCommand({
1168
- jobIdentifier: jobId
1169
- }));
1538
+ await service.send(
1539
+ new StopModelCustomizationJobCommand({
1540
+ jobIdentifier: jobId,
1541
+ }),
1542
+ );
1543
+ const job = await service.send(
1544
+ new GetModelCustomizationJobCommand({
1545
+ jobIdentifier: jobId,
1546
+ }),
1547
+ );
1170
1548
 
1171
1549
  return jobInfo(job, jobId);
1172
1550
  }
1173
1551
 
1174
1552
  async getTrainingJob(jobId: string): Promise<TrainingJob> {
1175
1553
  const service = this.getService();
1176
- const job = await service.send(new GetModelCustomizationJobCommand({
1177
- jobIdentifier: jobId
1178
- }));
1554
+ const job = await service.send(
1555
+ new GetModelCustomizationJobCommand({
1556
+ jobIdentifier: jobId,
1557
+ }),
1558
+ );
1179
1559
 
1180
1560
  return jobInfo(job, jobId);
1181
1561
  }
@@ -1184,22 +1564,24 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
1184
1564
 
1185
1565
  async validateConnection(): Promise<boolean> {
1186
1566
  const service = this.getService();
1187
- this.logger.debug("[Bedrock] validating connection", service.config.credentials.name);
1567
+ this.logger.debug('[Bedrock] validating connection', service.config.credentials.name);
1188
1568
  //return true as if the client has been initialized, it means the connection is valid
1189
1569
  return true;
1190
1570
  }
1191
1571
 
1192
-
1193
1572
  async listTrainableModels(): Promise<AIModel<string>[]> {
1194
- this.logger.debug("[Bedrock] listing trainable models");
1195
- return this._listModels(m => m.customizationsSupported ? m.customizationsSupported.includes("FINE_TUNING") : false);
1573
+ this.logger.debug('[Bedrock] listing trainable models');
1574
+ return this._listModels((m) =>
1575
+ m.customizationsSupported ? m.customizationsSupported.includes('FINE_TUNING') : false,
1576
+ );
1196
1577
  }
1197
1578
 
1198
1579
  async listModels(): Promise<AIModel[]> {
1199
- this.logger.debug("[Bedrock] listing models");
1580
+ this.logger.debug('[Bedrock] listing models');
1200
1581
  // exclude trainable models since they are not executable
1201
1582
  // exclude embedding models, not to be used for typical completions.
1202
- const filter = (m: FoundationModelSummary) => (m.inferenceTypesSupported?.includes("ON_DEMAND") && !m.outputModalities?.includes("EMBEDDING")) ?? false;
1583
+ const filter = (m: FoundationModelSummary) =>
1584
+ (m.inferenceTypesSupported?.includes('ON_DEMAND') && !m.outputModalities?.includes('EMBEDDING')) ?? false;
1203
1585
  return this._listModels(filter);
1204
1586
  }
1205
1587
 
@@ -1207,21 +1589,25 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
1207
1589
  const service = this.getService();
1208
1590
  const [foundationModelsList, customModelsList, inferenceProfilesList] = await Promise.all([
1209
1591
  service.listFoundationModels({}).catch(() => {
1210
- this.logger.warn("[Bedrock] Can't list foundation models. Check if the user has the right permissions.");
1211
- return undefined
1592
+ this.logger.warn(
1593
+ "[Bedrock] Can't list foundation models. Check if the user has the right permissions.",
1594
+ );
1595
+ return undefined;
1212
1596
  }),
1213
1597
  service.listCustomModels({}).catch(() => {
1214
1598
  this.logger.warn("[Bedrock] Can't list custom models. Check if the user has the right permissions.");
1215
- return undefined
1599
+ return undefined;
1216
1600
  }),
1217
1601
  service.listInferenceProfiles({}).catch(() => {
1218
- this.logger.warn("[Bedrock] Can't list inference profiles. Check if the user has the right permissions.");
1219
- return undefined
1602
+ this.logger.warn(
1603
+ "[Bedrock] Can't list inference profiles. Check if the user has the right permissions.",
1604
+ );
1605
+ return undefined;
1220
1606
  }),
1221
1607
  ]);
1222
1608
 
1223
1609
  if (!foundationModelsList?.modelSummaries) {
1224
- throw new Error("Foundation models not found");
1610
+ throw new Error('Foundation models not found');
1225
1611
  }
1226
1612
 
1227
1613
  let foundationModels = foundationModelsList.modelSummaries || [];
@@ -1229,20 +1615,30 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
1229
1615
  foundationModels = foundationModels.filter(foundationFilter);
1230
1616
  }
1231
1617
 
1232
- const supportedPublishers = ["amazon", "anthropic", "cohere", "ai21",
1233
- "mistral", "meta", "deepseek", "writer",
1234
- "openai", "twelvelabs", "qwen"];
1618
+ const supportedPublishers = [
1619
+ 'amazon',
1620
+ 'anthropic',
1621
+ 'cohere',
1622
+ 'ai21',
1623
+ 'mistral',
1624
+ 'meta',
1625
+ 'deepseek',
1626
+ 'writer',
1627
+ 'openai',
1628
+ 'twelvelabs',
1629
+ 'qwen',
1630
+ ];
1235
1631
  const unsupportedModelsByPublisher = {
1236
- amazon: ["titan-image-generator", "nova-reel", "nova-sonic", "rerank"],
1632
+ amazon: ['titan-image-generator', 'nova-reel', 'nova-sonic', 'rerank'],
1237
1633
  anthropic: [],
1238
- cohere: ["rerank", "embed"],
1634
+ cohere: ['rerank', 'embed'],
1239
1635
  ai21: [],
1240
1636
  mistral: [],
1241
1637
  meta: [],
1242
1638
  deepseek: [],
1243
1639
  writer: [],
1244
1640
  openai: [],
1245
- twelvelabs: ["marengo"],
1641
+ twelvelabs: ['marengo'],
1246
1642
  qwen: [],
1247
1643
  };
1248
1644
 
@@ -1253,33 +1649,27 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
1253
1649
  const normalizedProvider = providerName.toLowerCase();
1254
1650
 
1255
1651
  // Check if provider is supported
1256
- const isProviderSupported = supportedPublishers.some(provider =>
1257
- normalizedProvider.includes(provider)
1258
- );
1652
+ const isProviderSupported = supportedPublishers.some((provider) => normalizedProvider.includes(provider));
1259
1653
 
1260
1654
  if (!isProviderSupported) return false;
1261
1655
 
1262
1656
  // Check if model is in the unsupported list for its provider
1263
1657
  for (const provider of supportedPublishers) {
1264
1658
  if (normalizedProvider.includes(provider)) {
1265
- const unsupportedModels = unsupportedModelsByPublisher[provider as keyof typeof unsupportedModelsByPublisher] || [];
1266
- return !unsupportedModels.some(unsupported =>
1267
- modelId.toLowerCase().includes(unsupported)
1268
- );
1659
+ const unsupportedModels =
1660
+ unsupportedModelsByPublisher[provider as keyof typeof unsupportedModelsByPublisher] || [];
1661
+ return !unsupportedModels.some((unsupported) => modelId.toLowerCase().includes(unsupported));
1269
1662
  }
1270
1663
  }
1271
1664
 
1272
1665
  return true;
1273
1666
  };
1274
1667
 
1275
- foundationModels = foundationModels.filter(m =>
1276
- shouldIncludeModel(m.modelId, m.providerName)
1277
- );
1668
+ foundationModels = foundationModels.filter((m) => shouldIncludeModel(m.modelId, m.providerName));
1278
1669
 
1279
1670
  const aiModels: AIModel[] = foundationModels.map((m) => {
1280
-
1281
1671
  if (!m.modelId) {
1282
- throw new Error("modelId not found");
1672
+ throw new Error('modelId not found');
1283
1673
  }
1284
1674
 
1285
1675
  const modelCapability = getModelCapabilities(m.modelArn ?? m.modelId, this.provider);
@@ -1290,8 +1680,12 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
1290
1680
  provider: this.provider,
1291
1681
  owner: m.providerName,
1292
1682
  can_stream: m.responseStreamingSupported ?? false,
1293
- input_modalities: m.inputModalities ? formatAmazonModalities(m.inputModalities) : modelModalitiesToArray(modelCapability.input),
1294
- output_modalities: m.outputModalities ? formatAmazonModalities(m.outputModalities) : modelModalitiesToArray(modelCapability.input),
1683
+ input_modalities: m.inputModalities
1684
+ ? formatAmazonModalities(m.inputModalities)
1685
+ : modelModalitiesToArray(modelCapability.input),
1686
+ output_modalities: m.outputModalities
1687
+ ? formatAmazonModalities(m.outputModalities)
1688
+ : modelModalitiesToArray(modelCapability.input),
1295
1689
  tool_support: modelCapability.tool_support,
1296
1690
  };
1297
1691
 
@@ -1301,9 +1695,8 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
1301
1695
  //add custom models
1302
1696
  if (customModelsList?.modelSummaries) {
1303
1697
  customModelsList.modelSummaries.forEach((m) => {
1304
-
1305
1698
  if (!m.modelArn) {
1306
- throw new Error("Model ID not found");
1699
+ throw new Error('Model ID not found');
1307
1700
  }
1308
1701
 
1309
1702
  const modelCapability = getModelCapabilities(m.modelArn, this.provider);
@@ -1312,7 +1705,7 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
1312
1705
  id: m.modelArn,
1313
1706
  name: m.modelName ?? m.modelArn,
1314
1707
  provider: this.provider,
1315
- owner: "custom",
1708
+ owner: 'custom',
1316
1709
  description: `Custom model from ${m.baseModelName}`,
1317
1710
  is_custom: true,
1318
1711
  input_modalities: modelModalitiesToArray(modelCapability.input),
@@ -1321,7 +1714,6 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
1321
1714
  };
1322
1715
 
1323
1716
  aiModels.push(model);
1324
- this.validateConnection;
1325
1717
  });
1326
1718
  }
1327
1719
 
@@ -1329,15 +1721,15 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
1329
1721
  if (inferenceProfilesList?.inferenceProfileSummaries) {
1330
1722
  inferenceProfilesList.inferenceProfileSummaries.forEach((p) => {
1331
1723
  if (!p.inferenceProfileArn) {
1332
- throw new Error("Profile ARN not found");
1724
+ throw new Error('Profile ARN not found');
1333
1725
  }
1334
1726
 
1335
1727
  // Apply the same filtering logic to inference profiles based on their name
1336
- const profileId = p.inferenceProfileId || "";
1337
- const profileName = p.inferenceProfileName || "";
1728
+ const profileId = p.inferenceProfileId || '';
1729
+ const profileName = p.inferenceProfileName || '';
1338
1730
 
1339
1731
  // Extract provider name from profile name or ID
1340
- let providerName = "";
1732
+ let providerName = '';
1341
1733
  for (const provider of supportedPublishers) {
1342
1734
  if (profileName.toLowerCase().includes(provider) || profileId.toLowerCase().includes(provider)) {
1343
1735
  providerName = provider;
@@ -1345,7 +1737,10 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
1345
1737
  }
1346
1738
  }
1347
1739
 
1348
- const modelCapability = getModelCapabilities(p.inferenceProfileArn ?? p.inferenceProfileId, this.provider);
1740
+ const modelCapability = getModelCapabilities(
1741
+ p.inferenceProfileArn ?? p.inferenceProfileId,
1742
+ this.provider,
1743
+ );
1349
1744
 
1350
1745
  if (providerName && shouldIncludeModel(profileId, providerName)) {
1351
1746
  const model: AIModel = {
@@ -1366,92 +1761,8 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
1366
1761
  return aiModels;
1367
1762
  }
1368
1763
 
1369
- async generateEmbeddings({ text, image, model }: EmbeddingsOptions): Promise<EmbeddingsResult> {
1370
-
1371
- this.logger.info("[Bedrock] Generating embeddings with model " + model);
1372
-
1373
- // Handle TwelveLabs Marengo models
1374
- if (model?.includes("twelvelabs.marengo")) {
1375
- return this.generateTwelvelabsMarengoEmbeddings({ text, image, model });
1376
- }
1377
-
1378
- // Handle other Bedrock embedding models
1379
- const defaultModel = image ? "amazon.titan-embed-image-v1" : "amazon.titan-embed-text-v2:0";
1380
- const modelID = model ?? defaultModel;
1381
-
1382
- const invokeBody = {
1383
- inputText: text,
1384
- inputImage: image
1385
- }
1386
-
1387
- const executor = this.getExecutor();
1388
- const res = await executor.invokeModel(
1389
- {
1390
- modelId: modelID,
1391
- contentType: "application/json",
1392
- body: JSON.stringify(invokeBody),
1393
- }
1394
- );
1395
-
1396
- const decoder = new TextDecoder();
1397
- const body = decoder.decode(res.body);
1398
-
1399
- const result = JSON.parse(body);
1400
-
1401
- if (!result.embedding) {
1402
- throw new Error("Embeddings not found");
1403
- }
1404
-
1405
- return {
1406
- values: result.embedding,
1407
- model: modelID,
1408
- token_count: result.inputTextTokenCount
1409
- };
1410
- }
1411
-
1412
- private async generateTwelvelabsMarengoEmbeddings({ text, image, model }: EmbeddingsOptions): Promise<EmbeddingsResult> {
1413
- const executor = this.getExecutor();
1414
-
1415
- // Prepare the request payload for TwelveLabs Marengo
1416
- const invokeBody: TwelvelabsMarengoRequest = {
1417
- inputType: "text"
1418
- };
1419
-
1420
- if (text) {
1421
- invokeBody.inputText = text;
1422
- invokeBody.inputType = "text";
1423
- }
1424
-
1425
- if (image) {
1426
- // For the embeddings interface, image is expected to be base64
1427
- invokeBody.mediaSource = {
1428
- base64String: image
1429
- };
1430
- invokeBody.inputType = "image";
1431
- }
1432
-
1433
- const res = await executor.invokeModel({
1434
- modelId: model!,
1435
- contentType: "application/json",
1436
- accept: "application/json",
1437
- body: JSON.stringify(invokeBody),
1438
- });
1439
-
1440
- const decoder = new TextDecoder();
1441
- const body = decoder.decode(res.body);
1442
- const result: TwelvelabsMarengoResponse = JSON.parse(body);
1443
-
1444
- // TwelveLabs Marengo returns embedding data
1445
- if (!result.embedding) {
1446
- throw new Error("Embeddings not found in TwelveLabs Marengo response");
1447
- }
1448
-
1449
- return {
1450
- values: result.embedding,
1451
- model: model!,
1452
- // TwelveLabs Marengo doesn't return token count in the same way
1453
- token_count: undefined
1454
- };
1764
+ async generateEmbeddings(options: EmbeddingsOptions): Promise<EmbeddingsResult> {
1765
+ return generateBedrockEmbeddings(this, options);
1455
1766
  }
1456
1767
 
1457
1768
  /**
@@ -1460,6 +1771,9 @@ export class BedrockDriver extends AbstractDriver<BedrockDriverOptions, BedrockP
1460
1771
  destroy(): void {
1461
1772
  this._executor?.destroy();
1462
1773
  this._service?.destroy();
1774
+ this._executor = undefined;
1775
+ this._service = undefined;
1776
+ super.destroy();
1463
1777
  }
1464
1778
  }
1465
1779
 
@@ -1471,20 +1785,19 @@ function jobInfo(job: GetModelCustomizationJobCommandOutput, jobId: string): Tra
1471
1785
  status = TrainingJobStatus.succeeded;
1472
1786
  } else if (jobStatus === ModelCustomizationJobStatus.FAILED) {
1473
1787
  status = TrainingJobStatus.failed;
1474
- details = job.failureMessage || "error";
1788
+ details = job.failureMessage || 'error';
1475
1789
  } else if (jobStatus === ModelCustomizationJobStatus.STOPPED) {
1476
1790
  status = TrainingJobStatus.cancelled;
1477
1791
  } else {
1478
1792
  status = TrainingJobStatus.running;
1479
1793
  details = jobStatus;
1480
1794
  }
1481
- job.baseModelArn
1482
1795
  return {
1483
1796
  id: jobId,
1484
1797
  model: job.outputModelArn,
1485
1798
  status,
1486
- details
1487
- }
1799
+ details,
1800
+ };
1488
1801
  }
1489
1802
 
1490
1803
  function getToolDefinitions(tools?: ToolDefinition[]): Tool[] | undefined {
@@ -1497,10 +1810,10 @@ function getToolDefinition(tool: ToolDefinition): Tool.ToolSpecMember {
1497
1810
  name: tool.name,
1498
1811
  description: tool.description,
1499
1812
  inputSchema: {
1500
- json: tool.input_schema as any,
1501
- }
1502
- }
1503
- }
1813
+ json: tool.input_schema,
1814
+ } as NonNullable<NonNullable<Tool.ToolSpecMember['toolSpec']>['inputSchema']>,
1815
+ },
1816
+ };
1504
1817
  }
1505
1818
 
1506
1819
  /**
@@ -1510,8 +1823,7 @@ export function messagesContainToolBlocks(messages: Message[]): boolean {
1510
1823
  for (const msg of messages) {
1511
1824
  if (!msg.content) continue;
1512
1825
  for (const block of msg.content) {
1513
- if ((block as ContentBlock.ToolUseMember).toolUse ||
1514
- (block as ContentBlock.ToolResultMember).toolResult) {
1826
+ if ((block as ContentBlock.ToolUseMember).toolUse || (block as ContentBlock.ToolResultMember).toolResult) {
1515
1827
  return true;
1516
1828
  }
1517
1829
  }
@@ -1528,12 +1840,11 @@ export function messagesContainToolBlocks(messages: Message[]): boolean {
1528
1840
  * conversation history contains tool interactions from prior turns.
1529
1841
  */
1530
1842
  export function convertToolBlocksToText(messages: Message[]): Message[] {
1531
- return messages.map(msg => {
1843
+ return messages.map((msg) => {
1532
1844
  if (!msg.content) return msg;
1533
1845
  let hasToolBlocks = false;
1534
1846
  for (const block of msg.content) {
1535
- if ((block as ContentBlock.ToolUseMember).toolUse ||
1536
- (block as ContentBlock.ToolResultMember).toolResult) {
1847
+ if ((block as ContentBlock.ToolUseMember).toolUse || (block as ContentBlock.ToolResultMember).toolResult) {
1537
1848
  hasToolBlocks = true;
1538
1849
  break;
1539
1850
  }
@@ -1546,7 +1857,7 @@ export function convertToolBlocksToText(messages: Message[]): Message[] {
1546
1857
  const toolResult = (block as ContentBlock.ToolResultMember).toolResult;
1547
1858
  if (toolUse) {
1548
1859
  const inputStr = toolUse.input ? JSON.stringify(toolUse.input) : '';
1549
- const truncatedInput = inputStr.length > 500 ? inputStr.substring(0, 500) + '...' : inputStr;
1860
+ const truncatedInput = inputStr.length > 500 ? `${inputStr.substring(0, 500)}...` : inputStr;
1550
1861
  newContent.push({
1551
1862
  text: `[Tool call: ${toolUse.name}(${truncatedInput})]`,
1552
1863
  } as ContentBlock.TextMember);
@@ -1554,9 +1865,9 @@ export function convertToolBlocksToText(messages: Message[]): Message[] {
1554
1865
  const resultTexts: string[] = [];
1555
1866
  if (toolResult.content) {
1556
1867
  for (const c of toolResult.content) {
1557
- if ((c as any).text) {
1558
- const text = (c as any).text as string;
1559
- resultTexts.push(text.length > 500 ? text.substring(0, 500) + '...' : text);
1868
+ if ('text' in c && typeof c.text === 'string') {
1869
+ const text = c.text;
1870
+ resultTexts.push(text.length > 500 ? `${text.substring(0, 500)}...` : text);
1560
1871
  }
1561
1872
  }
1562
1873
  }
@@ -1577,16 +1888,16 @@ export function convertToolBlocksToText(messages: Message[]): Message[] {
1577
1888
  * AWS Bedrock's additionalModelRequestFields must be valid JSON, and undefined is not valid JSON.
1578
1889
  * Any unrecognized parameters will cause an exception.
1579
1890
  */
1580
- function removeUndefinedValues<T extends Record<string, any>>(obj: T): Partial<T> {
1891
+ function removeUndefinedValues(obj: Record<string, unknown>): Record<string, unknown> {
1581
1892
  if (obj === null || typeof obj !== 'object' || Array.isArray(obj)) {
1582
1893
  return obj;
1583
1894
  }
1584
1895
 
1585
- const cleaned: any = {};
1896
+ const cleaned: Record<string, unknown> = {};
1586
1897
  for (const [key, value] of Object.entries(obj)) {
1587
1898
  if (value !== undefined) {
1588
1899
  if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
1589
- const cleanedNested = removeUndefinedValues(value);
1900
+ const cleanedNested = removeUndefinedValues(value as Record<string, unknown>);
1590
1901
  // Only include nested objects if they have properties after cleaning
1591
1902
  if (Object.keys(cleanedNested).length > 0) {
1592
1903
  cleaned[key] = cleanedNested;
@@ -1609,8 +1920,11 @@ function updateConversation(conversation: ConverseRequest, prompt: ConverseReque
1609
1920
  const combinedMessages = [...(conversation?.messages || []), ...(prompt.messages || [])];
1610
1921
  const combinedSystem = prompt.system || conversation?.system;
1611
1922
 
1612
- // Fix orphaned toolUse blocks before returning
1613
- const fixedMessages = fixOrphanedToolUse(combinedMessages);
1923
+ // Fix both orphan directions before returning: a toolUse with no result
1924
+ // (interrupted run) gets a synthetic result; a toolResult with no matching
1925
+ // toolUse in the previous message (e.g. compaction-trimmed) is dropped. Either
1926
+ // would otherwise trip the Converse API's toolUse/toolResult pairing check.
1927
+ const fixedMessages = fixOrphanedToolResults(fixOrphanedToolUse(combinedMessages));
1614
1928
 
1615
1929
  return {
1616
1930
  modelId: prompt?.modelId || conversation?.modelId,
@@ -1620,20 +1934,24 @@ function updateConversation(conversation: ConverseRequest, prompt: ConverseReque
1620
1934
  }
1621
1935
 
1622
1936
  function stripClaudeCachePoints(messages: Message[]): Message[] {
1623
- return messages.map(message => ({
1937
+ return messages.map((message) => ({
1624
1938
  ...message,
1625
- content: message.content?.filter(block => !('cachePoint' in block)),
1939
+ content: message.content?.filter((block) => !('cachePoint' in block)),
1626
1940
  }));
1627
1941
  }
1628
1942
 
1629
1943
  function stripClaudeCachePointsFromSystem(system?: ConverseRequest['system']): ConverseRequest['system'] | undefined {
1630
- return (system?.filter(block => !('cachePoint' in (block as object))) ?? undefined) as ConverseRequest['system'] | undefined;
1944
+ return (system?.filter((block) => !('cachePoint' in (block as object))) ?? undefined) as
1945
+ | ConverseRequest['system']
1946
+ | undefined;
1631
1947
  }
1632
1948
 
1633
1949
  function stripClaudeCachePointsFromTools(
1634
- tools?: NonNullable<NonNullable<ConverseRequest['toolConfig']>['tools']>
1950
+ tools?: NonNullable<NonNullable<ConverseRequest['toolConfig']>['tools']>,
1635
1951
  ): NonNullable<NonNullable<ConverseRequest['toolConfig']>['tools']> | undefined {
1636
- return (tools?.filter(tool => !('cachePoint' in (tool as object))) ?? undefined) as NonNullable<NonNullable<ConverseRequest['toolConfig']>['tools']> | undefined;
1952
+ return (tools?.filter((tool) => !('cachePoint' in (tool as object))) ?? undefined) as
1953
+ | NonNullable<NonNullable<ConverseRequest['toolConfig']>['tools']>
1954
+ | undefined;
1637
1955
  }
1638
1956
 
1639
1957
  /**
@@ -1663,7 +1981,7 @@ export function fixOrphanedToolUse(messages: Message[]): Message[] {
1663
1981
  if (block.toolUse?.toolUseId) {
1664
1982
  toolUseBlocks.push({
1665
1983
  toolUseId: block.toolUse.toolUseId,
1666
- name: block.toolUse.name ?? 'unknown'
1984
+ name: block.toolUse.name ?? 'unknown',
1667
1985
  });
1668
1986
  }
1669
1987
  }
@@ -1682,23 +2000,25 @@ export function fixOrphanedToolUse(messages: Message[]): Message[] {
1682
2000
  }
1683
2001
 
1684
2002
  // Find orphaned toolUse blocks (no matching toolResult)
1685
- const orphanedToolUse = toolUseBlocks.filter(tu => !toolResultIds.has(tu.toolUseId));
2003
+ const orphanedToolUse = toolUseBlocks.filter((tu) => !toolResultIds.has(tu.toolUseId));
1686
2004
 
1687
2005
  if (orphanedToolUse.length > 0) {
1688
2006
  // Inject synthetic toolResults for orphaned toolUse
1689
- const syntheticResults: ContentBlock[] = orphanedToolUse.map(tu => ({
2007
+ const syntheticResults: ContentBlock[] = orphanedToolUse.map((tu) => ({
1690
2008
  toolResult: {
1691
2009
  toolUseId: tu.toolUseId,
1692
- content: [{
1693
- text: `[Tool interrupted: The user stopped the operation before "${tu.name}" could execute.]`
1694
- }]
1695
- }
2010
+ content: [
2011
+ {
2012
+ text: `[Tool interrupted: The user stopped the operation before "${tu.name}" could execute.]`,
2013
+ },
2014
+ ],
2015
+ },
1696
2016
  }));
1697
2017
 
1698
2018
  // Prepend synthetic results to the next user message
1699
2019
  const updatedNextMessage: Message = {
1700
2020
  ...nextMessage,
1701
- content: [...syntheticResults, ...nextMessage.content]
2021
+ content: [...syntheticResults, ...nextMessage.content],
1702
2022
  };
1703
2023
 
1704
2024
  // Replace the next message in our iteration
@@ -1707,18 +2027,20 @@ export function fixOrphanedToolUse(messages: Message[]): Message[] {
1707
2027
  } else if (nextMessage && nextMessage.role === 'user' && !nextMessage.content) {
1708
2028
  // Next message is a user message but has no content
1709
2029
  // We need to add toolResults
1710
- const syntheticResults: ContentBlock[] = toolUseBlocks.map(tu => ({
2030
+ const syntheticResults: ContentBlock[] = toolUseBlocks.map((tu) => ({
1711
2031
  toolResult: {
1712
2032
  toolUseId: tu.toolUseId,
1713
- content: [{
1714
- text: `[Tool interrupted: The user stopped the operation before "${tu.name}" could execute.]`
1715
- }]
1716
- }
2033
+ content: [
2034
+ {
2035
+ text: `[Tool interrupted: The user stopped the operation before "${tu.name}" could execute.]`,
2036
+ },
2037
+ ],
2038
+ },
1717
2039
  }));
1718
2040
 
1719
2041
  const updatedNextMessage: Message = {
1720
2042
  role: 'user',
1721
- content: syntheticResults
2043
+ content: syntheticResults,
1722
2044
  };
1723
2045
 
1724
2046
  messages[i + 1] = updatedNextMessage;
@@ -1732,19 +2054,63 @@ export function fixOrphanedToolUse(messages: Message[]): Message[] {
1732
2054
  return result;
1733
2055
  }
1734
2056
 
2057
+ /**
2058
+ * Drop toolResult blocks whose toolUseId has no matching toolUse in the
2059
+ * immediately-preceding assistant message. Mirror of {@link fixOrphanedToolUse}:
2060
+ * that function synthesizes results for an unanswered toolUse (e.g. a cancelled
2061
+ * run); this one removes results left dangling after their toolUse was dropped
2062
+ * (e.g. by conversation compaction/trimming).
2063
+ *
2064
+ * Without this, the AWS Converse API rejects the request because every
2065
+ * toolResult must correspond to a toolUse in the previous message. Bedrock
2066
+ * conversations are already role-alternating, so a compaction that drops an
2067
+ * assistant toolUse turn leaves an orphaned toolResult (and a user/user
2068
+ * adjacency); dropping the orphan — and the now-empty message — repairs both.
2069
+ */
2070
+ export function fixOrphanedToolResults(messages: Message[]): Message[] {
2071
+ if (messages.length === 0) return messages;
2072
+ const result: Message[] = [];
2073
+ for (let i = 0; i < messages.length; i++) {
2074
+ const message = messages[i];
2075
+ if (message.role !== 'user' || !message.content) {
2076
+ result.push(message);
2077
+ continue;
2078
+ }
2079
+ const hasToolResult = message.content.some((block) => block.toolResult);
2080
+ if (!hasToolResult) {
2081
+ result.push(message);
2082
+ continue;
2083
+ }
2084
+ const prev = messages[i - 1];
2085
+ const allowedIds = new Set<string>();
2086
+ if (prev && prev.role === 'assistant' && prev.content) {
2087
+ for (const block of prev.content) {
2088
+ if (block.toolUse?.toolUseId) allowedIds.add(block.toolUse.toolUseId);
2089
+ }
2090
+ }
2091
+ const filtered = message.content.filter((block) =>
2092
+ block.toolResult ? allowedIds.has(block.toolResult.toolUseId ?? '') : true,
2093
+ );
2094
+ // Drop the message if every block was an orphaned toolResult.
2095
+ if (filtered.length === 0) continue;
2096
+ result.push(filtered.length === message.content.length ? message : { ...message, content: filtered });
2097
+ }
2098
+ return result;
2099
+ }
2100
+
1735
2101
  function formatAmazonModalities(modalities: ModelModality[]): string[] {
1736
2102
  const standardizedModalities: string[] = [];
1737
2103
  for (const modality of modalities) {
1738
2104
  if (modality === ModelModality.TEXT) {
1739
- standardizedModalities.push("text");
2105
+ standardizedModalities.push('text');
1740
2106
  } else if (modality === ModelModality.IMAGE) {
1741
- standardizedModalities.push("image");
2107
+ standardizedModalities.push('image');
1742
2108
  } else if (modality === ModelModality.EMBEDDING) {
1743
- standardizedModalities.push("embedding");
1744
- } else if (modality === "SPEECH") {
1745
- standardizedModalities.push("audio");
1746
- } else if (modality === "VIDEO") {
1747
- standardizedModalities.push("video");
2109
+ standardizedModalities.push('embedding');
2110
+ } else if (modality === 'SPEECH') {
2111
+ standardizedModalities.push('audio');
2112
+ } else if (modality === 'VIDEO') {
2113
+ standardizedModalities.push('video');
1748
2114
  } else {
1749
2115
  // Handle other modalities as needed
1750
2116
  standardizedModalities.push((modality as string).toString().toLowerCase());