deepeval 3.5.7__py3-none-any.whl → 3.5.9__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: deepeval
3
- Version: 3.5.7
3
+ Version: 3.5.9
4
4
  Summary: The LLM Evaluation Framework
5
5
  Home-page: https://github.com/confident-ai/deepeval
6
6
  License: Apache-2.0
@@ -17,6 +17,7 @@ Requires-Dist: anthropic
17
17
  Requires-Dist: click (>=8.0.0,<8.3.0)
18
18
  Requires-Dist: google-genai (>=1.9.0,<2.0.0)
19
19
  Requires-Dist: grpcio (>=1.67.1,<2.0.0)
20
+ Requires-Dist: jinja2
20
21
  Requires-Dist: nest_asyncio
21
22
  Requires-Dist: ollama
22
23
  Requires-Dist: openai
@@ -1,5 +1,5 @@
1
1
  deepeval/__init__.py,sha256=6fsb813LD_jNhqR-xZnSdE5E-KsBbC3tc4oIg5ZMgTw,2115
2
- deepeval/_version.py,sha256=5PpKL25tWtYxTPc0_se2v49WDFVCzYaCu8yogWsx_qQ,27
2
+ deepeval/_version.py,sha256=pEL83SMnaXGf-TcVHz9_kQx6-qWl_kZPXsJxqkdMIto,27
3
3
  deepeval/annotation/__init__.py,sha256=ZFhUVNNuH_YgQSZJ-m5E9iUb9TkAkEV33a6ouMDZ8EI,111
4
4
  deepeval/annotation/annotation.py,sha256=3j3-syeJepAcEj3u3e4T_BeRDzNr7yXGDIoNQGMKpwQ,2298
5
5
  deepeval/annotation/api.py,sha256=EYN33ACVzVxsFleRYm60KB4Exvff3rPJKt1VBuuX970,2147
@@ -179,11 +179,10 @@ deepeval/integrations/llama_index/__init__.py,sha256=zBwUFQXDp6QFtp1cfANy8ucV08r
179
179
  deepeval/integrations/llama_index/agent/patched.py,sha256=4JbH0WQmt4lct7xxIH0phj8_Y-V35dgVv7DEDXK0jZI,2149
180
180
  deepeval/integrations/llama_index/handler.py,sha256=eqI1n8E4MsvfKoFs5Zrm9IdCR7g9eBgNedISs7UkU_I,8947
181
181
  deepeval/integrations/llama_index/utils.py,sha256=mxW71-3PjvBvJpLIU0kNWuTzCidy5l_-roLt8ZyWYA0,2599
182
- deepeval/integrations/pydantic_ai/__init__.py,sha256=0-GZpWgCnFI-fVHI-3DosWQK85rk6CoRRhl4AiytBAw,258
183
- deepeval/integrations/pydantic_ai/agent.py,sha256=HxfeTLsdWGgRMy00ymgXdE6dcFDmFBsdgfl9BbvyJns,12311
184
- deepeval/integrations/pydantic_ai/otel.py,sha256=2DpO3RapdztXPlT9BWhQfF4dJDMyp2X7YvuplJ0SwC8,1661
185
- deepeval/integrations/pydantic_ai/patcher.py,sha256=yy4SZRmRhgYxh6qGVWWf8DnSMCDA9GLkFw1HbPToQ1w,17696
186
- deepeval/integrations/pydantic_ai/utils.py,sha256=734e9un-fn5V7MueAmVsXh304qgumv_fdcmdOC4HrJw,10998
182
+ deepeval/integrations/pydantic_ai/__init__.py,sha256=UIkXn_g6h9LTQXG1PaWu1eCFkCssIwG48WSvN46UWgU,202
183
+ deepeval/integrations/pydantic_ai/agent.py,sha256=4wRV25O1tC-txH2j3TNJWry6gDNBqqThj7zgFKBxJpw,606
184
+ deepeval/integrations/pydantic_ai/instrumentator.py,sha256=tGHuP7nn4jL9bUFR2fZWbF4k_EhF5JXOnCwQm-tmDKc,6974
185
+ deepeval/integrations/pydantic_ai/otel.py,sha256=0OuIpmaMtEt1dFWFZtYAiZ9hVCWweEWr1TRHYcDb4I8,1918
187
186
  deepeval/key_handler.py,sha256=damdQEBLGy4IVk5DR5-E3blIZdLbcMtyeGAFn_4_SG4,6505
188
187
  deepeval/metrics/__init__.py,sha256=nvO0Wv2JROjK1I9MDNIFUJlrRAZI2C0xbGYSBZK5q4g,4013
189
188
  deepeval/metrics/answer_relevancy/__init__.py,sha256=WbZUpoSg2GQoqJ4VIRirVVQ1JDx5xwT-RskwqNKfWGM,46
@@ -404,9 +403,9 @@ deepeval/plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
404
403
  deepeval/plugins/plugin.py,sha256=_dwsdx4Dg9DbXxK3f7zJY4QWTJQWc7QE1HmIg2Zjjag,1515
405
404
  deepeval/progress_context.py,sha256=ZSKpxrE9sdgt9G3REKnVeXAv7GJXHHVGgLynpG1Pudw,3557
406
405
  deepeval/prompt/__init__.py,sha256=M99QTWdxOfiNeySGCSqN873Q80PPxqRvjLq4_Mw-X1w,49
407
- deepeval/prompt/api.py,sha256=ccrMT6_Otuef9zrRm9iQsmZ-Apkjj3nypvw3wc8-eW0,1708
408
- deepeval/prompt/prompt.py,sha256=DlUPib0EAVC2T54SQB1xxEQBNSpEirL5x-CtrKE1rek,15463
409
- deepeval/prompt/utils.py,sha256=Gk0zj_9BK8MQccs8GmiC8o-YVtkou6ZJEz8kWgW5Mog,1678
406
+ deepeval/prompt/api.py,sha256=kR3MkaHuU2wYILKVnvnXhQWxWp0XgtcWX-kIjpMJRl8,1728
407
+ deepeval/prompt/prompt.py,sha256=192W5zFBx08nELxRHHDQscMM3psj8OUFV_JR85BZv8Q,15823
408
+ deepeval/prompt/utils.py,sha256=Ermw9P-1-T5wQ5uYuj5yWgdj7pVB_JLw8D37Qvmh9ok,1938
410
409
  deepeval/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
411
410
  deepeval/red_teaming/README.md,sha256=BY5rAdpp3-sMMToEKwq0Nsd9ivkGDzPE16DeDb8GY7U,154
412
411
  deepeval/scorer/__init__.py,sha256=hTvtoV3a4l0dSBjERm-jX7jveTtKZXK0c9JerQo0T_w,27
@@ -453,16 +452,16 @@ deepeval/tracing/offline_evals/span.py,sha256=pXqTVXs-WnjRVpCYYEbNe0zSM6Wz9GsKHs
453
452
  deepeval/tracing/offline_evals/thread.py,sha256=bcSGFcZJKnszArOLIlWvnCyt0zSmsd7Xsw5rl4RTVFg,1981
454
453
  deepeval/tracing/offline_evals/trace.py,sha256=vTflaTKysKRiYvKA-Nx6PUJ3J6NrRLXiIdWieVcm90E,1868
455
454
  deepeval/tracing/otel/__init__.py,sha256=HQsaF5yLPwyW5qg8AOV81_nG_7pFHnatOTHi9Wx3HEk,88
456
- deepeval/tracing/otel/exporter.py,sha256=dXQd834zm5rm1ss9pWkBBlk-JSdtiw7aFLso2hM53XY,26372
457
- deepeval/tracing/otel/utils.py,sha256=g8yAzhqbPh1fOKCWkfNekC6AVotLfu1SUcfNMo6zii8,9786
455
+ deepeval/tracing/otel/exporter.py,sha256=YfzV2zyxRwD6FO-qV0PR-y1nk1kInPJp0TtIuWNHbh0,28606
456
+ deepeval/tracing/otel/utils.py,sha256=xydJyUgR1s4hTGcz-onvVHyiT7F6lUXRuh_nprHkKbU,12396
458
457
  deepeval/tracing/patchers.py,sha256=DAPNkhrDtoeyJIVeQDUMhTz-xGcXu00eqjQZmov8FiU,3096
459
458
  deepeval/tracing/perf_epoch_bridge.py,sha256=iyAPddB6Op7NpMtPHJ29lDm53Btz9yLaN6xSCfTRQm4,1825
460
459
  deepeval/tracing/tracing.py,sha256=b-0T3W6lAEOEGhODx0e-yIwBkm5V46EDNAWS9lcWkD0,42306
461
460
  deepeval/tracing/types.py,sha256=l_utWKerNlE5H3mOKpeUJLsvpP3cMyjH7HRANNgTmSQ,5306
462
461
  deepeval/tracing/utils.py,sha256=w_kdhuyBCygllnbqLpDdKJqpJo42t3ZMlGhNicV2A8c,6467
463
462
  deepeval/utils.py,sha256=r8tV_NYJSi6ib-oQw6cLw3L7ZSe4KIJVJc1ng6-kDX4,17179
464
- deepeval-3.5.7.dist-info/LICENSE.md,sha256=0ATkuLv6QgsJTBODUHC5Rak_PArA6gv2t7inJzNTP38,11352
465
- deepeval-3.5.7.dist-info/METADATA,sha256=NldO1OinDSv_gGUP-kkFk1zpMGXKTceoYMtF92XGbgs,18721
466
- deepeval-3.5.7.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
467
- deepeval-3.5.7.dist-info/entry_points.txt,sha256=fVr8UphXTfJe9I2rObmUtfU3gkSrYeM0pLy-NbJYg10,94
468
- deepeval-3.5.7.dist-info/RECORD,,
463
+ deepeval-3.5.9.dist-info/LICENSE.md,sha256=0ATkuLv6QgsJTBODUHC5Rak_PArA6gv2t7inJzNTP38,11352
464
+ deepeval-3.5.9.dist-info/METADATA,sha256=gsap42eEwklR_la4cilLkE2HKQxOP_rnSPmGtvjdqzg,18743
465
+ deepeval-3.5.9.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
466
+ deepeval-3.5.9.dist-info/entry_points.txt,sha256=fVr8UphXTfJe9I2rObmUtfU3gkSrYeM0pLy-NbJYg10,94
467
+ deepeval-3.5.9.dist-info/RECORD,,
@@ -1,484 +0,0 @@
1
- # import inspect
2
- # import functools
3
- # import warnings
4
- # from typing import List, Callable, Optional, Any
5
- # from deepeval.tracing.types import LlmOutput, LlmToolCall
6
- # from pydantic_ai.agent import AgentRunResult
7
- # from deepeval.tracing.context import current_trace_context
8
- # from deepeval.tracing.types import AgentSpan, LlmSpan
9
- # from deepeval.tracing.tracing import Observer
10
- # from deepeval.test_case.llm_test_case import ToolCall
11
- # from deepeval.metrics.base_metric import BaseMetric
12
- # from deepeval.confident.api import get_confident_api_key
13
- # from deepeval.integrations.pydantic_ai.otel import instrument_pydantic_ai
14
- # from deepeval.telemetry import capture_tracing_integration
15
- # from deepeval.prompt import Prompt
16
- # import deepeval
17
- # # from contextvars import ContextVar
18
-
19
- # try:
20
- # from pydantic_ai.agent import Agent
21
- # from pydantic_ai.models import Model
22
- # from pydantic_ai.messages import (
23
- # ModelResponse,
24
- # ModelRequest,
25
- # ModelResponsePart,
26
- # TextPart,
27
- # ToolCallPart,
28
- # SystemPromptPart,
29
- # ToolReturnPart,
30
- # UserPromptPart,
31
- # )
32
- # from pydantic_ai._run_context import RunContext
33
- # from deepeval.integrations.pydantic_ai.utils import (
34
- # extract_tools_called_from_llm_response,
35
- # extract_tools_called,
36
- # sanitize_run_context,
37
- # )
38
-
39
- # pydantic_ai_installed = True
40
- # except:
41
- # pydantic_ai_installed = True
42
-
43
- # # _IN_RUN_SYNC = ContextVar("deepeval_in_run_sync", default=False)
44
- # # _INSTRUMENTED = False
45
-
46
-
47
- import warnings
48
- from typing import Optional
49
-
50
-
51
- def instrument(otel: Optional[bool] = False, api_key: Optional[str] = None):
52
- """
53
- DEPRECATED: This function is deprecated and will be removed in a future version.
54
- Please deepeval.integrations.pydantic_ai.Agent to instrument instead.
55
- """
56
- warnings.warn(
57
- "The 'instrument_pydantic_ai()' function is deprecated and will be removed in a future version. "
58
- "Please use deepeval.integrations.pydantic_ai.Agent to instrument instead. Refer to the documentation [link]", # TODO: add the link,
59
- UserWarning,
60
- stacklevel=2,
61
- )
62
-
63
- # Don't execute the original functionality
64
- return
65
-
66
- # Original code below (commented out to prevent execution)
67
- # global _INSTRUMENTED
68
- # if api_key:
69
- # deepeval.login(api_key)
70
- #
71
- # api_key = get_confident_api_key()
72
- #
73
- # if not api_key:
74
- # raise ValueError("No api key provided.")
75
- #
76
- # if otel:
77
- # instrument_pydantic_ai(api_key)
78
- # else:
79
- # with capture_tracing_integration("pydantic_ai"):
80
- # if _INSTRUMENTED:
81
- # return
82
- # _patch_agent_init()
83
- # _patch_agent_tool_decorator()
84
- # _INSTRUMENTED = True
85
-
86
-
87
- # ################### Init Patches ###################
88
-
89
-
90
- # # def _patch_agent_init():
91
- # # original_init = Agent.__init__
92
-
93
- # # @functools.wraps(original_init)
94
- # # def wrapper(
95
- # # *args,
96
- # # llm_metric_collection: Optional[str] = None,
97
- # # llm_metrics: Optional[List[BaseMetric]] = None,
98
- # # llm_prompt: Optional[Prompt] = None,
99
- # # agent_metric_collection: Optional[str] = None,
100
- # # agent_metrics: Optional[List[BaseMetric]] = None,
101
- # # name: Optional[str] = None,
102
- # # tags: Optional[List[str]] = None,
103
- # # metadata: Optional[dict] = None,
104
- # # thread_id: Optional[str] = None,
105
- # # user_id: Optional[str] = None,
106
- # # metric_collection: Optional[str] = None,
107
- # # metrics: Optional[List[BaseMetric]] = None,
108
- # # **kwargs
109
- # # ):
110
- # # result = original_init(*args, **kwargs)
111
- # # _patch_llm_model(args[0]._model, llm_metric_collection, llm_metrics, llm_prompt) # runtime patch of the model
112
- # # _patch_agent_run(
113
- # # agent=args[0],
114
- # # agent_metric_collection=agent_metric_collection,
115
- # # agent_metrics=agent_metrics,
116
- # # init_trace_name=name,
117
- # # init_trace_tags=tags,
118
- # # init_trace_metadata=metadata,
119
- # # init_trace_thread_id=thread_id,
120
- # # init_trace_user_id=user_id,
121
- # # init_trace_metric_collection=metric_collection,
122
- # # init_trace_metrics=metrics,
123
- # # )
124
- # # _patch_agent_run_sync(
125
- # # agent=args[0],
126
- # # agent_metric_collection=agent_metric_collection,
127
- # # agent_metrics=agent_metrics,
128
- # # init_trace_name=name,
129
- # # init_trace_tags=tags,
130
- # # init_trace_metadata=metadata,
131
- # # init_trace_thread_id=thread_id,
132
- # # init_trace_user_id=user_id,
133
- # # init_trace_metric_collection=metric_collection,
134
- # # init_trace_metrics=metrics,
135
- # # )
136
- # # return result
137
-
138
- # # Agent.__init__ = wrapper
139
-
140
-
141
- # # def _patch_agent_tool_decorator():
142
- # # original_tool = Agent.tool
143
-
144
- # # @functools.wraps(original_tool)
145
- # # def wrapper(
146
- # # *args,
147
- # # metrics: Optional[List[BaseMetric]] = None,
148
- # # metric_collection: Optional[str] = None,
149
- # # **kwargs
150
- # # ):
151
- # # # Case 1: Direct decoration - @agent.tool
152
- # # if args and callable(args[0]):
153
- # # patched_func = _create_patched_tool(
154
- # # args[0], metrics, metric_collection
155
- # # )
156
- # # new_args = (patched_func,) + args[1:]
157
- # # return original_tool(*new_args, **kwargs)
158
-
159
- # # # Case 2: Decoration with arguments - @agent.tool(metrics=..., metric_collection=...)
160
- # # else:
161
- # # # Return a decorator function that will receive the actual function
162
- # # def decorator(func):
163
- # # patched_func = _create_patched_tool(
164
- # # func, metrics, metric_collection
165
- # # )
166
- # # return original_tool(*args, **kwargs)(patched_func)
167
-
168
- # # return decorator
169
-
170
- # # Agent.tool = wrapper
171
-
172
-
173
- # ################### Runtime Patches ###################
174
-
175
-
176
- # # def _patch_agent_run_sync(
177
- # # agent: Agent,
178
- # # agent_metric_collection: Optional[str] = None,
179
- # # agent_metrics: Optional[List[BaseMetric]] = None,
180
- # # init_trace_name: Optional[str] = None,
181
- # # init_trace_tags: Optional[List[str]] = None,
182
- # # init_trace_metadata: Optional[dict] = None,
183
- # # init_trace_thread_id: Optional[str] = None,
184
- # # init_trace_user_id: Optional[str] = None,
185
- # # init_trace_metric_collection: Optional[str] = None,
186
- # # init_trace_metrics: Optional[List[BaseMetric]] = None,
187
- # # ):
188
- # # original_run_sync = agent.run_sync
189
-
190
- # # @functools.wraps(original_run_sync)
191
- # # def wrapper(
192
- # # *args,
193
- # # metric_collection: Optional[str] = None,
194
- # # metrics: Optional[List[BaseMetric]] = None,
195
- # # name: Optional[str] = None,
196
- # # tags: Optional[List[str]] = None,
197
- # # metadata: Optional[dict] = None,
198
- # # thread_id: Optional[str] = None,
199
- # # user_id: Optional[str] = None,
200
- # # **kwargs
201
- # # ):
202
-
203
- # # sig = inspect.signature(original_run_sync)
204
- # # bound = sig.bind_partial(*args, **kwargs)
205
- # # bound.apply_defaults()
206
- # # input = bound.arguments.get("user_prompt", None)
207
-
208
- # # with Observer(
209
- # # span_type="agent",
210
- # # func_name="Agent",
211
- # # function_kwargs={"input": input},
212
- # # metrics=agent_metrics,
213
- # # metric_collection=agent_metric_collection,
214
- # # ) as observer:
215
-
216
- # # token = _IN_RUN_SYNC.set(True)
217
- # # try:
218
- # # result = original_run_sync(*args, **kwargs)
219
- # # finally:
220
- # # _IN_RUN_SYNC.reset(token)
221
-
222
- # # observer.update_span_properties = (
223
- # # lambda agent_span: set_agent_span_attributes(agent_span, result)
224
- # # )
225
- # # observer.result = result.output
226
-
227
- # # _update_trace_context(
228
- # # trace_name=init_trace_name if init_trace_name else name,
229
- # # trace_tags=init_trace_tags if init_trace_tags else tags,
230
- # # trace_metadata=init_trace_metadata if init_trace_metadata else metadata,
231
- # # trace_thread_id=init_trace_thread_id if init_trace_thread_id else thread_id,
232
- # # trace_user_id=init_trace_user_id if init_trace_user_id else user_id,
233
- # # trace_metric_collection=init_trace_metric_collection if init_trace_metric_collection else metric_collection,
234
- # # trace_metrics=init_trace_metrics if init_trace_metrics else metrics,
235
- # # trace_input=input,
236
- # # trace_output=result.output,
237
- # # )
238
-
239
- # # return result
240
-
241
- # # agent.run_sync = wrapper
242
-
243
-
244
- # # def _patch_agent_run(
245
- # # agent: Agent,
246
- # # agent_metric_collection: Optional[str] = None,
247
- # # agent_metrics: Optional[List[BaseMetric]] = None,
248
- # # init_trace_name: Optional[str] = None,
249
- # # init_trace_tags: Optional[List[str]] = None,
250
- # # init_trace_metadata: Optional[dict] = None,
251
- # # init_trace_thread_id: Optional[str] = None,
252
- # # init_trace_user_id: Optional[str] = None,
253
- # # init_trace_metric_collection: Optional[str] = None,
254
- # # init_trace_metrics: Optional[List[BaseMetric]] = None,
255
- # # ):
256
- # # original_run = agent.run
257
-
258
- # # @functools.wraps(original_run)
259
- # # async def wrapper(
260
- # # *args,
261
- # # metric_collection: Optional[str] = None,
262
- # # metrics: Optional[List[BaseMetric]] = None,
263
- # # name: Optional[str] = None,
264
- # # tags: Optional[List[str]] = None,
265
- # # metadata: Optional[dict] = None,
266
- # # thread_id: Optional[str] = None,
267
- # # user_id: Optional[str] = None,
268
- # # **kwargs
269
- # # ):
270
- # # sig = inspect.signature(original_run)
271
- # # bound = sig.bind_partial(*args, **kwargs)
272
- # # bound.apply_defaults()
273
- # # input = bound.arguments.get("user_prompt", None)
274
-
275
- # # in_sync = _IN_RUN_SYNC.get()
276
- # # with Observer(
277
- # # span_type="agent" if not in_sync else "custom",
278
- # # func_name="Agent" if not in_sync else "run",
279
- # # function_kwargs={"input": input},
280
- # # metrics=agent_metrics if not in_sync else None,
281
- # # metric_collection=agent_metric_collection if not in_sync else None,
282
- # # ) as observer:
283
- # # print(args)
284
- # # print(kwargs)
285
- # # result = await original_run(*args, **kwargs)
286
- # # observer.update_span_properties = (
287
- # # lambda agent_span: set_agent_span_attributes(agent_span, result)
288
- # # )
289
- # # observer.result = result.output
290
-
291
- # # _update_trace_context(
292
- # # trace_name=init_trace_name if init_trace_name else name,
293
- # # trace_tags=init_trace_tags if init_trace_tags else tags,
294
- # # trace_metadata=init_trace_metadata if init_trace_metadata else metadata,
295
- # # trace_thread_id=init_trace_thread_id if init_trace_thread_id else thread_id,
296
- # # trace_user_id=init_trace_user_id if init_trace_user_id else user_id,
297
- # # trace_metric_collection=init_trace_metric_collection if init_trace_metric_collection else metric_collection,
298
- # # trace_metrics=init_trace_metrics if init_trace_metrics else metrics,
299
- # # trace_input=input,
300
- # # trace_output=result.output,
301
- # # )
302
-
303
- # # return result
304
-
305
- # # agent.run = wrapper
306
-
307
-
308
- # def patch_llm_model(
309
- # model: Model,
310
- # llm_metric_collection: Optional[str] = None,
311
- # llm_metrics: Optional[List[BaseMetric]] = None,
312
- # llm_prompt: Optional[Prompt] = None,
313
- # ):
314
- # original_func = model.request
315
- # sig = inspect.signature(original_func)
316
-
317
- # try:
318
- # model_name = model.model_name
319
- # except Exception:
320
- # model_name = "unknown"
321
-
322
- # @functools.wraps(original_func)
323
- # async def wrapper(*args, **kwargs):
324
- # bound = sig.bind_partial(*args, **kwargs)
325
- # bound.apply_defaults()
326
- # request = bound.arguments.get("messages", [])
327
-
328
- # with Observer(
329
- # span_type="llm",
330
- # func_name="LLM",
331
- # observe_kwargs={"model": model_name},
332
- # metrics=llm_metrics,
333
- # metric_collection=llm_metric_collection,
334
- # ) as observer:
335
- # result = await original_func(*args, **kwargs)
336
- # observer.update_span_properties = (
337
- # lambda llm_span: set_llm_span_attributes(
338
- # llm_span, request, result, llm_prompt
339
- # )
340
- # )
341
- # observer.result = result
342
- # return result
343
-
344
- # model.request = wrapper
345
-
346
-
347
- # ################### Helper Functions ###################
348
-
349
-
350
- # def create_patched_tool(
351
- # func: Callable,
352
- # metrics: Optional[List[BaseMetric]] = None,
353
- # metric_collection: Optional[str] = None,
354
- # ):
355
- # import asyncio
356
-
357
- # original_func = func
358
-
359
- # is_async = asyncio.iscoroutinefunction(original_func)
360
-
361
- # if is_async:
362
-
363
- # @functools.wraps(original_func)
364
- # async def async_wrapper(*args, **kwargs):
365
- # sanitized_args = sanitize_run_context(args)
366
- # sanitized_kwargs = sanitize_run_context(kwargs)
367
- # with Observer(
368
- # span_type="tool",
369
- # func_name=original_func.__name__,
370
- # metrics=metrics,
371
- # metric_collection=metric_collection,
372
- # function_kwargs={"args": sanitized_args, **sanitized_kwargs},
373
- # ) as observer:
374
- # result = await original_func(*args, **kwargs)
375
- # observer.result = result
376
-
377
- # return result
378
-
379
- # return async_wrapper
380
- # else:
381
-
382
- # @functools.wraps(original_func)
383
- # def sync_wrapper(*args, **kwargs):
384
- # sanitized_args = sanitize_run_context(args)
385
- # sanitized_kwargs = sanitize_run_context(kwargs)
386
- # with Observer(
387
- # span_type="tool",
388
- # func_name=original_func.__name__,
389
- # metrics=metrics,
390
- # metric_collection=metric_collection,
391
- # function_kwargs={"args": sanitized_args, **sanitized_kwargs},
392
- # ) as observer:
393
- # result = original_func(*args, **kwargs)
394
- # observer.result = result
395
-
396
- # return result
397
-
398
- # return sync_wrapper
399
-
400
-
401
- # def update_trace_context(
402
- # trace_name: Optional[str] = None,
403
- # trace_tags: Optional[List[str]] = None,
404
- # trace_metadata: Optional[dict] = None,
405
- # trace_thread_id: Optional[str] = None,
406
- # trace_user_id: Optional[str] = None,
407
- # trace_metric_collection: Optional[str] = None,
408
- # trace_metrics: Optional[List[BaseMetric]] = None,
409
- # trace_input: Optional[Any] = None,
410
- # trace_output: Optional[Any] = None,
411
- # ):
412
-
413
- # current_trace = current_trace_context.get()
414
-
415
- # if trace_name:
416
- # current_trace.name = trace_name
417
- # if trace_tags:
418
- # current_trace.tags = trace_tags
419
- # if trace_metadata:
420
- # current_trace.metadata = trace_metadata
421
- # if trace_thread_id:
422
- # current_trace.thread_id = trace_thread_id
423
- # if trace_user_id:
424
- # current_trace.user_id = trace_user_id
425
- # if trace_metric_collection:
426
- # current_trace.metric_collection = trace_metric_collection
427
- # if trace_metrics:
428
- # current_trace.metrics = trace_metrics
429
- # if trace_input:
430
- # current_trace.input = trace_input
431
- # if trace_output:
432
- # current_trace.output = trace_output
433
-
434
-
435
- # def set_llm_span_attributes(
436
- # llm_span: LlmSpan,
437
- # requests: List[ModelRequest],
438
- # result: ModelResponse,
439
- # llm_prompt: Optional[Prompt] = None,
440
- # ):
441
- # llm_span.prompt = llm_prompt
442
-
443
- # input = []
444
- # for request in requests:
445
- # for part in request.parts:
446
- # if isinstance(part, SystemPromptPart):
447
- # input.append({"role": "System", "content": part.content})
448
- # elif isinstance(part, UserPromptPart):
449
- # input.append({"role": "User", "content": part.content})
450
- # elif isinstance(part, ToolCallPart):
451
- # input.append(
452
- # {
453
- # "role": "Tool Call",
454
- # "name": part.tool_name,
455
- # "content": part.args_as_json_str(),
456
- # }
457
- # )
458
- # elif isinstance(part, ToolReturnPart):
459
- # input.append(
460
- # {
461
- # "role": "Tool Return",
462
- # "name": part.tool_name,
463
- # "content": part.model_response_str(),
464
- # }
465
- # )
466
- # llm_span.input = input
467
-
468
- # content = ""
469
- # tool_calls = []
470
- # for part in result.parts:
471
- # if isinstance(part, TextPart):
472
- # content += part.content + "\n"
473
- # elif isinstance(part, ToolCallPart):
474
- # tool_calls.append(
475
- # LlmToolCall(name=part.tool_name, args=part.args_as_dict())
476
- # )
477
- # llm_span.output = LlmOutput(
478
- # role="Assistant", content=content, tool_calls=tool_calls
479
- # )
480
- # llm_span.tools_called = extract_tools_called_from_llm_response(result.parts)
481
-
482
-
483
- # def set_agent_span_attributes(agent_span: AgentSpan, result: AgentRunResult):
484
- # agent_span.tools_called = extract_tools_called(result)