diff --git a/.castiron.stats.yml b/.castiron.stats.yml index 74e5a0f40a..07cc92d5db 100644 --- a/.castiron.stats.yml +++ b/.castiron.stats.yml @@ -1,8 +1,8 @@ schema_version: 1 -generation_id: 021e41cf-0817-45e4-a61f-ed6fae979669 +generation_id: bb452d19-8d5f-4013-bfd3-3edecb25c37e openapi_spec_hash: 72d34e76f62e434dc0b71e0b4ac0ce8a -openapi_transformed_spec_hash: d432497f20d18a61808b4cd56a74dd06 -config_hash: db72038ac88cdb94ae1cafef6aada78e -codegen_sha: 2f57e709a2d02130135d501497f67d2c279150a6 -codegen_hash: b5dab72c84981b6bbd1709863e017a16f1902b9aa11cd721143186487fd2787b -public_codegen_sha: 12578924cd37047e1bff02ea0e6f90114b363d15 +openapi_transformed_spec_hash: bca4c6179df519f310841c4730b72c18 +config_hash: 8a49d8603252fe24c2dc96f50eb0d05b +codegen_sha: 016ee2b2da744118cf209752f57c8616ad20b842 +codegen_hash: 82cc4b7aca374db5d389b1ac06369a1ffa5946795a9ab86c87f57a5f5ec00390 +public_codegen_sha: e23db4894b46c4da1d4d9625eb0876d0ab512e78 diff --git a/api_reference/openapi.transformed.yml b/api_reference/openapi.transformed.yml index 797a0aa9d0..7eea64cdcb 100644 --- a/api_reference/openapi.transformed.yml +++ b/api_reference/openapi.transformed.yml @@ -77031,6 +77031,14 @@ components: description: The streamed output emitted by an apply patch tool call. CompactionTriggerItemParam: properties: + id: + anyOf: + - type: string + description: The unique ID of this compaction trigger. + example: msg_123 + - type: 'null' + x-stainless-skip: + - java type: type: string enum: @@ -77043,6 +77051,8 @@ components: - type title: Compaction trigger description: Compacts the current context. Must be the final input item. + x-openai-java-raw-discriminator-variant: true + x-stainless-go-constant-constructor: true ItemReferenceParam: properties: type: @@ -95934,6 +95944,12 @@ components: - $ref: '#/components/schemas/Beta_AgentTagParam' description: The agent that produced this item. - type: 'null' + id: + anyOf: + - type: string + description: The unique ID of this compaction trigger. + example: msg_123 + - type: 'null' type: type: string enum: diff --git a/scripts/castiron/generated-files.json b/scripts/castiron/generated-files.json index e5b09e89e7..1233e098ff 100644 --- a/scripts/castiron/generated-files.json +++ b/scripts/castiron/generated-files.json @@ -2715,11 +2715,11 @@ }, "src/openai/types/beta/beta_response_input_item.py": { "mode": "100644", - "sha256": "983b4bae43351fe29f230f57fdc8d4689517fb650624371ea31f05aff87adffc" + "sha256": "2ae060729add2cab2525c2023eb6c3c3d2c227102d6f2c147df2c2ee79a5a93d" }, "src/openai/types/beta/beta_response_input_item_param.py": { "mode": "100644", - "sha256": "7bbb9e784317227a262d463a49a89c0c332dd29fa0f42f6de80b2d8a8a79ad3f" + "sha256": "48f9c9460e33bcf927ea643429f17b9b6ff7887811b9e37f68433cc0b368e56d" }, "src/openai/types/beta/beta_response_input_message_content_list.py": { "mode": "100644", @@ -2735,7 +2735,7 @@ }, "src/openai/types/beta/beta_response_input_param.py": { "mode": "100644", - "sha256": "72f8184dea59a7964166fc435b539601d8fdbb68e34f764b27d93ef0e28f14f4" + "sha256": "dbbe5119f391595b268e03397d3825e62f8f7be5911e608dfb350fb9640f3c88" }, "src/openai/types/beta/beta_response_input_text.py": { "mode": "100644", @@ -6255,11 +6255,11 @@ }, "src/openai/types/responses/response_input_item.py": { "mode": "100644", - "sha256": "19a1c7e4bf2463166257d148b68edd9bec64825c30f83d64540bd93615791a76" + "sha256": "d11a8e20faa7b07c94fad1f425617ddc6928d41d67ed9cf996838f24fcebd935" }, "src/openai/types/responses/response_input_item_param.py": { "mode": "100644", - "sha256": "ecb035880fd48bcbb9070b53d38051809da70d232623dd9fb6959dee68a1817c" + "sha256": "6d82bca0fb97781662930e4b803b98ecbbe781b44b4de6563c023b31fb51003f" }, "src/openai/types/responses/response_input_message_content_list.py": { "mode": "100644", @@ -6275,7 +6275,7 @@ }, "src/openai/types/responses/response_input_param.py": { "mode": "100644", - "sha256": "76bf6aa06f060fa1668ca0e2d2e474ea343f0054bf1ab4abdc7bc5c501dfc72d" + "sha256": "4160fb61307b6b2680bf04ea49194a3d5c0dd05ab1de4f02545f1f80f8b973ff" }, "src/openai/types/responses/response_input_text.py": { "mode": "100644", diff --git a/src/openai/types/beta/beta_response_input_item.py b/src/openai/types/beta/beta_response_input_item.py index a5b2ea225d..35b1bbef55 100644 --- a/src/openai/types/beta/beta_response_input_item.py +++ b/src/openai/types/beta/beta_response_input_item.py @@ -1109,6 +1109,9 @@ class CompactionTrigger(BaseModel): type: Literal["compaction_trigger"] """The type of the item. Always `compaction_trigger`.""" + id: Optional[str] = None + """The unique ID of this compaction trigger.""" + agent: Optional[CompactionTriggerAgent] = None """The agent that produced this item.""" diff --git a/src/openai/types/beta/beta_response_input_item_param.py b/src/openai/types/beta/beta_response_input_item_param.py index 5cf212545c..66a88f2344 100644 --- a/src/openai/types/beta/beta_response_input_item_param.py +++ b/src/openai/types/beta/beta_response_input_item_param.py @@ -1097,6 +1097,9 @@ class CompactionTrigger(TypedDict, total=False): type: Required[Literal["compaction_trigger"]] """The type of the item. Always `compaction_trigger`.""" + id: Optional[str] + """The unique ID of this compaction trigger.""" + agent: Optional[CompactionTriggerAgent] """The agent that produced this item.""" diff --git a/src/openai/types/beta/beta_response_input_param.py b/src/openai/types/beta/beta_response_input_param.py index 3cfcdff328..2ecb1e1d0a 100644 --- a/src/openai/types/beta/beta_response_input_param.py +++ b/src/openai/types/beta/beta_response_input_param.py @@ -1098,6 +1098,9 @@ class CompactionTrigger(TypedDict, total=False): type: Required[Literal["compaction_trigger"]] """The type of the item. Always `compaction_trigger`.""" + id: Optional[str] + """The unique ID of this compaction trigger.""" + agent: Optional[CompactionTriggerAgent] """The agent that produced this item.""" diff --git a/src/openai/types/responses/response_input_item.py b/src/openai/types/responses/response_input_item.py index a4bb345dca..e31c9c277e 100644 --- a/src/openai/types/responses/response_input_item.py +++ b/src/openai/types/responses/response_input_item.py @@ -734,6 +734,9 @@ class CompactionTrigger(BaseModel): type: Literal["compaction_trigger"] """The type of the item. Always `compaction_trigger`.""" + id: Optional[str] = None + """The unique ID of this compaction trigger.""" + class ItemReference(BaseModel): """An internal identifier for an item to reference.""" diff --git a/src/openai/types/responses/response_input_item_param.py b/src/openai/types/responses/response_input_item_param.py index 98382175ae..f1469057a9 100644 --- a/src/openai/types/responses/response_input_item_param.py +++ b/src/openai/types/responses/response_input_item_param.py @@ -722,6 +722,9 @@ class CompactionTrigger(TypedDict, total=False): type: Required[Literal["compaction_trigger"]] """The type of the item. Always `compaction_trigger`.""" + id: Optional[str] + """The unique ID of this compaction trigger.""" + class ItemReference(TypedDict, total=False): """An internal identifier for an item to reference.""" diff --git a/src/openai/types/responses/response_input_param.py b/src/openai/types/responses/response_input_param.py index 50d9f73561..efcdb3c7fa 100644 --- a/src/openai/types/responses/response_input_param.py +++ b/src/openai/types/responses/response_input_param.py @@ -723,6 +723,9 @@ class CompactionTrigger(TypedDict, total=False): type: Required[Literal["compaction_trigger"]] """The type of the item. Always `compaction_trigger`.""" + id: Optional[str] + """The unique ID of this compaction trigger.""" + class ItemReference(TypedDict, total=False): """An internal identifier for an item to reference.""" diff --git a/tests/test_compaction_trigger_ids.py b/tests/test_compaction_trigger_ids.py new file mode 100644 index 0000000000..a6b4112c32 --- /dev/null +++ b/tests/test_compaction_trigger_ids.py @@ -0,0 +1,130 @@ +from __future__ import annotations + +import json +from typing import Any + +import httpx2 +import pytest + +from openai import OpenAI, AsyncOpenAI +from openai.types.beta.beta_response_input_item import CompactionTrigger as BetaCompactionTrigger +from openai.types.beta.beta_response_input_item_param import CompactionTrigger as BetaCompactionTriggerParam +from openai.types.responses.response_input_item_param import CompactionTrigger + + +@pytest.mark.parametrize("beta", [False, True]) +@pytest.mark.parametrize("fields", [{}, {"id": None}, {"id": ""}, {"id": "msg_transport_compat"}]) +def test_compaction_trigger_ids_cross_transport(beta: bool, fields: dict[str, Any]) -> None: + trigger: dict[str, Any] = {"type": "compaction_trigger", **fields} + if beta: + trigger["agent"] = {"agent_name": "assistant"} + calls: list[httpx2.Request] = [] + + def handle(request: httpx2.Request) -> httpx2.Response: + calls.append(request) + assert request.url.path == "/v1/responses/resp_compat" + return httpx2.Response( + 200, + json={"id": "resp_compat", "object": "response", "instructions": [trigger], "output": []}, + ) + + with OpenAI( + api_key="synthetic-key", + base_url="https://example.invalid/v1", + max_retries=0, + http_client=httpx2.Client(transport=httpx2.MockTransport(handle)), + ) as client: + result = client.beta.responses.retrieve("resp_compat") if beta else client.responses.retrieve("resp_compat") + assert isinstance(result.instructions, list) + item = result.instructions[0] + assert item.type == "compaction_trigger" + assert item.id == fields.get("id") + assert ("id" in item.model_fields_set) == ("id" in fields) + if beta: + assert isinstance(item, BetaCompactionTrigger) + assert item.agent is not None + assert item.agent.agent_name == "assistant" + assert len(calls) == 1 + assert calls[0].method == "GET" + + +@pytest.mark.parametrize("beta", [False, True]) +@pytest.mark.parametrize("fields", [{}, {"id": None}, {"id": ""}, {"id": "msg_request_compat"}]) +def test_compaction_trigger_request_compatibility(beta: bool, fields: dict[str, Any]) -> None: + # Existing callers can still construct a trigger with only its discriminator. + legacy: CompactionTrigger = {"type": "compaction_trigger"} + trigger: BetaCompactionTriggerParam = {**legacy} + if "id" in fields: + trigger["id"] = fields["id"] + if beta: + trigger["agent"] = {"agent_name": "assistant"} + bodies: list[dict[str, Any]] = [] + + def handle(request: httpx2.Request) -> httpx2.Response: + assert request.method == "POST" + assert request.url.path == "/v1/responses" + bodies.append(json.loads(request.content)) + return httpx2.Response(200, json={"id": "resp_compat", "object": "response", "output": []}) + + with OpenAI( + api_key="synthetic-key", + base_url="https://example.invalid/v1", + max_retries=0, + http_client=httpx2.Client(transport=httpx2.MockTransport(handle)), + ) as client: + if beta: + client.beta.responses.create(model="gpt-4o", input=[trigger]) + else: + client.responses.create(model="gpt-4o", input=[trigger]) + assert len(bodies) == 1 + assert bodies[0]["input"] == [trigger] + + +@pytest.mark.parametrize("beta", [False, True]) +@pytest.mark.parametrize("fields", [{}, {"id": None}, {"id": ""}, {"id": "msg_transport_compat"}]) +async def test_async_compaction_trigger_transport(beta: bool, fields: dict[str, Any]) -> None: + trigger: BetaCompactionTriggerParam = {"type": "compaction_trigger"} + if "id" in fields: + trigger["id"] = fields["id"] + if beta: + trigger["agent"] = {"agent_name": "assistant"} + methods: list[str] = [] + + def handle(request: httpx2.Request) -> httpx2.Response: + methods.append(request.method) + assert request.url.params.get("beta") == ("true" if beta else None) + if request.method == "POST": + assert request.url.path == "/v1/responses" + assert json.loads(request.content)["input"] == [trigger] + else: + assert request.method == "GET" + assert request.url.path == "/v1/responses/resp_compat" + return httpx2.Response( + 200, + json={"id": "resp_compat", "object": "response", "instructions": [trigger], "output": []}, + ) + + async with AsyncOpenAI( + api_key="synthetic-key", + base_url="https://example.invalid/v1", + max_retries=0, + http_client=httpx2.AsyncClient(transport=httpx2.MockTransport(handle)), + ) as client: + result = ( + await client.beta.responses.retrieve("resp_compat") + if beta + else await client.responses.retrieve("resp_compat") + ) + assert isinstance(result.instructions, list) + item = result.instructions[0] + assert item.type == "compaction_trigger" + assert item.id == fields.get("id") + assert ("id" in item.model_fields_set) == ("id" in fields) + if beta: + assert isinstance(item, BetaCompactionTrigger) + assert item.agent is not None + assert item.agent.agent_name == "assistant" + await client.beta.responses.create(model="gpt-4o", input=[trigger]) + else: + await client.responses.create(model="gpt-4o", input=[trigger]) + assert methods == ["GET", "POST"]