mirascope 2.1.1__py3-none-any.whl → 2.2.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 (30) hide show
  1. mirascope/api/_generated/functions/client.py +10 -0
  2. mirascope/api/_generated/functions/raw_client.py +8 -0
  3. mirascope/api/_generated/functions/types/functions_create_response.py +25 -8
  4. mirascope/api/_generated/functions/types/functions_find_by_hash_response.py +25 -10
  5. mirascope/api/_generated/functions/types/functions_get_by_env_response.py +1 -0
  6. mirascope/api/_generated/functions/types/functions_get_response.py +25 -8
  7. mirascope/api/_generated/functions/types/functions_list_by_env_response_functions_item.py +1 -0
  8. mirascope/api/_generated/functions/types/functions_list_response_functions_item.py +22 -7
  9. mirascope/api/_generated/reference.md +9 -0
  10. mirascope/llm/__init__.py +42 -0
  11. mirascope/llm/calls/calls.py +38 -11
  12. mirascope/llm/exceptions.py +69 -0
  13. mirascope/llm/prompts/prompts.py +47 -9
  14. mirascope/llm/responses/response.py +217 -0
  15. mirascope/llm/responses/stream_response.py +234 -0
  16. mirascope/llm/retries/__init__.py +51 -0
  17. mirascope/llm/retries/retry_calls.py +159 -0
  18. mirascope/llm/retries/retry_config.py +168 -0
  19. mirascope/llm/retries/retry_decorator.py +258 -0
  20. mirascope/llm/retries/retry_models.py +1313 -0
  21. mirascope/llm/retries/retry_prompts.py +227 -0
  22. mirascope/llm/retries/retry_responses.py +340 -0
  23. mirascope/llm/retries/retry_stream_responses.py +571 -0
  24. mirascope/llm/retries/utils.py +159 -0
  25. mirascope/ops/_internal/versioned_calls.py +249 -9
  26. mirascope/ops/_internal/versioned_functions.py +2 -0
  27. {mirascope-2.1.1.dist-info → mirascope-2.2.0.dist-info}/METADATA +1 -1
  28. {mirascope-2.1.1.dist-info → mirascope-2.2.0.dist-info}/RECORD +30 -21
  29. {mirascope-2.1.1.dist-info → mirascope-2.2.0.dist-info}/WHEEL +0 -0
  30. {mirascope-2.1.1.dist-info → mirascope-2.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,159 @@
1
+ """Utility functions for retry logic."""
2
+
3
+ import random
4
+ from collections.abc import Awaitable, Callable
5
+ from dataclasses import dataclass
6
+ from typing import TYPE_CHECKING, TypeVar
7
+
8
+ from ..exceptions import RetriesExhausted
9
+ from .retry_config import RetryConfig
10
+
11
+ if TYPE_CHECKING:
12
+ from ..models import Model
13
+ from .retry_models import RetryModel
14
+
15
+
16
+ def get_retry_model_from_context(stored_retry_model: "RetryModel") -> "RetryModel":
17
+ """Get the RetryModel to use, checking context for overrides.
18
+
19
+ If a model is set in context (via `llm.model()` or `llm.retry_model()`),
20
+ that model is used instead, wrapped with this response's retry config.
21
+
22
+ Args:
23
+ stored_retry_model: The RetryModel stored on the response.
24
+
25
+ Returns:
26
+ Either the context model (wrapped in RetryModel if needed) or the stored model.
27
+ """
28
+ from ..models import model_from_context
29
+ from .retry_models import RetryModel
30
+
31
+ context_model = model_from_context()
32
+ if context_model is not None:
33
+ if isinstance(context_model, RetryModel):
34
+ return context_model
35
+ return RetryModel(context_model, stored_retry_model.retry_config)
36
+ return stored_retry_model
37
+
38
+
39
+ _ResultT = TypeVar("_ResultT")
40
+
41
+
42
+ @dataclass
43
+ class RetryFailure:
44
+ """A failed attempt to call a model.
45
+
46
+ Attributes:
47
+ model: The model that was tried.
48
+ exception: The exception that was raised.
49
+ """
50
+
51
+ model: "Model"
52
+ exception: BaseException
53
+
54
+
55
+ def calculate_delay(config: RetryConfig, attempt_for_model: int) -> float:
56
+ """Calculate the delay before the next retry attempt.
57
+
58
+ Args:
59
+ config: The retry configuration with backoff settings.
60
+ attempt_for_model: The retry attempt number for this model (1-indexed).
61
+
62
+ Returns:
63
+ The delay in seconds, with exponential backoff, capped at max_delay,
64
+ and optionally with jitter applied.
65
+ """
66
+ # Calculate base delay with exponential backoff
67
+ delay = config.initial_delay * (
68
+ config.backoff_multiplier ** (attempt_for_model - 1)
69
+ )
70
+
71
+ # Cap at max_delay
72
+ delay = min(delay, config.max_delay)
73
+
74
+ # Apply jitter if configured
75
+ if config.jitter > 0:
76
+ jitter_range = delay * config.jitter
77
+ delay = delay + random.uniform(-jitter_range, jitter_range)
78
+ # Ensure delay doesn't go negative
79
+ delay = max(0, delay)
80
+
81
+ return delay
82
+
83
+
84
+ def with_retry(
85
+ fn: Callable[["Model"], _ResultT],
86
+ retry_model: "RetryModel",
87
+ ) -> tuple[_ResultT, list[RetryFailure], "RetryModel"]:
88
+ """Execute a function with retry logic across the RetryModel's models.
89
+
90
+ Tries the active model first, then fallbacks. Each model gets its own
91
+ full retry budget. Returns an updated RetryModel with the successful
92
+ model set as active.
93
+
94
+ Args:
95
+ fn: Function that takes a Model and returns a result.
96
+ retry_model: The RetryModel containing models and retry config.
97
+
98
+ Returns:
99
+ A tuple of (result, failures, updated_retry_model).
100
+ failures contains all failed attempts before success.
101
+ The updated_retry_model has the successful model as active.
102
+
103
+ Raises:
104
+ Exception: The last exception encountered if all models exhaust retries.
105
+ """
106
+ config = retry_model.retry_config
107
+ failures: list[RetryFailure] = []
108
+
109
+ for variant in retry_model.variants():
110
+ model = variant.get_active_model()
111
+ try:
112
+ result = fn(model)
113
+ return result, failures, variant
114
+ except config.retry_on as e:
115
+ failures.append(RetryFailure(model=model, exception=e))
116
+
117
+ # All models exhausted
118
+ if failures:
119
+ raise RetriesExhausted(failures)
120
+ raise AssertionError("Unreachable: no models provided") # pragma: no cover
121
+
122
+
123
+ async def with_retry_async(
124
+ fn: Callable[["Model"], Awaitable[_ResultT]],
125
+ retry_model: "RetryModel",
126
+ ) -> tuple[_ResultT, list[RetryFailure], "RetryModel"]:
127
+ """Execute an async function with retry logic across the RetryModel's models.
128
+
129
+ Tries the active model first, then fallbacks. Each model gets its own
130
+ full retry budget. Returns an updated RetryModel with the successful
131
+ model set as active.
132
+
133
+ Args:
134
+ fn: Async function that takes a Model and returns a result.
135
+ retry_model: The RetryModel containing models and retry config.
136
+
137
+ Returns:
138
+ A tuple of (result, failures, updated_retry_model).
139
+ failures contains all failed attempts before success.
140
+ The updated_retry_model has the successful model as active.
141
+
142
+ Raises:
143
+ Exception: The last exception encountered if all models exhaust retries.
144
+ """
145
+ config = retry_model.retry_config
146
+ failures: list[RetryFailure] = []
147
+
148
+ async for variant in retry_model.variants_async():
149
+ model = variant.get_active_model()
150
+ try:
151
+ result = await fn(model)
152
+ return result, failures, variant
153
+ except config.retry_on as e:
154
+ failures.append(RetryFailure(model=model, exception=e))
155
+
156
+ # All models exhausted
157
+ if failures:
158
+ raise RetriesExhausted(failures)
159
+ raise AssertionError("Unreachable: no models provided") # pragma: no cover
@@ -4,7 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import logging
6
6
  from dataclasses import dataclass, field
7
- from typing import Concatenate, Generic
7
+ from typing import Concatenate, Generic, cast, overload
8
8
  from typing_extensions import TypeIs
9
9
 
10
10
  from ...llm.calls import AsyncCall, AsyncContextCall, Call, ContextCall
@@ -238,23 +238,61 @@ class VersionedCall(_BaseVersionedCall, Generic[P, FormattableT]):
238
238
  )
239
239
  self._compute_closure(self._call, self.call, self.stream)
240
240
 
241
+ @overload
242
+ def __call__(
243
+ self: VersionedCall[P, None], *args: P.args, **kwargs: P.kwargs
244
+ ) -> Response: ...
245
+
246
+ @overload
247
+ def __call__(
248
+ self: VersionedCall[P, FormattableT], *args: P.args, **kwargs: P.kwargs
249
+ ) -> Response[FormattableT]: ...
250
+
241
251
  def __call__(
242
252
  self, *args: P.args, **kwargs: P.kwargs
243
253
  ) -> Response | Response[FormattableT]:
244
254
  """Call the versioned function and return Response directly."""
245
255
  return self.call(*args, **kwargs)
246
256
 
257
+ @overload
258
+ def wrapped(
259
+ self: VersionedCall[P, None], *args: P.args, **kwargs: P.kwargs
260
+ ) -> VersionedResult[Response]: ...
261
+
262
+ @overload
263
+ def wrapped(
264
+ self: VersionedCall[P, FormattableT], *args: P.args, **kwargs: P.kwargs
265
+ ) -> VersionedResult[Response[FormattableT]]: ...
266
+
247
267
  def wrapped(
248
268
  self, *args: P.args, **kwargs: P.kwargs
249
- ) -> VersionedResult[Response | Response[FormattableT]]:
269
+ ) -> VersionedResult[Response] | VersionedResult[Response[FormattableT]]:
250
270
  """Call the versioned function and return a wrapped Response."""
251
- return self.call.wrapped(*args, **kwargs)
271
+ return cast(
272
+ "VersionedResult[Response] | VersionedResult[Response[FormattableT]]",
273
+ self.call.wrapped(*args, **kwargs),
274
+ )
275
+
276
+ @overload
277
+ def wrapped_stream(
278
+ self: VersionedCall[P, None], *args: P.args, **kwargs: P.kwargs
279
+ ) -> VersionedResult[StreamResponse]: ...
280
+
281
+ @overload
282
+ def wrapped_stream(
283
+ self: VersionedCall[P, FormattableT], *args: P.args, **kwargs: P.kwargs
284
+ ) -> VersionedResult[StreamResponse[FormattableT]]: ...
252
285
 
253
286
  def wrapped_stream(
254
287
  self, *args: P.args, **kwargs: P.kwargs
255
- ) -> VersionedResult[StreamResponse | StreamResponse[FormattableT]]:
288
+ ) -> (
289
+ VersionedResult[StreamResponse] | VersionedResult[StreamResponse[FormattableT]]
290
+ ):
256
291
  """Stream the versioned function and return a wrapped StreamResponse."""
257
- return self.stream.wrapped(*args, **kwargs)
292
+ return cast(
293
+ "VersionedResult[StreamResponse] | VersionedResult[StreamResponse[FormattableT]]",
294
+ self.stream.wrapped(*args, **kwargs),
295
+ )
258
296
 
259
297
 
260
298
  @dataclass(kw_only=True)
@@ -308,23 +346,65 @@ class VersionedAsyncCall(_BaseVersionedCall, Generic[P, FormattableT]):
308
346
  )
309
347
  self._compute_closure(self._call, self.call, self.stream)
310
348
 
349
+ @overload
350
+ async def __call__(
351
+ self: VersionedAsyncCall[P, None], *args: P.args, **kwargs: P.kwargs
352
+ ) -> AsyncResponse: ...
353
+
354
+ @overload
355
+ async def __call__(
356
+ self: VersionedAsyncCall[P, FormattableT], *args: P.args, **kwargs: P.kwargs
357
+ ) -> AsyncResponse[FormattableT]: ...
358
+
311
359
  async def __call__(
312
360
  self, *args: P.args, **kwargs: P.kwargs
313
361
  ) -> AsyncResponse | AsyncResponse[FormattableT]:
314
362
  """Call the versioned function and return AsyncResponse directly."""
315
363
  return await self.call(*args, **kwargs)
316
364
 
365
+ @overload
366
+ async def wrapped(
367
+ self: VersionedAsyncCall[P, None], *args: P.args, **kwargs: P.kwargs
368
+ ) -> AsyncVersionedResult[AsyncResponse]: ...
369
+
370
+ @overload
371
+ async def wrapped(
372
+ self: VersionedAsyncCall[P, FormattableT], *args: P.args, **kwargs: P.kwargs
373
+ ) -> AsyncVersionedResult[AsyncResponse[FormattableT]]: ...
374
+
317
375
  async def wrapped(
318
376
  self, *args: P.args, **kwargs: P.kwargs
319
- ) -> AsyncVersionedResult[AsyncResponse | AsyncResponse[FormattableT]]:
377
+ ) -> (
378
+ AsyncVersionedResult[AsyncResponse]
379
+ | AsyncVersionedResult[AsyncResponse[FormattableT]]
380
+ ):
320
381
  """Call the versioned function and return a wrapped Response."""
321
- return await self.call.wrapped(*args, **kwargs)
382
+ return cast(
383
+ "AsyncVersionedResult[AsyncResponse] | AsyncVersionedResult[AsyncResponse[FormattableT]]",
384
+ await self.call.wrapped(*args, **kwargs),
385
+ )
386
+
387
+ @overload
388
+ async def wrapped_stream(
389
+ self: VersionedAsyncCall[P, None], *args: P.args, **kwargs: P.kwargs
390
+ ) -> AsyncVersionedResult[AsyncStreamResponse]: ...
391
+
392
+ @overload
393
+ async def wrapped_stream(
394
+ self: VersionedAsyncCall[P, FormattableT], *args: P.args, **kwargs: P.kwargs
395
+ ) -> AsyncVersionedResult[AsyncStreamResponse[FormattableT]]: ...
322
396
 
323
397
  async def wrapped_stream(
324
398
  self, *args: P.args, **kwargs: P.kwargs
325
- ) -> AsyncVersionedResult[AsyncStreamResponse | AsyncStreamResponse[FormattableT]]:
399
+ ) -> (
400
+ AsyncVersionedResult[AsyncStreamResponse]
401
+ | AsyncVersionedResult[AsyncStreamResponse[FormattableT]]
402
+ ):
326
403
  """Stream the versioned function and return a wrapped StreamResponse."""
327
- return await self.stream.wrapped(*args, **kwargs)
404
+ return cast(
405
+ "AsyncVersionedResult[AsyncStreamResponse] | AsyncVersionedResult[AsyncStreamResponse[FormattableT]]",
406
+ await self.stream.wrapped(*args, **kwargs),
407
+ )
328
408
 
329
409
 
330
410
  @dataclass(kw_only=True)
@@ -381,18 +461,66 @@ class VersionedContextCall(_BaseVersionedCall, Generic[P, DepsT, FormattableT]):
381
461
  )
382
462
  self._compute_closure(self._call, self._call_versioned, self._stream_versioned)
383
463
 
464
+ @overload
465
+ def call(
466
+ self: VersionedContextCall[P, DepsT, None],
467
+ ctx: Context[DepsT],
468
+ *args: P.args,
469
+ **kwargs: P.kwargs,
470
+ ) -> ContextResponse[DepsT, None]: ...
471
+
472
+ @overload
473
+ def call(
474
+ self: VersionedContextCall[P, DepsT, FormattableT],
475
+ ctx: Context[DepsT],
476
+ *args: P.args,
477
+ **kwargs: P.kwargs,
478
+ ) -> ContextResponse[DepsT, FormattableT]: ...
479
+
384
480
  def call(
385
481
  self, ctx: Context[DepsT], *args: P.args, **kwargs: P.kwargs
386
482
  ) -> ContextResponse[DepsT, None] | ContextResponse[DepsT, FormattableT]:
387
483
  """Call the versioned function and return ContextResponse directly."""
388
484
  return self._call_versioned(ctx, *args, **kwargs)
389
485
 
486
+ @overload
487
+ def __call__(
488
+ self: VersionedContextCall[P, DepsT, None],
489
+ ctx: Context[DepsT],
490
+ *args: P.args,
491
+ **kwargs: P.kwargs,
492
+ ) -> ContextResponse[DepsT, None]: ...
493
+
494
+ @overload
495
+ def __call__(
496
+ self: VersionedContextCall[P, DepsT, FormattableT],
497
+ ctx: Context[DepsT],
498
+ *args: P.args,
499
+ **kwargs: P.kwargs,
500
+ ) -> ContextResponse[DepsT, FormattableT]: ...
501
+
390
502
  def __call__(
391
503
  self, ctx: Context[DepsT], *args: P.args, **kwargs: P.kwargs
392
504
  ) -> ContextResponse[DepsT, None] | ContextResponse[DepsT, FormattableT]:
393
505
  """Call the versioned function and return ContextResponse directly."""
394
506
  return self.call(ctx, *args, **kwargs)
395
507
 
508
+ @overload
509
+ def stream(
510
+ self: VersionedContextCall[P, DepsT, None],
511
+ ctx: Context[DepsT],
512
+ *args: P.args,
513
+ **kwargs: P.kwargs,
514
+ ) -> ContextStreamResponse[DepsT, None]: ...
515
+
516
+ @overload
517
+ def stream(
518
+ self: VersionedContextCall[P, DepsT, FormattableT],
519
+ ctx: Context[DepsT],
520
+ *args: P.args,
521
+ **kwargs: P.kwargs,
522
+ ) -> ContextStreamResponse[DepsT, FormattableT]: ...
523
+
396
524
  def stream(
397
525
  self, ctx: Context[DepsT], *args: P.args, **kwargs: P.kwargs
398
526
  ) -> (
@@ -401,6 +529,22 @@ class VersionedContextCall(_BaseVersionedCall, Generic[P, DepsT, FormattableT]):
401
529
  """Stream the versioned function and return a ContextStreamResponse."""
402
530
  return self._stream_versioned(ctx, *args, **kwargs)
403
531
 
532
+ @overload
533
+ def wrapped(
534
+ self: VersionedContextCall[P, DepsT, None],
535
+ ctx: Context[DepsT],
536
+ *args: P.args,
537
+ **kwargs: P.kwargs,
538
+ ) -> VersionedResult[ContextResponse[DepsT, None]]: ...
539
+
540
+ @overload
541
+ def wrapped(
542
+ self: VersionedContextCall[P, DepsT, FormattableT],
543
+ ctx: Context[DepsT],
544
+ *args: P.args,
545
+ **kwargs: P.kwargs,
546
+ ) -> VersionedResult[ContextResponse[DepsT, FormattableT]]: ...
547
+
404
548
  def wrapped(
405
549
  self, ctx: Context[DepsT], *args: P.args, **kwargs: P.kwargs
406
550
  ) -> VersionedResult[
@@ -409,6 +553,22 @@ class VersionedContextCall(_BaseVersionedCall, Generic[P, DepsT, FormattableT]):
409
553
  """Call the versioned function and return a wrapped Response."""
410
554
  return self._call_versioned.wrapped(ctx, *args, **kwargs)
411
555
 
556
+ @overload
557
+ def wrapped_stream(
558
+ self: VersionedContextCall[P, DepsT, None],
559
+ ctx: Context[DepsT],
560
+ *args: P.args,
561
+ **kwargs: P.kwargs,
562
+ ) -> VersionedResult[ContextStreamResponse[DepsT, None]]: ...
563
+
564
+ @overload
565
+ def wrapped_stream(
566
+ self: VersionedContextCall[P, DepsT, FormattableT],
567
+ ctx: Context[DepsT],
568
+ *args: P.args,
569
+ **kwargs: P.kwargs,
570
+ ) -> VersionedResult[ContextStreamResponse[DepsT, FormattableT]]: ...
571
+
412
572
  def wrapped_stream(
413
573
  self, ctx: Context[DepsT], *args: P.args, **kwargs: P.kwargs
414
574
  ) -> VersionedResult[
@@ -473,18 +633,66 @@ class VersionedAsyncContextCall(_BaseVersionedCall, Generic[P, DepsT, Formattabl
473
633
  )
474
634
  self._compute_closure(self._call, self._call_versioned, self._stream_versioned)
475
635
 
636
+ @overload
637
+ async def call(
638
+ self: VersionedAsyncContextCall[P, DepsT, None],
639
+ ctx: Context[DepsT],
640
+ *args: P.args,
641
+ **kwargs: P.kwargs,
642
+ ) -> AsyncContextResponse[DepsT, None]: ...
643
+
644
+ @overload
645
+ async def call(
646
+ self: VersionedAsyncContextCall[P, DepsT, FormattableT],
647
+ ctx: Context[DepsT],
648
+ *args: P.args,
649
+ **kwargs: P.kwargs,
650
+ ) -> AsyncContextResponse[DepsT, FormattableT]: ...
651
+
476
652
  async def call(
477
653
  self, ctx: Context[DepsT], *args: P.args, **kwargs: P.kwargs
478
654
  ) -> AsyncContextResponse[DepsT, None] | AsyncContextResponse[DepsT, FormattableT]:
479
655
  """Call the versioned function and return AsyncContextResponse directly."""
480
656
  return await self._call_versioned(ctx, *args, **kwargs)
481
657
 
658
+ @overload
659
+ async def __call__(
660
+ self: VersionedAsyncContextCall[P, DepsT, None],
661
+ ctx: Context[DepsT],
662
+ *args: P.args,
663
+ **kwargs: P.kwargs,
664
+ ) -> AsyncContextResponse[DepsT, None]: ...
665
+
666
+ @overload
667
+ async def __call__(
668
+ self: VersionedAsyncContextCall[P, DepsT, FormattableT],
669
+ ctx: Context[DepsT],
670
+ *args: P.args,
671
+ **kwargs: P.kwargs,
672
+ ) -> AsyncContextResponse[DepsT, FormattableT]: ...
673
+
482
674
  async def __call__(
483
675
  self, ctx: Context[DepsT], *args: P.args, **kwargs: P.kwargs
484
676
  ) -> AsyncContextResponse[DepsT, None] | AsyncContextResponse[DepsT, FormattableT]:
485
677
  """Call the versioned function and return AsyncContextResponse directly."""
486
678
  return await self.call(ctx, *args, **kwargs)
487
679
 
680
+ @overload
681
+ async def stream(
682
+ self: VersionedAsyncContextCall[P, DepsT, None],
683
+ ctx: Context[DepsT],
684
+ *args: P.args,
685
+ **kwargs: P.kwargs,
686
+ ) -> AsyncContextStreamResponse[DepsT, None]: ...
687
+
688
+ @overload
689
+ async def stream(
690
+ self: VersionedAsyncContextCall[P, DepsT, FormattableT],
691
+ ctx: Context[DepsT],
692
+ *args: P.args,
693
+ **kwargs: P.kwargs,
694
+ ) -> AsyncContextStreamResponse[DepsT, FormattableT]: ...
695
+
488
696
  async def stream(
489
697
  self, ctx: Context[DepsT], *args: P.args, **kwargs: P.kwargs
490
698
  ) -> (
@@ -494,6 +702,22 @@ class VersionedAsyncContextCall(_BaseVersionedCall, Generic[P, DepsT, Formattabl
494
702
  """Stream the versioned function and return an AsyncContextStreamResponse."""
495
703
  return await self._stream_versioned(ctx, *args, **kwargs)
496
704
 
705
+ @overload
706
+ async def wrapped(
707
+ self: VersionedAsyncContextCall[P, DepsT, None],
708
+ ctx: Context[DepsT],
709
+ *args: P.args,
710
+ **kwargs: P.kwargs,
711
+ ) -> AsyncVersionedResult[AsyncContextResponse[DepsT, None]]: ...
712
+
713
+ @overload
714
+ async def wrapped(
715
+ self: VersionedAsyncContextCall[P, DepsT, FormattableT],
716
+ ctx: Context[DepsT],
717
+ *args: P.args,
718
+ **kwargs: P.kwargs,
719
+ ) -> AsyncVersionedResult[AsyncContextResponse[DepsT, FormattableT]]: ...
720
+
497
721
  async def wrapped(
498
722
  self, ctx: Context[DepsT], *args: P.args, **kwargs: P.kwargs
499
723
  ) -> AsyncVersionedResult[
@@ -502,6 +726,22 @@ class VersionedAsyncContextCall(_BaseVersionedCall, Generic[P, DepsT, Formattabl
502
726
  """Call the versioned function and return a wrapped Response."""
503
727
  return await self._call_versioned.wrapped(ctx, *args, **kwargs)
504
728
 
729
+ @overload
730
+ async def wrapped_stream(
731
+ self: VersionedAsyncContextCall[P, DepsT, None],
732
+ ctx: Context[DepsT],
733
+ *args: P.args,
734
+ **kwargs: P.kwargs,
735
+ ) -> AsyncVersionedResult[AsyncContextStreamResponse[DepsT, None]]: ...
736
+
737
+ @overload
738
+ async def wrapped_stream(
739
+ self: VersionedAsyncContextCall[P, DepsT, FormattableT],
740
+ ctx: Context[DepsT],
741
+ *args: P.args,
742
+ **kwargs: P.kwargs,
743
+ ) -> AsyncVersionedResult[AsyncContextStreamResponse[DepsT, FormattableT]]: ...
744
+
505
745
  async def wrapped_stream(
506
746
  self, ctx: Context[DepsT], *args: P.args, **kwargs: P.kwargs
507
747
  ) -> AsyncVersionedResult[
@@ -270,6 +270,7 @@ class VersionedFunction(_BaseVersionedFunction[P, R], BaseSyncTracedFunction[P,
270
270
  signature=self.closure.signature,
271
271
  signature_hash=self.closure.signature_hash,
272
272
  name=self.name or self.closure.name,
273
+ language="python",
273
274
  description=self.closure.docstring,
274
275
  tags=list(self.tags) if self.tags else None,
275
276
  metadata=cast(dict[str, str | None], self.metadata)
@@ -344,6 +345,7 @@ class AsyncVersionedFunction(
344
345
  signature=self.closure.signature,
345
346
  signature_hash=self.closure.signature_hash,
346
347
  name=self.name or self.closure.name,
348
+ language="python",
347
349
  description=self.closure.docstring,
348
350
  tags=list(self.tags) if self.tags else None,
349
351
  metadata=cast(dict[str, str | None], self.metadata)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mirascope
3
- Version: 2.1.1
3
+ Version: 2.2.0
4
4
  Summary: Every frontier LLM. One unified interface.
5
5
  Project-URL: Homepage, https://mirascope.com
6
6
  Project-URL: Documentation, https://mirascope.com/docs/mirascope/v2
@@ -8,7 +8,7 @@ mirascope/api/_generated/README.md,sha256=7-B_qhXCHaXKX9FPG-G112hKmXM64uM6eNqmSd
8
8
  mirascope/api/_generated/__init__.py,sha256=NL-bCeIoDl0-VavSWKQpN_WAXlIxh4VJb1zrFfFWdfI,16952
9
9
  mirascope/api/_generated/client.py,sha256=Xh_VGnnbdZaSUpWzjGWu-1lwoZ_6isz9eU-BATjo_vs,8775
10
10
  mirascope/api/_generated/environment.py,sha256=eKhvb5ZF3qzJj2OtEI7E9STAquQ1VivYLdmHRc4hFV4,262
11
- mirascope/api/_generated/reference.md,sha256=GvMROs5SFqtQQIHH31FLkpLgOznJI9BadG-dfq2GNNQ,54335
11
+ mirascope/api/_generated/reference.md,sha256=QHYOhEYd2WU8RHtMLcJ2wpNXAfHlKi4KnwQtjl66i0Q,54410
12
12
  mirascope/api/_generated/annotations/__init__.py,sha256=z1rsEyNXWcegCIeC-Y2P9TBI0fVbNs1FohqSJiqrK84,987
13
13
  mirascope/api/_generated/annotations/client.py,sha256=rikFtCmou4D4hSZqtaxFnIc7ZKMt86XztUyh4pMcXII,13818
14
14
  mirascope/api/_generated/annotations/raw_client.py,sha256=EEC2Rr5KT_WmLn9aFgQxApnxHGl3MdOOcoYAti4syhE,54205
@@ -72,23 +72,23 @@ mirascope/api/_generated/errors/service_unavailable_error.py,sha256=gLGMVEFuS7rz
72
72
  mirascope/api/_generated/errors/too_many_requests_error.py,sha256=uOvzFzeCaBzFI-uENVev0OmDJHLjNTHVQSxxffjnjp0,413
73
73
  mirascope/api/_generated/errors/unauthorized_error.py,sha256=d5MEGAcmZ65n2bx1WAVa4goJ2q7uugy6YZyGCs_zHoM,400
74
74
  mirascope/api/_generated/functions/__init__.py,sha256=oLjCzn-MKrHIxGV5z2elOK4dG4esHoJwMQFRjbEK7r4,1381
75
- mirascope/api/_generated/functions/client.py,sha256=vLykxRH6HVXeG7D7YPFmU6ttSRXZlTSNDb-hXtABCaM,16462
76
- mirascope/api/_generated/functions/raw_client.py,sha256=6eqPk4YI7o1X4L-tQ3n2RZkCkag3gKiTADH3vW_Pww0,72462
75
+ mirascope/api/_generated/functions/client.py,sha256=j-zalqXnjyqv5wOBlChkG0p5wy0fjs4yU_JzYG8k7aY,16688
76
+ mirascope/api/_generated/functions/raw_client.py,sha256=7gac4zL5i7s5Qsw0wT9hHFK7h4wM2yWHLBAq_Y9IYp4,72632
77
77
  mirascope/api/_generated/functions/types/__init__.py,sha256=ePNVxcxuQxjPllnMOXAB-4pVo1uW2aaX_NPv4EPR3hQ,2155
78
78
  mirascope/api/_generated/functions/types/functions_create_request_dependencies_value.py,sha256=A-bx9nZE0aYoNLuLo6xQYe2GvvUq76ZiBfdJOZ31n2c,603
79
- mirascope/api/_generated/functions/types/functions_create_response.py,sha256=-NIC1-HuzDHpAfnM4bYgSb1V3EkffqJ3Ud_Mi1LH_iQ,1642
79
+ mirascope/api/_generated/functions/types/functions_create_response.py,sha256=XvhaneMVKHNp9V9WYtMiRbASCp8kRN4e3WjhFDPx__M,1775
80
80
  mirascope/api/_generated/functions/types/functions_create_response_dependencies_value.py,sha256=uH0JsZ4QbarNF1eiVT_go8GbMVndHeBRPe7MOemlpJc,604
81
- mirascope/api/_generated/functions/types/functions_find_by_hash_response.py,sha256=yjm77Q3bPditf4xK7tVIPR9DkYWoGtt2nAup8px42EE,1676
81
+ mirascope/api/_generated/functions/types/functions_find_by_hash_response.py,sha256=teRk8SrU2nSxNeLKdhDjsUbF0acaFutUnYzGEWm0zGc,1793
82
82
  mirascope/api/_generated/functions/types/functions_find_by_hash_response_dependencies_value.py,sha256=ZrhLgxa2vDThOc9AgLjSiYMjFBQfLaT-6hRvNgx6pog,608
83
- mirascope/api/_generated/functions/types/functions_get_by_env_response.py,sha256=IdmzapxETNVX9ATkfl7VK2V7ZOO3ULXipA7UWGNPUW4,1767
83
+ mirascope/api/_generated/functions/types/functions_get_by_env_response.py,sha256=ot7ESVeqtHimuyXenjwxEM-Y0BfGwNob0ekt0FEdUXM,1785
84
84
  mirascope/api/_generated/functions/types/functions_get_by_env_response_dependencies_value.py,sha256=Z1BTN_3xh_VKtQj872eirU5o6dAbmUhv7bzjzKddhas,628
85
- mirascope/api/_generated/functions/types/functions_get_response.py,sha256=JLyHjIuf4tWSX6KNjt9_mobSZC9pUuGfwLFOno3i6pw,1630
85
+ mirascope/api/_generated/functions/types/functions_get_response.py,sha256=sZfNT1NAVCk--OUvaeDCQWngUncWy30nf2kwdV1lYdM,1763
86
86
  mirascope/api/_generated/functions/types/functions_get_response_dependencies_value.py,sha256=OiD6Z39V4cDImDRILIfQfgVlMH3idJz9RQ8p5jG6DWE,601
87
87
  mirascope/api/_generated/functions/types/functions_list_by_env_response.py,sha256=DnFTgOg7jP_WkghF8FCJM9zDE8SrUgGzQUW7NhSfJYc,735
88
- mirascope/api/_generated/functions/types/functions_list_by_env_response_functions_item.py,sha256=zO2mD0td0OJQdPxWJHmdEJqgdhzSENS90ApQxKDrtAM,1860
88
+ mirascope/api/_generated/functions/types/functions_list_by_env_response_functions_item.py,sha256=OGuqKYlGJbVdp9BMNEQCMtZgobAgvX62FYrfSPm1cQI,1878
89
89
  mirascope/api/_generated/functions/types/functions_list_by_env_response_functions_item_dependencies_value.py,sha256=hE_610_LWn5YVoxRiwbW1KHBTR9a3Fp1eFYIPhFdSjY,642
90
90
  mirascope/api/_generated/functions/types/functions_list_response.py,sha256=QFrlBjZugHKQ6oL1bqSvyhg1Tal6ZQG1ZW9rEN8PPMA,682
91
- mirascope/api/_generated/functions/types/functions_list_response_functions_item.py,sha256=oPJKwQdKo8M0vXVA333SLMI9M-LfpohjEfEn3ktMjl4,1711
91
+ mirascope/api/_generated/functions/types/functions_list_response_functions_item.py,sha256=OiZIwM598UzwytXS8a4b7FgesabKUGkP3_iOtJKonWM,1843
92
92
  mirascope/api/_generated/functions/types/functions_list_response_functions_item_dependencies_value.py,sha256=wPsajRsxnZ1Ut9dxmnMWOibrJ38IwiR0v-_6x9_P4Dg,615
93
93
  mirascope/api/_generated/health/__init__.py,sha256=UN1u0qzFG8zDGf3CABrpMNNEP467lQZKLQfTOpkwm2E,215
94
94
  mirascope/api/_generated/health/client.py,sha256=iqLicxinxNofeZfFkQVOv9Xv0o37amPQbDawA3UCVO8,2520
@@ -265,10 +265,10 @@ mirascope/api/_generated/types/subscription_past_due_error.py,sha256=a-1Rb33jN_p
265
265
  mirascope/api/_generated/types/subscription_past_due_error_tag.py,sha256=ghRiStRa--el9MUbcTwhfYKdhj60cqf08DIqZYUArFg,185
266
266
  mirascope/api/_generated/types/unauthorized_error_body.py,sha256=0k725xKXRagfrb1HJoygl87SQvZdd6WEU2ACrDbt694,618
267
267
  mirascope/api/_generated/types/unauthorized_error_tag.py,sha256=sx-QdNmQjboMaPni2EVKoorYvWk5OmHHlT5-IBiFhQw,165
268
- mirascope/llm/__init__.py,sha256=AeP8Lghi-EFgStXshoqO_MCgYtE8UyxpJ41CyCSyebA,6234
269
- mirascope/llm/exceptions.py,sha256=hYc8A8A6unqPaB9GmvdlWIEUso4NWlR7lXELEVVyGFc,10839
268
+ mirascope/llm/__init__.py,sha256=Lj4Goc1m5GLQPGSFujYjlskTwc73gpj6SjTjPwUG24A,7173
269
+ mirascope/llm/exceptions.py,sha256=Xj0RjkXb17FoGMC3YvGR6j2bVel_OMGPXh_qHwgzV-U,13120
270
270
  mirascope/llm/calls/__init__.py,sha256=aA-IoOlXdmhVybHTj_fGx1jDlIL-a7ed7xncO2aMIJY,293
271
- mirascope/llm/calls/calls.py,sha256=g71njIpo5hWvNCnSsDeT8c3l-IaAes01iKrwMyPIYlY,12089
271
+ mirascope/llm/calls/calls.py,sha256=ckHpAJzLSlnw5d3vIpKO_jaHhlcar-5FaY5OWEjhvRw,12807
272
272
  mirascope/llm/calls/decorator.py,sha256=dPD04bfpvJueZWcJ4H7LY-a63U-RYQ7VRnv0M3BKxqI,8945
273
273
  mirascope/llm/content/__init__.py,sha256=4a5UaoiF8OKfXS9j7INFvOnU7bkNpacpiZ6IlLgC6Lc,1926
274
274
  mirascope/llm/content/audio.py,sha256=W6liY1PuQ0pF91eDBnNKW52dr-G7-vnd-rhlSqebx9Y,5311
@@ -300,7 +300,7 @@ mirascope/llm/models/thinking_config.py,sha256=CkFOkw-fjDlsZbHJbV68v4yRwb5o6miVx
300
300
  mirascope/llm/prompts/__init__.py,sha256=rOtSiZvw6vsJl7vCFWzKZnm3haNhnLtPRzPfdbgoH7U,727
301
301
  mirascope/llm/prompts/_utils.py,sha256=42hTqm8PuLpDOz4Mi59kaUou43qeo5R-9703l8cciSg,1018
302
302
  mirascope/llm/prompts/decorator.py,sha256=lwGfPokTxaeiJlHby4vsN09DII8Rd4piThNWwtoGmoc,6921
303
- mirascope/llm/prompts/prompts.py,sha256=-HFdzebMOmp5Yy7fPfVSADdLZVVnhzo6g7cEfgeLa8M,16019
303
+ mirascope/llm/prompts/prompts.py,sha256=kNhvMOyCrVRQ4WFrwgMw5FBRQxkBjkPfLEC8G0Ui2UI,16936
304
304
  mirascope/llm/prompts/protocols.py,sha256=auopJnLAfOognCFVVnXrvb4zFj3102Ofi2iVHfublM0,2242
305
305
  mirascope/llm/providers/__init__.py,sha256=nGCTJsF0vbWiD6r4D4nkfTGWfMB23k0eV_HHRVkFdG8,2093
306
306
  mirascope/llm/providers/model_id.py,sha256=qr7RKkP_3Blgxjzw_HvQVJLM1aTzsP-jVFsycz0itI8,292
@@ -370,11 +370,20 @@ mirascope/llm/responses/_utils.py,sha256=0_vuY5qcFD91sF2uCOM1PxJse5vP6pEPedEFqKA
370
370
  mirascope/llm/responses/base_response.py,sha256=Se0tf3hIB8Y7cBvAeLJEctA-w-pdLIHOURBn023m51s,4269
371
371
  mirascope/llm/responses/base_stream_response.py,sha256=YujpLwk0T0Mi98p7OPlsmuuBKfXyuyEcTpMReQQWB_8,33363
372
372
  mirascope/llm/responses/finish_reason.py,sha256=Az5OY6pfZoOPEpzVnl07AqZPz5ZC-w4YKwpUPbFJGdM,798
373
- mirascope/llm/responses/response.py,sha256=sFwHQ8sko-jpJ8L6tRMOgXPHMY7sJ0ww2QcpISUUPFY,12357
373
+ mirascope/llm/responses/response.py,sha256=0EVH8FSMnH_4xPzJR18BUJxsY24d2QMLKOdi6HDkslY,20878
374
374
  mirascope/llm/responses/root_response.py,sha256=LXAMDgI29UF8VYv0a76IfZkiQnebpTPFDkgJR8zFdZo,9246
375
- mirascope/llm/responses/stream_response.py,sha256=CX9wLZ_80BKJ6M-Ukku4aSbtC5lRgE9evFsxk7-8y54,23933
375
+ mirascope/llm/responses/stream_response.py,sha256=JRewzc3AzdoEBuc6Er3IhiAesEZJG8X7tDTkKWalBfo,33086
376
376
  mirascope/llm/responses/streams.py,sha256=TmEFvLVEWHfVYplik61yUWisxe8JGbaZdh7yC7e-axI,10789
377
377
  mirascope/llm/responses/usage.py,sha256=OvPhe9TpSnxNu2fhH2nCTPDrNTZFtT2_MEhpzVLmw_s,4376
378
+ mirascope/llm/retries/__init__.py,sha256=AT7y9az-OYGPhz2aJUggaRC2uy_ETXRrQqGXiiBDl-Y,1415
379
+ mirascope/llm/retries/retry_calls.py,sha256=XMvozSh0W8dZh6QFT_DCNNznEcUYZcZdrTAyKnB2JoQ,5492
380
+ mirascope/llm/retries/retry_config.py,sha256=ppKeMyCLVVqAt49WsF7H4CieKPxm7tTZb3uBWM0_6HU,6349
381
+ mirascope/llm/retries/retry_decorator.py,sha256=fJicq_I2g1-5BhbhD9_8joCJsrR5LFhRtQXPv2idTzM,7634
382
+ mirascope/llm/retries/retry_models.py,sha256=_lC3YsiPrvynpFbUVyRBte8yn05CDsvt6fkvQyacKnE,43763
383
+ mirascope/llm/retries/retry_prompts.py,sha256=E1ldVxJp3u1A7qpWO6vb2aTdHm0R3bV3DWlYDQq8fWI,7394
384
+ mirascope/llm/retries/retry_responses.py,sha256=NeTz4q3fIE2Mttk8pBxnvk9ok_fpMNtLgvCJETCXzrE,12561
385
+ mirascope/llm/retries/retry_stream_responses.py,sha256=DhPlbIlzdnLy9JaMCaiEKWiqx0K4TgOGovQnr_ffIZ4,21885
386
+ mirascope/llm/retries/utils.py,sha256=ravA7Ex_Lb_PoE5Hwej8QWCiBG0DyVeczcWYOWdiQbo,5168
378
387
  mirascope/llm/tools/__init__.py,sha256=4Rrnl0GBdZrw3KqACLoDLWqDer32DuU6VKJmN4sjzRo,1515
379
388
  mirascope/llm/tools/_utils.py,sha256=mUi6vUEwYuwu8W9FCQcQ_9h_VE_U-Y3Y2UQ2YptPZL4,1171
380
389
  mirascope/llm/tools/decorator.py,sha256=2ZTvYH0jrft0E3BdQ2BB9Okyb72JOIqQvBkLWmWuo7w,5663
@@ -404,8 +413,8 @@ mirascope/ops/_internal/traced_functions.py,sha256=lPN8c-lzHY-BxhhbcDpKC7JQtvgnm
404
413
  mirascope/ops/_internal/tracing.py,sha256=RzHBc-yEbj3Z_Kjobh26FWDSnF6AGbRCsb0JXBSzPdc,10244
405
414
  mirascope/ops/_internal/types.py,sha256=5B1RgChTEbGkLZvdoX8XA2vMKn4bS8BczjGDElxmugI,412
406
415
  mirascope/ops/_internal/utils.py,sha256=uGGKuAToxUUlkiqcmZIAICCAtmQay_fQ_ciVWF6jcIQ,4907
407
- mirascope/ops/_internal/versioned_calls.py,sha256=7oePDEuf98ph6yrHKJmXSagc1mGz5sdTTJgQnB2CyHM,18445
408
- mirascope/ops/_internal/versioned_functions.py,sha256=g_m-szx6NiBmwxakygNDnJTOyOQN-cVEgsUZZXLFh0w,13528
416
+ mirascope/ops/_internal/versioned_calls.py,sha256=4l5S3oiDEL7sH8qatbS4no-FxOgBCGzXp9LVXics9uc,25759
417
+ mirascope/ops/_internal/versioned_functions.py,sha256=__lnbjJEjkrU_0mAqUZXeFzqfWmeYlSDrb5xIwLKG9o,13598
409
418
  mirascope/ops/_internal/versioning.py,sha256=MxiezWrGUPiLZxZnwwXDFTR7EMrfTHR7rmd14TuDCL8,8286
410
419
  mirascope/ops/_internal/exporters/__init__.py,sha256=3PUd75TczW_8bUImcWgddWyoRmygGf6T_jL7Jo3t_sY,608
411
420
  mirascope/ops/_internal/exporters/exporters.py,sha256=9RUKKgtKCxrhh-9H0eaYdG_LApmirmvRZjNIlhr3tGA,14043
@@ -431,7 +440,7 @@ mirascope/ops/_internal/instrumentation/providers/anthropic.py,sha256=P3NgIKg9zt
431
440
  mirascope/ops/_internal/instrumentation/providers/base.py,sha256=7jl37MhcDCfWMWkkUqgdqATv0OQIggk8t9JSlCOlNFo,6072
432
441
  mirascope/ops/_internal/instrumentation/providers/google_genai.py,sha256=1QtxjyCrM5vjXEW0TVdpzdYJuHB8YKsqY8EQEWnIn3o,2948
433
442
  mirascope/ops/_internal/instrumentation/providers/openai.py,sha256=mVXebcl8bwRvFfOVXfiX4uxo5X_uqIOXgttkifIGCZg,2638
434
- mirascope-2.1.1.dist-info/METADATA,sha256=OL-o1nh_DIYVQsSNFkWFKyImdZ9NF_JZxjj1CXkgroY,9719
435
- mirascope-2.1.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
436
- mirascope-2.1.1.dist-info/licenses/LICENSE,sha256=MxD-HQ4YHSi2YqZ3UH2MsjclZbesds6j5it4O2IWyJs,1072
437
- mirascope-2.1.1.dist-info/RECORD,,
443
+ mirascope-2.2.0.dist-info/METADATA,sha256=nUt1SVcAx9DNeTaMEcAnAUjcb2Kwq1iSDssGFAU6NGk,9719
444
+ mirascope-2.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
445
+ mirascope-2.2.0.dist-info/licenses/LICENSE,sha256=MxD-HQ4YHSi2YqZ3UH2MsjclZbesds6j5it4O2IWyJs,1072
446
+ mirascope-2.2.0.dist-info/RECORD,,