(controller)
| 105 | |
| 106 | const stream = new ReadableStream({ |
| 107 | async start(controller) { |
| 108 | let clientOpen = true; |
| 109 | const send = (event: string, data: unknown) => { |
| 110 | if (!clientOpen) return; |
| 111 | try { |
| 112 | controller.enqueue( |
| 113 | encoder.encode(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`), |
| 114 | ); |
| 115 | } catch { |
| 116 | clientOpen = false; |
| 117 | } |
| 118 | }; |
| 119 | |
| 120 | // Disconnect != cancel: the harness keeps running and persisting events |
| 121 | // to the transcript. The user sees them on next attach. |
| 122 | const noAbort = new AbortController(); |
| 123 | |
| 124 | try { |
| 125 | send("meta", { |
| 126 | project_slug: project.slug, |
| 127 | agent: resolved.agent_id, |
| 128 | session_id: session.id, |
| 129 | harness_adapter: project.harness_adapter, |
| 130 | message_chars: body.message.length, |
| 131 | is_kickoff: Boolean(taskId), |
| 132 | }); |
| 133 | |
| 134 | for await (const evt of adapter.execute({ |
| 135 | projectSlug: project.slug, |
| 136 | agentId: resolved.agent_id, |
| 137 | workspaceDir: workspaceDirFor(resolved.agent_id), |
| 138 | message: body.message, |
| 139 | threadId: session.id, |
| 140 | harnessSessionId: session.harness_session_id, |
| 141 | signal: noAbort.signal, |
| 142 | })) { |
| 143 | if (evt.kind === "session") { |
| 144 | // Remember the harness's own session id so the next turn can |
| 145 | // pass it back via --resume / `exec resume`. Don't persist as |
| 146 | // a transcript event — it's metadata, not chat content. |
| 147 | touchSession(session.id, evt.harnessSessionId); |
| 148 | continue; |
| 149 | } |
| 150 | try { |
| 151 | appendTranscriptEvent(session.id, evt.kind, evt); |
| 152 | } catch (err) { |
| 153 | console.error("[api/chat] transcript persist failed:", err); |
| 154 | } |
| 155 | |
| 156 | if (evt.kind === "delta") { |
| 157 | send("text", { chunk: evt.text }); |
| 158 | } else if (evt.kind === "tool") { |
| 159 | send("tool", { |
| 160 | phase: evt.phase, |
| 161 | tool_call_id: evt.toolCallId, |
| 162 | name: evt.name, |
| 163 | label: evt.label, |
| 164 | }); |
nothing calls this directly
no test coverage detected