Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: gooddata/gooddata-python-sdk
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: master
Choose a base ref
...
head repository: gooddata/gooddata-python-sdk
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: ptom/mic-evaluations
Choose a head ref
Checking mergeability… Don’t worry, you can still create the pull request.
  • 7 commits
  • 15 files changed
  • 2 contributors

Commits on Aug 5, 2026

  1. feat(gooddata-eval): capture agent reasoning steps in ChatResult

    The SSE reasoning events were already being read to produce
    reasoning_step_count, but the step text itself was discarded. Keep it
    as reasoning_steps on ChatResult/ItemReport and surface it in the JSON
    report so eval consumers can inspect the agent's actual reasoning
    trace, not just how many steps it took.
    Tomkess committed Aug 5, 2026
    Configuration menu
    Copy the full SHA
    389905b View commit details
    Browse the repository at this point in the history
  2. test(gooddata-eval): cover multi-run reasoning_steps retention

    Addresses CodeRabbit nitpick on PR #1708: a later run returning no
    reasoning events must not clobber an earlier run's captured steps
    (runner.py:120's `or` pattern, same as conversation_id/response_id).
    Tomkess committed Aug 5, 2026
    Configuration menu
    Copy the full SHA
    da26fe4 View commit details
    Browse the repository at this point in the history
  3. feat(gooddata-eval): capture reasoning_steps through the agentic-CLI …

    …path
    
    6001d2f wired ChatResult.reasoning_steps through runner.py's generic
    single-turn path only. The agentic-CLI path (cli/agentic_runner.py ->
    evaluate_agentic_*) builds its own ItemReport and never touched it, so
    agentic_alert_skill/agentic_metric_skill/agentic_conversation items could
    never produce a reasoning trace, no matter what the platform emitted.
    
    Accumulates reasoning_steps across every send_message call in each of the
    three evaluators' run loops, attaches it to the run/turn result, and
    surfaces it from evaluate_agentic_* either as the return value (pass) or
    as an attribute on the raised exception (fail) -- mirroring the existing
    conversation_id-on-exception idiom in ChatClient.ask(). run_agentic_items
    picks it up from either path onto ItemReport.reasoning_steps, which
    json_report.py already serializes unconditionally.
    
    general_question/guardrail/search_tool/visualization are left untouched --
    their evaluate_agentic_* functions still return None, unchanged.
    Tomkess committed Aug 5, 2026
    Configuration menu
    Copy the full SHA
    8010bd4 View commit details
    Browse the repository at this point in the history
  4. feat(gooddata-eval): capture conversation_id/response_id through the …

    …agentic-CLI path
    
    8010bd4 wired reasoning_steps through cli/agentic_runner.py -> evaluate_agentic_*,
    but conversation_id/response_id stayed unset on ItemReport for every agentic kind
    (agentic_alert_skill/agentic_metric_skill/agentic_conversation) -- each ChatResult
    already carries both, and conversation_id was already threaded up to the
    Alert/Metric/ConversationRunResult layer, but neither ever reached the top-level
    evaluate_agentic_* return value or its failure exception, so run_agentic_items had
    nothing to read.
    
    Mirrors the reasoning_steps idiom exactly: widens each evaluate_agentic_*'s return
    from list[str] to (reasoning_steps, conversation_id, response_id), attaches all
    three to the raised exception on failure, and has run_agentic_items unpack either
    form (tuple or the untouched kinds' bare list/None) onto ItemReport.conversation_id
    /response_id. response_id is new at the RunResult layer for all three kinds --
    captured as the last non-null value across a run's turns, same pattern already
    used for reasoning_steps accumulation.
    
    general_question/guardrail/search_tool/visualization untouched (already populated
    via the single-turn runner.py path, not this one).
    
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
    Tomkess and claude committed Aug 5, 2026
    Configuration menu
    Copy the full SHA
    1c328c4 View commit details
    Browse the repository at this point in the history

Commits on Aug 6, 2026

  1. fix(gooddata-eval): stop the metric-skill simulated user from droppin…

    …g MAQL clauses
    
    agentic_metric_skill's simulated-user reply (generate_simulated_response) is
    what keeps a multi-turn metric-creation conversation going after the agent
    asks a clarifying question -- it prompts an LLM to answer as the user, using
    the fixture's expected_output.maql as its only source of truth.
    
    The prompt told it to "reply briefly" with no instruction to preserve the
    MAQL's structure. In practice it would silently drop a WHERE/filter clause,
    or paraphrase a label id, whenever the agent's question didn't happen to ask
    about that part directly -- so a well-behaved agent, faithfully following
    the (already-wrong) simulated answer, still failed the eval.
    
    Reproduced live twice against a real gdc-mic-ai-evaluation fixture
    ("Create a metric for total ecommerce spend", expects
    SELECT {metric/spend_amount_-_cutcgco} WHERE {label/ecommerce_indicator_code}
    = "1"):
    
      1. Simulated reply dropped "_code" off ecommerce_indicator_code, anchoring
         the agent on a sibling attribute that doesn't have that filter.
      2. Simulated reply picked one of 3 metric options the agent offered and
         said "please proceed with that" -- never mentioning the WHERE clause
         that expected_output required, even though it had it in hand.
    
    Confirmed via a 5x-repeated A/B test that this is a prompt problem, not a
    model-capability one: swapping gpt-4o-mini for gpt-4o under the OLD prompt
    did not fix it (still dropped the clause); the NEW prompt fixes it on the
    ORIGINAL gpt-4o-mini (1/5 -> 5/5 runs preserving the exact filter).
    
    Fix: instruct the simulating LLM to (a) ensure every clause of the expected
    MAQL is eventually satisfied even if the agent's question didn't ask about
    it, (b) quote field/label identifiers verbatim rather than paraphrase them,
    and (c) proactively add a filter the agent's own offered options omitted.
    Also drop "reply briefly" and raise max_tokens 150->300, since brevity was
    part of what squeezed the filter clause out. This brings metric_skill's
    simulated-user prompt in line with alert_skill's generate_simulated_alert_response,
    which already passes structured facts + explicit "proactively tell the agent
    X" instructions rather than one freely-paraphrased string -- not a new
    pattern for this codebase.
    
    Added a regression test asserting the sent prompt preserves clause-fidelity
    language and the raised max_tokens. Full gooddata-eval suite: 272 passed
    (9 pre-existing unrelated failures, confirmed identical on clean master
    before this change -- missing openai extra in test env, and two unrelated
    test files).
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    Tomkess and claude committed Aug 6, 2026
    Configuration menu
    Copy the full SHA
    b6f621e View commit details
    Browse the repository at this point in the history
  2. test(gooddata-eval): assert exact MAQL string appears in simulated-us…

    …er prompt
    
    Addresses CodeRabbit review comment on #1718: the regression test only
    checked for generic instruction words ("verbatim", "every clause"), not that
    expected_output["maql"] itself made it into the prompt -- a regression that
    stripped the metric/label reference or filter value entirely could still
    pass. Assert the exact MAQL string is present.
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    Tomkess and claude committed Aug 6, 2026
    Configuration menu
    Copy the full SHA
    3822a80 View commit details
    Browse the repository at this point in the history
  3. fix(gooddata-eval): make MAQL comparison case-insensitive for keywords

    _normalize_maql/_best_maql_match compare an agent's generated MAQL against
    expected_output.maql via exact string equality after whitespace/wrapper
    normalization -- but MAQL keywords (SELECT, FOR PREVIOUS, WHERE, BY, ...) are
    case-insensitive at the query-engine level (confirmed against the MAQL
    reference), while the comparison itself was fully case-sensitive.
    
    Reproduced live in gdc-mic-ai-evaluation, post the #1718 fix: fixture
    "Create a metric for the prior-year value of Active cards" expects
      SELECT {metric/active_card_count_-_txn_-_cutcgco}
        FOR Previous({label/process_date.year})
    Agent produced, verbatim:
      SELECT {metric/active_card_count_-_txn_-_cutcgco} FOR PREVIOUS({label/process_date.year})
    Byte-identical except FOR PREVIOUS vs FOR Previous -- scored as a fail.
    
    First fix attempt considered and rejected: lowercase everything outside
    {type/id} braces. That's wrong -- WHERE-clause literal values are ALSO
    outside braces (e.g. WHERE {label/status} = "Active") and are real,
    case-sensitive data, not keywords; blindly folding them would create a new
    false-positive risk (two genuinely different filter values scored as equal).
    
    Actual fix: per the MAQL reference, every literal value is quoted and every
    identifier lives inside {..} -- both are exhaustively structural markers, so
    protecting text inside either while casefolding everything else needs no
    keyword list at all (which would risk being incomplete against MAQL's large
    vocabulary: SELECT, BY, WHERE, HAVING, FOR PREVIOUS/NEXT/EACH, WITHOUT PF,
    TOP/BOTTOM, WITHIN, RANK family, RUNSUM family, IFNULL, CASE/WHEN, 15+ math
    functions, ...). Added _casefold_outside_protected(), applied as the final
    step in _normalize_maql.
    
    Tests added:
    - keyword case-insensitivity on the exact reproduced case (FOR PREVIOUS vs
      FOR Previous)
    - identifier case preserved ({metric/Mixed_Case_Id} untouched)
    - quoted literal case preserved AND still distinguishes real differences
      (WHERE x = "Active" vs WHERE x = "active" must stay a genuine mismatch --
      this is the test that would have caught the rejected first draft)
    Updated the one existing test whose expected value assumed no case
    normalization ever happens (SELECT -> select).
    
    Full gooddata-eval suite: 274 passed, 9 pre-existing unrelated failures
    (missing openai extra in this test env; two unrelated test files) --
    identical count to before this change.
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    Tomkess and claude committed Aug 6, 2026
    Configuration menu
    Copy the full SHA
    3173acd View commit details
    Browse the repository at this point in the history
Loading