{filteredTrajectory.map((item, index) => {
- if (isAgentStateChange(item)) {
+ const rawItem = item as unknown as Record
;
+ if (typeof rawItem.step_id === "number" && typeof rawItem.source === "string") {
+ return ;
+ } else if (isAgentStateChange(item)) {
return ;
} else if (isUserMessage(item)) {
return ;
@@ -95,19 +99,31 @@ export const TrajectoryList: React.FC = ({ trajectory }) =>
} else if (isEditObservation(item)) {
return ;
} else {
+ const source = typeof rawItem.source === "string" ? rawItem.source : undefined;
+ const timestamp = typeof rawItem.timestamp === "string" ? rawItem.timestamp : undefined;
+ const message = typeof rawItem.message === "string" ? rawItem.message : undefined;
+
return (
-
-
-
- Item #{index + 1}
-
-
-
- {JSON.stringify(item, null, 2)}
-
+
+
+ {source ? `${source.charAt(0).toUpperCase()}${source.slice(1)} step` : `Item #${index + 1}`}
+
+
+ {message && (
+
+ {message}
+
+ )}
+
+ {JSON.stringify(item, null, 2)}
+
+
);
}
@@ -125,4 +141,4 @@ export const TrajectoryList: React.FC = ({ trajectory }) =>
);
};
-export default TrajectoryList;
\ No newline at end of file
+export default TrajectoryList;
diff --git a/src/components/upload/UploadTrajectory.tsx b/src/components/upload/UploadTrajectory.tsx
index 8870980..90bc1cb 100644
--- a/src/components/upload/UploadTrajectory.tsx
+++ b/src/components/upload/UploadTrajectory.tsx
@@ -44,6 +44,12 @@ export const UploadTrajectory: React.FC = ({
// Return the history array for the trajectory viewer
return content.history;
}
+
+ // Check if it is an ATIF trajectory (steps array)
+ if (content.steps && Array.isArray(content.steps)) {
+ console.log('Detected ATIF trajectory format - using trajectory viewer');
+ return content.steps;
+ }
// If it's not in a recognized format, return as is and let the converter handle it
console.log('Unknown format, passing to converter as-is');
@@ -217,4 +223,4 @@ export const UploadTrajectory: React.FC = ({
)}
);
-};
\ No newline at end of file
+};
diff --git a/src/components/upload/__tests__/UploadTrajectory.test.tsx b/src/components/upload/__tests__/UploadTrajectory.test.tsx
index d95780f..e059a29 100644
--- a/src/components/upload/__tests__/UploadTrajectory.test.tsx
+++ b/src/components/upload/__tests__/UploadTrajectory.test.tsx
@@ -108,6 +108,44 @@ describe('UploadTrajectory', () => {
});
});
+ it('handles ATIF trajectories correctly', async () => {
+ render(
);
+
+ const steps = [
+ {
+ step_id: 1,
+ timestamp: '2026-09-14T02:40:44.835462',
+ source: 'system',
+ message: 'System prompt'
+ },
+ {
+ step_id: 2,
+ timestamp: '2026-09-14T02:40:44.835462',
+ source: 'user',
+ message: 'User request'
+ }
+ ];
+ const file = new File(
+ [JSON.stringify({ schema_version: 'ATIF-v1.5', steps })],
+ 'trajectory.json',
+ { type: 'application/json' }
+ );
+
+ const dropzone = screen.getByText(/drag and drop a trajectory file here/i).parentElement!.parentElement!;
+ await act(async () => {
+ fireEvent.drop(dropzone, createDropEvent([file]));
+ });
+
+ await waitFor(() => {
+ expect(mockOnUpload).toHaveBeenCalledWith({
+ content: {
+ fileType: 'trajectory',
+ trajectoryData: steps
+ }
+ });
+ });
+ });
+
it('handles invalid JSON file', async () => {
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
const alertSpy = vi.spyOn(window, 'alert').mockImplementation(() => {});
@@ -145,4 +183,4 @@ function createDropEvent(files: File[]) {
types: ['Files']
}
};
-}
\ No newline at end of file
+}