Skip to content

Python: added generic types to ChatOptions and ChatResponse/AgentResponse for Response Format - #3305

Merged
Eduard van Valkenburg (eavanvalkenburg) merged 7 commits into
microsoft:mainfrom
eavanvalkenburg:typed_responses
Jan 28, 2026
Merged

Python: added generic types to ChatOptions and ChatResponse/AgentResponse for Response Format#3305
Eduard van Valkenburg (eavanvalkenburg) merged 7 commits into
microsoft:mainfrom
eavanvalkenburg:typed_responses

Conversation

@eavanvalkenburg

@eavanvalkenburgEduard van Valkenburg (eavanvalkenburg) commented Jan 20, 2026

Copy link
Copy Markdown
Member

Motivation and Context

Adds a Generic setup for ChatResponse/AgentResponse and the run and get_response methods.

This now is typed correctly:

agent=OpenAIResponsesClient().as_agent(name="Agent", instructions="...")
result=awaitagent.run("....", options={"response_format": OutputModel})
# result will have inferred type: `AgentResponse[OutputModel]` and result.value has `OutputModel | None` (because it still needs to parse the text into the model)

This does not work for the type inference of AgentResponse in the sample below, because I did not want agentto either have this always become ChatAgent[ChatOptions[OutputModel]] or have to add overloads to every client and explicit options settings when creating ChatAgent directly:

agent=OpenAIResponsesClient().as_agent(name="Agent", instructions="...", default_options={"response_format": OutputModel})")
result=awaitagent.run("...")
# result will have inferred type: `AgentResponse[Any]` and result.value has `Any | None`

It also works for:

result=awaitAgentResponse.from_agent_response_generator(
agent.run_stream(query, options={"response_format": OutputStruct}), output_format_type=OutputStruct,
)

Fixes#3091

Description

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • All unit tests pass, and I have added new tests where possible
  • Is this a breaking change? If yes, add "[BREAKING]" prefix to the title of the PR.

CopilotAI review requested due to automatic review settings January 20, 2026 14:14
@markwallace-microsoftMark Wallace (markwallace-microsoft) added the python Usage: [Issues, PRs], Target: Python label Jan 20, 2026

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR enhances type safety for structured outputs by adding generic type parameters to ChatOptions, ChatResponse, and AgentResponse. When using response_format with a Pydantic model, the type system now correctly infers the return type, improving IDE autocomplete and type checking.

Changes:

  • Added generic type parameters (TResponseModel) to ChatOptions, ChatResponse, and AgentResponse classes
  • Updated all provider-specific ChatOptions implementations (OpenAI, Azure, Anthropic, Bedrock, Ollama, Foundry Local, AG-UI) to support generics
  • Added overloads to get_response() and run() methods to properly infer types when response_format is specified
  • Updated sample code to use the simpler .value property instead of try_parse_value()
  • Cleaned up unused code in OpenAIAssistantsClient (removed duplicate as_agent implementation and unused imports)

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.

Show a summary per file
FileDescription
_types.pyAdded TResponseModel generic parameter to ChatOptions, ChatResponse, and AgentResponse; added overloads for try_parse_value, from_chat_response_generator, and from_agent_response_generator
_clients.pyAdded overloads to get_response() for type inference; updated as_agent() signature to accept generic options
_agents.pyAdded overloads to run() for type inference; updated to properly set response_format on AgentResponse
openai/_chat_client.pyMade OpenAIChatOptions generic over TResponseModel
openai/_responses_client.pyMade OpenAIResponsesOptions generic over TResponseFormat
openai/_assistants_client.pyMade OpenAIAssistantsOptions generic; removed duplicate as_agent override and cleaned up unused imports
azure/_chat_client.pyMade AzureOpenAIChatOptions generic over TResponseModel
anthropic/_chat_client.pyMade AnthropicChatOptions generic over TResponseModel
bedrock/_chat_client.pyMade BedrockChatOptions generic over TResponseModel
ollama/_chat_client.pyMade OllamaChatOptions generic over TResponseModel
foundry_local/_foundry_local_client.pyMade FoundryLocalChatOptions generic over TResponseModel
ag_ui/_types.pyMade AGUIChatOptions generic over TResponseModel
ag_ui/_client.pyAdded cast to ensure return type compatibility
openai_responses_client_with_structured_output.pyUpdated sample to use .value property instead of try_parse_value()

Comment threadpython/packages/core/agent_framework/_types.py Outdated
@markwallace-microsoft

Mark Wallace (markwallace-microsoft) commented Jan 21, 2026

Copy link
Copy Markdown
Contributor

Python Test Coverage

Python Test Coverage Report •
FileStmtsMissCoverMissing
packages/ag-ui/agent_framework_ag_ui
_client.py1371092%84–88, 234, 264, 419–421
_types.py360100%
packages/anthropic/agent_framework_anthropic
_chat_client.py36215058%367, 390, 392, 407, 429–432, 441, 443, 474–478, 480, 482–483, 485, 490–491, 493, 526–527, 536, 538–539, 544, 561–562, 604, 619, 623–624, 640, 649, 651, 655–656, 699–701, 703, 716–717, 724–726, 730–732, 736–739, 750, 752, 774, 784, 806–812, 819–820, 828–829, 837–840, 847–848, 854–855, 861–862, 868, 876–878, 882, 889–890, 896–897, 903–904, 910, 918–921, 928–929, 948, 955–956, 975, 997, 999, 1008–1009, 1015, 1037–1038, 1044–1045, 1054–1064, 1071–1077, 1084–1090, 1097–1106, 1113–1116
packages/azure-ai/agent_framework_azure_ai
_agent_provider.py1151289%122–123, 251, 444–446, 477–482
_chat_client.py4789480%377, 638–639, 641, 644, 647, 650–655, 658, 660, 668, 680–682, 686, 689–690, 698–701, 711, 719–722, 724–725, 727–728, 735, 743–744, 752–753, 758–759, 763–770, 775, 778, 786, 792, 800–802, 805, 827–828, 938, 940, 942, 957, 985, 998–1002, 1041–1043, 1046–1047, 1093–1099, 1121, 1147, 1156, 1165, 1167, 1172, 1181–1186, 1298
_client.py1934576%248–251, 256, 259–262, 267, 270–271, 274, 281, 345, 347, 395, 423–426, 469, 506, 508, 513, 515–516, 519–522, 524, 526–527, 529–537, 539, 584
_project_provider.py115992%132–133, 211, 309, 353, 386, 435–437
packages/chatkit/agent_framework_chatkit
_converter.py1334665%116, 121, 169, 171, 341, 394, 396, 415–417, 419, 437, 439, 441, 444, 456, 466, 484, 504–528, 530–532
packages/core/agent_framework
_agents.py3105283%91, 99, 102, 105, 407–409, 455, 639, 854, 857–859, 984–986, 991–993, 1094, 1135, 1137, 1146–1151, 1157, 1159, 1169–1170, 1177, 1179–1180, 1188–1192, 1200–1201, 1203, 1208, 1210, 1244, 1284, 1301–1302, 1304, 1306, 1317
_clients.py57492%287, 331, 479, 481
_middleware.py404798%810, 826, 873–874, 1079–1080, 1125
_tools.py7688588%226, 272, 323, 325, 353, 523, 558–559, 661, 663, 683, 701, 715, 727, 732, 734, 741, 774, 830–832, 873, 895–923, 958, 966, 1207, 1544, 1631–1635, 1657–1658, 1774, 1776, 1842, 1934, 1940, 1982–1983, 1996–1997, 2040, 2124, 2162–2163, 2202–2204, 2242–2243, 2253, 2310–2311, 2318–2319
_types.py95313286%80, 103–104, 158, 163, 182, 184, 188, 192, 194, 196, 198, 215–216, 218–220, 222–223, 225–226, 228–229, 244–246, 248–251, 268, 273, 278, 282, 308, 312, 658–659, 1030, 1092, 1109, 1127, 1132, 1150, 1158–1160, 1177–1178, 1180, 1198–1199, 1201, 1208–1209, 1211, 1246, 1257–1258, 1260, 1279–1280, 1283–1292, 1295–1298, 1300, 1304, 1338, 1371, 1543, 1548, 1552, 1556, 1748, 1758, 1803, 1848–1853, 1875, 1880, 2281, 2290, 2426, 2514–2516, 2555, 2647, 2674, 2683, 2921–2923, 2926–2928, 2932, 2937, 2941, 3053–3055, 3083, 3119, 3137, 3141–3143, 3145, 3156–3157, 3160–3164, 3170
packages/core/agent_framework/_workflows
_agent.py2804583%62, 70–76, 104–105, 261, 317, 331, 344, 393–396, 402, 408, 412–413, 416–422, 426–427, 496, 503, 509–510, 521, 553, 560, 581, 590, 594, 596–598, 605
_agent_executor.py1702386%94, 116, 150, 166–167, 218–219, 221–222, 254–256, 264–266, 276–278, 280, 284, 288, 292–293
_base_group_chat_orchestrator.py1701292%135, 301, 316, 350–352, 356, 375, 436, 480–482
_group_chat.py2595578%172, 333, 340, 366–367, 369–370, 374, 378–379, 385, 390, 406, 433–438, 440, 461, 464–466, 473–476, 478, 483–487, 563–566, 570–571, 576–577, 595, 599, 604, 659, 664, 702, 711, 717, 762, 850, 853, 885, 895
_handoff.py3845884%110–111, 113, 142–143, 163–173, 175, 177, 179, 184, 284, 338, 363, 389, 397–398, 412, 461–462, 492, 539–541, 729, 736, 741, 828, 831, 840–843, 853, 858, 865, 871–874, 909, 914, 1104, 1117, 1120, 1128, 1146, 1153, 1228
_magentic.py56710980%69–78, 83, 87–98, 263, 274, 278, 298, 359, 368, 370, 412, 429, 438–439, 441–443, 445, 456, 596–600, 602, 640, 688, 724–726, 728, 736–739, 743–746, 789, 816–819, 910, 916, 922, 961, 999, 1028, 1045, 1056, 1071–1074, 1110–1111, 1115–1117, 1141, 1162–1163, 1176, 1192, 1214, 1262–1263, 1301–1302, 1341–1342, 1344–1345, 1347, 1415, 1418, 1427, 1430, 1435, 1670–1671, 1673, 1687, 1696, 1713, 1722, 1725
_runner_context.py168696%84, 87, 383, 403, 491, 495
_workflow_builder.py2783687%259, 594, 693, 700–701, 802, 805, 810, 812, 819, 822–826, 828, 890, 965, 968, 1028–1029, 1174, 1188–1195, 1197, 1200, 1202–1204, 1212
_workflow_executor.py1724375%95, 444, 455, 467–470, 473–475, 478–479, 481, 484–486, 489–493, 497–498, 507, 512, 546, 572–577, 580, 583, 591, 596, 607, 617, 621, 627, 631, 641, 645
packages/core/agent_framework/azure
_assistants_client.py400100%
_chat_client.py81495%288, 290, 303–304
_responses_client.py40685%141, 164, 191–194
packages/core/agent_framework/openai
_assistant_provider.py1101190%156–157, 169, 294, 360, 475–480
_assistants_client.py2742989%348, 362, 365, 367–368, 371, 374, 377–378, 389, 414, 416, 418, 420, 422, 427, 430, 433, 437, 448, 533, 618, 653, 690–693, 745, 762
_chat_client.py2682192%183–184, 188, 274, 281, 362–369, 371–374, 384, 469, 506, 522
_responses_client.py5626488%258, 263, 265–266, 277, 295, 303, 326, 388, 420, 445, 451, 469–470, 492, 497, 553, 567, 584, 597, 652, 731, 736, 740–742, 746–747, 770, 839, 861–862, 877–878, 896–897, 1028–1029, 1045, 1047, 1122–1130, 1178, 1233, 1248, 1284–1285, 1287–1289, 1303–1305, 1315–1316, 1322, 1337
packages/mem0/agent_framework_mem0
_provider.py83396%164–165, 168
TOTAL16180239585%

Python Unit Test Overview

TestsSkippedFailuresErrorsTime
3450221 💤0 ❌0 🔥1m 4s ⏱️

Comment threadpython/packages/core/agent_framework/_types.py
Comment threadpython/packages/core/agent_framework/_agents.py
Comment threadpython/packages/core/agent_framework/_types.py
Comment threadpython/packages/core/agent_framework/_types.py
Merged via the queue into microsoft:main with commit 1226828Jan 28, 2026
23 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pythonUsage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: [Feature]: ChatAgent run should yield a Generic AgentRunResponse for response_format types

6 participants

@eavanvalkenburg@markwallace-microsoft@TaoChenOSU@moonbox3@giles17