-
Notifications
You must be signed in to change notification settings - Fork 449
feat: add OpenAI Responses API model implementation #975
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?
feat: add OpenAI Responses API model implementation #975
Conversation
} | ||
|
||
@classmethod | ||
def _format_request_tool_message(cls, tool_result: ToolResult) -> dict[str, Any]: |
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.
do we not handle images in tool results? Seems like these get dropped?
self, | ||
messages: Messages, | ||
tool_specs: Optional[list[ToolSpec]] = None, | ||
system_prompt: Optional[str] = None, |
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.
is the concept of tool_choice similar to how we have it in the existing provider?
if message.get("content") or message.get("type") in ["function_call", "function_call_output"] | ||
] | ||
|
||
def _format_request( |
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.
the ordering here is strange to me, it doesn't read like a story as much. I'd expect this to be something like the following top to bottom. Introducing a private method before it is used I'm not a fan of
stream
_format_request
_format_request_message_content
_format_request_message_tool_call
_format_request_tool_message
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.
honestly, I agree that it makes more sense. but this seems to be the existing pattern in other model providers in the codebase.
it follows:
- config methods
- private methods
- public methods
- main methods (stream, structured_output)
we can discuss if we want to move away from this pattern for this file and follow your suggestion.
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.
Yeah I don't want to go so far as to push my preference that all public methods are above private methods.
But a private method being above the only public method that uses it seems like some AI-slop that we've (not you) been perpetuating and pattern I'd rather clean up.
""" | ||
match event["chunk_type"]: | ||
case "message_start": | ||
return {"messageStart": {"role": "assistant"}} |
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.
reach out to @zastrowm , but I believe we can make this more readable by now returning the typed StreamEvents rather than the dictionaries
|
||
for message in messages: | ||
role = message["role"] | ||
if role == "system": |
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.
can you explain and add a comment why we are skipping these? And then higher up can in the description can you add a comment briefly describing opeai responses and how it differs fundamentally from the existing stateless models
async with openai.AsyncOpenAI(**self.client_args) as client: | ||
try: | ||
response = await client.responses.create(**request) | ||
except openai.APIError as e: |
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.
in some places we are catching RateLimitError and others it looks like we are just looking at the code. Same for badrequest+context overflow
can you explain why we have different error handling and unify if possibly
Description
This PR implements OpenAI Responses API as a separate model provider supporting streaming, structured output and tool calling.
Note: this commit does not include the extra capabilities that the Responses API supports such as the built-in tools and the stateful conversation runs.
Related Issues
#253
Documentation PR
TODO; coming next: will be adding a section for the Responses API within the existing openai model page
Type of Change
New feature
Testing
Added a unit test file similar to the existing
test_openai.py
model provider. Reusing the integ tests in the same filetest_model_openai.py
usingpytest.parameterize
withOpenAIResponses
model so that I could test that the funcitonality is the same between the two models.I ran everything in the CONTRIBUTING.md file.
hatch run integ-test
================== 81 passed, 68 skipped, 49 warnings in 106.56s (0:01:46) ==========
hatch run test-integ tests_integ/models/test_model_openai.py -v
============= 18 passed, 2 skipped in 13.44s =============
pre-commit run --all-files
hatch run prepare
--> yes, all tests passChecklist
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.