Skip to content

Output-Only Attached Stream

Emit live progress and output frames while committing exactly one terminal settlement fact.

One mode: "output_only" attached stream handler backed by the in-memory runtime. The same handler shape maps to SSE in the Cloudflare backend.

  1. Define an output-only handler:

    const outputOnly = {
    kind: "tutorial.output_only",
    mode: "output_only",
    cancellation: "cooperative",
    onDetach: "continue",
    parseStart: (raw) => attachedStreamParseOk(raw),
    run: async function* (_start, _input, ctx) {
    yield { kind: "progress", payload: { step: "started" } };
    yield { kind: "output", channel: "stdout", payload: "hello" };
    if (ctx.signal.aborted) {
    yield { kind: "cancelled", reason: "cancelled", terminal: { cancelled: true } };
    return;
    }
    yield { kind: "completed", terminal: { ok: true } };
    },
    commitTerminal: (terminal, tx) => {
    tx.insertEvent({
    kind:
    terminal.kind === "cancelled"
    ? "tutorial.output_only.cancelled"
    : "tutorial.output_only.completed",
    payload: terminal,
    });
    },
    } satisfies AttachedStreamHandler<unknown, { readonly ok?: true }>;
  2. Register it with the in-memory runtime or defineAgentDO({ streams }).

  3. Attach and collect outbound frames:

    const session = await streams.attach({ kind: "tutorial.output_only", payload: {} });
    const frames = await readUntilTerminal(session.output);
  4. Fold frames with projectAttachedStream(frames, session.streamRef).

  5. Test detach separately from cancel:

    await runtime.runPromise(session.detach()); // closes observer, not work
    await runtime.runPromise(session.cancel("user")); // explicit cancellation intent

Connected completion includes:

opened -> progress -> output -> completed

projectAttachedStream reports status: "completed" with no omitted frames, and the ledger has one tutorial.output_only.completed event.

With onDetach: "continue", detach() closes the reader but still allows terminal settlement. Explicit cancel() can produce cancelled and the tutorial.output_only.cancelled event.

Accept user input with streaming chatbot.