@yukino.js/yukino 0.0.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.
Files changed (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +320 -0
  3. package/dist/acp-IVY5HZR4.js +14 -0
  4. package/dist/agent-QANDY7FO.js +4 -0
  5. package/dist/anthropic-6YLT4JZR.js +4 -0
  6. package/dist/bwrap-MLSZLWHD.js +4 -0
  7. package/dist/chunk-2LHY3FND.js +67 -0
  8. package/dist/chunk-3KKA6537.js +4 -0
  9. package/dist/chunk-3QL446GD.js +4 -0
  10. package/dist/chunk-4GE22WHI.js +4 -0
  11. package/dist/chunk-5VOCXSSX.js +5 -0
  12. package/dist/chunk-77W2UPS2.js +4 -0
  13. package/dist/chunk-7MKA3SHV.js +4 -0
  14. package/dist/chunk-AGSYLE4E.js +16 -0
  15. package/dist/chunk-CU3IISCC.js +4 -0
  16. package/dist/chunk-GYBJR2RB.js +65 -0
  17. package/dist/chunk-HLE7243Q.js +4 -0
  18. package/dist/chunk-HMZQYFYG.js +4 -0
  19. package/dist/chunk-JFKC4VCA.js +4 -0
  20. package/dist/chunk-K4BYVVW7.js +5 -0
  21. package/dist/chunk-KCMBAHWU.js +4 -0
  22. package/dist/chunk-L2BWSPCF.js +10 -0
  23. package/dist/chunk-MDPSQ6L7.js +44 -0
  24. package/dist/chunk-OFC2GD5K.js +4 -0
  25. package/dist/chunk-RAS3ORX3.js +164 -0
  26. package/dist/chunk-RCXKUD3Y.js +4 -0
  27. package/dist/chunk-SAJCBGHL.js +4 -0
  28. package/dist/chunk-SOO5OXX2.js +237 -0
  29. package/dist/chunk-T4O4GQVL.js +607 -0
  30. package/dist/chunk-UPNNYP7M.js +60 -0
  31. package/dist/chunk-VCIRD267.js +4 -0
  32. package/dist/chunk-VU3JWAJR.js +4 -0
  33. package/dist/chunk-VWUGGYUP.js +6 -0
  34. package/dist/chunk-XO7ITAWR.js +4 -0
  35. package/dist/devtools-YWVUN4HX.js +7 -0
  36. package/dist/esm-57CJEGGK.js +4 -0
  37. package/dist/esm-6L5BJ5GT.js +4 -0
  38. package/dist/esm-DIYJ5HX6.js +4 -0
  39. package/dist/esm-HW2JMFYC.js +4 -0
  40. package/dist/esm-RPR2GBJ2.js +4 -0
  41. package/dist/esm-YKAO4ES6.js +4 -0
  42. package/dist/esm-ZTIYTMTS.js +229 -0
  43. package/dist/getMachineId-bsd-E27XJQLX.js +4 -0
  44. package/dist/getMachineId-darwin-35UPAIXP.js +5 -0
  45. package/dist/getMachineId-linux-MKXIYT6A.js +4 -0
  46. package/dist/getMachineId-unsupported-ZXVGGFX2.js +4 -0
  47. package/dist/getMachineId-win-RNVIYJG5.js +4 -0
  48. package/dist/lib/agent-6FZX4P2Y.js +16 -0
  49. package/dist/lib/anthropic-IP23YZ3P.js +21 -0
  50. package/dist/lib/bwrap-2OL7VPSO.js +7 -0
  51. package/dist/lib/chunk-2VF3XTGH.js +3382 -0
  52. package/dist/lib/chunk-5DVQ64YL.js +619 -0
  53. package/dist/lib/chunk-5TGXH7BX.js +624 -0
  54. package/dist/lib/chunk-6OMQD7MK.js +591 -0
  55. package/dist/lib/chunk-AZRC67RW.js +512 -0
  56. package/dist/lib/chunk-F2YJG72O.js +150 -0
  57. package/dist/lib/chunk-FFM2LB4C.js +132 -0
  58. package/dist/lib/chunk-FLKB4BK7.js +50 -0
  59. package/dist/lib/chunk-I34MAQRE.js +255 -0
  60. package/dist/lib/chunk-KA6POJKI.js +889 -0
  61. package/dist/lib/chunk-MLKGABMK.js +9 -0
  62. package/dist/lib/chunk-O7ELJUEK.js +262 -0
  63. package/dist/lib/chunk-QYBQT2DM.js +655 -0
  64. package/dist/lib/chunk-YIWNQ7OA.js +47 -0
  65. package/dist/lib/index.d.ts +8581 -0
  66. package/dist/lib/index.js +15905 -0
  67. package/dist/lib/openai-EMJ6U4FW.js +15 -0
  68. package/dist/lib/permissions-KZ5ACZAX.js +19 -0
  69. package/dist/lib/providers-2CGZPBFI.js +9 -0
  70. package/dist/lib/sandbox-runtime-CCQ3X3SM.js +9 -0
  71. package/dist/lib/seatbelt-WO7YWKLR.js +7 -0
  72. package/dist/lib/tool-filter-CKHZUUBQ.js +21 -0
  73. package/dist/main.js +332 -0
  74. package/dist/node-634LOHDX.js +15 -0
  75. package/dist/openai-YXYO5OW6.js +34 -0
  76. package/dist/permissions-VCDMNX3L.js +4 -0
  77. package/dist/providers-HNMBGGW6.js +4 -0
  78. package/dist/sandbox-runtime-ELKAYRIL.js +4 -0
  79. package/dist/seatbelt-JOCANLYS.js +4 -0
  80. package/dist/server-ZHQILOBP.js +4 -0
  81. package/dist/src-43CPCEK2.js +12 -0
  82. package/dist/src-JBRNH4FA.js +4 -0
  83. package/dist/src-R4BSSIJJ.js +4 -0
  84. package/dist/src-X6JWWHHT.js +4 -0
  85. package/dist/tool-filter-BQZDV3TF.js +4 -0
  86. package/dist/turndown.es-NQ3KDXM7.js +83 -0
  87. package/package.json +146 -0
@@ -0,0 +1,624 @@
1
+ import {
2
+ normalizeToolResultContentBlock
3
+ } from "./chunk-F2YJG72O.js";
4
+ import {
5
+ AuthenticationError,
6
+ ContextTooLongError,
7
+ LLMError,
8
+ MIN_THINKING_ANSWER_TOKENS,
9
+ NetworkError,
10
+ RateLimitError,
11
+ clampThinkingLevel,
12
+ ensureToolPairing,
13
+ getMaxOutputTokens,
14
+ getSupportedThinkingLevels,
15
+ getThinkingLevel,
16
+ resolveAPIKey,
17
+ thinkingBudgetForLevel,
18
+ toAnthropicThinkingEffort,
19
+ toReasoningEffort
20
+ } from "./chunk-QYBQT2DM.js";
21
+ import {
22
+ MCP_TOOL_PREFIX,
23
+ isMcpToolLike
24
+ } from "./chunk-I34MAQRE.js";
25
+ import {
26
+ asErrorString,
27
+ asRecord,
28
+ asString,
29
+ contentToText,
30
+ createChildLogger,
31
+ isRecord,
32
+ strArg
33
+ } from "./chunk-6OMQD7MK.js";
34
+ import {
35
+ __export
36
+ } from "./chunk-MLKGABMK.js";
37
+
38
+ // src/llm/anthropic.ts
39
+ var anthropic_exports = {};
40
+ __export(anthropic_exports, {
41
+ AnthropicClient: () => AnthropicClient,
42
+ buildAnthropicMessages: () => buildAnthropicMessages,
43
+ fetchModelContextWindow: () => fetchModelContextWindow,
44
+ markLastUserTailForCache: () => markLastUserTailForCache,
45
+ markToolsForCache: () => markToolsForCache,
46
+ needsToolSearchBeta: () => needsToolSearchBeta
47
+ });
48
+ import Anthropic from "@anthropic-ai/sdk";
49
+ import { safeParseAsync, z } from "zod";
50
+
51
+ // src/mcp/strategy.ts
52
+ var strategy_exports = {};
53
+ __export(strategy_exports, {
54
+ CHARS_PER_TOKEN: () => CHARS_PER_TOKEN,
55
+ DEFAULT_EAGER_THRESHOLD_PERCENT: () => DEFAULT_EAGER_THRESHOLD_PERCENT,
56
+ NATIVE_TOOL_USE_BETA: () => NATIVE_TOOL_USE_BETA,
57
+ applyMode: () => applyMode,
58
+ decideAndApply: () => decideAndApply,
59
+ decideMode: () => decideMode,
60
+ estimateSchemaTokens: () => estimateSchemaTokens,
61
+ isOfficialAnthropicEndpoint: () => isOfficialAnthropicEndpoint,
62
+ measureSchemaChars: () => measureSchemaChars
63
+ });
64
+ var DEFAULT_EAGER_THRESHOLD_PERCENT = 10;
65
+ var CHARS_PER_TOKEN = 2.5;
66
+ var NATIVE_TOOL_USE_BETA = "advanced-tool-use-2025-11-20";
67
+ var OFFICIAL_HOSTS = /* @__PURE__ */ new Set(["api.anthropic.com"]);
68
+ var ENV_OVERRIDE = "YUKINO_MCP_LOADING";
69
+ function isOfficialAnthropicEndpoint(baseUrl) {
70
+ if (!baseUrl) {
71
+ return true;
72
+ }
73
+ try {
74
+ return OFFICIAL_HOSTS.has(new URL(baseUrl).hostname.toLowerCase());
75
+ } catch {
76
+ return false;
77
+ }
78
+ }
79
+ function estimateSchemaTokens(schemaChars) {
80
+ return Math.floor(schemaChars / CHARS_PER_TOKEN);
81
+ }
82
+ function decideMode(baseUrl, contextWindow, mcpSchemaChars, thresholdPercent = DEFAULT_EAGER_THRESHOLD_PERCENT) {
83
+ const override = (process.env[ENV_OVERRIDE] ?? "").trim().toLowerCase();
84
+ if (override === "eager" || override === "native" || override === "dispatch") {
85
+ return override;
86
+ }
87
+ if (mcpSchemaChars <= 0) {
88
+ return "eager";
89
+ }
90
+ const budget = contextWindow * thresholdPercent / 100;
91
+ if (estimateSchemaTokens(mcpSchemaChars) < budget) {
92
+ return "eager";
93
+ }
94
+ return isOfficialAnthropicEndpoint(baseUrl) ? "native" : "dispatch";
95
+ }
96
+ function measureSchemaChars(registry) {
97
+ let total = 0;
98
+ for (const tool of registry.listTools()) {
99
+ if (!tool.name.startsWith(MCP_TOOL_PREFIX)) {
100
+ continue;
101
+ }
102
+ try {
103
+ total += JSON.stringify(tool.schema()).length;
104
+ } catch {
105
+ total += tool.name.length + (tool.description?.length ?? 0);
106
+ }
107
+ }
108
+ return total;
109
+ }
110
+ function applyMode(registry, mode) {
111
+ registry.mcpLoadingMode = mode;
112
+ const eager = mode === "eager";
113
+ for (const tool of registry.listTools()) {
114
+ if (isMcpToolLike(tool) && typeof tool.setDeferLoading === "function") {
115
+ tool.setDeferLoading(!eager);
116
+ }
117
+ }
118
+ registry.exposeToolSearch = !eager;
119
+ registry.exposeMcpCall = mode === "dispatch";
120
+ }
121
+ function decideAndApply(registry, baseUrl, contextWindow) {
122
+ const mode = decideMode(baseUrl, contextWindow, measureSchemaChars(registry));
123
+ applyMode(registry, mode);
124
+ return mode;
125
+ }
126
+
127
+ // src/llm/anthropic.ts
128
+ function markToolsForCache(tools) {
129
+ for (let i = tools.length - 1; i >= 0; i--) {
130
+ const t = tools[i];
131
+ if (t.defer_loading === true) {
132
+ continue;
133
+ }
134
+ t.cache_control = { type: "ephemeral" };
135
+ return;
136
+ }
137
+ }
138
+ function needsToolSearchBeta(toolSchemas) {
139
+ return toolSchemas.some(
140
+ (schema) => "defer_loading" in schema && schema.defer_loading === true
141
+ );
142
+ }
143
+ function toAnthropicToolSchema(schema, useExplicitCustomType) {
144
+ if ("input_schema" in schema) {
145
+ const tool = schema;
146
+ const { cache_control: cacheControl, ...rest } = tool;
147
+ if (!useExplicitCustomType) {
148
+ delete rest.type;
149
+ }
150
+ return {
151
+ ...rest,
152
+ ...useExplicitCustomType ? { type: "custom" } : {},
153
+ ...tool.defer_loading !== true && cacheControl ? { cache_control: cacheControl } : {}
154
+ };
155
+ }
156
+ throw new Error(
157
+ "Anthropic received a tool schema serialized for another protocol."
158
+ );
159
+ }
160
+ var log = createChildLogger({ module: "llm" });
161
+ var MODEL_FETCH_TIMEOUT_MS = 3e3;
162
+ var ModelContextWindowResSchema = z.object({
163
+ max_input_tokens: z.coerce.number()
164
+ });
165
+ async function fetchModelContextWindow(config) {
166
+ if (config.protocol !== "anthropic") {
167
+ return 0;
168
+ }
169
+ const apiKey = resolveAPIKey(config);
170
+ const base = config.base_url.replace(/\/+$/, "");
171
+ const url = `${base}/v1/models/${encodeURIComponent(config.model)}`;
172
+ const controller = new AbortController();
173
+ const timer = setTimeout(() => {
174
+ controller.abort();
175
+ }, MODEL_FETCH_TIMEOUT_MS);
176
+ try {
177
+ const res = await fetch(url, {
178
+ method: "GET",
179
+ headers: {
180
+ "anthropic-version": "2023-06-01",
181
+ ...apiKey ? { "x-api-key": apiKey } : {}
182
+ },
183
+ signal: controller.signal
184
+ });
185
+ if (!res.ok) {
186
+ return 0;
187
+ }
188
+ const body = await res.json();
189
+ const { success, error, data } = await safeParseAsync(
190
+ ModelContextWindowResSchema,
191
+ body
192
+ );
193
+ if (!success) {
194
+ log.warn(
195
+ { message: error.message },
196
+ "model context window schema validation failed"
197
+ );
198
+ return 0;
199
+ }
200
+ const maxInputTokens = data.max_input_tokens;
201
+ return Math.max(maxInputTokens, 0);
202
+ } catch (err) {
203
+ log.error({ err }, "failed to fetch model context window");
204
+ return 0;
205
+ } finally {
206
+ clearTimeout(timer);
207
+ }
208
+ }
209
+ function userBlocksFor(content) {
210
+ if (typeof content === "string") {
211
+ return [{ type: "text", text: content }];
212
+ }
213
+ return content.map((raw) => {
214
+ const block = normalizeToolResultContentBlock(raw);
215
+ if (!block || block.type === "tool_reference") {
216
+ throw new Error(
217
+ `Unsupported user content block: ${strArg(raw, "type", "unknown")}`
218
+ );
219
+ }
220
+ return block;
221
+ });
222
+ }
223
+ function buildAnthropicMessages(messages) {
224
+ const result = [];
225
+ for (const m of messages) {
226
+ if (m.role === "assistant") {
227
+ const blocks = [];
228
+ if (m.thinkingBlocks) {
229
+ for (const tb of m.thinkingBlocks) {
230
+ blocks.push({
231
+ type: "thinking",
232
+ thinking: tb.thinking,
233
+ signature: tb.signature
234
+ });
235
+ }
236
+ }
237
+ const assistantText = typeof m.content === "string" ? m.content : contentToText(m.content);
238
+ if (assistantText) {
239
+ blocks.push({
240
+ type: "text",
241
+ text: assistantText
242
+ });
243
+ }
244
+ if (m.toolUses) {
245
+ for (const tu of m.toolUses) {
246
+ blocks.push({
247
+ type: "tool_use",
248
+ // tool use **request**
249
+ id: tu.toolUseId,
250
+ name: tu.toolName === "ComputerUse" ? "computer" : tu.toolName,
251
+ input: tu.arguments
252
+ });
253
+ }
254
+ }
255
+ if (blocks.length === 0) {
256
+ blocks.push({ type: "text", text: "" });
257
+ }
258
+ result.push({ role: "assistant", content: blocks });
259
+ } else if (m.toolResults && m.toolResults.length > 0) {
260
+ const blocks = [];
261
+ for (const tr of m.toolResults) {
262
+ blocks.push({
263
+ type: "tool_result",
264
+ // tool result
265
+ tool_use_id: tr.toolUseId,
266
+ is_error: tr.isError,
267
+ content: tr.contentBlocks?.length ? tr.contentBlocks : tr.content
268
+ });
269
+ }
270
+ if (m.content.length > 0) {
271
+ blocks.push(...userBlocksFor(m.content));
272
+ }
273
+ result.push({ role: "user", content: blocks });
274
+ } else {
275
+ if (result.length === 0) {
276
+ result.push({
277
+ role: "user",
278
+ content: userBlocksFor(m.content)
279
+ });
280
+ continue;
281
+ }
282
+ let canMerge = false;
283
+ const prev = result[result.length - 1];
284
+ let content = prev.content;
285
+ if (prev.role === "user" && (typeof content === "string" || Array.isArray(content) && content.length > 0 && // content[0].type !== "tool_result"
286
+ (content[0].type === "text" || content[0].type === "image"))) {
287
+ canMerge = true;
288
+ }
289
+ if (canMerge) {
290
+ if (typeof content === "string") {
291
+ content = prev.content = content.trim().length > 0 ? [
292
+ {
293
+ type: "text",
294
+ text: content
295
+ }
296
+ ] : [];
297
+ }
298
+ content.push(...userBlocksFor(m.content));
299
+ } else {
300
+ result.push({
301
+ role: "user",
302
+ content: userBlocksFor(m.content)
303
+ });
304
+ }
305
+ }
306
+ }
307
+ return result;
308
+ }
309
+ var AnthropicClient = class {
310
+ protocol = "anthropic";
311
+ client;
312
+ model;
313
+ /** Effective logical level for budget or explicitly configured adaptive mode. */
314
+ thinkingLevel;
315
+ systemPrompt;
316
+ maxOutputTokens;
317
+ config;
318
+ useExplicitCustomToolType;
319
+ constructor(config, systemPrompt) {
320
+ const apiKey = resolveAPIKey(config);
321
+ if (!apiKey) {
322
+ throw new AuthenticationError(
323
+ "Anthropic API key not found, set ANTHROPIC_API_KEY in ~/.yukino/config.yaml, or via ANTHROPIC_API_KEY env variable."
324
+ );
325
+ }
326
+ this.client = new Anthropic({
327
+ apiKey,
328
+ baseURL: config.base_url
329
+ });
330
+ this.useExplicitCustomToolType = isOfficialAnthropicEndpoint(
331
+ config.base_url
332
+ );
333
+ this.model = config.model;
334
+ this.config = { ...config };
335
+ this.thinkingLevel = getThinkingLevel(config);
336
+ this.systemPrompt = systemPrompt;
337
+ this.maxOutputTokens = getMaxOutputTokens(config);
338
+ }
339
+ setSystemPrompt(prompt) {
340
+ this.systemPrompt = prompt;
341
+ }
342
+ setMaxOutputTokens(maxTokens) {
343
+ this.config = { ...this.config, max_output_tokens: maxTokens };
344
+ this.maxOutputTokens = getMaxOutputTokens(this.config);
345
+ this.setThinkingLevel(this.thinkingLevel);
346
+ }
347
+ setThinkingLevel(level) {
348
+ this.thinkingLevel = clampThinkingLevel(this.config, level);
349
+ return this.thinkingLevel;
350
+ }
351
+ getThinkingLevel() {
352
+ return this.thinkingLevel;
353
+ }
354
+ getSupportedThinkingLevels() {
355
+ return getSupportedThinkingLevels(this.config);
356
+ }
357
+ async *stream(conversation, toolSchemas, abortSignal) {
358
+ const messages = buildAnthropicMessages(
359
+ ensureToolPairing(conversation.getMessages())
360
+ );
361
+ const sendToolSearchBeta = needsToolSearchBeta(toolSchemas);
362
+ const antToolSchemas = toolSchemas.map(
363
+ (schema) => toAnthropicToolSchema(schema, this.useExplicitCustomToolType)
364
+ );
365
+ markToolsForCache(antToolSchemas);
366
+ markLastUserTailForCache(messages);
367
+ const params = {
368
+ model: this.model,
369
+ max_tokens: this.maxOutputTokens,
370
+ stream: true,
371
+ system: [
372
+ {
373
+ type: "text",
374
+ text: this.systemPrompt,
375
+ cache_control: {
376
+ type: "ephemeral"
377
+ // Prompt cache
378
+ }
379
+ }
380
+ ],
381
+ messages,
382
+ ...antToolSchemas.length > 0 ? (
383
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
384
+ { tools: antToolSchemas }
385
+ ) : {}
386
+ };
387
+ const level = this.getThinkingLevel();
388
+ if (this.config.reasoning !== false) {
389
+ if (level === "off") {
390
+ params.thinking = { type: "disabled" };
391
+ } else if (this.config.thinking_mode === "adaptive") {
392
+ const effort = toAnthropicThinkingEffort(level, this.config);
393
+ if (effort !== null) {
394
+ params.thinking = { type: "adaptive" };
395
+ params.output_config = { effort };
396
+ }
397
+ } else {
398
+ const effort = toReasoningEffort(level, this.config);
399
+ if (effort !== null && effort !== "none") {
400
+ params.thinking = {
401
+ type: "enabled",
402
+ budget_tokens: Math.min(
403
+ thinkingBudgetForLevel(effort),
404
+ this.maxOutputTokens - MIN_THINKING_ANSWER_TOKENS
405
+ )
406
+ };
407
+ }
408
+ }
409
+ }
410
+ let inputTokens = 0;
411
+ let outputTokens = 0;
412
+ let cacheReadInputTokens = 0;
413
+ let cacheCreationInputTokens = 0;
414
+ let stopReason = "end_turn";
415
+ let thinkingAccumulate = "";
416
+ let thinkingSignature = "";
417
+ let inThinking = false;
418
+ try {
419
+ const betas = [...sendToolSearchBeta ? [NATIVE_TOOL_USE_BETA] : []];
420
+ const response = this.client.messages.stream(params, {
421
+ ...abortSignal ? { signal: abortSignal } : {},
422
+ ...betas.length > 0 ? { headers: { "anthropic-beta": betas.join(",") } } : {}
423
+ });
424
+ let currentToolName = "";
425
+ let currentToolId = "";
426
+ let jsonAccumulate = "";
427
+ for await (const event of response) {
428
+ switch (event.type) {
429
+ case "content_block_start": {
430
+ const block = event.content_block;
431
+ if (block.type === "thinking") {
432
+ inThinking = true;
433
+ thinkingAccumulate = "";
434
+ thinkingSignature = "";
435
+ } else if (block.type === "tool_use") {
436
+ currentToolId = block.id;
437
+ currentToolName = block.name === "computer" ? "ComputerUse" : block.name;
438
+ jsonAccumulate = "";
439
+ yield {
440
+ type: "tool_call_start",
441
+ toolName: currentToolName,
442
+ toolId: currentToolId
443
+ };
444
+ }
445
+ break;
446
+ }
447
+ // end case "content_block_start"
448
+ case "content_block_delta": {
449
+ const delta = event.delta;
450
+ if (delta.type === "thinking_delta") {
451
+ thinkingAccumulate += delta.thinking;
452
+ yield {
453
+ type: "thinking_delta",
454
+ text: delta.thinking
455
+ };
456
+ } else if (delta.type === "signature_delta") {
457
+ thinkingSignature += delta.signature;
458
+ } else if (delta.type === "text_delta") {
459
+ yield {
460
+ type: "text_delta",
461
+ text: delta.text
462
+ };
463
+ } else if (delta.type === "input_json_delta") {
464
+ jsonAccumulate += delta.partial_json;
465
+ yield {
466
+ type: "tool_call_delta",
467
+ text: delta.partial_json
468
+ };
469
+ }
470
+ break;
471
+ }
472
+ // end case "content_block_delta"
473
+ case "content_block_stop": {
474
+ if (inThinking) {
475
+ yield {
476
+ type: "thinking_complete",
477
+ thinking: thinkingAccumulate,
478
+ signature: thinkingSignature
479
+ };
480
+ inThinking = false;
481
+ }
482
+ if (currentToolName) {
483
+ let args = {};
484
+ if (jsonAccumulate) {
485
+ try {
486
+ const parsed = JSON.parse(jsonAccumulate);
487
+ args = isRecord(parsed) ? asRecord(parsed) : {};
488
+ } catch (err) {
489
+ log.error({ err }, "llm operation failed");
490
+ args = {};
491
+ }
492
+ }
493
+ yield {
494
+ type: "tool_call_complete",
495
+ toolId: currentToolId,
496
+ toolName: currentToolName,
497
+ arguments: args
498
+ };
499
+ currentToolName = "";
500
+ currentToolId = "";
501
+ jsonAccumulate = "";
502
+ }
503
+ break;
504
+ }
505
+ // end case "content_block_stop"
506
+ case "message_delta": {
507
+ if (event.delta.stop_reason) {
508
+ stopReason = event.delta.stop_reason;
509
+ }
510
+ if (event.usage.output_tokens) {
511
+ outputTokens = event.usage.output_tokens;
512
+ if (event.usage.input_tokens) {
513
+ inputTokens = event.usage.input_tokens;
514
+ }
515
+ if (event.usage.cache_read_input_tokens) {
516
+ cacheReadInputTokens = event.usage.cache_read_input_tokens;
517
+ }
518
+ if (event.usage.cache_creation_input_tokens) {
519
+ cacheCreationInputTokens = event.usage.cache_creation_input_tokens;
520
+ }
521
+ }
522
+ break;
523
+ }
524
+ // end case "message_delta"
525
+ case "message_start": {
526
+ inputTokens = event.message.usage.input_tokens;
527
+ outputTokens = event.message.usage.output_tokens;
528
+ cacheReadInputTokens = event.message.usage.cache_read_input_tokens ?? 0;
529
+ cacheCreationInputTokens = event.message.usage.cache_creation_input_tokens ?? 0;
530
+ break;
531
+ }
532
+ }
533
+ }
534
+ yield {
535
+ type: "stream_end",
536
+ stopReason,
537
+ usage: {
538
+ inputTokens,
539
+ outputTokens,
540
+ cacheReadInputTokens,
541
+ cacheCreationInputTokens
542
+ }
543
+ };
544
+ } catch (err) {
545
+ log.error({ err }, "llm operation failed");
546
+ throw classifyAnthropicError(err);
547
+ }
548
+ }
549
+ };
550
+ function markLastUserTailForCache(messages) {
551
+ for (let i = messages.length - 1; i >= 0; i--) {
552
+ if (messages[i].role !== "user") {
553
+ continue;
554
+ }
555
+ let content = messages[i].content;
556
+ if (typeof content === "string" && content.length === 0 || Array.isArray(content) && content.length === 0) {
557
+ return;
558
+ }
559
+ if (typeof content === "string") {
560
+ content = messages[i].content = [
561
+ {
562
+ type: "text",
563
+ text: content
564
+ }
565
+ ];
566
+ }
567
+ let last = content[content.length - 1];
568
+ for (let j = content.length - 1; j >= 0; j--) {
569
+ if (content[j].type !== "image") {
570
+ last = content[j];
571
+ break;
572
+ }
573
+ }
574
+ Reflect.set(last, "cache_control", {
575
+ type: "ephemeral"
576
+ });
577
+ return;
578
+ }
579
+ }
580
+ function classifyAnthropicError(err) {
581
+ if (err instanceof Anthropic.APIError) {
582
+ if (err.status === 413 /* PromptTooLong */ || /prompts?\s+too\s+long/i.test(err.message)) {
583
+ return new ContextTooLongError(`Prompt too long: ${err.message}`);
584
+ }
585
+ if (err.status === 401 /* InvalidAPIKey */) {
586
+ return new AuthenticationError(`Invalid API key: ${err.message}`);
587
+ }
588
+ if (err.status === 429 /* RateLimitError */) {
589
+ const headers = err.headers;
590
+ const retryAfter = headers instanceof Headers ? headers.get("retry-after") : void 0;
591
+ let message = "Rate Limited";
592
+ if (retryAfter) {
593
+ const s = Number.parseInt(asString(retryAfter));
594
+ if (Number.isNaN(s)) {
595
+ message += ", please wait.";
596
+ } else {
597
+ message += `, retry after ${asString(s)}s.`;
598
+ }
599
+ } else {
600
+ message += ", please wait.";
601
+ }
602
+ return new RateLimitError(
603
+ message,
604
+ retryAfter ? asString(retryAfter) : void 0
605
+ );
606
+ }
607
+ return new LLMError(
608
+ `Anthropic API error (${asString(err.status)}): ${err.message}`
609
+ );
610
+ }
611
+ return new NetworkError(`Network error: ${asErrorString(err)}`);
612
+ }
613
+
614
+ export {
615
+ decideAndApply,
616
+ strategy_exports,
617
+ markToolsForCache,
618
+ needsToolSearchBeta,
619
+ fetchModelContextWindow,
620
+ buildAnthropicMessages,
621
+ AnthropicClient,
622
+ markLastUserTailForCache,
623
+ anthropic_exports
624
+ };