From 380fca2b9fb9b6cd2c77a955d76addceb6900df7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=B0=E6=9C=94?= <565183519@qq.com> Date: Wed, 5 Aug 2026 11:14:10 +0800 Subject: [PATCH] fix: honor registered DeepSeek endpoint --- .../bingshuo-tcs-controller/model-client.mjs | 10 ++++++++-- .../model-client.test.mjs | 17 ++++++++++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/server-tools/bingshuo-tcs-controller/model-client.mjs b/server-tools/bingshuo-tcs-controller/model-client.mjs index 7dc61d9..1fee14b 100644 --- a/server-tools/bingshuo-tcs-controller/model-client.mjs +++ b/server-tools/bingshuo-tcs-controller/model-client.mjs @@ -1,5 +1,11 @@ const DEFAULT_TIMEOUT_MS = 45_000; +function completionEndpoint(apiUrl) { + const value = String(apiUrl || "").replace(/\/+$/, ""); + if (/\/chat\/completions$/i.test(value)) return value; + return `${value}/chat/completions`; +} + function extractJson(text) { const value = String(text || "").trim(); if (!value) throw new Error("model_response_empty"); @@ -36,7 +42,7 @@ export class DeepSeekJsonClient { const controller = new AbortController(); const timer = setTimeout(() => controller.abort(), this.timeoutMs); try { - const response = await this.fetchImpl(`${this.apiUrl}/chat/completions`, { + const response = await this.fetchImpl(completionEndpoint(this.apiUrl), { method: "POST", headers: { authorization: `Bearer ${this.apiKey}`, @@ -78,4 +84,4 @@ export class DeepSeekJsonClient { } } -export { extractJson }; +export { completionEndpoint, extractJson }; diff --git a/server-tools/bingshuo-tcs-controller/model-client.test.mjs b/server-tools/bingshuo-tcs-controller/model-client.test.mjs index b803fe9..706063a 100644 --- a/server-tools/bingshuo-tcs-controller/model-client.test.mjs +++ b/server-tools/bingshuo-tcs-controller/model-client.test.mjs @@ -1,12 +1,27 @@ import assert from "node:assert/strict"; import test from "node:test"; -import { DeepSeekJsonClient, extractJson } from "./model-client.mjs"; +import { + DeepSeekJsonClient, + completionEndpoint, + extractJson, +} from "./model-client.mjs"; test("extractJson accepts strict JSON and fenced JSON", () => { assert.deepEqual(extractJson('{"ok":true}'), { ok: true }); assert.deepEqual(extractJson('```json\n{"ok":true}\n```'), { ok: true }); }); +test("completionEndpoint accepts either a base URL or a complete registered endpoint", () => { + assert.equal( + completionEndpoint("https://api.deepseek.com/v1"), + "https://api.deepseek.com/v1/chat/completions", + ); + assert.equal( + completionEndpoint("https://api.deepseek.com/chat/completions"), + "https://api.deepseek.com/chat/completions", + ); +}); + test("DeepSeek client sends the secret only as authorization and returns JSON", async () => { let observed; const client = new DeepSeekJsonClient({