# Streaming & SSE Guide

This guide explains how to use streaming responses and Server-Sent Events (SSE) in Logos ADK.

## Streaming Basics

Logos ADK supports two streaming modes:
1. **Simple Stream** (`/stream`) — Basic text streaming
2. **Stream-UI** (`/stream-ui`) — UI events with pause/resume support

## Simple Stream

### Python Usage

```python
from logos_adk import Agent
from logos_adk.types import TextChunk, ToolStart, ToolEnd, StreamDone

agent = Agent("assistant", model="gpt-4o")

# Stream responses
async for event in agent.stream("Tell me a story"):
    if isinstance(event, TextChunk):
        print(event.text, end="")
    elif isinstance(event, ToolStart):
        print(f"\n[Tool: {event.name}]")
    elif isinstance(event, ToolEnd):
        print(f"\n[Result: {event.result}]")
    elif isinstance(event, StreamDone):
        print(f"\n[Total tokens: {event.response.usage}]")
```

### HTTP Endpoint

```
POST /{agent}/stream
```

**Request:**
```json
{
  "prompt": "Tell me a story",
  "session_id": "optional-session"
}
```

**Response:** SSE stream

```
data: {"type": "text", "delta": "Once", "terminal": false}
data: {"type": "text", "delta": " upon", "terminal": false}
data: {"type": "text", "delta": " a time", "terminal": false}
data: {"type": "tool_start", "id": "call_123", "name": "search", "arguments": {}, "terminal": false}
data: {"type": "tool_end", "result": "Found results", "terminal": false}
data: {"type": "done", "terminal": true, "task_run_status": "completed", "resume_required": false, "retryable": false}
```

## Stream-UI

Stream-UI provides richer events for UI integration, including pause/resume for approval workflows.

### Python Usage

```python
async for event in agent.stream("Create report"):
    event_type = event.type
    
    if event_type == "text":
        print(event.delta, end="")
    elif event_type == "pause":
        print(f"\n[Paused: {event.reason}]")
        # Wait for user approval
    elif event_type == "graph_completed":
        print(f"\n[Status: {event.status}, Output: {event.output}]")
    elif event_type == "done":
        print(f"\n[Done: {event.content}]")
```

### HTTP Endpoint

```
POST /{agent}/stream-ui
```

**Request:**
```json
{
  "prompt": "Create report",
  "session_id": "session-123",
  "correlation_id": "corr-456"
}
```

**Response:** SSE stream

```
data: {"event": "text", "delta": "Creating", "terminal": false}
data: {"event": "text", "delta": " report", "terminal": false}
data: {"event": "pause", "reason": "approval_required", "terminal": false}
data: {"event": "graph_completed", "status": "completed", "output": "report.pdf", "terminal": true}
```

## Stream-UI Continue

Resume a paused session:

```
POST /{agent}/stream-ui/continue
```

```json
{
  "session_id": "session-123",
  "user_input": "approved",
  "continue_correlation_id": "corr-456",
  "continue_from_node": "review"
}
```

## Event Types

### /stream Events

| Type | Fields | Description |
|------|--------|-------------|
| `text` | `delta`, `terminal` | Text chunk |
| `tool_start` | `id`, `name`, `arguments`, `terminal` | Tool call start |
| `tool_end` | `result`, `terminal` | Tool call end |
| `error` | `error`, `terminal`, `retryable`, `task_run_status` | Error occurred |
| `done` | `terminal`, `resume_required`, `retryable`, `task_run_status` | Completed |
| `final` | `terminal` | Stream ended |

### /stream-ui Events

| Event | Fields | Description |
|-------|--------|-------------|
| `text` | `delta`, `terminal` | Text chunk |
| `tool_start` | `id`, `name`, `arguments`, `terminal` | Tool call start |
| `tool_end` | `result`, `terminal` | Tool call end |
| `pause` | `reason`, `terminal` | Waiting for approval |
| `graph_completed` | `status`, `output`, `terminal` | Graph finished |
| `done` | `content`, `terminal` | Response complete |
| `error` | `error`, `terminal`, `retryable`, `task_run_status` | Error occurred |

## Task Run Metadata

Both stream endpoints support task_run for UI integration:

```json
{
  "prompt": "Create report",
  "task_run": {
    "id": "task-1",
    "agentName": "bot",
    "profileId": "bot",
    "profileTitle": "Report Bot",
    "profileBadge": "📊",
    "prompt": "Create report",
    "fieldValues": {"type": "monthly"},
    "startedAt": "2026-03-26T10:00:00Z",
    "status": "running"
  }
}
```

Events include:
- `task_run_id` — From task_run.id
- `task_run_status` — From task_run.status

## Terminal Events

The `terminal` field indicates if the event is a terminal event (end of a processing step):

```python
# Non-terminal
{"type": "text", "delta": "Hello", "terminal": false}

# Terminal (end of response)
{"type": "done", "terminal": true, "task_run_status": "completed"}
```

## Error Handling

### Incomplete Execution

If the stream ends without a terminal event, an error event is emitted:

```json
{
  "type": "error",
  "error": "incomplete_execution",
  "terminal": true,
  "retryable": true,
  "task_run_status": "failed"
}
```

### Error During Stream

```json
{
  "type": "error",
  "error": "timeout",
  "detail": "Agent execution timed out",
  "terminal": true
}
```

## Client Example

### Python with httpx

```python
import asyncio
import httpx
import json

async def stream_example():
    async with httpx.AsyncClient() as client:
        async with client.stream(
            "POST",
            "http://localhost:8000/bot/stream",
            json={"prompt": "Hello"}
        ) as response:
            async for line in response.aiter_lines():
                if line.startswith("data: "):
                    event = json.loads(line[6:])
                    print(f"Event: {event}")

asyncio.run(stream_example())
```

### JavaScript

```javascript
const response = await fetch('http://localhost:8000/bot/stream', {
  method: 'POST',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify({prompt: 'Hello'})
});

const reader = response.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const {done, value} = await reader.read();
  if (done) break;
  
  const line = decoder.decode(value);
  if (line.startsWith('data: ')) {
    const event = JSON.parse(line.slice(6));
    console.log(event);
  }
}
```

## Best Practices

1. **Handle all event types** — Don't assume stream always completes
2. **Check terminal flag** — Use for UI state management
3. **Handle errors gracefully** — Both in-stream and incomplete
4. **Use task_run for UI workflows** — Track long-running operations
5. **Implement reconnection** — Handle connection drops
6. **Set timeouts** — Don't wait forever for responses