@@ -12,8 +12,18 @@ import {
1212 ProviderOptions ,
1313} from '../types.js' ;
1414
15- // Cache for model context window sizes
16- const modelContextWindowCache : Record < string , number > = { } ;
15+ const ANTHROPIC_CONTEXT_WINDOWS : Record < string , number > = {
16+ 'claude-3-7-sonnet-20250219' : 200000 ,
17+ 'claude-3-7-sonnet-latest' : 200000 ,
18+ 'claude-3-5-sonnet-20241022' : 200000 ,
19+ 'claude-3-5-sonnet-latest' : 200000 ,
20+ 'claude-3-haiku-20240307' : 200000 ,
21+ 'claude-3-opus-20240229' : 200000 ,
22+ 'claude-3-sonnet-20240229' : 200000 ,
23+ 'claude-2.1' : 100000 ,
24+ 'claude-2.0' : 100000 ,
25+ 'claude-instant-1.2' : 100000 ,
26+ } ;
1727
1828/**
1929 * Anthropic-specific options
@@ -87,7 +97,7 @@ function addCacheControlToMessages(
8797function tokenUsageFromMessage (
8898 message : Anthropic . Message ,
8999 model : string ,
90- contextWindow ? : number ,
100+ contextWindow : number | undefined ,
91101) {
92102 const usage = new TokenUsage ( ) ;
93103 usage . input = message . usage . input_tokens ;
@@ -97,19 +107,10 @@ function tokenUsageFromMessage(
97107
98108 const totalTokens = usage . input + usage . output ;
99109
100- // Use provided context window or fallback to cached value
101- const maxTokens = contextWindow || modelContextWindowCache [ model ] ;
102-
103- if ( ! maxTokens ) {
104- throw new Error (
105- `Context window size not available for model: ${ model } . Make sure to initialize the model properly.` ,
106- ) ;
107- }
108-
109110 return {
110111 usage,
111112 totalTokens,
112- maxTokens ,
113+ contextWindow ,
113114 } ;
114115}
115116
@@ -120,13 +121,14 @@ export class AnthropicProvider implements LLMProvider {
120121 name : string = 'anthropic' ;
121122 provider : string = 'anthropic.messages' ;
122123 model : string ;
124+ options : AnthropicOptions ;
123125 private client : Anthropic ;
124126 private apiKey : string ;
125127 private baseUrl ?: string ;
126- private modelContextWindow ?: number ;
127128
128129 constructor ( model : string , options : AnthropicOptions = { } ) {
129130 this . model = model ;
131+ this . options = options ;
130132 this . apiKey = options . apiKey ?? '' ;
131133 this . baseUrl = options . baseUrl ;
132134
@@ -139,79 +141,18 @@ export class AnthropicProvider implements LLMProvider {
139141 apiKey : this . apiKey ,
140142 ...( this . baseUrl && { baseURL : this . baseUrl } ) ,
141143 } ) ;
142-
143- // Initialize model context window detection
144- // This is async but we don't need to await it here
145- // If it fails, an error will be thrown when the model is used
146- this . initializeModelContextWindow ( ) . catch ( ( error ) => {
147- console . error (
148- `Failed to initialize model context window: ${ error . message } . The model will not work until context window information is available.` ,
149- ) ;
150- } ) ;
151- }
152-
153- /**
154- * Fetches the model context window size from the Anthropic API
155- *
156- * @returns The context window size
157- * @throws Error if the context window size cannot be determined
158- */
159- private async initializeModelContextWindow ( ) : Promise < number > {
160- try {
161- const response = await this . client . models . list ( ) ;
162-
163- if ( ! response ?. data || ! Array . isArray ( response . data ) ) {
164- throw new Error (
165- `Invalid response from models.list() for ${ this . model } ` ,
166- ) ;
167- }
168-
169- // Try to find the exact model
170- let model = response . data . find ( ( m ) => m . id === this . model ) ;
171-
172- // If not found, try to find a model that starts with the same name
173- // This helps with model aliases like 'claude-3-sonnet-latest'
174- if ( ! model ) {
175- // Split by '-latest' or '-20' to get the base model name
176- const parts = this . model . split ( '-latest' ) ;
177- const modelPrefix =
178- parts . length > 1 ? parts [ 0 ] : this . model . split ( '-20' ) [ 0 ] ;
179-
180- if ( modelPrefix ) {
181- model = response . data . find ( ( m ) => m . id . startsWith ( modelPrefix ) ) ;
182-
183- if ( model ) {
184- console . info (
185- `Model ${ this . model } not found, using ${ model . id } for context window size` ,
186- ) ;
187- }
188- }
189- }
190-
191- // Using type assertion to access context_window property
192- // The Anthropic API returns context_window but it may not be in the TypeScript definitions
193- if ( model && 'context_window' in model ) {
194- const contextWindow = ( model as any ) . context_window ;
195- this . modelContextWindow = contextWindow ;
196- // Cache the result for future use
197- modelContextWindowCache [ this . model ] = contextWindow ;
198- return contextWindow ;
199- } else {
200- throw new Error (
201- `No context window information found for model: ${ this . model } ` ,
202- ) ;
203- }
204- } catch ( error ) {
205- throw new Error (
206- `Failed to determine context window size for model ${ this . model } : ${ ( error as Error ) . message } ` ,
207- ) ;
208- }
209144 }
210145
211146 /**
212147 * Generate text using Anthropic API
213148 */
214149 async generateText ( options : GenerateOptions ) : Promise < LLMResponse > {
150+ // Use configuration contextWindow if provided, otherwise use model-specific value
151+ let modelContextWindow = ANTHROPIC_CONTEXT_WINDOWS [ this . model ] ;
152+ if ( ! modelContextWindow && this . options . contextWindow ) {
153+ modelContextWindow = this . options . contextWindow ;
154+ }
155+
215156 const { messages, functions, temperature = 0.7 , maxTokens, topP } = options ;
216157
217158 // Extract system message
@@ -227,63 +168,56 @@ export class AnthropicProvider implements LLMProvider {
227168 } ) ) ,
228169 ) ;
229170
230- try {
231- const requestOptions : Anthropic . MessageCreateParams = {
232- model : this . model ,
233- messages : addCacheControlToMessages ( formattedMessages ) ,
234- temperature,
235- max_tokens : maxTokens || 1024 ,
236- system : systemMessage ?. content
237- ? [
238- {
239- type : 'text' ,
240- text : systemMessage ?. content ,
241- cache_control : { type : 'ephemeral' } ,
242- } ,
243- ]
244- : undefined ,
245- top_p : topP ,
246- tools,
247- stream : false ,
248- } ;
171+ const requestOptions : Anthropic . MessageCreateParams = {
172+ model : this . model ,
173+ messages : addCacheControlToMessages ( formattedMessages ) ,
174+ temperature,
175+ max_tokens : maxTokens || 1024 ,
176+ system : systemMessage ?. content
177+ ? [
178+ {
179+ type : 'text' ,
180+ text : systemMessage ?. content ,
181+ cache_control : { type : 'ephemeral' } ,
182+ } ,
183+ ]
184+ : undefined ,
185+ top_p : topP ,
186+ tools,
187+ stream : false ,
188+ } ;
249189
250- const response = await this . client . messages . create ( requestOptions ) ;
190+ const response = await this . client . messages . create ( requestOptions ) ;
251191
252- // Extract content and tool calls
253- const content =
254- response . content . find ( ( c ) => c . type === 'text' ) ?. text || '' ;
255- const toolCalls = response . content
256- . filter ( ( c ) => {
257- const contentType = c . type ;
258- return contentType === 'tool_use' ;
259- } )
260- . map ( ( c ) => {
261- const toolUse = c as Anthropic . Messages . ToolUseBlock ;
262- return {
263- id : toolUse . id ,
264- name : toolUse . name ,
265- content : JSON . stringify ( toolUse . input ) ,
266- } ;
267- } ) ;
192+ // Extract content and tool calls
193+ const content = response . content . find ( ( c ) => c . type === 'text' ) ?. text || '' ;
194+ const toolCalls = response . content
195+ . filter ( ( c ) => {
196+ const contentType = c . type ;
197+ return contentType === 'tool_use' ;
198+ } )
199+ . map ( ( c ) => {
200+ const toolUse = c as Anthropic . Messages . ToolUseBlock ;
201+ return {
202+ id : toolUse . id ,
203+ name : toolUse . name ,
204+ content : JSON . stringify ( toolUse . input ) ,
205+ } ;
206+ } ) ;
268207
269- const tokenInfo = tokenUsageFromMessage (
270- response ,
271- this . model ,
272- this . modelContextWindow ,
273- ) ;
208+ const tokenInfo = tokenUsageFromMessage (
209+ response ,
210+ this . model ,
211+ modelContextWindow ,
212+ ) ;
274213
275- return {
276- text : content ,
277- toolCalls : toolCalls ,
278- tokenUsage : tokenInfo . usage ,
279- totalTokens : tokenInfo . totalTokens ,
280- maxTokens : tokenInfo . maxTokens ,
281- } ;
282- } catch ( error ) {
283- throw new Error (
284- `Error calling Anthropic API: ${ ( error as Error ) . message } ` ,
285- ) ;
286- }
214+ return {
215+ text : content ,
216+ toolCalls : toolCalls ,
217+ tokenUsage : tokenInfo . usage ,
218+ totalTokens : tokenInfo . totalTokens ,
219+ contextWindow : tokenInfo . contextWindow ,
220+ } ;
287221 }
288222
289223 /**
0 commit comments