diff --git a/src/openai/types/responses/response_text_delta_event.py b/src/openai/types/responses/response_text_delta_event.py index 4f802abfd2..2cae46d188 100644 --- a/src/openai/types/responses/response_text_delta_event.py +++ b/src/openai/types/responses/response_text_delta_event.py @@ -1,4 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +# NOTE: logprobs field manually changed to Optional to support non-OpenAI providers +# that may not include logprobs in streaming responses. See #2489. from typing import List, Optional from typing_extensions import Literal @@ -45,7 +47,7 @@ class ResponseTextDeltaEvent(BaseModel): item_id: str """The ID of the output item that the text delta was added to.""" - logprobs: List[Logprob] + logprobs: Optional[List[Logprob]] = None """The log probabilities of the tokens in the delta.""" output_index: int diff --git a/src/openai/types/responses/response_text_done_event.py b/src/openai/types/responses/response_text_done_event.py index 75bd479870..ab89dbc65c 100644 --- a/src/openai/types/responses/response_text_done_event.py +++ b/src/openai/types/responses/response_text_done_event.py @@ -1,4 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +# NOTE: logprobs field manually changed to Optional to support non-OpenAI providers +# that may not include logprobs in streaming responses. See #2489. from typing import List, Optional from typing_extensions import Literal @@ -42,7 +44,7 @@ class ResponseTextDoneEvent(BaseModel): item_id: str """The ID of the output item that the text content is finalized.""" - logprobs: List[Logprob] + logprobs: Optional[List[Logprob]] = None """The log probabilities of the tokens in the delta.""" output_index: int diff --git a/tests/test_response_event_logprobs.py b/tests/test_response_event_logprobs.py new file mode 100644 index 0000000000..61e664559a --- /dev/null +++ b/tests/test_response_event_logprobs.py @@ -0,0 +1,64 @@ +"""Tests for optional logprobs in response event types. + +Regression tests for https://github.com/openai/openai-python/issues/2489 +Non-OpenAI providers may not include logprobs in streaming responses. +""" + +from openai.types.responses.response_text_done_event import ResponseTextDoneEvent +from openai.types.responses.response_text_delta_event import ResponseTextDeltaEvent + +_DELTA_BASE = { + "content_index": 0, + "delta": "Hello", + "item_id": "item_1", + "output_index": 0, + "sequence_number": 1, + "type": "response.output_text.delta", +} + +_DONE_BASE = { + "content_index": 0, + "item_id": "item_1", + "output_index": 0, + "sequence_number": 2, + "text": "Hello world", + "type": "response.output_text.done", +} + +_SAMPLE_LOGPROBS = [{"token": "Hello", "logprob": -0.1, "top_logprobs": None}] + + +class TestResponseTextDeltaEventLogprobs: + def test_without_logprobs(self) -> None: + event = ResponseTextDeltaEvent.model_validate(_DELTA_BASE) + assert event.logprobs is None + + def test_with_logprobs(self) -> None: + data = {**_DELTA_BASE, "logprobs": _SAMPLE_LOGPROBS} + event = ResponseTextDeltaEvent.model_validate(data) + assert event.logprobs is not None + assert len(event.logprobs) == 1 + assert event.logprobs[0].token == "Hello" + + def test_with_empty_logprobs(self) -> None: + data = {**_DELTA_BASE, "logprobs": []} + event = ResponseTextDeltaEvent.model_validate(data) + assert event.logprobs == [] + + +class TestResponseTextDoneEventLogprobs: + def test_without_logprobs(self) -> None: + event = ResponseTextDoneEvent.model_validate(_DONE_BASE) + assert event.logprobs is None + + def test_with_logprobs(self) -> None: + data = {**_DONE_BASE, "logprobs": _SAMPLE_LOGPROBS} + event = ResponseTextDoneEvent.model_validate(data) + assert event.logprobs is not None + assert len(event.logprobs) == 1 + assert event.logprobs[0].token == "Hello" + + def test_with_empty_logprobs(self) -> None: + data = {**_DONE_BASE, "logprobs": []} + event = ResponseTextDoneEvent.model_validate(data) + assert event.logprobs == []