gooddata-eval 1.68.1.dev4__py3-none-any.whl → 1.69.1.dev1__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.
@@ -6,7 +6,7 @@ from __future__ import annotations
6
6
  import time
7
7
  from typing import Any, TypedDict
8
8
 
9
- from gooddata_eval.core.agentic._langfuse import HttpxLangfuseClient, make_langfuse_client
9
+ from gooddata_eval.core.agentic._langfuse import make_langfuse_client
10
10
  from gooddata_eval.core.agentic.alert_skill import evaluate_agentic_alert_skill
11
11
  from gooddata_eval.core.agentic.conversation import ConversationFixture, evaluate_agentic_conversation
12
12
  from gooddata_eval.core.agentic.general_question import evaluate_agentic_general_question
@@ -17,17 +17,14 @@ from gooddata_eval.core.agentic.visualization import evaluate_agentic_visualizat
17
17
  from gooddata_eval.core.models import CreatedVisualization, DatasetItem
18
18
  from gooddata_eval.core.runner import EvalReport, ItemReport
19
19
 
20
- _LfKw = TypedDict(
21
- "_LfKw",
22
- {
23
- "langfuse": Any,
24
- "dataset_item_id": str,
25
- "dataset_name": str,
26
- "run_timestamp": str,
27
- "model_version_override": str | None,
28
- },
29
- total=False,
30
- )
20
+
21
+ class _LfKw(TypedDict, total=False):
22
+ langfuse: Any
23
+ dataset_item_id: str
24
+ dataset_name: str
25
+ run_timestamp: str
26
+ model_version_override: str | None
27
+
31
28
 
32
29
  AGENTIC_TEST_KINDS = frozenset(
33
30
  {
gooddata_eval/cli/main.py CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  import argparse
5
5
  import sys
6
+ import threading
6
7
  from datetime import datetime, timezone
7
8
  from pathlib import Path
8
9
 
@@ -11,6 +12,7 @@ from gooddata_api_client.exceptions import ApiException
11
12
  from rich.console import Console
12
13
  from rich.table import Table
13
14
 
15
+ from gooddata_eval.cli.agentic_runner import AGENTIC_TEST_KINDS, run_agentic_items
14
16
  from gooddata_eval.core.chat.sse_client import ChatClient
15
17
  from gooddata_eval.core.config import RunConfig
16
18
  from gooddata_eval.core.connection import ConnectionError_, resolve_connection
@@ -19,7 +21,6 @@ from gooddata_eval.core.langfuse.sink import LangfuseSink
19
21
  from gooddata_eval.core.models import ChatResult, DatasetItem
20
22
  from gooddata_eval.core.reporting.console import render_comparison, render_console
21
23
  from gooddata_eval.core.reporting.json_report import write_multi_model_report
22
- from gooddata_eval.cli.agentic_runner import AGENTIC_TEST_KINDS, run_agentic_items
23
24
  from gooddata_eval.core.runner import ItemReport, run_items
24
25
  from gooddata_eval.core.summary.http_client import SummaryClient
25
26
  from gooddata_eval.core.workspace import ModelResolutionError, WorkspaceModelController
@@ -97,6 +98,12 @@ def _build_parser() -> argparse.ArgumentParser:
97
98
  )
98
99
  run.add_argument("--json", dest="json_path", help="Write a JSON report to this path.")
99
100
  run.add_argument("--quiet", action="store_true", help="Suppress per-item progress output.")
101
+ run.add_argument(
102
+ "--preserve-failed",
103
+ action="store_true",
104
+ dest="preserve_failed",
105
+ help="Keep failed conversations on the server for post-mortem inspection.",
106
+ )
100
107
  run.add_argument(
101
108
  "--langfuse",
102
109
  action="store_true",
@@ -139,14 +146,24 @@ def _parse_model_arg(val: str) -> tuple[str | None, str]:
139
146
 
140
147
 
141
148
  def _make_progress_callbacks(console: Console):
142
- """Build (on_item_start, on_run_done, on_item_done) callbacks that stream progress."""
149
+ """Build (on_item_start, on_run_done, on_item_done) callbacks that stream progress.
150
+
151
+ A threading lock guards all console.print() calls so that concurrent
152
+ ``--concurrency 2+`` workers do not deadlock when stdout is piped
153
+ (e.g. running in a background process).
154
+ """
155
+ _print_lock = threading.Lock()
143
156
 
144
157
  def on_item_start(index: int, total: int, item: DatasetItem) -> None:
145
- console.print(f"[dim]\\[{index}/{total}][/dim] [cyan]{item.id}[/cyan] {_truncate(item.question)}")
158
+ with _print_lock:
159
+ console.print(f"[dim]\\[{index}/{total}][/dim] [cyan]{item.id}[/cyan] {_truncate(item.question)}")
146
160
 
147
161
  def on_run_done(index: int, total: int, run_index: int, runs: int, passed: bool, latency: float) -> None:
148
162
  tag = "[green]pass[/green]" if passed else "[red]fail[/red]"
149
- console.print(f"[dim]\\[{index}/{total}][/dim] run {run_index}/{runs} {tag} [dim]{latency:.2f}s[/dim]")
163
+ with _print_lock:
164
+ console.print(
165
+ f"[dim]\\[{index}/{total}][/dim] run {run_index}/{runs} {tag} [dim]{latency:.2f}s[/dim]"
166
+ )
150
167
 
151
168
  def on_item_done(index: int, total: int, report: ItemReport) -> None:
152
169
  if report.skipped:
@@ -165,7 +182,8 @@ def _make_progress_callbacks(console: Console):
165
182
  f" [dim]({report.latency_s:.2f}s total, {report.avg_latency_s:.2f}s avg, "
166
183
  f"quality={quality_str}, {report.runs} run(s))[/dim]"
167
184
  )
168
- console.print(f"[dim]\\[{index}/{total}][/dim] -> {tag} [cyan]{report.id}[/cyan]{suffix}")
185
+ with _print_lock:
186
+ console.print(f"[dim]\\[{index}/{total}][/dim] -> {tag} [cyan]{report.id}[/cyan]{suffix}")
169
187
 
170
188
  return on_item_start, on_run_done, on_item_done
171
189
 
@@ -319,7 +337,12 @@ def _run(config: RunConfig) -> int:
319
337
 
320
338
  # --- non-agentic items (single-turn, use Evaluator) ---
321
339
  backend = _RoutingBackend(
322
- ChatClient(host=config.host, token=config.token, workspace_id=config.workspace_id),
340
+ ChatClient(
341
+ host=config.host,
342
+ token=config.token,
343
+ workspace_id=config.workspace_id,
344
+ preserve_failed=config.preserve_failed,
345
+ ),
323
346
  SummaryClient(host=config.host, token=config.token, workspace_id=config.workspace_id),
324
347
  )
325
348
  try:
@@ -409,6 +432,7 @@ def main(argv: list[str] | None = None) -> int:
409
432
  log_to_langfuse=args.langfuse,
410
433
  quiet=args.quiet,
411
434
  kind=args.kind,
435
+ preserve_failed=args.preserve_failed,
412
436
  )
413
437
  return _run(config)
414
438
  except (
@@ -7,12 +7,10 @@ import json
7
7
  import os
8
8
  import re
9
9
  from dataclasses import dataclass
10
-
11
10
  from typing import Any
12
11
 
13
- from gooddata_eval.core.chat.sse_client import ChatClient
14
12
  from gooddata_eval.core.agentic._catalog import CatalogMetricAlert
15
-
13
+ from gooddata_eval.core.chat.sse_client import ChatClient
16
14
  from gooddata_eval.core.models import ToolCallEvent
17
15
 
18
16
  try:
@@ -80,7 +78,11 @@ def _check_trigger(expected: CatalogMetricAlert, actual_args: dict) -> bool:
80
78
  if expected.operator == "ANOMALY":
81
79
  return True
82
80
  exp_trigger = expected.trigger
83
- act_trigger = actual_args.get("trigger", actual_args.get("triggerMode", "ALWAYS"))
81
+ # A missing OR explicit-null trigger means "unset" -> the product persists the
82
+ # default ALWAYS ("Every time"). `.get(k, default)` only returns the default when
83
+ # the key is ABSENT, but create_metric_alert serialises unset params as
84
+ # `trigger: null`, so chain with `or` to also cover the present-but-None case.
85
+ act_trigger = actual_args.get("trigger") or actual_args.get("triggerMode") or "ALWAYS"
84
86
  if exp_trigger in _ALWAYS_TRIGGER_VALUES:
85
87
  return act_trigger in {"ALWAYS", "Every time"}
86
88
  act_api = _TRIGGER_DISPLAY_TO_API.get(act_trigger, act_trigger)
@@ -438,7 +440,9 @@ def evaluate_agentic_alert_skill(
438
440
  model_version_override: str | None = None,
439
441
  ) -> None:
440
442
  """Run alert-skill evaluation, log to Langfuse, and raise AlertSkillAssertionError on failure."""
441
- from datetime import datetime as _dt, timezone as _tz # noqa: PLC0415
443
+ from datetime import datetime as _dt # noqa: PLC0415
444
+ from datetime import timezone as _tz # noqa: PLC0415
445
+
442
446
  from gooddata_eval.core.agentic._langfuse import try_make_langfuse_client # noqa: PLC0415
443
447
 
444
448
  if langfuse is None:
@@ -386,7 +386,9 @@ def evaluate_agentic_conversation(
386
386
  model_version_override: str | None = None,
387
387
  ) -> None:
388
388
  """Run conversation evaluation, log to Langfuse, and raise on failure."""
389
- from datetime import datetime as _dt, timezone as _tz # noqa: PLC0415
389
+ from datetime import datetime as _dt # noqa: PLC0415
390
+ from datetime import timezone as _tz # noqa: PLC0415
391
+
390
392
  from gooddata_eval.core.agentic._langfuse import try_make_langfuse_client # noqa: PLC0415
391
393
 
392
394
  if langfuse is None:
@@ -154,7 +154,9 @@ def evaluate_agentic_general_question(
154
154
  model_version_override: str | None = None,
155
155
  ) -> None:
156
156
  """Run general-question evaluation, log to Langfuse, and raise on failure."""
157
- from datetime import datetime as _dt, timezone as _tz # noqa: PLC0415
157
+ from datetime import datetime as _dt # noqa: PLC0415
158
+ from datetime import timezone as _tz # noqa: PLC0415
159
+
158
160
  from gooddata_eval.core.agentic._langfuse import try_make_langfuse_client # noqa: PLC0415
159
161
 
160
162
  if langfuse is None:
@@ -151,7 +151,9 @@ def evaluate_agentic_guardrail(
151
151
  model_version_override: str | None = None,
152
152
  ) -> None:
153
153
  """Run guardrail evaluation, log to Langfuse, and raise on failure."""
154
- from datetime import datetime as _dt, timezone as _tz # noqa: PLC0415
154
+ from datetime import datetime as _dt # noqa: PLC0415
155
+ from datetime import timezone as _tz # noqa: PLC0415
156
+
155
157
  from gooddata_eval.core.agentic._langfuse import try_make_langfuse_client # noqa: PLC0415
156
158
 
157
159
  if langfuse is None:
@@ -3,11 +3,10 @@
3
3
 
4
4
  from __future__ import annotations
5
5
 
6
- from typing import Any
7
-
8
6
  import os
9
7
  import re
10
8
  from dataclasses import dataclass
9
+ from typing import Any
11
10
 
12
11
  from gooddata_eval.core.chat.sse_client import ChatClient
13
12
  from gooddata_eval.core.models import ToolCallEvent
@@ -247,7 +246,9 @@ def evaluate_agentic_metric_skill(
247
246
  model_version_override: str | None = None,
248
247
  ) -> None:
249
248
  """Run metric-skill evaluation, log to Langfuse, and raise MetricSkillAssertionError on failure."""
250
- from datetime import datetime as _dt, timezone as _tz # noqa: PLC0415
249
+ from datetime import datetime as _dt # noqa: PLC0415
250
+ from datetime import timezone as _tz # noqa: PLC0415
251
+
251
252
  from gooddata_eval.core.agentic._langfuse import try_make_langfuse_client # noqa: PLC0415
252
253
 
253
254
  if langfuse is None:
@@ -145,7 +145,9 @@ def evaluate_agentic_search_tool(
145
145
  model_version_override: str | None = None,
146
146
  ) -> None:
147
147
  """Run search-tool evaluation, log to Langfuse, and raise SearchToolAssertionError on failure."""
148
- from datetime import datetime as _dt, timezone as _tz # noqa: PLC0415
148
+ from datetime import datetime as _dt # noqa: PLC0415
149
+ from datetime import timezone as _tz # noqa: PLC0415
150
+
149
151
  from gooddata_eval.core.agentic._langfuse import try_make_langfuse_client # noqa: PLC0415
150
152
 
151
153
  if langfuse is None:
@@ -267,7 +267,9 @@ def evaluate_agentic_visualization(
267
267
  ) -> None:
268
268
  """Run visualization evaluation, log to Langfuse, and raise VisualizationAssertionError on failure."""
269
269
  import json as _json # noqa: PLC0415
270
- from datetime import datetime as _dt, timezone as _tz # noqa: PLC0415
270
+ from datetime import datetime as _dt # noqa: PLC0415
271
+ from datetime import timezone as _tz # noqa: PLC0415
272
+
271
273
  from gooddata_eval.core.agentic._langfuse import try_make_langfuse_client # noqa: PLC0415
272
274
 
273
275
  if langfuse is None:
@@ -106,6 +106,7 @@ class _SseAccumulator:
106
106
  call_id_to_event_index: dict[str, int] = field(default_factory=dict)
107
107
  reasoning_steps: list[dict[str, Any]] = field(default_factory=list)
108
108
  adhoc_viz_args: list[dict[str, Any]] = field(default_factory=list)
109
+ response_id: str | None = None
109
110
 
110
111
 
111
112
  def _handle_text(content: dict[str, Any], acc: _SseAccumulator) -> None:
@@ -176,7 +177,9 @@ def _build_chat_result(acc: _SseAccumulator) -> ChatResult:
176
177
  "objects": [acc.adhoc_viz_args[-1]],
177
178
  "reasoning": "\n".join(acc.viz_reasoning_parts),
178
179
  }
179
- return ChatResult.model_validate(payload)
180
+ result = ChatResult.model_validate(payload)
181
+ result.response_id = acc.response_id
182
+ return result
180
183
 
181
184
 
182
185
  def parse_sse_lines(lines: Iterable[str]) -> ChatResult:
@@ -204,9 +207,13 @@ def parse_sse_lines(lines: Iterable[str]) -> ChatResult:
204
207
  if code in _RETRYABLE_STATUS_CODES:
205
208
  raise TransientChatError(message, status_code=code, detail=detail)
206
209
  raise ChatError(message, status_code=code, detail=detail)
210
+ if event_data.get("responseId") and not acc.response_id:
211
+ acc.response_id = event_data["responseId"]
207
212
  item = event_data.get("item")
208
213
  if not item:
209
214
  continue
215
+ if item.get("responseId") and not acc.response_id:
216
+ acc.response_id = item["responseId"]
210
217
  role = item.get("role")
211
218
  content: dict[str, Any] = item.get("content") or {}
212
219
  ctype = content.get("type")
@@ -227,10 +234,13 @@ def parse_sse_lines(lines: Iterable[str]) -> ChatResult:
227
234
  class ChatClient:
228
235
  """Single-turn AI chat client over the GoodData AI conversation endpoints."""
229
236
 
230
- def __init__(self, host: str, token: str, workspace_id: str, *, timeout: float = 300.0):
237
+ def __init__(
238
+ self, host: str, token: str, workspace_id: str, *, timeout: float = 300.0, preserve_failed: bool = False
239
+ ):
231
240
  self._base = f"{host.rstrip('/')}/api/v1/ai/workspaces/{workspace_id}/chat/conversations"
232
241
  self._auth = {"Authorization": f"Bearer {token}"}
233
242
  self._client = httpx.Client(timeout=timeout)
243
+ self._preserve_failed = preserve_failed
234
244
 
235
245
  def create_conversation(self) -> str:
236
246
  def _do() -> str:
@@ -264,12 +274,29 @@ class ChatClient:
264
274
  return _retry_transient(_do, is_retryable=_is_retryable_exc)
265
275
 
266
276
  def ask(self, item: DatasetItem) -> ChatResult:
267
- """Run one single-turn conversation: create, send, parse, clean up."""
277
+ """Run one conversation: create, send, parse, clean up.
278
+
279
+ The conversation_id is attached to the returned ChatResult for tracing.
280
+ When ``preserve_failed`` is set, failed conversations are kept on the
281
+ server so they can be inspected after the run; the conversation_id is
282
+ attached to the raised exception as well.
283
+ """
268
284
  conversation_id = self.create_conversation()
285
+ success = False
269
286
  try:
270
- return self.send_message(conversation_id, item.question)
287
+ result = self.send_message(conversation_id, item.question)
288
+ result.conversation_id = conversation_id
289
+ success = True
290
+ return result
291
+ except Exception as exc:
292
+ try:
293
+ object.__setattr__(exc, "conversation_id", conversation_id)
294
+ except TypeError:
295
+ pass # C-extension exception that rejects __setattr__
296
+ raise
271
297
  finally:
272
- self.delete_conversation(conversation_id)
298
+ if success or not self._preserve_failed:
299
+ self.delete_conversation(conversation_id)
273
300
 
274
301
  def close(self) -> None:
275
302
  self._client.close()
@@ -19,3 +19,4 @@ class RunConfig:
19
19
  log_to_langfuse: bool = False
20
20
  quiet: bool = False
21
21
  kind: str = "visualization"
22
+ preserve_failed: bool = False
@@ -78,7 +78,9 @@ class AlertSkillEvaluator:
78
78
 
79
79
  if "Trigger" in expected:
80
80
  expected_trigger = _TRIGGER_MAP.get(expected["Trigger"], expected["Trigger"])
81
- trigger_correct = args.get("trigger") == expected_trigger
81
+ # Omitted/null trigger persists as the product default ALWAYS ("Every time").
82
+ actual_trigger = args.get("trigger") or "ALWAYS"
83
+ trigger_correct = actual_trigger == expected_trigger
82
84
 
83
85
  if "Filters" in expected:
84
86
  actual_filters = args.get("filters") or []
@@ -5,14 +5,33 @@ from gooddata_eval.core.evaluators.base import ItemEvaluation
5
5
  from gooddata_eval.core.models import ChatResult, DatasetItem
6
6
 
7
7
 
8
+ def _normalize_str_list(value: object, *, lowercase: bool = False) -> list[str]:
9
+ # Arguments come from raw model-emitted JSON. The search_objects schema
10
+ # declares keywords/object_types as list[str], but a malformed tool call may
11
+ # send a non-list or non-string entries. Drop the offending entries defensively
12
+ # so bad input can't raise (.lower()/sorted() on a non-str) and abort the whole
13
+ # evaluation run; a non-list collapses to [] and the surviving strings are
14
+ # still compared normally.
15
+ if not isinstance(value, list):
16
+ return []
17
+ items = [item for item in value if isinstance(item, str)]
18
+ return sorted(item.lower() if lowercase else item for item in items)
19
+
20
+
8
21
  def _args_match(actual_args: dict, expected_args: dict) -> bool:
9
- if sorted(actual_args.get("keywords") or []) != sorted(expected_args.get("keywords") or []):
10
- return False
11
- if sorted(actual_args.get("object_types") or []) != sorted(expected_args.get("object_types") or []):
12
- return False
13
- if actual_args.get("limit") != expected_args.get("limit"):
22
+ # Only keywords and object_types determine semantic correctness.
23
+ # limit is optional with a server-side default; emit_widget was renamed to
24
+ # user_requested_search in the tool schema neither affects search quality.
25
+ actual_kw = _normalize_str_list(actual_args.get("keywords"), lowercase=True)
26
+ expected_kw = _normalize_str_list(expected_args.get("keywords"), lowercase=True)
27
+ if actual_kw != expected_kw:
14
28
  return False
15
- return actual_args.get("emit_widget") == expected_args.get("emit_widget")
29
+ # object_types is compared case-sensitively (no lowercase=True): they are
30
+ # controlled ObjectType StrEnum values the model emits verbatim ("metric",
31
+ # "dashboard"), so a case mismatch is a genuine error, not a formatting quirk.
32
+ return _normalize_str_list(actual_args.get("object_types")) == _normalize_str_list(
33
+ expected_args.get("object_types")
34
+ )
16
35
 
17
36
 
18
37
  class SearchToolEvaluator:
@@ -94,6 +94,8 @@ class ChatResult(BaseModel):
94
94
  created_visualizations: CreatedVisualizations | None = Field(default=None, alias="createdVisualizations")
95
95
  tool_call_events: list[ToolCallEvent] = Field(default_factory=list, alias="toolCallEvents")
96
96
  reasoning_step_count: int = Field(default=0, alias="reasoningStepCount")
97
+ conversation_id: str | None = Field(default=None, alias="conversationId")
98
+ response_id: str | None = Field(default=None, alias="responseId")
97
99
 
98
100
 
99
101
  class SummaryInput(BaseModel):
@@ -34,6 +34,8 @@ def _build_run_dict(report: EvalReport) -> dict:
34
34
  "latency_s": round(item.latency_s, 3),
35
35
  "avg_latency_s": round(item.avg_latency_s, 3),
36
36
  "detail": item.best_detail,
37
+ "conversation_id": item.conversation_id,
38
+ "response_id": item.response_id,
37
39
  }
38
40
  for item in report.items
39
41
  },
@@ -31,6 +31,8 @@ class ItemReport:
31
31
  runs: int = 0
32
32
  latency_s: float = 0.0 # total wall-clock across this item's runs
33
33
  best_detail: dict = field(default_factory=dict)
34
+ conversation_id: str | None = None
35
+ response_id: str | None = None
34
36
 
35
37
  @property
36
38
  def avg_latency_s(self) -> float:
@@ -112,6 +114,8 @@ def _run_one_item(
112
114
  for run_index in range(1, runs + 1):
113
115
  t0 = time.perf_counter()
114
116
  chat_result = backend.ask(item)
117
+ report.conversation_id = getattr(chat_result, "conversation_id", None) or report.conversation_id
118
+ report.response_id = getattr(chat_result, "response_id", None) or report.response_id
115
119
  evaluation = evaluator.evaluate(item, chat_result)
116
120
  latency = time.perf_counter() - t0
117
121
  report.runs += 1
@@ -123,7 +127,9 @@ def _run_one_item(
123
127
  if on_run_done is not None:
124
128
  on_run_done(run_index, runs, evaluation.passed, latency)
125
129
  except Exception as e: # agent/network/parse failure for this item
126
- report.error = f"{type(e).__name__}: {e}"
130
+ conv_id = getattr(e, "conversation_id", None)
131
+ report.conversation_id = conv_id or report.conversation_id
132
+ report.error = f"{type(e).__name__}: {e}" + (f" [conversation_id={conv_id}]" if conv_id else "")
127
133
  if best is not None:
128
134
  report.best_detail = best.detail
129
135
  return report
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gooddata-eval
3
- Version: 1.68.1.dev4
3
+ Version: 1.69.1.dev1
4
4
  Summary: Evaluate the GoodData AI agent against your own questions and models.
5
5
  Project-URL: Source, https://github.com/gooddata/gooddata-python-sdk
6
6
  Author-email: GoodData <support@gooddata.com>
@@ -17,7 +17,7 @@ Classifier: Topic :: Scientific/Engineering
17
17
  Classifier: Topic :: Software Development
18
18
  Classifier: Typing :: Typed
19
19
  Requires-Python: >=3.10
20
- Requires-Dist: gooddata-sdk~=1.68.1.dev4
20
+ Requires-Dist: gooddata-sdk~=1.69.1.dev1
21
21
  Requires-Dist: httpx<1.0,>=0.27
22
22
  Requires-Dist: orjson<4.0.0,>=3.9.15
23
23
  Requires-Dist: pydantic<3.0,>=2.6
@@ -1,27 +1,27 @@
1
1
  gooddata_eval/__init__.py,sha256=9Nz0iJXzkJWiL40PijM6AMpAqQOH-dbYNfDtDysBPYc,186
2
2
  gooddata_eval/_version.py,sha256=L4nT6RJQ2vc_F9stvO59xZv92xsRUqbpUh1sGlb-UNU,195
3
3
  gooddata_eval/cli/__init__.py,sha256=U54lANKm34yjqm7dZL9KkGouPbwAaQWC9wiAmb5B5g4,32
4
- gooddata_eval/cli/agentic_runner.py,sha256=0tKLjaohRYmszoF2DaZAJuIQ0rGNP4aDEFR5qbJsFjc,8091
5
- gooddata_eval/cli/main.py,sha256=fbXzTGlEid5pFqJ1AotE-BldQybGtCCQbD4QjTjQIZY,17937
4
+ gooddata_eval/cli/agentic_runner.py,sha256=eb8BD4ITDpLTpgSP5MT32NYkMGxQU9W0Ye0vT4mG5wE,8010
5
+ gooddata_eval/cli/main.py,sha256=hNRfsb4zWEuvvgDSPq8BRn0EsPbslyDdehghWeiLBX0,18693
6
6
  gooddata_eval/core/__init__.py,sha256=U54lANKm34yjqm7dZL9KkGouPbwAaQWC9wiAmb5B5g4,32
7
- gooddata_eval/core/config.py,sha256=c0lgsILU70VJejhJGSZJmyne8i2uNXDiZEXRRKJEOgs,560
7
+ gooddata_eval/core/config.py,sha256=MFI6af8mWBQyEjU-buG58hrCPKk0IMpCSzscyyF-wUQ,594
8
8
  gooddata_eval/core/connection.py,sha256=mh-Do5-Ti0-DXXikfCIH10eTTUbKuZUAS_sLoPNDJ5I,1229
9
- gooddata_eval/core/models.py,sha256=g7bi7OGxnADGidVQmJLNuvehddSoW_-4e4YhEFSSkKs,3989
10
- gooddata_eval/core/runner.py,sha256=vRo2SwRKRjkSNCp6tse4tSGRWC3zBPFdjAnM5rMg05M,8064
9
+ gooddata_eval/core/models.py,sha256=LNuT8wqjQs52LfUOvUr4tGMKz48G8ksu_k2KkAILe-o,4137
10
+ gooddata_eval/core/runner.py,sha256=sxE7kWDG6ttkSf5kUkZEJJ-B3DqWHXQOFBMEjMr4-D4,8520
11
11
  gooddata_eval/core/scoring.py,sha256=7ku48WEXtZl8EhowKikMiBmKfH7BDoZxHVvEOY8h3Rk,6007
12
12
  gooddata_eval/core/workspace.py,sha256=S8exiy5gpDtcRtT8-i2fIRALF34Pbo0J46xm8X_ldus,11846
13
13
  gooddata_eval/core/agentic/__init__.py,sha256=nPjJ9sbnJVvsAlo9QMQlnPFgLNTZRzy9-0IKlnRcU8Q,2671
14
14
  gooddata_eval/core/agentic/_catalog.py,sha256=eCaeyvLF-FCN0J3UnXSHaKtufU6HvrM2mxnmgyXsY1U,2085
15
15
  gooddata_eval/core/agentic/_langfuse.py,sha256=zJiZTz5xloWQBunwxXzdOY3NrA0S4QPFc6d3iB-cgkE,13432
16
- gooddata_eval/core/agentic/alert_skill.py,sha256=h5i-GVJOAUzgMhIF5yGKIz7JL3f6QXKZAKz6gcN7vpY,19702
17
- gooddata_eval/core/agentic/conversation.py,sha256=tTpN1AySPGDbYcpwY2G0J38lRYiU5sqvbdDJBOyPQHc,17542
18
- gooddata_eval/core/agentic/general_question.py,sha256=piPY5XOMjH4Xwl2qN0D5KWBL1RJjYaP63oX1eXp-7yU,7978
19
- gooddata_eval/core/agentic/guardrail.py,sha256=-vZg-jeL2LYKGaLesuu7Yg1AIEn-9bfDK130EMdw_7s,7865
20
- gooddata_eval/core/agentic/metric_skill.py,sha256=jFqVsxNEx-7IHa4v8aNLkDzD9OogDsgV4O3UJkiVDFw,11388
21
- gooddata_eval/core/agentic/search_tool.py,sha256=EiWuzwdWUTY8H6wLST1rBB-fvc4meMazLKhiy0nl9K0,7634
22
- gooddata_eval/core/agentic/visualization.py,sha256=ScSfx4-4lwHswqF_0ugOrIFu5d4tlAQf6CxaFVV9_mE,16743
16
+ gooddata_eval/core/agentic/alert_skill.py,sha256=48nZ7w7Eaxw89nYfVT-aXMmtiLWa_hcBv2VV1IkVflQ,20074
17
+ gooddata_eval/core/agentic/conversation.py,sha256=ff6d9Q5ujlAq31PqnvCZ4bFlmmPKVFZBKLTuzwdOwZk,17584
18
+ gooddata_eval/core/agentic/general_question.py,sha256=6MdDDf8_GFR2hi5SFNEyg5bg9fCwa9poEJrVwIHvDt4,8020
19
+ gooddata_eval/core/agentic/guardrail.py,sha256=f6eXxuDjGw-jhBDzQFfPGMEy880xy9gXspt48_Dm6Os,7907
20
+ gooddata_eval/core/agentic/metric_skill.py,sha256=5aXi-TniijR9-1-AmhI23Db80N5TuEElACO2cOLvG_0,11429
21
+ gooddata_eval/core/agentic/search_tool.py,sha256=IPdTegOcltFe0U5oqLL6ZeuokB7HgSQtRBNDtZdRMO8,7676
22
+ gooddata_eval/core/agentic/visualization.py,sha256=TxpgkrMfIom9pqVZgQX7bIzUIr3B_DGMj9oVvBeQaEE,16785
23
23
  gooddata_eval/core/chat/__init__.py,sha256=U54lANKm34yjqm7dZL9KkGouPbwAaQWC9wiAmb5B5g4,32
24
- gooddata_eval/core/chat/sse_client.py,sha256=1FVi2HWf2-uHMro7uWSiTiQTMEbh6WhVvQW8flnxymY,11205
24
+ gooddata_eval/core/chat/sse_client.py,sha256=XIXKhgvsJFAnZJpgZNu2Ux07UHzFyVFD50ch3He0TrM,12340
25
25
  gooddata_eval/core/dataset/__init__.py,sha256=U54lANKm34yjqm7dZL9KkGouPbwAaQWC9wiAmb5B5g4,32
26
26
  gooddata_eval/core/dataset/langfuse_source.py,sha256=R2KzNx6LxAUtDZwHL5_UW5CJ6q-QnQGW7AhLZKBTDKU,5589
27
27
  gooddata_eval/core/dataset/local.py,sha256=qoFFtRx_bNwlT1U37o8CKkSPwCad3JpmHPcNRuGSbjE,1233
@@ -29,23 +29,23 @@ gooddata_eval/core/evaluators/__init__.py,sha256=iFZER-ajMRqNEH6A0vd5cYJIqWc5RbV
29
29
  gooddata_eval/core/evaluators/_deep_subset.py,sha256=TonPUfkUZL4q1a9t3cczDC2vSF54ynEDDQRxP6p-fvc,1407
30
30
  gooddata_eval/core/evaluators/_llm_judge.py,sha256=411JCEgkXFEEbosbQ2Ys6JT9h6JCj2wBJ3XmJyEJSpE,2363
31
31
  gooddata_eval/core/evaluators/_text_utils.py,sha256=yj9jAhTsYGdP4NZiC-9xXmEZ_JperJfBvEwNChsYplw,363
32
- gooddata_eval/core/evaluators/alert_skill.py,sha256=b3zJjY6syKoTSerxfzXgNUGbfWNzHb3c0YwtQofH9n0,4674
32
+ gooddata_eval/core/evaluators/alert_skill.py,sha256=kRUX3Y1mLhYDPWbFwhwwQ15SeSa2Bv2GNoQ3I7rLxJs,4820
33
33
  gooddata_eval/core/evaluators/base.py,sha256=H9EMG57jX0W4vmasgJNUhwRjtGRuVBik2MhN9ZDV1Jk,777
34
34
  gooddata_eval/core/evaluators/general_question.py,sha256=FRG4jvxbyw-FW9bbl7vY2iVx_8g8n_apg2FlIJyQQfY,1438
35
35
  gooddata_eval/core/evaluators/guardrail.py,sha256=jbjEeXopQbELvUcLmAPRg3LxKtmF4t0R4GAZaqyAxso,2219
36
36
  gooddata_eval/core/evaluators/metric_skill.py,sha256=nduKivSzy6sqI_yRclOHL6jvjIeWFO0ny1p6x1fIO4Y,2046
37
- gooddata_eval/core/evaluators/search_tool.py,sha256=KRjJ7-Gy4Cd8rPcV-Khgtzw6A32T_cLiL2wT_19uJro,1825
37
+ gooddata_eval/core/evaluators/search_tool.py,sha256=L5C_esa_aHO8E3p4fl-Kk60Vsj1wuLaNjscdGs87rwM,2953
38
38
  gooddata_eval/core/evaluators/summary.py,sha256=arY6xeYDrJnS-qhG9KgX84p4hBp3k5OylP4WevTcEck,4533
39
39
  gooddata_eval/core/evaluators/visualization.py,sha256=MF5zFxyZpxbHZApW59YjHbvXnoU2dntFPgjKXotYi6E,6936
40
40
  gooddata_eval/core/langfuse/__init__.py,sha256=U54lANKm34yjqm7dZL9KkGouPbwAaQWC9wiAmb5B5g4,32
41
41
  gooddata_eval/core/langfuse/sink.py,sha256=c86VwfpCrNkS36UynzwCADHkFLv0IKs0YYJb5PAXGnA,7225
42
42
  gooddata_eval/core/reporting/__init__.py,sha256=U54lANKm34yjqm7dZL9KkGouPbwAaQWC9wiAmb5B5g4,32
43
43
  gooddata_eval/core/reporting/console.py,sha256=kCHt4sCSaSRh0ZWqaSEJOl6_Jgb6uiouS2gGpnqp1Us,4779
44
- gooddata_eval/core/reporting/json_report.py,sha256=NIA_PvnZ0PbJnXz_zZauxc1gGnzqlLD_ouVqWeNmjtw,2837
44
+ gooddata_eval/core/reporting/json_report.py,sha256=sKPG9-uxzDsf6EJyBXoaHVIfN1g-E2rZ8fA0wtyBYb4,2943
45
45
  gooddata_eval/core/summary/__init__.py,sha256=U54lANKm34yjqm7dZL9KkGouPbwAaQWC9wiAmb5B5g4,32
46
46
  gooddata_eval/core/summary/http_client.py,sha256=dPArJ6zoCu1W9xmYXFA1WMDNsSOkhn3gaCpYgCUp3gk,2174
47
- gooddata_eval-1.68.1.dev4.dist-info/METADATA,sha256=7eLGgge0gSIxqwAWeU3kPoPa4VjLC-WH0tQne-KWbS8,9513
48
- gooddata_eval-1.68.1.dev4.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
49
- gooddata_eval-1.68.1.dev4.dist-info/entry_points.txt,sha256=28nFp5Viknx4haPYgzK9QHlwPFfC6rPF6RmjC2ht8EI,56
50
- gooddata_eval-1.68.1.dev4.dist-info/licenses/LICENSE.txt,sha256=LVfVlC9maU3K9lgMwdZnClQQsOIbOekdcdVKr9qzJtk,256836
51
- gooddata_eval-1.68.1.dev4.dist-info/RECORD,,
47
+ gooddata_eval-1.69.1.dev1.dist-info/METADATA,sha256=aTsSASych8BWhzWaRwnZBm1ym7C6We7zP5DxL37MaZI,9513
48
+ gooddata_eval-1.69.1.dev1.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
49
+ gooddata_eval-1.69.1.dev1.dist-info/entry_points.txt,sha256=28nFp5Viknx4haPYgzK9QHlwPFfC6rPF6RmjC2ht8EI,56
50
+ gooddata_eval-1.69.1.dev1.dist-info/licenses/LICENSE.txt,sha256=LVfVlC9maU3K9lgMwdZnClQQsOIbOekdcdVKr9qzJtk,256836
51
+ gooddata_eval-1.69.1.dev1.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.30.1
2
+ Generator: hatchling 1.31.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any