view_image rejection on text-only models poisons model output — all subsequent turns return last_agent_message: null

Open 💬 0 comments Opened Jul 10, 2026 by selim-nba

Bug: view_image rejection on text-only models poisons model output — all subsequent turns return last_agent_message: null

Summary

When a text-only custom model (e.g. glm-5.2:cloud via Ollama provider) calls view_image, Codex rejects the call with "view_image is not allowed because you do not support image inputs". This rejection, fed back as a function_call_output, corrupts the model's output format: from that point onward, the model routes ALL output through the reasoning channel and never produces a message/assistant item. Every subsequent turn completes with last_agent_message: null — the UI shows nothing. The pattern is self-reinforcing: reasoning-only conversation history perpetuates reasoning-only output.

Environment

  • Codex Desktop (macOS), build 26.707.31428
  • Model: glm-5.2:cloud via built-in ollama provider (Responses API)
  • Model catalog: input_modalities: ["text"] only — no image support
  • Config: model_reasoning_effort = "medium", model_reasoning_summary = "detailed"
  • OS: macOS 15, Apple Silicon

Reproduction

  1. Start a Codex Desktop session with a text-only model (e.g. glm-5.2:cloud via Ollama).
  2. Work on a task where the model decides to view an image (e.g. macOS menubar app development — model takes a screenshot and calls view_image to inspect it).
  3. The model calls view_image with a path to a PNG.
  4. Codex returns: function_call_output: "view_image is not allowed because you do not support image inputs"
  5. The model continues working (more tool calls, reasoning), but on the final step of the turn, it produces only a reasoning response item — no message/assistant item.
  6. task_complete fires with last_agent_message: null. UI shows nothing.
  7. All subsequent turns (even trivial ones like "selam") produce only reasoning items and complete with last_agent_message: null.

Root cause analysis (from rollout JSONL)

Two sessions were compared — same model, same config, different outcomes:

| Metric | Healthy session | Broken session |
|--------|----------------|----------------|
| Session ID | 019f4c0b-... | 019f4c7f-... |
| Model | glm-5.2:cloud | glm-5.2:cloud |
| Provider | ollama | ollama |
| reasoning_effort | medium | medium |
| reasoning_summary | detailed | detailed |
| Turns | 52 (all OK) | 32 (last 5 NULL) |
| Max per-request context | 350,764 tokens | 261,648 tokens |
| Total cumulative tokens | 107M | 31M |
| view_image calls | 0 | 1 (rejected) |
| NULL last_agent_message | 0 | 5 |

The healthy session reached higher context usage (350K per-request, 107M total) with zero issues. The broken session broke at lower context usage (261K per-request, 31M total). Context window is definitively not the cause.

Trigger event (broken session, turn 27):

[line 1206] response_item/function_call: view_image, args={"path":"/tmp/menubar.png"}
[line 1207] response_item/function_call_output: "view_image is not allowed because you do not support image inputs"
[line 1208] tokens: last_out=16  (only 16 output tokens — model barely responded)

After this rejection, the turn continued with 9 function calls and 6 reasoning items. On the final step, the model produced a reasoning item (id: rs_17161) with the full response in summary and encrypted_content, but content: null — and no separate message/assistant item.

Turn-by-turn comparison (response item counts):

| Turn | Reasoning items | Assistant messages | last_agent_message |
|------|---------------|-------------------|---------------------|
| 26 (last working) | 0 | 1 | OK |
| 27 (trigger) | 6 | 0 | NULL |
| 28 | 1 | 0 | NULL |
| 29 | 1 | 0 | NULL |
| 30 | 1 | 0 | NULL |
| 31 | 1 | 0 | NULL |

Reasoning item structure is identical in working and broken turns (content: null, summary with text, encrypted_content with text). The difference is that working turns ALSO produce a separate message/assistant item; broken turns do not.

From turn 28 onward, the model produces only a single reasoning item per turn (no tool calls, no assistant message) and immediately completes with last_agent_message: null. The conversation history now contains reasoning-only outputs (no assistant messages), and the model perpetuates this pattern.

Expected behavior

  1. view_image should not be exposed to text-only models at all. The tool list should be filtered based on input_modalities — if a model only supports ["text"], view_image should not appear in the available tools. This prevents the model from ever calling it.
  1. If a tool rejection must occur at call time (e.g. as a fallback), the rejection response should be handled in a way that does not corrupt the model's output format. The current behavior — where a single rejected tool call permanently breaks assistant message generation for the entire session — is a severe regression.

Suggested fix

Primary: Filter view_image (and any other image-dependent tools) from the tool list when the active model's input_modalities does not include "image". This is the cleanest fix — the model can never call a tool it can't use.

Secondary: Investigate why a function_call_output containing an error message causes the model to permanently switch from content output to reasoning-only output. This may be an Ollama Responses API adapter issue where error-type tool outputs are not properly handled in the response stream, causing the model's content tokens to be misrouted to the reasoning channel.

Impact

  • Severity: High — the entire session becomes unusable (no responses shown to user) after a single view_image call on a text-only model.
  • Recovery: Only by starting a new session. The broken session cannot recover — every turn produces reasoning-only output.
  • Affected models: Any text-only model accessed via the Ollama provider (glm-5.2:cloud, kimi-k2.6:cloud, qwen3.5:cloud, etc.) — all have input_modalities: ["text"].
  • Trigger likelihood: Medium — the model must decide to call view_image, which happens when working on visual verification tasks (UI screenshots, menubar apps, etc.).

Session data

  • Broken session rollout: ~/.codex/sessions/2026/07/10/rollout-2026-07-10T17-47-41-019f4c7f-a632-7a42-86c7-24ed395e8067.jsonl (1268 lines)
  • Healthy session rollout: ~/.codex/sessions/2026/07/10/rollout-2026-07-10T15-41-04-019f4c0b-b820-7cc0-ab65-3a30595fb55f.jsonl (2513 lines)
  • Model catalog: ~/.codex/ollama-launch-models.json
  • Config: ~/.codex/config.toml

View original on GitHub ↗