Skip to main content
Long-running work shouldn’t make a user stare at a spinner. Aikeedo streams chat responses as Server-Sent Events, and a plugin can stream its own output the same way.

How streaming works here

A handler returns a response whose body is a CallbackStream. The emitter calls that callback while it writes the body, so your generator runs after the headers are already on the wire.
src/RequestHandlers/Api/StreamSummaryRequestHandler.php
Presentation\EventStream\Streamer writes one event at a time and flushes: Call open() before your first event if you send events yourself rather than through stream().

The wire format

Pick short event names, and keep each data payload to a single JSON object. Clients parse this with the browser’s EventSource, or with a streaming fetch and an SSE parser when they need to POST.

Handle the write side carefully

The entity manager is flushed after the response is emitted, which for a stream is after the last byte. If your generator creates records that the client will reference, inject Doctrine\ORM\EntityManagerInterface and call flush() before or during the stream.
A user who closes the tab shouldn’t keep a provider call running and a workspace paying for it. Streamer::open() exits when connection_aborted() reports a dead connection; check it in long loops of your own too.
Once the headers are sent you can’t change the status code. Catch exceptions inside the generator and emit an error event with a message the client can show.
Reserve credits before you start, then consume the real cost as usage arrives. See AI models and credits.

Forwarding AI output

When you stream a model’s answer, fold Aikeedo’s stream parts into your own events:
Stream parts are JsonSerializable, so passing one straight to sendEvent() produces a payload shaped like {"type": "...", ...}.

Consume the stream in the browser

PHP’s built-in development server handles one request at a time, so a stream blocks everything else. Test streaming against nginx with PHP-FPM, or a similar setup, before you ship.

Deployment notes

  • X-Accel-Buffering: no disables nginx buffering; other proxies and CDNs have their own switch.
  • Check output_buffering and any compression module, since gzip on a stream can delay flushes.
  • Keep max_execution_time in mind for long generations.