Skip to content

Rich markdown formatting (including streaming) in any mode with --rich - #571

Closed
gianlucatruda wants to merge 11 commits into
simonw:mainfrom
gianlucatruda:main
Closed

Rich markdown formatting (including streaming) in any mode with --rich#571
gianlucatruda wants to merge 11 commits into
simonw:mainfrom
gianlucatruda:main

Conversation

@gianlucatruda

@gianlucatruda gianlucatruda commented Sep 12, 2024

Copy link
Copy Markdown

Overview

Fixes #12

This builds on the excellent foundation that @juftin laid down in #278 and

  1. fixes a mysterious bug that was failing some tests and
  2. resolves merge conflicts caused by changes since rich printing #278 was proposed.

I love llm and use it constantly. My only gripe has been the lack of rich formatting in the terminal. I recently used rich for a project and found it excellent, so I was excited to add this to llm. I found #278 was open but dormant, so I decided to nudge things along.

@simonw thanks for your amazing tools and awsome blog!

Screenshots

SCR-20240912-rpqh SCR-20240912-rpxr SCR-20240912-rqws

@gianlucatruda

Copy link
Copy Markdown
Author

Here's a demo gif of streaming working with rich output:
llm-with-rich-demo

@gianlucatruda gianlucatruda mentioned this pull request Sep 12, 2024
@gianlucatruda

Copy link
Copy Markdown
Author

Update: I've added pytest tests for making sure that --rich mode works as intended. I also factored in release 0.16 commits. All 185 tests pass.

@simonw is there anything else this needs in order to be merged? That would allow you to close #12

@irthomasthomas

Copy link
Copy Markdown

What is the benefit versus piping to something? I like the idea of keeping the main project as light as possible.

Screenshot_20240916_180124-1

@dzmitry-kankalovich

Copy link
Copy Markdown

@irthomasthomas likely the difference is in syntax highlighting of a partial / streamed LLM response.

I've been piping llms output to glow for the past months, but the drawback is that you see the result only when streaming is completed, and until that there is like no output. It's a subpar UX when you need to wait some dozens of seconds to see the result.

As I get it from @gianlucatruda examples here this particular problem was solved.

@gianlucatruda

gianlucatruda commented Sep 16, 2024

Copy link
Copy Markdown
Author

I like the idea of keeping the main project as light as possible.

I normally would agree, @irthomasthomas. But as @dzmitry-kankalovich correctly points out, piping breaks streaming, which is a major drawback to usability. I think this justifies the choice.

@irthomasthomas

irthomasthomas commented Sep 16, 2024 via email

Copy link
Copy Markdown

@gianlucatruda

gianlucatruda commented Sep 16, 2024

Copy link
Copy Markdown
Author

Are you talking about the ansi codes being injected?

@irthomasthomas When you pipe the output of llm to another application that renders markdown (which may do ANSI code injection), you have to wait for the entire LLM response, which could be several seconds or even minutes. And in chat mode, it's not possible at all. So it's not a viable solution.

This PR enables llm to do the rich textual rendering itself in a way that supports response streaming. That means the user sees the llm output in realtime, rendered prettily, as it arrives from the LLM. It also allows this rich text streaming to work in chat mode (as seen in my screenshots).

Overall, this PR adds functionality to llm that is not possible when piping to other tools. It's a massive upgrade to the user experience and something that has been requested by many people for a long time.

@irthomasthomas

irthomasthomas commented Sep 16, 2024 via email

Copy link
Copy Markdown

@dzmitry-kankalovich

Copy link
Copy Markdown

@irthomasthomas I just checked, and indeed highlight unlike glow does process stream responses.

however it... does not render markdown?

it just highlights (I guess hence the name) markdown blocks, but it does not render them - at least not like glow or rich.

It is somewhat better than just plain text, but it does not feel as convenient as these other alternatives.

@gianlucatruda

Copy link
Copy Markdown
Author

That's not true. The example I gave, I'm using highlight and that displays the rendered markdown as it streams in.

@irthomasthomas

  1. can you link to the source for installing highlight? If it's cli-highlight, then I'm unable to replicate the streaming you claim.
  2. your screenshots with piping to highlight are showing syntax highlighting, not markdown rendering as Markdown renderer support  #12 is asking for and this PR provides.
  3. can you provide an example showing evidence that streaming works with piping in both normal and chat modes?

@gianlucatruda

Copy link
Copy Markdown
Author

@simonw let me know if you have any feedback on this PR. Happy to make any changes necessary.

Comment thread llm/cli.py

def print_response(response, stream=True, rich=False):
# These nested ifs are necessary!? Only way this works.
if stream:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could also work

live.update(
    Markdown(full_response)
    if rich
    else Text(full_response)
)

@gianlucatruda

Copy link
Copy Markdown
Author

UPDATE: Since Simon doesn't seem to want to review this, a few of us in #12 have been trading workarounds. See here where I talk about richify. It's the same core functionality, but with some tweaks to the styling of the output and uv's script runner mode to automatically install and isolate dependencies -- making it much nicer and simpler to run as a standalone script.

Feedback and contributions are actively welcomed!

Image

@irthomasthomas

Copy link
Copy Markdown

I use highlight

llm "prompt" | highlight --syntax=bash --out-format=ansi

llm-highlight-00 02 13 333-00 02 46 667

@bretello

Copy link
Copy Markdown

This would be a pretty nice improvement to have

@vphantom

Copy link
Copy Markdown

Since this is an opt-in feature, why is it not being considered for merging?

Coming from Aider, I really like streaming Markdown formatting, including code blocks, and I was hoping to be able to replicate the experience with LLM's interactive mode. The piping workarounds mentioned here only help in one-shot mode.

@gianlucatruda

Copy link
Copy Markdown
Author

Since this is an opt-in feature, why is it not being considered for merging?

I agree, @vphantom, but @simonw has never responded to this PR or previous PRs/issues relating to this functionality. I tried contacting him on other platforms over many months as well, to no avail. Given that the contributions guide is there (and we followed it), it would be nice to get some kind of response, but this is open source and he's under no obligation to anyone.

The piping workarounds mentioned here only help in one-shot mode.

I use richify.py as a stop-gap solution (though it doesn't work in chat mode, as you mention). I still use it constantly and it annoys me every time that this isn't just a flag option in llm 😢

I've thought about just forking or re-writing llm with rich rendering functionality, but then I'd have to constantly update it to keep up with evolving models and APIs and I don't love the prospect of taking that on.

Someone once suggested trying to add the rich rendering functionality via plugins, but I suspect that to be an ass-pain.

@gianlucatruda

gianlucatruda commented Jul 22, 2025

Copy link
Copy Markdown
Author

It looks like there's a recent open PR proposing an almost identical solution, with very similar code: #981

@gianlucatruda

Copy link
Copy Markdown
Author

I also found a fairly recent comment from Simon relating to this:

I don't want to bake this stuff into LLM core but I'd love to enable plugins to do custom stuff like this.

Hoping to get some clarity there

@ldelossa

ldelossa commented Aug 8, 2025

Copy link
Copy Markdown

Ouch, not providing a 'streaming' formatter, when the main application defaults to streaming text, is a pretty bad take from the authors

@gianlucatruda

Copy link
Copy Markdown
Author

Life is too short

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.

Markdown renderer support

9 participants