Jingrui77's picture
deploy: sync BayesScenParams Agent (2026-05-17T16:01:00Z)
f8a3ca2
Raw
History Blame Contribute Delete
2.63 kB
"""SSE streaming endpoint for the Agent.
Frontend ``POST /api/agent/chat`` with JSON body, gets back a Server-Sent
Events stream where each event is one of:
event: agent_started | data: {model, mode, tools}
event: assistant_text | data: {text}
event: thinking | data: {text}
event: tool_use | data: {id, name, input}
event: tool_result | data: {tool_use_id, content, is_error}
event: artifact | data: {artifact: {...}}
event: result | data: {session_id, total_cost_usd, duration_ms, ...}
event: error | data: {error}
event: done | data: {}
The frontend can resume a session by passing back ``session_id`` from the
``result`` event in the next request.
"""
from __future__ import annotations
import json
import logging
from collections.abc import AsyncIterator
from fastapi import APIRouter
from fastapi.responses import StreamingResponse
from app.agent.direct_orchestrator import stream_agent_direct
from app.agent.orchestrator import stream_agent as stream_agent_sdk
from app.api.schemas import AgentChatRequest
from app.core.config import get_settings
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/agent", tags=["agent"])
def _sse_format(event: str, payload: dict) -> bytes:
"""Encode one SSE event. Multi-line data is fine — we serialise the whole
payload as a single JSON string on one data: line for easy client parsing."""
data = json.dumps(payload, ensure_ascii=False, default=str)
return f"event: {event}\ndata: {data}\n\n".encode()
async def _event_stream(req: AgentChatRequest) -> AsyncIterator[bytes]:
runtime = get_settings().agent_runtime.lower()
streamer = stream_agent_sdk if runtime == "sdk" else stream_agent_direct
try:
async for ev in streamer(
prompt=req.prompt,
session_id=req.session_id,
mode=req.mode,
):
event_name = ev.get("type", "message")
yield _sse_format(event_name, ev)
except Exception as e:
logger.exception("agent stream crashed")
yield _sse_format("error", {"error": f"{type(e).__name__}: {e}"})
finally:
yield _sse_format("done", {})
@router.post("/chat")
async def chat(req: AgentChatRequest) -> StreamingResponse:
return StreamingResponse(
_event_stream(req),
media_type="text/event-stream",
headers={
"Cache-Control": "no-cache, no-transform",
"Connection": "keep-alive",
"X-Accel-Buffering": "no", # disable nginx buffering
},
)