deepeval 3.6.3__py3-none-any.whl → 3.6.5__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.
@@ -0,0 +1,35 @@
1
+ from typing import List, Dict, Any, Sequence
2
+ from opentelemetry.sdk.trace import ReadableSpan
3
+ from opentelemetry.sdk.trace.export import SpanExporter
4
+ from opentelemetry.sdk.trace.export import SpanExportResult
5
+ import json
6
+ from datetime import datetime
7
+
8
+
9
+ class TestExporter(SpanExporter):
10
+ """This exporter is used to test the exporter. It will store the spans in a list of dictionaries."""
11
+
12
+ span_json_list: List[Dict[str, Any]] = []
13
+
14
+ def export(
15
+ self, spans: Sequence[ReadableSpan], timeout_millis: int = 30000
16
+ ) -> SpanExportResult:
17
+ for span in spans:
18
+ _span_json = json.loads(span.to_json())
19
+ self.span_json_list.append(_span_json)
20
+
21
+ return SpanExportResult.SUCCESS
22
+
23
+ def get_span_json_list(self) -> List[Dict[str, Any]]:
24
+ return sorted(
25
+ self.span_json_list,
26
+ key=lambda x: datetime.fromisoformat(
27
+ x["start_time"].replace("Z", "+00:00")
28
+ ),
29
+ )
30
+
31
+ def clear_span_json_list(self):
32
+ self.span_json_list = []
33
+
34
+
35
+ test_exporter = TestExporter()
@@ -0,0 +1,14 @@
1
+ from .context import current_trace_context
2
+ from .tracing import trace_manager
3
+ from contextlib import contextmanager
4
+
5
+
6
+ @contextmanager
7
+ def trace():
8
+ current_trace = current_trace_context.get()
9
+
10
+ if not current_trace:
11
+ current_trace = trace_manager.start_new_trace()
12
+ current_trace_context.set(current_trace)
13
+
14
+ yield current_trace
@@ -1,3 +1,4 @@
1
+ import os
1
2
  from typing import Any, Dict, List, Literal, Optional, Set, Union, Callable
2
3
  from time import perf_counter
3
4
  import threading
@@ -47,13 +48,12 @@ from deepeval.tracing.utils import (
47
48
  tracing_enabled,
48
49
  validate_environment,
49
50
  validate_sampling_rate,
50
- dump_body_to_json_file,
51
- get_deepeval_trace_mode,
52
51
  )
53
52
  from deepeval.utils import dataclass_to_dict
54
53
  from deepeval.tracing.context import current_span_context, current_trace_context
55
54
  from deepeval.tracing.types import TestCaseMetricPair
56
55
  from deepeval.tracing.api import PromptApi
56
+ from tests.test_integrations.manager import trace_testing_manager
57
57
 
58
58
  EVAL_DUMMY_SPAN_NAME = "evals_iterator"
59
59
 
@@ -183,13 +183,14 @@ class TraceManager:
183
183
  if trace.status == TraceSpanStatus.IN_PROGRESS:
184
184
  trace.status = TraceSpanStatus.SUCCESS
185
185
 
186
- mode = get_deepeval_trace_mode()
187
- if mode == "gen":
186
+ if trace_testing_manager.test_name:
187
+ # Trace testing mode is enabled
188
+ # Instead posting the trace to the queue, it will be stored in this global variable
188
189
  body = self.create_trace_api(trace).model_dump(
189
190
  by_alias=True, exclude_none=True
190
191
  )
191
- dump_body_to_json_file(body)
192
- # Post the trace to the server before removing it
192
+ trace_testing_manager.test_dict = make_json_serializable(body)
193
+ # Post the trace to the server before removing it
193
194
  elif not self.evaluating:
194
195
  self.post_trace(trace)
195
196
  else:
deepeval/tracing/utils.py CHANGED
@@ -1,13 +1,8 @@
1
1
  import os
2
- import inspect
3
- import json
4
- import sys
5
2
  from datetime import datetime, timezone
6
3
  from enum import Enum
7
4
  from time import perf_counter
8
5
  from collections import deque
9
- from typing import Any, Dict, Optional
10
-
11
6
  from deepeval.constants import CONFIDENT_TRACING_ENABLED
12
7
 
13
8
 
@@ -186,84 +181,5 @@ def perf_counter_to_datetime(perf_counter_value: float) -> datetime:
186
181
  def replace_self_with_class_name(obj):
187
182
  try:
188
183
  return f"<{obj.__class__.__name__}>"
189
- except Exception:
190
- return "<self>"
191
-
192
-
193
- def get_deepeval_trace_mode() -> Optional[str]:
194
- deepeval_trace_mode = None
195
- try:
196
- args = sys.argv
197
- for idx, arg in enumerate(args):
198
- if isinstance(arg, str) and arg.startswith(
199
- "--deepeval-trace-mode="
200
- ):
201
- deepeval_trace_mode = (
202
- arg.split("=", 1)[1].strip().strip('"').strip("'").lower()
203
- )
204
- break
205
- if arg == "--deepeval-trace-mode" and idx + 1 < len(args):
206
- deepeval_trace_mode = (
207
- str(args[idx + 1]).strip().strip('"').strip("'").lower()
208
- )
209
- break
210
- except Exception:
211
- deepeval_trace_mode = None
212
-
213
- return deepeval_trace_mode
214
-
215
-
216
- def dump_body_to_json_file(
217
- body: Dict[str, Any], file_path: Optional[str] = None
218
- ) -> str:
219
- entry_file = None
220
- try:
221
- cmd0 = sys.argv[0] if sys.argv else None
222
- if cmd0 and cmd0.endswith(".py"):
223
- entry_file = cmd0
224
- else:
225
- for frame_info in reversed(inspect.stack()):
226
- fp = frame_info.filename
227
- if (
228
- fp
229
- and fp.endswith(".py")
230
- and "deepeval/tracing" not in fp
231
- and "site-packages" not in fp
232
- ):
233
- entry_file = fp
234
- break
235
- except Exception:
236
- entry_file = None
237
-
238
- if not entry_file:
239
- entry_file = "unknown.py"
240
-
241
- abs_entry = os.path.abspath(entry_file)
242
- dir_path = os.path.dirname(abs_entry)
243
-
244
- file_arg = None
245
- try:
246
- for idx, arg in enumerate(sys.argv):
247
- if isinstance(arg, str) and arg.startswith(
248
- "--deepeval-trace-file-name="
249
- ):
250
- file_arg = arg.split("=", 1)[1].strip().strip('"').strip("'")
251
- break
252
- if arg == "--deepeval-trace-file-name" and idx + 1 < len(sys.argv):
253
- file_arg = str(sys.argv[idx + 1]).strip().strip('"').strip("'")
254
- break
255
- except Exception:
256
- file_arg = None
257
-
258
- if file_path:
259
- dst_path = os.path.abspath(file_path)
260
- elif file_arg:
261
- dst_path = os.path.abspath(file_arg)
262
- else:
263
- base_name = os.path.splitext(os.path.basename(abs_entry))[0]
264
- dst_path = os.path.join(dir_path, f"{base_name}.json")
265
-
266
- actual_body = make_json_serializable(body)
267
- with open(dst_path, "w", encoding="utf-8") as f:
268
- json.dump(actual_body, f, ensure_ascii=False, indent=2, sort_keys=True)
269
- return dst_path
184
+ except:
185
+ return f"<self>"
deepeval/utils.py CHANGED
@@ -13,7 +13,7 @@ import math
13
13
 
14
14
  from contextvars import ContextVar
15
15
  from enum import Enum
16
- from typing import Any, Optional, Dict, List, Union
16
+ from typing import Any, Dict, List, Optional, Protocol, Sequence, Union
17
17
  from collections.abc import Iterable
18
18
  from dataclasses import asdict, is_dataclass
19
19
  from pydantic import BaseModel
@@ -28,6 +28,22 @@ from deepeval.config.utils import (
28
28
  )
29
29
 
30
30
 
31
+ ###############
32
+ # Local Types #
33
+ ###############
34
+
35
+
36
+ class TurnLike(Protocol):
37
+ order: int
38
+ role: str
39
+ content: str
40
+ user_id: Optional[str]
41
+ retrieval_context: Optional[Sequence[str]]
42
+ tools_called: Optional[Sequence[Any]]
43
+ additional_metadata: Optional[Dict[str, Any]]
44
+ comments: Optional[str]
45
+
46
+
31
47
  def get_lcs(seq1, seq2):
32
48
  m, n = len(seq1), len(seq2)
33
49
  dp = [[0] * (n + 1) for _ in range(m + 1)]
@@ -419,6 +435,138 @@ def is_missing(s: Optional[str]) -> bool:
419
435
  return s is None or (isinstance(s, str) and s.strip() == "")
420
436
 
421
437
 
438
+ def len_tiny() -> int:
439
+ value = get_settings().DEEPEVAL_MAXLEN_TINY
440
+ return value if (isinstance(value, int) and value > 0) else 40
441
+
442
+
443
+ def len_short() -> int:
444
+ value = get_settings().DEEPEVAL_MAXLEN_SHORT
445
+ return value if (isinstance(value, int) and value > 0) else 60
446
+
447
+
448
+ def len_medium() -> int:
449
+ value = get_settings().DEEPEVAL_MAXLEN_MEDIUM
450
+ return value if (isinstance(value, int) and value > 0) else 120
451
+
452
+
453
+ def len_long() -> int:
454
+ value = get_settings().DEEPEVAL_MAXLEN_LONG
455
+ return value if (isinstance(value, int) and value > 0) else 240
456
+
457
+
458
+ def shorten(
459
+ text: Optional[object],
460
+ max_len: Optional[int] = None,
461
+ suffix: Optional[str] = None,
462
+ ) -> str:
463
+ """
464
+ Truncate text to max_len characters, appending `suffix` if truncated.
465
+ - Accepts None and returns "", or any object is returned as str().
466
+ - Safe when max_len <= len(suffix).
467
+ """
468
+ settings = get_settings()
469
+
470
+ if max_len is None:
471
+ max_len = (
472
+ settings.DEEPEVAL_SHORTEN_DEFAULT_MAXLEN
473
+ if settings.DEEPEVAL_SHORTEN_DEFAULT_MAXLEN is not None
474
+ else len_long()
475
+ )
476
+ if suffix is None:
477
+ suffix = (
478
+ settings.DEEPEVAL_SHORTEN_SUFFIX
479
+ if settings.DEEPEVAL_SHORTEN_SUFFIX is not None
480
+ else "..."
481
+ )
482
+
483
+ if text is None:
484
+ return ""
485
+ stext = str(text)
486
+ if max_len <= 0:
487
+ return ""
488
+ if len(stext) <= max_len:
489
+ return stext
490
+ cut = max_len - len(suffix)
491
+ if cut <= 0:
492
+ return suffix[:max_len]
493
+ return stext[:cut] + suffix
494
+
495
+
496
+ def format_turn(
497
+ turn: TurnLike,
498
+ *,
499
+ content_length: Optional[int] = None,
500
+ max_context_items: Optional[int] = None,
501
+ context_length: Optional[int] = None,
502
+ meta_length: Optional[int] = None,
503
+ include_tools_in_header: bool = True,
504
+ include_order_role_in_header: bool = True,
505
+ ) -> str:
506
+ """
507
+ Build a multi-line, human-readable summary for a conversational turn.
508
+ Safe against missing fields and overly long content.
509
+ """
510
+ if content_length is None:
511
+ content_length = len_long()
512
+ if max_context_items is None:
513
+ max_context_items = 2
514
+ if context_length is None:
515
+ context_length = len_medium()
516
+ if meta_length is None:
517
+ meta_length = len_medium()
518
+
519
+ tools = turn.tools_called or []
520
+ tool_names = ", ".join(getattr(tc, "name", str(tc)) for tc in tools)
521
+ content = shorten(turn.content, content_length)
522
+
523
+ lines = []
524
+
525
+ if include_order_role_in_header:
526
+ header = f"{turn.order:>2}. {turn.role:<9} {content}"
527
+ if include_tools_in_header and tool_names:
528
+ header += f" | tools: {tool_names}"
529
+ if turn.user_id:
530
+ header += f" | user: {shorten(turn.user_id, len_tiny())}"
531
+ lines.append(header)
532
+ indent = " "
533
+ else:
534
+ # No order or role prefix in this mode
535
+ # keep tools out of header as well.
536
+ first = content
537
+ if turn.user_id:
538
+ first += f" | user: {shorten(turn.user_id, len_tiny())}"
539
+ lines.append(first)
540
+ indent = " " # ctx and meta indent
541
+
542
+ rctx = list(turn.retrieval_context or [])
543
+ if rctx:
544
+ show = rctx[:max_context_items]
545
+ for i, item in enumerate(show):
546
+ lines.append(f"{indent}↳ ctx[{i}]: {shorten(item, context_length)}")
547
+ hidden = max(0, len(rctx) - len(show))
548
+ if hidden:
549
+ lines.append(f"{indent}↳ ctx: (+{hidden} more)")
550
+
551
+ if turn.comments:
552
+ lines.append(
553
+ f"{indent}↳ comment: {shorten(str(turn.comments), meta_length)}"
554
+ )
555
+
556
+ meta = turn.additional_metadata or {}
557
+ if isinstance(meta, dict):
558
+ for k in list(meta.keys())[:3]:
559
+ if k in {"user_id", "userId"}:
560
+ continue
561
+ v = meta.get(k)
562
+ if v is not None:
563
+ lines.append(
564
+ f"{indent}↳ meta.{k}: {shorten(str(v), meta_length)}"
565
+ )
566
+
567
+ return "\n".join(lines)
568
+
569
+
422
570
  ###############################################
423
571
  # Source: https://github.com/tingofurro/summac
424
572
  ###############################################
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: deepeval
3
- Version: 3.6.3
3
+ Version: 3.6.5
4
4
  Summary: The LLM Evaluation Framework
5
5
  Home-page: https://github.com/confident-ai/deepeval
6
6
  License: Apache-2.0
@@ -1,5 +1,5 @@
1
1
  deepeval/__init__.py,sha256=6fsb813LD_jNhqR-xZnSdE5E-KsBbC3tc4oIg5ZMgTw,2115
2
- deepeval/_version.py,sha256=1BsEnmEpD1mtVjCYoXBeguVgrKPAi3TRpS_a7ndu4XU,27
2
+ deepeval/_version.py,sha256=7XydZTr-OhyEmxjczbOo90U1nYQK6hBYF4GXri8UIcY,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
@@ -141,14 +141,14 @@ deepeval/confident/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVG
141
141
  deepeval/confident/api.py,sha256=2ZhrQOtfxcnQSyY6OxrjY17y1yn-NB7pfIiJa20B1Pk,8519
142
142
  deepeval/confident/types.py,sha256=-slFhDof_1maMgpLxqDRZv6kz6ZVY2hP_0uj_aveJKU,533
143
143
  deepeval/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
144
- deepeval/config/settings.py,sha256=gRRi6nXEUKse13xAShU9MA18zo14vpIgl_R0xJ_0vnM,21314
144
+ deepeval/config/settings.py,sha256=EwCcYQYQDuayRVmRjYPtxUm9EHKLRu1eLaGfzNdaDEI,21827
145
145
  deepeval/config/settings_manager.py,sha256=enahSZN8krRu7-L94OBCt99fwUIqQtMRL97PlzsuKEY,4021
146
146
  deepeval/config/utils.py,sha256=gSOVv18Tx1R72GucbdQesbZLFL-Y9EzbS4p7qd2w_xE,3799
147
147
  deepeval/constants.py,sha256=Qe-es-WDPJndgBspEQXxddDCVanrAu03YWCpXsUkdo0,1368
148
148
  deepeval/contextvars.py,sha256=oqXtuYiKd4Zvc1rNoR1gcRBxzZYCGTMVn7XostwvkRI,524
149
149
  deepeval/dataset/__init__.py,sha256=N2c-rkuxWYiiJSOZArw0H02Cwo7cnfzFuNYJlvsIBEg,249
150
150
  deepeval/dataset/api.py,sha256=ZxkEqAF4nZH_Ys_1f5r9N2LFI_vBcAJxt8eJm7Mplpw,831
151
- deepeval/dataset/dataset.py,sha256=dDWTSPWN8i_mZBOAgZt0r5Id6q6aeDf8jAKxv81mP1o,51113
151
+ deepeval/dataset/dataset.py,sha256=giVTbjdS9zFfWNCD7WC4pyneLhXlvLJcBy38LYebIYY,51343
152
152
  deepeval/dataset/golden.py,sha256=T-rTk4Hw1tANx_Iimv977F6Y4QK3s5OIB4PecU5FJDM,2338
153
153
  deepeval/dataset/test_run_tracer.py,sha256=5CdpDvhzkEEBRyqWi6egocaxiN6IRS3XfbACxEQZQeM,2544
154
154
  deepeval/dataset/types.py,sha256=CWeOIBPK2WdmRUqjFa9gfN-w2da0r8Ilzl3ToDpJQoQ,558
@@ -158,15 +158,14 @@ deepeval/evaluate/__init__.py,sha256=315IaMiYEz7oJhZ4kPTBfeCNd1xF-wWVU6KOQnrKQpE
158
158
  deepeval/evaluate/api.py,sha256=rkblH0ZFAAdyuF0Ymh7JE1pIJPR9yFuPrn9SQaCEQp4,435
159
159
  deepeval/evaluate/compare.py,sha256=tdSJY4E7YJ_zO3dzvpwngZHLiUI2YQcTWJOLI83htsQ,9855
160
160
  deepeval/evaluate/configs.py,sha256=QfWjaWNxLsgEe8-5j4PIs5WcSyEckiWt0qdpXSpl57M,928
161
- deepeval/evaluate/evaluate.py,sha256=NPAJ2iJqJI_RurXKUIC0tft_ozYMIKwZf5iPfmnNhQc,10412
162
- deepeval/evaluate/execute.py,sha256=XS0XtDGKC1ZOo09lthillfi5aDI5TWFbJ-Y7yICNvGo,89056
163
- deepeval/evaluate/types.py,sha256=IGZ3Xsj0UecPI3JNeTpJaK1gDvlepokfCmHwtItIW9M,831
164
- deepeval/evaluate/utils.py,sha256=kkliSGzuICeUsXDtlMMPfN95dUKlqarNhfciSffd4gI,23143
161
+ deepeval/evaluate/evaluate.py,sha256=HoEERRLj8SVCcU1r70VQdSL4LQcSc9p20OhcD1nhEuQ,10594
162
+ deepeval/evaluate/execute.py,sha256=M0o4dpUSkvXnzEK6QIgy-2pa0HQx6w6ZRbXoI03tJeI,88931
163
+ deepeval/evaluate/types.py,sha256=zsL_lNbFMG20czzRQeWNDbLSzL8Uy7IIgvILe-X0kN0,918
164
+ deepeval/evaluate/utils.py,sha256=oBJFcUDYmmsRvXW7rXkQy3gI1Tuu5bixgvHx0yvnw1c,23563
165
165
  deepeval/integrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
166
- deepeval/integrations/crewai/__init__.py,sha256=hz3u-3PKg_FruRPkR3zEEXwTRa1VxoQFPpRK-eWhUvw,106
167
- deepeval/integrations/crewai/agent.py,sha256=ppWaaYaTKutsKOmQHhsNqoU8WltObfs6EOvzdmhM6eA,3288
168
- deepeval/integrations/crewai/handler.py,sha256=uz5qEtQeEzYNMb-fNKQFP6h863DlaMTwqOMyAeYUVc4,4480
169
- deepeval/integrations/crewai/patch.py,sha256=hqKM0RF8Tr5oeTCWuXB4oIrND_gjD2PfbmZKE_ry9C8,1299
166
+ deepeval/integrations/crewai/__init__.py,sha256=ERepE-h-1jWu_WqH5KSmMBFaoQ11lck88ojnrBIaTKw,72
167
+ deepeval/integrations/crewai/handler.py,sha256=8Cd_7N0B4o4ZhAuAbTdwOvnqUt8FRsuRsz-M_yljFWI,6508
168
+ deepeval/integrations/crewai/wrapper.py,sha256=ogJDfiB95EzvKIuY-YYXrD8CsH3CPpcsgNx-pSkNoAE,2378
170
169
  deepeval/integrations/hugging_face/__init__.py,sha256=MuHIf9im9Jypq4VkfLzhklxIrd7vSTGlT74iUNSPgvg,93
171
170
  deepeval/integrations/hugging_face/callback.py,sha256=15QQEzR34Cpdp5kUp5oVA6dEsShtiMNZ03akJWAh7lo,7911
172
171
  deepeval/integrations/hugging_face/rich_manager.py,sha256=WvFtPGpPmGeg2Ftsnojga6yvbBLiZv_tvNbnFcGb6og,3630
@@ -182,8 +181,9 @@ deepeval/integrations/llama_index/handler.py,sha256=eqI1n8E4MsvfKoFs5Zrm9IdCR7g9
182
181
  deepeval/integrations/llama_index/utils.py,sha256=mxW71-3PjvBvJpLIU0kNWuTzCidy5l_-roLt8ZyWYA0,2599
183
182
  deepeval/integrations/pydantic_ai/__init__.py,sha256=UIkXn_g6h9LTQXG1PaWu1eCFkCssIwG48WSvN46UWgU,202
184
183
  deepeval/integrations/pydantic_ai/agent.py,sha256=4wRV25O1tC-txH2j3TNJWry6gDNBqqThj7zgFKBxJpw,606
185
- deepeval/integrations/pydantic_ai/instrumentator.py,sha256=tGHuP7nn4jL9bUFR2fZWbF4k_EhF5JXOnCwQm-tmDKc,6974
184
+ deepeval/integrations/pydantic_ai/instrumentator.py,sha256=RALOL7sz-DWgUe_fd8jWqjGzKnqgVvkoMToLfuk0u10,8493
186
185
  deepeval/integrations/pydantic_ai/otel.py,sha256=0OuIpmaMtEt1dFWFZtYAiZ9hVCWweEWr1TRHYcDb4I8,1918
186
+ deepeval/integrations/pydantic_ai/test_instrumentator.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
187
187
  deepeval/key_handler.py,sha256=damdQEBLGy4IVk5DR5-E3blIZdLbcMtyeGAFn_4_SG4,6505
188
188
  deepeval/metrics/__init__.py,sha256=nvO0Wv2JROjK1I9MDNIFUJlrRAZI2C0xbGYSBZK5q4g,4013
189
189
  deepeval/metrics/answer_relevancy/__init__.py,sha256=WbZUpoSg2GQoqJ4VIRirVVQ1JDx5xwT-RskwqNKfWGM,46
@@ -236,7 +236,7 @@ deepeval/metrics/dag/schema.py,sha256=rJaMlXeESN0L3Igw0FTmErqjF6s8oKkUBEjhVKyBki
236
236
  deepeval/metrics/dag/templates.py,sha256=7pVyE1exfpU5z2OcAF4fH4xOxxIqO7orK3SQyMqGqEQ,2090
237
237
  deepeval/metrics/dag/utils.py,sha256=66D88fpjIUdVwZvYV8a1L9TlX1wvbCVuE6Y8BFTbpkE,6069
238
238
  deepeval/metrics/faithfulness/__init__.py,sha256=RffAtTOSdtWO1gHVMnPI-imJahf3JENOoJRiNw-Xv4g,43
239
- deepeval/metrics/faithfulness/faithfulness.py,sha256=bYVhHI7Tr7xH0x-7F2LijxRuCCEtLOnXLzncvJLVv60,12887
239
+ deepeval/metrics/faithfulness/faithfulness.py,sha256=KXI5VPcOsPZ2Pk1-69tR-kq4x-FYW0TxyUF4iRfD-zE,13184
240
240
  deepeval/metrics/faithfulness/schema.py,sha256=2dU9dwwmqpGJcWvY2webERWIfH_tn02xgLghHkAY_eM,437
241
241
  deepeval/metrics/faithfulness/template.py,sha256=RuZ0LFm4BjZ8lhVrKPgU3ecHszwkF0fe5-BxAkaP5AA,5839
242
242
  deepeval/metrics/g_eval/__init__.py,sha256=HAhsQFVq9LIpZXPN00Jc_WrMXrh47NIT86VnUpWM4_4,102
@@ -405,7 +405,7 @@ deepeval/plugins/plugin.py,sha256=_dwsdx4Dg9DbXxK3f7zJY4QWTJQWc7QE1HmIg2Zjjag,15
405
405
  deepeval/progress_context.py,sha256=ZSKpxrE9sdgt9G3REKnVeXAv7GJXHHVGgLynpG1Pudw,3557
406
406
  deepeval/prompt/__init__.py,sha256=M99QTWdxOfiNeySGCSqN873Q80PPxqRvjLq4_Mw-X1w,49
407
407
  deepeval/prompt/api.py,sha256=665mLKiq8irXWV8kM9P_qFJipdCYZUNQFwW8AkA3itM,1777
408
- deepeval/prompt/prompt.py,sha256=w2BmKtSzXxobjSlBQqUjdAB0Zwe6IYaLjLg7KQvVDXE,21999
408
+ deepeval/prompt/prompt.py,sha256=JjPm7rB-3rnTs8oEQT4EEwnqQqE8ZFNXebVngEOWsI4,23537
409
409
  deepeval/prompt/utils.py,sha256=Ermw9P-1-T5wQ5uYuj5yWgdj7pVB_JLw8D37Qvmh9ok,1938
410
410
  deepeval/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
411
411
  deepeval/red_teaming/README.md,sha256=BY5rAdpp3-sMMToEKwq0Nsd9ivkGDzPE16DeDb8GY7U,154
@@ -438,13 +438,13 @@ deepeval/test_case/llm_test_case.py,sha256=L-dCvJ4pMPPavZTyN9ZKN30h351DWI_TunmXf
438
438
  deepeval/test_case/mcp.py,sha256=Z625NLvz0E_UJpbyfyuAi_4nsqKH6DByBf0rfKd70xU,1879
439
439
  deepeval/test_case/mllm_test_case.py,sha256=8a0YoE72geX_fLI6yk_cObSxCPddwW-DOb-5OPE1-W8,5414
440
440
  deepeval/test_case/utils.py,sha256=5lT7QmhItsQHt44-qQfspuktilcrEyvl2cS0cgUJxds,809
441
- deepeval/test_run/__init__.py,sha256=3npHzm1Z96M2qFVtm22-RTfrVeQs27jKI-RmSWM2nh0,747
442
- deepeval/test_run/api.py,sha256=ztXrcMsz0gDebd--IqQrw_gEEBlrkxnAk-WxpUFJQg0,5427
441
+ deepeval/test_run/__init__.py,sha256=2Jdf9V2d_Wa6Fus31aUzMZ1oy3OkuhVhZhxxcGHxZaM,771
442
+ deepeval/test_run/api.py,sha256=s8q2wBsE8rgOn_1GU84a8aFRjyDxMm6qQJmpl5CorCM,5484
443
443
  deepeval/test_run/cache.py,sha256=2bKXQ4GvHe2xowFGz4ekoheLno1Yv7O6PfuanFkWnA4,12786
444
444
  deepeval/test_run/hooks.py,sha256=Qnd06bk9RJN4WmFUzJrBAi3Xj261hzyzI2iRmG8wbKw,375
445
445
  deepeval/test_run/hyperparameters.py,sha256=f7M07w1EfT8YPtiD9xVIVYa3ZewkxewSkK7knwv0YlY,2289
446
- deepeval/test_run/test_run.py,sha256=eCo_NESZruIAtSu2feSbz9AtOcu9v92TNiS0OON_i-I,33611
447
- deepeval/tracing/__init__.py,sha256=OPsA_VmYNLC1M-WYJ37R6SxGyLnoXIkuyMBTcAneeao,530
446
+ deepeval/test_run/test_run.py,sha256=vA515OlHBljO6M2RwAEDk0gw_8-ChPU48qjSkPZv8-U,36451
447
+ deepeval/tracing/__init__.py,sha256=WpiWzIIAzPIk043Si1jwTwHWxqtaIzeHj_xq9CH08nk,576
448
448
  deepeval/tracing/api.py,sha256=rq4rB5f3tfrv6l4mRJmDrwRj5CH4dyatwxhG7p8xbVk,4867
449
449
  deepeval/tracing/context.py,sha256=rzm42zYzP7jmQJO08AV-Qmw86ik45qRfF4UQNpGcmJw,5338
450
450
  deepeval/tracing/offline_evals/__init__.py,sha256=bEniJAl7PmS9u2ksiOTfHtlCPJ9_CJV5R6umrUOX5MM,102
@@ -454,15 +454,17 @@ deepeval/tracing/offline_evals/thread.py,sha256=bcSGFcZJKnszArOLIlWvnCyt0zSmsd7X
454
454
  deepeval/tracing/offline_evals/trace.py,sha256=vTflaTKysKRiYvKA-Nx6PUJ3J6NrRLXiIdWieVcm90E,1868
455
455
  deepeval/tracing/otel/__init__.py,sha256=HQsaF5yLPwyW5qg8AOV81_nG_7pFHnatOTHi9Wx3HEk,88
456
456
  deepeval/tracing/otel/exporter.py,sha256=wPO1ITKpjueLOSNLO6nD2QL9LAd8Xcu6en8hRkB61Wo,28891
457
+ deepeval/tracing/otel/test_exporter.py,sha256=bezihPGWJpwUEF3ZghxqhhorocVFTO2b43jRM-JHYMU,1076
457
458
  deepeval/tracing/otel/utils.py,sha256=yAXyPvTjax2HdLcvbVv9pyOVW4S7elIp3RLGuBTr_8o,15113
458
459
  deepeval/tracing/patchers.py,sha256=DAPNkhrDtoeyJIVeQDUMhTz-xGcXu00eqjQZmov8FiU,3096
459
460
  deepeval/tracing/perf_epoch_bridge.py,sha256=iyAPddB6Op7NpMtPHJ29lDm53Btz9yLaN6xSCfTRQm4,1825
460
- deepeval/tracing/tracing.py,sha256=xZEyuxdGY259nQaDkGp_qO7Avriv8hrf4L15ZfeMNV8,42728
461
+ deepeval/tracing/trace_context.py,sha256=jmOH3oBKz1FeNz_J61CUfkuQ3SpyFc6n7mo_HVX6JfU,352
462
+ deepeval/tracing/tracing.py,sha256=EhpZnKjYNCr_K5dTr9gqtK5uzKzhvE-lrk_t8OF5EOE,42903
461
463
  deepeval/tracing/types.py,sha256=l_utWKerNlE5H3mOKpeUJLsvpP3cMyjH7HRANNgTmSQ,5306
462
- deepeval/tracing/utils.py,sha256=SLnks8apGlrV6uVnvFVl2mWYABEkvXbPXnQvq3KaU_o,7943
463
- deepeval/utils.py,sha256=-_o3W892u7naX4Y7a8if4mP0Rtkgtapg6Krr1ZBpj0o,17197
464
- deepeval-3.6.3.dist-info/LICENSE.md,sha256=0ATkuLv6QgsJTBODUHC5Rak_PArA6gv2t7inJzNTP38,11352
465
- deepeval-3.6.3.dist-info/METADATA,sha256=BoRZ6BEBPwkypse9Xzw8gRlsezwSrDKsT5RO9C3thQc,18754
466
- deepeval-3.6.3.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
467
- deepeval-3.6.3.dist-info/entry_points.txt,sha256=fVr8UphXTfJe9I2rObmUtfU3gkSrYeM0pLy-NbJYg10,94
468
- deepeval-3.6.3.dist-info/RECORD,,
464
+ deepeval/tracing/utils.py,sha256=6SXJ7JJu-6OUziFZ_1IJppuVv7Rlq4cw3c3B7DL_eRQ,5295
465
+ deepeval/utils.py,sha256=J1JNzjAlmn-UsFTK8-c5bhUuk5crwFGVCrRvle-nNmA,21533
466
+ deepeval-3.6.5.dist-info/LICENSE.md,sha256=0ATkuLv6QgsJTBODUHC5Rak_PArA6gv2t7inJzNTP38,11352
467
+ deepeval-3.6.5.dist-info/METADATA,sha256=jVsdK4BG21hV9kceAgzk5Ug34I0d1T7s-R5BIKGiHiQ,18754
468
+ deepeval-3.6.5.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
469
+ deepeval-3.6.5.dist-info/entry_points.txt,sha256=fVr8UphXTfJe9I2rObmUtfU3gkSrYeM0pLy-NbJYg10,94
470
+ deepeval-3.6.5.dist-info/RECORD,,
@@ -1,98 +0,0 @@
1
- from typing import Optional, Dict, Any, List
2
- import weakref
3
- from deepeval.metrics import BaseMetric
4
- from deepeval.telemetry import capture_tracing_integration
5
-
6
- try:
7
- from crewai.agent import Agent as CrewAIAgent
8
-
9
- crewai_installed = True
10
- except:
11
- crewai_installed = False
12
-
13
-
14
- def is_crewai_installed():
15
- if not crewai_installed:
16
- raise ImportError(
17
- "CrewAI is not installed. Please install it with `pip install crewai`."
18
- )
19
-
20
-
21
- class AgentRegistry:
22
- """Global registry to track CrewAI agents, their metric collections, and metrics."""
23
-
24
- def __init__(self):
25
- is_crewai_installed()
26
- self._agent_metric_mapping: Dict[int, str] = {}
27
- self._agent_metrics_mapping: Dict[int, List[BaseMetric]] = {}
28
- self._agent_instances: Dict[int, weakref.ref] = {}
29
-
30
- def register_agent(
31
- self,
32
- agent: CrewAIAgent,
33
- metric_collection: Optional[str] = None,
34
- metrics: Optional[List[BaseMetric]] = None,
35
- ):
36
- """Register a CrewAI agent with its metric collection and metrics."""
37
- agent_id = id(agent)
38
- self._agent_metric_mapping[agent_id] = metric_collection
39
- self._agent_metrics_mapping[agent_id] = metrics or []
40
- self._agent_instances[agent_id] = weakref.ref(
41
- agent, self._cleanup_agent
42
- )
43
-
44
- def get_metric_collection(self, agent: CrewAIAgent) -> Optional[str]:
45
- """Get the metric collection for a given agent."""
46
- agent_id = id(agent)
47
- return self._agent_metric_mapping.get(agent_id)
48
-
49
- def get_metrics(self, agent: CrewAIAgent) -> List[BaseMetric]:
50
- agent_id = id(agent)
51
- return self._agent_metrics_mapping.get(agent_id, [])
52
-
53
- def _cleanup_agent(self, weak_ref):
54
- """Clean up agent references when they're garbage collected."""
55
- # Find and remove the agent_id for this weak reference
56
- agent_id = None
57
- for aid, ref in self._agent_instances.items():
58
- if ref == weak_ref:
59
- agent_id = aid
60
- break
61
-
62
- if agent_id:
63
- del self._agent_metric_mapping[agent_id]
64
- del self._agent_metrics_mapping[agent_id]
65
- del self._agent_instances[agent_id]
66
-
67
- def get_all_agents(self) -> Dict[int, Optional[str]]:
68
- """Get all registered agents and their metric collections."""
69
- return self._agent_metric_mapping.copy()
70
-
71
-
72
- # Global registry instance
73
- agent_registry = AgentRegistry()
74
-
75
-
76
- class Agent(CrewAIAgent):
77
- def __init__(
78
- self,
79
- *args,
80
- metric_collection: Optional[str] = None,
81
- metrics: Optional[List[BaseMetric]] = None,
82
- **kwargs
83
- ):
84
- with capture_tracing_integration("crewai.agent.Agent"):
85
- is_crewai_installed()
86
- super().__init__(*args, **kwargs)
87
- # Register this agent instance with its metric collection
88
- agent_registry.register_agent(self, metric_collection, metrics)
89
-
90
- @property
91
- def metric_collection(self) -> Optional[str]:
92
- """Get the metric collection for this agent."""
93
- return agent_registry.get_metric_collection(self)
94
-
95
- @property
96
- def metrics(self) -> List[BaseMetric]:
97
- """Get the list of metrics for this agent."""
98
- return agent_registry.get_metrics(self)
@@ -1,41 +0,0 @@
1
- from deepeval.tracing.tracing import Observer
2
-
3
-
4
- from deepeval.tracing.tracing import current_span_context
5
-
6
-
7
- def patch_build_context_for_task():
8
- from crewai.memory.contextual.contextual_memory import ContextualMemory
9
- from crewai.task import Task
10
-
11
- original_build_context_for_task = ContextualMemory.build_context_for_task
12
-
13
- def patched_build_context_for_task(*args, **kwargs):
14
- observer_kwargs = {
15
- "observe_kwargs": {
16
- "span_type": "retriever",
17
- "embedder": "contextual",
18
- }
19
- }
20
- with Observer(
21
- func_name="build_context_for_task",
22
- span_type="retriever",
23
- **observer_kwargs
24
- ):
25
- embedding_input = "No input"
26
- if isinstance(args[1], Task):
27
- embedding_input = args[1].prompt()
28
-
29
- result = original_build_context_for_task(*args, **kwargs)
30
-
31
- retrieval_context = []
32
- if isinstance(result, str):
33
- retrieval_context = [result]
34
-
35
- current_span = current_span_context.get()
36
- current_span.input = embedding_input
37
- current_span.retrieval_context = retrieval_context
38
-
39
- return result
40
-
41
- ContextualMemory.build_context_for_task = patched_build_context_for_task