@providerprotocol/ai 0.0.12 → 0.0.14
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/dist/anthropic/index.d.ts +51 -15
- package/dist/anthropic/index.js +80 -29
- package/dist/anthropic/index.js.map +1 -1
- package/dist/{chunk-SUNYWHTH.js → chunk-MOU4U3PO.js} +55 -3
- package/dist/chunk-MOU4U3PO.js.map +1 -0
- package/dist/{chunk-Y6Q7JCNP.js → chunk-MSR5P65T.js} +1 -1
- package/dist/chunk-MSR5P65T.js.map +1 -0
- package/dist/{chunk-W4BB4BG2.js → chunk-SVYROCLD.js} +31 -11
- package/dist/chunk-SVYROCLD.js.map +1 -0
- package/dist/chunk-U4JJC2YX.js +234 -0
- package/dist/chunk-U4JJC2YX.js.map +1 -0
- package/dist/{chunk-X5G4EHL7.js → chunk-Z7RBRCRN.js} +1 -1
- package/dist/chunk-Z7RBRCRN.js.map +1 -0
- package/dist/google/index.d.ts +376 -7
- package/dist/google/index.js +149 -21
- package/dist/google/index.js.map +1 -1
- package/dist/http/index.d.ts +222 -25
- package/dist/http/index.js +3 -3
- package/dist/index.d.ts +1484 -198
- package/dist/index.js +233 -47
- package/dist/index.js.map +1 -1
- package/dist/ollama/index.d.ts +92 -20
- package/dist/ollama/index.js +31 -7
- package/dist/ollama/index.js.map +1 -1
- package/dist/openai/index.d.ts +340 -61
- package/dist/openai/index.js +105 -31
- package/dist/openai/index.js.map +1 -1
- package/dist/openrouter/index.d.ts +107 -51
- package/dist/openrouter/index.js +84 -24
- package/dist/openrouter/index.js.map +1 -1
- package/dist/provider-Bi0nyNhA.d.ts +505 -0
- package/dist/retry-BatS2hjD.d.ts +508 -0
- package/dist/xai/index.d.ts +97 -22
- package/dist/xai/index.js +129 -45
- package/dist/xai/index.js.map +1 -1
- package/package.json +8 -3
- package/dist/chunk-CUCRF5W6.js +0 -136
- package/dist/chunk-CUCRF5W6.js.map +0 -1
- package/dist/chunk-SUNYWHTH.js.map +0 -1
- package/dist/chunk-W4BB4BG2.js.map +0 -1
- package/dist/chunk-X5G4EHL7.js.map +0 -1
- package/dist/chunk-Y6Q7JCNP.js.map +0 -1
- package/dist/provider-CUJWjgNl.d.ts +0 -192
- package/dist/retry-I2661_rv.d.ts +0 -118
|
@@ -1,40 +1,76 @@
|
|
|
1
|
-
import { b as Provider } from '../provider-
|
|
1
|
+
import { b as Provider } from '../provider-Bi0nyNhA.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Anthropic
|
|
5
|
-
*
|
|
4
|
+
* @fileoverview Anthropic API type definitions.
|
|
5
|
+
*
|
|
6
|
+
* Contains TypeScript interfaces for Anthropic's Messages API request/response
|
|
7
|
+
* structures, streaming events, and provider-specific parameters.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Provider-specific parameters for Anthropic Claude models.
|
|
11
|
+
*
|
|
12
|
+
* These parameters are passed through to the Anthropic Messages API and
|
|
13
|
+
* control model behavior such as sampling, token limits, and extended thinking.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const params: AnthropicLLMParams = {
|
|
18
|
+
* max_tokens: 4096,
|
|
19
|
+
* temperature: 0.7,
|
|
20
|
+
* thinking: { type: 'enabled', budget_tokens: 10000 },
|
|
21
|
+
* };
|
|
22
|
+
* ```
|
|
6
23
|
*/
|
|
7
24
|
interface AnthropicLLMParams {
|
|
8
|
-
/** Maximum number of tokens to generate
|
|
25
|
+
/** Maximum number of tokens to generate. Defaults to model maximum if not specified. */
|
|
9
26
|
max_tokens?: number;
|
|
10
|
-
/**
|
|
27
|
+
/** Sampling temperature from 0.0 (deterministic) to 1.0 (maximum randomness). */
|
|
11
28
|
temperature?: number;
|
|
12
|
-
/**
|
|
29
|
+
/** Nucleus sampling threshold. Only tokens with cumulative probability <= top_p are considered. */
|
|
13
30
|
top_p?: number;
|
|
14
|
-
/** Top-k sampling */
|
|
31
|
+
/** Top-k sampling. Only the k most likely tokens are considered at each step. */
|
|
15
32
|
top_k?: number;
|
|
16
|
-
/** Custom stop
|
|
33
|
+
/** Custom sequences that will cause the model to stop generating. */
|
|
17
34
|
stop_sequences?: string[];
|
|
18
|
-
/**
|
|
35
|
+
/** Request metadata for tracking and analytics. */
|
|
19
36
|
metadata?: {
|
|
37
|
+
/** Unique identifier for the end user making the request. */
|
|
20
38
|
user_id?: string;
|
|
21
39
|
};
|
|
22
|
-
/** Extended thinking configuration */
|
|
40
|
+
/** Extended thinking configuration for complex reasoning tasks. */
|
|
23
41
|
thinking?: {
|
|
42
|
+
/** Must be 'enabled' to activate extended thinking. */
|
|
24
43
|
type: 'enabled';
|
|
44
|
+
/** Token budget for the thinking process. */
|
|
25
45
|
budget_tokens: number;
|
|
26
46
|
};
|
|
27
47
|
/**
|
|
28
|
-
* Service tier for
|
|
29
|
-
* -
|
|
30
|
-
* -
|
|
48
|
+
* Service tier selection for capacity routing.
|
|
49
|
+
* - `auto`: Automatically select based on availability (default)
|
|
50
|
+
* - `standard_only`: Only use standard capacity, never priority
|
|
31
51
|
*/
|
|
32
52
|
service_tier?: 'auto' | 'standard_only';
|
|
33
53
|
}
|
|
34
54
|
|
|
35
55
|
/**
|
|
36
|
-
* Anthropic provider
|
|
37
|
-
*
|
|
56
|
+
* Anthropic provider instance for the Universal Provider Protocol.
|
|
57
|
+
*
|
|
58
|
+
* Provides access to Claude language models through a unified interface.
|
|
59
|
+
* Currently supports the LLM modality with full streaming, tool use,
|
|
60
|
+
* structured output, and image input capabilities.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* import { anthropic } from './providers/anthropic';
|
|
65
|
+
*
|
|
66
|
+
* const claude = anthropic.llm.bind('claude-sonnet-4-20250514');
|
|
67
|
+
* const response = await claude.complete({
|
|
68
|
+
* messages: [new UserMessage([{ type: 'text', text: 'Hello!' }])],
|
|
69
|
+
* config: { apiKey: 'sk-...' },
|
|
70
|
+
* });
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
* @see {@link AnthropicLLMParams} for provider-specific parameters
|
|
38
74
|
*/
|
|
39
75
|
declare const anthropic: Provider<unknown>;
|
|
40
76
|
|
package/dist/anthropic/index.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createProvider
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-MSR5P65T.js";
|
|
4
4
|
import {
|
|
5
5
|
AssistantMessage,
|
|
6
6
|
isAssistantMessage,
|
|
7
7
|
isToolResultMessage,
|
|
8
8
|
isUserMessage
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-SVYROCLD.js";
|
|
10
10
|
import {
|
|
11
11
|
parseSSEStream
|
|
12
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-Z7RBRCRN.js";
|
|
13
13
|
import {
|
|
14
14
|
UPPError,
|
|
15
15
|
doFetch,
|
|
16
16
|
doStreamFetch,
|
|
17
17
|
normalizeHttpError,
|
|
18
18
|
resolveApiKey
|
|
19
|
-
} from "../chunk-
|
|
19
|
+
} from "../chunk-MOU4U3PO.js";
|
|
20
20
|
|
|
21
21
|
// src/providers/anthropic/transform.ts
|
|
22
22
|
function transformRequest(request, modelId) {
|
|
@@ -51,24 +51,37 @@ function transformRequest(request, modelId) {
|
|
|
51
51
|
function filterValidContent(content) {
|
|
52
52
|
return content.filter((c) => c && typeof c.type === "string");
|
|
53
53
|
}
|
|
54
|
+
function extractCacheControl(message) {
|
|
55
|
+
const anthropicMeta = message.metadata?.anthropic;
|
|
56
|
+
return anthropicMeta?.cache_control;
|
|
57
|
+
}
|
|
54
58
|
function transformMessage(message) {
|
|
59
|
+
const cacheControl = extractCacheControl(message);
|
|
55
60
|
if (isUserMessage(message)) {
|
|
56
61
|
const validContent = filterValidContent(message.content);
|
|
62
|
+
const contentBlocks = validContent.map(
|
|
63
|
+
(block, index, arr) => transformContentBlock(block, index === arr.length - 1 ? cacheControl : void 0)
|
|
64
|
+
);
|
|
57
65
|
return {
|
|
58
66
|
role: "user",
|
|
59
|
-
content:
|
|
67
|
+
content: contentBlocks
|
|
60
68
|
};
|
|
61
69
|
}
|
|
62
70
|
if (isAssistantMessage(message)) {
|
|
63
71
|
const validContent = filterValidContent(message.content);
|
|
64
|
-
const content = validContent.map(
|
|
72
|
+
const content = validContent.map(
|
|
73
|
+
(block, index, arr) => transformContentBlock(block, index === arr.length - 1 && !message.toolCalls?.length ? cacheControl : void 0)
|
|
74
|
+
);
|
|
65
75
|
if (message.toolCalls) {
|
|
66
|
-
for (
|
|
76
|
+
for (let i = 0; i < message.toolCalls.length; i++) {
|
|
77
|
+
const call = message.toolCalls[i];
|
|
78
|
+
const isLast = i === message.toolCalls.length - 1;
|
|
67
79
|
content.push({
|
|
68
80
|
type: "tool_use",
|
|
69
81
|
id: call.toolCallId,
|
|
70
82
|
name: call.toolName,
|
|
71
|
-
input: call.arguments
|
|
83
|
+
input: call.arguments,
|
|
84
|
+
...isLast && cacheControl ? { cache_control: cacheControl } : {}
|
|
72
85
|
});
|
|
73
86
|
}
|
|
74
87
|
}
|
|
@@ -80,20 +93,25 @@ function transformMessage(message) {
|
|
|
80
93
|
if (isToolResultMessage(message)) {
|
|
81
94
|
return {
|
|
82
95
|
role: "user",
|
|
83
|
-
content: message.results.map((result) => ({
|
|
96
|
+
content: message.results.map((result, index, arr) => ({
|
|
84
97
|
type: "tool_result",
|
|
85
98
|
tool_use_id: result.toolCallId,
|
|
86
99
|
content: typeof result.result === "string" ? result.result : JSON.stringify(result.result),
|
|
87
|
-
is_error: result.isError
|
|
100
|
+
is_error: result.isError,
|
|
101
|
+
...index === arr.length - 1 && cacheControl ? { cache_control: cacheControl } : {}
|
|
88
102
|
}))
|
|
89
103
|
};
|
|
90
104
|
}
|
|
91
105
|
throw new Error(`Unknown message type: ${message.type}`);
|
|
92
106
|
}
|
|
93
|
-
function transformContentBlock(block) {
|
|
107
|
+
function transformContentBlock(block, cacheControl) {
|
|
94
108
|
switch (block.type) {
|
|
95
109
|
case "text":
|
|
96
|
-
return {
|
|
110
|
+
return {
|
|
111
|
+
type: "text",
|
|
112
|
+
text: block.text,
|
|
113
|
+
...cacheControl ? { cache_control: cacheControl } : {}
|
|
114
|
+
};
|
|
97
115
|
case "image": {
|
|
98
116
|
const imageBlock = block;
|
|
99
117
|
if (imageBlock.source.type === "base64") {
|
|
@@ -103,7 +121,8 @@ function transformContentBlock(block) {
|
|
|
103
121
|
type: "base64",
|
|
104
122
|
media_type: imageBlock.mimeType,
|
|
105
123
|
data: imageBlock.source.data
|
|
106
|
-
}
|
|
124
|
+
},
|
|
125
|
+
...cacheControl ? { cache_control: cacheControl } : {}
|
|
107
126
|
};
|
|
108
127
|
}
|
|
109
128
|
if (imageBlock.source.type === "url") {
|
|
@@ -112,7 +131,8 @@ function transformContentBlock(block) {
|
|
|
112
131
|
source: {
|
|
113
132
|
type: "url",
|
|
114
133
|
url: imageBlock.source.url
|
|
115
|
-
}
|
|
134
|
+
},
|
|
135
|
+
...cacheControl ? { cache_control: cacheControl } : {}
|
|
116
136
|
};
|
|
117
137
|
}
|
|
118
138
|
if (imageBlock.source.type === "bytes") {
|
|
@@ -125,7 +145,8 @@ function transformContentBlock(block) {
|
|
|
125
145
|
type: "base64",
|
|
126
146
|
media_type: imageBlock.mimeType,
|
|
127
147
|
data: base64
|
|
128
|
-
}
|
|
148
|
+
},
|
|
149
|
+
...cacheControl ? { cache_control: cacheControl } : {}
|
|
129
150
|
};
|
|
130
151
|
}
|
|
131
152
|
throw new Error(`Unknown image source type`);
|
|
@@ -134,7 +155,12 @@ function transformContentBlock(block) {
|
|
|
134
155
|
throw new Error(`Unsupported content type: ${block.type}`);
|
|
135
156
|
}
|
|
136
157
|
}
|
|
158
|
+
function extractToolCacheControl(tool) {
|
|
159
|
+
const anthropicMeta = tool.metadata?.anthropic;
|
|
160
|
+
return anthropicMeta?.cache_control;
|
|
161
|
+
}
|
|
137
162
|
function transformTool(tool) {
|
|
163
|
+
const cacheControl = extractToolCacheControl(tool);
|
|
138
164
|
return {
|
|
139
165
|
name: tool.name,
|
|
140
166
|
description: tool.description,
|
|
@@ -142,7 +168,8 @@ function transformTool(tool) {
|
|
|
142
168
|
type: "object",
|
|
143
169
|
properties: tool.parameters.properties,
|
|
144
170
|
required: tool.parameters.required
|
|
145
|
-
}
|
|
171
|
+
},
|
|
172
|
+
...cacheControl ? { cache_control: cacheControl } : {}
|
|
146
173
|
};
|
|
147
174
|
}
|
|
148
175
|
function transformResponse(data) {
|
|
@@ -180,7 +207,9 @@ function transformResponse(data) {
|
|
|
180
207
|
const usage = {
|
|
181
208
|
inputTokens: data.usage.input_tokens,
|
|
182
209
|
outputTokens: data.usage.output_tokens,
|
|
183
|
-
totalTokens: data.usage.input_tokens + data.usage.output_tokens
|
|
210
|
+
totalTokens: data.usage.input_tokens + data.usage.output_tokens,
|
|
211
|
+
cacheReadTokens: data.usage.cache_read_input_tokens ?? 0,
|
|
212
|
+
cacheWriteTokens: data.usage.cache_creation_input_tokens ?? 0
|
|
184
213
|
};
|
|
185
214
|
return {
|
|
186
215
|
message,
|
|
@@ -196,7 +225,9 @@ function createStreamState() {
|
|
|
196
225
|
content: [],
|
|
197
226
|
stopReason: null,
|
|
198
227
|
inputTokens: 0,
|
|
199
|
-
outputTokens: 0
|
|
228
|
+
outputTokens: 0,
|
|
229
|
+
cacheReadTokens: 0,
|
|
230
|
+
cacheWriteTokens: 0
|
|
200
231
|
};
|
|
201
232
|
}
|
|
202
233
|
function transformStreamEvent(event, state) {
|
|
@@ -205,6 +236,8 @@ function transformStreamEvent(event, state) {
|
|
|
205
236
|
state.messageId = event.message.id;
|
|
206
237
|
state.model = event.message.model;
|
|
207
238
|
state.inputTokens = event.message.usage.input_tokens;
|
|
239
|
+
state.cacheReadTokens = event.message.usage.cache_read_input_tokens ?? 0;
|
|
240
|
+
state.cacheWriteTokens = event.message.usage.cache_creation_input_tokens ?? 0;
|
|
208
241
|
return { type: "message_start", index: 0, delta: {} };
|
|
209
242
|
case "content_block_start":
|
|
210
243
|
if (event.content_block.type === "text") {
|
|
@@ -309,7 +342,9 @@ function buildResponseFromState(state) {
|
|
|
309
342
|
const usage = {
|
|
310
343
|
inputTokens: state.inputTokens,
|
|
311
344
|
outputTokens: state.outputTokens,
|
|
312
|
-
totalTokens: state.inputTokens + state.outputTokens
|
|
345
|
+
totalTokens: state.inputTokens + state.outputTokens,
|
|
346
|
+
cacheReadTokens: state.cacheReadTokens,
|
|
347
|
+
cacheWriteTokens: state.cacheWriteTokens
|
|
313
348
|
};
|
|
314
349
|
return {
|
|
315
350
|
message,
|
|
@@ -360,15 +395,23 @@ function createLLMHandler() {
|
|
|
360
395
|
);
|
|
361
396
|
const baseUrl = request.config.baseUrl ?? ANTHROPIC_API_URL;
|
|
362
397
|
const body = transformRequest(request, modelId);
|
|
398
|
+
const headers = {
|
|
399
|
+
"Content-Type": "application/json",
|
|
400
|
+
"x-api-key": apiKey,
|
|
401
|
+
"anthropic-version": request.config.apiVersion ?? ANTHROPIC_VERSION
|
|
402
|
+
};
|
|
403
|
+
if (request.config.headers) {
|
|
404
|
+
for (const [key, value] of Object.entries(request.config.headers)) {
|
|
405
|
+
if (value !== void 0) {
|
|
406
|
+
headers[key] = value;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
363
410
|
const response = await doFetch(
|
|
364
411
|
baseUrl,
|
|
365
412
|
{
|
|
366
413
|
method: "POST",
|
|
367
|
-
headers
|
|
368
|
-
"Content-Type": "application/json",
|
|
369
|
-
"x-api-key": apiKey,
|
|
370
|
-
"anthropic-version": request.config.apiVersion ?? ANTHROPIC_VERSION
|
|
371
|
-
},
|
|
414
|
+
headers,
|
|
372
415
|
body: JSON.stringify(body),
|
|
373
416
|
signal: request.signal
|
|
374
417
|
},
|
|
@@ -398,15 +441,23 @@ function createLLMHandler() {
|
|
|
398
441
|
const baseUrl = request.config.baseUrl ?? ANTHROPIC_API_URL;
|
|
399
442
|
const body = transformRequest(request, modelId);
|
|
400
443
|
body.stream = true;
|
|
444
|
+
const headers = {
|
|
445
|
+
"Content-Type": "application/json",
|
|
446
|
+
"x-api-key": apiKey,
|
|
447
|
+
"anthropic-version": request.config.apiVersion ?? ANTHROPIC_VERSION
|
|
448
|
+
};
|
|
449
|
+
if (request.config.headers) {
|
|
450
|
+
for (const [key, value] of Object.entries(request.config.headers)) {
|
|
451
|
+
if (value !== void 0) {
|
|
452
|
+
headers[key] = value;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
401
456
|
const response = await doStreamFetch(
|
|
402
457
|
baseUrl,
|
|
403
458
|
{
|
|
404
459
|
method: "POST",
|
|
405
|
-
headers
|
|
406
|
-
"Content-Type": "application/json",
|
|
407
|
-
"x-api-key": apiKey,
|
|
408
|
-
"anthropic-version": request.config.apiVersion ?? ANTHROPIC_VERSION
|
|
409
|
-
},
|
|
460
|
+
headers,
|
|
410
461
|
body: JSON.stringify(body),
|
|
411
462
|
signal: request.signal
|
|
412
463
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/providers/anthropic/transform.ts","../../src/providers/anthropic/llm.ts","../../src/providers/anthropic/index.ts"],"sourcesContent":["import type { LLMRequest, LLMResponse } from '../../types/llm.ts';\nimport type { Message } from '../../types/messages.ts';\nimport type { StreamEvent } from '../../types/stream.ts';\nimport type { Tool, ToolCall } from '../../types/tool.ts';\nimport type { TokenUsage } from '../../types/turn.ts';\nimport type { ContentBlock, TextBlock, ImageBlock } from '../../types/content.ts';\nimport {\n AssistantMessage,\n UserMessage,\n ToolResultMessage,\n isUserMessage,\n isAssistantMessage,\n isToolResultMessage,\n} from '../../types/messages.ts';\nimport type {\n AnthropicLLMParams,\n AnthropicRequest,\n AnthropicMessage,\n AnthropicContent,\n AnthropicTool,\n AnthropicResponse,\n AnthropicStreamEvent,\n AnthropicContentBlockDeltaEvent,\n} from './types.ts';\n\n/**\n * Transform UPP request to Anthropic format\n *\n * Params are spread directly to allow pass-through of any Anthropic API fields,\n * even those not explicitly defined in our type. This enables developers to\n * use new API features without waiting for library updates.\n */\nexport function transformRequest<TParams extends AnthropicLLMParams>(\n request: LLMRequest<TParams>,\n modelId: string\n): AnthropicRequest {\n const params = (request.params ?? {}) as AnthropicLLMParams;\n\n // Spread params to pass through all fields, then set required fields\n const anthropicRequest: AnthropicRequest = {\n ...params,\n model: modelId,\n messages: request.messages.map(transformMessage),\n };\n\n // System prompt (top-level in Anthropic)\n if (request.system) {\n anthropicRequest.system = request.system;\n }\n\n // Tools come from request, not params\n if (request.tools && request.tools.length > 0) {\n anthropicRequest.tools = request.tools.map(transformTool);\n anthropicRequest.tool_choice = { type: 'auto' };\n }\n\n // Structured output via tool-based approach\n // Anthropic doesn't have native structured output, so we use a tool to enforce the schema\n if (request.structure) {\n const structuredTool: AnthropicTool = {\n name: 'json_response',\n description: 'Return the response in the specified JSON format. You MUST use this tool to provide your response.',\n input_schema: {\n type: 'object',\n properties: request.structure.properties,\n required: request.structure.required,\n },\n };\n\n // Add the structured output tool (may coexist with user tools)\n anthropicRequest.tools = [...(anthropicRequest.tools ?? []), structuredTool];\n // Force the model to use the json_response tool\n anthropicRequest.tool_choice = { type: 'tool', name: 'json_response' };\n }\n\n return anthropicRequest;\n}\n\n/**\n * Filter to only valid content blocks with a type property\n */\nfunction filterValidContent<T extends { type?: string }>(content: T[]): T[] {\n return content.filter((c) => c && typeof c.type === 'string');\n}\n\n/**\n * Transform a UPP Message to Anthropic format\n */\nfunction transformMessage(message: Message): AnthropicMessage {\n if (isUserMessage(message)) {\n const validContent = filterValidContent(message.content);\n return {\n role: 'user',\n content: validContent.map(transformContentBlock),\n };\n }\n\n if (isAssistantMessage(message)) {\n const validContent = filterValidContent(message.content);\n const content: AnthropicContent[] = validContent.map(transformContentBlock);\n\n // Add tool calls as tool_use content blocks\n if (message.toolCalls) {\n for (const call of message.toolCalls) {\n content.push({\n type: 'tool_use',\n id: call.toolCallId,\n name: call.toolName,\n input: call.arguments,\n });\n }\n }\n\n return {\n role: 'assistant',\n content,\n };\n }\n\n if (isToolResultMessage(message)) {\n // Tool results are sent as user messages with tool_result content\n return {\n role: 'user',\n content: message.results.map((result) => ({\n type: 'tool_result' as const,\n tool_use_id: result.toolCallId,\n content:\n typeof result.result === 'string'\n ? result.result\n : JSON.stringify(result.result),\n is_error: result.isError,\n })),\n };\n }\n\n throw new Error(`Unknown message type: ${message.type}`);\n}\n\n/**\n * Transform a content block to Anthropic format\n */\nfunction transformContentBlock(block: ContentBlock): AnthropicContent {\n switch (block.type) {\n case 'text':\n return { type: 'text', text: block.text };\n\n case 'image': {\n const imageBlock = block as ImageBlock;\n if (imageBlock.source.type === 'base64') {\n return {\n type: 'image',\n source: {\n type: 'base64',\n media_type: imageBlock.mimeType,\n data: imageBlock.source.data,\n },\n };\n }\n if (imageBlock.source.type === 'url') {\n return {\n type: 'image',\n source: {\n type: 'url',\n url: imageBlock.source.url,\n },\n };\n }\n if (imageBlock.source.type === 'bytes') {\n // Convert bytes to base64\n const base64 = btoa(\n Array.from(imageBlock.source.data)\n .map((b) => String.fromCharCode(b))\n .join('')\n );\n return {\n type: 'image',\n source: {\n type: 'base64',\n media_type: imageBlock.mimeType,\n data: base64,\n },\n };\n }\n throw new Error(`Unknown image source type`);\n }\n\n default:\n throw new Error(`Unsupported content type: ${block.type}`);\n }\n}\n\n/**\n * Transform a UPP Tool to Anthropic format\n */\nfunction transformTool(tool: Tool): AnthropicTool {\n return {\n name: tool.name,\n description: tool.description,\n input_schema: {\n type: 'object',\n properties: tool.parameters.properties,\n required: tool.parameters.required,\n },\n };\n}\n\n/**\n * Transform Anthropic response to UPP LLMResponse\n */\nexport function transformResponse(data: AnthropicResponse): LLMResponse {\n // Extract text content\n const textContent: TextBlock[] = [];\n const toolCalls: ToolCall[] = [];\n let structuredData: unknown;\n\n for (const block of data.content) {\n if (block.type === 'text') {\n textContent.push({ type: 'text', text: block.text });\n } else if (block.type === 'tool_use') {\n // Check if this is the json_response tool (structured output)\n if (block.name === 'json_response') {\n // Extract structured data from tool arguments\n structuredData = block.input;\n }\n toolCalls.push({\n toolCallId: block.id,\n toolName: block.name,\n arguments: block.input,\n });\n }\n // Skip thinking blocks for now\n }\n\n const message = new AssistantMessage(\n textContent,\n toolCalls.length > 0 ? toolCalls : undefined,\n {\n id: data.id,\n metadata: {\n anthropic: {\n stop_reason: data.stop_reason,\n stop_sequence: data.stop_sequence,\n model: data.model,\n },\n },\n }\n );\n\n const usage: TokenUsage = {\n inputTokens: data.usage.input_tokens,\n outputTokens: data.usage.output_tokens,\n totalTokens: data.usage.input_tokens + data.usage.output_tokens,\n };\n\n return {\n message,\n usage,\n stopReason: data.stop_reason ?? 'end_turn',\n data: structuredData,\n };\n}\n\n/**\n * State for accumulating streaming response\n */\nexport interface StreamState {\n messageId: string;\n model: string;\n content: Array<{ type: string; text?: string; id?: string; name?: string; input?: string }>;\n stopReason: string | null;\n inputTokens: number;\n outputTokens: number;\n}\n\n/**\n * Create initial stream state\n */\nexport function createStreamState(): StreamState {\n return {\n messageId: '',\n model: '',\n content: [],\n stopReason: null,\n inputTokens: 0,\n outputTokens: 0,\n };\n}\n\n/**\n * Transform Anthropic stream event to UPP StreamEvent\n * Returns null for events that don't produce UPP events\n */\nexport function transformStreamEvent(\n event: AnthropicStreamEvent,\n state: StreamState\n): StreamEvent | null {\n switch (event.type) {\n case 'message_start':\n state.messageId = event.message.id;\n state.model = event.message.model;\n state.inputTokens = event.message.usage.input_tokens;\n return { type: 'message_start', index: 0, delta: {} };\n\n case 'content_block_start':\n // Initialize content block\n if (event.content_block.type === 'text') {\n state.content[event.index] = { type: 'text', text: '' };\n } else if (event.content_block.type === 'tool_use') {\n state.content[event.index] = {\n type: 'tool_use',\n id: event.content_block.id,\n name: event.content_block.name,\n input: '',\n };\n }\n return { type: 'content_block_start', index: event.index, delta: {} };\n\n case 'content_block_delta': {\n const delta = event.delta;\n if (delta.type === 'text_delta') {\n if (state.content[event.index]) {\n state.content[event.index]!.text =\n (state.content[event.index]!.text ?? '') + delta.text;\n }\n return {\n type: 'text_delta',\n index: event.index,\n delta: { text: delta.text },\n };\n }\n if (delta.type === 'input_json_delta') {\n if (state.content[event.index]) {\n state.content[event.index]!.input =\n (state.content[event.index]!.input ?? '') + delta.partial_json;\n }\n return {\n type: 'tool_call_delta',\n index: event.index,\n delta: {\n argumentsJson: delta.partial_json,\n toolCallId: state.content[event.index]?.id,\n toolName: state.content[event.index]?.name,\n },\n };\n }\n if (delta.type === 'thinking_delta') {\n return {\n type: 'reasoning_delta',\n index: event.index,\n delta: { text: delta.thinking },\n };\n }\n return null;\n }\n\n case 'content_block_stop':\n return { type: 'content_block_stop', index: event.index, delta: {} };\n\n case 'message_delta':\n state.stopReason = event.delta.stop_reason;\n state.outputTokens = event.usage.output_tokens;\n return null;\n\n case 'message_stop':\n return { type: 'message_stop', index: 0, delta: {} };\n\n case 'ping':\n case 'error':\n return null;\n\n default:\n return null;\n }\n}\n\n/**\n * Build LLMResponse from accumulated stream state\n */\nexport function buildResponseFromState(state: StreamState): LLMResponse {\n const textContent: TextBlock[] = [];\n const toolCalls: ToolCall[] = [];\n let structuredData: unknown;\n\n for (const block of state.content) {\n if (block.type === 'text' && block.text) {\n textContent.push({ type: 'text', text: block.text });\n } else if (block.type === 'tool_use' && block.id && block.name) {\n let args: Record<string, unknown> = {};\n if (block.input) {\n try {\n args = JSON.parse(block.input);\n } catch {\n // Invalid JSON - use empty object\n }\n }\n // Check if this is the json_response tool (structured output)\n if (block.name === 'json_response') {\n structuredData = args;\n }\n toolCalls.push({\n toolCallId: block.id,\n toolName: block.name,\n arguments: args,\n });\n }\n }\n\n const message = new AssistantMessage(\n textContent,\n toolCalls.length > 0 ? toolCalls : undefined,\n {\n id: state.messageId,\n metadata: {\n anthropic: {\n stop_reason: state.stopReason,\n model: state.model,\n },\n },\n }\n );\n\n const usage: TokenUsage = {\n inputTokens: state.inputTokens,\n outputTokens: state.outputTokens,\n totalTokens: state.inputTokens + state.outputTokens,\n };\n\n return {\n message,\n usage,\n stopReason: state.stopReason ?? 'end_turn',\n data: structuredData,\n };\n}\n","import type { LLMHandler, BoundLLMModel, LLMRequest, LLMResponse, LLMStreamResult, LLMCapabilities } from '../../types/llm.ts';\nimport type { StreamEvent } from '../../types/stream.ts';\nimport type { LLMProvider } from '../../types/provider.ts';\nimport { UPPError } from '../../types/errors.ts';\nimport { resolveApiKey } from '../../http/keys.ts';\nimport { doFetch, doStreamFetch } from '../../http/fetch.ts';\nimport { parseSSEStream } from '../../http/sse.ts';\nimport { normalizeHttpError } from '../../http/errors.ts';\nimport type { AnthropicLLMParams, AnthropicResponse, AnthropicStreamEvent } from './types.ts';\nimport {\n transformRequest,\n transformResponse,\n transformStreamEvent,\n createStreamState,\n buildResponseFromState,\n} from './transform.ts';\n\nconst ANTHROPIC_API_URL = 'https://api.anthropic.com/v1/messages';\nconst ANTHROPIC_VERSION = '2023-06-01';\n\n/**\n * Anthropic API capabilities\n */\nconst ANTHROPIC_CAPABILITIES: LLMCapabilities = {\n streaming: true,\n tools: true,\n structuredOutput: true,\n imageInput: true,\n videoInput: false,\n audioInput: false,\n};\n\n/**\n * Create Anthropic LLM handler\n */\nexport function createLLMHandler(): LLMHandler<AnthropicLLMParams> {\n // Provider reference injected by createProvider() after construction\n let providerRef: LLMProvider<AnthropicLLMParams> | null = null;\n\n return {\n _setProvider(provider: LLMProvider<AnthropicLLMParams>) {\n providerRef = provider;\n },\n\n bind(modelId: string): BoundLLMModel<AnthropicLLMParams> {\n // Use the injected provider reference (set by createProvider)\n if (!providerRef) {\n throw new UPPError(\n 'Provider reference not set. Handler must be used with createProvider().',\n 'INVALID_REQUEST',\n 'anthropic',\n 'llm'\n );\n }\n\n const model: BoundLLMModel<AnthropicLLMParams> = {\n modelId,\n capabilities: ANTHROPIC_CAPABILITIES,\n\n get provider(): LLMProvider<AnthropicLLMParams> {\n return providerRef!;\n },\n\n async complete(request: LLMRequest<AnthropicLLMParams>): Promise<LLMResponse> {\n const apiKey = await resolveApiKey(\n request.config,\n 'ANTHROPIC_API_KEY',\n 'anthropic',\n 'llm'\n );\n\n const baseUrl = request.config.baseUrl ?? ANTHROPIC_API_URL;\n const body = transformRequest(request, modelId);\n\n const response = await doFetch(\n baseUrl,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n 'anthropic-version': request.config.apiVersion ?? ANTHROPIC_VERSION,\n },\n body: JSON.stringify(body),\n signal: request.signal,\n },\n request.config,\n 'anthropic',\n 'llm'\n );\n\n const data = (await response.json()) as AnthropicResponse;\n return transformResponse(data);\n },\n\n stream(request: LLMRequest<AnthropicLLMParams>): LLMStreamResult {\n const state = createStreamState();\n let responseResolve: (value: LLMResponse) => void;\n let responseReject: (error: Error) => void;\n\n const responsePromise = new Promise<LLMResponse>((resolve, reject) => {\n responseResolve = resolve;\n responseReject = reject;\n });\n\n async function* generateEvents(): AsyncGenerator<StreamEvent, void, unknown> {\n try {\n const apiKey = await resolveApiKey(\n request.config,\n 'ANTHROPIC_API_KEY',\n 'anthropic',\n 'llm'\n );\n\n const baseUrl = request.config.baseUrl ?? ANTHROPIC_API_URL;\n const body = transformRequest(request, modelId);\n body.stream = true;\n\n const response = await doStreamFetch(\n baseUrl,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n 'anthropic-version': request.config.apiVersion ?? ANTHROPIC_VERSION,\n },\n body: JSON.stringify(body),\n signal: request.signal,\n },\n request.config,\n 'anthropic',\n 'llm'\n );\n\n if (!response.ok) {\n const error = await normalizeHttpError(response, 'anthropic', 'llm');\n responseReject(error);\n throw error;\n }\n\n if (!response.body) {\n const error = new UPPError(\n 'No response body for streaming request',\n 'PROVIDER_ERROR',\n 'anthropic',\n 'llm'\n );\n responseReject(error);\n throw error;\n }\n\n for await (const data of parseSSEStream(response.body)) {\n // Check for Anthropic error event\n if (typeof data === 'object' && data !== null && 'type' in data) {\n const event = data as AnthropicStreamEvent;\n\n if (event.type === 'error') {\n const error = new UPPError(\n event.error.message,\n 'PROVIDER_ERROR',\n 'anthropic',\n 'llm'\n );\n responseReject(error);\n throw error;\n }\n\n const uppEvent = transformStreamEvent(event, state);\n if (uppEvent) {\n yield uppEvent;\n }\n }\n }\n\n // Build final response\n responseResolve(buildResponseFromState(state));\n } catch (error) {\n responseReject(error as Error);\n throw error;\n }\n }\n\n return {\n [Symbol.asyncIterator]() {\n return generateEvents();\n },\n response: responsePromise,\n };\n },\n };\n\n return model;\n },\n };\n}\n","import { createProvider } from '../../core/provider.ts';\nimport { createLLMHandler } from './llm.ts';\n\n/**\n * Anthropic provider\n * Supports LLM modality with Claude models\n */\nexport const anthropic = createProvider({\n name: 'anthropic',\n version: '1.0.0',\n modalities: {\n llm: createLLMHandler(),\n },\n});\n\n// Re-export types\nexport type { AnthropicLLMParams } from './types.ts';\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/providers/anthropic/transform.ts","../../src/providers/anthropic/llm.ts","../../src/providers/anthropic/index.ts"],"sourcesContent":["/**\n * @fileoverview UPP to Anthropic message transformation utilities.\n *\n * This module handles bidirectional conversion between Universal Provider Protocol\n * message formats and Anthropic's native API structures. It supports:\n * - Request transformation (UPP -> Anthropic)\n * - Response transformation (Anthropic -> UPP)\n * - Stream event transformation for real-time responses\n * - Tool call and structured output handling\n */\n\nimport type { LLMRequest, LLMResponse } from '../../types/llm.ts';\nimport type { Message } from '../../types/messages.ts';\nimport type { StreamEvent } from '../../types/stream.ts';\nimport type { Tool, ToolCall } from '../../types/tool.ts';\nimport type { TokenUsage } from '../../types/turn.ts';\nimport type { ContentBlock, TextBlock, ImageBlock } from '../../types/content.ts';\nimport {\n AssistantMessage,\n isUserMessage,\n isAssistantMessage,\n isToolResultMessage,\n} from '../../types/messages.ts';\nimport type {\n AnthropicLLMParams,\n AnthropicRequest,\n AnthropicMessage,\n AnthropicContent,\n AnthropicTool,\n AnthropicResponse,\n AnthropicStreamEvent,\n AnthropicCacheControl,\n AnthropicSystemContent,\n} from './types.ts';\n\n/**\n * Transforms a UPP LLM request to Anthropic's native API format.\n *\n * Handles conversion of messages, system prompts, tools, and structured output\n * configuration. Parameters are spread directly to enable pass-through of any\n * Anthropic API fields, even those not explicitly defined in our types.\n *\n * @typeParam TParams - Anthropic-specific parameters extending AnthropicLLMParams\n * @param request - The UPP-formatted LLM request\n * @param modelId - The Anthropic model identifier (e.g., 'claude-sonnet-4-20250514')\n * @returns An AnthropicRequest ready for the Messages API\n *\n * @example\n * ```typescript\n * const anthropicRequest = transformRequest({\n * messages: [new UserMessage([{ type: 'text', text: 'Hello!' }])],\n * config: { apiKey: 'sk-...' },\n * params: { max_tokens: 1024, temperature: 0.7 },\n * }, 'claude-sonnet-4-20250514');\n * ```\n *\n * @see {@link transformResponse} for the reverse transformation\n */\nexport function transformRequest<TParams extends AnthropicLLMParams>(\n request: LLMRequest<TParams>,\n modelId: string\n): AnthropicRequest {\n const params = (request.params ?? {}) as AnthropicLLMParams;\n\n const anthropicRequest: AnthropicRequest = {\n ...params,\n model: modelId,\n messages: request.messages.map(transformMessage),\n };\n\n if (request.system) {\n // Pass through directly - accepts string or array of AnthropicSystemContent\n // Array format enables cache_control: [{type: 'text', text: '...', cache_control: {...}}]\n anthropicRequest.system = request.system as string | AnthropicSystemContent[];\n }\n\n if (request.tools && request.tools.length > 0) {\n // For tool caching, use params.tools directly with native Anthropic format\n anthropicRequest.tools = request.tools.map(transformTool);\n anthropicRequest.tool_choice = { type: 'auto' };\n }\n\n if (request.structure) {\n const structuredTool: AnthropicTool = {\n name: 'json_response',\n description: 'Return the response in the specified JSON format. You MUST use this tool to provide your response.',\n input_schema: {\n type: 'object',\n properties: request.structure.properties,\n required: request.structure.required,\n },\n };\n\n anthropicRequest.tools = [...(anthropicRequest.tools ?? []), structuredTool];\n anthropicRequest.tool_choice = { type: 'tool', name: 'json_response' };\n }\n\n return anthropicRequest;\n}\n\n/**\n * Filters content blocks to include only those with a valid type property.\n *\n * @param content - Array of content blocks to filter\n * @returns Filtered array containing only blocks with a string type property\n */\nfunction filterValidContent<T extends { type?: string }>(content: T[]): T[] {\n return content.filter((c) => c && typeof c.type === 'string');\n}\n\n/**\n * Extracts cache control configuration from message metadata.\n *\n * @param message - The message to extract cache control from\n * @returns The cache control configuration if present, undefined otherwise\n */\nfunction extractCacheControl(message: Message): AnthropicCacheControl | undefined {\n const anthropicMeta = message.metadata?.anthropic as\n | { cache_control?: AnthropicCacheControl }\n | undefined;\n return anthropicMeta?.cache_control;\n}\n\n/**\n * Transforms a UPP Message to Anthropic's message format.\n *\n * Handles three message types:\n * - UserMessage: Converted with content blocks\n * - AssistantMessage: Includes text and tool_use blocks\n * - ToolResultMessage: Converted to user role with tool_result content\n *\n * Cache control can be specified via message metadata:\n * ```typescript\n * new UserMessage(content, {\n * metadata: { anthropic: { cache_control: { type: \"ephemeral\" } } }\n * })\n * ```\n *\n * @param message - The UPP message to transform\n * @returns An AnthropicMessage with the appropriate role and content\n * @throws Error if the message type is unknown\n */\nfunction transformMessage(message: Message): AnthropicMessage {\n const cacheControl = extractCacheControl(message);\n\n if (isUserMessage(message)) {\n const validContent = filterValidContent(message.content);\n const contentBlocks = validContent.map((block, index, arr) =>\n transformContentBlock(block, index === arr.length - 1 ? cacheControl : undefined)\n );\n return {\n role: 'user',\n content: contentBlocks,\n };\n }\n\n if (isAssistantMessage(message)) {\n const validContent = filterValidContent(message.content);\n const content: AnthropicContent[] = validContent.map((block, index, arr) =>\n transformContentBlock(block, index === arr.length - 1 && !message.toolCalls?.length ? cacheControl : undefined)\n );\n\n if (message.toolCalls) {\n for (let i = 0; i < message.toolCalls.length; i++) {\n const call = message.toolCalls[i]!;\n const isLast = i === message.toolCalls.length - 1;\n content.push({\n type: 'tool_use',\n id: call.toolCallId,\n name: call.toolName,\n input: call.arguments,\n ...(isLast && cacheControl ? { cache_control: cacheControl } : {}),\n });\n }\n }\n\n return {\n role: 'assistant',\n content,\n };\n }\n\n if (isToolResultMessage(message)) {\n return {\n role: 'user',\n content: message.results.map((result, index, arr) => ({\n type: 'tool_result' as const,\n tool_use_id: result.toolCallId,\n content:\n typeof result.result === 'string'\n ? result.result\n : JSON.stringify(result.result),\n is_error: result.isError,\n ...(index === arr.length - 1 && cacheControl ? { cache_control: cacheControl } : {}),\n })),\n };\n }\n\n throw new Error(`Unknown message type: ${message.type}`);\n}\n\n/**\n * Transforms a UPP ContentBlock to Anthropic's content format.\n *\n * Supports text and image content types. Image blocks can be provided\n * as base64, URL, or raw bytes (which are converted to base64).\n *\n * @param block - The UPP content block to transform\n * @param cacheControl - Optional cache control to apply to the block\n * @returns An AnthropicContent object\n * @throws Error if the content type or image source type is unsupported\n */\nfunction transformContentBlock(\n block: ContentBlock,\n cacheControl?: AnthropicCacheControl\n): AnthropicContent {\n switch (block.type) {\n case 'text':\n return {\n type: 'text',\n text: block.text,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n };\n\n case 'image': {\n const imageBlock = block as ImageBlock;\n if (imageBlock.source.type === 'base64') {\n return {\n type: 'image',\n source: {\n type: 'base64',\n media_type: imageBlock.mimeType,\n data: imageBlock.source.data,\n },\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n };\n }\n if (imageBlock.source.type === 'url') {\n return {\n type: 'image',\n source: {\n type: 'url',\n url: imageBlock.source.url,\n },\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n };\n }\n if (imageBlock.source.type === 'bytes') {\n const base64 = btoa(\n Array.from(imageBlock.source.data)\n .map((b) => String.fromCharCode(b))\n .join('')\n );\n return {\n type: 'image',\n source: {\n type: 'base64',\n media_type: imageBlock.mimeType,\n data: base64,\n },\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n };\n }\n throw new Error(`Unknown image source type`);\n }\n\n default:\n throw new Error(`Unsupported content type: ${block.type}`);\n }\n}\n\n/**\n * Extracts cache control configuration from tool metadata.\n *\n * @param tool - The tool to extract cache control from\n * @returns The cache control configuration if present, undefined otherwise\n */\nfunction extractToolCacheControl(tool: Tool): AnthropicCacheControl | undefined {\n const anthropicMeta = tool.metadata?.anthropic as\n | { cache_control?: AnthropicCacheControl }\n | undefined;\n return anthropicMeta?.cache_control;\n}\n\n/**\n * Transforms a UPP Tool definition to Anthropic's tool format.\n *\n * Cache control can be specified via tool metadata:\n * ```typescript\n * const tool: Tool = {\n * name: 'search_docs',\n * description: 'Search documentation',\n * parameters: {...},\n * metadata: { anthropic: { cache_control: { type: 'ephemeral' } } },\n * run: async (params) => {...}\n * };\n * ```\n *\n * @param tool - The UPP tool definition\n * @returns An AnthropicTool with the appropriate input schema\n */\nfunction transformTool(tool: Tool): AnthropicTool {\n const cacheControl = extractToolCacheControl(tool);\n\n return {\n name: tool.name,\n description: tool.description,\n input_schema: {\n type: 'object',\n properties: tool.parameters.properties,\n required: tool.parameters.required,\n },\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n };\n}\n\n/**\n * Transforms an Anthropic API response to UPP's LLMResponse format.\n *\n * Extracts text content, tool calls, and structured output data from\n * Anthropic's response. The json_response tool is treated specially\n * for structured output extraction.\n *\n * @param data - The raw Anthropic API response\n * @returns A UPP LLMResponse with message, usage, and optional structured data\n *\n * @see {@link transformRequest} for the request transformation\n */\nexport function transformResponse(data: AnthropicResponse): LLMResponse {\n const textContent: TextBlock[] = [];\n const toolCalls: ToolCall[] = [];\n let structuredData: unknown;\n\n for (const block of data.content) {\n if (block.type === 'text') {\n textContent.push({ type: 'text', text: block.text });\n } else if (block.type === 'tool_use') {\n if (block.name === 'json_response') {\n structuredData = block.input;\n }\n toolCalls.push({\n toolCallId: block.id,\n toolName: block.name,\n arguments: block.input,\n });\n }\n }\n\n const message = new AssistantMessage(\n textContent,\n toolCalls.length > 0 ? toolCalls : undefined,\n {\n id: data.id,\n metadata: {\n anthropic: {\n stop_reason: data.stop_reason,\n stop_sequence: data.stop_sequence,\n model: data.model,\n },\n },\n }\n );\n\n const usage: TokenUsage = {\n inputTokens: data.usage.input_tokens,\n outputTokens: data.usage.output_tokens,\n totalTokens: data.usage.input_tokens + data.usage.output_tokens,\n cacheReadTokens: data.usage.cache_read_input_tokens ?? 0,\n cacheWriteTokens: data.usage.cache_creation_input_tokens ?? 0,\n };\n\n return {\n message,\n usage,\n stopReason: data.stop_reason ?? 'end_turn',\n data: structuredData,\n };\n}\n\n/**\n * Mutable state object for accumulating streamed response data.\n *\n * Used during streaming to collect content blocks, token counts, and\n * metadata as events arrive from the Anthropic API.\n */\nexport interface StreamState {\n /** Unique identifier for the message being streamed. */\n messageId: string;\n /** The model that generated this response. */\n model: string;\n /** Accumulated content blocks indexed by their stream position. */\n content: Array<{ type: string; text?: string; id?: string; name?: string; input?: string }>;\n /** The reason the response ended, if completed. */\n stopReason: string | null;\n /** Number of input tokens consumed. */\n inputTokens: number;\n /** Number of output tokens generated. */\n outputTokens: number;\n /** Number of tokens read from cache (cache hits). */\n cacheReadTokens: number;\n /** Number of tokens written to cache. */\n cacheWriteTokens: number;\n}\n\n/**\n * Creates an initialized StreamState for accumulating streaming responses.\n *\n * @returns A fresh StreamState with empty/default values\n */\nexport function createStreamState(): StreamState {\n return {\n messageId: '',\n model: '',\n content: [],\n stopReason: null,\n inputTokens: 0,\n outputTokens: 0,\n cacheReadTokens: 0,\n cacheWriteTokens: 0,\n };\n}\n\n/**\n * Transforms an Anthropic streaming event to a UPP StreamEvent.\n *\n * Updates the provided state object as a side effect to accumulate\n * response data across multiple events. Returns null for events that\n * don't produce corresponding UPP events (e.g., ping, message_delta).\n *\n * @param event - The Anthropic SSE event to transform\n * @param state - Mutable state object to update with accumulated data\n * @returns A UPP StreamEvent, or null if no event should be emitted\n *\n * @example\n * ```typescript\n * const state = createStreamState();\n * for await (const event of parseSSEStream(response.body)) {\n * const uppEvent = transformStreamEvent(event, state);\n * if (uppEvent) {\n * yield uppEvent;\n * }\n * }\n * const finalResponse = buildResponseFromState(state);\n * ```\n */\nexport function transformStreamEvent(\n event: AnthropicStreamEvent,\n state: StreamState\n): StreamEvent | null {\n switch (event.type) {\n case 'message_start':\n state.messageId = event.message.id;\n state.model = event.message.model;\n state.inputTokens = event.message.usage.input_tokens;\n state.cacheReadTokens = event.message.usage.cache_read_input_tokens ?? 0;\n state.cacheWriteTokens = event.message.usage.cache_creation_input_tokens ?? 0;\n return { type: 'message_start', index: 0, delta: {} };\n\n case 'content_block_start':\n if (event.content_block.type === 'text') {\n state.content[event.index] = { type: 'text', text: '' };\n } else if (event.content_block.type === 'tool_use') {\n state.content[event.index] = {\n type: 'tool_use',\n id: event.content_block.id,\n name: event.content_block.name,\n input: '',\n };\n }\n return { type: 'content_block_start', index: event.index, delta: {} };\n\n case 'content_block_delta': {\n const delta = event.delta;\n if (delta.type === 'text_delta') {\n if (state.content[event.index]) {\n state.content[event.index]!.text =\n (state.content[event.index]!.text ?? '') + delta.text;\n }\n return {\n type: 'text_delta',\n index: event.index,\n delta: { text: delta.text },\n };\n }\n if (delta.type === 'input_json_delta') {\n if (state.content[event.index]) {\n state.content[event.index]!.input =\n (state.content[event.index]!.input ?? '') + delta.partial_json;\n }\n return {\n type: 'tool_call_delta',\n index: event.index,\n delta: {\n argumentsJson: delta.partial_json,\n toolCallId: state.content[event.index]?.id,\n toolName: state.content[event.index]?.name,\n },\n };\n }\n if (delta.type === 'thinking_delta') {\n return {\n type: 'reasoning_delta',\n index: event.index,\n delta: { text: delta.thinking },\n };\n }\n return null;\n }\n\n case 'content_block_stop':\n return { type: 'content_block_stop', index: event.index, delta: {} };\n\n case 'message_delta':\n state.stopReason = event.delta.stop_reason;\n state.outputTokens = event.usage.output_tokens;\n return null;\n\n case 'message_stop':\n return { type: 'message_stop', index: 0, delta: {} };\n\n case 'ping':\n case 'error':\n return null;\n\n default:\n return null;\n }\n}\n\n/**\n * Builds a complete LLMResponse from accumulated stream state.\n *\n * Call this after all stream events have been processed to construct\n * the final response. Parses accumulated JSON for tool call arguments\n * and extracts structured output data.\n *\n * @param state - The accumulated stream state\n * @returns A complete UPP LLMResponse\n *\n * @see {@link createStreamState} for initializing state\n * @see {@link transformStreamEvent} for populating state from events\n */\nexport function buildResponseFromState(state: StreamState): LLMResponse {\n const textContent: TextBlock[] = [];\n const toolCalls: ToolCall[] = [];\n let structuredData: unknown;\n\n for (const block of state.content) {\n if (block.type === 'text' && block.text) {\n textContent.push({ type: 'text', text: block.text });\n } else if (block.type === 'tool_use' && block.id && block.name) {\n let args: Record<string, unknown> = {};\n if (block.input) {\n try {\n args = JSON.parse(block.input);\n } catch {\n // Invalid JSON - use empty object\n }\n }\n if (block.name === 'json_response') {\n structuredData = args;\n }\n toolCalls.push({\n toolCallId: block.id,\n toolName: block.name,\n arguments: args,\n });\n }\n }\n\n const message = new AssistantMessage(\n textContent,\n toolCalls.length > 0 ? toolCalls : undefined,\n {\n id: state.messageId,\n metadata: {\n anthropic: {\n stop_reason: state.stopReason,\n model: state.model,\n },\n },\n }\n );\n\n const usage: TokenUsage = {\n inputTokens: state.inputTokens,\n outputTokens: state.outputTokens,\n totalTokens: state.inputTokens + state.outputTokens,\n cacheReadTokens: state.cacheReadTokens,\n cacheWriteTokens: state.cacheWriteTokens,\n };\n\n return {\n message,\n usage,\n stopReason: state.stopReason ?? 'end_turn',\n data: structuredData,\n };\n}\n","/**\n * @fileoverview Anthropic LLM handler implementation.\n *\n * This module provides the core LLM handler for Anthropic's Claude models,\n * implementing both synchronous completion and streaming capabilities.\n */\n\nimport type { LLMHandler, BoundLLMModel, LLMRequest, LLMResponse, LLMStreamResult, LLMCapabilities } from '../../types/llm.ts';\nimport type { StreamEvent } from '../../types/stream.ts';\nimport type { LLMProvider } from '../../types/provider.ts';\nimport { UPPError } from '../../types/errors.ts';\nimport { resolveApiKey } from '../../http/keys.ts';\nimport { doFetch, doStreamFetch } from '../../http/fetch.ts';\nimport { parseSSEStream } from '../../http/sse.ts';\nimport { normalizeHttpError } from '../../http/errors.ts';\nimport type { AnthropicLLMParams, AnthropicResponse, AnthropicStreamEvent } from './types.ts';\nimport {\n transformRequest,\n transformResponse,\n transformStreamEvent,\n createStreamState,\n buildResponseFromState,\n} from './transform.ts';\n\n/** Base URL for the Anthropic Messages API. */\nconst ANTHROPIC_API_URL = 'https://api.anthropic.com/v1/messages';\n\n/** Default Anthropic API version header value. */\nconst ANTHROPIC_VERSION = '2023-06-01';\n\n/**\n * Capability flags for Anthropic Claude models.\n *\n * Defines what features are supported by the Anthropic provider:\n * - streaming: Real-time token generation via SSE\n * - tools: Function calling / tool use\n * - structuredOutput: JSON schema-constrained responses (via tool forcing)\n * - imageInput: Vision capabilities for image analysis\n */\nconst ANTHROPIC_CAPABILITIES: LLMCapabilities = {\n streaming: true,\n tools: true,\n structuredOutput: true,\n imageInput: true,\n videoInput: false,\n audioInput: false,\n};\n\n/**\n * Creates an Anthropic LLM handler for the Universal Provider Protocol.\n *\n * The handler provides methods to bind specific Claude models and make\n * completion requests. It handles API authentication, request transformation,\n * and response parsing.\n *\n * @returns An LLMHandler configured for Anthropic's Messages API\n *\n * @example\n * ```typescript\n * const handler = createLLMHandler();\n * const model = handler.bind('claude-sonnet-4-20250514');\n *\n * const response = await model.complete({\n * messages: [new UserMessage([{ type: 'text', text: 'Hello!' }])],\n * config: { apiKey: process.env.ANTHROPIC_API_KEY },\n * });\n * ```\n */\nexport function createLLMHandler(): LLMHandler<AnthropicLLMParams> {\n let providerRef: LLMProvider<AnthropicLLMParams> | null = null;\n\n return {\n _setProvider(provider: LLMProvider<AnthropicLLMParams>) {\n providerRef = provider;\n },\n\n bind(modelId: string): BoundLLMModel<AnthropicLLMParams> {\n if (!providerRef) {\n throw new UPPError(\n 'Provider reference not set. Handler must be used with createProvider().',\n 'INVALID_REQUEST',\n 'anthropic',\n 'llm'\n );\n }\n\n const model: BoundLLMModel<AnthropicLLMParams> = {\n modelId,\n capabilities: ANTHROPIC_CAPABILITIES,\n\n get provider(): LLMProvider<AnthropicLLMParams> {\n return providerRef!;\n },\n\n async complete(request: LLMRequest<AnthropicLLMParams>): Promise<LLMResponse> {\n const apiKey = await resolveApiKey(\n request.config,\n 'ANTHROPIC_API_KEY',\n 'anthropic',\n 'llm'\n );\n\n const baseUrl = request.config.baseUrl ?? ANTHROPIC_API_URL;\n const body = transformRequest(request, modelId);\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n 'anthropic-version': request.config.apiVersion ?? ANTHROPIC_VERSION,\n };\n\n if (request.config.headers) {\n for (const [key, value] of Object.entries(request.config.headers)) {\n if (value !== undefined) {\n headers[key] = value;\n }\n }\n }\n\n const response = await doFetch(\n baseUrl,\n {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n signal: request.signal,\n },\n request.config,\n 'anthropic',\n 'llm'\n );\n\n const data = (await response.json()) as AnthropicResponse;\n return transformResponse(data);\n },\n\n stream(request: LLMRequest<AnthropicLLMParams>): LLMStreamResult {\n const state = createStreamState();\n let responseResolve: (value: LLMResponse) => void;\n let responseReject: (error: Error) => void;\n\n const responsePromise = new Promise<LLMResponse>((resolve, reject) => {\n responseResolve = resolve;\n responseReject = reject;\n });\n\n async function* generateEvents(): AsyncGenerator<StreamEvent, void, unknown> {\n try {\n const apiKey = await resolveApiKey(\n request.config,\n 'ANTHROPIC_API_KEY',\n 'anthropic',\n 'llm'\n );\n\n const baseUrl = request.config.baseUrl ?? ANTHROPIC_API_URL;\n const body = transformRequest(request, modelId);\n body.stream = true;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n 'anthropic-version': request.config.apiVersion ?? ANTHROPIC_VERSION,\n };\n\n if (request.config.headers) {\n for (const [key, value] of Object.entries(request.config.headers)) {\n if (value !== undefined) {\n headers[key] = value;\n }\n }\n }\n\n const response = await doStreamFetch(\n baseUrl,\n {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n signal: request.signal,\n },\n request.config,\n 'anthropic',\n 'llm'\n );\n\n if (!response.ok) {\n const error = await normalizeHttpError(response, 'anthropic', 'llm');\n responseReject(error);\n throw error;\n }\n\n if (!response.body) {\n const error = new UPPError(\n 'No response body for streaming request',\n 'PROVIDER_ERROR',\n 'anthropic',\n 'llm'\n );\n responseReject(error);\n throw error;\n }\n\n for await (const data of parseSSEStream(response.body)) {\n if (typeof data === 'object' && data !== null && 'type' in data) {\n const event = data as AnthropicStreamEvent;\n\n if (event.type === 'error') {\n const error = new UPPError(\n event.error.message,\n 'PROVIDER_ERROR',\n 'anthropic',\n 'llm'\n );\n responseReject(error);\n throw error;\n }\n\n const uppEvent = transformStreamEvent(event, state);\n if (uppEvent) {\n yield uppEvent;\n }\n }\n }\n\n responseResolve(buildResponseFromState(state));\n } catch (error) {\n responseReject(error as Error);\n throw error;\n }\n }\n\n return {\n [Symbol.asyncIterator]() {\n return generateEvents();\n },\n response: responsePromise,\n };\n },\n };\n\n return model;\n },\n };\n}\n","import { createProvider } from '../../core/provider.ts';\nimport { createLLMHandler } from './llm.ts';\n\n/**\n * Anthropic provider instance for the Universal Provider Protocol.\n *\n * Provides access to Claude language models through a unified interface.\n * Currently supports the LLM modality with full streaming, tool use,\n * structured output, and image input capabilities.\n *\n * @example\n * ```typescript\n * import { anthropic } from './providers/anthropic';\n *\n * const claude = anthropic.llm.bind('claude-sonnet-4-20250514');\n * const response = await claude.complete({\n * messages: [new UserMessage([{ type: 'text', text: 'Hello!' }])],\n * config: { apiKey: 'sk-...' },\n * });\n * ```\n *\n * @see {@link AnthropicLLMParams} for provider-specific parameters\n */\nexport const anthropic = createProvider({\n name: 'anthropic',\n version: '1.0.0',\n modalities: {\n llm: createLLMHandler(),\n },\n});\n\nexport type { AnthropicLLMParams, AnthropicHeaders } from './types.ts';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA0DO,SAAS,iBACd,SACA,SACkB;AAClB,QAAM,SAAU,QAAQ,UAAU,CAAC;AAEnC,QAAM,mBAAqC;AAAA,IACzC,GAAG;AAAA,IACH,OAAO;AAAA,IACP,UAAU,QAAQ,SAAS,IAAI,gBAAgB;AAAA,EACjD;AAEA,MAAI,QAAQ,QAAQ;AAGlB,qBAAiB,SAAS,QAAQ;AAAA,EACpC;AAEA,MAAI,QAAQ,SAAS,QAAQ,MAAM,SAAS,GAAG;AAE7C,qBAAiB,QAAQ,QAAQ,MAAM,IAAI,aAAa;AACxD,qBAAiB,cAAc,EAAE,MAAM,OAAO;AAAA,EAChD;AAEA,MAAI,QAAQ,WAAW;AACrB,UAAM,iBAAgC;AAAA,MACpC,MAAM;AAAA,MACN,aAAa;AAAA,MACb,cAAc;AAAA,QACZ,MAAM;AAAA,QACN,YAAY,QAAQ,UAAU;AAAA,QAC9B,UAAU,QAAQ,UAAU;AAAA,MAC9B;AAAA,IACF;AAEA,qBAAiB,QAAQ,CAAC,GAAI,iBAAiB,SAAS,CAAC,GAAI,cAAc;AAC3E,qBAAiB,cAAc,EAAE,MAAM,QAAQ,MAAM,gBAAgB;AAAA,EACvE;AAEA,SAAO;AACT;AAQA,SAAS,mBAAgD,SAAmB;AAC1E,SAAO,QAAQ,OAAO,CAAC,MAAM,KAAK,OAAO,EAAE,SAAS,QAAQ;AAC9D;AAQA,SAAS,oBAAoB,SAAqD;AAChF,QAAM,gBAAgB,QAAQ,UAAU;AAGxC,SAAO,eAAe;AACxB;AAqBA,SAAS,iBAAiB,SAAoC;AAC5D,QAAM,eAAe,oBAAoB,OAAO;AAEhD,MAAI,cAAc,OAAO,GAAG;AAC1B,UAAM,eAAe,mBAAmB,QAAQ,OAAO;AACvD,UAAM,gBAAgB,aAAa;AAAA,MAAI,CAAC,OAAO,OAAO,QACpD,sBAAsB,OAAO,UAAU,IAAI,SAAS,IAAI,eAAe,MAAS;AAAA,IAClF;AACA,WAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,EACF;AAEA,MAAI,mBAAmB,OAAO,GAAG;AAC/B,UAAM,eAAe,mBAAmB,QAAQ,OAAO;AACvD,UAAM,UAA8B,aAAa;AAAA,MAAI,CAAC,OAAO,OAAO,QAClE,sBAAsB,OAAO,UAAU,IAAI,SAAS,KAAK,CAAC,QAAQ,WAAW,SAAS,eAAe,MAAS;AAAA,IAChH;AAEA,QAAI,QAAQ,WAAW;AACrB,eAAS,IAAI,GAAG,IAAI,QAAQ,UAAU,QAAQ,KAAK;AACjD,cAAM,OAAO,QAAQ,UAAU,CAAC;AAChC,cAAM,SAAS,MAAM,QAAQ,UAAU,SAAS;AAChD,gBAAQ,KAAK;AAAA,UACX,MAAM;AAAA,UACN,IAAI,KAAK;AAAA,UACT,MAAM,KAAK;AAAA,UACX,OAAO,KAAK;AAAA,UACZ,GAAI,UAAU,eAAe,EAAE,eAAe,aAAa,IAAI,CAAC;AAAA,QAClE,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAEA,MAAI,oBAAoB,OAAO,GAAG;AAChC,WAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS,QAAQ,QAAQ,IAAI,CAAC,QAAQ,OAAO,SAAS;AAAA,QACpD,MAAM;AAAA,QACN,aAAa,OAAO;AAAA,QACpB,SACE,OAAO,OAAO,WAAW,WACrB,OAAO,SACP,KAAK,UAAU,OAAO,MAAM;AAAA,QAClC,UAAU,OAAO;AAAA,QACjB,GAAI,UAAU,IAAI,SAAS,KAAK,eAAe,EAAE,eAAe,aAAa,IAAI,CAAC;AAAA,MACpF,EAAE;AAAA,IACJ;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,yBAAyB,QAAQ,IAAI,EAAE;AACzD;AAaA,SAAS,sBACP,OACA,cACkB;AAClB,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,QACN,MAAM,MAAM;AAAA,QACZ,GAAI,eAAe,EAAE,eAAe,aAAa,IAAI,CAAC;AAAA,MACxD;AAAA,IAEF,KAAK,SAAS;AACZ,YAAM,aAAa;AACnB,UAAI,WAAW,OAAO,SAAS,UAAU;AACvC,eAAO;AAAA,UACL,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM;AAAA,YACN,YAAY,WAAW;AAAA,YACvB,MAAM,WAAW,OAAO;AAAA,UAC1B;AAAA,UACA,GAAI,eAAe,EAAE,eAAe,aAAa,IAAI,CAAC;AAAA,QACxD;AAAA,MACF;AACA,UAAI,WAAW,OAAO,SAAS,OAAO;AACpC,eAAO;AAAA,UACL,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM;AAAA,YACN,KAAK,WAAW,OAAO;AAAA,UACzB;AAAA,UACA,GAAI,eAAe,EAAE,eAAe,aAAa,IAAI,CAAC;AAAA,QACxD;AAAA,MACF;AACA,UAAI,WAAW,OAAO,SAAS,SAAS;AACtC,cAAM,SAAS;AAAA,UACb,MAAM,KAAK,WAAW,OAAO,IAAI,EAC9B,IAAI,CAAC,MAAM,OAAO,aAAa,CAAC,CAAC,EACjC,KAAK,EAAE;AAAA,QACZ;AACA,eAAO;AAAA,UACL,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM;AAAA,YACN,YAAY,WAAW;AAAA,YACvB,MAAM;AAAA,UACR;AAAA,UACA,GAAI,eAAe,EAAE,eAAe,aAAa,IAAI,CAAC;AAAA,QACxD;AAAA,MACF;AACA,YAAM,IAAI,MAAM,2BAA2B;AAAA,IAC7C;AAAA,IAEA;AACE,YAAM,IAAI,MAAM,6BAA6B,MAAM,IAAI,EAAE;AAAA,EAC7D;AACF;AAQA,SAAS,wBAAwB,MAA+C;AAC9E,QAAM,gBAAgB,KAAK,UAAU;AAGrC,SAAO,eAAe;AACxB;AAmBA,SAAS,cAAc,MAA2B;AAChD,QAAM,eAAe,wBAAwB,IAAI;AAEjD,SAAO;AAAA,IACL,MAAM,KAAK;AAAA,IACX,aAAa,KAAK;AAAA,IAClB,cAAc;AAAA,MACZ,MAAM;AAAA,MACN,YAAY,KAAK,WAAW;AAAA,MAC5B,UAAU,KAAK,WAAW;AAAA,IAC5B;AAAA,IACA,GAAI,eAAe,EAAE,eAAe,aAAa,IAAI,CAAC;AAAA,EACxD;AACF;AAcO,SAAS,kBAAkB,MAAsC;AACtE,QAAM,cAA2B,CAAC;AAClC,QAAM,YAAwB,CAAC;AAC/B,MAAI;AAEJ,aAAW,SAAS,KAAK,SAAS;AAChC,QAAI,MAAM,SAAS,QAAQ;AACzB,kBAAY,KAAK,EAAE,MAAM,QAAQ,MAAM,MAAM,KAAK,CAAC;AAAA,IACrD,WAAW,MAAM,SAAS,YAAY;AACpC,UAAI,MAAM,SAAS,iBAAiB;AAClC,yBAAiB,MAAM;AAAA,MACzB;AACA,gBAAU,KAAK;AAAA,QACb,YAAY,MAAM;AAAA,QAClB,UAAU,MAAM;AAAA,QAChB,WAAW,MAAM;AAAA,MACnB,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,UAAU,IAAI;AAAA,IAClB;AAAA,IACA,UAAU,SAAS,IAAI,YAAY;AAAA,IACnC;AAAA,MACE,IAAI,KAAK;AAAA,MACT,UAAU;AAAA,QACR,WAAW;AAAA,UACT,aAAa,KAAK;AAAA,UAClB,eAAe,KAAK;AAAA,UACpB,OAAO,KAAK;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,QAAoB;AAAA,IACxB,aAAa,KAAK,MAAM;AAAA,IACxB,cAAc,KAAK,MAAM;AAAA,IACzB,aAAa,KAAK,MAAM,eAAe,KAAK,MAAM;AAAA,IAClD,iBAAiB,KAAK,MAAM,2BAA2B;AAAA,IACvD,kBAAkB,KAAK,MAAM,+BAA+B;AAAA,EAC9D;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,YAAY,KAAK,eAAe;AAAA,IAChC,MAAM;AAAA,EACR;AACF;AAgCO,SAAS,oBAAiC;AAC/C,SAAO;AAAA,IACL,WAAW;AAAA,IACX,OAAO;AAAA,IACP,SAAS,CAAC;AAAA,IACV,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,cAAc;AAAA,IACd,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,EACpB;AACF;AAyBO,SAAS,qBACd,OACA,OACoB;AACpB,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,YAAM,YAAY,MAAM,QAAQ;AAChC,YAAM,QAAQ,MAAM,QAAQ;AAC5B,YAAM,cAAc,MAAM,QAAQ,MAAM;AACxC,YAAM,kBAAkB,MAAM,QAAQ,MAAM,2BAA2B;AACvE,YAAM,mBAAmB,MAAM,QAAQ,MAAM,+BAA+B;AAC5E,aAAO,EAAE,MAAM,iBAAiB,OAAO,GAAG,OAAO,CAAC,EAAE;AAAA,IAEtD,KAAK;AACH,UAAI,MAAM,cAAc,SAAS,QAAQ;AACvC,cAAM,QAAQ,MAAM,KAAK,IAAI,EAAE,MAAM,QAAQ,MAAM,GAAG;AAAA,MACxD,WAAW,MAAM,cAAc,SAAS,YAAY;AAClD,cAAM,QAAQ,MAAM,KAAK,IAAI;AAAA,UAC3B,MAAM;AAAA,UACN,IAAI,MAAM,cAAc;AAAA,UACxB,MAAM,MAAM,cAAc;AAAA,UAC1B,OAAO;AAAA,QACT;AAAA,MACF;AACA,aAAO,EAAE,MAAM,uBAAuB,OAAO,MAAM,OAAO,OAAO,CAAC,EAAE;AAAA,IAEtE,KAAK,uBAAuB;AAC1B,YAAM,QAAQ,MAAM;AACpB,UAAI,MAAM,SAAS,cAAc;AAC/B,YAAI,MAAM,QAAQ,MAAM,KAAK,GAAG;AAC9B,gBAAM,QAAQ,MAAM,KAAK,EAAG,QACzB,MAAM,QAAQ,MAAM,KAAK,EAAG,QAAQ,MAAM,MAAM;AAAA,QACrD;AACA,eAAO;AAAA,UACL,MAAM;AAAA,UACN,OAAO,MAAM;AAAA,UACb,OAAO,EAAE,MAAM,MAAM,KAAK;AAAA,QAC5B;AAAA,MACF;AACA,UAAI,MAAM,SAAS,oBAAoB;AACrC,YAAI,MAAM,QAAQ,MAAM,KAAK,GAAG;AAC9B,gBAAM,QAAQ,MAAM,KAAK,EAAG,SACzB,MAAM,QAAQ,MAAM,KAAK,EAAG,SAAS,MAAM,MAAM;AAAA,QACtD;AACA,eAAO;AAAA,UACL,MAAM;AAAA,UACN,OAAO,MAAM;AAAA,UACb,OAAO;AAAA,YACL,eAAe,MAAM;AAAA,YACrB,YAAY,MAAM,QAAQ,MAAM,KAAK,GAAG;AAAA,YACxC,UAAU,MAAM,QAAQ,MAAM,KAAK,GAAG;AAAA,UACxC;AAAA,QACF;AAAA,MACF;AACA,UAAI,MAAM,SAAS,kBAAkB;AACnC,eAAO;AAAA,UACL,MAAM;AAAA,UACN,OAAO,MAAM;AAAA,UACb,OAAO,EAAE,MAAM,MAAM,SAAS;AAAA,QAChC;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,IAEA,KAAK;AACH,aAAO,EAAE,MAAM,sBAAsB,OAAO,MAAM,OAAO,OAAO,CAAC,EAAE;AAAA,IAErE,KAAK;AACH,YAAM,aAAa,MAAM,MAAM;AAC/B,YAAM,eAAe,MAAM,MAAM;AACjC,aAAO;AAAA,IAET,KAAK;AACH,aAAO,EAAE,MAAM,gBAAgB,OAAO,GAAG,OAAO,CAAC,EAAE;AAAA,IAErD,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IAET;AACE,aAAO;AAAA,EACX;AACF;AAeO,SAAS,uBAAuB,OAAiC;AACtE,QAAM,cAA2B,CAAC;AAClC,QAAM,YAAwB,CAAC;AAC/B,MAAI;AAEJ,aAAW,SAAS,MAAM,SAAS;AACjC,QAAI,MAAM,SAAS,UAAU,MAAM,MAAM;AACvC,kBAAY,KAAK,EAAE,MAAM,QAAQ,MAAM,MAAM,KAAK,CAAC;AAAA,IACrD,WAAW,MAAM,SAAS,cAAc,MAAM,MAAM,MAAM,MAAM;AAC9D,UAAI,OAAgC,CAAC;AACrC,UAAI,MAAM,OAAO;AACf,YAAI;AACF,iBAAO,KAAK,MAAM,MAAM,KAAK;AAAA,QAC/B,QAAQ;AAAA,QAER;AAAA,MACF;AACA,UAAI,MAAM,SAAS,iBAAiB;AAClC,yBAAiB;AAAA,MACnB;AACA,gBAAU,KAAK;AAAA,QACb,YAAY,MAAM;AAAA,QAClB,UAAU,MAAM;AAAA,QAChB,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,UAAU,IAAI;AAAA,IAClB;AAAA,IACA,UAAU,SAAS,IAAI,YAAY;AAAA,IACnC;AAAA,MACE,IAAI,MAAM;AAAA,MACV,UAAU;AAAA,QACR,WAAW;AAAA,UACT,aAAa,MAAM;AAAA,UACnB,OAAO,MAAM;AAAA,QACf;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,QAAoB;AAAA,IACxB,aAAa,MAAM;AAAA,IACnB,cAAc,MAAM;AAAA,IACpB,aAAa,MAAM,cAAc,MAAM;AAAA,IACvC,iBAAiB,MAAM;AAAA,IACvB,kBAAkB,MAAM;AAAA,EAC1B;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,YAAY,MAAM,cAAc;AAAA,IAChC,MAAM;AAAA,EACR;AACF;;;AC7jBA,IAAM,oBAAoB;AAG1B,IAAM,oBAAoB;AAW1B,IAAM,yBAA0C;AAAA,EAC9C,WAAW;AAAA,EACX,OAAO;AAAA,EACP,kBAAkB;AAAA,EAClB,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,YAAY;AACd;AAsBO,SAAS,mBAAmD;AACjE,MAAI,cAAsD;AAE1D,SAAO;AAAA,IACL,aAAa,UAA2C;AACtD,oBAAc;AAAA,IAChB;AAAA,IAEA,KAAK,SAAoD;AACvD,UAAI,CAAC,aAAa;AAChB,cAAM,IAAI;AAAA,UACR;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAEA,YAAM,QAA2C;AAAA,QAC/C;AAAA,QACA,cAAc;AAAA,QAEd,IAAI,WAA4C;AAC9C,iBAAO;AAAA,QACT;AAAA,QAEA,MAAM,SAAS,SAA+D;AAC5E,gBAAM,SAAS,MAAM;AAAA,YACnB,QAAQ;AAAA,YACR;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAEA,gBAAM,UAAU,QAAQ,OAAO,WAAW;AAC1C,gBAAM,OAAO,iBAAiB,SAAS,OAAO;AAE9C,gBAAM,UAAkC;AAAA,YACtC,gBAAgB;AAAA,YAChB,aAAa;AAAA,YACb,qBAAqB,QAAQ,OAAO,cAAc;AAAA,UACpD;AAEA,cAAI,QAAQ,OAAO,SAAS;AAC1B,uBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,OAAO,OAAO,GAAG;AACjE,kBAAI,UAAU,QAAW;AACvB,wBAAQ,GAAG,IAAI;AAAA,cACjB;AAAA,YACF;AAAA,UACF;AAEA,gBAAM,WAAW,MAAM;AAAA,YACrB;AAAA,YACA;AAAA,cACE,QAAQ;AAAA,cACR;AAAA,cACA,MAAM,KAAK,UAAU,IAAI;AAAA,cACzB,QAAQ,QAAQ;AAAA,YAClB;AAAA,YACA,QAAQ;AAAA,YACR;AAAA,YACA;AAAA,UACF;AAEA,gBAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,iBAAO,kBAAkB,IAAI;AAAA,QAC/B;AAAA,QAEA,OAAO,SAA0D;AAC/D,gBAAM,QAAQ,kBAAkB;AAChC,cAAI;AACJ,cAAI;AAEJ,gBAAM,kBAAkB,IAAI,QAAqB,CAAC,SAAS,WAAW;AACpE,8BAAkB;AAClB,6BAAiB;AAAA,UACnB,CAAC;AAED,0BAAgB,iBAA6D;AAC3E,gBAAI;AACF,oBAAM,SAAS,MAAM;AAAA,gBACnB,QAAQ;AAAA,gBACR;AAAA,gBACA;AAAA,gBACA;AAAA,cACF;AAEA,oBAAM,UAAU,QAAQ,OAAO,WAAW;AAC1C,oBAAM,OAAO,iBAAiB,SAAS,OAAO;AAC9C,mBAAK,SAAS;AAEd,oBAAM,UAAkC;AAAA,gBACtC,gBAAgB;AAAA,gBAChB,aAAa;AAAA,gBACb,qBAAqB,QAAQ,OAAO,cAAc;AAAA,cACpD;AAEA,kBAAI,QAAQ,OAAO,SAAS;AAC1B,2BAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,OAAO,OAAO,GAAG;AACjE,sBAAI,UAAU,QAAW;AACvB,4BAAQ,GAAG,IAAI;AAAA,kBACjB;AAAA,gBACF;AAAA,cACF;AAEA,oBAAM,WAAW,MAAM;AAAA,gBACrB;AAAA,gBACA;AAAA,kBACE,QAAQ;AAAA,kBACR;AAAA,kBACA,MAAM,KAAK,UAAU,IAAI;AAAA,kBACzB,QAAQ,QAAQ;AAAA,gBAClB;AAAA,gBACA,QAAQ;AAAA,gBACR;AAAA,gBACA;AAAA,cACF;AAEA,kBAAI,CAAC,SAAS,IAAI;AAChB,sBAAM,QAAQ,MAAM,mBAAmB,UAAU,aAAa,KAAK;AACnE,+BAAe,KAAK;AACpB,sBAAM;AAAA,cACR;AAEA,kBAAI,CAAC,SAAS,MAAM;AAClB,sBAAM,QAAQ,IAAI;AAAA,kBAChB;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,gBACF;AACA,+BAAe,KAAK;AACpB,sBAAM;AAAA,cACR;AAEA,+BAAiB,QAAQ,eAAe,SAAS,IAAI,GAAG;AACtD,oBAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,UAAU,MAAM;AAC/D,wBAAM,QAAQ;AAEd,sBAAI,MAAM,SAAS,SAAS;AAC1B,0BAAM,QAAQ,IAAI;AAAA,sBAChB,MAAM,MAAM;AAAA,sBACZ;AAAA,sBACA;AAAA,sBACA;AAAA,oBACF;AACA,mCAAe,KAAK;AACpB,0BAAM;AAAA,kBACR;AAEA,wBAAM,WAAW,qBAAqB,OAAO,KAAK;AAClD,sBAAI,UAAU;AACZ,0BAAM;AAAA,kBACR;AAAA,gBACF;AAAA,cACF;AAEA,8BAAgB,uBAAuB,KAAK,CAAC;AAAA,YAC/C,SAAS,OAAO;AACd,6BAAe,KAAc;AAC7B,oBAAM;AAAA,YACR;AAAA,UACF;AAEA,iBAAO;AAAA,YACL,CAAC,OAAO,aAAa,IAAI;AACvB,qBAAO,eAAe;AAAA,YACxB;AAAA,YACA,UAAU;AAAA,UACZ;AAAA,QACF;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;AC7NO,IAAM,YAAY,eAAe;AAAA,EACtC,MAAM;AAAA,EACN,SAAS;AAAA,EACT,YAAY;AAAA,IACV,KAAK,iBAAiB;AAAA,EACxB;AACF,CAAC;","names":[]}
|
|
@@ -1,11 +1,27 @@
|
|
|
1
1
|
// src/types/errors.ts
|
|
2
2
|
var UPPError = class _UPPError extends Error {
|
|
3
|
+
/** Normalized error code for programmatic handling */
|
|
3
4
|
code;
|
|
5
|
+
/** Name of the provider that generated the error */
|
|
4
6
|
provider;
|
|
7
|
+
/** The modality that was being used when the error occurred */
|
|
5
8
|
modality;
|
|
9
|
+
/** HTTP status code from the provider's response, if available */
|
|
6
10
|
statusCode;
|
|
11
|
+
/** The original error that caused this UPPError, if wrapping another error */
|
|
7
12
|
cause;
|
|
13
|
+
/** Error class name, always 'UPPError' */
|
|
8
14
|
name = "UPPError";
|
|
15
|
+
/**
|
|
16
|
+
* Creates a new UPPError instance.
|
|
17
|
+
*
|
|
18
|
+
* @param message - Human-readable error description
|
|
19
|
+
* @param code - Normalized error code for programmatic handling
|
|
20
|
+
* @param provider - Name of the provider that generated the error
|
|
21
|
+
* @param modality - The modality that was being used
|
|
22
|
+
* @param statusCode - HTTP status code from the provider's response
|
|
23
|
+
* @param cause - The original error being wrapped
|
|
24
|
+
*/
|
|
9
25
|
constructor(message, code, provider, modality, statusCode, cause) {
|
|
10
26
|
super(message);
|
|
11
27
|
this.code = code;
|
|
@@ -18,7 +34,9 @@ var UPPError = class _UPPError extends Error {
|
|
|
18
34
|
}
|
|
19
35
|
}
|
|
20
36
|
/**
|
|
21
|
-
*
|
|
37
|
+
* Creates a string representation of the error.
|
|
38
|
+
*
|
|
39
|
+
* @returns Formatted error string including code, message, provider, and modality
|
|
22
40
|
*/
|
|
23
41
|
toString() {
|
|
24
42
|
let str = `UPPError [${this.code}]: ${this.message}`;
|
|
@@ -30,7 +48,9 @@ var UPPError = class _UPPError extends Error {
|
|
|
30
48
|
return str;
|
|
31
49
|
}
|
|
32
50
|
/**
|
|
33
|
-
*
|
|
51
|
+
* Converts the error to a JSON-serializable object.
|
|
52
|
+
*
|
|
53
|
+
* @returns Plain object representation suitable for logging or transmission
|
|
34
54
|
*/
|
|
35
55
|
toJSON() {
|
|
36
56
|
return {
|
|
@@ -49,12 +69,23 @@ var UPPError = class _UPPError extends Error {
|
|
|
49
69
|
var RoundRobinKeys = class {
|
|
50
70
|
keys;
|
|
51
71
|
index = 0;
|
|
72
|
+
/**
|
|
73
|
+
* Creates a new RoundRobinKeys instance.
|
|
74
|
+
*
|
|
75
|
+
* @param keys - Array of API keys to rotate through
|
|
76
|
+
* @throws {Error} When the keys array is empty
|
|
77
|
+
*/
|
|
52
78
|
constructor(keys) {
|
|
53
79
|
if (keys.length === 0) {
|
|
54
80
|
throw new Error("RoundRobinKeys requires at least one key");
|
|
55
81
|
}
|
|
56
82
|
this.keys = keys;
|
|
57
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Returns the next key in the rotation sequence.
|
|
86
|
+
*
|
|
87
|
+
* @returns The next API key in round-robin order
|
|
88
|
+
*/
|
|
58
89
|
getKey() {
|
|
59
90
|
const key = this.keys[this.index];
|
|
60
91
|
this.index = (this.index + 1) % this.keys.length;
|
|
@@ -64,6 +95,12 @@ var RoundRobinKeys = class {
|
|
|
64
95
|
var WeightedKeys = class {
|
|
65
96
|
entries;
|
|
66
97
|
totalWeight;
|
|
98
|
+
/**
|
|
99
|
+
* Creates a new WeightedKeys instance.
|
|
100
|
+
*
|
|
101
|
+
* @param keys - Array of key-weight pairs defining selection probabilities
|
|
102
|
+
* @throws {Error} When the keys array is empty
|
|
103
|
+
*/
|
|
67
104
|
constructor(keys) {
|
|
68
105
|
if (keys.length === 0) {
|
|
69
106
|
throw new Error("WeightedKeys requires at least one key");
|
|
@@ -71,6 +108,11 @@ var WeightedKeys = class {
|
|
|
71
108
|
this.entries = keys;
|
|
72
109
|
this.totalWeight = keys.reduce((sum, k) => sum + k.weight, 0);
|
|
73
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* Returns a randomly selected key based on configured weights.
|
|
113
|
+
*
|
|
114
|
+
* @returns An API key selected with probability proportional to its weight
|
|
115
|
+
*/
|
|
74
116
|
getKey() {
|
|
75
117
|
const random = Math.random() * this.totalWeight;
|
|
76
118
|
let cumulative = 0;
|
|
@@ -85,9 +127,19 @@ var WeightedKeys = class {
|
|
|
85
127
|
};
|
|
86
128
|
var DynamicKey = class {
|
|
87
129
|
selector;
|
|
130
|
+
/**
|
|
131
|
+
* Creates a new DynamicKey instance.
|
|
132
|
+
*
|
|
133
|
+
* @param selector - Function that returns an API key (sync or async)
|
|
134
|
+
*/
|
|
88
135
|
constructor(selector) {
|
|
89
136
|
this.selector = selector;
|
|
90
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* Invokes the selector function to retrieve the current key.
|
|
140
|
+
*
|
|
141
|
+
* @returns Promise resolving to the selected API key
|
|
142
|
+
*/
|
|
91
143
|
async getKey() {
|
|
92
144
|
return this.selector();
|
|
93
145
|
}
|
|
@@ -334,4 +386,4 @@ export {
|
|
|
334
386
|
doFetch,
|
|
335
387
|
doStreamFetch
|
|
336
388
|
};
|
|
337
|
-
//# sourceMappingURL=chunk-
|
|
389
|
+
//# sourceMappingURL=chunk-MOU4U3PO.js.map
|