()
| 59 | }, [runId]); |
| 60 | |
| 61 | const loadRun = async () => { |
| 62 | try { |
| 63 | setLoading(true); |
| 64 | setError(null); |
| 65 | const runData = await api.getAgentRunWithRealTimeMetrics(runId); |
| 66 | setRun(runData); |
| 67 | |
| 68 | // If we have a session_id, try to load from JSONL file first |
| 69 | if (runData.session_id && runData.session_id !== '') { |
| 70 | try { |
| 71 | const history = await api.loadAgentSessionHistory(runData.session_id); |
| 72 | |
| 73 | // Convert history to messages format |
| 74 | const loadedMessages: ClaudeStreamMessage[] = history.map(entry => ({ |
| 75 | ...entry, |
| 76 | type: entry.type || "assistant" |
| 77 | })); |
| 78 | |
| 79 | setMessages(loadedMessages); |
| 80 | return; |
| 81 | } catch (err) { |
| 82 | console.warn('Failed to load from JSONL, falling back to output field:', err); |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | // Fallback: Parse JSONL output from the output field |
| 87 | if (runData.output) { |
| 88 | const parsedMessages: ClaudeStreamMessage[] = []; |
| 89 | const lines = runData.output.split('\n').filter(line => line.trim()); |
| 90 | |
| 91 | for (const line of lines) { |
| 92 | try { |
| 93 | const msg = JSON.parse(line) as ClaudeStreamMessage; |
| 94 | parsedMessages.push(msg); |
| 95 | } catch (err) { |
| 96 | console.error("Failed to parse line:", line, err); |
| 97 | } |
| 98 | } |
| 99 | |
| 100 | setMessages(parsedMessages); |
| 101 | } |
| 102 | } catch (err) { |
| 103 | console.error("Failed to load run:", err); |
| 104 | setError("Failed to load execution details"); |
| 105 | } finally { |
| 106 | setLoading(false); |
| 107 | } |
| 108 | }; |
| 109 | |
| 110 | const handleCopyAsJsonl = async () => { |
| 111 | if (!run?.output) return; |
no outgoing calls
no test coverage detected