@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.
- package/lib/cjs/adobe/firefly.js +120 -0
- package/lib/cjs/adobe/firefly.js.map +1 -0
- package/lib/cjs/azure/azure_foundry.js +432 -0
- package/lib/cjs/azure/azure_foundry.js.map +1 -0
- package/lib/cjs/bedrock/converse.js +359 -0
- package/lib/cjs/bedrock/converse.js.map +1 -0
- package/lib/cjs/bedrock/index.js +1441 -0
- package/lib/cjs/bedrock/index.js.map +1 -0
- package/lib/cjs/bedrock/nova-image-payload.js +207 -0
- package/lib/cjs/bedrock/nova-image-payload.js.map +1 -0
- package/lib/cjs/bedrock/payloads.js +3 -0
- package/lib/cjs/bedrock/payloads.js.map +1 -0
- package/lib/cjs/bedrock/s3.js +107 -0
- package/lib/cjs/bedrock/s3.js.map +1 -0
- package/lib/cjs/bedrock/twelvelabs.js +87 -0
- package/lib/cjs/bedrock/twelvelabs.js.map +1 -0
- package/lib/cjs/groq/index.js +326 -0
- package/lib/cjs/groq/index.js.map +1 -0
- package/lib/cjs/huggingface_ie.js +201 -0
- package/lib/cjs/huggingface_ie.js.map +1 -0
- package/lib/cjs/index.js +31 -0
- package/lib/cjs/index.js.map +1 -0
- package/lib/cjs/mistral/index.js +176 -0
- package/lib/cjs/mistral/index.js.map +1 -0
- package/lib/cjs/mistral/types.js +83 -0
- package/lib/cjs/mistral/types.js.map +1 -0
- package/lib/cjs/openai/azure_openai.js +72 -0
- package/lib/cjs/openai/azure_openai.js.map +1 -0
- package/lib/cjs/openai/index.js +1100 -0
- package/lib/cjs/openai/index.js.map +1 -0
- package/lib/cjs/openai/openai.js +21 -0
- package/lib/cjs/openai/openai.js.map +1 -0
- package/lib/cjs/openai/openai_compatible.js +63 -0
- package/lib/cjs/openai/openai_compatible.js.map +1 -0
- package/lib/cjs/openai/openai_format.js +131 -0
- package/lib/cjs/openai/openai_format.js.map +1 -0
- package/lib/cjs/package.json +3 -0
- package/lib/cjs/replicate.js +275 -0
- package/lib/cjs/replicate.js.map +1 -0
- package/lib/cjs/test-driver/TestErrorCompletionStream.js +20 -0
- package/lib/cjs/test-driver/TestErrorCompletionStream.js.map +1 -0
- package/lib/cjs/test-driver/TestValidationErrorCompletionStream.js +24 -0
- package/lib/cjs/test-driver/TestValidationErrorCompletionStream.js.map +1 -0
- package/lib/cjs/test-driver/index.js +109 -0
- package/lib/cjs/test-driver/index.js.map +1 -0
- package/lib/cjs/test-driver/utils.js +30 -0
- package/lib/cjs/test-driver/utils.js.map +1 -0
- package/lib/cjs/togetherai/index.js +126 -0
- package/lib/cjs/togetherai/index.js.map +1 -0
- package/lib/cjs/togetherai/interfaces.js +3 -0
- package/lib/cjs/togetherai/interfaces.js.map +1 -0
- package/lib/cjs/vertexai/debug.js +12 -0
- package/lib/cjs/vertexai/debug.js.map +1 -0
- package/lib/cjs/vertexai/embeddings/embeddings-image.js +27 -0
- package/lib/cjs/vertexai/embeddings/embeddings-image.js.map +1 -0
- package/lib/cjs/vertexai/embeddings/embeddings-text.js +23 -0
- package/lib/cjs/vertexai/embeddings/embeddings-text.js.map +1 -0
- package/lib/cjs/vertexai/index.js +635 -0
- package/lib/cjs/vertexai/index.js.map +1 -0
- package/lib/cjs/vertexai/models/claude.js +842 -0
- package/lib/cjs/vertexai/models/claude.js.map +1 -0
- package/lib/cjs/vertexai/models/gemini.js +1110 -0
- package/lib/cjs/vertexai/models/gemini.js.map +1 -0
- package/lib/cjs/vertexai/models/imagen.js +303 -0
- package/lib/cjs/vertexai/models/imagen.js.map +1 -0
- package/lib/cjs/vertexai/models/llama.js +183 -0
- package/lib/cjs/vertexai/models/llama.js.map +1 -0
- package/lib/cjs/vertexai/models.js +35 -0
- package/lib/cjs/vertexai/models.js.map +1 -0
- package/lib/cjs/watsonx/index.js +161 -0
- package/lib/cjs/watsonx/index.js.map +1 -0
- package/lib/cjs/watsonx/interfaces.js +3 -0
- package/lib/cjs/watsonx/interfaces.js.map +1 -0
- package/lib/cjs/xai/index.js +65 -0
- package/lib/cjs/xai/index.js.map +1 -0
- package/lib/esm/adobe/firefly.js +116 -0
- package/lib/esm/adobe/firefly.js.map +1 -0
- package/lib/esm/azure/azure_foundry.js +426 -0
- package/lib/esm/azure/azure_foundry.js.map +1 -0
- package/lib/esm/bedrock/converse.js +352 -0
- package/lib/esm/bedrock/converse.js.map +1 -0
- package/lib/esm/bedrock/index.js +1434 -0
- package/lib/esm/bedrock/index.js.map +1 -0
- package/lib/esm/bedrock/nova-image-payload.js +203 -0
- package/lib/esm/bedrock/nova-image-payload.js.map +1 -0
- package/lib/esm/bedrock/payloads.js +2 -0
- package/lib/esm/bedrock/payloads.js.map +1 -0
- package/lib/esm/bedrock/s3.js +99 -0
- package/lib/esm/bedrock/s3.js.map +1 -0
- package/lib/esm/bedrock/twelvelabs.js +84 -0
- package/lib/esm/bedrock/twelvelabs.js.map +1 -0
- package/lib/esm/groq/index.js +319 -0
- package/lib/esm/groq/index.js.map +1 -0
- package/lib/esm/huggingface_ie.js +197 -0
- package/lib/esm/huggingface_ie.js.map +1 -0
- package/lib/esm/index.js +15 -0
- package/lib/esm/index.js.map +1 -0
- package/lib/esm/mistral/index.js +172 -0
- package/lib/esm/mistral/index.js.map +1 -0
- package/lib/esm/mistral/types.js +80 -0
- package/lib/esm/mistral/types.js.map +1 -0
- package/lib/esm/openai/azure_openai.js +68 -0
- package/lib/esm/openai/azure_openai.js.map +1 -0
- package/lib/esm/openai/index.js +1093 -0
- package/lib/esm/openai/index.js.map +1 -0
- package/lib/esm/openai/openai.js +14 -0
- package/lib/esm/openai/openai.js.map +1 -0
- package/lib/esm/openai/openai_compatible.js +56 -0
- package/lib/esm/openai/openai_compatible.js.map +1 -0
- package/lib/esm/openai/openai_format.js +127 -0
- package/lib/esm/openai/openai_format.js.map +1 -0
- package/lib/esm/replicate.js +268 -0
- package/lib/esm/replicate.js.map +1 -0
- package/lib/esm/test-driver/TestErrorCompletionStream.js +16 -0
- package/lib/esm/test-driver/TestErrorCompletionStream.js.map +1 -0
- package/lib/esm/test-driver/TestValidationErrorCompletionStream.js +20 -0
- package/lib/esm/test-driver/TestValidationErrorCompletionStream.js.map +1 -0
- package/lib/esm/test-driver/index.js +91 -0
- package/lib/esm/test-driver/index.js.map +1 -0
- package/lib/esm/test-driver/utils.js +25 -0
- package/lib/esm/test-driver/utils.js.map +1 -0
- package/lib/esm/togetherai/index.js +122 -0
- package/lib/esm/togetherai/index.js.map +1 -0
- package/lib/esm/togetherai/interfaces.js +2 -0
- package/lib/esm/togetherai/interfaces.js.map +1 -0
- package/lib/esm/vertexai/debug.js +6 -0
- package/lib/esm/vertexai/debug.js.map +1 -0
- package/lib/esm/vertexai/embeddings/embeddings-image.js +24 -0
- package/lib/esm/vertexai/embeddings/embeddings-image.js.map +1 -0
- package/lib/esm/vertexai/embeddings/embeddings-text.js +20 -0
- package/lib/esm/vertexai/embeddings/embeddings-text.js.map +1 -0
- package/lib/esm/vertexai/index.js +630 -0
- package/lib/esm/vertexai/index.js.map +1 -0
- package/lib/esm/vertexai/models/claude.js +833 -0
- package/lib/esm/vertexai/models/claude.js.map +1 -0
- package/lib/esm/vertexai/models/gemini.js +1104 -0
- package/lib/esm/vertexai/models/gemini.js.map +1 -0
- package/lib/esm/vertexai/models/imagen.js +299 -0
- package/lib/esm/vertexai/models/imagen.js.map +1 -0
- package/lib/esm/vertexai/models/llama.js +179 -0
- package/lib/esm/vertexai/models/llama.js.map +1 -0
- package/lib/esm/vertexai/models.js +32 -0
- package/lib/esm/vertexai/models.js.map +1 -0
- package/lib/esm/watsonx/index.js +157 -0
- package/lib/esm/watsonx/index.js.map +1 -0
- package/lib/esm/watsonx/interfaces.js +2 -0
- package/lib/esm/watsonx/interfaces.js.map +1 -0
- package/lib/esm/xai/index.js +58 -0
- package/lib/esm/xai/index.js.map +1 -0
- package/lib/types/adobe/firefly.d.ts +30 -0
- package/lib/types/adobe/firefly.d.ts.map +1 -0
- package/lib/types/azure/azure_foundry.d.ts +52 -0
- package/lib/types/azure/azure_foundry.d.ts.map +1 -0
- package/lib/types/bedrock/converse.d.ts +8 -0
- package/lib/types/bedrock/converse.d.ts.map +1 -0
- package/lib/types/bedrock/index.d.ts +135 -0
- package/lib/types/bedrock/index.d.ts.map +1 -0
- package/lib/types/bedrock/nova-image-payload.d.ts +74 -0
- package/lib/types/bedrock/nova-image-payload.d.ts.map +1 -0
- package/lib/types/bedrock/payloads.d.ts +12 -0
- package/lib/types/bedrock/payloads.d.ts.map +1 -0
- package/lib/types/bedrock/s3.d.ts +23 -0
- package/lib/types/bedrock/s3.d.ts.map +1 -0
- package/lib/types/bedrock/twelvelabs.d.ts +50 -0
- package/lib/types/bedrock/twelvelabs.d.ts.map +1 -0
- package/lib/types/groq/index.d.ts +27 -0
- package/lib/types/groq/index.d.ts.map +1 -0
- package/lib/types/huggingface_ie.d.ts +35 -0
- package/lib/types/huggingface_ie.d.ts.map +1 -0
- package/lib/types/index.d.ts +15 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/mistral/index.d.ts +25 -0
- package/lib/types/mistral/index.d.ts.map +1 -0
- package/lib/types/mistral/types.d.ts +127 -0
- package/lib/types/mistral/types.d.ts.map +1 -0
- package/lib/types/openai/azure_openai.d.ts +25 -0
- package/lib/types/openai/azure_openai.d.ts.map +1 -0
- package/lib/types/openai/index.d.ts +126 -0
- package/lib/types/openai/index.d.ts.map +1 -0
- package/lib/types/openai/openai.d.ts +15 -0
- package/lib/types/openai/openai.d.ts.map +1 -0
- package/lib/types/openai/openai_compatible.d.ts +31 -0
- package/lib/types/openai/openai_compatible.d.ts.map +1 -0
- package/lib/types/openai/openai_format.d.ts +21 -0
- package/lib/types/openai/openai_format.d.ts.map +1 -0
- package/lib/types/replicate.d.ts +48 -0
- package/lib/types/replicate.d.ts.map +1 -0
- package/lib/types/test-driver/TestErrorCompletionStream.d.ts +9 -0
- package/lib/types/test-driver/TestErrorCompletionStream.d.ts.map +1 -0
- package/lib/types/test-driver/TestValidationErrorCompletionStream.d.ts +9 -0
- package/lib/types/test-driver/TestValidationErrorCompletionStream.d.ts.map +1 -0
- package/lib/types/test-driver/index.d.ts +24 -0
- package/lib/types/test-driver/index.d.ts.map +1 -0
- package/lib/types/test-driver/utils.d.ts +5 -0
- package/lib/types/test-driver/utils.d.ts.map +1 -0
- package/lib/types/togetherai/index.d.ts +23 -0
- package/lib/types/togetherai/index.d.ts.map +1 -0
- package/lib/types/togetherai/interfaces.d.ts +96 -0
- package/lib/types/togetherai/interfaces.d.ts.map +1 -0
- package/lib/types/vertexai/debug.d.ts +2 -0
- package/lib/types/vertexai/debug.d.ts.map +1 -0
- package/lib/types/vertexai/embeddings/embeddings-image.d.ts +11 -0
- package/lib/types/vertexai/embeddings/embeddings-image.d.ts.map +1 -0
- package/lib/types/vertexai/embeddings/embeddings-text.d.ts +10 -0
- package/lib/types/vertexai/embeddings/embeddings-text.d.ts.map +1 -0
- package/lib/types/vertexai/index.d.ts +79 -0
- package/lib/types/vertexai/index.d.ts.map +1 -0
- package/lib/types/vertexai/models/claude.d.ts +103 -0
- package/lib/types/vertexai/models/claude.d.ts.map +1 -0
- package/lib/types/vertexai/models/gemini.d.ts +78 -0
- package/lib/types/vertexai/models/gemini.d.ts.map +1 -0
- package/lib/types/vertexai/models/imagen.d.ts +75 -0
- package/lib/types/vertexai/models/imagen.d.ts.map +1 -0
- package/lib/types/vertexai/models/llama.d.ts +20 -0
- package/lib/types/vertexai/models/llama.d.ts.map +1 -0
- package/lib/types/vertexai/models.d.ts +20 -0
- package/lib/types/vertexai/models.d.ts.map +1 -0
- package/lib/types/watsonx/index.d.ts +27 -0
- package/lib/types/watsonx/index.d.ts.map +1 -0
- package/lib/types/watsonx/interfaces.d.ts +65 -0
- package/lib/types/watsonx/interfaces.d.ts.map +1 -0
- package/lib/types/xai/index.d.ts +18 -0
- package/lib/types/xai/index.d.ts.map +1 -0
- package/package.json +18 -18
- package/src/bedrock/converse.ts +85 -10
- package/src/bedrock/error-handling.test.ts +352 -0
- package/src/bedrock/index.ts +293 -16
- package/src/groq/index.ts +9 -4
- package/src/mistral/index.ts +25 -22
- package/src/mistral/types.ts +0 -5
- package/src/openai/error-handling.test.ts +567 -0
- package/src/openai/index.ts +513 -33
- package/src/openai/openai_compatible.ts +7 -0
- package/src/openai/openai_format.ts +1 -1
- package/src/vertexai/index.ts +61 -13
- package/src/vertexai/models/claude-error-handling.test.ts +432 -0
- package/src/vertexai/models/claude.ts +287 -10
- package/src/vertexai/models/gemini-error-handling.test.ts +353 -0
- package/src/vertexai/models/gemini.ts +329 -52
- 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,
|
|
4
|
-
|
|
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
|
|
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
|
-
|
|
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
|
+
}
|