Skip to content

Claude/Codex interactive question tool calls render as raw JSON — user has to cancel the turn to respond #98

Closed

Description

@Juliusolsson05

What happened

When Claude or Codex invokes an interactive "ask the user a question" tool call mid-turn, Agent Code has no UI for it. The tool call comes through as a generic tool_use block and is rendered as raw JSON in the feed. There's no input affordance, no way to send the response back into the live turn, no way for the agent to receive the answer. The only way to unblock is to cancel the in-flight turn, then send a follow-up message — which loses the connection between the question and the answer at the agent's protocol level (the agent sees a cancel + new turn, not a tool_result satisfying the question).

This is a significant UX gap because asking-the-user is one of the cleaner ways for an agent to handle ambiguity without making bad guesses, and both providers expose it. We currently make it useless.

Repro

  1. Prompt either provider with something ambiguous enough that it decides to ask a clarifying question via its question tool (Claude's `AskUserQuestion` / Codex's equivalent).
  2. Observe the feed: a tool_use block appears with the question payload as raw JSON.
  3. No input shows up. The composer doesn't repurpose itself. The turn stays "waiting".
  4. Cancel the turn → resubmit a new message → agent has lost the structured-question protocol.

Where

The handling has to happen across several layers (no file:line yet because in-progress code may already exist on a branch; flagging the subsystems):

  • Semantic event handling (`src/renderer/src/workspace/semantic/foldEvent.ts`) — needs to recognise the question tool_use and emit a structured "awaiting user answer" state instead of treating it as a generic block.
  • Feed renderer — a dedicated row component for the question, with the answer affordance inline. Similar shape to existing `TrustDialogModal` / permission prompts but anchored in the feed, not a modal.
  • Composer / IPC — sending the answer must commit it as a tool_result for the original tool_use_id, in the same turn, not as a new user message. Wiring on the provider side (claude-code-headless + codex-headless) for getting the answer back into the running CLI without cancelling.
  • State — the turn needs to be in a distinct "paused-awaiting-user" state so other UI affordances (the streaming indicator, the cancel button's meaning) reflect it correctly.

Output

N/A — UX-blocking, no crash.

State

Affects every conversation where either provider chooses to ask a clarifying question. Higher friction with Codex because its agent prompts are more inclined toward asking questions than Claude's are in practice.

Notes

Owner mentions work is already a good way along — won't sketch a fix shape here. Filing as the canonical issue to track that work and pick up under.

Activity

  1. Juliusolsson05 commented on Jul 7, 2026

    @Juliusolsson05
    OwnerAuthor

    Resolved: AskUserQuestion now renders a native picker and commits the selected answer as a tool_result into the same turn — no more cancel-and-resend.

    Shipped across #323 (native picker), #329/#330 (conditions AUQ module + answering driver), #335 (multi-question), and #462 (committed-plane answered row). See src/renderer/src/features/feed/ui/rows/AskUserQuestionAnsweredRow.tsx, semantic/AskUserQuestionRow.tsx, and packages/claude-code-headless/src/conditions/askUserQuestion*.ts.

    (#289 is a duplicate of this and is being closed alongside. If Codex live-answer parity is wanted, open a focused follow-up.) Closing.

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