diff --git a/packages/core/examples/nodejs/multi-provider.ts b/packages/core/examples/nodejs/multi-provider.ts index 999d4f95..cc105759 100644 --- a/packages/core/examples/nodejs/multi-provider.ts +++ b/packages/core/examples/nodejs/multi-provider.ts @@ -92,9 +92,9 @@ async function main() { // Anthropic: Mid-tier if (process.env.ANTHROPIC_API_KEY) { models.push({ - name: 'claude-3-haiku-20240307', + name: 'claude-haiku-4-5', provider: 'anthropic', - cost: 0.00075, + cost: 0.001, qualityThreshold: 0.85, apiKey: process.env.ANTHROPIC_API_KEY, }); diff --git a/packages/core/examples/nodejs/production-patterns.ts b/packages/core/examples/nodejs/production-patterns.ts index 19a283d8..ffef790d 100644 --- a/packages/core/examples/nodejs/production-patterns.ts +++ b/packages/core/examples/nodejs/production-patterns.ts @@ -46,8 +46,8 @@ async function example1_ErrorHandling() { const agent = new CascadeAgent({ models: [ - { name: 'claude-3-5-haiku-20241022', provider: 'anthropic', cost: 0.0008 }, - { name: 'gpt-5', provider: 'openai', cost: 0.00125 }, + { name: 'claude-haiku-4-5', provider: 'anthropic', cost: 0.001 }, + { name: 'claude-sonnet-4-5', provider: 'anthropic', cost: 0.003 }, ], }); @@ -106,8 +106,8 @@ async function example2_Caching() { const agent = new CascadeAgent({ models: [ - { name: 'claude-3-5-haiku-20241022', provider: 'anthropic', cost: 0.0008 }, - { name: 'gpt-5', provider: 'openai', cost: 0.00125 }, + { name: 'claude-haiku-4-5', provider: 'anthropic', cost: 0.001 }, + { name: 'claude-sonnet-4-5', provider: 'anthropic', cost: 0.003 }, ], }); @@ -246,8 +246,8 @@ async function example4_CostTracking() { const agent = new CascadeAgent({ models: [ - { name: 'claude-3-5-haiku-20241022', provider: 'anthropic', cost: 0.0008 }, - { name: 'gpt-5', provider: 'openai', cost: 0.00125 }, + { name: 'claude-haiku-4-5', provider: 'anthropic', cost: 0.001 }, + { name: 'claude-sonnet-4-5', provider: 'anthropic', cost: 0.003 }, ], }); @@ -314,8 +314,8 @@ async function example5_Monitoring() { const agent = new CascadeAgent({ models: [ - { name: 'claude-3-5-haiku-20241022', provider: 'anthropic', cost: 0.0008 }, - { name: 'gpt-5', provider: 'openai', cost: 0.00125 }, + { name: 'claude-haiku-4-5', provider: 'anthropic', cost: 0.001 }, + { name: 'claude-sonnet-4-5', provider: 'anthropic', cost: 0.003 }, ], }); @@ -343,15 +343,15 @@ async function example6_Failover() { // Primary cascade const primaryAgent = new CascadeAgent({ models: [ - { name: 'claude-3-5-haiku-20241022', provider: 'anthropic', cost: 0.0008 }, - { name: 'gpt-5', provider: 'openai', cost: 0.00125 }, + { name: 'claude-haiku-4-5', provider: 'anthropic', cost: 0.001 }, + { name: 'claude-sonnet-4-5', provider: 'anthropic', cost: 0.003 }, ], }); // Fallback cascade (different providers) const fallbackAgent = new CascadeAgent({ models: [ - { name: 'llama-3.1-8b-instant', provider: 'groq', cost: 0.00005 }, + { name: 'llama-4-scout', provider: 'groq', cost: 0.00011 }, { name: 'gpt-4o-mini', provider: 'openai', cost: 0.00015 }, ], }); diff --git a/packages/core/examples/nodejs/reasoning-models.ts b/packages/core/examples/nodejs/reasoning-models.ts index 22082169..45f778ce 100644 --- a/packages/core/examples/nodejs/reasoning-models.ts +++ b/packages/core/examples/nodejs/reasoning-models.ts @@ -3,15 +3,17 @@ * * cascadeflow supports reasoning models from 4 providers with automatic detection: * - * 1. OpenAI (o1, o1-mini, o3-mini) + * 1. OpenAI (o3, o4-mini) * - Chain-of-thought reasoning with hidden thinking * - reasoning_effort parameter (low/medium/high) * - max_completion_tokens required + * - o3 and o4-mini are the latest reasoning models (2025) * - * 2. Anthropic (claude-3-7-sonnet-20250219) + * 2. Anthropic (claude-sonnet-4-5, claude-opus-4-1) * - Extended thinking mode (enable with thinkingBudget) * - Minimum 1024 tokens thinking budget * - Visible reasoning in response + * - Claude Sonnet 4.5 and Opus 4.1 released in 2025 * * 3. Ollama (deepseek-r1, deepseek-r1-distill) * - Free local inference @@ -29,12 +31,12 @@ import { CascadeAgent } from '../../src/index'; async function reasoningModelsExample() { - // Example 1: o1-mini (supports streaming, no tools, no system messages) - console.log('\n=== Example 1: o1-mini (original reasoning model) ==='); + // Example 1: o4-mini (latest fast reasoning model) + console.log('\n=== Example 1: o4-mini (latest reasoning model) ==='); const agent1 = new CascadeAgent({ models: [ { - name: 'o1-mini', // Auto-detected as reasoning model + name: 'o4-mini', // Auto-detected as reasoning model provider: 'openai', }, ], @@ -55,12 +57,12 @@ async function reasoningModelsExample() { }); console.log('Cost:', `$${result1.cost.toFixed(6)}`); - // Example 2: o1-2024-12-17 (newer model with reasoning_effort) - console.log('\n=== Example 2: o1-2024-12-17 with reasoning_effort ==='); + // Example 2: o3 (latest advanced reasoning model with reasoning_effort) + console.log('\n=== Example 2: o3 with reasoning_effort ==='); const agent2 = new CascadeAgent({ models: [ { - name: 'o1-2024-12-17', + name: 'o3', provider: 'openai', }, ], @@ -89,7 +91,7 @@ async function reasoningModelsExample() { provider: 'openai', }, { - name: 'o1-mini', // Falls back to reasoning model if needed + name: 'o4-mini', // Falls back to reasoning model if needed provider: 'openai', }, ], @@ -128,12 +130,12 @@ async function reasoningModelsExample() { console.log(' Response length:', result.content.length, 'chars'); } - // Example 5: Anthropic Claude 3.7 Sonnet with Extended Thinking - console.log('\n=== Example 5: Claude 3.7 Sonnet (Extended Thinking) ==='); + // Example 5: Anthropic Claude Sonnet 4.5 with Extended Thinking + console.log('\n=== Example 5: Claude Sonnet 4.5 (Extended Thinking) ==='); const agent4 = new CascadeAgent({ models: [ { - name: 'claude-3-7-sonnet-20250219', + name: 'claude-sonnet-4-5', provider: 'anthropic', }, ], @@ -229,11 +231,11 @@ async function reasoningModelsExample() { cost: 0, // Free local inference }, { - name: 'o1-mini', + name: 'o4-mini', provider: 'openai', }, { - name: 'claude-3-7-sonnet-20250219', + name: 'claude-sonnet-4-5', provider: 'anthropic', }, ], @@ -242,8 +244,8 @@ async function reasoningModelsExample() { console.log('This cascade tries:'); console.log(' 1. DeepSeek-R1 (local, free)'); - console.log(' 2. Falls back to o1-mini if quality < 0.85'); - console.log(' 3. Falls back to Claude 3.7 as final option'); + console.log(' 2. Falls back to o4-mini if quality < 0.85'); + console.log(' 3. Falls back to Claude Sonnet 4.5 as final option'); console.log(); console.log('Perfect for cost optimization with reasoning models!'); } diff --git a/packages/core/src/presets.ts b/packages/core/src/presets.ts index d0280bc6..301e9225 100644 --- a/packages/core/src/presets.ts +++ b/packages/core/src/presets.ts @@ -88,9 +88,9 @@ function getQualityConfig(mode: QualityMode = 'balanced') { export const PRESET_BEST_OVERALL: { models: ModelConfig[] } = { models: [ { - name: 'claude-3-5-haiku-20241022', + name: 'claude-haiku-4-5', provider: 'anthropic', - cost: 0.0008, + cost: 0.001, }, { name: 'gpt-4o-mini', @@ -220,14 +220,14 @@ export const PRESET_OPENAI_ONLY: { models: ModelConfig[] } = { export const PRESET_ANTHROPIC_ONLY: { models: ModelConfig[] } = { models: [ { - name: 'claude-3-5-haiku-20241022', + name: 'claude-haiku-4-5', provider: 'anthropic', - cost: 0.0008, + cost: 0.001, }, { - name: 'claude-sonnet-4-5-20250929', + name: 'claude-sonnet-4-5', provider: 'anthropic', - cost: 0.009, + cost: 0.003, }, ], }; @@ -319,16 +319,16 @@ export function createPreset(config: PresetConfig = {}): { cost: 0.00015, }); models.push({ - name: 'claude-3-5-haiku-20241022', + name: 'claude-haiku-4-5', provider: 'anthropic', - cost: 0.0008, + cost: 0.001, }); } else { // Balanced - mix of speed and reliability models.push({ - name: 'claude-3-5-haiku-20241022', + name: 'claude-haiku-4-5', provider: 'anthropic', - cost: 0.0008, + cost: 0.001, }); models.push({ name: 'gpt-4o-mini', diff --git a/packages/core/src/providers/openai.ts b/packages/core/src/providers/openai.ts index ee9d554d..016cf1f6 100644 --- a/packages/core/src/providers/openai.ts +++ b/packages/core/src/providers/openai.ts @@ -46,15 +46,19 @@ const OPENAI_PRICING: Record = { 'gpt-4o-2024-08-06': { input: 0.0025, output: 0.010 }, 'gpt-4o-2024-05-13': { input: 0.005, output: 0.015 }, - // O1 series (reasoning models) + // O1 series (reasoning models - previous generation) 'o1-preview': { input: 0.015, output: 0.060 }, 'o1-mini': { input: 0.003, output: 0.012 }, 'o1': { input: 0.015, output: 0.060 }, // o1-2024-12-17 'o1-2024-12-17': { input: 0.015, output: 0.060 }, - // O3 series (reasoning models - future) + // O3 series (reasoning models - released April 2025) + 'o3': { input: 0.010, output: 0.040 }, 'o3-mini': { input: 0.001, output: 0.005 }, + // O4 series (reasoning models - latest, optimized for speed and cost) + 'o4-mini': { input: 0.0008, output: 0.004 }, + // GPT-4 series (previous generation) 'gpt-4-turbo': { input: 0.010, output: 0.030 }, 'gpt-4-turbo-2024-04-09': { input: 0.010, output: 0.030 }, @@ -103,7 +107,7 @@ export function getReasoningModelInfo(modelName: string): ReasoningModelInfo { }; } - // O3-mini (future reasoning model) + // O3 series (released April 2025) if (name.includes('o3-mini')) { return { isReasoning: true, @@ -116,6 +120,31 @@ export function getReasoningModelInfo(modelName: string): ReasoningModelInfo { }; } + if (name === 'o3' || name.startsWith('o3-')) { + return { + isReasoning: true, + provider: 'openai', + supportsStreaming: true, + supportsTools: true, + supportsSystemMessages: false, + supportsReasoningEffort: true, + requiresMaxCompletionTokens: true, + }; + } + + // O4 series (latest reasoning models) + if (name.includes('o4-mini') || name.includes('o4')) { + return { + isReasoning: true, + provider: 'openai', + supportsStreaming: true, + supportsTools: true, + supportsSystemMessages: false, + supportsReasoningEffort: true, + requiresMaxCompletionTokens: true, + }; + } + // Not a reasoning model return { isReasoning: false, diff --git a/packages/core/tests/basic-test.ts b/packages/core/tests/basic-test.ts index 5e765b6f..9a359783 100644 --- a/packages/core/tests/basic-test.ts +++ b/packages/core/tests/basic-test.ts @@ -9,94 +9,77 @@ * - Cost tracking functions */ +import { describe, it, expect } from 'vitest'; import { CascadeAgent } from '../src'; -async function testBasicCascade() { - console.log('๐Ÿงช Testing cascadeflow TypeScript Library\n'); - - // Check for API key - const apiKey = process.env.OPENAI_API_KEY; - if (!apiKey) { - console.error('โŒ OPENAI_API_KEY not found in environment'); - console.log('๐Ÿ’ก Set it in .env file or export it:'); - console.log(' export OPENAI_API_KEY=sk-...\n'); - process.exit(1); - } - - console.log('โœ… OpenAI API key found'); - console.log(` Key: ${apiKey.substring(0, 10)}...${apiKey.substring(apiKey.length - 4)}\n`); - - // Create agent with two-tier cascade - console.log('๐Ÿ“ฆ Creating CascadeAgent...'); - const agent = new CascadeAgent({ - models: [ - { - name: 'gpt-4o-mini', - provider: 'openai', - cost: 0.00015, - apiKey, - }, - { - name: 'gpt-4o', - provider: 'openai', - cost: 0.00625, - apiKey, - }, - ], - }); - - console.log(`โœ… Agent created with ${agent.getModelCount()} models`); - console.log(` Models: ${agent.getModels().map(m => m.name).join(' โ†’ ')}\n`); - - // Test 1: Simple query (should use draft model) - console.log('๐Ÿ” Test 1: Simple query (expect draft model)'); - console.log(' Query: "What is TypeScript?"\n'); - - const startTime = Date.now(); - const result1 = await agent.run('What is TypeScript?'); - const elapsed = Date.now() - startTime; - - console.log('๐Ÿ“Š Result:'); - console.log(` Model used: ${result1.modelUsed}`); - console.log(` Response: ${result1.content.substring(0, 100)}...`); - console.log(` Cost: $${result1.totalCost.toFixed(6)}`); - console.log(` Latency: ${elapsed}ms`); - console.log(` Cascaded: ${result1.cascaded ? 'Yes' : 'No'}`); - console.log(` Draft accepted: ${result1.draftAccepted ? 'Yes' : 'No'}`); - - if (result1.savingsPercentage !== undefined) { - console.log(` Savings: ${result1.savingsPercentage.toFixed(1)}%`); - } - - console.log(''); - - // Validate result - if (!result1.content) { - throw new Error('No content in response'); - } - - if (result1.totalCost <= 0) { - throw new Error('Cost should be greater than 0'); - } - - console.log('โœ… Test 1 passed!\n'); - - // Summary - console.log('โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•'); - console.log('๐ŸŽ‰ All tests passed!'); - console.log('โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•'); - console.log(`Total cost: $${result1.totalCost.toFixed(6)}`); - console.log(`Total time: ${elapsed}ms`); - console.log(''); -} - -// Run tests -testBasicCascade() - .then(() => { - console.log('โœ… Test suite completed successfully'); - process.exit(0); - }) - .catch((error) => { - console.error('\nโŒ Test failed:', error); - process.exit(1); - }); +// Check for API key +const apiKey = process.env.OPENAI_API_KEY; +const hasApiKey = !!apiKey; + +describe('Basic Integration Tests', () => { + it.skipIf(!hasApiKey)('should run basic cascade with OpenAI', async () => { + console.log('๐Ÿงช Testing cascadeflow TypeScript Library\n'); + + console.log('โœ… OpenAI API key found'); + console.log(` Key: ${apiKey!.substring(0, 10)}...${apiKey!.substring(apiKey!.length - 4)}\n`); + + // Create agent with two-tier cascade + console.log('๐Ÿ“ฆ Creating CascadeAgent...'); + const agent = new CascadeAgent({ + models: [ + { + name: 'gpt-4o-mini', + provider: 'openai', + cost: 0.00015, + apiKey, + }, + { + name: 'gpt-4o', + provider: 'openai', + cost: 0.00625, + apiKey, + }, + ], + }); + + console.log(`โœ… Agent created with ${agent.getModelCount()} models`); + console.log(` Models: ${agent.getModels().map(m => m.name).join(' โ†’ ')}\n`); + + // Test 1: Simple query (should use draft model) + console.log('๐Ÿ” Test 1: Simple query (expect draft model)'); + console.log(' Query: "What is TypeScript?"\n'); + + const startTime = Date.now(); + const result1 = await agent.run('What is TypeScript?'); + const elapsed = Date.now() - startTime; + + console.log('๐Ÿ“Š Result:'); + console.log(` Model used: ${result1.modelUsed}`); + console.log(` Response: ${result1.content.substring(0, 100)}...`); + console.log(` Cost: $${result1.totalCost.toFixed(6)}`); + console.log(` Latency: ${elapsed}ms`); + console.log(` Cascaded: ${result1.cascaded ? 'Yes' : 'No'}`); + console.log(` Draft accepted: ${result1.draftAccepted ? 'Yes' : 'No'}`); + + if (result1.savingsPercentage !== undefined) { + console.log(` Savings: ${result1.savingsPercentage.toFixed(1)}%`); + } + + console.log(''); + + // Validate result + expect(result1.content).toBeTruthy(); + expect(result1.content.length).toBeGreaterThan(0); + expect(result1.totalCost).toBeGreaterThan(0); + + console.log('โœ… Test 1 passed!\n'); + + // Summary + console.log('โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•'); + console.log('๐ŸŽ‰ All tests passed!'); + console.log('โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•'); + console.log(`Total cost: $${result1.totalCost.toFixed(6)}`); + console.log(`Total time: ${elapsed}ms`); + console.log(''); + }, 30000); // 30 second timeout for API calls +});