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
@@ -9,6 +9,8 @@ from monocle_apptrace.instrumentation.common.utils import (
9
9
  get_keys_as_tuple,
10
10
  get_nested_value,
11
11
  try_option,
12
+ get_exception_message,
13
+ get_status_code,
12
14
  )
13
15
 
14
16
 
@@ -35,18 +37,23 @@ def extract_messages(args):
35
37
  logger.warning("Warning: Error occurred in extract_messages: %s", str(e))
36
38
  return []
37
39
 
40
+ def extract_assistant_message(arguments):
41
+ status = get_status_code(arguments)
42
+ response: str = ""
43
+ if status == 'success':
44
+ if isinstance(arguments['result'], str):
45
+ response = arguments['result']
46
+ if hasattr(arguments['result'], "content"):
47
+ response = arguments['result'].content
48
+ if hasattr(arguments['result'], "message") and hasattr(arguments['result'].message, "content"):
49
+ response = arguments['result'].message.content
50
+ else:
51
+ if arguments["exception"] is not None:
52
+ response = get_exception_message(arguments)
53
+ elif hasattr(arguments["result"], "error"):
54
+ response = arguments["result"].error
38
55
 
39
- def extract_assistant_message(response):
40
- try:
41
- if isinstance(response, str):
42
- return [response]
43
- if hasattr(response, "content"):
44
- return [response.content]
45
- if hasattr(response, "message") and hasattr(response.message, "content"):
46
- return [response.message.content]
47
- except Exception as e:
48
- logger.warning("Warning: Error occurred in extract_assistant_message: %s", str(e))
49
- return []
56
+ return response
50
57
 
51
58
 
52
59
  def extract_provider_name(instance):
@@ -131,5 +138,4 @@ def update_span_from_llm_response(response, instance):
131
138
  {"completion_tokens": token_usage.get("completion_tokens") or token_usage.get("output_tokens")})
132
139
  meta_dict.update({"prompt_tokens": token_usage.get("prompt_tokens") or token_usage.get("input_tokens")})
133
140
  meta_dict.update({"total_tokens": token_usage.get("total_tokens")})
134
- return meta_dict
135
-
141
+ return meta_dict
@@ -1,7 +1,7 @@
1
1
  from monocle_apptrace.instrumentation.metamodel.langchain import (
2
2
  _helper,
3
3
  )
4
- from monocle_apptrace.instrumentation.common.utils import resolve_from_alias, get_llm_type
4
+ from monocle_apptrace.instrumentation.common.utils import resolve_from_alias, get_llm_type, get_status, get_status_code
5
5
 
6
6
  INFERENCE = {
7
7
  "type": "inference.framework",
@@ -54,8 +54,16 @@ INFERENCE = {
54
54
  "attributes": [
55
55
  {
56
56
  "_comment": "this is result from LLM",
57
+ "attribute": "status",
58
+ "accessor": lambda arguments: get_status(arguments)
59
+ },
60
+ {
61
+ "attribute": "status_code",
62
+ "accessor": lambda arguments: get_status_code(arguments)
63
+ },
64
+ {
57
65
  "attribute": "response",
58
- "accessor": lambda arguments: _helper.extract_assistant_message(arguments['result'])
66
+ "accessor": lambda arguments: _helper.extract_assistant_message(arguments)
59
67
  }
60
68
  ]
61
69
  },
@@ -11,6 +11,8 @@ from monocle_apptrace.instrumentation.common.utils import (
11
11
  get_keys_as_tuple,
12
12
  get_nested_value,
13
13
  try_option,
14
+ get_exception_message,
15
+ get_status_code,
14
16
  )
15
17
 
16
18
  logger = logging.getLogger(__name__)
@@ -60,19 +62,25 @@ def extract_messages(args):
60
62
  logger.warning("Error in extract_messages: %s", str(e))
61
63
  return []
62
64
 
63
- def extract_assistant_message(response):
64
- try:
65
- if isinstance(response, str):
66
- return [response]
67
- if hasattr(response, "content"):
68
- return [response.content]
69
- if hasattr(response, "message") and hasattr(response.message, "content"):
70
- return [response.message.content]
71
- if hasattr(response,"response") and isinstance(response.response, str):
72
- return [response.response]
73
- except Exception as e:
74
- logger.warning("Warning: Error occurred in extract_assistant_message: %s", str(e))
75
- return []
65
+ def extract_assistant_message(arguments):
66
+ status = get_status_code(arguments)
67
+ response: str = ""
68
+ if status == 'success':
69
+ if isinstance(arguments['result'], str):
70
+ response = arguments['result']
71
+ if hasattr(arguments['result'], "content"):
72
+ response = arguments['result'].content
73
+ if hasattr(arguments['result'], "message") and hasattr(arguments['result'].message, "content"):
74
+ response = arguments['result'].message.content
75
+ if hasattr(arguments['result'],"response") and isinstance(arguments['result'].response, str):
76
+ response = arguments['result'].response
77
+ else:
78
+ if arguments["exception"] is not None:
79
+ response = get_exception_message(arguments)
80
+ elif hasattr(response, "error"):
81
+ response = arguments['result'].error
82
+
83
+ return response
76
84
 
77
85
 
78
86
  def extract_query_from_content(content):
@@ -1,7 +1,7 @@
1
1
  from monocle_apptrace.instrumentation.metamodel.llamaindex import (
2
2
  _helper,
3
3
  )
4
- from monocle_apptrace.instrumentation.common.utils import resolve_from_alias, get_llm_type
4
+ from monocle_apptrace.instrumentation.common.utils import resolve_from_alias, get_llm_type, get_status, get_status_code
5
5
 
6
6
  INFERENCE = {
7
7
  "type": "inference.framework",
@@ -55,8 +55,16 @@ INFERENCE = {
55
55
  "attributes": [
56
56
  {
57
57
  "_comment": "this is response from LLM",
58
+ "attribute": "status",
59
+ "accessor": lambda arguments: get_status(arguments)
60
+ },
61
+ {
62
+ "attribute": "status_code",
63
+ "accessor": lambda arguments: get_status_code(arguments)
64
+ },
65
+ {
58
66
  "attribute": "response",
59
- "accessor": lambda arguments: _helper.extract_assistant_message(arguments['result'])
67
+ "accessor": lambda arguments: _helper.extract_assistant_message(arguments)
60
68
  }
61
69
  ]
62
70
  },
@@ -6,11 +6,12 @@ and assistant messages from various input formats.
6
6
  import logging
7
7
  from monocle_apptrace.instrumentation.common.utils import (
8
8
  Option,
9
- get_keys_as_tuple,
10
- get_nested_value,
11
9
  try_option,
10
+ get_exception_message,
11
+ get_parent_span,
12
+ get_status_code,
12
13
  )
13
- from monocle_apptrace.instrumentation.common.span_handler import NonFrameworkSpanHandler
14
+ from monocle_apptrace.instrumentation.common.span_handler import NonFrameworkSpanHandler, WORKFLOW_TYPE_MAP
14
15
 
15
16
  logger = logging.getLogger(__name__)
16
17
 
@@ -34,13 +35,23 @@ def extract_messages(kwargs):
34
35
  return []
35
36
 
36
37
 
37
- def extract_assistant_message(response):
38
+ def extract_assistant_message(arguments):
38
39
  try:
39
- if hasattr(response,"output_text") and len(response.output_text):
40
- return response.output_text
41
- if response is not None and hasattr(response,"choices") and len(response.choices) >0:
42
- if hasattr(response.choices[0],"message"):
43
- return response.choices[0].message.content
40
+ status = get_status_code(arguments)
41
+ response: str = ""
42
+ if status == 'success':
43
+ response = arguments["result"]
44
+ if hasattr(response,"output_text") and len(response.output_text):
45
+ return response.output_text
46
+ if response is not None and hasattr(response,"choices") and len(response.choices) >0:
47
+ if hasattr(response.choices[0],"message"):
48
+ return response.choices[0].message.content
49
+ else:
50
+ if arguments["exception"] is not None:
51
+ response = get_exception_message(arguments)
52
+ elif hasattr(arguments["result"], "error"):
53
+ response = arguments["result"].error
54
+ return response
44
55
  except (IndexError, AttributeError) as e:
45
56
  logger.warning("Warning: Error occurred in extract_assistant_message: %s", str(e))
46
57
  return None
@@ -117,9 +128,19 @@ def get_inference_type(instance):
117
128
  return 'openai'
118
129
 
119
130
  class OpenAISpanHandler(NonFrameworkSpanHandler):
131
+ def is_teams_span_in_progress(self) -> bool:
132
+ return self.is_framework_span_in_progess() and self.get_workflow_name_in_progress() == WORKFLOW_TYPE_MAP["teams.ai"]
133
+
120
134
  # If openAI is being called by Teams AI SDK, then retain the metadata part of the span events
121
135
  def skip_processor(self, to_wrap, wrapped, instance, span, args, kwargs) -> list[str]:
122
- if self.is_framework_span_in_progess() and self.get_workflow_name_in_progress() == "workflow.teams_ai":
136
+ if self.is_teams_span_in_progress():
123
137
  return ["attributes", "events.data.input", "events.data.output"]
124
138
  else:
125
139
  return super().skip_processor(to_wrap, wrapped, instance, span, args, kwargs)
140
+
141
+ def hydrate_events(self, to_wrap, wrapped, instance, args, kwargs, ret_result, span, parent_span=None, ex:Exception=None) -> bool:
142
+ # If openAI is being called by Teams AI SDK, then copy parent
143
+ if self.is_teams_span_in_progress() and ex is None:
144
+ return super().hydrate_events(to_wrap, wrapped, instance, args, kwargs, ret_result, span=parent_span, parent_span=None, ex=ex)
145
+
146
+ return super().hydrate_events(to_wrap, wrapped, instance, args, kwargs, ret_result, span, parent_span=parent_span, ex=ex)
@@ -8,6 +8,9 @@ from monocle_apptrace.instrumentation.metamodel.openai import (
8
8
  from monocle_apptrace.instrumentation.common.utils import (
9
9
  patch_instance_method,
10
10
  resolve_from_alias,
11
+ get_status,
12
+ get_exception_status_code,
13
+ get_status_code,
11
14
  )
12
15
 
13
16
  logger = logging.getLogger(__name__)
@@ -199,8 +202,16 @@ INFERENCE = {
199
202
  "_comment": "this is result from LLM",
200
203
  "attribute": "response",
201
204
  "accessor": lambda arguments: _helper.extract_assistant_message(
202
- arguments["result"]
205
+ arguments,
203
206
  ),
207
+ },
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)
204
215
  }
205
216
  ],
206
217
  },
@@ -1,3 +1,4 @@
1
+ import logging
1
2
  from monocle_apptrace.instrumentation.common.utils import MonocleSpanException
2
3
  from monocle_apptrace.instrumentation.common.utils import (
3
4
  Option,
@@ -7,6 +8,9 @@ from monocle_apptrace.instrumentation.common.utils import (
7
8
  get_exception_message,
8
9
  get_exception_status_code
9
10
  )
11
+
12
+ logger = logging.getLogger(__name__)
13
+
10
14
  def capture_input(arguments):
11
15
  """
12
16
  Captures the input from Teams AI state.
@@ -18,6 +22,7 @@ def capture_input(arguments):
18
22
  try:
19
23
  # Get the memory object from kwargs
20
24
  kwargs = arguments.get("kwargs", {})
25
+ messages = []
21
26
 
22
27
  # If memory exists, try to get the input from temp
23
28
  if "memory" in kwargs:
@@ -29,14 +34,20 @@ def capture_input(arguments):
29
34
  if temp and hasattr(temp, "get"):
30
35
  input_value = temp.get("input")
31
36
  if input_value:
32
- return str(input_value)
33
-
37
+ messages.append({'user': str(input_value)})
38
+ system_prompt = ""
39
+ try:
40
+ system_prompt = kwargs.get("template").prompt.sections[0].sections[0].template
41
+ messages.append({'system': system_prompt})
42
+ except Exception as e:
43
+ print(f"Debug - Error accessing system prompt: {str(e)}")
44
+
34
45
  # Try alternative path through context if memory path fails
35
46
  context = kwargs.get("context")
36
47
  if hasattr(context, "activity") and hasattr(context.activity, "text"):
37
- return str(context.activity.text)
48
+ messages.append({'user': str(context.activity.text)})
38
49
 
39
- return "No input found in memory or context"
50
+ return [str(message) for message in messages]
40
51
  except Exception as e:
41
52
  print(f"Debug - Arguments structure: {str(arguments)}")
42
53
  print(f"Debug - kwargs: {str(kwargs)}")
@@ -59,6 +70,41 @@ def capture_prompt_info(arguments):
59
70
  except Exception as e:
60
71
  return f"Error capturing prompt: {str(e)}"
61
72
 
73
+ def capture_prompt_template_info(arguments):
74
+ """Captures prompt information from ActionPlanner state"""
75
+ try:
76
+ kwargs = arguments.get("kwargs", {})
77
+ prompt = kwargs.get("prompt")
78
+
79
+ if hasattr(prompt,"prompt") and prompt.prompt is not None:
80
+ if "_text" in prompt.prompt.__dict__:
81
+ prompt_template = prompt.prompt.__dict__.get("_text", None)
82
+ return prompt_template
83
+ elif "_sections" in prompt.prompt.__dict__ and prompt.prompt._sections is not None:
84
+ sections = prompt.prompt._sections[0].__dict__.get("_sections", None)
85
+ if sections is not None and "_template" in sections[0].__dict__:
86
+ return sections[0].__dict__.get("_template", None)
87
+
88
+
89
+ return "No prompt information found"
90
+ except Exception as e:
91
+ return f"Error capturing prompt: {str(e)}"
92
+
93
+ def status_check(arguments):
94
+ if hasattr(arguments["result"], "error") and arguments["result"].error is not None:
95
+ error_msg:str = arguments["result"].error
96
+ error_code:str = arguments["result"].status if hasattr(arguments["result"], "status") else "unknown"
97
+ raise MonocleSpanException(f"Error: {error_code} - {error_msg}")
98
+
99
+ def get_prompt_template(arguments):
100
+ pass
101
+ return {
102
+ "prompt_template_name": capture_prompt_info(arguments),
103
+ "prompt_template": capture_prompt_template_info(arguments),
104
+ "prompt_template_description": get_nested_value(arguments.get("kwargs", {}), ["prompt", "config", "description"]),
105
+ "prompt_template_type": get_nested_value(arguments.get("kwargs", {}), ["prompt", "config", "type"])
106
+ }
107
+
62
108
  def get_status_code(arguments):
63
109
  if arguments["exception"] is not None:
64
110
  return get_exception_status_code(arguments)
@@ -28,22 +28,42 @@ ACTIONPLANNER_OUTPUT_PROCESSOR = {
28
28
  {
29
29
  "attribute": "tokenizer",
30
30
  "accessor": lambda arguments: arguments["instance"]._options.tokenizer.__class__.__name__ if hasattr(arguments["instance"], "_options") else "GPTTokenizer"
31
- },
32
- {
33
- "attribute": "prompt_name",
34
- "accessor": _helper.capture_prompt_info
35
- },
36
- {
37
- "attribute": "validator",
38
- "accessor": lambda arguments: arguments["kwargs"].get("validator").__class__.__name__ if arguments.get("kwargs", {}).get("validator") else "DefaultResponseValidator"
39
- },
40
- {
41
- "attribute": "memory_type",
42
- "accessor": lambda arguments: arguments["kwargs"].get("memory").__class__.__name__ if arguments.get("kwargs", {}).get("memory") else "unknown"
43
31
  }
44
32
  ]
45
33
  ],
46
34
  "events": [
35
+ {
36
+ "name": "data.input",
37
+ "_comment": "input configuration to ActionPlanner",
38
+ "attributes": [
39
+ {
40
+ "_comment": "execution metadata",
41
+ "accessor": lambda arguments: _helper.get_prompt_template(arguments)
42
+ },
43
+ {
44
+ "attribute": "validator",
45
+ "accessor": lambda arguments: arguments["kwargs"].get("validator").__class__.__name__ if arguments.get("kwargs", {}).get("validator") else "DefaultResponseValidator"
46
+ },
47
+ {
48
+ "attribute": "memory_type",
49
+ "accessor": lambda arguments: arguments["kwargs"].get("memory").__class__.__name__ if arguments.get("kwargs", {}).get("memory") else "unknown"
50
+ }
51
+ ]
52
+ },
53
+ {
54
+ "name": "data.output",
55
+ "_comment": "output from ActionPlanner",
56
+ "attributes": [
57
+ {
58
+ "attribute": "status",
59
+ "accessor": lambda arguments: _helper.status_check(arguments)
60
+ },
61
+ {
62
+ "attribute": "response",
63
+ "accessor": lambda arguments: arguments["result"].message.content if hasattr(arguments["result"], "message") else str(arguments["result"])
64
+ }
65
+ ]
66
+ },
47
67
  {
48
68
  "name": "metadata",
49
69
  "attributes": [
@@ -9,31 +9,44 @@ from monocle_apptrace.instrumentation.metamodel.teamsai.entities.inference.teams
9
9
  )
10
10
  from monocle_apptrace.instrumentation.metamodel.teamsai.entities.inference.actionplanner_output_processor import (
11
11
  ACTIONPLANNER_OUTPUT_PROCESSOR,
12
- )
13
-
14
-
12
+ )
15
13
  def get_id(args, kwargs):
16
14
  """
17
15
  Extracts the ID from the context.
18
16
  """
19
17
  scopes: dict[str, dict[str:str]] = {}
20
18
  context = kwargs.get("context")
21
- if context and context.activity and context.activity.conversation.id:
22
- conversation_id = context.activity.conversation.id or ""
23
- user_aad_object_id = context.activity.from_property.aad_object_id or ""
24
- user_teams_id = context.activity.from_property.id or ""
19
+ if context and context.activity and context.activity.channel_id:
25
20
  channel_id = context.activity.channel_id or ""
26
- recipient_id = context.activity.recipient.id or ""
27
- recipient_aad_object_id = context.activity.recipient.aad_object_id or ""
28
- scopes[f"teams.conversation.conversation.id"] = conversation_id
29
- scopes[f"teams.user.from_property.aad_object_id"] = user_aad_object_id
30
- scopes[f"teams.user.from_property.id"] = user_teams_id
31
21
  scopes[f"teams.channel.channel_id"] = channel_id
32
- scopes[f"teams.channel.recipient.id"] = recipient_id
33
- scopes[f"teams.channel.recipient.aad_object_id"] = recipient_aad_object_id
22
+ if channel_id == "msteams":
23
+ scopes[f"msteams.activity.type"] = context.activity.type or ""
34
24
 
35
- return scopes
25
+ if hasattr(context.activity,"conversation"):
26
+ scopes[f"msteams.conversation.id"] = context.activity.conversation.id or ""
27
+ scopes[f"msteams.conversation.type"] = context.activity.conversation.conversation_type or ""
28
+ scopes[f"msteams.conversation.name"] = context.activity.conversation.name or ""
36
29
 
30
+ if hasattr(context.activity,"from_property"):
31
+ scopes[f"msteams.user.from_property.id"] = context.activity.from_property.id or ""
32
+ scopes[f"msteams.user.from_property.name"] = context.activity.from_property.name or ""
33
+ scopes[f"msteams.user.from_property.role"] = context.activity.from_property.role or ""
34
+
35
+ if hasattr(context.activity,"recipient"):
36
+ scopes[f"msteams.recipient.id"] = context.activity.recipient.id or ""
37
+
38
+ if hasattr(context.activity,"channel_data"):
39
+ if "tenant" in context.activity.channel_data:
40
+ scopes[f"msteams.channel_data.tenant.id"] = context.activity.channel_data['tenant']['id'] or ""
41
+ if "team" in context.activity.channel_data:
42
+ scopes[f"msteams.channel_data.team.id"] = context.activity.channel_data['team']['id'] or ""
43
+ if "name" in context.activity.channel_data['team']:
44
+ scopes[f"msteams.channel_data.team.name"] = context.activity.channel_data['team']['name'] or ""
45
+ if "channel" in context.activity.channel_data:
46
+ scopes[f"msteams.channel_data.channel.id"] = context.activity.channel_data['channel']['id'] or ""
47
+ if "name" in context.activity.channel_data['channel']:
48
+ scopes[f"msteams.channel_data.channel.name"] = context.activity.channel_data['channel']['name'] or ""
49
+ return scopes
37
50
 
38
51
  TEAMAI_METHODS = [
39
52
  {
@@ -55,6 +68,6 @@ TEAMAI_METHODS = [
55
68
  "object": "ActionPlanner",
56
69
  "method": "complete_prompt",
57
70
  "scope_values": get_id,
58
- "wrapper_method": ascopes_wrapper,
59
- },
71
+ "wrapper_method": ascopes_wrapper,
72
+ }
60
73
  ]