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
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ Versioning: [Semantic Versioning](https://semver.org/spec/v2.0.0.html)

## [Unreleased]

### Added
- **Bedrock native structured outputs**: Add explicit `Mode.JSON_SCHEMA` and `Mode.TOOLS_STRICT` support through Converse `outputConfig.textFormat` and strict tool schemas, with recursive schema normalization and a boto3 `1.42.42` minimum. Model selection remains caller-controlled. ([#2084](https://github.com/567-labs/instructor/issues/2084), [#2086](https://github.com/567-labs/instructor/pull/2086))
- **Validation retry budgets**: Add positive cumulative `token_budget` limits for structured non-streaming retries, immutable `completion:usage` snapshots, sync/async cutoff parity, and stable cumulative usage metadata. Valid responses still win after crossing the budget; retries fail closed before another provider call when usage is unavailable. ([#2391](https://github.com/567-labs/instructor/issues/2391), [#2392](https://github.com/567-labs/instructor/pull/2392))

### Fixed
- **Mistral SDK compatibility**: Support the `mistralai` 2.x client export on Python 3.10+ while retaining the compatible 1.x fallback required by Python 3.9. ([#2298](https://github.com/567-labs/instructor/pull/2298), [#2365](https://github.com/567-labs/instructor/issues/2365))
- **Bedrock reasoning JSON**: Parse the final complete JSON value after reasoning text or `<think>` blocks, preserve JSON escape sequences, and keep caller-owned messages unchanged during Bedrock request preparation and retries. ([#2076](https://github.com/567-labs/instructor/issues/2076), [#2287](https://github.com/567-labs/instructor/pull/2287))

### Security
- **LLM validator isolation**: Send validation rules and candidate values as structured JSON data under a fixed trusted instruction to reduce prompt-injection risk, and raise `ValueError` for rejected values instead of relying on optimization-sensitive assertions. ([#2056](https://github.com/567-labs/instructor/issues/2056), [#2307](https://github.com/567-labs/instructor/pull/2307))

## [1.15.5] - 2026-08-07

### Fixed
Expand Down
44 changes: 23 additions & 21 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ By participating in this project, you agree to abide by our code of conduct: tre

### Environment Setup

1. **Fork the Repository**: Click the "Fork" button at the top right of the [repository page](https://github.com/instructor-ai/instructor).
1. **Fork the Repository**: Click the "Fork" button at the top right of the [repository page](https://github.com/567-labs/instructor).

2. **Clone Your Fork**:
```bash
Expand All @@ -48,7 +48,7 @@ By participating in this project, you agree to abide by our code of conduct: tre

3. **Set up Remote**:
```bash
git remote add upstream https://github.com/instructor-ai/instructor.git
git remote add upstream https://github.com/567-labs/instructor.git
```

4. **Install UV** (recommended):
Expand All @@ -63,19 +63,18 @@ By participating in this project, you agree to abide by our code of conduct: tre
5. **Install Dependencies**:
```bash
# Using uv (recommended)
uv pip install -e ".[dev,docs,test-docs]"
uv sync --extra dev --extra docs --extra test-docs

# Using poetry
poetry install --with dev,docs,test-docs

# For specific providers, add the provider name as an extra
# Example: uv pip install -e ".[dev,docs,test-docs,anthropic]"
# Example: uv sync --extra dev --extra docs --extra test-docs --extra anthropic
```

6. **Set up Pre-commit**:
```bash
pip install pre-commit
pre-commit install
uv run pre-commit install
```

### Development Workflow
Expand Down Expand Up @@ -115,16 +114,19 @@ UV is a fast Python package installer and resolver. It's recommended for day-to-
curl -LsSf https://astral.sh/uv/install.sh | sh

# Install project and development dependencies
uv pip install -e ".[dev,docs]"
uv sync --extra dev --extra docs

# Adding a new dependency (example)
uv pip install new-package
# Add a project dependency and update pyproject.toml plus uv.lock
uv add new-package
```

Key UV commands:
- `uv pip install -e .` - Install the project in editable mode
- `uv pip install -e ".[dev]"` - Install with development extras
- `uv pip freeze > requirements.txt` - Generate requirements file
- `uv sync` - Install the project and synchronize the environment with `uv.lock`
- `uv sync --extra dev` - Install with a selected optional extra
- `uv add package-name` - Add a project dependency and update the lockfile
- `uv pip install package-name` - Install only into the current environment without changing project metadata
- `uv pip compile pyproject.toml -o requirements.txt` - Regenerate the committed requirements export
- `uv lock --check` - Verify that `uv.lock` matches `pyproject.toml`
- `uv self update` - Update UV to the latest version

#### Using Poetry
Expand Down Expand Up @@ -173,9 +175,9 @@ Instructor uses optional dependencies to support different LLM providers. Provid
4. **Document Installation**: Update the documentation to include installation instructions:
```
# Install with your provider support
uv pip install "instructor[my-provider]"
uv add "instructor[my-provider]"
# or
poetry install --with my-provider
poetry add "instructor[my-provider]"
```

5. **Create Provider Utilities and Handlers**:
Expand All @@ -198,7 +200,7 @@ Instructor uses optional dependencies to support different LLM providers. Provid

### Reporting Bugs

If you find a bug, please create an issue on [our issue tracker](https://github.com/instructor-ai/instructor/issues) with:
If you find a bug, please create an issue on [our issue tracker](https://github.com/567-labs/instructor/issues) with:

1. A clear, descriptive title
2. A detailed description including:
Expand Down Expand Up @@ -241,7 +243,7 @@ Documentation improvements are always welcome! Follow these guidelines:

We encourage contributions to our evaluation tests:

1. Explore existing evals in the [evals directory](https://github.com/instructor-ai/instructor/tree/main/tests/llm)
1. Explore existing evals in the [evals directory](https://github.com/567-labs/instructor/tree/main/tests/llm)
2. Contribute new evals as pytest tests
3. Evals should test specific capabilities or edge cases of the library or models
4. Follow the existing patterns for structuring eval tests
Expand Down Expand Up @@ -350,17 +352,17 @@ Run tests using pytest:

```bash
# Run all tests
pytest tests/
uv run pytest tests/

# Run specific test
pytest tests/path_to_test.py::test_name
uv run pytest tests/path_to_test.py::test_name

# Skip LLM tests (faster for local development)
pytest tests/ -k 'not llm and not openai'
uv run pytest tests/ -k 'not llm and not openai'

# Generate coverage report
coverage run -m pytest tests/ -k "not docs"
coverage report
uv run coverage run -m pytest tests/ -k "not docs"
uv run coverage report
```

## Branch and Release Process
Expand Down
17 changes: 10 additions & 7 deletions docs/blog/posts/open_source.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,13 +232,17 @@ For those interested in exploring the capabilities of Mistral Large with Instruc
```python
import instructor
from pydantic import BaseModel
from mistralai.client import MistralClient

try:
from mistralai.client import Mistral
except ImportError:
from mistralai import Mistral

client = MistralClient()

patched_chat = instructor.from_openai(
create=client.chat, mode=instructor.Mode.TOOLS
client = Mistral(api_key="your-api-key-here")
patched_chat = instructor.from_mistral(
client=client,
model="mistral-large-latest",
mode=instructor.Mode.TOOLS,
)


Expand All @@ -247,8 +251,7 @@ class UserDetails(BaseModel):
age: int


resp = patched_chat(
model="mistral-large-latest",
resp = patched_chat.create(
response_model=UserDetails,
messages=[
{
Expand Down
26 changes: 25 additions & 1 deletion docs/concepts/hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,35 @@ Hooks let you intercept and handle events during the completion and parsing proc
|-------|-------------|-------------------|
| `completion:kwargs` | Arguments passed to completion | `def handler(*args, **kwargs)` |
| `completion:response` | Raw API response received | `def handler(response)` |
| `completion:usage` | Immutable snapshot of cumulative retry usage | `def handler(usage, *, attempt_number)` |
| `completion:error` | Error during a retry attempt | `def handler(error, *, attempt_number, max_attempts, is_last_attempt)` |
| `parse:error` | Pydantic validation failed | `def handler(error)` |
| `completion:last_attempt` | Final retry attempt exhausted | `def handler(error, *, attempt_number, max_attempts, is_last_attempt)` |

`completion:error` and `completion:last_attempt` handlers receive optional retry metadata as keyword arguments. Old-style handlers that only accept `error` continue to work — the metadata is silently dropped for backward compatibility.
`completion:usage`, `completion:error`, and `completion:last_attempt` handlers receive retry metadata as keyword arguments. Old-style error handlers that only accept `error` continue to work because the metadata is silently dropped for backward compatibility.

## Cumulative Usage

`completion:usage` runs after each response that includes compatible usage
metadata. Each event receives a separate cumulative snapshot, so retaining or
changing one snapshot does not affect later events or Instructor's accounting.

```python
import instructor

client = instructor.from_provider("openai/gpt-4.1-mini")


def record_usage(usage, *, attempt_number: int):
print(f"Attempt {attempt_number}: {usage.total_tokens} total tokens")


client.on("completion:usage", record_usage)
```

For a successful Pydantic model or list response, Instructor also attaches the
final cumulative snapshot as `_total_usage`. Primitive response models should
use the hook because they cannot carry response metadata.

## Registering and Removing Hooks

Expand Down
43 changes: 43 additions & 0 deletions docs/concepts/retrying.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,49 @@ description: "Learn how to implement retry logic with Tenacity for LLM applicati

Tenacity is a Python library for adding retry logic to your applications. Combined with Instructor, it helps handle API failures, rate limits, and validation errors.

## Limit Validation Retry Cost

Use `token_budget` to stop validation retries after cumulative provider usage
reaches a positive token limit:

```python
import instructor
from instructor.core import TokenBudgetExceeded
from pydantic import BaseModel

client = instructor.from_provider("openai/gpt-4.1-mini")


class UserInfo(BaseModel):
name: str
age: int


try:
user = client.create(
response_model=UserInfo,
messages=[{"role": "user", "content": "Extract: Jason is 25"}],
max_retries=3,
token_budget=2_000,
)
except TokenBudgetExceeded as error:
print(error.total_usage)
```

The budget is checked after a response fails validation and before Instructor
prepares another request. Reaching the exact budget stops the retry. A response
that validates successfully is returned even if that completed request takes
the cumulative total over the budget.

`token_budget` is a retry budget, not a hard per-request limit. The provider may
use more than the remaining budget while completing the current request. Use
the provider's output-token setting when you also need a per-request limit.

Budgeted retries currently require a structured, non-streaming response and
compatible provider usage metadata. Instructor raises
`TokenUsageUnavailableError` instead of making another request when it cannot
account for usage safely.

## Basic Retry with Exponential Backoff

The most common pattern uses exponential backoff to delay retries:
Expand Down
38 changes: 19 additions & 19 deletions docs/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ We welcome contributions to Instructor! This page covers the different ways you

Evals help us monitor the quality of both the OpenAI models and the Instructor library. To contribute:

1. **Explore Existing Evals**: Check out [our evals directory](https://github.com/instructor-ai/instructor/tree/main/tests/llm/test_openai/evals)
1. **Explore Existing Evals**: Check out [our evals directory](https://github.com/567-labs/instructor/tree/main/tests/llm)
2. **Create a New Eval**: Add new pytest tests that evaluate specific capabilities or edge cases
3. **Follow the Pattern**: Structure your eval similar to existing ones
4. **Submit a PR**: We'll review and incorporate your eval
Expand All @@ -22,7 +22,7 @@ Evals are run weekly, and results are tracked to monitor performance over time.

### Reporting Issues

If you encounter a bug or problem, please [file an issue on GitHub](https://github.com/instructor-ai/instructor/issues) with:
If you encounter a bug or problem, please [file an issue on GitHub](https://github.com/567-labs/instructor/issues) with:

1. A clear, descriptive title
2. Detailed information including:
Expand All @@ -38,8 +38,8 @@ If you encounter a bug or problem, please [file an issue on GitHub](https://gith
We welcome pull requests! Here's the process:

1. **For Small Changes**: Feel free to submit a PR directly
2. **For Larger Changes**: [Start with an issue](https://github.com/instructor-ai/instructor/issues) to discuss approach
3. **Looking for Ideas?** Check issues labeled [help wanted](https://github.com/instructor-ai/instructor/labels/help%20wanted) or [good first issue](https://github.com/instructor-ai/instructor/labels/good%20first%20issue)
2. **For Larger Changes**: [Start with an issue](https://github.com/567-labs/instructor/issues) to discuss approach
3. **Looking for Ideas?** Check issues labeled [help wanted](https://github.com/567-labs/instructor/labels/help%20wanted) or [good first issue](https://github.com/567-labs/instructor/labels/good%20first%20issue)

## Setting Up Your Development Environment

Expand All @@ -63,25 +63,26 @@ UV is a fast Python package installer and resolver that makes development easier
cd instructor

# Install with development dependencies
uv pip install -e ".[dev,docs]"
uv sync --extra dev --extra docs
```

3. **Adding New Dependencies**:
```bash
# Add a regular dependency
uv pip install some-package
# Add a project dependency and update pyproject.toml plus uv.lock
uv add some-package

# Install a specific version
uv pip install "some-package>=1.0.0,<2.0.0"
# Install only into the current environment without changing project metadata
uv pip install some-package
```

4. **Common UV Commands**:
```bash
# Update UV itself
uv self update

# Create a requirements file
uv pip freeze > requirements.txt
# Verify the lockfile and regenerate the committed requirements export
uv lock --check
uv pip compile pyproject.toml -o requirements.txt
```

### Using Poetry
Expand Down Expand Up @@ -142,9 +143,9 @@ Instructor uses optional dependencies to support different LLM providers. Provid
4. **Document Installation**:
```bash
# Installation command for your provider
uv pip install "instructor[my-provider]"
uv add "instructor[my-provider]"
# or with poetry
poetry install --with my-provider
poetry add "instructor[my-provider]"
```

5. **Create Provider Utilities and Handlers**:
Expand All @@ -171,7 +172,7 @@ Instructor uses optional dependencies to support different LLM providers. Provid
```bash
git clone https://github.com/YOUR-USERNAME/instructor.git
cd instructor
git remote add upstream https://github.com/instructor-ai/instructor.git
git remote add upstream https://github.com/567-labs/instructor.git
```
3. **Create a Branch**:
```bash
Expand All @@ -180,7 +181,7 @@ Instructor uses optional dependencies to support different LLM providers. Provid
4. **Make Changes, Test, and Commit**:
```bash
# Run tests
pytest tests/ -k 'not llm and not openai' # Skip LLM tests for faster local dev
uv run pytest tests/ -k 'not llm and not openai' # Skip LLM tests for faster local dev

# Commit changes
git add .
Expand Down Expand Up @@ -300,8 +301,7 @@ We use the following tools to maintain code quality:

```bash
# Install pre-commit hooks
pip install pre-commit
pre-commit install
uv run pre-commit install
```

Key style guidelines:
Expand Down Expand Up @@ -439,8 +439,8 @@ print(person.age) # 25

<!-- ALL-CONTRIBUTORS-LIST:END -->

<a href="https://github.com/instructor-ai/instructor/graphs/contributors">
<img src="https://contrib.rocks/image?repo=jxnl/instructor" />
<a href="https://github.com/567-labs/instructor/graphs/contributors">
<img src="https://contrib.rocks/image?repo=567-labs/instructor" />
</a>

## Documentation Resources
Expand Down
Loading
Loading