instructor 1.3.2__tar.gz → 1.3.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. {instructor-1.3.2 → instructor-1.3.4}/PKG-INFO +55 -13
  2. {instructor-1.3.2 → instructor-1.3.4}/README.md +49 -11
  3. {instructor-1.3.2 → instructor-1.3.4}/instructor/__init__.py +5 -0
  4. instructor-1.3.4/instructor/batch.py +74 -0
  5. instructor-1.3.4/instructor/cli/batch.py +101 -0
  6. {instructor-1.3.2 → instructor-1.3.4}/instructor/cli/cli.py +4 -2
  7. {instructor-1.3.2 → instructor-1.3.4}/instructor/cli/usage.py +5 -5
  8. {instructor-1.3.2 → instructor-1.3.4}/instructor/client.py +9 -20
  9. {instructor-1.3.2 → instructor-1.3.4}/instructor/client_anthropic.py +6 -11
  10. {instructor-1.3.2 → instructor-1.3.4}/instructor/client_cohere.py +2 -4
  11. instructor-1.3.4/instructor/client_gemini.py +61 -0
  12. {instructor-1.3.2 → instructor-1.3.4}/instructor/client_groq.py +2 -4
  13. {instructor-1.3.2 → instructor-1.3.4}/instructor/client_mistral.py +2 -4
  14. instructor-1.3.4/instructor/client_vertexai.py +118 -0
  15. {instructor-1.3.2 → instructor-1.3.4}/instructor/dsl/iterable.py +2 -2
  16. {instructor-1.3.2 → instructor-1.3.4}/instructor/dsl/parallel.py +14 -7
  17. {instructor-1.3.2 → instructor-1.3.4}/instructor/dsl/partial.py +9 -6
  18. {instructor-1.3.2 → instructor-1.3.4}/instructor/dsl/simple_type.py +24 -4
  19. instructor-1.3.4/instructor/exceptions.py +34 -0
  20. {instructor-1.3.2 → instructor-1.3.4}/instructor/function_calls.py +38 -4
  21. {instructor-1.3.2 → instructor-1.3.4}/instructor/mode.py +3 -1
  22. {instructor-1.3.2 → instructor-1.3.4}/instructor/patch.py +6 -12
  23. {instructor-1.3.2 → instructor-1.3.4}/instructor/process_response.py +36 -3
  24. {instructor-1.3.2 → instructor-1.3.4}/instructor/retry.py +30 -33
  25. {instructor-1.3.2 → instructor-1.3.4}/instructor/utils.py +14 -2
  26. {instructor-1.3.2 → instructor-1.3.4}/pyproject.toml +31 -7
  27. instructor-1.3.2/instructor/client_gemini.py +0 -31
  28. instructor-1.3.2/instructor/exceptions.py +0 -13
  29. {instructor-1.3.2 → instructor-1.3.4}/LICENSE +0 -0
  30. {instructor-1.3.2 → instructor-1.3.4}/instructor/_types/__init__.py +0 -0
  31. {instructor-1.3.2 → instructor-1.3.4}/instructor/_types/_alias.py +0 -0
  32. {instructor-1.3.2 → instructor-1.3.4}/instructor/cli/__init__.py +0 -0
  33. {instructor-1.3.2 → instructor-1.3.4}/instructor/cli/files.py +0 -0
  34. {instructor-1.3.2 → instructor-1.3.4}/instructor/cli/hub.py +0 -0
  35. {instructor-1.3.2 → instructor-1.3.4}/instructor/cli/jobs.py +0 -0
  36. {instructor-1.3.2 → instructor-1.3.4}/instructor/distil.py +0 -0
  37. {instructor-1.3.2 → instructor-1.3.4}/instructor/dsl/__init__.py +0 -0
  38. {instructor-1.3.2 → instructor-1.3.4}/instructor/dsl/citation.py +0 -0
  39. {instructor-1.3.2 → instructor-1.3.4}/instructor/dsl/maybe.py +0 -0
  40. {instructor-1.3.2 → instructor-1.3.4}/instructor/dsl/validators.py +0 -0
  41. {instructor-1.3.2 → instructor-1.3.4}/instructor/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: instructor
3
- Version: 1.3.2
3
+ Version: 1.3.4
4
4
  Summary: structured outputs for llm
5
5
  Home-page: https://github.com/jxnl/instructor
6
6
  License: MIT
@@ -20,14 +20,18 @@ Provides-Extra: groq
20
20
  Provides-Extra: litellm
21
21
  Provides-Extra: mistralai
22
22
  Provides-Extra: test-docs
23
+ Provides-Extra: vertexai
23
24
  Requires-Dist: aiohttp (>=3.9.1,<4.0.0)
24
- Requires-Dist: anthropic (>=0.26.0,<0.27.0) ; extra == "anthropic" or extra == "test-docs"
25
+ Requires-Dist: anthropic (>=0.27.0,<0.28.0) ; extra == "anthropic" or extra == "test-docs"
25
26
  Requires-Dist: cohere (>=5.1.8,<6.0.0) ; extra == "cohere" or extra == "test-docs"
26
27
  Requires-Dist: diskcache (>=5.6.3,<6.0.0) ; extra == "test-docs"
27
28
  Requires-Dist: docstring-parser (>=0.16,<0.17)
28
29
  Requires-Dist: fastapi (>=0.109.2,<0.110.0) ; extra == "test-docs"
30
+ Requires-Dist: google-cloud-aiplatform (>=1.53.0,<2.0.0) ; extra == "vertexai"
29
31
  Requires-Dist: google-generativeai (>=0.5.4,<0.6.0) ; extra == "google-generativeai"
30
32
  Requires-Dist: groq (>=0.4.2,<0.5.0) ; extra == "groq" or extra == "test-docs"
33
+ Requires-Dist: jiter (>=0.4.1,<0.5.0)
34
+ Requires-Dist: jsonref (>=1.1.0,<2.0.0) ; extra == "vertexai"
31
35
  Requires-Dist: litellm (>=1.35.31,<2.0.0) ; extra == "test-docs" or extra == "litellm"
32
36
  Requires-Dist: mistralai (>=0.1.8,<0.2.0) ; extra == "test-docs" or extra == "mistralai"
33
37
  Requires-Dist: openai (>=1.1.0,<2.0.0)
@@ -52,6 +56,10 @@ Instructor is a Python library that makes it a breeze to work with structured ou
52
56
  [![Discord](https://img.shields.io/discord/1192334452110659664?label=discord)](https://discord.gg/bD9YE9JArw)
53
57
  [![Downloads](https://img.shields.io/pypi/dm/instructor.svg)](https://pypi.python.org/pypi/instructor)
54
58
 
59
+ ## Want your logo on our website?
60
+
61
+ If your company use instructor a lot, we'd love to have your logo on our website! Please fill out [this form](https://q7gjsgfstrp.typeform.com/to/wluQlVVQ)
62
+
55
63
  ## Key Features
56
64
 
57
65
  - **Response Models**: Specify Pydantic models to define the structure of your LLM outputs
@@ -184,20 +192,53 @@ import instructor
184
192
  import google.generativeai as genai
185
193
  from pydantic import BaseModel
186
194
 
195
+
187
196
  class User(BaseModel):
188
197
  name: str
189
198
  age: int
190
199
 
200
+
191
201
  # genai.configure(api_key=os.environ["API_KEY"]) # alternative API key configuration
192
202
  client = instructor.from_gemini(
193
203
  client=genai.GenerativeModel(
194
- model_name="models/gemini-1.5-flash-latest", # model defaults to "gemini-pro"
204
+ model_name="models/gemini-1.5-flash-latest", # model defaults to "gemini-pro"
195
205
  ),
196
206
  mode=instructor.Mode.GEMINI_JSON,
197
207
  )
208
+ ```
209
+
210
+
211
+ Alternatively, you can [call Gemini from the OpenAI client](https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/call-gemini-using-openai-library#python).You'll have to setup [`gcloud`](https://cloud.google.com/docs/authentication/provide-credentials-adc#local-dev), get setup on Vertex AI, and install the Google Auth library.
212
+
213
+ ```sh
214
+ pip install google-auth
215
+ ```
216
+
217
+ ```python
218
+ import google.auth
219
+ import google.auth.transport.requests
220
+ import instructor
221
+ from openai import OpenAI
222
+ from pydantic import BaseModel
223
+
224
+ creds, project = google.auth.default()
225
+ auth_req = google.auth.transport.requests.Request()
226
+ creds.refresh(auth_req)
227
+
228
+ # Pass the Vertex endpoint and authentication to the OpenAI SDK
229
+ PROJECT = 'PROJECT_ID'
230
+ LOCATION = 'LOCATION' # https://cloud.google.com/vertex-ai/generative-ai/docs/learn/locations
231
+ base_url = f'https://{LOCATION}-aiplatform.googleapis.com/v1beta1/projects/{PROJECT}/locations/{LOCATION}/endpoints/openapi'
232
+
233
+ client = instructor.from_openai(OpenAI(base_url=base_url, api_key=creds.token), mode=instructor.Mode.JSON)
234
+ # JSON mode is req'd
235
+ class User(BaseModel):
236
+ name: str
237
+ age: int
198
238
 
199
- # note that client.chat.completions.create will also work
200
239
  resp = client.chat.completions.create(
240
+ model="google/gemini-1.5-flash-001",
241
+ max_tokens=1024,
201
242
  messages=[
202
243
  {
203
244
  "role": "user",
@@ -212,6 +253,7 @@ assert resp.name == "Jason"
212
253
  assert resp.age == 25
213
254
  ```
214
255
 
256
+
215
257
  ### Using Litellm
216
258
 
217
259
  ```python
@@ -369,13 +411,13 @@ for user in user_stream:
369
411
  #> name=None age=None
370
412
  #> name=None age=None
371
413
  #> name=None age=None
372
- #> name=None age=25
373
- #> name=None age=25
374
- #> name=None age=25
375
- #> name=None age=25
376
- #> name=None age=25
377
- #> name=None age=25
378
- #> name='John Doe' age=25
414
+ #> name=None age=None
415
+ #> name=None age=None
416
+ #> name='John Doe' age=None
417
+ #> name='John Doe' age=None
418
+ #> name='John Doe' age=None
419
+ #> name='John Doe' age=30
420
+ #> name='John Doe' age=30
379
421
  # name=None age=None
380
422
  # name='' age=None
381
423
  # name='John' age=None
@@ -415,8 +457,8 @@ users = client.chat.completions.create_iterable(
415
457
 
416
458
  for user in users:
417
459
  print(user)
418
- #> name='John' age=30
419
- #> name='Jane' age=25
460
+ #> name='John Doe' age=30
461
+ #> name='Jane Doe' age=28
420
462
  # User(name='John Doe', age=30)
421
463
  # User(name='Jane Smith', age=25)
422
464
  ```
@@ -6,6 +6,10 @@ Instructor is a Python library that makes it a breeze to work with structured ou
6
6
  [![Discord](https://img.shields.io/discord/1192334452110659664?label=discord)](https://discord.gg/bD9YE9JArw)
7
7
  [![Downloads](https://img.shields.io/pypi/dm/instructor.svg)](https://pypi.python.org/pypi/instructor)
8
8
 
9
+ ## Want your logo on our website?
10
+
11
+ If your company use instructor a lot, we'd love to have your logo on our website! Please fill out [this form](https://q7gjsgfstrp.typeform.com/to/wluQlVVQ)
12
+
9
13
  ## Key Features
10
14
 
11
15
  - **Response Models**: Specify Pydantic models to define the structure of your LLM outputs
@@ -138,20 +142,53 @@ import instructor
138
142
  import google.generativeai as genai
139
143
  from pydantic import BaseModel
140
144
 
145
+
141
146
  class User(BaseModel):
142
147
  name: str
143
148
  age: int
144
149
 
150
+
145
151
  # genai.configure(api_key=os.environ["API_KEY"]) # alternative API key configuration
146
152
  client = instructor.from_gemini(
147
153
  client=genai.GenerativeModel(
148
- model_name="models/gemini-1.5-flash-latest", # model defaults to "gemini-pro"
154
+ model_name="models/gemini-1.5-flash-latest", # model defaults to "gemini-pro"
149
155
  ),
150
156
  mode=instructor.Mode.GEMINI_JSON,
151
157
  )
158
+ ```
159
+
160
+
161
+ Alternatively, you can [call Gemini from the OpenAI client](https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/call-gemini-using-openai-library#python).You'll have to setup [`gcloud`](https://cloud.google.com/docs/authentication/provide-credentials-adc#local-dev), get setup on Vertex AI, and install the Google Auth library.
162
+
163
+ ```sh
164
+ pip install google-auth
165
+ ```
166
+
167
+ ```python
168
+ import google.auth
169
+ import google.auth.transport.requests
170
+ import instructor
171
+ from openai import OpenAI
172
+ from pydantic import BaseModel
173
+
174
+ creds, project = google.auth.default()
175
+ auth_req = google.auth.transport.requests.Request()
176
+ creds.refresh(auth_req)
177
+
178
+ # Pass the Vertex endpoint and authentication to the OpenAI SDK
179
+ PROJECT = 'PROJECT_ID'
180
+ LOCATION = 'LOCATION' # https://cloud.google.com/vertex-ai/generative-ai/docs/learn/locations
181
+ base_url = f'https://{LOCATION}-aiplatform.googleapis.com/v1beta1/projects/{PROJECT}/locations/{LOCATION}/endpoints/openapi'
182
+
183
+ client = instructor.from_openai(OpenAI(base_url=base_url, api_key=creds.token), mode=instructor.Mode.JSON)
184
+ # JSON mode is req'd
185
+ class User(BaseModel):
186
+ name: str
187
+ age: int
152
188
 
153
- # note that client.chat.completions.create will also work
154
189
  resp = client.chat.completions.create(
190
+ model="google/gemini-1.5-flash-001",
191
+ max_tokens=1024,
155
192
  messages=[
156
193
  {
157
194
  "role": "user",
@@ -166,6 +203,7 @@ assert resp.name == "Jason"
166
203
  assert resp.age == 25
167
204
  ```
168
205
 
206
+
169
207
  ### Using Litellm
170
208
 
171
209
  ```python
@@ -323,13 +361,13 @@ for user in user_stream:
323
361
  #> name=None age=None
324
362
  #> name=None age=None
325
363
  #> name=None age=None
326
- #> name=None age=25
327
- #> name=None age=25
328
- #> name=None age=25
329
- #> name=None age=25
330
- #> name=None age=25
331
- #> name=None age=25
332
- #> name='John Doe' age=25
364
+ #> name=None age=None
365
+ #> name=None age=None
366
+ #> name='John Doe' age=None
367
+ #> name='John Doe' age=None
368
+ #> name='John Doe' age=None
369
+ #> name='John Doe' age=30
370
+ #> name='John Doe' age=30
333
371
  # name=None age=None
334
372
  # name='' age=None
335
373
  # name='John' age=None
@@ -369,8 +407,8 @@ users = client.chat.completions.create_iterable(
369
407
 
370
408
  for user in users:
371
409
  print(user)
372
- #> name='John' age=30
373
- #> name='Jane' age=25
410
+ #> name='John Doe' age=30
411
+ #> name='Jane Doe' age=28
374
412
  # User(name='John Doe', age=30)
375
413
  # User(name='Jane Smith', age=25)
376
414
  ```
@@ -74,3 +74,8 @@ if importlib.util.find_spec("cohere") is not None:
74
74
  from .client_cohere import from_cohere
75
75
 
76
76
  __all__ += ["from_cohere"]
77
+
78
+ if importlib.util.find_spec("vertexai") is not None:
79
+ from .client_vertexai import from_vertexai
80
+
81
+ __all__ += ["from_vertexai"]
@@ -0,0 +1,74 @@
1
+ from typing import Literal, Any, Union
2
+ from pydantic import BaseModel, Field
3
+ from instructor.process_response import handle_response_model
4
+ import uuid
5
+
6
+ openai_models = Literal[
7
+ "gpt-4o",
8
+ "gpt-4-turbo",
9
+ "gpt-4",
10
+ "gpt-4-32k",
11
+ "gpt-3.5-turbo",
12
+ "gpt-3.5-turbo-16k",
13
+ "gpt-4-turbo-preview",
14
+ "gpt-4-vision-preview",
15
+ "gpt-4-turbo-2024-04-09",
16
+ "gpt-4-0314",
17
+ "gpt-4-32k-0314",
18
+ "gpt-4-32k-0613",
19
+ "gpt-3.5-turbo-0301",
20
+ "gpt-3.5-turbo-16k-0613",
21
+ "gpt-3.5-turbo-1106",
22
+ "gpt-3.5-turbo-0613",
23
+ ]
24
+
25
+
26
+ class Function(BaseModel):
27
+ name: str
28
+ description: str
29
+ parameters: Any
30
+
31
+
32
+ class Tool(BaseModel):
33
+ type: str
34
+ function: Function
35
+
36
+
37
+ class RequestBody(BaseModel):
38
+ model: Union[openai_models, str]
39
+ messages: list[dict[str, Any]]
40
+ max_tokens: int = Field(default=1000)
41
+ tools: list[Tool]
42
+
43
+
44
+ class BatchModel(BaseModel):
45
+ custom_id: str
46
+ method: Literal["POST"]
47
+ url: Literal["/v1/chat/completions"]
48
+ body: RequestBody
49
+
50
+
51
+ class BatchJob:
52
+ @classmethod
53
+ def create_from_messages(
54
+ cls,
55
+ messages_batch: list[list[dict[str, Any]]],
56
+ model: Union[openai_models, str],
57
+ response_model: type[BaseModel],
58
+ max_tokens: int = 1000,
59
+ ):
60
+ _, tools = handle_response_model(response_model=response_model)
61
+ return [
62
+ BatchModel(
63
+ custom_id=str(uuid.uuid4()),
64
+ method="POST",
65
+ url="/v1/chat/completions",
66
+ body=RequestBody(
67
+ model=model,
68
+ max_tokens=max_tokens,
69
+ messages=messages,
70
+ **tools,
71
+ ),
72
+ ).model_dump(mode="json")
73
+ for messages in messages_batch
74
+ ]
@@ -0,0 +1,101 @@
1
+ from rich.console import Console
2
+ from rich.table import Table
3
+ from rich.live import Live
4
+ from openai import OpenAI
5
+ from openai.types.batch import Batch
6
+ import typer
7
+ import datetime
8
+ import time
9
+
10
+ client = OpenAI()
11
+ app = typer.Typer()
12
+
13
+ console = Console()
14
+
15
+
16
+ def generate_table(batch_jobs: list[Batch]):
17
+ table = Table(
18
+ title="OpenAI Batch Jobs",
19
+ )
20
+
21
+ table.add_column("Batch ID", style="dim")
22
+ table.add_column("Created At")
23
+ table.add_column("Status")
24
+ table.add_column("Failed")
25
+ table.add_column("Completed")
26
+ table.add_column("Total")
27
+
28
+ for batch_job in batch_jobs:
29
+ table.add_row(
30
+ batch_job.id,
31
+ str(datetime.datetime.fromtimestamp(batch_job.created_at)),
32
+ batch_job.status,
33
+ str(batch_job.request_counts.failed), # type: ignore
34
+ str(batch_job.request_counts.completed), # type: ignore
35
+ str(batch_job.request_counts.total), # type: ignore
36
+ )
37
+
38
+ return table
39
+
40
+
41
+ def get_jobs(limit: int = 10):
42
+ return client.batches.list(limit=limit).data
43
+
44
+
45
+ @app.command(name="list", help="See all existing batch jobs")
46
+ def watch(
47
+ limit: int = typer.Option(10, help="Total number of batch jobs to show"),
48
+ poll: int = typer.Option(
49
+ 10, help="Time in seconds to wait for the batch job to complete"
50
+ ),
51
+ screen: bool = typer.Option(False, help="Enable or disable screen output"),
52
+ ):
53
+ """
54
+ Monitor the status of the most recent batch jobs
55
+ """
56
+ batch_jobs = get_jobs(limit)
57
+ table = generate_table(batch_jobs)
58
+ with Live(
59
+ generate_table(batch_jobs), refresh_per_second=2, screen=screen
60
+ ) as live_table:
61
+ while True:
62
+ batch_jobs = get_jobs(limit)
63
+ table = generate_table(batch_jobs)
64
+ live_table.update(table)
65
+ time.sleep(poll)
66
+
67
+
68
+ @app.command(
69
+ help="Create a batch job from a file",
70
+ )
71
+ def create_from_file(
72
+ file_path: str = typer.Option(help="File containing the batch job requests"),
73
+ ):
74
+ with console.status(f"[bold green] Uploading batch job file...", spinner="dots"):
75
+ batch_input_file = client.files.create(
76
+ file=open(file_path, "rb"), purpose="batch"
77
+ )
78
+
79
+ batch_input_file_id = batch_input_file.id
80
+
81
+ with console.status(
82
+ f"[bold green] Creating batch job from ID {batch_input_file_id}", spinner="dots"
83
+ ):
84
+ client.batches.create(
85
+ input_file_id=batch_input_file_id,
86
+ endpoint="/v1/chat/completions",
87
+ completion_window="24h",
88
+ metadata={"description": "testing job"},
89
+ )
90
+
91
+ watch(limit=5, poll=2, screen=False)
92
+
93
+
94
+ @app.command(help="Cancel a batch job")
95
+ def cancel(batch_id: str = typer.Option(help="Batch job ID to cancel")):
96
+ try:
97
+ client.batches.cancel(batch_id)
98
+ watch(limit=5, poll=2, screen=False)
99
+ console.log(f"[bold red]Job {batch_id} cancelled successfully!")
100
+ except Exception as e:
101
+ console.log(f"[bold red]Error cancelling job {batch_id}: {e}")
@@ -3,6 +3,7 @@ import instructor.cli.jobs as jobs
3
3
  import instructor.cli.files as files
4
4
  import instructor.cli.usage as usage
5
5
  import instructor.cli.hub as hub
6
+ import instructor.cli.batch as batch
6
7
 
7
8
  app = typer.Typer()
8
9
 
@@ -10,6 +11,7 @@ app.add_typer(jobs.app, name="jobs", help="Monitor and create fine tuning jobs")
10
11
  app.add_typer(files.app, name="files", help="Manage files on OpenAI's servers")
11
12
  app.add_typer(usage.app, name="usage", help="Check OpenAI API usage data")
12
13
  app.add_typer(hub.app, name="hub", help="Interact with the instructor hub")
14
+ app.add_typer(batch.app, name="batch", help="Manage OpenAI Batch jobs")
13
15
 
14
16
 
15
17
  @app.command()
@@ -18,6 +20,6 @@ def docs(query: str = typer.Argument(None, help="Search the documentation")) ->
18
20
  Open the instructor documentation website.
19
21
  """
20
22
  if query:
21
- typer.launch(f"https://jxnl.github.io/instructor/?q={query}")
23
+ typer.launch(f"https://python.useinstructor.com/?q={query}")
22
24
  else:
23
- typer.launch("https://jxnl.github.io/instructor")
25
+ typer.launch("https://python.useinstructor.com/")
@@ -118,11 +118,11 @@ def calculate_cost(
118
118
 
119
119
  def group_and_sum_by_date_and_snapshot(usage_data: list[dict[str, Any]]) -> Table:
120
120
  """Group and sum the usage data by date and snapshot, including costs."""
121
- summary: defaultdict[
122
- str, defaultdict[str, dict[str, Union[int, float]]]
123
- ] = defaultdict(
124
- lambda: defaultdict(
125
- lambda: {"total_requests": 0, "total_tokens": 0, "total_cost": 0.0}
121
+ summary: defaultdict[str, defaultdict[str, dict[str, Union[int, float]]]] = (
122
+ defaultdict(
123
+ lambda: defaultdict(
124
+ lambda: {"total_requests": 0, "total_tokens": 0, "total_cost": 0.0}
125
+ )
126
126
  )
127
127
  )
128
128
 
@@ -63,8 +63,7 @@ class Instructor:
63
63
  validation_context: dict[str, Any] | None = None,
64
64
  strict: bool = True,
65
65
  **kwargs: Any,
66
- ) -> Awaitable[T]:
67
- ...
66
+ ) -> Awaitable[T]: ...
68
67
 
69
68
  @overload
70
69
  def create(
@@ -75,8 +74,7 @@ class Instructor:
75
74
  validation_context: dict[str, Any] | None = None,
76
75
  strict: bool = True,
77
76
  **kwargs: Any,
78
- ) -> T:
79
- ...
77
+ ) -> T: ...
80
78
 
81
79
  # TODO: we should overload a case where response_model is None
82
80
  def create(
@@ -108,8 +106,7 @@ class Instructor:
108
106
  validation_context: dict[str, Any] | None = None,
109
107
  strict: bool = True,
110
108
  **kwargs: Any,
111
- ) -> AsyncGenerator[T, None]:
112
- ...
109
+ ) -> AsyncGenerator[T, None]: ...
113
110
 
114
111
  @overload
115
112
  def create_partial(
@@ -120,8 +117,7 @@ class Instructor:
120
117
  validation_context: dict[str, Any] | None = None,
121
118
  strict: bool = True,
122
119
  **kwargs: Any,
123
- ) -> Generator[T, None, None]:
124
- ...
120
+ ) -> Generator[T, None, None]: ...
125
121
 
126
122
  def create_partial(
127
123
  self,
@@ -155,8 +151,7 @@ class Instructor:
155
151
  validation_context: dict[str, Any] | None = None,
156
152
  strict: bool = True,
157
153
  **kwargs: Any,
158
- ) -> AsyncGenerator[T, None]:
159
- ...
154
+ ) -> AsyncGenerator[T, None]: ...
160
155
 
161
156
  @overload
162
157
  def create_iterable(
@@ -167,8 +162,7 @@ class Instructor:
167
162
  validation_context: dict[str, Any] | None = None,
168
163
  strict: bool = True,
169
164
  **kwargs: Any,
170
- ) -> Generator[T, None, None]:
171
- ...
165
+ ) -> Generator[T, None, None]: ...
172
166
 
173
167
  def create_iterable(
174
168
  self,
@@ -179,8 +173,6 @@ class Instructor:
179
173
  strict: bool = True,
180
174
  **kwargs: Any,
181
175
  ) -> Generator[T, None, None] | AsyncGenerator[T, None]:
182
- assert self.provider != Provider.ANTHROPIC, "Anthropic doesn't support iterable"
183
-
184
176
  kwargs["stream"] = True
185
177
  kwargs = self.handle_kwargs(kwargs)
186
178
 
@@ -203,8 +195,7 @@ class Instructor:
203
195
  validation_context: dict[str, Any] | None = None,
204
196
  strict: bool = True,
205
197
  **kwargs: Any,
206
- ) -> Awaitable[tuple[T, Any]]:
207
- ...
198
+ ) -> Awaitable[tuple[T, Any]]: ...
208
199
 
209
200
  @overload
210
201
  def create_with_completion(
@@ -215,8 +206,7 @@ class Instructor:
215
206
  validation_context: dict[str, Any] | None = None,
216
207
  strict: bool = True,
217
208
  **kwargs: Any,
218
- ) -> tuple[T, Any]:
219
- ...
209
+ ) -> tuple[T, Any]: ...
220
210
 
221
211
  def create_with_completion(
222
212
  self,
@@ -432,8 +422,7 @@ def from_litellm(
432
422
  completion: Callable[..., Any],
433
423
  mode: instructor.Mode = instructor.Mode.TOOLS,
434
424
  **kwargs: Any,
435
- ) -> Instructor:
436
- ...
425
+ ) -> Instructor: ...
437
426
 
438
427
 
439
428
  @overload
@@ -11,10 +11,9 @@ def from_anthropic(
11
11
  client: (
12
12
  anthropic.Anthropic | anthropic.AnthropicBedrock | anthropic.AnthropicVertex
13
13
  ),
14
- mode: instructor.Mode = instructor.Mode.ANTHROPIC_JSON,
14
+ mode: instructor.Mode = instructor.Mode.ANTHROPIC_TOOLS,
15
15
  **kwargs: Any,
16
- ) -> instructor.Instructor:
17
- ...
16
+ ) -> instructor.Instructor: ...
18
17
 
19
18
 
20
19
  @overload
@@ -24,10 +23,9 @@ def from_anthropic(
24
23
  | anthropic.AsyncAnthropicBedrock
25
24
  | anthropic.AsyncAnthropicVertex
26
25
  ),
27
- mode: instructor.Mode = instructor.Mode.ANTHROPIC_JSON,
26
+ mode: instructor.Mode = instructor.Mode.ANTHROPIC_TOOLS,
28
27
  **kwargs: Any,
29
- ) -> instructor.AsyncInstructor:
30
- ...
28
+ ) -> instructor.AsyncInstructor: ...
31
29
 
32
30
 
33
31
  def from_anthropic(
@@ -39,7 +37,7 @@ def from_anthropic(
39
37
  | anthropic.AsyncAnthropicVertex
40
38
  | anthropic.AnthropicVertex
41
39
  ),
42
- mode: instructor.Mode = instructor.Mode.ANTHROPIC_JSON,
40
+ mode: instructor.Mode = instructor.Mode.ANTHROPIC_TOOLS,
43
41
  **kwargs: Any,
44
42
  ) -> instructor.Instructor | instructor.AsyncInstructor:
45
43
  assert (
@@ -62,10 +60,7 @@ def from_anthropic(
62
60
  ),
63
61
  ), "Client must be an instance of {anthropic.Anthropic, anthropic.AsyncAnthropic, anthropic.AnthropicBedrock, anthropic.AsyncAnthropicBedrock, anthropic.AnthropicVertex, anthropic.AsyncAnthropicVertex}"
64
62
 
65
- if mode == instructor.Mode.ANTHROPIC_TOOLS:
66
- create = client.beta.tools.messages.create # type: ignore - unknown in stubs
67
- else:
68
- create = client.messages.create
63
+ create = client.messages.create
69
64
 
70
65
  if isinstance(
71
66
  client,
@@ -23,8 +23,7 @@ def from_cohere(
23
23
  client: cohere.Client,
24
24
  mode: instructor.Mode = instructor.Mode.COHERE_TOOLS,
25
25
  **kwargs: Any,
26
- ) -> instructor.Instructor:
27
- ...
26
+ ) -> instructor.Instructor: ...
28
27
 
29
28
 
30
29
  @overload
@@ -32,8 +31,7 @@ def from_cohere(
32
31
  client: cohere.AsyncClient,
33
32
  mode: instructor.Mode = instructor.Mode.COHERE_TOOLS,
34
33
  **kwargs: Any,
35
- ) -> instructor.AsyncInstructor:
36
- ...
34
+ ) -> instructor.AsyncInstructor: ...
37
35
 
38
36
 
39
37
  def from_cohere(