@aigne/anthropic 0.14.16-beta.2 → 0.14.16-beta.4

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/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.14.16-beta.4](https://github.com/AIGNE-io/aigne-framework/compare/anthropic-v0.14.16-beta.3...anthropic-v0.14.16-beta.4) (2025-12-24)
4
+
5
+
6
+ ### Dependencies
7
+
8
+ * The following workspace dependencies were updated
9
+ * dependencies
10
+ * @aigne/core bumped to 1.72.0-beta.4
11
+ * devDependencies
12
+ * @aigne/test-utils bumped to 0.5.69-beta.4
13
+
14
+ ## [0.14.16-beta.3](https://github.com/AIGNE-io/aigne-framework/compare/anthropic-v0.14.16-beta.2...anthropic-v0.14.16-beta.3) (2025-12-19)
15
+
16
+
17
+ ### Features
18
+
19
+ * add prompt caching for OpenAI/Gemini/Anthropic and cache token display ([#838](https://github.com/AIGNE-io/aigne-framework/issues/838)) ([46c628f](https://github.com/AIGNE-io/aigne-framework/commit/46c628f180572ea1b955d1a9888aad6145204842))
20
+
21
+
22
+ ### Dependencies
23
+
24
+ * The following workspace dependencies were updated
25
+ * dependencies
26
+ * @aigne/core bumped to 1.72.0-beta.3
27
+ * devDependencies
28
+ * @aigne/test-utils bumped to 0.5.69-beta.3
29
+
3
30
  ## [0.14.16-beta.2](https://github.com/AIGNE-io/aigne-framework/compare/anthropic-v0.14.16-beta.1...anthropic-v0.14.16-beta.2) (2025-12-19)
4
31
 
5
32
 
@@ -124,6 +124,9 @@ export declare class AnthropicChatModel extends ChatModel {
124
124
  reasoningEffort?: number | "minimal" | "low" | "medium" | "high" | {
125
125
  $get: string;
126
126
  } | undefined;
127
+ cacheConfig?: import("@aigne/core").CacheConfig | {
128
+ $get: string;
129
+ } | undefined;
127
130
  }> | undefined;
128
131
  get credential(): {
129
132
  apiKey: string | undefined;
@@ -166,10 +166,12 @@ class AnthropicChatModel extends core_1.ChatModel {
166
166
  model = chunk.message.model;
167
167
  controller.enqueue({ delta: { json: { model } } });
168
168
  }
169
- const { input_tokens, output_tokens } = chunk.message.usage;
169
+ const { input_tokens, output_tokens, cache_creation_input_tokens, cache_read_input_tokens, } = chunk.message.usage;
170
170
  usage = {
171
171
  inputTokens: input_tokens,
172
172
  outputTokens: output_tokens,
173
+ cacheCreationInputTokens: cache_creation_input_tokens ?? undefined,
174
+ cacheReadInputTokens: cache_read_input_tokens ?? undefined,
173
175
  };
174
176
  }
175
177
  if (chunk.type === "message_delta" && usage) {
@@ -261,14 +263,40 @@ class AnthropicChatModel extends core_1.ChatModel {
261
263
  }
262
264
  }
263
265
  exports.AnthropicChatModel = AnthropicChatModel;
264
- async function convertMessages({ messages, responseFormat, tools }) {
265
- const systemMessages = [];
266
+ /**
267
+ * Parse cache configuration from model options
268
+ */
269
+ function parseCacheConfig(modelOptions) {
270
+ const cacheConfig = modelOptions?.cacheConfig || {};
271
+ const shouldCache = cacheConfig.enabled !== false; // Default: enabled
272
+ const ttl = cacheConfig.ttl === "1h" ? "1h" : "5m"; // Default: 5m
273
+ const strategy = cacheConfig.strategy || "auto"; // Default: auto
274
+ const autoBreakpoints = {
275
+ tools: cacheConfig.autoBreakpoints?.tools !== false, // Default: true
276
+ system: cacheConfig.autoBreakpoints?.system !== false, // Default: true
277
+ lastMessage: cacheConfig.autoBreakpoints?.lastMessage === true, // Default: false
278
+ };
279
+ return {
280
+ shouldCache,
281
+ ttl,
282
+ strategy,
283
+ autoBreakpoints,
284
+ };
285
+ }
286
+ async function convertMessages({ messages, responseFormat, tools, modelOptions, }) {
287
+ const systemBlocks = [];
266
288
  const msgs = [];
289
+ // Extract cache configuration with defaults
290
+ const { shouldCache, ttl, strategy, autoBreakpoints } = parseCacheConfig(modelOptions);
267
291
  for (const msg of messages) {
268
292
  if (msg.role === "system") {
269
293
  if (typeof msg.content !== "string")
270
294
  throw new Error("System message must have content");
271
- systemMessages.push(msg.content);
295
+ const block = {
296
+ type: "text",
297
+ text: msg.content,
298
+ };
299
+ systemBlocks.push(block);
272
300
  }
273
301
  else if (msg.role === "tool") {
274
302
  if (!msg.toolCallId)
@@ -314,16 +342,48 @@ async function convertMessages({ messages, responseFormat, tools }) {
314
342
  // If there are tools and responseFormat is json_schema, we need to add a system message
315
343
  // to inform the model about the expected json schema, then trying to parse the response as json
316
344
  if (tools?.length && responseFormat?.type === "json_schema") {
317
- systemMessages.push(`You should provide a json response with schema: ${JSON.stringify(responseFormat.jsonSchema.schema)}`);
345
+ systemBlocks.push({
346
+ type: "text",
347
+ text: `You should provide a json response with schema: ${JSON.stringify(responseFormat.jsonSchema.schema)}`,
348
+ });
349
+ }
350
+ // Apply cache_control to the last system block if auto strategy is enabled
351
+ if (shouldCache && strategy === "auto" && autoBreakpoints.system && systemBlocks.length > 0) {
352
+ const lastBlock = systemBlocks[systemBlocks.length - 1];
353
+ if (lastBlock) {
354
+ lastBlock.cache_control = { type: "ephemeral" };
355
+ if (ttl === "1h") {
356
+ lastBlock.cache_control = { type: "ephemeral", ttl: "1h" };
357
+ }
358
+ }
359
+ }
360
+ // Manual cache control: apply user-specified cacheControl from system messages
361
+ if (shouldCache && strategy === "manual") {
362
+ for (const [index, msg] of messages.entries()) {
363
+ const msgWithCache = msg;
364
+ if (msg.role === "system" && msgWithCache.cacheControl) {
365
+ const block = systemBlocks[index];
366
+ if (block) {
367
+ block.cache_control = {
368
+ type: msgWithCache.cacheControl.type,
369
+ ...(msgWithCache.cacheControl.ttl && { ttl: msgWithCache.cacheControl.ttl }),
370
+ };
371
+ }
372
+ }
373
+ }
318
374
  }
319
- const system = systemMessages.join("\n").trim() || undefined;
320
375
  // Claude requires at least one message, so we add a system message if there are no messages
321
376
  if (msgs.length === 0) {
322
- if (!system)
377
+ if (systemBlocks.length === 0)
323
378
  throw new Error("No messages provided");
324
- return { messages: [{ role: "user", content: system }] };
379
+ // Convert system blocks to a single user message
380
+ const systemText = systemBlocks.map((b) => b.text).join("\n");
381
+ return { messages: [{ role: "user", content: systemText }] };
325
382
  }
326
- return { messages: msgs, system };
383
+ return {
384
+ messages: msgs,
385
+ system: systemBlocks.length > 0 ? systemBlocks : undefined,
386
+ };
327
387
  }
328
388
  async function convertContent(content) {
329
389
  if (typeof content === "string")
@@ -348,7 +408,7 @@ async function convertContent(content) {
348
408
  }
349
409
  throw new Error("Invalid chat message content");
350
410
  }
351
- function convertTools({ tools, toolChoice, disableParallelToolUse, }) {
411
+ function convertTools({ tools, toolChoice, disableParallelToolUse, modelOptions, }) {
352
412
  let choice;
353
413
  if (typeof toolChoice === "object" && "type" in toolChoice && toolChoice.type === "function") {
354
414
  choice = {
@@ -369,15 +429,38 @@ function convertTools({ tools, toolChoice, disableParallelToolUse, }) {
369
429
  else if (toolChoice === "none") {
370
430
  choice = { type: "none" };
371
431
  }
432
+ // Extract cache configuration with defaults
433
+ const { shouldCache, ttl, strategy, autoBreakpoints } = parseCacheConfig(modelOptions);
434
+ const shouldCacheTools = shouldCache && strategy === "auto" && autoBreakpoints.tools;
372
435
  return {
373
436
  tools: tools?.length
374
- ? tools.map((i) => ({
375
- name: i.function.name,
376
- description: i.function.description,
377
- input_schema: (0, type_utils_js_1.isEmpty)(i.function.parameters)
378
- ? { type: "object" }
379
- : i.function.parameters,
380
- }))
437
+ ? tools.map((i, index, arr) => {
438
+ const tool = {
439
+ name: i.function.name,
440
+ description: i.function.description,
441
+ input_schema: (0, type_utils_js_1.isEmpty)(i.function.parameters)
442
+ ? { type: "object" }
443
+ : i.function.parameters,
444
+ };
445
+ // Auto mode: add cache_control to the last tool
446
+ if (shouldCacheTools && index === arr.length - 1) {
447
+ tool.cache_control = { type: "ephemeral" };
448
+ if (ttl === "1h") {
449
+ tool.cache_control = { type: "ephemeral", ttl: "1h" };
450
+ }
451
+ }
452
+ // Manual mode: use tool-specific cacheControl if provided
453
+ else if (shouldCache && strategy === "manual") {
454
+ const toolWithCache = i;
455
+ if (toolWithCache.cacheControl) {
456
+ tool.cache_control = {
457
+ type: toolWithCache.cacheControl.type,
458
+ ...(toolWithCache.cacheControl.ttl && { ttl: toolWithCache.cacheControl.ttl }),
459
+ };
460
+ }
461
+ }
462
+ return tool;
463
+ })
381
464
  : undefined,
382
465
  tool_choice: choice,
383
466
  };
@@ -124,6 +124,9 @@ export declare class AnthropicChatModel extends ChatModel {
124
124
  reasoningEffort?: number | "minimal" | "low" | "medium" | "high" | {
125
125
  $get: string;
126
126
  } | undefined;
127
+ cacheConfig?: import("@aigne/core").CacheConfig | {
128
+ $get: string;
129
+ } | undefined;
127
130
  }> | undefined;
128
131
  get credential(): {
129
132
  apiKey: string | undefined;
@@ -124,6 +124,9 @@ export declare class AnthropicChatModel extends ChatModel {
124
124
  reasoningEffort?: number | "minimal" | "low" | "medium" | "high" | {
125
125
  $get: string;
126
126
  } | undefined;
127
+ cacheConfig?: import("@aigne/core").CacheConfig | {
128
+ $get: string;
129
+ } | undefined;
127
130
  }> | undefined;
128
131
  get credential(): {
129
132
  apiKey: string | undefined;
@@ -160,10 +160,12 @@ export class AnthropicChatModel extends ChatModel {
160
160
  model = chunk.message.model;
161
161
  controller.enqueue({ delta: { json: { model } } });
162
162
  }
163
- const { input_tokens, output_tokens } = chunk.message.usage;
163
+ const { input_tokens, output_tokens, cache_creation_input_tokens, cache_read_input_tokens, } = chunk.message.usage;
164
164
  usage = {
165
165
  inputTokens: input_tokens,
166
166
  outputTokens: output_tokens,
167
+ cacheCreationInputTokens: cache_creation_input_tokens ?? undefined,
168
+ cacheReadInputTokens: cache_read_input_tokens ?? undefined,
167
169
  };
168
170
  }
169
171
  if (chunk.type === "message_delta" && usage) {
@@ -254,14 +256,40 @@ export class AnthropicChatModel extends ChatModel {
254
256
  };
255
257
  }
256
258
  }
257
- async function convertMessages({ messages, responseFormat, tools }) {
258
- const systemMessages = [];
259
+ /**
260
+ * Parse cache configuration from model options
261
+ */
262
+ function parseCacheConfig(modelOptions) {
263
+ const cacheConfig = modelOptions?.cacheConfig || {};
264
+ const shouldCache = cacheConfig.enabled !== false; // Default: enabled
265
+ const ttl = cacheConfig.ttl === "1h" ? "1h" : "5m"; // Default: 5m
266
+ const strategy = cacheConfig.strategy || "auto"; // Default: auto
267
+ const autoBreakpoints = {
268
+ tools: cacheConfig.autoBreakpoints?.tools !== false, // Default: true
269
+ system: cacheConfig.autoBreakpoints?.system !== false, // Default: true
270
+ lastMessage: cacheConfig.autoBreakpoints?.lastMessage === true, // Default: false
271
+ };
272
+ return {
273
+ shouldCache,
274
+ ttl,
275
+ strategy,
276
+ autoBreakpoints,
277
+ };
278
+ }
279
+ async function convertMessages({ messages, responseFormat, tools, modelOptions, }) {
280
+ const systemBlocks = [];
259
281
  const msgs = [];
282
+ // Extract cache configuration with defaults
283
+ const { shouldCache, ttl, strategy, autoBreakpoints } = parseCacheConfig(modelOptions);
260
284
  for (const msg of messages) {
261
285
  if (msg.role === "system") {
262
286
  if (typeof msg.content !== "string")
263
287
  throw new Error("System message must have content");
264
- systemMessages.push(msg.content);
288
+ const block = {
289
+ type: "text",
290
+ text: msg.content,
291
+ };
292
+ systemBlocks.push(block);
265
293
  }
266
294
  else if (msg.role === "tool") {
267
295
  if (!msg.toolCallId)
@@ -307,16 +335,48 @@ async function convertMessages({ messages, responseFormat, tools }) {
307
335
  // If there are tools and responseFormat is json_schema, we need to add a system message
308
336
  // to inform the model about the expected json schema, then trying to parse the response as json
309
337
  if (tools?.length && responseFormat?.type === "json_schema") {
310
- systemMessages.push(`You should provide a json response with schema: ${JSON.stringify(responseFormat.jsonSchema.schema)}`);
338
+ systemBlocks.push({
339
+ type: "text",
340
+ text: `You should provide a json response with schema: ${JSON.stringify(responseFormat.jsonSchema.schema)}`,
341
+ });
342
+ }
343
+ // Apply cache_control to the last system block if auto strategy is enabled
344
+ if (shouldCache && strategy === "auto" && autoBreakpoints.system && systemBlocks.length > 0) {
345
+ const lastBlock = systemBlocks[systemBlocks.length - 1];
346
+ if (lastBlock) {
347
+ lastBlock.cache_control = { type: "ephemeral" };
348
+ if (ttl === "1h") {
349
+ lastBlock.cache_control = { type: "ephemeral", ttl: "1h" };
350
+ }
351
+ }
352
+ }
353
+ // Manual cache control: apply user-specified cacheControl from system messages
354
+ if (shouldCache && strategy === "manual") {
355
+ for (const [index, msg] of messages.entries()) {
356
+ const msgWithCache = msg;
357
+ if (msg.role === "system" && msgWithCache.cacheControl) {
358
+ const block = systemBlocks[index];
359
+ if (block) {
360
+ block.cache_control = {
361
+ type: msgWithCache.cacheControl.type,
362
+ ...(msgWithCache.cacheControl.ttl && { ttl: msgWithCache.cacheControl.ttl }),
363
+ };
364
+ }
365
+ }
366
+ }
311
367
  }
312
- const system = systemMessages.join("\n").trim() || undefined;
313
368
  // Claude requires at least one message, so we add a system message if there are no messages
314
369
  if (msgs.length === 0) {
315
- if (!system)
370
+ if (systemBlocks.length === 0)
316
371
  throw new Error("No messages provided");
317
- return { messages: [{ role: "user", content: system }] };
372
+ // Convert system blocks to a single user message
373
+ const systemText = systemBlocks.map((b) => b.text).join("\n");
374
+ return { messages: [{ role: "user", content: systemText }] };
318
375
  }
319
- return { messages: msgs, system };
376
+ return {
377
+ messages: msgs,
378
+ system: systemBlocks.length > 0 ? systemBlocks : undefined,
379
+ };
320
380
  }
321
381
  async function convertContent(content) {
322
382
  if (typeof content === "string")
@@ -341,7 +401,7 @@ async function convertContent(content) {
341
401
  }
342
402
  throw new Error("Invalid chat message content");
343
403
  }
344
- function convertTools({ tools, toolChoice, disableParallelToolUse, }) {
404
+ function convertTools({ tools, toolChoice, disableParallelToolUse, modelOptions, }) {
345
405
  let choice;
346
406
  if (typeof toolChoice === "object" && "type" in toolChoice && toolChoice.type === "function") {
347
407
  choice = {
@@ -362,15 +422,38 @@ function convertTools({ tools, toolChoice, disableParallelToolUse, }) {
362
422
  else if (toolChoice === "none") {
363
423
  choice = { type: "none" };
364
424
  }
425
+ // Extract cache configuration with defaults
426
+ const { shouldCache, ttl, strategy, autoBreakpoints } = parseCacheConfig(modelOptions);
427
+ const shouldCacheTools = shouldCache && strategy === "auto" && autoBreakpoints.tools;
365
428
  return {
366
429
  tools: tools?.length
367
- ? tools.map((i) => ({
368
- name: i.function.name,
369
- description: i.function.description,
370
- input_schema: isEmpty(i.function.parameters)
371
- ? { type: "object" }
372
- : i.function.parameters,
373
- }))
430
+ ? tools.map((i, index, arr) => {
431
+ const tool = {
432
+ name: i.function.name,
433
+ description: i.function.description,
434
+ input_schema: isEmpty(i.function.parameters)
435
+ ? { type: "object" }
436
+ : i.function.parameters,
437
+ };
438
+ // Auto mode: add cache_control to the last tool
439
+ if (shouldCacheTools && index === arr.length - 1) {
440
+ tool.cache_control = { type: "ephemeral" };
441
+ if (ttl === "1h") {
442
+ tool.cache_control = { type: "ephemeral", ttl: "1h" };
443
+ }
444
+ }
445
+ // Manual mode: use tool-specific cacheControl if provided
446
+ else if (shouldCache && strategy === "manual") {
447
+ const toolWithCache = i;
448
+ if (toolWithCache.cacheControl) {
449
+ tool.cache_control = {
450
+ type: toolWithCache.cacheControl.type,
451
+ ...(toolWithCache.cacheControl.ttl && { ttl: toolWithCache.cacheControl.ttl }),
452
+ };
453
+ }
454
+ }
455
+ return tool;
456
+ })
374
457
  : undefined,
375
458
  tool_choice: choice,
376
459
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aigne/anthropic",
3
- "version": "0.14.16-beta.2",
3
+ "version": "0.14.16-beta.4",
4
4
  "description": "AIGNE Anthropic SDK for integrating with Claude AI models",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -37,7 +37,7 @@
37
37
  "dependencies": {
38
38
  "@anthropic-ai/sdk": "^0.63.0",
39
39
  "zod": "^3.25.67",
40
- "@aigne/core": "^1.72.0-beta.2",
40
+ "@aigne/core": "^1.72.0-beta.4",
41
41
  "@aigne/platform-helpers": "^0.6.7-beta"
42
42
  },
43
43
  "devDependencies": {
@@ -46,7 +46,7 @@
46
46
  "npm-run-all": "^4.1.5",
47
47
  "rimraf": "^6.0.1",
48
48
  "typescript": "^5.9.2",
49
- "@aigne/test-utils": "^0.5.69-beta.2"
49
+ "@aigne/test-utils": "^0.5.69-beta.4"
50
50
  },
51
51
  "scripts": {
52
52
  "lint": "tsc --noEmit",