Skip to content

fix(providers): map agentrouter GLM thinking.type adaptive to enabled - #14043

Merged
diegosouzapw merged 1 commit into
release/v3.8.51from
fix/13696-agentrouter-adaptive-thinking
Sep 18, 2026
Merged

diegosouzapw merged 1 commit into
release/v3.8.51from
fix/13696-agentrouter-adaptive-thinking

Conversation

@diegosouzapw

Copy link
Copy Markdown
Collaborator

Root cause

AgentRouter routes GLM models through the generic DefaultExecutor (executor: "default"), which has no GLM-specific handling. When the connection's OpenAI-compatible alternate format is used and the client request already carries a Claude-style thinking: {type: "adaptive"} field (source format == target format == "openai", so translateRequest's hub-and-spoke conversion is skipped), that field survived stripUnsupportedParams untouched — STRIP_RULES in open-sse/translator/paramSupport.ts had no rule for provider agentrouter + glm-* — and reached AgentRouter's upstream GLM endpoint verbatim, which 400s with thinking.type "adaptive" is not supported by glm models; must be one of enabled, disabled.

The native GLM/ZAI executor (open-sse/executors/glm.ts:404-420) already performs exactly this adaptive → enabled remap for its own provider; AgentRouter just never reaches that code path since it uses the generic DefaultExecutor instead of GlmExecutor.

Fix

Extended the StripRule shape in open-sse/translator/paramSupport.ts with an optional mapThinkingType map (alongside the existing drop/clamp mechanisms), and added a rule scoped to provider: "agentrouter" + match: /glm-/i that remaps thinking.type from "adaptive" to "enabled", preserving any other thinking fields (e.g. budget_tokens) instead of dropping the whole field. Scoped to the whole glm-* family (not a single model id), since AgentRouter's static catalog carries no glm-* entries at all — passthroughModels: true lets arbitrary GLM ids through, so the fix must not be tied to one model.

Regression test

tests/unit/agentrouter-glm-thinking-adaptive-map.test.ts (new):

  • agentrouter + glm-5.3 with thinking.type: "adaptive" → asserts thinking becomes {type: "enabled", budget_tokens: ...} (other fields preserved)
  • agentrouter + claude-opus-5 (regression guard) → thinking.type stays "adaptive"
  • non-agentrouter provider with a glm-* model id → thinking.type stays "adaptive" (native GLM executor handles its own mapping separately)
  • agentrouter + glm-5.3 with no thinking field → no-op, nothing introduced

RED (before fix): AssertionError: adaptive must be mapped to enabled for agentrouter GLM models, preserving other thinking fields (actual {type: 'adaptive', budget_tokens: 1024} vs expected {type: 'enabled', budget_tokens: 1024}).

GREEN (after fix): all 4 new tests pass; npm run test:unit equivalent focused run — node --import tsx/esm --test tests/unit/agentrouter-glm-thinking-adaptive-map.test.ts → 4/4 pass.

Also updated the existing structural assertion in tests/unit/executors-strip-unsupported-params.test.ts ("STRIP_RULES is non-empty and every rule has a drop list or a clamp mechanism") to also accept the new mapThinkingType mechanism — it previously only recognized drop/clamp rules and would otherwise fail on the new rule shape. This is an alignment to the corrected contract (a StripRule may now sanitize by remapping a value, not only by dropping/clamping), not a weakening: the assertion still requires every rule to do something (drop, clamp, or map), just enumerates the new legitimate option.

Gates run

  • node scripts/check/check-file-size.mjs — OK (no violation on touched files; the reported test-file-size violation on tests/unit/chatcore-translation-paths.test.ts is pre-existing/untouched by this PR)
  • node scripts/check/check-complexity.mjs — OK (2857 violations vs baseline 3218)
  • node scripts/check/check-cognitive-complexity.mjs — OK (1291 violations vs baseline 1437)
  • npm run typecheck:core — exit 0
  • npm run check:open-sse-typecheck — OK, 0 errors
  • npx eslint --suppressions-location config/quality/eslint-suppressions.json <changed files> — clean
  • Existing param-support tests re-run individually (DB-per-file to avoid SQLITE_BUSY contention): azure-max-output-clamp, chatcore-unsupported-params-strip, default-reasoning-effort-6879, executors-strip-unsupported-params, glm-executor-max-tokens-clamp-7364, nvidia-minimax-thinking-strip, nvidia-strip-prompt-cache-key, param-filters-apply, param-filters-db, zai-glm-max-tokens-clamp-7364 — all pass
  • node scripts/check/check-changelog-integrity.mjs — OK

Live validation (Hard Rule #18)

Not performed against the production VPS in this pass — the fix is validated via TDD (a failing-then-passing regression test proving the exact reported 400 condition), which is the preferred validation path per the bug-fix protocol. The reported error string and root cause were confirmed by the prior triage's TDD probe and by the existing in-repo precedent (glm.ts's identical adaptive→enabled mapping for its own provider, and the identical NVIDIA NIM z-ai/glm-5.2 clash already fixed in paramSupport.ts).

⚠️ base-red inherited: #14004 — docs env/docs contract (fixed separately in #14022), chatHelpers file-size drift

Closes #13696

…#13696)

AgentRouter routes GLM models through the generic DefaultExecutor, which has
no GLM-specific handling. When the connection's OpenAI-compatible alternate
format is used, a Claude-style thinking:{type:"adaptive"} field survived
stripUnsupportedParams untouched and reached AgentRouter's upstream GLM
endpoint verbatim, which 400s (thinking.type "adaptive" is not supported by
glm models; must be one of enabled, disabled).

Add a mapThinkingType mechanism to paramSupport.ts's STRIP_RULES (in addition
to the existing drop/clamp mechanisms) and scope a rule to provider
"agentrouter" + model matching /glm-/i that remaps thinking.type from
"adaptive" to "enabled", preserving any other thinking fields (e.g.
budget_tokens) — mirroring the same mapping GlmExecutor already performs for
its own provider.
@diegosouzapw

Copy link
Copy Markdown
Collaborator Author

Validated in local merge-train /tmp/mt-train3b.log on 192.168.0.113 @ train tip 408e2128791696a18966681953136fc96aeb99b0 (32 PRs boarded): static gates green; full test:unit 40694 tests, 17 failing — every one reproduces on the pure release tip (base-red sweep list), zero new reds. Merged --admin per merge-gates §4/§7.

@diegosouzapw
diegosouzapw merged commit b095504 into release/v3.8.51 Sep 18, 2026
14 of 21 checks passed
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…cheaper-inference#13696) (cheaper-inference#14043)

AgentRouter routes GLM models through the generic DefaultExecutor, which has
no GLM-specific handling. When the connection's OpenAI-compatible alternate
format is used, a Claude-style thinking:{type:"adaptive"} field survived
stripUnsupportedParams untouched and reached AgentRouter's upstream GLM
endpoint verbatim, which 400s (thinking.type "adaptive" is not supported by
glm models; must be one of enabled, disabled).

Add a mapThinkingType mechanism to paramSupport.ts's STRIP_RULES (in addition
to the existing drop/clamp mechanisms) and scope a rule to provider
"agentrouter" + model matching /glm-/i that remaps thinking.type from
"adaptive" to "enabled", preserving any other thinking fields (e.g.
budget_tokens) — mirroring the same mapping GlmExecutor already performs for
its own provider.
@diegosouzapw
diegosouzapw deleted the fix/13696-agentrouter-adaptive-thinking branch October 18, 2026 23:49
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.

fix(providers): agentrouter GLM models reject thinking.type "adaptive" (400) — map to enabled for glm-*

1 participant