Skip to content

fix: map reasoning controls onto Zhipu BigModel's generation-specific thinking API - #748

Open
HUAN2022A wants to merge 1 commit into
nashsu:mainfrom
HUAN2022A:fix/zhipu-glm-thinking-controls
Open

fix: map reasoning controls onto Zhipu BigModel's generation-specific thinking API#748
HUAN2022A wants to merge 1 commit into
nashsu:mainfrom
HUAN2022A:fix/zhipu-glm-thinking-controls

Conversation

@HUAN2022A

Copy link
Copy Markdown

Problem

Structured ingest against a Zhipu BigModel endpoint (open.bigmodel.cn/api/paas/v4) with a GLM thinking model fails with the app's own diagnostic:

Analysis failed: Model produced 15,233 characters of reasoning / chain-of-thought, but no actual response content. This usually means the endpoint hit a thinking-token limit, the model didn't transition from thinking to answering, or the endpoint is misbehaving.

Two causes stack up:

  1. Wire layer: buildOpenAiCompatibleBody has no BigModel adapter — thinking.type=disabled is sent for Xiaomi MiMo and DeepSeek only, so reasoning: { mode: "off" } (every structured ingest call) is silently dropped and the GLM model thinks by default.
  2. Capability layer: resolveReasoningCapabilities buckets open.bigmodel.cn as a generic custom gateway (auto-only), so a saved off is normalized away before the wire is built — the user has no way to fix it from the UI.

Root cause: Zhipu's thinking API is generation-specific

Per Zhipu's docs (docs.bigmodel.cn/cn/guide/capabilities/thinking, .../guide/models/text/glm-5.3), verified empirically against glm-5.3-flash on /api/paas/v4:

request glm-5.3-flash behavior
nothing (server default) ~938 chars reasoning_content before content
thinking: {type: "disabled"} HTTP 200 + error 1210: 该模型始终思考,不支持关闭思考;请使用 low、high 或 max
reasoning_effort: "low" 0 chars reasoning, answers in ~24 completion tokens
thinking: {type: "enabled"} + reasoning_effort works, effort respected

So a straight copy of the DeepSeek/MiMo adapter would turn ingest failures into hard 400s on GLM-5.3+.

Fix

reasoning-capabilities.ts

  • isBigModelEndpoint(endpoint) (shared, endpoint-string form; llm-providers.ts now uses it for its image-support checks too)
  • parseGlmVersion / isGlmAtLeast — parse the generation out of model ids (glm-4.7-flash → 4.7, glm-5v-turbo → 5.0, glm-z1-* / non-GLM → null)
  • BigModel capability branch: pre-4.5 → auto-only; 4.5..5.1 → auto/off (TOGGLE_LEVELS); 5.2+ → auto/off/low/high/max (GLM_EFFORT_LEVELS; medium and custom budgets are not representable in Zhipu's lineup)

llm-providers.tsadaptBigModelBody:

  • offthinking: {type: "disabled"} on 4.5..5.2; reasoning_effort: "low" on 5.3+ (which rejects disabled with error 1210)
  • low/high/maxthinking: {type: "enabled"} + reasoning_effort on 5.2+
  • auto / unsupported modes → body untouched (server default)

Testing

  • New unit tests in llm-providers.test.ts (wire shapes per generation, incl. the 1210-avoidance path and generic-gateway isolation) and reasoning-capabilities.test.ts (mode sets per generation, version parsing)
  • npx vitest run (mock suite): 132 files / 1884 tests pass
  • npm run typecheck and npx vite build pass
  • Live endpoint check: the exact body the fixed app sends for ingest (reasoning_effort: "low", temperature: 0.1) returns normal content with zero reasoning content on glm-5.3-flash

Notes

  • Scope is the OpenAI-compatible wire (/api/paas/v4), matching the existing Zhipu preset; the Anthropic-compatible endpoint is untouched.
  • The endpoint gate is host-based (open.bigmodel.cn), consistent with the DeepSeek/MiMo branches; a GLM model id through a generic gateway keeps auto-only capabilities.

… thinking API

Structured ingest on Zhipu BigModel endpoints failed with 'Model produced
N chars of reasoning, but no actual response content': GLM thinking models
spent the whole budget on reasoning_content, and the app's reasoning-off
request was silently dropped because open.bigmodel.cn fell into the generic
custom-gateway bucket.

Wire the controls per generation, matching Zhipu's documented support:

- capability layer: glm-4.5..5.1 offer auto/off; glm-5.2+ add low/high/max
  (medium and custom budgets are not representable); pre-4.5 ids stay
  auto-only, mirroring DeepSeek's gating
- wire layer: reasoning off sends thinking.type=disabled on 4.5..5.2, but
  glm-5.3+ rejects that field with error 1210 (thinking is always on), so
  it maps to reasoning_effort=low; effort levels map to
  thinking.enabled + reasoning_effort on 5.2+

Verified against open.bigmodel.cn/api/paas/v4 with glm-5.3-flash:
reasoning_effort=low returns 0 reasoning chars where the default (max)
returned ~1k before the answer.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant