@standardagents/anthropic 0.0.0-stub.ffffff → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1432 @@
1
+ // src/AnthropicProvider.ts
2
+ import { ProviderError, defineTool } from "@standardagents/spec";
3
+ import { z } from "zod";
4
+
5
+ // src/transformers.ts
6
+ import { mapReasoningLevel } from "@standardagents/spec";
7
+
8
+ // src/pricing.ts
9
+ var TOKENS_PER_MILLION = 1e6;
10
+ var CACHE_WRITE_5M_MULTIPLIER = 1.25;
11
+ var CACHE_WRITE_1H_MULTIPLIER = 2;
12
+ var CACHE_READ_MULTIPLIER = 0.1;
13
+ var MODEL_PRICING = [
14
+ ["claude-fable-5", { inputPerMillion: 10, outputPerMillion: 50 }],
15
+ ["claude-mythos", { inputPerMillion: 10, outputPerMillion: 50 }],
16
+ ["claude-opus-4-8", { inputPerMillion: 5, outputPerMillion: 25 }],
17
+ ["claude-opus-4-7", { inputPerMillion: 5, outputPerMillion: 25 }],
18
+ ["claude-opus-4-6", { inputPerMillion: 5, outputPerMillion: 25 }],
19
+ ["claude-opus-4-5", { inputPerMillion: 5, outputPerMillion: 25 }],
20
+ ["claude-opus-4-1", { inputPerMillion: 15, outputPerMillion: 75 }],
21
+ ["claude-opus-4", { inputPerMillion: 15, outputPerMillion: 75 }],
22
+ ["claude-sonnet-4-6", { inputPerMillion: 3, outputPerMillion: 15 }],
23
+ ["claude-sonnet-4-5", { inputPerMillion: 3, outputPerMillion: 15 }],
24
+ ["claude-sonnet-4", { inputPerMillion: 3, outputPerMillion: 15 }],
25
+ ["claude-haiku-4-5", { inputPerMillion: 1, outputPerMillion: 5 }],
26
+ ["claude-3-7-sonnet", { inputPerMillion: 3, outputPerMillion: 15 }],
27
+ ["claude-3-5-sonnet", { inputPerMillion: 3, outputPerMillion: 15 }],
28
+ ["claude-3-5-haiku", { inputPerMillion: 0.8, outputPerMillion: 4 }],
29
+ ["claude-3-opus", { inputPerMillion: 15, outputPerMillion: 75 }],
30
+ ["claude-3-haiku", { inputPerMillion: 0.25, outputPerMillion: 1.25 }]
31
+ ];
32
+ function getAnthropicModelPricing(modelId) {
33
+ if (!modelId) return null;
34
+ const normalized = modelId.trim().toLowerCase();
35
+ let best = null;
36
+ for (const [prefix, pricing] of MODEL_PRICING) {
37
+ if (normalized.startsWith(prefix) && (!best || prefix.length > best.prefix.length)) {
38
+ best = { prefix, pricing };
39
+ }
40
+ }
41
+ return best ? { ...best.pricing } : null;
42
+ }
43
+ function extractUsageBuckets(usage) {
44
+ const totalCacheWrite = usage.cache_creation_input_tokens ?? 0;
45
+ const write1h = usage.cache_creation?.ephemeral_1h_input_tokens ?? 0;
46
+ const write5m = usage.cache_creation?.ephemeral_5m_input_tokens ?? Math.max(totalCacheWrite - write1h, 0);
47
+ return {
48
+ inputTokens: usage.input_tokens,
49
+ outputTokens: usage.output_tokens,
50
+ cacheReadTokens: usage.cache_read_input_tokens ?? 0,
51
+ cacheWrite5mTokens: write5m,
52
+ cacheWrite1hTokens: write1h
53
+ };
54
+ }
55
+ function roundCost(value) {
56
+ return Number(value.toFixed(12));
57
+ }
58
+ function calculateAnthropicUsageCost(modelId, buckets) {
59
+ const pricing = getAnthropicModelPricing(modelId);
60
+ if (!pricing) return void 0;
61
+ const inputRate = pricing.inputPerMillion / TOKENS_PER_MILLION;
62
+ const outputRate = pricing.outputPerMillion / TOKENS_PER_MILLION;
63
+ const cost = buckets.inputTokens * inputRate + buckets.cacheWrite5mTokens * inputRate * CACHE_WRITE_5M_MULTIPLIER + buckets.cacheWrite1hTokens * inputRate * CACHE_WRITE_1H_MULTIPLIER + buckets.cacheReadTokens * inputRate * CACHE_READ_MULTIPLIER + buckets.outputTokens * outputRate;
64
+ return roundCost(cost);
65
+ }
66
+
67
+ // src/transformers.ts
68
+ var THINKING_FORMAT = "anthropic-thinking-v1";
69
+ var REDACTED_THINKING_FORMAT = "anthropic-redacted-thinking-v1";
70
+ var DEFAULT_REASONING_LEVELS = {
71
+ 0: null,
72
+ 33: "low",
73
+ 66: "medium",
74
+ 100: "high"
75
+ };
76
+ var ANTHROPIC_NATIVE_TOOLS = /* @__PURE__ */ new Set(["web_search"]);
77
+ var DEFAULT_MAX_OUTPUT_TOKENS = 8192;
78
+ var THINKING_MODE_PREFIXES = [
79
+ ["claude-fable-5", "adaptive"],
80
+ ["claude-mythos", "adaptive"],
81
+ ["claude-opus-4-8", "adaptive"],
82
+ ["claude-opus-4-7", "adaptive"],
83
+ ["claude-opus-4-6", "adaptive"],
84
+ ["claude-opus-4-5", "budget"],
85
+ ["claude-opus-4-1", "budget"],
86
+ ["claude-opus-4-0", "budget"],
87
+ ["claude-opus-4-2", "budget"],
88
+ // dated full IDs like claude-opus-4-20250514
89
+ ["claude-sonnet-4-6", "adaptive"],
90
+ ["claude-sonnet-4-5", "budget"],
91
+ ["claude-sonnet-4-0", "budget"],
92
+ ["claude-sonnet-4-2", "budget"],
93
+ // dated full IDs like claude-sonnet-4-20250514
94
+ ["claude-haiku-4-5", "budget"],
95
+ ["claude-3-7-sonnet", "budget"],
96
+ ["claude-3", "none"]
97
+ ];
98
+ function getThinkingMode(modelId) {
99
+ for (const [prefix, mode] of THINKING_MODE_PREFIXES) {
100
+ if (modelId.startsWith(prefix)) {
101
+ return mode;
102
+ }
103
+ }
104
+ return "adaptive";
105
+ }
106
+ function parseDataUri(value) {
107
+ const match = /^data:([^;,]+)?(;base64)?,(.*)$/s.exec(value);
108
+ if (!match) return null;
109
+ return {
110
+ mediaType: match[1] || "application/octet-stream",
111
+ data: match[3]
112
+ };
113
+ }
114
+ var SUPPORTED_IMAGE_MEDIA_TYPES = /* @__PURE__ */ new Set([
115
+ "image/jpeg",
116
+ "image/png",
117
+ "image/gif",
118
+ "image/webp"
119
+ ]);
120
+ function normalizeImageMediaType(mediaType) {
121
+ if (mediaType && SUPPORTED_IMAGE_MEDIA_TYPES.has(mediaType)) {
122
+ return mediaType;
123
+ }
124
+ return "image/png";
125
+ }
126
+ function imageBlock(data, mediaType) {
127
+ if (data.startsWith("http://") || data.startsWith("https://")) {
128
+ return { type: "image", source: { type: "url", url: data } };
129
+ }
130
+ const parsed = parseDataUri(data);
131
+ if (parsed) {
132
+ return {
133
+ type: "image",
134
+ source: {
135
+ type: "base64",
136
+ media_type: normalizeImageMediaType(parsed.mediaType),
137
+ data: parsed.data
138
+ }
139
+ };
140
+ }
141
+ return {
142
+ type: "image",
143
+ source: {
144
+ type: "base64",
145
+ media_type: normalizeImageMediaType(mediaType),
146
+ data
147
+ }
148
+ };
149
+ }
150
+ function decodeBase64Text(data) {
151
+ try {
152
+ const binary = atob(data);
153
+ const bytes = new Uint8Array(binary.length);
154
+ for (let i = 0; i < binary.length; i++) {
155
+ bytes[i] = binary.charCodeAt(i);
156
+ }
157
+ return new TextDecoder().decode(bytes);
158
+ } catch {
159
+ return data;
160
+ }
161
+ }
162
+ function fileBlock(data, mediaType, filename) {
163
+ const parsed = parseDataUri(data);
164
+ const base64 = parsed ? parsed.data : data;
165
+ const resolvedMediaType = parsed?.mediaType || mediaType;
166
+ if (data.startsWith("http://") || data.startsWith("https://")) {
167
+ return { type: "document", source: { type: "url", url: data } };
168
+ }
169
+ if (resolvedMediaType === "application/pdf") {
170
+ return {
171
+ type: "document",
172
+ source: { type: "base64", media_type: "application/pdf", data: base64 },
173
+ ...filename ? { title: filename } : {}
174
+ };
175
+ }
176
+ if (resolvedMediaType.startsWith("text/") || resolvedMediaType === "application/json") {
177
+ return {
178
+ type: "document",
179
+ source: { type: "text", media_type: "text/plain", data: decodeBase64Text(base64) },
180
+ ...filename ? { title: filename } : {}
181
+ };
182
+ }
183
+ return {
184
+ type: "text",
185
+ text: `[Unsupported file attachment${filename ? `: ${filename}` : ""} (${resolvedMediaType})]`
186
+ };
187
+ }
188
+ function transformContentPart(part) {
189
+ if (part.type === "text") {
190
+ return { type: "text", text: part.text };
191
+ }
192
+ if (part.type === "image") {
193
+ return imageBlock(part.data || "", part.mediaType);
194
+ }
195
+ if (part.type === "image_url") {
196
+ return imageBlock(part.image_url?.url || "");
197
+ }
198
+ return fileBlock(part.data || "", part.mediaType || "application/octet-stream", part.filename);
199
+ }
200
+ function transformMessageContent(content) {
201
+ if (typeof content === "string") {
202
+ return content;
203
+ }
204
+ return content.map(transformContentPart);
205
+ }
206
+ function transformAssistantMessage(msg) {
207
+ const content = [];
208
+ if (msg.reasoningDetails) {
209
+ for (const detail of msg.reasoningDetails) {
210
+ if (detail.format === THINKING_FORMAT && detail.text !== void 0) {
211
+ content.push({
212
+ type: "thinking",
213
+ thinking: detail.text,
214
+ signature: detail.data ?? ""
215
+ });
216
+ } else if (detail.format === REDACTED_THINKING_FORMAT && detail.data) {
217
+ content.push({ type: "redacted_thinking", data: detail.data });
218
+ }
219
+ }
220
+ }
221
+ if (msg.content) {
222
+ content.push({ type: "text", text: msg.content });
223
+ }
224
+ if (msg.toolCalls) {
225
+ for (const tc of msg.toolCalls) {
226
+ if (ANTHROPIC_NATIVE_TOOLS.has(tc.name)) {
227
+ continue;
228
+ }
229
+ content.push({
230
+ type: "tool_use",
231
+ id: tc.id,
232
+ name: tc.name,
233
+ input: tc.arguments
234
+ });
235
+ }
236
+ }
237
+ if (content.length === 0) {
238
+ return null;
239
+ }
240
+ return { role: "assistant", content };
241
+ }
242
+ function transformToolMessage(msg) {
243
+ if (ANTHROPIC_NATIVE_TOOLS.has(msg.toolName)) {
244
+ return null;
245
+ }
246
+ let text;
247
+ let isError = false;
248
+ if (typeof msg.content === "string") {
249
+ text = msg.content;
250
+ } else if ("type" in msg.content) {
251
+ if (msg.content.type === "text") {
252
+ text = msg.content.text;
253
+ } else if (msg.content.type === "error") {
254
+ text = msg.content.error;
255
+ isError = true;
256
+ } else {
257
+ text = JSON.stringify(msg.content);
258
+ }
259
+ } else {
260
+ text = JSON.stringify(msg.content);
261
+ }
262
+ const blocks = [];
263
+ if (text) {
264
+ blocks.push({ type: "text", text });
265
+ }
266
+ if (msg.attachments?.length) {
267
+ for (const attachment of msg.attachments) {
268
+ if (attachment.type === "image" && attachment.data) {
269
+ blocks.push(imageBlock(attachment.data, attachment.mediaType));
270
+ }
271
+ }
272
+ }
273
+ return {
274
+ type: "tool_result",
275
+ tool_use_id: msg.toolCallId,
276
+ ...blocks.length > 0 ? { content: blocks } : {},
277
+ ...isError ? { is_error: true } : {}
278
+ };
279
+ }
280
+ function transformMessages(messages) {
281
+ let system;
282
+ const anthropicMessages = [];
283
+ let pendingToolResults = [];
284
+ const flushToolResults = () => {
285
+ if (pendingToolResults.length > 0) {
286
+ anthropicMessages.push({ role: "user", content: pendingToolResults });
287
+ pendingToolResults = [];
288
+ }
289
+ };
290
+ for (const msg of messages) {
291
+ switch (msg.role) {
292
+ case "system":
293
+ system = system ? `${system}
294
+
295
+ ${msg.content}` : msg.content;
296
+ break;
297
+ case "user":
298
+ flushToolResults();
299
+ anthropicMessages.push({
300
+ role: "user",
301
+ content: transformMessageContent(msg.content)
302
+ });
303
+ break;
304
+ case "assistant": {
305
+ flushToolResults();
306
+ const assistantMessage = transformAssistantMessage(msg);
307
+ if (assistantMessage) {
308
+ anthropicMessages.push(assistantMessage);
309
+ }
310
+ break;
311
+ }
312
+ case "tool": {
313
+ const toolResult = transformToolMessage(msg);
314
+ if (toolResult) {
315
+ pendingToolResults.push(toolResult);
316
+ }
317
+ break;
318
+ }
319
+ }
320
+ }
321
+ flushToolResults();
322
+ return { anthropicMessages, system };
323
+ }
324
+ function isRecord(value) {
325
+ return typeof value === "object" && value !== null && !Array.isArray(value);
326
+ }
327
+ function transformTool(tool) {
328
+ const parameters = isRecord(tool.function.parameters) ? tool.function.parameters : { type: "object", properties: {} };
329
+ return {
330
+ name: tool.function.name,
331
+ ...tool.function.description ? { description: tool.function.description } : {},
332
+ input_schema: {
333
+ ...parameters,
334
+ type: "object"
335
+ }
336
+ };
337
+ }
338
+ function transformTools(tools) {
339
+ const result = [];
340
+ for (const tool of tools) {
341
+ const toolName = tool.function.name;
342
+ if (tool.executionMode === "provider" && ANTHROPIC_NATIVE_TOOLS.has(toolName)) {
343
+ if (toolName === "web_search") {
344
+ result.push({ type: "web_search_20250305", name: "web_search" });
345
+ }
346
+ } else {
347
+ result.push(transformTool(tool));
348
+ }
349
+ }
350
+ return result;
351
+ }
352
+ function transformToolChoice(choice, parallelToolCalls) {
353
+ const disable = parallelToolCalls === false ? { disable_parallel_tool_use: true } : {};
354
+ if (choice === "none") {
355
+ return { type: "none" };
356
+ }
357
+ if (choice === "required") {
358
+ return { type: "any", ...disable };
359
+ }
360
+ if (typeof choice === "object" && choice !== null && "name" in choice) {
361
+ return { type: "tool", name: choice.name, ...disable };
362
+ }
363
+ if (choice === "auto" || parallelToolCalls === false) {
364
+ return { type: "auto", ...disable };
365
+ }
366
+ return void 0;
367
+ }
368
+ function mapFinishReason(stopReason) {
369
+ switch (stopReason) {
370
+ case "end_turn":
371
+ case "stop_sequence":
372
+ case "pause_turn":
373
+ return "stop";
374
+ case "max_tokens":
375
+ return "length";
376
+ case "tool_use":
377
+ return "tool_calls";
378
+ case "refusal":
379
+ return "content_filter";
380
+ default:
381
+ return "stop";
382
+ }
383
+ }
384
+ function extractTextContent(content) {
385
+ const textParts = [];
386
+ for (const block of content) {
387
+ if (block.type === "text") {
388
+ textParts.push(block.text);
389
+ }
390
+ }
391
+ return textParts.length > 0 ? textParts.join("") : null;
392
+ }
393
+ function extractReasoningContent(content) {
394
+ let reasoning = null;
395
+ const reasoningDetails = [];
396
+ for (const block of content) {
397
+ if (block.type === "thinking") {
398
+ if (block.thinking) {
399
+ reasoning = reasoning ? `${reasoning}
400
+ ${block.thinking}` : block.thinking;
401
+ }
402
+ reasoningDetails.push({
403
+ type: "text",
404
+ text: block.thinking,
405
+ data: block.signature,
406
+ format: THINKING_FORMAT
407
+ });
408
+ } else if (block.type === "redacted_thinking") {
409
+ reasoningDetails.push({
410
+ type: "encrypted",
411
+ data: block.data,
412
+ format: REDACTED_THINKING_FORMAT
413
+ });
414
+ }
415
+ }
416
+ return {
417
+ reasoning,
418
+ reasoningDetails: reasoningDetails.length > 0 ? reasoningDetails : void 0
419
+ };
420
+ }
421
+ function extractToolCalls(content) {
422
+ const toolCalls = [];
423
+ for (const block of content) {
424
+ if (block.type === "tool_use") {
425
+ toolCalls.push({
426
+ id: block.id,
427
+ name: block.name,
428
+ arguments: isRecord(block.input) ? block.input : {}
429
+ });
430
+ }
431
+ }
432
+ return toolCalls.length > 0 ? toolCalls : void 0;
433
+ }
434
+ function webSearchToolResult(id, input, resultContent) {
435
+ const query = isRecord(input) && typeof input.query === "string" ? input.query : void 0;
436
+ let status = "completed";
437
+ let sources;
438
+ if (Array.isArray(resultContent)) {
439
+ sources = resultContent.filter(isRecord).filter((item) => item.type === "web_search_result" && typeof item.url === "string").map((item) => ({
440
+ type: "url",
441
+ url: item.url,
442
+ ...typeof item.title === "string" ? { title: item.title } : {}
443
+ }));
444
+ } else if (isRecord(resultContent) && resultContent.type === "web_search_tool_result_error") {
445
+ status = "failed";
446
+ }
447
+ return {
448
+ name: "web_search",
449
+ type: "web_search",
450
+ provider: "anthropic",
451
+ id,
452
+ status,
453
+ result: {
454
+ actions: [{
455
+ type: "search",
456
+ ...query ? { query } : {},
457
+ ...sources && sources.length > 0 ? { sources } : {}
458
+ }]
459
+ }
460
+ };
461
+ }
462
+ function extractProviderToolResults(content) {
463
+ const providerTools = [];
464
+ const serverToolUses = /* @__PURE__ */ new Map();
465
+ for (const block of content) {
466
+ if (block.type === "server_tool_use") {
467
+ serverToolUses.set(block.id, { name: block.name, input: block.input });
468
+ } else if (block.type === "web_search_tool_result") {
469
+ const use = serverToolUses.get(block.tool_use_id);
470
+ providerTools.push(
471
+ webSearchToolResult(block.tool_use_id, use?.input, block.content)
472
+ );
473
+ }
474
+ }
475
+ return providerTools.length > 0 ? providerTools : void 0;
476
+ }
477
+ function transformUsage(usage, modelId) {
478
+ if (!usage) {
479
+ return { promptTokens: 0, completionTokens: 0, totalTokens: 0, provider: "anthropic" };
480
+ }
481
+ const cacheCreation = usage.cache_creation_input_tokens ?? 0;
482
+ const cacheRead = usage.cache_read_input_tokens ?? 0;
483
+ const promptTokens = usage.input_tokens + cacheCreation + cacheRead;
484
+ const completionTokens = usage.output_tokens;
485
+ const reasoningTokens = usage.output_tokens_details?.thinking_tokens;
486
+ const cost = modelId ? calculateAnthropicUsageCost(modelId, extractUsageBuckets(usage)) : void 0;
487
+ return {
488
+ promptTokens,
489
+ completionTokens,
490
+ totalTokens: promptTokens + completionTokens,
491
+ ...reasoningTokens !== void 0 ? { reasoningTokens } : {},
492
+ ...cacheRead > 0 ? { cachedTokens: cacheRead } : {},
493
+ ...cost !== void 0 ? { cost } : {},
494
+ provider: "anthropic"
495
+ };
496
+ }
497
+ function transformResponse(message) {
498
+ const content = extractTextContent(message.content);
499
+ const { reasoning, reasoningDetails } = extractReasoningContent(message.content);
500
+ const toolCalls = extractToolCalls(message.content);
501
+ const providerTools = extractProviderToolResults(message.content);
502
+ return {
503
+ content,
504
+ reasoning,
505
+ reasoningDetails,
506
+ toolCalls,
507
+ providerTools,
508
+ finishReason: mapFinishReason(message.stop_reason),
509
+ usage: transformUsage(message.usage, message.model),
510
+ metadata: {
511
+ model: message.model,
512
+ provider: "anthropic",
513
+ requestId: message.id,
514
+ ...message.stop_sequence ? { stopSequence: message.stop_sequence } : {},
515
+ ...message.usage?.cache_creation_input_tokens ? { cacheCreationInputTokens: message.usage.cache_creation_input_tokens } : {},
516
+ ...message.usage?.cache_read_input_tokens ? { cacheReadInputTokens: message.usage.cache_read_input_tokens } : {},
517
+ ...message.usage?.service_tier ? { serviceTier: message.usage.service_tier } : {},
518
+ ...message.usage?.server_tool_use ? { serverToolUse: { ...message.usage.server_tool_use } } : {}
519
+ }
520
+ };
521
+ }
522
+ function resolveThinkingOverride(value) {
523
+ if (!isRecord(value)) return void 0;
524
+ const display = value.display === "summarized" || value.display === "omitted" ? value.display : void 0;
525
+ if (value.type === "adaptive") {
526
+ return { type: "adaptive", ...display ? { display } : {} };
527
+ }
528
+ if (value.type === "enabled" && typeof value.budget_tokens === "number") {
529
+ return {
530
+ type: "enabled",
531
+ budget_tokens: value.budget_tokens,
532
+ ...display ? { display } : {}
533
+ };
534
+ }
535
+ if (value.type === "disabled") {
536
+ return { type: "disabled" };
537
+ }
538
+ return void 0;
539
+ }
540
+ function resolveThinkingBudget(level, maxTokens, explicitBudget) {
541
+ if (maxTokens < 2048) {
542
+ return null;
543
+ }
544
+ const ceiling = maxTokens - 1024;
545
+ const scaled = explicitBudget ?? Math.floor(maxTokens * Math.min(level, 100) / 100 * 0.75);
546
+ return Math.max(1024, Math.min(scaled, ceiling));
547
+ }
548
+ function buildCreateParams(request, reasoningLevels = DEFAULT_REASONING_LEVELS, defaultMaxTokens = DEFAULT_MAX_OUTPUT_TOKENS) {
549
+ const { anthropicMessages, system } = transformMessages(request.messages);
550
+ const maxTokens = request.maxOutputTokens ?? defaultMaxTokens;
551
+ const params = {
552
+ model: request.model,
553
+ max_tokens: maxTokens,
554
+ messages: anthropicMessages
555
+ };
556
+ const providerOptions = isRecord(request.providerOptions) ? request.providerOptions : {};
557
+ const {
558
+ cacheSystemPrompt,
559
+ thinking: thinkingOverride,
560
+ ...passthroughOptions
561
+ } = providerOptions;
562
+ let systemText = system;
563
+ if (request.responseFormat?.type === "json") {
564
+ if (request.responseFormat.schema) {
565
+ params.output_config = {
566
+ format: { type: "json_schema", schema: request.responseFormat.schema }
567
+ };
568
+ } else {
569
+ const jsonInstruction = "Respond with valid JSON only. Do not include any text outside the JSON.";
570
+ systemText = systemText ? `${systemText}
571
+
572
+ ${jsonInstruction}` : jsonInstruction;
573
+ }
574
+ }
575
+ if (systemText) {
576
+ params.system = cacheSystemPrompt === true ? [{ type: "text", text: systemText, cache_control: { type: "ephemeral" } }] : systemText;
577
+ }
578
+ if (request.tools && request.tools.length > 0) {
579
+ params.tools = transformTools(request.tools);
580
+ }
581
+ const toolChoice = transformToolChoice(request.toolChoice, request.parallelToolCalls);
582
+ if (toolChoice && params.tools && params.tools.length > 0) {
583
+ params.tool_choice = toolChoice;
584
+ }
585
+ const thinkingMode = getThinkingMode(request.model);
586
+ let thinkingEnabled = false;
587
+ const resolvedOverride = resolveThinkingOverride(thinkingOverride);
588
+ if (resolvedOverride) {
589
+ params.thinking = resolvedOverride;
590
+ thinkingEnabled = resolvedOverride.type !== "disabled";
591
+ } else if (request.reasoning?.level !== void 0 && request.reasoning.level > 0) {
592
+ if (thinkingMode === "adaptive") {
593
+ params.thinking = {
594
+ type: "adaptive",
595
+ ...request.reasoning.exclude ? { display: "omitted" } : {}
596
+ };
597
+ const effort = mapReasoningLevel(request.reasoning.level, reasoningLevels);
598
+ if (effort) {
599
+ params.output_config = {
600
+ ...params.output_config,
601
+ effort
602
+ };
603
+ }
604
+ thinkingEnabled = true;
605
+ } else if (thinkingMode === "budget") {
606
+ const budget = resolveThinkingBudget(
607
+ request.reasoning.level,
608
+ maxTokens,
609
+ request.reasoning.maxTokens
610
+ );
611
+ if (budget !== null) {
612
+ params.thinking = {
613
+ type: "enabled",
614
+ budget_tokens: budget,
615
+ ...request.reasoning.exclude ? { display: "omitted" } : {}
616
+ };
617
+ thinkingEnabled = true;
618
+ }
619
+ }
620
+ }
621
+ if (!thinkingEnabled) {
622
+ if (request.temperature !== void 0) {
623
+ params.temperature = request.temperature;
624
+ }
625
+ if (request.topP !== void 0) {
626
+ params.top_p = request.topP;
627
+ }
628
+ if (request.topK !== void 0) {
629
+ params.top_k = request.topK;
630
+ }
631
+ }
632
+ if (request.stopSequences && request.stopSequences.length > 0) {
633
+ params.stop_sequences = request.stopSequences;
634
+ }
635
+ Object.assign(params, passthroughOptions);
636
+ return params;
637
+ }
638
+ function createStreamState() {
639
+ return {
640
+ toolCallsByIndex: /* @__PURE__ */ new Map(),
641
+ thinkingByIndex: /* @__PURE__ */ new Map(),
642
+ serverToolsByIndex: /* @__PURE__ */ new Map(),
643
+ pendingServerTools: /* @__PURE__ */ new Map(),
644
+ reasoningDetails: [],
645
+ hasContent: false,
646
+ hasReasoning: false,
647
+ usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0, provider: "anthropic" },
648
+ buckets: {
649
+ inputTokens: 0,
650
+ outputTokens: 0,
651
+ cacheReadTokens: 0,
652
+ cacheWrite5mTokens: 0,
653
+ cacheWrite1hTokens: 0
654
+ },
655
+ finishReason: "stop",
656
+ model: null,
657
+ messageId: null,
658
+ serverToolUse: null
659
+ };
660
+ }
661
+ function parseToolCallArguments(argumentsJson) {
662
+ try {
663
+ const parsed = argumentsJson ? JSON.parse(argumentsJson) : {};
664
+ return isRecord(parsed) ? parsed : {};
665
+ } catch {
666
+ return {};
667
+ }
668
+ }
669
+ function applyDeltaUsage(state, usage) {
670
+ const cacheCreation = usage.cache_creation_input_tokens ?? 0;
671
+ const cacheRead = usage.cache_read_input_tokens ?? 0;
672
+ if (usage.input_tokens !== null && usage.input_tokens !== void 0) {
673
+ state.usage.promptTokens = usage.input_tokens + cacheCreation + cacheRead;
674
+ if (cacheRead > 0) {
675
+ state.usage.cachedTokens = cacheRead;
676
+ }
677
+ state.buckets.inputTokens = usage.input_tokens;
678
+ state.buckets.cacheReadTokens = cacheRead;
679
+ state.buckets.cacheWrite5mTokens = Math.max(
680
+ cacheCreation - state.buckets.cacheWrite1hTokens,
681
+ 0
682
+ );
683
+ }
684
+ state.buckets.outputTokens = usage.output_tokens;
685
+ state.usage.completionTokens = usage.output_tokens;
686
+ const thinkingTokens = usage.output_tokens_details?.thinking_tokens;
687
+ if (thinkingTokens !== void 0) {
688
+ state.usage.reasoningTokens = thinkingTokens;
689
+ }
690
+ state.usage.totalTokens = state.usage.promptTokens + state.usage.completionTokens;
691
+ if (usage.server_tool_use) {
692
+ state.serverToolUse = { ...usage.server_tool_use };
693
+ }
694
+ }
695
+ function processStreamEvent(event, state) {
696
+ const chunks = [];
697
+ switch (event.type) {
698
+ case "message_start": {
699
+ const usage = event.message.usage;
700
+ const cacheCreation = usage.cache_creation_input_tokens ?? 0;
701
+ const cacheRead = usage.cache_read_input_tokens ?? 0;
702
+ state.usage.promptTokens = usage.input_tokens + cacheCreation + cacheRead;
703
+ if (cacheRead > 0) {
704
+ state.usage.cachedTokens = cacheRead;
705
+ }
706
+ state.usage.completionTokens = usage.output_tokens;
707
+ state.usage.totalTokens = state.usage.promptTokens + state.usage.completionTokens;
708
+ state.buckets = extractUsageBuckets(usage);
709
+ state.model = event.message.model;
710
+ state.messageId = event.message.id;
711
+ break;
712
+ }
713
+ case "content_block_start": {
714
+ const block = event.content_block;
715
+ if (block.type === "tool_use") {
716
+ state.toolCallsByIndex.set(event.index, {
717
+ id: block.id,
718
+ name: block.name,
719
+ argumentsJson: ""
720
+ });
721
+ chunks.push({ type: "tool-call-start", id: block.id, name: block.name });
722
+ } else if (block.type === "thinking") {
723
+ state.thinkingByIndex.set(event.index, {
724
+ thinking: block.thinking || "",
725
+ signature: block.signature || ""
726
+ });
727
+ } else if (block.type === "redacted_thinking") {
728
+ state.reasoningDetails.push({
729
+ type: "encrypted",
730
+ data: block.data,
731
+ format: REDACTED_THINKING_FORMAT
732
+ });
733
+ } else if (block.type === "server_tool_use") {
734
+ state.serverToolsByIndex.set(event.index, {
735
+ id: block.id,
736
+ name: block.name,
737
+ inputJson: ""
738
+ });
739
+ } else if (block.type === "web_search_tool_result") {
740
+ const use = state.pendingServerTools.get(block.tool_use_id);
741
+ chunks.push({
742
+ type: "provider-tool-done",
743
+ tool: webSearchToolResult(block.tool_use_id, use?.input, block.content)
744
+ });
745
+ state.pendingServerTools.delete(block.tool_use_id);
746
+ }
747
+ break;
748
+ }
749
+ case "content_block_delta": {
750
+ const delta = event.delta;
751
+ if (delta.type === "text_delta") {
752
+ state.hasContent = true;
753
+ chunks.push({ type: "content-delta", delta: delta.text });
754
+ } else if (delta.type === "thinking_delta") {
755
+ state.hasReasoning = true;
756
+ const thinkingBlock = state.thinkingByIndex.get(event.index);
757
+ if (thinkingBlock) {
758
+ thinkingBlock.thinking += delta.thinking;
759
+ }
760
+ chunks.push({ type: "reasoning-delta", delta: delta.thinking });
761
+ } else if (delta.type === "signature_delta") {
762
+ const thinkingBlock = state.thinkingByIndex.get(event.index);
763
+ if (thinkingBlock) {
764
+ thinkingBlock.signature += delta.signature;
765
+ }
766
+ } else if (delta.type === "input_json_delta") {
767
+ const toolCall = state.toolCallsByIndex.get(event.index);
768
+ if (toolCall) {
769
+ toolCall.argumentsJson += delta.partial_json;
770
+ chunks.push({
771
+ type: "tool-call-delta",
772
+ id: toolCall.id,
773
+ argumentsDelta: delta.partial_json
774
+ });
775
+ } else {
776
+ const serverTool = state.serverToolsByIndex.get(event.index);
777
+ if (serverTool) {
778
+ serverTool.inputJson += delta.partial_json;
779
+ }
780
+ }
781
+ }
782
+ break;
783
+ }
784
+ case "content_block_stop": {
785
+ const toolCall = state.toolCallsByIndex.get(event.index);
786
+ if (toolCall) {
787
+ chunks.push({
788
+ type: "tool-call-done",
789
+ id: toolCall.id,
790
+ arguments: parseToolCallArguments(toolCall.argumentsJson)
791
+ });
792
+ state.toolCallsByIndex.delete(event.index);
793
+ break;
794
+ }
795
+ const thinkingBlock = state.thinkingByIndex.get(event.index);
796
+ if (thinkingBlock) {
797
+ state.reasoningDetails.push({
798
+ type: "text",
799
+ text: thinkingBlock.thinking,
800
+ data: thinkingBlock.signature,
801
+ format: THINKING_FORMAT
802
+ });
803
+ state.thinkingByIndex.delete(event.index);
804
+ break;
805
+ }
806
+ const serverTool = state.serverToolsByIndex.get(event.index);
807
+ if (serverTool) {
808
+ state.pendingServerTools.set(serverTool.id, {
809
+ name: serverTool.name,
810
+ input: parseToolCallArguments(serverTool.inputJson)
811
+ });
812
+ state.serverToolsByIndex.delete(event.index);
813
+ }
814
+ break;
815
+ }
816
+ case "message_delta": {
817
+ if (event.delta.stop_reason) {
818
+ state.finishReason = mapFinishReason(event.delta.stop_reason);
819
+ }
820
+ applyDeltaUsage(state, event.usage);
821
+ break;
822
+ }
823
+ case "message_stop": {
824
+ if (state.hasContent) {
825
+ chunks.push({ type: "content-done" });
826
+ }
827
+ if (state.hasReasoning) {
828
+ chunks.push({ type: "reasoning-done" });
829
+ }
830
+ const cost = calculateAnthropicUsageCost(state.model, state.buckets);
831
+ chunks.push({
832
+ type: "finish",
833
+ finishReason: state.finishReason,
834
+ usage: { ...state.usage, ...cost !== void 0 ? { cost } : {} },
835
+ ...state.reasoningDetails.length > 0 ? { reasoningDetails: [...state.reasoningDetails] } : {}
836
+ });
837
+ break;
838
+ }
839
+ default:
840
+ break;
841
+ }
842
+ return chunks;
843
+ }
844
+ function createErrorChunk(error, code) {
845
+ return { type: "error", error, code };
846
+ }
847
+ function isBase64Like(str) {
848
+ if (str.startsWith("data:")) return true;
849
+ if (str.length > 200) {
850
+ const base64Pattern = /^[A-Za-z0-9+/]+=*$/;
851
+ return base64Pattern.test(str.substring(0, 200));
852
+ }
853
+ return false;
854
+ }
855
+ function truncateBase64String(str, maxLength = 50) {
856
+ if (str.length <= maxLength) return str;
857
+ const preview = str.substring(0, maxLength);
858
+ return `${preview}...[truncated, ${str.length.toLocaleString()} chars]`;
859
+ }
860
+ function truncateBase64(obj, maxLength = 50) {
861
+ if (obj === null || obj === void 0) {
862
+ return obj;
863
+ }
864
+ if (typeof obj === "string") {
865
+ if (isBase64Like(obj)) {
866
+ return truncateBase64String(obj, maxLength);
867
+ }
868
+ return obj;
869
+ }
870
+ if (Array.isArray(obj)) {
871
+ return obj.map((item) => truncateBase64(item, maxLength));
872
+ }
873
+ if (typeof obj === "object") {
874
+ const result = {};
875
+ for (const [key, value] of Object.entries(obj)) {
876
+ result[key] = truncateBase64(value, maxLength);
877
+ }
878
+ return result;
879
+ }
880
+ return obj;
881
+ }
882
+
883
+ // src/icons.ts
884
+ var ANTHROPIC_ICON = `<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
885
+ <rect width="48" height="48" fill="#F0EFEA"/>
886
+ <path d="M32.84 10H26.72L37.88 38H44L32.84 10Z" fill="black"/>
887
+ <path d="M15.16 10L4 38H10.24L12.5224 32.12H24.1976L26.48 38H32.72L21.56 10H15.16ZM14.5408 26.92L18.36 17.08L22.1793 26.92H14.5408Z" fill="black"/>
888
+ </svg>`;
889
+ function svgToDataUri(svg) {
890
+ const encoded = encodeURIComponent(svg).replace(/'/g, "%27").replace(/"/g, "%22");
891
+ return `data:image/svg+xml,${encoded}`;
892
+ }
893
+ function normalizeIcon(icon) {
894
+ if (icon.startsWith("data:") || icon.endsWith(".svg") || icon.includes(".svg?")) {
895
+ return icon;
896
+ }
897
+ return svgToDataUri(icon);
898
+ }
899
+ function getAnthropicIconDataUri() {
900
+ return normalizeIcon(ANTHROPIC_ICON);
901
+ }
902
+
903
+ // src/AnthropicProvider.ts
904
+ function isObjectLike(value) {
905
+ return typeof value === "object" && value !== null;
906
+ }
907
+ function parseRetryAfter(headers) {
908
+ let raw;
909
+ if (isObjectLike(headers)) {
910
+ const get = headers.get;
911
+ if (typeof get === "function") {
912
+ raw = get.call(headers, "retry-after");
913
+ } else {
914
+ raw = headers["retry-after"];
915
+ }
916
+ }
917
+ if (typeof raw === "number") {
918
+ return raw;
919
+ }
920
+ if (typeof raw === "string") {
921
+ const parsed = parseInt(raw, 10);
922
+ return Number.isNaN(parsed) ? void 0 : parsed;
923
+ }
924
+ return void 0;
925
+ }
926
+ var ADAPTIVE_REASONING_LEVELS = DEFAULT_REASONING_LEVELS;
927
+ var BUDGET_REASONING_LEVELS = { 0: null, 100: "enabled" };
928
+ var NO_REASONING_LEVELS = { 0: null };
929
+ var AnthropicProvider = class _AnthropicProvider {
930
+ name = "anthropic";
931
+ specificationVersion = "1";
932
+ client = null;
933
+ config;
934
+ /** Cache for models list to avoid repeated API calls */
935
+ static modelsCache = null;
936
+ static modelsCacheTime = 0;
937
+ static CACHE_TTL = 5 * 60 * 1e3;
938
+ // 5 minutes
939
+ constructor(config) {
940
+ this.config = config;
941
+ }
942
+ async getClient() {
943
+ if (!this.client) {
944
+ const { default: Anthropic } = await import("@anthropic-ai/sdk");
945
+ this.client = new Anthropic({
946
+ apiKey: this.config.apiKey,
947
+ baseURL: this.config.baseUrl,
948
+ timeout: this.config.timeout
949
+ });
950
+ }
951
+ return this.client;
952
+ }
953
+ supportsModel(modelId) {
954
+ return modelId.startsWith("claude-");
955
+ }
956
+ /**
957
+ * Get the icon for this provider as a data URI.
958
+ * Always returns the Anthropic icon since all models are from Anthropic.
959
+ */
960
+ getIcon(_modelId) {
961
+ return getAnthropicIconDataUri();
962
+ }
963
+ // ============================================================================
964
+ // Model Capabilities
965
+ // ============================================================================
966
+ /**
967
+ * Capability mappings for Anthropic models, keyed by model ID prefix.
968
+ * Used as a fallback when the live Models API is unavailable; the API's
969
+ * capability listing takes precedence when reachable.
970
+ */
971
+ static MODEL_CAPABILITIES = {
972
+ "claude-fable-5": {
973
+ supportsImages: true,
974
+ supportsToolCalls: true,
975
+ supportsStreaming: true,
976
+ supportsJsonMode: true,
977
+ maxContextTokens: 1e6,
978
+ maxOutputTokens: 128e3,
979
+ reasoningLevels: ADAPTIVE_REASONING_LEVELS
980
+ },
981
+ "claude-mythos": {
982
+ supportsImages: true,
983
+ supportsToolCalls: true,
984
+ supportsStreaming: true,
985
+ supportsJsonMode: true,
986
+ maxContextTokens: 1e6,
987
+ maxOutputTokens: 128e3,
988
+ reasoningLevels: ADAPTIVE_REASONING_LEVELS
989
+ },
990
+ "claude-opus-4-8": {
991
+ supportsImages: true,
992
+ supportsToolCalls: true,
993
+ supportsStreaming: true,
994
+ supportsJsonMode: true,
995
+ maxContextTokens: 1e6,
996
+ maxOutputTokens: 128e3,
997
+ reasoningLevels: ADAPTIVE_REASONING_LEVELS
998
+ },
999
+ "claude-opus-4-7": {
1000
+ supportsImages: true,
1001
+ supportsToolCalls: true,
1002
+ supportsStreaming: true,
1003
+ supportsJsonMode: true,
1004
+ maxContextTokens: 1e6,
1005
+ maxOutputTokens: 128e3,
1006
+ reasoningLevels: ADAPTIVE_REASONING_LEVELS
1007
+ },
1008
+ "claude-opus-4-6": {
1009
+ supportsImages: true,
1010
+ supportsToolCalls: true,
1011
+ supportsStreaming: true,
1012
+ supportsJsonMode: true,
1013
+ maxContextTokens: 1e6,
1014
+ maxOutputTokens: 128e3,
1015
+ reasoningLevels: ADAPTIVE_REASONING_LEVELS
1016
+ },
1017
+ "claude-opus-4-5": {
1018
+ supportsImages: true,
1019
+ supportsToolCalls: true,
1020
+ supportsStreaming: true,
1021
+ supportsJsonMode: true,
1022
+ maxContextTokens: 2e5,
1023
+ maxOutputTokens: 64e3,
1024
+ reasoningLevels: BUDGET_REASONING_LEVELS
1025
+ },
1026
+ "claude-opus-4-1": {
1027
+ supportsImages: true,
1028
+ supportsToolCalls: true,
1029
+ supportsStreaming: true,
1030
+ supportsJsonMode: false,
1031
+ maxContextTokens: 2e5,
1032
+ maxOutputTokens: 32e3,
1033
+ reasoningLevels: BUDGET_REASONING_LEVELS
1034
+ },
1035
+ "claude-opus-4": {
1036
+ supportsImages: true,
1037
+ supportsToolCalls: true,
1038
+ supportsStreaming: true,
1039
+ supportsJsonMode: false,
1040
+ maxContextTokens: 2e5,
1041
+ maxOutputTokens: 32e3,
1042
+ reasoningLevels: BUDGET_REASONING_LEVELS
1043
+ },
1044
+ "claude-sonnet-4-6": {
1045
+ supportsImages: true,
1046
+ supportsToolCalls: true,
1047
+ supportsStreaming: true,
1048
+ supportsJsonMode: true,
1049
+ maxContextTokens: 1e6,
1050
+ maxOutputTokens: 64e3,
1051
+ reasoningLevels: ADAPTIVE_REASONING_LEVELS
1052
+ },
1053
+ "claude-sonnet-4-5": {
1054
+ supportsImages: true,
1055
+ supportsToolCalls: true,
1056
+ supportsStreaming: true,
1057
+ supportsJsonMode: true,
1058
+ maxContextTokens: 2e5,
1059
+ maxOutputTokens: 64e3,
1060
+ reasoningLevels: BUDGET_REASONING_LEVELS
1061
+ },
1062
+ "claude-sonnet-4": {
1063
+ supportsImages: true,
1064
+ supportsToolCalls: true,
1065
+ supportsStreaming: true,
1066
+ supportsJsonMode: false,
1067
+ maxContextTokens: 2e5,
1068
+ maxOutputTokens: 64e3,
1069
+ reasoningLevels: BUDGET_REASONING_LEVELS
1070
+ },
1071
+ "claude-haiku-4-5": {
1072
+ supportsImages: true,
1073
+ supportsToolCalls: true,
1074
+ supportsStreaming: true,
1075
+ supportsJsonMode: true,
1076
+ maxContextTokens: 2e5,
1077
+ maxOutputTokens: 64e3,
1078
+ reasoningLevels: BUDGET_REASONING_LEVELS
1079
+ },
1080
+ "claude-3-7-sonnet": {
1081
+ supportsImages: true,
1082
+ supportsToolCalls: true,
1083
+ supportsStreaming: true,
1084
+ supportsJsonMode: false,
1085
+ maxContextTokens: 2e5,
1086
+ maxOutputTokens: 64e3,
1087
+ reasoningLevels: BUDGET_REASONING_LEVELS
1088
+ },
1089
+ "claude-3-5-sonnet": {
1090
+ supportsImages: true,
1091
+ supportsToolCalls: true,
1092
+ supportsStreaming: true,
1093
+ supportsJsonMode: false,
1094
+ maxContextTokens: 2e5,
1095
+ maxOutputTokens: 8192,
1096
+ reasoningLevels: NO_REASONING_LEVELS
1097
+ },
1098
+ "claude-3-5-haiku": {
1099
+ supportsImages: true,
1100
+ supportsToolCalls: true,
1101
+ supportsStreaming: true,
1102
+ supportsJsonMode: false,
1103
+ maxContextTokens: 2e5,
1104
+ maxOutputTokens: 8192,
1105
+ reasoningLevels: NO_REASONING_LEVELS
1106
+ },
1107
+ "claude-3-opus": {
1108
+ supportsImages: true,
1109
+ supportsToolCalls: true,
1110
+ supportsStreaming: true,
1111
+ supportsJsonMode: false,
1112
+ maxContextTokens: 2e5,
1113
+ maxOutputTokens: 4096,
1114
+ reasoningLevels: NO_REASONING_LEVELS
1115
+ },
1116
+ "claude-3-haiku": {
1117
+ supportsImages: true,
1118
+ supportsToolCalls: true,
1119
+ supportsStreaming: true,
1120
+ supportsJsonMode: false,
1121
+ maxContextTokens: 2e5,
1122
+ maxOutputTokens: 4096,
1123
+ reasoningLevels: NO_REASONING_LEVELS
1124
+ }
1125
+ };
1126
+ /**
1127
+ * Look up static capabilities for a model by exact then prefix match.
1128
+ */
1129
+ static lookupStaticCapabilities(modelId) {
1130
+ if (_AnthropicProvider.MODEL_CAPABILITIES[modelId]) {
1131
+ return { ..._AnthropicProvider.MODEL_CAPABILITIES[modelId] };
1132
+ }
1133
+ let best = null;
1134
+ for (const [prefix, caps] of Object.entries(_AnthropicProvider.MODEL_CAPABILITIES)) {
1135
+ if (modelId.startsWith(prefix) && (!best || prefix.length > best.prefix.length)) {
1136
+ best = { prefix, caps };
1137
+ }
1138
+ }
1139
+ return best ? { ...best.caps } : null;
1140
+ }
1141
+ /**
1142
+ * Map a live Models API capability listing to Standard Agents capabilities.
1143
+ */
1144
+ static mapLiveCapabilities(model) {
1145
+ const caps = model.capabilities;
1146
+ if (!caps) return null;
1147
+ let reasoningLevels;
1148
+ if (caps.thinking.types.adaptive.supported && caps.effort.supported) {
1149
+ reasoningLevels = ADAPTIVE_REASONING_LEVELS;
1150
+ } else if (caps.thinking.supported) {
1151
+ reasoningLevels = BUDGET_REASONING_LEVELS;
1152
+ } else {
1153
+ reasoningLevels = NO_REASONING_LEVELS;
1154
+ }
1155
+ return {
1156
+ supportsImages: caps.image_input.supported,
1157
+ supportsToolCalls: true,
1158
+ supportsStreaming: true,
1159
+ supportsJsonMode: caps.structured_outputs.supported,
1160
+ ...model.max_input_tokens ? { maxContextTokens: model.max_input_tokens } : {},
1161
+ ...model.max_tokens ? { maxOutputTokens: model.max_tokens } : {},
1162
+ reasoningLevels
1163
+ };
1164
+ }
1165
+ /**
1166
+ * Get capabilities for a specific model.
1167
+ * Prefers the live Models API (which reports per-model capability flags)
1168
+ * and falls back to the static prefix table when the API is unreachable.
1169
+ */
1170
+ async getModelCapabilities(modelId) {
1171
+ try {
1172
+ const models = await this.fetchModelsWithCache();
1173
+ const model = models.find((m) => m.id === modelId);
1174
+ if (model) {
1175
+ const live = _AnthropicProvider.mapLiveCapabilities(model);
1176
+ if (live) {
1177
+ return live;
1178
+ }
1179
+ }
1180
+ } catch {
1181
+ }
1182
+ const staticCaps = _AnthropicProvider.lookupStaticCapabilities(modelId);
1183
+ if (staticCaps) {
1184
+ return staticCaps;
1185
+ }
1186
+ return {
1187
+ supportsImages: true,
1188
+ supportsToolCalls: true,
1189
+ supportsStreaming: true,
1190
+ supportsJsonMode: true,
1191
+ maxContextTokens: 2e5,
1192
+ maxOutputTokens: 8192,
1193
+ reasoningLevels: ADAPTIVE_REASONING_LEVELS
1194
+ };
1195
+ }
1196
+ // ============================================================================
1197
+ // Provider-Embedded Tools
1198
+ // ============================================================================
1199
+ /**
1200
+ * Provider-embedded tools using defineTool().
1201
+ * These are Anthropic's server-side tools that execute on Anthropic's
1202
+ * servers. The execute function is a no-op since execution is handled by
1203
+ * the provider; results surface as providerTools entries on the response.
1204
+ */
1205
+ static TOOLS = {
1206
+ web_search: defineTool({
1207
+ description: "Search the web for up-to-date information with citations",
1208
+ args: z.object({
1209
+ query: z.string().describe("Search query")
1210
+ }),
1211
+ execute: async (_state, _args) => {
1212
+ return { status: "success", result: "Handled by Anthropic" };
1213
+ },
1214
+ executionMode: "provider",
1215
+ executionProvider: "anthropic"
1216
+ })
1217
+ };
1218
+ /**
1219
+ * Get tools embedded in this provider.
1220
+ * Anthropic's web_search server tool is available on all current models.
1221
+ *
1222
+ * @param modelId - Optional filter to get tools available for a specific model
1223
+ * @returns Record of tool name to tool definition
1224
+ */
1225
+ getTools(_modelId) {
1226
+ return { ..._AnthropicProvider.TOOLS };
1227
+ }
1228
+ // ============================================================================
1229
+ // Model Listing
1230
+ // ============================================================================
1231
+ /**
1232
+ * Fetch models from the Anthropic Models API with caching.
1233
+ */
1234
+ async fetchModelsWithCache() {
1235
+ const now = Date.now();
1236
+ if (_AnthropicProvider.modelsCache && now - _AnthropicProvider.modelsCacheTime < _AnthropicProvider.CACHE_TTL) {
1237
+ return _AnthropicProvider.modelsCache;
1238
+ }
1239
+ const client = await this.getClient();
1240
+ const models = [];
1241
+ for await (const model of client.models.list({ limit: 100 })) {
1242
+ models.push(model);
1243
+ }
1244
+ _AnthropicProvider.modelsCache = models;
1245
+ _AnthropicProvider.modelsCacheTime = now;
1246
+ return models;
1247
+ }
1248
+ /**
1249
+ * Map Anthropic model info to ProviderModelInfo.
1250
+ */
1251
+ mapToProviderModelInfo(model) {
1252
+ const capabilities = _AnthropicProvider.mapLiveCapabilities(model) ?? _AnthropicProvider.lookupStaticCapabilities(model.id) ?? void 0;
1253
+ return {
1254
+ id: model.id,
1255
+ name: model.display_name,
1256
+ contextLength: model.max_input_tokens ?? capabilities?.maxContextTokens,
1257
+ iconId: this.getIcon(model.id),
1258
+ ...capabilities ? { capabilities } : {}
1259
+ };
1260
+ }
1261
+ /**
1262
+ * Get list of available models from Anthropic.
1263
+ * Fetches from the Models API with caching.
1264
+ *
1265
+ * @param filter - Optional search string to filter models by name/id
1266
+ */
1267
+ async getModels(filter) {
1268
+ try {
1269
+ const rawModels = await this.fetchModelsWithCache();
1270
+ let models = rawModels.map((m) => this.mapToProviderModelInfo(m));
1271
+ if (filter) {
1272
+ const lowerFilter = filter.toLowerCase();
1273
+ models = models.filter(
1274
+ (m) => m.id.toLowerCase().includes(lowerFilter) || m.name.toLowerCase().includes(lowerFilter)
1275
+ );
1276
+ }
1277
+ return models;
1278
+ } catch (error) {
1279
+ console.error("Failed to fetch models from Anthropic:", error);
1280
+ return [];
1281
+ }
1282
+ }
1283
+ // ============================================================================
1284
+ // Generation Methods
1285
+ // ============================================================================
1286
+ /**
1287
+ * Resolve the default max_tokens for a model from the static capability
1288
+ * table, clamped so non-streaming requests stay under HTTP timeouts.
1289
+ */
1290
+ defaultMaxTokensFor(modelId) {
1291
+ const caps = _AnthropicProvider.lookupStaticCapabilities(modelId);
1292
+ return Math.min(caps?.maxOutputTokens ?? 8192, 8192);
1293
+ }
1294
+ async generate(request) {
1295
+ const client = await this.getClient();
1296
+ try {
1297
+ const params = buildCreateParams(
1298
+ request,
1299
+ DEFAULT_REASONING_LEVELS,
1300
+ this.defaultMaxTokensFor(request.model)
1301
+ );
1302
+ const response = await client.messages.create(
1303
+ { ...params, stream: false },
1304
+ { signal: request.signal }
1305
+ );
1306
+ return transformResponse(response);
1307
+ } catch (error) {
1308
+ throw this.toProviderError(error);
1309
+ }
1310
+ }
1311
+ async stream(request) {
1312
+ const client = await this.getClient();
1313
+ const self = this;
1314
+ try {
1315
+ const params = buildCreateParams(
1316
+ request,
1317
+ DEFAULT_REASONING_LEVELS,
1318
+ this.defaultMaxTokensFor(request.model)
1319
+ );
1320
+ const stream = await client.messages.create(
1321
+ { ...params, stream: true },
1322
+ { signal: request.signal }
1323
+ );
1324
+ return {
1325
+ async *[Symbol.asyncIterator]() {
1326
+ const state = createStreamState();
1327
+ try {
1328
+ for await (const event of stream) {
1329
+ const chunks = processStreamEvent(event, state);
1330
+ for (const chunk of chunks) {
1331
+ yield chunk;
1332
+ }
1333
+ }
1334
+ } catch (error) {
1335
+ const providerError = self.toProviderError(error);
1336
+ yield createErrorChunk(providerError.message, providerError.code);
1337
+ }
1338
+ }
1339
+ };
1340
+ } catch (error) {
1341
+ throw this.toProviderError(error);
1342
+ }
1343
+ }
1344
+ // ============================================================================
1345
+ // Error Handling
1346
+ // ============================================================================
1347
+ toProviderError(error) {
1348
+ if (error instanceof ProviderError) {
1349
+ return error;
1350
+ }
1351
+ const record = isObjectLike(error) ? error : null;
1352
+ const status = typeof record?.status === "number" ? record.status : typeof record?.statusCode === "number" ? record.statusCode : void 0;
1353
+ const message = error instanceof Error ? error.message : String(error);
1354
+ if (status === 429) {
1355
+ return new ProviderError(message, "rate_limit", status, parseRetryAfter(record?.headers));
1356
+ }
1357
+ if (status === 401 || status === 403) {
1358
+ return new ProviderError(message, "auth_error", status);
1359
+ }
1360
+ if (status === 400 || status === 404 || status === 413) {
1361
+ return new ProviderError(message, "invalid_request", status);
1362
+ }
1363
+ if (status !== void 0 && status >= 500) {
1364
+ return new ProviderError(message, "server_error", status);
1365
+ }
1366
+ if (error instanceof Error && error.name === "AbortError" || record?.code === "ETIMEDOUT") {
1367
+ return new ProviderError(message, "timeout");
1368
+ }
1369
+ return new ProviderError(message, "unknown", status);
1370
+ }
1371
+ // ============================================================================
1372
+ // Inspection
1373
+ // ============================================================================
1374
+ /**
1375
+ * Transform a ProviderRequest to Anthropic Messages API format for inspection.
1376
+ * Returns the exact request body that would be sent, with base64 data truncated.
1377
+ */
1378
+ async inspectRequest(request) {
1379
+ const params = buildCreateParams(
1380
+ request,
1381
+ DEFAULT_REASONING_LEVELS,
1382
+ this.defaultMaxTokensFor(request.model)
1383
+ );
1384
+ const body = JSON.parse(JSON.stringify(params));
1385
+ return {
1386
+ body: truncateBase64(body),
1387
+ messagesPath: "messages",
1388
+ metadata: {
1389
+ endpoint: "messages.create"
1390
+ }
1391
+ };
1392
+ }
1393
+ };
1394
+
1395
+ // src/providerOptions.ts
1396
+ import { z as z2 } from "zod";
1397
+ var anthropicProviderOptions = z2.object({
1398
+ /** Request priority tier: 'auto' uses priority capacity when available, 'standard_only' opts out */
1399
+ service_tier: z2.enum(["auto", "standard_only"]).optional(),
1400
+ /** Request metadata. user_id is an opaque identifier for abuse monitoring */
1401
+ metadata: z2.object({
1402
+ user_id: z2.string().optional()
1403
+ }).optional(),
1404
+ /**
1405
+ * Cache the system prompt with a prompt-caching breakpoint.
1406
+ * Adds `cache_control: { type: 'ephemeral' }` to the system prompt so
1407
+ * repeated requests with the same prefix bill cached-input rates.
1408
+ */
1409
+ cacheSystemPrompt: z2.boolean().optional(),
1410
+ /**
1411
+ * Explicit thinking configuration override. When set, this takes precedence
1412
+ * over the thinking config derived from the request's reasoning level.
1413
+ * Accepts the Anthropic API shape, e.g. `{ type: 'adaptive' }` or
1414
+ * `{ type: 'enabled', budget_tokens: 8192 }`.
1415
+ */
1416
+ thinking: z2.record(z2.string(), z2.unknown()).optional()
1417
+ }).passthrough();
1418
+
1419
+ // src/index.ts
1420
+ var anthropic = Object.assign(
1421
+ (config) => new AnthropicProvider(config),
1422
+ { providerOptions: anthropicProviderOptions }
1423
+ );
1424
+ export {
1425
+ AnthropicProvider,
1426
+ anthropic,
1427
+ anthropicProviderOptions,
1428
+ calculateAnthropicUsageCost,
1429
+ extractUsageBuckets,
1430
+ getAnthropicModelPricing
1431
+ };
1432
+ //# sourceMappingURL=index.js.map