Advanced TypeScript for Harness Builders

16. Async Generators

async function* yields values lazily over time — perfect for SSE parsing and WebSocket streams.

Async generators produce values lazily over time. Used extensively for SSE parsing and WebSocket streams.

SSE Parser:

File: packages/ai/src/providers/openai-codex-responses.ts L469-510

async function* parseSSE(response: Response): AsyncGenerator<Record<string, unknown>> {
  if (!response.body) return;
  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let buffer = "";

  try {
    while (true) {
      const { done, value } = await reader.read();
      if (done) break;
      buffer += decoder.decode(value, { stream: true });
      // Parse and yield JSON events from buffer...
      yield JSON.parse(data);
    }
  } finally {
    await reader.cancel();
    reader.releaseLock();
  }
}

Composing generators (piping output of one into another):

File: packages/ai/src/providers/openai-codex-responses.ts L431-457

async function* mapCodexEvents(events: AsyncIterable<Record<string, unknown>>): AsyncGenerator<ResponseStreamEvent> {
  for await (const event of events) {
    // Transform and yield...
    yield event as unknown as ResponseStreamEvent;
  }
}

Consuming with for await:

File: packages/ai/src/providers/openai-responses-shared.ts L286-298

export async function processResponsesStream<TApi extends Api>(
  openaiStream: AsyncIterable<ResponseStreamEvent>,
  output: AssistantMessage,
  stream: AssistantMessageEventStream,
  model: Model<TApi>
): Promise<void> {
  for await (const event of openaiStream) {
    // Process each event...
  }
}

Open this chapter inside the full course