




















@@ -10,6 +10,48 @@ import { runSingleProviderCatalog } from "../test-support/provider-model-test-he
1010import deepseekPlugin from "./index.js";
1111import { createDeepSeekV4ThinkingWrapper } from "./stream.js";
121213+type OpenAICompletionsModel = Model<"openai-completions">;
14+15+type PayloadCapture = {
16+payload?: Record<string, unknown>;
17+};
18+19+function deepSeekV4Model(id: "deepseek-v4-flash" | "deepseek-v4-pro"): OpenAICompletionsModel {
20+return {
21+provider: "deepseek",
22+ id,
23+name: id === "deepseek-v4-flash" ? "DeepSeek V4 Flash" : "DeepSeek V4 Pro",
24+api: "openai-completions",
25+baseUrl: "https://api.deepseek.com",
26+reasoning: true,
27+input: ["text"],
28+cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
29+contextWindow: 1_000_000,
30+maxTokens: 384_000,
31+compat: {
32+supportsUsageInStreaming: true,
33+supportsReasoningEffort: true,
34+maxTokensField: "max_tokens",
35+},
36+} as OpenAICompletionsModel;
37+}
38+39+function createPayloadCapturingStream(capture: PayloadCapture) {
40+return (
41+streamModel: OpenAICompletionsModel,
42+streamContext: Context,
43+options?: { onPayload?: (payload: unknown, model: unknown) => unknown },
44+) => {
45+capture.payload = buildOpenAICompletionsParams(streamModel, streamContext, {
46+reasoning: "high",
47+} as never);
48+options?.onPayload?.(capture.payload, streamModel);
49+const stream = createAssistantMessageEventStream();
50+queueMicrotask(() => stream.end());
51+return stream;
52+};
53+}
54+1355describe("deepseek provider plugin", () => {
1456it("registers DeepSeek with api-key auth wizard metadata", async () => {
1557const provider = await registerSingleProviderPlugin(deepseekPlugin);
@@ -119,24 +161,8 @@ describe("deepseek provider plugin", () => {
119161});
120162121163it("preserves replayed reasoning_content when DeepSeek V4 thinking is enabled", async () => {
122-let capturedPayload: Record<string, unknown> | undefined;
123-const model = {
124-provider: "deepseek",
125-id: "deepseek-v4-flash",
126-name: "DeepSeek V4 Flash",
127-api: "openai-completions",
128-baseUrl: "https://api.deepseek.com",
129-reasoning: true,
130-input: ["text"],
131-cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
132-contextWindow: 1_000_000,
133-maxTokens: 384_000,
134-compat: {
135-supportsUsageInStreaming: true,
136-supportsReasoningEffort: true,
137-maxTokensField: "max_tokens",
138-},
139-} as Model<"openai-completions">;
164+const capture: PayloadCapture = {};
165+const model = deepSeekV4Model("deepseek-v4-flash");
140166const context = {
141167messages: [
142168{ role: "user", content: "hi", timestamp: 1 },
@@ -181,29 +207,17 @@ describe("deepseek provider plugin", () => {
181207},
182208],
183209} as Context;
184-const baseStreamFn = (
185-streamModel: Model<"openai-completions">,
186-streamContext: Context,
187-options?: { onPayload?: (payload: unknown, model: unknown) => unknown },
188-) => {
189-capturedPayload = buildOpenAICompletionsParams(streamModel, streamContext, {
190-reasoning: "high",
191-} as never);
192-options?.onPayload?.(capturedPayload, streamModel);
193-const stream = createAssistantMessageEventStream();
194-queueMicrotask(() => stream.end());
195-return stream;
196-};
210+const baseStreamFn = createPayloadCapturingStream(capture);
197211198212const wrapThinkingHigh = createDeepSeekV4ThinkingWrapper(baseStreamFn as never, "high");
199213expect(wrapThinkingHigh).toBeDefined();
200214await wrapThinkingHigh?.(model, context, {});
201215202-expect(capturedPayload).toMatchObject({
216+expect(capture.payload).toMatchObject({
203217thinking: { type: "enabled" },
204218reasoning_effort: "high",
205219});
206-expect((capturedPayload?.messages as Array<Record<string, unknown>>)[1]).toMatchObject({
220+expect((capture.payload?.messages as Array<Record<string, unknown>>)[1]).toMatchObject({
207221role: "assistant",
208222reasoning_content: "call reasoning",
209223tool_calls: [
@@ -220,24 +234,8 @@ describe("deepseek provider plugin", () => {
220234});
221235222236it("adds blank reasoning_content for replayed tool calls from non-DeepSeek turns", async () => {
223-let capturedPayload: Record<string, unknown> | undefined;
224-const model = {
225-provider: "deepseek",
226-id: "deepseek-v4-pro",
227-name: "DeepSeek V4 Pro",
228-api: "openai-completions",
229-baseUrl: "https://api.deepseek.com",
230-reasoning: true,
231-input: ["text"],
232-cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
233-contextWindow: 1_000_000,
234-maxTokens: 384_000,
235-compat: {
236-supportsUsageInStreaming: true,
237-supportsReasoningEffort: true,
238-maxTokensField: "max_tokens",
239-},
240-} as Model<"openai-completions">;
237+const capture: PayloadCapture = {};
238+const model = deepSeekV4Model("deepseek-v4-pro");
241239const context = {
242240messages: [
243241{ role: "user", content: "hi", timestamp: 1 },
@@ -275,25 +273,13 @@ describe("deepseek provider plugin", () => {
275273},
276274],
277275} as Context;
278-const baseStreamFn = (
279-streamModel: Model<"openai-completions">,
280-streamContext: Context,
281-options?: { onPayload?: (payload: unknown, model: unknown) => unknown },
282-) => {
283-capturedPayload = buildOpenAICompletionsParams(streamModel, streamContext, {
284-reasoning: "high",
285-} as never);
286-options?.onPayload?.(capturedPayload, streamModel);
287-const stream = createAssistantMessageEventStream();
288-queueMicrotask(() => stream.end());
289-return stream;
290-};
276+const baseStreamFn = createPayloadCapturingStream(capture);
291277292278const wrapThinkingHigh = createDeepSeekV4ThinkingWrapper(baseStreamFn as never, "high");
293279expect(wrapThinkingHigh).toBeDefined();
294280await wrapThinkingHigh?.(model, context, {});
295281296-expect((capturedPayload?.messages as Array<Record<string, unknown>>)[1]).toMatchObject({
282+expect((capture.payload?.messages as Array<Record<string, unknown>>)[1]).toMatchObject({
297283role: "assistant",
298284reasoning_content: "",
299285tool_calls: [
@@ -310,24 +296,8 @@ describe("deepseek provider plugin", () => {
310296});
311297312298it("adds blank reasoning_content for replayed plain assistant messages", async () => {
313-let capturedPayload: Record<string, unknown> | undefined;
314-const model = {
315-provider: "deepseek",
316-id: "deepseek-v4-pro",
317-name: "DeepSeek V4 Pro",
318-api: "openai-completions",
319-baseUrl: "https://api.deepseek.com",
320-reasoning: true,
321-input: ["text"],
322-cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
323-contextWindow: 1_000_000,
324-maxTokens: 384_000,
325-compat: {
326-supportsUsageInStreaming: true,
327-supportsReasoningEffort: true,
328-maxTokensField: "max_tokens",
329-},
330-} as Model<"openai-completions">;
299+const capture: PayloadCapture = {};
300+const model = deepSeekV4Model("deepseek-v4-pro");
331301const context = {
332302messages: [
333303{ role: "user", content: "hi", timestamp: 1 },
@@ -351,50 +321,22 @@ describe("deepseek provider plugin", () => {
351321{ role: "user", content: "next", timestamp: 3 },
352322],
353323} as Context;
354-const baseStreamFn = (
355-streamModel: Model<"openai-completions">,
356-streamContext: Context,
357-options?: { onPayload?: (payload: unknown, model: unknown) => unknown },
358-) => {
359-capturedPayload = buildOpenAICompletionsParams(streamModel, streamContext, {
360-reasoning: "high",
361-} as never);
362-options?.onPayload?.(capturedPayload, streamModel);
363-const stream = createAssistantMessageEventStream();
364-queueMicrotask(() => stream.end());
365-return stream;
366-};
324+const baseStreamFn = createPayloadCapturingStream(capture);
367325368326const wrapThinkingHigh = createDeepSeekV4ThinkingWrapper(baseStreamFn as never, "high");
369327expect(wrapThinkingHigh).toBeDefined();
370328await wrapThinkingHigh?.(model, context, {});
371329372-expect((capturedPayload?.messages as Array<Record<string, unknown>>)[1]).toMatchObject({
330+expect((capture.payload?.messages as Array<Record<string, unknown>>)[1]).toMatchObject({
373331role: "assistant",
374332content: "Hello.",
375333reasoning_content: "",
376334});
377335});
378336379337it("strips replayed reasoning_content when DeepSeek V4 thinking is disabled", async () => {
380-let capturedPayload: Record<string, unknown> | undefined;
381-const model = {
382-provider: "deepseek",
383-id: "deepseek-v4-flash",
384-name: "DeepSeek V4 Flash",
385-api: "openai-completions",
386-baseUrl: "https://api.deepseek.com",
387-reasoning: true,
388-input: ["text"],
389-cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
390-contextWindow: 1_000_000,
391-maxTokens: 384_000,
392-compat: {
393-supportsUsageInStreaming: true,
394-supportsReasoningEffort: true,
395-maxTokensField: "max_tokens",
396-},
397-} as Model<"openai-completions">;
338+const capture: PayloadCapture = {};
339+const model = deepSeekV4Model("deepseek-v4-flash");
398340const context = {
399341messages: [
400342{ role: "user", content: "hi", timestamp: 1 },
@@ -439,19 +381,7 @@ describe("deepseek provider plugin", () => {
439381},
440382],
441383} as Context;
442-const baseStreamFn = (
443-streamModel: Model<"openai-completions">,
444-streamContext: Context,
445-options?: { onPayload?: (payload: unknown, model: unknown) => unknown },
446-) => {
447-capturedPayload = buildOpenAICompletionsParams(streamModel, streamContext, {
448-reasoning: "high",
449-} as never);
450-options?.onPayload?.(capturedPayload, streamModel);
451-const stream = createAssistantMessageEventStream();
452-queueMicrotask(() => stream.end());
453-return stream;
454-};
384+const baseStreamFn = createPayloadCapturingStream(capture);
455385456386const wrapThinkingNone = createDeepSeekV4ThinkingWrapper(
457387baseStreamFn as never,
@@ -460,9 +390,9 @@ describe("deepseek provider plugin", () => {
460390expect(wrapThinkingNone).toBeDefined();
461391await wrapThinkingNone?.(model, context, {});
462392463-expect(capturedPayload).toMatchObject({ thinking: { type: "disabled" } });
464-expect(capturedPayload).not.toHaveProperty("reasoning_effort");
465-expect((capturedPayload?.messages as Array<Record<string, unknown>>)[1]).not.toHaveProperty(
393+expect(capture.payload).toMatchObject({ thinking: { type: "disabled" } });
394+expect(capture.payload).not.toHaveProperty("reasoning_effort");
395+expect((capture.payload?.messages as Array<Record<string, unknown>>)[1]).not.toHaveProperty(
466396"reasoning_content",
467397);
468398});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。