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()
}