fix: replace retired Anthropic model defaults

This commit is contained in:
dajiaohuang
2026-09-10 19:48:28 +08:00
parent 715fd4a6c0
commit 88578898e3
16 changed files with 144 additions and 30 deletions
+2 -1
View File
@@ -342,7 +342,7 @@ const STREAM_RESPONSE_PLATFORMS = new Set([
'teams',
'webchat',
]);
const MEMORY_EXTRACT_MODEL = process.env.CLODDS_MEMORY_EXTRACT_MODEL || process.env.CLODDS_SUMMARY_MODEL || 'claude-3-5-haiku-20241022';
const MEMORY_EXTRACT_MODEL = process.env.CLODDS_MEMORY_EXTRACT_MODEL || process.env.CLODDS_SUMMARY_MODEL || 'claude-haiku-4-5-20251001';
const KALSHI_API_BASE = 'https://api.elections.kalshi.com/trade-api/v2';
const DRIFT_GATEWAY_URL = process.env.DRIFT_GATEWAY_URL || 'http://localhost:8080';
@@ -17642,6 +17642,7 @@ export async function createAgentManager(
const MODEL_CONTEXT_WINDOWS: Record<string, number> = {
'claude-opus-4-6': 200000,
'claude-opus-4-5-20250514': 200000,
'claude-sonnet-4-6': 200000,
'claude-sonnet-4-5-20250929': 200000,
'claude-sonnet-4-20250514': 200000,
'claude-haiku-4-5-20251001': 200000,
+5 -1
View File
@@ -150,6 +150,10 @@ export interface RunRegistryEntry {
// =============================================================================
const MODEL_COSTS: Record<string, { input: number; output: number }> = {
'claude-opus-4-6': { input: 5, output: 25 },
'claude-sonnet-4-6': { input: 3, output: 15 },
'claude-sonnet-4-5-20250929': { input: 3, output: 15 },
'claude-haiku-4-5-20251001': { input: 1, output: 5 },
'claude-3-opus-20240229': { input: 15, output: 75 },
'claude-3-5-sonnet-20241022': { input: 3, output: 15 },
'claude-3-5-haiku-20241022': { input: 0.25, output: 1.25 },
@@ -553,7 +557,7 @@ export function createSubagentManager(): SubagentManager {
anthropicClient = new Anthropic({ apiKey });
}
const model = state.config.model || 'claude-3-5-sonnet-20241022';
const model = state.config.model || 'claude-sonnet-4-6';
const maxTurns = state.config.maxTurns || 10;
const timeout = state.config.timeout || 300000; // 5 min default
+5 -8
View File
@@ -135,10 +135,7 @@ export function createModelCommands(program: Command): void {
{ id: 'claude-opus-4-6', provider: 'anthropic', context: '200K' },
{ id: 'claude-sonnet-4-5-20250929', provider: 'anthropic', context: '200K' },
{ id: 'claude-haiku-4-5-20251001', provider: 'anthropic', context: '200K' },
// Anthropic (Legacy)
{ id: 'claude-3-5-sonnet-20241022', provider: 'anthropic', context: '200K' },
{ id: 'claude-3-opus-20240229', provider: 'anthropic', context: '200K' },
{ id: 'claude-3-5-haiku-20241022', provider: 'anthropic', context: '200K' },
{ id: 'claude-sonnet-4-6', provider: 'anthropic', context: '200K' },
// OpenAI
{ id: 'gpt-4o', provider: 'openai', context: '128K' },
{ id: 'gpt-4-turbo', provider: 'openai', context: '128K' },
@@ -175,7 +172,7 @@ export function createModelCommands(program: Command): void {
writeFileSync(configPath, JSON.stringify(data, null, 2));
console.log(`Default model set to: ${model}`);
} else {
console.log(`Default model: ${data.defaultModel || 'claude-3-5-sonnet-20241022'}`);
console.log(`Default model: ${data.defaultModel || 'claude-sonnet-4-6'}`);
}
});
}
@@ -2034,7 +2031,7 @@ export function createInitCommand(program: Command): void {
const defaultConfig = {
name: 'clodds-project',
version: '0.1.0',
model: 'claude-3-5-sonnet-20241022',
model: 'claude-sonnet-4-6',
features: {
memory: true,
tools: true,
@@ -2201,7 +2198,7 @@ export function createCredsCommands(program: Command): void {
'anthropic-version': '2023-06-01',
},
body: JSON.stringify({
model: 'claude-3-haiku-20240307',
model: 'claude-haiku-4-5-20251001',
max_tokens: 1,
messages: [{ role: 'user', content: 'hi' }],
}),
@@ -3434,7 +3431,7 @@ export function createDoctorCommand(program: Command): void {
const r = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'x-api-key': anthropicKey, 'anthropic-version': '2023-06-01' },
body: JSON.stringify({ model: 'claude-3-haiku-20240307', max_tokens: 1, messages: [{ role: 'user', content: 'hi' }] }),
body: JSON.stringify({ model: 'claude-haiku-4-5-20251001', max_tokens: 1, messages: [{ role: 'user', content: 'hi' }] }),
});
if (r.ok || r.status === 429) {
results.push({ name: 'Anthropic', status: 'pass', message: r.ok ? 'Key valid' : 'Key valid (rate limited)' });
+1 -1
View File
@@ -38,7 +38,7 @@ async function validateAnthropicKey(key: string): Promise<{ valid: boolean; erro
'anthropic-version': '2023-06-01',
},
body: JSON.stringify({
model: 'claude-3-haiku-20240307',
model: 'claude-haiku-4-5-20251001',
max_tokens: 1,
messages: [{ role: 'user', content: 'Hi' }],
}),
+1 -1
View File
@@ -268,7 +268,7 @@ const checks: Record<string, Check> = {
'anthropic-version': '2023-06-01',
},
body: JSON.stringify({
model: 'claude-3-haiku-20240307',
model: 'claude-haiku-4-5-20251001',
max_tokens: 1,
messages: [{ role: 'user', content: 'hi' }],
}),
+5 -5
View File
@@ -298,7 +298,7 @@ ${doc.content}
Respond with ONLY the edited document content, no explanations. Preserve the original format.`;
const response = await provider.complete({
model: 'claude-3-5-sonnet-20241022',
model: 'claude-sonnet-4-6',
messages: [{ role: 'user', content: prompt }],
maxTokens: 8192,
});
@@ -353,7 +353,7 @@ ${textAfter ? `Text after cursor:\n${textAfter}` : ''}
Provide only the completion text, no explanations. Write 1-3 sentences that naturally continue from where the cursor is.`;
const response = await provider.complete({
model: 'claude-3-5-sonnet-20241022',
model: 'claude-sonnet-4-6',
messages: [{ role: 'user', content: prompt }],
maxTokens: 500,
});
@@ -379,7 +379,7 @@ Provide only the completion text, no explanations. Write 1-3 sentences that natu
${doc.content}`;
const response = await provider.complete({
model: 'claude-3-5-sonnet-20241022',
model: 'claude-sonnet-4-6',
messages: [{ role: 'user', content: prompt }],
maxTokens: 200,
});
@@ -404,7 +404,7 @@ ${doc.content}
Output only the rewritten document content.`;
const response = await provider.complete({
model: 'claude-3-5-sonnet-20241022',
model: 'claude-sonnet-4-6',
messages: [{ role: 'user', content: prompt }],
maxTokens: 8192,
});
@@ -448,7 +448,7 @@ ${doc.content}
Output the expanded document.`;
const response = await provider.complete({
model: 'claude-3-5-sonnet-20241022',
model: 'claude-sonnet-4-6',
messages: [{ role: 'user', content: prompt }],
maxTokens: 8192,
});
+2 -2
View File
@@ -269,7 +269,7 @@ builtInExecutors.set('llm', {
async execute(task, context) {
const prompt = task.input?.prompt as string;
const systemPrompt = task.input?.system as string;
const model = (task.input?.model as string) || 'claude-3-5-sonnet-20241022';
const model = (task.input?.model as string) || 'claude-sonnet-4-6';
const messages: Array<{ role: 'system' | 'user' | 'assistant'; content: string }> = [];
if (systemPrompt) {
@@ -441,7 +441,7 @@ export class TaskRunner {
* Plan tasks from a high-level goal
*/
async planTasks(goal: string, context?: string): Promise<TaskDefinition[]> {
const planningModel = this.config.planningModel || 'claude-3-5-sonnet-20241022';
const planningModel = this.config.planningModel || 'claude-sonnet-4-6';
const systemPrompt = `You are a task planner. Given a high-level goal, break it down into concrete, executable tasks.
+1 -1
View File
@@ -822,7 +822,7 @@ export function createVisionService(): VisionService {
'anthropic-version': '2023-06-01',
},
body: JSON.stringify({
model: 'claude-sonnet-4-20250514',
model: 'claude-sonnet-4-6',
max_tokens: 1024,
messages: [{
role: 'user',
+1 -1
View File
@@ -12,7 +12,7 @@ interface ClaudeSummarizerOptions {
model?: string;
}
const DEFAULT_SUMMARY_MODEL = process.env.CLODDS_SUMMARY_MODEL || 'claude-3-5-haiku-20241022';
const DEFAULT_SUMMARY_MODEL = process.env.CLODDS_SUMMARY_MODEL || 'claude-haiku-4-5-20251001';
export function createClaudeSummarizer(options: ClaudeSummarizerOptions = {}): SummarizerFn | undefined {
const apiKey = options.apiKey || process.env.ANTHROPIC_API_KEY;
+1
View File
@@ -22,6 +22,7 @@ const MODEL_META: Record<string, ModelMeta> = {
// Latest models
'claude-opus-4-6': { costScore: 1, speedScore: 3, qualityScore: 10 },
'claude-opus-4-5-20250514': { costScore: 2, speedScore: 4, qualityScore: 10 },
'claude-sonnet-4-6': { costScore: 5, speedScore: 7, qualityScore: 9 },
'claude-sonnet-4-5-20250929': { costScore: 5, speedScore: 7, qualityScore: 9 },
'claude-sonnet-4-20250514': { costScore: 6, speedScore: 7, qualityScore: 8 },
'claude-haiku-4-5-20251001': { costScore: 9, speedScore: 10, qualityScore: 7 },
+32
View File
@@ -115,6 +115,38 @@ export function createModelRegistry(providers: Map<string, Provider>): ModelRegi
// Known model metadata
const KNOWN_MODELS: Record<string, Partial<DiscoveredModel>> = {
'claude-opus-4-6': {
name: 'Claude Opus 4.6',
contextWindow: 200000,
maxOutput: 128000,
inputCostPer1k: 0.005,
outputCostPer1k: 0.025,
capabilities: ['vision', 'tools', 'streaming'],
},
'claude-sonnet-4-6': {
name: 'Claude Sonnet 4.6',
contextWindow: 200000,
maxOutput: 64000,
inputCostPer1k: 0.003,
outputCostPer1k: 0.015,
capabilities: ['vision', 'tools', 'streaming'],
},
'claude-sonnet-4-5-20250929': {
name: 'Claude Sonnet 4.5',
contextWindow: 200000,
maxOutput: 8192,
inputCostPer1k: 0.003,
outputCostPer1k: 0.015,
capabilities: ['vision', 'tools', 'streaming'],
},
'claude-haiku-4-5-20251001': {
name: 'Claude Haiku 4.5',
contextWindow: 200000,
maxOutput: 8192,
inputCostPer1k: 0.001,
outputCostPer1k: 0.005,
capabilities: ['vision', 'tools', 'streaming'],
},
'claude-3-5-sonnet-20241022': {
name: 'Claude 3.5 Sonnet',
contextWindow: 200000,
+10 -6
View File
@@ -265,7 +265,7 @@ export class AnthropicProvider implements Provider {
constructor(config: ProviderConfig) {
this.config = {
baseUrl: 'https://api.anthropic.com',
defaultModel: 'claude-3-5-sonnet-20241022',
defaultModel: 'claude-sonnet-4-6',
timeout: 120000,
maxRetries: 3,
...config,
@@ -403,10 +403,10 @@ export class AnthropicProvider implements Provider {
async listModels(): Promise<string[]> {
return [
'claude-3-5-sonnet-20241022',
'claude-3-opus-20240229',
'claude-3-sonnet-20240229',
'claude-3-haiku-20240307',
'claude-opus-4-6',
'claude-sonnet-4-6',
'claude-sonnet-4-5-20250929',
'claude-haiku-4-5-20251001',
];
}
@@ -420,7 +420,7 @@ export class AnthropicProvider implements Provider {
'anthropic-version': '2023-06-01',
},
body: JSON.stringify({
model: 'claude-3-haiku-20240307',
model: 'claude-haiku-4-5-20251001',
max_tokens: 1,
messages: [{ role: 'user', content: 'hi' }],
}),
@@ -1044,6 +1044,10 @@ export interface CostConfig {
}
const MODEL_COSTS: Record<string, CostConfig> = {
'claude-opus-4-6': { inputCostPer1k: 0.005, outputCostPer1k: 0.025 },
'claude-sonnet-4-6': { inputCostPer1k: 0.003, outputCostPer1k: 0.015 },
'claude-sonnet-4-5-20250929': { inputCostPer1k: 0.003, outputCostPer1k: 0.015 },
'claude-haiku-4-5-20251001': { inputCostPer1k: 0.001, outputCostPer1k: 0.005 },
'claude-3-5-sonnet-20241022': { inputCostPer1k: 0.003, outputCostPer1k: 0.015 },
'claude-3-opus-20240229': { inputCostPer1k: 0.015, outputCostPer1k: 0.075 },
'claude-3-sonnet-20240229': { inputCostPer1k: 0.003, outputCostPer1k: 0.015 },
+1 -1
View File
@@ -175,7 +175,7 @@ async function execute(args: string): Promise<string> {
case 'estimate': {
// Estimate cost for a hypothetical request
const model = parts[1] || 'claude-sonnet-4-20250514';
const model = parts[1] || 'claude-sonnet-4-6';
const inputTokens = parseInt(parts[2] || '1000', 10);
const outputTokens = parseInt(parts[3] || '500', 10);
const cost = service.estimateCost(model, inputTokens, outputTokens);
+1 -1
View File
@@ -68,7 +68,7 @@ export interface ImageTool {
}
const DEFAULT_PROMPT = 'Describe this image in detail. Include any text visible in the image.';
const DEFAULT_MODEL = 'claude-sonnet-4-20250514';
const DEFAULT_MODEL = 'claude-sonnet-4-6';
const DEFAULT_MAX_TOKENS = 1024;
const DEFAULT_CACHE_TTL_MS = 5 * 60 * 1000;
const DEFAULT_RATE_LIMIT_WINDOW_MS = 60_000;
+4 -1
View File
@@ -15,8 +15,11 @@ import { generateId } from '../utils/id';
/** Model pricing (per 1M tokens) */
const MODEL_PRICING: Record<string, { input: number; output: number }> = {
'claude-opus-4-6': { input: 5.0, output: 25.0 },
'claude-sonnet-4-6': { input: 3.0, output: 15.0 },
'claude-sonnet-4-5-20250929': { input: 3.0, output: 15.0 },
'claude-haiku-4-5-20251001': { input: 1.0, output: 5.0 },
'claude-opus-4-5-20250514': { input: 15.0, output: 75.0 },
'claude-sonnet-4-20250514': { input: 3.0, output: 15.0 },
'claude-haiku-3-5-20250514': { input: 0.25, output: 1.25 },
// Fallback for unknown models
default: { input: 3.0, output: 15.0 },
@@ -0,0 +1,72 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import { join } from 'node:path';
import { AnthropicProvider } from '../../src/providers/index';
const RETIRED_MODELS = [
'claude-3-haiku-20240307',
'claude-3-5-haiku-20241022',
'claude-3-5-sonnet-20241022',
'claude-sonnet-4-20250514',
];
test('runtime model defaults do not use retired Anthropic IDs', () => {
const runtimeFiles = [
'src/cli/commands/index.ts',
'src/cli/commands/onboard.ts',
'src/doctor/index.ts',
'src/extensions/open-prose/index.ts',
'src/extensions/task-runner/index.ts',
'src/memory/summarizer.ts',
'src/media/index.ts',
'src/skills/bundled/usage/index.ts',
'src/tools/image.ts',
'src/usage/index.ts',
];
for (const relativePath of runtimeFiles) {
const source = readFileSync(join(process.cwd(), relativePath), 'utf8');
for (const retiredModel of RETIRED_MODELS) {
assert.equal(
source.includes(retiredModel),
false,
`${relativePath} still references retired model ${retiredModel}`,
);
}
}
});
test('Anthropic provider uses active defaults for completion and health checks', async () => {
const requests: Array<{ url: string; body: Record<string, unknown> }> = [];
const originalFetch = globalThis.fetch;
globalThis.fetch = (async (input, init) => {
requests.push({
url: String(input),
body: JSON.parse(String(init?.body)) as Record<string, unknown>,
});
return new Response(JSON.stringify({
content: [{ text: 'ok' }],
model: 'claude-sonnet-4-6',
usage: { input_tokens: 1, output_tokens: 1 },
stop_reason: 'end_turn',
}), { status: 200, headers: { 'content-type': 'application/json' } });
}) as typeof fetch;
try {
const provider = new AnthropicProvider({ apiKey: 'test-key' });
await provider.complete([{ role: 'user', content: 'hello' }]);
await provider.isAvailable();
assert.equal(requests[0].body.model, 'claude-sonnet-4-6');
assert.equal(requests[1].body.model, 'claude-haiku-4-5-20251001');
assert.deepEqual(await provider.listModels(), [
'claude-opus-4-6',
'claude-sonnet-4-6',
'claude-sonnet-4-5-20250929',
'claude-haiku-4-5-20251001',
]);
} finally {
globalThis.fetch = originalFetch;
}
});