Skip to content

feat(assisted-query): Add AI search bar to metrics tab#111797

Open
isaacwang-sentry wants to merge 2 commits intomasterfrom
isaac/feat/metrics-ai-search-frontend
Open

feat(assisted-query): Add AI search bar to metrics tab#111797
isaacwang-sentry wants to merge 2 commits intomasterfrom
isaac/feat/metrics-ai-search-frontend

Conversation

@isaacwang-sentry
Copy link
Copy Markdown
Member

Summary

  • Create MetricsTabSeerComboBox component following the established logs/spans pattern, with metrics-specific adaptations (per-query state updates, default mode 'metrics')
  • Modify metrics Filter component to enable AI search via SearchQueryBuilderProvider and conditionally render the seer combobox
  • Register metrics AI query analytics events (ai_query_applied, ai_query_submitted, ai_query_rejected, ai_query_interface)
  • Gated behind the existing gen-ai-search-agent-translate feature flag

Test plan

  • Enable gen-ai-features and gen-ai-search-agent-translate feature flags
  • Navigate to Explore > Metrics tab
  • Verify sparkle icon (AI search toggle) appears in the filter bar
  • Submit a natural language query (e.g., "count of http.request.duration by environment last 7 days")
  • Verify query, group-bys, mode, and time range update for the specific metric row
  • Verify other metric query rows are unaffected
  • Test "None of these" feedback flow

🤖 Generated with Claude Code

Integrate the Seer assisted query agent into the metrics tab filter bar,
enabling natural language to metrics query translation. The Seer backend
already supports the Metrics strategy; this wires up the frontend.

- Create MetricsTabSeerComboBox component following the logs/spans pattern
- Modify filter.tsx to conditionally render AI search when feature flag is on
- Register metrics AI query analytics events

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@isaacwang-sentry isaacwang-sentry requested review from a team as code owners March 30, 2026 17:14
@github-actions github-actions bot added the Scope: Frontend Automatically applied to PRs that change frontend components label Mar 30, 2026
Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared a fix for 1 of the 2 issues found in the latest run.

  • ✅ Fixed: AI search props may be overridden by spread
    • Moved enableAISearch and aiSearchBadgeType props after the spread operator to ensure they take priority and cannot be overridden.

Create PR

Or push these changes by commenting:

@cursor push cf15e7c25b
Preview (cf15e7c25b)
diff --git a/static/app/views/explore/metrics/metricToolbar/filter.tsx b/static/app/views/explore/metrics/metricToolbar/filter.tsx
--- a/static/app/views/explore/metrics/metricToolbar/filter.tsx
+++ b/static/app/views/explore/metrics/metricToolbar/filter.tsx
@@ -166,9 +166,9 @@
       // Use the metric name as a key to force remount when it changes
       // This prevents race conditions when navigating between different metrics
       key={traceMetric.name}
+      {...searchQueryBuilderProviderProps}
       enableAISearch={hasTranslateEndpoint}
       aiSearchBadgeType="alpha"
-      {...searchQueryBuilderProviderProps}
     >
       <MetricsSearchBar
         tracesItemSearchQueryBuilderProps={tracesItemSearchQueryBuilderProps}

This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.

Comment on lines +88 to +95
const filteredCommittedQuery = queryDetails?.parsedQuery
?.filter(
token =>
!(token.type === Token.FREE_TEXT && inputValue && token.text.includes(inputValue))
)
?.map(token => stringifyToken(token))
?.join(' ')
?.trim();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kinda overusing ?. here

Comment on lines +140 to +146
query: r?.query ?? '',
sort: r?.sort ?? '',
groupBys: r?.group_by ?? [],
statsPeriod: r?.stats_period ?? '',
start: r?.start ?? null,
end: r?.end ?? null,
mode: r?.mode ?? 'metrics',
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does everything need a fallabck?

Move spread operator before explicit AI search props so they cannot be
silently overridden. Remove unnecessary optional chaining on values
that are always defined, and remove redundant fallback defaults where
TypeScript types already guarantee the values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
}

// Update per-query state atomically (query, aggregateFields, mode)
setQueryParams({query: queryToUse, aggregateFields, mode});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The AI search feature updates the global time range via navigate(), causing all metric rows to change their time range, instead of only affecting the specific row being edited.
Severity: HIGH

Suggested Fix

Instead of using navigate() to update the global time range, use the per-metric setQueryParams function to update the time range for only the specific metric row. This will align the time range update mechanism with how other per-metric parameters like query and aggregateFields are handled, respecting the intended row isolation.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: static/app/views/explore/metrics/metricsTabSeerComboBox.tsx#L227

Potential issue: The `applySeerSearchQuery` callback updates the time range by calling
`navigate()` with new `start`, `end`, and `statsPeriod` values in the global
`location.query`. This action modifies the time range for all metric rows displayed on
the page simultaneously. This behavior contradicts the intended design, where changes
from an AI search should only apply to the specific metric row being edited. The current
implementation breaks the per-row isolation, causing an AI search on one metric to
unexpectedly alter the time range for all other metrics on the page.

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

)
.map(token => stringifyToken(token))
.join(' ')
.trim();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing optional chaining causes crash on null parsedQuery

High Severity

parseQueryBuilderValue returns ParseResult | null. When parsedQuery is null, the ?.filter(...) evaluates to undefined, but the subsequent .map(), .join(), and .trim() calls lack optional chaining and will throw a TypeError. The equivalent code in LogsTabSeerComboBox and SpansTabSeerComboBox correctly uses ?.map(...)?.join(' ')?.trim() throughout the chain.

Fix in Cursor Fix in Web

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

Labels

Scope: Frontend Automatically applied to PRs that change frontend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants