From b31ac86c07ab0f52242bef11e04cc8c1eec02928 Mon Sep 17 00:00:00 2001 From: su-fen <60851806+su-fen@users.noreply.github.com> Date: Mon, 2 Nov 2026 10:56:37 +0000 Subject: [PATCH 1/2] chore(models): refresh model catalog --- .../src/lib/models/catalog.generated.ts | 64 ++++++++----------- 1 file changed, 26 insertions(+), 38 deletions(-) diff --git a/crates/agent-ui/src/lib/models/catalog.generated.ts b/crates/agent-ui/src/lib/models/catalog.generated.ts index 101faf051..439a83623 100644 --- a/crates/agent-ui/src/lib/models/catalog.generated.ts +++ b/crates/agent-ui/src/lib/models/catalog.generated.ts @@ -26,7 +26,7 @@ export type CatalogModelEntry = { export type CatalogProviderId = "anthropic" | "google" | "openai" | "xai" | "deepseek" | "zhipuai" | "moonshotai" | "minimax" | "stepfun" | "xiaomi" | "longcat" | "alibaba" | "tencent"; -export const MODEL_CATALOG_SNAPSHOT_DATE = "2026-10-02"; +export const MODEL_CATALOG_SNAPSHOT_DATE = "2026-11-02"; export const MODEL_CATALOG: Record = { anthropic: [ @@ -34,6 +34,7 @@ export const MODEL_CATALOG: Record Date: Mon, 2 Nov 2026 23:55:57 +0800 Subject: [PATCH 2/2] =?UTF-8?q?test(models):=20=E7=9B=AE=E5=BD=95=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E6=96=AD=E8=A8=80=E5=AF=B9=E7=85=A7=E5=BF=AB=E7=85=A7?= =?UTF-8?q?=EF=BC=8C=E4=B8=8D=E5=86=8D=E5=86=99=E6=AD=BB=E9=99=90=E9=A2=9D?= =?UTF-8?q?=E4=B8=8E=E6=A1=A3=E4=BD=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 模型目录每日自动刷新(#1127)把 deepseek-v4 窗口改为 1048576、xai 档位加了 xhigh,4 个测试写死的旧值随之失败。改为: - 限额断言对照 MODEL_CATALOG 快照条目,并断言不等于供应商兜底值 - xai 档位逐条对照目录里每个 xai 条目,能区分按型号取档与固定表 - 钳制用例从档位阶梯动态挑表外档 新旧两份目录下均通过。 Co-Authored-By: Claude Opus 5.5 --- .../test/webui/web-settings.test.mjs | 40 ++++++++++++------- .../test/models/model-catalog.test.mjs | 6 ++- .../test/settings/normalization.test.mjs | 30 ++++++++++++-- 3 files changed, 57 insertions(+), 19 deletions(-) diff --git a/crates/agent-gateway/test/webui/web-settings.test.mjs b/crates/agent-gateway/test/webui/web-settings.test.mjs index d056c9e83..c7fa59057 100644 --- a/crates/agent-gateway/test/webui/web-settings.test.mjs +++ b/crates/agent-gateway/test/webui/web-settings.test.mjs @@ -6,6 +6,7 @@ const loader = createWebModuleLoader(); const webSettings = loader.loadModule("src/lib/webSettings.ts"); const settings = loader.loadModule("@/lib/settings/index.ts"); const settingsSync = loader.loadModule("@liveagent/ui/lib/settings/sync.ts"); +const catalog = loader.loadModule("@liveagent/ui/lib/models/modelCatalog.ts"); const chatHelpers = loader.loadModule("@/lib/chat/chatPageHelpers.ts"); const adminApi = loader.loadModule("@/lib/adminApi.ts"); const RIGHT_DOCK_TAB_IDS = settings.RIGHT_DOCK_SINGLETON_TAB_IDS; @@ -1879,21 +1880,32 @@ test("xai model limits use the generated catalog without changing thinking detec }); test("xai thinking levels come from the catalog per model, thinking always on", () => { - // 档位按型号差异化(目录真值):grok-4.5 只有 low/medium/high; - // grok-4.20-multi-agent-0309 声明到 xhigh。xai 思考一律恒开 - //(wire 无法表达 off),目录的 off 声明对 xai 供应商不生效。 - assert.deepEqual(settings.getKnownModelThinkingLevels("xai", "grok-4.5"), [ - "low", - "medium", - "high", - ]); - assert.equal(settings.isThinkingAlwaysOnForModel("xai", "grok-4.5"), true); - const multiAgent = settings.getKnownModelThinkingLevels("xai", "grok-4.20-multi-agent-0309"); - assert.ok(multiAgent.includes("xhigh")); - assert.equal(settings.isThinkingAlwaysOnForModel("xai", "grok-4.3"), true); - // 钳制路径:xhigh 超出 grok-4.5 档位表时压回默认 high。 + // 档位按型号取目录真值:逐条对照快照里每个 xai 条目,不写死档位表(目录每日 + // 自动刷新)。单点对照分不出"按型号读目录"和"整个供应商一张固定表",逐条 + // 对照可以(快照里有档位为空的条目)。xai 思考一律恒开(wire 无法表达 off), + // 目录里 off: true 的条目对 xai 供应商同样不生效。 + const entries = catalog.MODEL_CATALOG.xai.filter((model) => model.thinking); + assert.ok(entries.length >= 2, "xai thinking entries missing from the catalog snapshot"); + for (const entry of entries) { + assert.deepEqual( + settings.getKnownModelThinkingLevels("xai", entry.id), + [...entry.thinking.levels], + `${entry.id} levels`, + ); + assert.equal( + settings.isThinkingAlwaysOnForModel("xai", entry.id), + true, + `${entry.id} always on`, + ); + } + // 钳制路径:表外档位(取档位阶梯里最高的表外档)压回默认 high。 + const grok45Levels = settings.getKnownModelThinkingLevels("xai", "grok-4.5"); + const outside = ["minimal", "low", "medium", "high", "xhigh", "max"] + .filter((level) => !grok45Levels.includes(level)) + .at(-1); + assert.ok(outside, "grok-4.5 covers the whole level ladder; clamp needs another model"); const clamped = settings.normalizeChatRuntimeControlsForProvider( - { reasoning: "xhigh", reasoningByProvider: { xai: "xhigh" } }, + { reasoning: outside, reasoningByProvider: { xai: outside } }, { providerId: "xai", modelId: "grok-4.5" }, ); assert.equal(clamped.reasoning, "high"); diff --git a/crates/agent-gui/test/models/model-catalog.test.mjs b/crates/agent-gui/test/models/model-catalog.test.mjs index 8b35deeae..10862be11 100644 --- a/crates/agent-gui/test/models/model-catalog.test.mjs +++ b/crates/agent-gui/test/models/model-catalog.test.mjs @@ -172,7 +172,11 @@ test("normalizeModelIdCandidates strips a month-day date suffix only when no ful test("a dated relay id resolves to the catalog entry, an exact dated id keeps its own entry", () => { const relayed = catalog.findCatalogModelAcrossProviders("deepseek-ai/deepseek-v4-pro-0813"); assert.equal(relayed?.id, "deepseek-v4-pro"); - assert.equal(relayed?.contextWindow, 1000000); + // 限额对照目录快照本身,不写死数值:目录每日自动刷新会改动上游限额。 + assert.deepEqual( + relayed, + catalog.MODEL_CATALOG.deepseek.find((model) => model.id === "deepseek-v4-pro"), + ); assert.equal(catalog.findCatalogModelAcrossProviders("deepseek-r1-0528")?.id, "deepseek-r1-0528"); assert.equal(catalog.findCatalogModelAcrossProviders("deepseek-r1-0601")?.id, "deepseek-r1"); }); diff --git a/crates/agent-gui/test/settings/normalization.test.mjs b/crates/agent-gui/test/settings/normalization.test.mjs index 04b33b20d..821420725 100644 --- a/crates/agent-gui/test/settings/normalization.test.mjs +++ b/crates/agent-gui/test/settings/normalization.test.mjs @@ -6,8 +6,21 @@ const loader = createTsModuleLoader(); const settings = loader.loadModule("src/lib/settings/index.ts"); const normalize = loader.loadModule("@liveagent/ui/lib/settings/normalize.ts"); const sync = loader.loadModule("@liveagent/ui/lib/settings/sync.ts"); +const modelCatalog = loader.loadModule("@liveagent/ui/lib/models/modelCatalog.ts"); const RIGHT_DOCK_TAB_IDS = settings.RIGHT_DOCK_SINGLETON_TAB_IDS; +// 目录每日自动刷新会改动上游限额:断言"取到目录真值"的用例对照快照条目, +// 不写死数值。 +function catalogLimits(section, modelId) { + const entry = modelCatalog.MODEL_CATALOG[section].find((model) => model.id === modelId); + assert.ok(entry, `${section}/${modelId} missing from the catalog snapshot`); + return { contextWindow: entry.contextWindow, maxOutputToken: entry.maxOutputToken }; +} + +function pickLimits(limits) { + return { contextWindow: limits.contextWindow, maxOutputToken: limits.maxOutputToken }; +} + async function withNavigator(value, task) { const previous = Object.getOwnPropertyDescriptor(globalThis, "navigator"); Object.defineProperty(globalThis, "navigator", { @@ -315,8 +328,11 @@ test("DeepSeek provider normalization keeps native routing and native search", ( assert.equal(provider.promptCachingEnabled, false); assert.equal(provider.promptCacheHintMode, undefined); assert.equal(provider.nativeWebSearchEnabled, true); - assert.equal(provider.models[0].contextWindow, 1_000_000); - assert.equal(provider.models[0].maxOutputToken, 393_216); + assert.deepEqual(pickLimits(provider.models[0]), catalogLimits("deepseek", "deepseek-v4-flash")); + assert.notDeepEqual( + pickLimits(provider.models[0]), + modelCatalog.PROVIDER_FALLBACK_LIMITS.deepseek, + ); }); test("legacy Codex-group DeepSeek configs stay untouched — migration is user-driven", () => { @@ -3044,8 +3060,14 @@ test("cross-provider models resolve real catalog limits instead of provider fall "claude_code", "deepseek-v4-flash", ); - assert.equal(deepseekUnderClaude.contextWindow, 1_000_000); - assert.equal(deepseekUnderClaude.maxOutputToken, 393_216); + assert.deepEqual( + pickLimits(deepseekUnderClaude), + catalogLimits("deepseek", "deepseek-v4-flash"), + ); + assert.notDeepEqual( + pickLimits(deepseekUnderClaude), + modelCatalog.PROVIDER_FALLBACK_LIMITS.claude_code, + ); const glmUnderCodex = settings.getProviderModelDefaults("codex", "glm-4.7"); assert.equal(glmUnderCodex.contextWindow, 204_800); assert.equal(glmUnderCodex.maxOutputToken, 131_072);