monocle-apptrace 0.4.0b2__py3-none-any.whl → 0.4.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 (37) hide show
  1. monocle_apptrace/instrumentation/__init__.py +2 -1
  2. monocle_apptrace/instrumentation/common/constants.py +3 -0
  3. monocle_apptrace/instrumentation/common/instrumentor.py +1 -1
  4. monocle_apptrace/instrumentation/common/span_handler.py +8 -6
  5. monocle_apptrace/instrumentation/common/utils.py +33 -2
  6. monocle_apptrace/instrumentation/common/wrapper.py +59 -79
  7. monocle_apptrace/instrumentation/common/wrapper_method.py +5 -1
  8. monocle_apptrace/instrumentation/metamodel/anthropic/_helper.py +29 -4
  9. monocle_apptrace/instrumentation/metamodel/anthropic/entities/inference.py +12 -2
  10. monocle_apptrace/instrumentation/metamodel/azfunc/_helper.py +78 -0
  11. monocle_apptrace/instrumentation/metamodel/azfunc/entities/http.py +51 -0
  12. monocle_apptrace/instrumentation/metamodel/azfunc/methods.py +23 -0
  13. monocle_apptrace/instrumentation/metamodel/azfunc/wrapper.py +23 -0
  14. monocle_apptrace/instrumentation/metamodel/azureaiinference/__init__.py +1 -0
  15. monocle_apptrace/instrumentation/metamodel/azureaiinference/_helper.py +216 -0
  16. monocle_apptrace/instrumentation/metamodel/azureaiinference/entities/inference.py +208 -0
  17. monocle_apptrace/instrumentation/metamodel/azureaiinference/methods.py +23 -0
  18. monocle_apptrace/instrumentation/metamodel/botocore/_helper.py +42 -17
  19. monocle_apptrace/instrumentation/metamodel/botocore/entities/inference.py +11 -3
  20. monocle_apptrace/instrumentation/metamodel/flask/_helper.py +1 -1
  21. monocle_apptrace/instrumentation/metamodel/haystack/_helper.py +20 -12
  22. monocle_apptrace/instrumentation/metamodel/haystack/entities/inference.py +10 -2
  23. monocle_apptrace/instrumentation/metamodel/langchain/_helper.py +19 -13
  24. monocle_apptrace/instrumentation/metamodel/langchain/entities/inference.py +10 -2
  25. monocle_apptrace/instrumentation/metamodel/llamaindex/_helper.py +21 -13
  26. monocle_apptrace/instrumentation/metamodel/llamaindex/entities/inference.py +10 -2
  27. monocle_apptrace/instrumentation/metamodel/openai/_helper.py +31 -10
  28. monocle_apptrace/instrumentation/metamodel/openai/entities/inference.py +12 -1
  29. monocle_apptrace/instrumentation/metamodel/teamsai/_helper.py +50 -4
  30. monocle_apptrace/instrumentation/metamodel/teamsai/entities/inference/actionplanner_output_processor.py +32 -12
  31. monocle_apptrace/instrumentation/metamodel/teamsai/methods.py +30 -17
  32. monocle_apptrace/instrumentation/metamodel/teamsai/sample.json +448 -0
  33. {monocle_apptrace-0.4.0b2.dist-info → monocle_apptrace-0.4.1.dist-info}/METADATA +21 -18
  34. {monocle_apptrace-0.4.0b2.dist-info → monocle_apptrace-0.4.1.dist-info}/RECORD +37 -28
  35. {monocle_apptrace-0.4.0b2.dist-info → monocle_apptrace-0.4.1.dist-info}/WHEEL +0 -0
  36. {monocle_apptrace-0.4.0b2.dist-info → monocle_apptrace-0.4.1.dist-info}/licenses/LICENSE +0 -0
  37. {monocle_apptrace-0.4.0b2.dist-info → monocle_apptrace-0.4.1.dist-info}/licenses/NOTICE +0 -0
@@ -0,0 +1,216 @@
1
+ import logging
2
+ from typing import Any, Dict, Optional
3
+ from urllib.parse import urlparse
4
+ from monocle_apptrace.instrumentation.common.utils import (
5
+ resolve_from_alias,
6
+ get_exception_message,
7
+ )
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ def extract_messages(args_or_kwargs: Any) -> str:
13
+ """Extract messages from azure-ai-inference request arguments."""
14
+ try:
15
+ messages = []
16
+ if "instructions" in args_or_kwargs:
17
+ messages.append({"instructions": args_or_kwargs.get("instructions", {})})
18
+ if "input" in args_or_kwargs:
19
+ messages.append({"input": args_or_kwargs.get("input", {})})
20
+ if "messages" in args_or_kwargs and len(args_or_kwargs["messages"]) > 0:
21
+ for msg in args_or_kwargs["messages"]:
22
+ if msg.get("content") and msg.get("role"):
23
+ messages.append({msg["role"]: msg["content"]})
24
+
25
+ return [str(message) for message in messages]
26
+ except Exception as e:
27
+ logger.warning("Warning: Error occurred in extract_messages: %s", str(e))
28
+ return []
29
+
30
+
31
+ def extract_inference_endpoint(instance: Any) -> str:
32
+ """Extract inference endpoint from azure-ai-inference client instance."""
33
+ try:
34
+ return instance._config.endpoint
35
+ except Exception as e:
36
+ logger.warning(
37
+ "Warning: Error occurred in extract_inference_endpoint: %s", str(e)
38
+ )
39
+ return ""
40
+
41
+
42
+ def extract_embeddings_input(args_or_kwargs: Any) -> str:
43
+ """Extract input text from azure-ai-inference embeddings request."""
44
+ try:
45
+ # Handle both args and kwargs scenarios
46
+ if isinstance(args_or_kwargs, dict):
47
+ if "input" in args_or_kwargs:
48
+ input_data = args_or_kwargs["input"]
49
+ elif len(args_or_kwargs) > 0:
50
+ first_arg = list(args_or_kwargs.values())[0]
51
+ if isinstance(first_arg, dict) and "input" in first_arg:
52
+ input_data = first_arg["input"]
53
+ else:
54
+ input_data = first_arg
55
+ else:
56
+ return ""
57
+ elif hasattr(args_or_kwargs, "__iter__") and len(args_or_kwargs) > 0:
58
+ first_arg = args_or_kwargs[0]
59
+ if hasattr(first_arg, "get") and "input" in first_arg:
60
+ input_data = first_arg["input"]
61
+ else:
62
+ input_data = first_arg
63
+ else:
64
+ return ""
65
+
66
+ # Format input for display
67
+ if isinstance(input_data, (list, tuple)):
68
+ return " | ".join(str(item) for item in input_data)
69
+ else:
70
+ return str(input_data)
71
+ except Exception as e:
72
+ logger.warning(
73
+ "Warning: Error occurred in extract_embeddings_input: %s", str(e)
74
+ )
75
+ return ""
76
+
77
+
78
+ def extract_assistant_message(arguments: Dict[str, Any]) -> str:
79
+ """Extract assistant response from azure-ai-inference completion result."""
80
+ try:
81
+ # Check for exception first
82
+ if arguments.get("exception") is not None:
83
+ return get_exception_message(arguments)
84
+
85
+ result = arguments.get("result")
86
+ if not result:
87
+ return ""
88
+ if hasattr(result, "output_text"):
89
+ # If the result has output_text attribute
90
+ return result.output_text
91
+ if (
92
+ result.choices
93
+ and result.choices[0].message
94
+ and result.choices[0].message.content
95
+ ):
96
+ # If the result is a chat completion with content
97
+ return result.choices[0].message.content
98
+
99
+ return str(result)
100
+ except Exception as e:
101
+ logger.warning(
102
+ "Warning: Error occurred in extract_assistant_message: %s", str(e)
103
+ )
104
+ return ""
105
+
106
+
107
+ def extract_embeddings_output(arguments: Dict[str, Any]) -> str:
108
+ """Extract embeddings from azure-ai-inference embeddings result."""
109
+ try:
110
+ result = arguments.get("result")
111
+ if not result:
112
+ return ""
113
+
114
+ if hasattr(result, "data") and result.data:
115
+ # Format as summary of embeddings data
116
+ embeddings_info = []
117
+ for i, item in enumerate(result.data):
118
+ if hasattr(item, "embedding") and hasattr(item, "index"):
119
+ embedding_length = len(item.embedding) if item.embedding else 0
120
+ embeddings_info.append(
121
+ f"index={item.index}, embedding=[{embedding_length} dimensions]"
122
+ )
123
+ return " | ".join(embeddings_info)
124
+
125
+ return str(result)
126
+ except Exception as e:
127
+ logger.warning(
128
+ "Warning: Error occurred in extract_embeddings_output: %s", str(e)
129
+ )
130
+ return ""
131
+
132
+
133
+ def update_span_from_llm_response(result: Any, instance: Any = None) -> Dict[str, Any]:
134
+ """Extract usage metadata from azure-ai-inference response."""
135
+ try:
136
+ attributes = {}
137
+
138
+ # Handle streaming responses with accumulated usage data
139
+ if hasattr(result, "usage") and result.usage:
140
+ usage = result.usage
141
+ if hasattr(usage, "completion_tokens"):
142
+ attributes["completion_tokens"] = usage.completion_tokens
143
+ if hasattr(usage, "prompt_tokens"):
144
+ attributes["prompt_tokens"] = usage.prompt_tokens
145
+ if hasattr(usage, "total_tokens"):
146
+ attributes["total_tokens"] = usage.total_tokens
147
+
148
+ # Handle regular response usage
149
+ elif hasattr(result, "usage"):
150
+ usage = result.usage
151
+ if hasattr(usage, "completion_tokens"):
152
+ attributes["completion_tokens"] = usage.completion_tokens
153
+ if hasattr(usage, "prompt_tokens"):
154
+ attributes["prompt_tokens"] = usage.prompt_tokens
155
+ if hasattr(usage, "total_tokens"):
156
+ attributes["total_tokens"] = usage.total_tokens
157
+
158
+ # Extract model information if available
159
+ if hasattr(result, "model"):
160
+ attributes["model"] = result.model
161
+
162
+ return attributes
163
+ except Exception as e:
164
+ logger.warning(
165
+ "Warning: Error occurred in update_span_from_llm_response: %s", str(e)
166
+ )
167
+ return {}
168
+
169
+
170
+ def get_model_name(arguments: Dict[str, Any]) -> str:
171
+ """Extract model name from azure-ai-inference request arguments."""
172
+ try:
173
+
174
+ # Try to get from instance
175
+ instance = arguments.get("instance")
176
+ if arguments.get('kwargs') and arguments.get('kwargs').get('model'):
177
+ return arguments['kwargs'].get('model')
178
+ if instance and hasattr(instance, "_config") and hasattr(instance._config, "model"):
179
+ return instance._config.endpoint.split("/")[-1]
180
+
181
+ return ""
182
+ except Exception as e:
183
+ logger.warning("Warning: Error occurred in get_model_name: %s", str(e))
184
+ return ""
185
+
186
+
187
+ def get_inference_type(arguments) -> str:
188
+ instance = arguments.get("instance")
189
+ if instance and hasattr(instance, "_config") and hasattr(instance._config, "endpoint"):
190
+ endpoint = instance._config.endpoint
191
+ try:
192
+ parsed = urlparse(endpoint)
193
+ hostname = parsed.hostname or endpoint
194
+ hostname = hostname.lower()
195
+ except Exception:
196
+ hostname = str(endpoint).lower()
197
+ if hostname.endswith("services.ai.azure.com"):
198
+ return "azure_ai_inference"
199
+ if hostname.endswith("openai.azure.com"):
200
+ return "azure_openai"
201
+ return "azure_ai_inference"
202
+
203
+
204
+ def get_provider_name(instance: Any) -> str:
205
+ """Extract provider name from azure-ai-inference client instance."""
206
+ try:
207
+ # extract hostname from instance._config.endpoint
208
+ # https://okahu-openai-dev.openai.azure.com/openai/deployments/kshitiz-gpt => okahu-openai-dev.openai.azure.com
209
+ endpoint = instance._config.endpoint
210
+ if endpoint:
211
+ # Extract the hostname part
212
+ provider_name = endpoint.split("/")[2] if "/" in endpoint else endpoint
213
+ return provider_name
214
+ except Exception as e:
215
+ logger.warning("Warning: Error occurred in get_provider_name: %s", str(e))
216
+ return "azure_ai_inference"
@@ -0,0 +1,208 @@
1
+ import logging
2
+ import time
3
+ from types import SimpleNamespace
4
+ from monocle_apptrace.instrumentation.metamodel.azureaiinference import _helper
5
+ from monocle_apptrace.instrumentation.common.utils import (
6
+ resolve_from_alias,
7
+ patch_instance_method,
8
+ get_status,
9
+ get_exception_status_code
10
+ )
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ def process_stream(to_wrap, response, span_processor):
16
+ """Process streaming responses from Azure AI Inference."""
17
+ waiting_for_first_token = True
18
+ stream_start_time = time.time_ns()
19
+ first_token_time = stream_start_time
20
+ stream_closed_time = None
21
+ accumulated_response = ""
22
+ token_usage = None
23
+
24
+ # For sync iteration - patch __next__ instead of __iter__
25
+ if to_wrap and hasattr(response, "__next__"):
26
+ original_next = response.__next__
27
+
28
+ def new_next(self):
29
+ nonlocal waiting_for_first_token, first_token_time, stream_closed_time, accumulated_response, token_usage
30
+
31
+ try:
32
+ item = original_next()
33
+
34
+ # Handle Azure AI Inference streaming chunks
35
+ if hasattr(item, 'choices') and item.choices:
36
+ choice = item.choices[0]
37
+ if hasattr(choice, 'delta') and hasattr(choice.delta, 'content') and choice.delta.content:
38
+ if waiting_for_first_token:
39
+ waiting_for_first_token = False
40
+ first_token_time = time.time_ns()
41
+
42
+ accumulated_response += choice.delta.content
43
+
44
+ # Check for usage information at the end of stream
45
+ if hasattr(item, 'usage') and item.usage:
46
+ token_usage = item.usage
47
+ stream_closed_time = time.time_ns()
48
+
49
+ return item
50
+
51
+ except StopIteration:
52
+ # Stream is complete, process final span
53
+ if span_processor:
54
+ ret_val = SimpleNamespace(
55
+ type="stream",
56
+ timestamps={
57
+ "data.input": int(stream_start_time),
58
+ "data.output": int(first_token_time),
59
+ "metadata": int(stream_closed_time or time.time_ns()),
60
+ },
61
+ output_text=accumulated_response,
62
+ usage=token_usage,
63
+ )
64
+ span_processor(ret_val)
65
+ raise
66
+ except Exception as e:
67
+ logger.warning(
68
+ "Warning: Error occurred while processing item in new_next: %s",
69
+ str(e),
70
+ )
71
+ raise
72
+
73
+ patch_instance_method(response, "__next__", new_next)
74
+
75
+ # For async iteration - patch __anext__ instead of __aiter__
76
+ if to_wrap and hasattr(response, "__anext__"):
77
+ original_anext = response.__anext__
78
+
79
+ async def new_anext(self):
80
+ nonlocal waiting_for_first_token, first_token_time, stream_closed_time, accumulated_response, token_usage
81
+
82
+ try:
83
+ item = await original_anext()
84
+
85
+ # Handle Azure AI Inference streaming chunks
86
+ if hasattr(item, 'choices') and item.choices:
87
+ choice = item.choices[0]
88
+ if hasattr(choice, 'delta') and hasattr(choice.delta, 'content') and choice.delta.content:
89
+ if waiting_for_first_token:
90
+ waiting_for_first_token = False
91
+ first_token_time = time.time_ns()
92
+
93
+ accumulated_response += choice.delta.content
94
+
95
+ # Check for usage information at the end of stream
96
+ if hasattr(item, 'usage') and item.usage:
97
+ token_usage = item.usage
98
+ stream_closed_time = time.time_ns()
99
+
100
+ return item
101
+
102
+ except StopAsyncIteration:
103
+ # Stream is complete, process final span
104
+ if span_processor:
105
+ ret_val = SimpleNamespace(
106
+ type="stream",
107
+ timestamps={
108
+ "data.input": int(stream_start_time),
109
+ "data.output": int(first_token_time),
110
+ "metadata": int(stream_closed_time or time.time_ns()),
111
+ },
112
+ output_text=accumulated_response,
113
+ usage=token_usage,
114
+ )
115
+ span_processor(ret_val)
116
+ raise
117
+ except Exception as e:
118
+ logger.warning(
119
+ "Warning: Error occurred while processing item in new_anext: %s",
120
+ str(e),
121
+ )
122
+ raise
123
+
124
+ patch_instance_method(response, "__anext__", new_anext)
125
+
126
+
127
+ INFERENCE = {
128
+ "type": "inference",
129
+ "is_auto_close": lambda kwargs: kwargs.get("stream", False) is False,
130
+ "response_processor": process_stream,
131
+ "attributes": [
132
+ [
133
+ {
134
+ "_comment": "Azure AI Inference provider type, endpoint",
135
+ "attribute": "type",
136
+ "accessor": lambda arguments: f"inference.{_helper.get_inference_type(arguments)}"
137
+ },
138
+ {
139
+ "attribute": "provider_name",
140
+ "accessor": lambda arguments: _helper.get_provider_name(arguments['instance'])
141
+ },
142
+ {
143
+ "attribute": "inference_endpoint",
144
+ "accessor": lambda arguments: _helper.extract_inference_endpoint(arguments['instance'])
145
+ },
146
+ {
147
+ "attribute": "deployment",
148
+ "accessor": lambda arguments: resolve_from_alias(
149
+ arguments['instance'].__dict__,
150
+ ['deployment', 'deployment_name', 'azure_deployment', '_deployment']
151
+ )
152
+ }
153
+ ],
154
+ [
155
+ {
156
+ "_comment": "LLM Model information",
157
+ "attribute": "name",
158
+ "accessor": lambda arguments: _helper.get_model_name(arguments)
159
+ },
160
+ {
161
+ "attribute": "type",
162
+ "accessor": lambda arguments: f"model.llm.{_helper.get_model_name(arguments)}" if _helper.get_model_name(arguments) else "model.llm.unknown"
163
+ }
164
+ ]
165
+ ],
166
+ "events": [
167
+ {
168
+ "name": "data.input",
169
+ "attributes": [
170
+ {
171
+ "_comment": "Chat messages input to Azure AI Inference",
172
+ "attribute": "input",
173
+ "accessor": lambda arguments: _helper.extract_messages(arguments['kwargs'])
174
+ }
175
+ ]
176
+ },
177
+ {
178
+ "name": "data.output",
179
+ "attributes": [
180
+ {
181
+ "_comment": "Response from Azure AI Inference",
182
+ "attribute": "response",
183
+ "accessor": lambda arguments: _helper.extract_assistant_message(arguments)
184
+ },
185
+ {
186
+ "attribute": "status",
187
+ "accessor": lambda arguments: get_status(arguments)
188
+ },
189
+ {
190
+ "attribute": "status_code",
191
+ "accessor": lambda arguments: get_exception_status_code(arguments)
192
+ }
193
+ ]
194
+ },
195
+ {
196
+ "name": "metadata",
197
+ "attributes": [
198
+ {
199
+ "_comment": "Usage metadata from Azure AI Inference",
200
+ "accessor": lambda arguments: _helper.update_span_from_llm_response(
201
+ arguments['result'],
202
+ arguments.get('instance')
203
+ )
204
+ }
205
+ ]
206
+ }
207
+ ]
208
+ }
@@ -0,0 +1,23 @@
1
+ from monocle_apptrace.instrumentation.common.wrapper import atask_wrapper, task_wrapper
2
+ from monocle_apptrace.instrumentation.metamodel.azureaiinference.entities.inference import INFERENCE
3
+
4
+ AZURE_AI_INFERENCE_METHODS = [
5
+ # Chat Completions - Synchronous
6
+ {
7
+ "package": "azure.ai.inference",
8
+ "object": "ChatCompletionsClient",
9
+ "method": "complete",
10
+ "wrapper_method": task_wrapper,
11
+ "span_handler": "non_framework_handler",
12
+ "output_processor": INFERENCE
13
+ },
14
+ # Chat Completions - Asynchronous
15
+ {
16
+ "package": "azure.ai.inference.aio",
17
+ "object": "ChatCompletionsClient",
18
+ "method": "complete",
19
+ "wrapper_method": atask_wrapper,
20
+ "span_handler": "non_framework_handler",
21
+ "output_processor": INFERENCE
22
+ }
23
+ ]
@@ -8,7 +8,7 @@ import json
8
8
  from io import BytesIO
9
9
  from functools import wraps
10
10
  from monocle_apptrace.instrumentation.common.span_handler import SpanHandler
11
-
11
+ from monocle_apptrace.instrumentation.common.utils import ( get_exception_message,)
12
12
  logger = logging.getLogger(__name__)
13
13
 
14
14
 
@@ -30,24 +30,49 @@ def extract_messages(args):
30
30
  logger.warning("Warning: Error occurred in extract_messages: %s", str(e))
31
31
  return []
32
32
 
33
+ def get_exception_status_code(arguments):
34
+ if arguments['exception'] is not None and hasattr(arguments['exception'], 'response') and arguments['exception'].response is not None:
35
+ if "ResponseMetadata" in arguments['exception'].response and "HTTPStatusCode" in arguments['exception'].response["ResponseMetadata"]:
36
+ return arguments['exception'].response["ResponseMetadata"]["HTTPStatusCode"]
37
+ elif arguments['exception'] is not None:
38
+ return 'error'
39
+ else:
40
+ return 'success'
41
+
42
+ def get_status_code(arguments):
43
+ if arguments["exception"] is not None:
44
+ return get_exception_status_code(arguments)
45
+ elif hasattr(arguments["result"], "status"):
46
+ return arguments["result"].status
47
+ else:
48
+ return 'success'
33
49
 
34
- def extract_assistant_message(response):
50
+ def extract_assistant_message(arguments):
35
51
  try:
36
- if "Body" in response and hasattr(response['Body'], "_raw_stream"):
37
- raw_stream = getattr(response['Body'], "_raw_stream")
38
- if hasattr(raw_stream, "data"):
39
- response_bytes = getattr(raw_stream, "data")
40
- response_str = response_bytes.decode('utf-8')
41
- response_dict = json.loads(response_str)
42
- response['Body'] = BytesIO(response_bytes)
43
- return [response_dict["answer"]]
44
- if "output" in response:
45
- output = response.get("output", {})
46
- message = output.get("message", {})
47
- content = message.get("content", [])
48
- if isinstance(content, list) and len(content) > 0 and "text" in content[0]:
49
- reply = content[0]["text"]
50
- return [reply]
52
+ status = get_status_code(arguments)
53
+ response: str = ""
54
+ if status == 'success':
55
+ if "Body" in arguments['result'] and hasattr(arguments['result']['Body'], "_raw_stream"):
56
+ raw_stream = getattr(arguments['result']['Body'], "_raw_stream")
57
+ if hasattr(raw_stream, "data"):
58
+ response_bytes = getattr(raw_stream, "data")
59
+ response_str = response_bytes.decode('utf-8')
60
+ response_dict = json.loads(response_str)
61
+ arguments['result']['Body'] = BytesIO(response_bytes)
62
+ response = response_dict["answer"]
63
+ if "output" in arguments['result']:
64
+ output = arguments['result'].get("output", {})
65
+ message = output.get("message", {})
66
+ content = message.get("content", [])
67
+ if isinstance(content, list) and len(content) > 0 and "text" in content[0]:
68
+ reply = content[0]["text"]
69
+ response = reply
70
+ else:
71
+ if arguments["exception"] is not None:
72
+ response = get_exception_message(arguments)
73
+ elif hasattr(arguments["result"], "error"):
74
+ response = arguments["result"].error
75
+ return response
51
76
  except Exception as e:
52
77
  logger.warning("Warning: Error occurred in extract_assistant_message: %s", str(e))
53
78
  return []
@@ -1,7 +1,7 @@
1
1
  from monocle_apptrace.instrumentation.metamodel.botocore 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_llm_type, get_status,)
5
5
  INFERENCE = {
6
6
  "type": "inference",
7
7
  "attributes": [
@@ -33,7 +33,6 @@ INFERENCE = {
33
33
  "events": [
34
34
  {"name": "data.input",
35
35
  "attributes": [
36
-
37
36
  {
38
37
  "_comment": "this is instruction and user query to LLM",
39
38
  "attribute": "input",
@@ -44,10 +43,19 @@ INFERENCE = {
44
43
  {
45
44
  "name": "data.output",
46
45
  "attributes": [
46
+ {
47
+ "_comment": "this is result from LLM",
48
+ "attribute": "status",
49
+ "accessor": lambda arguments: get_status(arguments)
50
+ },
51
+ {
52
+ "attribute": "status_code",
53
+ "accessor": lambda arguments: _helper.get_status_code(arguments)
54
+ },
47
55
  {
48
56
  "_comment": "this is response from LLM",
49
57
  "attribute": "response",
50
- "accessor": lambda arguments: _helper.extract_assistant_message(arguments['result'])
58
+ "accessor": lambda arguments: _helper.extract_assistant_message(arguments)
51
59
  }
52
60
  ]
53
61
  },
@@ -70,7 +70,7 @@ class FlaskResponseSpanHandler(SpanHandler):
70
70
  if _parent_span_context is not None:
71
71
  parent_span: Span = _parent_span_context.get(_SPAN_KEY, None)
72
72
  if parent_span is not None:
73
- self.hydrate_events(to_wrap, wrapped, instance, args, kwargs, return_value, parent_span)
73
+ self.hydrate_events(to_wrap, wrapped, instance, args, kwargs, return_value, parent_span=parent_span)
74
74
  except Exception as e:
75
75
  logger.info(f"Failed to propogate flask response: {e}")
76
76
  super().post_tracing(to_wrap, wrapped, instance, args, kwargs, return_value)
@@ -5,6 +5,8 @@ from monocle_apptrace.instrumentation.common.utils import (
5
5
  get_keys_as_tuple,
6
6
  get_nested_value,
7
7
  try_option,
8
+ get_exception_message,
9
+ get_status_code,
8
10
  )
9
11
  logger = logging.getLogger(__name__)
10
12
 
@@ -52,19 +54,25 @@ def extract_question_from_prompt(content):
52
54
  logger.warning("Warning: Error occurred in extract_question_from_prompt: %s", str(e))
53
55
  return ""
54
56
 
55
-
56
- def extract_assistant_message(response):
57
- try:
58
- if "replies" in response:
59
- reply = response["replies"][0]
57
+ def extract_assistant_message(arguments):
58
+ status = get_status_code(arguments)
59
+ response: str = ""
60
+ if status == 'success':
61
+ if "replies" in arguments['result']:
62
+ reply = arguments['result']["replies"][0]
60
63
  if hasattr(reply, 'content'):
61
- return [reply.content]
62
- if hasattr(reply, 'text'):
63
- return [reply.text]
64
- return [reply]
65
- except Exception as e:
66
- logger.warning("Warning: Error occurred in extract_assistant_message: %s", str(e))
67
- return []
64
+ response = reply.content
65
+ elif hasattr(reply, 'text'):
66
+ response = reply.text
67
+ else:
68
+ response = reply
69
+ else:
70
+ if arguments["exception"] is not None:
71
+ response = get_exception_message(arguments)
72
+ elif hasattr(response, "error"):
73
+ response = arguments['result'].error
74
+
75
+ return response
68
76
 
69
77
 
70
78
  def get_vectorstore_deployment(my_map):
@@ -1,7 +1,7 @@
1
1
  from monocle_apptrace.instrumentation.metamodel.haystack 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_llm_type, get_status, get_status_code
5
5
 
6
6
  INFERENCE = {
7
7
  "type": "inference.framework",
@@ -60,8 +60,16 @@ INFERENCE = {
60
60
  "attributes": [
61
61
  {
62
62
  "_comment": "this is response from LLM",
63
+ "attribute": "status",
64
+ "accessor": lambda arguments: get_status(arguments)
65
+ },
66
+ {
67
+ "attribute": "status_code",
68
+ "accessor": lambda arguments: get_status_code(arguments)
69
+ },
70
+ {
63
71
  "attribute": "response",
64
- "accessor": lambda arguments: _helper.extract_assistant_message(arguments['result'])
72
+ "accessor": lambda arguments: _helper.extract_assistant_message(arguments)
65
73
  }
66
74
  ]
67
75
  },