Skip to content

feat: Render Markdown in chat and query output using rich#22

Open
KylinMountain wants to merge 6 commits intomainfrom
feat/chat-rich-markdown
Open

feat: Render Markdown in chat and query output using rich#22
KylinMountain wants to merge 6 commits intomainfrom
feat/chat-rich-markdown

Conversation

@KylinMountain
Copy link
Copy Markdown
Collaborator

Summary

  • Use rich.live.Live + rich.markdown.Markdown to progressively render LLM responses with proper terminal formatting (headings, bold, code blocks, lists, etc.)
  • Applied to both openkb chat (interactive REPL) and openkb query (single-shot)
  • Falls back to plain text when --no-color is set (chat) or stdout is not a tty (query)
  • Add rich>=13.0 as an explicit dependency

Test plan

  • python -m pytest tests/ — 197 passed
  • openkb chat — verify headings, bold, code blocks render with formatting
  • openkb chat --no-color — verify plain text fallback
  • openkb query "question" — verify formatted output
  • openkb query "question" > file.txt — verify no ANSI codes in file

@KylinMountain
Copy link
Copy Markdown
Collaborator Author

KylinMountain commented Apr 12, 2026

image

Use rich's Live + Markdown to progressively render LLM responses
in the chat REPL with proper formatting (headings, bold, code
blocks, lists, etc.) instead of raw text output. Falls back to
plain text when --no-color is set. Tool call lines still use
prompt_toolkit styled output.
Apply the same rich Live + Markdown streaming render to `openkb query`
as was added to chat. Falls back to plain text when stdout is not a tty.
@KylinMountain KylinMountain force-pushed the feat/chat-rich-markdown branch from f206c75 to 5d2b4b4 Compare April 12, 2026 01:40
@KylinMountain
Copy link
Copy Markdown
Collaborator Author

Code review

Found 1 issue:

  1. In query.py, after live.stop() writes the tool call line to stdout, live.start() re-activates the auto-refresh thread (4 Hz by default). On the next refresh cycle, Live uses position_cursor() — which emits ANSI CURSOR_UP sequences based on the previous render height — to move back up into the already-printed area and overwrite it with the last Markdown renderable. This means the tool call text printed between live.stop() and live.start() will be overwritten/erased by the next Live refresh. The fix is to not re-start Live after a tool call (keep it stopped until more text arrives, then start a fresh Live), or to use live.console.print(tool_call_text) before stopping so it is incorporated into the live area.

args = getattr(raw, "arguments", "{}")
if live:
live.stop()
sys.stdout.write(f"\n[tool call] {raw.name}({args})\n\n")
sys.stdout.flush()
if live:
live.start()
elif item.type == "tool_call_output_item":

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

@KylinMountain KylinMountain changed the title Render Markdown in chat and query output using rich feat: Render Markdown in chat and query output using rich Apr 12, 2026
@KylinMountain
Copy link
Copy Markdown
Collaborator Author

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

@KylinMountain KylinMountain requested a review from rejojer April 12, 2026 01:47
- Create a fresh Live instance after each tool call instead of
  stop/start on the same instance, preventing the auto-refresh
  thread from overwriting stdout text with CURSOR_UP sequences
- Respect NO_COLOR env var in query.py (consistent with chat.py)
- Fix print("\n") → print() in chat.py finally block to avoid
  extra blank line when Live is active
Custom Rich Theme: bold headings without color, dark background for
inline code, subtle link/list/blockquote colors. Shared via
_make_rich_console() used by both chat and query.
- Headings: blue (#5fa0e0)
- Code: yellow-ish on dark background
- List bullets: green (#6ac0a0)
- Bold: bright white, italic: light gray
- Paragraph text: light gray for visibility
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