From 2d1a86cac96eefa46feb07fd36a611282c4906c2 Mon Sep 17 00:00:00 2001 From: Hongming Wang Date: Sun, 3 May 2026 12:46:21 -0700 Subject: [PATCH] fix(canvas): AgentCommsPanel light-mode markdown contrast MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Discovered during code review of the #2623 hotfix audit. Same regression class as #2618: prose-invert applied where the bubble bg themes between light/dark, leaving markdown unreadable in one theme. `MarkdownBody` was unconditionally `prose-invert` — fine for the outgoing-message bubble (bg-cyan-900, dark in both themes) and the failure bubble (bg-red-950, dark in both themes), but WRONG for the incoming-message bubble (bg-surface-card, which themes LIGHT in light mode). Result: light prose body text on light cream bg = invisible markdown for incoming peer-to-peer messages in light mode. Added an `invert: "always" | "dark-only"` prop to MarkdownBody. The NormalMessage call sites switch on `msg.flow` so each bubble gets the direction matching its bg's theming behavior. Failure bubble keeps the default ("always") since red-950 stays dark. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../components/tabs/chat/AgentCommsPanel.tsx | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/canvas/src/components/tabs/chat/AgentCommsPanel.tsx b/canvas/src/components/tabs/chat/AgentCommsPanel.tsx index 4d5ca91e..268953ce 100644 --- a/canvas/src/components/tabs/chat/AgentCommsPanel.tsx +++ b/canvas/src/components/tabs/chat/AgentCommsPanel.tsx @@ -574,12 +574,22 @@ function NormalMessage({ msg }: { msg: CommMessage }) { {msg.flow === "out" ? `→ To ${msg.peerName}` : `← From ${msg.peerName}`} {msg.text ? ( - {msg.text} + // Outgoing bubble (cyan-900) is dark in both themes → prose-invert default. + // Incoming bubble (surface-card) themes light → only invert in dark. + + {msg.text} + ) : (
(no message text)
)} {msg.responseText && ( - + {msg.responseText} )} @@ -706,17 +716,29 @@ function ErrorMessage({ msg }: { msg: CommMessage }) { * prose tweaks that keep paragraphs tight inside a small bubble. * Code blocks get an `overflow-x-auto` so a long line of code doesn't * blow out the bubble's max-width — agent-to-agent replies routinely - * ship code samples and JSON. */ + * ship code samples and JSON. + * + * `invert` controls the prose color flip: + * - "always": container bg is dark in BOTH themes (cyan-900, red-950), + * so prose always wants light body text. + * - "dark-only": container bg uses a theming token that goes light in + * light mode (e.g. bg-surface-card). Prose only inverts in dark + * mode; light mode keeps default dark prose colors against the + * light bg. Without this, light mode rendered light text on light + * bg = invisible markdown. */ function MarkdownBody({ children, className, + invert = "always", }: { children: string; className?: string; + invert?: "always" | "dark-only"; }) { + const proseInvert = invert === "always" ? "prose-invert" : "dark:prose-invert"; return (
p]:mb-1 [&>p:last-child]:mb-0 [&_pre]:overflow-x-auto [&_table]:block [&_table]:overflow-x-auto ${className ?? ""}`} + className={`prose prose-sm ${proseInvert} max-w-none [&>p]:mb-1 [&>p:last-child]:mb-0 [&_pre]:overflow-x-auto [&_table]:block [&_table]:overflow-x-auto ${className ?? ""}`} > {children}