Repository navigation
Description
Description
When a Foundry tool (toolbox / MCP connection) needs the user's OAuth consent, the service returns an oauth_consent_request output item with a consent_link and marks the response incomplete.
The streaming path surfaces it: try_parse_oauth_consent_event (added for #3950) turns response.output_item.added / response.oauth_consent_requested into Content.from_oauth_consent_request(...).
The non-streaming path does not. RawFoundryChatClient._parse_response_from_openai and RawFoundryAgentChatClient._parse_response_from_openai only post-process reasoning items / agent_session_id, and the base RawOpenAIChatClient._parse_response_from_openai hits case _: logger.debug("Unparsed output of type ...") for the consent item. agent.run() (non-streaming is the default) therefore returns an empty assistant message, finish_reason=None, no exception, and the consent link is lost. The caller cannot tell the user to sign in.
- Expected: the response contains an
oauth_consent_requestcontent with theconsent_link, same as withstream=True. - Actual: the response has no content at all.
Code Sample
Self-contained repro (no Azure resources; the HTTP layer is mocked, the real OpenAI SDK parses the payload):
import asyncio, importlib
from unittest.mock import MagicMock
from openai import AsyncOpenAI, DefaultAsyncHttpxClient
from agent_framework_foundry import FoundryAgent
# httpx (openai 2.x) or httpx2 (openai 3.x), whichever the installed SDK uses
httpx = importlib.import_module(DefaultAsyncHttpxClient.__mro__[1].__module__.partition(".")[0])
def handler(request):
return httpx.Response(200, json={
"id": "resp_1", "object": "response", "created_at": 0, "model": "gpt-5.4",
"status": "incomplete",
"output": [{
"type": "oauth_consent_request", "id": "oauth-item-1",
"consent_link": "https://consent-host.example.com/login?data=abc123",
"server_label": "github",
}],
})
async def main():
oai = AsyncOpenAI(api_key="x", http_client=DefaultAsyncHttpxClient(transport=httpx.MockTransport(handler)))
project = MagicMock()
project.get_openai_client.return_value = oai
agent = FoundryAgent(project_client=project, agent_name="toolbox-agent")
response = await agent.run("List my repos")
print([c.type for m in response.messages for c in m.contents]) # [] -> consent link lost
asyncio.run(main())Same result with FoundryChatClient(...).get_response(...). With stream=True the consent content is returned.
Root cause
python/packages/foundry/agent_framework_foundry/_chat_client.py:338(RawFoundryChatClient._parse_response_from_openai) andpython/packages/foundry/agent_framework_foundry/_agent.py:423(RawFoundryAgentChatClient._parse_response_from_openai) never look foroauth_consent_requestitems; only the streaming overrides (:367/:434) calltry_parse_oauth_consent_event.- The item then falls through to
python/packages/openai/agent_framework_openai/_chat_client.py:3543(logger.debug("Unparsed output of type ...")).
Proposed fix
Add a small helper in _oauth_helpers.py that converts oauth_consent_request items of a completed response's output into Content.from_oauth_consent_request (same HTTPS validation as the streaming path), and append the result to the message in both non-streaming overrides. PR with regression tests for both clients is ready.
Code Sample
Error Messages / Stack Traces
Package Versions
agent-framework-foundry: 1.14.0, agent-framework-openai: 1.15.0, agent-framework-core: 1.20.0 (main @ e9857bd)
Python Version
Python 3.12
Additional Context
Related: #3950 (streaming events silently dropped). That fix covers the streaming path only.
Metadata
Metadata
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
github-actions commentedon Oct 2, 2026
🤖 Automated triage reproduction notes (agent-authored — trust but verify)
Agent analysis
The bug occurs in
python/packages/foundry/agent_framework_foundry/_chat_client.py::RawFoundryChatClient._parse_response_from_openaiand_agent.py::RawFoundryAgentChatClient._parse_response_from_openaiwhen a non-streaming response contains anoauth_consent_requestoutput item. Minimal repro: mock an OpenAI Responses API payload containing that item, then callFoundryChatClient.get_response()orFoundryAgent.run()and assert that the returned message contains OAuth consent content; both currently return none.python/packages/foundry/tests/foundry/test_foundry_chat_client.py::test_get_response_non_streaming_surfaces_oauth_consent_request1.14.01.14.0