Skip to content

Commit c393ec5

Browse files
Fix screenshot display in timeline entries by properly handling metadata
1 parent dcbea10 commit c393ec5

File tree

3 files changed

+90
-1
lines changed

3 files changed

+90
-1
lines changed

Diff for: src/components/timeline/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export interface TimelineEntry {
99
actorType?: 'User' | 'Assistant' | 'System';
1010
metadata?: {
1111
cost?: number;
12+
screenshot?: string; // Base64 encoded image data or image URL
1213
[key: string]: any;
1314
};
1415
}

Diff for: src/tests/SimpleScreenshot.test.tsx

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { render, screen } from '@testing-library/react';
2+
import '@testing-library/jest-dom';
3+
import { vi, describe, test, expect } from 'vitest';
4+
import { Timeline } from '../components/timeline/Timeline';
5+
import { TimelineEntry } from '../components/timeline/types';
6+
import { convertOpenHandsTrajectory } from '../utils/openhands-converter';
7+
8+
describe('Simple Screenshot Test', () => {
9+
// Mock the formatTimelineDate function
10+
const mockFormatTimelineDate = vi.fn().mockReturnValue('12:34 PM');
11+
const mockOnStepSelect = vi.fn();
12+
13+
test('timeline should properly display entries with screenshots', () => {
14+
// Create a simple trajectory with a screenshot
15+
const simpleTrajectory = [
16+
{
17+
"id": 1,
18+
"timestamp": "2025-01-20T20:29:32.262843",
19+
"source": "user",
20+
"message": "This is a test message with a screenshot",
21+
"action": "message",
22+
"args": {
23+
"content": "This is a test message with a screenshot",
24+
"image_urls": [],
25+
"wait_for_response": false
26+
},
27+
"extras": {
28+
"metadata": {
29+
"screenshot": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="
30+
}
31+
}
32+
}
33+
];
34+
35+
// Convert the simple trajectory to timeline entries
36+
const timelineEntries = convertOpenHandsTrajectory(simpleTrajectory);
37+
38+
// Verify we have entries
39+
expect(timelineEntries.length).toBeGreaterThan(0);
40+
41+
// Log the entries to see what's happening
42+
console.log('Timeline entries:', JSON.stringify(timelineEntries, null, 2));
43+
44+
// Render the Timeline component with the converted entries
45+
render(
46+
<Timeline
47+
entries={timelineEntries}
48+
selectedIndex={0}
49+
onStepSelect={mockOnStepSelect}
50+
formatTimelineDate={mockFormatTimelineDate}
51+
createdAt={new Date().toISOString()}
52+
/>
53+
);
54+
55+
// Check if the timeline is rendered with entries
56+
expect(screen.queryByText('No timeline entries available')).not.toBeInTheDocument();
57+
58+
// Check for the test message
59+
expect(screen.getByText('This is a test message with a screenshot')).toBeInTheDocument();
60+
61+
// Check for the screenshot
62+
const screenshot = screen.queryByAltText('Screenshot');
63+
expect(screenshot).toBeInTheDocument();
64+
});
65+
});

Diff for: src/utils/openhands-converter.ts

+24-1
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,14 @@ export function convertOpenHandsTrajectory(trajectory: OpenHandsEvent[] | { entr
151151
...event.tool_call_metadata.tool_args
152152
};
153153
}
154+
155+
// Add screenshot if available in extras.metadata
156+
if (event.extras?.metadata?.screenshot) {
157+
entry.metadata = {
158+
...entry.metadata,
159+
screenshot: event.extras.metadata.screenshot
160+
};
161+
}
154162

155163
entries.push(entry as TimelineEntry);
156164
} else if (event.observation) {
@@ -160,11 +168,26 @@ export function convertOpenHandsTrajectory(trajectory: OpenHandsEvent[] | { entr
160168
timestamp: event.timestamp || new Date().toISOString(),
161169
title: event.message || event.observation,
162170
content: event.content || '',
163-
metadata: event.extras || {},
171+
metadata: {},
164172
actorType: getActorType(event.source),
165173
command: '',
166174
path: ''
167175
};
176+
177+
// Add extras as metadata
178+
if (event.extras) {
179+
entry.metadata = {
180+
...event.extras
181+
};
182+
183+
// If extras.metadata exists, merge it with the entry metadata
184+
if (event.extras.metadata) {
185+
entry.metadata = {
186+
...entry.metadata,
187+
...event.extras.metadata
188+
};
189+
}
190+
}
168191

169192
entries.push(entry as TimelineEntry);
170193
}

0 commit comments

Comments
 (0)