mirascope 1.18.3__py3-none-any.whl → 1.19.0__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 (101) hide show
  1. mirascope/__init__.py +20 -2
  2. mirascope/beta/openai/__init__.py +1 -1
  3. mirascope/beta/openai/realtime/__init__.py +1 -1
  4. mirascope/beta/openai/realtime/tool.py +1 -1
  5. mirascope/beta/rag/__init__.py +2 -2
  6. mirascope/beta/rag/base/__init__.py +2 -2
  7. mirascope/beta/rag/weaviate/__init__.py +1 -1
  8. mirascope/core/__init__.py +26 -8
  9. mirascope/core/anthropic/__init__.py +3 -3
  10. mirascope/core/anthropic/_utils/_calculate_cost.py +114 -47
  11. mirascope/core/anthropic/call_response.py +9 -1
  12. mirascope/core/anthropic/call_response_chunk.py +7 -0
  13. mirascope/core/anthropic/stream.py +3 -1
  14. mirascope/core/azure/__init__.py +2 -2
  15. mirascope/core/azure/_utils/_calculate_cost.py +4 -1
  16. mirascope/core/azure/call_response.py +9 -1
  17. mirascope/core/azure/call_response_chunk.py +5 -0
  18. mirascope/core/azure/stream.py +3 -1
  19. mirascope/core/base/__init__.py +11 -9
  20. mirascope/core/base/_utils/__init__.py +10 -10
  21. mirascope/core/base/_utils/_get_common_usage.py +8 -4
  22. mirascope/core/base/_utils/_get_create_fn_or_async_create_fn.py +2 -2
  23. mirascope/core/base/_utils/_protocols.py +9 -8
  24. mirascope/core/base/call_response.py +22 -20
  25. mirascope/core/base/call_response_chunk.py +12 -1
  26. mirascope/core/base/stream.py +24 -21
  27. mirascope/core/base/tool.py +7 -5
  28. mirascope/core/base/types.py +22 -5
  29. mirascope/core/bedrock/__init__.py +3 -3
  30. mirascope/core/bedrock/_utils/_calculate_cost.py +4 -1
  31. mirascope/core/bedrock/call_response.py +8 -1
  32. mirascope/core/bedrock/call_response_chunk.py +5 -0
  33. mirascope/core/bedrock/stream.py +3 -1
  34. mirascope/core/cohere/__init__.py +2 -2
  35. mirascope/core/cohere/_utils/_calculate_cost.py +4 -3
  36. mirascope/core/cohere/call_response.py +9 -1
  37. mirascope/core/cohere/call_response_chunk.py +5 -0
  38. mirascope/core/cohere/stream.py +3 -1
  39. mirascope/core/gemini/__init__.py +2 -2
  40. mirascope/core/gemini/_utils/_calculate_cost.py +4 -1
  41. mirascope/core/gemini/_utils/_convert_message_params.py +1 -1
  42. mirascope/core/gemini/call_response.py +9 -1
  43. mirascope/core/gemini/call_response_chunk.py +5 -0
  44. mirascope/core/gemini/stream.py +3 -1
  45. mirascope/core/google/__init__.py +2 -2
  46. mirascope/core/google/_utils/_calculate_cost.py +141 -14
  47. mirascope/core/google/_utils/_convert_message_params.py +23 -51
  48. mirascope/core/google/_utils/_message_param_converter.py +34 -33
  49. mirascope/core/google/_utils/_validate_media_type.py +34 -0
  50. mirascope/core/google/call_response.py +26 -4
  51. mirascope/core/google/call_response_chunk.py +17 -9
  52. mirascope/core/google/stream.py +20 -2
  53. mirascope/core/groq/__init__.py +2 -2
  54. mirascope/core/groq/_utils/_calculate_cost.py +12 -11
  55. mirascope/core/groq/call_response.py +9 -1
  56. mirascope/core/groq/call_response_chunk.py +5 -0
  57. mirascope/core/groq/stream.py +3 -1
  58. mirascope/core/litellm/__init__.py +1 -1
  59. mirascope/core/litellm/_utils/_setup_call.py +7 -3
  60. mirascope/core/mistral/__init__.py +2 -2
  61. mirascope/core/mistral/_utils/_calculate_cost.py +10 -9
  62. mirascope/core/mistral/call_response.py +9 -1
  63. mirascope/core/mistral/call_response_chunk.py +5 -0
  64. mirascope/core/mistral/stream.py +3 -1
  65. mirascope/core/openai/__init__.py +2 -2
  66. mirascope/core/openai/_utils/_calculate_cost.py +78 -37
  67. mirascope/core/openai/call_params.py +13 -0
  68. mirascope/core/openai/call_response.py +14 -1
  69. mirascope/core/openai/call_response_chunk.py +12 -0
  70. mirascope/core/openai/stream.py +6 -4
  71. mirascope/core/vertex/__init__.py +1 -1
  72. mirascope/core/vertex/_utils/_calculate_cost.py +1 -0
  73. mirascope/core/vertex/_utils/_convert_message_params.py +1 -1
  74. mirascope/core/vertex/call_response.py +9 -1
  75. mirascope/core/vertex/call_response_chunk.py +5 -0
  76. mirascope/core/vertex/stream.py +3 -1
  77. mirascope/core/xai/__init__.py +28 -0
  78. mirascope/core/xai/_call.py +67 -0
  79. mirascope/core/xai/_utils/__init__.py +6 -0
  80. mirascope/core/xai/_utils/_calculate_cost.py +104 -0
  81. mirascope/core/xai/_utils/_setup_call.py +113 -0
  82. mirascope/core/xai/call_params.py +10 -0
  83. mirascope/core/xai/call_response.py +27 -0
  84. mirascope/core/xai/call_response_chunk.py +14 -0
  85. mirascope/core/xai/dynamic_config.py +8 -0
  86. mirascope/core/xai/py.typed +0 -0
  87. mirascope/core/xai/stream.py +57 -0
  88. mirascope/core/xai/tool.py +13 -0
  89. mirascope/integrations/_middleware_factory.py +6 -6
  90. mirascope/integrations/logfire/_utils.py +1 -1
  91. mirascope/llm/__init__.py +2 -2
  92. mirascope/llm/_protocols.py +34 -28
  93. mirascope/llm/call_response.py +16 -7
  94. mirascope/llm/llm_call.py +50 -46
  95. mirascope/llm/stream.py +43 -31
  96. mirascope/retries/__init__.py +1 -1
  97. mirascope/tools/__init__.py +2 -2
  98. {mirascope-1.18.3.dist-info → mirascope-1.19.0.dist-info}/METADATA +3 -1
  99. {mirascope-1.18.3.dist-info → mirascope-1.19.0.dist-info}/RECORD +101 -88
  100. {mirascope-1.18.3.dist-info → mirascope-1.19.0.dist-info}/WHEEL +0 -0
  101. {mirascope-1.18.3.dist-info → mirascope-1.19.0.dist-info}/licenses/LICENSE +0 -0
@@ -13,6 +13,7 @@ from mirascope.core.base import (
13
13
  BaseCallResponse,
14
14
  BaseMessageParam,
15
15
  BaseTool,
16
+ Usage,
16
17
  transform_tool_outputs,
17
18
  )
18
19
  from mirascope.core.base.message_param import ToolResultPart
@@ -22,14 +23,11 @@ from mirascope.llm.tool import Tool
22
23
 
23
24
  _ResponseT = TypeVar("_ResponseT")
24
25
 
25
- _ToolMessageParamT = TypeVar("_ToolMessageParamT")
26
- _BaseToolT = TypeVar("_BaseToolT", bound=BaseTool)
27
-
28
26
 
29
27
  class CallResponse(
30
28
  BaseCallResponse[
31
29
  _ResponseT,
32
- _BaseToolT,
30
+ Tool,
33
31
  Any,
34
32
  BaseDynamicConfig[Any, Any, Any],
35
33
  BaseMessageParam,
@@ -44,11 +42,11 @@ class CallResponse(
44
42
  We rely on _response having `common_` methods or properties for normalization.
45
43
  """
46
44
 
47
- _response: BaseCallResponse[_ResponseT, _BaseToolT, Any, Any, Any, Any, Any]
45
+ _response: BaseCallResponse[_ResponseT, Tool, Any, Any, Any, Any, Any]
48
46
 
49
47
  def __init__(
50
48
  self,
51
- response: BaseCallResponse[_ResponseT, _BaseToolT, Any, Any, Any, Any, Any],
49
+ response: BaseCallResponse[_ResponseT, Tool, Any, Any, Any, Any, Any],
52
50
  ) -> None:
53
51
  super().__init__(
54
52
  **{
@@ -65,7 +63,13 @@ class CallResponse(
65
63
  def __getattribute__(self, name: str) -> Any: # noqa: ANN401
66
64
  special_names = {
67
65
  "_response",
66
+ "finish_reasons",
67
+ "usage",
68
+ "message_param",
68
69
  "user_message_param",
70
+ "tools",
71
+ "tool",
72
+ "tool_message_params",
69
73
  "__dict__",
70
74
  "__class__",
71
75
  "model_fields",
@@ -97,6 +101,11 @@ class CallResponse(
97
101
  def finish_reasons(self) -> list[FinishReason] | None: # pyright: ignore [reportIncompatibleMethodOverride]
98
102
  return self._response.common_finish_reasons
99
103
 
104
+ @property
105
+ def usage(self) -> Usage | None:
106
+ """Returns the usage of the chat completion."""
107
+ return self._response.common_usage
108
+
100
109
  @computed_field
101
110
  @cached_property
102
111
  def message_param(self) -> BaseMessageParam:
@@ -116,7 +125,7 @@ class CallResponse(
116
125
  @classmethod
117
126
  @transform_tool_outputs
118
127
  def tool_message_params(
119
- cls, tools_and_outputs: list[tuple[BaseTool, str]]
128
+ cls, tools_and_outputs: list[tuple[Tool, str]]
120
129
  ) -> list[BaseMessageParam]:
121
130
  """Returns the tool message parameters for tool call results.
122
131
 
mirascope/llm/llm_call.py CHANGED
@@ -5,12 +5,7 @@ from __future__ import annotations
5
5
  from collections.abc import AsyncIterable, Awaitable, Callable, Iterable
6
6
  from enum import Enum
7
7
  from functools import wraps
8
- from typing import (
9
- Any,
10
- ParamSpec,
11
- TypeVar,
12
- cast,
13
- )
8
+ from typing import Any, ParamSpec, TypeVar, cast, get_args
14
9
 
15
10
  from pydantic import BaseModel
16
11
 
@@ -31,6 +26,7 @@ from ._protocols import (
31
26
  AsyncLLMFunctionDecorator,
32
27
  CallDecorator,
33
28
  LLMFunctionDecorator,
29
+ LocalProvider,
34
30
  Provider,
35
31
  SyncLLMFunctionDecorator,
36
32
  )
@@ -52,7 +48,31 @@ _BaseStreamT = TypeVar("_BaseStreamT", covariant=True)
52
48
  _ResultT = TypeVar("_ResultT")
53
49
 
54
50
 
55
- def _get_provider_call(provider: str) -> Callable:
51
+ def _get_local_provider_call(
52
+ provider: LocalProvider,
53
+ client: Any | None, # noqa: ANN401
54
+ ) -> tuple[Callable, Any | None]:
55
+ if provider == "ollama":
56
+ from mirascope.core.openai import openai_call
57
+
58
+ if client:
59
+ return openai_call, client
60
+ from openai import OpenAI
61
+
62
+ client = OpenAI(api_key="ollama", base_url="http://localhost:11434/v1")
63
+ return openai_call, client
64
+ else: # provider == "vllm"
65
+ from mirascope.core.openai import openai_call
66
+
67
+ if client:
68
+ return openai_call, client
69
+ from openai import OpenAI
70
+
71
+ client = OpenAI(api_key="ollama", base_url="http://localhost:8000/v1")
72
+ return openai_call, client
73
+
74
+
75
+ def _get_provider_call(provider: Provider) -> Callable:
56
76
  """Returns the provider-specific call decorator based on the provider name."""
57
77
  if provider == "anthropic":
58
78
  from mirascope.core.anthropic import anthropic_call
@@ -98,6 +118,10 @@ def _get_provider_call(provider: str) -> Callable:
98
118
  from mirascope.core.vertex import vertex_call
99
119
 
100
120
  return vertex_call
121
+ elif provider == "xai":
122
+ from mirascope.core.xai import xai_call
123
+
124
+ return xai_call
101
125
  raise ValueError(f"Unsupported provider: {provider}")
102
126
 
103
127
 
@@ -125,7 +149,7 @@ def _wrap_result(
125
149
 
126
150
 
127
151
  def _call(
128
- provider: Provider,
152
+ provider: Provider | LocalProvider,
129
153
  model: str,
130
154
  *,
131
155
  stream: bool | StreamConfig = False,
@@ -171,7 +195,22 @@ def _call(
171
195
  ]
172
196
  ):
173
197
  """Decorator for defining a function that calls a language model."""
174
- provider_call = _get_provider_call(provider)
198
+ if provider in get_args(LocalProvider):
199
+ provider_call, client = _get_local_provider_call(
200
+ cast(LocalProvider, provider), client
201
+ )
202
+ else:
203
+ provider_call = _get_provider_call(cast(Provider, provider))
204
+ _original_args = {
205
+ "model": model,
206
+ "stream": stream,
207
+ "tools": tools,
208
+ "response_model": response_model,
209
+ "output_parser": output_parser,
210
+ "json_mode": json_mode,
211
+ "client": client,
212
+ "call_params": call_params,
213
+ }
175
214
 
176
215
  def wrapper(
177
216
  fn: Callable[_P, _R | Awaitable[_R]],
@@ -179,16 +218,6 @@ def _call(
179
218
  _P,
180
219
  CallResponse | Stream | Awaitable[CallResponse | Stream],
181
220
  ]:
182
- _original_args = {
183
- "model": model,
184
- "stream": stream,
185
- "tools": tools,
186
- "response_model": response_model,
187
- "output_parser": output_parser,
188
- "json_mode": json_mode,
189
- "client": client,
190
- "call_params": call_params,
191
- }
192
221
  decorated = provider_call(**_original_args)(fn)
193
222
 
194
223
  if fn_is_async(decorated):
@@ -219,32 +248,6 @@ def _call(
219
248
  inner._original_provider = provider # pyright: ignore [reportAttributeAccessIssue]
220
249
  return inner
221
250
 
222
- # @wraps(decorated)
223
- # def inner(
224
- # *args: _P.args, **kwargs: _P.kwargs
225
- # ) -> CallResponse | Stream | Awaitable[CallResponse | Stream]:
226
- # result = decorated(*args, **kwargs)
227
- # if fn_is_async(decorated):
228
-
229
- # async def async_wrapper() -> CallResponse | Stream:
230
- # final = await result
231
- # return _wrap_result(final)
232
-
233
- # return async_wrapper()
234
- # else:
235
-
236
- # def sync_wrapper() -> CallResponse | Stream:
237
- # final = result
238
- # return _wrap_result(final)
239
-
240
- # return sync_wrapper()
241
-
242
- # inner._original_args = _original_args # pyright: ignore [reportAttributeAccessIssue]
243
- # inner._original_provider_call = provider_call # pyright: ignore [reportAttributeAccessIssue]
244
- # inner._original_fn = fn # pyright: ignore [reportAttributeAccessIssue]
245
- # inner._original_provider = provider # pyright: ignore [reportAttributeAccessIssue]
246
- # return inner
247
-
248
251
  return wrapper # pyright: ignore [reportReturnType]
249
252
 
250
253
 
@@ -274,7 +277,8 @@ print(response.content)
274
277
  ```
275
278
 
276
279
  Args:
277
- provider (str): The LLM provider to use (e.g., "openai", "anthropic").
280
+ provider (Provider | LocalProvider): The LLM provider to use
281
+ (e.g., "openai", "anthropic").
278
282
  model (str): The model to use for the specified provider (e.g., "gpt-4o-mini").
279
283
  stream (bool): Whether to stream the response from the API call.
280
284
  tools (list[BaseTool | Callable]): The tools available for the LLM to use.
mirascope/llm/stream.py CHANGED
@@ -62,10 +62,21 @@ class Stream(
62
62
  _BaseCallParamsT,
63
63
  ],
64
64
  ):
65
- """
66
- A non-pydantic class that inherits from BaseStream.
65
+ """A non-pydantic class that inherits from BaseStream."""
67
66
 
68
- """
67
+ _stream: BaseStream[
68
+ _BaseCallResponseT,
69
+ _BaseCallResponseChunkT,
70
+ _UserMessageParamT,
71
+ _AssistantMessageParamT,
72
+ _ToolMessageParamT,
73
+ _MessageParamT,
74
+ _BaseToolT,
75
+ _ToolSchemaT,
76
+ _BaseDynamicConfigT,
77
+ _BaseCallParamsT,
78
+ FinishReason,
79
+ ]
69
80
 
70
81
  def __init__(
71
82
  self,
@@ -85,20 +96,27 @@ class Stream(
85
96
  ],
86
97
  ) -> None:
87
98
  """Initialize the Stream class."""
88
- self._stream = stream
89
- super().__init__(
90
- stream=stream.stream,
91
- metadata=stream.metadata,
92
- tool_types=stream.tool_types,
93
- call_response_type=stream.call_response_type,
94
- model=stream.model,
95
- prompt_template=stream.prompt_template,
96
- fn_args=stream.fn_args or {},
97
- dynamic_config=stream.dynamic_config,
98
- messages=stream.messages,
99
- call_params=stream.call_params,
100
- call_kwargs=stream.call_kwargs,
101
- )
99
+ object.__setattr__(self, "_stream", stream)
100
+
101
+ def __getattribute__(self, name: str) -> Any: # noqa: ANN401
102
+ special_names = {
103
+ "_stream",
104
+ "cost",
105
+ "_construct_message_param",
106
+ "construct_call_response",
107
+ "tool_message_params",
108
+ "__dict__",
109
+ "__class__",
110
+ "__repr__",
111
+ "__str__",
112
+ "__iter__",
113
+ "__aiter__",
114
+ }
115
+
116
+ if name in special_names:
117
+ return object.__getattribute__(self, name)
118
+ response = object.__getattribute__(self, "_stream")
119
+ return getattr(response, name)
102
120
 
103
121
  def __iter__( # pyright: ignore [reportIncompatibleMethodOverride]
104
122
  self,
@@ -110,7 +128,7 @@ class Stream(
110
128
  None,
111
129
  ]:
112
130
  """Iterate over the stream."""
113
- for chunk, tool in super().__iter__():
131
+ for chunk, tool in self._stream:
114
132
  yield (
115
133
  CallResponseChunk(response=chunk), # pyright: ignore [reportAbstractUsage]
116
134
  Tool(tool=tool) if tool is not None else None, # pyright: ignore [reportAbstractUsage]
@@ -125,20 +143,12 @@ class Stream(
125
143
  None,
126
144
  ]:
127
145
  """Iterates over the stream and stores useful information."""
128
- async for chunk, tool in super().__aiter__():
146
+ async for chunk, tool in self._stream:
129
147
  yield (
130
148
  CallResponseChunk(response=chunk), # pyright: ignore [reportAbstractUsage]
131
149
  Tool(tool=tool) if tool is not None else None, # pyright: ignore [reportAbstractUsage]
132
150
  )
133
151
 
134
- def common_construct_call_response(
135
- self,
136
- ) -> CallResponse[_BaseCallResponseT, Tool[_ToolMessageParamT]]:
137
- """A common method that constructs a CallResponse instance."""
138
- return CallResponse[_BaseCallResponseT, Tool](
139
- response=self._stream.construct_call_response()
140
- ) # pyright: ignore [reportAbstractUsage]
141
-
142
152
  @property
143
153
  def cost(self) -> float | None:
144
154
  return self._stream.cost
@@ -152,12 +162,14 @@ class Stream(
152
162
 
153
163
  def construct_call_response( # pyright: ignore [reportIncompatibleMethodOverride]
154
164
  self,
155
- ) -> CallResponse[_BaseCallResponseT, Tool[_ToolMessageParamT]]:
156
- return self.common_construct_call_response()
165
+ ) -> CallResponse[_BaseCallResponseT]:
166
+ return CallResponse[_BaseCallResponseT](
167
+ response=self._stream.construct_call_response()
168
+ ) # pyright: ignore [reportAbstractUsage]
157
169
 
158
170
  @classmethod
159
- def common_tool_message_params(
160
- cls, tools_and_outputs: list[tuple[BaseTool, JsonableType]]
171
+ def tool_message_params( # pyright: ignore [reportIncompatibleMethodOverride]
172
+ cls, tools_and_outputs: list[tuple[Tool, JsonableType]]
161
173
  ) -> list[BaseMessageParam]:
162
174
  """Returns the tool message parameters for tool call results.
163
175
 
@@ -8,4 +8,4 @@ with suppress(ImportError):
8
8
  from . import tenacity as tenacity
9
9
 
10
10
 
11
- __all__ = ["fallback", "FallbackError", "tenacity"]
11
+ __all__ = ["FallbackError", "fallback", "tenacity"]
@@ -21,6 +21,7 @@ with suppress(ImportError):
21
21
  from .web._requests import Requests, RequestsConfig
22
22
 
23
23
  __all__ = [
24
+ "HTTPX",
24
25
  "AsyncHTTPX",
25
26
  "DockerOperationToolKit",
26
27
  "DockerOperationToolKitConfig",
@@ -28,10 +29,9 @@ __all__ = [
28
29
  "DuckDuckGoSearchConfig",
29
30
  "FileSystemToolKit",
30
31
  "FileSystemToolKitConfig",
31
- "HTTPX",
32
32
  "HTTPXConfig",
33
- "ParseURLContent",
34
33
  "ParseURLConfig",
34
+ "ParseURLContent",
35
35
  "Requests",
36
36
  "RequestsConfig",
37
37
  ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mirascope
3
- Version: 1.18.3
3
+ Version: 1.19.0
4
4
  Summary: LLM abstractions that aren't obstructions
5
5
  Project-URL: Homepage, https://mirascope.com
6
6
  Project-URL: Documentation, https://mirascope.com/WELCOME
@@ -96,6 +96,8 @@ Provides-Extra: tenacity
96
96
  Requires-Dist: tenacity<9,>=8.4.2; extra == 'tenacity'
97
97
  Provides-Extra: vertex
98
98
  Requires-Dist: google-cloud-aiplatform<2,>=1.38.0; extra == 'vertex'
99
+ Provides-Extra: xai
100
+ Requires-Dist: openai<2,>=1.6.0; extra == 'xai'
99
101
  Description-Content-Type: text/markdown
100
102
 
101
103
  <div align="center" justiry="start">