Skip to content

Commit f9f0d6d

Browse files
committed
chore(models): 默认黑名单与线上生效值对齐
默认 MODEL_BLOCKLIST 由 11 条扩到 49 条:只展示当前在售新模型, 上游内部/代理占位(default-model/fast/balanced/deep/primary/auto 等)、 被新一代取代的老模型(glm-4.*/glm-5.0*/5.1/5.2*、kimi-k2.*、minimax-m2.5/m2.7/m3、 deepseek-v3-*/v4-*、qwen3.7-*、gpt-5.4/5.5、hy3*/hy4-preview、hunyuan-*、 seed-2.1*/seed-code-pro-*/seed-evolving、nemotron-3*/lfm2*/laguna* 等)与实测 不可用噪音(glyph-cluster、qwen3.8-flash)一律滤掉;在售主力 (deepseek-v4.1-flash / kimi-k3 / glm-5.3* / mimo-v2.6* / qwen3.8-max / openpangu-2.0-*)不受影响。 同步更新 docker-compose 默认值、README/README.en 配置表与 TECHNICAL 口径, 测试 fixture 从被滤的老模型换成在售模型(glm-5.3 / kimi-k3 / deepseek-v4.1-flash)。
1 parent a7e0787 commit f9f0d6d

16 files changed

Lines changed: 158 additions & 141 deletions

‎README.en.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ Key variables below; the full list is in `src/config.py` (authoritative), and **
458458
| `QUOTA_EXPIRY_WINDOW_SECONDS` | `129600` | Main expiry window: credits expiring within it burn account-first; `≤0` disables expiry sorting |
459459
| `QUOTA_EXPIRY_SECONDARY_WINDOW_SECONDS` | `604800` | Tie-breaking window; `≤0` disables |
460460
| `CONVERSATION_STICKY_SECONDS` | `3600` | Session-affinity TTL. Precedence: **explicit request-body session id** (`conversation_id` / `prompt_cache_key`, `metadata` first) > **session header** (`x-session-id` / `x-opencode-session` / `x-session-affinity` / `conversation-id`) > **message-prefix fingerprint** fallback; a manual pin beats all. Header and fingerprint values are salted with `username` before hashing, so two users sending the same value never share an account; headers must match `[A-Za-z0-9._:-]{1,128}` or they are dropped. `user_id` still suppresses the prefix fallback (headers keep working); `≤0` disables |
461-
| `MODEL_BLOCKLIST` | `custom_model_*,*sub*agent*,summary,browser_use_*,file_search_agent,default,hunyuan-image-*,hy4-preview-x,qwen3.8-flash,glyph-cluster` | Model-list blocklist (fnmatch, display only), matched on the outward spellings |
461+
| `MODEL_BLOCKLIST` | `custom_model_*,*sub*agent*,summary,browser_use_*,file_search_agent,default,seed-code-pro-*,sagitta,aquila,glm-4.*,glm-5,glm-5-turbo,glm-5.0*,glm-5.1,glm-5v-*,kimi-k2.5,kimi-k2.6,kimi-k2-thinking,minimax-m2.5,deepseek-v3-*,hunyuan-*,hy3*,deepseek-v4-*,qwen3.7-*,auto,nemotron-3-*,glm-5.2*,nemotron-3*,lfm2*,north-mini-code,openrouter-models-router,fast,balanced,deep,primary,hy4-preview,inkling-small,minimax-m2.7,kimi-k2.*,minimax-m3,gpt-5.4,gpt-5.5,laguna*,qwen3-vl-235b,seed-2.1*,xing4.0-29b-a4,glyph-cluster,qwen3.8-flash,seed-evolving` | Model-list blocklist (fnmatch, display only), matched on the outward spellings |
462462
| `MODEL_FALLBACK_GROUPS` | `""` | Cross-channel fallback groups: `name=m1,m2;name2=m3`; members may carry `@channel`; switches only **before any frame is emitted** |
463463
| `ALLOWED_HOSTS` | empty | Host allowlist (DNS rebinding) |
464464
| `ALLOW_TEST_HOST` | `false` | Also allow the TestClient host `testserver`. **Tests only** |

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,7 @@ python3 scripts/restore_db.py data/backups/coding2api-20261014-030000.sqlite3 --
637637
| `QUOTA_EXPIRY_WINDOW_SECONDS` | `129600` | 主到期排序窗口:把距到期 ≤ 该秒数的积分加总,多的账号先用;CodeBuddy 与 TRAE 都按包独立到期、都参与;`≤0` 关闭整套到期排序 |
638638
| `QUOTA_EXPIRY_SECONDARY_WINDOW_SECONDS` | `604800` | 次到期排序窗口:主窗口打平时才比较;`≤0` 关闭该级 |
639639
| `CONVERSATION_STICKY_SECONDS` | `3600` | 会话粘性 TTL:优先级 **请求体显式会话标识**(`conversation_id` / `prompt_cache_key`,`metadata` 优先)> **请求头会话标识**(`x-session-id` / `x-opencode-session` / `x-session-affinity` / `conversation-id`)> **消息前缀指纹**兜底;手动 pin 优先于全部。头与指纹值都掺 `username` 再哈希,两用户同值不串号;头必须过字符白名单(`[A-Za-z0-9._:-]`,≤128),非法则丢弃退回兜底。带 `user_id` 时不派生前缀兜底键(头照常生效);`≤0` 关闭 |
640-
| `MODEL_BLOCKLIST` | `custom_model_*,*sub*agent*,summary,browser_use_*,file_search_agent,default,hunyuan-image-*,hy4-preview-x,qwen3.8-flash,glyph-cluster` | 模型列表黑名单(fnmatch,仅影响列表展示);按**归一后的对外写法**匹配(原代号、归一键、展示名、展示名归一键四种任一命中即滤) |
640+
| `MODEL_BLOCKLIST` | `custom_model_*,*sub*agent*,summary,browser_use_*,file_search_agent,default,seed-code-pro-*,sagitta,aquila,glm-4.*,glm-5,glm-5-turbo,glm-5.0*,glm-5.1,glm-5v-*,kimi-k2.5,kimi-k2.6,kimi-k2-thinking,minimax-m2.5,deepseek-v3-*,hunyuan-*,hy3*,deepseek-v4-*,qwen3.7-*,auto,nemotron-3-*,glm-5.2*,nemotron-3*,lfm2*,north-mini-code,openrouter-models-router,fast,balanced,deep,primary,hy4-preview,inkling-small,minimax-m2.7,kimi-k2.*,minimax-m3,gpt-5.4,gpt-5.5,laguna*,qwen3-vl-235b,seed-2.1*,xing4.0-29b-a4,glyph-cluster,qwen3.8-flash,seed-evolving` | 模型列表黑名单(fnmatch,仅影响列表展示);按**归一后的对外写法**匹配(原代号、归一键、展示名、展示名归一键四种任一命中即滤) |
641641
| `MODEL_FALLBACK_GROUPS` | `""` | 跨渠道 fallback 兼容组:格式 `组名=成员1,成员2;组名2=成员3`;成员可带 `@渠道`。请求任一成员时该成员置首、组内其余依次回退;主渠道全不可用才回退,**仅在本次尝试尚未产出任何响应帧前**切换。留空 = 不启用 |
642642
| `ALLOWED_HOSTS` | 空 | Host 白名单,防 DNS rebinding |
643643
| `ALLOW_TEST_HOST` | `false` | 额外放行 FastAPI TestClient 的默认 Host `testserver`。**仅测试用**,生产保持 `false` |

‎TECHNICAL.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ def health_score(q: Quota | None) -> int | None:
158158
| `supports_reasoning` | `supportsReasoning` | `display_config.model_capability`(`reasoning_model`→true、`chat_model`→false),缺失回落 `reasoning_effort_config.support_thinking` | true / false / null |
159159
| `default_effort` | `reasoning.effort` | 无对应字段 | CB: `high` / `medium`;TRAE 恒 null |
160160

161-
`supported_efforts`(可接受档位集合)**不实现**:上游只给「默认档位」不给档位清单,凭空枚举 ChatGPT 三档属编造。CB 的 `onlyReasoning`/`canDisableThinking` 同样**不透传**(语义未经核实)。**唯一例外是 Playground 的入参控件**(`web/src/lib/playgroundParams.ts`):它只帮用户拼请求体,不对外声明能力——档位候选固定为 OpenAI 标准三档(`low`/`medium`/`high`),上游声明的 `default_effort` 若不在其中则追加进候选;控件在 `supports_reasoning !== true` 且无 `default_effort` 时**不渲染**,默认选中「不发送」(渠道各自补默认,如 CB 补 `medium`)。三个高级参数(`temperature` / `max_tokens` / `reasoning_effort`)均**留空即不发送该键**,前端校验边界与 `compat/openai/request.py` 对齐(`temperature` ≤ 1000、`max_tokens` 为 1–4e6 的正整数),避免前端放过、后端 400。逐字段补缺(多上游同名模型先到先填、后到只补 None)。**黑名单**(`MODEL_BLOCKLIST`,fnmatch glob,只影响列表展示、直连不受影响)。默认模式含上游内部/代理模型与**确认不可用**的噪音模型:`custom_model_*` / `*sub*agent*` / `summary` / `browser_use_*` / `file_search_agent`,以及 `default`(HTTP 200 但零内容)、`hunyuan-image-*`(400 `11103` backend not supported)、`hy4-preview-x`(400 `11102` service info not found,下架)、`qwen3.8-flash`(Qoder `qfmodel` 400「Execution failed: null」)、`glyph-cluster`(Kilo 两次 121s 后 408)。**按归一后的对外写法匹配**(`_block_names`):原代号、原代号归一键、展示名、展示名归一键四种写法取并集,用户照列表里看到的 `kimi-k3` / `Kimi K3` 写也能生效;保留原代号是因为默认规则带下划线(`custom_model_*`),归一键把下划线换成连字符后不命中;清洗后退化为空的名字不参与匹配。**非模型级问题不进黑名单**:CodeArts `deepseek-v4-*` / `glm-5.3-flash` 的 `InferHub.4291.200 insufficient quota` 与 `TM.00001041` 是账号级,Kilo `poolside/laguna-xs-2.1` / `nemotron-3-nano-omni` 的 429·502 与 `thinkingmachines/inkling-small` 的 `limit_rpd` 日配额都会自行恢复。**两条存疑未加**:Qoder `mmodel`(MiniMax-M2.7)回 inner body `null` 触发协议异常,但与 CB 正常的同名模型合并成一条,滤掉会连带隐藏可用渠道;zen `ling-3.1-flash-free` 两次 429,同样与 Kilo 可用的同名模型合并。**黑名单热更与列表缓存**:`MODEL_BLOCKLIST` 是热更项,但 `list_models` 的缓存只存**未过滤原始表**,过滤在每个出口现做(`_visible()`,命中缓存 / 成功拉取 / 失败兜底三条路径都过);前端保存后显式 `invalidateQueries(["playground-models"])`,黑名单与列表两条缓存都立即生效,不依赖 TTL。**失败也进 TTL(负缓存)**:`model_list_fetched_at` 记**上次尝试**时间(成功或失败都刷新),TTL(300s)内不再打上游——有缓存用缓存,没缓存跳过该渠道。
161+
`supported_efforts`(可接受档位集合)**不实现**:上游只给「默认档位」不给档位清单,凭空枚举 ChatGPT 三档属编造。CB 的 `onlyReasoning`/`canDisableThinking` 同样**不透传**(语义未经核实)。**唯一例外是 Playground 的入参控件**(`web/src/lib/playgroundParams.ts`):它只帮用户拼请求体,不对外声明能力——档位候选固定为 OpenAI 标准三档(`low`/`medium`/`high`),上游声明的 `default_effort` 若不在其中则追加进候选;控件在 `supports_reasoning !== true` 且无 `default_effort` 时**不渲染**,默认选中「不发送」(渠道各自补默认,如 CB 补 `medium`)。三个高级参数(`temperature` / `max_tokens` / `reasoning_effort`)均**留空即不发送该键**,前端校验边界与 `compat/openai/request.py` 对齐(`temperature` ≤ 1000、`max_tokens` 为 1–4e6 的正整数),避免前端放过、后端 400。逐字段补缺(多上游同名模型先到先填、后到只补 None)。**黑名单**(`MODEL_BLOCKLIST`,fnmatch glob,只影响列表展示、直连不受影响)。默认口径是**只展示当前在售的新模型**,三类一律滤掉:① 上游内部/代理模型——`custom_model_*` / `*sub*agent*` / `summary` / `browser_use_*` / `file_search_agent`,以及各渠道的「自动路由」占位 `default` / `default-model` / `fast-model` / `balanced-model` / `primary-model` / `deep-model` / `auto`;② 已被新一代取代的老模型——`glm-4.*` / `glm-5` / `glm-5.0*` / `glm-5.1` / `glm-5.2*` / `glm-5v-*` / `glm-5-turbo`、`kimi-k2.*`、`minimax-m2.5`/`m2.7`/`m3`、`deepseek-v3-*` / `deepseek-v4-*`(`v4.1` 不受影响)、`qwen3.7-*`、`gpt-5.4`/`gpt-5.5`、`hy3*` / `hy4-preview`、`hunyuan-*`、`seed-2.1*` / `seed-code-pro-*` / `seed-evolving`、`qwen3-vl-235b`、`nemotron-3*` / `lfm2*` / `laguna*` / `north-mini-code` / `inkling-small` / `xing4.0-29b-a4` / `openrouter-models-router`;③ 实测不可用的噪音——`glyph-cluster`(Kilo 两次 121s 后 408)、`qwen3.8-flash`(Qoder `qfmodel` 400「Execution failed: null」,CB/TRAE 的 `qwen3.8-max` 不受影响)。在售主力刻意不加:`deepseek-v4.1-flash` / `kimi-k3` / `glm-5.3*` / `mimo-v2.6*` / `qwen3.8-max` / `openpangu-2.0-*`。**按归一后的对外写法匹配**(`_block_names`):原代号、原代号归一键、展示名、展示名归一键四种写法取并集,用户照列表里看到的 `kimi-k3` / `Kimi K3` 写也能生效;保留原代号是因为默认规则带下划线(`custom_model_*`),归一键把下划线换成连字符后不命中;清洗后退化为空的名字不参与匹配。**非模型级问题不进黑名单**:CodeArts `deepseek-v4-*` / `glm-5.3-flash` 的 `InferHub.4291.200 insufficient quota` 与 `TM.00001041` 是账号级,Kilo `poolside/laguna-xs-2.1` / `nemotron-3-nano-omni` 的 429·502 与 `thinkingmachines/inkling-small` 的 `limit_rpd` 日配额都会自行恢复。**两条存疑未加**:Qoder `mmodel`(MiniMax-M2.7)回 inner body `null` 触发协议异常,但与 CB 正常的同名模型合并成一条,滤掉会连带隐藏可用渠道;zen `ling-3.1-flash-free` 两次 429,同样与 Kilo 可用的同名模型合并。**黑名单热更与列表缓存**:`MODEL_BLOCKLIST` 是热更项,但 `list_models` 的缓存只存**未过滤原始表**,过滤在每个出口现做(`_visible()`,命中缓存 / 成功拉取 / 失败兜底三条路径都过);前端保存后显式 `invalidateQueries(["playground-models"])`,黑名单与列表两条缓存都立即生效,不依赖 TTL。**失败也进 TTL(负缓存)**:`model_list_fetched_at` 记**上次尝试**时间(成功或失败都刷新),TTL(300s)内不再打上游——有缓存用缓存,没缓存跳过该渠道。
162162
### 3.7 Responses 出口(Codex CLI)
163163
`POST /v1/responses`:`src/api/responses.py`(端点)+ `src/compat/responses/request.py`(入站映射)+ `src/compat/responses/response.py`(出站翻译)。与 `/v1/chat/completions` **共用同一个 executor**,选号 / 冷却 / 轮换 / 记账 / 会话粘性全部零改动;引擎侧唯一改动是 `Executor.stream(..., translator=...)` 注入缝——出口形状由 translator 决定,引擎不再硬编码 chat 形状的 SSE 帧。字段形状全部取自官方 `openai` Python SDK(3.x)由 OpenAPI 生成的类型定义,并用该 SDK 作客户端做端到端契约验证。**入站映射**(Responses → 内部 chat 载荷):
164164

‎docker-compose.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ services:
2020
CODEBUDDY_API_ENDPOINT: ${CODEBUDDY_API_ENDPOINT:-https://copilot.tencent.com}
2121
DEFAULT_MODEL: ${DEFAULT_MODEL:-glm-5.2}
2222
# 模型列表黑名单(fnmatch glob,逗号分隔,完全替换语义)
23-
MODEL_BLOCKLIST: ${MODEL_BLOCKLIST:-custom_model_*,*sub*agent*,summary,browser_use_*,file_search_agent,default,hunyuan-image-*,hy4-preview-x,qwen3.8-flash,glyph-cluster}
23+
MODEL_BLOCKLIST: ${MODEL_BLOCKLIST:-custom_model_*,*sub*agent*,summary,browser_use_*,file_search_agent,default,seed-code-pro-*,sagitta,aquila,glm-4.*,glm-5,glm-5-turbo,glm-5.0*,glm-5.1,glm-5v-*,kimi-k2.5,kimi-k2.6,kimi-k2-thinking,minimax-m2.5,deepseek-v3-*,hunyuan-*,hy3*,deepseek-v4-*,qwen3.7-*,auto,nemotron-3-*,glm-5.2*,nemotron-3*,lfm2*,north-mini-code,openrouter-models-router,fast,balanced,deep,primary,hy4-preview,inkling-small,minimax-m2.7,kimi-k2.*,minimax-m3,gpt-5.4,gpt-5.5,laguna*,qwen3-vl-235b,seed-2.1*,xing4.0-29b-a4,glyph-cluster,qwen3.8-flash,seed-evolving}
2424
QUOTA_PROBE_MINUTES: ${QUOTA_PROBE_MINUTES:-60}
2525
# token 预刷新轮询周期(分钟):短寿命渠道(CodeArts STS 2h)的预刷新
2626
# 窗口会被封顶,窗口必须窄于该周期才不会整轮漏过、拖到到期才刷

‎src/config.py‎

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -237,23 +237,33 @@ class Settings(BaseSettings):
237237
# 原代号的归一键、展示名、展示名的归一键四种写法任一命中即滤——用户照列表
238238
# 里看到的 `kimi-k3` / `Kimi K3` 写就能生效,老规则按原代号写也仍生效。
239239
# 覆盖此值时为完全替换(含默认噪音规则),增删请重写全量。
240-
# 实测(2026-09-21,两边上游真实清单)补入的内部/不可用模型:
241-
# custom_model_* / *sub*agent* / summary / browser_use_* / file_search_agent
242-
# 为上游内部或代理模型(chat 报 3003 / 非用户模型)
243-
# default 实测 HTTP 200 但零内容(不可用于 chat)
244-
# hunyuan-image-* 实测 HTTP 400 11103「backend is not supported」
245-
# 2026-10-10 复测七渠道全量清单后补入三条「上游已下架」:
246-
# hy4-preview-x(CB 400 11102 service info not found;同名的 hy4-preview
247-
# 仍可用,故写全名不用 glob)
248-
# qwen3.8-flash(Qoder qfmodel 400「Execution failed: null」;CB/TRAE 的
249-
# qwen3.8-max 正常,不受影响)
250-
# glyph-cluster(Kilo stealth/glyph-cluster 两次 121s 后 408;Kilo 其余正常)
251-
# 刻意不加的:*-volc(deepseek-v3-2-volc 实测正常 chat)、aquila/sagitta/
252-
# seed-code-pro-0430(TRAE 实测均正常 chat)、glm-5.0-turbo/glm-5v-turbo/
253-
# hunyuan-chat/hy3/auto(2026-10-10 复测均正常 chat)
240+
# 默认口径(2026-10-19 与线上生效值对齐):**只展示当前在售的新模型**,
241+
# 三类一律滤掉——
242+
# 1. 上游内部/代理模型:custom_model_* / *sub*agent* / summary /
243+
# browser_use_* / file_search_agent(chat 报 3003 / 非用户模型);
244+
# default 与 codebuddy_intl 的 default-model/fast-model/balanced-model/
245+
# primary-model/deep-model、Qoder 的 auto 是各上游的「自动路由」占位。
246+
# 2. 已停售/被新一代取代的老模型:glm-4.* / glm-5 / glm-5.0* / glm-5.1 /
247+
# glm-5.2* / glm-5v-* / glm-5-turbo、kimi-k2.*(含 k2.5/2.6/k2-thinking)、
248+
# minimax-m2.5/m2.7/m3、deepseek-v3-* / deepseek-v4-*(v4.1 不受影响)、
249+
# qwen3.7-*、gpt-5.4/5.5、hy3* / hy4-preview、hunyuan-*、
250+
# seed-2.1* / seed-code-pro-* / seed-evolving、qwen3-vl-235b、
251+
# openpangu 之外的开源小模型(nemotron-3* / lfm2* / laguna* /
252+
# north-mini-code / inkling-small / xing4.0-29b-a4 / openrouter-models-router)。
253+
# 3. 实测不可用的噪音:glyph-cluster(Kilo 两次 121s 后 408)、
254+
# hunyuan-*(含 hunyuan-image-* 的 400 11103 backend not supported)。
255+
# 刻意不加的:deepseek-v4.1-flash / kimi-k3 / glm-5.3* / mimo-v2.6* /
256+
# qwen3.8-max / openpangu-2.0-*(在售主力,2026-10-19 实测正常 chat)。
254257
model_blocklist: str = (
255258
"custom_model_*,*sub*agent*,summary,browser_use_*,file_search_agent,"
256-
"default,hunyuan-image-*,hy4-preview-x,qwen3.8-flash,glyph-cluster"
259+
"default,seed-code-pro-*,sagitta,aquila,glm-4.*,glm-5,glm-5-turbo,"
260+
"glm-5.0*,glm-5.1,glm-5v-*,kimi-k2.5,kimi-k2.6,kimi-k2-thinking,"
261+
"minimax-m2.5,deepseek-v3-*,hunyuan-*,hy3*,deepseek-v4-*,qwen3.7-*,auto,"
262+
"nemotron-3-*,glm-5.2*,nemotron-3*,lfm2*,north-mini-code,"
263+
"openrouter-models-router,fast,balanced,deep,primary,hy4-preview,"
264+
"inkling-small,minimax-m2.7,kimi-k2.*,minimax-m3,gpt-5.4,gpt-5.5,"
265+
"laguna*,qwen3-vl-235b,seed-2.1*,xing4.0-29b-a4,glyph-cluster,"
266+
"qwen3.8-flash,seed-evolving"
257267
)
258268
# 诊断:把 /v1 入口的原始请求体落到 data/dumps/(排查客户端差异用)
259269
dump_request_bodies: bool = False

0 commit comments

Comments
 (0)