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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ codegen.log
Brewfile.lock.json

.DS_Store
.coverage
.coveragedocs/review/
marc-only/
4 changes: 2 additions & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,8 @@ trace_eval = client.trace_evaluations.create(
judge_id=judge.id,
)

# Get results
results = client.trace_evaluations.get_results(trace_eval.id)
# Wait for completion and get results
result = client.trace_evaluations.wait_for_completion(trace_eval.id)
```

### Custom models
Expand Down
13 changes: 13 additions & 0 deletions docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@
* [Judges and Traces](examples/judges-and-traces.md)
* [Public API](examples/public-api.md)

## Samples & Tutorials
* [Samples Overview](samples-guide.md)
* [Core SDK Operations](samples-guide.md#core-sdk-operations-18-samples) -- Traces, judges, evaluations, results, models, benchmarks, async
* [Industry Solutions](samples-guide.md#industry-solutions-10-samples) -- Healthcare, finance, legal, government, insurance, retail
* [Multi-Agent Evaluation](samples-guide.md#multi-agent-evaluation-5-samples) -- Cowork and Agent Teams patterns
* [Content-Type Evaluations](samples-guide.md#content-type-evaluations-3-samples) -- Text, brand, document
* [CI/CD Integration](samples-guide.md#cicd-integration-2-samples--workflow) -- Quality gates, pre-commit hooks, GitHub Actions
* [LLM Provider Integrations](samples-guide.md#llm-provider-integrations-2-samples) -- OpenAI, Anthropic
* [OpenClaw Agent Evaluation](samples-guide.md#openclaw-agent-evaluation-10-demos--skill) -- Cage match, code gate, safety audit, red-team
* [MCP Server](samples-guide.md#mcp-server-1-sample) -- LayerLens as tools for Claude and other MCP clients
* [CopilotKit Integration](samples-guide.md#copilotkit-integration-2-agents--ui-components) -- LangGraph CoAgents, React components
* [Claude Code Skills](samples-guide.md#claude-code-skills-6-skills) -- Slash commands for CLI and desktop

## Troubleshooting
* [Overview](troubleshooting/README.md)
* [Common Issues](troubleshooting/common-issues.md)
Expand Down
30 changes: 24 additions & 6 deletions docs/api-reference/client.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,14 @@ client = AsyncStratix(api_key="your_api_key")

## Constructor Parameters

### `Stratix(api_key, base_url, timeout)` and `AsyncStratix(api_key, base_url, timeout)`
### `Stratix(api_key, base_url, timeout, max_retries)` and `AsyncStratix(api_key, base_url, timeout, max_retries)`

| Parameter | Type | Required | Default | Description |
| ---------- | -------------------------------- | -------- | ------------- | ----------------------------- |
| `api_key` | `str \| None` | Yes\* | `None` | Your LayerLens Stratix API key |
| `base_url` | `str \| httpx.URL \| None` | No | Stratix API URL | Custom API base URL |
| `timeout` | `float \| httpx.Timeout \| None` | No | 10 minutes | Request timeout configuration |
| Parameter | Type | Required | Default | Description |
| ------------- | -------------------------------- | -------- | ------------- | ----------------------------- |
| `api_key` | `str \| None` | Yes\* | `None` | Your LayerLens Stratix API key |
| `base_url` | `str \| httpx.URL \| None` | No | Stratix API URL | Custom API base URL |
| `timeout` | `float \| httpx.Timeout \| None` | No | 10 minutes | Request timeout configuration |
| `max_retries` | `int` | No | `2` | Maximum number of retries on retryable errors (429, 500, 502, 503, 504) |

\*Required unless set via environment variables

Expand Down Expand Up @@ -81,6 +82,23 @@ from layerlens import Stratix
client = Stratix(timeout=30.0)
```

### Retry Configuration

The client automatically retries requests that fail with retryable status codes (429 Too Many Requests, 500, 502, 503, 504) using exponential backoff. If the server sends a `Retry-After` header, the client respects it.

```python
from layerlens import Stratix

# Default: 2 retries
client = Stratix()

# More retries for batch-heavy workloads
client = Stratix(max_retries=5)

# Disable retries entirely
client = Stratix(max_retries=0)
```

### Per-Request Timeout Override

```python
Expand Down
2 changes: 1 addition & 1 deletion docs/api-reference/judges.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ Creates a new judge with the specified evaluation criteria.
| ----------------- | -------------------------------- | -------- | -------------------------------------------- |
| `name` | `str` | Yes | Display name for the judge |
| `evaluation_goal` | `str` | Yes | Description of what the judge should evaluate |
| `model_id` | `str \| None` | Yes* | ID of the LLM model to use (required by API)|
| `model_id` | `str \| None` | No | ID of the LLM model to use. If omitted, the server uses a default model |
| `timeout` | `float \| httpx.Timeout \| None` | No | Override request timeout |

#### Returns
Expand Down
73 changes: 57 additions & 16 deletions docs/api-reference/trace-evaluations.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ evaluation = client.trace_evaluations.create(
judge_id="judge-123",
)

# Get results
results = client.trace_evaluations.get_results(evaluation.id)
for result in results.results:
# Wait for completion and get results
result = client.trace_evaluations.wait_for_completion(evaluation.id)
if result:
print(f"Score: {result.score}, Passed: {result.passed}")
print(f"Reasoning: {result.reasoning}")
```
Expand All @@ -47,8 +47,8 @@ async def main():
judge_id="judge-123",
)

results = await client.trace_evaluations.get_results(evaluation.id)
for result in results.results:
result = await client.trace_evaluations.wait_for_completion(evaluation.id)
if result:
print(f"Score: {result.score}, Passed: {result.passed}")

if __name__ == "__main__":
Expand Down Expand Up @@ -149,6 +149,8 @@ response = client.trace_evaluations.get_many(

Retrieves the detailed results of a completed trace evaluation, including scores, reasoning, and step-by-step analysis.

Returns `None` if results are not yet available (evaluation still pending or in progress).

#### Parameters

| Parameter | Type | Required | Description |
Expand All @@ -158,23 +160,62 @@ Retrieves the detailed results of a completed trace evaluation, including scores

#### Returns

Returns a `TraceEvaluationResultsResponse` object containing:
Returns a `TraceEvaluationResultsResponse` object with the evaluation result fields (score, passed, reasoning, etc.).

- `results`: List of `TraceEvaluationResult` objects
Returns `None` if the evaluation has not completed yet or if the request fails.

Returns `None` if the request fails.
#### Example

```python
result = client.trace_evaluations.get_results("eval-123")
if result:
print(f"Score: {result.score}")
print(f"Passed: {result.passed}")
print(f"Reasoning: {result.reasoning}")
for step in result.steps:
print(f" Tool: {step.tool}, Result: {step.result}")
```

### `wait_for_completion(id, interval_seconds=3, timeout_seconds=300)`

Polls the evaluation status until it reaches a terminal state (success or failure), then returns the results. This is the recommended way to wait for trace evaluation results.

#### Parameters

| Parameter | Type | Required | Default | Description |
| ------------------ | -------------- | -------- | ------- | ------------------------------------------------ |
| `id` | `str` | Yes | | The unique trace evaluation ID |
| `interval_seconds` | `int` | No | `3` | Seconds between status polls |
| `timeout_seconds` | `int \| None` | No | `300` | Maximum wait time. `None` waits indefinitely |

#### Returns

Returns a `TraceEvaluationResultsResponse` object if the evaluation completes successfully.

Returns `None` if the evaluation failed or no results are available.

Raises `TimeoutError` if `timeout_seconds` is exceeded.

#### Example

```python
results_response = client.trace_evaluations.get_results("eval-123")
if results_response:
for result in results_response.results:
print(f"Score: {result.score}")
print(f"Passed: {result.passed}")
print(f"Reasoning: {result.reasoning}")
for step in result.steps:
print(f" Step {step.step}: {step.reasoning}")
evaluation = client.trace_evaluations.create(
trace_id="trace-abc",
judge_id="judge-xyz",
)

# Wait up to 5 minutes for results
result = client.trace_evaluations.wait_for_completion(evaluation.id)
if result:
print(f"Score: {result.score}, Passed: {result.passed}")
print(f"Reasoning: {result.reasoning}")

# Custom timeout and polling interval
result = client.trace_evaluations.wait_for_completion(
evaluation.id,
interval_seconds=5,
timeout_seconds=600,
)
```

### `estimate_cost(trace_ids, judge_id, timeout=None)`
Expand Down
61 changes: 27 additions & 34 deletions docs/examples/README.md
Original file line number Diff line number Diff line change
@@ -1,41 +1,34 @@
# Examples
# Code Examples

This section provides practical code examples for common SDK use cases. All examples are available as runnable scripts in the [`examples/`](../../examples/) directory.
This section provides practical code examples for common SDK use cases. All examples are available as runnable scripts in the [`samples/`](../../samples/) directory.

## Quick Reference

| Example | Description |
| ------- | ----------- |
| [`client_simple.py`](../../examples/client_simple.py) | Minimal sync client usage |
| [`client.py`](../../examples/client.py) | Full sync evaluation workflow |
| [`async_client_simple.py`](../../examples/async_client_simple.py) | Minimal async client usage |
| [`async_client.py`](../../examples/async_client.py) | Full async evaluation workflow |
| [`async_run_evaluations.py`](../../examples/async_run_evaluations.py) | Run multiple evaluations in parallel |
| [`get_models.py`](../../examples/get_models.py) | Filter models by name, company, region, type |
| [`get_benchmarks.py`](../../examples/get_benchmarks.py) | Filter benchmarks by name and type |
| [`get_evaluation.py`](../../examples/get_evaluation.py) | Fetch an evaluation by ID |
| [`evaluation_sorting.py`](../../examples/evaluation_sorting.py) | Sort and filter evaluations |
| [`compare_evaluations.py`](../../examples/compare_evaluations.py) | Compare two models on a benchmark |
| [`paginated_results.py`](../../examples/paginated_results.py) | Paginate through evaluation results |
| [`all_results_no_pagination.py`](../../examples/all_results_no_pagination.py) | Fetch all results at once |
| [`fetch_results_async.py`](../../examples/fetch_results_async.py) | Fetch results for multiple evaluations concurrently |
| [`create_custom_model.py`](../../examples/create_custom_model.py) | Create a custom model with an OpenAI-compatible API |
| [`create_custom_benchmark.py`](../../examples/create_custom_benchmark.py) | Create a custom benchmark from a JSONL file |
| [`create_smart_benchmark.py`](../../examples/create_smart_benchmark.py) | Create an AI-generated benchmark from documents |
| [`manage_project_models_benchmarks.py`](../../examples/manage_project_models_benchmarks.py) | Add/remove models and benchmarks from a project |
| [`judges.py`](../../examples/judges.py) | Create, list, update, and delete judges |
| [`traces.py`](../../examples/traces.py) | Upload, list, get, and delete traces |
| [`trace_evaluations.py`](../../examples/trace_evaluations.py) | Run judges on traces, estimate cost, get results |
| [`async_judges_and_traces.py`](../../examples/async_judges_and_traces.py) | Async judge and trace evaluation workflow |
| [`judge_optimizations.py`](../../examples/judge_optimizations.py) | Estimate, run, and apply judge optimizations |
| [`public_models.py`](../../examples/public_models.py) | Browse, search, and filter public models |
| [`public_benchmarks.py`](../../examples/public_benchmarks.py) | Browse public benchmarks and download prompts |
| [`public_evaluations.py`](../../examples/public_evaluations.py) | Get public evaluation details and results |
| Sample | Description |
|--------|-------------|
| [`benchmark_evaluation.py`](../../samples/core/benchmark_evaluation.py) | Run a model against a benchmark, wait for completion, retrieve results |
| [`quickstart.py`](../../samples/core/quickstart.py) | Minimal end-to-end trace evaluation |
| [`async_workflow.py`](../../samples/core/async_workflow.py) | Full async evaluation workflow with concurrent operations |
| [`async_results.py`](../../samples/core/async_results.py) | Fetch results for multiple evaluations concurrently |
| [`model_benchmark_management.py`](../../samples/core/model_benchmark_management.py) | Filter models by name/company/region, add/remove from project |
| [`evaluation_filtering.py`](../../samples/core/evaluation_filtering.py) | Sort and filter evaluations by status, accuracy, date |
| [`compare_evaluations.py`](../../samples/core/compare_evaluations.py) | Compare two models on a benchmark with outcome filtering |
| [`paginated_results.py`](../../samples/core/paginated_results.py) | Paginate through results or fetch all at once |
| [`custom_model.py`](../../samples/core/custom_model.py) | Register a custom model with an OpenAI-compatible API |
| [`custom_benchmark.py`](../../samples/core/custom_benchmark.py) | Create custom and smart benchmarks from data files |
| [`create_judge.py`](../../samples/core/create_judge.py) | Create, list, update, and delete judges |
| [`basic_trace.py`](../../samples/core/basic_trace.py) | Upload, list, get, and delete traces |
| [`trace_evaluation.py`](../../samples/core/trace_evaluation.py) | Run judges on traces, estimate cost, get results with steps |
| [`judge_optimization.py`](../../samples/core/judge_optimization.py) | Estimate, run, and apply judge optimizations |
| [`public_catalog.py`](../../samples/core/public_catalog.py) | Browse public models, benchmarks, evaluations, and prompts |
| [`integration_management.py`](../../samples/core/integration_management.py) | List, inspect, and test configured integrations |

## Guides

- [Creating Evaluations](creating-evaluations.md) - Sync, async, and parallel evaluations
- [Retrieving Results](retrieving-results.md) - Paginated, bulk, and concurrent result fetching
- [Models and Benchmarks](models-and-benchmarks.md) - Filtering, custom models, custom/smart benchmarks, project management
- [Judges and Traces](judges-and-traces.md) - Judge CRUD, trace uploads, trace evaluations, and optimizations
- [Public API](public-api.md) - Public models, benchmarks, evaluations, and comparisons
- [Creating Evaluations](creating-evaluations.md) -- Sync, async, and parallel evaluations
- [Retrieving Results](retrieving-results.md) -- Paginated, bulk, and concurrent result fetching
- [Models and Benchmarks](models-and-benchmarks.md) -- Filtering, custom models, custom/smart benchmarks, project management
- [Judges and Traces](judges-and-traces.md) -- Judge CRUD, trace uploads, trace evaluations, and optimizations
- [Public API](public-api.md) -- Public models, benchmarks, evaluations, and comparisons

For the complete samples catalog including industry solutions, OpenClaw agent evaluation, CI/CD integration, and more, see the [Samples Guide](../samples-guide.md).
26 changes: 17 additions & 9 deletions docs/examples/creating-evaluations.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Examples for creating evaluations on the Stratix platform using the LayerLens Py

### Using Synchronous Client

> Source: [`examples/client.py`](../../examples/client.py)
> Source: [`samples/core/benchmark_evaluation.py`](../../samples/core/benchmark_evaluation.py)

```python
from layerlens import Stratix
Expand Down Expand Up @@ -49,7 +49,7 @@ else:

### Minimal Sync Example

> Source: [`examples/client_simple.py`](../../examples/client_simple.py)
> Source: [`samples/core/benchmark_evaluation.py`](../../samples/core/benchmark_evaluation.py)

```python
from layerlens import Stratix
Expand All @@ -70,7 +70,7 @@ evaluation = client.evaluations.create(

### Using Async Client

> Source: [`examples/async_client_simple.py`](../../examples/async_client_simple.py)
> Source: [`samples/core/async_workflow.py`](../../samples/core/async_workflow.py)

```python
import asyncio
Expand Down Expand Up @@ -106,7 +106,7 @@ if __name__ == "__main__":

## Sorting and Filtering Evaluations

> Source: [`examples/evaluation_sorting.py`](../../examples/evaluation_sorting.py)
> Source: [`samples/core/evaluation_filtering.py`](../../samples/core/evaluation_filtering.py)

```python
import asyncio
Expand Down Expand Up @@ -163,7 +163,7 @@ if __name__ == "__main__":

## Comparing Evaluations

> Source: [`examples/compare_evaluations.py`](../../examples/compare_evaluations.py)
> Source: [`samples/core/compare_evaluations.py`](../../samples/core/compare_evaluations.py)

```python
from layerlens import PublicClient
Expand Down Expand Up @@ -200,7 +200,7 @@ comparison = client.comparisons.compare(

## Running Multiple Evaluations in Parallel

> Source: [`examples/async_run_evaluations.py`](../../examples/async_run_evaluations.py)
> Source: [`samples/core/async_results.py`](../../samples/core/async_results.py)

```python
import asyncio
Expand Down Expand Up @@ -253,7 +253,7 @@ if __name__ == "__main__":

### Paginated Results

> Source: [`examples/paginated_results.py`](../../examples/paginated_results.py)
> Source: [`samples/core/paginated_results.py`](../../samples/core/paginated_results.py)

```python
import asyncio
Expand Down Expand Up @@ -298,7 +298,7 @@ if __name__ == "__main__":

### All Results Without Pagination

> Source: [`examples/all_results_no_pagination.py`](../../examples/all_results_no_pagination.py)
> Source: [`samples/core/paginated_results.py`](../../samples/core/paginated_results.py)

```python
import asyncio
Expand Down Expand Up @@ -326,7 +326,7 @@ if __name__ == "__main__":

### Fetch Results for Multiple Evaluations Concurrently

> Source: [`examples/fetch_results_async.py`](../../examples/fetch_results_async.py)
> Source: [`samples/core/async_results.py`](../../samples/core/async_results.py)

```python
import asyncio
Expand Down Expand Up @@ -385,3 +385,11 @@ except layerlens.NotFoundError:
except layerlens.APIError as e:
print(f"API error: {e}")
```

## Related Samples

- [`samples/core/benchmark_evaluation.py`](../../samples/core/benchmark_evaluation.py) -- Full model+benchmark evaluation workflow with result pagination
- [`samples/core/run_evaluation.py`](../../samples/core/run_evaluation.py) -- Evaluation lifecycle management
- [`samples/core/trace_evaluation.py`](../../samples/core/trace_evaluation.py) -- Trace-level evaluation with judges
- [`samples/core/async_results.py`](../../samples/core/async_results.py) -- Concurrent async evaluation and result fetching
- [`samples/core/compare_evaluations.py`](../../samples/core/compare_evaluations.py) -- Side-by-side evaluation comparison
Loading
Loading