Skip to content

Commit 7d53f4f

Browse files
committed
feat(v2/anthropic): implement provider with mode registry integration
1 parent 864de29 commit 7d53f4f

File tree

4 files changed

+71
-0
lines changed

4 files changed

+71
-0
lines changed

instructor/providers/anthropic/client.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,15 @@ def from_anthropic(
6969
warnings.warn(
7070
"from_anthropic() is deprecated and will be removed in v2.0. "
7171
"Use instructor.v2.from_anthropic() with Mode instead:\n"
72+
<<<<<<< HEAD
7273
" from instructor.v2.providers.anthropic import from_anthropic\n"
7374
" from instructor import Mode\n"
7475
" client = from_anthropic(anthropic_client, mode=Mode.TOOLS)\n"
76+
=======
77+
" from instructor.v2 import from_anthropic\n"
78+
" from instructor import Mode\n"
79+
" client = from_anthropic(anthropic_client, Mode.ANTHROPIC_TOOLS)\n"
80+
>>>>>>> 13857221 (feat(v2/anthropic): implement provider with mode registry integration)
7581
"Or use from_provider() which automatically routes to v2:\n"
7682
" client = instructor.from_provider('anthropic/claude-3-sonnet')",
7783
DeprecationWarning,

instructor/v2/providers/anthropic/handlers.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ def prepare_request(
191191
) -> tuple[type[BaseModel] | None, dict[str, Any]]:
192192
"""Prepare request kwargs for TOOLS mode.
193193
194+
<<<<<<< HEAD
194195
Supports:
195196
- Regular single tool use (single model)
196197
- Parallel tool calling (Iterable[Union[Model1, Model2, ...]])
@@ -200,16 +201,21 @@ def prepare_request(
200201
If thinking is enabled, automatically adjusts tool_choice to "auto"
201202
(required by API constraint).
202203
204+
=======
205+
>>>>>>> 13857221 (feat(v2/anthropic): implement provider with mode registry integration)
203206
Args:
204207
response_model: Pydantic model to extract (or None)
205208
kwargs: Original request kwargs
206209
207210
Returns:
208211
Tuple of (response_model, modified_kwargs)
209212
"""
213+
<<<<<<< HEAD
210214
from collections.abc import Iterable
211215
from typing import get_origin
212216

217+
=======
218+
>>>>>>> 13857221 (feat(v2/anthropic): implement provider with mode registry integration)
213219
new_kwargs = kwargs.copy()
214220

215221
# Extract and combine system messages BEFORE serializing message content
@@ -235,6 +241,7 @@ def prepare_request(
235241
# Just return with processed messages and extracted system
236242
return None, new_kwargs
237243

244+
<<<<<<< HEAD
238245
# Detect if this is a parallel tools request (Iterable[Union[...]])
239246
is_parallel = False
240247
if get_origin(response_model) is Iterable:
@@ -283,6 +290,15 @@ def prepare_request(
283290
"type": "tool",
284291
"name": response_model.__name__,
285292
}
293+
=======
294+
# Generate tool schema
295+
tool_descriptions = generate_anthropic_schema(response_model)
296+
new_kwargs["tools"] = [tool_descriptions]
297+
new_kwargs["tool_choice"] = {
298+
"type": "tool",
299+
"name": response_model.__name__,
300+
}
301+
>>>>>>> 13857221 (feat(v2/anthropic): implement provider with mode registry integration)
286302

287303
return response_model, new_kwargs
288304

@@ -358,6 +374,7 @@ def parse_response(
358374
response_model: type[BaseModel],
359375
validation_context: dict[str, Any] | None = None,
360376
strict: bool | None = None,
377+
<<<<<<< HEAD
361378
) -> BaseModel | Any:
362379
"""Parse TOOLS mode response.
363380
@@ -366,26 +383,39 @@ def parse_response(
366383
- Parallel tool use (returns generator of model instances)
367384
- Extended thinking responses (filters out thinking blocks)
368385
386+
=======
387+
) -> BaseModel:
388+
"""Parse TOOLS mode response.
389+
390+
>>>>>>> 13857221 (feat(v2/anthropic): implement provider with mode registry integration)
369391
Args:
370392
response: Anthropic API response
371393
response_model: Pydantic model to validate against
372394
validation_context: Optional context for validation
373395
strict: Optional strict validation mode
374396

375397
Returns:
398+
<<<<<<< HEAD
376399
Validated Pydantic model instance or generator of instances for parallel
400+
=======
401+
Validated Pydantic model instance
402+
>>>>>>> 13857221 (feat(v2/anthropic): implement provider with mode registry integration)
377403

378404
Raises:
379405
IncompleteOutputException: If response hit max_tokens
380406
ValidationError: If response doesn't match model
381407
"""
382408
from anthropic.types import Message
409+
<<<<<<< HEAD
383410
from collections.abc import Iterable
384411
from typing import get_origin
412+
=======
413+
>>>>>>> 13857221 (feat(v2/anthropic): implement provider with mode registry integration)
385414
386415
if isinstance(response, Message) and response.stop_reason == "max_tokens":
387416
raise IncompleteOutputException(last_completion=response)
388417
418+
<<<<<<< HEAD
389419
# Check if this is a parallel response (Iterable[Union[...]])
390420
is_parallel = get_origin(response_model) is Iterable
391421
@@ -463,6 +493,27 @@ def prepare_request(
463493
Mode.warn_anthropic_reasoning_tools_deprecation()
464494
# Delegate to parent handler
465495
return super().prepare_request(response_model, kwargs)
496+
=======
497+
# Extract tool calls
498+
tool_calls = [
499+
json.dumps(c.input) for c in response.content if c.type == "tool_use"
500+
]
501+
502+
# Validate exactly one tool call
503+
tool_calls_validator = TypeAdapter(
504+
Annotated[list[Any], Field(min_length=1, max_length=1)]
505+
)
506+
tool_call = tool_calls_validator.validate_python(tool_calls)[0]
507+
508+
parsed = response_model.model_validate_json(
509+
tool_call, context=validation_context, strict=strict
510+
)
511+
512+
# Attach raw response for access via create_with_completion
513+
parsed._raw_response = response # type: ignore
514+
515+
return parsed
516+
>>>>>>> 13857221 (feat(v2/anthropic): implement provider with mode registry integration)
466517
467518
468519
@register_mode_handler(Provider.ANTHROPIC, Mode.JSON)

tests/v2/test_anthropic_integration.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,15 +92,20 @@ def test_query_anthropic_modes():
9292

9393
assert Mode.TOOLS in modes
9494
assert Mode.JSON in modes
95+
<<<<<<< HEAD
9596
assert Mode.ANTHROPIC_REASONING_TOOLS in modes
9697
assert len(modes) == 3 # TOOLS, JSON, and ANTHROPIC_REASONING_TOOLS
98+
=======
99+
assert len(modes) == 2 # Only TOOLS and JSON for now
100+
>>>>>>> 13857221 (feat(v2/anthropic): implement provider with mode registry integration)
97101

98102

99103
def test_query_tools_providers():
100104
"""Test querying v2 registry for TOOLS mode providers."""
101105
providers = mode_registry.get_providers_for_mode(Mode.TOOLS)
102106

103107
assert Provider.ANTHROPIC in providers
108+
<<<<<<< HEAD
104109

105110

106111
def test_anthropic_reasoning_tools_mode_registered():
@@ -197,3 +202,5 @@ def test_tools_mode_respects_user_tool_choice():
197202

198203
# Should respect user's tool_choice
199204
assert result["tool_choice"]["type"] == "auto"
205+
=======
206+
>>>>>>> 13857221 (feat(v2/anthropic): implement provider with mode registry integration)

tests/v2/test_routing.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,11 @@ def test_from_provider_anthropic_async():
4040

4141

4242
def test_old_from_anthropic_deprecation_warning():
43+
<<<<<<< HEAD
4344
"""Test that old from_anthropic() emits deprecation warning with correct v2 example."""
45+
=======
46+
"""Test that old from_anthropic() emits deprecation warning."""
47+
>>>>>>> 13857221 (feat(v2/anthropic): implement provider with mode registry integration)
4448
import anthropic
4549
from instructor import from_anthropic
4650

@@ -55,10 +59,13 @@ def test_old_from_anthropic_deprecation_warning():
5559
assert issubclass(w[0].category, DeprecationWarning)
5660
assert "deprecated" in str(w[0].message).lower()
5761
assert "v2" in str(w[0].message)
62+
<<<<<<< HEAD
5863
# Verify the warning shows correct v2 Mode enum (TOOLS not ANTHROPIC_TOOLS)
5964
assert "Mode.TOOLS" in str(w[0].message)
6065
# Verify it mentions the correct v2 import path
6166
assert "instructor.v2.providers.anthropic" in str(w[0].message)
67+
=======
68+
>>>>>>> 13857221 (feat(v2/anthropic): implement provider with mode registry integration)
6269

6370

6471
@pytest.mark.skip(reason="Requires Anthropic API key")

0 commit comments

Comments
 (0)