Skip to content

StreamingResponse with FastAPI return error ContextVar #435

Closed
@passacagllia

Description

@passacagllia

Describe the bug

When using the stream endpoint in the normal_v2 router, the server throws an exception during the streaming process. The error occurs when processing the stream_events method in the Agent's Runner. The client receives partial responses before the connection is abruptly closed with the error: curl: (18) transfer closed with outstanding read data remaining.

Debug information

  • Agents SDK version: (e.g. v0.0.7)
  • Python version (e.g. Python 3.11)

Repro steps

Set up the normal_v2 router with the provided code.
Send a POST request to the /normal_v2/stream endpoint with the following payload:

{
    "chat_history": [{"role": "system", "content": "You are a helpful assistant."}],
    "user_query": "What is the weather today?"
}

Observe the server logs and client response.

Expected behavior

The server should stream the response without errors, and the client should receive the full response in a properly formatted streaming format (e.g., application/x-ndjson).

Server logs: The server throws the following exception:

ERROR:    Exception in ASGI application
+ Exception Group Traceback (most recent call last):
...lib/python3.12/site-packages/agents/tracing/scope.py", line 45, in reset_current_trace
    |     _current_trace.reset(token)
ValueError: <Token var=<ContextVar name='current_trace' default=None at 0x1462a79c0> at 0x169dfec80> was created in a different Context

Client response: The client receives partial responses:

{"event_type":"data","data":{"answer":" those"}}
{"event_type":"data","data":{"answer":"!"}}

Followed by the error:

curl: (18) transfer closed with outstanding read data remaining

Additional context

Code snippets
Router code:

import uuid
from fastapi import APIRouter
from agents import Agent, Runner
from app.core.chat_interface.base import ChatInterface
from app.core.models.human_input import NormalQueryInput
from app.core.services.openai.model import openai_model, openai_model_settings
from starlette.responses import StreamingResponse

router = APIRouter(prefix="/normal_v2", tags=["normal_v2"])

agent = Agent(
    name="Assistant",
    instructions="You are a helpful assistant.",
    model=openai_model,
    model_settings=openai_model_settings,
)

@router.post("/stream")
async def stream(query_input: NormalQueryInput):
    full_history = query_input.chat_history + [{"role": "user", "content": query_input.user_query}]
    result = Runner.run_streamed(agent, input=full_history)
    chat_interface = ChatInterface(result.stream_events(), trace_id=str(uuid.uuid4()))
    return StreamingResponse(chat_interface.process_stream(), media_type="application/x-ndjson")
ChatInterface code:

from enum import Enum
from typing import Optional, AsyncIterator
from openai.types.responses import ResponseTextDeltaEvent
from pydantic import BaseModel

class EventType(Enum):
    DATA = "data"
    METADATA = "metadata"

class EventData(BaseModel):
    answer: Optional[str] = None
    trace_id: Optional[str] = None

class EventStreamOutput(BaseModel):
    event_type: EventType
    data: EventData

class ChatInterface:
    def __init__(self, result: AsyncIterator, trace_id: Optional[str]):
        self.stream_result = result
        self.trace_id = trace_id

    async def process_stream(self):
        if self.trace_id:
            ted = EventStreamOutput(
                event_type=EventType.METADATA,
                data=EventData(trace_id=self.trace_id)
            )
            yield f"{ted.json(exclude_none=True)}\n\n"
        async for event in self.stream_result:
            if event.type == "raw_response_event" and isinstance(event.data, ResponseTextDeltaEvent):
                eed = EventStreamOutput(
                    event_type=EventType.DATA,
                    data=EventData(answer=event.data.delta)
                )
                yield f"{eed.json(exclude_none=True)}\n\n"


Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions