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.
- mirascope/_stubs.py +39 -18
- mirascope/api/_generated/__init__.py +4 -0
- mirascope/api/_generated/project_memberships/__init__.py +4 -0
- mirascope/api/_generated/project_memberships/client.py +91 -0
- mirascope/api/_generated/project_memberships/raw_client.py +239 -0
- mirascope/api/_generated/project_memberships/types/__init__.py +4 -0
- mirascope/api/_generated/project_memberships/types/project_memberships_get_response.py +33 -0
- mirascope/api/_generated/project_memberships/types/project_memberships_get_response_role.py +7 -0
- mirascope/api/_generated/reference.md +72 -0
- mirascope/llm/__init__.py +19 -0
- mirascope/llm/calls/decorator.py +17 -24
- mirascope/llm/formatting/__init__.py +2 -2
- mirascope/llm/formatting/format.py +2 -4
- mirascope/llm/formatting/types.py +19 -2
- mirascope/llm/models/models.py +66 -146
- mirascope/llm/prompts/decorator.py +5 -16
- mirascope/llm/prompts/prompts.py +5 -13
- mirascope/llm/providers/anthropic/_utils/beta_decode.py +22 -7
- mirascope/llm/providers/anthropic/_utils/beta_encode.py +22 -16
- mirascope/llm/providers/anthropic/_utils/decode.py +45 -7
- mirascope/llm/providers/anthropic/_utils/encode.py +28 -15
- mirascope/llm/providers/anthropic/beta_provider.py +33 -69
- mirascope/llm/providers/anthropic/provider.py +52 -91
- mirascope/llm/providers/base/_utils.py +4 -9
- mirascope/llm/providers/base/base_provider.py +89 -205
- mirascope/llm/providers/google/_utils/decode.py +51 -1
- mirascope/llm/providers/google/_utils/encode.py +38 -21
- mirascope/llm/providers/google/provider.py +33 -69
- mirascope/llm/providers/mirascope/provider.py +25 -61
- mirascope/llm/providers/mlx/encoding/base.py +3 -6
- mirascope/llm/providers/mlx/encoding/transformers.py +4 -8
- mirascope/llm/providers/mlx/mlx.py +9 -21
- mirascope/llm/providers/mlx/provider.py +33 -69
- mirascope/llm/providers/openai/completions/_utils/encode.py +39 -20
- mirascope/llm/providers/openai/completions/base_provider.py +34 -75
- mirascope/llm/providers/openai/provider.py +25 -61
- mirascope/llm/providers/openai/responses/_utils/decode.py +31 -2
- mirascope/llm/providers/openai/responses/_utils/encode.py +32 -17
- mirascope/llm/providers/openai/responses/provider.py +34 -75
- mirascope/llm/responses/__init__.py +2 -1
- mirascope/llm/responses/base_stream_response.py +4 -0
- mirascope/llm/responses/response.py +8 -12
- mirascope/llm/responses/stream_response.py +8 -12
- mirascope/llm/responses/usage.py +44 -0
- mirascope/llm/tools/__init__.py +24 -0
- mirascope/llm/tools/provider_tools.py +18 -0
- mirascope/llm/tools/tool_schema.py +4 -2
- mirascope/llm/tools/toolkit.py +24 -6
- mirascope/llm/tools/types.py +112 -0
- mirascope/llm/tools/web_search_tool.py +32 -0
- mirascope/ops/__init__.py +19 -1
- mirascope/ops/_internal/instrumentation/__init__.py +20 -0
- mirascope/ops/_internal/instrumentation/llm/common.py +19 -49
- mirascope/ops/_internal/instrumentation/llm/model.py +61 -82
- mirascope/ops/_internal/instrumentation/llm/serialize.py +36 -12
- mirascope/ops/_internal/instrumentation/providers/__init__.py +29 -0
- mirascope/ops/_internal/instrumentation/providers/anthropic.py +78 -0
- mirascope/ops/_internal/instrumentation/providers/base.py +179 -0
- mirascope/ops/_internal/instrumentation/providers/google_genai.py +85 -0
- mirascope/ops/_internal/instrumentation/providers/openai.py +82 -0
- {mirascope-2.0.2.dist-info → mirascope-2.1.0.dist-info}/METADATA +96 -68
- {mirascope-2.0.2.dist-info → mirascope-2.1.0.dist-info}/RECORD +64 -54
- {mirascope-2.0.2.dist-info → mirascope-2.1.0.dist-info}/WHEEL +0 -0
- {mirascope-2.0.2.dist-info → mirascope-2.1.0.dist-info}/licenses/LICENSE +0 -0
mirascope/llm/responses/usage.py
CHANGED
|
@@ -6,6 +6,38 @@ from dataclasses import dataclass
|
|
|
6
6
|
from typing import Any, Literal
|
|
7
7
|
|
|
8
8
|
|
|
9
|
+
@dataclass(kw_only=True)
|
|
10
|
+
class ProviderToolUsage:
|
|
11
|
+
"""Usage data for a provider's server-side tool.
|
|
12
|
+
|
|
13
|
+
Tracks usage of tools executed by the provider that have separate pricing
|
|
14
|
+
beyond standard token costs (e.g., web search, code execution).
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
name: str
|
|
18
|
+
"""Tool name matching our ProviderTool.name (e.g., "web_search").
|
|
19
|
+
|
|
20
|
+
This is the consistent cross-provider identifier that matches
|
|
21
|
+
the corresponding Mirascope ProviderTool class (e.g., WebSearchTool.name).
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
call_count: int = 0
|
|
25
|
+
"""Number of invocations/calls of this tool."""
|
|
26
|
+
|
|
27
|
+
duration_seconds: float | None = None
|
|
28
|
+
"""Duration in seconds for time-based tools (e.g., code execution).
|
|
29
|
+
|
|
30
|
+
None if not applicable to this tool type.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
metadata: dict[str, Any] | None = None
|
|
34
|
+
"""Provider-specific metadata for debugging/analytics.
|
|
35
|
+
|
|
36
|
+
Examples:
|
|
37
|
+
- Google grounding: {"queries": ["query1", "query2"]}
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
|
|
9
41
|
@dataclass(kw_only=True)
|
|
10
42
|
class UsageDeltaChunk:
|
|
11
43
|
"""A chunk containing incremental token usage information from a streaming response.
|
|
@@ -31,6 +63,9 @@ class UsageDeltaChunk:
|
|
|
31
63
|
reasoning_tokens: int = 0
|
|
32
64
|
"""Delta in reasoning/thinking tokens."""
|
|
33
65
|
|
|
66
|
+
provider_tool_usage: list[ProviderToolUsage] | None = None
|
|
67
|
+
"""Provider tool usage (emitted in final chunk only)."""
|
|
68
|
+
|
|
34
69
|
|
|
35
70
|
@dataclass(kw_only=True)
|
|
36
71
|
class Usage:
|
|
@@ -86,6 +121,15 @@ class Usage:
|
|
|
86
121
|
Will be 0 if not reported by the provider or if the model does not support reasoning.
|
|
87
122
|
"""
|
|
88
123
|
|
|
124
|
+
provider_tool_usage: list[ProviderToolUsage] | None = None
|
|
125
|
+
"""Provider tool usage data for tools with separate pricing.
|
|
126
|
+
|
|
127
|
+
Tracks usage of server-side tools executed by the provider (e.g., web search,
|
|
128
|
+
code execution) that have pricing beyond standard token costs.
|
|
129
|
+
|
|
130
|
+
Will be None if no provider tools were used.
|
|
131
|
+
"""
|
|
132
|
+
|
|
89
133
|
raw: Any = None
|
|
90
134
|
"""The raw usage object from the provider."""
|
|
91
135
|
|
mirascope/llm/tools/__init__.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from .decorator import ToolDecorator, tool
|
|
4
4
|
from .protocols import AsyncContextToolFn, AsyncToolFn, ContextToolFn, ToolFn
|
|
5
|
+
from .provider_tools import ProviderTool
|
|
5
6
|
from .tool_schema import (
|
|
6
7
|
FORMAT_TOOL_NAME,
|
|
7
8
|
AnyToolFn,
|
|
@@ -19,21 +20,38 @@ from .toolkit import (
|
|
|
19
20
|
ToolkitT,
|
|
20
21
|
)
|
|
21
22
|
from .tools import AsyncContextTool, AsyncTool, ContextTool, Tool, ToolT
|
|
23
|
+
from .types import (
|
|
24
|
+
AnyTools,
|
|
25
|
+
AsyncContextTools,
|
|
26
|
+
AsyncTools,
|
|
27
|
+
ContextTools,
|
|
28
|
+
Tools,
|
|
29
|
+
normalize_async_context_tools,
|
|
30
|
+
normalize_async_tools,
|
|
31
|
+
normalize_context_tools,
|
|
32
|
+
normalize_tools,
|
|
33
|
+
)
|
|
34
|
+
from .web_search_tool import WebSearchTool
|
|
22
35
|
|
|
23
36
|
__all__ = [
|
|
24
37
|
"FORMAT_TOOL_NAME",
|
|
25
38
|
"AnyToolFn",
|
|
26
39
|
"AnyToolSchema",
|
|
40
|
+
"AnyTools",
|
|
27
41
|
"AsyncContextTool",
|
|
28
42
|
"AsyncContextToolFn",
|
|
29
43
|
"AsyncContextToolkit",
|
|
44
|
+
"AsyncContextTools",
|
|
30
45
|
"AsyncTool",
|
|
31
46
|
"AsyncToolFn",
|
|
32
47
|
"AsyncToolkit",
|
|
48
|
+
"AsyncTools",
|
|
33
49
|
"BaseToolkit",
|
|
34
50
|
"ContextTool",
|
|
35
51
|
"ContextToolFn",
|
|
36
52
|
"ContextToolkit",
|
|
53
|
+
"ContextTools",
|
|
54
|
+
"ProviderTool",
|
|
37
55
|
"Tool",
|
|
38
56
|
"ToolDecorator",
|
|
39
57
|
"ToolFn",
|
|
@@ -43,5 +61,11 @@ __all__ = [
|
|
|
43
61
|
"ToolT",
|
|
44
62
|
"Toolkit",
|
|
45
63
|
"ToolkitT",
|
|
64
|
+
"Tools",
|
|
65
|
+
"WebSearchTool",
|
|
66
|
+
"normalize_async_context_tools",
|
|
67
|
+
"normalize_async_tools",
|
|
68
|
+
"normalize_context_tools",
|
|
69
|
+
"normalize_tools",
|
|
46
70
|
"tool",
|
|
47
71
|
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Base class for provider-native tools."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass(frozen=True)
|
|
7
|
+
class ProviderTool:
|
|
8
|
+
"""Base class for tools executed natively by providers.
|
|
9
|
+
|
|
10
|
+
Unlike regular tools which define functions that you execute locally,
|
|
11
|
+
provider tools are capabilities built into the provider's API.
|
|
12
|
+
The provider handles execution entirely server-side.
|
|
13
|
+
|
|
14
|
+
Provider tools have no sync/async distinction since they are not
|
|
15
|
+
executed by your code - they are configuration passed to the provider.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
name: str
|
|
@@ -40,8 +40,7 @@ ToolFnT = TypeVar(
|
|
|
40
40
|
covariant=True,
|
|
41
41
|
)
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
ToolSchemaT = TypeVar("ToolSchemaT", bound=AnyToolSchema, covariant=True)
|
|
43
|
+
ToolSchemaT = TypeVar("ToolSchemaT", bound="ToolSchema[AnyToolFn]", covariant=True)
|
|
45
44
|
|
|
46
45
|
|
|
47
46
|
ModelJsonSchema = TypedDict(
|
|
@@ -317,3 +316,6 @@ class ToolSchema(Generic[ToolFnT]):
|
|
|
317
316
|
is performed.
|
|
318
317
|
"""
|
|
319
318
|
return tool_call.name == self.name
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
AnyToolSchema: TypeAlias = ToolSchema[AnyToolFn]
|
mirascope/llm/tools/toolkit.py
CHANGED
|
@@ -6,6 +6,7 @@ from ..content import ToolCall, ToolOutput
|
|
|
6
6
|
from ..context import Context, DepsT
|
|
7
7
|
from ..exceptions import ToolNotFoundError
|
|
8
8
|
from ..types import Jsonable
|
|
9
|
+
from .provider_tools import ProviderTool
|
|
9
10
|
from .tool_schema import ToolSchemaT
|
|
10
11
|
from .tools import AsyncContextTool, AsyncTool, ContextTool, Tool
|
|
11
12
|
|
|
@@ -24,13 +25,24 @@ class BaseToolkit(Generic[ToolSchemaT]):
|
|
|
24
25
|
including name validation and tool lookup.
|
|
25
26
|
"""
|
|
26
27
|
|
|
27
|
-
tools: Sequence[ToolSchemaT]
|
|
28
|
+
tools: Sequence[ToolSchemaT | ProviderTool]
|
|
28
29
|
"""The tools included in the toolkit."""
|
|
29
30
|
|
|
30
31
|
tools_dict: dict[str, ToolSchemaT]
|
|
31
|
-
"""A mapping from tool names to tools in the toolkit.
|
|
32
|
+
"""A mapping from tool names to tools in the toolkit.
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
This dict does not include any `ProviderTool`s, since they do not correspond
|
|
35
|
+
to tool calls that your code executes.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
provider_tools_dict: dict[str, ProviderTool]
|
|
39
|
+
"""A mapping from provider tool names to provider tools in the toolkit.
|
|
40
|
+
|
|
41
|
+
Provider tools are capabilities built into the provider's API (like web search)
|
|
42
|
+
that are executed server-side, not by your code.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
def __init__(self, tools: Sequence[ToolSchemaT | ProviderTool] | None) -> None:
|
|
34
46
|
"""Initialize the toolkit with a collection of tools.
|
|
35
47
|
|
|
36
48
|
Args:
|
|
@@ -41,10 +53,16 @@ class BaseToolkit(Generic[ToolSchemaT]):
|
|
|
41
53
|
"""
|
|
42
54
|
self.tools = tools or []
|
|
43
55
|
self.tools_dict = {}
|
|
56
|
+
self.provider_tools_dict = {}
|
|
44
57
|
for tool in self.tools:
|
|
45
|
-
if tool
|
|
46
|
-
|
|
47
|
-
|
|
58
|
+
if isinstance(tool, ProviderTool):
|
|
59
|
+
if tool.name in self.provider_tools_dict:
|
|
60
|
+
raise ValueError(f"Multiple provider tools with name: {tool.name}")
|
|
61
|
+
self.provider_tools_dict[tool.name] = tool
|
|
62
|
+
else:
|
|
63
|
+
if tool.name in self.tools_dict:
|
|
64
|
+
raise ValueError(f"Multiple tools with name: {tool.name}")
|
|
65
|
+
self.tools_dict[tool.name] = tool
|
|
48
66
|
|
|
49
67
|
def get(self, tool_call: ToolCall) -> ToolSchemaT:
|
|
50
68
|
"""Get a tool that can execute a specific tool call.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""Type aliases for tool parameter types used in provider signatures."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Sequence
|
|
6
|
+
from typing import TypeAlias
|
|
7
|
+
from typing_extensions import TypeAliasType
|
|
8
|
+
|
|
9
|
+
from ..context import DepsT
|
|
10
|
+
from .provider_tools import ProviderTool
|
|
11
|
+
from .tool_schema import AnyToolSchema
|
|
12
|
+
from .toolkit import (
|
|
13
|
+
AsyncContextToolkit,
|
|
14
|
+
AsyncToolkit,
|
|
15
|
+
BaseToolkit,
|
|
16
|
+
ContextToolkit,
|
|
17
|
+
Toolkit,
|
|
18
|
+
)
|
|
19
|
+
from .tools import AsyncContextTool, AsyncTool, ContextTool, Tool
|
|
20
|
+
|
|
21
|
+
AnyTools: TypeAlias = (
|
|
22
|
+
Sequence[AnyToolSchema | ProviderTool] | BaseToolkit[AnyToolSchema]
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
Tools: TypeAlias = Sequence[Tool | ProviderTool] | Toolkit
|
|
26
|
+
"""Type alias for sync tool parameters: a sequence of Tools or a Toolkit."""
|
|
27
|
+
|
|
28
|
+
AsyncTools: TypeAlias = Sequence[AsyncTool | ProviderTool] | AsyncToolkit
|
|
29
|
+
"""Type alias for async tool parameters: a sequence of AsyncTools or an AsyncToolkit."""
|
|
30
|
+
|
|
31
|
+
ContextTools = TypeAliasType(
|
|
32
|
+
"ContextTools",
|
|
33
|
+
Sequence[Tool | ContextTool[DepsT] | ProviderTool] | ContextToolkit[DepsT],
|
|
34
|
+
type_params=(DepsT,),
|
|
35
|
+
)
|
|
36
|
+
"""Type alias for sync context tool parameters: a sequence of Tools/ContextTools or a ContextToolkit."""
|
|
37
|
+
|
|
38
|
+
AsyncContextTools = TypeAliasType(
|
|
39
|
+
"AsyncContextTools",
|
|
40
|
+
Sequence[AsyncTool | AsyncContextTool[DepsT] | ProviderTool]
|
|
41
|
+
| AsyncContextToolkit[DepsT],
|
|
42
|
+
type_params=(DepsT,),
|
|
43
|
+
)
|
|
44
|
+
"""Type alias for async context tool parameters: a sequence of AsyncTools/AsyncContextTools or an AsyncContextToolkit."""
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def normalize_tools(tools: Tools | None) -> Toolkit:
|
|
48
|
+
"""Normalize tools input to a Toolkit.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
tools: A sequence of Tools, a Toolkit, or None.
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
A Toolkit containing the tools (or an empty Toolkit if None).
|
|
55
|
+
"""
|
|
56
|
+
if tools is None:
|
|
57
|
+
return Toolkit(None)
|
|
58
|
+
if isinstance(tools, Toolkit):
|
|
59
|
+
return tools
|
|
60
|
+
return Toolkit(tools)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def normalize_async_tools(tools: AsyncTools | None) -> AsyncToolkit:
|
|
64
|
+
"""Normalize async tools input to an AsyncToolkit.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
tools: A sequence of AsyncTools, an AsyncToolkit, or None.
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
An AsyncToolkit containing the tools (or an empty AsyncToolkit if None).
|
|
71
|
+
"""
|
|
72
|
+
if tools is None:
|
|
73
|
+
return AsyncToolkit(None)
|
|
74
|
+
if isinstance(tools, AsyncToolkit):
|
|
75
|
+
return tools
|
|
76
|
+
return AsyncToolkit(tools)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def normalize_context_tools(
|
|
80
|
+
tools: ContextTools[DepsT] | None,
|
|
81
|
+
) -> ContextToolkit[DepsT]:
|
|
82
|
+
"""Normalize context tools input to a ContextToolkit.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
tools: A sequence of Tools/ContextTools, a ContextToolkit, or None.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
A ContextToolkit containing the tools (or an empty ContextToolkit if None).
|
|
89
|
+
"""
|
|
90
|
+
if tools is None:
|
|
91
|
+
return ContextToolkit(None)
|
|
92
|
+
if isinstance(tools, ContextToolkit):
|
|
93
|
+
return tools
|
|
94
|
+
return ContextToolkit(tools)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def normalize_async_context_tools(
|
|
98
|
+
tools: AsyncContextTools[DepsT] | None,
|
|
99
|
+
) -> AsyncContextToolkit[DepsT]:
|
|
100
|
+
"""Normalize async context tools input to an AsyncContextToolkit.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
tools: A sequence of AsyncTools/AsyncContextTools, an AsyncContextToolkit, or None.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
An AsyncContextToolkit containing the tools (or an empty AsyncContextToolkit if None).
|
|
107
|
+
"""
|
|
108
|
+
if tools is None:
|
|
109
|
+
return AsyncContextToolkit(None)
|
|
110
|
+
if isinstance(tools, AsyncContextToolkit):
|
|
111
|
+
return tools
|
|
112
|
+
return AsyncContextToolkit(tools)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Web search tool for provider-native web search capabilities."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
|
|
5
|
+
from .provider_tools import ProviderTool
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass(frozen=True)
|
|
9
|
+
class WebSearchTool(ProviderTool):
|
|
10
|
+
"""Web search tool that allows the model to search the internet.
|
|
11
|
+
|
|
12
|
+
This is a provider tool - the search is executed server-side by the provider,
|
|
13
|
+
not by your code. The model decides when to search based on the prompt,
|
|
14
|
+
and the provider returns search results with citations.
|
|
15
|
+
|
|
16
|
+
Supported providers include Anthropic, Google, and OpenAI (when using the Responses API).
|
|
17
|
+
|
|
18
|
+
Example:
|
|
19
|
+
```python
|
|
20
|
+
from mirascope import llm
|
|
21
|
+
|
|
22
|
+
@llm.call("anthropic/claude-sonnet-4-5", tools=[llm.WebSearchTool()])
|
|
23
|
+
def search_web(query: str) -> str:
|
|
24
|
+
return f"Search the web for: {query}"
|
|
25
|
+
|
|
26
|
+
response = search_web("Who won the 2024 Super Bowl?")
|
|
27
|
+
print(response.text()) # Response includes citations from web search
|
|
28
|
+
```
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
name: str = field(default="web_search", init=False)
|
|
32
|
+
"""The tool name. Always "web_search" for this tool type."""
|
mirascope/ops/__init__.py
CHANGED
|
@@ -12,9 +12,18 @@ stub_module_if_missing("mirascope.ops", "ops")
|
|
|
12
12
|
# ruff: noqa: E402
|
|
13
13
|
from ._internal.configuration import configure, tracer_context
|
|
14
14
|
from ._internal.context import propagated_context
|
|
15
|
-
from ._internal.instrumentation
|
|
15
|
+
from ._internal.instrumentation import (
|
|
16
|
+
instrument_anthropic,
|
|
17
|
+
instrument_google_genai,
|
|
16
18
|
instrument_llm,
|
|
19
|
+
instrument_openai,
|
|
20
|
+
is_anthropic_instrumented,
|
|
21
|
+
is_google_genai_instrumented,
|
|
22
|
+
is_openai_instrumented,
|
|
23
|
+
uninstrument_anthropic,
|
|
24
|
+
uninstrument_google_genai,
|
|
17
25
|
uninstrument_llm,
|
|
26
|
+
uninstrument_openai,
|
|
18
27
|
)
|
|
19
28
|
from ._internal.propagation import (
|
|
20
29
|
ContextPropagator,
|
|
@@ -99,13 +108,22 @@ __all__ = [
|
|
|
99
108
|
"extract_session_id",
|
|
100
109
|
"get_propagator",
|
|
101
110
|
"inject_context",
|
|
111
|
+
"instrument_anthropic",
|
|
112
|
+
"instrument_google_genai",
|
|
102
113
|
"instrument_llm",
|
|
114
|
+
"instrument_openai",
|
|
115
|
+
"is_anthropic_instrumented",
|
|
116
|
+
"is_google_genai_instrumented",
|
|
117
|
+
"is_openai_instrumented",
|
|
103
118
|
"propagated_context",
|
|
104
119
|
"reset_propagator",
|
|
105
120
|
"session",
|
|
106
121
|
"span",
|
|
107
122
|
"trace",
|
|
108
123
|
"tracer_context",
|
|
124
|
+
"uninstrument_anthropic",
|
|
125
|
+
"uninstrument_google_genai",
|
|
109
126
|
"uninstrument_llm",
|
|
127
|
+
"uninstrument_openai",
|
|
110
128
|
"version",
|
|
111
129
|
]
|
|
@@ -1,8 +1,28 @@
|
|
|
1
1
|
"""Instrumentation modules for various frameworks and libraries."""
|
|
2
2
|
|
|
3
3
|
from .llm import instrument_llm, uninstrument_llm
|
|
4
|
+
from .providers import (
|
|
5
|
+
instrument_anthropic,
|
|
6
|
+
instrument_google_genai,
|
|
7
|
+
instrument_openai,
|
|
8
|
+
is_anthropic_instrumented,
|
|
9
|
+
is_google_genai_instrumented,
|
|
10
|
+
is_openai_instrumented,
|
|
11
|
+
uninstrument_anthropic,
|
|
12
|
+
uninstrument_google_genai,
|
|
13
|
+
uninstrument_openai,
|
|
14
|
+
)
|
|
4
15
|
|
|
5
16
|
__all__ = [
|
|
17
|
+
"instrument_anthropic",
|
|
18
|
+
"instrument_google_genai",
|
|
6
19
|
"instrument_llm",
|
|
20
|
+
"instrument_openai",
|
|
21
|
+
"is_anthropic_instrumented",
|
|
22
|
+
"is_google_genai_instrumented",
|
|
23
|
+
"is_openai_instrumented",
|
|
24
|
+
"uninstrument_anthropic",
|
|
25
|
+
"uninstrument_google_genai",
|
|
7
26
|
"uninstrument_llm",
|
|
27
|
+
"uninstrument_openai",
|
|
8
28
|
]
|
|
@@ -17,10 +17,11 @@ from opentelemetry.semconv.attributes import error_attributes as ErrorAttributes
|
|
|
17
17
|
from opentelemetry.trace import SpanKind, Status, StatusCode
|
|
18
18
|
|
|
19
19
|
from .....llm import (
|
|
20
|
-
|
|
20
|
+
AnyTools,
|
|
21
21
|
AnyToolSchema,
|
|
22
22
|
BaseToolkit,
|
|
23
23
|
Format,
|
|
24
|
+
FormatSpec,
|
|
24
25
|
FormattableT,
|
|
25
26
|
Jsonable,
|
|
26
27
|
Message,
|
|
@@ -28,9 +29,9 @@ from .....llm import (
|
|
|
28
29
|
ModelId,
|
|
29
30
|
Params,
|
|
30
31
|
ProviderId,
|
|
32
|
+
ProviderTool,
|
|
31
33
|
RootResponse,
|
|
32
34
|
ToolkitT,
|
|
33
|
-
ToolSchema,
|
|
34
35
|
)
|
|
35
36
|
from ...configuration import get_tracer
|
|
36
37
|
from ...utils import json_dumps
|
|
@@ -45,6 +46,7 @@ from .serialize import (
|
|
|
45
46
|
serialize_mirascope_cost,
|
|
46
47
|
serialize_mirascope_messages,
|
|
47
48
|
serialize_mirascope_usage,
|
|
49
|
+
serialize_tools,
|
|
48
50
|
)
|
|
49
51
|
|
|
50
52
|
logger = logging.getLogger(__name__)
|
|
@@ -64,10 +66,7 @@ else:
|
|
|
64
66
|
Tracer = None
|
|
65
67
|
|
|
66
68
|
|
|
67
|
-
|
|
68
|
-
Sequence[ToolSchema[AnyToolFn]] | BaseToolkit[AnyToolSchema] | None
|
|
69
|
-
)
|
|
70
|
-
FormatParam: TypeAlias = Format[FormattableT] | None
|
|
69
|
+
FormatParam: TypeAlias = FormatSpec[FormattableT] | None
|
|
71
70
|
ParamsDict: TypeAlias = Mapping[str, str | int | float | bool | Sequence[str] | None]
|
|
72
71
|
SpanAttributes: TypeAlias = Mapping[str, AttributeValue]
|
|
73
72
|
AttributeSetter: TypeAlias = Callable[[str, AttributeValue], None]
|
|
@@ -180,53 +179,13 @@ def _assign_request_message_attributes(
|
|
|
180
179
|
)
|
|
181
180
|
|
|
182
181
|
|
|
183
|
-
def _collect_tool_schemas(
|
|
184
|
-
tools: Sequence[ToolSchema[AnyToolFn]] | BaseToolkit[AnyToolSchema],
|
|
185
|
-
) -> list[ToolSchema[AnyToolFn]]:
|
|
186
|
-
"""Collect ToolSchema instances from a tools parameter."""
|
|
187
|
-
iterable = list(tools.tools) if isinstance(tools, BaseToolkit) else list(tools)
|
|
188
|
-
schemas: list[ToolSchema[AnyToolFn]] = []
|
|
189
|
-
for tool in iterable:
|
|
190
|
-
if isinstance(tool, ToolSchema):
|
|
191
|
-
schemas.append(tool)
|
|
192
|
-
return schemas
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
def _serialize_tool_definitions(
|
|
196
|
-
tools: ToolsParam,
|
|
197
|
-
format: FormatParam = None,
|
|
198
|
-
) -> str | None:
|
|
199
|
-
"""Serialize tool definitions to JSON for span attributes."""
|
|
200
|
-
if tools is None:
|
|
201
|
-
tool_schemas: list[ToolSchema[AnyToolFn]] = []
|
|
202
|
-
else:
|
|
203
|
-
tool_schemas = _collect_tool_schemas(tools)
|
|
204
|
-
|
|
205
|
-
if isinstance(format, Format) and format.mode == "tool":
|
|
206
|
-
tool_schemas.append(format.create_tool_schema())
|
|
207
|
-
|
|
208
|
-
if not tool_schemas:
|
|
209
|
-
return None
|
|
210
|
-
definitions: list[dict[str, str | int | bool | dict[str, str | int | bool]]] = []
|
|
211
|
-
for tool in tool_schemas:
|
|
212
|
-
tool_def: dict[str, str | int | bool | dict[str, str | int | bool]] = {
|
|
213
|
-
"name": tool.name,
|
|
214
|
-
"description": tool.description,
|
|
215
|
-
"parameters": tool.parameters.model_dump(by_alias=True, mode="json"),
|
|
216
|
-
}
|
|
217
|
-
if tool.strict is not None:
|
|
218
|
-
tool_def["strict"] = tool.strict
|
|
219
|
-
definitions.append(tool_def)
|
|
220
|
-
return json_dumps(definitions)
|
|
221
|
-
|
|
222
|
-
|
|
223
182
|
def _build_request_attributes(
|
|
224
183
|
*,
|
|
225
184
|
operation: str,
|
|
226
185
|
provider: ProviderId,
|
|
227
186
|
model_id: ModelId,
|
|
228
187
|
messages: Sequence[Message],
|
|
229
|
-
tools:
|
|
188
|
+
tools: AnyTools | None,
|
|
230
189
|
format: FormatParam,
|
|
231
190
|
params: ParamsDict,
|
|
232
191
|
) -> dict[str, AttributeValue]:
|
|
@@ -244,7 +203,18 @@ def _build_request_attributes(
|
|
|
244
203
|
messages=messages,
|
|
245
204
|
)
|
|
246
205
|
|
|
247
|
-
|
|
206
|
+
tool_schemas: list[AnyToolSchema | ProviderTool] = []
|
|
207
|
+
if tools is None:
|
|
208
|
+
tool_schemas = []
|
|
209
|
+
elif isinstance(tools, BaseToolkit):
|
|
210
|
+
tool_schemas = list(tools.tools)
|
|
211
|
+
else:
|
|
212
|
+
tool_schemas = list(tools)
|
|
213
|
+
|
|
214
|
+
if isinstance(format, Format) and format.mode == "tool":
|
|
215
|
+
tool_schemas.append(format.create_tool_schema())
|
|
216
|
+
|
|
217
|
+
tool_payload = serialize_tools(tool_schemas)
|
|
248
218
|
if tool_payload:
|
|
249
219
|
# The incubating semconv module does not yet expose a constant for this key.
|
|
250
220
|
attrs["gen_ai.tool.definitions"] = tool_payload
|
|
@@ -477,7 +447,7 @@ def start_model_span(
|
|
|
477
447
|
model: Model,
|
|
478
448
|
*,
|
|
479
449
|
messages: Sequence[Message],
|
|
480
|
-
tools:
|
|
450
|
+
tools: AnyTools | None,
|
|
481
451
|
format: FormatParam,
|
|
482
452
|
activate: bool = True,
|
|
483
453
|
) -> Iterator[SpanContext]:
|