Summary
Hindsight's Reflect agent loop forces a retrieval tool on its first turn by sending
tool_choice: "required" (named tool_choice is normalized to required with the tools
list pre-filtered to the single forced tool, per openai_compatible_llm.py). The Z.AI
(Zhipu) endpoint — used for GLM models, e.g. z-ai/glm-5.3-flash — rejects every
tool_choice value except "auto" with HTTP 400. This is behaviorally identical to
Meta Model API, which is already handled via _NON_AUTO_TOOL_CHOICE_UNSUPPORTED_PROVIDERS.
Reproduction
Via OpenRouter with provider.only: ["z-ai"] — the error originates from the Z.AI
backend (see metadata.provider_name in the payload):
| Request |
Result |
tool_choice: {"type":"function","function":{"name":"recall"}} + tools |
❌ HTTP 400 |
tool_choice: "required" + tools |
❌ HTTP 400 |
tool_choice: "auto" + same single tool |
✅ 200, tool called 5/5 |
Error payload:
{"error":{"message":"Tool choice must be auto","code":400,"metadata":{"provider_name":"Z.AI"}}}
The "auto" row was verified with 5/5 successful tool calls on memory-retrieval style
prompts (system prompt instructing mandatory tool use, single tool available), so the
model does not need the forced tool_choice to reliably call the tool.
Impact
Every Reflect (and any other forced-tool) operation against GLM models routed to Z.AI
fails after retries. Retain/Consolidation are unaffected (no forced tool_choice).
Tested on z-ai/glm-5.3-flash with Hindsight 0.9.2, September 2026 — still current.
Suggested fix
Add Z.AI (zai) to _NON_AUTO_TOOL_CHOICE_UNSUPPORTED_PROVIDERS. The downgrade to auto
is functionally safe here: named tool_choice is already normalized to required with the
tools list narrowed to the single forced tool, so under auto the call remains practically
forced — the same reasoning as the existing DeepSeek and Meta branches.
Workaround currently in use
HINDSIGHT_API_REFLECT_LLM_EXTRA_BODY={"tool_choice":"auto"}
Verified working (Reflect succeeds end-to-end on Z.AI), but it relies on extra_body
merge precedence and is not an API contract. Alternative: route Reflect to a
tool-forcing-compatible host (e.g. Novita).
Summary
Hindsight's Reflect agent loop forces a retrieval tool on its first turn by sending
tool_choice: "required"(named tool_choice is normalized torequiredwith the toolslist pre-filtered to the single forced tool, per
openai_compatible_llm.py). The Z.AI(Zhipu) endpoint — used for GLM models, e.g.
z-ai/glm-5.3-flash— rejects everytool_choicevalue except"auto"with HTTP 400. This is behaviorally identical toMeta Model API, which is already handled via
_NON_AUTO_TOOL_CHOICE_UNSUPPORTED_PROVIDERS.Reproduction
Via OpenRouter with
provider.only: ["z-ai"]— the error originates from the Z.AIbackend (see
metadata.provider_namein the payload):tool_choice: {"type":"function","function":{"name":"recall"}}+ toolstool_choice: "required"+ toolstool_choice: "auto"+ same single toolError payload:
{"error":{"message":"Tool choice must be auto","code":400,"metadata":{"provider_name":"Z.AI"}}}The
"auto"row was verified with 5/5 successful tool calls on memory-retrieval styleprompts (system prompt instructing mandatory tool use, single tool available), so the
model does not need the forced tool_choice to reliably call the tool.
Impact
Every Reflect (and any other forced-tool) operation against GLM models routed to Z.AI
fails after retries. Retain/Consolidation are unaffected (no forced tool_choice).
Tested on
z-ai/glm-5.3-flashwith Hindsight 0.9.2, September 2026 — still current.Suggested fix
Add Z.AI (
zai) to_NON_AUTO_TOOL_CHOICE_UNSUPPORTED_PROVIDERS. The downgrade to autois functionally safe here: named tool_choice is already normalized to
requiredwith thetools list narrowed to the single forced tool, so under auto the call remains practically
forced — the same reasoning as the existing DeepSeek and Meta branches.
Workaround currently in use
Verified working (Reflect succeeds end-to-end on Z.AI), but it relies on
extra_bodymerge precedence and is not an API contract. Alternative: route Reflect to a
tool-forcing-compatible host (e.g. Novita).