From 03594db039fc1c11246ec9b0c2365f2fb3b88a3c Mon Sep 17 00:00:00 2001 From: openhands Date: Fri, 21 Mar 2025 01:28:03 +0000 Subject: [PATCH 1/4] Add Diff File View for instance.patch and test_result.git_patch --- .openhands/microagents/repo.md | 50 ++++++++++++++++++++ src/components/RunDetails.tsx | 34 +++++++++++-- src/components/artifacts/ArtifactDetails.tsx | 33 ++++++++++++- 3 files changed, 112 insertions(+), 5 deletions(-) create mode 100644 .openhands/microagents/repo.md diff --git a/.openhands/microagents/repo.md b/.openhands/microagents/repo.md new file mode 100644 index 0000000..9f0ad3c --- /dev/null +++ b/.openhands/microagents/repo.md @@ -0,0 +1,50 @@ +# Trajectory Visualizer Repository Information + +## Project Overview +The Trajectory Visualizer is a web application for visualizing OpenHands Resolver execution trajectories. It provides a timeline view of actions and observations during the execution of OpenHands agents. + +## Repository Structure +- `/src/components/`: React components + - `/src/components/timeline/`: Timeline visualization components + - `/src/components/artifacts/`: Artifact details components + - `/src/components/diff-viewer.tsx`: Diff viewer component for file changes +- `/src/services/`: API services +- `/src/utils/`: Utility functions +- `/src/types/`: TypeScript type definitions + +## Common Commands +- `npm start`: Start development server +- `npm build`: Build production-ready app +- `npm test`: Run tests + +## Code Style Preferences +- React functional components with TypeScript +- Tailwind CSS for styling +- React hooks for state management + +## Key Components + +### Timeline Components +- `Timeline.tsx`: Main timeline component that renders a list of timeline steps +- `TimelineStep.tsx`: Individual timeline step component +- `TimelineEntry`: Interface for timeline entry data + +### Artifact Components +- `ArtifactDetails.tsx`: Component for displaying artifact details, including diff views for patches + +### Diff Viewer +- `diff-viewer.tsx`: Component for displaying file diffs using `react-diff-viewer-continued` + +## Implementation Details + +### Diff File View +- The diff viewer is implemented in `/src/components/diff-viewer.tsx` +- It uses `react-diff-viewer-continued` to display file diffs +- The diff viewer is used in the `ArtifactDetails` component to display `.instance.patch` and `.test_result.git_patch` files +- The `handleFileEditClick` function in `RunDetails.tsx` updates the artifact content with patch data when a file edit is clicked + +### Data Flow +1. Timeline entries are loaded from the artifact content +2. When a file edit is clicked, the patch data is extracted from the entry metadata +3. The patch data is added to the artifact content +4. The `ArtifactDetails` component renders the patch data using the `DiffViewer` component \ No newline at end of file diff --git a/src/components/RunDetails.tsx b/src/components/RunDetails.tsx index cc03998..d2257e8 100644 --- a/src/components/RunDetails.tsx +++ b/src/components/RunDetails.tsx @@ -134,12 +134,38 @@ const RunDetails: React.FC = ({ owner, repo, run, initialConten if (timelineEntries && timelineEntries.length > selectedStepIndex) { const entry = timelineEntries[selectedStepIndex]; - // Show file changes in an alert for now - if (entry.path) { - alert(`File: ${entry.path}\n\nChanges are not available in this view. This would typically show a diff of the changes made to the file.`); + // If the entry has a path and metadata with file edit information, we can show it + if (entry.path && entry.metadata) { + // Check if there's a patch in the metadata + if (entry.metadata.instance?.patch || entry.metadata.test_result?.git_patch) { + // The diff viewer will be shown in the ArtifactDetails component + // We just need to make sure the metadata is available in the artifactContent + if (!artifactContent) { + // If no artifact content exists, create a minimal one with just the patch data + setArtifactContent({ + content: { + instance: entry.metadata.instance, + test_result: entry.metadata.test_result + } + }); + } else if (artifactContent.content) { + // If artifact content exists, update it with the patch data + setArtifactContent({ + ...artifactContent, + content: { + ...artifactContent.content, + instance: entry.metadata.instance, + test_result: entry.metadata.test_result + } + }); + } + } else { + // No patch data available + alert(`File: ${entry.path}\n\nNo diff information available for this file edit.`); + } } } - }, [getTimelineEntries, selectedStepIndex]); + }, [getTimelineEntries, selectedStepIndex, artifactContent]); const handleArtifactSelect = useCallback(async (artifact: Artifact) => { if (!artifact) return; diff --git a/src/components/artifacts/ArtifactDetails.tsx b/src/components/artifacts/ArtifactDetails.tsx index ae30156..0cde50f 100644 --- a/src/components/artifacts/ArtifactDetails.tsx +++ b/src/components/artifacts/ArtifactDetails.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { DiffViewer } from '../diff-viewer'; interface Issue { title: string; @@ -14,6 +15,12 @@ interface ArtifactContent { issue?: Issue; metrics?: Metrics; success?: boolean; + instance?: { + patch?: string; + }; + test_result?: { + git_patch?: string; + }; } interface ArtifactDetailsProps { @@ -29,8 +36,12 @@ export const ArtifactDetails: React.FC = ({ content }) => ); } + // Check for patch files + const instancePatch = content.instance?.patch; + const gitPatch = content.test_result?.git_patch; + return ( -
+
{content.issue && (

{content.issue.title}

@@ -57,6 +68,26 @@ export const ArtifactDetails: React.FC = ({ content }) =>
)} + + {/* Instance Patch Diff Viewer */} + {instancePatch && ( +
+

Instance Patch

+
+ +
+
+ )} + + {/* Git Patch Diff Viewer */} + {gitPatch && ( +
+

Git Patch

+
+ +
+
+ )}
); }; From 6dc68b793bb8c5c717eb0483842f37b57523f7d2 Mon Sep 17 00:00:00 2001 From: openhands Date: Fri, 21 Mar 2025 01:32:39 +0000 Subject: [PATCH 2/4] Refactor: Move diff viewer to EntryMetadataPanel component --- .openhands/microagents/repo.md | 16 ++++--- src/components/RunDetails.tsx | 32 ++------------ src/components/artifacts/ArtifactDetails.tsx | 33 +------------- .../components/EntryMetadataPanel.tsx | 43 +++++++++++++++++++ .../timeline/components/TimelineStep.tsx | 4 ++ 5 files changed, 62 insertions(+), 66 deletions(-) create mode 100644 src/components/timeline/components/EntryMetadataPanel.tsx diff --git a/.openhands/microagents/repo.md b/.openhands/microagents/repo.md index 9f0ad3c..5edc2c6 100644 --- a/.openhands/microagents/repo.md +++ b/.openhands/microagents/repo.md @@ -6,6 +6,8 @@ The Trajectory Visualizer is a web application for visualizing OpenHands Resolve ## Repository Structure - `/src/components/`: React components - `/src/components/timeline/`: Timeline visualization components + - `/src/components/timeline/components/`: Timeline subcomponents + - `/src/components/timeline/components/EntryMetadataPanel.tsx`: Panel for displaying entry metadata - `/src/components/artifacts/`: Artifact details components - `/src/components/diff-viewer.tsx`: Diff viewer component for file changes - `/src/services/`: API services @@ -28,9 +30,10 @@ The Trajectory Visualizer is a web application for visualizing OpenHands Resolve - `Timeline.tsx`: Main timeline component that renders a list of timeline steps - `TimelineStep.tsx`: Individual timeline step component - `TimelineEntry`: Interface for timeline entry data +- `EntryMetadataPanel.tsx`: Component for displaying entry metadata, including diff views for patches ### Artifact Components -- `ArtifactDetails.tsx`: Component for displaying artifact details, including diff views for patches +- `ArtifactDetails.tsx`: Component for displaying artifact details ### Diff Viewer - `diff-viewer.tsx`: Component for displaying file diffs using `react-diff-viewer-continued` @@ -40,11 +43,12 @@ The Trajectory Visualizer is a web application for visualizing OpenHands Resolve ### Diff File View - The diff viewer is implemented in `/src/components/diff-viewer.tsx` - It uses `react-diff-viewer-continued` to display file diffs -- The diff viewer is used in the `ArtifactDetails` component to display `.instance.patch` and `.test_result.git_patch` files -- The `handleFileEditClick` function in `RunDetails.tsx` updates the artifact content with patch data when a file edit is clicked +- The diff viewer is used in the `EntryMetadataPanel` component to display `.instance.patch` and `.test_result.git_patch` files +- The `EntryMetadataPanel` is displayed directly within the selected timeline step +- The `handleFileEditClick` function in `RunDetails.tsx` ensures the entry is selected when a file edit is clicked ### Data Flow 1. Timeline entries are loaded from the artifact content -2. When a file edit is clicked, the patch data is extracted from the entry metadata -3. The patch data is added to the artifact content -4. The `ArtifactDetails` component renders the patch data using the `DiffViewer` component \ No newline at end of file +2. When a file edit is clicked, the entry is selected +3. The `EntryMetadataPanel` component is displayed for the selected entry +4. The `EntryMetadataPanel` renders the patch data using the `DiffViewer` component \ No newline at end of file diff --git a/src/components/RunDetails.tsx b/src/components/RunDetails.tsx index d2257e8..f11b7dd 100644 --- a/src/components/RunDetails.tsx +++ b/src/components/RunDetails.tsx @@ -136,36 +136,12 @@ const RunDetails: React.FC = ({ owner, repo, run, initialConten // If the entry has a path and metadata with file edit information, we can show it if (entry.path && entry.metadata) { - // Check if there's a patch in the metadata - if (entry.metadata.instance?.patch || entry.metadata.test_result?.git_patch) { - // The diff viewer will be shown in the ArtifactDetails component - // We just need to make sure the metadata is available in the artifactContent - if (!artifactContent) { - // If no artifact content exists, create a minimal one with just the patch data - setArtifactContent({ - content: { - instance: entry.metadata.instance, - test_result: entry.metadata.test_result - } - }); - } else if (artifactContent.content) { - // If artifact content exists, update it with the patch data - setArtifactContent({ - ...artifactContent, - content: { - ...artifactContent.content, - instance: entry.metadata.instance, - test_result: entry.metadata.test_result - } - }); - } - } else { - // No patch data available - alert(`File: ${entry.path}\n\nNo diff information available for this file edit.`); - } + // The diff viewer is now shown directly in the timeline entry via the EntryMetadataPanel + // We just need to ensure the entry is selected + setSelectedStepIndex(selectedStepIndex); } } - }, [getTimelineEntries, selectedStepIndex, artifactContent]); + }, [getTimelineEntries, selectedStepIndex]); const handleArtifactSelect = useCallback(async (artifact: Artifact) => { if (!artifact) return; diff --git a/src/components/artifacts/ArtifactDetails.tsx b/src/components/artifacts/ArtifactDetails.tsx index 0cde50f..ae30156 100644 --- a/src/components/artifacts/ArtifactDetails.tsx +++ b/src/components/artifacts/ArtifactDetails.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import { DiffViewer } from '../diff-viewer'; interface Issue { title: string; @@ -15,12 +14,6 @@ interface ArtifactContent { issue?: Issue; metrics?: Metrics; success?: boolean; - instance?: { - patch?: string; - }; - test_result?: { - git_patch?: string; - }; } interface ArtifactDetailsProps { @@ -36,12 +29,8 @@ export const ArtifactDetails: React.FC = ({ content }) => ); } - // Check for patch files - const instancePatch = content.instance?.patch; - const gitPatch = content.test_result?.git_patch; - return ( -
+
{content.issue && (

{content.issue.title}

@@ -68,26 +57,6 @@ export const ArtifactDetails: React.FC = ({ content }) =>
)} - - {/* Instance Patch Diff Viewer */} - {instancePatch && ( -
-

Instance Patch

-
- -
-
- )} - - {/* Git Patch Diff Viewer */} - {gitPatch && ( -
-

Git Patch

-
- -
-
- )}
); }; diff --git a/src/components/timeline/components/EntryMetadataPanel.tsx b/src/components/timeline/components/EntryMetadataPanel.tsx new file mode 100644 index 0000000..85b1893 --- /dev/null +++ b/src/components/timeline/components/EntryMetadataPanel.tsx @@ -0,0 +1,43 @@ +import React from 'react'; +import { TimelineEntry } from '../types'; +import { DiffViewer } from '../../diff-viewer'; + +interface EntryMetadataPanelProps { + entry: TimelineEntry; +} + +const EntryMetadataPanel: React.FC = ({ entry }) => { + // Check for patch files in the metadata + const instancePatch = entry.metadata?.instance?.patch; + const gitPatch = entry.metadata?.test_result?.git_patch; + + if (!instancePatch && !gitPatch) { + return null; + } + + return ( +
+ {/* Instance Patch Diff Viewer */} + {instancePatch && ( +
+

Instance Patch

+
+ +
+
+ )} + + {/* Git Patch Diff Viewer */} + {gitPatch && ( +
+

Git Patch

+
+ +
+
+ )} +
+ ); +}; + +export default EntryMetadataPanel; \ No newline at end of file diff --git a/src/components/timeline/components/TimelineStep.tsx b/src/components/timeline/components/TimelineStep.tsx index e8b327a..4b7f34a 100644 --- a/src/components/timeline/components/TimelineStep.tsx +++ b/src/components/timeline/components/TimelineStep.tsx @@ -4,6 +4,7 @@ import { getStepInfo } from '../utils/getStepInfo'; import { colorClasses } from '../utils/styles'; import MarkdownContent from './MarkdownContent'; import CommandBlock from './CommandBlock'; +import EntryMetadataPanel from './EntryMetadataPanel'; export const TimelineStep: React.FC = memo(({ entry, @@ -110,6 +111,9 @@ export const TimelineStep: React.FC = memo(({ )} )} + + {/* Entry Metadata Panel - only show when selected */} + {isSelected && } From 78bdfadbe86665139c83dad6cc2998f5a2a3d689 Mon Sep 17 00:00:00 2001 From: openhands Date: Fri, 21 Mar 2025 13:51:29 +0000 Subject: [PATCH 3/4] Add Diff File View to Entry Metadata panel in JsonlViewer --- src/components/jsonl-viewer/JsonlViewer.tsx | 26 ++++++++++++++++++- .../timeline/components/TimelineStep.tsx | 4 +-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/components/jsonl-viewer/JsonlViewer.tsx b/src/components/jsonl-viewer/JsonlViewer.tsx index 7825ef5..2c4a143 100644 --- a/src/components/jsonl-viewer/JsonlViewer.tsx +++ b/src/components/jsonl-viewer/JsonlViewer.tsx @@ -5,6 +5,7 @@ import { getNestedValue, formatValueForDisplay } from '../../utils/object-utils' import { TrajectoryItem } from '../../types/share'; import JsonVisualizer from '../json-visualizer/JsonVisualizer'; import { DEFAULT_JSONL_VIEWER_SETTINGS } from '../../config/jsonl-viewer-config'; +import { DiffViewer } from '../diff-viewer'; import { isAgentStateChange, isUserMessage, @@ -356,7 +357,30 @@ const JsonlViewer: React.FC = ({ content }) => {
{currentEntryWithoutHistory ? ( - +
+ {/* Instance Patch Diff Viewer */} + {entries[currentEntryIndex]?.instance?.patch && ( +
+

Instance Patch

+
+ +
+
+ )} + + {/* Git Patch Diff Viewer */} + {entries[currentEntryIndex]?.test_result?.git_patch && ( +
+

Git Patch

+
+ +
+
+ )} + + {/* JSON Visualizer for other metadata */} + +
) : (
No metadata available diff --git a/src/components/timeline/components/TimelineStep.tsx b/src/components/timeline/components/TimelineStep.tsx index 4b7f34a..c50b2a8 100644 --- a/src/components/timeline/components/TimelineStep.tsx +++ b/src/components/timeline/components/TimelineStep.tsx @@ -4,7 +4,6 @@ import { getStepInfo } from '../utils/getStepInfo'; import { colorClasses } from '../utils/styles'; import MarkdownContent from './MarkdownContent'; import CommandBlock from './CommandBlock'; -import EntryMetadataPanel from './EntryMetadataPanel'; export const TimelineStep: React.FC = memo(({ entry, @@ -112,8 +111,7 @@ export const TimelineStep: React.FC = memo(({
)} - {/* Entry Metadata Panel - only show when selected */} - {isSelected && } + {/* Entry metadata is now shown in the right panel */}
From 5c945e9af5acb26e7b700b0954ff39b7740bc07d Mon Sep 17 00:00:00 2001 From: openhands Date: Fri, 21 Mar 2025 13:53:30 +0000 Subject: [PATCH 4/4] Update repository memory file --- .openhands/microagents/repo.md | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/.openhands/microagents/repo.md b/.openhands/microagents/repo.md index 5edc2c6..c0fbdc9 100644 --- a/.openhands/microagents/repo.md +++ b/.openhands/microagents/repo.md @@ -7,9 +7,10 @@ The Trajectory Visualizer is a web application for visualizing OpenHands Resolve - `/src/components/`: React components - `/src/components/timeline/`: Timeline visualization components - `/src/components/timeline/components/`: Timeline subcomponents - - `/src/components/timeline/components/EntryMetadataPanel.tsx`: Panel for displaying entry metadata - `/src/components/artifacts/`: Artifact details components - `/src/components/diff-viewer.tsx`: Diff viewer component for file changes + - `/src/components/jsonl-viewer/`: JSONL viewer components + - `/src/components/share/`: Shared components for trajectory visualization - `/src/services/`: API services - `/src/utils/`: Utility functions - `/src/types/`: TypeScript type definitions @@ -30,10 +31,13 @@ The Trajectory Visualizer is a web application for visualizing OpenHands Resolve - `Timeline.tsx`: Main timeline component that renders a list of timeline steps - `TimelineStep.tsx`: Individual timeline step component - `TimelineEntry`: Interface for timeline entry data -- `EntryMetadataPanel.tsx`: Component for displaying entry metadata, including diff views for patches + +### JSONL Viewer Components +- `JsonlViewer.tsx`: Component for viewing JSONL files with trajectory data +- `JsonlViewerSettings.tsx`: Settings for the JSONL viewer ### Artifact Components -- `ArtifactDetails.tsx`: Component for displaying artifact details +- `ArtifactDetails.tsx`: Component for displaying artifact details, including diff views for patches ### Diff Viewer - `diff-viewer.tsx`: Component for displaying file diffs using `react-diff-viewer-continued` @@ -43,12 +47,14 @@ The Trajectory Visualizer is a web application for visualizing OpenHands Resolve ### Diff File View - The diff viewer is implemented in `/src/components/diff-viewer.tsx` - It uses `react-diff-viewer-continued` to display file diffs -- The diff viewer is used in the `EntryMetadataPanel` component to display `.instance.patch` and `.test_result.git_patch` files -- The `EntryMetadataPanel` is displayed directly within the selected timeline step -- The `handleFileEditClick` function in `RunDetails.tsx` ensures the entry is selected when a file edit is clicked +- The diff viewer is used in two places: + 1. In the `ArtifactDetails` component to display `.instance.patch` and `.test_result.git_patch` files + 2. In the `JsonlViewer` component's Entry Metadata panel to display the same patch files +- The `handleFileEditClick` function in `RunDetails.tsx` updates the artifact content with patch data when a file edit is clicked ### Data Flow 1. Timeline entries are loaded from the artifact content -2. When a file edit is clicked, the entry is selected -3. The `EntryMetadataPanel` component is displayed for the selected entry -4. The `EntryMetadataPanel` renders the patch data using the `DiffViewer` component \ No newline at end of file +2. When a file edit is clicked, the patch data is extracted from the entry metadata +3. The patch data is added to the artifact content +4. The `ArtifactDetails` component renders the patch data using the `DiffViewer` component +5. The `JsonlViewer` component's Entry Metadata panel also renders the patch data using the `DiffViewer` component \ No newline at end of file