Now when the agent reads images (which the tool now explicitly advertises to agents that it is capable of; previously the tool said it could only read text even though it can actually read images), we see them in the thread, and also they are auto-expanded by default so you can see them when scrolling through: <img width="725" height="1019" alt="Screenshot 2026-01-06 at 2 57 11 PM" src="https://github.com/user-attachments/assets/5c908bad-48f2-46c2-afaa-7f189a178e05" /> This also adds a visual regression test that verifies images render correctly in the agent thread view. Unlike our previous visual tests, this one only renders the agent panel, not the entire Zed window. The "screenshot" it generates (rendered to a Metal texture) is from completely mocked/simulated data structures, and looks like this: <img width="546" height="984" alt="Screenshot 2026-01-06 at 2 54 41 PM" src="https://github.com/user-attachments/assets/89a0921f-59e9-4dfe-94b2-4c3b625a851b" /> ## Changes - **New visual test**: `agent_thread_with_image` renders an `AcpThreadView` containing a tool call with image content (the Zed app icon) - **Test infrastructure**: Added `StubAgentServer` helper and required feature flags for visual testing - **Test-support API**: Added `expand_tool_call()` method to `AcpThreadView` to allow expanding tool calls for visual testing - **Baseline screenshot**: Included baseline image showing the Zed logo rendered in a tool call output ## How to run ```bash # Run the visual tests cargo run -p zed --bin visual_test_runner --features visual-tests # Update baselines if UI intentionally changed UPDATE_BASELINE=1 cargo run -p zed --bin visual_test_runner --features visual-tests ``` Release Notes: - N/A --------- Co-authored-by: Zed Zippy <234243425+zed-zippy[bot]@users.noreply.github.com> Co-authored-by: Amp <amp@ampcode.com>
8.3 KiB
Visual Test Plan: Agent Panel Image Rendering
🎯 The Goal
We want a visual regression test that catches bugs in how read_file displays images.
If someone changes the code in ReadFileTool or the UI rendering in thread_view.rs, this test should fail and show us visually what changed.
⚠️ Current Problem: The Test is Useless
The current test in crates/zed/src/visual_test_runner.rs does NOT test the real code!
Here's what it does now (WRONG):
- Creates a
StubAgentConnection - Hard-codes a fake tool call response with pre-baked image data
- Injects that directly into
AcpThread - Takes a screenshot
Why this is useless: If you change how ReadFileTool produces its output (in crates/agent/src/tools/read_file_tool.rs), the test will still pass because it never runs that code! The test bypasses the entire tool execution pipeline.
✅ What We Actually Need
The test should:
- Create a real project with a real image file
- Actually run the real
ReadFileTool::run()method - Let the tool produce its real output via
event_stream.update_fields() - Have that real output flow through to
AcpThreadand render in the UI - Take a screenshot of the real rendered result
This way, if someone changes ReadFileTool or the UI rendering, the test will catch it.
📚 Architecture Background (For Newcomers)
Here's how the agent system works:
The Two "Thread" Types
Thread(incrates/agent/src/thread.rs) - Runs tools, talks to LLMs, produces eventsAcpThread(incrates/acp_thread/src/acp_thread.rs) - Receives events and stores data for UI rendering
How Tools Work
Threadhas registered tools (likeReadFileTool)- When a tool runs, it gets a
ToolCallEventStream - The tool calls
event_stream.update_fields(...)to send updates - Those updates become
ThreadEvent::ToolCallUpdateevents - Events flow to
AcpThreadviahandle_thread_events()inNativeAgentConnection AcpThreadstores the data and the UI renders it
The Key File Locations
- Tool implementation:
crates/agent/src/tools/read_file_tool.rs- Lines 163-188: Image file handling (calls
event_stream.update_fields())
- Lines 163-188: Image file handling (calls
- Event stream:
crates/agent/src/thread.rsToolCallEventStream::update_fields()- sends updatesToolCallEventStream::test()- creates a test event stream
- UI rendering:
crates/agent_ui/src/acp/thread_view.rsrender_image_output()- renders images in tool call output
- Current (broken) test:
crates/zed/src/visual_test_runner.rsrun_agent_thread_view_test()- the function that needs fixing
🔧 Implementation Plan
Option A: Direct Tool Invocation (Recommended)
Run the real tool and capture its output:
// 1. Create a project with a real image file
let fs = FakeFs::new(cx.executor());
fs.insert_file("/project/test-image.png", EMBEDDED_TEST_IMAGE.to_vec()).await;
let project = Project::test(fs.clone(), ["/project"], cx).await;
// 2. Create the ReadFileTool (needs Thread, ActionLog)
let action_log = cx.new(|_| ActionLog::new(project.clone()));
// ... create Thread with project ...
let tool = Arc::new(ReadFileTool::new(thread.downgrade(), project.clone(), action_log));
// 3. Run the tool and capture events
let (event_stream, mut event_receiver) = ToolCallEventStream::test();
let input = ReadFileToolInput {
path: "project/test-image.png".to_string(),
start_line: None,
end_line: None,
};
tool.run(input, event_stream, cx).await?;
// 4. Collect the ToolCallUpdateFields that the tool produced
let updates = event_receiver.collect_updates();
// 5. Create an AcpThread and inject the real tool output
// ... create AcpThread ...
acp_thread.update(cx, |thread, cx| {
// First create the tool call entry
thread.upsert_tool_call(initial_tool_call, cx)?;
// Then update it with the real output from the tool
for update in updates {
thread.update_tool_call(update, cx)?;
}
})?;
// 6. Render and screenshot
Required Exports
The agent crate needs to export these for the visual test:
ReadFileToolandReadFileToolInputToolCallEventStream::test()(already has#[cfg(feature = "test-support")])Thread(to create the tool)
Check crates/agent/src/lib.rs and add exports if needed.
Required Dependencies in crates/zed/Cargo.toml
The visual-tests feature needs:
"agent/test-support" # For ToolCallEventStream::test() and tool exports
Option B: Use NativeAgentConnection with Fake Model
Alternatively, use the full agent flow with a fake LLM:
- Create
NativeAgentServerwith aFakeLanguageModel - Program the fake model to return a tool call for
read_file - Let the real agent flow execute the tool
- The tool runs, produces output, flows through to UI
This is more complex but tests more of the real code path.
📋 Step-by-Step Implementation Checklist
Phase 1: Enable Tool Access
- Add
agent/test-supporttovisual-testsfeature incrates/zed/Cargo.toml - Verify
ReadFileTool,ReadFileToolInput,ToolCallEventStream::test()are exported - Added additional required features:
language_model/test-support,fs/test-support,action_log
Phase 2: Rewrite the Test
- In
run_agent_thread_view_test(), remove the fake stub response - Create a real temp directory with a real image file (FakeFs doesn't work in visual test runner)
- Create the real
ReadFileToolwith Thread, ActionLog, etc. - Run the tool with
ToolCallEventStream::test() - Capture the
ToolCallUpdateFieldsit produces - Use the real tool output to populate the stub connection's response
Phase 3: Verify It Works
- Run
UPDATE_BASELINE=1 cargo run -p zed --bin visual_test_runner --features visual-tests - Check the screenshot shows the real tool output
- Intentionally break
read_file_tool.rs(comment outevent_stream.update_fields) - Verified the test fails with: "ReadFileTool did not produce any content - the tool is broken!"
- Restored the code and verified test passes again
🧪 How to Verify the Test is Actually Testing Real Code
After implementing, do this sanity check:
-
In
crates/agent/src/tools/read_file_tool.rs, comment out lines 181-185:// event_stream.update_fields(ToolCallUpdateFields::new().content(vec![ // acp::ToolCallContent::Content(acp::Content::new(acp::ContentBlock::Image( // acp::ImageContent::new(language_model_image.source.clone(), "image/png"), // ))), // ])); -
Run the visual test - it should FAIL or produce a visibly different screenshot
-
Restore the code - test should pass again
If commenting out the real tool code doesn't affect the test, the test is still broken!
📁 Files Modified
| File | Change |
|---|---|
crates/zed/Cargo.toml |
Added agent/test-support, language_model/test-support, fs/test-support, action_log to visual-tests feature |
crates/zed/src/visual_test_runner.rs |
Rewrote run_agent_thread_view_test() to run the real ReadFileTool and capture its output |
Note: No changes needed to crates/agent/src/lib.rs - all necessary exports were already public.
✅ Already Completed (Don't Redo These)
These changes have already been made and are working:
-
read_filetool sends image content -crates/agent/src/tools/read_file_tool.rsnow callsevent_stream.update_fields()with image content blocks (lines 181-185) -
UI renders images -
crates/agent_ui/src/acp/thread_view.rshasrender_image_output()that shows dimensions ("512×512 PNG") and a "Go to File" button -
Image tool calls auto-expand - The UI automatically expands tool calls that return images
-
Visual test infrastructure exists - The test runner, baseline comparison, etc. all work
The only thing broken is that the test doesn't actually run the real tool code!
🔗 Related Code References
- Tool implementation: read_file_tool.rs
- Event stream: thread.rs lines 2501-2596
- UI rendering: thread_view.rs render_image_output
- Current test: visual_test_runner.rs run_agent_thread_view_test