Answer agent prompts from the chat, and recognize Claude Code 2.1 / Codex 0.156 prompts - #6
Conversation
devswha
left a comment
There was a problem hiding this comment.
Thanks. The stale-prompt guard (re-read the screen, 409 on an id mismatch) is solid. Two things before merge:
- Multi-question Claude prompts can answer the next question.
claudeTabs(server/prompt.ts) only looks for the tab bar within 8 lines above the first option, and it requires the bar to end inSubmit →. On a narrow pane the question wraps or the bar gets cut off, sotabbedcomes out false. The answer then sends→+ Enter, and that Enter picks option 1 of the next question. I reproduced this with a question that wraps to about 7 lines. Suggested fix: send only→and let the review card handle the submit step. - Short chat replies approve prompts. While a card is showing, a composer message like "yes" or "1" is matched against the option labels and approves whatever is on screen, which could be an
rm -rfapproval. Please add an explicit confirm step for approval cards, or only treat text as an answer when the user taps an option.
Minor: a ──── line inside a file preview can confuse the approval title, and a label that wraps onto more than two lines is still cut off. Both fail safe. Please also add parser tests for wrapped questions and a cut-off tab bar.
8150887 to
9ef780b
Compare
|
Thanks. Both points are fixed:
Minor: the approval title now comes from the rule under the |
0b73cc6 to
6c8f0de
Compare
devswha
left a comment
There was a problem hiding this comment.
Thanks. Both earlier points are fixed: a Claude multiple choice now always ends with → alone (checked with a 9-line wrapped question and a missing, cut-off or whole tab bar), and typed picks on approval and plan cards wait for Confirm. The new Codex queued-question feature has the same kind of problem as the second point, though:
- Queued Codex questions take over the composer. Codex keeps working while questions sit in its queue, and
busyis forced off whenever a card shows (PaneTerminal.tsx~470–495). So a message meant for Codex, like "stop, don't touch prod", goes out at once as the typed answer to the queued question: alt+↑, the text, then Enter. There is no confirm step. For a question with no options, any text counts as the answer. And the user has no way left to message Codex normally from the chat. Please make typed text answer a queued question only when the user opts in, for example by tapping the card first, and send ordinary composer text as a normal message. - Some typed picks still skip confirmation. Claude's "Review your answers" card is a question, so a typed
1submits every answer at once (claude-submit). A Codex menu card behaves the same way. Please put submit-all and menu picks behind the same Confirm. - alt+↑ can open the wrong queue. If Codex also has queued user messages, alt+↑ may open those instead of the questions (
openQueuedQuestion). The 409 guard catches it, but only after the key has been sent.
Minor: parseClaudeApproval takes the first rule after the last ● line, and Claude also prefixes its own text with ●. A rule inside that text gives an rm -rf approval the title "Results table follows". It fails safe. Also, unansweredCodexQuestions reads up to 16MB synchronously on a poll.
6c8f0de to
bab593f
Compare
|
Thanks. Addressed in bab593f, on top of a rebase onto main (#11 and #18 are merged):
Minor.
Checked live on Codex 0.156.1:
|
… queue herdr reports Codex blocked while questions asked with request_user_input_async wait collapsed above its main prompt, so agent.prompt refused a message the TUI would take (Codex then drops the questions). When agent.prompt answers agent_blocked and the screen shows only that collapsed queue, the message goes through send_text and its own Enter. An open question, whose "enter submit … skip" hint means it holds the input, is still refused. Found while checking this with devswha#6's queue cards on a live Codex 0.156.1 pane. A contract test runs a stand-in `codex` reported blocked that shows the collapsed queue, and fails without this change. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Note on merge order: #6 and #15 both touch |
devswha
left a comment
There was a problem hiding this comment.
Thanks. The three points are fixed: queued cards answer only from the card, menus wait for Confirm, and the count line is re-checked before alt+↑. Two new issues bring back the first problem:
- The queue can be left open, and then the composer answers again (
prompt.ts~700–707,PaneTerminal.tsx~472–488). IfopenQueuedQuestionfinds a different question, or nothing within 2s, it returns 409 and leaves the queue open. The next poll shows acodex-async-questionwithoutqueued, so the composer takes over again, and "stop, don't touch prod" goes out as the free-form answer while Codex keeps working. Please send alt+↓ on the 409 path. Also close an open queue before any composer send, or treat an open queue asqueuedas well. - Concurrent polls corrupt the async scan cache (
codex.ts~210–253). Two calls share one scan object across theawait, so both push the same questions and both add tosize. Reproduced:["First?","Second?","Second?"]. With a count of 2,slice(-count)gives[Second, Second], so the card shows the wrong question, the answer gets a 409, and the queue stays open (see 1). Two viewers, or a poll overlapping an answer, are enough to trigger it. Please share one in-flight scan per file, or build the result locally and commit it once.
Lower priority:
- Composer sends go straight to the terminal and aren't ordered with a card answer. A send between alt+↑ and the answer keys, or between the next question opening and alt+↓, becomes that question's answer. This can share #15's per-pane queue.
closeQueuecan read a stale screen at 100ms and send alt+↓ after Codex has returned to its main prompt or put up an approval. Please check what alt+↓ does there.- MCP calls (
● srv - tool (MCP)() don't match the new approval regex. It still fails safe.
… queue herdr reports Codex blocked while questions asked with request_user_input_async wait collapsed above its main prompt, so agent.prompt refused a message the TUI would take (Codex then drops the questions). When agent.prompt answers agent_blocked and the screen shows only that collapsed queue, the message goes through send_text and its own Enter. An open question, whose "enter submit … skip" hint means it holds the input, is still refused. Found while checking this with devswha#6's queue cards on a live Codex 0.156.1 pane. A contract test runs a stand-in `codex` reported blocked that shows the collapsed queue, and fails without this change. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
bab593f to
44973b0
Compare
|
Thanks. Addressed in 44973b0, rebased onto main (#16, #17 and #19 are merged):
Lower priority.
Checked live on Codex 0.156.1:
|
devswha
left a comment
There was a problem hiding this comment.
Thanks. Both fixes check out. With a fake Codex pane that swaps screens as keys arrive, a wrong question now gives a 409, alt+↓ and the remembered question on the next card. A late-opening queue becomes queued:"open", card-only. The two-poll test fails on the old scanner. #6 on top of #15 passes 306 tests, and the ordering holds: alt+up, enter, alt+down, SUBMIT.
#15 and #20 are now merged, so please rebase onto main. The resolution needs care:
- Put the whole answer flow inside #15's
serialize: read, open the queue, keys, close the queue. A naive resolution leaves open and close outside the pane's turn, and then a composer submit can land between them, which is the ordering this depends on. Composer.tsx: after the merge, both PRs declareconst [sending, setSending], and typecheck fails until one is removed.server/codex.test.ts: thenode:fsimport line conflicts with #20 (appendFileSyncvsrenameSync). Keep both.
Lower priority, fine as a follow-up:
- "Send now" skips the open-queue check.
PaneTerminal.tsx~628 callssendComposerTextdirectly, and the refusal lives only incomposerSend. With #15 merged the server refuses it, but please route it through the same check. - Remembered question with a repeated title. The card matches the remembered question by title only (
prompt.ts~340), taking the oldest match. If an earlier skipped question has the same title but different options, every tap gives a 409 plus alt+↑/alt+↓. It fails safe, but the chat can never answer it. Please match on the options too, and clear the remembered question when the rollout changes. - Consecutive questions with the same title.
closeQueuetakes the next one for the question just answered and leaves the queue open. Fails safe.
Checked against live Claude Code 2.1.280 and Codex 0.156.0 panes, several
prompts left the chat at INPUT with no card:
- Claude with several questions: the hint reads "Tab/Arrow keys to
navigate" and the answers are reviewed before sending. Each question is now
a card titled with its tab ("Route · 1 of 2"), the review is its own card,
and a multiple choice among several questions moves on with → instead of
→ enter, which picked the next question's first option.
- Claude tool approvals no longer print "This command requires approval" or
"Dangerous rm operation": the panel under a rule opens with the tool ("Bash
command", "Create file") and asks "Do you want to …?". Options end at the key
hint, so a label wrapped by a narrow pane reads whole.
- Codex's last question submits them all ("enter to submit all"), and its
folder trust now asks "Trust this folder?" with "enter continue · esc back".
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
While a prompt card shows, a message from the composer answers it instead
of being typed into the agent's menu: an option's number as the agent shows
it, its label, or the letter it binds ("y"); several numbers for a multiple
choice. Anything else is the prompt's own reply when it takes one; a prompt
that takes only its options keeps the text and says how to choose. The
placeholder tells which, the card numbers its options, and a message is
never queued behind a prompt.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Review follow-ups: - A Claude multiple choice ended with → + enter when its question looked like the only one. With a long question wrapping the tab bar out of reach, or a narrow pane cutting the bar off, that enter picked the next question's first option. It now always ends with → alone: Claude moves on to the next question, or to the review of the answers, which has its own card (checked live on Claude Code 2.1.280 with one and with two questions). - The tab bar is looked for up the panel however far the question wraps, and a bar cut off at the pane's edge still counts; the question's wrapped lines are joined back into one. - A typed "1" or "yes" no longer answers an approval or a plan by itself: the card highlights the pick and asks to Confirm or Cancel. A tap on an option in the card, and a question's typed answer, still send at once. - An approval's title comes from the panel under the tool call, not from a rule inside a file preview, and an option wrapped over several lines reads whole. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Codex 0.156 asks with request_user_input_async without stopping: the questions wait in a queue above the main prompt, collapsed to "? 2 questions / alt+↑ to answer". The chat saw no prompt there, and herdr's own alt+↑ binding keeps the keyboard from opening it (shift+← does). - The collapsed queue now shows as a card. The screen gives only a count, so the questions come from the pane's rollout: the newest unanswered request_user_input_async questions (a skip leaves no record), read incrementally from what the rollout appends. - Answering it opens the queue (alt+↑ sent to the pane) and answers there only if the question shown is the card's (title and options, compared across wrapping). Otherwise the queue stays open and the chat re-reads the question actually waiting. - An open question: the title may wrap, "1 of 2" becomes the card's title, the last row takes a typed answer (it is typed into directly, no enter), and a free-form question with no options is answered with text alone. - The chat shows an answer as the text chosen, not the <send_user_message_question_reply> JSON Codex sends the model, and the question tool's summary lists the questions asked. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…enu picks Review follow-ups: - A question in Codex's queue no longer takes over the composer. Codex keeps working while it waits, so a message like "stop, don't touch prod" goes to Codex as a message, and the card alone answers the question (its option buttons, or its own text field). The prompt carries `queued: true`, and the card says so. After an answer from the chat, the queue closes again (alt+↓), so the next question waits collapsed and the main prompt has the input back. - A typed pick on a menu now waits for Confirm, like approvals and plans. Claude's "Review your answers" (now kind "menu") would submit every answer at once, and Codex's continue menus act at once. - alt+↑ is sent only while the screen still shows the questions' count. On Codex 0.156.1 a queued message of the user's own replaces the questions' block (and alt+↑ or shift+← then open nothing), so no card shows then. - A Claude approval's panel is found under the tool call (`● Name(`), not under Claude's own text, which opens with ● too. A rule in its table no longer titles an rm -rf approval. - The rollout scan for queued questions reads without blocking and starts with the last 4MB rather than 16MB. Checked live on Codex 0.156.1: the card shows while the message box still reads "Message Codex…". A tap on an option answered it and the queue folded back to "? 1 question". The free-form answer was sent from the card. With a question queued, a message from the box reached Codex as a message. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…a time
Review follow-ups:
- The queue is never left open by the chat. When it opens on another
question than the card's, or does not open within 2s, it is closed
again (alt+↓), and the question it opened on is remembered, so the next
card shows that one instead of the rollout's newest-first guess (a
skipped question leaves that guess wrong). After an answer, the queue
closes only once a different question shows, never on the stale screen
of the one just answered. Checked on Codex 0.156.1: alt+↓ on the main
prompt or an approval changes nothing.
- An open queue is card-only too (`queued: "open"`). It holds the
terminal's input, so the composer sends nothing while it shows and
says why, rather than typing the message into the question. A
collapsed queue (`queued: "collapsed"`) still leaves the composer
talking to Codex.
- Concurrent polls of one rollout share a single scan, and the scan is
built on a copy and kept only once complete. Two viewers, or a poll
overlapping an answer, no longer push the same questions twice. There is
a test that fails with the old scanner.
- An MCP call ("● server - tool (MCP)(…)") anchors a Claude approval's
panel like any tool call.
- Text typed in the composer while a message was on its way stays: only
what was sent leaves the box (as in devswha#15).
Checked live on Codex 0.156.1:
- With the queue opened in the terminal, a chat message was held with the
reason and nothing reached the question. The card answered it.
- With the second of two questions skipped, the card's guess (Beta?)
answered nothing, the queue closed, and the next card showed Alpha?,
which the card then answered.
- The earlier flows (tap, free-form, message box to Codex) still pass.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Rebased onto main (devswha#15 and devswha#20 merged). The whole answer runs inside devswha#15's per-pane serialize: read, open the queue, keys, close. A composer submit can't land between them. Review follow-ups: - "Send now" on a held message goes through the same check as the composer. It is disabled, with the reason as its title, while Codex's queue is open in the terminal. - The remembered question (the one the queue really opened on) is matched by title and options, the newest such one. It is dropped when the pane's rollout changes. An older skipped question with the same title no longer takes its place. - closeQueue tells the question just answered from its twin by prompt id, and after 600ms treats an identical question still open as the next one (Codex takes the Enter at once). Two questions with the same title and options no longer leave the queue open. Checked live on Codex 0.156.1: two identical queued questions, each answered from its card, with the queue folded back to "? 1 question" in between. The earlier queue flows still pass. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
44973b0 to
e44244d
Compare
|
Thanks. Rebased onto main (#15, #20 and #22 are merged), resolved as you described:
The lower-priority items are in e44244d:
Checked live on Codex 0.156.1, on top of #15 and #20 (the same build as main plus this branch):
|
The prompt card numbers its options ("1. Yes, continue") so a typed "1"
in the composer can be matched to a card button. The UI regression still
looked for the bare label and timed out on the startup-prompt step.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Pushed 098e959: |
devswha
left a comment
There was a problem hiding this comment.
Thanks, this is close. All three earlier asks are done:
- The whole answer runs inside
serialize: read, open the queue, keys, close. Composer.tsxhas a singlesendingdeclaration and main's settle code.- The
codex.test.tsimports are fixed.
I also merged it into current main (0.3.4). There are no conflicts, bun test passes 316/316, and scripts/ui-regression.ts passes 7/7. I found no path that types into the wrong pane or answers a stale prompt without a tap.
Two small fixes before merge:
1. A typed pick waiting for Confirm outlives its prompt.
pendingAnswer (PaneTerminal.tsx:109) is cleared only by these:
- Confirm or Cancel
- a later composer send that answers directly (
:501)
Three things leave it set:
- a tap on an option in the card
- answering in the terminal
- the prompt going away
The card shows it again whenever pendingAnswer.promptId === prompt.id, and that id is a hash of the prompt's content.
Scenario:
- The user types
1on a Claude approval forrm -rf build, and "Send 1. Yes? Confirm" appears. - They approve in the terminal instead.
- Later Claude asks for the same command again.
- The new card opens with "Send 1. Yes?" already in place, and the composer says "Confirm your answer in the card above". One tap approves.
It still needs a tap, but it's an easy accidental approval. Please drop pendingAnswer whenever the pane's prompt changes or goes away, in onChatPrompt for example, and after any successful answer.
2. An invalid answer can leave Codex's queue open.
In handlePromptRequest (server/prompt.ts ~808–829), a codex-queued-question card sends alt+↑ (openQueuedQuestion) first and validates the answer afterwards. If answerKeys throws, the request returns 400 without alt+↓. The same happens if a key send throws partway through. It fails safe, because the next poll sees queued: "open" and submits are refused. Still, it breaks the PR's own promise that the chat never leaves the queue open.
Please validate the answer against the collapsed prompt before opening the queue, or close the queue in a try/finally once it has been opened.
Nits, optional:
codexQuestionsCollapsed(main, used bysubmitText) and the newqueuedQuestionCountstill both detect a collapsed queue. If they disagree, the card and the server's send refusal tell different stories.closeQueue(~705) andqueuedPrompt(~182) each have two JSDoc blocks stacked.
A pick typed in the composer ("1") waits in the card for Confirm. It was
cleared only by Confirm, Cancel or a later direct answer. Answered some
other way (a tap in the card, or the terminal), it stayed, and the same
prompt asked again (same content, so same id) opened with "Send 1. Yes?"
already waiting one tap from Confirm.
It is now dropped when:
- the pane's prompt changes or goes away,
- the card answers,
- the agent goes back to work (the same prompt asked again between two
reads),
- the page is hidden (prompts are not read then).
The UI regression types "1" on the startup menu, answers in the terminal,
paints the same menu again and checks no Confirm waits on it.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…detector - An answer to a collapsed-queue card is checked against the card before alt+up opens the queue, so an invalid one returns 400 with the queue still closed. Once this request has opened the queue, a failure on the way (invalid keys for the opened question, a key send that throws) closes it again in a finally. - codexQuestionsCollapsed (the send path's fallback) now reads the same queuedQuestionCount as the card. That count requires the "to answer" hint with the main prompt right under it, so the card and the send refusal cannot disagree. - One JSDoc block each for closeQueue and queuedPrompt. Checked on a live Codex 0.157.0 pane, with a question queued while the turn runs: - before: three invalid answers each returned 400 and left the queue open - after: all three returned 400 and '? 1 question' stayed collapsed; a valid answer was recorded as the question's reply Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Thanks. Both fixes and both nits are in 52c0bab and e8e30e0. 1. A typed pick outlives its prompt (52c0bab).
2. An invalid answer leaves the queue open (e8e30e0). The answer is checked against the collapsed card before alt+↑. Once the request has opened the queue, any later failure (keys for the opened question, a key send that throws) closes it again in a
Nits:
One thing I noticed on the way: Codex 0.157.0 changed async questions. The question also shows as an agent message, and its queue is dropped when the turn ends, leaving no record. On 0.157 the collapsed card only appears while Codex is still working. After that, the question is simply gone and a normal message answers it. The live check above ran on 0.157.0. Answering from the card during the turn works, and Codex takes the reply at its next step. |
…mpts Conflicts: - server/prompt.ts: codexQuestionsCollapsed reads queuedQuestionCount now; main's "not a numbered menu row" check (devswha#23) moves into that one count. - src/components/ChatView.tsx: main's memo wrapper, with this branch's prompt props.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Merged current main (0.3.6) into the branch (1d48e5c). There were two conflicts. In |
devswha
left a comment
There was a problem hiding this comment.
Thanks, both fixes are exactly right. A typed pick is dropped whenever its prompt changes, is answered, the agent goes back to work or the page is hidden, and the new ui-regression step covers the scenario. An answer to a queued card is now checked before alt+↑, and the finally closes a queue this request opened. I merged this together with #40–#42 onto current main: bun test passes 330/330, test:ui passes 8/8 and chat-browser-qa passes 5/5. I'll add the CHANGELOG entry in the release commit.
Summary
Prompts the parser missed (
fix(prompt)). I checked live Claude Code 2.1.280 and Codex 0.156.0 panes. Each of these used to leave the chat at INPUT with no card, and now gets one:Answering from the composer (
feat(chat)). While a card shows, a message answers it: an option's number, its label, or its bound letter. Any other text becomes the prompt's own reply when the prompt takes one. A prompt that takes only its options keeps the text in the box and says how to choose.Review follow-ups (
fix(prompt)). Typed picks on menus (Claude's "Review your answers", Codex's continue menus) now wait for Confirm as well:→alone. That moves to the next question or to the review card, which has its own Submit. I checked this live with one question and with two.Codex's queued questions (
feat(prompt)). Codex 0.156 can ask withrequest_user_input_asyncwithout stopping. The questions then wait in a queue above its main prompt, collapsed to "? 2 questions / alt+↑ to answer", so the chat showed no card. herdr's own alt+↑ binding also keeps the keyboard from opening the queue.queued: "collapsed"), the message box keeps talking to Codex. While it is open in the terminal (queued: "open"), it holds the input, so the chat sends nothing and says why. The chat never leaves the queue open itself.1 of 2becomes the title, a wrapped title reads whole, an own answer is typed into the last row, and a free-form question with no options takes text alone.<send_user_message_question_reply>JSON that Codex sends the model.Testing
bun run typecheckpasses andbun testpasses 281/281 (rebased onto main). Parser tests are built from screens captured live, including a question wrapped over seven lines, a cut-off tab bar, a file preview containing a rule, and a label wrapped over three lines.End to end on a live Claude Code pane in a headless Chrome chat view:
2, then answered with a reply of my own, then the review submitted by click. Claude recorded both answers.rm -rf junkapproval:1waits for Confirm, and then Cancel sends nothing, so the directory stays4then Confirm answers NoEnd to end on a live Codex 0.156.1 pane: two queued questions, one choice and one free-form. The collapsed queue showed as a "Question 1 of 2" card.
2answered the choice, and a typed reply answered the free-form question. Codex recorded both answers ("YCB-V selected. Note: keep the logs"), and the chat shows onlyYCB-Vandkeep the logs.Rebased onto main now that #5 is merged.
🤖 Generated with Claude Code