Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .stats.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
configured_endpoints: 65
openapi_spec_hash: eeb8ebc5600523bdfad046381a929572
openapi_spec_hash: 80696dc202de8bacc0e43506d7c210b0
config_hash: 14b2643a0ec60cf326dfed00939644ff
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
27 changes: 27 additions & 0 deletions requirements-dev.lock
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,24 @@
# 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
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
Expand All @@ -34,23 +45,33 @@ 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
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
Expand All @@ -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
Expand Down Expand Up @@ -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
27 changes: 27 additions & 0 deletions requirements.lock
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,51 @@
# 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
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
Expand All @@ -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
3 changes: 2 additions & 1 deletion src/codex/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__ = [
Expand Down Expand Up @@ -80,6 +80,7 @@
"DEFAULT_CONNECTION_LIMITS",
"DefaultHttpxClient",
"DefaultAsyncHttpxClient",
"DefaultAioHttpClient",
]

if not _t.TYPE_CHECKING:
Expand Down
22 changes: 22 additions & 0 deletions src/codex/_base_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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):
Expand Down
48 changes: 36 additions & 12 deletions src/codex/resources/projects/evals.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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,
},
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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

Expand All @@ -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.
Expand All @@ -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

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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,
},
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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,
},
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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

Expand All @@ -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.
Expand All @@ -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

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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,
},
Expand Down
Loading