From 7ee4e09545e52eaa3d10522709e833b38221ecad Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 31 Mar 2025 23:24:22 +0000
Subject: [PATCH 01/14] chore(internal): version bump (#81)
From b41e3bf21e10b11b6d64e15f320cf3d8aa66bfb8 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 13 Mar 2025 21:29:05 +0000
Subject: [PATCH 02/14] feat(api): api update (#83)
---
src/codex/resources/projects/entries.py | 14 +++++++++++++-
src/codex/types/projects/entry.py | 7 +++++++
src/codex/types/projects/entry_create_params.py | 2 ++
src/codex/types/projects/entry_list_params.py | 3 +++
src/codex/types/projects/entry_update_params.py | 2 ++
tests/api_resources/projects/test_entries.py | 6 ++++++
6 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/src/codex/resources/projects/entries.py b/src/codex/resources/projects/entries.py
index 2fcc8e0b..e2c16547 100644
--- a/src/codex/resources/projects/entries.py
+++ b/src/codex/resources/projects/entries.py
@@ -2,7 +2,7 @@
from __future__ import annotations
-from typing import Optional
+from typing import List, Optional
from typing_extensions import Literal
import httpx
@@ -60,6 +60,7 @@ def create(
*,
question: str,
answer: Optional[str] | NotGiven = NOT_GIVEN,
+ draft_answer: Optional[str] | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -89,6 +90,7 @@ def create(
{
"question": question,
"answer": answer,
+ "draft_answer": draft_answer,
},
entry_create_params.EntryCreateParams,
),
@@ -140,6 +142,7 @@ def update(
*,
project_id: str,
answer: Optional[str] | NotGiven = NOT_GIVEN,
+ draft_answer: Optional[str] | NotGiven = NOT_GIVEN,
frequency_count: Optional[int] | NotGiven = NOT_GIVEN,
question: Optional[str] | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
@@ -170,6 +173,7 @@ def update(
body=maybe_transform(
{
"answer": answer,
+ "draft_answer": draft_answer,
"frequency_count": frequency_count,
"question": question,
},
@@ -190,6 +194,7 @@ def list(
offset: int | NotGiven = NOT_GIVEN,
order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN,
sort: Literal["created_at", "answered_at"] | NotGiven = NOT_GIVEN,
+ states: List[Literal["unanswered", "draft", "published", "published_with_draft"]] | NotGiven = NOT_GIVEN,
unanswered_only: bool | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -227,6 +232,7 @@ def list(
"offset": offset,
"order": order,
"sort": sort,
+ "states": states,
"unanswered_only": unanswered_only,
},
entry_list_params.EntryListParams,
@@ -379,6 +385,7 @@ async def create(
*,
question: str,
answer: Optional[str] | NotGiven = NOT_GIVEN,
+ draft_answer: Optional[str] | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -408,6 +415,7 @@ async def create(
{
"question": question,
"answer": answer,
+ "draft_answer": draft_answer,
},
entry_create_params.EntryCreateParams,
),
@@ -459,6 +467,7 @@ async def update(
*,
project_id: str,
answer: Optional[str] | NotGiven = NOT_GIVEN,
+ draft_answer: Optional[str] | NotGiven = NOT_GIVEN,
frequency_count: Optional[int] | NotGiven = NOT_GIVEN,
question: Optional[str] | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
@@ -489,6 +498,7 @@ async def update(
body=await async_maybe_transform(
{
"answer": answer,
+ "draft_answer": draft_answer,
"frequency_count": frequency_count,
"question": question,
},
@@ -509,6 +519,7 @@ def list(
offset: int | NotGiven = NOT_GIVEN,
order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN,
sort: Literal["created_at", "answered_at"] | NotGiven = NOT_GIVEN,
+ states: List[Literal["unanswered", "draft", "published", "published_with_draft"]] | NotGiven = NOT_GIVEN,
unanswered_only: bool | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -546,6 +557,7 @@ def list(
"offset": offset,
"order": order,
"sort": sort,
+ "states": states,
"unanswered_only": unanswered_only,
},
entry_list_params.EntryListParams,
diff --git a/src/codex/types/projects/entry.py b/src/codex/types/projects/entry.py
index 4621cc4b..7a2c4502 100644
--- a/src/codex/types/projects/entry.py
+++ b/src/codex/types/projects/entry.py
@@ -2,6 +2,7 @@
from typing import Optional
from datetime import datetime
+from typing_extensions import Literal
from ..._models import BaseModel
@@ -13,10 +14,16 @@ class Entry(BaseModel):
question: str
+ state: Literal["unanswered", "draft", "published", "published_with_draft"]
+
id: Optional[str] = None
answer: Optional[str] = None
answered_at: Optional[datetime] = None
+ draft_answer: Optional[str] = None
+
+ draft_answer_last_edited: Optional[datetime] = None
+
frequency_count: Optional[int] = None
diff --git a/src/codex/types/projects/entry_create_params.py b/src/codex/types/projects/entry_create_params.py
index 1ac23dd4..daf30897 100644
--- a/src/codex/types/projects/entry_create_params.py
+++ b/src/codex/types/projects/entry_create_params.py
@@ -12,3 +12,5 @@ class EntryCreateParams(TypedDict, total=False):
question: Required[str]
answer: Optional[str]
+
+ draft_answer: Optional[str]
diff --git a/src/codex/types/projects/entry_list_params.py b/src/codex/types/projects/entry_list_params.py
index b50181f7..605ea482 100644
--- a/src/codex/types/projects/entry_list_params.py
+++ b/src/codex/types/projects/entry_list_params.py
@@ -2,6 +2,7 @@
from __future__ import annotations
+from typing import List
from typing_extensions import Literal, TypedDict
__all__ = ["EntryListParams"]
@@ -18,4 +19,6 @@ class EntryListParams(TypedDict, total=False):
sort: Literal["created_at", "answered_at"]
+ states: List[Literal["unanswered", "draft", "published", "published_with_draft"]]
+
unanswered_only: bool
diff --git a/src/codex/types/projects/entry_update_params.py b/src/codex/types/projects/entry_update_params.py
index ba105495..05a6332d 100644
--- a/src/codex/types/projects/entry_update_params.py
+++ b/src/codex/types/projects/entry_update_params.py
@@ -13,6 +13,8 @@ class EntryUpdateParams(TypedDict, total=False):
answer: Optional[str]
+ draft_answer: Optional[str]
+
frequency_count: Optional[int]
question: Optional[str]
diff --git a/tests/api_resources/projects/test_entries.py b/tests/api_resources/projects/test_entries.py
index 026add46..fbbf6f25 100644
--- a/tests/api_resources/projects/test_entries.py
+++ b/tests/api_resources/projects/test_entries.py
@@ -36,6 +36,7 @@ def test_method_create_with_all_params(self, client: Codex) -> None:
project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
question="question",
answer="answer",
+ draft_answer="draft_answer",
)
assert_matches_type(Entry, entry, path=["response"])
@@ -144,6 +145,7 @@ def test_method_update_with_all_params(self, client: Codex) -> None:
entry_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
answer="answer",
+ draft_answer="draft_answer",
frequency_count=0,
question="question",
)
@@ -210,6 +212,7 @@ def test_method_list_with_all_params(self, client: Codex) -> None:
offset=0,
order="asc",
sort="created_at",
+ states=["unanswered"],
unanswered_only=True,
)
assert_matches_type(SyncOffsetPageEntries[Entry], entry, path=["response"])
@@ -412,6 +415,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncCodex) ->
project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
question="question",
answer="answer",
+ draft_answer="draft_answer",
)
assert_matches_type(Entry, entry, path=["response"])
@@ -520,6 +524,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncCodex) ->
entry_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
answer="answer",
+ draft_answer="draft_answer",
frequency_count=0,
question="question",
)
@@ -586,6 +591,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncCodex) -> No
offset=0,
order="asc",
sort="created_at",
+ states=["unanswered"],
unanswered_only=True,
)
assert_matches_type(AsyncOffsetPageEntries[Entry], entry, path=["response"])
From e4b2929d58b466199bb02e24b8e0a7c9c63f1b3a Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 14 Mar 2025 08:05:45 +0000
Subject: [PATCH 03/14] chore(internal): remove extra empty newlines (#84)
---
pyproject.toml | 2 --
1 file changed, 2 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index ede43513..d771e49b 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -38,7 +38,6 @@ Homepage = "https://github.com/cleanlab/codex-python"
Repository = "https://github.com/cleanlab/codex-python"
-
[tool.rye]
managed = true
# version pins are in requirements-dev.lock
@@ -152,7 +151,6 @@ reportImplicitOverride = true
reportImportCycles = false
reportPrivateUsage = false
-
[tool.ruff]
line-length = 120
output-format = "grouped"
From 7e1eaca4c5f2c779b264c34883688b52e1a8602e Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Sat, 15 Mar 2025 06:29:25 +0000
Subject: [PATCH 04/14] chore(internal): codegen related update (#85)
---
requirements-dev.lock | 1 +
requirements.lock | 1 +
2 files changed, 2 insertions(+)
diff --git a/requirements-dev.lock b/requirements-dev.lock
index 1961e8d6..5b7189d6 100644
--- a/requirements-dev.lock
+++ b/requirements-dev.lock
@@ -7,6 +7,7 @@
# all-features: true
# with-sources: false
# generate-hashes: false
+# universal: false
-e file:.
annotated-types==0.6.0
diff --git a/requirements.lock b/requirements.lock
index 5d7fff82..1f6c5f7f 100644
--- a/requirements.lock
+++ b/requirements.lock
@@ -7,6 +7,7 @@
# all-features: true
# with-sources: false
# generate-hashes: false
+# universal: false
-e file:.
annotated-types==0.6.0
From e026b73fb62aa19689890f14b7dcf355910029a8 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Sat, 15 Mar 2025 06:32:58 +0000
Subject: [PATCH 05/14] chore(internal): bump rye to 0.44.0 (#86)
---
.devcontainer/Dockerfile | 2 +-
.github/workflows/ci.yml | 2 +-
.github/workflows/publish-pypi.yml | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index 55d20255..ff261bad 100644
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -3,7 +3,7 @@ FROM mcr.microsoft.com/vscode/devcontainers/python:0-${VARIANT}
USER vscode
-RUN curl -sSf https://rye.astral.sh/get | RYE_VERSION="0.35.0" RYE_INSTALL_OPTION="--yes" bash
+RUN curl -sSf https://rye.astral.sh/get | RYE_VERSION="0.44.0" RYE_INSTALL_OPTION="--yes" bash
ENV PATH=/home/vscode/.rye/shims:$PATH
RUN echo "[[ -d .venv ]] && source .venv/bin/activate || export PATH=\$PATH" >> /home/vscode/.bashrc
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e503784c..5ac5f63f 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -21,7 +21,7 @@ jobs:
curl -sSf https://rye.astral.sh/get | bash
echo "$HOME/.rye/shims" >> $GITHUB_PATH
env:
- RYE_VERSION: '0.35.0'
+ RYE_VERSION: '0.44.0'
RYE_INSTALL_OPTION: '--yes'
- name: Install dependencies
diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml
index 5ed611c7..7c078aa3 100644
--- a/.github/workflows/publish-pypi.yml
+++ b/.github/workflows/publish-pypi.yml
@@ -21,7 +21,7 @@ jobs:
curl -sSf https://rye.astral.sh/get | bash
echo "$HOME/.rye/shims" >> $GITHUB_PATH
env:
- RYE_VERSION: '0.35.0'
+ RYE_VERSION: '0.44.0'
RYE_INSTALL_OPTION: '--yes'
- name: Publish to PyPI
From ea6a9422c2a1ff25f14ade1a790ffd943dadbd81 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Sat, 15 Mar 2025 06:37:06 +0000
Subject: [PATCH 06/14] fix(types): handle more discriminated union shapes
(#87)
---
src/codex/_models.py | 7 +++++--
tests/test_models.py | 32 ++++++++++++++++++++++++++++++++
2 files changed, 37 insertions(+), 2 deletions(-)
diff --git a/src/codex/_models.py b/src/codex/_models.py
index c4401ff8..b51a1bf5 100644
--- a/src/codex/_models.py
+++ b/src/codex/_models.py
@@ -65,7 +65,7 @@
from ._constants import RAW_RESPONSE_HEADER
if TYPE_CHECKING:
- from pydantic_core.core_schema import ModelField, LiteralSchema, ModelFieldsSchema
+ from pydantic_core.core_schema import ModelField, ModelSchema, LiteralSchema, ModelFieldsSchema
__all__ = ["BaseModel", "GenericModel"]
@@ -646,15 +646,18 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any,
def _extract_field_schema_pv2(model: type[BaseModel], field_name: str) -> ModelField | None:
schema = model.__pydantic_core_schema__
+ if schema["type"] == "definitions":
+ schema = schema["schema"]
+
if schema["type"] != "model":
return None
+ schema = cast("ModelSchema", schema)
fields_schema = schema["schema"]
if fields_schema["type"] != "model-fields":
return None
fields_schema = cast("ModelFieldsSchema", fields_schema)
-
field = fields_schema["fields"].get(field_name)
if not field:
return None
diff --git a/tests/test_models.py b/tests/test_models.py
index 26df341f..73e6d67c 100644
--- a/tests/test_models.py
+++ b/tests/test_models.py
@@ -854,3 +854,35 @@ class Model(BaseModel):
m = construct_type(value={"cls": "foo"}, type_=Model)
assert isinstance(m, Model)
assert isinstance(m.cls, str)
+
+
+def test_discriminated_union_case() -> None:
+ class A(BaseModel):
+ type: Literal["a"]
+
+ data: bool
+
+ class B(BaseModel):
+ type: Literal["b"]
+
+ data: List[Union[A, object]]
+
+ class ModelA(BaseModel):
+ type: Literal["modelA"]
+
+ data: int
+
+ class ModelB(BaseModel):
+ type: Literal["modelB"]
+
+ required: str
+
+ data: Union[A, B]
+
+ # when constructing ModelA | ModelB, value data doesn't match ModelB exactly - missing `required`
+ m = construct_type(
+ value={"type": "modelB", "data": {"type": "a", "data": True}},
+ type_=cast(Any, Annotated[Union[ModelA, ModelB], PropertyInfo(discriminator="type")]),
+ )
+
+ assert isinstance(m, ModelB)
From 86a40ccd3892d23bb12f78bf5ff13eaa23d8eb2d Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 17 Mar 2025 17:58:10 +0000
Subject: [PATCH 07/14] fix(ci): ensure pip is always available (#88)
---
bin/publish-pypi | 1 +
1 file changed, 1 insertion(+)
diff --git a/bin/publish-pypi b/bin/publish-pypi
index 05bfccbb..ebebf916 100644
--- a/bin/publish-pypi
+++ b/bin/publish-pypi
@@ -5,5 +5,6 @@ mkdir -p dist
rye build --clean
# Patching importlib-metadata version until upstream library version is updated
# https://github.com/pypa/twine/issues/977#issuecomment-2189800841
+"$HOME/.rye/self/bin/python3" -m ensurepip
"$HOME/.rye/self/bin/python3" -m pip install 'importlib-metadata==7.2.1'
rye publish --yes --token=$PYPI_TOKEN
From 674c6613c7709c93cca936f086d5348041252972 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 17 Mar 2025 18:05:48 +0000
Subject: [PATCH 08/14] fix(ci): remove publishing patch (#89)
---
bin/publish-pypi | 4 ----
pyproject.toml | 2 +-
2 files changed, 1 insertion(+), 5 deletions(-)
diff --git a/bin/publish-pypi b/bin/publish-pypi
index ebebf916..826054e9 100644
--- a/bin/publish-pypi
+++ b/bin/publish-pypi
@@ -3,8 +3,4 @@
set -eux
mkdir -p dist
rye build --clean
-# Patching importlib-metadata version until upstream library version is updated
-# https://github.com/pypa/twine/issues/977#issuecomment-2189800841
-"$HOME/.rye/self/bin/python3" -m ensurepip
-"$HOME/.rye/self/bin/python3" -m pip install 'importlib-metadata==7.2.1'
rye publish --yes --token=$PYPI_TOKEN
diff --git a/pyproject.toml b/pyproject.toml
index d771e49b..61f43447 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -86,7 +86,7 @@ typecheck = { chain = [
"typecheck:mypy" = "mypy ."
[build-system]
-requires = ["hatchling", "hatch-fancy-pypi-readme"]
+requires = ["hatchling==1.26.3", "hatch-fancy-pypi-readme"]
build-backend = "hatchling.build"
[tool.hatch.build]
From 52933f2bc708e1f2b5f2e144071a9ee41b27251c Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 19 Mar 2025 17:29:08 +0000
Subject: [PATCH 09/14] feat(api): api update (#90)
---
src/codex/resources/projects/access_keys.py | 31 +++++++
src/codex/resources/projects/entries.py | 91 +++++++++++++++++++
.../projects/access_key_create_params.py | 8 ++
.../projects/entry_add_question_params.py | 12 ++-
.../types/projects/entry_create_params.py | 12 ++-
.../types/projects/entry_query_params.py | 12 ++-
.../projects/test_access_keys.py | 8 ++
tests/api_resources/projects/test_entries.py | 60 ++++++++++++
8 files changed, 231 insertions(+), 3 deletions(-)
diff --git a/src/codex/resources/projects/access_keys.py b/src/codex/resources/projects/access_keys.py
index d375dbca..61987399 100644
--- a/src/codex/resources/projects/access_keys.py
+++ b/src/codex/resources/projects/access_keys.py
@@ -10,6 +10,7 @@
from ..._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven
from ..._utils import (
maybe_transform,
+ strip_not_given,
async_maybe_transform,
)
from ..._compat import cached_property
@@ -56,6 +57,10 @@ def create(
name: str,
description: Optional[str] | NotGiven = NOT_GIVEN,
expires_at: Union[str, datetime, None] | NotGiven = NOT_GIVEN,
+ x_client_library_version: str | NotGiven = NOT_GIVEN,
+ x_integration_type: str | NotGiven = NOT_GIVEN,
+ x_source: str | NotGiven = NOT_GIVEN,
+ x_stainless_package_version: str | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -77,6 +82,17 @@ def create(
"""
if not project_id:
raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}")
+ extra_headers = {
+ **strip_not_given(
+ {
+ "x-client-library-version": x_client_library_version,
+ "x-integration-type": x_integration_type,
+ "x-source": x_source,
+ "x-stainless-package-version": x_stainless_package_version,
+ }
+ ),
+ **(extra_headers or {}),
+ }
return self._post(
f"/api/projects/{project_id}/access_keys/",
body=maybe_transform(
@@ -330,6 +346,10 @@ async def create(
name: str,
description: Optional[str] | NotGiven = NOT_GIVEN,
expires_at: Union[str, datetime, None] | NotGiven = NOT_GIVEN,
+ x_client_library_version: str | NotGiven = NOT_GIVEN,
+ x_integration_type: str | NotGiven = NOT_GIVEN,
+ x_source: str | NotGiven = NOT_GIVEN,
+ x_stainless_package_version: str | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -351,6 +371,17 @@ async def create(
"""
if not project_id:
raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}")
+ extra_headers = {
+ **strip_not_given(
+ {
+ "x-client-library-version": x_client_library_version,
+ "x-integration-type": x_integration_type,
+ "x-source": x_source,
+ "x-stainless-package-version": x_stainless_package_version,
+ }
+ ),
+ **(extra_headers or {}),
+ }
return await self._post(
f"/api/projects/{project_id}/access_keys/",
body=await async_maybe_transform(
diff --git a/src/codex/resources/projects/entries.py b/src/codex/resources/projects/entries.py
index e2c16547..f5eebad6 100644
--- a/src/codex/resources/projects/entries.py
+++ b/src/codex/resources/projects/entries.py
@@ -10,6 +10,7 @@
from ..._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven
from ..._utils import (
maybe_transform,
+ strip_not_given,
async_maybe_transform,
)
from ..._compat import cached_property
@@ -61,6 +62,10 @@ def create(
question: str,
answer: Optional[str] | NotGiven = NOT_GIVEN,
draft_answer: Optional[str] | NotGiven = NOT_GIVEN,
+ x_client_library_version: str | NotGiven = NOT_GIVEN,
+ x_integration_type: str | NotGiven = NOT_GIVEN,
+ x_source: str | NotGiven = NOT_GIVEN,
+ x_stainless_package_version: str | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -84,6 +89,17 @@ def create(
"""
if not project_id:
raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}")
+ extra_headers = {
+ **strip_not_given(
+ {
+ "x-client-library-version": x_client_library_version,
+ "x-integration-type": x_integration_type,
+ "x-source": x_source,
+ "x-stainless-package-version": x_stainless_package_version,
+ }
+ ),
+ **(extra_headers or {}),
+ }
return self._post(
f"/api/projects/{project_id}/entries/",
body=maybe_transform(
@@ -283,6 +299,10 @@ def add_question(
project_id: str,
*,
question: str,
+ x_client_library_version: str | NotGiven = NOT_GIVEN,
+ x_integration_type: str | NotGiven = NOT_GIVEN,
+ x_source: str | NotGiven = NOT_GIVEN,
+ x_stainless_package_version: str | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -307,6 +327,17 @@ def add_question(
"""
if not project_id:
raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}")
+ extra_headers = {
+ **strip_not_given(
+ {
+ "x-client-library-version": x_client_library_version,
+ "x-integration-type": x_integration_type,
+ "x-source": x_source,
+ "x-stainless-package-version": x_stainless_package_version,
+ }
+ ),
+ **(extra_headers or {}),
+ }
return self._post(
f"/api/projects/{project_id}/entries/add_question",
body=maybe_transform({"question": question}, entry_add_question_params.EntryAddQuestionParams),
@@ -321,6 +352,10 @@ def query(
project_id: str,
*,
question: str,
+ x_client_library_version: str | NotGiven = NOT_GIVEN,
+ x_integration_type: str | NotGiven = NOT_GIVEN,
+ x_source: str | NotGiven = NOT_GIVEN,
+ x_stainless_package_version: str | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -349,6 +384,17 @@ def query(
"""
if not project_id:
raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}")
+ extra_headers = {
+ **strip_not_given(
+ {
+ "x-client-library-version": x_client_library_version,
+ "x-integration-type": x_integration_type,
+ "x-source": x_source,
+ "x-stainless-package-version": x_stainless_package_version,
+ }
+ ),
+ **(extra_headers or {}),
+ }
return self._post(
f"/api/projects/{project_id}/entries/query",
body=maybe_transform({"question": question}, entry_query_params.EntryQueryParams),
@@ -386,6 +432,10 @@ async def create(
question: str,
answer: Optional[str] | NotGiven = NOT_GIVEN,
draft_answer: Optional[str] | NotGiven = NOT_GIVEN,
+ x_client_library_version: str | NotGiven = NOT_GIVEN,
+ x_integration_type: str | NotGiven = NOT_GIVEN,
+ x_source: str | NotGiven = NOT_GIVEN,
+ x_stainless_package_version: str | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -409,6 +459,17 @@ async def create(
"""
if not project_id:
raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}")
+ extra_headers = {
+ **strip_not_given(
+ {
+ "x-client-library-version": x_client_library_version,
+ "x-integration-type": x_integration_type,
+ "x-source": x_source,
+ "x-stainless-package-version": x_stainless_package_version,
+ }
+ ),
+ **(extra_headers or {}),
+ }
return await self._post(
f"/api/projects/{project_id}/entries/",
body=await async_maybe_transform(
@@ -608,6 +669,10 @@ async def add_question(
project_id: str,
*,
question: str,
+ x_client_library_version: str | NotGiven = NOT_GIVEN,
+ x_integration_type: str | NotGiven = NOT_GIVEN,
+ x_source: str | NotGiven = NOT_GIVEN,
+ x_stainless_package_version: str | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -632,6 +697,17 @@ async def add_question(
"""
if not project_id:
raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}")
+ extra_headers = {
+ **strip_not_given(
+ {
+ "x-client-library-version": x_client_library_version,
+ "x-integration-type": x_integration_type,
+ "x-source": x_source,
+ "x-stainless-package-version": x_stainless_package_version,
+ }
+ ),
+ **(extra_headers or {}),
+ }
return await self._post(
f"/api/projects/{project_id}/entries/add_question",
body=await async_maybe_transform({"question": question}, entry_add_question_params.EntryAddQuestionParams),
@@ -646,6 +722,10 @@ async def query(
project_id: str,
*,
question: str,
+ x_client_library_version: str | NotGiven = NOT_GIVEN,
+ x_integration_type: str | NotGiven = NOT_GIVEN,
+ x_source: str | NotGiven = NOT_GIVEN,
+ x_stainless_package_version: str | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -674,6 +754,17 @@ async def query(
"""
if not project_id:
raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}")
+ extra_headers = {
+ **strip_not_given(
+ {
+ "x-client-library-version": x_client_library_version,
+ "x-integration-type": x_integration_type,
+ "x-source": x_source,
+ "x-stainless-package-version": x_stainless_package_version,
+ }
+ ),
+ **(extra_headers or {}),
+ }
return await self._post(
f"/api/projects/{project_id}/entries/query",
body=await async_maybe_transform({"question": question}, entry_query_params.EntryQueryParams),
diff --git a/src/codex/types/projects/access_key_create_params.py b/src/codex/types/projects/access_key_create_params.py
index 1cbc202f..cf5f00fb 100644
--- a/src/codex/types/projects/access_key_create_params.py
+++ b/src/codex/types/projects/access_key_create_params.py
@@ -17,3 +17,11 @@ class AccessKeyCreateParams(TypedDict, total=False):
description: Optional[str]
expires_at: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
+
+ x_client_library_version: Annotated[str, PropertyInfo(alias="x-client-library-version")]
+
+ x_integration_type: Annotated[str, PropertyInfo(alias="x-integration-type")]
+
+ x_source: Annotated[str, PropertyInfo(alias="x-source")]
+
+ x_stainless_package_version: Annotated[str, PropertyInfo(alias="x-stainless-package-version")]
diff --git a/src/codex/types/projects/entry_add_question_params.py b/src/codex/types/projects/entry_add_question_params.py
index e2d009b4..b310f96b 100644
--- a/src/codex/types/projects/entry_add_question_params.py
+++ b/src/codex/types/projects/entry_add_question_params.py
@@ -2,10 +2,20 @@
from __future__ import annotations
-from typing_extensions import Required, TypedDict
+from typing_extensions import Required, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
__all__ = ["EntryAddQuestionParams"]
class EntryAddQuestionParams(TypedDict, total=False):
question: Required[str]
+
+ x_client_library_version: Annotated[str, PropertyInfo(alias="x-client-library-version")]
+
+ x_integration_type: Annotated[str, PropertyInfo(alias="x-integration-type")]
+
+ x_source: Annotated[str, PropertyInfo(alias="x-source")]
+
+ x_stainless_package_version: Annotated[str, PropertyInfo(alias="x-stainless-package-version")]
diff --git a/src/codex/types/projects/entry_create_params.py b/src/codex/types/projects/entry_create_params.py
index daf30897..0022942f 100644
--- a/src/codex/types/projects/entry_create_params.py
+++ b/src/codex/types/projects/entry_create_params.py
@@ -3,7 +3,9 @@
from __future__ import annotations
from typing import Optional
-from typing_extensions import Required, TypedDict
+from typing_extensions import Required, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
__all__ = ["EntryCreateParams"]
@@ -14,3 +16,11 @@ class EntryCreateParams(TypedDict, total=False):
answer: Optional[str]
draft_answer: Optional[str]
+
+ x_client_library_version: Annotated[str, PropertyInfo(alias="x-client-library-version")]
+
+ x_integration_type: Annotated[str, PropertyInfo(alias="x-integration-type")]
+
+ x_source: Annotated[str, PropertyInfo(alias="x-source")]
+
+ x_stainless_package_version: Annotated[str, PropertyInfo(alias="x-stainless-package-version")]
diff --git a/src/codex/types/projects/entry_query_params.py b/src/codex/types/projects/entry_query_params.py
index b6fbc437..bc0e317c 100644
--- a/src/codex/types/projects/entry_query_params.py
+++ b/src/codex/types/projects/entry_query_params.py
@@ -2,10 +2,20 @@
from __future__ import annotations
-from typing_extensions import Required, TypedDict
+from typing_extensions import Required, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
__all__ = ["EntryQueryParams"]
class EntryQueryParams(TypedDict, total=False):
question: Required[str]
+
+ x_client_library_version: Annotated[str, PropertyInfo(alias="x-client-library-version")]
+
+ x_integration_type: Annotated[str, PropertyInfo(alias="x-integration-type")]
+
+ x_source: Annotated[str, PropertyInfo(alias="x-source")]
+
+ x_stainless_package_version: Annotated[str, PropertyInfo(alias="x-stainless-package-version")]
diff --git a/tests/api_resources/projects/test_access_keys.py b/tests/api_resources/projects/test_access_keys.py
index 240c31e1..ad4ee5e4 100644
--- a/tests/api_resources/projects/test_access_keys.py
+++ b/tests/api_resources/projects/test_access_keys.py
@@ -39,6 +39,10 @@ def test_method_create_with_all_params(self, client: Codex) -> None:
name="name",
description="description",
expires_at=parse_datetime("2019-12-27T18:11:19.117Z"),
+ x_client_library_version="x-client-library-version",
+ x_integration_type="x-integration-type",
+ x_source="x-source",
+ x_stainless_package_version="x-stainless-package-version",
)
assert_matches_type(AccessKeySchema, access_key, path=["response"])
@@ -395,6 +399,10 @@ async def test_method_create_with_all_params(self, async_client: AsyncCodex) ->
name="name",
description="description",
expires_at=parse_datetime("2019-12-27T18:11:19.117Z"),
+ x_client_library_version="x-client-library-version",
+ x_integration_type="x-integration-type",
+ x_source="x-source",
+ x_stainless_package_version="x-stainless-package-version",
)
assert_matches_type(AccessKeySchema, access_key, path=["response"])
diff --git a/tests/api_resources/projects/test_entries.py b/tests/api_resources/projects/test_entries.py
index fbbf6f25..8a18dc01 100644
--- a/tests/api_resources/projects/test_entries.py
+++ b/tests/api_resources/projects/test_entries.py
@@ -37,6 +37,10 @@ def test_method_create_with_all_params(self, client: Codex) -> None:
question="question",
answer="answer",
draft_answer="draft_answer",
+ x_client_library_version="x-client-library-version",
+ x_integration_type="x-integration-type",
+ x_source="x-source",
+ x_stainless_package_version="x-stainless-package-version",
)
assert_matches_type(Entry, entry, path=["response"])
@@ -312,6 +316,19 @@ def test_method_add_question(self, client: Codex) -> None:
)
assert_matches_type(Entry, entry, path=["response"])
+ @pytest.mark.skip()
+ @parametrize
+ def test_method_add_question_with_all_params(self, client: Codex) -> None:
+ entry = client.projects.entries.add_question(
+ project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ question="question",
+ x_client_library_version="x-client-library-version",
+ x_integration_type="x-integration-type",
+ x_source="x-source",
+ x_stainless_package_version="x-stainless-package-version",
+ )
+ assert_matches_type(Entry, entry, path=["response"])
+
@pytest.mark.skip()
@parametrize
def test_raw_response_add_question(self, client: Codex) -> None:
@@ -358,6 +375,19 @@ def test_method_query(self, client: Codex) -> None:
)
assert_matches_type(Optional[Entry], entry, path=["response"])
+ @pytest.mark.skip()
+ @parametrize
+ def test_method_query_with_all_params(self, client: Codex) -> None:
+ entry = client.projects.entries.query(
+ project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ question="question",
+ x_client_library_version="x-client-library-version",
+ x_integration_type="x-integration-type",
+ x_source="x-source",
+ x_stainless_package_version="x-stainless-package-version",
+ )
+ assert_matches_type(Optional[Entry], entry, path=["response"])
+
@pytest.mark.skip()
@parametrize
def test_raw_response_query(self, client: Codex) -> None:
@@ -416,6 +446,10 @@ async def test_method_create_with_all_params(self, async_client: AsyncCodex) ->
question="question",
answer="answer",
draft_answer="draft_answer",
+ x_client_library_version="x-client-library-version",
+ x_integration_type="x-integration-type",
+ x_source="x-source",
+ x_stainless_package_version="x-stainless-package-version",
)
assert_matches_type(Entry, entry, path=["response"])
@@ -691,6 +725,19 @@ async def test_method_add_question(self, async_client: AsyncCodex) -> None:
)
assert_matches_type(Entry, entry, path=["response"])
+ @pytest.mark.skip()
+ @parametrize
+ async def test_method_add_question_with_all_params(self, async_client: AsyncCodex) -> None:
+ entry = await async_client.projects.entries.add_question(
+ project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ question="question",
+ x_client_library_version="x-client-library-version",
+ x_integration_type="x-integration-type",
+ x_source="x-source",
+ x_stainless_package_version="x-stainless-package-version",
+ )
+ assert_matches_type(Entry, entry, path=["response"])
+
@pytest.mark.skip()
@parametrize
async def test_raw_response_add_question(self, async_client: AsyncCodex) -> None:
@@ -737,6 +784,19 @@ async def test_method_query(self, async_client: AsyncCodex) -> None:
)
assert_matches_type(Optional[Entry], entry, path=["response"])
+ @pytest.mark.skip()
+ @parametrize
+ async def test_method_query_with_all_params(self, async_client: AsyncCodex) -> None:
+ entry = await async_client.projects.entries.query(
+ project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ question="question",
+ x_client_library_version="x-client-library-version",
+ x_integration_type="x-integration-type",
+ x_source="x-source",
+ x_stainless_package_version="x-stainless-package-version",
+ )
+ assert_matches_type(Optional[Entry], entry, path=["response"])
+
@pytest.mark.skip()
@parametrize
async def test_raw_response_query(self, async_client: AsyncCodex) -> None:
From 6b97689646d7b3611ace81c630fafa1962b5c94d Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 27 Mar 2025 05:25:22 +0000
Subject: [PATCH 10/14] chore: fix typos (#91)
---
src/codex/_models.py | 2 +-
src/codex/_utils/_transform.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/codex/_models.py b/src/codex/_models.py
index b51a1bf5..34935716 100644
--- a/src/codex/_models.py
+++ b/src/codex/_models.py
@@ -681,7 +681,7 @@ def set_pydantic_config(typ: Any, config: pydantic.ConfigDict) -> None:
setattr(typ, "__pydantic_config__", config) # noqa: B010
-# our use of subclasssing here causes weirdness for type checkers,
+# our use of subclassing here causes weirdness for type checkers,
# so we just pretend that we don't subclass
if TYPE_CHECKING:
GenericModel = BaseModel
diff --git a/src/codex/_utils/_transform.py b/src/codex/_utils/_transform.py
index 18afd9d8..7ac2e17f 100644
--- a/src/codex/_utils/_transform.py
+++ b/src/codex/_utils/_transform.py
@@ -126,7 +126,7 @@ def _get_annotated_type(type_: type) -> type | None:
def _maybe_transform_key(key: str, type_: type) -> str:
"""Transform the given `data` based on the annotations provided in `type_`.
- Note: this function only looks at `Annotated` types that contain `PropertInfo` metadata.
+ Note: this function only looks at `Annotated` types that contain `PropertyInfo` metadata.
"""
annotated_type = _get_annotated_type(type_)
if annotated_type is None:
From c32a0ad259c79661a55ba563bd50ea1a6b590de5 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 27 Mar 2025 05:26:03 +0000
Subject: [PATCH 11/14] codegen metadata
---
.stats.yml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.stats.yml b/.stats.yml
index 7982133f..d526653e 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1 +1,3 @@
configured_endpoints: 37
+openapi_spec_hash: c2648fabb12e6096d5f7a3ab78300d66
+config_hash: 0529917e0e61d8cd6366481b77eff77e
From f22253d7ed83003b8ff9652b7d2f16e8bd744a54 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 27 Mar 2025 21:28:44 +0000
Subject: [PATCH 12/14] codegen metadata
---
.stats.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.stats.yml b/.stats.yml
index d526653e..893f8fab 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,3 +1,3 @@
configured_endpoints: 37
-openapi_spec_hash: c2648fabb12e6096d5f7a3ab78300d66
+openapi_spec_hash: 6993cffe14e021af26bf142f5b557263
config_hash: 0529917e0e61d8cd6366481b77eff77e
From 14da02311e598a1d5f4e41a100160b81befd4f61 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 2 Apr 2025 21:15:22 +0000
Subject: [PATCH 13/14] feat(api): updates from question grouping (#93)
---
.stats.yml | 6 +-
api.md | 20 +-
src/codex/pagination.py | 62 ++++
src/codex/resources/health.py | 50 ---
src/codex/resources/projects/__init__.py | 14 +
src/codex/resources/projects/clusters.py | 296 +++++++++++++++++
src/codex/resources/projects/entries.py | 299 +-----------------
src/codex/resources/projects/projects.py | 32 ++
src/codex/types/projects/__init__.py | 6 +-
..._list_params.py => cluster_list_params.py} | 10 +-
.../types/projects/cluster_list_response.py | 36 +++
.../cluster_list_variants_response.py | 14 +
src/codex/types/projects/entry.py | 8 +-
.../projects/entry_add_question_params.py | 21 --
.../types/projects/entry_query_response.py | 23 ++
.../types/projects/entry_update_params.py | 2 -
tests/api_resources/projects/test_clusters.py | 241 ++++++++++++++
tests/api_resources/projects/test_entries.py | 257 +--------------
tests/api_resources/test_health.py | 56 ----
19 files changed, 771 insertions(+), 682 deletions(-)
create mode 100644 src/codex/resources/projects/clusters.py
rename src/codex/types/projects/{entry_list_params.py => cluster_list_params.py} (66%)
create mode 100644 src/codex/types/projects/cluster_list_response.py
create mode 100644 src/codex/types/projects/cluster_list_variants_response.py
delete mode 100644 src/codex/types/projects/entry_add_question_params.py
create mode 100644 src/codex/types/projects/entry_query_response.py
create mode 100644 tests/api_resources/projects/test_clusters.py
diff --git a/.stats.yml b/.stats.yml
index 893f8fab..d2d3f6a5 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,3 +1,3 @@
-configured_endpoints: 37
-openapi_spec_hash: 6993cffe14e021af26bf142f5b557263
-config_hash: 0529917e0e61d8cd6366481b77eff77e
+configured_endpoints: 36
+openapi_spec_hash: 4e7cb2cd6132c29f60a87a958f617a41
+config_hash: adbedb6317fca6f566f54564cc341846
diff --git a/api.md b/api.md
index 5e258334..b241c15c 100644
--- a/api.md
+++ b/api.md
@@ -10,7 +10,6 @@ Methods:
- client.health.check() -> HealthCheckResponse
- client.health.db() -> HealthCheckResponse
-- client.health.weaviate() -> HealthCheckResponse
# Organizations
@@ -175,7 +174,7 @@ Methods:
Types:
```python
-from codex.types.projects import Entry
+from codex.types.projects import Entry, EntryQueryResponse
```
Methods:
@@ -183,10 +182,21 @@ Methods:
- client.projects.entries.create(project_id, \*\*params) -> Entry
- client.projects.entries.retrieve(entry_id, \*, project_id) -> Entry
- client.projects.entries.update(entry_id, \*, project_id, \*\*params) -> Entry
-- client.projects.entries.list(project_id, \*\*params) -> SyncOffsetPageEntries[Entry]
- client.projects.entries.delete(entry_id, \*, project_id) -> None
-- client.projects.entries.add_question(project_id, \*\*params) -> Entry
-- client.projects.entries.query(project_id, \*\*params) -> Optional[Entry]
+- client.projects.entries.query(project_id, \*\*params) -> EntryQueryResponse
+
+## Clusters
+
+Types:
+
+```python
+from codex.types.projects import ClusterListResponse, ClusterListVariantsResponse
+```
+
+Methods:
+
+- client.projects.clusters.list(project_id, \*\*params) -> SyncOffsetPageClusters[ClusterListResponse]
+- client.projects.clusters.list_variants(representative_entry_id, \*, project_id) -> ClusterListVariantsResponse
# Tlm
diff --git a/src/codex/pagination.py b/src/codex/pagination.py
index 48ed5018..1f590df5 100644
--- a/src/codex/pagination.py
+++ b/src/codex/pagination.py
@@ -12,6 +12,8 @@
__all__ = [
"SyncMyOffsetPageTopLevelArray",
"AsyncMyOffsetPageTopLevelArray",
+ "SyncOffsetPageClusters",
+ "AsyncOffsetPageClusters",
"SyncOffsetPageEntries",
"AsyncOffsetPageEntries",
]
@@ -83,6 +85,66 @@ def build(cls: Type[_BaseModelT], *, response: Response, data: object) -> _BaseM
)
+class SyncOffsetPageClusters(BaseSyncPage[_T], BasePage[_T], Generic[_T]):
+ clusters: List[_T]
+ total_count: Optional[int] = None
+
+ @override
+ def _get_page_items(self) -> List[_T]:
+ clusters = self.clusters
+ if not clusters:
+ return []
+ return clusters
+
+ @override
+ def next_page_info(self) -> Optional[PageInfo]:
+ offset = self._options.params.get("offset") or 0
+ if not isinstance(offset, int):
+ raise ValueError(f'Expected "offset" param to be an integer but got {offset}')
+
+ length = len(self._get_page_items())
+ current_count = offset + length
+
+ total_count = self.total_count
+ if total_count is None:
+ return None
+
+ if current_count < total_count:
+ return PageInfo(params={"offset": current_count})
+
+ return None
+
+
+class AsyncOffsetPageClusters(BaseAsyncPage[_T], BasePage[_T], Generic[_T]):
+ clusters: List[_T]
+ total_count: Optional[int] = None
+
+ @override
+ def _get_page_items(self) -> List[_T]:
+ clusters = self.clusters
+ if not clusters:
+ return []
+ return clusters
+
+ @override
+ def next_page_info(self) -> Optional[PageInfo]:
+ offset = self._options.params.get("offset") or 0
+ if not isinstance(offset, int):
+ raise ValueError(f'Expected "offset" param to be an integer but got {offset}')
+
+ length = len(self._get_page_items())
+ current_count = offset + length
+
+ total_count = self.total_count
+ if total_count is None:
+ return None
+
+ if current_count < total_count:
+ return PageInfo(params={"offset": current_count})
+
+ return None
+
+
class SyncOffsetPageEntries(BaseSyncPage[_T], BasePage[_T], Generic[_T]):
entries: List[_T]
total_count: Optional[int] = None
diff --git a/src/codex/resources/health.py b/src/codex/resources/health.py
index 6a777c63..d74d23a5 100644
--- a/src/codex/resources/health.py
+++ b/src/codex/resources/health.py
@@ -77,25 +77,6 @@ def db(
cast_to=HealthCheckResponse,
)
- def weaviate(
- self,
- *,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
- ) -> HealthCheckResponse:
- """Check the weaviate connection."""
- return self._get(
- "/api/health/weaviate",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=HealthCheckResponse,
- )
-
class AsyncHealthResource(AsyncAPIResource):
@cached_property
@@ -155,25 +136,6 @@ async def db(
cast_to=HealthCheckResponse,
)
- async def weaviate(
- self,
- *,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
- ) -> HealthCheckResponse:
- """Check the weaviate connection."""
- return await self._get(
- "/api/health/weaviate",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=HealthCheckResponse,
- )
-
class HealthResourceWithRawResponse:
def __init__(self, health: HealthResource) -> None:
@@ -185,9 +147,6 @@ def __init__(self, health: HealthResource) -> None:
self.db = to_raw_response_wrapper(
health.db,
)
- self.weaviate = to_raw_response_wrapper(
- health.weaviate,
- )
class AsyncHealthResourceWithRawResponse:
@@ -200,9 +159,6 @@ def __init__(self, health: AsyncHealthResource) -> None:
self.db = async_to_raw_response_wrapper(
health.db,
)
- self.weaviate = async_to_raw_response_wrapper(
- health.weaviate,
- )
class HealthResourceWithStreamingResponse:
@@ -215,9 +171,6 @@ def __init__(self, health: HealthResource) -> None:
self.db = to_streamed_response_wrapper(
health.db,
)
- self.weaviate = to_streamed_response_wrapper(
- health.weaviate,
- )
class AsyncHealthResourceWithStreamingResponse:
@@ -230,6 +183,3 @@ def __init__(self, health: AsyncHealthResource) -> None:
self.db = async_to_streamed_response_wrapper(
health.db,
)
- self.weaviate = async_to_streamed_response_wrapper(
- health.weaviate,
- )
diff --git a/src/codex/resources/projects/__init__.py b/src/codex/resources/projects/__init__.py
index 01599858..2c0595d2 100644
--- a/src/codex/resources/projects/__init__.py
+++ b/src/codex/resources/projects/__init__.py
@@ -8,6 +8,14 @@
EntriesResourceWithStreamingResponse,
AsyncEntriesResourceWithStreamingResponse,
)
+from .clusters import (
+ ClustersResource,
+ AsyncClustersResource,
+ ClustersResourceWithRawResponse,
+ AsyncClustersResourceWithRawResponse,
+ ClustersResourceWithStreamingResponse,
+ AsyncClustersResourceWithStreamingResponse,
+)
from .projects import (
ProjectsResource,
AsyncProjectsResource,
@@ -38,6 +46,12 @@
"AsyncEntriesResourceWithRawResponse",
"EntriesResourceWithStreamingResponse",
"AsyncEntriesResourceWithStreamingResponse",
+ "ClustersResource",
+ "AsyncClustersResource",
+ "ClustersResourceWithRawResponse",
+ "AsyncClustersResourceWithRawResponse",
+ "ClustersResourceWithStreamingResponse",
+ "AsyncClustersResourceWithStreamingResponse",
"ProjectsResource",
"AsyncProjectsResource",
"ProjectsResourceWithRawResponse",
diff --git a/src/codex/resources/projects/clusters.py b/src/codex/resources/projects/clusters.py
new file mode 100644
index 00000000..54b6c4c3
--- /dev/null
+++ b/src/codex/resources/projects/clusters.py
@@ -0,0 +1,296 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import List
+from typing_extensions import Literal
+
+import httpx
+
+from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from ..._utils import maybe_transform
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from ..._response import (
+ to_raw_response_wrapper,
+ to_streamed_response_wrapper,
+ async_to_raw_response_wrapper,
+ async_to_streamed_response_wrapper,
+)
+from ...pagination import SyncOffsetPageClusters, AsyncOffsetPageClusters
+from ..._base_client import AsyncPaginator, make_request_options
+from ...types.projects import cluster_list_params
+from ...types.projects.cluster_list_response import ClusterListResponse
+from ...types.projects.cluster_list_variants_response import ClusterListVariantsResponse
+
+__all__ = ["ClustersResource", "AsyncClustersResource"]
+
+
+class ClustersResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> ClustersResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/cleanlab/codex-python#accessing-raw-response-data-eg-headers
+ """
+ return ClustersResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> ClustersResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/cleanlab/codex-python#with_streaming_response
+ """
+ return ClustersResourceWithStreamingResponse(self)
+
+ def list(
+ self,
+ project_id: str,
+ *,
+ limit: int | NotGiven = NOT_GIVEN,
+ offset: int | NotGiven = NOT_GIVEN,
+ order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN,
+ sort: Literal["created_at", "answered_at", "cluster_frequency_count"] | NotGiven = NOT_GIVEN,
+ states: List[Literal["unanswered", "draft", "published", "published_with_draft"]] | NotGiven = NOT_GIVEN,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> SyncOffsetPageClusters[ClusterListResponse]:
+ """
+ List knowledge entries for a project.
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not project_id:
+ raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}")
+ return self._get_api_list(
+ f"/api/projects/{project_id}/entries/clusters",
+ page=SyncOffsetPageClusters[ClusterListResponse],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "limit": limit,
+ "offset": offset,
+ "order": order,
+ "sort": sort,
+ "states": states,
+ },
+ cluster_list_params.ClusterListParams,
+ ),
+ ),
+ model=ClusterListResponse,
+ )
+
+ def list_variants(
+ self,
+ representative_entry_id: str,
+ *,
+ project_id: str,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> ClusterListVariantsResponse:
+ """
+ Get Cluster Variants Route
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not project_id:
+ raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}")
+ if not representative_entry_id:
+ raise ValueError(
+ f"Expected a non-empty value for `representative_entry_id` but received {representative_entry_id!r}"
+ )
+ return self._get(
+ f"/api/projects/{project_id}/entries/clusters/{representative_entry_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ClusterListVariantsResponse,
+ )
+
+
+class AsyncClustersResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncClustersResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/cleanlab/codex-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncClustersResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncClustersResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/cleanlab/codex-python#with_streaming_response
+ """
+ return AsyncClustersResourceWithStreamingResponse(self)
+
+ def list(
+ self,
+ project_id: str,
+ *,
+ limit: int | NotGiven = NOT_GIVEN,
+ offset: int | NotGiven = NOT_GIVEN,
+ order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN,
+ sort: Literal["created_at", "answered_at", "cluster_frequency_count"] | NotGiven = NOT_GIVEN,
+ states: List[Literal["unanswered", "draft", "published", "published_with_draft"]] | NotGiven = NOT_GIVEN,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> AsyncPaginator[ClusterListResponse, AsyncOffsetPageClusters[ClusterListResponse]]:
+ """
+ List knowledge entries for a project.
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not project_id:
+ raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}")
+ return self._get_api_list(
+ f"/api/projects/{project_id}/entries/clusters",
+ page=AsyncOffsetPageClusters[ClusterListResponse],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "limit": limit,
+ "offset": offset,
+ "order": order,
+ "sort": sort,
+ "states": states,
+ },
+ cluster_list_params.ClusterListParams,
+ ),
+ ),
+ model=ClusterListResponse,
+ )
+
+ async def list_variants(
+ self,
+ representative_entry_id: str,
+ *,
+ project_id: str,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> ClusterListVariantsResponse:
+ """
+ Get Cluster Variants Route
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not project_id:
+ raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}")
+ if not representative_entry_id:
+ raise ValueError(
+ f"Expected a non-empty value for `representative_entry_id` but received {representative_entry_id!r}"
+ )
+ return await self._get(
+ f"/api/projects/{project_id}/entries/clusters/{representative_entry_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ClusterListVariantsResponse,
+ )
+
+
+class ClustersResourceWithRawResponse:
+ def __init__(self, clusters: ClustersResource) -> None:
+ self._clusters = clusters
+
+ self.list = to_raw_response_wrapper(
+ clusters.list,
+ )
+ self.list_variants = to_raw_response_wrapper(
+ clusters.list_variants,
+ )
+
+
+class AsyncClustersResourceWithRawResponse:
+ def __init__(self, clusters: AsyncClustersResource) -> None:
+ self._clusters = clusters
+
+ self.list = async_to_raw_response_wrapper(
+ clusters.list,
+ )
+ self.list_variants = async_to_raw_response_wrapper(
+ clusters.list_variants,
+ )
+
+
+class ClustersResourceWithStreamingResponse:
+ def __init__(self, clusters: ClustersResource) -> None:
+ self._clusters = clusters
+
+ self.list = to_streamed_response_wrapper(
+ clusters.list,
+ )
+ self.list_variants = to_streamed_response_wrapper(
+ clusters.list_variants,
+ )
+
+
+class AsyncClustersResourceWithStreamingResponse:
+ def __init__(self, clusters: AsyncClustersResource) -> None:
+ self._clusters = clusters
+
+ self.list = async_to_streamed_response_wrapper(
+ clusters.list,
+ )
+ self.list_variants = async_to_streamed_response_wrapper(
+ clusters.list_variants,
+ )
diff --git a/src/codex/resources/projects/entries.py b/src/codex/resources/projects/entries.py
index f5eebad6..8be96b06 100644
--- a/src/codex/resources/projects/entries.py
+++ b/src/codex/resources/projects/entries.py
@@ -2,8 +2,7 @@
from __future__ import annotations
-from typing import List, Optional
-from typing_extensions import Literal
+from typing import Optional
import httpx
@@ -21,16 +20,10 @@
async_to_raw_response_wrapper,
async_to_streamed_response_wrapper,
)
-from ...pagination import SyncOffsetPageEntries, AsyncOffsetPageEntries
-from ..._base_client import AsyncPaginator, make_request_options
-from ...types.projects import (
- entry_list_params,
- entry_query_params,
- entry_create_params,
- entry_update_params,
- entry_add_question_params,
-)
+from ..._base_client import make_request_options
+from ...types.projects import entry_query_params, entry_create_params, entry_update_params
from ...types.projects.entry import Entry
+from ...types.projects.entry_query_response import EntryQueryResponse
__all__ = ["EntriesResource", "AsyncEntriesResource"]
@@ -74,9 +67,7 @@ def create(
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> Entry:
"""
- Create a knowledge entry for a project.
-
- Raises: HTTPException: If an existing entry is found with the same question.
+ Create a new knowledge entry for a project.
Args:
extra_headers: Send extra headers
@@ -159,7 +150,6 @@ def update(
project_id: str,
answer: Optional[str] | NotGiven = NOT_GIVEN,
draft_answer: Optional[str] | NotGiven = NOT_GIVEN,
- frequency_count: Optional[int] | NotGiven = NOT_GIVEN,
question: Optional[str] | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -190,7 +180,6 @@ def update(
{
"answer": answer,
"draft_answer": draft_answer,
- "frequency_count": frequency_count,
"question": question,
},
entry_update_params.EntryUpdateParams,
@@ -201,62 +190,6 @@ def update(
cast_to=Entry,
)
- def list(
- self,
- project_id: str,
- *,
- answered_only: bool | NotGiven = NOT_GIVEN,
- limit: int | NotGiven = NOT_GIVEN,
- offset: int | NotGiven = NOT_GIVEN,
- order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN,
- sort: Literal["created_at", "answered_at"] | NotGiven = NOT_GIVEN,
- states: List[Literal["unanswered", "draft", "published", "published_with_draft"]] | NotGiven = NOT_GIVEN,
- unanswered_only: bool | NotGiven = NOT_GIVEN,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
- ) -> SyncOffsetPageEntries[Entry]:
- """
- List knowledge entries for a project.
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not project_id:
- raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}")
- return self._get_api_list(
- f"/api/projects/{project_id}/entries/",
- page=SyncOffsetPageEntries[Entry],
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=maybe_transform(
- {
- "answered_only": answered_only,
- "limit": limit,
- "offset": offset,
- "order": order,
- "sort": sort,
- "states": states,
- "unanswered_only": unanswered_only,
- },
- entry_list_params.EntryListParams,
- ),
- ),
- model=Entry,
- )
-
def delete(
self,
entry_id: str,
@@ -294,59 +227,6 @@ def delete(
cast_to=NoneType,
)
- def add_question(
- self,
- project_id: str,
- *,
- question: str,
- x_client_library_version: str | NotGiven = NOT_GIVEN,
- x_integration_type: str | NotGiven = NOT_GIVEN,
- x_source: str | NotGiven = NOT_GIVEN,
- x_stainless_package_version: str | NotGiven = NOT_GIVEN,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
- ) -> Entry:
- """
- Add a question to a project.
-
- Returns: 201 Created if a new question was added 200 OK if the question already
- existed
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not project_id:
- raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}")
- extra_headers = {
- **strip_not_given(
- {
- "x-client-library-version": x_client_library_version,
- "x-integration-type": x_integration_type,
- "x-source": x_source,
- "x-stainless-package-version": x_stainless_package_version,
- }
- ),
- **(extra_headers or {}),
- }
- return self._post(
- f"/api/projects/{project_id}/entries/add_question",
- body=maybe_transform({"question": question}, entry_add_question_params.EntryAddQuestionParams),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=Entry,
- )
-
def query(
self,
project_id: str,
@@ -362,16 +242,9 @@ def query(
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
- ) -> Optional[Entry]:
- """Query knowledge for a project.
-
- Also increments the frequency_count for the
- matching entry if found.
-
- Returns the matching entry if found and answered, otherwise returns None. This
- allows the client to distinguish between: (1) no matching question found
- (returns None), and (2) matching question found but not yet answered (returns
- Entry with answer=None).
+ ) -> EntryQueryResponse:
+ """
+ Query Entries Route
Args:
extra_headers: Send extra headers
@@ -401,7 +274,7 @@ def query(
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=Entry,
+ cast_to=EntryQueryResponse,
)
@@ -444,9 +317,7 @@ async def create(
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> Entry:
"""
- Create a knowledge entry for a project.
-
- Raises: HTTPException: If an existing entry is found with the same question.
+ Create a new knowledge entry for a project.
Args:
extra_headers: Send extra headers
@@ -529,7 +400,6 @@ async def update(
project_id: str,
answer: Optional[str] | NotGiven = NOT_GIVEN,
draft_answer: Optional[str] | NotGiven = NOT_GIVEN,
- frequency_count: Optional[int] | NotGiven = NOT_GIVEN,
question: Optional[str] | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -560,7 +430,6 @@ async def update(
{
"answer": answer,
"draft_answer": draft_answer,
- "frequency_count": frequency_count,
"question": question,
},
entry_update_params.EntryUpdateParams,
@@ -571,62 +440,6 @@ async def update(
cast_to=Entry,
)
- def list(
- self,
- project_id: str,
- *,
- answered_only: bool | NotGiven = NOT_GIVEN,
- limit: int | NotGiven = NOT_GIVEN,
- offset: int | NotGiven = NOT_GIVEN,
- order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN,
- sort: Literal["created_at", "answered_at"] | NotGiven = NOT_GIVEN,
- states: List[Literal["unanswered", "draft", "published", "published_with_draft"]] | NotGiven = NOT_GIVEN,
- unanswered_only: bool | NotGiven = NOT_GIVEN,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
- ) -> AsyncPaginator[Entry, AsyncOffsetPageEntries[Entry]]:
- """
- List knowledge entries for a project.
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not project_id:
- raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}")
- return self._get_api_list(
- f"/api/projects/{project_id}/entries/",
- page=AsyncOffsetPageEntries[Entry],
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=maybe_transform(
- {
- "answered_only": answered_only,
- "limit": limit,
- "offset": offset,
- "order": order,
- "sort": sort,
- "states": states,
- "unanswered_only": unanswered_only,
- },
- entry_list_params.EntryListParams,
- ),
- ),
- model=Entry,
- )
-
async def delete(
self,
entry_id: str,
@@ -664,59 +477,6 @@ async def delete(
cast_to=NoneType,
)
- async def add_question(
- self,
- project_id: str,
- *,
- question: str,
- x_client_library_version: str | NotGiven = NOT_GIVEN,
- x_integration_type: str | NotGiven = NOT_GIVEN,
- x_source: str | NotGiven = NOT_GIVEN,
- x_stainless_package_version: str | NotGiven = NOT_GIVEN,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
- ) -> Entry:
- """
- Add a question to a project.
-
- Returns: 201 Created if a new question was added 200 OK if the question already
- existed
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not project_id:
- raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}")
- extra_headers = {
- **strip_not_given(
- {
- "x-client-library-version": x_client_library_version,
- "x-integration-type": x_integration_type,
- "x-source": x_source,
- "x-stainless-package-version": x_stainless_package_version,
- }
- ),
- **(extra_headers or {}),
- }
- return await self._post(
- f"/api/projects/{project_id}/entries/add_question",
- body=await async_maybe_transform({"question": question}, entry_add_question_params.EntryAddQuestionParams),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=Entry,
- )
-
async def query(
self,
project_id: str,
@@ -732,16 +492,9 @@ async def query(
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
- ) -> Optional[Entry]:
- """Query knowledge for a project.
-
- Also increments the frequency_count for the
- matching entry if found.
-
- Returns the matching entry if found and answered, otherwise returns None. This
- allows the client to distinguish between: (1) no matching question found
- (returns None), and (2) matching question found but not yet answered (returns
- Entry with answer=None).
+ ) -> EntryQueryResponse:
+ """
+ Query Entries Route
Args:
extra_headers: Send extra headers
@@ -771,7 +524,7 @@ async def query(
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=Entry,
+ cast_to=EntryQueryResponse,
)
@@ -788,15 +541,9 @@ def __init__(self, entries: EntriesResource) -> None:
self.update = to_raw_response_wrapper(
entries.update,
)
- self.list = to_raw_response_wrapper(
- entries.list,
- )
self.delete = to_raw_response_wrapper(
entries.delete,
)
- self.add_question = to_raw_response_wrapper(
- entries.add_question,
- )
self.query = to_raw_response_wrapper(
entries.query,
)
@@ -815,15 +562,9 @@ def __init__(self, entries: AsyncEntriesResource) -> None:
self.update = async_to_raw_response_wrapper(
entries.update,
)
- self.list = async_to_raw_response_wrapper(
- entries.list,
- )
self.delete = async_to_raw_response_wrapper(
entries.delete,
)
- self.add_question = async_to_raw_response_wrapper(
- entries.add_question,
- )
self.query = async_to_raw_response_wrapper(
entries.query,
)
@@ -842,15 +583,9 @@ def __init__(self, entries: EntriesResource) -> None:
self.update = to_streamed_response_wrapper(
entries.update,
)
- self.list = to_streamed_response_wrapper(
- entries.list,
- )
self.delete = to_streamed_response_wrapper(
entries.delete,
)
- self.add_question = to_streamed_response_wrapper(
- entries.add_question,
- )
self.query = to_streamed_response_wrapper(
entries.query,
)
@@ -869,15 +604,9 @@ def __init__(self, entries: AsyncEntriesResource) -> None:
self.update = async_to_streamed_response_wrapper(
entries.update,
)
- self.list = async_to_streamed_response_wrapper(
- entries.list,
- )
self.delete = async_to_streamed_response_wrapper(
entries.delete,
)
- self.add_question = async_to_streamed_response_wrapper(
- entries.add_question,
- )
self.query = async_to_streamed_response_wrapper(
entries.query,
)
diff --git a/src/codex/resources/projects/projects.py b/src/codex/resources/projects/projects.py
index 38d7b036..8a7ff1b3 100644
--- a/src/codex/resources/projects/projects.py
+++ b/src/codex/resources/projects/projects.py
@@ -21,6 +21,14 @@
maybe_transform,
async_maybe_transform,
)
+from .clusters import (
+ ClustersResource,
+ AsyncClustersResource,
+ ClustersResourceWithRawResponse,
+ AsyncClustersResourceWithRawResponse,
+ ClustersResourceWithStreamingResponse,
+ AsyncClustersResourceWithStreamingResponse,
+)
from ..._compat import cached_property
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import (
@@ -53,6 +61,10 @@ def access_keys(self) -> AccessKeysResource:
def entries(self) -> EntriesResource:
return EntriesResource(self._client)
+ @cached_property
+ def clusters(self) -> ClustersResource:
+ return ClustersResource(self._client)
+
@cached_property
def with_raw_response(self) -> ProjectsResourceWithRawResponse:
"""
@@ -321,6 +333,10 @@ def access_keys(self) -> AsyncAccessKeysResource:
def entries(self) -> AsyncEntriesResource:
return AsyncEntriesResource(self._client)
+ @cached_property
+ def clusters(self) -> AsyncClustersResource:
+ return AsyncClustersResource(self._client)
+
@cached_property
def with_raw_response(self) -> AsyncProjectsResourceWithRawResponse:
"""
@@ -611,6 +627,10 @@ def access_keys(self) -> AccessKeysResourceWithRawResponse:
def entries(self) -> EntriesResourceWithRawResponse:
return EntriesResourceWithRawResponse(self._projects.entries)
+ @cached_property
+ def clusters(self) -> ClustersResourceWithRawResponse:
+ return ClustersResourceWithRawResponse(self._projects.clusters)
+
class AsyncProjectsResourceWithRawResponse:
def __init__(self, projects: AsyncProjectsResource) -> None:
@@ -643,6 +663,10 @@ def access_keys(self) -> AsyncAccessKeysResourceWithRawResponse:
def entries(self) -> AsyncEntriesResourceWithRawResponse:
return AsyncEntriesResourceWithRawResponse(self._projects.entries)
+ @cached_property
+ def clusters(self) -> AsyncClustersResourceWithRawResponse:
+ return AsyncClustersResourceWithRawResponse(self._projects.clusters)
+
class ProjectsResourceWithStreamingResponse:
def __init__(self, projects: ProjectsResource) -> None:
@@ -675,6 +699,10 @@ def access_keys(self) -> AccessKeysResourceWithStreamingResponse:
def entries(self) -> EntriesResourceWithStreamingResponse:
return EntriesResourceWithStreamingResponse(self._projects.entries)
+ @cached_property
+ def clusters(self) -> ClustersResourceWithStreamingResponse:
+ return ClustersResourceWithStreamingResponse(self._projects.clusters)
+
class AsyncProjectsResourceWithStreamingResponse:
def __init__(self, projects: AsyncProjectsResource) -> None:
@@ -706,3 +734,7 @@ def access_keys(self) -> AsyncAccessKeysResourceWithStreamingResponse:
@cached_property
def entries(self) -> AsyncEntriesResourceWithStreamingResponse:
return AsyncEntriesResourceWithStreamingResponse(self._projects.entries)
+
+ @cached_property
+ def clusters(self) -> AsyncClustersResourceWithStreamingResponse:
+ return AsyncClustersResourceWithStreamingResponse(self._projects.clusters)
diff --git a/src/codex/types/projects/__init__.py b/src/codex/types/projects/__init__.py
index 44c304f5..2733406c 100644
--- a/src/codex/types/projects/__init__.py
+++ b/src/codex/types/projects/__init__.py
@@ -4,14 +4,16 @@
from .entry import Entry as Entry
from .access_key_schema import AccessKeySchema as AccessKeySchema
-from .entry_list_params import EntryListParams as EntryListParams
from .entry_query_params import EntryQueryParams as EntryQueryParams
+from .cluster_list_params import ClusterListParams as ClusterListParams
from .entry_create_params import EntryCreateParams as EntryCreateParams
from .entry_update_params import EntryUpdateParams as EntryUpdateParams
+from .entry_query_response import EntryQueryResponse as EntryQueryResponse
+from .cluster_list_response import ClusterListResponse as ClusterListResponse
from .access_key_create_params import AccessKeyCreateParams as AccessKeyCreateParams
from .access_key_list_response import AccessKeyListResponse as AccessKeyListResponse
from .access_key_update_params import AccessKeyUpdateParams as AccessKeyUpdateParams
-from .entry_add_question_params import EntryAddQuestionParams as EntryAddQuestionParams
+from .cluster_list_variants_response import ClusterListVariantsResponse as ClusterListVariantsResponse
from .access_key_retrieve_project_id_response import (
AccessKeyRetrieveProjectIDResponse as AccessKeyRetrieveProjectIDResponse,
)
diff --git a/src/codex/types/projects/entry_list_params.py b/src/codex/types/projects/cluster_list_params.py
similarity index 66%
rename from src/codex/types/projects/entry_list_params.py
rename to src/codex/types/projects/cluster_list_params.py
index 605ea482..438b4812 100644
--- a/src/codex/types/projects/entry_list_params.py
+++ b/src/codex/types/projects/cluster_list_params.py
@@ -5,20 +5,16 @@
from typing import List
from typing_extensions import Literal, TypedDict
-__all__ = ["EntryListParams"]
+__all__ = ["ClusterListParams"]
-class EntryListParams(TypedDict, total=False):
- answered_only: bool
-
+class ClusterListParams(TypedDict, total=False):
limit: int
offset: int
order: Literal["asc", "desc"]
- sort: Literal["created_at", "answered_at"]
+ sort: Literal["created_at", "answered_at", "cluster_frequency_count"]
states: List[Literal["unanswered", "draft", "published", "published_with_draft"]]
-
- unanswered_only: bool
diff --git a/src/codex/types/projects/cluster_list_response.py b/src/codex/types/projects/cluster_list_response.py
new file mode 100644
index 00000000..7b4ef3ad
--- /dev/null
+++ b/src/codex/types/projects/cluster_list_response.py
@@ -0,0 +1,36 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["ClusterListResponse"]
+
+
+class ClusterListResponse(BaseModel):
+ id: str
+
+ cluster_frequency_count: int
+
+ created_at: datetime
+
+ project_id: str
+
+ question: str
+
+ state: Literal["unanswered", "draft", "published", "published_with_draft"]
+
+ answer: Optional[str] = None
+
+ answered_at: Optional[datetime] = None
+
+ draft_answer: Optional[str] = None
+
+ draft_answer_last_edited: Optional[datetime] = None
+
+ frequency_count: Optional[int] = None
+ """number of times the entry matched for a /query request"""
+
+ representative_entry_id: Optional[str] = None
diff --git a/src/codex/types/projects/cluster_list_variants_response.py b/src/codex/types/projects/cluster_list_variants_response.py
new file mode 100644
index 00000000..aa359058
--- /dev/null
+++ b/src/codex/types/projects/cluster_list_variants_response.py
@@ -0,0 +1,14 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List
+
+from .entry import Entry
+from ..._models import BaseModel
+
+__all__ = ["ClusterListVariantsResponse"]
+
+
+class ClusterListVariantsResponse(BaseModel):
+ entries: List[Entry]
+
+ total_count: int
diff --git a/src/codex/types/projects/entry.py b/src/codex/types/projects/entry.py
index 7a2c4502..442eddd8 100644
--- a/src/codex/types/projects/entry.py
+++ b/src/codex/types/projects/entry.py
@@ -10,14 +10,16 @@
class Entry(BaseModel):
+ id: str
+
created_at: datetime
+ project_id: str
+
question: str
state: Literal["unanswered", "draft", "published", "published_with_draft"]
- id: Optional[str] = None
-
answer: Optional[str] = None
answered_at: Optional[datetime] = None
@@ -25,5 +27,3 @@ class Entry(BaseModel):
draft_answer: Optional[str] = None
draft_answer_last_edited: Optional[datetime] = None
-
- frequency_count: Optional[int] = None
diff --git a/src/codex/types/projects/entry_add_question_params.py b/src/codex/types/projects/entry_add_question_params.py
deleted file mode 100644
index b310f96b..00000000
--- a/src/codex/types/projects/entry_add_question_params.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Required, Annotated, TypedDict
-
-from ..._utils import PropertyInfo
-
-__all__ = ["EntryAddQuestionParams"]
-
-
-class EntryAddQuestionParams(TypedDict, total=False):
- question: Required[str]
-
- x_client_library_version: Annotated[str, PropertyInfo(alias="x-client-library-version")]
-
- x_integration_type: Annotated[str, PropertyInfo(alias="x-integration-type")]
-
- x_source: Annotated[str, PropertyInfo(alias="x-source")]
-
- x_stainless_package_version: Annotated[str, PropertyInfo(alias="x-stainless-package-version")]
diff --git a/src/codex/types/projects/entry_query_response.py b/src/codex/types/projects/entry_query_response.py
new file mode 100644
index 00000000..ad106d7a
--- /dev/null
+++ b/src/codex/types/projects/entry_query_response.py
@@ -0,0 +1,23 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+
+from ..._models import BaseModel
+
+__all__ = ["EntryQueryResponse", "Entry"]
+
+
+class Entry(BaseModel):
+ id: str
+
+ question: str
+
+ answer: Optional[str] = None
+
+ draft_answer: Optional[str] = None
+
+
+class EntryQueryResponse(BaseModel):
+ entry: Entry
+
+ answer: Optional[str] = None
diff --git a/src/codex/types/projects/entry_update_params.py b/src/codex/types/projects/entry_update_params.py
index 05a6332d..aac256f9 100644
--- a/src/codex/types/projects/entry_update_params.py
+++ b/src/codex/types/projects/entry_update_params.py
@@ -15,6 +15,4 @@ class EntryUpdateParams(TypedDict, total=False):
draft_answer: Optional[str]
- frequency_count: Optional[int]
-
question: Optional[str]
diff --git a/tests/api_resources/projects/test_clusters.py b/tests/api_resources/projects/test_clusters.py
new file mode 100644
index 00000000..5a464970
--- /dev/null
+++ b/tests/api_resources/projects/test_clusters.py
@@ -0,0 +1,241 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from codex import Codex, AsyncCodex
+from tests.utils import assert_matches_type
+from codex.pagination import SyncOffsetPageClusters, AsyncOffsetPageClusters
+from codex.types.projects import ClusterListResponse, ClusterListVariantsResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestClusters:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_method_list(self, client: Codex) -> None:
+ cluster = client.projects.clusters.list(
+ project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(SyncOffsetPageClusters[ClusterListResponse], cluster, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_method_list_with_all_params(self, client: Codex) -> None:
+ cluster = client.projects.clusters.list(
+ project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ limit=1,
+ offset=0,
+ order="asc",
+ sort="created_at",
+ states=["unanswered"],
+ )
+ assert_matches_type(SyncOffsetPageClusters[ClusterListResponse], cluster, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_raw_response_list(self, client: Codex) -> None:
+ response = client.projects.clusters.with_raw_response.list(
+ project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ cluster = response.parse()
+ assert_matches_type(SyncOffsetPageClusters[ClusterListResponse], cluster, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_streaming_response_list(self, client: Codex) -> None:
+ with client.projects.clusters.with_streaming_response.list(
+ project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ cluster = response.parse()
+ assert_matches_type(SyncOffsetPageClusters[ClusterListResponse], cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_path_params_list(self, client: Codex) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"):
+ client.projects.clusters.with_raw_response.list(
+ project_id="",
+ )
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_method_list_variants(self, client: Codex) -> None:
+ cluster = client.projects.clusters.list_variants(
+ representative_entry_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(ClusterListVariantsResponse, cluster, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_raw_response_list_variants(self, client: Codex) -> None:
+ response = client.projects.clusters.with_raw_response.list_variants(
+ representative_entry_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ cluster = response.parse()
+ assert_matches_type(ClusterListVariantsResponse, cluster, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_streaming_response_list_variants(self, client: Codex) -> None:
+ with client.projects.clusters.with_streaming_response.list_variants(
+ representative_entry_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ cluster = response.parse()
+ assert_matches_type(ClusterListVariantsResponse, cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_path_params_list_variants(self, client: Codex) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"):
+ client.projects.clusters.with_raw_response.list_variants(
+ representative_entry_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ project_id="",
+ )
+
+ with pytest.raises(
+ ValueError, match=r"Expected a non-empty value for `representative_entry_id` but received ''"
+ ):
+ client.projects.clusters.with_raw_response.list_variants(
+ representative_entry_id="",
+ project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+
+class TestAsyncClusters:
+ parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_method_list(self, async_client: AsyncCodex) -> None:
+ cluster = await async_client.projects.clusters.list(
+ project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(AsyncOffsetPageClusters[ClusterListResponse], cluster, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncCodex) -> None:
+ cluster = await async_client.projects.clusters.list(
+ project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ limit=1,
+ offset=0,
+ order="asc",
+ sort="created_at",
+ states=["unanswered"],
+ )
+ assert_matches_type(AsyncOffsetPageClusters[ClusterListResponse], cluster, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncCodex) -> None:
+ response = await async_client.projects.clusters.with_raw_response.list(
+ project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ cluster = await response.parse()
+ assert_matches_type(AsyncOffsetPageClusters[ClusterListResponse], cluster, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncCodex) -> None:
+ async with async_client.projects.clusters.with_streaming_response.list(
+ project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ cluster = await response.parse()
+ assert_matches_type(AsyncOffsetPageClusters[ClusterListResponse], cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_path_params_list(self, async_client: AsyncCodex) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"):
+ await async_client.projects.clusters.with_raw_response.list(
+ project_id="",
+ )
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_method_list_variants(self, async_client: AsyncCodex) -> None:
+ cluster = await async_client.projects.clusters.list_variants(
+ representative_entry_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(ClusterListVariantsResponse, cluster, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_raw_response_list_variants(self, async_client: AsyncCodex) -> None:
+ response = await async_client.projects.clusters.with_raw_response.list_variants(
+ representative_entry_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ cluster = await response.parse()
+ assert_matches_type(ClusterListVariantsResponse, cluster, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_streaming_response_list_variants(self, async_client: AsyncCodex) -> None:
+ async with async_client.projects.clusters.with_streaming_response.list_variants(
+ representative_entry_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ cluster = await response.parse()
+ assert_matches_type(ClusterListVariantsResponse, cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_path_params_list_variants(self, async_client: AsyncCodex) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"):
+ await async_client.projects.clusters.with_raw_response.list_variants(
+ representative_entry_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ project_id="",
+ )
+
+ with pytest.raises(
+ ValueError, match=r"Expected a non-empty value for `representative_entry_id` but received ''"
+ ):
+ await async_client.projects.clusters.with_raw_response.list_variants(
+ representative_entry_id="",
+ project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
diff --git a/tests/api_resources/projects/test_entries.py b/tests/api_resources/projects/test_entries.py
index 8a18dc01..e8965e4a 100644
--- a/tests/api_resources/projects/test_entries.py
+++ b/tests/api_resources/projects/test_entries.py
@@ -3,16 +3,13 @@
from __future__ import annotations
import os
-from typing import Any, Optional, cast
+from typing import Any, cast
import pytest
from codex import Codex, AsyncCodex
from tests.utils import assert_matches_type
-from codex.pagination import SyncOffsetPageEntries, AsyncOffsetPageEntries
-from codex.types.projects import (
- Entry,
-)
+from codex.types.projects import Entry, EntryQueryResponse
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -150,7 +147,6 @@ def test_method_update_with_all_params(self, client: Codex) -> None:
project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
answer="answer",
draft_answer="draft_answer",
- frequency_count=0,
question="question",
)
assert_matches_type(Entry, entry, path=["response"])
@@ -198,63 +194,6 @@ def test_path_params_update(self, client: Codex) -> None:
project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
)
- @pytest.mark.skip()
- @parametrize
- def test_method_list(self, client: Codex) -> None:
- entry = client.projects.entries.list(
- project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
- )
- assert_matches_type(SyncOffsetPageEntries[Entry], entry, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- def test_method_list_with_all_params(self, client: Codex) -> None:
- entry = client.projects.entries.list(
- project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
- answered_only=True,
- limit=1,
- offset=0,
- order="asc",
- sort="created_at",
- states=["unanswered"],
- unanswered_only=True,
- )
- assert_matches_type(SyncOffsetPageEntries[Entry], entry, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- def test_raw_response_list(self, client: Codex) -> None:
- response = client.projects.entries.with_raw_response.list(
- project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- entry = response.parse()
- assert_matches_type(SyncOffsetPageEntries[Entry], entry, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- def test_streaming_response_list(self, client: Codex) -> None:
- with client.projects.entries.with_streaming_response.list(
- project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- entry = response.parse()
- assert_matches_type(SyncOffsetPageEntries[Entry], entry, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip()
- @parametrize
- def test_path_params_list(self, client: Codex) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"):
- client.projects.entries.with_raw_response.list(
- project_id="",
- )
-
@pytest.mark.skip()
@parametrize
def test_method_delete(self, client: Codex) -> None:
@@ -307,65 +246,6 @@ def test_path_params_delete(self, client: Codex) -> None:
project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
)
- @pytest.mark.skip()
- @parametrize
- def test_method_add_question(self, client: Codex) -> None:
- entry = client.projects.entries.add_question(
- project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
- question="question",
- )
- assert_matches_type(Entry, entry, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- def test_method_add_question_with_all_params(self, client: Codex) -> None:
- entry = client.projects.entries.add_question(
- project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
- question="question",
- x_client_library_version="x-client-library-version",
- x_integration_type="x-integration-type",
- x_source="x-source",
- x_stainless_package_version="x-stainless-package-version",
- )
- assert_matches_type(Entry, entry, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- def test_raw_response_add_question(self, client: Codex) -> None:
- response = client.projects.entries.with_raw_response.add_question(
- project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
- question="question",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- entry = response.parse()
- assert_matches_type(Entry, entry, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- def test_streaming_response_add_question(self, client: Codex) -> None:
- with client.projects.entries.with_streaming_response.add_question(
- project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
- question="question",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- entry = response.parse()
- assert_matches_type(Entry, entry, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip()
- @parametrize
- def test_path_params_add_question(self, client: Codex) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"):
- client.projects.entries.with_raw_response.add_question(
- project_id="",
- question="question",
- )
-
@pytest.mark.skip()
@parametrize
def test_method_query(self, client: Codex) -> None:
@@ -373,7 +253,7 @@ def test_method_query(self, client: Codex) -> None:
project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
question="question",
)
- assert_matches_type(Optional[Entry], entry, path=["response"])
+ assert_matches_type(EntryQueryResponse, entry, path=["response"])
@pytest.mark.skip()
@parametrize
@@ -386,7 +266,7 @@ def test_method_query_with_all_params(self, client: Codex) -> None:
x_source="x-source",
x_stainless_package_version="x-stainless-package-version",
)
- assert_matches_type(Optional[Entry], entry, path=["response"])
+ assert_matches_type(EntryQueryResponse, entry, path=["response"])
@pytest.mark.skip()
@parametrize
@@ -399,7 +279,7 @@ def test_raw_response_query(self, client: Codex) -> None:
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
entry = response.parse()
- assert_matches_type(Optional[Entry], entry, path=["response"])
+ assert_matches_type(EntryQueryResponse, entry, path=["response"])
@pytest.mark.skip()
@parametrize
@@ -412,7 +292,7 @@ def test_streaming_response_query(self, client: Codex) -> None:
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
entry = response.parse()
- assert_matches_type(Optional[Entry], entry, path=["response"])
+ assert_matches_type(EntryQueryResponse, entry, path=["response"])
assert cast(Any, response.is_closed) is True
@@ -559,7 +439,6 @@ async def test_method_update_with_all_params(self, async_client: AsyncCodex) ->
project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
answer="answer",
draft_answer="draft_answer",
- frequency_count=0,
question="question",
)
assert_matches_type(Entry, entry, path=["response"])
@@ -607,63 +486,6 @@ async def test_path_params_update(self, async_client: AsyncCodex) -> None:
project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
)
- @pytest.mark.skip()
- @parametrize
- async def test_method_list(self, async_client: AsyncCodex) -> None:
- entry = await async_client.projects.entries.list(
- project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
- )
- assert_matches_type(AsyncOffsetPageEntries[Entry], entry, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- async def test_method_list_with_all_params(self, async_client: AsyncCodex) -> None:
- entry = await async_client.projects.entries.list(
- project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
- answered_only=True,
- limit=1,
- offset=0,
- order="asc",
- sort="created_at",
- states=["unanswered"],
- unanswered_only=True,
- )
- assert_matches_type(AsyncOffsetPageEntries[Entry], entry, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- async def test_raw_response_list(self, async_client: AsyncCodex) -> None:
- response = await async_client.projects.entries.with_raw_response.list(
- project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- entry = await response.parse()
- assert_matches_type(AsyncOffsetPageEntries[Entry], entry, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- async def test_streaming_response_list(self, async_client: AsyncCodex) -> None:
- async with async_client.projects.entries.with_streaming_response.list(
- project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- entry = await response.parse()
- assert_matches_type(AsyncOffsetPageEntries[Entry], entry, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip()
- @parametrize
- async def test_path_params_list(self, async_client: AsyncCodex) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"):
- await async_client.projects.entries.with_raw_response.list(
- project_id="",
- )
-
@pytest.mark.skip()
@parametrize
async def test_method_delete(self, async_client: AsyncCodex) -> None:
@@ -716,65 +538,6 @@ async def test_path_params_delete(self, async_client: AsyncCodex) -> None:
project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
)
- @pytest.mark.skip()
- @parametrize
- async def test_method_add_question(self, async_client: AsyncCodex) -> None:
- entry = await async_client.projects.entries.add_question(
- project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
- question="question",
- )
- assert_matches_type(Entry, entry, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- async def test_method_add_question_with_all_params(self, async_client: AsyncCodex) -> None:
- entry = await async_client.projects.entries.add_question(
- project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
- question="question",
- x_client_library_version="x-client-library-version",
- x_integration_type="x-integration-type",
- x_source="x-source",
- x_stainless_package_version="x-stainless-package-version",
- )
- assert_matches_type(Entry, entry, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- async def test_raw_response_add_question(self, async_client: AsyncCodex) -> None:
- response = await async_client.projects.entries.with_raw_response.add_question(
- project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
- question="question",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- entry = await response.parse()
- assert_matches_type(Entry, entry, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- async def test_streaming_response_add_question(self, async_client: AsyncCodex) -> None:
- async with async_client.projects.entries.with_streaming_response.add_question(
- project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
- question="question",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- entry = await response.parse()
- assert_matches_type(Entry, entry, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip()
- @parametrize
- async def test_path_params_add_question(self, async_client: AsyncCodex) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"):
- await async_client.projects.entries.with_raw_response.add_question(
- project_id="",
- question="question",
- )
-
@pytest.mark.skip()
@parametrize
async def test_method_query(self, async_client: AsyncCodex) -> None:
@@ -782,7 +545,7 @@ async def test_method_query(self, async_client: AsyncCodex) -> None:
project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
question="question",
)
- assert_matches_type(Optional[Entry], entry, path=["response"])
+ assert_matches_type(EntryQueryResponse, entry, path=["response"])
@pytest.mark.skip()
@parametrize
@@ -795,7 +558,7 @@ async def test_method_query_with_all_params(self, async_client: AsyncCodex) -> N
x_source="x-source",
x_stainless_package_version="x-stainless-package-version",
)
- assert_matches_type(Optional[Entry], entry, path=["response"])
+ assert_matches_type(EntryQueryResponse, entry, path=["response"])
@pytest.mark.skip()
@parametrize
@@ -808,7 +571,7 @@ async def test_raw_response_query(self, async_client: AsyncCodex) -> None:
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
entry = await response.parse()
- assert_matches_type(Optional[Entry], entry, path=["response"])
+ assert_matches_type(EntryQueryResponse, entry, path=["response"])
@pytest.mark.skip()
@parametrize
@@ -821,7 +584,7 @@ async def test_streaming_response_query(self, async_client: AsyncCodex) -> None:
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
entry = await response.parse()
- assert_matches_type(Optional[Entry], entry, path=["response"])
+ assert_matches_type(EntryQueryResponse, entry, path=["response"])
assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/test_health.py b/tests/api_resources/test_health.py
index 09700120..ed942cd2 100644
--- a/tests/api_resources/test_health.py
+++ b/tests/api_resources/test_health.py
@@ -73,34 +73,6 @@ def test_streaming_response_db(self, client: Codex) -> None:
assert cast(Any, response.is_closed) is True
- @pytest.mark.skip()
- @parametrize
- def test_method_weaviate(self, client: Codex) -> None:
- health = client.health.weaviate()
- assert_matches_type(HealthCheckResponse, health, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- def test_raw_response_weaviate(self, client: Codex) -> None:
- response = client.health.with_raw_response.weaviate()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- health = response.parse()
- assert_matches_type(HealthCheckResponse, health, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- def test_streaming_response_weaviate(self, client: Codex) -> None:
- with client.health.with_streaming_response.weaviate() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- health = response.parse()
- assert_matches_type(HealthCheckResponse, health, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
class TestAsyncHealth:
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
@@ -160,31 +132,3 @@ async def test_streaming_response_db(self, async_client: AsyncCodex) -> None:
assert_matches_type(HealthCheckResponse, health, path=["response"])
assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip()
- @parametrize
- async def test_method_weaviate(self, async_client: AsyncCodex) -> None:
- health = await async_client.health.weaviate()
- assert_matches_type(HealthCheckResponse, health, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- async def test_raw_response_weaviate(self, async_client: AsyncCodex) -> None:
- response = await async_client.health.with_raw_response.weaviate()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- health = await response.parse()
- assert_matches_type(HealthCheckResponse, health, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- async def test_streaming_response_weaviate(self, async_client: AsyncCodex) -> None:
- async with async_client.health.with_streaming_response.weaviate() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- health = await response.parse()
- assert_matches_type(HealthCheckResponse, health, path=["response"])
-
- assert cast(Any, response.is_closed) is True
From 78be44a4186727fb5053099da3075f6ce81043de Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 2 Apr 2025 21:15:41 +0000
Subject: [PATCH 14/14] release: 0.1.0-alpha.13
---
.release-please-manifest.json | 2 +-
CHANGELOG.md | 26 ++++++++++++++++++++++++++
pyproject.toml | 2 +-
src/codex/_version.py | 2 +-
4 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index fd0ccba9..000572ec 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.1.0-alpha.12"
+ ".": "0.1.0-alpha.13"
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index abb16021..67d337b6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,31 @@
# Changelog
+## 0.1.0-alpha.13 (2025-04-02)
+
+Full Changelog: [v0.1.0-alpha.12...v0.1.0-alpha.13](https://github.com/cleanlab/codex-python/compare/v0.1.0-alpha.12...v0.1.0-alpha.13)
+
+### Features
+
+* **api:** api update ([#83](https://github.com/cleanlab/codex-python/issues/83)) ([b41e3bf](https://github.com/cleanlab/codex-python/commit/b41e3bf21e10b11b6d64e15f320cf3d8aa66bfb8))
+* **api:** api update ([#90](https://github.com/cleanlab/codex-python/issues/90)) ([52933f2](https://github.com/cleanlab/codex-python/commit/52933f2bc708e1f2b5f2e144071a9ee41b27251c))
+* **api:** updates from question grouping ([#93](https://github.com/cleanlab/codex-python/issues/93)) ([14da023](https://github.com/cleanlab/codex-python/commit/14da02311e598a1d5f4e41a100160b81befd4f61))
+
+
+### Bug Fixes
+
+* **ci:** ensure pip is always available ([#88](https://github.com/cleanlab/codex-python/issues/88)) ([86a40cc](https://github.com/cleanlab/codex-python/commit/86a40ccd3892d23bb12f78bf5ff13eaa23d8eb2d))
+* **ci:** remove publishing patch ([#89](https://github.com/cleanlab/codex-python/issues/89)) ([674c661](https://github.com/cleanlab/codex-python/commit/674c6613c7709c93cca936f086d5348041252972))
+* **types:** handle more discriminated union shapes ([#87](https://github.com/cleanlab/codex-python/issues/87)) ([ea6a942](https://github.com/cleanlab/codex-python/commit/ea6a9422c2a1ff25f14ade1a790ffd943dadbd81))
+
+
+### Chores
+
+* fix typos ([#91](https://github.com/cleanlab/codex-python/issues/91)) ([6b97689](https://github.com/cleanlab/codex-python/commit/6b97689646d7b3611ace81c630fafa1962b5c94d))
+* **internal:** bump rye to 0.44.0 ([#86](https://github.com/cleanlab/codex-python/issues/86)) ([e026b73](https://github.com/cleanlab/codex-python/commit/e026b73fb62aa19689890f14b7dcf355910029a8))
+* **internal:** codegen related update ([#85](https://github.com/cleanlab/codex-python/issues/85)) ([7e1eaca](https://github.com/cleanlab/codex-python/commit/7e1eaca4c5f2c779b264c34883688b52e1a8602e))
+* **internal:** remove extra empty newlines ([#84](https://github.com/cleanlab/codex-python/issues/84)) ([e4b2929](https://github.com/cleanlab/codex-python/commit/e4b2929d58b466199bb02e24b8e0a7c9c63f1b3a))
+* **internal:** version bump ([#81](https://github.com/cleanlab/codex-python/issues/81)) ([7ee4e09](https://github.com/cleanlab/codex-python/commit/7ee4e09545e52eaa3d10522709e833b38221ecad))
+
## 0.1.0-alpha.12 (2025-03-11)
Full Changelog: [v0.1.0-alpha.11...v0.1.0-alpha.12](https://github.com/cleanlab/codex-python/compare/v0.1.0-alpha.11...v0.1.0-alpha.12)
diff --git a/pyproject.toml b/pyproject.toml
index 61f43447..70b5b9c2 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "codex-sdk"
-version = "0.1.0-alpha.12"
+version = "0.1.0-alpha.13"
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 fe7cc739..8790f4ea 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.12" # x-release-please-version
+__version__ = "0.1.0-alpha.13" # x-release-please-version