Skip to content

bug: gateway renders only the tool name to OpenAI-compatible clients — arguments are available but discarded, and nothing renders on completion #244

Description

@ThalynLabs

Summary

_format_tool_call in cptr/routers/gateway.py renders a tool call to OpenAI-compatible clients as the tool's name and nothing else — no command, no arguments, no output. The arguments are available on the item by the time this function runs; it reads them only to extract title, then discards the rest.

This is the remaining half of #196. That issue fixed capture (input_json_delta fragments are now accumulated) and #197 fixed the name. Both landed. But the gateway still drops everything except the name on the way out, so for an OpenAI-compatible client the original symptom of #196 is unchanged: "You can see that Bash ran; you can never see what command it ran."

Verified in v0.9.21, running live against Open WebUI 0.11.1.

Current behaviour

cptr/routers/gateway.py:

def _format_tool_call(item: dict) -> str | None:
    """Render a tool call as compact markdown for OpenAI-compatible clients."""
    if item.get("type") != "function_call" or item.get("status") != "in_progress":
        return None

    arguments = item.get("arguments")
    title = arguments.get("title") if isinstance(arguments, dict) else None
    name = str(title or item.get("name") or "tool").strip() or "tool"
    return f"\n\n`{name}`\n\n"

arguments is in scope and populated — claude_code.py reassembles it from the accumulated input_json and attaches it alongside title — but only title is read.

Two consequences

1. Arguments are discarded. A turn that runs five commands renders as five identical `Bash` markers with no way to tell them apart, in the response or in the persisted chat.

2. Nothing renders on completion. The guard is status != "in_progress", so the only event that produces output is the tool starting. There is no terminal output, no result, and no success/failure signal — a tool that errored looks exactly like one that succeeded.

Why this matters more than it looks

I'm reporting this on behalf of a totally blind daily user (VoiceOver, macOS) who drives cptr agents through Open WebUI as the frontend — which is the arrangement gateway.py's own docstring describes.

For a sighted user a bare Bash marker is uninformative. For a screen-reader user it is worse than uninformative: the reply reads as a sequence of identical one-word announcements with no content between them, and there is no way to tell whether the agent did what was asked, did something else, or failed. The visual UI at least conveys shape; read aloud, there is nothing there at all.

Suggested direction

Not prescriptive about the form, but two things would resolve it:

  • Render the arguments, at least the primary one — the command for Bash, the path for Read/Write/Edit. A fenced block keyed on the tool would fit the existing compact-markdown style.
  • Emit on completion as well as start, so output and failure are visible. The output event already carries the item; the status != "in_progress" guard is what excludes it.

A verbosity setting would be reasonable if full output is considered too noisy for the default — though for the accessibility case the failure signal in particular should probably not be behind a flag.

Happy to open a PR if that would help; I've read the surrounding code and the change looks contained to this function and its two call sites. Given the project's first-time-contributor policy I'd rather be asked than assume.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions