@byfriends/kosong 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,720 @@
1
+ import { a as APITimeoutError, o as ChatProviderError, s as normalizeAPIStatusError, t as APIConnectionError$1 } from "../errors-WFxxzL1B.mjs";
2
+ import { n as requireProviderApiKey, r as resolveAuthBackedClient, t as mergeRequestHeaders } from "../request-auth-DCWSyCKI.mjs";
3
+ import { t as getAnthropicModelCapability } from "../capability-registry-CMBuEYcf.mjs";
4
+ import Anthropic, { APIConnectionError, APIConnectionTimeoutError, APIError, AnthropicError } from "@anthropic-ai/sdk";
5
+ //#region src/providers/anthropic.ts
6
+ /**
7
+ * Normalize an Anthropic `stop_reason` string to the unified
8
+ * {@link FinishReason} enum.
9
+ *
10
+ * Source: `message.stop_reason` (non-stream) or the last `message_delta`
11
+ * event's `delta.stop_reason` (stream).
12
+ */
13
+ function normalizeAnthropicStopReason(raw) {
14
+ if (raw === null || raw === void 0) return {
15
+ finishReason: null,
16
+ rawFinishReason: null
17
+ };
18
+ switch (raw) {
19
+ case "end_turn":
20
+ case "stop_sequence": return {
21
+ finishReason: "completed",
22
+ rawFinishReason: raw
23
+ };
24
+ case "max_tokens": return {
25
+ finishReason: "truncated",
26
+ rawFinishReason: raw
27
+ };
28
+ case "tool_use": return {
29
+ finishReason: "tool_calls",
30
+ rawFinishReason: raw
31
+ };
32
+ case "pause_turn": return {
33
+ finishReason: "paused",
34
+ rawFinishReason: raw
35
+ };
36
+ case "refusal": return {
37
+ finishReason: "filtered",
38
+ rawFinishReason: raw
39
+ };
40
+ default: return {
41
+ finishReason: "other",
42
+ rawFinishReason: raw
43
+ };
44
+ }
45
+ }
46
+ const INTERLEAVED_THINKING_BETA = "interleaved-thinking-2025-05-14";
47
+ const FAMILY_VERSION_RE = /(?:opus|sonnet|haiku)[.-](\d+)[.-](\d{1,2})(?!\d)/;
48
+ const OPUS_VERSION_RE = /opus[.-](\d+)[.-](\d{1,2})(?!\d)/;
49
+ const ADAPTIVE_MIN_VERSION = {
50
+ major: 4,
51
+ minor: 6
52
+ };
53
+ /**
54
+ * Per-version default output ceilings sourced from Anthropic's Messages
55
+ * API model cards (platform.claude.com/docs/en/about-claude/models/overview).
56
+ * Values are the documented synchronous Messages-API maximum — we send
57
+ * the full ceiling because Claude 4 + interleaved-thinking shares this
58
+ * budget with encrypted reasoning, so anything below the documented cap
59
+ * can silently truncate mid-`tool_use`.
60
+ *
61
+ * Keys are `<family>-<major>[-<minor>]`. Lookups try the most specific
62
+ * key first, then fall back to the family/major-only entry, so an
63
+ * unrecognized minor version (e.g. a future `opus-4-10`) gets the
64
+ * family's baseline rather than the generic fallback.
65
+ */
66
+ const CEILING_BY_FAMILY_VERSION = {
67
+ "opus-4-7": 128e3,
68
+ "opus-4-6": 128e3,
69
+ "opus-4-5": 64e3,
70
+ "opus-4-1": 32e3,
71
+ "opus-4-0": 32e3,
72
+ "opus-4": 32e3,
73
+ "sonnet-4-6": 64e3,
74
+ "sonnet-4-5": 64e3,
75
+ "sonnet-4-0": 64e3,
76
+ "sonnet-4": 64e3,
77
+ "haiku-4-5": 64e3,
78
+ "haiku-4": 64e3,
79
+ "opus-3-5": 8192,
80
+ "sonnet-3-5": 8192,
81
+ "sonnet-3-7": 8192,
82
+ "haiku-3-5": 8192,
83
+ "opus-3": 4096,
84
+ "sonnet-3": 4096,
85
+ "haiku-3": 4096
86
+ };
87
+ const FALLBACK_MAX_TOKENS = 32e3;
88
+ const FAMILY_FIRST_RE = /(opus|sonnet|haiku)[-._](\d{1,2})(?!\d)(?:[-._](\d{1,2})(?!\d))?/;
89
+ const VERSION_FIRST_RE = /(\d{1,2})[-._](\d{1,2})[-._](opus|sonnet|haiku)/;
90
+ const BARE_FAMILY_RE = /(\d{1,2})[-._](opus|sonnet|haiku)/;
91
+ /**
92
+ * Extract Claude family + version from a model id.
93
+ *
94
+ * Designed to survive the naming variants we see across vendors:
95
+ * vendor prefixes (`anthropic.`, `aws/`, `openrouter/`,
96
+ * `online-`), suffixes (date stamps like `-20251001`, build tags
97
+ * like `-construct`, `-v1:0`), and `.` vs `-` separators between
98
+ * the family and version components.
99
+ *
100
+ * Returns `null` when the id contains no Claude marker or no
101
+ * recognizable family/version, in which case the resolver should fall
102
+ * back to the override or {@link FALLBACK_MAX_TOKENS}.
103
+ */
104
+ function parseClaudeVersion(model) {
105
+ const normalized = model.toLowerCase();
106
+ if (!normalized.includes("claude")) return null;
107
+ const familyFirst = FAMILY_FIRST_RE.exec(normalized);
108
+ if (familyFirst !== null) return {
109
+ family: familyFirst[1],
110
+ major: Number.parseInt(familyFirst[2], 10),
111
+ minor: familyFirst[3] !== void 0 ? Number.parseInt(familyFirst[3], 10) : null
112
+ };
113
+ const versionFirst = VERSION_FIRST_RE.exec(normalized);
114
+ if (versionFirst !== null) return {
115
+ major: Number.parseInt(versionFirst[1], 10),
116
+ minor: Number.parseInt(versionFirst[2], 10),
117
+ family: versionFirst[3]
118
+ };
119
+ const bare = BARE_FAMILY_RE.exec(normalized);
120
+ if (bare !== null) return {
121
+ major: Number.parseInt(bare[1], 10),
122
+ minor: null,
123
+ family: bare[2]
124
+ };
125
+ return null;
126
+ }
127
+ function lookupClaudeCeiling(version) {
128
+ const { family, major, minor } = version;
129
+ if (minor !== null) {
130
+ const exact = CEILING_BY_FAMILY_VERSION[`${family}-${major}-${minor}`];
131
+ if (exact !== void 0) return exact;
132
+ }
133
+ return CEILING_BY_FAMILY_VERSION[`${family}-${major}`];
134
+ }
135
+ /**
136
+ * Resolve the default `max_tokens` for an Anthropic request.
137
+ *
138
+ * Precedence:
139
+ * 1. Caller-provided `override` (e.g. `models.<alias>.maxOutputSize`
140
+ * from the harness config) — honored when present so users can
141
+ * intentionally lower the budget (handy for forcing truncation
142
+ * in tests) or raise it on a model we don't yet know about.
143
+ * 2. When the model id parses to a known Claude family + version,
144
+ * the override is clamped to the documented Messages-API ceiling
145
+ * so we never send a value the server would reject.
146
+ * 3. With no override and no recognized version, fall back to
147
+ * {@link FALLBACK_MAX_TOKENS}.
148
+ */
149
+ function resolveDefaultMaxTokens(model, override) {
150
+ const parsed = parseClaudeVersion(model);
151
+ const ceiling = parsed === null ? void 0 : lookupClaudeCeiling(parsed);
152
+ if (ceiling === void 0) return override ?? FALLBACK_MAX_TOKENS;
153
+ return override === void 0 ? ceiling : Math.min(override, ceiling);
154
+ }
155
+ function parseVersion(match) {
156
+ const majorRaw = match[1];
157
+ const minorRaw = match[2];
158
+ if (majorRaw === void 0 || minorRaw === void 0) throw new Error("Model version regex did not capture major and minor versions.");
159
+ return {
160
+ major: Number.parseInt(majorRaw, 10),
161
+ minor: Number.parseInt(minorRaw, 10)
162
+ };
163
+ }
164
+ function versionAtLeast(version, minimum) {
165
+ return version.major > minimum.major || version.major === minimum.major && version.minor >= minimum.minor;
166
+ }
167
+ function supportsAdaptiveThinking(model) {
168
+ const normalized = model.toLowerCase();
169
+ const match = FAMILY_VERSION_RE.exec(normalized);
170
+ if (match === null) return false;
171
+ return versionAtLeast(parseVersion(match), ADAPTIVE_MIN_VERSION);
172
+ }
173
+ function isOpus47(model) {
174
+ const match = OPUS_VERSION_RE.exec(model.toLowerCase());
175
+ if (match === null) return false;
176
+ const version = parseVersion(match);
177
+ return version.major === 4 && version.minor === 7;
178
+ }
179
+ function supportsEffortParam(model) {
180
+ if (supportsAdaptiveThinking(model)) return true;
181
+ const normalized = model.toLowerCase();
182
+ return normalized.includes("opus-4-5") || normalized.includes("opus-4.5");
183
+ }
184
+ function clampEffort(effort, model) {
185
+ if (effort === "off") return effort;
186
+ if (effort === "xhigh" && !isOpus47(model)) return "high";
187
+ if (effort === "max" && !supportsAdaptiveThinking(model)) return "high";
188
+ return effort;
189
+ }
190
+ function budgetTokensForEffort(effort) {
191
+ switch (effort) {
192
+ case "low": return 1024;
193
+ case "medium": return 4096;
194
+ case "high": return 32e3;
195
+ case "off":
196
+ case "xhigh":
197
+ case "max": throw new Error(`Unsupported budget-based thinking effort: ${effort}`);
198
+ }
199
+ throw new Error(`Unknown thinking effort: ${String(effort)}`);
200
+ }
201
+ const CACHE_CONTROL = { type: "ephemeral" };
202
+ /**
203
+ * Content block types that support cache_control injection.
204
+ */
205
+ const CACHEABLE_TYPES = new Set([
206
+ "text",
207
+ "image",
208
+ "document",
209
+ "search_result",
210
+ "tool_use",
211
+ "tool_result",
212
+ "server_tool_use",
213
+ "web_search_tool_result"
214
+ ]);
215
+ function injectCacheControlOnLastBlock(messages) {
216
+ const lastMessage = messages.at(-1);
217
+ if (lastMessage === void 0) return;
218
+ const content = lastMessage.content;
219
+ if (!Array.isArray(content) || content.length === 0) return;
220
+ const lastBlock = content.at(-1);
221
+ if (lastBlock === void 0) return;
222
+ if (CACHEABLE_TYPES.has(lastBlock.type)) lastBlock.cache_control = CACHE_CONTROL;
223
+ }
224
+ /**
225
+ * Check whether a MessageParam is a user message whose content consists
226
+ * entirely of `tool_result` blocks.
227
+ *
228
+ * Used to detect adjacent tool-result-only messages that must be merged
229
+ * before hitting the Anthropic wire. Per the Messages API parallel-tool-use
230
+ * spec, all `tool_result` blocks answering parallel `tool_use` calls must
231
+ * live in a single user message — splitting them across consecutive user
232
+ * messages fails on strict Anthropic-compatible backends (HTTP 400) and
233
+ * silently degrades parallel tool use on api.anthropic.com.
234
+ */
235
+ function isToolResultOnly(message) {
236
+ if (message.role !== "user") return false;
237
+ const content = message.content;
238
+ if (!Array.isArray(content) || content.length === 0) return false;
239
+ return content.every((block) => block.type === "tool_result");
240
+ }
241
+ const SUPPORTED_B64_MEDIA_TYPES = new Set([
242
+ "image/png",
243
+ "image/jpeg",
244
+ "image/gif",
245
+ "image/webp"
246
+ ]);
247
+ function imageUrlPartToAnthropic(url) {
248
+ if (url.startsWith("data:")) {
249
+ const parts = url.slice(5).split(";base64,", 2);
250
+ if (parts.length !== 2 || parts[0] === void 0 || parts[1] === void 0) throw new ChatProviderError(`Invalid data URL for image: ${url}`);
251
+ const mediaType = parts[0];
252
+ const data = parts[1];
253
+ if (!SUPPORTED_B64_MEDIA_TYPES.has(mediaType)) throw new ChatProviderError(`Unsupported media type for base64 image: ${mediaType}, url: ${url}`);
254
+ return {
255
+ type: "image",
256
+ source: {
257
+ type: "base64",
258
+ data,
259
+ media_type: mediaType
260
+ }
261
+ };
262
+ }
263
+ return {
264
+ type: "image",
265
+ source: {
266
+ type: "url",
267
+ url
268
+ }
269
+ };
270
+ }
271
+ function convertTool(tool) {
272
+ return {
273
+ name: tool.name,
274
+ description: tool.description,
275
+ input_schema: tool.parameters
276
+ };
277
+ }
278
+ function toolResultToBlock(toolCallId, content) {
279
+ const blocks = [];
280
+ for (const part of content) if (part.type === "text") {
281
+ if (part.text) blocks.push({
282
+ type: "text",
283
+ text: part.text
284
+ });
285
+ } else if (part.type === "image_url") blocks.push(imageUrlPartToAnthropic(part.imageUrl.url));
286
+ return {
287
+ type: "tool_result",
288
+ tool_use_id: toolCallId,
289
+ content: blocks
290
+ };
291
+ }
292
+ function convertMessage(message) {
293
+ const role = message.role;
294
+ if (role === "system") return {
295
+ role: "user",
296
+ content: [{
297
+ type: "text",
298
+ text: `<system>${message.content.filter((p) => p.type === "text").map((p) => p.text).join("\n")}</system>`
299
+ }]
300
+ };
301
+ if (role === "tool") {
302
+ if (message.toolCallId === void 0) throw new ChatProviderError("Tool message missing `toolCallId`.");
303
+ return {
304
+ role: "user",
305
+ content: [toolResultToBlock(message.toolCallId, message.content)]
306
+ };
307
+ }
308
+ const blocks = [];
309
+ for (const part of message.content) if (part.type === "text") blocks.push({
310
+ type: "text",
311
+ text: part.text
312
+ });
313
+ else if (part.type === "image_url") blocks.push(imageUrlPartToAnthropic(part.imageUrl.url));
314
+ else if (part.type === "think") {
315
+ if (part.encrypted === void 0) continue;
316
+ blocks.push({
317
+ type: "thinking",
318
+ thinking: part.think,
319
+ signature: part.encrypted
320
+ });
321
+ }
322
+ if (message.toolCalls.length > 0) for (const tc of message.toolCalls) {
323
+ let toolInput = {};
324
+ if (tc.arguments) try {
325
+ const parsed = JSON.parse(tc.arguments);
326
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) toolInput = parsed;
327
+ else throw new ChatProviderError("Tool call arguments must be a JSON object.");
328
+ } catch (error) {
329
+ if (error instanceof ChatProviderError) throw error;
330
+ throw new ChatProviderError("Tool call arguments must be valid JSON.");
331
+ }
332
+ blocks.push({
333
+ type: "tool_use",
334
+ id: tc.id,
335
+ name: tc.name,
336
+ input: toolInput
337
+ });
338
+ }
339
+ return {
340
+ role,
341
+ content: blocks
342
+ };
343
+ }
344
+ function convertAnthropicError(error) {
345
+ if (error instanceof APIConnectionTimeoutError) return new APITimeoutError(error.message);
346
+ if (error instanceof APIConnectionError) return new APIConnectionError$1(error.message);
347
+ if (error instanceof APIError && typeof error.status === "number") {
348
+ const reqId = error.requestID ?? null;
349
+ return normalizeAPIStatusError(error.status, error.message, reqId);
350
+ }
351
+ if (error instanceof AnthropicError) return new ChatProviderError(`Anthropic error: ${error.message}`);
352
+ if (error instanceof Error) return new ChatProviderError(`Error: ${error.message}`);
353
+ return new ChatProviderError(`Error: ${String(error)}`);
354
+ }
355
+ var AnthropicStreamedMessage = class {
356
+ _id = null;
357
+ _usage = {
358
+ inputOther: 0,
359
+ output: 0,
360
+ inputCacheRead: 0,
361
+ inputCacheCreation: 0
362
+ };
363
+ _finishReason = null;
364
+ _rawFinishReason = null;
365
+ _iter;
366
+ constructor(response, isStream) {
367
+ if (isStream) this._iter = this._convertStreamResponse(response);
368
+ else this._iter = this._convertNonStreamResponse(response);
369
+ }
370
+ get id() {
371
+ return this._id;
372
+ }
373
+ get usage() {
374
+ return this._usage;
375
+ }
376
+ get finishReason() {
377
+ return this._finishReason;
378
+ }
379
+ get rawFinishReason() {
380
+ return this._rawFinishReason;
381
+ }
382
+ async *[Symbol.asyncIterator]() {
383
+ yield* this._iter;
384
+ }
385
+ _captureStopReason(raw) {
386
+ const normalized = normalizeAnthropicStopReason(raw);
387
+ this._finishReason = normalized.finishReason;
388
+ this._rawFinishReason = normalized.rawFinishReason;
389
+ }
390
+ _extractUsage(usage) {
391
+ this._usage = {
392
+ inputOther: usage.input_tokens ?? 0,
393
+ output: usage.output_tokens ?? 0,
394
+ inputCacheRead: usage.cache_read_input_tokens ?? 0,
395
+ inputCacheCreation: usage.cache_creation_input_tokens ?? 0
396
+ };
397
+ }
398
+ async *_convertNonStreamResponse(response) {
399
+ this._id = response.id;
400
+ this._extractUsage(response.usage);
401
+ this._captureStopReason(response.stop_reason);
402
+ for (const block of response.content) switch (block.type) {
403
+ case "text":
404
+ if (block.text !== void 0) yield {
405
+ type: "text",
406
+ text: block.text
407
+ };
408
+ break;
409
+ case "thinking":
410
+ yield block.signature !== void 0 ? {
411
+ type: "think",
412
+ think: block.thinking ?? "",
413
+ encrypted: block.signature
414
+ } : {
415
+ type: "think",
416
+ think: block.thinking ?? ""
417
+ };
418
+ break;
419
+ case "redacted_thinking":
420
+ yield block.data !== void 0 ? {
421
+ type: "think",
422
+ think: "",
423
+ encrypted: block.data
424
+ } : {
425
+ type: "think",
426
+ think: ""
427
+ };
428
+ break;
429
+ case "tool_use":
430
+ yield {
431
+ type: "function",
432
+ id: block.id ?? crypto.randomUUID(),
433
+ name: block.name ?? "",
434
+ arguments: block.input !== void 0 ? JSON.stringify(block.input) : null
435
+ };
436
+ break;
437
+ }
438
+ }
439
+ async *_convertStreamResponse(response) {
440
+ const toolUseBlockIndexes = /* @__PURE__ */ new Set();
441
+ try {
442
+ for await (const event of response) {
443
+ const evt = event;
444
+ const eventType = evt["type"];
445
+ if (eventType === "message_start") {
446
+ const startEvt = evt;
447
+ this._id = startEvt.message.id;
448
+ this._extractUsage(startEvt.message.usage);
449
+ } else if (eventType === "content_block_start") {
450
+ const blockEvt = evt;
451
+ const block = blockEvt.content_block;
452
+ const blockIndex = blockEvt.index;
453
+ switch (block.type) {
454
+ case "text":
455
+ yield {
456
+ type: "text",
457
+ text: block.text
458
+ };
459
+ break;
460
+ case "thinking":
461
+ yield {
462
+ type: "think",
463
+ think: block.thinking
464
+ };
465
+ break;
466
+ case "redacted_thinking":
467
+ yield {
468
+ type: "think",
469
+ think: "",
470
+ encrypted: block.data
471
+ };
472
+ break;
473
+ case "tool_use":
474
+ toolUseBlockIndexes.add(blockIndex);
475
+ yield {
476
+ type: "function",
477
+ id: block.id,
478
+ name: block.name,
479
+ arguments: "",
480
+ _streamIndex: blockIndex
481
+ };
482
+ break;
483
+ }
484
+ } else if (eventType === "content_block_delta") {
485
+ const deltaEvt = evt;
486
+ const delta = deltaEvt.delta;
487
+ const blockIndex = deltaEvt.index;
488
+ switch (delta.type) {
489
+ case "text_delta":
490
+ yield {
491
+ type: "text",
492
+ text: delta.text
493
+ };
494
+ break;
495
+ case "thinking_delta":
496
+ yield {
497
+ type: "think",
498
+ think: delta.thinking
499
+ };
500
+ break;
501
+ case "input_json_delta":
502
+ yield {
503
+ type: "tool_call_part",
504
+ argumentsPart: delta.partial_json,
505
+ index: blockIndex
506
+ };
507
+ break;
508
+ case "signature_delta":
509
+ yield {
510
+ type: "think",
511
+ think: "",
512
+ encrypted: delta.signature
513
+ };
514
+ break;
515
+ }
516
+ } else if (eventType === "content_block_stop") {} else if (eventType === "message_delta") {
517
+ const deltaUsage = evt.usage;
518
+ if (deltaUsage !== void 0) {
519
+ if (typeof deltaUsage["output_tokens"] === "number") this._usage.output = deltaUsage["output_tokens"];
520
+ if (typeof deltaUsage["cache_read_input_tokens"] === "number") this._usage.inputCacheRead = deltaUsage["cache_read_input_tokens"];
521
+ if (typeof deltaUsage["cache_creation_input_tokens"] === "number") this._usage.inputCacheCreation = deltaUsage["cache_creation_input_tokens"];
522
+ if (typeof deltaUsage["input_tokens"] === "number") this._usage.inputOther = deltaUsage["input_tokens"];
523
+ }
524
+ const messageDeltaPayload = evt.delta;
525
+ if (messageDeltaPayload !== void 0 && "stop_reason" in messageDeltaPayload) this._captureStopReason(messageDeltaPayload["stop_reason"]);
526
+ }
527
+ }
528
+ } catch (error) {
529
+ throw convertAnthropicError(error);
530
+ }
531
+ }
532
+ };
533
+ var AnthropicChatProvider = class {
534
+ name = "anthropic";
535
+ _model;
536
+ _stream;
537
+ _client;
538
+ _generationKwargs;
539
+ _metadata;
540
+ _apiKey;
541
+ _baseUrl;
542
+ _defaultHeaders;
543
+ _clientFactory;
544
+ constructor(options) {
545
+ this._model = options.model;
546
+ this._stream = options.stream ?? true;
547
+ this._metadata = options.metadata;
548
+ const apiKey = options.apiKey ?? process.env["ANTHROPIC_API_KEY"];
549
+ this._apiKey = apiKey === void 0 || apiKey.length === 0 ? void 0 : apiKey;
550
+ this._baseUrl = options.baseUrl;
551
+ this._defaultHeaders = options.defaultHeaders;
552
+ this._clientFactory = options.clientFactory;
553
+ this._client = this._apiKey === void 0 ? void 0 : this._buildClient(this._apiKey);
554
+ this._generationKwargs = {
555
+ max_tokens: resolveDefaultMaxTokens(options.model, options.defaultMaxTokens),
556
+ betaFeatures: options.betaFeatures ?? [INTERLEAVED_THINKING_BETA]
557
+ };
558
+ }
559
+ get modelName() {
560
+ return this._model;
561
+ }
562
+ get thinkingEffort() {
563
+ const thinkingConfig = this._generationKwargs.thinking;
564
+ if (thinkingConfig === void 0 || thinkingConfig === null) return null;
565
+ if (thinkingConfig.type === "disabled") return "off";
566
+ if (thinkingConfig.type === "adaptive") {
567
+ const effort = this._generationKwargs.output_config?.effort;
568
+ if (effort === void 0 || effort === null) return "high";
569
+ switch (effort) {
570
+ case "low":
571
+ case "medium":
572
+ case "high":
573
+ case "xhigh":
574
+ case "max": return effort;
575
+ }
576
+ }
577
+ const budget = thinkingConfig.budget_tokens ?? 0;
578
+ if (budget <= 1024) return "low";
579
+ if (budget <= 4096) return "medium";
580
+ return "high";
581
+ }
582
+ get modelParameters() {
583
+ return {
584
+ model: this._model,
585
+ ...this._generationKwargs
586
+ };
587
+ }
588
+ getCapability(model) {
589
+ return getAnthropicModelCapability(model ?? this._model);
590
+ }
591
+ async generate(systemPrompt, tools, history, options) {
592
+ const system = systemPrompt ? [{
593
+ type: "text",
594
+ text: systemPrompt,
595
+ cache_control: CACHE_CONTROL
596
+ }] : void 0;
597
+ const messages = [];
598
+ for (const msg of history) {
599
+ const converted = convertMessage(msg);
600
+ const last = messages.at(-1);
601
+ if (last !== void 0 && isToolResultOnly(last) && isToolResultOnly(converted)) last.content = [...last.content, ...converted.content];
602
+ else messages.push(converted);
603
+ }
604
+ injectCacheControlOnLastBlock(messages);
605
+ const kwargs = {};
606
+ if (this._generationKwargs.max_tokens !== void 0) kwargs["max_tokens"] = this._generationKwargs.max_tokens;
607
+ if (this._generationKwargs.temperature !== void 0) kwargs["temperature"] = this._generationKwargs.temperature;
608
+ if (this._generationKwargs.top_k !== void 0) kwargs["top_k"] = this._generationKwargs.top_k;
609
+ if (this._generationKwargs.top_p !== void 0) kwargs["top_p"] = this._generationKwargs.top_p;
610
+ if (this._generationKwargs.thinking !== void 0) kwargs["thinking"] = this._generationKwargs.thinking;
611
+ if (this._generationKwargs.output_config !== void 0) kwargs["output_config"] = this._generationKwargs.output_config;
612
+ const betas = this._generationKwargs.betaFeatures ?? [];
613
+ const extraHeaders = {};
614
+ if (betas.length > 0) extraHeaders["anthropic-beta"] = betas.join(",");
615
+ const anthropicTools = tools.map((t) => convertTool(t));
616
+ if (anthropicTools.length > 0) {
617
+ const lastTool = anthropicTools.at(-1);
618
+ if (lastTool !== void 0) lastTool.cache_control = CACHE_CONTROL;
619
+ }
620
+ const createParams = {
621
+ model: this._model,
622
+ messages,
623
+ ...kwargs
624
+ };
625
+ if (system !== void 0) createParams["system"] = system;
626
+ if (anthropicTools.length > 0) createParams["tools"] = anthropicTools;
627
+ if (this._metadata !== void 0) createParams["metadata"] = this._metadata;
628
+ const requestOptions = {};
629
+ const headers = mergeRequestHeaders(extraHeaders, options?.auth?.headers);
630
+ if (headers !== void 0) requestOptions["headers"] = headers;
631
+ if (options?.signal) requestOptions["signal"] = options.signal;
632
+ const finalRequestOptions = Object.keys(requestOptions).length > 0 ? requestOptions : void 0;
633
+ const client = this._createClient(options?.auth);
634
+ if (this._stream) try {
635
+ return new AnthropicStreamedMessage(await client.messages.create({
636
+ ...createParams,
637
+ stream: true
638
+ }, finalRequestOptions), true);
639
+ } catch (error) {
640
+ throw convertAnthropicError(error);
641
+ }
642
+ try {
643
+ return new AnthropicStreamedMessage(await client.messages.create({
644
+ ...createParams,
645
+ stream: false
646
+ }, finalRequestOptions), false);
647
+ } catch (error) {
648
+ throw convertAnthropicError(error);
649
+ }
650
+ }
651
+ _createClient(auth) {
652
+ return resolveAuthBackedClient({
653
+ cachedClient: this._client,
654
+ clientFactory: this._clientFactory
655
+ }, auth, (a) => this._buildClient(requireProviderApiKey("AnthropicChatProvider", a, this._apiKey)));
656
+ }
657
+ _buildClient(apiKey) {
658
+ return new Anthropic({
659
+ apiKey,
660
+ baseURL: this._baseUrl,
661
+ defaultHeaders: this._defaultHeaders
662
+ });
663
+ }
664
+ withThinking(effort) {
665
+ if (effort === "off") {
666
+ let newBetas = [...this._generationKwargs.betaFeatures ?? []];
667
+ if (supportsAdaptiveThinking(this._model)) newBetas = newBetas.filter((b) => b !== INTERLEAVED_THINKING_BETA);
668
+ const clone = this._withGenerationKwargs({
669
+ thinking: { type: "disabled" },
670
+ betaFeatures: newBetas
671
+ });
672
+ delete clone._generationKwargs.output_config;
673
+ return clone;
674
+ }
675
+ const effectiveEffort = clampEffort(effort, this._model);
676
+ if (effectiveEffort === "off") throw new Error("Non-off thinking effort unexpectedly clamped to off.");
677
+ let newBetas = [...this._generationKwargs.betaFeatures ?? []];
678
+ if (supportsAdaptiveThinking(this._model)) {
679
+ newBetas = newBetas.filter((b) => b !== INTERLEAVED_THINKING_BETA);
680
+ return this._withGenerationKwargs({
681
+ thinking: {
682
+ type: "adaptive",
683
+ display: "summarized"
684
+ },
685
+ output_config: { effort: effectiveEffort },
686
+ betaFeatures: newBetas
687
+ });
688
+ }
689
+ const kwargs = {
690
+ thinking: {
691
+ type: "enabled",
692
+ budget_tokens: budgetTokensForEffort(effectiveEffort)
693
+ },
694
+ betaFeatures: newBetas
695
+ };
696
+ if (supportsEffortParam(this._model)) kwargs.output_config = { effort: effectiveEffort };
697
+ else kwargs.output_config = void 0;
698
+ const clone = this._withGenerationKwargs(kwargs);
699
+ if (!supportsEffortParam(this._model)) delete clone._generationKwargs.output_config;
700
+ return clone;
701
+ }
702
+ withGenerationKwargs(kwargs) {
703
+ return this._withGenerationKwargs(kwargs);
704
+ }
705
+ _withGenerationKwargs(kwargs) {
706
+ const clone = this._clone();
707
+ clone._generationKwargs = {
708
+ ...clone._generationKwargs,
709
+ ...kwargs
710
+ };
711
+ return clone;
712
+ }
713
+ _clone() {
714
+ const clone = Object.assign(Object.create(Object.getPrototypeOf(this)), this);
715
+ clone._generationKwargs = { ...this._generationKwargs };
716
+ return clone;
717
+ }
718
+ };
719
+ //#endregion
720
+ export { AnthropicChatProvider, convertAnthropicError, resolveDefaultMaxTokens };