mirror of
https://github.com/HeyPuter/puter.git
synced 2026-09-23 13:46:11 +00:00
fix: updaet deepseek models (#3082)
This commit is contained in:
@@ -145,9 +145,9 @@ describe('DeepSeekProvider construction', () => {
|
||||
// ── Model catalog ───────────────────────────────────────────────────
|
||||
|
||||
describe('DeepSeekProvider model catalog', () => {
|
||||
it('returns deepseek-chat as the default', () => {
|
||||
it('returns deepseek-v4-flash as the default', () => {
|
||||
const { provider } = makeProvider();
|
||||
expect(provider.getDefaultModel()).toBe('deepseek-chat');
|
||||
expect(provider.getDefaultModel()).toBe('deepseek-v4-flash');
|
||||
});
|
||||
|
||||
it('exposes the static DEEPSEEK_MODELS list verbatim from models()', () => {
|
||||
@@ -164,8 +164,10 @@ 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-chat');
|
||||
expect(ids).toContain('deepseek/deepseek-v4-pro');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -188,13 +190,13 @@ describe('DeepSeekProvider.complete request shape', () => {
|
||||
|
||||
await withTestActor(() =>
|
||||
provider.complete({
|
||||
model: 'deepseek-chat',
|
||||
model: 'deepseek-v4-flash',
|
||||
messages: [{ role: 'user', content: 'hello' }],
|
||||
}),
|
||||
);
|
||||
|
||||
const [args] = createMock.mock.calls[0]!;
|
||||
expect(args.model).toBe('deepseek-chat');
|
||||
expect(args.model).toBe('deepseek-v4-flash');
|
||||
expect(args.messages).toEqual([{ role: 'user', content: 'hello' }]);
|
||||
expect(args.max_tokens).toBe(1000);
|
||||
});
|
||||
@@ -205,7 +207,7 @@ describe('DeepSeekProvider.complete request shape', () => {
|
||||
|
||||
await withTestActor(() =>
|
||||
provider.complete({
|
||||
model: 'deepseek-chat',
|
||||
model: 'deepseek-v4-flash',
|
||||
messages: [{ role: 'user', content: 'hi' }],
|
||||
max_tokens: 256,
|
||||
}),
|
||||
@@ -220,7 +222,7 @@ describe('DeepSeekProvider.complete request shape', () => {
|
||||
|
||||
await withTestActor(() =>
|
||||
provider.complete({
|
||||
model: 'deepseek-chat',
|
||||
model: 'deepseek-v4-flash',
|
||||
messages: [{ role: 'user', content: 'hi' }],
|
||||
}),
|
||||
);
|
||||
@@ -244,7 +246,7 @@ describe('DeepSeekProvider.complete request shape', () => {
|
||||
];
|
||||
await withTestActor(() =>
|
||||
provider.complete({
|
||||
model: 'deepseek-chat',
|
||||
model: 'deepseek-v4-flash',
|
||||
messages: [{ role: 'user', content: 'hi' }],
|
||||
tools,
|
||||
}),
|
||||
@@ -258,7 +260,7 @@ describe('DeepSeekProvider.complete request shape', () => {
|
||||
createMock.mockResolvedValueOnce(baseCompletion);
|
||||
await withTestActor(() =>
|
||||
provider.complete({
|
||||
model: 'deepseek-chat',
|
||||
model: 'deepseek-v4-flash',
|
||||
messages: [{ role: 'user', content: 'hi' }],
|
||||
stream: false,
|
||||
}),
|
||||
@@ -270,7 +272,7 @@ describe('DeepSeekProvider.complete request shape', () => {
|
||||
createMock.mockReturnValueOnce(asAsyncIterable([]));
|
||||
await withTestActor(() =>
|
||||
provider.complete({
|
||||
model: 'deepseek-chat',
|
||||
model: 'deepseek-v4-flash',
|
||||
messages: [{ role: 'user', content: 'hi' }],
|
||||
stream: true,
|
||||
}),
|
||||
@@ -286,7 +288,7 @@ describe('DeepSeekProvider.complete request shape', () => {
|
||||
|
||||
await withTestActor(() =>
|
||||
provider.complete({
|
||||
model: 'deepseek-chat',
|
||||
model: 'deepseek-v4-flash',
|
||||
messages: [
|
||||
{
|
||||
role: 'assistant',
|
||||
@@ -327,7 +329,7 @@ describe('DeepSeekProvider.complete request shape', () => {
|
||||
|
||||
await withTestActor(() =>
|
||||
provider.complete({
|
||||
model: 'deepseek-chat',
|
||||
model: 'deepseek-v4-flash',
|
||||
messages: [
|
||||
{
|
||||
role: 'assistant',
|
||||
@@ -364,7 +366,7 @@ describe('DeepSeekProvider.complete request shape', () => {
|
||||
|
||||
await withTestActor(() =>
|
||||
provider.complete({
|
||||
model: 'deepseek-chat',
|
||||
model: 'deepseek-v4-flash',
|
||||
messages: [
|
||||
{ role: 'user', content: 'do tool call' },
|
||||
{
|
||||
@@ -412,16 +414,16 @@ describe('DeepSeekProvider model resolution', () => {
|
||||
|
||||
await withTestActor(() =>
|
||||
provider.complete({
|
||||
model: 'deepseek-reasoner',
|
||||
model: 'deepseek-v4-flash',
|
||||
messages: [{ role: 'user', content: 'hi' }],
|
||||
}),
|
||||
);
|
||||
|
||||
expect(createMock.mock.calls[0]![0].model).toBe('deepseek-reasoner');
|
||||
expect(createMock.mock.calls[0]![0].model).toBe('deepseek-v4-flash');
|
||||
expect(recordSpy).toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
expect.anything(),
|
||||
'deepseek:deepseek-reasoner',
|
||||
'deepseek:deepseek-v4-flash',
|
||||
expect.any(Object),
|
||||
);
|
||||
});
|
||||
@@ -432,17 +434,17 @@ describe('DeepSeekProvider model resolution', () => {
|
||||
|
||||
await withTestActor(() =>
|
||||
provider.complete({
|
||||
// `deepseek/deepseek-chat` is an alias of `deepseek-chat`.
|
||||
model: 'deepseek/deepseek-chat',
|
||||
// `deepseek/deepseek-v4-flash` is an alias of `deepseek-v4-flash`.
|
||||
model: 'deepseek/deepseek-v4-flash',
|
||||
messages: [{ role: 'user', content: 'hi' }],
|
||||
}),
|
||||
);
|
||||
|
||||
expect(createMock.mock.calls[0]![0].model).toBe('deepseek-chat');
|
||||
expect(createMock.mock.calls[0]![0].model).toBe('deepseek-v4-flash');
|
||||
expect(recordSpy).toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
expect.anything(),
|
||||
'deepseek:deepseek-chat',
|
||||
'deepseek:deepseek-v4-flash',
|
||||
expect.any(Object),
|
||||
);
|
||||
});
|
||||
@@ -458,11 +460,41 @@ describe('DeepSeekProvider model resolution', () => {
|
||||
}),
|
||||
);
|
||||
|
||||
expect(createMock.mock.calls[0]![0].model).toBe('deepseek-chat');
|
||||
expect(createMock.mock.calls[0]![0].model).toBe('deepseek-v4-flash');
|
||||
expect(recordSpy).toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
expect.anything(),
|
||||
'deepseek:deepseek-chat',
|
||||
'deepseek:deepseek-v4-flash',
|
||||
expect.any(Object),
|
||||
);
|
||||
});
|
||||
|
||||
// The legacy DeepSeek chat/reasoner ids (and their `deepseek/…` and
|
||||
// `deepseek:deepseek/…` variants) are aliased onto deepseek-v4-flash
|
||||
// so callers using the old names get transparently upgraded — and
|
||||
// metered against the v4-flash 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) => {
|
||||
const { provider } = makeProvider();
|
||||
createMock.mockResolvedValueOnce(baseCompletion);
|
||||
|
||||
await withTestActor(() =>
|
||||
provider.complete({
|
||||
model: alias,
|
||||
messages: [{ role: 'user', content: 'hi' }],
|
||||
}),
|
||||
);
|
||||
|
||||
expect(createMock.mock.calls[0]![0].model).toBe('deepseek-v4-flash');
|
||||
expect(recordSpy).toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
expect.anything(),
|
||||
'deepseek:deepseek-v4-flash',
|
||||
expect.any(Object),
|
||||
);
|
||||
});
|
||||
@@ -489,7 +521,7 @@ describe('DeepSeekProvider.complete non-stream output', () => {
|
||||
|
||||
const result = await withTestActor(() =>
|
||||
provider.complete({
|
||||
model: 'deepseek-chat',
|
||||
model: 'deepseek-v4-flash',
|
||||
messages: [{ role: 'user', content: 'hi' }],
|
||||
}),
|
||||
);
|
||||
@@ -504,8 +536,8 @@ describe('DeepSeekProvider.complete non-stream output', () => {
|
||||
cached_tokens: 10,
|
||||
});
|
||||
|
||||
// deepseek-chat costs: prompt=56, completion=168, cached=0.
|
||||
const chat = DEEPSEEK_MODELS.find((m) => m.id === 'deepseek-chat')!;
|
||||
// deepseek-v4-flash costs: prompt=14, completion=28, cached=0.28
|
||||
const chat = DEEPSEEK_MODELS.find((m) => m.id === 'deepseek-v4-flash')!;
|
||||
expect(recordSpy).toHaveBeenCalledTimes(1);
|
||||
const [usage, actor, prefix, overrides] = recordSpy.mock.calls[0]!;
|
||||
expect(usage).toEqual({
|
||||
@@ -514,7 +546,7 @@ describe('DeepSeekProvider.complete non-stream output', () => {
|
||||
cached_tokens: 10,
|
||||
});
|
||||
expect(actor).toBe(SYSTEM_ACTOR);
|
||||
expect(prefix).toBe('deepseek:deepseek-chat');
|
||||
expect(prefix).toBe('deepseek:deepseek-v4-flash');
|
||||
expect(overrides).toEqual({
|
||||
prompt_tokens: 100 * Number(chat.costs.prompt_tokens),
|
||||
completion_tokens: 50 * Number(chat.costs.completion_tokens),
|
||||
@@ -549,7 +581,7 @@ describe('DeepSeekProvider.complete non-stream output', () => {
|
||||
|
||||
const result = (await withTestActor(() =>
|
||||
provider.complete({
|
||||
model: 'deepseek-chat',
|
||||
model: 'deepseek-v4-flash',
|
||||
messages: [{ role: 'user', content: 'do a tool call' }],
|
||||
tools: [
|
||||
{
|
||||
@@ -584,7 +616,7 @@ describe('DeepSeekProvider.complete non-stream output', () => {
|
||||
|
||||
await withTestActor(() =>
|
||||
provider.complete({
|
||||
model: 'deepseek-chat',
|
||||
model: 'deepseek-v4-flash',
|
||||
messages: [{ role: 'user', content: 'hi' }],
|
||||
}),
|
||||
);
|
||||
@@ -617,7 +649,7 @@ describe('DeepSeekProvider.complete streaming', () => {
|
||||
|
||||
const result = await withTestActor(() =>
|
||||
provider.complete({
|
||||
model: 'deepseek-chat',
|
||||
model: 'deepseek-v4-flash',
|
||||
messages: [{ role: 'user', content: 'say hi' }],
|
||||
stream: true,
|
||||
}),
|
||||
@@ -642,10 +674,10 @@ describe('DeepSeekProvider.complete streaming', () => {
|
||||
cached_tokens: 1,
|
||||
});
|
||||
|
||||
const chat = DEEPSEEK_MODELS.find((m) => m.id === 'deepseek-chat')!;
|
||||
const chat = DEEPSEEK_MODELS.find((m) => m.id === 'deepseek-v4-flash')!;
|
||||
expect(recordSpy).toHaveBeenCalledTimes(1);
|
||||
const [, , prefix, overrides] = recordSpy.mock.calls[0]!;
|
||||
expect(prefix).toBe('deepseek:deepseek-chat');
|
||||
expect(prefix).toBe('deepseek:deepseek-v4-flash');
|
||||
expect(overrides).toEqual({
|
||||
prompt_tokens: 4 * Number(chat.costs.prompt_tokens),
|
||||
completion_tokens: 2 * Number(chat.costs.completion_tokens),
|
||||
@@ -698,7 +730,7 @@ describe('DeepSeekProvider.complete streaming', () => {
|
||||
|
||||
const result = await withTestActor(() =>
|
||||
provider.complete({
|
||||
model: 'deepseek-chat',
|
||||
model: 'deepseek-v4-flash',
|
||||
messages: [{ role: 'user', content: 'do tool call' }],
|
||||
tools: [
|
||||
{
|
||||
@@ -737,7 +769,7 @@ describe('DeepSeekProvider.complete error mapping', () => {
|
||||
await expect(
|
||||
withTestActor(() =>
|
||||
provider.complete({
|
||||
model: 'deepseek-chat',
|
||||
model: 'deepseek-v4-flash',
|
||||
messages: [{ role: 'user', content: 'boom' }],
|
||||
}),
|
||||
),
|
||||
|
||||
@@ -40,7 +40,7 @@ export class DeepSeekProvider implements IChatProvider {
|
||||
}
|
||||
|
||||
getDefaultModel() {
|
||||
return 'deepseek-chat';
|
||||
return 'deepseek-v4-flash';
|
||||
}
|
||||
|
||||
models() {
|
||||
@@ -137,20 +137,18 @@ export class DeepSeekProvider implements IChatProvider {
|
||||
);
|
||||
this.#meteringService.utilRecordUsageObject(
|
||||
trackedUsage,
|
||||
actor,
|
||||
actor!,
|
||||
`deepseek:${modelUsed.id}`,
|
||||
costsOverrideFromModel,
|
||||
);
|
||||
return trackedUsage;
|
||||
},
|
||||
stream,
|
||||
stream: stream,
|
||||
completion,
|
||||
});
|
||||
}
|
||||
|
||||
checkModeration(
|
||||
_text: string,
|
||||
): ReturnType<IChatProvider['checkModeration']> {
|
||||
checkModeration(_text: string) {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,47 +22,54 @@ import type { IChatModel } from '../../types.js';
|
||||
// Hardcoded from https://models.dev/api.json
|
||||
export const DEEPSEEK_MODELS: IChatModel[] = [
|
||||
{
|
||||
puterId: 'deepseek:deepseek/deepseek-chat',
|
||||
id: 'deepseek-chat',
|
||||
puterId: 'deepseek:deepseek/deepseek-v4-flash',
|
||||
id: 'deepseek-v4-flash',
|
||||
modalities: { input: ['text'], output: ['text'] },
|
||||
open_weights: false,
|
||||
tool_call: true,
|
||||
knowledge: '2024-07',
|
||||
release_date: '2024-12-26',
|
||||
knowledge: '2026-04',
|
||||
release_date: '2026-04-24',
|
||||
name: 'DeepSeek Chat',
|
||||
aliases: ['deepseek/deepseek-chat'],
|
||||
context: 128000,
|
||||
aliases: [
|
||||
'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: 56,
|
||||
completion_tokens: 168,
|
||||
cached_tokens: 0,
|
||||
prompt_tokens: 14,
|
||||
completion_tokens: 28,
|
||||
cached_tokens: 0.28,
|
||||
},
|
||||
max_tokens: 8000,
|
||||
max_tokens: 384_000,
|
||||
},
|
||||
{
|
||||
puterId: 'deepseek:deepseek/deepseek-reasoner',
|
||||
id: 'deepseek-reasoner',
|
||||
puterId: 'deepseek:deepseek/deepseek-v4-pro',
|
||||
id: 'deepseek-v4-pro',
|
||||
modalities: { input: ['text'], output: ['text'] },
|
||||
open_weights: false,
|
||||
tool_call: true,
|
||||
knowledge: '2024-07',
|
||||
release_date: '2025-01-20',
|
||||
name: 'DeepSeek Reasoner',
|
||||
aliases: ['deepseek/deepseek-reasoner'],
|
||||
context: 128000,
|
||||
knowledge: '2026-04',
|
||||
release_date: '2026-04-24',
|
||||
name: 'DeepSeek Chat',
|
||||
aliases: ['deepseek/deepseek-v4-pro', 'deepseek-v4-pro'],
|
||||
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: 56,
|
||||
completion_tokens: 168,
|
||||
cached_tokens: 0,
|
||||
prompt_tokens: 174,
|
||||
completion_tokens: 348,
|
||||
cached_tokens: 1.45,
|
||||
},
|
||||
max_tokens: 64000,
|
||||
max_tokens: 384_000,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -384,20 +384,10 @@ export const create_chat_stream_handler_responses_api =
|
||||
chatStream.end(usage);
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {object} params
|
||||
* @param {(args: {usage: import("openai/resources/completions.mjs").CompletionUsage})=> unknown } params.usage_calculator
|
||||
* @returns
|
||||
*/
|
||||
export const handle_completion_output = async ({
|
||||
deviations,
|
||||
stream,
|
||||
completion,
|
||||
moderate,
|
||||
usage_calculator,
|
||||
finally_fn,
|
||||
}) => {
|
||||
export const handle_completion_output = async (
|
||||
/** @type {Record<string,unknown> & {usage_calculator:(args: {usage: import("openai/resources/completions.mjs").CompletionUsage})=> unknown }}*/
|
||||
{ deviations, stream, completion, moderate, usage_calculator, finally_fn },
|
||||
) => {
|
||||
deviations = Object.assign(
|
||||
{
|
||||
// affected by: Mistral
|
||||
|
||||
Reference in New Issue
Block a user