Skip to content

Commit 8cde6db

Browse files
committed
docs(v2): explain provider-owned client architecture
1 parent a2259f7 commit 8cde6db

17 files changed

Lines changed: 617 additions & 245 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,13 @@ Versioning: [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
99

1010
## [Unreleased]
1111

12+
### Changed
13+
- **Provider architecture**: Native provider factories now declare SDK client contracts and delegate shared validation, mode normalization, sync/async selection, streaming dispatch, patching, and wrapper construction to one implementation.
14+
- **Provider tests**: Replace repeated provider client suites with manifest-driven behavioral contracts, including async streaming parity.
15+
1216
### Fixed
17+
- **Hooks**: Emit `completion:error` and `completion:last_attempt` consistently for raw and structured provider failures, including attempt metadata.
18+
- **Documentation**: Correct Mistral and Bedrock async examples and clarify that provider-specific native-client helpers remain supported.
1319
- **v2 cleanup**: Consolidate small provider/runtime fixes for Gemini JSON prompts, Cohere templating, JSON array extraction, iterable streaming, missing `jsonref` dependency guidance, retry semantics and hook metadata, and multimodal autodetection.
1420

1521
### Tests / CI

docs/blog/posts/whats-new-in-v2.md

Lines changed: 295 additions & 154 deletions
Large diffs are not rendered by default.

docs/concepts/citation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,6 @@ Use CitationMixin when:
185185
## See Also
186186

187187
- [Validation](./validation.md) - Learn about validation in Instructor
188-
- [Context-Based Validation](./validation.md#context-based-validation) - Using context for validation
188+
- [Custom Validators](./validation.md#custom-validators) - Using context for validation
189189
- [Citation Examples](../examples/exact_citations.md) - More citation examples
190190
- [RAG Patterns](../blog/posts/rag-and-beyond.md) - Building RAG systems with Instructor

docs/concepts/from_provider.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,13 +331,21 @@ client = instructor.from_provider("openai/gpt-4o-mini")
331331

332332
### from_provider vs. Provider-Specific Functions
333333

334-
Provider-specific helpers were removed. Use `from_provider` for all clients:
334+
Provider-specific helpers remain supported for applications that already construct
335+
native SDK clients. Use `from_provider` when a model string is the most convenient
336+
entrypoint; use `from_openai`, `from_anthropic`, and the other `from_*` helpers when
337+
you need to configure the underlying SDK client directly.
335338

336339
```python
337340
import instructor
338341

339342
openai_client = instructor.from_provider("openai/gpt-4o-mini")
340343
anthropic_client = instructor.from_provider("anthropic/claude-3-5-sonnet")
344+
345+
# Existing native-client factories remain public compatibility entrypoints.
346+
from openai import OpenAI
347+
348+
native_client = instructor.from_openai(OpenAI())
341349
```
342350

343351
## Troubleshooting

docs/concepts/hooks.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ Hooks let you intercept and handle events during the completion and parsing proc
1919

2020
`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.
2121

22+
For custom Tenacity policies, `max_attempts` is populated when the policy uses a
23+
direct `stop_after_attempt` limit. With predicate- or delay-based stop conditions,
24+
the runtime may not know that an error is terminal when `completion:error` is
25+
emitted; use `completion:last_attempt` as the authoritative exhaustion signal.
26+
2227
## Registering and Removing Hooks
2328

2429
```python

docs/concepts/migration.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ user = await client.create(...)
100100
### Anthropic
101101

102102
```python
103-
# Before (removed)
103+
# Before (still supported)
104104
import anthropic
105105
from instructor import from_anthropic
106106

@@ -115,7 +115,7 @@ user = client.create(...)
115115
### Google/Gemini
116116

117117
```python
118-
# Before (removed)
118+
# Before (still supported)
119119
import google.genai as genai
120120
from instructor import from_genai
121121

@@ -188,13 +188,16 @@ anthropic_client = instructor.from_provider("anthropic/claude-3-5-sonnet")
188188

189189
## Backward Compatibility
190190

191-
Legacy helpers have been removed:
191+
V2 keeps the established v1 factory and patch import paths as lazy
192+
compatibility facades. Existing applications do not need a flag-day rewrite:
192193

193-
- `instructor.patch()` → Use `from_provider` instead
194-
- `instructor.apatch()` → Use `from_provider` with `async_client=True`
195-
- `from_openai()`, `from_anthropic()`, etc. → Use `from_provider`
194+
- `instructor.patch()` and `instructor.apatch()` continue to work.
195+
- `from_openai()`, `from_anthropic()`, and other provider factories continue to work.
196+
- Provider-specific legacy modes normalize to the corresponding core modes with
197+
deprecation warnings.
196198

197-
Update all call sites before upgrading.
199+
Prefer `from_provider()` and core modes in new code because their capability
200+
contract and type surface receive the new conformance checks.
198201

199202
## See Also
200203

docs/concepts/mode-migration.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Use this table to replace legacy modes:
3131
| `FUNCTIONS` | `TOOLS` |
3232
| `TOOLS_STRICT` | `TOOLS` |
3333
| `ANTHROPIC_TOOLS` | `TOOLS` |
34-
| `ANTHROPIC_JSON` | `MD_JSON` |
34+
| `ANTHROPIC_JSON` | `JSON` |
3535
| `COHERE_TOOLS` | `TOOLS` |
3636
| `COHERE_JSON_SCHEMA` | `JSON_SCHEMA` |
3737
| `XAI_TOOLS` | `TOOLS` |
@@ -99,7 +99,7 @@ from instructor import Mode
9999

100100
client = instructor.from_provider(
101101
"bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0",
102-
mode=Mode.BEDROCK_TOOLS,
102+
mode=Mode.TOOLS,
103103
)
104104
```
105105

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
# Provider Architecture and Parity Inventory
2+
3+
This page records the provider architecture introduced by the
4+
`provider-owned-clients` change and the compatibility decisions verified on
5+
June 7, 2026. The measured baseline is commit `0212d8833cba`, immediately
6+
before the shared native-client factory migration.
7+
8+
The implementation, documentation, and deterministic contract tests are split
9+
into three reviewable changes. The documentation and tests changes both target
10+
the same core implementation commit; the test evidence and measurements below
11+
are supplied by the companion tests change rather than duplicated here.
12+
13+
## Architecture decisions
14+
15+
- `ProviderSpec` is the provider control plane. It declares aliases, canonical
16+
provider identity, supported and legacy modes, handler modules, builders,
17+
capabilities, dependency errors, and the native client contract.
18+
- `ClientSpec` is an internal declarative contract for native sync and async SDK
19+
types, create and stream method paths, model fallback behavior, and legacy
20+
validation precedence. It is not a public export.
21+
- `create_instructor()` is the single implementation of native client
22+
validation, mode normalization, sync/async selection, method resolution,
23+
stream switching, patching, model defaults, and wrapper construction.
24+
- The mode registry remains the single runtime lookup for request, re-ask,
25+
response, sync stream, async stream, message, and template handlers. Legacy
26+
provider ownership and normalization are derived from `ProviderSpec`.
27+
- `retry_sync_v2()` and `retry_async_v2()` own validation retries, re-asks,
28+
usage accumulation, hook emission, error propagation, and final response
29+
attachment for every retained provider.
30+
- Provider modules retain only SDK construction and behavior that cannot be
31+
expressed by the common contract. OpenAI Responses, xAI, and LiteLLM remain
32+
explicit compatibility exceptions.
33+
34+
## Public export inventory
35+
36+
Every name in `instructor.__all__` remains available. Optional factories remain
37+
conditional on their SDK being importable, matching the previous behavior.
38+
39+
| Export | Result |
40+
| --- | --- |
41+
| `Instructor` | Preserved |
42+
| `AsyncInstructor` | Preserved |
43+
| `Image` | Preserved |
44+
| `Audio` | Preserved |
45+
| `from_openai` | Preserved |
46+
| `from_anyscale` | Preserved |
47+
| `from_together` | Preserved |
48+
| `from_databricks` | Preserved |
49+
| `from_deepseek` | Preserved |
50+
| `from_openrouter` | Preserved |
51+
| `from_litellm` | Preserved |
52+
| `from_vertexai` | Preserved; deprecated provider guidance is unchanged |
53+
| `from_provider` | Preserved |
54+
| `Provider` | Preserved |
55+
| `ResponseSchema` | Preserved |
56+
| `response_schema` | Preserved |
57+
| `OpenAISchema` | Preserved |
58+
| `CitationMixin` | Preserved |
59+
| `IterableModel` | Preserved |
60+
| `Maybe` | Preserved |
61+
| `Partial` | Preserved |
62+
| `openai_schema` | Preserved |
63+
| `generate_openai_schema` | Preserved |
64+
| `generate_anthropic_schema` | Preserved |
65+
| `generate_gemini_schema` | Preserved |
66+
| `Mode` | Preserved |
67+
| `patch` | Preserved |
68+
| `apatch` | Preserved |
69+
| `FinetuneFormat` | Preserved |
70+
| `Instructions` | Preserved |
71+
| `BatchProcessor` | Preserved |
72+
| `BatchRequest` | Preserved |
73+
| `BatchJob` | Preserved |
74+
| `llm_validator` | Preserved |
75+
| `openai_moderation` | Preserved |
76+
| `hooks` | Preserved |
77+
| `v2` | Preserved |
78+
| `from_anthropic` | Preserved as an optional export |
79+
| `from_gemini` | Preserved as an optional export |
80+
| `from_fireworks` | Preserved as an optional export |
81+
| `from_cerebras` | Preserved as an optional export |
82+
| `from_groq` | Preserved as an optional export |
83+
| `from_mistral` | Preserved as an optional export |
84+
| `from_cohere` | Preserved as an optional export |
85+
| `from_bedrock` | Preserved as an optional export |
86+
| `from_writer` | Preserved as an optional export |
87+
| `from_xai` | Preserved as an optional export |
88+
| `from_perplexity` | Preserved as an optional export |
89+
| `from_genai` | Preserved as an optional export |
90+
91+
`instructor.__version__` also remains available. No public export was removed.
92+
93+
## Provider and mode inventory
94+
95+
The table lists canonical modes after normalization. Existing provider-specific
96+
mode enum values remain accepted as deprecated aliases where declared by the
97+
provider specification.
98+
99+
| Provider or alias | Factory | Canonical modes | Result |
100+
| --- | --- | --- | --- |
101+
| OpenAI | `from_openai` | `TOOLS`, `JSON`, `JSON_SCHEMA`, `MD_JSON`, `PARALLEL_TOOLS`, `RESPONSES_TOOLS` | Preserved |
102+
| Anyscale | `from_anyscale` | `TOOLS`, `JSON`, `JSON_SCHEMA`, `MD_JSON`, `PARALLEL_TOOLS` | Preserved through OpenAI-compatible handlers |
103+
| Together | `from_together` | `TOOLS`, `JSON`, `JSON_SCHEMA`, `MD_JSON`, `PARALLEL_TOOLS` | Preserved through OpenAI-compatible handlers |
104+
| Databricks | `from_databricks` | `TOOLS`, `JSON`, `JSON_SCHEMA`, `MD_JSON`, `PARALLEL_TOOLS` | Preserved through OpenAI-compatible handlers |
105+
| DeepSeek | `from_deepseek` | `TOOLS`, `JSON`, `JSON_SCHEMA`, `MD_JSON`, `PARALLEL_TOOLS` | Preserved through OpenAI-compatible handlers |
106+
| OpenRouter | `from_openrouter` | `TOOLS`, `JSON_SCHEMA`, `MD_JSON`, `PARALLEL_TOOLS` | Preserved |
107+
| Anthropic | `from_anthropic` | `TOOLS`, `JSON`, `JSON_SCHEMA`, `PARALLEL_TOOLS` | Preserved, including beta client routing |
108+
| Google GenAI (`google/...`) | `from_genai` | `TOOLS`, `JSON` | Preserved |
109+
| `generative-ai` | `from_provider` alias | Canonicalizes to Google GenAI | Preserved deprecated alias |
110+
| Gemini | `from_gemini` | `TOOLS`, `MD_JSON` | Preserved deprecated SDK integration |
111+
| Cohere | `from_cohere` | `TOOLS`, `JSON_SCHEMA`, `MD_JSON` | Preserved, including V1/V2 and split stream methods |
112+
| Perplexity | `from_perplexity` | `MD_JSON` | Preserved |
113+
| xAI | `from_xai` | `TOOLS`, `JSON_SCHEMA`, `MD_JSON`, `PARALLEL_TOOLS` | Preserved custom adapter |
114+
| Groq | `from_groq` | `TOOLS`, `JSON_SCHEMA`, `MD_JSON` | Preserved |
115+
| Mistral | `from_mistral` | `TOOLS`, `JSON_SCHEMA`, `MD_JSON` | Preserved, including split stream methods |
116+
| Fireworks | `from_fireworks` | `TOOLS`, `JSON_SCHEMA`, `MD_JSON` | Preserved |
117+
| Cerebras | `from_cerebras` | `TOOLS`, `JSON_SCHEMA`, `MD_JSON`, `PARALLEL_TOOLS` | Preserved |
118+
| Writer | `from_writer` | `TOOLS`, `JSON_SCHEMA`, `MD_JSON` | Preserved |
119+
| Bedrock | `from_bedrock` | `TOOLS`, `MD_JSON` | Preserved, including async wrapping of the sync SDK method |
120+
| Vertex AI | `from_vertexai` | `TOOLS`, `MD_JSON`, `PARALLEL_TOOLS` | Preserved deprecated provider path |
121+
| Azure OpenAI | `from_provider` alias | Canonicalizes to OpenAI | Preserved compatibility alias |
122+
| Ollama | `from_provider` alias | Canonicalizes to OpenAI | Preserved compatibility alias |
123+
| LiteLLM | `from_litellm` | Callable wrapper modes | Preserved custom adapter |
124+
125+
Unsupported provider/mode combinations continue to raise `ModeError`; they are
126+
not advertised as capabilities by `ProviderSpec`.
127+
128+
## Workflow parity
129+
130+
| Workflow | Result | Deterministic evidence |
131+
| --- | --- | --- |
132+
| Sync structured extraction | Preserved | Shared provider/client, handler, patch, and retry suites |
133+
| Async structured extraction | Preserved | Shared wrapper selection and async retry suites |
134+
| Pydantic response validation | Preserved | Shared response parser and retry runtime suites |
135+
| Full streaming | Preserved | Provider capability runtime contracts |
136+
| Async streaming | Preserved | Async extractor contract for every advertised stream mode |
137+
| `Partial[T]` streaming | Preserved | DSL and provider capability suites |
138+
| `Iterable[T]` responses and streaming | Preserved | DSL, response-list, and provider capability suites |
139+
| Retries and re-asks | Preserved | Central sync/async retry runtime suites |
140+
| `completion:kwargs` and `completion:response` hooks | Preserved | Retry runtime suites |
141+
| `completion:error` and `completion:last_attempt` hooks | Intentionally changed to match the documented contract | Raw and structured failure hook tests |
142+
| Usage accumulation and reporting | Preserved | Shared retry usage paths and provider usage tests |
143+
| `Maybe`, citations, schemas, multimodal DSL | Preserved | Public typing and deterministic DSL suites |
144+
| Automatic provider detection | Preserved | `from_provider` and provider URL detection suites |
145+
| Provider-specific factory imports | Preserved | Lazy public import and legacy compatibility suites |
146+
| Documented Mistral async workflow | Preserved and corrected | Uses `async_client=True` explicitly |
147+
| Documented Bedrock async workflow | Preserved and corrected | Uses `async_client=True` explicitly |
148+
149+
## Intentional changes and removals
150+
151+
| Item | Result | Evidence and migration |
152+
| --- | --- | --- |
153+
| Provider-local sync/async validation, patching, stream switching, and wrapper construction | Removed as obsolete duplication | Replaced by `ClientSpec` and `create_instructor()`; public factory signatures are unchanged |
154+
| Repeated Bedrock, Cerebras, Fireworks, Groq, Mistral, and Writer client suites | Removed as meaningless duplication | Replaced by the manifest-driven shared client contract; provider-specific handler tests remain |
155+
| Bedrock `_async` documentation | Removed as broken or obsolete | `_async` was not a supported selector; pass `async_client=True` to `from_provider()` or use the async factory overload |
156+
| Claim that provider-specific helpers were removed | Removed as incorrect documentation | Native-client helpers remain public; prefer `from_provider()` for model-string construction |
157+
| Vertex AI deterministic test without the optional SDK | Intentionally changed | The test now skips when `vertexai` is unavailable instead of failing during patch setup |
158+
| Final failure hook behavior | Intentionally changed to restore documented behavior | `completion:error` and `completion:last_attempt` now receive attempt metadata; existing hook signatures remain backward-compatible |
159+
160+
No provider, working mode, DSL type, retry path, stream workflow, hook name, or
161+
documented supported factory was removed.
162+
163+
## Measurements
164+
165+
Measurements compare the working tree with `0212d8833cba` using the same
166+
fully populated `.venv`, with proxy variables unset. Generated files and
167+
dependency locks are excluded. Production LOC counts nonblank, non-comment
168+
implementation-body lines and excludes overloads and docstrings; test LOC is
169+
physical file length for the replaced contract slice.
170+
171+
| Slice | Baseline | Current | Reduction |
172+
| --- | ---: | ---: | ---: |
173+
| Executable body LOC in the 11 migrated `from_*` implementations | 589 LOC | 150 LOC | 74.5% |
174+
| Provider client contract tests replaced by `test_client_unified.py` | 869 LOC | 260 LOC | 70.1% |
175+
176+
The selected deterministic parity command is:
177+
178+
```bash
179+
python -m pytest \
180+
tests/v2/test_provider_specs.py \
181+
tests/v2/test_client_unified.py \
182+
tests/v2/test_auto_client_deterministic.py \
183+
tests/providers/test_auto_client.py -q
184+
```
185+
186+
For the selected parity command, three baseline runs from an isolated archive
187+
had a 16.68-second median with 513 passing and 46 skipped. Three working-tree
188+
runs had a 16.28-second median with 101 passing and 27 skipped, a 2.4% runtime
189+
reduction. The complete deterministic `tests/v2 tests/providers` suite improved
190+
from a 34.76-second three-run median (1,644 passing, 199 skipped) to a
191+
32.88-second median (1,279 passing, 170 skipped), a 5.4% reduction. Optional SDK
192+
imports and pytest startup dominate both measurements, so the 75% timing target
193+
remains unmet even though repeated test cases and provider implementations were
194+
removed.
195+
196+
Browser automation verified the rendered `from_provider`, Mistral, Bedrock, and
197+
provider parity pages on the local MkDocs site. The parity inventory rendered
198+
all five tables without console errors.

docs/integrations/bedrock.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pip install "instructor[bedrock]"
2121
- [from_provider Guide](../concepts/from_provider.md) - Detailed client configuration
2222
- [Mode Migration Guide](../concepts/mode-migration.md) - Move to core modes
2323
- [Provider Examples](../index.md#provider-examples) - Quick examples for all providers
24-
- [AWS Integration Guide](../examples/index.md#aws-integration) - More AWS examples
24+
- [Examples](../examples/index.md) - More integration examples
2525

2626
# AWS Bedrock
2727

@@ -43,11 +43,10 @@ client = instructor.from_provider("bedrock/anthropic.claude-3-5-sonnet-20241022-
4343
# - Mode selection based on model (Claude models use TOOLS)
4444
```
4545

46-
## Deprecation Notice
46+
## Async Clients
4747

48-
> **Deprecation Notice:**
49-
>
50-
> The `_async` argument to `instructor.from_bedrock` is deprecated. Please use `async_client=True` for async clients instead. Support for `_async` may be removed in a future release. All new code and examples should use `async_client`.
48+
Use `async_client=True` with `from_provider` or `from_bedrock`. The obsolete
49+
`_async` keyword is no longer accepted as an async selector.
5150

5251
### Environment Configuration
5352

docs/integrations/genai.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -545,13 +545,13 @@ print(response)
545545

546546
## Streaming Responses
547547

548-
!!! warning "Streaming Limitations"
548+
!!! note "V2 streaming contract"
549549

550-
**As of July 11, 2025, Google GenAI does not support streaming with tool/function calling or structured outputs for regular models.**
551-
552-
- `Mode.TOOLS` and `Mode.JSON` do not support streaming with regular models
553-
- To use streaming, you must use `Partial[YourModel]` explicitly or switch to other modes like `Mode.JSON`
554-
- Alternatively, set `stream=False` to disable streaming
550+
The v2 GenAI client advertises public partial and iterable streaming for
551+
`Mode.TOOLS` and `Mode.JSON`. This contract covers Instructor's request and
552+
parsing path; select a Gemini model that supports the requested operation.
553+
The legacy `gemini` and `vertexai` provider families have separate feature
554+
contracts and do not currently expose public iterable streaming.
555555

556556
Streaming allows you to process responses incrementally rather than waiting for the complete result. This is extremely useful for making UI changes feel instant and responsive.
557557

0 commit comments

Comments
 (0)