hammad-python 0.0.14__py3-none-any.whl → 0.0.16__py3-none-any.whl

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 (122) hide show
  1. hammad/__init__.py +177 -0
  2. hammad/{performance/imports.py → _internal.py} +7 -1
  3. hammad/cache/__init__.py +1 -1
  4. hammad/cli/__init__.py +3 -1
  5. hammad/cli/_runner.py +265 -0
  6. hammad/cli/animations.py +1 -1
  7. hammad/cli/plugins.py +133 -78
  8. hammad/cli/styles/__init__.py +1 -1
  9. hammad/cli/styles/utils.py +149 -3
  10. hammad/data/__init__.py +56 -29
  11. hammad/data/collections/__init__.py +27 -17
  12. hammad/data/collections/collection.py +205 -383
  13. hammad/data/collections/indexes/__init__.py +37 -0
  14. hammad/data/collections/indexes/qdrant/__init__.py +1 -0
  15. hammad/data/collections/indexes/qdrant/index.py +735 -0
  16. hammad/data/collections/indexes/qdrant/settings.py +94 -0
  17. hammad/data/collections/indexes/qdrant/utils.py +220 -0
  18. hammad/data/collections/indexes/tantivy/__init__.py +1 -0
  19. hammad/data/collections/indexes/tantivy/index.py +428 -0
  20. hammad/data/collections/indexes/tantivy/settings.py +51 -0
  21. hammad/data/collections/indexes/tantivy/utils.py +200 -0
  22. hammad/data/configurations/__init__.py +2 -2
  23. hammad/data/configurations/configuration.py +2 -2
  24. hammad/data/models/__init__.py +20 -9
  25. hammad/data/models/extensions/__init__.py +4 -0
  26. hammad/data/models/{pydantic → extensions/pydantic}/__init__.py +6 -19
  27. hammad/data/models/{pydantic → extensions/pydantic}/converters.py +143 -16
  28. hammad/data/models/{base/fields.py → fields.py} +1 -1
  29. hammad/data/models/{base/model.py → model.py} +1 -1
  30. hammad/data/models/{base/utils.py → utils.py} +1 -1
  31. hammad/data/sql/__init__.py +23 -0
  32. hammad/data/sql/database.py +578 -0
  33. hammad/data/sql/types.py +141 -0
  34. hammad/data/types/__init__.py +1 -3
  35. hammad/data/types/file.py +3 -3
  36. hammad/data/types/multimodal/__init__.py +2 -2
  37. hammad/data/types/multimodal/audio.py +2 -2
  38. hammad/data/types/multimodal/image.py +2 -2
  39. hammad/formatting/__init__.py +9 -27
  40. hammad/formatting/json/__init__.py +8 -2
  41. hammad/formatting/json/converters.py +7 -1
  42. hammad/formatting/text/__init__.py +1 -1
  43. hammad/formatting/yaml/__init__.py +1 -1
  44. hammad/genai/__init__.py +78 -0
  45. hammad/genai/agents/__init__.py +1 -0
  46. hammad/genai/agents/types/__init__.py +35 -0
  47. hammad/genai/agents/types/history.py +277 -0
  48. hammad/genai/agents/types/tool.py +490 -0
  49. hammad/genai/embedding_models/__init__.py +41 -0
  50. hammad/{ai/embeddings/client/litellm_embeddings_client.py → genai/embedding_models/embedding_model.py} +47 -142
  51. hammad/genai/embedding_models/embedding_model_name.py +77 -0
  52. hammad/genai/embedding_models/embedding_model_request.py +65 -0
  53. hammad/{ai/embeddings/types.py → genai/embedding_models/embedding_model_response.py} +3 -3
  54. hammad/genai/embedding_models/run.py +161 -0
  55. hammad/genai/language_models/__init__.py +35 -0
  56. hammad/genai/language_models/_streaming.py +622 -0
  57. hammad/genai/language_models/_types.py +276 -0
  58. hammad/genai/language_models/_utils/__init__.py +31 -0
  59. hammad/genai/language_models/_utils/_completions.py +131 -0
  60. hammad/genai/language_models/_utils/_messages.py +89 -0
  61. hammad/genai/language_models/_utils/_requests.py +202 -0
  62. hammad/genai/language_models/_utils/_structured_outputs.py +124 -0
  63. hammad/genai/language_models/language_model.py +734 -0
  64. hammad/genai/language_models/language_model_request.py +135 -0
  65. hammad/genai/language_models/language_model_response.py +219 -0
  66. hammad/genai/language_models/language_model_response_chunk.py +53 -0
  67. hammad/genai/language_models/run.py +530 -0
  68. hammad/genai/multimodal_models.py +48 -0
  69. hammad/genai/rerank_models.py +26 -0
  70. hammad/logging/__init__.py +1 -1
  71. hammad/logging/decorators.py +1 -1
  72. hammad/logging/logger.py +2 -2
  73. hammad/mcp/__init__.py +1 -1
  74. hammad/mcp/client/__init__.py +35 -0
  75. hammad/mcp/client/client.py +105 -4
  76. hammad/mcp/client/client_service.py +10 -3
  77. hammad/mcp/servers/__init__.py +24 -0
  78. hammad/{performance/runtime → runtime}/__init__.py +2 -2
  79. hammad/{performance/runtime → runtime}/decorators.py +1 -1
  80. hammad/{performance/runtime → runtime}/run.py +1 -1
  81. hammad/service/__init__.py +1 -1
  82. hammad/service/create.py +3 -8
  83. hammad/service/decorators.py +8 -8
  84. hammad/typing/__init__.py +28 -0
  85. hammad/web/__init__.py +3 -3
  86. hammad/web/http/client.py +1 -1
  87. hammad/web/models.py +53 -21
  88. hammad/web/search/client.py +99 -52
  89. hammad/web/utils.py +13 -13
  90. hammad_python-0.0.16.dist-info/METADATA +191 -0
  91. hammad_python-0.0.16.dist-info/RECORD +110 -0
  92. hammad/ai/__init__.py +0 -1
  93. hammad/ai/_utils.py +0 -142
  94. hammad/ai/completions/__init__.py +0 -45
  95. hammad/ai/completions/client.py +0 -684
  96. hammad/ai/completions/create.py +0 -710
  97. hammad/ai/completions/settings.py +0 -100
  98. hammad/ai/completions/types.py +0 -792
  99. hammad/ai/completions/utils.py +0 -486
  100. hammad/ai/embeddings/__init__.py +0 -35
  101. hammad/ai/embeddings/client/__init__.py +0 -1
  102. hammad/ai/embeddings/client/base_embeddings_client.py +0 -26
  103. hammad/ai/embeddings/client/fastembed_text_embeddings_client.py +0 -200
  104. hammad/ai/embeddings/create.py +0 -159
  105. hammad/data/collections/base_collection.py +0 -58
  106. hammad/data/collections/searchable_collection.py +0 -556
  107. hammad/data/collections/vector_collection.py +0 -596
  108. hammad/data/databases/__init__.py +0 -21
  109. hammad/data/databases/database.py +0 -902
  110. hammad/data/models/base/__init__.py +0 -35
  111. hammad/data/models/pydantic/models/__init__.py +0 -28
  112. hammad/data/models/pydantic/models/arbitrary_model.py +0 -46
  113. hammad/data/models/pydantic/models/cacheable_model.py +0 -79
  114. hammad/data/models/pydantic/models/fast_model.py +0 -318
  115. hammad/data/models/pydantic/models/function_model.py +0 -176
  116. hammad/data/models/pydantic/models/subscriptable_model.py +0 -63
  117. hammad/performance/__init__.py +0 -36
  118. hammad/py.typed +0 -0
  119. hammad_python-0.0.14.dist-info/METADATA +0 -70
  120. hammad_python-0.0.14.dist-info/RECORD +0 -99
  121. {hammad_python-0.0.14.dist-info → hammad_python-0.0.16.dist-info}/WHEEL +0 -0
  122. {hammad_python-0.0.14.dist-info → hammad_python-0.0.16.dist-info}/licenses/LICENSE +0 -0
@@ -1,684 +0,0 @@
1
- """hammad.ai.completions.client"""
2
-
3
- from httpx import Timeout
4
- from typing import Any, Dict, List, Generic, Literal, TypeVar, Optional, Union, Type
5
- import sys
6
-
7
- if sys.version_info >= (3, 12):
8
- from typing import TypedDict, Required, NotRequired
9
- else:
10
- from typing_extensions import TypedDict, Required, NotRequired
11
-
12
- try:
13
- from openai.types.chat import (
14
- ChatCompletionModality,
15
- ChatCompletionPredictionContentParam,
16
- ChatCompletionAudioParam,
17
- )
18
- except ImportError:
19
- raise ImportError(
20
- "Using the `hammad.ai.completions` extension requires the `openai` package to be installed.\n"
21
- "Please either install the `openai` package, or install the `hammad.ai` extension with:\n"
22
- "`pip install 'hammad-python[ai]'"
23
- )
24
-
25
- from ...data.models.pydantic.converters import convert_to_pydantic_model
26
- from .._utils import get_litellm, get_instructor
27
- from ...typing import is_pydantic_basemodel
28
- from .utils import (
29
- format_tool_calls,
30
- parse_completions_input,
31
- convert_response_to_completion,
32
- create_async_completion_stream,
33
- create_completion_stream,
34
- InstructorStreamWrapper,
35
- AsyncInstructorStreamWrapper,
36
- )
37
- from .settings import (
38
- CompletionsSettings,
39
- OpenAIWebSearchOptions,
40
- AnthropicThinkingParam,
41
- )
42
- from .types import (
43
- CompletionsInstructorModeParam,
44
- CompletionsInputParam,
45
- CompletionsOutputType,
46
- Completion,
47
- )
48
-
49
-
50
- __all__ = "CompletionsClient"
51
-
52
-
53
- class CompletionsError(Exception):
54
- """Error raised when an error occurs during a completion."""
55
-
56
- def __init__(
57
- self,
58
- message: str,
59
- *args: Any,
60
- **kwargs: Any,
61
- ):
62
- super().__init__(message, *args, **kwargs)
63
- self.message = message
64
- self.args = args
65
- self.kwargs = kwargs
66
-
67
-
68
- class CompletionsClient(Generic[CompletionsOutputType]):
69
- """Client for working with language model completions and structured
70
- outputs using the `litellm` and `instructor` libraries."""
71
-
72
- @staticmethod
73
- async def async_chat_completion(
74
- messages: CompletionsInputParam,
75
- instructions: Optional[str] = None,
76
- model: str = "openai/gpt-4o-mini",
77
- *,
78
- timeout: Optional[Union[float, str, Timeout]] = None,
79
- temperature: Optional[float] = None,
80
- top_p: Optional[float] = None,
81
- n: Optional[int] = None,
82
- stream: Optional[bool] = None,
83
- stream_options: Optional[Dict[str, Any]] = None,
84
- stop: Optional[str] = None,
85
- max_completion_tokens: Optional[int] = None,
86
- max_tokens: Optional[int] = None,
87
- modalities: Optional[List[ChatCompletionModality]] = None,
88
- prediction: Optional[ChatCompletionPredictionContentParam] = None,
89
- audio: Optional[ChatCompletionAudioParam] = None,
90
- presence_penalty: Optional[float] = None,
91
- frequency_penalty: Optional[float] = None,
92
- logit_bias: Optional[Dict[str, float]] = None,
93
- user: Optional[str] = None,
94
- reasoning_effort: Optional[Literal["low", "medium", "high"]] = None,
95
- # NOTE: response_format is not used within the `completions` resource
96
- # in place of `instructor` and the `type` parameter
97
- seed: Optional[int] = None,
98
- tools: Optional[List] = None,
99
- tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
100
- logprobs: Optional[bool] = None,
101
- top_logprobs: Optional[int] = None,
102
- parallel_tool_calls: Optional[bool] = None,
103
- web_search_options: Optional[OpenAIWebSearchOptions] = None,
104
- deployment_id: Optional[str] = None,
105
- extra_headers: Optional[Dict[str, str]] = None,
106
- base_url: Optional[str] = None,
107
- functions: Optional[List] = None,
108
- function_call: Optional[str] = None,
109
- # set api_base, api_version, api_key
110
- api_version: Optional[str] = None,
111
- api_key: Optional[str] = None,
112
- model_list: Optional[list] = None,
113
- # Optional liteLLM function params
114
- thinking: Optional[AnthropicThinkingParam] = None,
115
- ):
116
- try:
117
- parsed_messages = parse_completions_input(messages, instructions)
118
- except Exception as e:
119
- raise CompletionsError(
120
- f"Error parsing completions input: {e}",
121
- input=messages,
122
- ) from e
123
-
124
- params: CompletionsSettings = {
125
- "model": model,
126
- "messages": parsed_messages,
127
- "timeout": timeout,
128
- "temperature": temperature,
129
- "top_p": top_p,
130
- "n": n,
131
- "stop": stop,
132
- "max_completion_tokens": max_completion_tokens,
133
- "max_tokens": max_tokens,
134
- "modalities": modalities,
135
- "prediction": prediction,
136
- "audio": audio,
137
- "presence_penalty": presence_penalty,
138
- "frequency_penalty": frequency_penalty,
139
- "logit_bias": logit_bias,
140
- "user": user,
141
- "reasoning_effort": reasoning_effort,
142
- "seed": seed,
143
- "tools": tools,
144
- "tool_choice": tool_choice,
145
- "logprobs": logprobs,
146
- "top_logprobs": top_logprobs,
147
- "parallel_tool_calls": parallel_tool_calls,
148
- "web_search_options": web_search_options,
149
- "deployment_id": deployment_id,
150
- "extra_headers": extra_headers,
151
- "base_url": base_url,
152
- "functions": functions,
153
- "function_call": function_call,
154
- "api_version": api_version,
155
- "api_key": api_key,
156
- "model_list": model_list,
157
- "thinking": thinking,
158
- }
159
-
160
- if not stream:
161
- response = await get_litellm().acompletion(
162
- **{k: v for k, v in params.items() if v is not None}
163
- )
164
- return convert_response_to_completion(response)
165
- else:
166
- stream = await get_litellm().acompletion(
167
- **{k: v for k, v in params.items() if v is not None},
168
- stream=True,
169
- stream_options=stream_options if stream_options else None,
170
- )
171
- return create_async_completion_stream(stream, output_type=str, model=model)
172
-
173
- @staticmethod
174
- def chat_completion(
175
- messages: CompletionsInputParam,
176
- instructions: Optional[str] = None,
177
- model: str = "openai/gpt-4o-mini",
178
- *,
179
- timeout: Optional[Union[float, str, Timeout]] = None,
180
- temperature: Optional[float] = None,
181
- top_p: Optional[float] = None,
182
- n: Optional[int] = None,
183
- stream: Optional[bool] = None,
184
- stream_options: Optional[Dict[str, Any]] = None,
185
- stop: Optional[str] = None,
186
- max_completion_tokens: Optional[int] = None,
187
- max_tokens: Optional[int] = None,
188
- modalities: Optional[List[ChatCompletionModality]] = None,
189
- prediction: Optional[ChatCompletionPredictionContentParam] = None,
190
- audio: Optional[ChatCompletionAudioParam] = None,
191
- presence_penalty: Optional[float] = None,
192
- frequency_penalty: Optional[float] = None,
193
- logit_bias: Optional[Dict[str, float]] = None,
194
- user: Optional[str] = None,
195
- reasoning_effort: Optional[Literal["low", "medium", "high"]] = None,
196
- # NOTE: response_format is not used within the `completions` resource
197
- # in place of `instructor` and the `type` parameter
198
- seed: Optional[int] = None,
199
- tools: Optional[List] = None,
200
- tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
201
- logprobs: Optional[bool] = None,
202
- top_logprobs: Optional[int] = None,
203
- parallel_tool_calls: Optional[bool] = None,
204
- web_search_options: Optional[OpenAIWebSearchOptions] = None,
205
- deployment_id: Optional[str] = None,
206
- extra_headers: Optional[Dict[str, str]] = None,
207
- base_url: Optional[str] = None,
208
- functions: Optional[List] = None,
209
- function_call: Optional[str] = None,
210
- # set api_base, api_version, api_key
211
- api_version: Optional[str] = None,
212
- api_key: Optional[str] = None,
213
- model_list: Optional[list] = None,
214
- # Optional liteLLM function params
215
- thinking: Optional[AnthropicThinkingParam] = None,
216
- ):
217
- try:
218
- parsed_messages = parse_completions_input(messages, instructions)
219
- except Exception as e:
220
- raise CompletionsError(
221
- f"Error parsing completions input: {e}",
222
- input=messages,
223
- ) from e
224
-
225
- params: CompletionsSettings = {
226
- "model": model,
227
- "messages": parsed_messages,
228
- "timeout": timeout,
229
- "temperature": temperature,
230
- "top_p": top_p,
231
- "n": n,
232
- "stop": stop,
233
- "max_completion_tokens": max_completion_tokens,
234
- "max_tokens": max_tokens,
235
- "modalities": modalities,
236
- "prediction": prediction,
237
- "audio": audio,
238
- "presence_penalty": presence_penalty,
239
- "frequency_penalty": frequency_penalty,
240
- "logit_bias": logit_bias,
241
- "user": user,
242
- "reasoning_effort": reasoning_effort,
243
- "seed": seed,
244
- "tools": tools,
245
- "tool_choice": tool_choice,
246
- "logprobs": logprobs,
247
- "top_logprobs": top_logprobs,
248
- "parallel_tool_calls": parallel_tool_calls,
249
- "web_search_options": web_search_options,
250
- "deployment_id": deployment_id,
251
- "extra_headers": extra_headers,
252
- "base_url": base_url,
253
- "functions": functions,
254
- "function_call": function_call,
255
- "api_version": api_version,
256
- "api_key": api_key,
257
- "model_list": model_list,
258
- "thinking": thinking,
259
- }
260
-
261
- if not stream:
262
- response = get_litellm().completion(
263
- **{k: v for k, v in params.items() if v is not None}
264
- )
265
- return convert_response_to_completion(response)
266
- else:
267
- stream = get_litellm().completion(
268
- **{k: v for k, v in params.items() if v is not None},
269
- stream=True,
270
- stream_options=stream_options if stream_options else None,
271
- )
272
- return create_completion_stream(stream, output_type=str, model=model)
273
-
274
- @staticmethod
275
- async def async_structured_output(
276
- messages: CompletionsInputParam,
277
- instructions: Optional[str] = None,
278
- model: str = "openai/gpt-4o-mini",
279
- type: CompletionsOutputType = str,
280
- response_field_name: str = "content",
281
- response_field_instruction: str = "A response in the correct type as requested by the user, or relevant content.",
282
- instructor_mode: CompletionsInstructorModeParam = "tool_call",
283
- max_retries: int = 3,
284
- strict: bool = True,
285
- *,
286
- timeout: Optional[Union[float, str, Timeout]] = None,
287
- temperature: Optional[float] = None,
288
- top_p: Optional[float] = None,
289
- n: Optional[int] = None,
290
- stream: Optional[bool] = None,
291
- stream_options: Optional[Dict[str, Any]] = None,
292
- stop: Optional[str] = None,
293
- max_completion_tokens: Optional[int] = None,
294
- max_tokens: Optional[int] = None,
295
- modalities: Optional[List[ChatCompletionModality]] = None,
296
- prediction: Optional[ChatCompletionPredictionContentParam] = None,
297
- audio: Optional[ChatCompletionAudioParam] = None,
298
- presence_penalty: Optional[float] = None,
299
- frequency_penalty: Optional[float] = None,
300
- logit_bias: Optional[Dict[str, float]] = None,
301
- user: Optional[str] = None,
302
- reasoning_effort: Optional[Literal["low", "medium", "high"]] = None,
303
- # NOTE: response_format is not used within the `completions` resource
304
- # in place of `instructor` and the `type` parameter
305
- seed: Optional[int] = None,
306
- tools: Optional[List] = None,
307
- tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
308
- logprobs: Optional[bool] = None,
309
- top_logprobs: Optional[int] = None,
310
- parallel_tool_calls: Optional[bool] = None,
311
- web_search_options: Optional[OpenAIWebSearchOptions] = None,
312
- deployment_id: Optional[str] = None,
313
- extra_headers: Optional[Dict[str, str]] = None,
314
- base_url: Optional[str] = None,
315
- functions: Optional[List] = None,
316
- function_call: Optional[str] = None,
317
- # set api_base, api_version, api_key
318
- api_version: Optional[str] = None,
319
- api_key: Optional[str] = None,
320
- model_list: Optional[list] = None,
321
- # Optional liteLLM function params
322
- thinking: Optional[AnthropicThinkingParam] = None,
323
- ):
324
- try:
325
- parsed_messages = parse_completions_input(messages, instructions)
326
- except Exception as e:
327
- raise CompletionsError(
328
- f"Error parsing completions input: {e}",
329
- input=messages,
330
- ) from e
331
-
332
- parsed_messages = format_tool_calls(parsed_messages)
333
-
334
- params: CompletionsSettings = {
335
- "model": model,
336
- "messages": parsed_messages,
337
- "timeout": timeout,
338
- "temperature": temperature,
339
- "top_p": top_p,
340
- "n": n,
341
- "stop": stop,
342
- "max_completion_tokens": max_completion_tokens,
343
- "max_tokens": max_tokens,
344
- "modalities": modalities,
345
- "prediction": prediction,
346
- "audio": audio,
347
- "presence_penalty": presence_penalty,
348
- "frequency_penalty": frequency_penalty,
349
- "logit_bias": logit_bias,
350
- "user": user,
351
- "reasoning_effort": reasoning_effort,
352
- "seed": seed,
353
- "tools": tools,
354
- "tool_choice": tool_choice,
355
- "logprobs": logprobs,
356
- "top_logprobs": top_logprobs,
357
- "parallel_tool_calls": parallel_tool_calls,
358
- "web_search_options": web_search_options,
359
- "deployment_id": deployment_id,
360
- "extra_headers": extra_headers,
361
- "base_url": base_url,
362
- "functions": functions,
363
- "function_call": function_call,
364
- "api_version": api_version,
365
- "api_key": api_key,
366
- "model_list": model_list,
367
- "thinking": thinking,
368
- }
369
-
370
- if type is str:
371
- return await CompletionsClient.async_chat_completion(
372
- messages=messages,
373
- instructions=instructions,
374
- model=model,
375
- timeout=timeout,
376
- temperature=temperature,
377
- top_p=top_p,
378
- n=n,
379
- stream=stream,
380
- stream_options=stream_options,
381
- stop=stop,
382
- max_completion_tokens=max_completion_tokens,
383
- max_tokens=max_tokens,
384
- modalities=modalities,
385
- prediction=prediction,
386
- audio=audio,
387
- presence_penalty=presence_penalty,
388
- frequency_penalty=frequency_penalty,
389
- logit_bias=logit_bias,
390
- user=user,
391
- reasoning_effort=reasoning_effort,
392
- seed=seed,
393
- tools=tools,
394
- tool_choice=tool_choice,
395
- logprobs=logprobs,
396
- top_logprobs=top_logprobs,
397
- parallel_tool_calls=parallel_tool_calls,
398
- web_search_options=web_search_options,
399
- deployment_id=deployment_id,
400
- extra_headers=extra_headers,
401
- base_url=base_url,
402
- functions=functions,
403
- function_call=function_call,
404
- api_version=api_version,
405
- api_key=api_key,
406
- model_list=model_list,
407
- thinking=thinking,
408
- )
409
-
410
- try:
411
- client = get_instructor().from_litellm(
412
- completion=get_litellm().acompletion,
413
- mode=get_instructor().Mode(instructor_mode),
414
- )
415
- except Exception as e:
416
- raise CompletionsError(
417
- f"Error creating instructor client: {e}",
418
- input=messages,
419
- ) from e
420
-
421
- if not is_pydantic_basemodel(type):
422
- response_model = convert_to_pydantic_model(
423
- target=type,
424
- name="Response",
425
- field_name=response_field_name,
426
- description=response_field_instruction,
427
- )
428
- else:
429
- response_model = type
430
-
431
- if stream:
432
- # Create wrapper to capture raw content via hooks
433
- wrapper = AsyncInstructorStreamWrapper(
434
- client=client,
435
- response_model=response_model,
436
- params={
437
- "max_retries": max_retries,
438
- "strict": strict,
439
- **{k: v for k, v in params.items() if v is not None},
440
- },
441
- output_type=type,
442
- model=model,
443
- )
444
- return create_async_completion_stream(
445
- wrapper, output_type=type, model=model
446
- )
447
- else:
448
- response, completion = await client.chat.completions.create_with_completion(
449
- response_model=response_model,
450
- max_retries=max_retries,
451
- strict=strict,
452
- **{k: v for k, v in params.items() if v is not None},
453
- )
454
-
455
- # Extract the actual value if using converted pydantic model
456
- if not is_pydantic_basemodel(type) and hasattr(
457
- response, response_field_name
458
- ):
459
- actual_output = getattr(response, response_field_name)
460
- else:
461
- actual_output = response
462
-
463
- # Extract content and tool calls from the completion
464
- content = None
465
- tool_calls = None
466
- if hasattr(completion, "choices") and completion.choices:
467
- choice = completion.choices[0]
468
- if hasattr(choice, "message"):
469
- message = choice.message
470
- content = getattr(message, "content", None)
471
- tool_calls = getattr(message, "tool_calls", None)
472
-
473
- return Completion(
474
- output=actual_output,
475
- model=model,
476
- content=content,
477
- tool_calls=tool_calls,
478
- completion=completion,
479
- )
480
-
481
- @staticmethod
482
- def structured_output(
483
- messages: CompletionsInputParam,
484
- instructions: Optional[str] = None,
485
- model: str = "openai/gpt-4o-mini",
486
- type: CompletionsOutputType = str,
487
- response_field_name: str = "content",
488
- response_field_instruction: str = "A response in the correct type as requested by the user, or relevant content.",
489
- instructor_mode: CompletionsInstructorModeParam = "tool_call",
490
- max_retries: int = 3,
491
- strict: bool = True,
492
- *,
493
- timeout: Optional[Union[float, str, Timeout]] = None,
494
- temperature: Optional[float] = None,
495
- top_p: Optional[float] = None,
496
- n: Optional[int] = None,
497
- stream: Optional[bool] = None,
498
- stream_options: Optional[Dict[str, Any]] = None,
499
- stop: Optional[str] = None,
500
- max_completion_tokens: Optional[int] = None,
501
- max_tokens: Optional[int] = None,
502
- modalities: Optional[List[ChatCompletionModality]] = None,
503
- prediction: Optional[ChatCompletionPredictionContentParam] = None,
504
- audio: Optional[ChatCompletionAudioParam] = None,
505
- presence_penalty: Optional[float] = None,
506
- frequency_penalty: Optional[float] = None,
507
- logit_bias: Optional[Dict[str, float]] = None,
508
- user: Optional[str] = None,
509
- reasoning_effort: Optional[Literal["low", "medium", "high"]] = None,
510
- # NOTE: response_format is not used within the `completions` resource
511
- # in place of `instructor` and the `type` parameter
512
- seed: Optional[int] = None,
513
- tools: Optional[List] = None,
514
- tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
515
- logprobs: Optional[bool] = None,
516
- top_logprobs: Optional[int] = None,
517
- parallel_tool_calls: Optional[bool] = None,
518
- web_search_options: Optional[OpenAIWebSearchOptions] = None,
519
- deployment_id: Optional[str] = None,
520
- extra_headers: Optional[Dict[str, str]] = None,
521
- base_url: Optional[str] = None,
522
- functions: Optional[List] = None,
523
- function_call: Optional[str] = None,
524
- # set api_base, api_version, api_key
525
- api_version: Optional[str] = None,
526
- api_key: Optional[str] = None,
527
- model_list: Optional[list] = None,
528
- # Optional liteLLM function params
529
- thinking: Optional[AnthropicThinkingParam] = None,
530
- ):
531
- try:
532
- parsed_messages = parse_completions_input(messages, instructions)
533
- except Exception as e:
534
- raise CompletionsError(
535
- f"Error parsing completions input: {e}",
536
- input=messages,
537
- ) from e
538
-
539
- parsed_messages = format_tool_calls(parsed_messages)
540
-
541
- params: CompletionsSettings = {
542
- "model": model,
543
- "messages": parsed_messages,
544
- "timeout": timeout,
545
- "temperature": temperature,
546
- "top_p": top_p,
547
- "n": n,
548
- "stop": stop,
549
- "max_completion_tokens": max_completion_tokens,
550
- "max_tokens": max_tokens,
551
- "modalities": modalities,
552
- "prediction": prediction,
553
- "audio": audio,
554
- "presence_penalty": presence_penalty,
555
- "frequency_penalty": frequency_penalty,
556
- "logit_bias": logit_bias,
557
- "user": user,
558
- "reasoning_effort": reasoning_effort,
559
- "seed": seed,
560
- "tools": tools,
561
- "tool_choice": tool_choice,
562
- "logprobs": logprobs,
563
- "top_logprobs": top_logprobs,
564
- "parallel_tool_calls": parallel_tool_calls,
565
- "web_search_options": web_search_options,
566
- "deployment_id": deployment_id,
567
- "extra_headers": extra_headers,
568
- "base_url": base_url,
569
- "functions": functions,
570
- "function_call": function_call,
571
- "api_version": api_version,
572
- "api_key": api_key,
573
- "model_list": model_list,
574
- "thinking": thinking,
575
- }
576
-
577
- if type is str:
578
- return CompletionsClient.chat_completion(
579
- messages=messages,
580
- instructions=instructions,
581
- model=model,
582
- timeout=timeout,
583
- temperature=temperature,
584
- top_p=top_p,
585
- n=n,
586
- stream=stream,
587
- stream_options=stream_options,
588
- stop=stop,
589
- max_completion_tokens=max_completion_tokens,
590
- max_tokens=max_tokens,
591
- modalities=modalities,
592
- prediction=prediction,
593
- audio=audio,
594
- presence_penalty=presence_penalty,
595
- frequency_penalty=frequency_penalty,
596
- logit_bias=logit_bias,
597
- user=user,
598
- reasoning_effort=reasoning_effort,
599
- seed=seed,
600
- tools=tools,
601
- tool_choice=tool_choice,
602
- logprobs=logprobs,
603
- top_logprobs=top_logprobs,
604
- parallel_tool_calls=parallel_tool_calls,
605
- web_search_options=web_search_options,
606
- deployment_id=deployment_id,
607
- extra_headers=extra_headers,
608
- base_url=base_url,
609
- functions=functions,
610
- function_call=function_call,
611
- api_version=api_version,
612
- api_key=api_key,
613
- model_list=model_list,
614
- thinking=thinking,
615
- )
616
-
617
- try:
618
- client = get_instructor().from_litellm(
619
- completion=get_litellm().completion,
620
- mode=get_instructor().Mode(instructor_mode),
621
- )
622
- except Exception as e:
623
- raise CompletionsError(
624
- f"Error creating instructor client: {e}",
625
- input=messages,
626
- ) from e
627
-
628
- if not is_pydantic_basemodel(type):
629
- response_model = convert_to_pydantic_model(
630
- target=type,
631
- name="Response",
632
- field_name=response_field_name,
633
- description=response_field_instruction,
634
- )
635
- else:
636
- response_model = type
637
-
638
- if stream:
639
- # Create wrapper to capture raw content via hooks
640
- wrapper = InstructorStreamWrapper(
641
- client=client,
642
- response_model=response_model,
643
- params={
644
- "max_retries": max_retries,
645
- "strict": strict,
646
- **{k: v for k, v in params.items() if v is not None},
647
- },
648
- output_type=type,
649
- model=model,
650
- )
651
- return create_completion_stream(wrapper, output_type=type, model=model)
652
- else:
653
- response, completion = client.chat.completions.create_with_completion(
654
- response_model=response_model,
655
- max_retries=max_retries,
656
- strict=strict,
657
- **{k: v for k, v in params.items() if v is not None},
658
- )
659
-
660
- # Extract the actual value if using converted pydantic model
661
- if not is_pydantic_basemodel(type) and hasattr(
662
- response, response_field_name
663
- ):
664
- actual_output = getattr(response, response_field_name)
665
- else:
666
- actual_output = response
667
-
668
- # Extract content and tool calls from the completion
669
- content = None
670
- tool_calls = None
671
- if hasattr(completion, "choices") and completion.choices:
672
- choice = completion.choices[0]
673
- if hasattr(choice, "message"):
674
- message = choice.message
675
- content = getattr(message, "content", None)
676
- tool_calls = getattr(message, "tool_calls", None)
677
-
678
- return Completion(
679
- output=actual_output,
680
- model=model,
681
- content=content,
682
- tool_calls=tool_calls,
683
- completion=completion,
684
- )