-
Notifications
You must be signed in to change notification settings - Fork 2.4k
fix: handle dict format in response processing for web_search tools #8966
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
fix: handle dict format in response processing for web_search tools #8966
Conversation
- Modified _process_response to handle both object and dict formats - web_search tools return response.output items as dicts instead of objects - Added isinstance checks throughout the method for type safety - Tested with real GPT-5 API and web_search - confirms fix works - Maintains backward compatibility with normal responses - Fixes AttributeError: 'dict' object has no attribute 'type' - Resolves stanfordnlp#8958 Signed-off-by: Bhaskar <bhaskar@zasti.ai>
|
While this fix works, I wonder if this needs to be fixed on the LiteLLM side. It's probably not expected to change the output type based on the tool argument. |
|
@TomeHirata You're right that ideally LiteLLM should return a consistent format regardless of tool usage. I checked the OpenAI Responses API directly (not through LiteLLM) and confirmed that the dict format is coming directly from OpenAI's API when web_search tools are used. So this appears to be an OpenAI API behavior rather than a LiteLLM transformation issue. However, I agree this could potentially be normalized on the LiteLLM side for consistency. A few options: Option 1: Keep this fix in DSPy (defensive coding)
Option 2: Report to LiteLLM
Option 3: Both
I'm happy to:
What would you recommend? I want to make sure we're following DSPy's preferred approach for handling upstream API inconsistencies. Thanks for the thoughtful review! |
|
LiteLLM should adhere to the responses API, making delegation there an impractical option. The parsing in DSPy incorporates specific assumptions about the structure of a response, which unfortunately fail to align with the format of web search results. In my opinion, this issue can and should be easily addressed within DSPy, as demonstrated in this PR. |
|
Thanks for the support, @casper-hansen! You're exactly right - since LiteLLM is correctly passing through the OpenAI Responses API format, the parsing logic in DSPy needs to handle both structures. The fix is straightforward defensive programming: check the type before accessing attributes. This makes DSPy robust to API format variations without requiring upstream changes. @TomeHirata Given Casper's input and the fact that this is OpenAI's native format (not a LiteLLM transformation), would you be comfortable merging this defensive fix? It solves the immediate issue for users while keeping DSPy resilient to API format variations. Happy to make any adjustments you'd like to see! |
|
Got it, it's interesting that the response type is changed based on the presence of tool argument. Sure, we can support the conversion on our side. Then can we convert the response to a dict first regardingless of the tool presence? We can simplify the parse logic in this way. Also can you add a unit test? |
Signed-off-by: Bhaskar <bhaskar@zasti.ai>
- Refactor _process_response to convert all outputs to dict format first - Simplifies parsing logic (no isinstance checks throughout) - Add comprehensive unit tests for both dict and object formats - Tests cover: message, function_call, reasoning types - Tests cover: object format (normal) and dict format (web_search) - Addresses @TomeHirata feedback for cleaner implementation - Fixes stanfordnlp#8958
|
@TomeHirata Done! I've refactored the code as you suggested: Changes:
Unit Tests Coverage:
Test Results: The refactored implementation is cleaner, well-tested, and handles both formats transparently with a single normalization point. Ready for review! |
| @@ -0,0 +1,204 @@ | |||
| """ | |||
| Unit tests for _process_response method handling both dict and object formats. | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't create a new test file and use the existing test_base_lm.py
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also I don't think we don't need to add such a large number of tests.
| List of processed outputs, which is always of size 1 because the Response API only supports one output. | ||
| """ | ||
|
|
||
| def _normalize_output_item(item): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't OpenAI provide this conversion out of box?
Fixes #8958
Summary
Fixed the
AttributeError: 'dict' object has no attribute 'type'that occurred when usingweb_searchtools with the Responses API, enabling proper web search functionality with GPT-5 and other reasoning models.Problem
When
web_searchtools are used with the OpenAI Responses API, the API returnsresponse.outputitems as dictionaries instead of objects with attributes. This caused the_process_response()method inbase_lm.pyto crash at line 233:Why This Happened
The Responses API changes its response format based on tool usage:
.type,.contentattributes"type","content"keysThe existing code only handled the object format, causing crashes when web_search was enabled.
Solution
Modified
_process_response()indspy/clients/base_lm.pyto handle both formats usingisinstance()checks:Applied this dual-format handling pattern throughout the method for:
Changes
File:
dspy/clients/base_lm.pyMethod:
_process_response()(lines 220-275)Type: Added isinstance checks for dict and object response formats
Code Changes Detail
output_itemis dict or object before accessing attributes.get()for dict access, attribute access for objectsmessage,function_call, andreasoningTesting
Manual Testing with GPT-5 and Web Search
Verified the fix with actual GPT-5 API access and web_search tools:
Test Configuration:
Test Query:
"What are the latest AI developments in October 2025?"
Results:
Backward Compatibility Test
Tested normal responses without web_search:
Result: ✅ Normal mode continues to work perfectly - backward compatible
Related Work
This PR works in conjunction with PR #8963:
Together, these two PRs fully enable web_search support with the Responses API.
Backward Compatibility
✅ Fully backward compatible - No breaking changes:
The code gracefully detects and handles both formats at runtime.
Impact
This fix enables users to:
Implementation Notes
The key insight is that OpenAI's Responses API returns different data structures based on whether tools (specifically web_search) are enabled. This fix makes DSPy robust to both formats by:
.get()vs attribute)Testing Instructions for Reviewers
To test this fix (requires GPT-5 access):
@casper-hansen This fully resolves the web_search issue you reported! You should now be able to use web_search tools with your GEPA optimization workflow. 🎉
@TomeHirata @chenmoneygithub Would appreciate your review when you have a chance. The fix is straightforward - just adds proper type checking before attribute access.