From 29cec0d27b7396cca76e93ebe2736369e8cc2cda Mon Sep 17 00:00:00 2001 From: Willow Lopez <100782273+Oxygen56@users.noreply.github.com> Date: Tue, 9 Jun 2026 23:17:39 +0800 Subject: [PATCH] Python: fix: use getattr for non-OpenAI provider response compatibility (#6270) * fix: use getattr for non-OpenAI provider response compatibility Fixes #6234 Fixes #6235 Use getattr with None fallback for system_fingerprint and output attributes to prevent AttributeError when non-OpenAI providers return response objects without these fields. * fix: use typed variable for response output to satisfy pyright Fixes #6235 Use getattr with None fallback for the output attribute, and assign to a typed list variable before the match statement to help pyright narrow the response item types correctly. * fix: rename response_outputs to avoid name collision with case-block variable Fixes #6235 Rename outputs to response_outputs on line 1974 to avoid mypy error about conflicting variable names in the match statement's case blocks. Also use list[Any] for explicit generic type annotation. * fix: use cast(list[Any]) for response output to satisfy pyright Fixes #6235 The getattr() call returns Unknown type which pyright cannot narrow in the match statement. Use an explicit cast to list[Any]. * fix: use hasattr guard instead of getattr for response.output Fixes #6235 Using hasattr(response, 'output') and then accessing response.output directly gives pyright enough type information to verify the match statement exhaustiveness. This avoids the cast(list[Any]) approach which pyright still flagged as partially unknown. * fix: use ternary operator for response_outputs assignment Replace if-else block with ternary expression to satisfy ruff SIM108 lint rule. This fixes the Package Checks (3.11) CI failure. * fix: use ternary with cast for ruff SIM108 and pyright type safety Replace if-else block with ternary expression using cast(list[Any], ...) to satisfy: - ruff SIM108 (use ternary instead of if-else) - ruff E501 (line length < 120) - pyright type narrowing (cast preserves type info lost in ternary) All local checks pass: ruff check, ruff format, pyright, 298 tests. * fix: replace hasattr+cast with try/except to preserve pyright types --------- Co-authored-by: Tao Chen --- .../packages/openai/agent_framework_openai/_chat_client.py | 6 +++++- .../agent_framework_openai/_chat_completion_client.py | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/python/packages/openai/agent_framework_openai/_chat_client.py b/python/packages/openai/agent_framework_openai/_chat_client.py index d998875d1c..2d5cda9ee5 100644 --- a/python/packages/openai/agent_framework_openai/_chat_client.py +++ b/python/packages/openai/agent_framework_openai/_chat_client.py @@ -1997,7 +1997,11 @@ class RawOpenAIChatClient( # type: ignore[misc] metadata: dict[str, Any] = response.metadata or {} contents: list[Content] = [] local_shell_tool_name = self._get_local_shell_tool_name(options.get("tools")) - for item in response.output: # type: ignore[reportUnknownMemberType] + try: + response_outputs = response.output # type: ignore[reportUnknownMemberType] + except AttributeError: + response_outputs = [] + for item in response_outputs: # type: ignore[reportUnknownVariableType] match item.type: # types: # ParsedResponseOutputMessage[Unknown] | diff --git a/python/packages/openai/agent_framework_openai/_chat_completion_client.py b/python/packages/openai/agent_framework_openai/_chat_completion_client.py index a6878c9f2d..0fd14aa2ef 100644 --- a/python/packages/openai/agent_framework_openai/_chat_completion_client.py +++ b/python/packages/openai/agent_framework_openai/_chat_completion_client.py @@ -788,13 +788,13 @@ class RawOpenAIChatCompletionClient( # type: ignore[misc] def _get_metadata_from_chat_response(self, response: ChatCompletion) -> dict[str, Any]: """Get metadata from a chat response.""" return { - "system_fingerprint": response.system_fingerprint, + "system_fingerprint": getattr(response, "system_fingerprint", None), } def _get_metadata_from_streaming_chat_response(self, response: ChatCompletionChunk) -> dict[str, Any]: """Get metadata from a streaming chat response.""" return { - "system_fingerprint": response.system_fingerprint, + "system_fingerprint": getattr(response, "system_fingerprint", None), } def _get_metadata_from_chat_choice(self, choice: Choice | ChunkChoice) -> dict[str, Any]: