microsoft / microsoft/agent-framework

Python: [Bug]: Streaming Agent telemetry fails across FastAPI/Azure Functions response context

Open
#7,767 2 comments 0 reactions 1 assignee View on GitHub

@moonbox3 is already working on this.

Since Aug 19, 2026.

likely-fixed python
Dominant language
Python
Stars
13.6k
Forks
2.3k
Avg merge
2d 45m
Merged PRs (30d)
358

Description

### Description

### What happened?

With native Microsoft Agent Framework telemetry enabled, consuming an `Agent.run(..., stream=True)` response through a FastAPI/Azure Functions `StreamingResponse` fails during telemetry finalization.

The response stream is created in the request context and consumed by the ASGI response task. MAF stores a `ContextVar` token when creating the stream and later resets it while finalizing in the consuming context. Python rejects that reset because the token was created in a different context.

The model response may stream successfully, but cleanup then raises `ValueError`. This can terminate the SSE response and means native MAF telemetry cannot be safely enabled.

Disabling MAF instrumentation makes the same streaming execution complete normally.

### Expected behavior

The stream should complete normally and MAF should export its agent/model/tool spans. Telemetry must not change or fail agent execution when an ASGI host consumes a stream in another task or copied context.

### Steps to reproduce

1. Enable native MAF instrumentation.
2. Create an agent response with `agent.run("Hello", stream=True)` during an HTTP request.
3. Return an ASGI/FastAPI `StreamingResponse` that consumes that response.
4. Exhaust/finalize the stream.
5. Observe the `ContextVar` token-reset exception during MAF telemetry cleanup.

### Code Sample

```markdown
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from agent_framework.observability import configure_otel_providers

app = FastAPI()
configure_otel_providers()

# agent is a normally configured Microsoft Agent Framework Agent.

@app.post("/agent")
async def run_agent():
# Created in the request context.
stream = agent.run("Hello", stream=True)

# StreamingResponse consumes this iterator in the ASGI response context.
async def consume():
async for update in stream:
yield f"data: {update.text}\n\n"

return StreamingResponse(consume(), media_type="text/event-stream")

A reduced cross-task lifecycle has the same shape:

stream = agent.run("Hello", stream=True)

async def consume():
return [update async for update in stream]

updates = await asyncio.create_task(consume())
```

### Error Messages / Stack Traces

```markdown
ValueError: >
was created in a different Context

The relevant stack terminates in:

agent_framework/_types.py ResponseStream cleanup hooks
agent_framework/observability.py _finalize_stream
INNER_RESPONSE_TELEMETRY_CAPTURED_FIELDS.reset(token)
```

### Package Versions

agent-framework-core: 1.13.0agent-framework-openai: 1.12.0agent-framework-orchestrations: 1.0.2azure-functions: 1.25.0azurefunctions-extensions-http-fastapi: 1.0.1fastapi: 0.141.1starlette: 1.6.0opentelemetry-api/sdk: 1.43.0

### Python Version

Python 3.11.13

### Additional Context

This appears related to:

- #6762
- #6764

PR #6764 fixed the non-streaming/background-agent path by moving `ContextVar` creation into the awaited coroutine. The streaming path was explicitly left unchanged, and review discussion noted that streaming cleanup could run in a different consuming context. This report covers that remaining streaming variant.

This usage also matches the framework's documented streaming API and the repository's ChatKit/FastAPI `StreamingResponse` integration pattern.

Suggested regression coverage:

1. Create an instrumented `Agent.run(..., stream=True)` response.
2. Consume it inside `asyncio.create_task()` or an ASGI `StreamingResponse`.
3. Exhaust and finalize the stream.
4. Verify no `ContextVar` reset exception occurs and the telemetry span completes.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.