Skip to content

Commit d78723b

Browse files
committed
feat: add token caching. issue 145
1 parent cc192c5 commit d78723b

File tree

1 file changed

+64
-13
lines changed

1 file changed

+64
-13
lines changed

packages/agent/src/core/llm/providers/anthropic.ts

Lines changed: 64 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,64 @@ export interface AnthropicOptions extends ProviderOptions {
1919
baseUrl?: string;
2020
}
2121

22+
// a function that takes a list of messages and returns a list of messages but with the last message having a cache_control of ephemeral
23+
function addCacheControlToTools<T>(messages: T[]): T[] {
24+
return messages.map((m, i) => ({
25+
...m,
26+
...(i === messages.length - 1
27+
? { cache_control: { type: 'ephemeral' } }
28+
: {}),
29+
}));
30+
}
31+
32+
function addCacheControlToContentBlocks(
33+
content: Anthropic.Messages.TextBlock[],
34+
): Anthropic.Messages.TextBlock[] {
35+
return content.map((c, i) => {
36+
if (i === content.length - 1) {
37+
if (
38+
c.type === 'text' ||
39+
c.type === 'document' ||
40+
c.type === 'image' ||
41+
c.type === 'tool_use' ||
42+
c.type === 'tool_result' ||
43+
c.type === 'thinking' ||
44+
c.type === 'redacted_thinking'
45+
) {
46+
return { ...c, cache_control: { type: 'ephemeral' } };
47+
}
48+
}
49+
return c;
50+
});
51+
}
52+
function addCacheControlToMessages(
53+
messages: Anthropic.Messages.MessageParam[],
54+
): Anthropic.Messages.MessageParam[] {
55+
return messages.map((m, i) => {
56+
if (typeof m.content === 'string') {
57+
return {
58+
...m,
59+
content: [
60+
{
61+
type: 'text',
62+
text: m.content,
63+
cache_control: { type: 'ephemeral' },
64+
},
65+
],
66+
};
67+
}
68+
return {
69+
...m,
70+
content:
71+
i >= messages.length - 2
72+
? addCacheControlToContentBlocks(
73+
m.content as Anthropic.Messages.TextBlock[],
74+
)
75+
: m.content,
76+
};
77+
});
78+
}
79+
2280
/**
2381
* Anthropic provider implementation
2482
*/
@@ -50,14 +108,7 @@ export class AnthropicProvider implements LLMProvider {
50108
* Generate text using Anthropic API
51109
*/
52110
async generateText(options: GenerateOptions): Promise<LLMResponse> {
53-
const {
54-
messages,
55-
functions,
56-
temperature = 0.7,
57-
maxTokens,
58-
stopSequences,
59-
topP,
60-
} = options;
111+
const { messages, functions, temperature = 0.7, maxTokens, topP } = options;
61112

62113
// Extract system message
63114
const systemMessage = messages.find((msg) => msg.role === 'system');
@@ -67,12 +118,12 @@ export class AnthropicProvider implements LLMProvider {
67118
try {
68119
const requestOptions: Anthropic.MessageCreateParams = {
69120
model: this.model,
70-
messages: formattedMessages,
121+
messages: addCacheControlToMessages(formattedMessages),
71122
temperature,
72123
max_tokens: maxTokens || 1024,
73-
...(stopSequences && { stop_sequences: stopSequences }),
74-
...(topP && { top_p: topP }),
75-
...(systemMessage && { system: systemMessage.content }),
124+
system: systemMessage?.content,
125+
top_p: topP,
126+
stream: false,
76127
};
77128

78129
// Add tools if provided
@@ -82,7 +133,7 @@ export class AnthropicProvider implements LLMProvider {
82133
description: fn.description,
83134
input_schema: fn.parameters,
84135
}));
85-
(requestOptions as any).tools = tools;
136+
(requestOptions as any).tools = addCacheControlToTools(tools);
86137
}
87138

88139
const response = await this.client.messages.create(requestOptions);

0 commit comments

Comments
 (0)