{safeError}
)}
+ {/* v1.22 (W5) — accompanying chart(s). The token was already
+ stripped from the prose by
; here it mounts the
+ real, self-fetching Recharts chart for the user's own series.
+ The model never emits data — only a metric identifier from a
+ closed allowlist, intersected with the turn's grounded metrics. */}
+ {chartTokens.length > 0 && (
+
+ {chartTokens.map((token) => {
+ const metric = tokenToMetric(token);
+ return (
+
+
+
+ );
+ })}
+
+ )}
{/* v1.18.6 — a "no provider configured anywhere" turn is a
setup gap, not a transient failure: surface a direct link to
Settings → AI so the Coach guides the user into BYOK / local
@@ -829,14 +1173,19 @@ function ChatBubble({
)}
{/* v1.4.23 H7 — per-message thumbs feedback. Only persisted
assistant messages get the row (skipped for refusals,
- errors, in-flight stream bubbles). The aggregator buckets
- the rating by (promptVersion, tone, verbosity). */}
- {messageId &&
- !inProgress &&
- !errorCode &&
- providerType !== "refusal" && (
-
- )}
+ errors, in-flight stream bubbles). v1.22 (W5) — the
+ read-aloud toggle joins the same action row on a settled turn;
+ the bubble timestamp trails it. */}
+ {!inProgress && !errorCode && providerType !== "refusal" && content && (
+
+ {!streaming && }
+ {messageId && }
+ {createdAt && }
+
+ )}
);