Python: foundry-hosting drops request `metadata` from the stored response — `_create_response_event_stream` never passes `request` to `ResponseEventStream` · Issue #9529 · microsoft/agent-framework · GitHub
Skip to content

Python: foundry-hosting drops request metadata from the stored response — _create_response_event_stream never passes request to ResponseEventStream #9529

Open

Description

Description

When a client calls POST /responses on a ResponsesHostServer with a metadata object, that metadata is not present on the response object that is emitted (response.created / terminal events) or persisted, so GET /responses/{id} returns metadata: null.

This breaks the standard OpenAI Responses contract, where request metadata is echoed onto the response, and prevents clients from using response metadata to label/correlate turns (for example, recording per-turn settings and reading them back when listing conversation history).

Client impact (.NET SDK)

Our client is a .NET service using Azure.AI.Projects / Azure.AI.Extensions.OpenAI (2.1.0-beta.4). It sends the metadata when creating the response (CreateResponseOptions.Metadata), and when listing conversation history it reads it back per turn:

  1. GetProjectConversationItemsAsync(conversationId) to enumerate message items (items carry no metadata, only ResponseId).
  2. GetResponseAsync(new GetResponseOptions(responseId)) and read result.Value.Metadata.

Because the hosted agent never seeds metadata onto the response, result.Value.Metadata is always empty for responses produced by a ResponsesHostServer-hosted agent, so the .NET client has no way to recover the per-turn values it sent.

Root cause

azure-ai-agentserver-responses already supports this: ResponseEventStream(request=...) seeds metadata, background, previous_response_id, conversation, model and agent_reference from the request.

However, in agent_framework_foundry_hosting/_responses.py the stream is created without the request:

def _create_response_event_stream(context: ResponseContext) -> ResponseEventStream:
    """Create a response stream seeded from recovery state when available."""
    if context.is_recovery:
        persisted_response = context.persisted_response
        if persisted_response is not None:
            return ResponseEventStream(response=persisted_response, response_id=context.response_id)
    return ResponseEventStream(response_id=context.response_id)

and ResponsesHostServer._handle_response(self, request, context, cancellation_signal) calls _create_response_event_stream(context) even though request is in scope. The same code is still present on main.

Steps to reproduce

  1. Host any agent or workflow with ResponsesHostServer.
  2. POST /responses with "metadata": {"foo": "bar"} and "store": true.
  3. Inspect the response.created event, or GET /responses/{id}.

Expected: metadata == {"foo": "bar"}
Actual: metadata is null / missing.

Suggested fix

Pass the request through for fresh (non-recovery) responses:

def _create_response_event_stream(context: ResponseContext, request: CreateResponse) -> ResponseEventStream:
    if context.is_recovery:
        persisted_response = context.persisted_response
        if persisted_response is not None:
            return ResponseEventStream(response=persisted_response, response_id=context.response_id)
    return ResponseEventStream(request=request, response_id=context.response_id)

and call _create_response_event_stream(context, request) from _handle_response.

Current workaround

Monkey-patching the private agent_framework_foundry_hosting._responses._create_response_event_stream to stamp metadata onto stream.response["metadata"] before response.created is emitted. This depends on a private symbol and breaks on upgrade.

Related: #9265 (public per-request / stream-wrapping hooks).

Versions

  • agent-framework-foundry-hosting 1.0.0b260903 (also verified on main)
  • agent-framework 1.18.x
  • azure-ai-agentserver-responses 2.2.0b1, azure-ai-agentserver-core 2.1.0
  • Python 3.14

Activity

  1. added
    pythonUsage: [Issues, PRs], Target: Python
    triageUsage: [Issues], Target: All issues that still need to be triaged
    on Oct 19, 2026
  2. its-amann commented on Oct 19, 2026

    @its-amann

    Hi! I'd like to work on this. Eduard van Valkenburg (@eavanvalkenburg), could you assign it to me? I'll follow up with a PR that includes a fix and tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    pythonUsage: [Issues, PRs], Target: PythontriageUsage: [Issues], Target: All issues that still need to be triaged

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions