| 139 | * Ported from the original analyze page's inline reader. |
| 140 | */ |
| 141 | export async function* streamRun( |
| 142 | runId: string, |
| 143 | signal: AbortSignal, |
| 144 | ): AsyncGenerator<RunEvent> { |
| 145 | const send = () => |
| 146 | fetch(apiUrl(`/runs/${runId}/stream`), { |
| 147 | signal, |
| 148 | headers: authHeaders(), |
| 149 | }); |
| 150 | let res = await send(); |
| 151 | if (res.status === 401 && (await tryRefresh())) { |
| 152 | res = await send(); |
| 153 | } |
| 154 | if (!res.ok || !res.body) throw new Error(`stream failed: HTTP ${res.status}`); |
| 155 | const reader = res.body.getReader(); |
| 156 | const decoder = new TextDecoder(); |
| 157 | let buf = ""; |
| 158 | for (;;) { |
| 159 | const { done, value } = await reader.read(); |
| 160 | if (done) break; |
| 161 | buf += decoder.decode(value, { stream: true }); |
| 162 | let idx: number; |
| 163 | while ((idx = buf.indexOf("\n")) >= 0) { |
| 164 | const line = buf.slice(0, idx); |
| 165 | buf = buf.slice(idx + 1); |
| 166 | if (line.trim()) yield JSON.parse(line) as RunEvent; |
| 167 | } |
| 168 | } |
| 169 | } |