---
name: agentbyte-fastapi-sse-streaming
description: Guide for building or updating FastAPI-based Server-Sent Events streaming in Agentbyte, especially POST /chat/stream endpoints that use EventSourceResponse and ServerSentEvent for browser or curl clients.
license: MIT
---

Use this skill when adding or maintaining FastAPI SSE streaming in Agentbyte, especially for `agentbyte.microwebui`.

## Inputs to confirm
- Whether the stream should stay on `POST` because the client sends a JSON body
- Whether the frontend expects plain `data: <json>` SSE frames with no named SSE events
- Whether session continuity requires `session_id` and `user_id` in the request body
- Whether the stream should persist the final `AgentContext` and replayable event history

## Pattern: Native FastAPI SSE for POST streaming

Prefer FastAPI's built-in SSE support over manual `StreamingResponse` framing.

```python
from collections.abc import AsyncIterable
from typing import Any

from fastapi import FastAPI
from fastapi.sse import EventSourceResponse, ServerSentEvent
from pydantic import BaseModel

app = FastAPI()


class ChatRequest(BaseModel):
    message: str
    session_id: str | None = None
    user_id: str | None = None
    agent_name: str | None = None


async def stream_events(request: ChatRequest) -> AsyncIterable[ServerSentEvent]:
    for payload in [{"event_type": "task_start", "task": request.message}]:
        yield ServerSentEvent(data=payload)


@app.post("/chat/stream", response_class=EventSourceResponse)
async def chat_stream(request: ChatRequest) -> AsyncIterable[ServerSentEvent]:
    async for event in stream_events(request):
        yield event
```

## Current Agentbyte pattern

For `microwebui`, the stream generator:

- resolves the selected agent
- loads or creates `AgentContext` from `InMemorySessionStore`
- runs `agent.run_stream(..., context=context, verbose=True, stream_tokens=True)`
- yields `ServerSentEvent(data=event_payload)` for each streamed item
- persists the final `AgentContext` plus stored event history when the final `AgentResponse` arrives

The important point is that Agentbyte no longer manually builds:

```python
f"data: {json_payload}\\n\\n"
```

FastAPI now handles the SSE framing for us.

## Request shape after the API is running

For a live server on `127.0.0.1:8070`, use:

```bash
curl -N -X POST http://127.0.0.1:8070/chat/stream \
  -H "Content-Type: application/json" \
  -d '{
    "message": "What is the weather in Prague?",
    "session_id": "demo-session-1",
    "user_id": "demo-user-1",
    "agent_name": "weather_assistant"
  }'
```

To test follow-up memory, reuse the same `session_id` and `user_id`:

```bash
curl -N -X POST http://127.0.0.1:8070/chat/stream \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Summarize the previous answer in one sentence.",
    "session_id": "demo-session-1",
    "user_id": "demo-user-1",
    "agent_name": "weather_assistant"
  }'
```

## Expected stream shape

The browser or curl client still sees normal SSE frames such as:

```text
data: {"event_type":"task_start",...}

data: {"event_type":"model_call",...}

data: {"content":"...","role":"assistant",...}
```

The frontend can keep parsing `data: ` lines exactly as before.

## Guardrails

- For body-carrying chat streams, keep `POST` plus `fetch()`; browser `EventSource` is not a drop-in replacement because it does not send JSON request bodies.
- When using native FastAPI SSE, yield `ServerSentEvent(data=...)` instead of manually formatting `data: ...\\n\\n`.
- Keep the JSON payload shape stable unless the frontend/parser is updated in the same change set.
- If memory is part of the demo, reuse the same `session_id` and `user_id` across follow-up requests.
- Store replayable session events only after normalizing them to JSON-friendly payloads.
