mirascope 1.18.3__py3-none-any.whl → 1.18.4__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 (88) 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/integrations/_middleware_factory.py +6 -6
  78. mirascope/integrations/logfire/_utils.py +1 -1
  79. mirascope/llm/__init__.py +1 -1
  80. mirascope/llm/_protocols.py +5 -5
  81. mirascope/llm/call_response.py +16 -7
  82. mirascope/llm/stream.py +43 -31
  83. mirascope/retries/__init__.py +1 -1
  84. mirascope/tools/__init__.py +2 -2
  85. {mirascope-1.18.3.dist-info → mirascope-1.18.4.dist-info}/METADATA +1 -1
  86. {mirascope-1.18.3.dist-info → mirascope-1.18.4.dist-info}/RECORD +88 -87
  87. {mirascope-1.18.3.dist-info → mirascope-1.18.4.dist-info}/WHEEL +0 -0
  88. {mirascope-1.18.3.dist-info → mirascope-1.18.4.dist-info}/licenses/LICENSE +0 -0
@@ -6,7 +6,10 @@ usage docs: learn/streams.md#handling-streamed-responses
6
6
  from typing import cast
7
7
 
8
8
  from google.genai.types import FinishReason as GoogleFinishReason
9
- from google.genai.types import GenerateContentResponse
9
+ from google.genai.types import (
10
+ GenerateContentResponse,
11
+ GenerateContentResponseUsageMetadata,
12
+ )
10
13
 
11
14
  from mirascope.core.base.types import FinishReason
12
15
 
@@ -57,12 +60,12 @@ class GoogleCallResponseChunk(
57
60
  ]
58
61
 
59
62
  @property
60
- def model(self) -> None:
63
+ def model(self) -> str | None:
61
64
  """Returns the model name.
62
65
 
63
66
  google.generativeai does not return model, so we return None
64
67
  """
65
- return None
68
+ return self.chunk.model_version
66
69
 
67
70
  @property
68
71
  def id(self) -> str | None:
@@ -73,22 +76,27 @@ class GoogleCallResponseChunk(
73
76
  return None
74
77
 
75
78
  @property
76
- def usage(self) -> None:
79
+ def usage(self) -> GenerateContentResponseUsageMetadata | None:
77
80
  """Returns the usage of the chat completion.
78
81
 
79
82
  google.generativeai does not have Usage, so we return None
80
83
  """
81
- return None
84
+ return self.chunk.usage_metadata
82
85
 
83
86
  @property
84
- def input_tokens(self) -> None:
87
+ def input_tokens(self) -> int | None:
85
88
  """Returns the number of input tokens."""
86
- return None
89
+ return self.usage.prompt_token_count if self.usage else None
87
90
 
88
91
  @property
89
- def output_tokens(self) -> None:
92
+ def cached_tokens(self) -> int | None:
93
+ """Returns the number of cached tokens."""
94
+ return self.usage.cached_content_token_count if self.usage else None
95
+
96
+ @property
97
+ def output_tokens(self) -> int | None:
90
98
  """Returns the number of output tokens."""
91
- return None
99
+ return self.usage.candidates_token_count if self.usage else None
92
100
 
93
101
  @property
94
102
  def common_finish_reasons(self) -> list[FinishReason] | None:
@@ -14,6 +14,7 @@ from google.genai.types import (
14
14
  FinishReason,
15
15
  FunctionCall,
16
16
  GenerateContentResponse,
17
+ GenerateContentResponseUsageMetadata,
17
18
  PartDict,
18
19
  Tool,
19
20
  )
@@ -66,7 +67,9 @@ class GoogleStream(
66
67
  @property
67
68
  def cost(self) -> float | None:
68
69
  """Returns the cost of the call."""
69
- return calculate_cost(self.input_tokens, self.output_tokens, self.model)
70
+ return calculate_cost(
71
+ self.input_tokens, self.cached_tokens, self.output_tokens, self.model
72
+ )
70
73
 
71
74
  def _construct_message_param(
72
75
  self, tool_calls: list[FunctionCall] | None = None, content: str | None = None
@@ -98,6 +101,15 @@ class GoogleStream(
98
101
  raise ValueError(
99
102
  "No stream response, check if the stream has been consumed."
100
103
  )
104
+ candidates_token_count = (
105
+ int(self.output_tokens) if self.output_tokens is not None else None
106
+ )
107
+ prompt_token_count = (
108
+ int(self.input_tokens) if self.input_tokens is not None else None
109
+ )
110
+ total_token_count = int(candidates_token_count or 0) + int(
111
+ prompt_token_count or 0
112
+ )
101
113
  response = GenerateContentResponse(
102
114
  candidates=[
103
115
  Candidate(
@@ -109,7 +121,13 @@ class GoogleStream(
109
121
  parts=self.message_param["parts"], # pyright: ignore [reportTypedDictNotRequiredAccess, reportArgumentType]
110
122
  ),
111
123
  )
112
- ]
124
+ ],
125
+ model_version=self.model,
126
+ usage_metadata=GenerateContentResponseUsageMetadata(
127
+ candidates_token_count=candidates_token_count,
128
+ prompt_token_count=prompt_token_count,
129
+ total_token_count=total_token_count,
130
+ ),
113
131
  )
114
132
 
115
133
  return GoogleCallResponse(
@@ -18,13 +18,13 @@ GroqMessageParam: TypeAlias = ChatCompletionMessageParam | BaseMessageParam
18
18
 
19
19
  __all__ = [
20
20
  "AsyncGroqDynamicConfig",
21
- "call",
22
- "GroqDynamicConfig",
23
21
  "GroqCallParams",
24
22
  "GroqCallResponse",
25
23
  "GroqCallResponseChunk",
24
+ "GroqDynamicConfig",
26
25
  "GroqMessageParam",
27
26
  "GroqStream",
28
27
  "GroqTool",
28
+ "call",
29
29
  "groq_call",
30
30
  ]
@@ -3,6 +3,7 @@
3
3
 
4
4
  def calculate_cost(
5
5
  input_tokens: int | float | None,
6
+ cached_tokens: int | float | None,
6
7
  output_tokens: int | float | None,
7
8
  model: str = "mixtral-8x7b-32768",
8
9
  ) -> float | None:
@@ -10,17 +11,17 @@ def calculate_cost(
10
11
 
11
12
  https://wow.groq.com/
12
13
 
13
- Model Input Output
14
- llama-3.1-405b-reasoning N/A N/A
15
- llama-3.1-70b-versatile N/A N/A
16
- llama-3.1-8b-instant N/A N/A
17
- llama3-groq-70b-8192-tool-use-preview $0.89 / 1M tokens $0.89 / 1M tokens
18
- llama3-groq-8b-8192-tool-use-preview $0.19 / 1M tokens $0.19 / 1M tokens
19
- llama3-70b-8192 $0.59 / 1M tokens $0.79 / 1M tokens
20
- llama3-8b-8192 $0.05 / 1M tokens $0.08 / 1M tokens
21
- mixtral-8x7b-32768 $0.27 / 1M tokens $0.27 / 1M tokens
22
- gemma-7b-it $0.07 / 1M tokens $0.07 / 1M tokens
23
- gemma2-9b-it $0.20 / 1M tokens $0.20 / 1M tokens
14
+ Model Input Cached Output
15
+ llama-3.1-405b-reasoning N/A N/A
16
+ llama-3.1-70b-versatile N/A N/A
17
+ llama-3.1-8b-instant N/A N/A
18
+ llama3-groq-70b-8192-tool-use-preview $0.89 / 1M tokens $0.89 / 1M tokens
19
+ llama3-groq-8b-8192-tool-use-preview $0.19 / 1M tokens $0.19 / 1M tokens
20
+ llama3-70b-8192 $0.59 / 1M tokens $0.79 / 1M tokens
21
+ llama3-8b-8192 $0.05 / 1M tokens $0.08 / 1M tokens
22
+ mixtral-8x7b-32768 $0.27 / 1M tokens $0.27 / 1M tokens
23
+ gemma-7b-it $0.07 / 1M tokens $0.07 / 1M tokens
24
+ gemma2-9b-it $0.20 / 1M tokens $0.20 / 1M tokens
24
25
  """
25
26
  pricing = {
26
27
  "llama3-groq-70b-8192-tool-use-preview": {
@@ -98,6 +98,12 @@ class GroqCallResponse(
98
98
  """Returns the number of input tokens."""
99
99
  return self.usage.prompt_tokens if self.usage else None
100
100
 
101
+ @computed_field
102
+ @property
103
+ def cached_tokens(self) -> int | None:
104
+ """Returns the number of cached tokens."""
105
+ return 0
106
+
101
107
  @computed_field
102
108
  @property
103
109
  def output_tokens(self) -> int | None:
@@ -108,7 +114,9 @@ class GroqCallResponse(
108
114
  @property
109
115
  def cost(self) -> float | None:
110
116
  """Returns the cost of the call."""
111
- return calculate_cost(self.input_tokens, self.output_tokens, self.model)
117
+ return calculate_cost(
118
+ self.input_tokens, self.cached_tokens, self.output_tokens, self.model
119
+ )
112
120
 
113
121
  @computed_field
114
122
  @cached_property
@@ -81,6 +81,11 @@ class GroqCallResponseChunk(BaseCallResponseChunk[ChatCompletionChunk, FinishRea
81
81
  return self.usage.prompt_tokens
82
82
  return None
83
83
 
84
+ @property
85
+ def cached_tokens(self) -> int | None:
86
+ """Returns the number of cached tokens."""
87
+ return 0
88
+
84
89
  @property
85
90
  def output_tokens(self) -> int | None:
86
91
  """Returns the number of output tokens."""
@@ -66,7 +66,9 @@ class GroqStream(
66
66
  @property
67
67
  def cost(self) -> float | None:
68
68
  """Returns the cost of the call."""
69
- return calculate_cost(self.input_tokens, self.output_tokens, self.model)
69
+ return calculate_cost(
70
+ self.input_tokens, self.cached_tokens, self.output_tokens, self.model
71
+ )
70
72
 
71
73
  def _construct_message_param(
72
74
  self,
@@ -16,7 +16,6 @@ LiteLLMMessageParam: TypeAlias = OpenAIMessageParam
16
16
 
17
17
  __all__ = [
18
18
  "AsyncLiteLLMDynamicConfig",
19
- "call",
20
19
  "LiteLLMCallParams",
21
20
  "LiteLLMCallResponse",
22
21
  "LiteLLMCallResponseChunk",
@@ -24,5 +23,6 @@ __all__ = [
24
23
  "LiteLLMMessageParam",
25
24
  "LiteLLMStream",
26
25
  "LiteLLMTool",
26
+ "call",
27
27
  "litellm_call",
28
28
  ]
@@ -1,7 +1,7 @@
1
1
  """This module contains the setup_call function for OpenAI tools."""
2
2
 
3
3
  from collections.abc import Awaitable, Callable
4
- from typing import Any, cast, overload
4
+ from typing import Any, TypeAlias, cast, overload
5
5
 
6
6
  from litellm import acompletion, completion
7
7
  from openai import OpenAI
@@ -21,12 +21,16 @@ from ...openai import (
21
21
  from ...openai._call_kwargs import OpenAICallKwargs
22
22
  from ...openai._utils import setup_call as setup_call_openai
23
23
 
24
+ # Note: MyPy doesn't like `client: ...` so we use these aliases instead.
25
+ _AsyncLiteLLMClient: TypeAlias = Any
26
+ _SyncLiteLLMClient: TypeAlias = Any
27
+
24
28
 
25
29
  @overload
26
30
  def setup_call(
27
31
  *,
28
32
  model: str,
29
- client: ...,
33
+ client: _AsyncLiteLLMClient | None,
30
34
  fn: Callable[..., Awaitable[AsyncOpenAIDynamicConfig]],
31
35
  fn_args: dict[str, Any],
32
36
  dynamic_config: AsyncOpenAIDynamicConfig,
@@ -48,7 +52,7 @@ def setup_call(
48
52
  def setup_call(
49
53
  *,
50
54
  model: str,
51
- client: ...,
55
+ client: _SyncLiteLLMClient | None,
52
56
  fn: Callable[..., OpenAIDynamicConfig],
53
57
  fn_args: dict[str, Any],
54
58
  dynamic_config: OpenAIDynamicConfig,
@@ -24,13 +24,13 @@ MistralMessageParam: TypeAlias = (
24
24
  )
25
25
 
26
26
  __all__ = [
27
- "call",
28
- "MistralDynamicConfig",
29
27
  "MistralCallParams",
30
28
  "MistralCallResponse",
31
29
  "MistralCallResponseChunk",
30
+ "MistralDynamicConfig",
32
31
  "MistralMessageParam",
33
32
  "MistralStream",
34
33
  "MistralTool",
34
+ "call",
35
35
  "mistral_call",
36
36
  ]
@@ -3,6 +3,7 @@
3
3
 
4
4
  def calculate_cost(
5
5
  input_tokens: int | float | None,
6
+ cached_tokens: int | float | None,
6
7
  output_tokens: int | float | None,
7
8
  model: str = "open-mistral-7b",
8
9
  ) -> float | None:
@@ -10,15 +11,15 @@ def calculate_cost(
10
11
 
11
12
  https://mistral.ai/technology/#pricing
12
13
 
13
- Model Input Output
14
- open-mistral-nemo $0.3/1M tokens $0.3/1M tokens
15
- mistral-large-latest $3/1M tokens $9/1M tokens
16
- codestral-2405 $1/1M tokens $3/1M tokens
17
- open-mistral-7b $0.25/1M tokens $0.25/1M tokens
18
- open-mixtral-8x7b $0.7/1M tokens $0.7/1M tokens
19
- open-mixtral-8x22b $2/1M tokens $6/1M tokens
20
- mistral-small-latest $2/1M tokens $6/1M tokens
21
- mistral-medium-latest $2.75/1M tokens $8.1/1M tokens
14
+ Model Input Cached Output
15
+ open-mistral-nemo $0.3/1M tokens $0.3/1M tokens
16
+ mistral-large-latest $3/1M tokens $9/1M tokens
17
+ codestral-2405 $1/1M tokens $3/1M tokens
18
+ open-mistral-7b $0.25/1M tokens $0.25/1M tokens
19
+ open-mixtral-8x7b $0.7/1M tokens $0.7/1M tokens
20
+ open-mixtral-8x22b $2/1M tokens $6/1M tokens
21
+ mistral-small-latest $2/1M tokens $6/1M tokens
22
+ mistral-medium-latest $2.75/1M tokens $8.1/1M tokens
22
23
  """
23
24
  pricing = {
24
25
  "open-mistral-nemo": {"prompt": 0.000_000_3, "completion": 0.000_000_3},
@@ -107,6 +107,12 @@ class MistralCallResponse(
107
107
  """Returns the number of input tokens."""
108
108
  return self.usage.prompt_tokens
109
109
 
110
+ @computed_field
111
+ @property
112
+ def cached_tokens(self) -> int:
113
+ """Returns the number of cached tokens."""
114
+ return 0
115
+
110
116
  @computed_field
111
117
  @property
112
118
  def output_tokens(self) -> int | None:
@@ -117,7 +123,9 @@ class MistralCallResponse(
117
123
  @property
118
124
  def cost(self) -> float | None:
119
125
  """Returns the cost of the call."""
120
- return calculate_cost(self.input_tokens, self.output_tokens, self.model)
126
+ return calculate_cost(
127
+ self.input_tokens, self.cached_tokens, self.output_tokens, self.model
128
+ )
121
129
 
122
130
  @computed_field
123
131
  @cached_property
@@ -80,6 +80,11 @@ class MistralCallResponseChunk(BaseCallResponseChunk[CompletionChunk, FinishReas
80
80
  return self.usage.prompt_tokens
81
81
  return None
82
82
 
83
+ @property
84
+ def cached_tokens(self) -> int:
85
+ """Returns the number of cached tokens."""
86
+ return 0
87
+
83
88
  @property
84
89
  def output_tokens(self) -> int | None:
85
90
  """Returns the number of output tokens."""
@@ -65,7 +65,9 @@ class MistralStream(
65
65
  @property
66
66
  def cost(self) -> float | None:
67
67
  """Returns the cost of the call."""
68
- return calculate_cost(self.input_tokens, self.output_tokens, self.model)
68
+ return calculate_cost(
69
+ self.input_tokens, self.cached_tokens, self.output_tokens, self.model
70
+ )
69
71
 
70
72
  def _construct_message_param(
71
73
  self, tool_calls: list | None = None, content: str | None = None
@@ -18,14 +18,14 @@ OpenAIMessageParam: TypeAlias = ChatCompletionMessageParam | BaseMessageParam
18
18
 
19
19
  __all__ = [
20
20
  "AsyncOpenAIDynamicConfig",
21
- "call",
22
- "OpenAIDynamicConfig",
23
21
  "OpenAICallParams",
24
22
  "OpenAICallResponse",
25
23
  "OpenAICallResponseChunk",
24
+ "OpenAIDynamicConfig",
26
25
  "OpenAIMessageParam",
27
26
  "OpenAIStream",
28
27
  "OpenAITool",
29
28
  "OpenAIToolConfig",
29
+ "call",
30
30
  "openai_call",
31
31
  ]