@llumiverse/drivers 1.0.0-dev.20260202.145450Z → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/lib/cjs/adobe/firefly.js +120 -0
  2. package/lib/cjs/adobe/firefly.js.map +1 -0
  3. package/lib/cjs/azure/azure_foundry.js +432 -0
  4. package/lib/cjs/azure/azure_foundry.js.map +1 -0
  5. package/lib/cjs/bedrock/converse.js +359 -0
  6. package/lib/cjs/bedrock/converse.js.map +1 -0
  7. package/lib/cjs/bedrock/index.js +1441 -0
  8. package/lib/cjs/bedrock/index.js.map +1 -0
  9. package/lib/cjs/bedrock/nova-image-payload.js +207 -0
  10. package/lib/cjs/bedrock/nova-image-payload.js.map +1 -0
  11. package/lib/cjs/bedrock/payloads.js +3 -0
  12. package/lib/cjs/bedrock/payloads.js.map +1 -0
  13. package/lib/cjs/bedrock/s3.js +107 -0
  14. package/lib/cjs/bedrock/s3.js.map +1 -0
  15. package/lib/cjs/bedrock/twelvelabs.js +87 -0
  16. package/lib/cjs/bedrock/twelvelabs.js.map +1 -0
  17. package/lib/cjs/groq/index.js +326 -0
  18. package/lib/cjs/groq/index.js.map +1 -0
  19. package/lib/cjs/huggingface_ie.js +201 -0
  20. package/lib/cjs/huggingface_ie.js.map +1 -0
  21. package/lib/cjs/index.js +31 -0
  22. package/lib/cjs/index.js.map +1 -0
  23. package/lib/cjs/mistral/index.js +176 -0
  24. package/lib/cjs/mistral/index.js.map +1 -0
  25. package/lib/cjs/mistral/types.js +83 -0
  26. package/lib/cjs/mistral/types.js.map +1 -0
  27. package/lib/cjs/openai/azure_openai.js +72 -0
  28. package/lib/cjs/openai/azure_openai.js.map +1 -0
  29. package/lib/cjs/openai/index.js +1100 -0
  30. package/lib/cjs/openai/index.js.map +1 -0
  31. package/lib/cjs/openai/openai.js +21 -0
  32. package/lib/cjs/openai/openai.js.map +1 -0
  33. package/lib/cjs/openai/openai_compatible.js +63 -0
  34. package/lib/cjs/openai/openai_compatible.js.map +1 -0
  35. package/lib/cjs/openai/openai_format.js +131 -0
  36. package/lib/cjs/openai/openai_format.js.map +1 -0
  37. package/lib/cjs/package.json +3 -0
  38. package/lib/cjs/replicate.js +275 -0
  39. package/lib/cjs/replicate.js.map +1 -0
  40. package/lib/cjs/test-driver/TestErrorCompletionStream.js +20 -0
  41. package/lib/cjs/test-driver/TestErrorCompletionStream.js.map +1 -0
  42. package/lib/cjs/test-driver/TestValidationErrorCompletionStream.js +24 -0
  43. package/lib/cjs/test-driver/TestValidationErrorCompletionStream.js.map +1 -0
  44. package/lib/cjs/test-driver/index.js +109 -0
  45. package/lib/cjs/test-driver/index.js.map +1 -0
  46. package/lib/cjs/test-driver/utils.js +30 -0
  47. package/lib/cjs/test-driver/utils.js.map +1 -0
  48. package/lib/cjs/togetherai/index.js +126 -0
  49. package/lib/cjs/togetherai/index.js.map +1 -0
  50. package/lib/cjs/togetherai/interfaces.js +3 -0
  51. package/lib/cjs/togetherai/interfaces.js.map +1 -0
  52. package/lib/cjs/vertexai/debug.js +12 -0
  53. package/lib/cjs/vertexai/debug.js.map +1 -0
  54. package/lib/cjs/vertexai/embeddings/embeddings-image.js +27 -0
  55. package/lib/cjs/vertexai/embeddings/embeddings-image.js.map +1 -0
  56. package/lib/cjs/vertexai/embeddings/embeddings-text.js +23 -0
  57. package/lib/cjs/vertexai/embeddings/embeddings-text.js.map +1 -0
  58. package/lib/cjs/vertexai/index.js +635 -0
  59. package/lib/cjs/vertexai/index.js.map +1 -0
  60. package/lib/cjs/vertexai/models/claude.js +842 -0
  61. package/lib/cjs/vertexai/models/claude.js.map +1 -0
  62. package/lib/cjs/vertexai/models/gemini.js +1110 -0
  63. package/lib/cjs/vertexai/models/gemini.js.map +1 -0
  64. package/lib/cjs/vertexai/models/imagen.js +303 -0
  65. package/lib/cjs/vertexai/models/imagen.js.map +1 -0
  66. package/lib/cjs/vertexai/models/llama.js +183 -0
  67. package/lib/cjs/vertexai/models/llama.js.map +1 -0
  68. package/lib/cjs/vertexai/models.js +35 -0
  69. package/lib/cjs/vertexai/models.js.map +1 -0
  70. package/lib/cjs/watsonx/index.js +161 -0
  71. package/lib/cjs/watsonx/index.js.map +1 -0
  72. package/lib/cjs/watsonx/interfaces.js +3 -0
  73. package/lib/cjs/watsonx/interfaces.js.map +1 -0
  74. package/lib/cjs/xai/index.js +65 -0
  75. package/lib/cjs/xai/index.js.map +1 -0
  76. package/lib/esm/adobe/firefly.js +116 -0
  77. package/lib/esm/adobe/firefly.js.map +1 -0
  78. package/lib/esm/azure/azure_foundry.js +426 -0
  79. package/lib/esm/azure/azure_foundry.js.map +1 -0
  80. package/lib/esm/bedrock/converse.js +352 -0
  81. package/lib/esm/bedrock/converse.js.map +1 -0
  82. package/lib/esm/bedrock/index.js +1434 -0
  83. package/lib/esm/bedrock/index.js.map +1 -0
  84. package/lib/esm/bedrock/nova-image-payload.js +203 -0
  85. package/lib/esm/bedrock/nova-image-payload.js.map +1 -0
  86. package/lib/esm/bedrock/payloads.js +2 -0
  87. package/lib/esm/bedrock/payloads.js.map +1 -0
  88. package/lib/esm/bedrock/s3.js +99 -0
  89. package/lib/esm/bedrock/s3.js.map +1 -0
  90. package/lib/esm/bedrock/twelvelabs.js +84 -0
  91. package/lib/esm/bedrock/twelvelabs.js.map +1 -0
  92. package/lib/esm/groq/index.js +319 -0
  93. package/lib/esm/groq/index.js.map +1 -0
  94. package/lib/esm/huggingface_ie.js +197 -0
  95. package/lib/esm/huggingface_ie.js.map +1 -0
  96. package/lib/esm/index.js +15 -0
  97. package/lib/esm/index.js.map +1 -0
  98. package/lib/esm/mistral/index.js +172 -0
  99. package/lib/esm/mistral/index.js.map +1 -0
  100. package/lib/esm/mistral/types.js +80 -0
  101. package/lib/esm/mistral/types.js.map +1 -0
  102. package/lib/esm/openai/azure_openai.js +68 -0
  103. package/lib/esm/openai/azure_openai.js.map +1 -0
  104. package/lib/esm/openai/index.js +1093 -0
  105. package/lib/esm/openai/index.js.map +1 -0
  106. package/lib/esm/openai/openai.js +14 -0
  107. package/lib/esm/openai/openai.js.map +1 -0
  108. package/lib/esm/openai/openai_compatible.js +56 -0
  109. package/lib/esm/openai/openai_compatible.js.map +1 -0
  110. package/lib/esm/openai/openai_format.js +127 -0
  111. package/lib/esm/openai/openai_format.js.map +1 -0
  112. package/lib/esm/replicate.js +268 -0
  113. package/lib/esm/replicate.js.map +1 -0
  114. package/lib/esm/test-driver/TestErrorCompletionStream.js +16 -0
  115. package/lib/esm/test-driver/TestErrorCompletionStream.js.map +1 -0
  116. package/lib/esm/test-driver/TestValidationErrorCompletionStream.js +20 -0
  117. package/lib/esm/test-driver/TestValidationErrorCompletionStream.js.map +1 -0
  118. package/lib/esm/test-driver/index.js +91 -0
  119. package/lib/esm/test-driver/index.js.map +1 -0
  120. package/lib/esm/test-driver/utils.js +25 -0
  121. package/lib/esm/test-driver/utils.js.map +1 -0
  122. package/lib/esm/togetherai/index.js +122 -0
  123. package/lib/esm/togetherai/index.js.map +1 -0
  124. package/lib/esm/togetherai/interfaces.js +2 -0
  125. package/lib/esm/togetherai/interfaces.js.map +1 -0
  126. package/lib/esm/vertexai/debug.js +6 -0
  127. package/lib/esm/vertexai/debug.js.map +1 -0
  128. package/lib/esm/vertexai/embeddings/embeddings-image.js +24 -0
  129. package/lib/esm/vertexai/embeddings/embeddings-image.js.map +1 -0
  130. package/lib/esm/vertexai/embeddings/embeddings-text.js +20 -0
  131. package/lib/esm/vertexai/embeddings/embeddings-text.js.map +1 -0
  132. package/lib/esm/vertexai/index.js +630 -0
  133. package/lib/esm/vertexai/index.js.map +1 -0
  134. package/lib/esm/vertexai/models/claude.js +833 -0
  135. package/lib/esm/vertexai/models/claude.js.map +1 -0
  136. package/lib/esm/vertexai/models/gemini.js +1104 -0
  137. package/lib/esm/vertexai/models/gemini.js.map +1 -0
  138. package/lib/esm/vertexai/models/imagen.js +299 -0
  139. package/lib/esm/vertexai/models/imagen.js.map +1 -0
  140. package/lib/esm/vertexai/models/llama.js +179 -0
  141. package/lib/esm/vertexai/models/llama.js.map +1 -0
  142. package/lib/esm/vertexai/models.js +32 -0
  143. package/lib/esm/vertexai/models.js.map +1 -0
  144. package/lib/esm/watsonx/index.js +157 -0
  145. package/lib/esm/watsonx/index.js.map +1 -0
  146. package/lib/esm/watsonx/interfaces.js +2 -0
  147. package/lib/esm/watsonx/interfaces.js.map +1 -0
  148. package/lib/esm/xai/index.js +58 -0
  149. package/lib/esm/xai/index.js.map +1 -0
  150. package/lib/types/adobe/firefly.d.ts +30 -0
  151. package/lib/types/adobe/firefly.d.ts.map +1 -0
  152. package/lib/types/azure/azure_foundry.d.ts +52 -0
  153. package/lib/types/azure/azure_foundry.d.ts.map +1 -0
  154. package/lib/types/bedrock/converse.d.ts +8 -0
  155. package/lib/types/bedrock/converse.d.ts.map +1 -0
  156. package/lib/types/bedrock/index.d.ts +135 -0
  157. package/lib/types/bedrock/index.d.ts.map +1 -0
  158. package/lib/types/bedrock/nova-image-payload.d.ts +74 -0
  159. package/lib/types/bedrock/nova-image-payload.d.ts.map +1 -0
  160. package/lib/types/bedrock/payloads.d.ts +12 -0
  161. package/lib/types/bedrock/payloads.d.ts.map +1 -0
  162. package/lib/types/bedrock/s3.d.ts +23 -0
  163. package/lib/types/bedrock/s3.d.ts.map +1 -0
  164. package/lib/types/bedrock/twelvelabs.d.ts +50 -0
  165. package/lib/types/bedrock/twelvelabs.d.ts.map +1 -0
  166. package/lib/types/groq/index.d.ts +27 -0
  167. package/lib/types/groq/index.d.ts.map +1 -0
  168. package/lib/types/huggingface_ie.d.ts +35 -0
  169. package/lib/types/huggingface_ie.d.ts.map +1 -0
  170. package/lib/types/index.d.ts +15 -0
  171. package/lib/types/index.d.ts.map +1 -0
  172. package/lib/types/mistral/index.d.ts +25 -0
  173. package/lib/types/mistral/index.d.ts.map +1 -0
  174. package/lib/types/mistral/types.d.ts +127 -0
  175. package/lib/types/mistral/types.d.ts.map +1 -0
  176. package/lib/types/openai/azure_openai.d.ts +25 -0
  177. package/lib/types/openai/azure_openai.d.ts.map +1 -0
  178. package/lib/types/openai/index.d.ts +126 -0
  179. package/lib/types/openai/index.d.ts.map +1 -0
  180. package/lib/types/openai/openai.d.ts +15 -0
  181. package/lib/types/openai/openai.d.ts.map +1 -0
  182. package/lib/types/openai/openai_compatible.d.ts +31 -0
  183. package/lib/types/openai/openai_compatible.d.ts.map +1 -0
  184. package/lib/types/openai/openai_format.d.ts +21 -0
  185. package/lib/types/openai/openai_format.d.ts.map +1 -0
  186. package/lib/types/replicate.d.ts +48 -0
  187. package/lib/types/replicate.d.ts.map +1 -0
  188. package/lib/types/test-driver/TestErrorCompletionStream.d.ts +9 -0
  189. package/lib/types/test-driver/TestErrorCompletionStream.d.ts.map +1 -0
  190. package/lib/types/test-driver/TestValidationErrorCompletionStream.d.ts +9 -0
  191. package/lib/types/test-driver/TestValidationErrorCompletionStream.d.ts.map +1 -0
  192. package/lib/types/test-driver/index.d.ts +24 -0
  193. package/lib/types/test-driver/index.d.ts.map +1 -0
  194. package/lib/types/test-driver/utils.d.ts +5 -0
  195. package/lib/types/test-driver/utils.d.ts.map +1 -0
  196. package/lib/types/togetherai/index.d.ts +23 -0
  197. package/lib/types/togetherai/index.d.ts.map +1 -0
  198. package/lib/types/togetherai/interfaces.d.ts +96 -0
  199. package/lib/types/togetherai/interfaces.d.ts.map +1 -0
  200. package/lib/types/vertexai/debug.d.ts +2 -0
  201. package/lib/types/vertexai/debug.d.ts.map +1 -0
  202. package/lib/types/vertexai/embeddings/embeddings-image.d.ts +11 -0
  203. package/lib/types/vertexai/embeddings/embeddings-image.d.ts.map +1 -0
  204. package/lib/types/vertexai/embeddings/embeddings-text.d.ts +10 -0
  205. package/lib/types/vertexai/embeddings/embeddings-text.d.ts.map +1 -0
  206. package/lib/types/vertexai/index.d.ts +79 -0
  207. package/lib/types/vertexai/index.d.ts.map +1 -0
  208. package/lib/types/vertexai/models/claude.d.ts +103 -0
  209. package/lib/types/vertexai/models/claude.d.ts.map +1 -0
  210. package/lib/types/vertexai/models/gemini.d.ts +78 -0
  211. package/lib/types/vertexai/models/gemini.d.ts.map +1 -0
  212. package/lib/types/vertexai/models/imagen.d.ts +75 -0
  213. package/lib/types/vertexai/models/imagen.d.ts.map +1 -0
  214. package/lib/types/vertexai/models/llama.d.ts +20 -0
  215. package/lib/types/vertexai/models/llama.d.ts.map +1 -0
  216. package/lib/types/vertexai/models.d.ts +20 -0
  217. package/lib/types/vertexai/models.d.ts.map +1 -0
  218. package/lib/types/watsonx/index.d.ts +27 -0
  219. package/lib/types/watsonx/index.d.ts.map +1 -0
  220. package/lib/types/watsonx/interfaces.d.ts +65 -0
  221. package/lib/types/watsonx/interfaces.d.ts.map +1 -0
  222. package/lib/types/xai/index.d.ts +18 -0
  223. package/lib/types/xai/index.d.ts.map +1 -0
  224. package/package.json +18 -18
  225. package/src/bedrock/converse.ts +85 -10
  226. package/src/bedrock/error-handling.test.ts +352 -0
  227. package/src/bedrock/index.ts +293 -16
  228. package/src/groq/index.ts +9 -4
  229. package/src/mistral/index.ts +25 -22
  230. package/src/mistral/types.ts +0 -5
  231. package/src/openai/error-handling.test.ts +567 -0
  232. package/src/openai/index.ts +513 -33
  233. package/src/openai/openai_compatible.ts +7 -0
  234. package/src/openai/openai_format.ts +1 -1
  235. package/src/vertexai/index.ts +61 -13
  236. package/src/vertexai/models/claude-error-handling.test.ts +432 -0
  237. package/src/vertexai/models/claude.ts +287 -10
  238. package/src/vertexai/models/gemini-error-handling.test.ts +353 -0
  239. package/src/vertexai/models/gemini.ts +329 -52
  240. package/src/vertexai/models.ts +7 -2
@@ -1,13 +1,37 @@
1
+ import {
2
+ APIConnectionError,
3
+ APIConnectionTimeoutError,
4
+ APIError,
5
+ AuthenticationError,
6
+ BadRequestError,
7
+ ConflictError,
8
+ InternalServerError,
9
+ NotFoundError,
10
+ PermissionDeniedError,
11
+ RateLimitError,
12
+ UnprocessableEntityError,
13
+ } from '@anthropic-ai/sdk/error';
1
14
  import { ContentBlock, ContentBlockParam, DocumentBlockParam, ImageBlockParam, Message, MessageParam, TextBlockParam, ToolResultBlockParam } from "@anthropic-ai/sdk/resources/index.js";
15
+ import { MessageStreamParams } from "@anthropic-ai/sdk/resources/index.mjs";
16
+ import { MessageCreateParamsBase, MessageCreateParamsNonStreaming, RawMessageStreamEvent } from "@anthropic-ai/sdk/resources/messages.js";
2
17
  import {
3
- AIModel, Completion, CompletionChunkObject, ExecutionOptions, getMaxTokensLimitVertexAi, JSONObject, ModelType,
4
- PromptRole, PromptSegment, readStreamAsBase64, readStreamAsString, StatelessExecutionOptions, ToolUse, VertexAIClaudeOptions
18
+ AIModel, Completion, CompletionChunkObject, ExecutionOptions,
19
+ getConversationMeta,
20
+ getMaxTokensLimitVertexAi,
21
+ incrementConversationTurn,
22
+ JSONObject,
23
+ LlumiverseError, LlumiverseErrorContext,
24
+ ModelType,
25
+ PromptRole, PromptSegment, readStreamAsBase64, readStreamAsString, StatelessExecutionOptions,
26
+ stripBase64ImagesFromConversation,
27
+ stripHeartbeatsFromConversation,
28
+ ToolUse,
29
+ truncateLargeTextInConversation,
30
+ VertexAIClaudeOptions
5
31
  } from "@llumiverse/core";
6
32
  import { asyncMap } from "@llumiverse/core/async";
7
33
  import { VertexAIDriver } from "../index.js";
8
34
  import { ModelDefinition } from "../models.js";
9
- import { MessageCreateParamsBase, MessageCreateParamsNonStreaming, RawMessageStreamEvent } from "@anthropic-ai/sdk/resources/messages.js";
10
- import { MessageStreamParams } from "@anthropic-ai/sdk/resources/index.mjs";
11
35
 
12
36
  export const ANTHROPIC_REGIONS: Record<string, string> = {
13
37
  us: "us-east5",
@@ -83,13 +107,12 @@ function maxToken(option: StatelessExecutionOptions): number {
83
107
  if (modelOptions && typeof modelOptions.max_tokens === "number") {
84
108
  return modelOptions.max_tokens;
85
109
  } else {
86
- const thinking_budget = modelOptions?.thinking_budget_tokens ?? 0;
87
110
  let maxSupportedTokens = getMaxTokensLimitVertexAi(option.model);
88
111
  // Fallback to the default max tokens limit for the model
89
112
  if (option.model.includes('claude-3-7-sonnet') && (modelOptions?.thinking_budget_tokens ?? 0) < 48000) {
90
113
  maxSupportedTokens = 64000; // Claude 3.7 can go up to 128k with a beta header, but when no max tokens is specified, we default to 64k.
91
114
  }
92
- return Math.min(16000 + thinking_budget, maxSupportedTokens); // Cap to 16k, to avoid taking up too much context window and quota.
115
+ return maxSupportedTokens;
93
116
  }
94
117
  }
95
118
 
@@ -291,6 +314,21 @@ export class ClaudeModelDefinition implements ModelDefinition<ClaudePrompt> {
291
314
 
292
315
  conversation = updateConversation(conversation, createPromptFromResponse(result));
293
316
 
317
+ // Increment turn counter and apply stripping (same pattern as other drivers)
318
+ conversation = incrementConversationTurn(conversation) as ClaudePrompt;
319
+ const currentTurn = getConversationMeta(conversation).turnNumber;
320
+ const stripOptions = {
321
+ keepForTurns: options.stripImagesAfterTurns ?? Infinity,
322
+ currentTurn,
323
+ textMaxTokens: options.stripTextMaxTokens,
324
+ };
325
+ let processedConversation = stripBase64ImagesFromConversation(conversation, stripOptions);
326
+ processedConversation = truncateLargeTextInConversation(processedConversation, stripOptions);
327
+ processedConversation = stripHeartbeatsFromConversation(processedConversation, {
328
+ keepForTurns: options.stripHeartbeatsAfterTurns ?? 1,
329
+ currentTurn,
330
+ });
331
+
294
332
  return {
295
333
  result: text ? [{ type: "text", value: text }] : [{ type: "text", value: '' }],
296
334
  tool_use,
@@ -301,7 +339,7 @@ export class ClaudeModelDefinition implements ModelDefinition<ClaudePrompt> {
301
339
  },
302
340
  // make sure we set finish_reason to the correct value (claude is normally setting this by itself)
303
341
  finish_reason: tool_use ? "tool_use" : claudeFinishReason(result?.stop_reason ?? ''),
304
- conversation
342
+ conversation: processedConversation
305
343
  } satisfies Completion;
306
344
  }
307
345
 
@@ -433,6 +471,170 @@ export class ClaudeModelDefinition implements ModelDefinition<ClaudePrompt> {
433
471
 
434
472
  return stream;
435
473
  }
474
+
475
+ /**
476
+ * Format Anthropic API errors into LlumiverseError with proper status codes and retryability.
477
+ *
478
+ * Anthropic API errors have a specific structure:
479
+ * - APIError.status: HTTP status code (400, 401, 403, 404, 409, 422, 429, 500+)
480
+ * - APIError.error: Nested error object with type and message
481
+ * - APIError.requestID: Request ID for support (can be null)
482
+ *
483
+ * Common error types:
484
+ * - BadRequestError (400): Invalid request parameters
485
+ * - AuthenticationError (401): Authentication required
486
+ * - PermissionDeniedError (403): Insufficient permissions
487
+ * - NotFoundError (404): Resource not found
488
+ * - ConflictError (409): Resource conflict
489
+ * - UnprocessableEntityError (422): Validation error
490
+ * - RateLimitError (429): Rate limit exceeded
491
+ * - InternalServerError (500+): Server-side errors
492
+ * - APIConnectionError: Connection issues (no status code)
493
+ * - APIConnectionTimeoutError: Request timeout (no status code)
494
+ *
495
+ * @see https://docs.anthropic.com/en/api/errors
496
+ */
497
+ formatLlumiverseError(
498
+ _driver: VertexAIDriver,
499
+ error: unknown,
500
+ context: LlumiverseErrorContext
501
+ ): LlumiverseError {
502
+ // Check if it's an Anthropic API error
503
+ const isAnthropicError = this.isAnthropicApiError(error);
504
+
505
+ if (!isAnthropicError) {
506
+ // Not an Anthropic API error, use default handling
507
+ throw error;
508
+ }
509
+
510
+ const apiError = error as APIError;
511
+ const httpStatusCode = apiError.status;
512
+
513
+ // Extract error message and nested error details
514
+ let message = apiError.message || String(error);
515
+
516
+ // Extract error type from nested error object if available
517
+ let errorType: string | undefined;
518
+ if (apiError.error && typeof apiError.error === 'object') {
519
+ const nestedError = apiError.error as any;
520
+ if (nestedError.error && typeof nestedError.error === 'object') {
521
+ errorType = nestedError.error.type;
522
+ // Use the nested error message if it's more specific
523
+ if (nestedError.error.message) {
524
+ message = nestedError.error.message;
525
+ }
526
+ }
527
+ }
528
+
529
+ // Build user-facing message with status code
530
+ let userMessage = message;
531
+
532
+ // Include status code in message (for end-user visibility)
533
+ if (httpStatusCode) {
534
+ userMessage = `[${httpStatusCode}] ${userMessage}`;
535
+ }
536
+
537
+ // Include error type if available
538
+ if (errorType && errorType !== 'error') {
539
+ userMessage = `${errorType}: ${userMessage}`;
540
+ }
541
+
542
+ // Add request ID if available (useful for Anthropic support)
543
+ if (apiError.requestID) {
544
+ userMessage += ` (Request ID: ${apiError.requestID})`;
545
+ }
546
+
547
+ // Determine retryability based on Anthropic error types
548
+ const retryable = this.isClaudeErrorRetryable(error, httpStatusCode, errorType);
549
+
550
+ // Use the error constructor name as the error name
551
+ const errorName = error.constructor?.name || 'AnthropicError';
552
+
553
+ return new LlumiverseError(
554
+ `[${context.provider}] ${userMessage}`,
555
+ retryable,
556
+ context,
557
+ error,
558
+ httpStatusCode,
559
+ errorName
560
+ );
561
+ }
562
+
563
+ /**
564
+ * Type guard to check if error is an Anthropic API error.
565
+ */
566
+ private isAnthropicApiError(error: unknown): error is APIError {
567
+ return (
568
+ error !== null &&
569
+ typeof error === 'object' &&
570
+ error instanceof APIError
571
+ );
572
+ }
573
+
574
+ /**
575
+ * Determine if an Anthropic API error is retryable.
576
+ *
577
+ * Retryable errors:
578
+ * - RateLimitError (429): Rate limit exceeded, retry with backoff
579
+ * - InternalServerError (500+): Server-side errors
580
+ * - APIConnectionTimeoutError: Request timeout
581
+ * - 408 (Request Timeout): Request timeout
582
+ * - 529 (Overloaded): Service overloaded
583
+ *
584
+ * Non-retryable errors:
585
+ * - BadRequestError (400): Invalid request parameters
586
+ * - AuthenticationError (401): Authentication failure
587
+ * - PermissionDeniedError (403): Insufficient permissions
588
+ * - NotFoundError (404): Resource not found
589
+ * - ConflictError (409): Resource conflict
590
+ * - UnprocessableEntityError (422): Validation error
591
+ * - Other 4xx client errors
592
+ * - invalid_request_error: Invalid request structure
593
+ *
594
+ * @param error - The error object
595
+ * @param httpStatusCode - The HTTP status code if available
596
+ * @param errorType - The nested error type if available
597
+ * @returns True if retryable, false if not retryable, undefined if unknown
598
+ */
599
+ private isClaudeErrorRetryable(
600
+ error: unknown,
601
+ httpStatusCode: number | undefined,
602
+ errorType: string | undefined
603
+ ): boolean | undefined {
604
+ // Check specific Anthropic error types by class
605
+ if (error instanceof RateLimitError) return true;
606
+ if (error instanceof InternalServerError) return true;
607
+ if (error instanceof APIConnectionTimeoutError) return true;
608
+
609
+ // Non-retryable by error type
610
+ if (error instanceof BadRequestError) return false;
611
+ if (error instanceof AuthenticationError) return false;
612
+ if (error instanceof PermissionDeniedError) return false;
613
+ if (error instanceof NotFoundError) return false;
614
+ if (error instanceof ConflictError) return false;
615
+ if (error instanceof UnprocessableEntityError) return false;
616
+
617
+ // Check nested error type
618
+ if (errorType === 'invalid_request_error') return false;
619
+
620
+ // Use HTTP status code
621
+ if (httpStatusCode !== undefined) {
622
+ if (httpStatusCode === 429) return true; // Rate limit
623
+ if (httpStatusCode === 408) return true; // Request timeout
624
+ if (httpStatusCode === 529) return true; // Overloaded
625
+ if (httpStatusCode >= 500 && httpStatusCode < 600) return true; // Server errors
626
+ if (httpStatusCode >= 400 && httpStatusCode < 500) return false; // Client errors
627
+ }
628
+
629
+ // Connection errors without status codes
630
+ if (error instanceof APIConnectionError && !(error instanceof APIConnectionTimeoutError)) {
631
+ // Generic connection errors might be retryable (network issues)
632
+ return true;
633
+ }
634
+
635
+ // Unknown error type - let consumer decide retry strategy
636
+ return undefined;
637
+ }
436
638
  }
437
639
 
438
640
  function createPromptFromResponse(response: Message): ClaudePrompt {
@@ -668,7 +870,7 @@ function getClaudePayload(options: ExecutionOptions, prompt: ClaudePrompt): { pa
668
870
  // Fix orphaned tool_use blocks (can occur when agent is stopped mid-tool-execution)
669
871
  const fixedMessages = fixOrphanedToolUse(prompt.messages);
670
872
  // Sanitize messages to remove empty text blocks (can occur from interrupted streaming)
671
- const sanitizedMessages = sanitizeMessages(fixedMessages);
873
+ let sanitizedMessages = sanitizeMessages(fixedMessages);
672
874
 
673
875
  // Validate tools have input_schema.type set to 'object' as required by the Anthropic SDK
674
876
  if (options.tools) {
@@ -679,14 +881,21 @@ function getClaudePayload(options: ExecutionOptions, prompt: ClaudePrompt): { pa
679
881
  }
680
882
  }
681
883
 
884
+ // When no tools are provided but conversation contains tool_use/tool_result blocks
885
+ // (e.g. checkpoint summary calls), convert tool blocks to text to avoid API errors
886
+ const hasTools = options.tools && options.tools.length > 0;
887
+ if (!hasTools && claudeMessagesContainToolBlocks(sanitizedMessages)) {
888
+ sanitizedMessages = convertClaudeToolBlocksToText(sanitizedMessages);
889
+ }
890
+
682
891
  const payload = {
683
892
  messages: sanitizedMessages,
684
893
  system: prompt.system,
685
- tools: options.tools as MessageCreateParamsBase['tools'],
894
+ tools: hasTools ? options.tools as MessageCreateParamsBase['tools'] : undefined,
686
895
  temperature: model_options?.temperature,
687
896
  model: modelName,
688
897
  max_tokens: maxToken(options),
689
- top_p: model_options?.top_p,
898
+ top_p: model_options?.temperature != null ? undefined : model_options?.top_p,
690
899
  top_k: model_options?.top_k,
691
900
  stop_sequences: model_options?.stop_sequence,
692
901
  thinking: model_options?.thinking_mode ?
@@ -700,3 +909,71 @@ function getClaudePayload(options: ExecutionOptions, prompt: ClaudePrompt): { pa
700
909
 
701
910
  return { payload, requestOptions };
702
911
  }
912
+
913
+ /**
914
+ * Checks whether any Claude message contains tool_use or tool_result content blocks.
915
+ */
916
+ export function claudeMessagesContainToolBlocks(messages: MessageParam[]): boolean {
917
+ for (const msg of messages) {
918
+ if (!Array.isArray(msg.content)) continue;
919
+ for (const block of msg.content) {
920
+ if (typeof block === 'object' && block !== null && 'type' in block) {
921
+ if (block.type === 'tool_use' || block.type === 'tool_result') return true;
922
+ }
923
+ }
924
+ }
925
+ return false;
926
+ }
927
+
928
+ /**
929
+ * Converts tool_use and tool_result blocks to text in Claude messages.
930
+ * Preserves tool call information while removing structured blocks that
931
+ * require tools to be defined in the API request.
932
+ */
933
+ export function convertClaudeToolBlocksToText(messages: MessageParam[]): MessageParam[] {
934
+ return messages.map(msg => {
935
+ if (!Array.isArray(msg.content)) return msg;
936
+ let hasToolBlocks = false;
937
+ for (const block of msg.content) {
938
+ if (typeof block === 'object' && block !== null && 'type' in block &&
939
+ (block.type === 'tool_use' || block.type === 'tool_result')) {
940
+ hasToolBlocks = true;
941
+ break;
942
+ }
943
+ }
944
+ if (!hasToolBlocks) return msg;
945
+
946
+ const newContent: MessageParam['content'] = [];
947
+ for (const block of msg.content) {
948
+ if (typeof block === 'string') {
949
+ newContent.push(block);
950
+ continue;
951
+ }
952
+ if (block.type === 'tool_use') {
953
+ const inputStr = block.input ? JSON.stringify(block.input) : '';
954
+ const truncated = inputStr.length > 500 ? inputStr.substring(0, 500) + '...' : inputStr;
955
+ (newContent as Array<{ type: 'text'; text: string }>).push({
956
+ type: 'text',
957
+ text: `[Tool call: ${block.name}(${truncated})]`,
958
+ });
959
+ } else if (block.type === 'tool_result') {
960
+ let resultStr = 'No content';
961
+ if (typeof block.content === 'string') {
962
+ resultStr = block.content.length > 500 ? block.content.substring(0, 500) + '...' : block.content;
963
+ } else if (Array.isArray(block.content)) {
964
+ const texts = block.content
965
+ .filter((c): c is { type: 'text'; text: string } => c.type === 'text')
966
+ .map(c => c.text.length > 500 ? c.text.substring(0, 500) + '...' : c.text);
967
+ resultStr = texts.join('\n') || 'No text content';
968
+ }
969
+ (newContent as Array<{ type: 'text'; text: string }>).push({
970
+ type: 'text',
971
+ text: `[Tool result: ${resultStr}]`,
972
+ });
973
+ } else {
974
+ newContent.push(block as any);
975
+ }
976
+ }
977
+ return { ...msg, content: newContent };
978
+ });
979
+ }