Skip to content

Feature: print CLI replies in the order they happened, and fix loose numbered lists - #99

Merged
DevMando merged 3 commits into
mainfrom
feature/stream-reply-split
Sep 25, 2026
Merged

DevMando merged 3 commits into
mainfrom
feature/stream-reply-split

Conversation

@DevMando

Copy link
Copy Markdown
Owner

Summary

When the model writes something before using a tool ("let me check the docs…") and then answers afterwards, the CLI used to hold everything until the very end and print it as one block, below all of the tool lines. The two parts now print separately and in the order they happened: the lead-in above the tool line, the answer below it.

This PR also fixes numbered lists that rendered with each number alone on its own line.

What changed

  • Engine: AIService now reports reply text while it streams (OnResponseTextDelta), when each model call starts (OnResponseStreamStarted), and whether a model call is currently streaming (IsStreamingModelCall). The CLI uses these below. MandoCode Desktop uses the same hooks to show replies as they're written (separate Desktop PR).
  • CLI: text streamed before a tool call prints as its own block when the call starts. When the turn finishes, only the part not yet shown prints. Auto-continued turns now print as each one finishes instead of all at the end.
  • Tool calls written as plain text: some local models write their tool calls as text, which is only parsed after the reply ends. Those never trigger an early print, so raw tool-call text never reaches the terminal.
  • ReplyText helper: works out what's left to print by removing the already-printed parts from the final reply. Desktop uses it too.
  • Markdown rendering: in lists with blank lines between items, each number now stays on the same line as its text.

Why this was done

A reply printed out of order was hard to follow. The sentence the model wrote before looking something up ended up glued to the answer it wrote afterwards, below the tool calls that happened in between. Separately, numbered lists from some models came out with every number on a line of its own and a blank line after each item.

How it was tested

  • New unit tests for ReplyText and for loose-list rendering. The full harness test suite passes.
  • Checked in the CLI with a question that triggers a web search: the lead-in, the tool line and the answer print in order.

Notes

  • This only applies when response streaming is on for the model, which is the default. With streaming off, output is unchanged.
  • Two follow-up PRs build on this branch: the tok/s fix and the CLI live-UI work.
  • Changelog: entries added under [Unreleased].

DevMando and others added 3 commits September 24, 2026 14:01
AIService now raises OnResponseTextDelta with each chunk of a streaming
chat turn, OnResponseStreamStarted at the start of every model call
attempt, and exposes IsStreamingModelCall. A tool call that starts while
the flag is true was made mid-reply, so the text before it is final; a
text-written call runs after the stream, when it is false.

The CLI uses these to print the text written before a tool call as its
own block above the call's line, then prints only the rest of the turn
once it finishes. Each auto-continuation turn prints as its own block.
ReplyText.Unshown reconciles what was printed early with the turn's
authoritative text, and is shared with the Desktop app.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A list with blank lines between items is loose, so Markdig wraps each
item's text in <p> with whitespace-only text nodes around it. That
whitespace led the item, pushing its text below the number and leaving a
blank line after every item. The item's inline text is now trimmed at the
ends; spacing between inline elements and the break between two
paragraphs are kept.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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