mirror of
https://github.com/HeyPuter/puter.git
synced 2026-10-10 22:01:40 +00:00
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 <anujshrivastava10e@gmail.com> Signed-off-by: Anuj Shrivastava <anuj.shrivastava@btr.group>
This commit is contained in:
1 parent
5721bdeb1d
commit
e041fb6b9b
6 files changed
+81
-203
No files matched your search
@@ -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' }],
|
||||
}),
|
||||
),
|
||||
|
||||
@@ -41,7 +41,7 @@ export class DeepSeekProvider implements IChatProvider {
|
||||
}
|
||||
|
||||
getDefaultModel() {
|
||||
return 'deepseek-v4-flash';
|
||||
return 'deepseek-v4-pro';
|
||||
}
|
||||
|
||||
models() {
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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' }],
|
||||
}),
|
||||
),
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in new issue
Block a user