Skip to content

chat: messages sent while a turn runs wait in a queue - #11

Merged
foxnne merged 1 commit into
chat/compactfrom
chat/queue
Oct 16, 2026
Merged

foxnne merged 1 commit into
chat/compactfrom
chat/queue

Conversation

@foxnne

@foxnne foxnne commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #10.

While a turn ran there was no way to send anything. The view only sent when idle. The ACP client also returns early from chat_send while prompting, since ACP's session/prompt is one turn at a time: it answers when the turn is over, and a second prompt has to wait for it.

Now, while a turn runs:

  • Enter queues the message. The text and anything attached go into a list shown above the message box: a quiet row each with its first line, +N for attached files, and an x to take it off. The placeholder says "Queue a message for when this turn ends".
  • When the turn ends (the client calls chat.set_busy with false), the queue goes as the next message: one person message, the queued texts in order separated by blank lines, all their attachments. That's what someone who kept typing would have sent, and it is one chat_send, so one prompt.
  • Stop doesn't send the queue unasked. It goes back into the message box, ahead of any draft, with its attachments, to send or edit.

The chat keeps the queue (Chat.queued), not a client, so every client the chat serves gets it the same way, with no contract change. It's sent from the plugin's beginFrame, so never from inside a client's own chat.set_busy call.

The Sample client (Debug only) now goes busy for its reply and stays busy until its last question is answered or Stop is pressed (new sample.chat_cancel), the way an agent waits on a permission. That lets the queue be seen with no agent running.

Seen

macOS, sandbox profile, driven by demo tapes against the Sample client, captured:

  • Sent "Show me", then typed three messages while the reply was busy: three queued rows above the box, Stop in place of Send, the new placeholder.
  • Took the second one off with its x: two rows left.
  • Answered Allow: the turn ended, the queue went at once (the saved transcript has a person message First queued message\n\nThird), the Sample answered it, the queue is empty, and the next turn is busy again.
  • Queued three and typed a draft, then pressed Stop: "Stopped." note, the queue's texts back in the message box above the draft, Send back.

Not run against a real ACP agent (not used here, as it costs and needs auth). The ACP path is the same chat_send once the turn has ended (setBusy(false) comes after state = .ready).

zig fmt --check src plugin.zig and zig build test clean; built against the fizzy main SDK (--fork).

🤖 Generated with Claude Code

Rebased 2026-10-16 onto main after #6 removed the Sample client. The Sample changes described above are gone with it. The queue itself is unchanged, but there is no longer a built-in way to see it without a real agent.

@foxnne
foxnne marked this pull request as ready for review October 16, 2026 14:53
@foxnne
foxnne added this pull request to stack #13 October 16, 2026 14:53
While a turn ran, Enter did nothing: the chat only sent when idle, and the
ACP client drops a prompt that arrives mid-turn (`session/prompt` is one
turn at a time). Now Enter, while busy, puts the message (and what was
attached) in a queue shown above the message box, each with an x to take
it off. When the turn ends, the queue goes as one message, its texts in
order. Stop puts the queue back in the message box rather than sending it.

The chat keeps the queue, not a client, so it works the same for every
client; it is sent from the plugin's `beginFrame`, never from inside a
client's `chat.set_busy` call. The Sample client now holds its turn busy
until its question is answered (or Stop), as an agent waits on a
permission, so the queue can be seen without an agent.
@foxnne
foxnne merged commit b277bc2 into main Oct 16, 2026
6 of 10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant