circuit-breaker-labs 1.0.7
A client library for accessing Circuit Breaker Labs API
Requires Python: >=3.10

# Circuit Breaker Labs Python Client

![Python Version](https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2Fcircuitbreakerlabs%2Fcircuitbreakerlabs-python%2Frefs%2Fheads%2Fmain%2Fpyproject.toml&logo=python&logoColor=yellow&label=Python&color=blue)
![Ruff](https://img.shields.io/badge/Ruff-Check-34223D?logo=ruff)
[![MyPy](https://img.shields.io/badge/Mypy-Check-blue?logo=python)](https://github.com/circuitbreakerlabs/circuitbreakerlabs-python/actions/workflows/type-checking.yml)
[![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv)
[![PyPI - Version](https://img.shields.io/pypi/v/circuit-breaker-labs?logo=pypi&label=PyPi)](https://pypi.org/project/circuit-breaker-labs/)

<!-- prettier-ignore-start -->
> [!Note]
> This project was automatically generated by [OpenAPI Python Client](https://github.com/openapi-generators/openapi-python-client)
> from [this OpenAPI spec](https://github.com/circuitbreakerlabs/circuitbreakerlabs-python/blob/main/openapi.json).
<!-- prettier-ignore-end -->

## Installation

Install from PyPi directly:

```sh
uv pip install circuit-breaker-labs
```

Or install using a wheel/sdist distributed with [each release](https://github.com/circuitbreakerlabs/circuitbreakerlabs-python/releases).

## Usage

First, create a client:

```python
from circuit_breaker_labs import Client

client = Client(base_url="https://api.circuitbreakerlabs.ai/v1/")
```

Now build a request and use it when calling an endpoint

```python
import os

from circuit_breaker_labs.api.evaluations import singleturn_evaluate_system_prompt_post
from circuit_breaker_labs.models import SingleTurnEvaluateSystemPromptRequest

with client as client:
    request = SingleTurnEvaluateSystemPromptRequest(
        threshold=0.5,
        variations=3,
        maximum_iteration_layers=2,
        system_prompt=os.getenv("SYSTEM_PROMPT"),
        openrouter_model_name="anthropic/claude-3.7-sonnet",
    )

    run_tests_response = singleturn_evaluate_system_prompt_post.sync(
        client=client,
        cbl_api_key=os.getenv("CBL_API_KEY"),
        body=request,
    )
```

Or do the same thing with an async version:

```python
import os

from circuit_breaker_labs.api.evaluations import singleturn_evaluate_system_prompt_post
from circuit_breaker_labs.models import SingleTurnEvaluateSystemPromptRequest

async with client as client:
    request = SingleTurnEvaluateSystemPromptRequest(
        threshold=0.5,
        variations=3,
        maximum_iteration_layers=2,
        system_prompt=os.getenv("SYSTEM_PROMPT"),
        openrouter_model_name="anthropic/claude-3.7-sonnet",
    )

    run_tests_response = await singleturn_evaluate_system_prompt_post.asyncio(
        client=client,
        cbl_api_key=os.getenv("CBL_API_KEY"),
        body=request,
    )
```

Want to test multi-turn conversations instead? Use the multi-turn endpoint (async version also available):

```python
import os

from circuit_breaker_labs.api.evaluations import multi_turn_evaluate_system_prompt_post
from circuit_breaker_labs.models import (
    MultiTurnEvaluateSystemPromptRequest,
    MultiTurnTestType,
    TestCasePack,
)

with client as client:
    request = MultiTurnEvaluateSystemPromptRequest(
        threshold=0.6,
        max_turns=6,
        test_types=[
            MultiTurnTestType.SEMANTIC_CHUNKS,
            MultiTurnTestType.USER_PERSONA,
        ],
        system_prompt=os.getenv("SYSTEM_PROMPT"),
        openrouter_model_name="anthropic/claude-3.7-sonnet",
        test_case_packs=[TestCasePack.SUICIDAL_IDEATION],
    )

    run_tests_response = multi_turn_evaluate_system_prompt_post.sync(
        client=client,
        cbl_api_key=os.getenv("CBL_API_KEY"),
        body=request,
    )
```

Things to know:

1. Every path/method combo becomes a Python module with four functions:
   1. `sync`: Blocking request that returns parsed data (if successful) or `None`
   1. `sync_detailed`: Blocking request that always returns a `Request`, optionally with `parsed` set if the request was successful.
   1. `asyncio`: Like `sync` but async instead of blocking
   1. `asyncio_detailed`: Like `sync_detailed` but async instead of blocking

1. All path/query params, and bodies become method arguments.
1. If your endpoint had any tags on it, the first tag will be used as a module name for the function (my_tag above)
1. Any endpoint which did not have a tag will be in `circuit_breaker_labs.api.default`

## Advanced customizations

There are more settings on the generated `Client` class which let you control more runtime behavior, check out the docstring on that class for more info. You can also customize the underlying `httpx.Client` or `httpx.AsyncClient` (depending on your use-case):

```python
from circuit_breaker_labs import Client

def log_request(request):
    print(f"Request event hook: {request.method} {request.url} - Waiting for response")

def log_response(response):
    request = response.request
    print(f"Response event hook: {request.method} {request.url} - Status {response.status_code}")

client = Client(
    base_url="https://api.circuitbreakerlabs.ai/v1/",
    httpx_args={"event_hooks": {"request": [log_request], "response": [log_response]}},
)

# Or get the underlying httpx client to modify directly with client.get_httpx_client() or client.get_async_httpx_client()
```

You can even set the httpx client directly, but beware that this will override any existing settings (e.g., base_url):

```python
import httpx
from circuit_breaker_labs import Client

client = Client(
    base_url="https://api.circuitbreakerlabs.ai/v1/",
)
# Note that base_url needs to be re-set, as would any shared cookies, headers, etc.
client.set_httpx_client(httpx.Client(base_url="https://api.circuitbreakerlabs.ai/v1/", proxies="http://localhost:8030"))
```