From e041fb6b9b4bcebb670de482eb061a71c8a347c9 Mon Sep 17 00:00:00 2001 From: Anuj Shrivastava Date: Fri, 25 Sep 2026 12:59:13 +0000 Subject: [PATCH] Remove deprecated AI chat models flagged by live model check OpenAI's o3-pro, Mistral's mistral-large-2512 and zai-glm-5-2, and DeepSeek's deepseek-v4-flash / deepseek-v4-flash-vision-exp are no longer served by their upstream APIs, so drop them from the hardcoded provider model lists (closes HeyPuter/puter#3945). DeepSeek's legacy chat/reasoner aliases and default model previously pointed at deepseek-v4-flash; they now resolve to deepseek-v4-pro, the remaining model in that catalog, so existing callers keep working. Signed-off-by: Anuj Shrivastava Signed-off-by: Anuj Shrivastava --- .../deepseek/DeepSeekProvider.test.ts | 77 +++++++++---------- .../providers/deepseek/DeepSeekProvider.ts | 2 +- .../ai-chat/providers/deepseek/models.ts | 63 ++------------- .../ai-chat/providers/mistral/models.ts | 52 ------------- .../OpenAiChatResponsesProvider.test.ts | 68 ++++++++-------- .../ai-chat/providers/openai/models.ts | 22 ------ 6 files changed, 81 insertions(+), 203 deletions(-) diff --git a/src/backend/drivers/ai-chat/providers/deepseek/DeepSeekProvider.test.ts b/src/backend/drivers/ai-chat/providers/deepseek/DeepSeekProvider.test.ts index 423270069..942577c4e 100644 --- a/src/backend/drivers/ai-chat/providers/deepseek/DeepSeekProvider.test.ts +++ b/src/backend/drivers/ai-chat/providers/deepseek/DeepSeekProvider.test.ts @@ -145,9 +145,9 @@ describe('DeepSeekProvider construction', () => { // ── Model catalog ─────────────────────────────────────────────────── describe('DeepSeekProvider model catalog', () => { - it('returns deepseek-v4-flash as the default', () => { + it('returns deepseek-v4-pro as the default', () => { const { provider } = makeProvider(); - expect(provider.getDefaultModel()).toBe('deepseek-v4-flash'); + expect(provider.getDefaultModel()).toBe('deepseek-v4-pro'); }); it('exposes the static DEEPSEEK_MODELS list verbatim from models()', () => { @@ -164,7 +164,6 @@ describe('DeepSeekProvider model catalog', () => { expect(ids).toContain(a); } } - expect(ids).toContain('deepseek-v4-flash'); expect(ids).toContain('deepseek-v4-pro'); expect(ids).toContain('deepseek-chat'); expect(ids).toContain('deepseek/deepseek-v4-pro'); @@ -190,13 +189,13 @@ describe('DeepSeekProvider.complete request shape', () => { await withTestActor(() => provider.complete({ - model: 'deepseek-v4-flash', + model: 'deepseek-v4-pro', messages: [{ role: 'user', content: 'hello' }], }), ); const [args] = createMock.mock.calls[0]!; - expect(args.model).toBe('deepseek-v4-flash'); + expect(args.model).toBe('deepseek-v4-pro'); expect(args.messages).toEqual([{ role: 'user', content: 'hello' }]); expect(args.max_tokens).toBe(1000); }); @@ -207,7 +206,7 @@ describe('DeepSeekProvider.complete request shape', () => { await withTestActor(() => provider.complete({ - model: 'deepseek-v4-flash', + model: 'deepseek-v4-pro', messages: [{ role: 'user', content: 'hi' }], max_tokens: 256, }), @@ -222,7 +221,7 @@ describe('DeepSeekProvider.complete request shape', () => { await withTestActor(() => provider.complete({ - model: 'deepseek-v4-flash', + model: 'deepseek-v4-pro', messages: [{ role: 'user', content: 'hi' }], max_tokens: 0, }), @@ -237,7 +236,7 @@ describe('DeepSeekProvider.complete request shape', () => { await withTestActor(() => provider.complete({ - model: 'deepseek-v4-flash', + model: 'deepseek-v4-pro', messages: [{ role: 'user', content: 'hi' }], }), ); @@ -261,7 +260,7 @@ describe('DeepSeekProvider.complete request shape', () => { ]; await withTestActor(() => provider.complete({ - model: 'deepseek-v4-flash', + model: 'deepseek-v4-pro', messages: [{ role: 'user', content: 'hi' }], tools, }), @@ -275,7 +274,7 @@ describe('DeepSeekProvider.complete request shape', () => { createMock.mockResolvedValueOnce(baseCompletion); await withTestActor(() => provider.complete({ - model: 'deepseek-v4-flash', + model: 'deepseek-v4-pro', messages: [{ role: 'user', content: 'hi' }], stream: false, }), @@ -287,7 +286,7 @@ describe('DeepSeekProvider.complete request shape', () => { createMock.mockReturnValueOnce(asAsyncIterable([])); await withTestActor(() => provider.complete({ - model: 'deepseek-v4-flash', + model: 'deepseek-v4-pro', messages: [{ role: 'user', content: 'hi' }], stream: true, }), @@ -303,7 +302,7 @@ describe('DeepSeekProvider.complete request shape', () => { await withTestActor(() => provider.complete({ - model: 'deepseek-v4-flash', + model: 'deepseek-v4-pro', messages: [ { role: 'assistant', @@ -344,7 +343,7 @@ describe('DeepSeekProvider.complete request shape', () => { await withTestActor(() => provider.complete({ - model: 'deepseek-v4-flash', + model: 'deepseek-v4-pro', messages: [ { role: 'assistant', @@ -381,7 +380,7 @@ describe('DeepSeekProvider.complete request shape', () => { await withTestActor(() => provider.complete({ - model: 'deepseek-v4-flash', + model: 'deepseek-v4-pro', messages: [ { role: 'user', content: 'do tool call' }, { @@ -429,16 +428,16 @@ describe('DeepSeekProvider model resolution', () => { await withTestActor(() => provider.complete({ - model: 'deepseek-v4-flash', + model: 'deepseek-v4-pro', messages: [{ role: 'user', content: 'hi' }], }), ); - expect(createMock.mock.calls[0]![0].model).toBe('deepseek-v4-flash'); + expect(createMock.mock.calls[0]![0].model).toBe('deepseek-v4-pro'); expect(recordSpy).toHaveBeenCalledWith( expect.any(Object), expect.anything(), - 'deepseek:deepseek-v4-flash', + 'deepseek:deepseek-v4-pro', expect.any(Object), ); }); @@ -449,17 +448,17 @@ describe('DeepSeekProvider model resolution', () => { await withTestActor(() => provider.complete({ - // `deepseek/deepseek-v4-flash` is an alias of `deepseek-v4-flash`. - model: 'deepseek/deepseek-v4-flash', + // `deepseek/deepseek-v4-pro` is an alias of `deepseek-v4-pro`. + model: 'deepseek/deepseek-v4-pro', messages: [{ role: 'user', content: 'hi' }], }), ); - expect(createMock.mock.calls[0]![0].model).toBe('deepseek-v4-flash'); + expect(createMock.mock.calls[0]![0].model).toBe('deepseek-v4-pro'); expect(recordSpy).toHaveBeenCalledWith( expect.any(Object), expect.anything(), - 'deepseek:deepseek-v4-flash', + 'deepseek:deepseek-v4-pro', expect.any(Object), ); }); @@ -475,26 +474,26 @@ describe('DeepSeekProvider model resolution', () => { }), ); - expect(createMock.mock.calls[0]![0].model).toBe('deepseek-v4-flash'); + expect(createMock.mock.calls[0]![0].model).toBe('deepseek-v4-pro'); expect(recordSpy).toHaveBeenCalledWith( expect.any(Object), expect.anything(), - 'deepseek:deepseek-v4-flash', + 'deepseek:deepseek-v4-pro', expect.any(Object), ); }); // The legacy DeepSeek chat/reasoner ids (and their `deepseek/…` and - // `deepseek:deepseek/…` variants) are aliased onto deepseek-v4-flash + // `deepseek:deepseek/…` variants) are aliased onto deepseek-v4-pro // so callers using the old names get transparently upgraded — and - // metered against the v4-flash canonical prefix. + // metered against the v4-pro canonical prefix. it.each([ 'deepseek-chat', 'deepseek/deepseek-chat', 'deepseek:deepseek/deepseek-chat', 'deepseek/deepseek-reasoner', 'deepseek:deepseek/deepseek-reasoner', - ])('maps legacy alias %s onto deepseek-v4-flash', async (alias) => { + ])('maps legacy alias %s onto deepseek-v4-pro', async (alias) => { const { provider } = makeProvider(); createMock.mockResolvedValueOnce(baseCompletion); @@ -505,11 +504,11 @@ describe('DeepSeekProvider model resolution', () => { }), ); - expect(createMock.mock.calls[0]![0].model).toBe('deepseek-v4-flash'); + expect(createMock.mock.calls[0]![0].model).toBe('deepseek-v4-pro'); expect(recordSpy).toHaveBeenCalledWith( expect.any(Object), expect.anything(), - 'deepseek:deepseek-v4-flash', + 'deepseek:deepseek-v4-pro', expect.any(Object), ); }); @@ -536,7 +535,7 @@ describe('DeepSeekProvider.complete non-stream output', () => { const result = await withTestActor(() => provider.complete({ - model: 'deepseek-v4-flash', + model: 'deepseek-v4-pro', messages: [{ role: 'user', content: 'hi' }], }), ); @@ -551,8 +550,8 @@ describe('DeepSeekProvider.complete non-stream output', () => { cached_tokens: 10, }); - // deepseek-v4-flash costs: prompt=14, completion=28, cached=0.28 - const chat = DEEPSEEK_MODELS.find((m) => m.id === 'deepseek-v4-flash')!; + // deepseek-v4-pro costs: prompt=174, completion=348, cached=1.45 + const chat = DEEPSEEK_MODELS.find((m) => m.id === 'deepseek-v4-pro')!; expect(recordSpy).toHaveBeenCalledTimes(1); const [usage, actor, prefix, overrides] = recordSpy.mock.calls[0]!; expect(usage).toEqual({ @@ -561,7 +560,7 @@ describe('DeepSeekProvider.complete non-stream output', () => { cached_tokens: 10, }); expect(actor).toBe(SYSTEM_ACTOR); - expect(prefix).toBe('deepseek:deepseek-v4-flash'); + expect(prefix).toBe('deepseek:deepseek-v4-pro'); expect(overrides).toEqual({ prompt_tokens: 100 * Number(chat.costs.prompt_tokens), completion_tokens: 50 * Number(chat.costs.completion_tokens), @@ -596,7 +595,7 @@ describe('DeepSeekProvider.complete non-stream output', () => { const result = (await withTestActor(() => provider.complete({ - model: 'deepseek-v4-flash', + model: 'deepseek-v4-pro', messages: [{ role: 'user', content: 'do a tool call' }], tools: [ { @@ -631,7 +630,7 @@ describe('DeepSeekProvider.complete non-stream output', () => { await withTestActor(() => provider.complete({ - model: 'deepseek-v4-flash', + model: 'deepseek-v4-pro', messages: [{ role: 'user', content: 'hi' }], }), ); @@ -664,7 +663,7 @@ describe('DeepSeekProvider.complete streaming', () => { const result = await withTestActor(() => provider.complete({ - model: 'deepseek-v4-flash', + model: 'deepseek-v4-pro', messages: [{ role: 'user', content: 'say hi' }], stream: true, }), @@ -689,10 +688,10 @@ describe('DeepSeekProvider.complete streaming', () => { cached_tokens: 1, }); - const chat = DEEPSEEK_MODELS.find((m) => m.id === 'deepseek-v4-flash')!; + const chat = DEEPSEEK_MODELS.find((m) => m.id === 'deepseek-v4-pro')!; expect(recordSpy).toHaveBeenCalledTimes(1); const [, , prefix, overrides] = recordSpy.mock.calls[0]!; - expect(prefix).toBe('deepseek:deepseek-v4-flash'); + expect(prefix).toBe('deepseek:deepseek-v4-pro'); expect(overrides).toEqual({ prompt_tokens: 4 * Number(chat.costs.prompt_tokens), completion_tokens: 2 * Number(chat.costs.completion_tokens), @@ -745,7 +744,7 @@ describe('DeepSeekProvider.complete streaming', () => { const result = await withTestActor(() => provider.complete({ - model: 'deepseek-v4-flash', + model: 'deepseek-v4-pro', messages: [{ role: 'user', content: 'do tool call' }], tools: [ { @@ -784,7 +783,7 @@ describe('DeepSeekProvider.complete error mapping', () => { await expect( withTestActor(() => provider.complete({ - model: 'deepseek-v4-flash', + model: 'deepseek-v4-pro', messages: [{ role: 'user', content: 'boom' }], }), ), diff --git a/src/backend/drivers/ai-chat/providers/deepseek/DeepSeekProvider.ts b/src/backend/drivers/ai-chat/providers/deepseek/DeepSeekProvider.ts index a8faac7ae..4bc788717 100644 --- a/src/backend/drivers/ai-chat/providers/deepseek/DeepSeekProvider.ts +++ b/src/backend/drivers/ai-chat/providers/deepseek/DeepSeekProvider.ts @@ -41,7 +41,7 @@ export class DeepSeekProvider implements IChatProvider { } getDefaultModel() { - return 'deepseek-v4-flash'; + return 'deepseek-v4-pro'; } models() { diff --git a/src/backend/drivers/ai-chat/providers/deepseek/models.ts b/src/backend/drivers/ai-chat/providers/deepseek/models.ts index a940e317c..e363b748d 100644 --- a/src/backend/drivers/ai-chat/providers/deepseek/models.ts +++ b/src/backend/drivers/ai-chat/providers/deepseek/models.ts @@ -21,60 +21,6 @@ import type { IChatModel } from '../../types.js'; // Hardcoded from https://models.dev/api.json export const DEEPSEEK_MODELS: IChatModel[] = [ - { - puterId: 'deepseek:deepseek/deepseek-v4-flash', - id: 'deepseek-v4-flash', - modalities: { input: ['text'], output: ['text'] }, - open_weights: false, - tool_call: true, - knowledge: '2026-04', - release_date: '2026-04-24', - name: 'DeepSeek Chat', - aliases: [ - 'deepseek/deepseek-v4-flash', - 'deepseek-chat', - 'deepseek/deepseek-chat', - 'deepseek/deepseek-reasoner', - 'deepseek:deepseek/deepseek-reasoner', - 'deepseek:deepseek/deepseek-chat', - ], - context: 1_000_000, - costs_currency: 'usd-cents', - input_cost_key: 'prompt_tokens', - output_cost_key: 'completion_tokens', - costs: { - tokens: 1_000_000, - prompt_tokens: 14, - completion_tokens: 28, - cached_tokens: 0.28, - }, - max_tokens: 384_000, - }, - { - // Priced identically to deepseek-v4-flash per DeepSeek's launch note - // (https://api-docs.deepseek.com/news/news260821/) and the pricing - // page, which lists the same rates for both models; images are - // tokenized (up to 384 tokens each) and billed as input tokens. - puterId: 'deepseek:deepseek/deepseek-v4-flash-vision-exp', - id: 'deepseek-v4-flash-vision-exp', - modalities: { input: ['text', 'image'], output: ['text'] }, - open_weights: false, - tool_call: true, - release_date: '2026-08-21', - name: 'DeepSeek V4 Flash Vision (Experimental)', - aliases: ['deepseek/deepseek-v4-flash-vision-exp'], - context: 1_000_000, - costs_currency: 'usd-cents', - input_cost_key: 'prompt_tokens', - output_cost_key: 'completion_tokens', - costs: { - tokens: 1_000_000, - prompt_tokens: 14, - completion_tokens: 28, - cached_tokens: 0.28, - }, - max_tokens: 384_000, - }, { puterId: 'deepseek:deepseek/deepseek-v4-pro', id: 'deepseek-v4-pro', @@ -84,7 +30,14 @@ export const DEEPSEEK_MODELS: IChatModel[] = [ knowledge: '2026-04', release_date: '2026-04-24', name: 'DeepSeek Chat', - aliases: ['deepseek/deepseek-v4-pro'], + aliases: [ + 'deepseek/deepseek-v4-pro', + 'deepseek-chat', + 'deepseek/deepseek-chat', + 'deepseek/deepseek-reasoner', + 'deepseek:deepseek/deepseek-reasoner', + 'deepseek:deepseek/deepseek-chat', + ], context: 1_000_000, costs_currency: 'usd-cents', input_cost_key: 'prompt_tokens', diff --git a/src/backend/drivers/ai-chat/providers/mistral/models.ts b/src/backend/drivers/ai-chat/providers/mistral/models.ts index cbcc1d753..c99803dae 100644 --- a/src/backend/drivers/ai-chat/providers/mistral/models.ts +++ b/src/backend/drivers/ai-chat/providers/mistral/models.ts @@ -53,35 +53,6 @@ export const MISTRAL_MODELS: IChatModel[] = [ completion_tokens: 750, }, }, - { - puterId: 'mistralai:mistralai/mistral-large-2512', - id: 'mistral-large-2512', - modalities: { input: ['text', 'image'], output: ['text'] }, - open_weights: true, - tool_call: true, - knowledge: '2025-12', - release_date: '2025-12-02', - name: 'Mistral Large 3', - aliases: [ - 'mistral-large-latest', - 'mistral-large', - 'mistralai/mistral-large-latest', - 'mistralai/mistral-large-2512', - ], - context: 262_144, - max_tokens: 262_144, - description: - 'State-of-the-art, open-weight, general-purpose multimodal model.', - provider: 'mistral', - costs_currency: 'usd-cents', - input_cost_key: 'prompt_tokens', - output_cost_key: 'completion_tokens', - costs: { - tokens: 1_000_000, - prompt_tokens: 50, - completion_tokens: 150, - }, - }, { puterId: 'mistralai:mistralai/mistral-small-2603', id: 'mistral-small-2603', @@ -111,29 +82,6 @@ export const MISTRAL_MODELS: IChatModel[] = [ completion_tokens: 60, }, }, - { - puterId: 'mistralai:mistralai/zai-glm-5-2', - id: 'zai-glm-5-2', - modalities: { input: ['text'], output: ['text'] }, - open_weights: true, - tool_call: true, - release_date: '2026-08-06', - name: 'Z.ai GLM 5.2', - aliases: ['glm-5-2'], - context: 1_000_000, - max_tokens: 128_000, - description: - 'Third-party open-source model from Z.ai, hosted by Mistral for long-context coding and agentic workflows.', - provider: 'mistral', - costs_currency: 'usd-cents', - input_cost_key: 'prompt_tokens', - output_cost_key: 'completion_tokens', - costs: { - tokens: 1_000_000, - prompt_tokens: 140, - completion_tokens: 440, - }, - }, { puterId: 'mistralai:mistralai/codestral-2508', id: 'codestral-2508', diff --git a/src/backend/drivers/ai-chat/providers/openai/OpenAiChatResponsesProvider.test.ts b/src/backend/drivers/ai-chat/providers/openai/OpenAiChatResponsesProvider.test.ts index 784f078bc..93be22226 100644 --- a/src/backend/drivers/ai-chat/providers/openai/OpenAiChatResponsesProvider.test.ts +++ b/src/backend/drivers/ai-chat/providers/openai/OpenAiChatResponsesProvider.test.ts @@ -193,7 +193,7 @@ describe('OpenAiResponsesChatProvider model catalog', () => { it('models() exposes Responses-only and dual-API entries', () => { const { provider } = makeProvider(); const ids = provider.models().map((m: { id: string }) => m.id); - expect(ids).toContain('o3-pro'); + expect(ids).toContain('gpt-5.6-sol'); expect(ids).toContain('gpt-6-astra'); expect(ids).not.toContain('gpt-5-nano-2025-08-07'); }); @@ -236,15 +236,15 @@ describe('OpenAiResponsesChatProvider model catalog', () => { .models({ no_restrictions: true }) .map((m: { id: string }) => m.id); // Both responses-only AND chat-only ids should be present. - expect(ids).toContain('o3-pro'); + expect(ids).toContain('gpt-5.6-sol'); expect(ids).toContain('gpt-5-nano-2025-08-07'); }); it('list() flattens canonical ids and aliases for Responses models', () => { const { provider } = makeProvider(); const ids = provider.list(); - expect(ids).toContain('o3-pro'); - expect(ids).toContain('openai/o3-pro'); + expect(ids).toContain('gpt-5.6-sol'); + expect(ids).toContain('openai/gpt-5.6-sol'); expect(ids).toContain('gpt-6-astra'); expect(ids).toContain('openai/gpt-6-astra'); }); @@ -258,7 +258,7 @@ describe('OpenAiResponsesChatProvider.complete argument validation', () => { await expect( withTestActor(() => provider.complete({ - model: 'o3-pro', + model: 'gpt-5.6-sol', messages: 'hello' as unknown as never, }), ), @@ -283,7 +283,7 @@ describe('OpenAiResponsesChatProvider.complete request shape', () => { await withTestActor(() => provider.complete({ - model: 'o3-pro', + model: 'gpt-5.6-sol', messages: [{ role: 'user', content: 'hello' }], max_tokens: 256, temperature: 0.4, @@ -291,7 +291,7 @@ describe('OpenAiResponsesChatProvider.complete request shape', () => { ); const [args] = responsesCreateMock.mock.calls[0]!; - expect(args.model).toBe('o3-pro'); + expect(args.model).toBe('gpt-5.6-sol'); // Responses API takes `input`, not `messages`. expect(args.input).toEqual([{ role: 'user', content: 'hello' }]); expect(args.max_output_tokens).toBe(256); @@ -306,7 +306,7 @@ describe('OpenAiResponsesChatProvider.complete request shape', () => { await withTestActor( () => provider.complete({ - model: 'o3-pro', + model: 'gpt-5.6-sol', messages: [{ role: 'user', content: 'hello' }], }), actor, @@ -325,7 +325,7 @@ describe('OpenAiResponsesChatProvider.complete request shape', () => { await withTestActor(() => provider.complete({ - model: 'o3-pro', + model: 'gpt-5.6-sol', messages: [{ role: 'user', content: 'hi' }], tools: [ { @@ -363,7 +363,7 @@ describe('OpenAiResponsesChatProvider.complete request shape', () => { await withTestActor(() => provider.complete({ - model: 'o3-pro', + model: 'gpt-5.6-sol', messages: [{ role: 'user', content: 'hi' }], tool_choice: 'auto', parallel_tool_calls: false, @@ -404,11 +404,11 @@ describe('OpenAiResponsesChatProvider.complete request shape', () => { expect('reasoning_effort' in gpt5Args).toBe(false); expect('verbosity' in gpt5Args).toBe(false); - // o3-pro: not gpt-5 → forwards both. + // o3: not gpt-5 → forwards both. responsesCreateMock.mockResolvedValueOnce(baseResponse); await withTestActor(() => provider.complete({ - model: 'o3-pro', + model: 'o3', messages: [{ role: 'user', content: 'hi' }], reasoning_effort: 'medium', verbosity: 'low', @@ -509,17 +509,17 @@ describe('OpenAiResponsesChatProvider model resolution', () => { await withTestActor(() => provider.complete({ - // openai/o3-pro is an alias of o3-pro. - model: 'openai/o3-pro', + // openai/gpt-5.6-sol is an alias of gpt-5.6-sol. + model: 'openai/gpt-5.6-sol', messages: [{ role: 'user', content: 'hi' }], }), ); - expect(responsesCreateMock.mock.calls[0]![0].model).toBe('o3-pro'); + expect(responsesCreateMock.mock.calls[0]![0].model).toBe('gpt-5.6-sol'); expect(recordSpy).toHaveBeenCalledWith( expect.any(Object), expect.anything(), - 'openai:o3-pro', + 'openai:gpt-5.6-sol', expect.any(Object), ); }); @@ -565,7 +565,7 @@ describe('OpenAiResponsesChatProvider.complete non-stream output', () => { const result = await withTestActor(() => provider.complete({ - model: 'o3-pro', + model: 'gpt-5.6-sol', messages: [{ role: 'user', content: 'hi' }], }), ); @@ -584,21 +584,21 @@ describe('OpenAiResponsesChatProvider.complete non-stream output', () => { cached_tokens: 10, }); - // o3-pro costs: prompt=2000, completion=8000, cached=50. - const o3pro = OPEN_AI_MODELS.find((m) => m.id === 'o3-pro')!; + // gpt-5.6-sol costs: prompt=400, completion=2000, cached=40. + const sol = OPEN_AI_MODELS.find((m) => m.id === 'gpt-5.6-sol')!; expect(recordSpy).toHaveBeenCalledTimes(1); const [usage, actor, prefix, overrides] = recordSpy.mock.calls[0]!; expect(actor).toBe(SYSTEM_ACTOR); - expect(prefix).toBe('openai:o3-pro'); + expect(prefix).toBe('openai:gpt-5.6-sol'); expect(usage).toEqual({ prompt_tokens: 90, completion_tokens: 50, cached_tokens: 10, }); expect(overrides).toEqual({ - prompt_tokens: 90 * Number(o3pro.costs.prompt_tokens), - completion_tokens: 50 * Number(o3pro.costs.completion_tokens), - cached_tokens: 10 * Number(o3pro.costs.cached_tokens ?? 0), + prompt_tokens: 90 * Number(sol.costs.prompt_tokens), + completion_tokens: 50 * Number(sol.costs.completion_tokens), + cached_tokens: 10 * Number(sol.costs.cached_tokens ?? 0), }); }); @@ -742,7 +742,7 @@ describe('OpenAiResponsesChatProvider.complete non-stream output', () => { const result = (await withTestActor(() => provider.complete({ - model: 'o3-pro', + model: 'gpt-5.6-sol', messages: [{ role: 'user', content: 'do a tool call' }], }), )) as { message: { tool_calls?: unknown[] } }; @@ -768,7 +768,7 @@ describe('OpenAiResponsesChatProvider.complete non-stream output', () => { await expect( withTestActor(() => provider.complete({ - model: 'o3-pro', + model: 'gpt-5.6-sol', messages: [{ role: 'user', content: 'silence' }], }), ), @@ -800,7 +800,7 @@ describe('OpenAiResponsesChatProvider.complete streaming', () => { const result = await withTestActor(() => provider.complete({ - model: 'o3-pro', + model: 'gpt-5.6-sol', messages: [{ role: 'user', content: 'say hi' }], stream: true, }), @@ -826,15 +826,15 @@ describe('OpenAiResponsesChatProvider.complete streaming', () => { cached_tokens: 1, }); - // o3-pro costs: prompt=2000, completion=8000, cached=50. - const o3pro = OPEN_AI_MODELS.find((m) => m.id === 'o3-pro')!; + // gpt-5.6-sol costs: prompt=400, completion=2000, cached=40. + const sol = OPEN_AI_MODELS.find((m) => m.id === 'gpt-5.6-sol')!; expect(recordSpy).toHaveBeenCalledTimes(1); const [, , prefix, overrides] = recordSpy.mock.calls[0]!; - expect(prefix).toBe('openai:o3-pro'); + expect(prefix).toBe('openai:gpt-5.6-sol'); expect(overrides).toEqual({ - prompt_tokens: 3 * Number(o3pro.costs.prompt_tokens), - completion_tokens: 2 * Number(o3pro.costs.completion_tokens), - cached_tokens: 1 * Number(o3pro.costs.cached_tokens ?? 0), + prompt_tokens: 3 * Number(sol.costs.prompt_tokens), + completion_tokens: 2 * Number(sol.costs.completion_tokens), + cached_tokens: 1 * Number(sol.costs.cached_tokens ?? 0), }); }); @@ -863,7 +863,7 @@ describe('OpenAiResponsesChatProvider.complete streaming', () => { const result = await withTestActor(() => provider.complete({ - model: 'o3-pro', + model: 'gpt-5.6-sol', messages: [{ role: 'user', content: 'tool call' }], stream: true, }), @@ -928,7 +928,7 @@ describe('OpenAiResponsesChatProvider.complete error mapping', () => { await expect( withTestActor(() => provider.complete({ - model: 'o3-pro', + model: 'gpt-5.6-sol', messages: [{ role: 'user', content: 'boom' }], }), ), diff --git a/src/backend/drivers/ai-chat/providers/openai/models.ts b/src/backend/drivers/ai-chat/providers/openai/models.ts index 099ec70ac..657ec0609 100644 --- a/src/backend/drivers/ai-chat/providers/openai/models.ts +++ b/src/backend/drivers/ai-chat/providers/openai/models.ts @@ -556,28 +556,6 @@ export const OPEN_AI_MODELS: IChatModel[] = [ context: 200_000, max_tokens: 100000, }, - { - puterId: 'openai:openai/o3-pro', - id: 'o3-pro', - modalities: { input: ['text', 'image'], output: ['text'] }, - open_weights: false, - tool_call: true, - knowledge: '2024-05', - release_date: '2025-06-10', - aliases: ['o3-pro-2025-06-10', 'openai/o3-pro'], - costs_currency: 'usd-cents', - input_cost_key: 'prompt_tokens', - output_cost_key: 'completion_tokens', - costs: { - tokens: 1_000_000, - prompt_tokens: 2000, - cached_tokens: 50, - completion_tokens: 8000, - }, - context: 200_000, - max_tokens: 100000, - responses_api_only: true, - }, { puterId: 'openai:openai/o3-mini', id: 'o3-mini',