feat(assisted-query): Add AI search bar and built-in fields for metrics#111795
feat(assisted-query): Add AI search bar and built-in fields for metrics#111795isaacwang-sentry wants to merge 2 commits intomasterfrom
Conversation
…in_fields Add metrics-specific built-in field definitions (metric.name, metric.type, metric.unit, value, etc.) so the get_attribute_names RPC returns correct built-in fields for tracemetrics instead of falling through to span fields. This eliminates the need for the _reclassify_metrics_built_in_fields workaround in Seer. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
|
🚨 Warning: This pull request contains Frontend and Backend changes! It's discouraged to make changes to Sentry's Frontend and Backend in a single pull request. The Frontend and Backend are not atomically deployed. If the changes are interdependent of each other, they must be separated into two pull requests and be made forward or backwards compatible, such that the Backend or Frontend can be safely deployed independently. Have questions? Please ask in the |
| } | ||
|
|
||
| // Update per-query state atomically (query, aggregateFields, mode) | ||
| setQueryParams({query: queryToUse, aggregateFields, mode}); |
There was a problem hiding this comment.
Bug: AI-suggested visualizations from the Seer response are extracted but never applied to the metrics query, causing the AI's visualization recommendations to be ignored.
Severity: HIGH
Suggested Fix
Incorporate the visualizations array from the Seer response into the parameters passed to setQueryParams. This can be achieved by transforming the visualizations into a format suitable for the URL query, similar to the implementation in spansTabSeerComboBox.tsx.
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#L228
Potential issue: In the Metrics tab's AI-assisted search, the code fetches query
suggestions from the Seer API, which can include recommended visualizations. While the
`visualizations` array is correctly extracted from the API response and its count is
tracked for analytics, it is never actually applied to the query. The `setQueryParams`
function call omits these new visualizations, only using the query string and existing
aggregations. This results in the AI's suggested visualizations (e.g., `p95(value)`,
chart type) being silently ignored, providing an incomplete query to the user and
creating an inconsistency with the Spans and Logs implementations where this
functionality works correctly.
Did we get this right? 👍 / 👎 to inform future reviews.
|
Split into separate backend and frontend PRs: |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Sequential navigations cause per-query state changes to be lost
- Replaced sequential navigations with a single navigation that combines metric query state (query, aggregateFields, mode) and datetime params, preventing the second navigation from overwriting the first with stale location.query.
Or push these changes by commenting:
@cursor push c6d9c5f768
Preview (c6d9c5f768)
diff --git a/static/app/views/explore/metrics/metricsTabSeerComboBox.tsx b/static/app/views/explore/metrics/metricsTabSeerComboBox.tsx
--- a/static/app/views/explore/metrics/metricsTabSeerComboBox.tsx
+++ b/static/app/views/explore/metrics/metricsTabSeerComboBox.tsx
@@ -9,18 +9,22 @@
import {stringifyToken} from 'sentry/components/searchSyntax/utils';
import {ConfigStore} from 'sentry/stores/configStore';
import type {DateString} from 'sentry/types/core';
+import {defined} from 'sentry/utils';
import {trackAnalytics} from 'sentry/utils/analytics';
import {getFieldDefinition} from 'sentry/utils/fields';
import {fetchMutation, mutationOptions} from 'sentry/utils/queryClient';
+import {decodeList} from 'sentry/utils/queryString';
import {useLocation} from 'sentry/utils/useLocation';
import {useNavigate} from 'sentry/utils/useNavigate';
import {useOrganization} from 'sentry/utils/useOrganization';
import {useProjects} from 'sentry/utils/useProjects';
+import {
+ decodeMetricsQueryParams,
+ encodeMetricQueryParams,
+ type BaseMetricQuery,
+} from 'sentry/views/explore/metrics/metricQuery';
import type {WritableAggregateField} from 'sentry/views/explore/queryParams/aggregateField';
-import {
- useQueryParams,
- useSetQueryParams,
-} from 'sentry/views/explore/queryParams/context';
+import {useQueryParams} from 'sentry/views/explore/queryParams/context';
import {isGroupBy} from 'sentry/views/explore/queryParams/groupBy';
import {Mode} from 'sentry/views/explore/queryParams/mode';
import {isVisualize} from 'sentry/views/explore/queryParams/visualize';
@@ -66,7 +70,6 @@
const pageFilters = usePageFilters();
const organization = useOrganization();
const queryParams = useQueryParams();
- const setQueryParams = useSetQueryParams();
const {
currentInputValueRef,
query,
@@ -224,10 +227,7 @@
aggregateFields.push({groupBy});
}
- // Update per-query state atomically (query, aggregateFields, mode)
- setQueryParams({query: queryToUse, aggregateFields, mode});
-
- // Update global time range via navigation
+ // Build datetime selection
const selection = {
...pageFilters.selection,
datetime: {
@@ -255,12 +255,42 @@
visualize_count: visualizations?.length ?? 0,
});
- // Navigate to update global time range params
+ // Get current metric queries from URL and update the first one
+ const rawQueryParams = decodeList(location.query.metric);
+ const metricQueries = rawQueryParams
+ .map(value => decodeMetricsQueryParams(value))
+ .filter(defined);
+
+ // Update the first metric query with new params
+ const updatedMetricQueries = metricQueries.map(
+ (metricQuery: BaseMetricQuery, index: number) => {
+ if (index !== 0) {
+ return metricQuery;
+ }
+ return {
+ metric: metricQuery.metric,
+ queryParams: queryParams.replace({
+ query: queryToUse,
+ aggregateFields,
+ mode,
+ }),
+ };
+ }
+ );
+
+ // Encode updated metric queries
+ const newMetricParams = updatedMetricQueries
+ .map((metricQuery: BaseMetricQuery) => encodeMetricQueryParams(metricQuery))
+ .filter(defined)
+ .filter(Boolean);
+
+ // Single navigation with all params (metric query state + datetime)
navigate(
{
...location,
query: {
...location.query,
+ metric: newMetricParams,
start: selection.datetime.start,
end: selection.datetime.end,
statsPeriod: selection.datetime.period,
@@ -276,8 +306,7 @@
navigate,
organization,
pageFilters.selection,
- queryParams.aggregateFields,
- setQueryParams,
+ queryParams,
]
);This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.
| }, | ||
| }, | ||
| {replace: true, preventScrollReset: true} | ||
| ); |
There was a problem hiding this comment.
Sequential navigations cause per-query state changes to be lost
High Severity
The applySeerSearchQuery callback calls setQueryParams({query, aggregateFields, mode}) on line 228, which internally triggers a navigate() via setQueryParamsForIndex in multiMetricsQueryParams.tsx to update the metric URL param. Immediately after, a second navigate() on line 259 updates datetime params but spreads the stale location.query — which still contains the old metric value. The second navigation overwrites the first, so the per-query state changes (query, aggregateFields, mode) are silently discarded. This makes the entire Seer AI query feature non-functional for metrics. Compare with LogsTabSeerComboBox, which correctly combines all URL param changes into a single navigate() call.



Summary
metric.name,metric.type,metric.unit,value) to_get_built_in_fieldsso the Seer assisted query agent can discover themai_query_applied,ai_query_submitted,ai_query_rejected,ai_query_interface)Details
The Seer backend already has a fully implemented
MetricsStrategyfor the assisted query agent. This PR wires up the frontend by:MetricsTabSeerComboBox— follows the establishedLogsTabSeerComboBox/SpansTabSeerComboBoxpattern with metrics-specific adaptations (per-query state updates viauseSetQueryParams, global time range vianavigate(), default mode'metrics')Filtercomponent to addenableAISearchtoSearchQueryBuilderProviderand conditionally render the seer combobox whendisplayAskSeeris truegen-ai-search-agent-translatefeature flagTest plan
gen-ai-featuresandgen-ai-search-agent-translatefeature flags for org🤖 Generated with Claude Code