gooddata-eval 1.76.0__tar.gz → 1.76.1.dev1__tar.gz
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.
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/PKG-INFO +2 -2
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/pyproject.toml +2 -2
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/cli/agentic_runner.py +30 -1
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/agentic/__init__.py +14 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/agentic/alert_skill.py +58 -5
- gooddata_eval-1.76.1.dev1/src/gooddata_eval/core/agentic/anomaly_detection.py +642 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/agentic/conversation.py +63 -7
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/agentic/kda_skill.py +30 -2
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/agentic/metric_skill.py +43 -2
- gooddata_eval-1.76.1.dev1/src/gooddata_eval/core/agentic/report_skill.py +842 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/agentic/visualization.py +55 -6
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/chat/sse_client.py +1 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/models.py +41 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_agentic_alert_skill.py +251 -1
- gooddata_eval-1.76.1.dev1/tests/test_agentic_anomaly_detection.py +530 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_agentic_conversation.py +121 -6
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_agentic_kda_skill.py +12 -1
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_agentic_metric_skill.py +127 -1
- gooddata_eval-1.76.1.dev1/tests/test_agentic_report_skill.py +843 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_agentic_runner.py +2 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_agentic_visualization.py +90 -1
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_chat_render.py +42 -1
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_trace_linker.py +2 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/.gitignore +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/AGENTS.md +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/CLAUDE.md +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/LICENSE.txt +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/Makefile +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/README.md +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/scripts/verify_guardrail_refusal_criteria.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/__init__.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/_version.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/cli/__init__.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/cli/main.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/__init__.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/_output.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/agentic/_catalog.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/agentic/_conversation_context.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/agentic/_gate.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/agentic/_langfuse.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/agentic/_trace_linker.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/agentic/dashboard_skill.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/agentic/general_question.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/agentic/guardrail.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/agentic/search_tool.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/agentic/what_if.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/chat/__init__.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/chat/render.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/config.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/connection.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/dataset/__init__.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/dataset/from_insights.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/dataset/langfuse_source.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/dataset/local.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/evaluators/__init__.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/evaluators/_deep_subset.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/evaluators/_guardrail_criteria.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/evaluators/_llm_judge.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/evaluators/_maql.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/evaluators/_text_utils.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/evaluators/alert_skill.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/evaluators/base.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/evaluators/general_question.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/evaluators/guardrail.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/evaluators/metric_skill.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/evaluators/search_tool.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/evaluators/summary.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/evaluators/visualization.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/granularity.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/langfuse/__init__.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/langfuse/_env.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/langfuse/client.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/langfuse/experiment.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/langfuse/observations.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/langfuse/otlp.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/langfuse/sink.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/reporting/__init__.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/reporting/console.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/reporting/html_report.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/reporting/json_report.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/reporting/report_template.html +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/runner.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/scoring.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/summary/__init__.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/summary/http_client.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/timing.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/workspace.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/__init__.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/_fake_langfuse.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/conftest.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/fixtures/sample_dataset/metric_skill_create.json +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/fixtures/sample_dataset/visualization_revenue.json +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/fixtures/sse_visualization_stream.txt +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_agentic_dashboard_skill.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_agentic_gate.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_agentic_general_question.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_agentic_guardrail.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_agentic_langfuse_trace.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_agentic_observe_experiment.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_agentic_run_context.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_agentic_search_tool.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_agentic_what_if.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_alert_skill_evaluator.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_cli.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_connection.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_deep_subset.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_fake_langfuse.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_from_insights.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_guardrail_criteria.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_html_report.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_langfuse_client.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_langfuse_e2e_fake_server.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_langfuse_env.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_langfuse_experiment.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_langfuse_observations.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_langfuse_otlp.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_langfuse_sink.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_langfuse_source.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_llm_judge.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_local_loader.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_maql_normalize.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_metric_skill_evaluator.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_models.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_reporting.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_runner.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_scoring.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_search_tool_evaluator.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_sse_client.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_summary_client.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_summary_evaluator.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_text_evaluators.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_timing.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_visualization_evaluator.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tests/test_workspace.py +0 -0
- {gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/tox.ini +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: gooddata-eval
|
|
3
|
-
Version: 1.76.
|
|
3
|
+
Version: 1.76.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.76.
|
|
20
|
+
Requires-Dist: gooddata-sdk~=1.76.1.dev1
|
|
21
21
|
Requires-Dist: httpx<1.0,>=0.27
|
|
22
22
|
Requires-Dist: jsonpatch<2.0,>=1.33
|
|
23
23
|
Requires-Dist: orjson<4.0.0,>=3.9.15
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# (C) 2026 GoodData Corporation
|
|
2
2
|
[project]
|
|
3
3
|
name = "gooddata-eval"
|
|
4
|
-
version = "1.76.
|
|
4
|
+
version = "1.76.1.dev1"
|
|
5
5
|
description = "Evaluate the GoodData AI agent against your own questions and models."
|
|
6
6
|
readme = "README.md"
|
|
7
7
|
license = "MIT"
|
|
@@ -11,7 +11,7 @@ authors = [
|
|
|
11
11
|
keywords = ["gooddata", "ai", "evaluation", "llm", "analytics", "cli"]
|
|
12
12
|
requires-python = ">=3.10"
|
|
13
13
|
dependencies = [
|
|
14
|
-
"gooddata-sdk~=1.76.
|
|
14
|
+
"gooddata-sdk~=1.76.1.dev1",
|
|
15
15
|
"httpx>=0.27,<1.0",
|
|
16
16
|
"jsonpatch>=1.33,<2.0",
|
|
17
17
|
"orjson>=3.9.15,<4.0.0",
|
|
@@ -12,12 +12,14 @@ from gooddata_eval.core.agentic._gate import DEFAULT_GATE, EvalGate, normalize_g
|
|
|
12
12
|
from gooddata_eval.core.agentic._langfuse import make_langfuse_client
|
|
13
13
|
from gooddata_eval.core.agentic._trace_linker import BackgroundTraceLinker, SubmitTraceLink, run_trace_link_inline
|
|
14
14
|
from gooddata_eval.core.agentic.alert_skill import evaluate_agentic_alert_skill
|
|
15
|
+
from gooddata_eval.core.agentic.anomaly_detection import evaluate_agentic_anomaly_detection
|
|
15
16
|
from gooddata_eval.core.agentic.conversation import ConversationFixture, evaluate_agentic_conversation
|
|
16
17
|
from gooddata_eval.core.agentic.dashboard_skill import evaluate_agentic_dashboard_skill
|
|
17
18
|
from gooddata_eval.core.agentic.general_question import evaluate_agentic_general_question
|
|
18
19
|
from gooddata_eval.core.agentic.guardrail import evaluate_agentic_guardrail
|
|
19
20
|
from gooddata_eval.core.agentic.kda_skill import evaluate_agentic_kda_skill
|
|
20
21
|
from gooddata_eval.core.agentic.metric_skill import evaluate_agentic_metric_skill
|
|
22
|
+
from gooddata_eval.core.agentic.report_skill import evaluate_agentic_report_skill
|
|
21
23
|
from gooddata_eval.core.agentic.search_tool import evaluate_agentic_search_tool
|
|
22
24
|
from gooddata_eval.core.agentic.visualization import evaluate_agentic_visualization
|
|
23
25
|
from gooddata_eval.core.agentic.what_if import evaluate_agentic_what_if
|
|
@@ -43,11 +45,13 @@ AGENTIC_TEST_KINDS = frozenset(
|
|
|
43
45
|
"agentic_metric_skill",
|
|
44
46
|
"agentic_alert_skill",
|
|
45
47
|
"agentic_dashboard_skill",
|
|
48
|
+
"agentic_report_skill",
|
|
46
49
|
"agentic_search",
|
|
47
50
|
"agentic_general_question",
|
|
48
51
|
"agentic_guardrail",
|
|
49
52
|
"agentic_conversation",
|
|
50
53
|
"agentic_kda_skill",
|
|
54
|
+
"agentic_anomaly_detection",
|
|
51
55
|
"agentic_what_if",
|
|
52
56
|
}
|
|
53
57
|
)
|
|
@@ -92,7 +96,8 @@ PARALLEL_SAFE_TEST_KINDS = frozenset(
|
|
|
92
96
|
#
|
|
93
97
|
# agentic_dashboard_skill is absent by default rather than by evidence: gen-ai holds the draft and
|
|
94
98
|
# any chart it authors in conversation state and writes neither until a user saves from the UI, so
|
|
95
|
-
# it is a candidate for the allowlist once the dataset has runs behind it.
|
|
99
|
+
# it is a candidate for the allowlist once the dataset has runs behind it. agentic_report_skill is
|
|
100
|
+
# absent for the same reason: the report draft stays in conversation state until a user saves it.
|
|
96
101
|
WORKSPACE_MUTATING_TEST_KINDS = frozenset(AGENTIC_TEST_KINDS) - PARALLEL_SAFE_TEST_KINDS
|
|
97
102
|
|
|
98
103
|
|
|
@@ -203,6 +208,18 @@ def _dispatch_agentic(
|
|
|
203
208
|
agent_id=agent_id,
|
|
204
209
|
**lf_kw,
|
|
205
210
|
)
|
|
211
|
+
elif kind == "agentic_report_skill":
|
|
212
|
+
return evaluate_agentic_report_skill(
|
|
213
|
+
host=host,
|
|
214
|
+
token=token,
|
|
215
|
+
workspace_id=workspace_id,
|
|
216
|
+
question=item.question,
|
|
217
|
+
expected_output=eo,
|
|
218
|
+
k=k,
|
|
219
|
+
gate=gate,
|
|
220
|
+
agent_id=agent_id,
|
|
221
|
+
**lf_kw,
|
|
222
|
+
)
|
|
206
223
|
elif kind == "agentic_alert_skill":
|
|
207
224
|
return evaluate_agentic_alert_skill(
|
|
208
225
|
host=host,
|
|
@@ -278,6 +295,18 @@ def _dispatch_agentic(
|
|
|
278
295
|
agent_id=agent_id,
|
|
279
296
|
**lf_kw,
|
|
280
297
|
)
|
|
298
|
+
elif kind == "agentic_anomaly_detection":
|
|
299
|
+
return evaluate_agentic_anomaly_detection(
|
|
300
|
+
host=host,
|
|
301
|
+
token=token,
|
|
302
|
+
workspace_id=workspace_id,
|
|
303
|
+
question=item.question,
|
|
304
|
+
expected_output=eo if isinstance(eo, dict) else {},
|
|
305
|
+
k=k,
|
|
306
|
+
gate=gate,
|
|
307
|
+
agent_id=agent_id,
|
|
308
|
+
**lf_kw,
|
|
309
|
+
)
|
|
281
310
|
elif kind == "agentic_conversation":
|
|
282
311
|
fixture_data = eo.get("fixture") or eo if isinstance(eo, dict) else {}
|
|
283
312
|
return evaluate_agentic_conversation(
|
{gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/agentic/__init__.py
RENAMED
|
@@ -53,6 +53,14 @@ from gooddata_eval.core.agentic.metric_skill import (
|
|
|
53
53
|
evaluate_agentic_metric_skill,
|
|
54
54
|
run_agentic_metric_skill,
|
|
55
55
|
)
|
|
56
|
+
from gooddata_eval.core.agentic.report_skill import (
|
|
57
|
+
AgenticReportSummary,
|
|
58
|
+
ReportEvaluation,
|
|
59
|
+
ReportRunResult,
|
|
60
|
+
ReportSkillAssertionError,
|
|
61
|
+
evaluate_agentic_report_skill,
|
|
62
|
+
run_agentic_report_skill,
|
|
63
|
+
)
|
|
56
64
|
from gooddata_eval.core.agentic.search_tool import (
|
|
57
65
|
AgenticSearchSummary,
|
|
58
66
|
SearchResult,
|
|
@@ -75,6 +83,7 @@ __all__ = [
|
|
|
75
83
|
"AgenticGuardrailSummary",
|
|
76
84
|
"AgenticKdaSummary",
|
|
77
85
|
"AgenticMetricSummary",
|
|
86
|
+
"AgenticReportSummary",
|
|
78
87
|
"AgenticSearchSummary",
|
|
79
88
|
"AgenticRunSummary",
|
|
80
89
|
"AlertEvaluation",
|
|
@@ -95,6 +104,9 @@ __all__ = [
|
|
|
95
104
|
"KdaSkillAssertionError",
|
|
96
105
|
"MetricRunResult",
|
|
97
106
|
"MetricSkillAssertionError",
|
|
107
|
+
"ReportEvaluation",
|
|
108
|
+
"ReportRunResult",
|
|
109
|
+
"ReportSkillAssertionError",
|
|
98
110
|
"RunResult",
|
|
99
111
|
"SearchResult",
|
|
100
112
|
"SearchToolAssertionError",
|
|
@@ -108,6 +120,7 @@ __all__ = [
|
|
|
108
120
|
"evaluate_agentic_guardrail",
|
|
109
121
|
"evaluate_agentic_kda_skill",
|
|
110
122
|
"evaluate_agentic_metric_skill",
|
|
123
|
+
"evaluate_agentic_report_skill",
|
|
111
124
|
"evaluate_agentic_search_tool",
|
|
112
125
|
"evaluate_agentic_visualization",
|
|
113
126
|
"run_agentic_alert_skill",
|
|
@@ -117,6 +130,7 @@ __all__ = [
|
|
|
117
130
|
"run_agentic_guardrail",
|
|
118
131
|
"run_agentic_kda_skill",
|
|
119
132
|
"run_agentic_metric_skill",
|
|
133
|
+
"run_agentic_report_skill",
|
|
120
134
|
"run_agentic_search_tool",
|
|
121
135
|
"run_agentic_visualization",
|
|
122
136
|
]
|
{gooddata_eval-1.76.0 → gooddata_eval-1.76.1.dev1}/src/gooddata_eval/core/agentic/alert_skill.py
RENAMED
|
@@ -30,11 +30,12 @@ from gooddata_eval.core.agentic._trace_linker import (
|
|
|
30
30
|
utc_now,
|
|
31
31
|
)
|
|
32
32
|
from gooddata_eval.core.chat.render import render_answer_text
|
|
33
|
-
from gooddata_eval.core.chat.sse_client import ChatClient
|
|
33
|
+
from gooddata_eval.core.chat.sse_client import ChatClient, ChatError
|
|
34
34
|
from gooddata_eval.core.config import ReasoningEffort
|
|
35
35
|
from gooddata_eval.core.models import (
|
|
36
36
|
AgenticAssertionError,
|
|
37
37
|
AgenticEvalOutcome,
|
|
38
|
+
LoopExit,
|
|
38
39
|
ReasoningStepEvent,
|
|
39
40
|
ToolCallEvent,
|
|
40
41
|
shift_and_index_events,
|
|
@@ -483,6 +484,12 @@ class AlertRunResult:
|
|
|
483
484
|
response_id: str | None = None
|
|
484
485
|
tool_call_events: list[ToolCallEvent] = field(default_factory=list)
|
|
485
486
|
reasoning_step_events: list[ReasoningStepEvent] = field(default_factory=list)
|
|
487
|
+
# Why the simulated-user loop stopped, and how many turns it took. Without these a run
|
|
488
|
+
# that ran out of turns is indistinguishable from one that refused: both land on
|
|
489
|
+
# alert_created=False, and every downstream check is `alert_created and ...`, so both
|
|
490
|
+
# also report operator/threshold/metric/recipients as False.
|
|
491
|
+
exit_reason: LoopExit = LoopExit.BUDGET_EXHAUSTED
|
|
492
|
+
turns_used: int = 0
|
|
486
493
|
|
|
487
494
|
|
|
488
495
|
@dataclass
|
|
@@ -681,8 +688,35 @@ def run_agentic_alert_skill(
|
|
|
681
688
|
turns = 0
|
|
682
689
|
steps = 0
|
|
683
690
|
|
|
691
|
+
# Defaults to BUDGET_EXHAUSTED: every other exit sets it explicitly, so a loop
|
|
692
|
+
# that simply runs out of range() is correctly labelled without a trailing else.
|
|
693
|
+
exit_reason = LoopExit.BUDGET_EXHAUSTED
|
|
694
|
+
turns_used = 0
|
|
684
695
|
for _iteration in range(max_iterations):
|
|
685
|
-
|
|
696
|
+
turns_used = _iteration + 1
|
|
697
|
+
try:
|
|
698
|
+
chat_result = client.send_message(conv_id, current_question)
|
|
699
|
+
except ChatError as exc:
|
|
700
|
+
# Without this the exception escapes run_agentic_alert_skill entirely,
|
|
701
|
+
# discarding every K-run already completed along with any exit_reason.
|
|
702
|
+
print(f"[CHAT] send_message failed for conversation {conv_id}: {exc}")
|
|
703
|
+
# The stream can break AFTER create_metric_alert already succeeded
|
|
704
|
+
# server-side. That id only ever reached alert_id_to_delete from the
|
|
705
|
+
# normal path below, so breaking here left the alert in the workspace for
|
|
706
|
+
# the `finally` cleanup to miss -- a real object leaking out of a failed
|
|
707
|
+
# run, not a reporting gap.
|
|
708
|
+
partial = exc.partial_result
|
|
709
|
+
if partial is not None:
|
|
710
|
+
reasoning_steps.extend(partial.reasoning_steps or [])
|
|
711
|
+
response_id = partial.response_id or response_id
|
|
712
|
+
partial_alert_id, _, partial_tool_called = _extract_alert_call(partial.tool_call_events or [])
|
|
713
|
+
if partial_tool_called:
|
|
714
|
+
alert_id_to_delete = partial_alert_id
|
|
715
|
+
exit_reason = LoopExit.CHAT_ERROR
|
|
716
|
+
break
|
|
717
|
+
# `turns_used` counts attempts (set above, so a failed send still shows the
|
|
718
|
+
# loop reached this iteration); `turns`/`steps` count completed work, so they
|
|
719
|
+
# advance only once send_message has actually returned.
|
|
686
720
|
turns += 1
|
|
687
721
|
steps += chat_result.reasoning_step_count
|
|
688
722
|
reasoning_steps.extend(chat_result.reasoning_steps or [])
|
|
@@ -698,6 +732,7 @@ def run_agentic_alert_skill(
|
|
|
698
732
|
alert_id, actual_args, tool_called = _extract_alert_call(chat_result.tool_call_events or [])
|
|
699
733
|
if tool_called:
|
|
700
734
|
alert_id_to_delete = alert_id
|
|
735
|
+
exit_reason = LoopExit.SUCCESS
|
|
701
736
|
break
|
|
702
737
|
response_text = (chat_result.text_response or "").strip()
|
|
703
738
|
if not response_text and chat_result.alert_proposals:
|
|
@@ -706,13 +741,24 @@ def run_agentic_alert_skill(
|
|
|
706
741
|
response_text = render_answer_text(chat_result)
|
|
707
742
|
# Stop if agent gave a completely empty response (stuck)
|
|
708
743
|
if not response_text and not chat_result.tool_call_events:
|
|
744
|
+
exit_reason = LoopExit.AGENT_SILENT
|
|
709
745
|
break
|
|
710
746
|
# Stop before generating a follow-up for the last iteration
|
|
711
747
|
if _iteration >= max_iterations - 1:
|
|
712
748
|
break
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
749
|
+
# Recorded rather than raised, matching metric_skill and kda_skill. Letting it
|
|
750
|
+
# propagate did keep a harness fault from being scored as a content failure,
|
|
751
|
+
# but it also discarded the K-runs already completed -- and SIMULATED_USER_FAILED
|
|
752
|
+
# achieves the same separation while keeping them, since reporting reads the
|
|
753
|
+
# exit reason to classify the run as an error rather than an agent failure.
|
|
754
|
+
try:
|
|
755
|
+
follow_up = generate_simulated_alert_response(
|
|
756
|
+
response_text, expected, conversation_history, question=question
|
|
757
|
+
)
|
|
758
|
+
except Exception as exc: # noqa: BLE001 -- harness-side fault; end only this run
|
|
759
|
+
print(f"[SIM-USER] Simulated reply failed for conversation {conv_id}: {exc}")
|
|
760
|
+
exit_reason = LoopExit.SIMULATED_USER_FAILED
|
|
761
|
+
break
|
|
716
762
|
# Record this exchange so the next call has full history
|
|
717
763
|
conversation_history.append({"role": "assistant", "content": response_text})
|
|
718
764
|
conversation_history.append({"role": "user", "content": follow_up})
|
|
@@ -740,6 +786,8 @@ def run_agentic_alert_skill(
|
|
|
740
786
|
response_id=response_id,
|
|
741
787
|
tool_call_events=all_tool_call_events,
|
|
742
788
|
reasoning_step_events=all_reasoning_step_events,
|
|
789
|
+
exit_reason=exit_reason,
|
|
790
|
+
turns_used=turns_used,
|
|
743
791
|
)
|
|
744
792
|
finally:
|
|
745
793
|
if alert_id_to_delete:
|
|
@@ -908,6 +956,11 @@ def evaluate_agentic_alert_skill(
|
|
|
908
956
|
"attributes_correct": ev.attributes_correct,
|
|
909
957
|
"granularity_correct": ev.granularity_correct,
|
|
910
958
|
"actual_alert_arguments": best.actual_alert_arguments,
|
|
959
|
+
# Why the loop stopped. alert_created=False alone cannot tell a refusal from a run
|
|
960
|
+
# that hit max_iterations while still on track -- see LoopExit.
|
|
961
|
+
"exit_reason": best.exit_reason.value,
|
|
962
|
+
"turns_used": best.turns_used,
|
|
963
|
+
"max_iterations": max_iterations,
|
|
911
964
|
**timeline_detail(best.tool_call_events, best.reasoning_step_events),
|
|
912
965
|
}
|
|
913
966
|
|