mirascope 2.0.2__py3-none-any.whl → 2.1.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 (64) hide show
  1. mirascope/_stubs.py +39 -18
  2. mirascope/api/_generated/__init__.py +4 -0
  3. mirascope/api/_generated/project_memberships/__init__.py +4 -0
  4. mirascope/api/_generated/project_memberships/client.py +91 -0
  5. mirascope/api/_generated/project_memberships/raw_client.py +239 -0
  6. mirascope/api/_generated/project_memberships/types/__init__.py +4 -0
  7. mirascope/api/_generated/project_memberships/types/project_memberships_get_response.py +33 -0
  8. mirascope/api/_generated/project_memberships/types/project_memberships_get_response_role.py +7 -0
  9. mirascope/api/_generated/reference.md +72 -0
  10. mirascope/llm/__init__.py +19 -0
  11. mirascope/llm/calls/decorator.py +17 -24
  12. mirascope/llm/formatting/__init__.py +2 -2
  13. mirascope/llm/formatting/format.py +2 -4
  14. mirascope/llm/formatting/types.py +19 -2
  15. mirascope/llm/models/models.py +66 -146
  16. mirascope/llm/prompts/decorator.py +5 -16
  17. mirascope/llm/prompts/prompts.py +5 -13
  18. mirascope/llm/providers/anthropic/_utils/beta_decode.py +22 -7
  19. mirascope/llm/providers/anthropic/_utils/beta_encode.py +22 -16
  20. mirascope/llm/providers/anthropic/_utils/decode.py +45 -7
  21. mirascope/llm/providers/anthropic/_utils/encode.py +28 -15
  22. mirascope/llm/providers/anthropic/beta_provider.py +33 -69
  23. mirascope/llm/providers/anthropic/provider.py +52 -91
  24. mirascope/llm/providers/base/_utils.py +4 -9
  25. mirascope/llm/providers/base/base_provider.py +89 -205
  26. mirascope/llm/providers/google/_utils/decode.py +51 -1
  27. mirascope/llm/providers/google/_utils/encode.py +38 -21
  28. mirascope/llm/providers/google/provider.py +33 -69
  29. mirascope/llm/providers/mirascope/provider.py +25 -61
  30. mirascope/llm/providers/mlx/encoding/base.py +3 -6
  31. mirascope/llm/providers/mlx/encoding/transformers.py +4 -8
  32. mirascope/llm/providers/mlx/mlx.py +9 -21
  33. mirascope/llm/providers/mlx/provider.py +33 -69
  34. mirascope/llm/providers/openai/completions/_utils/encode.py +39 -20
  35. mirascope/llm/providers/openai/completions/base_provider.py +34 -75
  36. mirascope/llm/providers/openai/provider.py +25 -61
  37. mirascope/llm/providers/openai/responses/_utils/decode.py +31 -2
  38. mirascope/llm/providers/openai/responses/_utils/encode.py +32 -17
  39. mirascope/llm/providers/openai/responses/provider.py +34 -75
  40. mirascope/llm/responses/__init__.py +2 -1
  41. mirascope/llm/responses/base_stream_response.py +4 -0
  42. mirascope/llm/responses/response.py +8 -12
  43. mirascope/llm/responses/stream_response.py +8 -12
  44. mirascope/llm/responses/usage.py +44 -0
  45. mirascope/llm/tools/__init__.py +24 -0
  46. mirascope/llm/tools/provider_tools.py +18 -0
  47. mirascope/llm/tools/tool_schema.py +4 -2
  48. mirascope/llm/tools/toolkit.py +24 -6
  49. mirascope/llm/tools/types.py +112 -0
  50. mirascope/llm/tools/web_search_tool.py +32 -0
  51. mirascope/ops/__init__.py +19 -1
  52. mirascope/ops/_internal/instrumentation/__init__.py +20 -0
  53. mirascope/ops/_internal/instrumentation/llm/common.py +19 -49
  54. mirascope/ops/_internal/instrumentation/llm/model.py +61 -82
  55. mirascope/ops/_internal/instrumentation/llm/serialize.py +36 -12
  56. mirascope/ops/_internal/instrumentation/providers/__init__.py +29 -0
  57. mirascope/ops/_internal/instrumentation/providers/anthropic.py +78 -0
  58. mirascope/ops/_internal/instrumentation/providers/base.py +179 -0
  59. mirascope/ops/_internal/instrumentation/providers/google_genai.py +85 -0
  60. mirascope/ops/_internal/instrumentation/providers/openai.py +82 -0
  61. {mirascope-2.0.2.dist-info → mirascope-2.1.0.dist-info}/METADATA +96 -68
  62. {mirascope-2.0.2.dist-info → mirascope-2.1.0.dist-info}/RECORD +64 -54
  63. {mirascope-2.0.2.dist-info → mirascope-2.1.0.dist-info}/WHEEL +0 -0
  64. {mirascope-2.0.2.dist-info → mirascope-2.1.0.dist-info}/licenses/LICENSE +0 -0
@@ -19,35 +19,30 @@ from opentelemetry import trace as otel_trace
19
19
  from .....llm import (
20
20
  AsyncContextResponse,
21
21
  AsyncContextStreamResponse,
22
- AsyncContextTool,
23
- AsyncContextToolkit,
22
+ AsyncContextTools,
24
23
  AsyncResponse,
25
24
  AsyncStreamResponse,
26
- AsyncTool,
27
- AsyncToolkit,
25
+ AsyncTools,
28
26
  Context,
29
27
  ContextResponse,
30
28
  ContextStreamResponse,
31
- ContextTool,
32
- ContextToolkit,
29
+ ContextTools,
33
30
  DepsT,
31
+ FormatSpec,
34
32
  FormattableT,
35
33
  Message,
36
34
  Model,
37
- OutputParser,
38
35
  Response,
39
36
  RootResponse,
40
37
  StreamResponse,
41
38
  StreamResponseChunk,
42
- Tool,
43
- Toolkit,
39
+ Tools,
44
40
  UserContent,
45
41
  )
46
42
  from .....llm.messages import promote_to_messages, user
47
43
  from .common import (
48
44
  FormatParam,
49
45
  SpanContext,
50
- ToolsParam,
51
46
  attach_response,
52
47
  attach_response_async,
53
48
  record_dropped_params,
@@ -108,7 +103,7 @@ def _instrumented_model_call(
108
103
  self: Model,
109
104
  content: UserContent | Sequence[Message],
110
105
  *,
111
- tools: Sequence[Tool] | Toolkit | None = None,
106
+ tools: Tools | None = None,
112
107
  format: None = None,
113
108
  ) -> Response: ...
114
109
 
@@ -118,8 +113,8 @@ def _instrumented_model_call(
118
113
  self: Model,
119
114
  content: UserContent | Sequence[Message],
120
115
  *,
121
- tools: Sequence[Tool] | Toolkit | None = None,
122
- format: type[FormattableT] | FormatParam,
116
+ tools: Tools | None = None,
117
+ format: FormatSpec[FormattableT],
123
118
  ) -> Response[FormattableT]: ...
124
119
 
125
120
 
@@ -128,8 +123,8 @@ def _instrumented_model_call(
128
123
  self: Model,
129
124
  content: UserContent | Sequence[Message],
130
125
  *,
131
- tools: Sequence[Tool] | Toolkit | None = None,
132
- format: type[FormattableT] | FormatParam | OutputParser[FormattableT] | None = None,
126
+ tools: Tools | None = None,
127
+ format: FormatSpec[FormattableT] | None = None,
133
128
  ) -> Response | Response[FormattableT]: ...
134
129
 
135
130
 
@@ -138,7 +133,7 @@ def _instrumented_model_call(
138
133
  self: Model,
139
134
  content: UserContent | Sequence[Message],
140
135
  *,
141
- tools: Sequence[Tool] | Toolkit | None = None,
136
+ tools: Tools | None = None,
142
137
  format: FormatParam = None,
143
138
  ) -> Response | Response[FormattableT]:
144
139
  """Returns a GenAI-instrumented result of `Model.call`."""
@@ -193,7 +188,7 @@ async def _instrumented_model_call_async(
193
188
  self: Model,
194
189
  content: UserContent | Sequence[Message],
195
190
  *,
196
- tools: Sequence[AsyncTool] | AsyncToolkit | None = None,
191
+ tools: AsyncTools | None = None,
197
192
  format: None = None,
198
193
  ) -> AsyncResponse: ...
199
194
 
@@ -203,8 +198,8 @@ async def _instrumented_model_call_async(
203
198
  self: Model,
204
199
  content: UserContent | Sequence[Message],
205
200
  *,
206
- tools: Sequence[AsyncTool] | AsyncToolkit | None = None,
207
- format: type[FormattableT] | FormatParam,
201
+ tools: AsyncTools | None = None,
202
+ format: FormatSpec[FormattableT],
208
203
  ) -> AsyncResponse[FormattableT]: ...
209
204
 
210
205
 
@@ -213,8 +208,8 @@ async def _instrumented_model_call_async(
213
208
  self: Model,
214
209
  content: UserContent | Sequence[Message],
215
210
  *,
216
- tools: Sequence[AsyncTool] | AsyncToolkit | None = None,
217
- format: type[FormattableT] | FormatParam | OutputParser[FormattableT] | None = None,
211
+ tools: AsyncTools | None = None,
212
+ format: FormatSpec[FormattableT] | None = None,
218
213
  ) -> AsyncResponse | AsyncResponse[FormattableT]: ...
219
214
 
220
215
 
@@ -223,7 +218,7 @@ async def _instrumented_model_call_async(
223
218
  self: Model,
224
219
  content: UserContent | Sequence[Message],
225
220
  *,
226
- tools: Sequence[AsyncTool] | AsyncToolkit | None = None,
221
+ tools: AsyncTools | None = None,
227
222
  format: FormatParam = None,
228
223
  ) -> AsyncResponse | AsyncResponse[FormattableT]:
229
224
  """Returns a GenAI-instrumented result of `Model.call_async`."""
@@ -280,7 +275,7 @@ def _instrumented_model_context_call(
280
275
  content: UserContent | Sequence[Message],
281
276
  *,
282
277
  ctx: Context[DepsT],
283
- tools: Sequence[Tool | ContextTool[DepsT]] | ContextToolkit[DepsT] | None = None,
278
+ tools: ContextTools[DepsT] | None = None,
284
279
  format: None = None,
285
280
  ) -> ContextResponse[DepsT, None]: ...
286
281
 
@@ -291,8 +286,8 @@ def _instrumented_model_context_call(
291
286
  content: UserContent | Sequence[Message],
292
287
  *,
293
288
  ctx: Context[DepsT],
294
- tools: Sequence[Tool | ContextTool[DepsT]] | ContextToolkit[DepsT] | None = None,
295
- format: type[FormattableT] | FormatParam,
289
+ tools: ContextTools[DepsT] | None = None,
290
+ format: FormatSpec[FormattableT],
296
291
  ) -> ContextResponse[DepsT, FormattableT]: ...
297
292
 
298
293
 
@@ -302,8 +297,8 @@ def _instrumented_model_context_call(
302
297
  content: UserContent | Sequence[Message],
303
298
  *,
304
299
  ctx: Context[DepsT],
305
- tools: Sequence[Tool | ContextTool[DepsT]] | ContextToolkit[DepsT] | None = None,
306
- format: type[FormattableT] | FormatParam | OutputParser[FormattableT] | None = None,
300
+ tools: ContextTools[DepsT] | None = None,
301
+ format: FormatSpec[FormattableT] | None = None,
307
302
  ) -> ContextResponse[DepsT, None] | ContextResponse[DepsT, FormattableT]: ...
308
303
 
309
304
 
@@ -313,7 +308,7 @@ def _instrumented_model_context_call(
313
308
  content: UserContent | Sequence[Message],
314
309
  *,
315
310
  ctx: Context[DepsT],
316
- tools: Sequence[Tool | ContextTool[DepsT]] | ContextToolkit[DepsT] | None = None,
311
+ tools: ContextTools[DepsT] | None = None,
317
312
  format: FormatParam = None,
318
313
  ) -> ContextResponse[DepsT, None] | ContextResponse[DepsT, FormattableT]:
319
314
  """Returns a GenAI-instrumented result of `Model.context_call`."""
@@ -371,9 +366,7 @@ async def _instrumented_model_context_call_async(
371
366
  content: UserContent | Sequence[Message],
372
367
  *,
373
368
  ctx: Context[DepsT],
374
- tools: Sequence[AsyncTool | AsyncContextTool[DepsT]]
375
- | AsyncContextToolkit[DepsT]
376
- | None = None,
369
+ tools: AsyncContextTools[DepsT] | None = None,
377
370
  format: None = None,
378
371
  ) -> AsyncContextResponse[DepsT, None]: ...
379
372
 
@@ -384,10 +377,8 @@ async def _instrumented_model_context_call_async(
384
377
  content: UserContent | Sequence[Message],
385
378
  *,
386
379
  ctx: Context[DepsT],
387
- tools: Sequence[AsyncTool | AsyncContextTool[DepsT]]
388
- | AsyncContextToolkit[DepsT]
389
- | None = None,
390
- format: type[FormattableT] | FormatParam,
380
+ tools: AsyncContextTools[DepsT] | None = None,
381
+ format: FormatSpec[FormattableT],
391
382
  ) -> AsyncContextResponse[DepsT, FormattableT]: ...
392
383
 
393
384
 
@@ -397,10 +388,8 @@ async def _instrumented_model_context_call_async(
397
388
  content: UserContent | Sequence[Message],
398
389
  *,
399
390
  ctx: Context[DepsT],
400
- tools: Sequence[AsyncTool | AsyncContextTool[DepsT]]
401
- | AsyncContextToolkit[DepsT]
402
- | None = None,
403
- format: type[FormattableT] | FormatParam | OutputParser[FormattableT] | None = None,
391
+ tools: AsyncContextTools[DepsT] | None = None,
392
+ format: FormatSpec[FormattableT] | None = None,
404
393
  ) -> AsyncContextResponse[DepsT, None] | AsyncContextResponse[DepsT, FormattableT]: ...
405
394
 
406
395
 
@@ -410,9 +399,7 @@ async def _instrumented_model_context_call_async(
410
399
  content: UserContent | Sequence[Message],
411
400
  *,
412
401
  ctx: Context[DepsT],
413
- tools: Sequence[AsyncTool | AsyncContextTool[DepsT]]
414
- | AsyncContextToolkit[DepsT]
415
- | None = None,
402
+ tools: AsyncContextTools[DepsT] | None = None,
416
403
  format: FormatParam = None,
417
404
  ) -> AsyncContextResponse[DepsT, None] | AsyncContextResponse[DepsT, FormattableT]:
418
405
  """Returns a GenAI-instrumented result of `Model.context_call_async`."""
@@ -567,7 +554,7 @@ def _instrumented_model_stream(
567
554
  self: Model,
568
555
  content: UserContent | Sequence[Message],
569
556
  *,
570
- tools: Sequence[Tool] | Toolkit | None = None,
557
+ tools: Tools | None = None,
571
558
  format: None = None,
572
559
  ) -> StreamResponse: ...
573
560
 
@@ -577,8 +564,8 @@ def _instrumented_model_stream(
577
564
  self: Model,
578
565
  content: UserContent | Sequence[Message],
579
566
  *,
580
- tools: Sequence[Tool] | Toolkit | None = None,
581
- format: type[FormattableT] | FormatParam,
567
+ tools: Tools | None = None,
568
+ format: FormatSpec[FormattableT],
582
569
  ) -> StreamResponse[FormattableT]: ...
583
570
 
584
571
 
@@ -587,8 +574,8 @@ def _instrumented_model_stream(
587
574
  self: Model,
588
575
  content: UserContent | Sequence[Message],
589
576
  *,
590
- tools: Sequence[Tool] | Toolkit | None = None,
591
- format: type[FormattableT] | FormatParam | OutputParser[FormattableT] | None = None,
577
+ tools: Tools | None = None,
578
+ format: FormatSpec[FormattableT] | None = None,
592
579
  ) -> StreamResponse | StreamResponse[FormattableT]: ...
593
580
 
594
581
 
@@ -597,7 +584,7 @@ def _instrumented_model_stream(
597
584
  self: Model,
598
585
  content: UserContent | Sequence[Message],
599
586
  *,
600
- tools: Sequence[Tool] | Toolkit | None = None,
587
+ tools: Tools | None = None,
601
588
  format: FormatParam = None,
602
589
  ) -> StreamResponse | StreamResponse[FormattableT]:
603
590
  """Returns a GenAI-instrumented result of `Model.stream`."""
@@ -676,7 +663,7 @@ async def _instrumented_model_stream_async(
676
663
  self: Model,
677
664
  content: UserContent | Sequence[Message],
678
665
  *,
679
- tools: Sequence[AsyncTool] | AsyncToolkit | None = None,
666
+ tools: AsyncTools | None = None,
680
667
  format: None = None,
681
668
  ) -> AsyncStreamResponse: ...
682
669
 
@@ -686,8 +673,8 @@ async def _instrumented_model_stream_async(
686
673
  self: Model,
687
674
  content: UserContent | Sequence[Message],
688
675
  *,
689
- tools: Sequence[AsyncTool] | AsyncToolkit | None = None,
690
- format: type[FormattableT] | FormatParam,
676
+ tools: AsyncTools | None = None,
677
+ format: FormatSpec[FormattableT],
691
678
  ) -> AsyncStreamResponse[FormattableT]: ...
692
679
 
693
680
 
@@ -696,8 +683,8 @@ async def _instrumented_model_stream_async(
696
683
  self: Model,
697
684
  content: UserContent | Sequence[Message],
698
685
  *,
699
- tools: Sequence[AsyncTool] | AsyncToolkit | None = None,
700
- format: type[FormattableT] | FormatParam | OutputParser[FormattableT] | None = None,
686
+ tools: AsyncTools | None = None,
687
+ format: FormatSpec[FormattableT] | None = None,
701
688
  ) -> AsyncStreamResponse | AsyncStreamResponse[FormattableT]: ...
702
689
 
703
690
 
@@ -706,7 +693,7 @@ async def _instrumented_model_stream_async(
706
693
  self: Model,
707
694
  content: UserContent | Sequence[Message],
708
695
  *,
709
- tools: Sequence[AsyncTool] | AsyncToolkit | None = None,
696
+ tools: AsyncTools | None = None,
710
697
  format: FormatParam = None,
711
698
  ) -> AsyncStreamResponse | AsyncStreamResponse[FormattableT]:
712
699
  """Returns a GenAI-instrumented result of `Model.stream_async`."""
@@ -788,7 +775,7 @@ def _instrumented_model_context_stream(
788
775
  content: UserContent | Sequence[Message],
789
776
  *,
790
777
  ctx: Context[DepsT],
791
- tools: Sequence[Tool | ContextTool[DepsT]] | ContextToolkit[DepsT] | None = None,
778
+ tools: ContextTools[DepsT] | None = None,
792
779
  format: None = None,
793
780
  ) -> ContextStreamResponse[DepsT, None]: ...
794
781
 
@@ -799,8 +786,8 @@ def _instrumented_model_context_stream(
799
786
  content: UserContent | Sequence[Message],
800
787
  *,
801
788
  ctx: Context[DepsT],
802
- tools: Sequence[Tool | ContextTool[DepsT]] | ContextToolkit[DepsT] | None = None,
803
- format: type[FormattableT] | FormatParam,
789
+ tools: ContextTools[DepsT] | None = None,
790
+ format: FormatSpec[FormattableT],
804
791
  ) -> ContextStreamResponse[DepsT, FormattableT]: ...
805
792
 
806
793
 
@@ -810,8 +797,8 @@ def _instrumented_model_context_stream(
810
797
  content: UserContent | Sequence[Message],
811
798
  *,
812
799
  ctx: Context[DepsT],
813
- tools: Sequence[Tool | ContextTool[DepsT]] | ContextToolkit[DepsT] | None = None,
814
- format: type[FormattableT] | FormatParam | OutputParser[FormattableT] | None = None,
800
+ tools: ContextTools[DepsT] | None = None,
801
+ format: FormatSpec[FormattableT] | None = None,
815
802
  ) -> (
816
803
  ContextStreamResponse[DepsT, None] | ContextStreamResponse[DepsT, FormattableT]
817
804
  ): ...
@@ -823,7 +810,7 @@ def _instrumented_model_context_stream(
823
810
  content: UserContent | Sequence[Message],
824
811
  *,
825
812
  ctx: Context[DepsT],
826
- tools: Sequence[Tool | ContextTool[DepsT]] | ContextToolkit[DepsT] | None = None,
813
+ tools: ContextTools[DepsT] | None = None,
827
814
  format: FormatParam = None,
828
815
  ) -> ContextStreamResponse[DepsT, None] | ContextStreamResponse[DepsT, FormattableT]:
829
816
  """Returns a GenAI-instrumented result of `Model.context_stream`."""
@@ -905,9 +892,7 @@ async def _instrumented_model_context_stream_async(
905
892
  content: UserContent | Sequence[Message],
906
893
  *,
907
894
  ctx: Context[DepsT],
908
- tools: Sequence[AsyncTool | AsyncContextTool[DepsT]]
909
- | AsyncContextToolkit[DepsT]
910
- | None = None,
895
+ tools: AsyncContextTools[DepsT] | None = None,
911
896
  format: None = None,
912
897
  ) -> AsyncContextStreamResponse[DepsT, None]: ...
913
898
 
@@ -918,10 +903,8 @@ async def _instrumented_model_context_stream_async(
918
903
  content: UserContent | Sequence[Message],
919
904
  *,
920
905
  ctx: Context[DepsT],
921
- tools: Sequence[AsyncTool | AsyncContextTool[DepsT]]
922
- | AsyncContextToolkit[DepsT]
923
- | None = None,
924
- format: type[FormattableT] | FormatParam,
906
+ tools: AsyncContextTools[DepsT] | None = None,
907
+ format: FormatSpec[FormattableT],
925
908
  ) -> AsyncContextStreamResponse[DepsT, FormattableT]: ...
926
909
 
927
910
 
@@ -931,10 +914,8 @@ async def _instrumented_model_context_stream_async(
931
914
  content: UserContent | Sequence[Message],
932
915
  *,
933
916
  ctx: Context[DepsT],
934
- tools: Sequence[AsyncTool | AsyncContextTool[DepsT]]
935
- | AsyncContextToolkit[DepsT]
936
- | None = None,
937
- format: type[FormattableT] | FormatParam | OutputParser[FormattableT] | None = None,
917
+ tools: AsyncContextTools[DepsT] | None = None,
918
+ format: FormatSpec[FormattableT] | None = None,
938
919
  ) -> (
939
920
  AsyncContextStreamResponse[DepsT, None]
940
921
  | AsyncContextStreamResponse[DepsT, FormattableT]
@@ -947,9 +928,7 @@ async def _instrumented_model_context_stream_async(
947
928
  content: UserContent | Sequence[Message],
948
929
  *,
949
930
  ctx: Context[DepsT],
950
- tools: Sequence[AsyncTool | AsyncContextTool[DepsT]]
951
- | AsyncContextToolkit[DepsT]
952
- | None = None,
931
+ tools: AsyncContextTools[DepsT] | None = None,
953
932
  format: FormatParam = None,
954
933
  ) -> (
955
934
  AsyncContextStreamResponse[DepsT, None]
@@ -1067,7 +1046,7 @@ def _instrumented_model_resume(
1067
1046
  with start_model_span(
1068
1047
  self,
1069
1048
  messages=messages,
1070
- tools=cast(ToolsParam, response.toolkit),
1049
+ tools=response.toolkit,
1071
1050
  format=cast(FormatParam, response.format),
1072
1051
  ) as span_ctx:
1073
1052
  result = _ORIGINAL_MODEL_RESUME(
@@ -1147,7 +1126,7 @@ async def _instrumented_model_resume_async(
1147
1126
  with start_model_span(
1148
1127
  self,
1149
1128
  messages=messages,
1150
- tools=cast(ToolsParam, response.toolkit),
1129
+ tools=response.toolkit,
1151
1130
  format=cast(FormatParam, response.format),
1152
1131
  activate=True,
1153
1132
  ) as span_ctx:
@@ -1232,7 +1211,7 @@ def _instrumented_model_context_resume(
1232
1211
  with start_model_span(
1233
1212
  self,
1234
1213
  messages=messages,
1235
- tools=cast(ToolsParam, response.toolkit),
1214
+ tools=response.toolkit,
1236
1215
  format=cast(FormatParam, response.format),
1237
1216
  activate=True,
1238
1217
  ) as span_ctx:
@@ -1320,7 +1299,7 @@ async def _instrumented_model_context_resume_async(
1320
1299
  with start_model_span(
1321
1300
  self,
1322
1301
  messages=messages,
1323
- tools=cast(ToolsParam, response.toolkit),
1302
+ tools=response.toolkit,
1324
1303
  format=cast(FormatParam, response.format),
1325
1304
  activate=True,
1326
1305
  ) as span_ctx:
@@ -1402,7 +1381,7 @@ def _instrumented_model_resume_stream(
1402
1381
  span_cm = start_model_span(
1403
1382
  self,
1404
1383
  messages=messages,
1405
- tools=cast(ToolsParam, response.toolkit),
1384
+ tools=response.toolkit,
1406
1385
  format=cast(FormatParam, response.format),
1407
1386
  activate=False,
1408
1387
  )
@@ -1505,7 +1484,7 @@ async def _instrumented_model_resume_stream_async(
1505
1484
  span_cm = start_model_span(
1506
1485
  self,
1507
1486
  messages=messages,
1508
- tools=cast(ToolsParam, response.toolkit),
1487
+ tools=response.toolkit,
1509
1488
  format=cast(FormatParam, response.format),
1510
1489
  activate=False,
1511
1490
  )
@@ -1618,7 +1597,7 @@ def _instrumented_model_context_resume_stream(
1618
1597
  span_cm = start_model_span(
1619
1598
  self,
1620
1599
  messages=messages,
1621
- tools=cast(ToolsParam, response.toolkit),
1600
+ tools=response.toolkit,
1622
1601
  format=cast(FormatParam, response.format),
1623
1602
  activate=False,
1624
1603
  )
@@ -1735,7 +1714,7 @@ async def _instrumented_model_context_resume_stream_async(
1735
1714
  span_cm = start_model_span(
1736
1715
  self,
1737
1716
  messages=messages,
1738
- tools=cast(ToolsParam, response.toolkit),
1717
+ tools=response.toolkit,
1739
1718
  format=cast(FormatParam, response.format),
1740
1719
  activate=False,
1741
1720
  )
@@ -4,30 +4,33 @@ from __future__ import annotations
4
4
 
5
5
  import logging
6
6
  from collections.abc import Sequence
7
- from typing import TYPE_CHECKING, Any, Protocol
7
+ from typing import Any, Protocol
8
8
 
9
- from .....llm.content import (
9
+ from opentelemetry.util.types import AttributeValue
10
+
11
+ from .....llm import (
12
+ AnyToolSchema,
13
+ AssistantMessage,
10
14
  Audio,
11
15
  Base64ImageSource,
12
16
  Document,
13
17
  Image,
18
+ Jsonable,
19
+ Message,
20
+ ProviderTool,
21
+ RootResponse,
22
+ SystemMessage,
14
23
  Text,
15
24
  Thought,
16
25
  ToolCall,
17
26
  ToolOutput,
27
+ Usage,
28
+ UserMessage,
18
29
  )
19
30
  from .....llm.content.document import Base64DocumentSource, TextDocumentSource
20
- from .....llm.messages import AssistantMessage, Message, SystemMessage, UserMessage
21
- from .....llm.responses.usage import Usage
22
31
  from ...utils import json_dumps
23
32
  from .cost import calculate_cost_async, calculate_cost_sync
24
33
 
25
- if TYPE_CHECKING:
26
- from opentelemetry.util.types import AttributeValue
27
-
28
- from .....llm.responses.root_response import RootResponse
29
- from .....llm.types import Jsonable
30
-
31
34
  logger = logging.getLogger(__name__)
32
35
 
33
36
 
@@ -41,7 +44,7 @@ class SpanProtocol(Protocol):
41
44
 
42
45
  def _serialize_content_part(
43
46
  part: Text | ToolCall | Thought | Image | Audio | Document | ToolOutput[Jsonable],
44
- ) -> dict[str, Any]:
47
+ ) -> dict[str, Jsonable]:
45
48
  """Serialize a single content part to a dict matching the Mirascope dataclass structure."""
46
49
  if isinstance(part, Text):
47
50
  return {"type": "text", "text": part.text}
@@ -116,7 +119,7 @@ def _serialize_content_part(
116
119
  return {"type": "unknown"} # pragma: no cover
117
120
 
118
121
 
119
- def _serialize_message(message: Message) -> dict[str, Any]:
122
+ def _serialize_message(message: Message) -> dict[str, Jsonable]:
120
123
  """Serialize a Message to a dict matching the Mirascope dataclass structure."""
121
124
  if isinstance(message, SystemMessage):
122
125
  return {
@@ -166,6 +169,27 @@ def serialize_mirascope_usage(usage: Usage | None) -> AttributeValue | None:
166
169
  )
167
170
 
168
171
 
172
+ def _serialize_tool(tool: AnyToolSchema | ProviderTool) -> dict[str, Jsonable]:
173
+ if isinstance(tool, ProviderTool):
174
+ return {"name": tool.name, "type": "extension"}
175
+ result: dict[str, Jsonable] = {
176
+ "name": tool.name,
177
+ "description": tool.description,
178
+ "type": "function",
179
+ "parameters": tool.parameters.model_dump(by_alias=True, mode="json"),
180
+ }
181
+ if tool.strict is not None:
182
+ result["strict"] = tool.strict
183
+ return result
184
+
185
+
186
+ def serialize_tools(tools: Sequence[AnyToolSchema | ProviderTool]) -> str | None:
187
+ """Serialize a sequence of Mirascope tools"""
188
+ if not tools:
189
+ return None
190
+ return json_dumps([_serialize_tool(t) for t in tools])
191
+
192
+
169
193
  def serialize_mirascope_cost(
170
194
  input_cost: float,
171
195
  output_cost: float,
@@ -0,0 +1,29 @@
1
+ """Provider instrumentation modules."""
2
+
3
+ from .anthropic import (
4
+ instrument_anthropic,
5
+ is_anthropic_instrumented,
6
+ uninstrument_anthropic,
7
+ )
8
+ from .google_genai import (
9
+ instrument_google_genai,
10
+ is_google_genai_instrumented,
11
+ uninstrument_google_genai,
12
+ )
13
+ from .openai import (
14
+ instrument_openai,
15
+ is_openai_instrumented,
16
+ uninstrument_openai,
17
+ )
18
+
19
+ __all__ = [
20
+ "instrument_anthropic",
21
+ "instrument_google_genai",
22
+ "instrument_openai",
23
+ "is_anthropic_instrumented",
24
+ "is_google_genai_instrumented",
25
+ "is_openai_instrumented",
26
+ "uninstrument_anthropic",
27
+ "uninstrument_google_genai",
28
+ "uninstrument_openai",
29
+ ]
@@ -0,0 +1,78 @@
1
+ """OpenTelemetry instrumentation for Anthropic SDK."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ from opentelemetry.instrumentation.anthropic import AnthropicInstrumentor
8
+
9
+ from .base import BaseInstrumentation, ContentCaptureMode
10
+
11
+ if TYPE_CHECKING:
12
+ from opentelemetry.trace import TracerProvider
13
+
14
+
15
+ class AnthropicInstrumentation(BaseInstrumentation[AnthropicInstrumentor]):
16
+ """Manages OpenTelemetry instrumentation lifecycle for the Anthropic SDK."""
17
+
18
+ def _create_instrumentor(self) -> AnthropicInstrumentor:
19
+ """Create a new Anthropic instrumentor instance."""
20
+ return AnthropicInstrumentor()
21
+
22
+ def _configure_capture_content(self, capture_content: ContentCaptureMode) -> None:
23
+ """Configure environment variables for Anthropic content capture."""
24
+ if capture_content == "enabled":
25
+ self._set_env_var("TRACELOOP_TRACE_CONTENT", "true")
26
+ elif capture_content == "disabled":
27
+ self._set_env_var("TRACELOOP_TRACE_CONTENT", "false")
28
+
29
+
30
+ def instrument_anthropic(
31
+ *,
32
+ tracer_provider: TracerProvider | None = None,
33
+ capture_content: ContentCaptureMode = "default",
34
+ ) -> None:
35
+ """Enable OpenTelemetry instrumentation for the Anthropic Python SDK.
36
+
37
+ Uses the provided tracer_provider or the global OpenTelemetry tracer provider.
38
+
39
+ Args:
40
+ tracer_provider: Optional tracer provider to use. If not provided,
41
+ uses the global OpenTelemetry tracer provider.
42
+ capture_content: Controls whether to capture message content in spans.
43
+ - "enabled": Capture message content
44
+ - "disabled": Do not capture message content
45
+ - "default": Use the library's default behavior
46
+
47
+ Example:
48
+
49
+ Enable instrumentation with Mirascope Cloud:
50
+ ```python
51
+ from mirascope import ops
52
+
53
+ ops.configure()
54
+ ops.instrument_anthropic()
55
+ ```
56
+
57
+ Enable instrumentation with content capture:
58
+ ```python
59
+ from mirascope import ops
60
+
61
+ ops.configure()
62
+ ops.instrument_anthropic(capture_content="enabled")
63
+ ```
64
+ """
65
+ AnthropicInstrumentation().instrument(
66
+ tracer_provider=tracer_provider,
67
+ capture_content=capture_content,
68
+ )
69
+
70
+
71
+ def uninstrument_anthropic() -> None:
72
+ """Disable previously configured Anthropic instrumentation."""
73
+ AnthropicInstrumentation().uninstrument()
74
+
75
+
76
+ def is_anthropic_instrumented() -> bool:
77
+ """Return whether Anthropic instrumentation is currently active."""
78
+ return AnthropicInstrumentation().is_instrumented