Skip to content

Empty-result hints: make them specific to the cause, concise, and machine-readable #1279

Open

Description

@sd2k

Problem

When query_prometheus / query_loki_logs return no data, the response includes a hints object with a fixed list of ~4–6 possibleCauses and ~4–6 suggestedActions. The text is the same regardless of why the result is empty.

  • Chat clients: it's several hundred bytes of generic advice on every empty result, and it rarely names the actual cause.
  • Code-mode clients: scripts just check for emptiness, so the prose is pure noise. A script that fans out N queries pays for it N times.

Concrete example: querying rate(foo_count[5m]) where foo is only exported as a native histogram returns empty, and none of the hints mention it. The fix (histogram_count(rate(foo[5m]))) is cheap to detect: the series metadata / list_prometheus_metric_names shows foo exists without a _count suffix.

Proposal

  1. Make hints specific where we can cheaply detect the cause, e.g. for Prometheus:

    • metric name not found → suggest close matches (prefix/suffix matches, _total/_count/_bucket variants);
    • _count/_sum/_bucket requested but only the native-histogram base series exists → suggest histogram_count/histogram_quantile on the base name;
    • selector label doesn't exist on the metric → list the metric's actual labels;
    • range shorter than ~2× scrape interval inside rate().

    Similar for Loki (stream selector matches no streams vs. line filter removed everything — query_loki_stats can distinguish these).

  2. Make the generic fallback short: a one-line summary plus a pointer to the relevant discovery tool, instead of the full list.

  3. Keep a stable machine-readable field (e.g. hints.reason: "metric_not_found" | "no_matching_series" | ...) so scripts can branch on it without parsing prose. This ties in with the structured-output work.

Activity

  1. jpdefo commented on Oct 14, 2026

    @jpdefo
    Contributor

    I reproduced the generic-hint overhead on main at 8424d57: the hints alone serialize to 615 bytes for a plain Prometheus up query and 614 bytes for a Loki stream selector, before optional debug metadata.

    I'll take a small, separate first step on item 2: shorten the generic Prometheus/Loki fallback while preserving the existing response fields, discovery-tool pointers, query-specific advice, and debugging metadata. This will not add backend requests or claim to diagnose the actual cause. Cause detection and machine-readable reasons remain follow-up work for this issue.

  2. MehmetSecgin commented on Oct 16, 2026

    @MehmetSecgin
    Contributor

    Four Loki-side cases from our usage that fit this proposal. Each is cheap to detect, and each sent the model to the wrong next call.

    • Window older than retention: an empty result over an expired window gets the same hint as a selector that matches nothing, so the model concludes "never happened". query_loki_stats on the same selector tells the two apart, or the hint could report the oldest timestamp with data.
    • Datasource UID not found: a one-character typo returns datasource with UID '...' not found. Listing the closest UIDs of the same type would fix it in one step.
    • Log query sent as queryType: "instant": Loki returns 400 log queries are not supported as an instant query type. The server could switch to range, or the hint could say so.
    • | json on mixed lines in a metric query: Loki returns 400 pipeline error: 'JSONParserErr'. A hint suggesting | __error__="" after the parser resolves it.
  3. jpdefo commented on Oct 19, 2026

    @jpdefo
    Contributor

    Thanks @MehmetSecgin, those concrete Loki examples are helpful and worth considering in the follow-up work. PR #1336 covers only item 2, shortening the generic fallback. I plan to tackle items 1 and 3 after #1282 merges, since its structured-output and response-shape changes could affect how we expose diagnostics and machine-readable reasons.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesttoolsChanges to MCP tools

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions