diff --git a/docs/architecture/overview.md b/docs/architecture/overview.md
index 3283d4bb2..ab84ffb7b 100644
--- a/docs/architecture/overview.md
+++ b/docs/architecture/overview.md
@@ -304,7 +304,7 @@ Some tools (`search_events` and `search_issues`) implement a two-tier agent patt
```
1. User: "Show me errors from yesterday"
↓
-2. Claude: Calls search_events(query="errors from yesterday")
+2. Claude: Calls search_events(dataset="errors", query="errors from yesterday")
↓
3. MCP Tool Handler: Receives request
↓
diff --git a/docs/specs/search-events.md b/docs/specs/search-events.md
index 6a9868c13..34a93ed98 100644
--- a/docs/specs/search-events.md
+++ b/docs/specs/search-events.md
@@ -16,7 +16,7 @@ A unified search tool that accepts natural language queries and translates them
interface SearchEventsParams {
organizationSlug: string; // Required
query: string; // Natural language search description
- dataset?: "spans" | "errors" | "logs" | "metrics"; // Dataset to search (default: "errors")
+ dataset: "spans" | "errors" | "logs" | "metrics" | "profiles" | "replays"; // Required; the agent may correct it
projectSlug?: string; // Optional - limit to specific project
regionUrl?: string;
limit?: number; // Default: 10, Max: 100
@@ -27,9 +27,10 @@ interface SearchEventsParams {
### Examples
```typescript
-// Find errors (errors dataset is default)
+// Find errors
search_events({
organizationSlug: "my-org",
+ dataset: "errors",
query: "database timeouts in checkout flow from last hour"
})
@@ -152,6 +153,7 @@ find_errors({
// After
search_events({
organizationSlug: "sentry",
+ dataset: "errors",
query: "unresolved errors in checkout.js"
})
```
diff --git a/docs/testing/stdio.md b/docs/testing/stdio.md
index 8a1aa0076..1c6e51ea3 100644
--- a/docs/testing/stdio.md
+++ b/docs/testing/stdio.md
@@ -198,7 +198,7 @@ This opens the MCP Inspector at `http://localhost:6274`
1. **List Tools** - Verify expected tools appear
2. **Call a tool** - Start with `execute_sentry_tool` using `name="whoami"` and `arguments={}`
3. **Test with parameters** - Try `find_organizations()`
-4. **Test complex operations** - Try `search_events(query="errors in the last hour")`
+4. **Test complex operations** - Try `search_events(dataset="errors", query="errors in the last hour")`
**Example test sequence:**
```
@@ -207,6 +207,7 @@ This opens the MCP Inspector at `http://localhost:6274`
3. find_projects(organizationSlug="your-org")
4. search_events(
organizationSlug="your-org",
+ dataset="errors",
query="errors from yesterday"
)
```
@@ -483,7 +484,7 @@ OPENAI_API_KEY=your-key pnpm start --access-token=TOKEN
# Test search_events and search_issues work
# In MCP Inspector:
-# - Call search_events(query="errors in production")
+# - Call search_events(dataset="errors", query="errors in production")
# - Call search_issues(query="unresolved crashes")
```
diff --git a/packages/mcp-core/src/skillDefinitions.json b/packages/mcp-core/src/skillDefinitions.json
index 11cba76f5..216ff0272 100644
--- a/packages/mcp-core/src/skillDefinitions.json
+++ b/packages/mcp-core/src/skillDefinitions.json
@@ -194,7 +194,7 @@
},
{
"name": "search_events",
- "description": "Search Sentry events and replays. Use for event counts/statistics.\n\n`query` is natural language or Sentry search syntax; a configured agent fixes dataset, query, fields, and sort.\n\nSupports THREE query types:\n1. AGGREGATIONS (counts, sums, averages): 'how many errors', 'total tokens'\n2. Individual events with timestamps: 'error logs from last hour'\n3. TIME SERIES (metric over time): 'errors per hour', 'error trend over time'\n\nDatasets:\n- errors: Exception/crash events with stack traces, usually grouped into issues\n- logs: Application log entries, including error-severity log messages\n- spans: Raw trace/span events for performance, AI/LLM calls, requests, and operations\n- metrics: Metric rows and aggregates: counters, gauges, distributions, values\n- profiles: Transaction/continuous profile results, profile IDs, profiled transactions\n- replays: Session replay results: rage clicks, dead clicks, visited pages, replay users\nIf the user says logs, log messages, error logs, or warning logs, choose logs instead of errors.\n\nReplay searches return replay lists only; replay count()/avg()/sum() are not supported.\n\nNOT for grouped issue lists (use search_issues) or app screenshots/images (use get_latest_base_snapshot).\n\n\nsearch_events(organizationSlug='my-org', dataset='errors', query='how many errors today')\nsearch_events(organizationSlug='my-org', dataset='errors', fields=['issue', 'count()'], sort='-count()')\nsearch_events(organizationSlug='my-org', dataset='errors', query='errors per hour last 24h')\nsearch_events(organizationSlug='my-org', dataset='spans', query='span.op:db', sort='-span.duration')\nsearch_events(organizationSlug='my-org', dataset='replays', query='count_errors:>0', sort='-count_errors')\n\n\n\n- name/otherName notation means /; parse it directly, don't call find_organizations/find_projects.\n- Use fields with aggregate functions like count(), avg(), sum() for statistics\n- Sort by -count() for most common, -timestamp for newest\n",
+ "description": "Search Sentry events and replays. Use for event counts/statistics.\n\n`query` is natural language or Sentry search syntax; a configured agent fixes dataset, query, fields, and sort.\n\nSupports THREE query types:\n1. AGGREGATIONS (counts, sums, averages): 'how many errors', 'total tokens'\n2. Individual events with timestamps: 'error logs from last hour'\n3. TIME SERIES (metric over time): 'errors per hour', 'error trend over time'\n\nDatasets:\n- errors: Exception/crash events with stack traces, usually grouped into issues\n- logs: Application log entries, including error-severity log messages\n- spans: Raw trace/span events for performance, AI/LLM calls, requests, and operations\n- metrics: Metric rows and aggregates: counters, gauges, distributions, values\n- profiles: Transaction/continuous profile results, profile IDs, profiled transactions\n- replays: Session replay results: rage clicks, dead clicks, visited pages, replay users\nPick logs for log messages (incl. error/warning logs); spans for API/HTTP calls, DB queries, latency.\n\nReplay searches return replay lists only; replay count()/avg()/sum() are not supported.\n\nNOT for grouped issue lists (use search_issues) or app screenshots/images (use get_latest_base_snapshot).\n\n\nsearch_events(organizationSlug='my-org', dataset='errors', query='how many errors today')\nsearch_events(organizationSlug='my-org', dataset='errors', fields=['issue', 'count()'], sort='-count()')\nsearch_events(organizationSlug='my-org', dataset='errors', query='errors per hour last 24h')\nsearch_events(organizationSlug='my-org', dataset='spans', query='span.op:db', sort='-span.duration')\nsearch_events(organizationSlug='my-org', dataset='replays', query='count_errors:>0', sort='-count_errors')\n\n\n\n- name/otherName notation means /; parse it directly, don't call find_organizations/find_projects.\n- Use fields with aggregate functions like count(), avg(), sum() for statistics\n- Sort by -count() for most common, -timestamp for newest\n",
"requiredScopes": ["event:read"]
},
{
@@ -269,7 +269,7 @@
},
{
"name": "search_events",
- "description": "Search Sentry events and replays. Use for event counts/statistics.\n\n`query` is natural language or Sentry search syntax; a configured agent fixes dataset, query, fields, and sort.\n\nSupports THREE query types:\n1. AGGREGATIONS (counts, sums, averages): 'how many errors', 'total tokens'\n2. Individual events with timestamps: 'error logs from last hour'\n3. TIME SERIES (metric over time): 'errors per hour', 'error trend over time'\n\nDatasets:\n- errors: Exception/crash events with stack traces, usually grouped into issues\n- logs: Application log entries, including error-severity log messages\n- spans: Raw trace/span events for performance, AI/LLM calls, requests, and operations\n- metrics: Metric rows and aggregates: counters, gauges, distributions, values\n- profiles: Transaction/continuous profile results, profile IDs, profiled transactions\n- replays: Session replay results: rage clicks, dead clicks, visited pages, replay users\nIf the user says logs, log messages, error logs, or warning logs, choose logs instead of errors.\n\nReplay searches return replay lists only; replay count()/avg()/sum() are not supported.\n\nNOT for grouped issue lists (use search_issues) or app screenshots/images (use get_latest_base_snapshot).\n\n\nsearch_events(organizationSlug='my-org', dataset='errors', query='how many errors today')\nsearch_events(organizationSlug='my-org', dataset='errors', fields=['issue', 'count()'], sort='-count()')\nsearch_events(organizationSlug='my-org', dataset='errors', query='errors per hour last 24h')\nsearch_events(organizationSlug='my-org', dataset='spans', query='span.op:db', sort='-span.duration')\nsearch_events(organizationSlug='my-org', dataset='replays', query='count_errors:>0', sort='-count_errors')\n\n\n\n- name/otherName notation means /; parse it directly, don't call find_organizations/find_projects.\n- Use fields with aggregate functions like count(), avg(), sum() for statistics\n- Sort by -count() for most common, -timestamp for newest\n",
+ "description": "Search Sentry events and replays. Use for event counts/statistics.\n\n`query` is natural language or Sentry search syntax; a configured agent fixes dataset, query, fields, and sort.\n\nSupports THREE query types:\n1. AGGREGATIONS (counts, sums, averages): 'how many errors', 'total tokens'\n2. Individual events with timestamps: 'error logs from last hour'\n3. TIME SERIES (metric over time): 'errors per hour', 'error trend over time'\n\nDatasets:\n- errors: Exception/crash events with stack traces, usually grouped into issues\n- logs: Application log entries, including error-severity log messages\n- spans: Raw trace/span events for performance, AI/LLM calls, requests, and operations\n- metrics: Metric rows and aggregates: counters, gauges, distributions, values\n- profiles: Transaction/continuous profile results, profile IDs, profiled transactions\n- replays: Session replay results: rage clicks, dead clicks, visited pages, replay users\nPick logs for log messages (incl. error/warning logs); spans for API/HTTP calls, DB queries, latency.\n\nReplay searches return replay lists only; replay count()/avg()/sum() are not supported.\n\nNOT for grouped issue lists (use search_issues) or app screenshots/images (use get_latest_base_snapshot).\n\n\nsearch_events(organizationSlug='my-org', dataset='errors', query='how many errors today')\nsearch_events(organizationSlug='my-org', dataset='errors', fields=['issue', 'count()'], sort='-count()')\nsearch_events(organizationSlug='my-org', dataset='errors', query='errors per hour last 24h')\nsearch_events(organizationSlug='my-org', dataset='spans', query='span.op:db', sort='-span.duration')\nsearch_events(organizationSlug='my-org', dataset='replays', query='count_errors:>0', sort='-count_errors')\n\n\n\n- name/otherName notation means /; parse it directly, don't call find_organizations/find_projects.\n- Use fields with aggregate functions like count(), avg(), sum() for statistics\n- Sort by -count() for most common, -timestamp for newest\n",
"requiredScopes": ["event:read"]
},
{
@@ -405,7 +405,7 @@
},
{
"name": "search_events",
- "description": "Search Sentry events and replays. Use for event counts/statistics.\n\n`query` is natural language or Sentry search syntax; a configured agent fixes dataset, query, fields, and sort.\n\nSupports THREE query types:\n1. AGGREGATIONS (counts, sums, averages): 'how many errors', 'total tokens'\n2. Individual events with timestamps: 'error logs from last hour'\n3. TIME SERIES (metric over time): 'errors per hour', 'error trend over time'\n\nDatasets:\n- errors: Exception/crash events with stack traces, usually grouped into issues\n- logs: Application log entries, including error-severity log messages\n- spans: Raw trace/span events for performance, AI/LLM calls, requests, and operations\n- metrics: Metric rows and aggregates: counters, gauges, distributions, values\n- profiles: Transaction/continuous profile results, profile IDs, profiled transactions\n- replays: Session replay results: rage clicks, dead clicks, visited pages, replay users\nIf the user says logs, log messages, error logs, or warning logs, choose logs instead of errors.\n\nReplay searches return replay lists only; replay count()/avg()/sum() are not supported.\n\nNOT for grouped issue lists (use search_issues) or app screenshots/images (use get_latest_base_snapshot).\n\n\nsearch_events(organizationSlug='my-org', dataset='errors', query='how many errors today')\nsearch_events(organizationSlug='my-org', dataset='errors', fields=['issue', 'count()'], sort='-count()')\nsearch_events(organizationSlug='my-org', dataset='errors', query='errors per hour last 24h')\nsearch_events(organizationSlug='my-org', dataset='spans', query='span.op:db', sort='-span.duration')\nsearch_events(organizationSlug='my-org', dataset='replays', query='count_errors:>0', sort='-count_errors')\n\n\n\n- name/otherName notation means /; parse it directly, don't call find_organizations/find_projects.\n- Use fields with aggregate functions like count(), avg(), sum() for statistics\n- Sort by -count() for most common, -timestamp for newest\n",
+ "description": "Search Sentry events and replays. Use for event counts/statistics.\n\n`query` is natural language or Sentry search syntax; a configured agent fixes dataset, query, fields, and sort.\n\nSupports THREE query types:\n1. AGGREGATIONS (counts, sums, averages): 'how many errors', 'total tokens'\n2. Individual events with timestamps: 'error logs from last hour'\n3. TIME SERIES (metric over time): 'errors per hour', 'error trend over time'\n\nDatasets:\n- errors: Exception/crash events with stack traces, usually grouped into issues\n- logs: Application log entries, including error-severity log messages\n- spans: Raw trace/span events for performance, AI/LLM calls, requests, and operations\n- metrics: Metric rows and aggregates: counters, gauges, distributions, values\n- profiles: Transaction/continuous profile results, profile IDs, profiled transactions\n- replays: Session replay results: rage clicks, dead clicks, visited pages, replay users\nPick logs for log messages (incl. error/warning logs); spans for API/HTTP calls, DB queries, latency.\n\nReplay searches return replay lists only; replay count()/avg()/sum() are not supported.\n\nNOT for grouped issue lists (use search_issues) or app screenshots/images (use get_latest_base_snapshot).\n\n\nsearch_events(organizationSlug='my-org', dataset='errors', query='how many errors today')\nsearch_events(organizationSlug='my-org', dataset='errors', fields=['issue', 'count()'], sort='-count()')\nsearch_events(organizationSlug='my-org', dataset='errors', query='errors per hour last 24h')\nsearch_events(organizationSlug='my-org', dataset='spans', query='span.op:db', sort='-span.duration')\nsearch_events(organizationSlug='my-org', dataset='replays', query='count_errors:>0', sort='-count_errors')\n\n\n\n- name/otherName notation means /; parse it directly, don't call find_organizations/find_projects.\n- Use fields with aggregate functions like count(), avg(), sum() for statistics\n- Sort by -count() for most common, -timestamp for newest\n",
"requiredScopes": ["event:read"]
},
{
diff --git a/packages/mcp-core/src/toolDefinitions.json b/packages/mcp-core/src/toolDefinitions.json
index 534c64d3c..67159e0fc 100644
--- a/packages/mcp-core/src/toolDefinitions.json
+++ b/packages/mcp-core/src/toolDefinitions.json
@@ -7203,7 +7203,7 @@
},
{
"name": "search_events",
- "description": "Search Sentry events and replays. Use for event counts/statistics.\n\n`query` is natural language or Sentry search syntax; a configured agent fixes dataset, query, fields, and sort.\n\nSupports THREE query types:\n1. AGGREGATIONS (counts, sums, averages): 'how many errors', 'total tokens'\n2. Individual events with timestamps: 'error logs from last hour'\n3. TIME SERIES (metric over time): 'errors per hour', 'error trend over time'\n\nDatasets:\n- errors: Exception/crash events with stack traces, usually grouped into issues\n- logs: Application log entries, including error-severity log messages\n- spans: Raw trace/span events for performance, AI/LLM calls, requests, and operations\n- metrics: Metric rows and aggregates: counters, gauges, distributions, values\n- profiles: Transaction/continuous profile results, profile IDs, profiled transactions\n- replays: Session replay results: rage clicks, dead clicks, visited pages, replay users\nIf the user says logs, log messages, error logs, or warning logs, choose logs instead of errors.\n\nReplay searches return replay lists only; replay count()/avg()/sum() are not supported.\n\nNOT for grouped issue lists (use search_issues) or app screenshots/images (use get_latest_base_snapshot).\n\n\nsearch_events(organizationSlug='my-org', dataset='errors', query='how many errors today')\nsearch_events(organizationSlug='my-org', dataset='errors', fields=['issue', 'count()'], sort='-count()')\nsearch_events(organizationSlug='my-org', dataset='errors', query='errors per hour last 24h')\nsearch_events(organizationSlug='my-org', dataset='spans', query='span.op:db', sort='-span.duration')\nsearch_events(organizationSlug='my-org', dataset='replays', query='count_errors:>0', sort='-count_errors')\n\n\n\n- name/otherName notation means /; parse it directly, don't call find_organizations/find_projects.\n- Use fields with aggregate functions like count(), avg(), sum() for statistics\n- Sort by -count() for most common, -timestamp for newest\n",
+ "description": "Search Sentry events and replays. Use for event counts/statistics.\n\n`query` is natural language or Sentry search syntax; a configured agent fixes dataset, query, fields, and sort.\n\nSupports THREE query types:\n1. AGGREGATIONS (counts, sums, averages): 'how many errors', 'total tokens'\n2. Individual events with timestamps: 'error logs from last hour'\n3. TIME SERIES (metric over time): 'errors per hour', 'error trend over time'\n\nDatasets:\n- errors: Exception/crash events with stack traces, usually grouped into issues\n- logs: Application log entries, including error-severity log messages\n- spans: Raw trace/span events for performance, AI/LLM calls, requests, and operations\n- metrics: Metric rows and aggregates: counters, gauges, distributions, values\n- profiles: Transaction/continuous profile results, profile IDs, profiled transactions\n- replays: Session replay results: rage clicks, dead clicks, visited pages, replay users\nPick logs for log messages (incl. error/warning logs); spans for API/HTTP calls, DB queries, latency.\n\nReplay searches return replay lists only; replay count()/avg()/sum() are not supported.\n\nNOT for grouped issue lists (use search_issues) or app screenshots/images (use get_latest_base_snapshot).\n\n\nsearch_events(organizationSlug='my-org', dataset='errors', query='how many errors today')\nsearch_events(organizationSlug='my-org', dataset='errors', fields=['issue', 'count()'], sort='-count()')\nsearch_events(organizationSlug='my-org', dataset='errors', query='errors per hour last 24h')\nsearch_events(organizationSlug='my-org', dataset='spans', query='span.op:db', sort='-span.duration')\nsearch_events(organizationSlug='my-org', dataset='replays', query='count_errors:>0', sort='-count_errors')\n\n\n\n- name/otherName notation means /; parse it directly, don't call find_organizations/find_projects.\n- Use fields with aggregate functions like count(), avg(), sum() for statistics\n- Sort by -count() for most common, -timestamp for newest\n",
"inputSchema": {
"type": "object",
"properties": {
@@ -7212,9 +7212,9 @@
"description": "The organization's slug. You can find a existing list of organizations you have access to using the `find_organizations()` tool."
},
"dataset": {
- "description": "Initial dataset hint: errors, logs, spans, metrics, profiles, or replays. Always pass it, including for natural language queries. The agent may correct it when configured.",
"type": "string",
- "enum": ["spans", "errors", "logs", "metrics", "profiles", "replays"]
+ "enum": ["spans", "errors", "logs", "metrics", "profiles", "replays"],
+ "description": "Dataset to search: errors, logs, spans, metrics, profiles, or replays. Pick the one that matches the question, including for natural language queries. The agent may correct it when configured."
},
"query": {
"description": "Natural language or Sentry event search query syntax.",
@@ -7304,7 +7304,7 @@
"type": "boolean"
}
},
- "required": ["organizationSlug"]
+ "required": ["organizationSlug", "dataset"]
},
"requiredScopes": ["event:read"],
"skills": ["inspect", "triage", "seer"],
diff --git a/packages/mcp-core/src/tools/catalog/search-events.test.ts b/packages/mcp-core/src/tools/catalog/search-events.test.ts
index b3cfb3f40..bb3a8ebca 100644
--- a/packages/mcp-core/src/tools/catalog/search-events.test.ts
+++ b/packages/mcp-core/src/tools/catalog/search-events.test.ts
@@ -2,6 +2,7 @@ import { mswServer } from "@sentry/mcp-server-mocks";
import { APICallError, generateText } from "ai";
import { HttpResponse, http } from "msw";
import { beforeEach, describe, expect, it, vi } from "vitest";
+import { z } from "zod";
import { UserInputError } from "../../errors";
import searchEvents from "./search-events";
@@ -126,6 +127,24 @@ describe("search_events", () => {
mockValidEventsValidation();
});
+ it("requires a dataset so callers pick one up front", () => {
+ const schema = z.object(searchEvents.inputSchema);
+
+ expect(
+ schema.safeParse({
+ organizationSlug: "test-org",
+ query: "slowest api calls in the last 24 hours",
+ }).success,
+ ).toBe(false);
+ expect(
+ schema.safeParse({
+ organizationSlug: "test-org",
+ dataset: "spans",
+ query: "slowest api calls in the last 24 hours",
+ }).success,
+ ).toBe(true);
+ });
+
it("falls back to the original query when the AI provider is unavailable", async () => {
mockGenerateText.mockRejectedValue(
new APICallError({
@@ -1183,6 +1202,7 @@ describe("search_events", () => {
const result = await searchEvents.handler(
{
organizationSlug: "test-org",
+ dataset: "errors",
regionUrl: null,
projectSlug: null,
query: "slow request duration metrics",
@@ -1283,6 +1303,7 @@ describe("search_events", () => {
const result = await searchEvents.handler(
{
organizationSlug: "test-org",
+ dataset: "errors",
regionUrl: null,
projectSlug: null,
query: "recent metrics",
@@ -1370,6 +1391,7 @@ describe("search_events", () => {
const result = await searchEvents.handler(
{
organizationSlug: "test-org",
+ dataset: "errors",
regionUrl: null,
projectSlug: null,
query: "recent profiles for /api/users",
@@ -1441,6 +1463,7 @@ describe("search_events", () => {
const result = await searchEvents.handler(
{
organizationSlug: "test-org",
+ dataset: "errors",
regionUrl: null,
projectSlug: null,
query: "recent profiles for /api/users",
@@ -1511,6 +1534,7 @@ describe("search_events", () => {
const result = await searchEvents.handler(
{
organizationSlug: "test-org",
+ dataset: "errors",
regionUrl: null,
projectSlug: null,
query: "recent profiles for /api/users",
@@ -1566,6 +1590,7 @@ describe("search_events", () => {
const result = await searchEvents.handler(
{
organizationSlug: "test-org",
+ dataset: "errors",
regionUrl: null,
projectSlug: null,
query: "count profiles by release",
@@ -1639,6 +1664,7 @@ describe("search_events", () => {
const result = await searchEvents.handler(
{
organizationSlug: "test-org",
+ dataset: "errors",
regionUrl: null,
projectSlug: null,
query: "recent profiles for /api/users",
@@ -1713,6 +1739,7 @@ describe("search_events", () => {
const result = await searchEvents.handler(
{
organizationSlug: "test-org",
+ dataset: "errors",
regionUrl: null,
projectSlug: null,
query: "production checkout replays with errors in the last day",
@@ -1770,6 +1797,7 @@ describe("search_events", () => {
const result = await searchEvents.handler(
{
organizationSlug: "test-org",
+ dataset: "errors",
regionUrl: null,
projectSlug: null,
query: "checkout replays yesterday",
@@ -2016,6 +2044,7 @@ describe("search_events", () => {
const result = await searchEvents.handler(
{
organizationSlug: "test-org",
+ dataset: "errors",
regionUrl: null,
projectSlug: null,
query: "recent errors with geo-only user data",
@@ -2072,6 +2101,7 @@ describe("search_events", () => {
const result = await searchEvents.handler(
{
organizationSlug: "test-org",
+ dataset: "errors",
regionUrl: null,
projectSlug: null,
query: "logs with user geo",
@@ -2131,6 +2161,7 @@ describe("search_events", () => {
const result = await searchEvents.handler(
{
organizationSlug: "test-org",
+ dataset: "errors",
regionUrl: null,
projectSlug: null,
query: "spans with user geo",
diff --git a/packages/mcp-core/src/tools/catalog/search-events.ts b/packages/mcp-core/src/tools/catalog/search-events.ts
index 180c53d84..f97cdb36d 100644
--- a/packages/mcp-core/src/tools/catalog/search-events.ts
+++ b/packages/mcp-core/src/tools/catalog/search-events.ts
@@ -1,6 +1,5 @@
import { getActiveSpan, setTag } from "@sentry/core";
import { z } from "zod";
-import { setOrganizationContext } from "../../telem/organization";
import { UserInputError } from "../../errors";
import { hasAgentProvider } from "../../internal/agents/provider-factory";
import { withProviderFallback } from "../../internal/agents/provider-fallback";
@@ -13,6 +12,7 @@ import {
ParamRegionUrl,
} from "../../schema";
import { logWarn } from "../../telem/logging";
+import { setOrganizationContext } from "../../telem/organization";
import { scrubSensitiveText } from "../../telem/sentry";
import type { ServerContext } from "../../types";
import {
@@ -395,7 +395,7 @@ export default defineTool({
"- metrics: Metric rows and aggregates: counters, gauges, distributions, values",
"- profiles: Transaction/continuous profile results, profile IDs, profiled transactions",
"- replays: Session replay results: rage clicks, dead clicks, visited pages, replay users",
- "If the user says logs, log messages, error logs, or warning logs, choose logs instead of errors.",
+ "Pick logs for log messages (incl. error/warning logs); spans for API/HTTP calls, DB queries, latency.",
"",
"Replay searches return replay lists only; replay count()/avg()/sum() are not supported.",
"",
@@ -419,9 +419,8 @@ export default defineTool({
organizationSlug: ParamOrganizationSlug,
dataset: z
.enum(SEARCH_EVENTS_DATASETS)
- .optional()
.describe(
- "Initial dataset hint: errors, logs, spans, metrics, profiles, or replays. Always pass it, including for natural language queries. The agent may correct it when configured.",
+ "Dataset to search: errors, logs, spans, metrics, profiles, or replays. Pick the one that matches the question, including for natural language queries. The agent may correct it when configured.",
),
query: z
.string()
@@ -506,7 +505,7 @@ export default defineTool({
setOrganizationContext(organizationSlug);
if (params.projectSlug) setTag("project.slug", params.projectSlug);
- const inputDataset = params.dataset ?? "errors";
+ const inputDataset = params.dataset;
const hasStructuredQuery = looksLikeSentrySearchSyntax(params.query);
const canApplyEnvironmentFilter =
inputDataset !== "replays" &&
@@ -532,14 +531,11 @@ export default defineTool({
let timeSeries: { yAxis: string; interval: string | null } | null = null;
const explicitSort = params.sort?.trim() || undefined;
- const hasExplicitDataset = params.dataset !== undefined;
const hasExplicitFields = hasFields(params.fields);
const hasExplicitSort = explicitSort !== undefined;
const hasExplicitPeriod = params.period !== undefined;
- const hasExplicitTraceItemDataset =
- hasExplicitDataset && isTraceItemDataset(inputDataset);
const shouldTrustStructuredTraceSearch =
- hasStructuredQuery && hasExplicitTraceItemDataset;
+ hasStructuredQuery && isTraceItemDataset(inputDataset);
const environmentFilter = formatEnvironmentFilter(params.environment);
const explicitStructuredTraceQuery = shouldTrustStructuredTraceSearch
? appendSearchFilter(params.query ?? "", environmentFilter)
@@ -551,8 +547,8 @@ export default defineTool({
// (below) and to flag any requested environment that doesn't exist. Skipped
// only when nothing references an environment — including a structured query
// that skips the agent but puts `environment:` in the query string.
- // Seer only translates into the dataset it is given, so it runs only when
- // one is explicit. It only sees the natural language query, so skip it for
+ // Seer only translates into the dataset it is given, so it runs only for
+ // the datasets it has a strategy for. It only sees the natural language query, so skip it for
// structured queries and explicit fields or sort, which the embedded agent
// preserves. Like the UI, an explicit environment is added to Seer's query
// afterwards.