diff --git a/.castiron.stats.yml b/.castiron.stats.yml index f7808a54e5..9368af3714 100644 --- a/.castiron.stats.yml +++ b/.castiron.stats.yml @@ -1,7 +1,7 @@ schema_version: 1 -generation_id: 65a0f13e-756e-4f10-b075-12ae5d3d27a9 -openapi_spec_hash: 51b199ef7fd5542bc4910765f9becd60 -openapi_transformed_spec_hash: 73822d924c15a6ed58dcfe8f616bd4be +generation_id: 287e1fa6-451c-4f5f-9a80-498c77a0bd65 +openapi_spec_hash: 17689beb6a2da96f6cf9e5ac1e758a99 +openapi_transformed_spec_hash: 75a7f7b19910025d8f8f8aa1556d9b69 config_hash: b707b209c892562880c415693d111ad6 -codegen_sha: 52c5bafacb27ede81a3d66b62b29d946df4ed2cd -codegen_hash: 536c408e94523f4af5a3ddf0c2f8f0764014bad6b9287cacdb9b8e3eeb60ba7d +codegen_sha: b79c2ec277007e5a097e73a710864b77338da840 +codegen_hash: 7acc6ff9d93bbfd3be9e38f79d6b509bfd063f80cdd751f997b86e000327b9ae diff --git a/api_reference/openapi.transformed.yml b/api_reference/openapi.transformed.yml index b17e12fee9..1b228fd734 100644 --- a/api_reference/openapi.transformed.yml +++ b/api_reference/openapi.transformed.yml @@ -68596,6 +68596,12 @@ components: `stream_id` controls routing; `previous_response_id` controls conversation lineage, so a new lane can fork from a response created on another lane. + generate: + type: boolean + description: | + Whether to generate output for this response. Defaults to true when omitted. + Set to false to prepare request state without model output; the response + ID can be used as previous_response_id on a later turn. required: - type - $ref: '#/components/schemas/CreateResponse' @@ -111544,6 +111550,12 @@ components: `stream_id` controls routing; `previous_response_id` controls conversation lineage, so a new lane can fork from a response created on another lane. + generate: + type: boolean + description: | + Whether to generate output for this response. Defaults to true when omitted. + Set to false to prepare request state without model output; the response + ID can be used as previous_response_id on a later turn. required: - type - $ref: '#/components/schemas/BetaCreateResponse' diff --git a/scripts/castiron/generated-files.json b/scripts/castiron/generated-files.json index 665807274b..f0d145120c 100644 --- a/scripts/castiron/generated-files.json +++ b/scripts/castiron/generated-files.json @@ -379,7 +379,7 @@ }, "src/openai/resources/beta/responses/responses.py": { "mode": "100644", - "sha256": "effa8db6d9a676f1f264f0b6acb3252d8dcd5f75db251bfd8b5d45ea49f0f533" + "sha256": "c5a3b0cb69c3f990dc2ae76db0d2c5fb2df54b8fc312d330cb33d223d1389d26" }, "src/openai/resources/beta/threads/__init__.py": { "mode": "100644", @@ -559,11 +559,11 @@ }, "src/openai/resources/live/forks.py": { "mode": "100644", - "sha256": "7fe78c144680df54628773683f9dd5b06c5241d0218b4f4c745890ddae225c92" + "sha256": "f65742e893b6af599b97156ed30e80629364a4cf74fa76593c26b845c4fd6a1b" }, "src/openai/resources/live/live.py": { "mode": "100644", - "sha256": "86be3e074d011a750fa52a4d216a7e87ee5c8e82f6ccec00102c03a539199882" + "sha256": "4f9a3128d0a4d56f14c74c80a1d6bb8ee76fdb8096699f6573bc6c4ed434b9d6" }, "src/openai/resources/live/sessions.py": { "mode": "100644", @@ -571,7 +571,7 @@ }, "src/openai/resources/live/sideband.py": { "mode": "100644", - "sha256": "d19149c042afcd8c8efca3d7794092acc1c2f76a4bcb4f6f620547314a78e59b" + "sha256": "57b9f15595dc68614203c5c0fa4c92f309e27a90f927a0cf8e46542cfa3eb79b" }, "src/openai/resources/models.py": { "mode": "100644", @@ -599,7 +599,7 @@ }, "src/openai/resources/realtime/realtime.py": { "mode": "100644", - "sha256": "9cb69e1f54c6e21d9111ddfb59a2a4de18466a1a86487fc65a0e17224b72475e" + "sha256": "57a32212a3d102145e054727e00c979b616b38d85a2802761dd2f6c2848a0db1" }, "src/openai/resources/realtime/translations/__init__.py": { "mode": "100644", @@ -611,7 +611,7 @@ }, "src/openai/resources/realtime/translations/translations.py": { "mode": "100644", - "sha256": "4a6f072cea78d5afab3fe1c995b939ff8c79f449665346c729abb5c516c53f21" + "sha256": "dd26ca4fe27aa6b23b9d0add6e5aa41d10379ee3c6fa8c22293a26da867ca90e" }, "src/openai/resources/responses/__init__.py": { "mode": "100644", @@ -631,7 +631,7 @@ }, "src/openai/resources/responses/responses.py": { "mode": "100644", - "sha256": "f844db6ec37b49de883ab2c507570b94c29e8c2609ee93cf45c0aec19fd671d3" + "sha256": "86130a834c60c1b7df85118cbc918e84d0a23c122099f1f4e931c1a39b35abfa" }, "src/openai/resources/safety/__init__.py": { "mode": "100644", @@ -3087,11 +3087,11 @@ }, "src/openai/types/beta/beta_responses_client_event.py": { "mode": "100644", - "sha256": "939052a456df5a661ed334033a9151c18ed63dfba6c520fd92a7572d50efc091" + "sha256": "977d2d22d8468005d9dcf27c5e9c7e5c6430bb9dacd5258369022f1513431d3d" }, "src/openai/types/beta/beta_responses_client_event_param.py": { "mode": "100644", - "sha256": "ba2e2d06061761345308086b4b1d2ce39f86db631c46db825c5bbc7f62f63ccb" + "sha256": "0ad4be42df7202197e66ed97ae6fbfbdcad2aeb4e92328064630497d18fb457c" }, "src/openai/types/beta/beta_responses_server_event.py": { "mode": "100644", @@ -6735,11 +6735,11 @@ }, "src/openai/types/responses/responses_client_event.py": { "mode": "100644", - "sha256": "77d64183c9c69abfd4300c8094fbd3bc9c3a89743b9efa83a5264bd3dc165961" + "sha256": "3993eec234392a96646408fb959860a86b2711ac53dc7e8ae1338c43ca6383b4" }, "src/openai/types/responses/responses_client_event_param.py": { "mode": "100644", - "sha256": "95444697e02d702e9f568da381903d251b3d5c649de9c5d26662a1782431647b" + "sha256": "20cbab38d02cfd2506ad2104d09e2b3bfb0d2b0d8a55adec13882f3a15c9db2d" }, "src/openai/types/responses/responses_server_event.py": { "mode": "100644", diff --git a/src/openai/resources/beta/responses/responses.py b/src/openai/resources/beta/responses/responses.py index aa5aa1507d..64016c7ae6 100644 --- a/src/openai/resources/beta/responses/responses.py +++ b/src/openai/resources/beta/responses/responses.py @@ -5278,7 +5278,7 @@ async def __aexit__( if self.__connection is not None: try: await self.__connection.close() - except BaseException: + except Exception: if exc is None: raise @@ -5696,7 +5696,7 @@ def __exit__( if self.__connection is not None: try: self.__connection.close() - except BaseException: + except Exception: if exc is None: raise @@ -5715,6 +5715,7 @@ def create( context_management: Optional[Iterable[beta_responses_client_event_param.ResponseCreateContextManagement]] | Omit = omit, conversation: Optional[beta_responses_client_event_param.ResponseCreateConversation] | Omit = omit, + generate: bool | Omit = omit, include: Optional[List[BetaResponseIncludable]] | Omit = omit, input: Union[str, BetaResponseInputParam] | Omit = omit, instructions: Optional[str] | Omit = omit, @@ -5881,6 +5882,7 @@ def create( "background": background, "context_management": context_management, "conversation": conversation, + "generate": generate, "include": include, "input": input, "instructions": instructions, @@ -5973,6 +5975,7 @@ async def create( context_management: Optional[Iterable[beta_responses_client_event_param.ResponseCreateContextManagement]] | Omit = omit, conversation: Optional[beta_responses_client_event_param.ResponseCreateConversation] | Omit = omit, + generate: bool | Omit = omit, include: Optional[List[BetaResponseIncludable]] | Omit = omit, input: Union[str, BetaResponseInputParam] | Omit = omit, instructions: Optional[str] | Omit = omit, @@ -6139,6 +6142,7 @@ async def create( "background": background, "context_management": context_management, "conversation": conversation, + "generate": generate, "include": include, "input": input, "instructions": instructions, diff --git a/src/openai/resources/live/forks.py b/src/openai/resources/live/forks.py index 7ca2d8420b..b5a8a9a4cf 100644 --- a/src/openai/resources/live/forks.py +++ b/src/openai/resources/live/forks.py @@ -533,7 +533,7 @@ async def __aexit__( if self.__connection is not None: try: await self.__connection.close() - except BaseException: + except Exception: if exc is None: raise @@ -959,7 +959,7 @@ def __exit__( if self.__connection is not None: try: self.__connection.close() - except BaseException: + except Exception: if exc is None: raise diff --git a/src/openai/resources/live/live.py b/src/openai/resources/live/live.py index 82d95aaaa5..438b2797fb 100644 --- a/src/openai/resources/live/live.py +++ b/src/openai/resources/live/live.py @@ -746,7 +746,7 @@ async def __aexit__( if self.__connection is not None: try: await self.__connection.close() - except BaseException: + except Exception: if exc is None: raise @@ -1164,7 +1164,7 @@ def __exit__( if self.__connection is not None: try: self.__connection.close() - except BaseException: + except Exception: if exc is None: raise diff --git a/src/openai/resources/live/sideband.py b/src/openai/resources/live/sideband.py index f9e767805c..38746f31de 100644 --- a/src/openai/resources/live/sideband.py +++ b/src/openai/resources/live/sideband.py @@ -545,7 +545,7 @@ async def __aexit__( if self.__connection is not None: try: await self.__connection.close() - except BaseException: + except Exception: if exc is None: raise @@ -980,7 +980,7 @@ def __exit__( if self.__connection is not None: try: self.__connection.close() - except BaseException: + except Exception: if exc is None: raise diff --git a/src/openai/resources/realtime/realtime.py b/src/openai/resources/realtime/realtime.py index 13c7b0063c..2382f9d78a 100644 --- a/src/openai/resources/realtime/realtime.py +++ b/src/openai/resources/realtime/realtime.py @@ -756,7 +756,7 @@ async def __aexit__( if self.__connection is not None: try: await self.__connection.close() - except BaseException: + except Exception: if exc is None: raise @@ -1213,7 +1213,7 @@ def __exit__( if self.__connection is not None: try: self.__connection.close() - except BaseException: + except Exception: if exc is None: raise diff --git a/src/openai/resources/realtime/translations/translations.py b/src/openai/resources/realtime/translations/translations.py index 37c8058780..b5843aac6b 100644 --- a/src/openai/resources/realtime/translations/translations.py +++ b/src/openai/resources/realtime/translations/translations.py @@ -617,7 +617,7 @@ async def __aexit__( if self.__connection is not None: try: await self.__connection.close() - except BaseException: + except Exception: if exc is None: raise @@ -1041,7 +1041,7 @@ def __exit__( if self.__connection is not None: try: self.__connection.close() - except BaseException: + except Exception: if exc is None: raise diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 4e03633b7f..854e429823 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -4467,7 +4467,7 @@ async def __aexit__( if self.__connection is not None: try: await self.__connection.close() - except BaseException: + except Exception: if exc is None: raise @@ -4886,7 +4886,7 @@ def __exit__( if self.__connection is not None: try: self.__connection.close() - except BaseException: + except Exception: if exc is None: raise @@ -4939,6 +4939,7 @@ def create( context_management: Optional[Iterable[responses_client_event_param.ResponseCreateContextManagement]] | Omit = omit, conversation: Optional[responses_client_event_param.ResponseCreateConversation] | Omit = omit, + generate: bool | Omit = omit, include: Optional[List[ResponseIncludable]] | Omit = omit, input: Union[str, ResponseInputParam] | Omit = omit, instructions: Optional[str] | Omit = omit, @@ -4989,6 +4990,7 @@ def create( "background": background, "context_management": context_management, "conversation": conversation, + "generate": generate, "include": include, "input": input, "instructions": instructions, @@ -5074,6 +5076,7 @@ async def create( context_management: Optional[Iterable[responses_client_event_param.ResponseCreateContextManagement]] | Omit = omit, conversation: Optional[responses_client_event_param.ResponseCreateConversation] | Omit = omit, + generate: bool | Omit = omit, include: Optional[List[ResponseIncludable]] | Omit = omit, input: Union[str, ResponseInputParam] | Omit = omit, instructions: Optional[str] | Omit = omit, @@ -5124,6 +5127,7 @@ async def create( "background": background, "context_management": context_management, "conversation": conversation, + "generate": generate, "include": include, "input": input, "instructions": instructions, diff --git a/src/openai/types/beta/beta_responses_client_event.py b/src/openai/types/beta/beta_responses_client_event.py index 111e4dd070..32047d9ae0 100644 --- a/src/openai/types/beta/beta_responses_client_event.py +++ b/src/openai/types/beta/beta_responses_client_event.py @@ -281,6 +281,14 @@ class ResponseCreate(BaseModel): to this conversation after this response completes. """ + generate: Optional[bool] = None + """Whether to generate output for this response. + + Defaults to true when omitted. Set to false to prepare request state without + model output; the response ID can be used as previous_response_id on a later + turn. + """ + include: Optional[List[BetaResponseIncludable]] = None """Specify additional output data to include in the model response. diff --git a/src/openai/types/beta/beta_responses_client_event_param.py b/src/openai/types/beta/beta_responses_client_event_param.py index 63f1049cf1..4ef82d7e5f 100644 --- a/src/openai/types/beta/beta_responses_client_event_param.py +++ b/src/openai/types/beta/beta_responses_client_event_param.py @@ -281,6 +281,14 @@ class ResponseCreate(TypedDict, total=False): to this conversation after this response completes. """ + generate: bool + """Whether to generate output for this response. + + Defaults to true when omitted. Set to false to prepare request state without + model output; the response ID can be used as previous_response_id on a later + turn. + """ + include: Optional[List[BetaResponseIncludable]] """Specify additional output data to include in the model response. diff --git a/src/openai/types/responses/responses_client_event.py b/src/openai/types/responses/responses_client_event.py index a800572d43..5e79932a21 100644 --- a/src/openai/types/responses/responses_client_event.py +++ b/src/openai/types/responses/responses_client_event.py @@ -222,6 +222,14 @@ class ResponseCreate(BaseModel): to this conversation after this response completes. """ + generate: Optional[bool] = None + """Whether to generate output for this response. + + Defaults to true when omitted. Set to false to prepare request state without + model output; the response ID can be used as previous_response_id on a later + turn. + """ + include: Optional[List[ResponseIncludable]] = None """Specify additional output data to include in the model response. diff --git a/src/openai/types/responses/responses_client_event_param.py b/src/openai/types/responses/responses_client_event_param.py index ced1672300..76a7761ad5 100644 --- a/src/openai/types/responses/responses_client_event_param.py +++ b/src/openai/types/responses/responses_client_event_param.py @@ -222,6 +222,14 @@ class ResponseCreate(TypedDict, total=False): to this conversation after this response completes. """ + generate: bool + """Whether to generate output for this response. + + Defaults to true when omitted. Set to false to prepare request state without + model output; the response ID can be used as previous_response_id on a later + turn. + """ + include: Optional[List[ResponseIncludable]] """Specify additional output data to include in the model response. diff --git a/tests/lib/test_websocket_entry_cleanup.py b/tests/lib/test_websocket_entry_cleanup.py index 7c1248c2af..c0ff2e0ba9 100644 --- a/tests/lib/test_websocket_entry_cleanup.py +++ b/tests/lib/test_websocket_entry_cleanup.py @@ -163,3 +163,59 @@ def fail_construct(*_args: Any, **_kwargs: Any) -> None: await session.enter() assert raised.value is original assert sock.close_called + + +@pytest.mark.parametrize("product", ["responses", "beta.responses"]) +@pytest.mark.asyncio +async def test_task_cancel_during_exit_preserves_new_cancellation( + monkeypatch: pytest.MonkeyPatch, product: str +) -> None: + entered_close = asyncio.Event() + body_error = ValueError("synthetic ordinary body failure") + close_cancel: list[asyncio.CancelledError] = [] + + class Socket: + close_count = 0 + sent: list[str] = [] + + async def send(self, data: str) -> None: + self.sent.append(data) + + async def close(self, **_kwargs: Any) -> None: + self.close_count += 1 + entered_close.set() + try: + await asyncio.Event().wait() + except asyncio.CancelledError as exc: + close_cancel.append(exc) + raise + + sock = Socket() + + async def connect(*_args: Any, **_kwargs: Any) -> Socket: + return sock + + monkeypatch.setattr("openai.lib._websocket._WebSocketConnect", connect) + async with AsyncOpenAI(api_key="fake-key") as client: + session = manager(client, product) + session.send({"type": "synthetic.first"}) + + async def use_session() -> None: + async with session: + assert [json.loads(data)["type"] for data in sock.sent] == ["synthetic.first"] + raise body_error + + task = asyncio.create_task(use_session()) + try: + await asyncio.wait_for(entered_close.wait(), timeout=3) + assert not task.done() and sock.close_count == 1 + assert task.cancel("new cancellation during cleanup") + with pytest.raises(asyncio.CancelledError): + await asyncio.wait_for(task, timeout=3) + assert task.cancelled() + assert len(close_cancel) == 1 + assert close_cancel[0].args == ("new cancellation during cleanup",) + finally: + if not task.done(): + task.cancel() + await asyncio.gather(task, return_exceptions=True)