Skip to content

Generate transport breaks parallel image reads: "Tool result is missing for tool call ... server_error" #96

Description

@zidanefaqih

Summary

On a Go plan account, the extension falls back to the legacy /alpha/generate transport (the Provider API answers 403 upgrade_required). On that transport, messagesToCC() interleaves image parts between consecutive tool results:

assistant: [tool-call A, tool-call B]
tool:      [tool-result A]
user:      [image A]        <-- inserted here
tool:      [tool-result B]
user:      [image B]

The gateway closes the tool turn as soon as it sees the user message, so call B is still unanswered and the request aborts with:

Error: Tool result is missing for tool call call_01_...: server_error
Error: Retry failed after 3 attempts: Tool result is missing for tool call call_01_...: server_error

The failure is deterministic: all 3 retries send the same body and fail identically. The session JSONL stays valid (every toolCall has exactly one toolResult, no orphans, no duplicates) — only the serialized request is malformed.

Minimal reproduction

  1. Be on a Command Code Go plan so the transport router selects /alpha/generate.
  2. Have two images on disk (/tmp/a.png, /tmp/b.png).
  3. Ask the agent to read both in the same assistant turn, so the model issues two parallel read calls.
read both of these screenshots /tmp/a.png /tmp/b.png

Result: Tool result is missing for tool call ...: server_error, stuck after 3 retries.

Reading one image per turn succeeds every time in the same session. Reading two in one turn fails every time. Three would fail the same way.

Local verification of the cause

I ran the exact message array through messagesToCC() from src/converters.ts (0.6.4) using the real session context that failed:

user:      text
assistant: tool-call, tool-call
tool:      tool-result
user:      image            <-- tool result B has not been emitted yet
tool:      tool-result
user:      image

Then I applied the diff from #84 locally and re-ran the same context:

assistant: tool-call, tool-call
tool:      tool-result
tool:      tool-result
user:      image, image     <-- batched, at the end

The malformed ordering is gone. Regression checks with the patched converter for 1 / 2 / 3 parallel image reads, text-only models (allowImages: false), tool errors, and mixed text+image results all produce the expected shapes.

Note: pi-ai already does this correctly

pi-ai/dist/api/openai-completions.js batches consecutive toolResult messages before emitting images (for (; j < transformedMessages.length && transformedMessages[j].role === "toolResult"; j++)) and emits a single user message with all accumulated images afterwards. messagesToCC() does not, which is why the same conversation works through the native provider path and breaks on /alpha/generate.

This is the only difference needed to fix it — see #84.

Why this is not a duplicate of #84

#84 contains the same root cause and the fix, but it is not merged and it was verified against Oh My Pi with Qwen/Qwen3.8-Flash. This report adds:

  • a pi host reproduction (not OMP),
  • a Command Code Go plan account, where the transport router forces /alpha/generate instead of the Provider API,
  • the observation that the Provider API path (/provider/v1) is never reached on Go plans, so Go-plan users hit the broken converter unconditionally,
  • confirmation that the bug is unrelated to the model — any non-claude- model on the generate transport is affected.

If you prefer to keep tracking to #84, feel free to close this as a duplicate. The Go-plan transport routing is the part #84 does not cover.

Environment

pi 0.84.3
pi-commandcode-provider 0.6.4
Node v22.23.1
OS Linux x64
Plan Go (/provider/v1 returns 403 upgrade_required)
Transport /alpha/generate (legacy)
Model deepseek/deepseek-v4.1-flash

Workaround

Read images one per turn. Already applied #84 locally as a patch until it lands upstream.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions