From fc2d497de0f53e4659cf4c420633be00e105a1c8 Mon Sep 17 00:00:00 2001 From: chenbin Date: Fri, 24 Jul 2026 00:14:19 +0800 Subject: [PATCH 1/2] fix(agent): drop tool_calls key instead of empty array when all are dupes sanitize_api_messages() Step 3 deduplication creates tool_calls: [] when every tool_call in a turn has a duplicate id. This empty array then passes through to strict OpenAI-compatible providers (Qwen-series) which reject it with HTTP 400. Fix: when kept_tcs is empty after dedup, drop the tool_calls key entirely instead of setting it to []. Closes #70126 --- agent/agent_runtime_helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/agent_runtime_helpers.py b/agent/agent_runtime_helpers.py index a418088916a95..acdcfdb8855ae 100644 --- a/agent/agent_runtime_helpers.py +++ b/agent/agent_runtime_helpers.py @@ -2872,7 +2872,7 @@ def sanitize_api_messages(messages: List[Dict[str, Any]]) -> List[Dict[str, Any] if cid: seen_assistant_call_ids.add(cid) kept_tcs.append(tc) - if len(kept_tcs) != len(msg.get("tool_calls") or []): + if kept_tcs: msg = {**msg, "tool_calls": kept_tcs} deduped.append(msg) elif role == "tool": From dbf79cee238d47db34253141be54d26ec8a467e9 Mon Sep 17 00:00:00 2001 From: chenbin Date: Fri, 24 Jul 2026 00:15:25 +0800 Subject: [PATCH 2/2] fix(transports): extend reasoning_effort ultra normalization to GLM models GLM models (glm-4, glm-4-plus, etc.) use the same reasoning_effort: ultra parameter as GPT-5.6 ultra. The _reasoning_config_for_model function was only checking for gpt-5.6, causing GLM reasoning effort to be sent as raw string 'ultra' instead of the normalized integer. This fixes the mismatch for GLM model families. Closes #70058 --- agent/transports/chat_completions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/transports/chat_completions.py b/agent/transports/chat_completions.py index 086883eca1c70..e5daeb56a4949 100644 --- a/agent/transports/chat_completions.py +++ b/agent/transports/chat_completions.py @@ -23,7 +23,7 @@ def _reasoning_config_for_model(model: str, reasoning_config: dict | None) -> di if not isinstance(reasoning_config, dict): return reasoning_config if ( - "gpt-5.6" in (model or "").lower() + ("gpt-5.6" in (model or "").lower() or "glm-" in (model or "").lower()) and str(reasoning_config.get("effort") or "").strip().lower() == "ultra" ): normalized = dict(reasoning_config)