File size: 2,341 Bytes
1f21206 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | /**
* Parse task run output into displayable text.
*
* The output may be in one of two formats:
*
* 1. **Extracted text** (new runs) — The server's `extractAssistantText` has
* already parsed the raw NDJSON and stored only the AI's text response.
* This is plain text / markdown that should be returned as-is.
*
* 2. **Raw NDJSON** (old runs before the server-side extraction was added) —
* Each line is a JSON object from the CLI's stream-json output. We parse
* these and extract assistant text blocks + result messages.
*
* Detection: if at least one line parses as JSON with a recognized `type`
* field, treat as NDJSON. Otherwise return as-is.
*/
export function parseRunOutput(raw: string): string {
if (!raw || !raw.trim()) return ''
const lines = raw.trim().split('\n')
// Quick check: does this look like NDJSON? (first non-empty line starts with '{')
const firstLine = lines.find((l) => l.trim())
if (!firstLine || !firstLine.trim().startsWith('{')) {
// Already extracted plain text — return as-is
return raw.trim()
}
// Try to parse as NDJSON (legacy format)
const textParts: string[] = []
let anyRecognized = false
for (const line of lines) {
if (!line.trim()) continue
let parsed: any
try {
parsed = JSON.parse(line)
} catch {
continue
}
const type = parsed?.type
if (type === 'assistant') {
anyRecognized = true
const content = parsed?.message?.content
if (!Array.isArray(content)) continue
for (const block of content) {
if (block.type === 'text' && block.text?.trim()) {
textParts.push(block.text.trim())
}
}
}
if (type === 'result') {
anyRecognized = true
const result = parsed?.result
if (typeof result === 'string' && result.trim()) {
textParts.push(result.trim())
} else if (result?.message?.trim()) {
textParts.push(result.message.trim())
}
}
if (type === 'system' || type === 'user') {
anyRecognized = true
// Skip these — not useful to display
}
}
// If we recognized NDJSON structure, return extracted text
if (anyRecognized) {
return textParts.join('\n\n')
}
// Fallback: the JSON lines didn't have recognized types — return raw
return raw.trim()
}
|