Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f3fcb9e
test(core): standardize provider tests with from_provider() parameter…
claude Nov 6, 2025
6fd61f5
feat(tests): consolidate providers into core test suite
claude Nov 6, 2025
74e2e56
docs(tests): add workflow update instructions for maintainers
claude Nov 6, 2025
c44fffa
fix(tests): update models to claude-haiku-4-5-latest and gemini-2.5-f…
claude Nov 6, 2025
c796c1c
fix(tests): complete model updates in util.py and README
claude Nov 6, 2025
7c1fc73
docs(tests): add comprehensive parameterization and provider-specific…
claude Nov 6, 2025
3866388
docs(tests): answer key questions about parameterization and provider…
claude Nov 6, 2025
c7cd45e
feat(tests): add unified multimodal tests to core suite
claude Nov 6, 2025
7f26778
refactor(tests): massive cleanup - delete all duplicate tests
claude Nov 6, 2025
2fbf2fc
Refactor: Update instructor modes for Fireworks and Perplexity
cursoragent Nov 6, 2025
eaf5a05
feat(tests): add unified multimodal tests to core suite
claude Nov 6, 2025
e6c6cf3
docs(tests): remove temporary analysis markdown files
claude Nov 6, 2025
04c8017
Refactor: Separate core provider tests and update test matrix
cursoragent Nov 6, 2025
afe8c14
refactor(tests): delete more duplicate test files
claude Nov 6, 2025
4f15c89
feat(xai): enhance tool handling and add capability definitions for p…
jxnl Nov 6, 2025
e5ce61a
fix(tests): stabilize core provider response modes
jxnl Nov 6, 2025
a3d0fc0
fix(ci): fix ruff linting errors and type check issues
jxnl Nov 6, 2025
515ac81
fix(types): add type ignores for xAI SDK method calls
jxnl Nov 6, 2025
8209d5a
fix(anthropic): respect strict JSON control character handling
jxnl Nov 6, 2025
de36d2b
Merge remote-tracking branch 'origin/main' into claude/standardize-fr…
jxnl Nov 12, 2025
5a6b0b2
refactor(tests): remove provider-specific tests and utility configura…
jxnl Nov 12, 2025
9ff3df0
fix(tests): update test commands to use asyncio mode
jxnl Nov 12, 2025
ad165b5
feat(tests): expand core provider tests for OpenAI, Anthropic, Google…
jxnl Nov 12, 2025
6da9110
fix(tests): skip unsupported provider capabilities for Google Gemini
jxnl Nov 12, 2025
ef2af12
docs(google): add known limitations as of Nov 12, 2024
jxnl Nov 12, 2025
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
2 changes: 1 addition & 1 deletion .github/workflows/evals.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ jobs:
run: uv sync --all-extras --dev

- name: Run all tests
run: uv run pytest tests/
run: uv run pytest tests/ --asyncio-mode=auto
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
120 changes: 110 additions & 10 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ jobs:
- name: Install the project
run: uv sync --all-extras
- name: Run core tests
run: uv run pytest tests/ -k 'not llm and not openai and not gemini and not anthropic and not cohere and not vertexai and not mistral and not xai and not docs'
run: >-
uv run pytest tests/ --asyncio-mode=auto -n auto
-k 'not test_core_providers and not test_openai and not test_anthropic
and not test_gemini and not test_genai and not test_writer and not
test_vertexai and not docs'
env:
INSTRUCTOR_ENV: CI
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
Expand All @@ -31,15 +35,110 @@ jobs:
XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}

# Core provider tests for OpenAI
core-openai:
name: Core Provider Tests (OpenAI)
runs-on: ubuntu-latest
needs: core-tests

steps:
- uses: actions/checkout@v2
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
enable-cache: true
- name: Set up Python
run: uv python install 3.11
- name: Install the project
run: uv sync --all-extras
- name: Run core provider tests (OpenAI)
run: uv run pytest tests/llm/test_core_providers -v --asyncio-mode=auto -n auto -k "openai"
env:
INSTRUCTOR_ENV: CI
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}

# Core provider tests for Anthropic
core-anthropic:
name: Core Provider Tests (Anthropic)
runs-on: ubuntu-latest
needs: core-tests

steps:
- uses: actions/checkout@v2
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
enable-cache: true
- name: Set up Python
run: uv python install 3.11
- name: Install the project
run: uv sync --all-extras
- name: Run core provider tests (Anthropic)
run: uv run pytest tests/llm/test_core_providers -v --asyncio-mode=auto -n auto -k "anthropic"
env:
INSTRUCTOR_ENV: CI
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

# Core provider tests for Google
core-google:
name: Core Provider Tests (Google)
runs-on: ubuntu-latest
needs: core-tests

steps:
- uses: actions/checkout@v2
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
enable-cache: true
- name: Set up Python
run: uv python install 3.11
- name: Install the project
run: uv sync --all-extras
- name: Run core provider tests (Google)
run: uv run pytest tests/llm/test_core_providers -v --asyncio-mode=auto -n auto -k "google"
env:
INSTRUCTOR_ENV: CI
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}

# Core provider tests for other providers
core-other:
name: Core Provider Tests (Other)
runs-on: ubuntu-latest
needs: core-tests

steps:
- uses: actions/checkout@v2
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
enable-cache: true
- name: Set up Python
run: uv python install 3.11
- name: Install the project
run: uv sync --all-extras
- name: Run core provider tests (Cohere, xAI, Mistral, etc)
run: uv run pytest tests/llm/test_core_providers -v --asyncio-mode=auto -n auto -k "cohere or xai or mistral or cerebras or fireworks or writer or perplexity"
env:
INSTRUCTOR_ENV: CI
COHERE_API_KEY: ${{ secrets.COHERE_API_KEY }}
XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
CEREBRAS_API_KEY: ${{ secrets.CEREBRAS_API_KEY }}
FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}
WRITER_API_KEY: ${{ secrets.WRITER_API_KEY }}
PERPLEXITY_API_KEY: ${{ secrets.PERPLEXITY_API_KEY }}

# Provider tests run in parallel
provider-tests:
name: ${{ matrix.provider.name }} Tests
runs-on: ubuntu-latest
needs: [core-openai, core-anthropic, core-google, core-other]
strategy:
fail-fast: false
matrix:
provider:
- name: Openai
- name: OpenAI
env_key: OPENAI_API_KEY
test_path: tests/llm/test_openai
- name: Anthropic
Expand All @@ -51,12 +150,12 @@ jobs:
- name: Google GenAI
env_key: GOOGLE_API_KEY
test_path: tests/llm/test_genai
- name: Cohere
env_key: COHERE_API_KEY
test_path: tests/llm/test_cohere
- name: XAI
env_key: XAI_API_KEY
test_path: tests/llm/test_xai
- name: Vertex AI
env_key: GOOGLE_API_KEY
test_path: tests/llm/test_vertexai
- name: Writer
env_key: WRITER_API_KEY
test_path: tests/llm/test_writer

steps:
- uses: actions/checkout@v2
Expand All @@ -69,7 +168,7 @@ jobs:
- name: Install the project
run: uv sync --all-extras
- name: Run ${{ matrix.provider.name }} tests
run: uv run pytest ${{ matrix.provider.test_path }} -n auto
run: uv run pytest ${{ matrix.provider.test_path }} --asyncio-mode=auto -n auto
env:
INSTRUCTOR_ENV: CI
${{ matrix.provider.env_key }}: ${{ secrets[matrix.provider.env_key] }}
Expand All @@ -78,6 +177,7 @@ jobs:
auto-client-test:
name: Auto Client Tests
runs-on: ubuntu-latest
needs: [core-openai, core-anthropic, core-google, core-other]

steps:
- uses: actions/checkout@v2
Expand All @@ -90,7 +190,7 @@ jobs:
- name: Install the project
run: uv sync --all-extras
- name: Run Auto Client tests
run: uv run pytest tests/test_auto_client.py
run: uv run pytest tests/test_auto_client.py --asyncio-mode=auto -n auto
env:
INSTRUCTOR_ENV: CI
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test_docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ jobs:
- name: Install the project
run: uv sync --all-extras
- name: Run tests
run: uv run pytest tests/docs
run: uv run pytest tests/docs --asyncio-mode=auto
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

## Commands
- Install deps: `uv pip install -e ".[dev,anthropic]"` or `poetry install --with dev,anthropic`
- Run tests: `uv run pytest tests/`
- Run tests: `uv run pytest tests/ -n auto`
- Run specific test: `uv run pytest tests/path_to_test.py::test_name`
- Skip LLM tests: `uv run pytest tests/ -k 'not llm and not openai'`
- Type check: `uv run ty check`
Expand Down
10 changes: 10 additions & 0 deletions docs/integrations/google.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,16 @@ for user in users:
#> name='Mike' age=28
```

## Known Limitations (as of Nov 12, 2024)

Google Gemini has the following known limitations when used with Instructor:

1. **Union Types**: Gemini does not support Union types (except for Optional). Use separate response models or Literal types instead.
2. **Enum Types**: Gemini returns string values instead of properly typed Enum instances. You may need to manually convert strings to enums after extraction.
3. **Union Streaming**: Streaming is not supported for Union types with Iterable.

These limitations are specific to Google Gemini and do not affect other providers like OpenAI or Anthropic. Tests automatically skip these features for Google to prevent failures.

## Instructor Modes

We provide several modes to make it easy to work with the different response models that Gemini supports:
Expand Down
7 changes: 2 additions & 5 deletions instructor/processing/function_calls.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,10 +399,7 @@ def parse_anthropic_json(
# read: https://docs.anthropic.com/en/docs/build-with-claude/tool-use/web-search-tool#response
text_blocks = [c for c in completion.content if c.type == "text"]
last_block = text_blocks[-1]
# Strip raw control characters (0x00-0x1F) that would cause json.loads to fail
# Note: This preserves escaped sequences like \n in JSON strings, which are handled
# correctly by the JSON parser. Only raw, unescaped control bytes are removed.
text = re.sub(r"[\u0000-\u001F]", "", last_block.text)
text = last_block.text

extra_text = extract_json_from_codeblock(text)

Expand All @@ -411,7 +408,7 @@ def parse_anthropic_json(
extra_text, context=validation_context, strict=True
)
else:
# Allow control characters.
# Allow control characters to pass through by using the non-strict JSON parser.
parsed = json.loads(extra_text, strict=False)
# Pydantic non-strict: https://docs.pydantic.dev/latest/concepts/strict_mode/
model = cls.model_validate(parsed, context=validation_context, strict=False)
Expand Down
Loading
Loading