From 8dd01a1e69d82ccbc4f05b72bd980d16cb93e5e5 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 19 Feb 2025 04:39:14 +0000
Subject: [PATCH 1/6] chore(internal): codegen related update (#551)
---
README.md | 19 +++++++++++++++++++
src/runloop_api_client/_files.py | 2 +-
2 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index f480d2d45..cf864f391 100644
--- a/README.md
+++ b/README.md
@@ -136,6 +136,25 @@ for devbox in first_page.devboxes:
# Remove `await` for non-async usage.
```
+## File uploads
+
+Request parameters that correspond to file uploads can be passed as `bytes`, a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance or a tuple of `(filename, contents, media type)`.
+
+```python
+from pathlib import Path
+from runloop_api_client import Runloop
+
+client = Runloop()
+
+client.devboxes.upload_file(
+ id="id",
+ path="path",
+ file=Path("/path/to/file"),
+)
+```
+
+The async client uses the exact same interface. If you pass a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance, the file contents will be read asynchronously automatically.
+
## Handling errors
When the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `runloop_api_client.APIConnectionError` is raised.
diff --git a/src/runloop_api_client/_files.py b/src/runloop_api_client/_files.py
index 715cc2078..1b1825115 100644
--- a/src/runloop_api_client/_files.py
+++ b/src/runloop_api_client/_files.py
@@ -34,7 +34,7 @@ def assert_is_file_content(obj: object, *, key: str | None = None) -> None:
if not is_file_content(obj):
prefix = f"Expected entry at `{key}`" if key is not None else f"Expected file input `{obj!r}`"
raise RuntimeError(
- f"{prefix} to be bytes, an io.IOBase instance, PathLike or a tuple but received {type(obj)} instead."
+ f"{prefix} to be bytes, an io.IOBase instance, PathLike or a tuple but received {type(obj)} instead. See https://github.com/runloopai/api-client-python/tree/main#file-uploads"
) from None
From dc21caec97e15ccde2c396c6a2f0fce0f2bad313 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 21 Feb 2025 06:31:28 +0000
Subject: [PATCH 2/6] feat(client): allow passing `NotGiven` for body (#553)
fix(client): mark some request bodies as optional
---
src/runloop_api_client/_base_client.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/runloop_api_client/_base_client.py b/src/runloop_api_client/_base_client.py
index 22e3bc630..6ed767c04 100644
--- a/src/runloop_api_client/_base_client.py
+++ b/src/runloop_api_client/_base_client.py
@@ -518,7 +518,7 @@ def _build_request(
# so that passing a `TypedDict` doesn't cause an error.
# https://github.com/microsoft/pyright/issues/3526#event-6715453066
params=self.qs.stringify(cast(Mapping[str, Any], params)) if params else None,
- json=json_data,
+ json=json_data if is_given(json_data) else None,
files=files,
**kwargs,
)
From 9260eb4443fc50ecb07e99af2307896e32027158 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Sat, 22 Feb 2025 04:47:09 +0000
Subject: [PATCH 3/6] chore(internal): fix devcontainers setup (#554)
---
.devcontainer/Dockerfile | 2 +-
.devcontainer/devcontainer.json | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index ac9a2e752..55d20255c 100644
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -6,4 +6,4 @@ USER vscode
RUN curl -sSf https://rye.astral.sh/get | RYE_VERSION="0.35.0" RYE_INSTALL_OPTION="--yes" bash
ENV PATH=/home/vscode/.rye/shims:$PATH
-RUN echo "[[ -d .venv ]] && source .venv/bin/activate" >> /home/vscode/.bashrc
+RUN echo "[[ -d .venv ]] && source .venv/bin/activate || export PATH=\$PATH" >> /home/vscode/.bashrc
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index bbeb30b14..c17fdc169 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -24,6 +24,9 @@
}
}
}
+ },
+ "features": {
+ "ghcr.io/devcontainers/features/node:1": {}
}
// Features to add to the dev container. More info: https://containers.dev/features.
From 7c1d55de7fe3f157a30080ddc7e7f0ea5053304a Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 26 Feb 2025 01:47:17 +0000
Subject: [PATCH 4/6] feat(api): api update (#555)
---
.stats.yml | 4 +-
api.md | 1 +
.../resources/scenarios/scenarios.py | 157 +++++++++++
src/runloop_api_client/types/__init__.py | 1 +
.../types/scenario_update_params.py | 36 +++
.../types/scoring_function.py | 2 +-
.../types/scoring_function_param.py | 2 +-
tests/api_resources/test_scenarios.py | 246 ++++++++++++++++++
8 files changed, 445 insertions(+), 4 deletions(-)
create mode 100644 src/runloop_api_client/types/scenario_update_params.py
diff --git a/.stats.yml b/.stats.yml
index 89dc8775e..08c183bf8 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,2 +1,2 @@
-configured_endpoints: 77
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-cb8add05a7b418d6f8a5624be8477564853da49e8bf9671ae89b8ce49a04b6cd.yml
+configured_endpoints: 78
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-4ccbc7c04012cbcca678f13e39f66bb770b8b3a9d6f1815ce1b9c20fee099128.yml
diff --git a/api.md b/api.md
index 90c237349..aaecbbfdd 100644
--- a/api.md
+++ b/api.md
@@ -278,6 +278,7 @@ Methods:
- client.scenarios.create(\*\*params) -> ScenarioView
- client.scenarios.retrieve(id) -> ScenarioView
+- client.scenarios.update(id, \*\*params) -> ScenarioView
- client.scenarios.list(\*\*params) -> SyncScenariosCursorIDPage[ScenarioView]
- client.scenarios.list_public(\*\*params) -> SyncScenariosCursorIDPage[ScenarioView]
- client.scenarios.start_run(\*\*params) -> ScenarioRunView
diff --git a/src/runloop_api_client/resources/scenarios/scenarios.py b/src/runloop_api_client/resources/scenarios/scenarios.py
index 54a3dfbbd..d76cae28d 100644
--- a/src/runloop_api_client/resources/scenarios/scenarios.py
+++ b/src/runloop_api_client/resources/scenarios/scenarios.py
@@ -17,6 +17,7 @@
from ...types import (
scenario_list_params,
scenario_create_params,
+ scenario_update_params,
scenario_start_run_params,
scenario_list_public_params,
)
@@ -183,6 +184,78 @@ def retrieve(
cast_to=ScenarioView,
)
+ def update(
+ self,
+ id: str,
+ *,
+ input_context: InputContextParam,
+ name: str,
+ scoring_contract: ScoringContractParam,
+ environment_parameters: Optional[ScenarioEnvironmentParam] | NotGiven = NOT_GIVEN,
+ metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN,
+ reference_output: 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ idempotency_key: str | None = None,
+ ) -> ScenarioView:
+ """
+ Update a Scenario, a repeatable AI coding evaluation test that defines the
+ starting environment as well as evaluation success criteria.
+
+ Args:
+ input_context: The input context for the Scenario.
+
+ name: Name of the scenario.
+
+ scoring_contract: The scoring contract for the Scenario.
+
+ environment_parameters: The Environment in which the Scenario will run.
+
+ metadata: User defined metadata to attach to the scenario for organization.
+
+ reference_output: A string representation of the reference output to solve the scenario. Commonly
+ can be the result of a git diff or a sequence of command actions to apply to the
+ environment.
+
+ 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
+
+ idempotency_key: Specify a custom idempotency key for this request
+ """
+ if not id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return self._post(
+ f"/v1/scenarios/{id}",
+ body=maybe_transform(
+ {
+ "input_context": input_context,
+ "name": name,
+ "scoring_contract": scoring_contract,
+ "environment_parameters": environment_parameters,
+ "metadata": metadata,
+ "reference_output": reference_output,
+ },
+ scenario_update_params.ScenarioUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
+ ),
+ cast_to=ScenarioView,
+ )
+
def list(
self,
*,
@@ -532,6 +605,78 @@ async def retrieve(
cast_to=ScenarioView,
)
+ async def update(
+ self,
+ id: str,
+ *,
+ input_context: InputContextParam,
+ name: str,
+ scoring_contract: ScoringContractParam,
+ environment_parameters: Optional[ScenarioEnvironmentParam] | NotGiven = NOT_GIVEN,
+ metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN,
+ reference_output: 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ idempotency_key: str | None = None,
+ ) -> ScenarioView:
+ """
+ Update a Scenario, a repeatable AI coding evaluation test that defines the
+ starting environment as well as evaluation success criteria.
+
+ Args:
+ input_context: The input context for the Scenario.
+
+ name: Name of the scenario.
+
+ scoring_contract: The scoring contract for the Scenario.
+
+ environment_parameters: The Environment in which the Scenario will run.
+
+ metadata: User defined metadata to attach to the scenario for organization.
+
+ reference_output: A string representation of the reference output to solve the scenario. Commonly
+ can be the result of a git diff or a sequence of command actions to apply to the
+ environment.
+
+ 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
+
+ idempotency_key: Specify a custom idempotency key for this request
+ """
+ if not id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return await self._post(
+ f"/v1/scenarios/{id}",
+ body=await async_maybe_transform(
+ {
+ "input_context": input_context,
+ "name": name,
+ "scoring_contract": scoring_contract,
+ "environment_parameters": environment_parameters,
+ "metadata": metadata,
+ "reference_output": reference_output,
+ },
+ scenario_update_params.ScenarioUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
+ ),
+ cast_to=ScenarioView,
+ )
+
def list(
self,
*,
@@ -738,6 +883,9 @@ def __init__(self, scenarios: ScenariosResource) -> None:
self.retrieve = to_raw_response_wrapper(
scenarios.retrieve,
)
+ self.update = to_raw_response_wrapper(
+ scenarios.update,
+ )
self.list = to_raw_response_wrapper(
scenarios.list,
)
@@ -767,6 +915,9 @@ def __init__(self, scenarios: AsyncScenariosResource) -> None:
self.retrieve = async_to_raw_response_wrapper(
scenarios.retrieve,
)
+ self.update = async_to_raw_response_wrapper(
+ scenarios.update,
+ )
self.list = async_to_raw_response_wrapper(
scenarios.list,
)
@@ -796,6 +947,9 @@ def __init__(self, scenarios: ScenariosResource) -> None:
self.retrieve = to_streamed_response_wrapper(
scenarios.retrieve,
)
+ self.update = to_streamed_response_wrapper(
+ scenarios.update,
+ )
self.list = to_streamed_response_wrapper(
scenarios.list,
)
@@ -825,6 +979,9 @@ def __init__(self, scenarios: AsyncScenariosResource) -> None:
self.retrieve = async_to_streamed_response_wrapper(
scenarios.retrieve,
)
+ self.update = async_to_streamed_response_wrapper(
+ scenarios.update,
+ )
self.list = async_to_streamed_response_wrapper(
scenarios.list,
)
diff --git a/src/runloop_api_client/types/__init__.py b/src/runloop_api_client/types/__init__.py
index 62b6d30e3..31b76176f 100644
--- a/src/runloop_api_client/types/__init__.py
+++ b/src/runloop_api_client/types/__init__.py
@@ -35,6 +35,7 @@
from .repository_list_params import RepositoryListParams as RepositoryListParams
from .scenario_create_params import ScenarioCreateParams as ScenarioCreateParams
from .scenario_run_list_view import ScenarioRunListView as ScenarioRunListView
+from .scenario_update_params import ScenarioUpdateParams as ScenarioUpdateParams
from .scoring_contract_param import ScoringContractParam as ScoringContractParam
from .scoring_function_param import ScoringFunctionParam as ScoringFunctionParam
from .benchmark_create_params import BenchmarkCreateParams as BenchmarkCreateParams
diff --git a/src/runloop_api_client/types/scenario_update_params.py b/src/runloop_api_client/types/scenario_update_params.py
new file mode 100644
index 000000000..1004e7bc8
--- /dev/null
+++ b/src/runloop_api_client/types/scenario_update_params.py
@@ -0,0 +1,36 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict, Optional
+from typing_extensions import Required, TypedDict
+
+from .input_context_param import InputContextParam
+from .scoring_contract_param import ScoringContractParam
+from .scenario_environment_param import ScenarioEnvironmentParam
+
+__all__ = ["ScenarioUpdateParams"]
+
+
+class ScenarioUpdateParams(TypedDict, total=False):
+ input_context: Required[InputContextParam]
+ """The input context for the Scenario."""
+
+ name: Required[str]
+ """Name of the scenario."""
+
+ scoring_contract: Required[ScoringContractParam]
+ """The scoring contract for the Scenario."""
+
+ environment_parameters: Optional[ScenarioEnvironmentParam]
+ """The Environment in which the Scenario will run."""
+
+ metadata: Optional[Dict[str, str]]
+ """User defined metadata to attach to the scenario for organization."""
+
+ reference_output: Optional[str]
+ """A string representation of the reference output to solve the scenario.
+
+ Commonly can be the result of a git diff or a sequence of command actions to
+ apply to the environment.
+ """
diff --git a/src/runloop_api_client/types/scoring_function.py b/src/runloop_api_client/types/scoring_function.py
index bef775eca..f7a2a6e0d 100644
--- a/src/runloop_api_client/types/scoring_function.py
+++ b/src/runloop_api_client/types/scoring_function.py
@@ -20,7 +20,7 @@ class ScoringFunction(BaseModel):
"""
weight: float
- """Wight to apply to scoring function score.
+ """Weight to apply to scoring function score.
Weights of all scoring functions should sum to 1.0.
"""
diff --git a/src/runloop_api_client/types/scoring_function_param.py b/src/runloop_api_client/types/scoring_function_param.py
index 0caa61468..5bcbacc58 100644
--- a/src/runloop_api_client/types/scoring_function_param.py
+++ b/src/runloop_api_client/types/scoring_function_param.py
@@ -21,7 +21,7 @@ class ScoringFunctionParam(TypedDict, total=False):
"""
weight: Required[float]
- """Wight to apply to scoring function score.
+ """Weight to apply to scoring function score.
Weights of all scoring functions should sum to 1.0.
"""
diff --git a/tests/api_resources/test_scenarios.py b/tests/api_resources/test_scenarios.py
index 245da96bd..218ebb542 100644
--- a/tests/api_resources/test_scenarios.py
+++ b/tests/api_resources/test_scenarios.py
@@ -160,6 +160,129 @@ def test_path_params_retrieve(self, client: Runloop) -> None:
"",
)
+ @parametrize
+ def test_method_update(self, client: Runloop) -> None:
+ scenario = client.scenarios.update(
+ id="id",
+ input_context={"problem_statement": "problem_statement"},
+ name="name",
+ scoring_contract={
+ "scoring_function_parameters": [
+ {
+ "name": "name",
+ "type": "type",
+ "weight": 0,
+ }
+ ]
+ },
+ )
+ assert_matches_type(ScenarioView, scenario, path=["response"])
+
+ @parametrize
+ def test_method_update_with_all_params(self, client: Runloop) -> None:
+ scenario = client.scenarios.update(
+ id="id",
+ input_context={
+ "problem_statement": "problem_statement",
+ "additional_context": {},
+ },
+ name="name",
+ scoring_contract={
+ "scoring_function_parameters": [
+ {
+ "name": "name",
+ "type": "type",
+ "weight": 0,
+ "bash_script": "bash_script",
+ "scorer_params": {},
+ }
+ ]
+ },
+ environment_parameters={
+ "blueprint_id": "blueprint_id",
+ "launch_parameters": {
+ "after_idle": {
+ "idle_time_seconds": 0,
+ "on_idle": "shutdown",
+ },
+ "available_ports": [0],
+ "keep_alive_time_seconds": 0,
+ "launch_commands": ["string"],
+ "resource_size_request": "SMALL",
+ },
+ "prebuilt_id": "prebuilt_id",
+ "snapshot_id": "snapshot_id",
+ "working_directory": "working_directory",
+ },
+ metadata={"foo": "string"},
+ reference_output="reference_output",
+ )
+ assert_matches_type(ScenarioView, scenario, path=["response"])
+
+ @parametrize
+ def test_raw_response_update(self, client: Runloop) -> None:
+ response = client.scenarios.with_raw_response.update(
+ id="id",
+ input_context={"problem_statement": "problem_statement"},
+ name="name",
+ scoring_contract={
+ "scoring_function_parameters": [
+ {
+ "name": "name",
+ "type": "type",
+ "weight": 0,
+ }
+ ]
+ },
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ scenario = response.parse()
+ assert_matches_type(ScenarioView, scenario, path=["response"])
+
+ @parametrize
+ def test_streaming_response_update(self, client: Runloop) -> None:
+ with client.scenarios.with_streaming_response.update(
+ id="id",
+ input_context={"problem_statement": "problem_statement"},
+ name="name",
+ scoring_contract={
+ "scoring_function_parameters": [
+ {
+ "name": "name",
+ "type": "type",
+ "weight": 0,
+ }
+ ]
+ },
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ scenario = response.parse()
+ assert_matches_type(ScenarioView, scenario, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_update(self, client: Runloop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ client.scenarios.with_raw_response.update(
+ id="",
+ input_context={"problem_statement": "problem_statement"},
+ name="name",
+ scoring_contract={
+ "scoring_function_parameters": [
+ {
+ "name": "name",
+ "type": "type",
+ "weight": 0,
+ }
+ ]
+ },
+ )
+
@parametrize
def test_method_list(self, client: Runloop) -> None:
scenario = client.scenarios.list()
@@ -412,6 +535,129 @@ async def test_path_params_retrieve(self, async_client: AsyncRunloop) -> None:
"",
)
+ @parametrize
+ async def test_method_update(self, async_client: AsyncRunloop) -> None:
+ scenario = await async_client.scenarios.update(
+ id="id",
+ input_context={"problem_statement": "problem_statement"},
+ name="name",
+ scoring_contract={
+ "scoring_function_parameters": [
+ {
+ "name": "name",
+ "type": "type",
+ "weight": 0,
+ }
+ ]
+ },
+ )
+ assert_matches_type(ScenarioView, scenario, path=["response"])
+
+ @parametrize
+ async def test_method_update_with_all_params(self, async_client: AsyncRunloop) -> None:
+ scenario = await async_client.scenarios.update(
+ id="id",
+ input_context={
+ "problem_statement": "problem_statement",
+ "additional_context": {},
+ },
+ name="name",
+ scoring_contract={
+ "scoring_function_parameters": [
+ {
+ "name": "name",
+ "type": "type",
+ "weight": 0,
+ "bash_script": "bash_script",
+ "scorer_params": {},
+ }
+ ]
+ },
+ environment_parameters={
+ "blueprint_id": "blueprint_id",
+ "launch_parameters": {
+ "after_idle": {
+ "idle_time_seconds": 0,
+ "on_idle": "shutdown",
+ },
+ "available_ports": [0],
+ "keep_alive_time_seconds": 0,
+ "launch_commands": ["string"],
+ "resource_size_request": "SMALL",
+ },
+ "prebuilt_id": "prebuilt_id",
+ "snapshot_id": "snapshot_id",
+ "working_directory": "working_directory",
+ },
+ metadata={"foo": "string"},
+ reference_output="reference_output",
+ )
+ assert_matches_type(ScenarioView, scenario, path=["response"])
+
+ @parametrize
+ async def test_raw_response_update(self, async_client: AsyncRunloop) -> None:
+ response = await async_client.scenarios.with_raw_response.update(
+ id="id",
+ input_context={"problem_statement": "problem_statement"},
+ name="name",
+ scoring_contract={
+ "scoring_function_parameters": [
+ {
+ "name": "name",
+ "type": "type",
+ "weight": 0,
+ }
+ ]
+ },
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ scenario = await response.parse()
+ assert_matches_type(ScenarioView, scenario, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_update(self, async_client: AsyncRunloop) -> None:
+ async with async_client.scenarios.with_streaming_response.update(
+ id="id",
+ input_context={"problem_statement": "problem_statement"},
+ name="name",
+ scoring_contract={
+ "scoring_function_parameters": [
+ {
+ "name": "name",
+ "type": "type",
+ "weight": 0,
+ }
+ ]
+ },
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ scenario = await response.parse()
+ assert_matches_type(ScenarioView, scenario, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_update(self, async_client: AsyncRunloop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ await async_client.scenarios.with_raw_response.update(
+ id="",
+ input_context={"problem_statement": "problem_statement"},
+ name="name",
+ scoring_contract={
+ "scoring_function_parameters": [
+ {
+ "name": "name",
+ "type": "type",
+ "weight": 0,
+ }
+ ]
+ },
+ )
+
@parametrize
async def test_method_list(self, async_client: AsyncRunloop) -> None:
scenario = await async_client.scenarios.list()
From 449683002d1fb31b01c4d167973058684b7ee654 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 26 Feb 2025 03:59:14 +0000
Subject: [PATCH 5/6] chore(internal): properly set __pydantic_private__ (#556)
---
src/runloop_api_client/_base_client.py | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/runloop_api_client/_base_client.py b/src/runloop_api_client/_base_client.py
index 6ed767c04..7e97db227 100644
--- a/src/runloop_api_client/_base_client.py
+++ b/src/runloop_api_client/_base_client.py
@@ -63,7 +63,7 @@
ModelBuilderProtocol,
)
from ._utils import is_dict, is_list, asyncify, is_given, lru_cache, is_mapping
-from ._compat import model_copy, model_dump
+from ._compat import PYDANTIC_V2, model_copy, model_dump
from ._models import GenericModel, FinalRequestOptions, validate_type, construct_type
from ._response import (
APIResponse,
@@ -207,6 +207,9 @@ def _set_private_attributes(
model: Type[_T],
options: FinalRequestOptions,
) -> None:
+ if PYDANTIC_V2 and getattr(self, "__pydantic_private__", None) is None:
+ self.__pydantic_private__ = {}
+
self._model = model
self._client = client
self._options = options
@@ -292,6 +295,9 @@ def _set_private_attributes(
client: AsyncAPIClient,
options: FinalRequestOptions,
) -> None:
+ if PYDANTIC_V2 and getattr(self, "__pydantic_private__", None) is None:
+ self.__pydantic_private__ = {}
+
self._model = model
self._client = client
self._options = options
From 6e07d96968f46936ce69ee25a14238dce5d41e37 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 26 Feb 2025 03:59:35 +0000
Subject: [PATCH 6/6] release: 0.25.0
---
.release-please-manifest.json | 2 +-
CHANGELOG.md | 21 +++++++++++++++++++++
pyproject.toml | 2 +-
src/runloop_api_client/_version.py | 2 +-
4 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index d2d60a3df..a36746b8b 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.24.0"
+ ".": "0.25.0"
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a27f0172d..8bceee61e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,26 @@
# Changelog
+## 0.25.0 (2025-02-26)
+
+Full Changelog: [v0.24.0...v0.25.0](https://github.com/runloopai/api-client-python/compare/v0.24.0...v0.25.0)
+
+### Features
+
+* **api:** api update ([#555](https://github.com/runloopai/api-client-python/issues/555)) ([7c1d55d](https://github.com/runloopai/api-client-python/commit/7c1d55de7fe3f157a30080ddc7e7f0ea5053304a))
+* **client:** allow passing `NotGiven` for body ([#553](https://github.com/runloopai/api-client-python/issues/553)) ([dc21cae](https://github.com/runloopai/api-client-python/commit/dc21caec97e15ccde2c396c6a2f0fce0f2bad313))
+
+
+### Bug Fixes
+
+* **client:** mark some request bodies as optional ([dc21cae](https://github.com/runloopai/api-client-python/commit/dc21caec97e15ccde2c396c6a2f0fce0f2bad313))
+
+
+### Chores
+
+* **internal:** codegen related update ([#551](https://github.com/runloopai/api-client-python/issues/551)) ([8dd01a1](https://github.com/runloopai/api-client-python/commit/8dd01a1e69d82ccbc4f05b72bd980d16cb93e5e5))
+* **internal:** fix devcontainers setup ([#554](https://github.com/runloopai/api-client-python/issues/554)) ([9260eb4](https://github.com/runloopai/api-client-python/commit/9260eb4443fc50ecb07e99af2307896e32027158))
+* **internal:** properly set __pydantic_private__ ([#556](https://github.com/runloopai/api-client-python/issues/556)) ([4496830](https://github.com/runloopai/api-client-python/commit/449683002d1fb31b01c4d167973058684b7ee654))
+
## 0.24.0 (2025-02-19)
Full Changelog: [v0.23.0...v0.24.0](https://github.com/runloopai/api-client-python/compare/v0.23.0...v0.24.0)
diff --git a/pyproject.toml b/pyproject.toml
index 1e703a82d..377bb5507 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "runloop_api_client"
-version = "0.24.0"
+version = "0.25.0"
description = "The official Python library for the runloop API"
dynamic = ["readme"]
license = "MIT"
diff --git a/src/runloop_api_client/_version.py b/src/runloop_api_client/_version.py
index c03b20ee6..2bb1b212e 100644
--- a/src/runloop_api_client/_version.py
+++ b/src/runloop_api_client/_version.py
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
__title__ = "runloop_api_client"
-__version__ = "0.24.0" # x-release-please-version
+__version__ = "0.25.0" # x-release-please-version