From f90d62f83e7dc80d1a94c090724ca3a7c285e3e2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 21:52:40 +0000 Subject: [PATCH 1/4] feat(client): add support for aiohttp --- pyproject.toml | 2 + requirements-dev.lock | 27 +++++++++++++ requirements.lock | 27 +++++++++++++ src/codex/__init__.py | 3 +- src/codex/_base_client.py | 22 +++++++++++ .../billing/test_card_details.py | 4 +- .../billing/test_plan_details.py | 4 +- .../billing/test_setup_intent.py | 4 +- .../organizations/test_billing.py | 4 +- .../projects/test_access_keys.py | 4 +- tests/api_resources/projects/test_clusters.py | 4 +- tests/api_resources/projects/test_entries.py | 4 +- tests/api_resources/projects/test_evals.py | 4 +- .../api_resources/projects/test_query_logs.py | 4 +- .../projects/test_remediations.py | 4 +- tests/api_resources/test_health.py | 4 +- tests/api_resources/test_organizations.py | 4 +- tests/api_resources/test_projects.py | 4 +- tests/api_resources/test_tlm.py | 4 +- tests/api_resources/test_users.py | 4 +- .../users/myself/test_api_key.py | 4 +- .../users/myself/test_organizations.py | 4 +- tests/api_resources/users/test_myself.py | 4 +- .../api_resources/users/test_verification.py | 4 +- tests/conftest.py | 39 ++++++++++++++++--- 25 files changed, 171 insertions(+), 25 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 088289dc..5fb6cb07 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,6 +37,8 @@ classifiers = [ Homepage = "https://github.com/cleanlab/codex-python" Repository = "https://github.com/cleanlab/codex-python" +[project.optional-dependencies] +aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.6"] [tool.rye] managed = true diff --git a/requirements-dev.lock b/requirements-dev.lock index 9e127b74..11a27038 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -10,6 +10,13 @@ # universal: false -e file:. +aiohappyeyeballs==2.6.1 + # via aiohttp +aiohttp==3.12.8 + # via codex-sdk + # via httpx-aiohttp +aiosignal==1.3.2 + # via aiohttp annotated-types==0.6.0 # via pydantic anyio==4.4.0 @@ -17,6 +24,10 @@ anyio==4.4.0 # via httpx argcomplete==3.1.2 # via nox +async-timeout==5.0.1 + # via aiohttp +attrs==25.3.0 + # via aiohttp certifi==2023.7.22 # via httpcore # via httpx @@ -34,16 +45,23 @@ execnet==2.1.1 # via pytest-xdist filelock==3.12.4 # via virtualenv +frozenlist==1.6.2 + # via aiohttp + # via aiosignal h11==0.14.0 # via httpcore httpcore==1.0.2 # via httpx httpx==0.28.1 # via codex-sdk + # via httpx-aiohttp # via respx +httpx-aiohttp==0.1.6 + # via codex-sdk idna==3.4 # via anyio # via httpx + # via yarl importlib-metadata==7.0.0 iniconfig==2.0.0 # via pytest @@ -51,6 +69,9 @@ markdown-it-py==3.0.0 # via rich mdurl==0.1.2 # via markdown-it-py +multidict==6.4.4 + # via aiohttp + # via yarl mypy==1.14.1 mypy-extensions==1.0.0 # via mypy @@ -65,6 +86,9 @@ platformdirs==3.11.0 # via virtualenv pluggy==1.5.0 # via pytest +propcache==0.3.1 + # via aiohttp + # via yarl pydantic==2.10.3 # via codex-sdk pydantic-core==2.27.1 @@ -98,11 +122,14 @@ tomli==2.0.2 typing-extensions==4.12.2 # via anyio # via codex-sdk + # via multidict # via mypy # via pydantic # via pydantic-core # via pyright virtualenv==20.24.5 # via nox +yarl==1.20.0 + # via aiohttp zipp==3.17.0 # via importlib-metadata diff --git a/requirements.lock b/requirements.lock index 1f6c5f7f..5eda9d9c 100644 --- a/requirements.lock +++ b/requirements.lock @@ -10,11 +10,22 @@ # universal: false -e file:. +aiohappyeyeballs==2.6.1 + # via aiohttp +aiohttp==3.12.8 + # via codex-sdk + # via httpx-aiohttp +aiosignal==1.3.2 + # via aiohttp annotated-types==0.6.0 # via pydantic anyio==4.4.0 # via codex-sdk # via httpx +async-timeout==5.0.1 + # via aiohttp +attrs==25.3.0 + # via aiohttp certifi==2023.7.22 # via httpcore # via httpx @@ -22,15 +33,28 @@ distro==1.8.0 # via codex-sdk exceptiongroup==1.2.2 # via anyio +frozenlist==1.6.2 + # via aiohttp + # via aiosignal h11==0.14.0 # via httpcore httpcore==1.0.2 # via httpx httpx==0.28.1 # via codex-sdk + # via httpx-aiohttp +httpx-aiohttp==0.1.6 + # via codex-sdk idna==3.4 # via anyio # via httpx + # via yarl +multidict==6.4.4 + # via aiohttp + # via yarl +propcache==0.3.1 + # via aiohttp + # via yarl pydantic==2.10.3 # via codex-sdk pydantic-core==2.27.1 @@ -41,5 +65,8 @@ sniffio==1.3.0 typing-extensions==4.12.2 # via anyio # via codex-sdk + # via multidict # via pydantic # via pydantic-core +yarl==1.20.0 + # via aiohttp diff --git a/src/codex/__init__.py b/src/codex/__init__.py index 5c5f678c..2b07cd12 100644 --- a/src/codex/__init__.py +++ b/src/codex/__init__.py @@ -37,7 +37,7 @@ UnprocessableEntityError, APIResponseValidationError, ) -from ._base_client import DefaultHttpxClient, DefaultAsyncHttpxClient +from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient from ._utils._logs import setup_logging as _setup_logging __all__ = [ @@ -80,6 +80,7 @@ "DEFAULT_CONNECTION_LIMITS", "DefaultHttpxClient", "DefaultAsyncHttpxClient", + "DefaultAioHttpClient", ] if not _t.TYPE_CHECKING: diff --git a/src/codex/_base_client.py b/src/codex/_base_client.py index 6ef7dd5f..1eca89e0 100644 --- a/src/codex/_base_client.py +++ b/src/codex/_base_client.py @@ -1289,6 +1289,24 @@ def __init__(self, **kwargs: Any) -> None: super().__init__(**kwargs) +try: + import httpx_aiohttp +except ImportError: + + class _DefaultAioHttpClient(httpx.AsyncClient): + def __init__(self, **_kwargs: Any) -> None: + raise RuntimeError("To use the aiohttp client you must have installed the package with the `aiohttp` extra") +else: + + class _DefaultAioHttpClient(httpx_aiohttp.HttpxAiohttpClient): # type: ignore + def __init__(self, **kwargs: Any) -> None: + kwargs.setdefault("timeout", DEFAULT_TIMEOUT) + kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) + kwargs.setdefault("follow_redirects", True) + + super().__init__(**kwargs) + + if TYPE_CHECKING: DefaultAsyncHttpxClient = httpx.AsyncClient """An alias to `httpx.AsyncClient` that provides the same defaults that this SDK @@ -1297,8 +1315,12 @@ def __init__(self, **kwargs: Any) -> None: This is useful because overriding the `http_client` with your own instance of `httpx.AsyncClient` will result in httpx's defaults being used, not ours. """ + + DefaultAioHttpClient = httpx.AsyncClient + """An alias to `httpx.AsyncClient` that changes the default HTTP transport to `aiohttp`.""" else: DefaultAsyncHttpxClient = _DefaultAsyncHttpxClient + DefaultAioHttpClient = _DefaultAioHttpClient class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient): diff --git a/tests/api_resources/organizations/billing/test_card_details.py b/tests/api_resources/organizations/billing/test_card_details.py index 2fb71fc5..3a034833 100644 --- a/tests/api_resources/organizations/billing/test_card_details.py +++ b/tests/api_resources/organizations/billing/test_card_details.py @@ -61,7 +61,9 @@ def test_path_params_retrieve(self, client: Codex) -> None: class TestAsyncCardDetails: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip() @parametrize diff --git a/tests/api_resources/organizations/billing/test_plan_details.py b/tests/api_resources/organizations/billing/test_plan_details.py index 2fc1b810..76d9732e 100644 --- a/tests/api_resources/organizations/billing/test_plan_details.py +++ b/tests/api_resources/organizations/billing/test_plan_details.py @@ -61,7 +61,9 @@ def test_path_params_retrieve(self, client: Codex) -> None: class TestAsyncPlanDetails: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip() @parametrize diff --git a/tests/api_resources/organizations/billing/test_setup_intent.py b/tests/api_resources/organizations/billing/test_setup_intent.py index 3eb05fbc..49d80b0d 100644 --- a/tests/api_resources/organizations/billing/test_setup_intent.py +++ b/tests/api_resources/organizations/billing/test_setup_intent.py @@ -61,7 +61,9 @@ def test_path_params_create(self, client: Codex) -> None: class TestAsyncSetupIntent: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip() @parametrize diff --git a/tests/api_resources/organizations/test_billing.py b/tests/api_resources/organizations/test_billing.py index e3bb1d1d..237562b5 100644 --- a/tests/api_resources/organizations/test_billing.py +++ b/tests/api_resources/organizations/test_billing.py @@ -103,7 +103,9 @@ def test_path_params_usage(self, client: Codex) -> None: class TestAsyncBilling: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip() @parametrize diff --git a/tests/api_resources/projects/test_access_keys.py b/tests/api_resources/projects/test_access_keys.py index ad4ee5e4..c3bc1785 100644 --- a/tests/api_resources/projects/test_access_keys.py +++ b/tests/api_resources/projects/test_access_keys.py @@ -380,7 +380,9 @@ def test_path_params_revoke(self, client: Codex) -> None: class TestAsyncAccessKeys: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip() @parametrize diff --git a/tests/api_resources/projects/test_clusters.py b/tests/api_resources/projects/test_clusters.py index 496236f8..87734277 100644 --- a/tests/api_resources/projects/test_clusters.py +++ b/tests/api_resources/projects/test_clusters.py @@ -131,7 +131,9 @@ def test_path_params_list_variants(self, client: Codex) -> None: class TestAsyncClusters: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip() @parametrize diff --git a/tests/api_resources/projects/test_entries.py b/tests/api_resources/projects/test_entries.py index eb6fd372..1b077d10 100644 --- a/tests/api_resources/projects/test_entries.py +++ b/tests/api_resources/projects/test_entries.py @@ -517,7 +517,9 @@ def test_path_params_unpublish_answer(self, client: Codex) -> None: class TestAsyncEntries: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip() @parametrize diff --git a/tests/api_resources/projects/test_evals.py b/tests/api_resources/projects/test_evals.py index c16fbc37..1fd4216f 100644 --- a/tests/api_resources/projects/test_evals.py +++ b/tests/api_resources/projects/test_evals.py @@ -348,7 +348,9 @@ def test_path_params_delete(self, client: Codex) -> None: class TestAsyncEvals: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip() @parametrize diff --git a/tests/api_resources/projects/test_query_logs.py b/tests/api_resources/projects/test_query_logs.py index 847af5df..d75dcabe 100644 --- a/tests/api_resources/projects/test_query_logs.py +++ b/tests/api_resources/projects/test_query_logs.py @@ -308,7 +308,9 @@ def test_path_params_start_remediation(self, client: Codex) -> None: class TestAsyncQueryLogs: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip() @parametrize diff --git a/tests/api_resources/projects/test_remediations.py b/tests/api_resources/projects/test_remediations.py index cfd5ae76..c75a255c 100644 --- a/tests/api_resources/projects/test_remediations.py +++ b/tests/api_resources/projects/test_remediations.py @@ -626,7 +626,9 @@ def test_path_params_unpause(self, client: Codex) -> None: class TestAsyncRemediations: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip() @parametrize diff --git a/tests/api_resources/test_health.py b/tests/api_resources/test_health.py index ed942cd2..92db3a81 100644 --- a/tests/api_resources/test_health.py +++ b/tests/api_resources/test_health.py @@ -75,7 +75,9 @@ def test_streaming_response_db(self, client: Codex) -> None: class TestAsyncHealth: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip() @parametrize diff --git a/tests/api_resources/test_organizations.py b/tests/api_resources/test_organizations.py index c665e85c..eecdf3f7 100644 --- a/tests/api_resources/test_organizations.py +++ b/tests/api_resources/test_organizations.py @@ -149,7 +149,9 @@ def test_path_params_retrieve_permissions(self, client: Codex) -> None: class TestAsyncOrganizations: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip() @parametrize diff --git a/tests/api_resources/test_projects.py b/tests/api_resources/test_projects.py index 86bd8053..6c95f273 100644 --- a/tests/api_resources/test_projects.py +++ b/tests/api_resources/test_projects.py @@ -723,7 +723,9 @@ def test_path_params_validate(self, client: Codex) -> None: class TestAsyncProjects: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip() @parametrize diff --git a/tests/api_resources/test_tlm.py b/tests/api_resources/test_tlm.py index 32d5a67f..41376a46 100644 --- a/tests/api_resources/test_tlm.py +++ b/tests/api_resources/test_tlm.py @@ -135,7 +135,9 @@ def test_streaming_response_score(self, client: Codex) -> None: class TestAsyncTlm: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip() @parametrize diff --git a/tests/api_resources/test_users.py b/tests/api_resources/test_users.py index 101d0f66..661ee559 100644 --- a/tests/api_resources/test_users.py +++ b/tests/api_resources/test_users.py @@ -71,7 +71,9 @@ def test_streaming_response_activate_account(self, client: Codex) -> None: class TestAsyncUsers: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip() @parametrize diff --git a/tests/api_resources/users/myself/test_api_key.py b/tests/api_resources/users/myself/test_api_key.py index c6ed0209..f0a7ccf7 100644 --- a/tests/api_resources/users/myself/test_api_key.py +++ b/tests/api_resources/users/myself/test_api_key.py @@ -75,7 +75,9 @@ def test_streaming_response_refresh(self, client: Codex) -> None: class TestAsyncAPIKey: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip() @parametrize diff --git a/tests/api_resources/users/myself/test_organizations.py b/tests/api_resources/users/myself/test_organizations.py index 9f35f7c6..fd377ea0 100644 --- a/tests/api_resources/users/myself/test_organizations.py +++ b/tests/api_resources/users/myself/test_organizations.py @@ -47,7 +47,9 @@ def test_streaming_response_list(self, client: Codex) -> None: class TestAsyncOrganizations: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip() @parametrize diff --git a/tests/api_resources/users/test_myself.py b/tests/api_resources/users/test_myself.py index 63123275..1c56b0be 100644 --- a/tests/api_resources/users/test_myself.py +++ b/tests/api_resources/users/test_myself.py @@ -47,7 +47,9 @@ def test_streaming_response_retrieve(self, client: Codex) -> None: class TestAsyncMyself: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip() @parametrize diff --git a/tests/api_resources/users/test_verification.py b/tests/api_resources/users/test_verification.py index 8332327e..fbf6b667 100644 --- a/tests/api_resources/users/test_verification.py +++ b/tests/api_resources/users/test_verification.py @@ -47,7 +47,9 @@ def test_streaming_response_resend(self, client: Codex) -> None: class TestAsyncVerification: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip() @parametrize diff --git a/tests/conftest.py b/tests/conftest.py index 05c77729..3472c36d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -6,10 +6,12 @@ import logging from typing import TYPE_CHECKING, Iterator, AsyncIterator +import httpx import pytest from pytest_asyncio import is_async_test -from codex import Codex, AsyncCodex +from codex import Codex, AsyncCodex, DefaultAioHttpClient +from codex._utils import is_dict if TYPE_CHECKING: from _pytest.fixtures import FixtureRequest # pyright: ignore[reportPrivateImportUsage] @@ -27,6 +29,19 @@ def pytest_collection_modifyitems(items: list[pytest.Function]) -> None: for async_test in pytest_asyncio_tests: async_test.add_marker(session_scope_marker, append=False) + # We skip tests that use both the aiohttp client and respx_mock as respx_mock + # doesn't support custom transports. + for item in items: + if "async_client" not in item.fixturenames or "respx_mock" not in item.fixturenames: + continue + + if not hasattr(item, "callspec"): + continue + + async_client_param = item.callspec.params.get("async_client") + if is_dict(async_client_param) and async_client_param.get("http_client") == "aiohttp": + item.add_marker(pytest.mark.skip(reason="aiohttp client is not compatible with respx_mock")) + base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -43,9 +58,23 @@ def client(request: FixtureRequest) -> Iterator[Codex]: @pytest.fixture(scope="session") async def async_client(request: FixtureRequest) -> AsyncIterator[AsyncCodex]: - strict = getattr(request, "param", True) - if not isinstance(strict, bool): - raise TypeError(f"Unexpected fixture parameter type {type(strict)}, expected {bool}") + param = getattr(request, "param", True) + + # defaults + strict = True + http_client: None | httpx.AsyncClient = None + + if isinstance(param, bool): + strict = param + elif is_dict(param): + strict = param.get("strict", True) + assert isinstance(strict, bool) + + http_client_type = param.get("http_client", "httpx") + if http_client_type == "aiohttp": + http_client = DefaultAioHttpClient() + else: + raise TypeError(f"Unexpected fixture parameter type {type(param)}, expected bool or dict") - async with AsyncCodex(base_url=base_url, _strict_response_validation=strict) as client: + async with AsyncCodex(base_url=base_url, _strict_response_validation=strict, http_client=http_client) as client: yield client From aea4c5ce68120a12fe8248c4611b5b336f36ab0f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 04:11:04 +0000 Subject: [PATCH 2/4] chore(tests): skip some failing tests on the latest python versions --- tests/test_client.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_client.py b/tests/test_client.py index 9cf7e943..c012f4d5 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -182,6 +182,7 @@ def test_copy_signature(self) -> None: copy_param = copy_signature.parameters.get(name) assert copy_param is not None, f"copy() signature is missing the {name} param" + @pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12") def test_copy_build_request(self) -> None: options = FinalRequestOptions(method="get", url="/foo") @@ -965,6 +966,7 @@ def test_copy_signature(self) -> None: copy_param = copy_signature.parameters.get(name) assert copy_param is not None, f"copy() signature is missing the {name} param" + @pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12") def test_copy_build_request(self) -> None: options = FinalRequestOptions(method="get", url="/foo") From e9ca3b5ce636b8572f168ed8d2c82d416f22b823 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 17:17:38 +0000 Subject: [PATCH 3/4] feat(api): api update --- .stats.yml | 2 +- src/codex/resources/projects/evals.py | 48 ++++++++++++++----- src/codex/types/project_create_params.py | 42 +++++++++++----- src/codex/types/project_list_response.py | 42 +++++++++++----- src/codex/types/project_retrieve_response.py | 42 +++++++++++----- src/codex/types/project_return_schema.py | 42 +++++++++++----- src/codex/types/project_update_params.py | 42 +++++++++++----- src/codex/types/project_validate_response.py | 23 ++++++++- .../types/projects/eval_create_params.py | 7 ++- .../types/projects/eval_list_response.py | 7 ++- .../types/projects/eval_update_params.py | 14 ++++-- .../query_log_list_by_group_response.py | 7 ++- .../query_log_list_groups_response.py | 11 ++++- .../types/projects/query_log_list_response.py | 7 ++- .../projects/query_log_retrieve_response.py | 7 ++- .../query_log_start_remediation_response.py | 4 +- .../projects/remediation_create_response.py | 4 +- .../remediation_edit_answer_response.py | 4 +- .../remediation_edit_draft_answer_response.py | 4 +- ...iation_get_resolved_logs_count_response.py | 4 +- ...remediation_list_resolved_logs_response.py | 7 ++- .../projects/remediation_list_response.py | 4 +- .../projects/remediation_pause_response.py | 4 +- .../projects/remediation_publish_response.py | 4 +- .../projects/remediation_retrieve_response.py | 4 +- .../projects/remediation_unpause_response.py | 4 +- tests/api_resources/projects/test_evals.py | 6 +++ tests/api_resources/test_projects.py | 24 ++++++++++ 28 files changed, 321 insertions(+), 99 deletions(-) diff --git a/.stats.yml b/.stats.yml index 20dc969f..04c13865 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,3 +1,3 @@ configured_endpoints: 65 -openapi_spec_hash: eeb8ebc5600523bdfad046381a929572 +openapi_spec_hash: 80696dc202de8bacc0e43506d7c210b0 config_hash: 14b2643a0ec60cf326dfed00939644ff diff --git a/src/codex/resources/projects/evals.py b/src/codex/resources/projects/evals.py index 1a6a6876..1fc95890 100644 --- a/src/codex/resources/projects/evals.py +++ b/src/codex/resources/projects/evals.py @@ -59,6 +59,7 @@ def create( query_identifier: Optional[str] | NotGiven = NOT_GIVEN, response_identifier: Optional[str] | NotGiven = NOT_GIVEN, should_escalate: bool | NotGiven = NOT_GIVEN, + should_guardrail: bool | NotGiven = NOT_GIVEN, threshold: float | NotGiven = NOT_GIVEN, threshold_direction: Literal["above", "below"] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -95,8 +96,10 @@ def create( response_identifier: The exact string used in your evaluation criteria to reference the RAG/LLM response. - should_escalate: If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + should_escalate: If true, failing this eval means the question should be escalated to Codex for + an SME to review + + should_guardrail: If true, failing this eval means the response should be guardrailed threshold: Threshold value that determines if the evaluation fails @@ -126,6 +129,7 @@ def create( "query_identifier": query_identifier, "response_identifier": response_identifier, "should_escalate": should_escalate, + "should_guardrail": should_guardrail, "threshold": threshold, "threshold_direction": threshold_direction, }, @@ -153,6 +157,7 @@ def update( query_identifier: Optional[str] | NotGiven = NOT_GIVEN, response_identifier: Optional[str] | NotGiven = NOT_GIVEN, should_escalate: bool | NotGiven = NOT_GIVEN, + should_guardrail: bool | NotGiven = NOT_GIVEN, threshold: float | NotGiven = NOT_GIVEN, threshold_direction: Literal["above", "below"] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -189,8 +194,10 @@ def update( response_identifier: The exact string used in your evaluation criteria to reference the RAG/LLM response. - should_escalate: If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + should_escalate: If true, failing this eval means the question should be escalated to Codex for + an SME to review + + should_guardrail: If true, failing this eval means the response should be guardrailed threshold: Threshold value that determines if the evaluation fails @@ -216,6 +223,7 @@ def update( enabled: bool | NotGiven = NOT_GIVEN, priority: Optional[int] | NotGiven = NOT_GIVEN, should_escalate: bool | NotGiven = NOT_GIVEN, + should_guardrail: bool | NotGiven = NOT_GIVEN, threshold: float | NotGiven = NOT_GIVEN, threshold_direction: Literal["above", "below"] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -237,8 +245,10 @@ def update( priority: Priority order for evals (lower number = higher priority) to determine primary eval issue to surface - should_escalate: If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + should_escalate: If true, failing this eval means the question should be escalated to Codex for + an SME to review + + should_guardrail: If true, failing this eval means the response should be guardrailed threshold: Threshold value that determines if the evaluation fails @@ -270,6 +280,7 @@ def update( query_identifier: Optional[str] | NotGiven = NOT_GIVEN, response_identifier: Optional[str] | NotGiven = NOT_GIVEN, should_escalate: bool | NotGiven = NOT_GIVEN, + should_guardrail: bool | NotGiven = NOT_GIVEN, threshold: float | NotGiven = NOT_GIVEN, threshold_direction: Literal["above", "below"] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -297,6 +308,7 @@ def update( "query_identifier": query_identifier, "response_identifier": response_identifier, "should_escalate": should_escalate, + "should_guardrail": should_guardrail, "threshold": threshold, "threshold_direction": threshold_direction, }, @@ -412,6 +424,7 @@ async def create( query_identifier: Optional[str] | NotGiven = NOT_GIVEN, response_identifier: Optional[str] | NotGiven = NOT_GIVEN, should_escalate: bool | NotGiven = NOT_GIVEN, + should_guardrail: bool | NotGiven = NOT_GIVEN, threshold: float | NotGiven = NOT_GIVEN, threshold_direction: Literal["above", "below"] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -448,8 +461,10 @@ async def create( response_identifier: The exact string used in your evaluation criteria to reference the RAG/LLM response. - should_escalate: If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + should_escalate: If true, failing this eval means the question should be escalated to Codex for + an SME to review + + should_guardrail: If true, failing this eval means the response should be guardrailed threshold: Threshold value that determines if the evaluation fails @@ -479,6 +494,7 @@ async def create( "query_identifier": query_identifier, "response_identifier": response_identifier, "should_escalate": should_escalate, + "should_guardrail": should_guardrail, "threshold": threshold, "threshold_direction": threshold_direction, }, @@ -506,6 +522,7 @@ async def update( query_identifier: Optional[str] | NotGiven = NOT_GIVEN, response_identifier: Optional[str] | NotGiven = NOT_GIVEN, should_escalate: bool | NotGiven = NOT_GIVEN, + should_guardrail: bool | NotGiven = NOT_GIVEN, threshold: float | NotGiven = NOT_GIVEN, threshold_direction: Literal["above", "below"] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -542,8 +559,10 @@ async def update( response_identifier: The exact string used in your evaluation criteria to reference the RAG/LLM response. - should_escalate: If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + should_escalate: If true, failing this eval means the question should be escalated to Codex for + an SME to review + + should_guardrail: If true, failing this eval means the response should be guardrailed threshold: Threshold value that determines if the evaluation fails @@ -569,6 +588,7 @@ async def update( enabled: bool | NotGiven = NOT_GIVEN, priority: Optional[int] | NotGiven = NOT_GIVEN, should_escalate: bool | NotGiven = NOT_GIVEN, + should_guardrail: bool | NotGiven = NOT_GIVEN, threshold: float | NotGiven = NOT_GIVEN, threshold_direction: Literal["above", "below"] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -590,8 +610,10 @@ async def update( priority: Priority order for evals (lower number = higher priority) to determine primary eval issue to surface - should_escalate: If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + should_escalate: If true, failing this eval means the question should be escalated to Codex for + an SME to review + + should_guardrail: If true, failing this eval means the response should be guardrailed threshold: Threshold value that determines if the evaluation fails @@ -623,6 +645,7 @@ async def update( query_identifier: Optional[str] | NotGiven = NOT_GIVEN, response_identifier: Optional[str] | NotGiven = NOT_GIVEN, should_escalate: bool | NotGiven = NOT_GIVEN, + should_guardrail: bool | NotGiven = NOT_GIVEN, threshold: float | NotGiven = NOT_GIVEN, threshold_direction: Literal["above", "below"] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -650,6 +673,7 @@ async def update( "query_identifier": query_identifier, "response_identifier": response_identifier, "should_escalate": should_escalate, + "should_guardrail": should_guardrail, "threshold": threshold, "threshold_direction": threshold_direction, }, diff --git a/src/codex/types/project_create_params.py b/src/codex/types/project_create_params.py index 4d9d31f5..a8369782 100644 --- a/src/codex/types/project_create_params.py +++ b/src/codex/types/project_create_params.py @@ -79,10 +79,13 @@ class ConfigEvalConfigCustomEvalsEvals(TypedDict, total=False): should_escalate: bool """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: bool + """If true, failing this eval means the response should be guardrailed""" + threshold: float """Threshold value that determines if the evaluation fails""" @@ -115,10 +118,13 @@ class ConfigEvalConfigDefaultEvalsContextSufficiency(TypedDict, total=False): should_escalate: bool """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: bool + """If true, failing this eval means the response should be guardrailed""" + threshold: float """Threshold value that determines if the evaluation fails""" @@ -147,10 +153,13 @@ class ConfigEvalConfigDefaultEvalsQueryEase(TypedDict, total=False): should_escalate: bool """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: bool + """If true, failing this eval means the response should be guardrailed""" + threshold: float """Threshold value that determines if the evaluation fails""" @@ -179,10 +188,13 @@ class ConfigEvalConfigDefaultEvalsResponseGroundedness(TypedDict, total=False): should_escalate: bool """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: bool + """If true, failing this eval means the response should be guardrailed""" + threshold: float """Threshold value that determines if the evaluation fails""" @@ -211,10 +223,13 @@ class ConfigEvalConfigDefaultEvalsResponseHelpfulness(TypedDict, total=False): should_escalate: bool """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: bool + """If true, failing this eval means the response should be guardrailed""" + threshold: float """Threshold value that determines if the evaluation fails""" @@ -243,10 +258,13 @@ class ConfigEvalConfigDefaultEvalsTrustworthiness(TypedDict, total=False): should_escalate: bool """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: bool + """If true, failing this eval means the response should be guardrailed""" + threshold: float """Threshold value that determines if the evaluation fails""" diff --git a/src/codex/types/project_list_response.py b/src/codex/types/project_list_response.py index a7df3f38..c39bf086 100644 --- a/src/codex/types/project_list_response.py +++ b/src/codex/types/project_list_response.py @@ -69,10 +69,13 @@ class ProjectConfigEvalConfigCustomEvalsEvals(BaseModel): should_escalate: Optional[bool] = None """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: Optional[bool] = None + """If true, failing this eval means the response should be guardrailed""" + threshold: Optional[float] = None """Threshold value that determines if the evaluation fails""" @@ -105,10 +108,13 @@ class ProjectConfigEvalConfigDefaultEvalsContextSufficiency(BaseModel): should_escalate: Optional[bool] = None """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: Optional[bool] = None + """If true, failing this eval means the response should be guardrailed""" + threshold: Optional[float] = None """Threshold value that determines if the evaluation fails""" @@ -137,10 +143,13 @@ class ProjectConfigEvalConfigDefaultEvalsQueryEase(BaseModel): should_escalate: Optional[bool] = None """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: Optional[bool] = None + """If true, failing this eval means the response should be guardrailed""" + threshold: Optional[float] = None """Threshold value that determines if the evaluation fails""" @@ -169,10 +178,13 @@ class ProjectConfigEvalConfigDefaultEvalsResponseGroundedness(BaseModel): should_escalate: Optional[bool] = None """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: Optional[bool] = None + """If true, failing this eval means the response should be guardrailed""" + threshold: Optional[float] = None """Threshold value that determines if the evaluation fails""" @@ -201,10 +213,13 @@ class ProjectConfigEvalConfigDefaultEvalsResponseHelpfulness(BaseModel): should_escalate: Optional[bool] = None """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: Optional[bool] = None + """If true, failing this eval means the response should be guardrailed""" + threshold: Optional[float] = None """Threshold value that determines if the evaluation fails""" @@ -233,10 +248,13 @@ class ProjectConfigEvalConfigDefaultEvalsTrustworthiness(BaseModel): should_escalate: Optional[bool] = None """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: Optional[bool] = None + """If true, failing this eval means the response should be guardrailed""" + threshold: Optional[float] = None """Threshold value that determines if the evaluation fails""" diff --git a/src/codex/types/project_retrieve_response.py b/src/codex/types/project_retrieve_response.py index 53624096..7d1f8edd 100644 --- a/src/codex/types/project_retrieve_response.py +++ b/src/codex/types/project_retrieve_response.py @@ -68,10 +68,13 @@ class ConfigEvalConfigCustomEvalsEvals(BaseModel): should_escalate: Optional[bool] = None """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: Optional[bool] = None + """If true, failing this eval means the response should be guardrailed""" + threshold: Optional[float] = None """Threshold value that determines if the evaluation fails""" @@ -104,10 +107,13 @@ class ConfigEvalConfigDefaultEvalsContextSufficiency(BaseModel): should_escalate: Optional[bool] = None """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: Optional[bool] = None + """If true, failing this eval means the response should be guardrailed""" + threshold: Optional[float] = None """Threshold value that determines if the evaluation fails""" @@ -136,10 +142,13 @@ class ConfigEvalConfigDefaultEvalsQueryEase(BaseModel): should_escalate: Optional[bool] = None """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: Optional[bool] = None + """If true, failing this eval means the response should be guardrailed""" + threshold: Optional[float] = None """Threshold value that determines if the evaluation fails""" @@ -168,10 +177,13 @@ class ConfigEvalConfigDefaultEvalsResponseGroundedness(BaseModel): should_escalate: Optional[bool] = None """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: Optional[bool] = None + """If true, failing this eval means the response should be guardrailed""" + threshold: Optional[float] = None """Threshold value that determines if the evaluation fails""" @@ -200,10 +212,13 @@ class ConfigEvalConfigDefaultEvalsResponseHelpfulness(BaseModel): should_escalate: Optional[bool] = None """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: Optional[bool] = None + """If true, failing this eval means the response should be guardrailed""" + threshold: Optional[float] = None """Threshold value that determines if the evaluation fails""" @@ -232,10 +247,13 @@ class ConfigEvalConfigDefaultEvalsTrustworthiness(BaseModel): should_escalate: Optional[bool] = None """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: Optional[bool] = None + """If true, failing this eval means the response should be guardrailed""" + threshold: Optional[float] = None """Threshold value that determines if the evaluation fails""" diff --git a/src/codex/types/project_return_schema.py b/src/codex/types/project_return_schema.py index 2ad7433a..170d7994 100644 --- a/src/codex/types/project_return_schema.py +++ b/src/codex/types/project_return_schema.py @@ -68,10 +68,13 @@ class ConfigEvalConfigCustomEvalsEvals(BaseModel): should_escalate: Optional[bool] = None """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: Optional[bool] = None + """If true, failing this eval means the response should be guardrailed""" + threshold: Optional[float] = None """Threshold value that determines if the evaluation fails""" @@ -104,10 +107,13 @@ class ConfigEvalConfigDefaultEvalsContextSufficiency(BaseModel): should_escalate: Optional[bool] = None """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: Optional[bool] = None + """If true, failing this eval means the response should be guardrailed""" + threshold: Optional[float] = None """Threshold value that determines if the evaluation fails""" @@ -136,10 +142,13 @@ class ConfigEvalConfigDefaultEvalsQueryEase(BaseModel): should_escalate: Optional[bool] = None """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: Optional[bool] = None + """If true, failing this eval means the response should be guardrailed""" + threshold: Optional[float] = None """Threshold value that determines if the evaluation fails""" @@ -168,10 +177,13 @@ class ConfigEvalConfigDefaultEvalsResponseGroundedness(BaseModel): should_escalate: Optional[bool] = None """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: Optional[bool] = None + """If true, failing this eval means the response should be guardrailed""" + threshold: Optional[float] = None """Threshold value that determines if the evaluation fails""" @@ -200,10 +212,13 @@ class ConfigEvalConfigDefaultEvalsResponseHelpfulness(BaseModel): should_escalate: Optional[bool] = None """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: Optional[bool] = None + """If true, failing this eval means the response should be guardrailed""" + threshold: Optional[float] = None """Threshold value that determines if the evaluation fails""" @@ -232,10 +247,13 @@ class ConfigEvalConfigDefaultEvalsTrustworthiness(BaseModel): should_escalate: Optional[bool] = None """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: Optional[bool] = None + """If true, failing this eval means the response should be guardrailed""" + threshold: Optional[float] = None """Threshold value that determines if the evaluation fails""" diff --git a/src/codex/types/project_update_params.py b/src/codex/types/project_update_params.py index fc6c52d4..73dad672 100644 --- a/src/codex/types/project_update_params.py +++ b/src/codex/types/project_update_params.py @@ -77,10 +77,13 @@ class ConfigEvalConfigCustomEvalsEvals(TypedDict, total=False): should_escalate: bool """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: bool + """If true, failing this eval means the response should be guardrailed""" + threshold: float """Threshold value that determines if the evaluation fails""" @@ -113,10 +116,13 @@ class ConfigEvalConfigDefaultEvalsContextSufficiency(TypedDict, total=False): should_escalate: bool """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: bool + """If true, failing this eval means the response should be guardrailed""" + threshold: float """Threshold value that determines if the evaluation fails""" @@ -145,10 +151,13 @@ class ConfigEvalConfigDefaultEvalsQueryEase(TypedDict, total=False): should_escalate: bool """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: bool + """If true, failing this eval means the response should be guardrailed""" + threshold: float """Threshold value that determines if the evaluation fails""" @@ -177,10 +186,13 @@ class ConfigEvalConfigDefaultEvalsResponseGroundedness(TypedDict, total=False): should_escalate: bool """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: bool + """If true, failing this eval means the response should be guardrailed""" + threshold: float """Threshold value that determines if the evaluation fails""" @@ -209,10 +221,13 @@ class ConfigEvalConfigDefaultEvalsResponseHelpfulness(TypedDict, total=False): should_escalate: bool """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: bool + """If true, failing this eval means the response should be guardrailed""" + threshold: float """Threshold value that determines if the evaluation fails""" @@ -241,10 +256,13 @@ class ConfigEvalConfigDefaultEvalsTrustworthiness(TypedDict, total=False): should_escalate: bool """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: bool + """If true, failing this eval means the response should be guardrailed""" + threshold: float """Threshold value that determines if the evaluation fails""" diff --git a/src/codex/types/project_validate_response.py b/src/codex/types/project_validate_response.py index a88874da..db65f676 100644 --- a/src/codex/types/project_validate_response.py +++ b/src/codex/types/project_validate_response.py @@ -8,14 +8,27 @@ class EvalScores(BaseModel): - failed: bool - score: Optional[float] = None + triggered: bool + + triggered_escalation: bool + + triggered_guardrail: bool + + failed: Optional[bool] = None + log: Optional[object] = None class ProjectValidateResponse(BaseModel): + escalated_to_sme: bool + """ + True if the question should be escalated to Codex for an SME to review, False + otherwise. When True, a lookup is performed, which logs this query in the + project for SMEs to answer, if it does not already exist. + """ + eval_scores: Dict[str, EvalScores] """ Evaluation scores for the original response along with a boolean flag, `failed`, @@ -34,3 +47,9 @@ class ProjectValidateResponse(BaseModel): When True, a lookup is performed, which logs this query in the project for SMEs to answer, if it does not already exist. """ + + should_guardrail: bool + """ + True if the response should be guardrailed by the AI system, False if the + response is okay to return to the user. + """ diff --git a/src/codex/types/projects/eval_create_params.py b/src/codex/types/projects/eval_create_params.py index 20dcdd3d..aead432e 100644 --- a/src/codex/types/projects/eval_create_params.py +++ b/src/codex/types/projects/eval_create_params.py @@ -55,10 +55,13 @@ class EvalCreateParams(TypedDict, total=False): should_escalate: bool """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: bool + """If true, failing this eval means the response should be guardrailed""" + threshold: float """Threshold value that determines if the evaluation fails""" diff --git a/src/codex/types/projects/eval_list_response.py b/src/codex/types/projects/eval_list_response.py index e7f2b1b3..48859b8d 100644 --- a/src/codex/types/projects/eval_list_response.py +++ b/src/codex/types/projects/eval_list_response.py @@ -55,10 +55,13 @@ class EvalListResponseItem(BaseModel): should_escalate: Optional[bool] = None """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: Optional[bool] = None + """If true, failing this eval means the response should be guardrailed""" + threshold: Optional[float] = None """Threshold value that determines if the evaluation fails""" diff --git a/src/codex/types/projects/eval_update_params.py b/src/codex/types/projects/eval_update_params.py index b690ec43..545c0b29 100644 --- a/src/codex/types/projects/eval_update_params.py +++ b/src/codex/types/projects/eval_update_params.py @@ -59,10 +59,13 @@ class CustomEvalCreateOrUpdateSchema(TypedDict, total=False): should_escalate: bool """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: bool + """If true, failing this eval means the response should be guardrailed""" + threshold: float """Threshold value that determines if the evaluation fails""" @@ -90,10 +93,13 @@ class DefaultEvalUpdateSchema(TypedDict, total=False): should_escalate: bool """ - If true, failing this eval means the response is considered bad and can trigger - escalation to Codex/SME + If true, failing this eval means the question should be escalated to Codex for + an SME to review """ + should_guardrail: bool + """If true, failing this eval means the response should be guardrailed""" + threshold: float """Threshold value that determines if the evaluation fails""" diff --git a/src/codex/types/projects/query_log_list_by_group_response.py b/src/codex/types/projects/query_log_list_by_group_response.py index ee79b6fa..d11d8276 100644 --- a/src/codex/types/projects/query_log_list_by_group_response.py +++ b/src/codex/types/projects/query_log_list_by_group_response.py @@ -45,7 +45,6 @@ class QueryLogsByGroupQueryLog(BaseModel): """ is_bad_response: bool - """If an eval with should_escalate=True failed""" project_id: str @@ -65,6 +64,9 @@ class QueryLogsByGroupQueryLog(BaseModel): custom_metadata_keys: Optional[List[str]] = None """Keys of the custom metadata""" + escalated: Optional[bool] = None + """If true, the question was escalated to Codex for an SME to review""" + eval_issue_labels: Optional[List[str]] = None """Labels derived from evaluation scores""" @@ -77,6 +79,9 @@ class QueryLogsByGroupQueryLog(BaseModel): evaluated_response: Optional[str] = None """The response being evaluated from the RAG system (before any remediation)""" + guardrailed: Optional[bool] = None + """If true, the response was guardrailed""" + primary_eval_issue: Optional[str] = None """Primary issue identified in evaluation""" diff --git a/src/codex/types/projects/query_log_list_groups_response.py b/src/codex/types/projects/query_log_list_groups_response.py index 979d34d6..fd87c309 100644 --- a/src/codex/types/projects/query_log_list_groups_response.py +++ b/src/codex/types/projects/query_log_list_groups_response.py @@ -40,7 +40,8 @@ class QueryLogGroup(BaseModel): """ is_bad_response: bool - """If an eval with should_escalate=True failed""" + + needs_review: bool project_id: str @@ -48,7 +49,7 @@ class QueryLogGroup(BaseModel): remediation_id: str - status: Literal["ACTIVE", "DRAFT", "ACTIVE_WITH_DRAFT", "NOT_STARTED", "PAUSED"] + status: Literal["ACTIVE", "DRAFT", "ACTIVE_WITH_DRAFT", "NOT_STARTED", "PAUSED", "NO_ACTION_NEEDED"] total_count: int @@ -64,6 +65,9 @@ class QueryLogGroup(BaseModel): custom_metadata_keys: Optional[List[str]] = None """Keys of the custom metadata""" + escalated: Optional[bool] = None + """If true, the question was escalated to Codex for an SME to review""" + eval_issue_labels: Optional[List[str]] = None """Labels derived from evaluation scores""" @@ -76,6 +80,9 @@ class QueryLogGroup(BaseModel): evaluated_response: Optional[str] = None """The response being evaluated from the RAG system (before any remediation)""" + guardrailed: Optional[bool] = None + """If true, the response was guardrailed""" + primary_eval_issue: Optional[str] = None """Primary issue identified in evaluation""" diff --git a/src/codex/types/projects/query_log_list_response.py b/src/codex/types/projects/query_log_list_response.py index d570ea50..bfd37cdd 100644 --- a/src/codex/types/projects/query_log_list_response.py +++ b/src/codex/types/projects/query_log_list_response.py @@ -40,7 +40,6 @@ class QueryLog(BaseModel): """ is_bad_response: bool - """If an eval with should_escalate=True failed""" project_id: str @@ -60,6 +59,9 @@ class QueryLog(BaseModel): custom_metadata_keys: Optional[List[str]] = None """Keys of the custom metadata""" + escalated: Optional[bool] = None + """If true, the question was escalated to Codex for an SME to review""" + eval_issue_labels: Optional[List[str]] = None """Labels derived from evaluation scores""" @@ -72,6 +74,9 @@ class QueryLog(BaseModel): evaluated_response: Optional[str] = None """The response being evaluated from the RAG system (before any remediation)""" + guardrailed: Optional[bool] = None + """If true, the response was guardrailed""" + primary_eval_issue: Optional[str] = None """Primary issue identified in evaluation""" diff --git a/src/codex/types/projects/query_log_retrieve_response.py b/src/codex/types/projects/query_log_retrieve_response.py index f918c214..3b813eea 100644 --- a/src/codex/types/projects/query_log_retrieve_response.py +++ b/src/codex/types/projects/query_log_retrieve_response.py @@ -40,7 +40,6 @@ class QueryLogRetrieveResponse(BaseModel): """ is_bad_response: bool - """If an eval with should_escalate=True failed""" project_id: str @@ -60,6 +59,9 @@ class QueryLogRetrieveResponse(BaseModel): custom_metadata_keys: Optional[List[str]] = None """Keys of the custom metadata""" + escalated: Optional[bool] = None + """If true, the question was escalated to Codex for an SME to review""" + eval_issue_labels: Optional[List[str]] = None """Labels derived from evaluation scores""" @@ -72,6 +74,9 @@ class QueryLogRetrieveResponse(BaseModel): evaluated_response: Optional[str] = None """The response being evaluated from the RAG system (before any remediation)""" + guardrailed: Optional[bool] = None + """If true, the response was guardrailed""" + primary_eval_issue: Optional[str] = None """Primary issue identified in evaluation""" diff --git a/src/codex/types/projects/query_log_start_remediation_response.py b/src/codex/types/projects/query_log_start_remediation_response.py index 0250fb15..ee7f0c72 100644 --- a/src/codex/types/projects/query_log_start_remediation_response.py +++ b/src/codex/types/projects/query_log_start_remediation_response.py @@ -22,11 +22,13 @@ class QueryLogStartRemediationResponse(BaseModel): last_edited_by: Optional[str] = None + needs_review: bool + project_id: str question: str - status: Literal["ACTIVE", "DRAFT", "ACTIVE_WITH_DRAFT", "NOT_STARTED", "PAUSED"] + status: Literal["ACTIVE", "DRAFT", "ACTIVE_WITH_DRAFT", "NOT_STARTED", "PAUSED", "NO_ACTION_NEEDED"] answer: Optional[str] = None diff --git a/src/codex/types/projects/remediation_create_response.py b/src/codex/types/projects/remediation_create_response.py index ad4e6893..9b8a8775 100644 --- a/src/codex/types/projects/remediation_create_response.py +++ b/src/codex/types/projects/remediation_create_response.py @@ -22,11 +22,13 @@ class RemediationCreateResponse(BaseModel): last_edited_by: Optional[str] = None + needs_review: bool + project_id: str question: str - status: Literal["ACTIVE", "DRAFT", "ACTIVE_WITH_DRAFT", "NOT_STARTED", "PAUSED"] + status: Literal["ACTIVE", "DRAFT", "ACTIVE_WITH_DRAFT", "NOT_STARTED", "PAUSED", "NO_ACTION_NEEDED"] answer: Optional[str] = None diff --git a/src/codex/types/projects/remediation_edit_answer_response.py b/src/codex/types/projects/remediation_edit_answer_response.py index d8b34323..1d43c082 100644 --- a/src/codex/types/projects/remediation_edit_answer_response.py +++ b/src/codex/types/projects/remediation_edit_answer_response.py @@ -22,11 +22,13 @@ class RemediationEditAnswerResponse(BaseModel): last_edited_by: Optional[str] = None + needs_review: bool + project_id: str question: str - status: Literal["ACTIVE", "DRAFT", "ACTIVE_WITH_DRAFT", "NOT_STARTED", "PAUSED"] + status: Literal["ACTIVE", "DRAFT", "ACTIVE_WITH_DRAFT", "NOT_STARTED", "PAUSED", "NO_ACTION_NEEDED"] answer: Optional[str] = None diff --git a/src/codex/types/projects/remediation_edit_draft_answer_response.py b/src/codex/types/projects/remediation_edit_draft_answer_response.py index 828035e8..80f80c07 100644 --- a/src/codex/types/projects/remediation_edit_draft_answer_response.py +++ b/src/codex/types/projects/remediation_edit_draft_answer_response.py @@ -22,11 +22,13 @@ class RemediationEditDraftAnswerResponse(BaseModel): last_edited_by: Optional[str] = None + needs_review: bool + project_id: str question: str - status: Literal["ACTIVE", "DRAFT", "ACTIVE_WITH_DRAFT", "NOT_STARTED", "PAUSED"] + status: Literal["ACTIVE", "DRAFT", "ACTIVE_WITH_DRAFT", "NOT_STARTED", "PAUSED", "NO_ACTION_NEEDED"] answer: Optional[str] = None diff --git a/src/codex/types/projects/remediation_get_resolved_logs_count_response.py b/src/codex/types/projects/remediation_get_resolved_logs_count_response.py index 79997b09..9222eb9a 100644 --- a/src/codex/types/projects/remediation_get_resolved_logs_count_response.py +++ b/src/codex/types/projects/remediation_get_resolved_logs_count_response.py @@ -22,13 +22,15 @@ class RemediationGetResolvedLogsCountResponse(BaseModel): last_edited_by: Optional[str] = None + needs_review: bool + project_id: str question: str resolved_logs_count: int - status: Literal["ACTIVE", "DRAFT", "ACTIVE_WITH_DRAFT", "NOT_STARTED", "PAUSED"] + status: Literal["ACTIVE", "DRAFT", "ACTIVE_WITH_DRAFT", "NOT_STARTED", "PAUSED", "NO_ACTION_NEEDED"] answer: Optional[str] = None diff --git a/src/codex/types/projects/remediation_list_resolved_logs_response.py b/src/codex/types/projects/remediation_list_resolved_logs_response.py index 6181028d..4f9682b6 100644 --- a/src/codex/types/projects/remediation_list_resolved_logs_response.py +++ b/src/codex/types/projects/remediation_list_resolved_logs_response.py @@ -40,7 +40,6 @@ class QueryLog(BaseModel): """ is_bad_response: bool - """If an eval with should_escalate=True failed""" project_id: str @@ -60,6 +59,9 @@ class QueryLog(BaseModel): custom_metadata_keys: Optional[List[str]] = None """Keys of the custom metadata""" + escalated: Optional[bool] = None + """If true, the question was escalated to Codex for an SME to review""" + eval_issue_labels: Optional[List[str]] = None """Labels derived from evaluation scores""" @@ -72,6 +74,9 @@ class QueryLog(BaseModel): evaluated_response: Optional[str] = None """The response being evaluated from the RAG system (before any remediation)""" + guardrailed: Optional[bool] = None + """If true, the response was guardrailed""" + primary_eval_issue: Optional[str] = None """Primary issue identified in evaluation""" diff --git a/src/codex/types/projects/remediation_list_response.py b/src/codex/types/projects/remediation_list_response.py index 3e737970..9d5cda86 100644 --- a/src/codex/types/projects/remediation_list_response.py +++ b/src/codex/types/projects/remediation_list_response.py @@ -22,13 +22,15 @@ class Remediation(BaseModel): last_edited_by: Optional[str] = None + needs_review: bool + project_id: str question: str resolved_logs_count: int - status: Literal["ACTIVE", "DRAFT", "ACTIVE_WITH_DRAFT", "NOT_STARTED", "PAUSED"] + status: Literal["ACTIVE", "DRAFT", "ACTIVE_WITH_DRAFT", "NOT_STARTED", "PAUSED", "NO_ACTION_NEEDED"] answer: Optional[str] = None diff --git a/src/codex/types/projects/remediation_pause_response.py b/src/codex/types/projects/remediation_pause_response.py index ae453581..97e1ac58 100644 --- a/src/codex/types/projects/remediation_pause_response.py +++ b/src/codex/types/projects/remediation_pause_response.py @@ -22,11 +22,13 @@ class RemediationPauseResponse(BaseModel): last_edited_by: Optional[str] = None + needs_review: bool + project_id: str question: str - status: Literal["ACTIVE", "DRAFT", "ACTIVE_WITH_DRAFT", "NOT_STARTED", "PAUSED"] + status: Literal["ACTIVE", "DRAFT", "ACTIVE_WITH_DRAFT", "NOT_STARTED", "PAUSED", "NO_ACTION_NEEDED"] answer: Optional[str] = None diff --git a/src/codex/types/projects/remediation_publish_response.py b/src/codex/types/projects/remediation_publish_response.py index 5eb2c622..b43c8b98 100644 --- a/src/codex/types/projects/remediation_publish_response.py +++ b/src/codex/types/projects/remediation_publish_response.py @@ -22,11 +22,13 @@ class RemediationPublishResponse(BaseModel): last_edited_by: Optional[str] = None + needs_review: bool + project_id: str question: str - status: Literal["ACTIVE", "DRAFT", "ACTIVE_WITH_DRAFT", "NOT_STARTED", "PAUSED"] + status: Literal["ACTIVE", "DRAFT", "ACTIVE_WITH_DRAFT", "NOT_STARTED", "PAUSED", "NO_ACTION_NEEDED"] answer: Optional[str] = None diff --git a/src/codex/types/projects/remediation_retrieve_response.py b/src/codex/types/projects/remediation_retrieve_response.py index 6fbd60d2..69a327e0 100644 --- a/src/codex/types/projects/remediation_retrieve_response.py +++ b/src/codex/types/projects/remediation_retrieve_response.py @@ -22,11 +22,13 @@ class RemediationRetrieveResponse(BaseModel): last_edited_by: Optional[str] = None + needs_review: bool + project_id: str question: str - status: Literal["ACTIVE", "DRAFT", "ACTIVE_WITH_DRAFT", "NOT_STARTED", "PAUSED"] + status: Literal["ACTIVE", "DRAFT", "ACTIVE_WITH_DRAFT", "NOT_STARTED", "PAUSED", "NO_ACTION_NEEDED"] answer: Optional[str] = None diff --git a/src/codex/types/projects/remediation_unpause_response.py b/src/codex/types/projects/remediation_unpause_response.py index 789484cd..c3ce44fd 100644 --- a/src/codex/types/projects/remediation_unpause_response.py +++ b/src/codex/types/projects/remediation_unpause_response.py @@ -22,11 +22,13 @@ class RemediationUnpauseResponse(BaseModel): last_edited_by: Optional[str] = None + needs_review: bool + project_id: str question: str - status: Literal["ACTIVE", "DRAFT", "ACTIVE_WITH_DRAFT", "NOT_STARTED", "PAUSED"] + status: Literal["ACTIVE", "DRAFT", "ACTIVE_WITH_DRAFT", "NOT_STARTED", "PAUSED", "NO_ACTION_NEEDED"] answer: Optional[str] = None diff --git a/tests/api_resources/projects/test_evals.py b/tests/api_resources/projects/test_evals.py index 1fd4216f..22b83803 100644 --- a/tests/api_resources/projects/test_evals.py +++ b/tests/api_resources/projects/test_evals.py @@ -44,6 +44,7 @@ def test_method_create_with_all_params(self, client: Codex) -> None: query_identifier="query_identifier", response_identifier="response_identifier", should_escalate=True, + should_guardrail=True, threshold=0, threshold_direction="above", ) @@ -120,6 +121,7 @@ def test_method_update_with_all_params_overload_1(self, client: Codex) -> None: query_identifier="query_identifier", response_identifier="response_identifier", should_escalate=True, + should_guardrail=True, threshold=0, threshold_direction="above", ) @@ -200,6 +202,7 @@ def test_method_update_with_all_params_overload_2(self, client: Codex) -> None: enabled=True, priority=0, should_escalate=True, + should_guardrail=True, threshold=0, threshold_direction="above", ) @@ -378,6 +381,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncCodex) -> query_identifier="query_identifier", response_identifier="response_identifier", should_escalate=True, + should_guardrail=True, threshold=0, threshold_direction="above", ) @@ -454,6 +458,7 @@ async def test_method_update_with_all_params_overload_1(self, async_client: Asyn query_identifier="query_identifier", response_identifier="response_identifier", should_escalate=True, + should_guardrail=True, threshold=0, threshold_direction="above", ) @@ -534,6 +539,7 @@ async def test_method_update_with_all_params_overload_2(self, async_client: Asyn enabled=True, priority=0, should_escalate=True, + should_guardrail=True, threshold=0, threshold_direction="above", ) diff --git a/tests/api_resources/test_projects.py b/tests/api_resources/test_projects.py index 6c95f273..e7d7eb1f 100644 --- a/tests/api_resources/test_projects.py +++ b/tests/api_resources/test_projects.py @@ -56,6 +56,7 @@ def test_method_create_with_all_params(self, client: Codex) -> None: "query_identifier": "query_identifier", "response_identifier": "response_identifier", "should_escalate": True, + "should_guardrail": True, "threshold": 0, "threshold_direction": "above", } @@ -68,6 +69,7 @@ def test_method_create_with_all_params(self, client: Codex) -> None: "enabled": True, "priority": 0, "should_escalate": True, + "should_guardrail": True, "threshold": 0, "threshold_direction": "above", }, @@ -77,6 +79,7 @@ def test_method_create_with_all_params(self, client: Codex) -> None: "enabled": True, "priority": 0, "should_escalate": True, + "should_guardrail": True, "threshold": 0, "threshold_direction": "above", }, @@ -86,6 +89,7 @@ def test_method_create_with_all_params(self, client: Codex) -> None: "enabled": True, "priority": 0, "should_escalate": True, + "should_guardrail": True, "threshold": 0, "threshold_direction": "above", }, @@ -95,6 +99,7 @@ def test_method_create_with_all_params(self, client: Codex) -> None: "enabled": True, "priority": 0, "should_escalate": True, + "should_guardrail": True, "threshold": 0, "threshold_direction": "above", }, @@ -104,6 +109,7 @@ def test_method_create_with_all_params(self, client: Codex) -> None: "enabled": True, "priority": 0, "should_escalate": True, + "should_guardrail": True, "threshold": 0, "threshold_direction": "above", }, @@ -226,6 +232,7 @@ def test_method_update_with_all_params(self, client: Codex) -> None: "query_identifier": "query_identifier", "response_identifier": "response_identifier", "should_escalate": True, + "should_guardrail": True, "threshold": 0, "threshold_direction": "above", } @@ -238,6 +245,7 @@ def test_method_update_with_all_params(self, client: Codex) -> None: "enabled": True, "priority": 0, "should_escalate": True, + "should_guardrail": True, "threshold": 0, "threshold_direction": "above", }, @@ -247,6 +255,7 @@ def test_method_update_with_all_params(self, client: Codex) -> None: "enabled": True, "priority": 0, "should_escalate": True, + "should_guardrail": True, "threshold": 0, "threshold_direction": "above", }, @@ -256,6 +265,7 @@ def test_method_update_with_all_params(self, client: Codex) -> None: "enabled": True, "priority": 0, "should_escalate": True, + "should_guardrail": True, "threshold": 0, "threshold_direction": "above", }, @@ -265,6 +275,7 @@ def test_method_update_with_all_params(self, client: Codex) -> None: "enabled": True, "priority": 0, "should_escalate": True, + "should_guardrail": True, "threshold": 0, "threshold_direction": "above", }, @@ -274,6 +285,7 @@ def test_method_update_with_all_params(self, client: Codex) -> None: "enabled": True, "priority": 0, "should_escalate": True, + "should_guardrail": True, "threshold": 0, "threshold_direction": "above", }, @@ -757,6 +769,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncCodex) -> "query_identifier": "query_identifier", "response_identifier": "response_identifier", "should_escalate": True, + "should_guardrail": True, "threshold": 0, "threshold_direction": "above", } @@ -769,6 +782,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncCodex) -> "enabled": True, "priority": 0, "should_escalate": True, + "should_guardrail": True, "threshold": 0, "threshold_direction": "above", }, @@ -778,6 +792,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncCodex) -> "enabled": True, "priority": 0, "should_escalate": True, + "should_guardrail": True, "threshold": 0, "threshold_direction": "above", }, @@ -787,6 +802,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncCodex) -> "enabled": True, "priority": 0, "should_escalate": True, + "should_guardrail": True, "threshold": 0, "threshold_direction": "above", }, @@ -796,6 +812,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncCodex) -> "enabled": True, "priority": 0, "should_escalate": True, + "should_guardrail": True, "threshold": 0, "threshold_direction": "above", }, @@ -805,6 +822,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncCodex) -> "enabled": True, "priority": 0, "should_escalate": True, + "should_guardrail": True, "threshold": 0, "threshold_direction": "above", }, @@ -927,6 +945,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncCodex) -> "query_identifier": "query_identifier", "response_identifier": "response_identifier", "should_escalate": True, + "should_guardrail": True, "threshold": 0, "threshold_direction": "above", } @@ -939,6 +958,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncCodex) -> "enabled": True, "priority": 0, "should_escalate": True, + "should_guardrail": True, "threshold": 0, "threshold_direction": "above", }, @@ -948,6 +968,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncCodex) -> "enabled": True, "priority": 0, "should_escalate": True, + "should_guardrail": True, "threshold": 0, "threshold_direction": "above", }, @@ -957,6 +978,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncCodex) -> "enabled": True, "priority": 0, "should_escalate": True, + "should_guardrail": True, "threshold": 0, "threshold_direction": "above", }, @@ -966,6 +988,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncCodex) -> "enabled": True, "priority": 0, "should_escalate": True, + "should_guardrail": True, "threshold": 0, "threshold_direction": "above", }, @@ -975,6 +998,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncCodex) -> "enabled": True, "priority": 0, "should_escalate": True, + "should_guardrail": True, "threshold": 0, "threshold_direction": "above", }, From d592b4ffd69abbf933aeb2aa7d95d64ba199f2a1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 21:53:13 +0000 Subject: [PATCH 4/4] release: 0.1.0-alpha.22 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 14 ++++++++++++++ pyproject.toml | 2 +- src/codex/_version.py | 2 +- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 7c31fce2..aa848759 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0-alpha.21" + ".": "0.1.0-alpha.22" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 00c2b1a9..2b2988f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 0.1.0-alpha.22 (2025-06-24) + +Full Changelog: [v0.1.0-alpha.21...v0.1.0-alpha.22](https://github.com/cleanlab/codex-python/compare/v0.1.0-alpha.21...v0.1.0-alpha.22) + +### Features + +* **api:** api update ([e9ca3b5](https://github.com/cleanlab/codex-python/commit/e9ca3b5ce636b8572f168ed8d2c82d416f22b823)) +* **client:** add support for aiohttp ([f90d62f](https://github.com/cleanlab/codex-python/commit/f90d62f83e7dc80d1a94c090724ca3a7c285e3e2)) + + +### Chores + +* **tests:** skip some failing tests on the latest python versions ([aea4c5c](https://github.com/cleanlab/codex-python/commit/aea4c5ce68120a12fe8248c4611b5b336f36ab0f)) + ## 0.1.0-alpha.21 (2025-06-22) Full Changelog: [v0.1.0-alpha.20...v0.1.0-alpha.21](https://github.com/cleanlab/codex-python/compare/v0.1.0-alpha.20...v0.1.0-alpha.21) diff --git a/pyproject.toml b/pyproject.toml index 5fb6cb07..b71f9f0f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "codex-sdk" -version = "0.1.0-alpha.21" +version = "0.1.0-alpha.22" description = "Internal SDK used within cleanlab-codex package. Refer to https://pypi.org/project/cleanlab-codex/ instead." dynamic = ["readme"] license = "MIT" diff --git a/src/codex/_version.py b/src/codex/_version.py index 3b23c98f..a88a1c39 100644 --- a/src/codex/_version.py +++ b/src/codex/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "codex" -__version__ = "0.1.0-alpha.21" # x-release-please-version +__version__ = "0.1.0-alpha.22" # x-release-please-version