Skip to content

Refactor: Remove fallbacks from Anthropic context window detection #346

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions packages/agent/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
# [mycoder-agent-v1.7.0](https://github.com/drivecore/mycoder/compare/mycoder-agent-v1.6.0...mycoder-agent-v1.7.0) (2025-03-21)

### Bug Fixes

- Fix TypeScript errors and tests for message compaction feature ([d4f1fb5](https://github.com/drivecore/mycoder/commit/d4f1fb5d197e623bf98f2221352f9132dcb3e5de))

### Features

- Add automatic compaction of historical messages for agents ([a5caf46](https://github.com/drivecore/mycoder/commit/a5caf464a0a8dca925c7b46023ebde4727e211f8)), closes [#338](https://github.com/drivecore/mycoder/issues/338)
- Improve message compaction with proactive suggestions ([6276bc0](https://github.com/drivecore/mycoder/commit/6276bc0bc5fa27c4f1e9be61ff4375690ad04c62))

# [mycoder-agent-v1.6.0](https://github.com/drivecore/mycoder/compare/mycoder-agent-v1.5.0...mycoder-agent-v1.6.0) (2025-03-21)

### Features
Expand Down
2 changes: 1 addition & 1 deletion packages/agent/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mycoder-agent",
"version": "1.6.0",
"version": "1.7.0",
"description": "Agent module for mycoder - an AI-powered software development assistant",
"type": "module",
"main": "dist/index.js",
Expand Down
106 changes: 89 additions & 17 deletions packages/agent/src/core/llm/providers/anthropic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,8 @@
ProviderOptions,
} from '../types.js';

// Define model context window sizes for Anthropic models
const ANTHROPIC_MODEL_LIMITS: Record<string, number> = {
default: 200000,
'claude-3-7-sonnet-20250219': 200000,
'claude-3-7-sonnet-latest': 200000,
'claude-3-5-sonnet-20241022': 200000,
'claude-3-5-sonnet-latest': 200000,
'claude-3-haiku-20240307': 200000,
'claude-3-opus-20240229': 200000,
'claude-3-sonnet-20240229': 200000,
'claude-2.1': 100000,
'claude-2.0': 100000,
'claude-instant-1.2': 100000,
};
// Cache for model context window sizes
const modelContextWindowCache: Record<string, number> = {};

/**
* Anthropic-specific options
Expand Down Expand Up @@ -96,15 +84,27 @@
});
}

function tokenUsageFromMessage(message: Anthropic.Message, model: string) {
function tokenUsageFromMessage(
message: Anthropic.Message,
model: string,
contextWindow?: number,
) {
const usage = new TokenUsage();
usage.input = message.usage.input_tokens;
usage.cacheWrites = message.usage.cache_creation_input_tokens ?? 0;
usage.cacheReads = message.usage.cache_read_input_tokens ?? 0;
usage.output = message.usage.output_tokens;

const totalTokens = usage.input + usage.output;
const maxTokens = ANTHROPIC_MODEL_LIMITS[model] || 100000; // Default fallback

// Use provided context window or fallback to cached value
const maxTokens = contextWindow || modelContextWindowCache[model];

if (!maxTokens) {
throw new Error(
`Context window size not available for model: ${model}. Make sure to initialize the model properly.`,
);
}

return {
usage,
Expand All @@ -123,6 +123,7 @@
private client: Anthropic;
private apiKey: string;
private baseUrl?: string;
private modelContextWindow?: number;

constructor(model: string, options: AnthropicOptions = {}) {
this.model = model;
Expand All @@ -138,6 +139,73 @@
apiKey: this.apiKey,
...(this.baseUrl && { baseURL: this.baseUrl }),
});

// Initialize model context window detection
// This is async but we don't need to await it here
// If it fails, an error will be thrown when the model is used
this.initializeModelContextWindow().catch((error) => {
console.error(
`Failed to initialize model context window: ${error.message}. The model will not work until context window information is available.`,
);
});
}

/**
* Fetches the model context window size from the Anthropic API
*
* @returns The context window size
* @throws Error if the context window size cannot be determined
*/
private async initializeModelContextWindow(): Promise<number> {
try {
const response = await this.client.models.list();

if (!response?.data || !Array.isArray(response.data)) {
throw new Error(
`Invalid response from models.list() for ${this.model}`,
);
}

// Try to find the exact model
let model = response.data.find((m) => m.id === this.model);

// If not found, try to find a model that starts with the same name
// This helps with model aliases like 'claude-3-sonnet-latest'
if (!model) {
// Split by '-latest' or '-20' to get the base model name
const parts = this.model.split('-latest');
const modelPrefix =
parts.length > 1 ? parts[0] : this.model.split('-20')[0];

if (modelPrefix) {
model = response.data.find((m) => m.id.startsWith(modelPrefix));

if (model) {
console.info(
`Model ${this.model} not found, using ${model.id} for context window size`,
);
}
}
}

// Using type assertion to access context_window property
// The Anthropic API returns context_window but it may not be in the TypeScript definitions
if (model && 'context_window' in model) {
const contextWindow = (model as any).context_window;

Check warning on line 194 in packages/agent/src/core/llm/providers/anthropic.ts

View workflow job for this annotation

GitHub Actions / ci

Unexpected any. Specify a different type
this.modelContextWindow = contextWindow;
// Cache the result for future use
modelContextWindowCache[this.model] = contextWindow;
return contextWindow;
} else {
throw new Error(
`No context window information found for model: ${this.model}`,
);
}
} catch (error) {
throw new Error(
`Failed to determine context window size for model ${this.model}: ${(error as Error).message}`,
);
}
}

/**
Expand Down Expand Up @@ -198,7 +266,11 @@
};
});

const tokenInfo = tokenUsageFromMessage(response, this.model);
const tokenInfo = tokenUsageFromMessage(
response,
this.model,
this.modelContextWindow,
);

return {
text: content,
Expand Down
Loading