HTTP streaming and SSE dual channels
Streaming does not depend on “pushing tokens in the same POST response body.” Agent Forge uses dual channels: the write channel triggers session scheduling and may wait for this turn to finish; the read channel uses a long-lived SSE connection to subscribe to bus events for text deltas, tool state, and session busy/idle.
Dual channels
Section titled “Dual channels”flowchart LR C[Client] -->|POST /session/.../message| W[Write channel SessionPrompt] C -->|GET /event| R[Read channel SSE] W --> Loop[runLoop / Processor] Loop --> Bus[Bus] Bus --> R| Channel | Typical API | Role |
|---|---|---|
| Write | POST .../message or .../prompt_async | Issue work; sync waits for this turn’s result, async accepts first |
| Read | GET /event | text/event-stream, continuous events |
End-to-end timeline
Section titled “End-to-end timeline”sequenceDiagram participant C as Client participant E as SSE participant H as HTTP participant L as runLoop participant B as Bus
C->>E: Subscribe /event E-->>C: connected / heartbeat C->>H: POST message H->>L: prompt L->>B: PartDelta / status B-->>E: Push E-->>C: Incremental render L-->>H: This-turn assistant H-->>C: Sync response (if sync API)Clients should open SSE before or alongside sending a prompt. POST only, no event subscription, usually yields a full blob after the request ends.
Server behavior highlights
Section titled “Server behavior highlights”- Subscribe to the bus and write events into the SSE stream
- Periodic heartbeat to reduce idle disconnects through proxies
- Clean up subscriptions when the connection aborts
- There are also global-level event and sync-event channels for control plane and multi-instance sync; the session UI main path remains instance-level
/event
Where events come from
Section titled “Where events come from”| Source | Typical content |
|---|---|
| Processor | text / reasoning Part deltas |
| Session projection | Message / Part update sync events |
| Session state | busy / idle / retry |
| Permission | Pending user authorization |
updatePartDelta may emit to the bus only; the full Part lands at moments such as text-end. So “SSE already has a delta, storage catches up later” is expected. See Message model and cross-turn memory.
Sync vs async prompt
Section titled “Sync vs async prompt”| API | HTTP semantics | Progress |
|---|---|---|
| Sync message/prompt | Wait until this turn ends, then return the assistant message | Still use SSE for deltas |
| prompt_async | Accept first (for example 204), run the same SessionPrompt in background | Only SSE or read messages afterward |
SDK wrapping: SDK-to-server flow.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Check first |
|---|---|
| UI does not stream | Subscribed to /event? Proxy buffering SSE? |
| Occasional disconnect | Heartbeat arriving? Reverse-proxy timeout? |
| Async task “silent” | Mistakenly reading the sync response body? Bus session error events? |
Related reading: