monocle-apptrace 0.4.2__py3-none-any.whl → 0.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of monocle-apptrace might be problematic. Click here for more details.

Files changed (88) hide show
  1. monocle_apptrace/__main__.py +1 -1
  2. monocle_apptrace/exporters/file_exporter.py +125 -37
  3. monocle_apptrace/instrumentation/common/__init__.py +16 -1
  4. monocle_apptrace/instrumentation/common/constants.py +14 -1
  5. monocle_apptrace/instrumentation/common/instrumentor.py +19 -152
  6. monocle_apptrace/instrumentation/common/method_wrappers.py +376 -0
  7. monocle_apptrace/instrumentation/common/span_handler.py +58 -32
  8. monocle_apptrace/instrumentation/common/utils.py +52 -15
  9. monocle_apptrace/instrumentation/common/wrapper.py +124 -18
  10. monocle_apptrace/instrumentation/common/wrapper_method.py +47 -1
  11. monocle_apptrace/instrumentation/metamodel/a2a/__init__.py +0 -0
  12. monocle_apptrace/instrumentation/metamodel/a2a/_helper.py +37 -0
  13. monocle_apptrace/instrumentation/metamodel/a2a/entities/__init__.py +0 -0
  14. monocle_apptrace/instrumentation/metamodel/a2a/entities/inference.py +112 -0
  15. monocle_apptrace/instrumentation/metamodel/a2a/methods.py +22 -0
  16. monocle_apptrace/instrumentation/metamodel/adk/__init__.py +0 -0
  17. monocle_apptrace/instrumentation/metamodel/adk/_helper.py +182 -0
  18. monocle_apptrace/instrumentation/metamodel/adk/entities/agent.py +50 -0
  19. monocle_apptrace/instrumentation/metamodel/adk/entities/tool.py +57 -0
  20. monocle_apptrace/instrumentation/metamodel/adk/methods.py +24 -0
  21. monocle_apptrace/instrumentation/metamodel/agents/__init__.py +0 -0
  22. monocle_apptrace/instrumentation/metamodel/agents/_helper.py +220 -0
  23. monocle_apptrace/instrumentation/metamodel/agents/agents_processor.py +152 -0
  24. monocle_apptrace/instrumentation/metamodel/agents/entities/__init__.py +0 -0
  25. monocle_apptrace/instrumentation/metamodel/agents/entities/inference.py +191 -0
  26. monocle_apptrace/instrumentation/metamodel/agents/methods.py +56 -0
  27. monocle_apptrace/instrumentation/metamodel/aiohttp/_helper.py +6 -11
  28. monocle_apptrace/instrumentation/metamodel/anthropic/_helper.py +112 -18
  29. monocle_apptrace/instrumentation/metamodel/anthropic/entities/inference.py +18 -10
  30. monocle_apptrace/instrumentation/metamodel/azfunc/_helper.py +13 -11
  31. monocle_apptrace/instrumentation/metamodel/azfunc/entities/http.py +5 -0
  32. monocle_apptrace/instrumentation/metamodel/azureaiinference/_helper.py +88 -8
  33. monocle_apptrace/instrumentation/metamodel/azureaiinference/entities/inference.py +22 -8
  34. monocle_apptrace/instrumentation/metamodel/botocore/_helper.py +92 -16
  35. monocle_apptrace/instrumentation/metamodel/botocore/entities/inference.py +13 -8
  36. monocle_apptrace/instrumentation/metamodel/botocore/handlers/botocore_span_handler.py +1 -1
  37. monocle_apptrace/instrumentation/metamodel/fastapi/__init__.py +0 -0
  38. monocle_apptrace/instrumentation/metamodel/fastapi/_helper.py +82 -0
  39. monocle_apptrace/instrumentation/metamodel/fastapi/entities/__init__.py +0 -0
  40. monocle_apptrace/instrumentation/metamodel/fastapi/entities/http.py +44 -0
  41. monocle_apptrace/instrumentation/metamodel/fastapi/methods.py +23 -0
  42. monocle_apptrace/instrumentation/metamodel/finish_types.py +463 -0
  43. monocle_apptrace/instrumentation/metamodel/flask/_helper.py +6 -11
  44. monocle_apptrace/instrumentation/metamodel/gemini/_helper.py +51 -7
  45. monocle_apptrace/instrumentation/metamodel/gemini/entities/inference.py +22 -11
  46. monocle_apptrace/instrumentation/metamodel/gemini/entities/retrieval.py +43 -0
  47. monocle_apptrace/instrumentation/metamodel/gemini/methods.py +18 -1
  48. monocle_apptrace/instrumentation/metamodel/haystack/_helper.py +79 -8
  49. monocle_apptrace/instrumentation/metamodel/haystack/entities/inference.py +15 -10
  50. monocle_apptrace/instrumentation/metamodel/haystack/methods.py +7 -0
  51. monocle_apptrace/instrumentation/metamodel/lambdafunc/_helper.py +78 -0
  52. monocle_apptrace/instrumentation/metamodel/lambdafunc/entities/http.py +51 -0
  53. monocle_apptrace/instrumentation/metamodel/lambdafunc/methods.py +23 -0
  54. monocle_apptrace/instrumentation/metamodel/lambdafunc/wrapper.py +23 -0
  55. monocle_apptrace/instrumentation/metamodel/langchain/_helper.py +145 -19
  56. monocle_apptrace/instrumentation/metamodel/langchain/entities/inference.py +19 -10
  57. monocle_apptrace/instrumentation/metamodel/langgraph/_helper.py +67 -10
  58. monocle_apptrace/instrumentation/metamodel/langgraph/entities/inference.py +127 -20
  59. monocle_apptrace/instrumentation/metamodel/langgraph/langgraph_processor.py +46 -0
  60. monocle_apptrace/instrumentation/metamodel/langgraph/methods.py +35 -9
  61. monocle_apptrace/instrumentation/metamodel/litellm/__init__.py +0 -0
  62. monocle_apptrace/instrumentation/metamodel/litellm/_helper.py +89 -0
  63. monocle_apptrace/instrumentation/metamodel/litellm/entities/__init__.py +0 -0
  64. monocle_apptrace/instrumentation/metamodel/litellm/entities/inference.py +108 -0
  65. monocle_apptrace/instrumentation/metamodel/litellm/methods.py +19 -0
  66. monocle_apptrace/instrumentation/metamodel/llamaindex/_helper.py +227 -16
  67. monocle_apptrace/instrumentation/metamodel/llamaindex/entities/agent.py +127 -10
  68. monocle_apptrace/instrumentation/metamodel/llamaindex/entities/inference.py +13 -8
  69. monocle_apptrace/instrumentation/metamodel/llamaindex/llamaindex_processor.py +62 -0
  70. monocle_apptrace/instrumentation/metamodel/llamaindex/methods.py +68 -1
  71. monocle_apptrace/instrumentation/metamodel/mcp/__init__.py +0 -0
  72. monocle_apptrace/instrumentation/metamodel/mcp/_helper.py +118 -0
  73. monocle_apptrace/instrumentation/metamodel/mcp/entities/__init__.py +0 -0
  74. monocle_apptrace/instrumentation/metamodel/mcp/entities/inference.py +48 -0
  75. monocle_apptrace/instrumentation/metamodel/mcp/mcp_processor.py +8 -0
  76. monocle_apptrace/instrumentation/metamodel/mcp/methods.py +21 -0
  77. monocle_apptrace/instrumentation/metamodel/openai/_helper.py +188 -16
  78. monocle_apptrace/instrumentation/metamodel/openai/entities/inference.py +148 -92
  79. monocle_apptrace/instrumentation/metamodel/openai/entities/retrieval.py +1 -1
  80. monocle_apptrace/instrumentation/metamodel/teamsai/_helper.py +53 -23
  81. monocle_apptrace/instrumentation/metamodel/teamsai/entities/inference/actionplanner_output_processor.py +1 -1
  82. monocle_apptrace/instrumentation/metamodel/teamsai/entities/inference/teamsai_output_processor.py +15 -9
  83. monocle_apptrace/instrumentation/metamodel/teamsai/sample.json +0 -4
  84. {monocle_apptrace-0.4.2.dist-info → monocle_apptrace-0.5.0.dist-info}/METADATA +27 -11
  85. {monocle_apptrace-0.4.2.dist-info → monocle_apptrace-0.5.0.dist-info}/RECORD +88 -47
  86. {monocle_apptrace-0.4.2.dist-info → monocle_apptrace-0.5.0.dist-info}/WHEEL +0 -0
  87. {monocle_apptrace-0.4.2.dist-info → monocle_apptrace-0.5.0.dist-info}/licenses/LICENSE +0 -0
  88. {monocle_apptrace-0.4.2.dist-info → monocle_apptrace-0.5.0.dist-info}/licenses/NOTICE +0 -0
@@ -6,117 +6,159 @@ from monocle_apptrace.instrumentation.metamodel.openai import (
6
6
  _helper,
7
7
  )
8
8
  from monocle_apptrace.instrumentation.common.utils import (
9
+ get_error_message,
9
10
  patch_instance_method,
10
11
  resolve_from_alias,
11
- get_status,
12
- get_exception_status_code,
13
- get_status_code,
14
12
  )
15
13
 
16
14
  logger = logging.getLogger(__name__)
17
15
 
18
16
 
17
+ def _process_stream_item(item, state):
18
+ """Process a single stream item and update state."""
19
+ try:
20
+ if (
21
+ hasattr(item, "type")
22
+ and isinstance(item.type, str)
23
+ and item.type.startswith("response.")
24
+ ):
25
+ if state["waiting_for_first_token"]:
26
+ state["waiting_for_first_token"] = False
27
+ state["first_token_time"] = time.time_ns()
28
+ if item.type == "response.output_text.delta":
29
+ state["accumulated_response"] += item.delta
30
+ if item.type == "response.completed":
31
+ state["stream_closed_time"] = time.time_ns()
32
+ if hasattr(item, "response") and hasattr(item.response, "usage"):
33
+ state["token_usage"] = item.response.usage
34
+ elif (
35
+ hasattr(item, "choices")
36
+ and item.choices
37
+ and item.choices[0].delta
38
+ and item.choices[0].delta.content
39
+ ):
40
+ if hasattr(item.choices[0].delta, "role") and item.choices[0].delta.role:
41
+ state["role"] = item.choices[0].delta.role
42
+ if state["waiting_for_first_token"]:
43
+ state["waiting_for_first_token"] = False
44
+ state["first_token_time"] = time.time_ns()
45
+
46
+ state["accumulated_response"] += item.choices[0].delta.content
47
+ elif (
48
+ hasattr(item, "object")
49
+ and item.object == "chat.completion.chunk"
50
+ and item.usage
51
+ ):
52
+ # Handle the case where the response is a chunk
53
+ state["token_usage"] = item.usage
54
+ state["stream_closed_time"] = time.time_ns()
55
+ # Capture finish_reason from the chunk
56
+ if (
57
+ hasattr(item, "choices")
58
+ and item.choices
59
+ and len(item.choices) > 0
60
+ and hasattr(item.choices[0], "finish_reason")
61
+ and item.choices[0].finish_reason
62
+ ):
63
+ finish_reason = item.choices[0].finish_reason
64
+ state["finish_reason"] = finish_reason
65
+
66
+ except Exception as e:
67
+ logger.warning(
68
+ "Warning: Error occurred while processing stream item: %s",
69
+ str(e),
70
+ )
71
+ finally:
72
+ state["accumulated_temp_list"].append(item)
73
+
74
+
75
+ def _create_span_result(state, stream_start_time):
76
+ # extract tool calls from the accumulated_temp_list
77
+ # this can only be done when all the streaming is complete.
78
+ for item in state["accumulated_temp_list"]:
79
+ try:
80
+ if (
81
+ item.choices
82
+ and isinstance(item.choices, list)
83
+ and hasattr(item.choices[0], "delta")
84
+ and hasattr(item.choices[0].delta, "tool_calls")
85
+ and item.choices[0].delta.tool_calls
86
+ and item.choices[0].delta.tool_calls[0].id
87
+ and item.choices[0].delta.tool_calls[0].function
88
+ ):
89
+ state["tools"] = state.get("tools", [])
90
+ state["tools"].append(
91
+ {
92
+ "id": item.choices[0].delta.tool_calls[0].id,
93
+ "name": item.choices[0].delta.tool_calls[0].function.name,
94
+ "arguments": item.choices[0]
95
+ .delta.tool_calls[0]
96
+ .function.arguments,
97
+ }
98
+ )
99
+ if (item.choices and item.choices[0].finish_reason):
100
+ state["finish_reason"] = item.choices[0].finish_reason
101
+ except Exception as e:
102
+ logger.warning(
103
+ "Warning: Error occurred while processing tool calls: %s",
104
+ str(e),
105
+ )
106
+
107
+ """Create the span result object."""
108
+ return SimpleNamespace(
109
+ type="stream",
110
+ timestamps={
111
+ "role": state["role"],
112
+ "data.input": int(stream_start_time),
113
+ "data.output": int(state["first_token_time"]),
114
+ "metadata": int(state["stream_closed_time"] or time.time_ns()),
115
+ },
116
+ output_text=state["accumulated_response"],
117
+ tools=state["tools"] if "tools" in state else None,
118
+ usage=state["token_usage"],
119
+ finish_reason=state["finish_reason"],
120
+ )
121
+
122
+
19
123
  def process_stream(to_wrap, response, span_processor):
20
- waiting_for_first_token = True
21
124
  stream_start_time = time.time_ns()
22
- first_token_time = stream_start_time
23
- stream_closed_time = None
24
- accumulated_response = ""
25
- token_usage = None
26
- accumulated_temp_list = []
125
+
126
+ # Shared state for both sync and async processing
127
+ state = {
128
+ "waiting_for_first_token": True,
129
+ "first_token_time": stream_start_time,
130
+ "stream_closed_time": None,
131
+ "accumulated_response": "",
132
+ "token_usage": None,
133
+ "accumulated_temp_list": [],
134
+ "finish_reason": None,
135
+ "role": "assistant",
136
+ }
27
137
 
28
138
  if to_wrap and hasattr(response, "__iter__"):
29
139
  original_iter = response.__iter__
30
140
 
31
141
  def new_iter(self):
32
- nonlocal waiting_for_first_token, first_token_time, stream_closed_time, accumulated_response, token_usage
33
-
34
142
  for item in original_iter():
35
- try:
36
- if (
37
- item.choices
38
- and item.choices[0].delta
39
- and item.choices[0].delta.content
40
- ):
41
- if waiting_for_first_token:
42
- waiting_for_first_token = False
43
- first_token_time = time.time_ns()
44
-
45
- accumulated_response += item.choices[0].delta.content
46
- # token_usage = item.usage
47
- elif item.object == "chat.completion.chunk" and item.usage:
48
- # Handle the case where the response is a chunk
49
- token_usage = item.usage
50
- stream_closed_time = time.time_ns()
51
-
52
- except Exception as e:
53
- logger.warning(
54
- "Warning: Error occurred while processing item in new_iter: %s",
55
- str(e),
56
- )
57
- finally:
58
- accumulated_temp_list.append(item)
59
- yield item
143
+ _process_stream_item(item, state)
144
+ yield item
60
145
 
61
146
  if span_processor:
62
- ret_val = SimpleNamespace(
63
- type="stream",
64
- timestamps={
65
- "data.input": int(stream_start_time),
66
- "data.output": int(first_token_time),
67
- "metadata": int(stream_closed_time or time.time_ns()),
68
- },
69
- output_text=accumulated_response,
70
- usage=token_usage,
71
- )
147
+ ret_val = _create_span_result(state, stream_start_time)
72
148
  span_processor(ret_val)
73
149
 
74
150
  patch_instance_method(response, "__iter__", new_iter)
75
-
151
+
76
152
  if to_wrap and hasattr(response, "__aiter__"):
77
153
  original_iter = response.__aiter__
78
154
 
79
155
  async def new_aiter(self):
80
- nonlocal waiting_for_first_token, first_token_time, stream_closed_time, accumulated_response, token_usage
81
-
82
156
  async for item in original_iter():
83
- try:
84
- if (
85
- item.choices
86
- and item.choices[0].delta
87
- and item.choices[0].delta.content
88
- ):
89
- if waiting_for_first_token:
90
- waiting_for_first_token = False
91
- first_token_time = time.time_ns()
92
-
93
- accumulated_response += item.choices[0].delta.content
94
- # token_usage = item.usage
95
- elif item.object == "chat.completion.chunk" and item.usage:
96
- # Handle the case where the response is a chunk
97
- token_usage = item.usage
98
- stream_closed_time = time.time_ns()
99
-
100
- except Exception as e:
101
- logger.warning(
102
- "Warning: Error occurred while processing item in new_aiter: %s",
103
- str(e),
104
- )
105
- finally:
106
- accumulated_temp_list.append(item)
107
- yield item
157
+ _process_stream_item(item, state)
158
+ yield item
108
159
 
109
160
  if span_processor:
110
- ret_val = SimpleNamespace(
111
- type="stream",
112
- timestamps={
113
- "data.input": int(stream_start_time),
114
- "data.output": int(first_token_time),
115
- "metadata": int(stream_closed_time or time.time_ns()),
116
- },
117
- output_text=accumulated_response,
118
- usage=token_usage,
119
- )
161
+ ret_val = _create_span_result(state, stream_start_time)
120
162
  span_processor(ret_val)
121
163
 
122
164
  patch_instance_method(response, "__aiter__", new_aiter)
@@ -198,6 +240,10 @@ INFERENCE = {
198
240
  {
199
241
  "name": "data.output",
200
242
  "attributes": [
243
+ {
244
+ "attribute": "error_code",
245
+ "accessor": lambda arguments: get_error_message(arguments),
246
+ },
201
247
  {
202
248
  "_comment": "this is result from LLM",
203
249
  "attribute": "response",
@@ -205,14 +251,6 @@ INFERENCE = {
205
251
  arguments,
206
252
  ),
207
253
  },
208
- {
209
- "attribute": "status",
210
- "accessor": lambda arguments: get_status(arguments)
211
- },
212
- {
213
- "attribute": "status_code",
214
- "accessor": lambda arguments: get_status_code(arguments)
215
- }
216
254
  ],
217
255
  },
218
256
  {
@@ -223,6 +261,24 @@ INFERENCE = {
223
261
  "accessor": lambda arguments: _helper.update_span_from_llm_response(
224
262
  arguments["result"]
225
263
  ),
264
+ },
265
+ {
266
+ "_comment": "finish reason from OpenAI response",
267
+ "attribute": "finish_reason",
268
+ "accessor": lambda arguments: _helper.extract_finish_reason(
269
+ arguments
270
+ ),
271
+ },
272
+ {
273
+ "_comment": "finish type mapped from finish reason",
274
+ "attribute": "finish_type",
275
+ "accessor": lambda arguments: _helper.map_finish_reason_to_finish_type(
276
+ _helper.extract_finish_reason(arguments)
277
+ ),
278
+ },
279
+ {
280
+ "attribute": "inference_sub_type",
281
+ "accessor": lambda arguments: _helper.agent_inference_type(arguments)
226
282
  }
227
283
  ],
228
284
  },
@@ -4,7 +4,7 @@ from monocle_apptrace.instrumentation.metamodel.openai import (
4
4
  from monocle_apptrace.instrumentation.common.utils import resolve_from_alias
5
5
 
6
6
  RETRIEVAL = {
7
- "type": "retrieval",
7
+ "type": "embedding",
8
8
  "attributes": [
9
9
  [
10
10
  {
@@ -1,17 +1,23 @@
1
+ import json
1
2
  import logging
2
- from monocle_apptrace.instrumentation.common.utils import MonocleSpanException
3
3
  from monocle_apptrace.instrumentation.common.utils import (
4
4
  Option,
5
+ MonocleSpanException,
5
6
  get_keys_as_tuple,
6
7
  get_nested_value,
7
8
  try_option,
8
9
  get_exception_message,
9
- get_exception_status_code
10
+ get_json_dumps,
11
+ get_status_code
10
12
  )
11
-
13
+ from monocle_apptrace.instrumentation.metamodel.finish_types import (
14
+ map_teamsai_finish_reason_to_finish_type,
15
+ TEAMSAI_FINISH_REASON_MAPPING
16
+ )
17
+ from monocle_apptrace.instrumentation.common.constants import CHILD_ERROR_CODE
12
18
  logger = logging.getLogger(__name__)
13
19
 
14
- def capture_input(arguments):
20
+ def extract_messages(arguments):
15
21
  """
16
22
  Captures the input from Teams AI state.
17
23
  Args:
@@ -47,7 +53,7 @@ def capture_input(arguments):
47
53
  if hasattr(context, "activity") and hasattr(context.activity, "text"):
48
54
  messages.append({'user': str(context.activity.text)})
49
55
 
50
- return [str(message) for message in messages]
56
+ return [get_json_dumps(message) for message in messages]
51
57
  except Exception as e:
52
58
  print(f"Debug - Arguments structure: {str(arguments)}")
53
59
  print(f"Debug - kwargs: {str(kwargs)}")
@@ -105,14 +111,6 @@ def get_prompt_template(arguments):
105
111
  "prompt_template_type": get_nested_value(arguments.get("kwargs", {}), ["prompt", "config", "type"])
106
112
  }
107
113
 
108
- def get_status_code(arguments):
109
- if arguments["exception"] is not None:
110
- return get_exception_status_code(arguments)
111
- elif hasattr(arguments["result"], "status"):
112
- return arguments["result"].status
113
- else:
114
- return 'success'
115
-
116
114
  def get_status(arguments):
117
115
  if arguments["exception"] is not None:
118
116
  return 'error'
@@ -120,27 +118,49 @@ def get_status(arguments):
120
118
  return 'success'
121
119
  else:
122
120
  return 'error'
123
-
124
- def get_response(arguments) -> str:
121
+
122
+ def extract_assistant_message(arguments) -> str:
125
123
  status = get_status_code(arguments)
126
- response:str = ""
124
+ messages = []
125
+ role = "assistant"
127
126
  if status == 'success':
128
127
  if hasattr(arguments["result"], "message"):
129
- response = arguments["result"].message.content
128
+ messages.append({role: arguments["result"].message.content})
130
129
  else:
131
- response = str(arguments["result"])
130
+ messages.append({role: str(arguments["result"])})
132
131
  else:
133
132
  if arguments["exception"] is not None:
134
- response = get_exception_message(arguments)
133
+ return get_exception_message(arguments)
135
134
  elif hasattr(arguments["result"], "error"):
136
- response = arguments["result"].error
137
- return response
135
+ return arguments["result"].error
136
+ return get_json_dumps(messages[0]) if messages else ""
137
+
138
+ def extract_finish_reason(arguments):
139
+ """Map TeamAI finish_reason to standardized finish_type."""
140
+ return get_status_code(arguments)
141
+
142
+ def extract_status_code(arguments):
143
+ # TeamsAI doesn't capture the status and other metadata from underlying OpenAI SDK.
144
+ # Thus we save the OpenAI status code in the parent span and retrieve it here to preserve meaningful error codes.
145
+ status = get_status_code(arguments)
146
+ if status == 'error' and arguments['exception'] is None:
147
+ child_status = arguments['span'].attributes.get(CHILD_ERROR_CODE)
148
+ if child_status is not None:
149
+ return child_status
150
+ return status
138
151
 
139
152
  def check_status(arguments):
140
153
  status = get_status_code(arguments)
141
- if status != 'success':
154
+ if status != 'success' and arguments['exception'] is None:
142
155
  raise MonocleSpanException(f"{status}")
143
156
 
157
+ def map_finish_reason_to_finish_type(finish_reason):
158
+ """Map TeamsAI finish_reason to standardized finish_type."""
159
+ if not finish_reason:
160
+ return None
161
+
162
+ return map_teamsai_finish_reason_to_finish_type(finish_reason)
163
+
144
164
  def extract_provider_name(instance):
145
165
  provider_url: Option[str] = try_option(getattr, instance._client.base_url, 'host')
146
166
  return provider_url.unwrap_or(None)
@@ -151,4 +171,14 @@ def extract_inference_endpoint(instance):
151
171
  if inference_endpoint.is_none() and "meta" in instance.client.__dict__:
152
172
  inference_endpoint = try_option(getattr, instance.client.meta, 'endpoint_url').map(str)
153
173
 
154
- return inference_endpoint.unwrap_or(extract_provider_name(instance))
174
+ return inference_endpoint.unwrap_or(extract_provider_name(instance))
175
+
176
+ def agent_inference_type(arguments):
177
+ """
178
+ Extracts the agent inference type from the arguments.
179
+ """
180
+ output = extract_assistant_message(arguments)
181
+ command = json.loads(json.loads(output).get("assistant", "")).get("action", "").get("name")
182
+ if command == "SAY":
183
+ return "turn"
184
+ return "tool_call"
@@ -55,7 +55,7 @@ ACTIONPLANNER_OUTPUT_PROCESSOR = {
55
55
  "_comment": "output from ActionPlanner",
56
56
  "attributes": [
57
57
  {
58
- "attribute": "status",
58
+ "attribute": "status_check",
59
59
  "accessor": lambda arguments: _helper.status_check(arguments)
60
60
  },
61
61
  {
@@ -1,7 +1,7 @@
1
1
  from monocle_apptrace.instrumentation.metamodel.teamsai import (
2
2
  _helper,
3
3
  )
4
- from monocle_apptrace.instrumentation.common.utils import get_llm_type
4
+ from monocle_apptrace.instrumentation.common.utils import get_error_message, get_llm_type
5
5
  TEAMAI_OUTPUT_PROCESSOR = {
6
6
  "type": "inference.framework",
7
7
  "attributes": [
@@ -44,7 +44,7 @@ TEAMAI_OUTPUT_PROCESSOR = {
44
44
  "attributes": [
45
45
  {
46
46
  "attribute": "input",
47
- "accessor": _helper.capture_input
47
+ "accessor": _helper.extract_messages
48
48
  }
49
49
  ]
50
50
  },
@@ -53,16 +53,12 @@ TEAMAI_OUTPUT_PROCESSOR = {
53
53
  "_comment": "output from Teams AI",
54
54
  "attributes": [
55
55
  {
56
- "attribute": "status",
57
- "accessor": lambda arguments: _helper.get_status(arguments)
58
- },
59
- {
60
- "attribute": "status_code",
61
- "accessor": lambda arguments: _helper.get_status_code(arguments)
56
+ "attribute": "error_code",
57
+ "accessor": lambda arguments: _helper.extract_status_code(arguments)
62
58
  },
63
59
  {
64
60
  "attribute": "response",
65
- "accessor": lambda arguments: _helper.get_response(arguments)
61
+ "accessor": lambda arguments: _helper.extract_assistant_message(arguments)
66
62
  },
67
63
  {
68
64
  "attribute": "check_status",
@@ -70,5 +66,15 @@ TEAMAI_OUTPUT_PROCESSOR = {
70
66
  }
71
67
  ]
72
68
  },
69
+ {
70
+ "name": "metadata",
71
+ "_comment": "metadata for Teams AI",
72
+ "attributes": [
73
+ {
74
+ "attribute": "inference_sub_type",
75
+ "accessor": lambda arguments: _helper.agent_inference_type(arguments)
76
+ }
77
+ ]
78
+ }
73
79
  ]
74
80
  }
@@ -100,8 +100,6 @@
100
100
  "name": "data.output",
101
101
  "timestamp": "2025-06-06T09:00:00.682278Z",
102
102
  "attributes": {
103
- "status": "success",
104
- "status_code": "success",
105
103
  "response": "Ah, the French press! The only thing more sophisticated than a monocle-wearing cat. Here\u2019s how to brew a cup of coffee that\u2019ll make you feel like you\u2019re sipping in a Parisian caf\u00e9:\n\n1. **Gather Your Gear**: You\u2019ll need coarsely ground coffee, hot water (just off the boil), a French press, and a timer. Optional: a beret for that extra flair.\n\n2. **Measure Your Coffee**: A good rule of thumb is"
106
104
  }
107
105
  }
@@ -324,8 +322,6 @@
324
322
  "name": "data.output",
325
323
  "timestamp": "2025-06-06T09:01:20.299355Z",
326
324
  "attributes": {
327
- "status": "success",
328
- "status_code": "success",
329
325
  "response": "Brewing coffee can be a delightful experience, and there are several methods to choose from. Below, I\u2019ll provide a detailed guide for three popular brewing methods: Pour-Over, French Press, and Espresso. Each method has its unique characteristics, so you can choose one based on your preference.\n\n### 1. Pour-Over Coffee\n\n**Equipment Needed:**\n- Pour-over dripper (e.g., Hario V60, Chemex)\n- Coffee filter\n- Kettle (preferably a gooseneck kettle for control)\n- Scale\n- Coffee grinder\n- Mug or carafe\n\n**Ingredients:**\n- Fresh coffee beans (medium roast recommended)\n- Filtered water\n\n**Steps:**\n1. **Measure Coffee:** Use a coffee-to-water ratio of 1:15. For example, for 300g of water, use 20g of coffee.\n2. **Grind Coffee:** Grind the coffee to a medium-coarse consistency, similar to sea salt.\n3. **Boil Water:** Heat water to about 200\u00b0F (93\u00b0C). If you don\u2019t have a thermometer, bring water to a boil and let it sit for 30 seconds.\n4. **Prepare Filter:** Place the coffee filter in the dripper and rinse it with hot water to eliminate paper taste and preheat the dripper.\n5. **Add Coffee:** Place the ground coffee in the filter and create a small well in the center.\n6. **Bloom:** Pour just enough hot water (about 40g) to saturate the grounds. Let it bloom for 30-45 seconds.\n7. **Brew:** Slowly pour the remaining water in a circular motion, avoiding the edges. Aim to finish pouring in about 2-3 minutes.\n8. **Serve:** Once the water has fully drained, remove the dripper, and enjoy your coffee!\n\n### 2. French Press Coffee\n\n**Equipment Needed:**\n- French press\n- Kettle\n- Scale\n- Coffee grinder\n- Stirring spoon\n- Timer\n\n**Ingredients:**\n- Fresh coffee beans (coarse grind recommended)\n- Filtered water\n\n**Steps:**\n1. **Measure Coffee:** Use a coffee-to-water ratio of 1:15. For example, for 350g of water, use 23g of coffee.\n2. **Grind Coffee:** Grind the coffee to a coarse consistency, similar to breadcrumbs.\n3. **Boil Water:** Heat water to about 200\u00b0F (93\u00b0C).\n4. **Add Coffee:** Place the ground coffee in the French press.\n5. **Add Water:** Pour hot water over the coffee grounds, ensuring all grounds are saturated. Stir gently to mix.\n6. **Steep:** Place the lid on the French press and let it steep for 4 minutes.\n7. **Press:** Slowly press the plunger down to separate the grounds from the coffee.\n8. **Serve:** Pour the coffee into your mug and enjoy!\n\n### 3. Espresso\n\n**Equipment Needed:**\n- Espresso machine\n- Coffee grinder\n- Tamper\n- Scale\n- Shot glass or demitasse\n\n**Ingredients:**\n- Fresh coffee beans (dark roast recommended)\n- Filtered water\n\n**Steps:**\n1. **Measure Coffee:** Use about 18-20g of coffee for a double shot (about 60ml).\n2. **Grind Coffee:** Grind the coffee to a fine consistency, similar to table salt.\n3. **Preheat Machine:** Turn on your espresso machine and allow it to heat up.\n4. **Add Coffee:** Place the ground coffee in the portafilter and distribute evenly.\n5. **Tamp:** Use a tamper to press the coffee evenly and firmly.\n6. **Brew:** Lock the portafilter into the machine and start the extraction. Aim for a brew time of 25-30 seconds.\n7. **Serve:** Once the espresso is brewed, pour it into a shot glass or demitasse and enjoy!\n\n### Troubleshooting Common Problems\n\n- **Bitter Coffee:** This can be due to over-extraction. Try a coarser grind or reduce the brew time.\n- **Weak Coffee:** This may be due to under-extraction. Use a finer grind or increase the brew time.\n- **Sour Coffee:** This can happen if the coffee is under-extracted or brewed with water that is too cool. Ensure your water is at the right temperature.\n\n### Conclusion\n\nEach brewing method has its nuances, and experimenting with different variables (grind size, water temperature, brew time) can help you find your perfect cup. Enjoy the process, and happy brewing!"
330
326
  }
331
327
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: monocle_apptrace
3
- Version: 0.4.2
3
+ Version: 0.5.0
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
@@ -20,43 +20,59 @@ Requires-Dist: boto3==1.37.24; extra == 'aws'
20
20
  Provides-Extra: azure
21
21
  Requires-Dist: azure-storage-blob==12.22.0; extra == 'azure'
22
22
  Provides-Extra: dev
23
+ Requires-Dist: a2a-sdk==0.2.8; extra == 'dev'
23
24
  Requires-Dist: anthropic-haystack; extra == 'dev'
24
- Requires-Dist: anthropic==0.52.0; extra == 'dev'
25
+ Requires-Dist: anthropic==0.57.1; extra == 'dev'
25
26
  Requires-Dist: azure-storage-blob==12.22.0; extra == 'dev'
26
27
  Requires-Dist: boto3==1.37.24; extra == 'dev'
27
- Requires-Dist: chromadb==1.0.10; extra == 'dev'
28
+ Requires-Dist: chromadb==1.0.15; extra == 'dev'
29
+ Requires-Dist: click==8.2.1; extra == 'dev'
28
30
  Requires-Dist: datasets==2.20.0; extra == 'dev'
29
31
  Requires-Dist: faiss-cpu==1.8.0; extra == 'dev'
32
+ Requires-Dist: fastapi>=0.115.0; extra == 'dev'
30
33
  Requires-Dist: flask; extra == 'dev'
34
+ Requires-Dist: google-adk==1.10.0; extra == 'dev'
35
+ Requires-Dist: google-generativeai==0.8.5; extra == 'dev'
31
36
  Requires-Dist: haystack-ai==2.3.0; extra == 'dev'
37
+ Requires-Dist: httpx==0.28.1; extra == 'dev'
32
38
  Requires-Dist: instructorembedding==1.0.1; extra == 'dev'
33
39
  Requires-Dist: langchain-anthropic==0.3.13; extra == 'dev'
34
40
  Requires-Dist: langchain-aws==0.2.23; extra == 'dev'
35
41
  Requires-Dist: langchain-chroma==0.2.4; extra == 'dev'
36
42
  Requires-Dist: langchain-community==0.3.24; extra == 'dev'
43
+ Requires-Dist: langchain-google-genai==2.1.8; extra == 'dev'
44
+ Requires-Dist: langchain-mcp-adapters==0.1.8; extra == 'dev'
37
45
  Requires-Dist: langchain-mistralai==0.2.10; extra == 'dev'
38
46
  Requires-Dist: langchain-openai==0.3.18; extra == 'dev'
39
47
  Requires-Dist: langchain==0.3.25; extra == 'dev'
40
48
  Requires-Dist: langchainhub==0.1.21; extra == 'dev'
41
- Requires-Dist: langgraph==0.2.68; extra == 'dev'
42
- Requires-Dist: llama-index-embeddings-huggingface==0.5.4; extra == 'dev'
43
- Requires-Dist: llama-index-llms-anthropic==0.6.19; extra == 'dev'
44
- Requires-Dist: llama-index-llms-azure-openai==0.3.2; extra == 'dev'
45
- Requires-Dist: llama-index-llms-mistralai==0.4.0; extra == 'dev'
46
- Requires-Dist: llama-index-vector-stores-chroma==0.4.1; extra == 'dev'
47
- Requires-Dist: llama-index-vector-stores-opensearch==0.5.4; extra == 'dev'
48
- Requires-Dist: llama-index==0.12.37; extra == 'dev'
49
+ Requires-Dist: langgraph-supervisor==0.0.28; extra == 'dev'
50
+ Requires-Dist: langgraph==0.5.4; extra == 'dev'
51
+ Requires-Dist: llama-index-embeddings-huggingface==0.6.0; extra == 'dev'
52
+ Requires-Dist: llama-index-llms-anthropic==0.8.1; extra == 'dev'
53
+ Requires-Dist: llama-index-llms-azure-openai==0.4.0; extra == 'dev'
54
+ Requires-Dist: llama-index-llms-mistralai==0.7.0; extra == 'dev'
55
+ Requires-Dist: llama-index-llms-openai==0.5.0; extra == 'dev'
56
+ Requires-Dist: llama-index-tools-mcp==0.3.0; extra == 'dev'
57
+ Requires-Dist: llama-index-vector-stores-chroma==0.5.0; extra == 'dev'
58
+ Requires-Dist: llama-index-vector-stores-opensearch==0.6.0; extra == 'dev'
59
+ Requires-Dist: llama-index==0.13.0; extra == 'dev'
60
+ Requires-Dist: mcp==1.12.1; extra == 'dev'
49
61
  Requires-Dist: mistral-haystack==0.0.2; extra == 'dev'
50
62
  Requires-Dist: numpy==1.26.4; extra == 'dev'
63
+ Requires-Dist: openai-agents==0.2.6; extra == 'dev'
51
64
  Requires-Dist: opendal==0.45.14; extra == 'dev'
52
65
  Requires-Dist: opensearch-haystack==1.2.0; extra == 'dev'
53
66
  Requires-Dist: opentelemetry-instrumentation-flask; extra == 'dev'
54
67
  Requires-Dist: parameterized==0.9.0; extra == 'dev'
68
+ Requires-Dist: pydantic==2.11.7; extra == 'dev'
55
69
  Requires-Dist: pytest-asyncio==0.26.0; extra == 'dev'
56
70
  Requires-Dist: pytest==8.3.5; extra == 'dev'
71
+ Requires-Dist: python-dotenv>=1.1.0; extra == 'dev'
57
72
  Requires-Dist: requests-aws4auth==1.2.3; extra == 'dev'
58
73
  Requires-Dist: sentence-transformers==2.6.1; extra == 'dev'
59
74
  Requires-Dist: types-requests==2.31.0.20240106; extra == 'dev'
75
+ Requires-Dist: uvicorn==0.35.0; extra == 'dev'
60
76
  Description-Content-Type: text/markdown
61
77
 
62
78
  # Monocle for tracing GenAI app code