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.

Files changed (56) hide show
  1. monocle_apptrace/exporters/file_exporter.py +7 -1
  2. monocle_apptrace/instrumentation/common/constants.py +8 -0
  3. monocle_apptrace/instrumentation/common/instrumentor.py +1 -1
  4. monocle_apptrace/instrumentation/common/span_handler.py +75 -24
  5. monocle_apptrace/instrumentation/common/utils.py +63 -6
  6. monocle_apptrace/instrumentation/common/wrapper.py +111 -42
  7. monocle_apptrace/instrumentation/common/wrapper_method.py +6 -2
  8. monocle_apptrace/instrumentation/metamodel/a2a/methods.py +1 -1
  9. monocle_apptrace/instrumentation/metamodel/adk/_helper.py +7 -4
  10. monocle_apptrace/instrumentation/metamodel/adk/entities/agent.py +6 -1
  11. monocle_apptrace/instrumentation/metamodel/agents/_helper.py +8 -8
  12. monocle_apptrace/instrumentation/metamodel/agents/entities/inference.py +9 -2
  13. monocle_apptrace/instrumentation/metamodel/aiohttp/_helper.py +1 -1
  14. monocle_apptrace/instrumentation/metamodel/anthropic/entities/inference.py +1 -4
  15. monocle_apptrace/instrumentation/metamodel/azfunc/_helper.py +1 -1
  16. monocle_apptrace/instrumentation/metamodel/botocore/_helper.py +5 -0
  17. monocle_apptrace/instrumentation/metamodel/botocore/entities/inference.py +4 -0
  18. monocle_apptrace/instrumentation/metamodel/fastapi/_helper.py +4 -4
  19. monocle_apptrace/instrumentation/metamodel/fastapi/methods.py +4 -4
  20. monocle_apptrace/instrumentation/metamodel/finish_types.py +32 -1
  21. monocle_apptrace/instrumentation/metamodel/flask/_helper.py +3 -3
  22. monocle_apptrace/instrumentation/metamodel/hugging_face/__init__.py +0 -0
  23. monocle_apptrace/instrumentation/metamodel/hugging_face/_helper.py +138 -0
  24. monocle_apptrace/instrumentation/metamodel/hugging_face/entities/__init__.py +0 -0
  25. monocle_apptrace/instrumentation/metamodel/hugging_face/entities/inference.py +94 -0
  26. monocle_apptrace/instrumentation/metamodel/hugging_face/methods.py +23 -0
  27. monocle_apptrace/instrumentation/metamodel/lambdafunc/_helper.py +1 -1
  28. monocle_apptrace/instrumentation/metamodel/langchain/entities/inference.py +1 -4
  29. monocle_apptrace/instrumentation/metamodel/langgraph/_helper.py +34 -8
  30. monocle_apptrace/instrumentation/metamodel/langgraph/entities/inference.py +8 -3
  31. monocle_apptrace/instrumentation/metamodel/langgraph/langgraph_processor.py +88 -19
  32. monocle_apptrace/instrumentation/metamodel/langgraph/methods.py +22 -6
  33. monocle_apptrace/instrumentation/metamodel/llamaindex/_helper.py +30 -10
  34. monocle_apptrace/instrumentation/metamodel/llamaindex/entities/agent.py +4 -3
  35. monocle_apptrace/instrumentation/metamodel/llamaindex/llamaindex_processor.py +15 -7
  36. monocle_apptrace/instrumentation/metamodel/llamaindex/methods.py +1 -8
  37. monocle_apptrace/instrumentation/metamodel/mcp/_helper.py +7 -6
  38. monocle_apptrace/instrumentation/metamodel/mistral/_helper.py +98 -49
  39. monocle_apptrace/instrumentation/metamodel/mistral/entities/inference.py +15 -9
  40. monocle_apptrace/instrumentation/metamodel/mistral/entities/retrieval.py +41 -0
  41. monocle_apptrace/instrumentation/metamodel/mistral/methods.py +10 -1
  42. monocle_apptrace/instrumentation/metamodel/openai/_helper.py +47 -7
  43. monocle_apptrace/instrumentation/metamodel/openai/entities/inference.py +20 -4
  44. monocle_apptrace/instrumentation/metamodel/openai/methods.py +1 -1
  45. monocle_apptrace/instrumentation/metamodel/strands/_helper.py +44 -0
  46. monocle_apptrace/instrumentation/metamodel/strands/entities/agent.py +179 -0
  47. monocle_apptrace/instrumentation/metamodel/strands/entities/tool.py +62 -0
  48. monocle_apptrace/instrumentation/metamodel/strands/methods.py +20 -0
  49. {monocle_apptrace-0.5.3.dist-info → monocle_apptrace-0.6.6.dist-info}/METADATA +23 -79
  50. {monocle_apptrace-0.5.3.dist-info → monocle_apptrace-0.6.6.dist-info}/RECORD +53 -46
  51. monocle_apptrace/README.md +0 -101
  52. monocle_apptrace/mcp_server.py +0 -94
  53. monocle_apptrace-0.5.3.dist-info/licenses/NOTICE +0 -4
  54. {monocle_apptrace-0.5.3.dist-info → monocle_apptrace-0.6.6.dist-info}/WHEEL +0 -0
  55. {monocle_apptrace-0.5.3.dist-info → monocle_apptrace-0.6.6.dist-info}/entry_points.txt +0 -0
  56. {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
- return provider_url.unwrap_or(None)
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
- else:
255
- return 'openai'
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, then retain the metadata part of the span events
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
  },
@@ -56,4 +56,4 @@ OPENAI_METHODS = [
56
56
  "output_processor": INFERENCE
57
57
  }
58
58
 
59
- ]
59
+ ]
@@ -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.5.3
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.2.8; extra == 'dev'
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.37.24; extra == 'dev'
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==2.20.0; extra == 'dev'
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.1.8; extra == 'dev'
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 for tracing GenAI app code
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