GLM-5.3-Flash on a local vLLM, used from Codex Desktop through magpie's Responses endpoint, wrote its calls into its text as GLM's template does: <tool_call>exec<arg_key>input</arg_key><arg_value>…</arg_value></tool_call>. magpie held text from <tool_call> on but read only Hermes' JSON after it, so the block went to Codex as text and the turn ended. parseTextCalls now reads GLM's form when what follows <tool_call> is not JSON: the tool's name, then each <arg_key>/<arg_value> pair, a value that is JSON (number, object, list, boolean) taken as JSON, else the string it says. As before, every block must name a tool the request offered, else the whole reply stays the text it was. It works wherever the text is read for calls: Chat's relay, the translated Chat, Responses and Anthropic paths, streamed and whole, and a plugin's model; a Responses custom tool (Codex's exec) becomes a custom_tool_call carrying the input.
Tested end to end in a sandbox HOME: a fake vLLM streaming GLM's markup split mid-tag, added as a provider, magpie serve on a spare port, and a Responses client offering exec as a custom tool and update_plan: streamed and whole, the reply came back as the text before the block and a custom_tool_call exec whose input is the code. TestGLMTextCallCustomTool (stream split mid-tag, streamed and whole), TestGLMTextCallFunctionTool (JSON values kept, two calls), TestGLMTextCallChatAndMessages and TestPluginGLMTextCall are new and fail without the change; TestGLMTextCallUnofferedLeftAsText (an unoffered tool stays text) passes with and without it. go vet, go build (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui ./... under a temp HOME pass (TestClientGoneRecordedAsCanceled fails now and then on main without this change too).