feat(gooddata-eval): report created metric/automation id from single-turn evaluators#1694
Conversation
…turn evaluators metric_skill and alert_skill evaluators already parse the create_metric / create_metric_alert tool call's result to grade the run, but discarded the real server-assigned id. Downstream consumers running these single-turn evals against a shared workspace (e.g. a CI orchestrator) currently have no way to know exactly what was created, and have to diff the workspace catalog before/after to guess at cleanup -- fragile under concurrent activity. Surface the id gd-eval already has in memory instead.
|
Warning Review limit reached
Next review available in: 18 minutes Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAlert and metric evaluators now expose created object identifiers in evaluation details, including ChangesEvaluator result identifiers
Estimated code review effort: 2 (Simple) | ~10 minutes Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/gooddata-eval/src/gooddata_eval/core/evaluators/alert_skill.py`:
- Around line 28-38: Update _extract_automation_id to validate
result_data["data"] is a dict before calling .get("id"), returning None when the
nested value is malformed; add a regression case covering a non-mapping data
payload and asserting automation_id is None.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 32104030-f7c1-4215-a07c-bbbe300bd31e
📒 Files selected for processing (4)
packages/gooddata-eval/src/gooddata_eval/core/evaluators/alert_skill.pypackages/gooddata-eval/src/gooddata_eval/core/evaluators/metric_skill.pypackages/gooddata-eval/tests/test_alert_skill_evaluator.pypackages/gooddata-eval/tests/test_metric_skill_evaluator.py
result_data["data"] being present but not a dict (malformed/unexpected
tool-result payload) crashed with AttributeError on .get("id") instead of
reporting automation_id=None like the rest of the function already does
for other malformed shapes.
Addresses CodeRabbit review comment on #1694.
Problem
MetricSkillEvaluatorandAlertSkillEvaluator(packages/gooddata-eval/src/gooddata_eval/core/evaluators/{metric_skill,alert_skill}.py) already parse thecreate_metric/create_metric_alerttool call's result to grade a run (MAQL/format match, operator/threshold/trigger/filters/metric/recipients match), but discard the real server-assigned id of whatever object the agent created.This matters for any consumer running these single-turn kinds against a persistent/shared workspace: there is currently no way to identify the exact object a run created from
gd-eval's own--jsonreport. The agentic counterparts (agentic_metric_skill/agentic_alert_skill,core/agentic/{metric_skill,alert_skill}.py) already extract this same id from the identical tool-call-result payload to self-clean viaentities_api.delete_entity_metrics/delete_entity_automationsin afinallyblock — the single-turn path has the same data in hand and simply never surfaces it.Concretely: a caller orchestrating single-turn
metric_skill/alert_skillruns against a shared eval workspace (e.g. a scheduled CI job) has no choice today but to diff the workspace's metric/automation catalog before and after each call and guess which new object belongs to which run — fragile under any concurrent activity, and foralert_skillthere's no deterministic field to cross-check the guess against at all.Change
MetricSkillEvaluator.evaluate(): addsdetail["metric_id"], read from the already-unwrappedcreate_metrictool result (payload.get("metric_id")).nullwhen no tool call fired.AlertSkillEvaluator.evaluate(): addsdetail["automation_id"], extracted from thecreate_metric_alerttool call's result (not its arguments — the id is server-assigned, the agent's requested arguments don't carry it) via a new_extract_automation_id()helper, mirroringcore/agentic/alert_skill.py's_extract_alert_call'sresult_data.get("id") or (result_data.get("data") or {}).get("id")unwrap shape.nullwhen no tool call fired.passed/rank_keycomputation, or the JSON report's shape/schema beyond the two newdetailkeys —json_report.py's_build_run_dictalready serializesitem.best_detailverbatim, so both new fields flow through to--jsonoutput with no further changes needed there.Testing
tests/test_metric_skill_evaluator.py: assertsdetail["metric_id"]on the existing exact-match fixture (already encoded"metric_id": "avg_order_value"in its tool-result JSON, previously unused by any assertion) and assertsNoneon the no-tool-call path.tests/test_alert_skill_evaluator.py: extends_chat_with_alert()to accept an optionalresultpayload (previously hardcoded to"{}"), adds three new cases — top-level{"id": ...}, nested{"data": {"id": ...}}, and no-id-present — plus aNoneassertion on the no-tool-call path.pytest packages/gooddata-eval/tests— 242 passed (245 with the 3 new cases in this PR).gd-eval run --dataset <single metric_skill item> --json report.jsonand confirmedreport["runs"][...]["items"][...]["detail"]["metric_id"]is present in the actual CLI output (nullin that particular run, since the agent didn't callcreate_metricthat time — confirms the field wires through end-to-end regardless of outcome).Compatibility
Purely additive — two new keys in each evaluator's
detaildict. No existing key removed, renamed, or changed in meaning; no public function signatures changed.Summary by CodeRabbit
New Features
Tests