(text, fileName, filePath, side)
| 1393 | } |
| 1394 | |
| 1395 | function normalizeTrajectory(text, fileName, filePath, side) { |
| 1396 | const parsed = safeJsonParse(text); |
| 1397 | if (!parsed || typeof parsed !== 'object' || !Array.isArray(parsed.messages)) { |
| 1398 | throw new Error('Invalid trajectory.json structure'); |
| 1399 | } |
| 1400 | const events = []; |
| 1401 | const thoughtEntries = []; |
| 1402 | const commandRuns = []; |
| 1403 | const finalResponses = []; |
| 1404 | const pythonScripts = []; |
| 1405 | const pythonSeen = new Set(); |
| 1406 | const detailEntries = []; |
| 1407 | const estimateParts = []; |
| 1408 | let latestTokens = null; |
| 1409 | let taskPrompt = ''; |
| 1410 | let thoughtOrder = 0; |
| 1411 | let commandOrder = 0; |
| 1412 | let finalOrder = 0; |
| 1413 | let pendingRun = null; |
| 1414 | parsed.messages.forEach((message, index) => { |
| 1415 | const id = side + '-trajectory-' + index; |
| 1416 | const timeLabel = 'step ' + (index + 1); |
| 1417 | const role = message.role || 'unknown'; |
| 1418 | const contentText = contentToText(message.content); |
| 1419 | if (role === 'user') { |
| 1420 | const observation = normalizeObservation(message); |
| 1421 | if (observation && pendingRun) { |
| 1422 | if (observation.command && !pendingRun.command) { |
| 1423 | pendingRun.command = observation.command; |
| 1424 | pendingRun.primaryCommand = primaryCommand(observation.command); |
| 1425 | } |
| 1426 | pendingRun.exitCode = observation.exitCode; |
| 1427 | pendingRun.outputPreview = shortMultiline(observation.output, 520); |
| 1428 | pendingRun.outputText = observation.output; |
| 1429 | const state = statusFromExit(observation.exitCode, '', observation.output, false); |
| 1430 | pendingRun.status = state.label; |
| 1431 | pendingRun.statusClass = state.css; |
| 1432 | pendingRun.sections = buildCommandSections(pendingRun.command, pendingRun.channel, observation.output); |
| 1433 | estimateParts.push({ label: 'observation outputs', text: observation.output }); |
| 1434 | events.push({ id, kind: 'observation', summary: shortMultiline(observation.output, 460), timeLabel, chips: observation.exitCode !== null ? ['exit ' + observation.exitCode] : ['observation'] }); |
| 1435 | detailEntries.push(createDetailEntry({ |
| 1436 | id: id + '-observation-detail', |
| 1437 | kind: 'observation', |
| 1438 | kindLabel: 'Observation', |
| 1439 | summary: shortMultiline(observation.output, 460), |
| 1440 | timeLabel, |
| 1441 | chips: observation.exitCode !== null ? ['exit ' + observation.exitCode] : ['observation'], |
| 1442 | sections: [makeCodeSection(observation.output, inferCodeLanguage(observation.output), 'Output')] |
| 1443 | })); |
| 1444 | } else if (contentText) { |
| 1445 | if (!taskPrompt) { |
| 1446 | taskPrompt = shortMultiline(contentText, 360); |
| 1447 | } |
| 1448 | estimateParts.push({ label: 'user messages', text: contentText }); |
| 1449 | events.push({ id, kind: 'user_message', summary: shortMultiline(contentText, 420), timeLabel, chips: ['user'] }); |
| 1450 | detailEntries.push(createDetailEntry({ |
| 1451 | id: id + '-detail', |
| 1452 | kind: 'user_message', |
no test coverage detected