monocle-apptrace 0.5.3__py3-none-any.whl → 0.6.6__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/exporters/file_exporter.py +7 -1
- monocle_apptrace/instrumentation/common/constants.py +8 -0
- monocle_apptrace/instrumentation/common/instrumentor.py +1 -1
- monocle_apptrace/instrumentation/common/span_handler.py +75 -24
- monocle_apptrace/instrumentation/common/utils.py +63 -6
- monocle_apptrace/instrumentation/common/wrapper.py +111 -42
- monocle_apptrace/instrumentation/common/wrapper_method.py +6 -2
- monocle_apptrace/instrumentation/metamodel/a2a/methods.py +1 -1
- monocle_apptrace/instrumentation/metamodel/adk/_helper.py +7 -4
- monocle_apptrace/instrumentation/metamodel/adk/entities/agent.py +6 -1
- monocle_apptrace/instrumentation/metamodel/agents/_helper.py +8 -8
- monocle_apptrace/instrumentation/metamodel/agents/entities/inference.py +9 -2
- monocle_apptrace/instrumentation/metamodel/aiohttp/_helper.py +1 -1
- monocle_apptrace/instrumentation/metamodel/anthropic/entities/inference.py +1 -4
- monocle_apptrace/instrumentation/metamodel/azfunc/_helper.py +1 -1
- monocle_apptrace/instrumentation/metamodel/botocore/_helper.py +5 -0
- monocle_apptrace/instrumentation/metamodel/botocore/entities/inference.py +4 -0
- monocle_apptrace/instrumentation/metamodel/fastapi/_helper.py +4 -4
- monocle_apptrace/instrumentation/metamodel/fastapi/methods.py +4 -4
- monocle_apptrace/instrumentation/metamodel/finish_types.py +32 -1
- monocle_apptrace/instrumentation/metamodel/flask/_helper.py +3 -3
- monocle_apptrace/instrumentation/metamodel/hugging_face/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/hugging_face/_helper.py +138 -0
- monocle_apptrace/instrumentation/metamodel/hugging_face/entities/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/hugging_face/entities/inference.py +94 -0
- monocle_apptrace/instrumentation/metamodel/hugging_face/methods.py +23 -0
- monocle_apptrace/instrumentation/metamodel/lambdafunc/_helper.py +1 -1
- monocle_apptrace/instrumentation/metamodel/langchain/entities/inference.py +1 -4
- monocle_apptrace/instrumentation/metamodel/langgraph/_helper.py +34 -8
- monocle_apptrace/instrumentation/metamodel/langgraph/entities/inference.py +8 -3
- monocle_apptrace/instrumentation/metamodel/langgraph/langgraph_processor.py +88 -19
- monocle_apptrace/instrumentation/metamodel/langgraph/methods.py +22 -6
- monocle_apptrace/instrumentation/metamodel/llamaindex/_helper.py +30 -10
- monocle_apptrace/instrumentation/metamodel/llamaindex/entities/agent.py +4 -3
- monocle_apptrace/instrumentation/metamodel/llamaindex/llamaindex_processor.py +15 -7
- monocle_apptrace/instrumentation/metamodel/llamaindex/methods.py +1 -8
- monocle_apptrace/instrumentation/metamodel/mcp/_helper.py +7 -6
- monocle_apptrace/instrumentation/metamodel/mistral/_helper.py +98 -49
- monocle_apptrace/instrumentation/metamodel/mistral/entities/inference.py +15 -9
- monocle_apptrace/instrumentation/metamodel/mistral/entities/retrieval.py +41 -0
- monocle_apptrace/instrumentation/metamodel/mistral/methods.py +10 -1
- monocle_apptrace/instrumentation/metamodel/openai/_helper.py +47 -7
- monocle_apptrace/instrumentation/metamodel/openai/entities/inference.py +20 -4
- monocle_apptrace/instrumentation/metamodel/openai/methods.py +1 -1
- monocle_apptrace/instrumentation/metamodel/strands/_helper.py +44 -0
- monocle_apptrace/instrumentation/metamodel/strands/entities/agent.py +179 -0
- monocle_apptrace/instrumentation/metamodel/strands/entities/tool.py +62 -0
- monocle_apptrace/instrumentation/metamodel/strands/methods.py +20 -0
- {monocle_apptrace-0.5.3.dist-info → monocle_apptrace-0.6.6.dist-info}/METADATA +23 -79
- {monocle_apptrace-0.5.3.dist-info → monocle_apptrace-0.6.6.dist-info}/RECORD +53 -46
- monocle_apptrace/README.md +0 -101
- monocle_apptrace/mcp_server.py +0 -94
- monocle_apptrace-0.5.3.dist-info/licenses/NOTICE +0 -4
- {monocle_apptrace-0.5.3.dist-info → monocle_apptrace-0.6.6.dist-info}/WHEEL +0 -0
- {monocle_apptrace-0.5.3.dist-info → monocle_apptrace-0.6.6.dist-info}/entry_points.txt +0 -0
- {monocle_apptrace-0.5.3.dist-info → monocle_apptrace-0.6.6.dist-info}/licenses/LICENSE +0 -0
|
@@ -5,6 +5,7 @@ and assistant messages from various input formats.
|
|
|
5
5
|
|
|
6
6
|
import json
|
|
7
7
|
import logging
|
|
8
|
+
from urllib.parse import urlparse
|
|
8
9
|
from opentelemetry.context import get_value
|
|
9
10
|
from monocle_apptrace.instrumentation.common.utils import (
|
|
10
11
|
Option,
|
|
@@ -23,6 +24,12 @@ from monocle_apptrace.instrumentation.common.constants import AGENT_PREFIX_KEY,
|
|
|
23
24
|
|
|
24
25
|
logger = logging.getLogger(__name__)
|
|
25
26
|
|
|
27
|
+
# Mapping of URL substrings to provider names
|
|
28
|
+
URL_MAP = {
|
|
29
|
+
"deepseek.com": "deepseek",
|
|
30
|
+
# add more providers here as needed
|
|
31
|
+
}
|
|
32
|
+
|
|
26
33
|
def extract_messages(kwargs):
|
|
27
34
|
"""Extract system and user messages"""
|
|
28
35
|
try:
|
|
@@ -184,8 +191,19 @@ def extract_assistant_message(arguments):
|
|
|
184
191
|
|
|
185
192
|
|
|
186
193
|
def extract_provider_name(instance):
|
|
194
|
+
# Try to get host from base_url if it's a parsed object
|
|
187
195
|
provider_url: Option[str] = try_option(getattr, instance._client.base_url, 'host')
|
|
188
|
-
|
|
196
|
+
if provider_url.unwrap_or(None) is not None:
|
|
197
|
+
return provider_url.unwrap_or(None)
|
|
198
|
+
|
|
199
|
+
# If base_url is just a string (e.g., "https://api.deepseek.com")
|
|
200
|
+
base_url = getattr(instance._client, "base_url", None)
|
|
201
|
+
if isinstance(base_url, str):
|
|
202
|
+
parsed = urlparse(base_url)
|
|
203
|
+
if parsed.hostname:
|
|
204
|
+
return parsed.hostname
|
|
205
|
+
|
|
206
|
+
return None
|
|
189
207
|
|
|
190
208
|
|
|
191
209
|
def extract_inference_endpoint(instance):
|
|
@@ -248,29 +266,49 @@ def extract_vector_output(vector_output):
|
|
|
248
266
|
return ""
|
|
249
267
|
|
|
250
268
|
def get_inference_type(instance):
|
|
269
|
+
# Check if it's Azure OpenAI first
|
|
251
270
|
inference_type: Option[str] = try_option(getattr, instance._client, '_api_version')
|
|
252
271
|
if inference_type.unwrap_or(None):
|
|
253
272
|
return 'azure_openai'
|
|
254
|
-
|
|
255
|
-
|
|
273
|
+
|
|
274
|
+
# Check based on base_url using the mapping
|
|
275
|
+
base_url = getattr(instance, "base_url", None) or getattr(instance._client, "base_url", None)
|
|
276
|
+
|
|
277
|
+
if base_url:
|
|
278
|
+
base_url_str = str(base_url).lower()
|
|
279
|
+
for key, name in URL_MAP.items():
|
|
280
|
+
if key in base_url_str:
|
|
281
|
+
return name
|
|
282
|
+
|
|
283
|
+
# fallback default
|
|
284
|
+
return "openai"
|
|
256
285
|
|
|
257
286
|
class OpenAISpanHandler(NonFrameworkSpanHandler):
|
|
258
287
|
def is_teams_span_in_progress(self) -> bool:
|
|
259
288
|
return self.is_framework_span_in_progress() and self.get_workflow_name_in_progress() == WORKFLOW_TYPE_MAP["teams.ai"]
|
|
289
|
+
|
|
290
|
+
def is_llamaindex_span_in_progress(self) -> bool:
|
|
291
|
+
return self.is_framework_span_in_progress() and self.get_workflow_name_in_progress() == WORKFLOW_TYPE_MAP["llama_index"]
|
|
260
292
|
|
|
261
|
-
# If openAI is being called by Teams AI SDK
|
|
293
|
+
# If openAI is being called by Teams AI SDK or LlamaIndex, customize event processing
|
|
262
294
|
def skip_processor(self, to_wrap, wrapped, instance, span, args, kwargs) -> list[str]:
|
|
263
295
|
if self.is_teams_span_in_progress():
|
|
264
296
|
return ["attributes", "events.data.input", "events.data.output"]
|
|
297
|
+
elif self.is_llamaindex_span_in_progress():
|
|
298
|
+
# For LlamaIndex, we want to keep all inference span attributes and events
|
|
299
|
+
return []
|
|
265
300
|
else:
|
|
266
301
|
return super().skip_processor(to_wrap, wrapped, instance, span, args, kwargs)
|
|
267
302
|
|
|
268
|
-
def hydrate_events(self, to_wrap, wrapped, instance, args, kwargs, ret_result, span, parent_span=None, ex:Exception=None) -> bool:
|
|
303
|
+
def hydrate_events(self, to_wrap, wrapped, instance, args, kwargs, ret_result, span, parent_span=None, ex:Exception=None, is_post_exec:bool=False) -> bool:
|
|
269
304
|
# If openAI is being called by Teams AI SDK, then copy parent
|
|
270
305
|
if self.is_teams_span_in_progress() and ex is None:
|
|
271
|
-
return super().hydrate_events(to_wrap, wrapped, instance, args, kwargs, ret_result, span=parent_span, parent_span=None, ex=ex)
|
|
306
|
+
return super().hydrate_events(to_wrap, wrapped, instance, args, kwargs, ret_result, span=parent_span, parent_span=None, ex=ex, is_post_exec=is_post_exec)
|
|
307
|
+
# For LlamaIndex, process events normally on the inference span
|
|
308
|
+
elif self.is_llamaindex_span_in_progress():
|
|
309
|
+
return super().hydrate_events(to_wrap, wrapped, instance, args, kwargs, ret_result, span, parent_span=parent_span, ex=ex, is_post_exec=is_post_exec)
|
|
272
310
|
|
|
273
|
-
return super().hydrate_events(to_wrap, wrapped, instance, args, kwargs, ret_result, span, parent_span=parent_span, ex=ex)
|
|
311
|
+
return super().hydrate_events(to_wrap, wrapped, instance, args, kwargs, ret_result, span, parent_span=parent_span, ex=ex, is_post_exec=is_post_exec)
|
|
274
312
|
|
|
275
313
|
def post_task_processing(self, to_wrap, wrapped, instance, args, kwargs, result, ex, span, parent_span):
|
|
276
314
|
# TeamsAI doesn't capture the status and other metadata from underlying OpenAI SDK.
|
|
@@ -316,3 +354,5 @@ def agent_inference_type(arguments):
|
|
|
316
354
|
return INFERENCE_AGENT_DELEGATION
|
|
317
355
|
return INFERENCE_TOOL_CALL
|
|
318
356
|
return INFERENCE_TURN_END
|
|
357
|
+
|
|
358
|
+
|
|
@@ -11,6 +11,7 @@ from monocle_apptrace.instrumentation.common.utils import (
|
|
|
11
11
|
patch_instance_method,
|
|
12
12
|
resolve_from_alias,
|
|
13
13
|
)
|
|
14
|
+
from monocle_apptrace.instrumentation.common.constants import PROVIDER_BASE_URLS
|
|
14
15
|
|
|
15
16
|
logger = logging.getLogger(__name__)
|
|
16
17
|
|
|
@@ -120,6 +121,24 @@ def _create_span_result(state, stream_start_time):
|
|
|
120
121
|
finish_reason=state["finish_reason"],
|
|
121
122
|
)
|
|
122
123
|
|
|
124
|
+
# Registry mapping client detection functions → entity_type
|
|
125
|
+
CLIENT_ENTITY_MAP = {
|
|
126
|
+
"deepseek": "inference.deepseek",
|
|
127
|
+
# add more clients in future
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
def get_entity_type(response, helper=None):
|
|
131
|
+
for client_name, entity in CLIENT_ENTITY_MAP.items():
|
|
132
|
+
check_fn = globals().get(f"is_{client_name}_client")
|
|
133
|
+
if check_fn and check_fn(response):
|
|
134
|
+
return entity
|
|
135
|
+
|
|
136
|
+
# fallback to helper if available
|
|
137
|
+
if helper and hasattr(helper, "get_inference_type"):
|
|
138
|
+
return "inference." + helper.get_inference_type(response)
|
|
139
|
+
|
|
140
|
+
# default fallback
|
|
141
|
+
return "inference.openai"
|
|
123
142
|
|
|
124
143
|
def process_stream(to_wrap, response, span_processor):
|
|
125
144
|
stream_start_time = time.time_ns()
|
|
@@ -167,6 +186,7 @@ def process_stream(to_wrap, response, span_processor):
|
|
|
167
186
|
|
|
168
187
|
INFERENCE = {
|
|
169
188
|
"type": SPAN_TYPES.INFERENCE,
|
|
189
|
+
"subtype": lambda arguments: _helper.agent_inference_type(arguments),
|
|
170
190
|
"is_auto_close": lambda kwargs: kwargs.get("stream", False) is False,
|
|
171
191
|
"response_processor": process_stream,
|
|
172
192
|
"attributes": [
|
|
@@ -276,10 +296,6 @@ INFERENCE = {
|
|
|
276
296
|
"accessor": lambda arguments: _helper.map_finish_reason_to_finish_type(
|
|
277
297
|
_helper.extract_finish_reason(arguments)
|
|
278
298
|
),
|
|
279
|
-
},
|
|
280
|
-
{
|
|
281
|
-
"attribute": "inference_sub_type",
|
|
282
|
-
"accessor": lambda arguments: _helper.agent_inference_type(arguments)
|
|
283
299
|
}
|
|
284
300
|
],
|
|
285
301
|
},
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
|
|
2
|
+
from monocle_apptrace.instrumentation.common.constants import SPAN_TYPES
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def get_agent_name(instance):
|
|
6
|
+
return instance.name
|
|
7
|
+
|
|
8
|
+
def get_agent_description(instance):
|
|
9
|
+
return instance.description
|
|
10
|
+
|
|
11
|
+
def extract_agent_input(arguments):
|
|
12
|
+
return arguments['args'][0]
|
|
13
|
+
|
|
14
|
+
def extract_agent_response(result):
|
|
15
|
+
return result.message['content'][0]['text']
|
|
16
|
+
|
|
17
|
+
def get_tool_type(arguments):
|
|
18
|
+
## TODO: check for MCP type
|
|
19
|
+
return "tool.strands"
|
|
20
|
+
|
|
21
|
+
def get_tool_name(arguments):
|
|
22
|
+
return arguments.get('args')[1][0]['name']
|
|
23
|
+
|
|
24
|
+
def get_tool_description(arguments):
|
|
25
|
+
return arguments.get('args')[1][0]['description']
|
|
26
|
+
|
|
27
|
+
def get_source_agent(arguments):
|
|
28
|
+
return arguments.get('args')[0].name
|
|
29
|
+
|
|
30
|
+
def extract_tool_input(arguments):
|
|
31
|
+
return str(arguments.get('args')[1][0]['input'])
|
|
32
|
+
|
|
33
|
+
def extract_tool_response(result):
|
|
34
|
+
return result.tool_result['content'][0]['text']
|
|
35
|
+
|
|
36
|
+
def should_skip_delegation(arguments):
|
|
37
|
+
if arguments.get('parent_span') and arguments.get('parent_span').attributes.get("span.type") != SPAN_TYPES.AGENTIC_TOOL_INVOCATION:
|
|
38
|
+
return True
|
|
39
|
+
return False
|
|
40
|
+
|
|
41
|
+
def should_skip_request(arguments):
|
|
42
|
+
if arguments.get('parent_span') and arguments.get('parent_span').attributes.get("span.type") in [SPAN_TYPES.AGENTIC_TOOL_INVOCATION, SPAN_TYPES.AGENTIC_REQUEST]:
|
|
43
|
+
return True
|
|
44
|
+
return False
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
from monocle_apptrace.instrumentation.common.constants import AGENT_REQUEST_SPAN_NAME, SPAN_SUBTYPES, SPAN_TYPES
|
|
2
|
+
from monocle_apptrace.instrumentation.metamodel.strands import (
|
|
3
|
+
_helper
|
|
4
|
+
)
|
|
5
|
+
from monocle_apptrace.instrumentation.common.utils import get_error_message
|
|
6
|
+
|
|
7
|
+
AGENT = {
|
|
8
|
+
"type": SPAN_TYPES.AGENTIC_INVOCATION,
|
|
9
|
+
"subtype": SPAN_SUBTYPES.CONTENT_PROCESSING,
|
|
10
|
+
"attributes": [
|
|
11
|
+
[
|
|
12
|
+
{
|
|
13
|
+
"_comment": "agent type",
|
|
14
|
+
"attribute": "type",
|
|
15
|
+
"accessor": lambda arguments:'agent.strands'
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"_comment": "name of the agent",
|
|
19
|
+
"attribute": "name",
|
|
20
|
+
"accessor": lambda arguments: _helper.get_agent_name(arguments['instance'])
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"_comment": "agent description",
|
|
24
|
+
"attribute": "description",
|
|
25
|
+
"accessor": lambda arguments: _helper.get_agent_description(arguments['instance'])
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
],
|
|
29
|
+
"events": [
|
|
30
|
+
{
|
|
31
|
+
"name":"data.input",
|
|
32
|
+
"attributes": [
|
|
33
|
+
{
|
|
34
|
+
"_comment": "this is Agent input",
|
|
35
|
+
"attribute": "input",
|
|
36
|
+
"accessor": lambda arguments: _helper.extract_agent_input(arguments)
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"name":"data.output",
|
|
42
|
+
"attributes": [
|
|
43
|
+
{
|
|
44
|
+
"attribute": "error_code",
|
|
45
|
+
"accessor": lambda arguments: get_error_message(arguments)
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"_comment": "this is response from LLM",
|
|
49
|
+
"attribute": "response",
|
|
50
|
+
"accessor": lambda arguments: _helper.extract_agent_response(arguments['result'])
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
AGENT_REQUEST = {
|
|
58
|
+
"type": SPAN_TYPES.AGENTIC_REQUEST,
|
|
59
|
+
"subtype": SPAN_SUBTYPES.PLANNING,
|
|
60
|
+
"should_skip": lambda arguments: _helper.should_skip_request(arguments),
|
|
61
|
+
"attributes": [
|
|
62
|
+
[
|
|
63
|
+
{
|
|
64
|
+
"_comment": "agent type",
|
|
65
|
+
"attribute": "type",
|
|
66
|
+
"accessor": lambda arguments:'agent.strands'
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
],
|
|
70
|
+
"events": [
|
|
71
|
+
{
|
|
72
|
+
"name":"data.input",
|
|
73
|
+
"attributes": [
|
|
74
|
+
{
|
|
75
|
+
"_comment": "this is Agent input",
|
|
76
|
+
"attribute": "input",
|
|
77
|
+
"accessor": lambda arguments: _helper.extract_agent_input(arguments)
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"name":"data.output",
|
|
83
|
+
"attributes": [
|
|
84
|
+
{
|
|
85
|
+
"attribute": "error_code",
|
|
86
|
+
"accessor": lambda arguments: get_error_message(arguments)
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"_comment": "this is response from LLM",
|
|
90
|
+
"attribute": "response",
|
|
91
|
+
"accessor": lambda arguments: _helper.extract_agent_response(arguments['result'])
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
TOOLS = {
|
|
99
|
+
"type": SPAN_TYPES.AGENTIC_TOOL_INVOCATION,
|
|
100
|
+
"subtype": SPAN_SUBTYPES.ROUTING,
|
|
101
|
+
"attributes": [
|
|
102
|
+
[
|
|
103
|
+
{
|
|
104
|
+
"_comment": "tool type",
|
|
105
|
+
"attribute": "type",
|
|
106
|
+
"accessor": lambda arguments: _helper.get_tool_type(arguments['span'])
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"_comment": "name of the tool",
|
|
110
|
+
"attribute": "name",
|
|
111
|
+
"accessor": lambda arguments: _helper.get_tool_name(arguments['instance'])
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"_comment": "tool description",
|
|
115
|
+
"attribute": "description",
|
|
116
|
+
"accessor": lambda arguments: _helper.get_tool_description(arguments['instance'])
|
|
117
|
+
}
|
|
118
|
+
],
|
|
119
|
+
[
|
|
120
|
+
{
|
|
121
|
+
"_comment": "name of the agent",
|
|
122
|
+
"attribute": "name",
|
|
123
|
+
"accessor": lambda arguments: _helper.get_source_agent()
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"_comment": "agent type",
|
|
127
|
+
"attribute": "type",
|
|
128
|
+
"accessor": lambda arguments:'agent.strands'
|
|
129
|
+
}
|
|
130
|
+
]
|
|
131
|
+
],
|
|
132
|
+
"events": [
|
|
133
|
+
{
|
|
134
|
+
"name":"data.input",
|
|
135
|
+
"attributes": [
|
|
136
|
+
{
|
|
137
|
+
"_comment": "this is Tool input",
|
|
138
|
+
"attribute": "input",
|
|
139
|
+
"accessor": lambda arguments: _helper.extract_tool_input(arguments)
|
|
140
|
+
},
|
|
141
|
+
]
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"name":"data.output",
|
|
145
|
+
"attributes": [
|
|
146
|
+
{
|
|
147
|
+
"_comment": "this is response from Tool",
|
|
148
|
+
"attribute": "response",
|
|
149
|
+
"accessor": lambda arguments: _helper.extract_tool_response(arguments['result'])
|
|
150
|
+
}
|
|
151
|
+
]
|
|
152
|
+
}
|
|
153
|
+
]
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
AGENT_DELEGATION = {
|
|
157
|
+
"type": SPAN_TYPES.AGENTIC_DELEGATION,
|
|
158
|
+
"subtype": SPAN_SUBTYPES.ROUTING,
|
|
159
|
+
"should_skip": lambda arguments: _helper.should_skip_delegation(arguments),
|
|
160
|
+
"attributes": [
|
|
161
|
+
[
|
|
162
|
+
{
|
|
163
|
+
"_comment": "agent type",
|
|
164
|
+
"attribute": "type",
|
|
165
|
+
"accessor": lambda arguments:'agent.strands'
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"_comment": "name of the agent",
|
|
169
|
+
"attribute": "from_agent",
|
|
170
|
+
"accessor": lambda arguments: _helper.get_source_agent()
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"_comment": "name of the agent called",
|
|
174
|
+
"attribute": "to_agent",
|
|
175
|
+
"accessor": lambda arguments: _helper.get_target_agent(arguments['instance'])
|
|
176
|
+
}
|
|
177
|
+
]
|
|
178
|
+
]
|
|
179
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from monocle_apptrace.instrumentation.common.constants import AGENT_REQUEST_SPAN_NAME, SPAN_SUBTYPES, SPAN_TYPES
|
|
2
|
+
from monocle_apptrace.instrumentation.metamodel.strands import (
|
|
3
|
+
_helper
|
|
4
|
+
)
|
|
5
|
+
from monocle_apptrace.instrumentation.common.utils import get_error_message
|
|
6
|
+
TOOL = {
|
|
7
|
+
"type": SPAN_TYPES.AGENTIC_TOOL_INVOCATION,
|
|
8
|
+
"subtype": SPAN_SUBTYPES.CONTENT_GENERATION,
|
|
9
|
+
"attributes": [
|
|
10
|
+
[
|
|
11
|
+
{
|
|
12
|
+
"_comment": "tool type",
|
|
13
|
+
"attribute": "type",
|
|
14
|
+
"accessor": lambda arguments: _helper.get_tool_type(arguments)
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"_comment": "name of the tool",
|
|
18
|
+
"attribute": "name",
|
|
19
|
+
"accessor": lambda arguments: _helper.get_tool_name(arguments)
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"_comment": "tool description",
|
|
23
|
+
"attribute": "description",
|
|
24
|
+
"accessor": lambda arguments: _helper.get_tool_description(arguments)
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
[
|
|
28
|
+
{
|
|
29
|
+
"_comment": "name of the agent",
|
|
30
|
+
"attribute": "name",
|
|
31
|
+
"accessor": lambda arguments: _helper.get_source_agent(arguments)
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"_comment": "agent type",
|
|
35
|
+
"attribute": "type",
|
|
36
|
+
"accessor": lambda arguments:'agent.stands'
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
],
|
|
40
|
+
"events": [
|
|
41
|
+
{
|
|
42
|
+
"name":"data.input",
|
|
43
|
+
"attributes": [
|
|
44
|
+
{
|
|
45
|
+
"_comment": "this is Tool input",
|
|
46
|
+
"attribute": "input",
|
|
47
|
+
"accessor": lambda arguments: _helper.extract_tool_input(arguments)
|
|
48
|
+
},
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"name":"data.output",
|
|
53
|
+
"attributes": [
|
|
54
|
+
{
|
|
55
|
+
"_comment": "this is response from Tool",
|
|
56
|
+
"attribute": "response",
|
|
57
|
+
"accessor": lambda arguments: _helper.extract_tool_response(arguments['result'])
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from monocle_apptrace.instrumentation.common.wrapper import task_wrapper, atask_wrapper, atask_iter_wrapper
|
|
2
|
+
from monocle_apptrace.instrumentation.metamodel.strands.entities.agent import AGENT, AGENT_REQUEST, AGENT_DELEGATION
|
|
3
|
+
from monocle_apptrace.instrumentation.metamodel.strands.entities.tool import TOOL
|
|
4
|
+
|
|
5
|
+
STRAND_METHODS = [
|
|
6
|
+
{
|
|
7
|
+
"package": "strands.agent.agent",
|
|
8
|
+
"object": "Agent",
|
|
9
|
+
"method": "__call__",
|
|
10
|
+
"wrapper_method": task_wrapper,
|
|
11
|
+
"output_processor_list": [AGENT_REQUEST, AGENT_DELEGATION, AGENT]
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"package": "strands.tools.executors.concurrent",
|
|
15
|
+
"object": "ConcurrentToolExecutor",
|
|
16
|
+
"method": "_execute",
|
|
17
|
+
"wrapper_method": atask_iter_wrapper,
|
|
18
|
+
"output_processor": TOOL,
|
|
19
|
+
}
|
|
20
|
+
]
|
|
@@ -1,51 +1,54 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: monocle_apptrace
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.6
|
|
4
4
|
Summary: package with monocle genAI tracing
|
|
5
5
|
Project-URL: Homepage, https://github.com/monocle2ai/monocle
|
|
6
6
|
Project-URL: Issues, https://github.com/monocle2ai/monocle/issues
|
|
7
7
|
Author-email: "Okahu Inc." <okahu-pypi@okahu.ai>
|
|
8
8
|
License: Apache-2.0
|
|
9
9
|
License-File: LICENSE
|
|
10
|
-
License-File: NOTICE
|
|
11
10
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
11
|
Classifier: Operating System :: OS Independent
|
|
13
12
|
Classifier: Programming Language :: Python :: 3
|
|
14
13
|
Requires-Python: >=3.8
|
|
15
|
-
Requires-Dist: click==8.2.1
|
|
16
|
-
Requires-Dist: mcp>=1.13.1
|
|
17
14
|
Requires-Dist: opentelemetry-api>=1.21.0
|
|
18
15
|
Requires-Dist: opentelemetry-instrumentation
|
|
19
16
|
Requires-Dist: opentelemetry-sdk>=1.21.0
|
|
20
|
-
Requires-Dist: pydantic>=2.11.7
|
|
21
17
|
Requires-Dist: requests
|
|
18
|
+
Requires-Dist: rfc3986>=2.0.0
|
|
22
19
|
Requires-Dist: wrapt>=1.14.0
|
|
20
|
+
Provides-Extra: ai-test
|
|
21
|
+
Requires-Dist: bert-score; extra == 'ai-test'
|
|
22
|
+
Requires-Dist: transformers; extra == 'ai-test'
|
|
23
23
|
Provides-Extra: aws
|
|
24
24
|
Requires-Dist: boto3==1.37.24; extra == 'aws'
|
|
25
25
|
Provides-Extra: azure
|
|
26
|
+
Requires-Dist: azure-ai-inference; extra == 'azure'
|
|
26
27
|
Requires-Dist: azure-storage-blob==12.22.0; extra == 'azure'
|
|
27
28
|
Provides-Extra: dev
|
|
28
|
-
Requires-Dist: a2a-sdk==0.
|
|
29
|
+
Requires-Dist: a2a-sdk==0.3.6; extra == 'dev'
|
|
29
30
|
Requires-Dist: anthropic-haystack; extra == 'dev'
|
|
30
31
|
Requires-Dist: anthropic==0.57.1; extra == 'dev'
|
|
31
32
|
Requires-Dist: azure-storage-blob==12.22.0; extra == 'dev'
|
|
32
|
-
Requires-Dist: boto3==1.
|
|
33
|
+
Requires-Dist: boto3==1.39.0; extra == 'dev'
|
|
33
34
|
Requires-Dist: chromadb==1.0.15; extra == 'dev'
|
|
34
35
|
Requires-Dist: click==8.2.1; extra == 'dev'
|
|
35
|
-
Requires-Dist: datasets==
|
|
36
|
+
Requires-Dist: datasets==4.3.0; extra == 'dev'
|
|
36
37
|
Requires-Dist: faiss-cpu==1.8.0; extra == 'dev'
|
|
37
38
|
Requires-Dist: fastapi>=0.115.0; extra == 'dev'
|
|
38
39
|
Requires-Dist: flask; extra == 'dev'
|
|
39
40
|
Requires-Dist: google-adk==1.10.0; extra == 'dev'
|
|
41
|
+
Requires-Dist: google-ai-haystack; extra == 'dev'
|
|
40
42
|
Requires-Dist: google-generativeai==0.8.5; extra == 'dev'
|
|
41
43
|
Requires-Dist: haystack-ai==2.3.0; extra == 'dev'
|
|
42
44
|
Requires-Dist: httpx==0.28.1; extra == 'dev'
|
|
45
|
+
Requires-Dist: huggingface-hub==0.35.3; extra == 'dev'
|
|
43
46
|
Requires-Dist: instructorembedding==1.0.1; extra == 'dev'
|
|
44
47
|
Requires-Dist: langchain-anthropic==0.3.13; extra == 'dev'
|
|
45
48
|
Requires-Dist: langchain-aws==0.2.23; extra == 'dev'
|
|
46
49
|
Requires-Dist: langchain-chroma==0.2.4; extra == 'dev'
|
|
47
50
|
Requires-Dist: langchain-community==0.3.24; extra == 'dev'
|
|
48
|
-
Requires-Dist: langchain-google-genai==2.
|
|
51
|
+
Requires-Dist: langchain-google-genai==2.0.10; extra == 'dev'
|
|
49
52
|
Requires-Dist: langchain-mcp-adapters==0.1.8; extra == 'dev'
|
|
50
53
|
Requires-Dist: langchain-mistralai==0.2.10; extra == 'dev'
|
|
51
54
|
Requires-Dist: langchain-openai==0.3.18; extra == 'dev'
|
|
@@ -53,6 +56,7 @@ Requires-Dist: langchain==0.3.25; extra == 'dev'
|
|
|
53
56
|
Requires-Dist: langchainhub==0.1.21; extra == 'dev'
|
|
54
57
|
Requires-Dist: langgraph-supervisor==0.0.28; extra == 'dev'
|
|
55
58
|
Requires-Dist: langgraph==0.5.4; extra == 'dev'
|
|
59
|
+
Requires-Dist: litellm==1.77.5; extra == 'dev'
|
|
56
60
|
Requires-Dist: llama-index-embeddings-huggingface==0.6.0; extra == 'dev'
|
|
57
61
|
Requires-Dist: llama-index-llms-anthropic==0.8.1; extra == 'dev'
|
|
58
62
|
Requires-Dist: llama-index-llms-azure-openai==0.4.0; extra == 'dev'
|
|
@@ -64,6 +68,7 @@ Requires-Dist: llama-index-vector-stores-opensearch==0.6.0; extra == 'dev'
|
|
|
64
68
|
Requires-Dist: llama-index==0.13.0; extra == 'dev'
|
|
65
69
|
Requires-Dist: mcp==1.12.1; extra == 'dev'
|
|
66
70
|
Requires-Dist: mistral-haystack==0.0.2; extra == 'dev'
|
|
71
|
+
Requires-Dist: mistralai==1.9.9; extra == 'dev'
|
|
67
72
|
Requires-Dist: numpy==1.26.4; extra == 'dev'
|
|
68
73
|
Requires-Dist: openai-agents==0.2.6; extra == 'dev'
|
|
69
74
|
Requires-Dist: opendal==0.45.14; extra == 'dev'
|
|
@@ -72,50 +77,27 @@ Requires-Dist: opentelemetry-instrumentation-flask; extra == 'dev'
|
|
|
72
77
|
Requires-Dist: parameterized==0.9.0; extra == 'dev'
|
|
73
78
|
Requires-Dist: pydantic==2.11.7; extra == 'dev'
|
|
74
79
|
Requires-Dist: pytest-asyncio==0.26.0; extra == 'dev'
|
|
80
|
+
Requires-Dist: pytest-venv; extra == 'dev'
|
|
75
81
|
Requires-Dist: pytest==8.3.5; extra == 'dev'
|
|
76
82
|
Requires-Dist: python-dotenv>=1.1.0; extra == 'dev'
|
|
77
83
|
Requires-Dist: requests-aws4auth==1.2.3; extra == 'dev'
|
|
78
|
-
Requires-Dist: sentence-transformers==2.6.1; extra == 'dev'
|
|
79
84
|
Requires-Dist: types-requests==2.31.0.20240106; extra == 'dev'
|
|
80
85
|
Requires-Dist: uvicorn==0.35.0; extra == 'dev'
|
|
86
|
+
Provides-Extra: dev-gemini
|
|
87
|
+
Requires-Dist: llama-index-llms-gemini==0.6.0; extra == 'dev-gemini'
|
|
88
|
+
Provides-Extra: dev-strands
|
|
89
|
+
Requires-Dist: strands-agents-tools==0.2.10; extra == 'dev-strands'
|
|
90
|
+
Requires-Dist: strands-agents==1.11.0; extra == 'dev-strands'
|
|
91
|
+
Provides-Extra: dev-tranformers
|
|
92
|
+
Requires-Dist: sentence-transformers==3.3.0; extra == 'dev-tranformers'
|
|
81
93
|
Description-Content-Type: text/markdown
|
|
82
94
|
|
|
83
|
-
# Monocle
|
|
95
|
+
# Monocle Apptrace
|
|
84
96
|
|
|
85
97
|
**Monocle** helps developers and platform engineers building or managing GenAI apps monitor these in prod by making it easy to instrument their code to capture traces that are compliant with open-source cloud-native observability ecosystem.
|
|
86
98
|
|
|
87
99
|
**Monocle** is a community-driven OSS framework for tracing GenAI app code governed as a [Linux Foundation AI & Data project](https://lfaidata.foundation/projects/monocle/).
|
|
88
100
|
|
|
89
|
-
## Why Monocle
|
|
90
|
-
|
|
91
|
-
Monocle is built for:
|
|
92
|
-
- **app developers** to trace their app code in any environment without lots of custom code decoration
|
|
93
|
-
- **platform engineers** to instrument apps in prod through wrapping instead of asking app devs to recode
|
|
94
|
-
- **GenAI component providers** to add observability features to their products
|
|
95
|
-
- **enterprises** to consume traces from GenAI apps in their existing open-source observability stack
|
|
96
|
-
|
|
97
|
-
Benefits:
|
|
98
|
-
- Monocle provides an implementation + package, not just a spec
|
|
99
|
-
- No expertise in OpenTelemetry spec required
|
|
100
|
-
- No bespoke implementation of that spec required
|
|
101
|
-
- No last-mile GenAI domain specific code required to instrument your app
|
|
102
|
-
- Monocle provides consistency
|
|
103
|
-
- Connect traces across app code executions, model inference or data retrievals
|
|
104
|
-
- No cleansing of telemetry data across GenAI component providers required
|
|
105
|
-
- Works the same in personal lab dev or org cloud prod environments
|
|
106
|
-
- Send traces to location that fits your scale, budget and observability stack
|
|
107
|
-
- Monocle is fully open source and community driven
|
|
108
|
-
- No vendor lock-in
|
|
109
|
-
- Implementation is transparent
|
|
110
|
-
- You can freely use or customize it to fit your needs
|
|
111
|
-
|
|
112
|
-
## What Monocle provides
|
|
113
|
-
|
|
114
|
-
- Easy to [use](#use-monocle) code instrumentation
|
|
115
|
-
- OpenTelemetry compatible format for [spans](src/monocle_apptrace/metamodel/spans/span_format.json).
|
|
116
|
-
- Community-curated and extensible [metamodel](src/monocle_apptrace/metamodel/README.md) for consisent tracing of GenAI components.
|
|
117
|
-
- Export to local and cloud storage
|
|
118
|
-
|
|
119
101
|
## Use Monocle
|
|
120
102
|
|
|
121
103
|
- Get the Monocle package
|
|
@@ -137,42 +119,4 @@ Benefits:
|
|
|
137
119
|
See [Monocle user guide](Monocle_User_Guide.md) for more details.
|
|
138
120
|
|
|
139
121
|
|
|
140
|
-
## Use Monocle MCP
|
|
141
|
-
|
|
142
|
-
First install monocle-apptrace: pip install monocle-apptrace
|
|
143
|
-
|
|
144
|
-
Open bash and run the following command to run the monocle mcp server with stdio:
|
|
145
|
-
monocle_apptrace
|
|
146
|
-
|
|
147
|
-
If you are using VS Code you can add following entry to your .vscode/mcp.json
|
|
148
|
-
|
|
149
|
-
```json
|
|
150
|
-
"monocle-mcp-server": {
|
|
151
|
-
"type": "stdio",
|
|
152
|
-
"command": "uvx",
|
|
153
|
-
"args": [
|
|
154
|
-
"monocle_apptrace"
|
|
155
|
-
],
|
|
156
|
-
"env": {}
|
|
157
|
-
}
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
## Roadmap
|
|
161
|
-
|
|
162
|
-
Goal of Monocle is to support tracing for apps written in *any language* with *any LLM orchestration or agentic framework* and built using models, vectors, agents or other components served up by *any cloud or model inference provider*.
|
|
163
|
-
|
|
164
|
-
Current version supports:
|
|
165
|
-
- Language: (🟢) Python , (🔜) [Typescript](https://github.com/monocle2ai/monocle-typescript)
|
|
166
|
-
- LLM-frameworks: (🟢) Langchain, (🟢) Llamaindex, (🟢) Haystack, (🔜) Flask
|
|
167
|
-
- LLM inference providers: (🟢) OpenAI, (🟢) Azure OpenAI, (🟢) Nvidia Triton, (🔜) AWS Bedrock, (🔜) Google Vertex, (🔜) Azure ML, (🔜) Hugging Face
|
|
168
|
-
- Vector stores: (🟢) FAISS, (🔜) OpenSearch, (🔜) Milvus
|
|
169
|
-
- Exporter: (🟢) stdout, (🟢) file, (🔜) Azure Blob Storage, (🔜) AWS S3, (🔜) Google Cloud Storage
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
## Get involved
|
|
173
|
-
### Provide feedback
|
|
174
|
-
- Submit issues and enhancements requests via Github issues
|
|
175
|
-
|
|
176
|
-
### Contribute
|
|
177
|
-
- Monocle is community based open source project. We welcome your contributions. Please refer to the CONTRIBUTING and CODE_OF_CONDUCT for guidelines. The [contributor's guide](CONTRIBUTING.md) provides technical details of the project.
|
|
178
122
|
|