monocle-apptrace 0.5.0__py3-none-any.whl → 0.5.1__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.

Files changed (54) hide show
  1. monocle_apptrace/instrumentation/common/__init__.py +7 -5
  2. monocle_apptrace/instrumentation/common/constants.py +95 -12
  3. monocle_apptrace/instrumentation/common/instrumentor.py +1 -6
  4. monocle_apptrace/instrumentation/common/method_wrappers.py +1 -112
  5. monocle_apptrace/instrumentation/common/scope_wrapper.py +126 -0
  6. monocle_apptrace/instrumentation/common/span_handler.py +13 -0
  7. monocle_apptrace/instrumentation/common/utils.py +2 -2
  8. monocle_apptrace/instrumentation/common/wrapper.py +113 -51
  9. monocle_apptrace/instrumentation/metamodel/a2a/entities/inference.py +3 -1
  10. monocle_apptrace/instrumentation/metamodel/adk/_helper.py +24 -0
  11. monocle_apptrace/instrumentation/metamodel/adk/entities/agent.py +62 -1
  12. monocle_apptrace/instrumentation/metamodel/adk/entities/tool.py +3 -1
  13. monocle_apptrace/instrumentation/metamodel/adk/methods.py +9 -2
  14. monocle_apptrace/instrumentation/metamodel/agents/_helper.py +5 -0
  15. monocle_apptrace/instrumentation/metamodel/agents/agents_processor.py +30 -8
  16. monocle_apptrace/instrumentation/metamodel/agents/entities/inference.py +10 -5
  17. monocle_apptrace/instrumentation/metamodel/agents/methods.py +3 -4
  18. monocle_apptrace/instrumentation/metamodel/aiohttp/entities/http.py +2 -1
  19. monocle_apptrace/instrumentation/metamodel/anthropic/_helper.py +3 -3
  20. monocle_apptrace/instrumentation/metamodel/anthropic/entities/inference.py +2 -1
  21. monocle_apptrace/instrumentation/metamodel/azfunc/entities/http.py +2 -1
  22. monocle_apptrace/instrumentation/metamodel/azureaiinference/entities/inference.py +2 -1
  23. monocle_apptrace/instrumentation/metamodel/botocore/entities/inference.py +2 -1
  24. monocle_apptrace/instrumentation/metamodel/fastapi/entities/http.py +2 -1
  25. monocle_apptrace/instrumentation/metamodel/finish_types.py +2 -0
  26. monocle_apptrace/instrumentation/metamodel/flask/entities/http.py +2 -1
  27. monocle_apptrace/instrumentation/metamodel/gemini/entities/inference.py +2 -1
  28. monocle_apptrace/instrumentation/metamodel/gemini/entities/retrieval.py +2 -1
  29. monocle_apptrace/instrumentation/metamodel/haystack/entities/inference.py +2 -1
  30. monocle_apptrace/instrumentation/metamodel/haystack/entities/retrieval.py +2 -1
  31. monocle_apptrace/instrumentation/metamodel/lambdafunc/entities/http.py +2 -1
  32. monocle_apptrace/instrumentation/metamodel/langchain/_helper.py +2 -2
  33. monocle_apptrace/instrumentation/metamodel/langchain/entities/inference.py +2 -1
  34. monocle_apptrace/instrumentation/metamodel/langchain/entities/retrieval.py +2 -1
  35. monocle_apptrace/instrumentation/metamodel/langgraph/_helper.py +6 -0
  36. monocle_apptrace/instrumentation/metamodel/langgraph/entities/inference.py +10 -5
  37. monocle_apptrace/instrumentation/metamodel/langgraph/langgraph_processor.py +8 -4
  38. monocle_apptrace/instrumentation/metamodel/langgraph/methods.py +2 -0
  39. monocle_apptrace/instrumentation/metamodel/litellm/entities/inference.py +2 -1
  40. monocle_apptrace/instrumentation/metamodel/llamaindex/entities/agent.py +9 -4
  41. monocle_apptrace/instrumentation/metamodel/llamaindex/entities/inference.py +2 -1
  42. monocle_apptrace/instrumentation/metamodel/llamaindex/entities/retrieval.py +2 -1
  43. monocle_apptrace/instrumentation/metamodel/mcp/_helper.py +2 -1
  44. monocle_apptrace/instrumentation/metamodel/mcp/entities/inference.py +3 -1
  45. monocle_apptrace/instrumentation/metamodel/mcp/methods.py +1 -1
  46. monocle_apptrace/instrumentation/metamodel/openai/_helper.py +2 -2
  47. monocle_apptrace/instrumentation/metamodel/openai/entities/inference.py +2 -1
  48. monocle_apptrace/instrumentation/metamodel/requests/entities/http.py +2 -1
  49. monocle_apptrace/instrumentation/metamodel/teamsai/entities/inference/teamsai_output_processor.py +2 -1
  50. {monocle_apptrace-0.5.0.dist-info → monocle_apptrace-0.5.1.dist-info}/METADATA +1 -1
  51. {monocle_apptrace-0.5.0.dist-info → monocle_apptrace-0.5.1.dist-info}/RECORD +54 -53
  52. {monocle_apptrace-0.5.0.dist-info → monocle_apptrace-0.5.1.dist-info}/WHEEL +0 -0
  53. {monocle_apptrace-0.5.0.dist-info → monocle_apptrace-0.5.1.dist-info}/licenses/LICENSE +0 -0
  54. {monocle_apptrace-0.5.0.dist-info → monocle_apptrace-0.5.1.dist-info}/licenses/NOTICE +0 -0
@@ -10,6 +10,7 @@ from opentelemetry.context import set_value, attach, detach, get_value
10
10
  from opentelemetry.context import create_key, get_value, set_value
11
11
  from opentelemetry.context.context import Context
12
12
  from opentelemetry.trace.span import INVALID_SPAN, Span
13
+ from opentelemetry.trace.status import StatusCode
13
14
 
14
15
  from monocle_apptrace.instrumentation.common.span_handler import SpanHandler
15
16
  from monocle_apptrace.instrumentation.common.utils import (
@@ -20,7 +21,9 @@ from monocle_apptrace.instrumentation.common.utils import (
20
21
  get_current_monocle_span,
21
22
  set_monocle_span_in_context
22
23
  )
23
- from monocle_apptrace.instrumentation.common.constants import WORKFLOW_TYPE_KEY, ADD_NEW_WORKFLOW
24
+ from monocle_apptrace.instrumentation.common.constants import WORKFLOW_TYPE_KEY, ADD_NEW_WORKFLOW, AGENTIC_SPANS
25
+ from monocle_apptrace.instrumentation.common.scope_wrapper import monocle_trace_scope
26
+
24
27
  logger = logging.getLogger(__name__)
25
28
  ISOLATE_MONOCLE_SPANS = os.getenv("MONOCLE_ISOLATE_SPANS", "true").lower() == "true"
26
29
 
@@ -79,26 +82,36 @@ def monocle_wrapper_span_processor(tracer: Tracer, handler: SpanHandler, to_wrap
79
82
  if SpanHandler.is_root_span(span) or add_workflow_span:
80
83
  # Recursive call for the actual span
81
84
  return_value, span_status = monocle_wrapper_span_processor(tracer, handler, to_wrap, wrapped, instance, source_path, False, args, kwargs)
82
- span.set_status(span_status)
85
+ span.set_status(StatusCode.OK)
83
86
  if not auto_close_span:
84
87
  span.end()
85
88
  else:
86
89
  ex:Exception = None
87
- try:
88
- with SpanHandler.workflow_type(to_wrap, span):
89
- return_value = wrapped(*args, **kwargs)
90
- except Exception as e:
91
- ex = e
92
- raise
93
- finally:
94
- def post_process_span_internal(ret_val):
95
- post_process_span(handler, to_wrap, wrapped, instance, args, kwargs, ret_val, span, parent_span ,ex)
96
- if not auto_close_span:
97
- span.end()
98
- if ex is None and not auto_close_span and to_wrap.get("output_processor") and to_wrap.get("output_processor").get("response_processor"):
99
- to_wrap.get("output_processor").get("response_processor")(to_wrap, return_value, post_process_span_internal)
100
- else:
90
+ to_wrap = get_wrapper_with_next_processor(to_wrap, handler, instance, args, kwargs)
91
+ if has_more_processors(to_wrap):
92
+ try:
93
+ return_value, span_status = monocle_wrapper_span_processor(tracer, handler, to_wrap, wrapped, instance, source_path, False, args, kwargs)
94
+ except Exception as e:
95
+ ex = e
96
+ raise
97
+ finally:
101
98
  post_process_span_internal(return_value)
99
+ else:
100
+ try:
101
+ with SpanHandler.workflow_type(to_wrap, span):
102
+ return_value = wrapped(*args, **kwargs)
103
+ except Exception as e:
104
+ ex = e
105
+ raise
106
+ finally:
107
+ def post_process_span_internal(ret_val):
108
+ post_process_span(handler, to_wrap, wrapped, instance, args, kwargs, ret_val, span, parent_span ,ex)
109
+ if not auto_close_span:
110
+ span.end()
111
+ if ex is None and not auto_close_span and to_wrap.get("output_processor") and to_wrap.get("output_processor").get("response_processor"):
112
+ to_wrap.get("output_processor").get("response_processor")(to_wrap, return_value, post_process_span_internal)
113
+ else:
114
+ post_process_span_internal(return_value)
102
115
  span_status = span.status
103
116
  return return_value, span_status
104
117
 
@@ -117,7 +130,8 @@ def monocle_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, inst
117
130
  add_workflow_span = get_value(ADD_NEW_WORKFLOW) == True
118
131
  token = attach(set_value(ADD_NEW_WORKFLOW, False))
119
132
  try:
120
- return_value, span_status = monocle_wrapper_span_processor(tracer, handler, to_wrap, wrapped, instance, source_path, add_workflow_span, args, kwargs)
133
+ with monocle_trace_scope(get_builtin_scope_names(to_wrap)):
134
+ return_value, span_status = monocle_wrapper_span_processor(tracer, handler, to_wrap, wrapped, instance, source_path, add_workflow_span, args, kwargs)
121
135
  finally:
122
136
  detach(token)
123
137
  return return_value
@@ -141,26 +155,36 @@ async def amonocle_wrapper_span_processor(tracer: Tracer, handler: SpanHandler,
141
155
  if SpanHandler.is_root_span(span) or add_workflow_span:
142
156
  # Recursive call for the actual span
143
157
  return_value, span_status = await amonocle_wrapper_span_processor(tracer, handler, to_wrap, wrapped, instance, source_path, False, args, kwargs)
144
- span.set_status(span_status)
158
+ span.set_status(StatusCode.OK)
145
159
  if not auto_close_span:
146
160
  span.end()
147
161
  else:
148
162
  ex:Exception = None
149
- try:
150
- with SpanHandler.workflow_type(to_wrap, span):
151
- return_value = await wrapped(*args, **kwargs)
152
- except Exception as e:
153
- ex = e
154
- raise
155
- finally:
156
- def post_process_span_internal(ret_val):
157
- post_process_span(handler, to_wrap, wrapped, instance, args, kwargs, ret_val, span, parent_span, ex)
158
- if not auto_close_span:
159
- span.end()
160
- if ex is None and not auto_close_span and to_wrap.get("output_processor") and to_wrap.get("output_processor").get("response_processor"):
161
- to_wrap.get("output_processor").get("response_processor")(to_wrap, return_value, post_process_span_internal)
162
- else:
163
+ to_wrap = get_wrapper_with_next_processor(to_wrap, handler, instance, args, kwargs)
164
+ if has_more_processors(to_wrap):
165
+ try:
166
+ return_value, span_status = await amonocle_wrapper_span_processor(tracer, handler, to_wrap, wrapped, instance, source_path, False, args, kwargs)
167
+ except Exception as e:
168
+ ex = e
169
+ raise
170
+ finally:
163
171
  post_process_span_internal(return_value)
172
+ else:
173
+ try:
174
+ with SpanHandler.workflow_type(to_wrap, span):
175
+ return_value = await wrapped(*args, **kwargs)
176
+ except Exception as e:
177
+ ex = e
178
+ raise
179
+ finally:
180
+ def post_process_span_internal(ret_val):
181
+ post_process_span(handler, to_wrap, wrapped, instance, args, kwargs, ret_val, span, parent_span, ex)
182
+ if not auto_close_span:
183
+ span.end()
184
+ if ex is None and not auto_close_span and to_wrap.get("output_processor") and to_wrap.get("output_processor").get("response_processor"):
185
+ to_wrap.get("output_processor").get("response_processor")(to_wrap, return_value, post_process_span_internal)
186
+ else:
187
+ post_process_span_internal(return_value)
164
188
  span_status = span.status
165
189
  return return_value, span_status
166
190
 
@@ -179,28 +203,40 @@ async def amonocle_iter_wrapper_span_processor(tracer: Tracer, handler: SpanHand
179
203
  # Recursive call for the actual span
180
204
  async for item in amonocle_iter_wrapper_span_processor(tracer, handler, to_wrap, wrapped, instance, source_path, False, args, kwargs):
181
205
  yield item
182
-
206
+ span.set_status(StatusCode.OK)
183
207
  if not auto_close_span:
184
208
  span.end()
185
209
  else:
186
210
  ex:Exception = None
187
- try:
188
- with SpanHandler.workflow_type(to_wrap, span):
189
- async for item in wrapped(*args, **kwargs):
211
+ to_wrap = get_wrapper_with_next_processor(to_wrap, handler, instance, args, kwargs)
212
+ if has_more_processors(to_wrap):
213
+ try:
214
+ async for item in amonocle_iter_wrapper_span_processor(tracer, handler, to_wrap, wrapped, instance, source_path, False, args, kwargs):
190
215
  last_item = item
191
216
  yield item
192
- except Exception as e:
193
- ex = e
194
- raise
195
- finally:
196
- def post_process_span_internal(ret_val):
197
- post_process_span(handler, to_wrap, wrapped, instance, args, kwargs, ret_val, span, parent_span, ex)
198
- if not auto_close_span:
199
- span.end()
200
- if ex is None and not auto_close_span and to_wrap.get("output_processor") and to_wrap.get("output_processor").get("response_processor"):
201
- to_wrap.get("output_processor").get("response_processor")(to_wrap, None, post_process_span_internal)
202
- else:
203
- post_process_span_internal(last_item)
217
+ except Exception as e:
218
+ ex = e
219
+ raise
220
+ finally:
221
+ post_process_span(handler, to_wrap, wrapped, instance, args, kwargs, last_item, span, parent_span, ex)
222
+ else:
223
+ try:
224
+ with SpanHandler.workflow_type(to_wrap, span):
225
+ async for item in wrapped(*args, **kwargs):
226
+ last_item = item
227
+ yield item
228
+ except Exception as e:
229
+ ex = e
230
+ raise
231
+ finally:
232
+ def post_process_span_internal(ret_val):
233
+ post_process_span(handler, to_wrap, wrapped, instance, args, kwargs, ret_val, span, parent_span, ex)
234
+ if not auto_close_span:
235
+ span.end()
236
+ if ex is None and not auto_close_span and to_wrap.get("output_processor") and to_wrap.get("output_processor").get("response_processor"):
237
+ to_wrap.get("output_processor").get("response_processor")(to_wrap, None, post_process_span_internal)
238
+ else:
239
+ post_process_span_internal(last_item)
204
240
  return
205
241
 
206
242
  async def amonocle_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instance, source_path, args, kwargs):
@@ -218,7 +254,8 @@ async def amonocle_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, wrappe
218
254
  add_workflow_span = get_value(ADD_NEW_WORKFLOW) == True
219
255
  token = attach(set_value(ADD_NEW_WORKFLOW, False))
220
256
  try:
221
- return_value, span_status = await amonocle_wrapper_span_processor(tracer, handler, to_wrap, wrapped, instance, source_path,
257
+ with monocle_trace_scope(get_builtin_scope_names(to_wrap)):
258
+ return_value, span_status = await amonocle_wrapper_span_processor(tracer, handler, to_wrap, wrapped, instance, source_path,
222
259
  add_workflow_span, args, kwargs)
223
260
  finally:
224
261
  detach(token)
@@ -244,8 +281,9 @@ async def amonocle_iter_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, w
244
281
  add_workflow_span = get_value(ADD_NEW_WORKFLOW) == True
245
282
  token = attach(set_value(ADD_NEW_WORKFLOW, False))
246
283
  try:
247
- async for item in amonocle_iter_wrapper_span_processor(tracer, handler, to_wrap, wrapped, instance, source_path, add_workflow_span, args, kwargs):
248
- yield item
284
+ with monocle_trace_scope(get_builtin_scope_names(to_wrap)):
285
+ async for item in amonocle_iter_wrapper_span_processor(tracer, handler, to_wrap, wrapped, instance, source_path, add_workflow_span, args, kwargs):
286
+ yield item
249
287
  finally:
250
288
  detach(token)
251
289
  return
@@ -351,3 +389,27 @@ def start_as_monocle_span(tracer: Tracer, name: str, auto_close_span: bool) -> I
351
389
  detach(original_span_token)
352
390
  detach(new_monocle_token)
353
391
  detach(monocle_span_token)
392
+
393
+ def get_builtin_scope_names(to_wrap) -> str:
394
+ output_processor = to_wrap.get("output_processor", None)
395
+ span_type = output_processor.get("type", None) if output_processor else None
396
+ if span_type and span_type in AGENTIC_SPANS:
397
+ return span_type
398
+ return None
399
+
400
+ def get_wrapper_with_next_processor(to_wrap, handler, instance, args, kwargs):
401
+ if has_more_processors(to_wrap):
402
+ next_output_processor_list = to_wrap.get('output_processor_list',[]).copy()
403
+ while len(next_output_processor_list) > 0:
404
+ next_output_processor = next_output_processor_list.pop(0)
405
+ if handler.should_skip(next_output_processor, instance, args, kwargs):
406
+ next_output_processor = None
407
+ else:
408
+ break
409
+ to_wrap = to_wrap.copy()
410
+ to_wrap['output_processor_list'] = next_output_processor_list
411
+ to_wrap['output_processor'] = next_output_processor
412
+ return to_wrap
413
+
414
+ def has_more_processors(to_wrap) -> bool:
415
+ return len(to_wrap.get('output_processor_list', [])) > 0
@@ -1,7 +1,9 @@
1
+ from monocle_apptrace.instrumentation.common.constants import SPAN_SUBTYPES, SPAN_TYPES
1
2
  from monocle_apptrace.instrumentation.metamodel.a2a import _helper
2
3
 
3
4
  A2A_CLIENT = {
4
- "type": "agentic.invocation",
5
+ "type": SPAN_TYPES.AGENTIC_INVOCATION,
6
+ "subtype": SPAN_SUBTYPES.ROUTING,
5
7
  "attributes": [
6
8
  [
7
9
  {
@@ -84,6 +84,18 @@ def extract_agent_input(arguments: Dict[str, Any]) -> Any:
84
84
  """
85
85
  return arguments['args'][0].user_content.parts[0].text
86
86
 
87
+ def extract_agent_request_input(arguments: Dict[str, Any]) -> Any:
88
+ """
89
+ Extract the input data from agent request.
90
+
91
+ Args:
92
+ arguments: Dictionary containing agent call arguments
93
+
94
+ Returns:
95
+ Any: The extracted input data
96
+ """
97
+ return arguments['kwargs']['new_message'].parts[0].text if 'new_message' in arguments['kwargs'] else None
98
+
87
99
  def extract_agent_response(result: Any) -> Any:
88
100
  """
89
101
  Extract the response data from agent result.
@@ -145,6 +157,18 @@ def get_delegating_agent(arguments) -> str:
145
157
  return None
146
158
  return from_agent
147
159
 
160
+ def should_skip_delegation(arguments):
161
+ """
162
+ Determine whether to skip the delegation based on the arguments.
163
+
164
+ Args:
165
+ arguments: Dictionary containing agent call arguments
166
+
167
+ Returns:
168
+ bool: True if delegation should be skipped, False otherwise
169
+ """
170
+ return get_delegating_agent(arguments) is None
171
+
148
172
  def extract_tool_input(arguments: Dict[str, Any]) -> Any:
149
173
  """
150
174
  Extract the input data from tool arguments.
@@ -1,6 +1,8 @@
1
+ from monocle_apptrace.instrumentation.common.constants import SPAN_SUBTYPES, SPAN_TYPES
1
2
  from monocle_apptrace.instrumentation.metamodel.adk import _helper
2
3
  AGENT = {
3
- "type": "agentic.invocation",
4
+ "type": SPAN_TYPES.AGENTIC_INVOCATION,
5
+ "subtype": SPAN_SUBTYPES.ROUTING,
4
6
  "attributes": [
5
7
  [
6
8
  {
@@ -48,3 +50,62 @@ AGENT = {
48
50
  }
49
51
  ]
50
52
  }
53
+
54
+ REQUEST = {
55
+ "type": "agentic.request",
56
+ "attributes": [
57
+ [
58
+ {
59
+ "_comment": "agent type",
60
+ "attribute": "type",
61
+ "accessor": lambda arguments:'agent.adk'
62
+ }
63
+ ],
64
+ ],
65
+ "events": [
66
+ {
67
+ "name":"data.input",
68
+ "attributes": [
69
+ {
70
+ "_comment": "this is Agent input",
71
+ "attribute": "input",
72
+ "accessor": lambda arguments: _helper.extract_agent_request_input(arguments)
73
+ }
74
+ ]
75
+ },
76
+ {
77
+ "name":"data.output",
78
+ "attributes": [
79
+ {
80
+ "_comment": "this is response from LLM",
81
+ "attribute": "response",
82
+ "accessor": lambda arguments: _helper.extract_agent_response(arguments['result'])
83
+ }
84
+ ]
85
+ }
86
+ ]
87
+ }
88
+
89
+ DELEGATION = {
90
+ "type": "agentic.delegation",
91
+ "should_skip": lambda arguments: _helper.should_skip_delegation(arguments),
92
+ "attributes": [
93
+ [
94
+ {
95
+ "_comment": "agent type",
96
+ "attribute": "type",
97
+ "accessor": lambda arguments:'agent.adk'
98
+ },
99
+ {
100
+ "_comment": "name of the agent",
101
+ "attribute": "from_agent",
102
+ "accessor": lambda arguments: _helper.get_delegating_agent(arguments)
103
+ },
104
+ {
105
+ "_comment": "name of the agent called",
106
+ "attribute": "to_agent",
107
+ "accessor": lambda arguments: _helper.get_agent_name(arguments['instance'])
108
+ }
109
+ ]
110
+ ]
111
+ }
@@ -1,6 +1,8 @@
1
+ from monocle_apptrace.instrumentation.common.constants import SPAN_SUBTYPES, SPAN_TYPES
1
2
  from monocle_apptrace.instrumentation.metamodel.adk import _helper
2
3
  TOOL = {
3
- "type": "agentic.tool.invocation",
4
+ "type": SPAN_TYPES.AGENTIC_TOOL_INVOCATION,
5
+ "subtype": SPAN_SUBTYPES.ROUTING,
4
6
  "attributes": [
5
7
  [
6
8
  {
@@ -1,6 +1,6 @@
1
1
  from monocle_apptrace.instrumentation.common.wrapper import task_wrapper, atask_wrapper, atask_iter_wrapper
2
2
  from monocle_apptrace.instrumentation.metamodel.adk.entities.agent import (
3
- AGENT,
3
+ AGENT, REQUEST, DELEGATION
4
4
  )
5
5
  from monocle_apptrace.instrumentation.metamodel.adk.entities.tool import (
6
6
  TOOL
@@ -12,7 +12,7 @@ ADK_METHODS = [
12
12
  "object": "BaseAgent",
13
13
  "method": "run_async",
14
14
  "wrapper_method": atask_iter_wrapper,
15
- "output_processor": AGENT,
15
+ "output_processor_list": [DELEGATION, AGENT]
16
16
  },
17
17
  {
18
18
  "package": "google.adk.tools.function_tool",
@@ -20,5 +20,12 @@ ADK_METHODS = [
20
20
  "method": "run_async",
21
21
  "wrapper_method": atask_wrapper,
22
22
  "output_processor": TOOL,
23
+ },
24
+ {
25
+ "package": "google.adk.runners",
26
+ "object": "Runner",
27
+ "method": "run_async",
28
+ "wrapper_method": atask_iter_wrapper,
29
+ "output_processor": REQUEST,
23
30
  }
24
31
  ]
@@ -158,6 +158,11 @@ def get_runner_agent_name(instance) -> str:
158
158
  """Get the name of an agent."""
159
159
  return get_name(instance)
160
160
 
161
+ def get_tool_type(span):
162
+ if (span.attributes.get("is_mcp", False)):
163
+ return "tool.mcp"
164
+ else:
165
+ return "tool.openai_agents"
161
166
 
162
167
  def get_tool_name(instance) -> str:
163
168
  """Get the name of a tool."""
@@ -34,21 +34,42 @@ def constructor_wrapper(
34
34
 
35
35
  original_func = kwargs.get("on_invoke_tool", None)
36
36
  result = None
37
+ mcp_url = None
38
+ # kwargs.get("on_invoke_tool").args[0].params["url"]
39
+ if (
40
+ kwargs.get("on_invoke_tool")
41
+ and hasattr(kwargs.get("on_invoke_tool"), "args")
42
+ and len(kwargs.get("on_invoke_tool").args) > 0
43
+ and hasattr(kwargs.get("on_invoke_tool").args[0], "params")
44
+ ):
45
+ mcp_url = kwargs.get("on_invoke_tool").args[0].params.get("url", None)
46
+ if mcp_url:
47
+ logger.debug(f"Using MCP URL: {mcp_url}")
37
48
  tool_instance = SimpleNamespace(
38
49
  name=kwargs.get("name", "unknown_tool"),
39
50
  description=kwargs.get("description", "No description provided"),
40
51
  )
41
52
  if original_func and not getattr(original_func, "_monocle_wrapped", False):
42
53
  # Now wrap the function with our instrumentation
54
+
43
55
  async def wrapped_func(*func_args, **func_kwargs):
44
- # Use the handler to create spans when the decorated function is called
45
- return await atask_wrapper(tracer=tracer, handler=handler, to_wrap=to_wrap)(
46
- wrapped=original_func,
47
- instance=tool_instance,
48
- source_path=source_path,
49
- args=func_args,
50
- kwargs=func_kwargs,
51
- )
56
+ token = None
57
+ try:
58
+ if mcp_url:
59
+ token = attach(set_value("mcp.url", mcp_url))
60
+ # Use the handler to create spans when the decorated function is called
61
+ return await atask_wrapper(
62
+ tracer=tracer, handler=handler, to_wrap=to_wrap
63
+ )(
64
+ wrapped=original_func,
65
+ instance=tool_instance,
66
+ source_path=source_path,
67
+ args=func_args,
68
+ kwargs=func_kwargs,
69
+ )
70
+ finally:
71
+ if token:
72
+ detach(token)
52
73
 
53
74
  kwargs["on_invoke_tool"] = wrapped_func
54
75
  # Preserve function metadata
@@ -150,3 +171,4 @@ class AgentsSpanHandler(BaseSpanHandler):
150
171
  return super().post_task_processing(
151
172
  to_wrap, wrapped, instance, args, kwargs, result, ex, span, parent_span
152
173
  )
174
+
@@ -1,7 +1,9 @@
1
+ from monocle_apptrace.instrumentation.common.constants import AGENT_REQUEST_SPAN_NAME, SPAN_SUBTYPES, SPAN_TYPES
1
2
  from monocle_apptrace.instrumentation.metamodel.agents import _helper
2
3
 
3
4
  AGENT = {
4
- "type": "agentic.invocation",
5
+ "type": SPAN_TYPES.AGENTIC_INVOCATION,
6
+ "subtype": SPAN_SUBTYPES.ROUTING,
5
7
  "attributes": [
6
8
  [
7
9
  {
@@ -66,7 +68,8 @@ AGENT = {
66
68
  }
67
69
 
68
70
  AGENT_REQUEST = {
69
- "type": "agentic.request",
71
+ "type": AGENT_REQUEST_SPAN_NAME,
72
+ "subtype": SPAN_SUBTYPES.PLANNING,
70
73
  "attributes": [
71
74
  [
72
75
  {
@@ -105,13 +108,14 @@ AGENT_REQUEST = {
105
108
  }
106
109
 
107
110
  TOOLS = {
108
- "type": "agentic.tool.invocation",
111
+ "type": SPAN_TYPES.AGENTIC_TOOL_INVOCATION,
112
+ "subtype": SPAN_SUBTYPES.ROUTING,
109
113
  "attributes": [
110
114
  [
111
115
  {
112
116
  "_comment": "tool type",
113
117
  "attribute": "type",
114
- "accessor": lambda arguments: "tool.openai_agents",
118
+ "accessor": lambda arguments: _helper.get_tool_type(arguments["span"]),
115
119
  },
116
120
  {
117
121
  "_comment": "name of the tool",
@@ -168,7 +172,8 @@ TOOLS = {
168
172
  }
169
173
 
170
174
  AGENT_DELEGATION = {
171
- "type": "agentic.delegation",
175
+ "type": SPAN_TYPES.AGENTIC_DELEGATION,
176
+ "subtype": SPAN_SUBTYPES.ROUTING,
172
177
  "attributes": [
173
178
  [
174
179
  {
@@ -3,6 +3,7 @@ from monocle_apptrace.instrumentation.metamodel.agents.entities.inference import
3
3
  AGENT,
4
4
  AGENT_DELEGATION,
5
5
  TOOLS,
6
+ AGENT_REQUEST
6
7
  )
7
8
  from monocle_apptrace.instrumentation.metamodel.agents.agents_processor import (
8
9
  constructor_wrapper,
@@ -17,7 +18,7 @@ AGENTS_METHODS = [
17
18
  "method": "run",
18
19
  "wrapper_method": atask_wrapper,
19
20
  "span_handler": "agents_agent_handler",
20
- "output_processor": AGENT,
21
+ "output_processor": AGENT_REQUEST,
21
22
  },
22
23
  {
23
24
  "package": "agents.run",
@@ -25,7 +26,7 @@ AGENTS_METHODS = [
25
26
  "method": "run_sync",
26
27
  "wrapper_method": task_wrapper,
27
28
  "span_handler": "agents_agent_handler",
28
- "output_processor": AGENT,
29
+ "output_processor": AGENT_REQUEST,
29
30
  },
30
31
  # AgentRunner class methods (internal runner)
31
32
  {
@@ -42,7 +43,6 @@ AGENTS_METHODS = [
42
43
  "object": "FunctionTool",
43
44
  "method": "__init__", # Empty string means wrap the function itself
44
45
  "wrapper_method": constructor_wrapper,
45
- "span_handler": "agents_tool_handler",
46
46
  "output_processor": TOOLS,
47
47
  },
48
48
  {
@@ -50,7 +50,6 @@ AGENTS_METHODS = [
50
50
  "object": "Handoff",
51
51
  "method": "__init__", # Empty string means wrap the function itself
52
52
  "wrapper_method": handoff_constructor_wrapper,
53
- "span_handler": "agents_tool_handler",
54
53
  "output_processor": AGENT_DELEGATION,
55
54
  },
56
55
  ]
@@ -1,6 +1,7 @@
1
+ from monocle_apptrace.instrumentation.common.constants import SPAN_TYPES
1
2
  from monocle_apptrace.instrumentation.metamodel.aiohttp import _helper
2
3
  AIO_HTTP_PROCESSOR = {
3
- "type": "http.process",
4
+ "type": SPAN_TYPES.HTTP_PROCESS,
4
5
  "attributes": [
5
6
  [
6
7
  {
@@ -16,7 +16,7 @@ from monocle_apptrace.instrumentation.common.utils import (
16
16
  get_exception_message,
17
17
  )
18
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
19
+ from monocle_apptrace.instrumentation.common.constants import AGENT_PREFIX_KEY, INFERENCE_AGENT_DELEGATION, INFERENCE_TURN_END, INFERENCE_TOOL_CALL
20
20
 
21
21
 
22
22
  logger = logging.getLogger(__name__)
@@ -177,7 +177,7 @@ def agent_inference_type(arguments):
177
177
  if agent_prefix and agent_prefix in assistant_message:
178
178
  return INFERENCE_AGENT_DELEGATION
179
179
 
180
- return INFERENCE_COMMUNICATION
180
+ return INFERENCE_TURN_END
181
181
  except Exception as e:
182
182
  logger.warning("Warning: Error occurred in agent_inference_type: %s", str(e))
183
- return INFERENCE_COMMUNICATION
183
+ return INFERENCE_TURN_END
@@ -1,10 +1,11 @@
1
+ from monocle_apptrace.instrumentation.common.constants import SPAN_TYPES
1
2
  from monocle_apptrace.instrumentation.metamodel.anthropic import (
2
3
  _helper,
3
4
  )
4
5
  from monocle_apptrace.instrumentation.common.utils import (get_error_message, resolve_from_alias)
5
6
 
6
7
  INFERENCE = {
7
- "type": "inference",
8
+ "type": SPAN_TYPES.INFERENCE,
8
9
  "attributes": [
9
10
  [
10
11
  {
@@ -1,6 +1,7 @@
1
+ from monocle_apptrace.instrumentation.common.constants import SPAN_TYPES
1
2
  from monocle_apptrace.instrumentation.metamodel.azfunc import _helper
2
3
  AZFUNC_HTTP_PROCESSOR = {
3
- "type": "http.process",
4
+ "type": SPAN_TYPES.HTTP_PROCESS,
4
5
  "attributes": [
5
6
  [
6
7
  {
@@ -1,6 +1,7 @@
1
1
  import logging
2
2
  import time
3
3
  from types import SimpleNamespace
4
+ from monocle_apptrace.instrumentation.common.constants import SPAN_TYPES
4
5
  from monocle_apptrace.instrumentation.metamodel.azureaiinference import _helper
5
6
  from monocle_apptrace.instrumentation.common.utils import (
6
7
  get_error_message,
@@ -133,7 +134,7 @@ def process_stream(to_wrap, response, span_processor):
133
134
 
134
135
 
135
136
  INFERENCE = {
136
- "type": "inference",
137
+ "type": SPAN_TYPES.INFERENCE,
137
138
  "is_auto_close": lambda kwargs: kwargs.get("stream", False) is False,
138
139
  "response_processor": process_stream,
139
140
  "attributes": [
@@ -1,9 +1,10 @@
1
+ from monocle_apptrace.instrumentation.common.constants import SPAN_TYPES
1
2
  from monocle_apptrace.instrumentation.metamodel.botocore import (
2
3
  _helper,
3
4
  )
4
5
  from monocle_apptrace.instrumentation.common.utils import (get_error_message, get_llm_type, get_status,)
5
6
  INFERENCE = {
6
- "type": "inference",
7
+ "type": SPAN_TYPES.INFERENCE,
7
8
  "attributes": [
8
9
  [
9
10
  {
@@ -1,7 +1,8 @@
1
+ from monocle_apptrace.instrumentation.common.constants import SPAN_TYPES
1
2
  from monocle_apptrace.instrumentation.metamodel.fastapi import _helper
2
3
 
3
4
  FASTAPI_HTTP_PROCESSOR = {
4
- "type": "http.process",
5
+ "type": SPAN_TYPES.HTTP_PROCESS,
5
6
  "attributes": [
6
7
  [
7
8
  {