diff --git a/apps/web/src/app/api/openrouter/[...path]/route.ts b/apps/web/src/app/api/openrouter/[...path]/route.ts index 0aeaa0023..f15667c47 100644 --- a/apps/web/src/app/api/openrouter/[...path]/route.ts +++ b/apps/web/src/app/api/openrouter/[...path]/route.ts @@ -28,6 +28,7 @@ import { isExcludedForFeature, isKiloExclusiveFreeModel, isKiloStealthModel, + requiresKiloDataCollection, } from '@/lib/ai-gateway/models'; import { isFreeModel } from '@/lib/ai-gateway/is-free-model'; import { @@ -498,7 +499,7 @@ export async function POST(request: NextRequest): Promise { describe('free models', () => { @@ -54,6 +56,16 @@ describe('isFreeModel', () => { } }); + test('routes the discounted Claude Opus offering through the stealth provider identity', () => { + expect(getInferenceProvider(claude_opus_4_7_stealth_model)).toBe('stealth'); + expect(claude_opus_4_7_stealth_model.public_id).toBe('stealth/claude-opus-4.7'); + }); + + test('requires data collection for paid training-enabled offerings', () => { + expect(requiresKiloDataCollection(claude_opus_4_7_stealth_model.public_id)).toBe(true); + expect(requiresKiloDataCollection(qwen36_plus_model.public_id)).toBe(false); + }); + test('all Kilo exclusive models should have either no pricing or valid pricing', () => { // Verify that all kilo exclusive models have valid pricing structure for (const model of kiloExclusiveModels) { diff --git a/apps/web/src/lib/ai-gateway/models.ts b/apps/web/src/lib/ai-gateway/models.ts index fed0d76ec..2c4ae0197 100644 --- a/apps/web/src/lib/ai-gateway/models.ts +++ b/apps/web/src/lib/ai-gateway/models.ts @@ -10,6 +10,7 @@ import { } from '@/lib/ai-gateway/auto-model'; import { CLAUDE_OPUS_CURRENT_MODEL_ID, + claude_opus_4_7_stealth_model, claude_sonnet_clawsetup_model, CLAUDE_SONNET_CURRENT_MODEL_ID, } from '@/lib/ai-gateway/providers/anthropic.constants'; @@ -80,9 +81,19 @@ export const kiloExclusiveModels = [ seed_20_code_free_model, ...alibabaDirectModels, claude_sonnet_clawsetup_model, + claude_opus_4_7_stealth_model, stepfun_35_flash_free_model, ] as KiloExclusiveModel[]; +export function requiresKiloDataCollection(model: string): boolean { + return kiloExclusiveModels.some( + m => + m.public_id === model && + m.status !== 'disabled' && + (!m.pricing || m.flags.includes('requires-data-collection')) + ); +} + export function isKiloStealthModel(model: string): boolean { return kiloExclusiveModels.some(m => m.public_id === model && m.flags.includes('stealth')); } diff --git a/apps/web/src/lib/ai-gateway/processUsage.calculatKiloExclusiveCost.test.ts b/apps/web/src/lib/ai-gateway/processUsage.calculatKiloExclusiveCost.test.ts index 60fc64253..e224cbb60 100644 --- a/apps/web/src/lib/ai-gateway/processUsage.calculatKiloExclusiveCost.test.ts +++ b/apps/web/src/lib/ai-gateway/processUsage.calculatKiloExclusiveCost.test.ts @@ -2,6 +2,7 @@ import { test, describe, expect } from '@jest/globals'; import { calculateKiloExclusiveCost_mUsd } from './processUsage'; import type { JustTheCostsUsageStats } from './processUsage.types'; import type { KiloExclusiveModel } from '@/lib/ai-gateway/providers/kilo-exclusive-model'; +import { claude_opus_4_7_stealth_model } from '@/lib/ai-gateway/providers/anthropic.constants'; import { qwen36_27b_model, qwen36_flash_model, @@ -401,6 +402,29 @@ describe('calculatKiloExclusiveCost_mUsd with qwen3.6-max-preview', () => { }); }); +describe('calculatKiloExclusiveCost_mUsd with stealth Claude Opus 4.7', () => { + test('uses the 20% lower flat price for uncached tokens', () => { + const result = calculateKiloExclusiveCost_mUsd( + claude_opus_4_7_stealth_model, + makeUsage({ inputTokens: 100_000, outputTokens: 10_000 }) + ); + expect(result).toBe(600_000); + }); + + test('uses the discounted Anthropic-compatible cache prices', () => { + const result = calculateKiloExclusiveCost_mUsd( + claude_opus_4_7_stealth_model, + makeUsage({ + inputTokens: 150_000, + outputTokens: 10_000, + cacheHitTokens: 25_000, + cacheWriteTokens: 25_000, + }) + ); + expect(result).toBe(735_000); + }); +}); + describe('calculatKiloExclusiveCost_mUsd with qwen3.6-27b', () => { // Pre-discount prices (35% Kilo discount applied in code): // Input: $0.5/1M → $0.325/1M Output: $5/1M → $3.25/1M diff --git a/apps/web/src/lib/ai-gateway/providers/anthropic.constants.ts b/apps/web/src/lib/ai-gateway/providers/anthropic.constants.ts index 8272fafb0..89dbe15f7 100644 --- a/apps/web/src/lib/ai-gateway/providers/anthropic.constants.ts +++ b/apps/web/src/lib/ai-gateway/providers/anthropic.constants.ts @@ -1,13 +1,46 @@ -import type { KiloExclusiveModel } from '@/lib/ai-gateway/providers/kilo-exclusive-model'; +import type { + KiloExclusiveModel, + Pricing, + Usage, +} from '@/lib/ai-gateway/providers/kilo-exclusive-model'; export const CLAUDE_SONNET_CURRENT_MODEL_ID = 'anthropic/claude-sonnet-4.6'; export const CLAUDE_OPUS_CURRENT_MODEL_ID = 'anthropic/claude-opus-4.7'; export const CLAUDE_HAIKU_CURRENT_MODEL_ID = 'anthropic/claude-haiku-4.5'; +export const CLAUDE_OPUS_STEALTH_MODEL_ID = 'stealth/claude-opus-4.7'; export const CLAUDE_SONNET_CURRENT_VERCEL_MODEL_ID = CLAUDE_SONNET_CURRENT_MODEL_ID; export const CLAUDE_OPUS_CURRENT_VERCEL_MODEL_ID = CLAUDE_OPUS_CURRENT_MODEL_ID; export const CLAUDE_HAIKU_CURRENT_VERCEL_MODEL_ID = CLAUDE_HAIKU_CURRENT_MODEL_ID; +const CLAUDE_OPUS_STEALTH_PRICING: Pricing = { + prompt_per_million: 4, + completion_per_million: 20, + input_cache_read_per_million: 0.4, + input_cache_write_per_million: 5, + calculate_mUsd: (usage: Usage) => + usage.uncachedInputTokens * 4 + + usage.totalOutputTokens * 20 + + usage.cacheHitTokens * 0.4 + + usage.cacheWriteTokens * 5, +}; + +export const claude_opus_4_7_stealth_model: KiloExclusiveModel = { + public_id: CLAUDE_OPUS_STEALTH_MODEL_ID, + internal_id: 'anthropic/claude-opus-4-7:optimized', + display_name: 'Stealth: Claude Opus 4.7 (20% off)', + description: + "Your prompts and completions may be retained and used to train or improve the provider's services. This third-party-served variant of Claude Opus 4.7 is offered at 20% lower cost than standard Claude Opus 4.7 pricing and is not served by Anthropic or Kilo Code.", + status: 'public', + context_length: 1_000_000, + max_completion_tokens: 128_000, + gateway: 'martian', + flags: ['reasoning', 'vision', 'stealth', 'requires-data-collection'], + pricing: CLAUDE_OPUS_STEALTH_PRICING, + exclusive_to: [], + inference_provider_restriction: [], +}; + export const claude_sonnet_clawsetup_model: KiloExclusiveModel = { public_id: CLAUDE_SONNET_CURRENT_MODEL_ID + ':clawsetup', internal_id: CLAUDE_SONNET_CURRENT_MODEL_ID, diff --git a/apps/web/src/lib/ai-gateway/providers/kilo-exclusive-model.ts b/apps/web/src/lib/ai-gateway/providers/kilo-exclusive-model.ts index 288f65c1f..67a41a108 100644 --- a/apps/web/src/lib/ai-gateway/providers/kilo-exclusive-model.ts +++ b/apps/web/src/lib/ai-gateway/providers/kilo-exclusive-model.ts @@ -6,7 +6,12 @@ import { import type { ProviderId } from '@/lib/ai-gateway/providers/types'; import type { GatewayRequest } from '@/lib/ai-gateway/providers/openrouter/types'; -export type KiloExclusiveModelFlag = 'reasoning' | 'vision' | 'stealth' | 'vercel-routing'; +export type KiloExclusiveModelFlag = + | 'reasoning' + | 'vision' + | 'stealth' + | 'vercel-routing' + | 'requires-data-collection'; export type Usage = { uncachedInputTokens: number; diff --git a/apps/web/src/lib/ai-gateway/providers/provider-definitions.ts b/apps/web/src/lib/ai-gateway/providers/provider-definitions.ts index 01e803d0a..bc9cd7560 100644 --- a/apps/web/src/lib/ai-gateway/providers/provider-definitions.ts +++ b/apps/web/src/lib/ai-gateway/providers/provider-definitions.ts @@ -52,7 +52,7 @@ export default { id: 'martian', apiUrl: 'https://api.withmartian.com/v1', apiKey: getEnvVariable('MARTIAN_API_KEY'), - supportedChatApis: ['responses'], + supportedChatApis: ['responses', 'messages'], transformRequest() {}, }, MISTRAL: {