You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Python: [Bug]: Harness Agent drops structured value on the streaming path with tool approval #7418
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
Create a create_harness_agent(...) with stream=True.
Register a tool that requires approval.
Pass options={"response_format": SomePydanticModel} to agent.run.
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: NoneTypeassert isinstance(response.value, Answer) # Fails today
asyncio.run(main())
Your issue describes a clear pattern where ToolApprovalMiddleware._process_stream re-wraps the response stream via ResponseStream(_stream(), finalizer=AgentResponse.from_updates) without forwarding the output_format_type parameter, which would cause response.value to be None for structured-output streaming runs with tool approval. This appears consistent with the sibling issues you referenced (#7402, #7236). Unfortunately, were unable to verify against the current source code due to environment access issues, so it's possible this has already been addressed in a newer version; worth checking if you're on the latest release.
If this still reproduces after trying the above, please reopen and we'll take another look. 🙏
Your issue describes a clear pattern where ToolApprovalMiddleware._process_stream re-wraps the response stream via ResponseStream(_stream(), finalizer=AgentResponse.from_updates) without forwarding the output_format_type parameter, which would cause response.value to be None for structured-output streaming runs with tool approval. This appears consistent with the sibling issues you referenced (#7402, #7236). Unfortunately, were unable to verify against the current source code due to environment access issues, so it's possible this has already been addressed in a newer version; worth checking if you're on the latest release.
If this still reproduces after trying the above, please reopen and we'll take another look. 🙏
Confirmed this still reproduces on current main. The finalizer at python/packages/core/agent_framework/_harness/_tool_approval.py:500 still calls:
without passing output_format_type. Because AgentResponse.value is a lazy property that only parses structured output when _response_format is set, streaming runs with tool approval currently return response.value = None.
This is a distinct finalizer omission from the sibling issues #7402 / #7236 (both are about the agent loop, not the harness middleware re-wrapping layer). I have a focused fix + regression test ready and will link a PR shortly. Could the likely-fixed label be removed?
ToolApprovalMiddleware._process_stream now forwards response_format (run options, then agent default_options) into AgentResponse.from_updates, so streaming structured output is parsed the same way as the non-streaming path.
Activity
github-actions commentedon Jul 30, 2026
👋 Hi lmx-2077 — thanks for the report!
Your issue describes a clear pattern where
ToolApprovalMiddleware._process_streamre-wraps the response stream viaResponseStream(_stream(), finalizer=AgentResponse.from_updates)without forwarding theoutput_format_typeparameter, which would causeresponse.valueto beNonefor structured-output streaming runs with tool approval. This appears consistent with the sibling issues you referenced (#7402, #7236). Unfortunately, were unable to verify against the current source code due to environment access issues, so it's possible this has already been addressed in a newer version; worth checking if you're on the latest release.If this still reproduces after trying the above, please reopen and we'll take another look. 🙏
lmx-2077 commentedon Jul 30, 2026
Confirmed this still reproduces on current main. The finalizer at python/packages/core/agent_framework/_harness/_tool_approval.py:500 still calls:
return ResponseStream(_stream(), finalizer=AgentResponse.from_updates)
without passing output_format_type. Because AgentResponse.value is a lazy property that only parses structured output when _response_format is set, streaming runs with tool approval currently return response.value = None.
This is a distinct finalizer omission from the sibling issues #7402 / #7236 (both are about the agent loop, not the harness middleware re-wrapping layer). I have a focused fix + regression test ready and will link a PR shortly. Could the likely-fixed label be removed?
Shivani767 commentedon Aug 20, 2026
Opened a fix in #7800.
ToolApprovalMiddleware._process_streamnow forwardsresponse_format(run options, then agentdefault_options) intoAgentResponse.from_updates, so streaming structured output is parsed the same way as the non-streaming path.Python: Preserve structured output on streaming harness tool-approval…