monocle-apptrace 0.4.2__py3-none-any.whl → 0.5.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.
Potentially problematic release.
This version of monocle-apptrace might be problematic. Click here for more details.
- monocle_apptrace/__main__.py +1 -1
- monocle_apptrace/exporters/file_exporter.py +125 -37
- monocle_apptrace/instrumentation/common/__init__.py +16 -1
- monocle_apptrace/instrumentation/common/constants.py +14 -1
- monocle_apptrace/instrumentation/common/instrumentor.py +19 -152
- monocle_apptrace/instrumentation/common/method_wrappers.py +376 -0
- monocle_apptrace/instrumentation/common/span_handler.py +58 -32
- monocle_apptrace/instrumentation/common/utils.py +52 -15
- monocle_apptrace/instrumentation/common/wrapper.py +124 -18
- monocle_apptrace/instrumentation/common/wrapper_method.py +47 -1
- monocle_apptrace/instrumentation/metamodel/a2a/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/a2a/_helper.py +37 -0
- monocle_apptrace/instrumentation/metamodel/a2a/entities/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/a2a/entities/inference.py +112 -0
- monocle_apptrace/instrumentation/metamodel/a2a/methods.py +22 -0
- monocle_apptrace/instrumentation/metamodel/adk/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/adk/_helper.py +182 -0
- monocle_apptrace/instrumentation/metamodel/adk/entities/agent.py +50 -0
- monocle_apptrace/instrumentation/metamodel/adk/entities/tool.py +57 -0
- monocle_apptrace/instrumentation/metamodel/adk/methods.py +24 -0
- monocle_apptrace/instrumentation/metamodel/agents/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/agents/_helper.py +220 -0
- monocle_apptrace/instrumentation/metamodel/agents/agents_processor.py +152 -0
- monocle_apptrace/instrumentation/metamodel/agents/entities/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/agents/entities/inference.py +191 -0
- monocle_apptrace/instrumentation/metamodel/agents/methods.py +56 -0
- monocle_apptrace/instrumentation/metamodel/aiohttp/_helper.py +6 -11
- monocle_apptrace/instrumentation/metamodel/anthropic/_helper.py +112 -18
- monocle_apptrace/instrumentation/metamodel/anthropic/entities/inference.py +18 -10
- monocle_apptrace/instrumentation/metamodel/azfunc/_helper.py +13 -11
- monocle_apptrace/instrumentation/metamodel/azfunc/entities/http.py +5 -0
- monocle_apptrace/instrumentation/metamodel/azureaiinference/_helper.py +88 -8
- monocle_apptrace/instrumentation/metamodel/azureaiinference/entities/inference.py +22 -8
- monocle_apptrace/instrumentation/metamodel/botocore/_helper.py +92 -16
- monocle_apptrace/instrumentation/metamodel/botocore/entities/inference.py +13 -8
- monocle_apptrace/instrumentation/metamodel/botocore/handlers/botocore_span_handler.py +1 -1
- monocle_apptrace/instrumentation/metamodel/fastapi/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/fastapi/_helper.py +82 -0
- monocle_apptrace/instrumentation/metamodel/fastapi/entities/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/fastapi/entities/http.py +44 -0
- monocle_apptrace/instrumentation/metamodel/fastapi/methods.py +23 -0
- monocle_apptrace/instrumentation/metamodel/finish_types.py +463 -0
- monocle_apptrace/instrumentation/metamodel/flask/_helper.py +6 -11
- monocle_apptrace/instrumentation/metamodel/gemini/_helper.py +51 -7
- monocle_apptrace/instrumentation/metamodel/gemini/entities/inference.py +22 -11
- monocle_apptrace/instrumentation/metamodel/gemini/entities/retrieval.py +43 -0
- monocle_apptrace/instrumentation/metamodel/gemini/methods.py +18 -1
- monocle_apptrace/instrumentation/metamodel/haystack/_helper.py +79 -8
- monocle_apptrace/instrumentation/metamodel/haystack/entities/inference.py +15 -10
- monocle_apptrace/instrumentation/metamodel/haystack/methods.py +7 -0
- monocle_apptrace/instrumentation/metamodel/lambdafunc/_helper.py +78 -0
- monocle_apptrace/instrumentation/metamodel/lambdafunc/entities/http.py +51 -0
- monocle_apptrace/instrumentation/metamodel/lambdafunc/methods.py +23 -0
- monocle_apptrace/instrumentation/metamodel/lambdafunc/wrapper.py +23 -0
- monocle_apptrace/instrumentation/metamodel/langchain/_helper.py +145 -19
- monocle_apptrace/instrumentation/metamodel/langchain/entities/inference.py +19 -10
- monocle_apptrace/instrumentation/metamodel/langgraph/_helper.py +67 -10
- monocle_apptrace/instrumentation/metamodel/langgraph/entities/inference.py +127 -20
- monocle_apptrace/instrumentation/metamodel/langgraph/langgraph_processor.py +46 -0
- monocle_apptrace/instrumentation/metamodel/langgraph/methods.py +35 -9
- monocle_apptrace/instrumentation/metamodel/litellm/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/litellm/_helper.py +89 -0
- monocle_apptrace/instrumentation/metamodel/litellm/entities/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/litellm/entities/inference.py +108 -0
- monocle_apptrace/instrumentation/metamodel/litellm/methods.py +19 -0
- monocle_apptrace/instrumentation/metamodel/llamaindex/_helper.py +227 -16
- monocle_apptrace/instrumentation/metamodel/llamaindex/entities/agent.py +127 -10
- monocle_apptrace/instrumentation/metamodel/llamaindex/entities/inference.py +13 -8
- monocle_apptrace/instrumentation/metamodel/llamaindex/llamaindex_processor.py +62 -0
- monocle_apptrace/instrumentation/metamodel/llamaindex/methods.py +68 -1
- monocle_apptrace/instrumentation/metamodel/mcp/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/mcp/_helper.py +118 -0
- monocle_apptrace/instrumentation/metamodel/mcp/entities/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/mcp/entities/inference.py +48 -0
- monocle_apptrace/instrumentation/metamodel/mcp/mcp_processor.py +8 -0
- monocle_apptrace/instrumentation/metamodel/mcp/methods.py +21 -0
- monocle_apptrace/instrumentation/metamodel/openai/_helper.py +188 -16
- monocle_apptrace/instrumentation/metamodel/openai/entities/inference.py +148 -92
- monocle_apptrace/instrumentation/metamodel/openai/entities/retrieval.py +1 -1
- monocle_apptrace/instrumentation/metamodel/teamsai/_helper.py +53 -23
- monocle_apptrace/instrumentation/metamodel/teamsai/entities/inference/actionplanner_output_processor.py +1 -1
- monocle_apptrace/instrumentation/metamodel/teamsai/entities/inference/teamsai_output_processor.py +15 -9
- monocle_apptrace/instrumentation/metamodel/teamsai/sample.json +0 -4
- {monocle_apptrace-0.4.2.dist-info → monocle_apptrace-0.5.0.dist-info}/METADATA +27 -11
- {monocle_apptrace-0.4.2.dist-info → monocle_apptrace-0.5.0.dist-info}/RECORD +88 -47
- {monocle_apptrace-0.4.2.dist-info → monocle_apptrace-0.5.0.dist-info}/WHEEL +0 -0
- {monocle_apptrace-0.4.2.dist-info → monocle_apptrace-0.5.0.dist-info}/licenses/LICENSE +0 -0
- {monocle_apptrace-0.4.2.dist-info → monocle_apptrace-0.5.0.dist-info}/licenses/NOTICE +0 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
from monocle_apptrace.instrumentation.metamodel.agents import _helper
|
|
2
|
+
|
|
3
|
+
AGENT = {
|
|
4
|
+
"type": "agentic.invocation",
|
|
5
|
+
"attributes": [
|
|
6
|
+
[
|
|
7
|
+
{
|
|
8
|
+
"_comment": "agent type",
|
|
9
|
+
"attribute": "type",
|
|
10
|
+
"accessor": lambda arguments: _helper.AGENTS_AGENT_NAME_KEY,
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"_comment": "name of the agent",
|
|
14
|
+
"attribute": "name",
|
|
15
|
+
"accessor": lambda arguments: _helper.get_agent_name(arguments),
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"_comment": "agent description",
|
|
19
|
+
"attribute": "description",
|
|
20
|
+
"accessor": lambda arguments: _helper.get_agent_description(arguments),
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"_comment": "agent instructions",
|
|
24
|
+
"attribute": "instructions",
|
|
25
|
+
"accessor": lambda arguments: _helper.get_agent_instructions(arguments),
|
|
26
|
+
},
|
|
27
|
+
]
|
|
28
|
+
],
|
|
29
|
+
"events": [
|
|
30
|
+
{
|
|
31
|
+
"name": "data.input",
|
|
32
|
+
"attributes": [
|
|
33
|
+
{
|
|
34
|
+
"_comment": "this is Agent input",
|
|
35
|
+
"attribute": "query",
|
|
36
|
+
"accessor": lambda arguments: _helper.extract_agent_input(
|
|
37
|
+
arguments
|
|
38
|
+
),
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"name": "data.output",
|
|
44
|
+
"attributes": [
|
|
45
|
+
{
|
|
46
|
+
"_comment": "this is response from Agent",
|
|
47
|
+
"attribute": "response",
|
|
48
|
+
"accessor": lambda arguments: _helper.extract_agent_response(
|
|
49
|
+
arguments["result"]
|
|
50
|
+
),
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"name": "metadata",
|
|
56
|
+
"attributes": [
|
|
57
|
+
{
|
|
58
|
+
"_comment": "this is metadata from Agent response",
|
|
59
|
+
"accessor": lambda arguments: _helper.update_span_from_agent_response(
|
|
60
|
+
arguments["result"]
|
|
61
|
+
),
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
AGENT_REQUEST = {
|
|
69
|
+
"type": "agentic.request",
|
|
70
|
+
"attributes": [
|
|
71
|
+
[
|
|
72
|
+
{
|
|
73
|
+
"_comment": "agent type",
|
|
74
|
+
"attribute": "type",
|
|
75
|
+
"accessor": lambda arguments: _helper.AGENTS_AGENT_NAME_KEY,
|
|
76
|
+
}
|
|
77
|
+
],
|
|
78
|
+
],
|
|
79
|
+
"events": [
|
|
80
|
+
{
|
|
81
|
+
"name": "data.input",
|
|
82
|
+
"attributes": [
|
|
83
|
+
{
|
|
84
|
+
"_comment": "this is Agent input",
|
|
85
|
+
"attribute": "input",
|
|
86
|
+
"accessor": lambda arguments: _helper.extract_agent_input(
|
|
87
|
+
arguments
|
|
88
|
+
),
|
|
89
|
+
}
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"name": "data.output",
|
|
94
|
+
"attributes": [
|
|
95
|
+
{
|
|
96
|
+
"_comment": "this is response from Agent",
|
|
97
|
+
"attribute": "response",
|
|
98
|
+
"accessor": lambda arguments: _helper.extract_agent_response(
|
|
99
|
+
arguments["result"]
|
|
100
|
+
),
|
|
101
|
+
}
|
|
102
|
+
],
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
TOOLS = {
|
|
108
|
+
"type": "agentic.tool.invocation",
|
|
109
|
+
"attributes": [
|
|
110
|
+
[
|
|
111
|
+
{
|
|
112
|
+
"_comment": "tool type",
|
|
113
|
+
"attribute": "type",
|
|
114
|
+
"accessor": lambda arguments: "tool.openai_agents",
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"_comment": "name of the tool",
|
|
118
|
+
"attribute": "name",
|
|
119
|
+
"accessor": lambda arguments: _helper.get_tool_name(
|
|
120
|
+
arguments["instance"]
|
|
121
|
+
),
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"_comment": "tool description",
|
|
125
|
+
"attribute": "description",
|
|
126
|
+
"accessor": lambda arguments: _helper.get_tool_description(
|
|
127
|
+
arguments["instance"]
|
|
128
|
+
),
|
|
129
|
+
},
|
|
130
|
+
],
|
|
131
|
+
[
|
|
132
|
+
{
|
|
133
|
+
"_comment": "name of the agent",
|
|
134
|
+
"attribute": "name",
|
|
135
|
+
"accessor": lambda arguments: _helper.get_source_agent(),
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"_comment": "agent type",
|
|
139
|
+
"attribute": "type",
|
|
140
|
+
"accessor": lambda arguments: _helper.AGENTS_AGENT_NAME_KEY,
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
],
|
|
144
|
+
"events": [
|
|
145
|
+
{
|
|
146
|
+
"name": "data.input",
|
|
147
|
+
"attributes": [
|
|
148
|
+
{
|
|
149
|
+
"_comment": "this is Tool input",
|
|
150
|
+
"attribute": "Inputs",
|
|
151
|
+
"accessor": lambda arguments: _helper.extract_tool_input(arguments),
|
|
152
|
+
},
|
|
153
|
+
],
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"name": "data.output",
|
|
157
|
+
"attributes": [
|
|
158
|
+
{
|
|
159
|
+
"_comment": "this is response from Tool",
|
|
160
|
+
"attribute": "response",
|
|
161
|
+
"accessor": lambda arguments: _helper.extract_tool_response(
|
|
162
|
+
arguments["result"]
|
|
163
|
+
),
|
|
164
|
+
}
|
|
165
|
+
],
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
AGENT_DELEGATION = {
|
|
171
|
+
"type": "agentic.delegation",
|
|
172
|
+
"attributes": [
|
|
173
|
+
[
|
|
174
|
+
{
|
|
175
|
+
"_comment": "agent type",
|
|
176
|
+
"attribute": "type",
|
|
177
|
+
"accessor": lambda arguments: _helper.AGENTS_AGENT_NAME_KEY,
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"_comment": "name of the source agent",
|
|
181
|
+
"attribute": "from_agent",
|
|
182
|
+
"accessor": lambda arguments: _helper.get_source_agent(),
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"_comment": "name of the target agent",
|
|
186
|
+
"attribute": "to_agent",
|
|
187
|
+
"accessor": lambda arguments: _helper.extract_handoff_target(arguments),
|
|
188
|
+
},
|
|
189
|
+
]
|
|
190
|
+
],
|
|
191
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from monocle_apptrace.instrumentation.common.wrapper import task_wrapper, atask_wrapper
|
|
2
|
+
from monocle_apptrace.instrumentation.metamodel.agents.entities.inference import (
|
|
3
|
+
AGENT,
|
|
4
|
+
AGENT_DELEGATION,
|
|
5
|
+
TOOLS,
|
|
6
|
+
)
|
|
7
|
+
from monocle_apptrace.instrumentation.metamodel.agents.agents_processor import (
|
|
8
|
+
constructor_wrapper,
|
|
9
|
+
handoff_constructor_wrapper,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
AGENTS_METHODS = [
|
|
13
|
+
# Main agent runner methods
|
|
14
|
+
{
|
|
15
|
+
"package": "agents.run",
|
|
16
|
+
"object": "Runner",
|
|
17
|
+
"method": "run",
|
|
18
|
+
"wrapper_method": atask_wrapper,
|
|
19
|
+
"span_handler": "agents_agent_handler",
|
|
20
|
+
"output_processor": AGENT,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"package": "agents.run",
|
|
24
|
+
"object": "Runner",
|
|
25
|
+
"method": "run_sync",
|
|
26
|
+
"wrapper_method": task_wrapper,
|
|
27
|
+
"span_handler": "agents_agent_handler",
|
|
28
|
+
"output_processor": AGENT,
|
|
29
|
+
},
|
|
30
|
+
# AgentRunner class methods (internal runner)
|
|
31
|
+
{
|
|
32
|
+
"package": "agents.run",
|
|
33
|
+
"object": "AgentRunner",
|
|
34
|
+
"method": "_run_single_turn",
|
|
35
|
+
"wrapper_method": atask_wrapper,
|
|
36
|
+
"span_handler": "agents_agent_handler",
|
|
37
|
+
"output_processor": AGENT,
|
|
38
|
+
},
|
|
39
|
+
# Function tool decorator - wrap the function_tool function directly
|
|
40
|
+
{
|
|
41
|
+
"package": "agents.tool",
|
|
42
|
+
"object": "FunctionTool",
|
|
43
|
+
"method": "__init__", # Empty string means wrap the function itself
|
|
44
|
+
"wrapper_method": constructor_wrapper,
|
|
45
|
+
"span_handler": "agents_tool_handler",
|
|
46
|
+
"output_processor": TOOLS,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"package": "agents.handoffs",
|
|
50
|
+
"object": "Handoff",
|
|
51
|
+
"method": "__init__", # Empty string means wrap the function itself
|
|
52
|
+
"wrapper_method": handoff_constructor_wrapper,
|
|
53
|
+
"span_handler": "agents_tool_handler",
|
|
54
|
+
"output_processor": AGENT_DELEGATION,
|
|
55
|
+
},
|
|
56
|
+
]
|
|
@@ -7,8 +7,6 @@ from urllib.parse import unquote
|
|
|
7
7
|
|
|
8
8
|
logger = logging.getLogger(__name__)
|
|
9
9
|
MAX_DATA_LENGTH = 1000
|
|
10
|
-
token_data = local()
|
|
11
|
-
token_data.current_token = None
|
|
12
10
|
|
|
13
11
|
def get_route(args) -> str:
|
|
14
12
|
route_path: Option[str] = try_option(getattr, args[0], 'path')
|
|
@@ -41,11 +39,10 @@ def extract_status(result) -> str:
|
|
|
41
39
|
return status
|
|
42
40
|
|
|
43
41
|
def aiohttp_pre_tracing(args):
|
|
44
|
-
|
|
42
|
+
return extract_http_headers(args[0].headers)
|
|
45
43
|
|
|
46
|
-
def aiohttp_post_tracing():
|
|
47
|
-
clear_http_scopes(
|
|
48
|
-
token_data.current_token = None
|
|
44
|
+
def aiohttp_post_tracing(token):
|
|
45
|
+
clear_http_scopes(token)
|
|
49
46
|
|
|
50
47
|
def aiohttp_skip_span(args) -> bool:
|
|
51
48
|
if get_method(args) == "HEAD":
|
|
@@ -55,12 +52,10 @@ def aiohttp_skip_span(args) -> bool:
|
|
|
55
52
|
class aiohttpSpanHandler(SpanHandler):
|
|
56
53
|
|
|
57
54
|
def pre_tracing(self, to_wrap, wrapped, instance, args, kwargs):
|
|
58
|
-
aiohttp_pre_tracing(args)
|
|
59
|
-
return super().pre_tracing(to_wrap, wrapped, instance, args, kwargs)
|
|
55
|
+
return aiohttp_pre_tracing(args)
|
|
60
56
|
|
|
61
|
-
def post_tracing(self, to_wrap, wrapped, instance, args, kwargs, return_value):
|
|
62
|
-
aiohttp_post_tracing()
|
|
63
|
-
return super().post_tracing(to_wrap, wrapped, instance, args, kwargs, return_value)
|
|
57
|
+
def post_tracing(self, to_wrap, wrapped, instance, args, kwargs, return_value, token):
|
|
58
|
+
aiohttp_post_tracing(token)
|
|
64
59
|
|
|
65
60
|
def skip_span(self, to_wrap, wrapped, instance, args, kwargs) -> bool:
|
|
66
61
|
return aiohttp_skip_span(args)
|
|
@@ -3,14 +3,20 @@ This module provides utility functions for extracting system, user,
|
|
|
3
3
|
and assistant messages from various input formats.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
import json
|
|
6
7
|
import logging
|
|
8
|
+
from opentelemetry.context import get_value
|
|
7
9
|
from monocle_apptrace.instrumentation.common.utils import (
|
|
8
10
|
Option,
|
|
11
|
+
get_json_dumps,
|
|
9
12
|
get_keys_as_tuple,
|
|
10
13
|
get_nested_value,
|
|
14
|
+
get_status_code,
|
|
11
15
|
try_option,
|
|
12
16
|
get_exception_message,
|
|
13
17
|
)
|
|
18
|
+
from monocle_apptrace.instrumentation.metamodel.finish_types import map_anthropic_finish_reason_to_finish_type
|
|
19
|
+
from monocle_apptrace.instrumentation.common.constants import AGENT_PREFIX_KEY, INFERENCE_AGENT_DELEGATION, INFERENCE_COMMUNICATION, INFERENCE_TOOL_CALL
|
|
14
20
|
|
|
15
21
|
|
|
16
22
|
logger = logging.getLogger(__name__)
|
|
@@ -30,12 +36,13 @@ def extract_messages(kwargs):
|
|
|
30
36
|
"""Extract system and user messages"""
|
|
31
37
|
try:
|
|
32
38
|
messages = []
|
|
39
|
+
if "system" in kwargs and isinstance(kwargs["system"], str):
|
|
40
|
+
messages.append({"system": kwargs["system"]})
|
|
33
41
|
if 'messages' in kwargs and len(kwargs['messages']) >0:
|
|
34
42
|
for msg in kwargs['messages']:
|
|
35
43
|
if msg.get('content') and msg.get('role'):
|
|
36
44
|
messages.append({msg['role']: msg['content']})
|
|
37
|
-
|
|
38
|
-
return [str(message) for message in messages]
|
|
45
|
+
return [get_json_dumps(message) for message in messages]
|
|
39
46
|
except Exception as e:
|
|
40
47
|
logger.warning("Warning: Error occurred in extract_messages: %s", str(e))
|
|
41
48
|
return []
|
|
@@ -48,28 +55,55 @@ def get_exception_status_code(arguments):
|
|
|
48
55
|
else:
|
|
49
56
|
return 'success'
|
|
50
57
|
|
|
51
|
-
def get_status_code(arguments):
|
|
52
|
-
if arguments["exception"] is not None:
|
|
53
|
-
return get_exception_status_code(arguments)
|
|
54
|
-
elif hasattr(arguments["result"], "status"):
|
|
55
|
-
return arguments["result"].status
|
|
56
|
-
else:
|
|
57
|
-
return 'success'
|
|
58
|
-
|
|
59
58
|
def extract_assistant_message(arguments):
|
|
60
59
|
try:
|
|
61
60
|
status = get_status_code(arguments)
|
|
62
|
-
response
|
|
61
|
+
response = arguments["result"]
|
|
63
62
|
if status == 'success':
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
messages = []
|
|
64
|
+
role = response.role if hasattr(response, 'role') else "assistant"
|
|
65
|
+
|
|
66
|
+
# Handle tool use content blocks
|
|
67
|
+
if hasattr(response, "content") and response.content:
|
|
68
|
+
tools = []
|
|
69
|
+
text_content = []
|
|
70
|
+
|
|
71
|
+
for content_block in response.content:
|
|
72
|
+
if hasattr(content_block, "type"):
|
|
73
|
+
if content_block.type == "tool_use":
|
|
74
|
+
# Extract tool use information
|
|
75
|
+
tool_info = {
|
|
76
|
+
"tool_id": getattr(content_block, "id", ""),
|
|
77
|
+
"tool_name": getattr(content_block, "name", ""),
|
|
78
|
+
"tool_arguments": getattr(content_block, "input", "")
|
|
79
|
+
}
|
|
80
|
+
tools.append(tool_info)
|
|
81
|
+
elif content_block.type == "text":
|
|
82
|
+
# Extract text content
|
|
83
|
+
if hasattr(content_block, "text"):
|
|
84
|
+
text_content.append(content_block.text)
|
|
85
|
+
|
|
86
|
+
# If we have tools, add them to the message
|
|
87
|
+
if tools:
|
|
88
|
+
messages.append({"tools": tools})
|
|
89
|
+
|
|
90
|
+
# If we have text content, add it to the message
|
|
91
|
+
if text_content:
|
|
92
|
+
messages.append({role: " ".join(text_content)})
|
|
93
|
+
|
|
94
|
+
# Fallback to original logic if no content blocks were processed
|
|
95
|
+
if not messages and len(response.content) > 0:
|
|
96
|
+
if hasattr(response.content[0], "text"):
|
|
97
|
+
messages.append({role: response.content[0].text})
|
|
98
|
+
|
|
99
|
+
# Return first message if list is not empty
|
|
100
|
+
return get_json_dumps(messages[0]) if messages else ""
|
|
67
101
|
else:
|
|
68
102
|
if arguments["exception"] is not None:
|
|
69
|
-
|
|
103
|
+
return get_exception_message(arguments)
|
|
70
104
|
elif hasattr(arguments["result"], "error"):
|
|
71
|
-
|
|
72
|
-
|
|
105
|
+
return arguments["result"].error
|
|
106
|
+
|
|
73
107
|
except (IndexError, AttributeError) as e:
|
|
74
108
|
logger.warning("Warning: Error occurred in extract_assistant_message: %s", str(e))
|
|
75
109
|
return None
|
|
@@ -86,4 +120,64 @@ def update_span_from_llm_response(response):
|
|
|
86
120
|
meta_dict.update({"completion_tokens": getattr(response.usage, "output_tokens", 0)})
|
|
87
121
|
meta_dict.update({"prompt_tokens": getattr(response.usage, "input_tokens", 0)})
|
|
88
122
|
meta_dict.update({"total_tokens": getattr(response.usage, "input_tokens", 0)+getattr(response.usage, "output_tokens", 0)})
|
|
89
|
-
return meta_dict
|
|
123
|
+
return meta_dict
|
|
124
|
+
|
|
125
|
+
def extract_finish_reason(arguments):
|
|
126
|
+
"""Extract stop_reason from Anthropic response (Claude)."""
|
|
127
|
+
try:
|
|
128
|
+
# Arguments may be a dict with 'result' or just the response object
|
|
129
|
+
response = arguments.get("result") if isinstance(arguments, dict) else arguments
|
|
130
|
+
if response is not None and hasattr(response, "stop_reason"):
|
|
131
|
+
return response.stop_reason
|
|
132
|
+
except Exception as e:
|
|
133
|
+
logger.warning("Warning: Error occurred in extract_finish_reason: %s", str(e))
|
|
134
|
+
return None
|
|
135
|
+
return None
|
|
136
|
+
|
|
137
|
+
def map_finish_reason_to_finish_type(finish_reason):
|
|
138
|
+
"""Map Anthropic stop_reason to finish_type, similar to OpenAI mapping."""
|
|
139
|
+
return map_anthropic_finish_reason_to_finish_type(finish_reason)
|
|
140
|
+
|
|
141
|
+
def agent_inference_type(arguments):
|
|
142
|
+
"""Extract agent inference type from Anthropic response"""
|
|
143
|
+
try:
|
|
144
|
+
status = get_status_code(arguments)
|
|
145
|
+
if status == 'success' or status == 'completed':
|
|
146
|
+
response = arguments["result"]
|
|
147
|
+
|
|
148
|
+
# Check if stop_reason indicates tool use
|
|
149
|
+
if hasattr(response, "stop_reason") and response.stop_reason == "tool_use":
|
|
150
|
+
# Check if this is agent delegation by looking at tool names
|
|
151
|
+
if hasattr(response, "content") and response.content:
|
|
152
|
+
agent_prefix = get_value(AGENT_PREFIX_KEY)
|
|
153
|
+
for content_block in response.content:
|
|
154
|
+
if (hasattr(content_block, "type") and
|
|
155
|
+
content_block.type == "tool_use" and
|
|
156
|
+
hasattr(content_block, "name")):
|
|
157
|
+
tool_name = content_block.name
|
|
158
|
+
if agent_prefix and tool_name.startswith(agent_prefix):
|
|
159
|
+
return INFERENCE_AGENT_DELEGATION
|
|
160
|
+
# If we found tool use but no agent delegation, it's a regular tool call
|
|
161
|
+
return INFERENCE_TOOL_CALL
|
|
162
|
+
|
|
163
|
+
# Fallback: check the extracted message for tool content
|
|
164
|
+
assistant_message = extract_assistant_message(arguments)
|
|
165
|
+
if assistant_message:
|
|
166
|
+
try:
|
|
167
|
+
message = json.loads(assistant_message)
|
|
168
|
+
if message and isinstance(message, dict):
|
|
169
|
+
assistant_content = message.get("assistant", "")
|
|
170
|
+
if assistant_content:
|
|
171
|
+
agent_prefix = get_value(AGENT_PREFIX_KEY)
|
|
172
|
+
if agent_prefix and agent_prefix in assistant_content:
|
|
173
|
+
return INFERENCE_AGENT_DELEGATION
|
|
174
|
+
except (json.JSONDecodeError, TypeError):
|
|
175
|
+
# If JSON parsing fails, fall back to string analysis
|
|
176
|
+
agent_prefix = get_value(AGENT_PREFIX_KEY)
|
|
177
|
+
if agent_prefix and agent_prefix in assistant_message:
|
|
178
|
+
return INFERENCE_AGENT_DELEGATION
|
|
179
|
+
|
|
180
|
+
return INFERENCE_COMMUNICATION
|
|
181
|
+
except Exception as e:
|
|
182
|
+
logger.warning("Warning: Error occurred in agent_inference_type: %s", str(e))
|
|
183
|
+
return INFERENCE_COMMUNICATION
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
from monocle_apptrace.instrumentation.metamodel.anthropic import (
|
|
2
2
|
_helper,
|
|
3
3
|
)
|
|
4
|
-
from monocle_apptrace.instrumentation.common.utils import (
|
|
5
|
-
get_status, get_status_code
|
|
6
|
-
)
|
|
4
|
+
from monocle_apptrace.instrumentation.common.utils import (get_error_message, resolve_from_alias)
|
|
7
5
|
|
|
8
6
|
INFERENCE = {
|
|
9
7
|
"type": "inference",
|
|
@@ -12,7 +10,7 @@ INFERENCE = {
|
|
|
12
10
|
{
|
|
13
11
|
"_comment": "provider type ,name , deployment , inference_endpoint",
|
|
14
12
|
"attribute": "type",
|
|
15
|
-
"accessor": lambda arguments: 'inference.'
|
|
13
|
+
"accessor": lambda arguments: 'inference.anthropic'
|
|
16
14
|
|
|
17
15
|
},
|
|
18
16
|
{
|
|
@@ -55,12 +53,8 @@ INFERENCE = {
|
|
|
55
53
|
"name": "data.output",
|
|
56
54
|
"attributes": [
|
|
57
55
|
{
|
|
58
|
-
"attribute": "
|
|
59
|
-
"accessor": lambda arguments:
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
"attribute": "status_code",
|
|
63
|
-
"accessor": lambda arguments: _helper.get_status_code(arguments)
|
|
56
|
+
"attribute": "error_code",
|
|
57
|
+
"accessor": lambda arguments: get_error_message(arguments)
|
|
64
58
|
},
|
|
65
59
|
{
|
|
66
60
|
"_comment": "this is result from LLM",
|
|
@@ -75,6 +69,20 @@ INFERENCE = {
|
|
|
75
69
|
{
|
|
76
70
|
"_comment": "this is metadata usage from LLM",
|
|
77
71
|
"accessor": lambda arguments: _helper.update_span_from_llm_response(arguments['result'])
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"_comment": "finish reason from Anthropic response",
|
|
75
|
+
"attribute": "finish_reason",
|
|
76
|
+
"accessor": lambda arguments: _helper.extract_finish_reason(arguments)
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"_comment": "finish type mapped from finish reason",
|
|
80
|
+
"attribute": "finish_type",
|
|
81
|
+
"accessor": lambda arguments: _helper.map_finish_reason_to_finish_type(_helper.extract_finish_reason(arguments))
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"attribute": "inference_sub_type",
|
|
85
|
+
"accessor": lambda arguments: _helper.agent_inference_type(arguments)
|
|
78
86
|
}
|
|
79
87
|
]
|
|
80
88
|
}
|
|
@@ -8,8 +8,6 @@ from urllib.parse import unquote, urlparse, ParseResult
|
|
|
8
8
|
|
|
9
9
|
logger = logging.getLogger(__name__)
|
|
10
10
|
MAX_DATA_LENGTH = 1000
|
|
11
|
-
token_data = local()
|
|
12
|
-
token_data.current_token = None
|
|
13
11
|
|
|
14
12
|
def get_url(kwargs) -> ParseResult:
|
|
15
13
|
url_str = try_option(getattr, kwargs['req'], 'url')
|
|
@@ -19,6 +17,13 @@ def get_url(kwargs) -> ParseResult:
|
|
|
19
17
|
else:
|
|
20
18
|
return None
|
|
21
19
|
|
|
20
|
+
def get_function_name(kwargs) -> str:
|
|
21
|
+
context = kwargs.get('context', None)
|
|
22
|
+
if context is not None and hasattr(context, 'function_name'):
|
|
23
|
+
return context.function_name
|
|
24
|
+
return ""
|
|
25
|
+
|
|
26
|
+
|
|
22
27
|
def get_route(kwargs) -> str:
|
|
23
28
|
url:ParseResult = get_url(kwargs)
|
|
24
29
|
if url is not None:
|
|
@@ -61,18 +66,15 @@ def extract_status(result) -> str:
|
|
|
61
66
|
|
|
62
67
|
def azure_func_pre_tracing(kwargs):
|
|
63
68
|
headers = kwargs['req'].headers if hasattr(kwargs['req'], 'headers') else {}
|
|
64
|
-
|
|
69
|
+
return extract_http_headers(headers)
|
|
65
70
|
|
|
66
|
-
def azure_func_post_tracing():
|
|
67
|
-
clear_http_scopes(
|
|
68
|
-
token_data.current_token = None
|
|
71
|
+
def azure_func_post_tracing(token):
|
|
72
|
+
clear_http_scopes(token)
|
|
69
73
|
|
|
70
74
|
class azureSpanHandler(SpanHandler):
|
|
71
75
|
|
|
72
76
|
def pre_tracing(self, to_wrap, wrapped, instance, args, kwargs):
|
|
73
|
-
azure_func_pre_tracing(kwargs)
|
|
74
|
-
return super().pre_tracing(to_wrap, wrapped, instance, args, kwargs)
|
|
77
|
+
return azure_func_pre_tracing(kwargs)
|
|
75
78
|
|
|
76
|
-
def post_tracing(self, to_wrap, wrapped, instance, args, kwargs, return_value):
|
|
77
|
-
azure_func_post_tracing()
|
|
78
|
-
return super().post_tracing(to_wrap, wrapped, instance, args, kwargs, return_value)
|
|
79
|
+
def post_tracing(self, to_wrap, wrapped, instance, args, kwargs, return_value, token):
|
|
80
|
+
azure_func_post_tracing(token)
|
|
@@ -18,6 +18,11 @@ AZFUNC_HTTP_PROCESSOR = {
|
|
|
18
18
|
"attribute": "body",
|
|
19
19
|
"accessor": lambda arguments: _helper.get_body(arguments['kwargs'])
|
|
20
20
|
},
|
|
21
|
+
{
|
|
22
|
+
"_comment": "request function name",
|
|
23
|
+
"attribute": "function_name",
|
|
24
|
+
"accessor": lambda arguments: _helper.get_function_name(arguments['kwargs'])
|
|
25
|
+
}
|
|
21
26
|
]
|
|
22
27
|
],
|
|
23
28
|
"events": [
|