Skip to content

Python: [Bug]: Harness Agent drops structured value on the streaming path with tool approval #7418

Description

@lmx-2077

Description

What happened?

ToolApprovalMiddleware._process_stream finalizes the outer stream with AgentResponse.from_updates without passing output_format_type:

return ResponseStream(_stream(), finalizer=AgentResponse.from_updates)

Because from_updates receives the text updates but no response_format, the final AgentResponse.value is None for streaming runs that combine tool approval with a structured-output schema.

The non-streaming path is unaffected because it returns the inner AgentResponse directly.

What did you expect to happen?

response.value should be parsed into the Pydantic model / schema supplied via response_format, matching the non-harness streaming path in _agents.py:1229.

Steps to reproduce the issue

  1. Create a create_harness_agent(...) with stream=True.
  2. Register a tool that requires approval.
  3. Pass options={"response_format": SomePydanticModel} to agent.run.
  4. Inspect response.value — it is None.

Same "per-run concept lost by a re-wrapping layer" family as #7402 and #7236.

Code Sample

from typing import Any

import asyncio
from pydantic import BaseModel

from agent_framework import (
    AgentSession,
    BaseChatClient,
    ChatResponse,
    Message,
    create_harness_agent,
)


class Answer(BaseModel):
    answer: str


class EchoTool:
    @tool(approval_mode="always_require")
    async def echo(self, text: str) -> str:
        return text


class FakeStreamingClient(BaseChatClient):
    async def _inner_get_response(self, *, messages, stream, options, **kwargs):
        return ChatResponse(
            messages=[Message("assistant", ['{"answer": "42"}'])]
        )


async def main():
    agent = create_harness_agent(
        client=FakeStreamingClient(),
        tools=[EchoTool().echo],
        stream=True,
    )
    session = AgentSession()

    response = await agent.run(
        "Call echo and return an Answer.",
        session=session,
        options={"response_format": Answer},
    )

    print(type(response.value))  # Currently: NoneType
    assert isinstance(response.value, Answer)  # Fails today


asyncio.run(main())

Error Messages / Stack Traces

Package Versions

agent-framework-core: 1.12.1

Python Version

No response

Additional Context

No response

Activity

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

Metadata

Metadata

Labels

agentsUsage: [Issues, PRs], Target: Single agentharness[Issues, PRs], Target: harness-level itemslikely-fixedpythonUsage: [Issues, PRs], Target: Python

Type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions