mirror of
https://github.com/openai/codex.git
synced 2026-11-05 16:29:31 +00:00
Render inline visualization links in the TUI (#33925)
## Why
Assistant-authored inline visualizations need a terminal fallback that lets users open generated artifacts in a browser.
## What changed
- Recognize `::codex-inline-vis{file="..."}` directives in assistant Markdown and replace them with browser links during streaming, finalized history rendering, and local transcript previews.
- Materialize visualization fragments in sandboxed viewer documents with a content security policy, while restricting artifacts to HTML files within the thread's visualization directory and limiting their size.
- Show an explicit unavailable message for invalid or missing artifacts, hide incomplete streaming directives, and preserve directive text in code blocks and user Markdown.
- Add a trusted file-link path for generated viewers without enabling arbitrary `file:` links in Markdown.
## Testing
Add coverage for directive rewriting, streaming and replay, artifact validation, sandboxed viewer generation, trusted terminal hyperlinks, and literal preservation.
GitOrigin-RevId: a666b4ebc82bb5798ad45bd137fd815d538e1de2
This commit is contained in:
1 parent
97dbd01a3d
commit
f896ab9f25
23 files changed
+2123
-106
No files matched your search
@@ -45,10 +45,17 @@ impl ChatWidget {
|
||||
if let Some(source) = source {
|
||||
let source =
|
||||
parse_assistant_markdown(&source, self.config.cwd.as_path()).visible_markdown;
|
||||
let inline_visualization_context = self.thread_id.and_then(|thread_id| {
|
||||
crate::inline_visualization::InlineVisualizationContext::from_config(
|
||||
&self.config,
|
||||
thread_id,
|
||||
)
|
||||
});
|
||||
self.note_stream_consolidation_queued();
|
||||
self.app_event_tx.send(AppEvent::ConsolidateAgentMessage {
|
||||
source,
|
||||
cwd: self.config.cwd.to_path_buf(),
|
||||
inline_visualization_context,
|
||||
scrollback_reflow,
|
||||
deferred_history_cell,
|
||||
});
|
||||
@@ -408,10 +415,17 @@ impl ChatWidget {
|
||||
// Reset the flag even if we don't show separator (no work was done)
|
||||
self.transcript.needs_final_message_separator = false;
|
||||
}
|
||||
self.stream_controller = Some(StreamController::new(
|
||||
let inline_visualization_context = self.thread_id.and_then(|thread_id| {
|
||||
crate::inline_visualization::InlineVisualizationContext::from_config(
|
||||
&self.config,
|
||||
thread_id,
|
||||
)
|
||||
});
|
||||
self.stream_controller = Some(StreamController::new_with_inline_visualizations(
|
||||
self.current_stream_width(/*reserved_cols*/ 2),
|
||||
&self.config.cwd,
|
||||
self.history_render_mode(),
|
||||
inline_visualization_context,
|
||||
));
|
||||
}
|
||||
if let Some(controller) = self.stream_controller.as_mut()
|
||||
|
||||
Reference in new issue
Block a user