Support content references for inline visualizations (#37341)

## What changed

- Recognize structured `visualize` content references alongside the existing inline visualization directive in cached, streaming, and finalized TUI rendering.
- Resolve absolute visualization paths only when they belong to the active thread directory, and show the existing unavailable fallback for incomplete, invalid, or out-of-scope references.
- Let embedded visualizations inherit host color, typography, and radius tokens while retaining standalone defaults and legacy aliases. Keep Lucide icons at a stable size when model-authored chart styles are present.

## Testing

- Cover content-reference fallback, replay, render-cache bypass, and canonical streaming behavior.

GitOrigin-RevId: 887d13647df11c23d519e64d0958fdc41ef3f472
This commit is contained in:
Philipp Spiess authored and copyberry committed 2026-08-07 00:37:50 +00:00
1 parent f8ac8fa6c6
commit 29dce2db43
7 files changed
+209 -55

No files matched your search

+3 -3
View File
@@ -5,8 +5,8 @@
use crate::history_cell::HistoryRenderMode;
use crate::history_cell::raw_lines_from_source;
use crate::inline_visualization::DIRECTIVE_PREFIX;
use crate::inline_visualization::InlineVisualizationContext;
use crate::inline_visualization::contains_inline_visualization;
use crate::markdown::render_markdown_agent_with_links_cwd_and_visualizations;
use crate::markdown::render_streaming_markdown_agent_with_links_and_cwd;
use crate::terminal_hyperlinks::HyperlinkLine;
@@ -61,7 +61,7 @@ impl StreamingRender {
render_mode: HistoryRenderMode,
inline_visualization_context: Option<&InlineVisualizationContext>,
) {
self.has_inline_visualization_directive = source.contains(DIRECTIVE_PREFIX);
self.has_inline_visualization_directive = contains_inline_visualization(source);
self.lines = match (render_mode, inline_visualization_context) {
(HistoryRenderMode::Rich, None) if !self.has_inline_visualization_directive => {
let rendered =
@@ -107,7 +107,7 @@ impl StreamingRender {
return;
}
self.has_inline_visualization_directive |= committed_source.contains(DIRECTIVE_PREFIX);
self.has_inline_visualization_directive |= contains_inline_visualization(committed_source);
if self.has_inline_visualization_directive {
self.recompute(
raw_source,
@@ -250,6 +250,20 @@ fn inline_visualizations_without_context_use_canonical_full_render() {
);
}
#[test]
fn inline_visualization_content_references_use_canonical_full_render() {
let (_, render) = assert_rich_stream_matches_full_render(
&[
"Before.\n\n",
"\u{e200}visualize\u{e202}{\"path\":\"/tmp/missing.html\"}\u{e201}\n",
],
Some(80),
);
assert_eq!(render.stable_source_len, 0);
assert!(render.has_inline_visualization_directive);
}
#[test]
fn inline_visualization_directive_survives_raw_to_rich_render_mode_switch() {
let cwd = test_cwd();