fix(ui): support bidirectional chat markdown#11944
Conversation
Code Review SummaryStatus: No Issues Found | Recommendation: Merge This update adds a subtle background tint and a high-contrast-only border to Files Reviewed (1 file)
Previous Review Summaries (2 snapshots, latest commit a8bb361)Current summary above is authoritative. Previous snapshots are kept for context only. Previous review (commit a8bb361)Status: No Issues Found | Recommendation: Merge Both previously flagged items are resolved in this update:
The Files Reviewed (5 files)
Previous review (commit e5730d1)Status: 2 Issues Found | Recommendation: Address before merge Overview
Issue Details (click to expand)WARNING
SUGGESTION
Files Reviewed (7 files)
Reviewed by claude-sonnet-5-20260630 · Input: 50 · Output: 17.2K · Cached: 1.5M Review guidance: REVIEW.md from base branch |
|
@mjnaderi So whats a bit problematic with this: Left right actually separates user and assistant messages. So I wonder if the user messages should then be on the other side as well? How do other agent changes do that in this language? |
|
@marius-kilocode I will check this and find a solution. |
|
@marius-kilocode I decided not to move RTL user messages to the other side. I checked a few other chat/agent-style interfaces, and they generally keep sender placement stable rather than changing the user message side based on text direction. If the bubble moved based on message language, mixed-language chats could make the same speaker jump between sides, which seems more confusing than helpful. Example UI (ChatGPT):
Instead, I kept the user message position stable and made the bubble itself more visually distinct from the page background. Previously it used the same background as the surface behind it. The text still uses I also removed the user-message border, similar to other AI chat UIs, for a simpler look, and added a high-contrast fallback border so the bubble remains visible in high-contrast themes. What do you think about this approach? |

Issue
Text in right-to-left languages is currently rendered with the wrong direction in chat messages, which makes RTL and mixed RTL/LTR conversations hard to read. This affects plain user messages and rendered assistant markdown, especially lists, blockquotes, tables, and code nested inside RTL content.
Context
This PR adds bidirectional text support in chat messages. The goal is for Persian, Arabic, English, and mixed-language content to choose the correct base direction at the right visual boundary while preserving readable code rendering.
Implementation
The final implementation applies bidi direction as a post-render DOM decoration step in the shared Markdown component.
After Marked renders and DOMPurify sanitizes markdown, the existing
decorate(...)path now addsdir="auto"to:The decoration intentionally only marks direct markdown children for block/container direction. It does not recursively add
dir="auto"to nested paragraphs, list items, table cells, or quote contents. This matters because the HTML directionality algorithm fordir=autoskips text inside descendants that already have their owndirattribute. If every nested element getsdir="auto", then a parent list, table, or blockquote may fail to detect its RTL text and keep the wrong direction.The bidi decoration logic is exported from the Markdown component module so it stays next to the existing DOM decoration helpers while still having focused regression coverage that does not depend on the full Solid rendering harness. The Markdown CSS also uses logical inline-start spacing and borders for lists and blockquotes, and table cells now use logical
text-align: startso cell content follows the table’s resolved direction. Plain user message text bubbles also usedir="auto".References:
dir=auto: https://html.spec.whatwg.org/multipage/dom.html#the-dir-attributedir: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/dirdirection: https://developer.mozilla.org/en-US/docs/Web/CSS/directionI first implemented this with Marked renderer overrides for paragraphs, headings, lists, blockquotes, tables, and code. That worked functionally, but it required reimplementing some of Marked’s built-in HTML rendering, especially table/list markup. I changed the approach to the current
decorate(...)implementation so Marked remains responsible for generating HTML and our code only annotates the rendered DOM with direction metadata. This reduces maintenance risk, avoids diverging from Marked’s native output, and keeps the bidi behavior in the same client-side decoration path already used for code wrappers and markdown links.Screenshots / Video
How to Test
Manual/local verification
bun test tests/unit/kilo-ui-contract.test.tsinpackages/kilo-vscode/; passed.bun run typecheckinpackages/ui/; passed.bun run typecheckinpackages/kilo-vscode/; passed.Reviewer test steps
Blocked checks and substitute verification
bun run typecheckcould not be run inpackages/kilo-uibecause that package has notypecheckscript. Substitute verification wasbun run typecheckinpackages/kilo-vscode, which consumes@kilocode/kilo-ui/message-part.Checklist