@@ -12,20 +12,8 @@ import {
12
12
ProviderOptions ,
13
13
} from '../types.js' ;
14
14
15
- // Define model context window sizes for Anthropic models
16
- const ANTHROPIC_MODEL_LIMITS : Record < string , number > = {
17
- default : 200000 ,
18
- 'claude-3-7-sonnet-20250219' : 200000 ,
19
- 'claude-3-7-sonnet-latest' : 200000 ,
20
- 'claude-3-5-sonnet-20241022' : 200000 ,
21
- 'claude-3-5-sonnet-latest' : 200000 ,
22
- 'claude-3-haiku-20240307' : 200000 ,
23
- 'claude-3-opus-20240229' : 200000 ,
24
- 'claude-3-sonnet-20240229' : 200000 ,
25
- 'claude-2.1' : 100000 ,
26
- 'claude-2.0' : 100000 ,
27
- 'claude-instant-1.2' : 100000 ,
28
- } ;
15
+ // Cache for model context window sizes
16
+ const modelContextWindowCache : Record < string , number > = { } ;
29
17
30
18
/**
31
19
* Anthropic-specific options
@@ -96,15 +84,27 @@ function addCacheControlToMessages(
96
84
} ) ;
97
85
}
98
86
99
- function tokenUsageFromMessage ( message : Anthropic . Message , model : string ) {
87
+ function tokenUsageFromMessage (
88
+ message : Anthropic . Message ,
89
+ model : string ,
90
+ contextWindow ?: number ,
91
+ ) {
100
92
const usage = new TokenUsage ( ) ;
101
93
usage . input = message . usage . input_tokens ;
102
94
usage . cacheWrites = message . usage . cache_creation_input_tokens ?? 0 ;
103
95
usage . cacheReads = message . usage . cache_read_input_tokens ?? 0 ;
104
96
usage . output = message . usage . output_tokens ;
105
97
106
98
const totalTokens = usage . input + usage . output ;
107
- const maxTokens = ANTHROPIC_MODEL_LIMITS [ model ] || 100000 ; // Default fallback
99
+
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
108
109
109
return {
110
110
usage,
@@ -123,6 +123,7 @@ export class AnthropicProvider implements LLMProvider {
123
123
private client : Anthropic ;
124
124
private apiKey : string ;
125
125
private baseUrl ?: string ;
126
+ private modelContextWindow ?: number ;
126
127
127
128
constructor ( model : string , options : AnthropicOptions = { } ) {
128
129
this . model = model ;
@@ -138,6 +139,73 @@ export class AnthropicProvider implements LLMProvider {
138
139
apiKey : this . apiKey ,
139
140
...( this . baseUrl && { baseURL : this . baseUrl } ) ,
140
141
} ) ;
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
+ }
141
209
}
142
210
143
211
/**
@@ -198,7 +266,11 @@ export class AnthropicProvider implements LLMProvider {
198
266
} ;
199
267
} ) ;
200
268
201
- const tokenInfo = tokenUsageFromMessage ( response , this . model ) ;
269
+ const tokenInfo = tokenUsageFromMessage (
270
+ response ,
271
+ this . model ,
272
+ this . modelContextWindow ,
273
+ ) ;
202
274
203
275
return {
204
276
text : content ,
0 commit comments