Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/sentry/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,7 @@
from sentry.seer.endpoints.project_seer_preferences import ProjectSeerPreferencesEndpoint
from sentry.seer.endpoints.search_agent_start import SearchAgentStartEndpoint
from sentry.seer.endpoints.search_agent_state import SearchAgentStateEndpoint
from sentry.seer.endpoints.seer_models import SeerModelsEndpoint
from sentry.seer.endpoints.seer_rpc import SeerRpcServiceEndpoint
from sentry.seer.endpoints.trace_explorer_ai_query import TraceExplorerAIQuery
from sentry.seer.endpoints.trace_explorer_ai_setup import TraceExplorerAISetup
Expand Down Expand Up @@ -837,7 +838,6 @@
RelayRegisterResponseEndpoint,
)
from .endpoints.rule_snooze import MetricRuleSnoozeEndpoint, RuleSnoozeEndpoint
from .endpoints.seer_models import SeerModelsEndpoint
from .endpoints.setup_wizard import SetupWizard
from .endpoints.system_health import SystemHealthEndpoint
from .endpoints.system_options import SystemOptionsEndpoint
Expand Down Expand Up @@ -2375,6 +2375,11 @@ def create_group_urls(name_prefix: str) -> list[URLPattern | URLResolver]:
SearchAgentStateEndpoint.as_view(),
name="sentry-api-0-search-agent-state",
),
re_path(
r"^(?P<organization_id_or_slug>[^/]+)/seer/models/$",
SeerModelsEndpoint.as_view(),
name="sentry-api-0-organization-seer-models",
),
re_path(
r"^(?P<organization_id_or_slug>[^/]+)/seer/explorer-chat/(?:(?P<run_id>[^/]+)/)?$",
OrganizationSeerExplorerChatEndpoint.as_view(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

import logging
from typing import TypedDict
from typing import Any, TypedDict

import requests
from django.conf import settings
Expand All @@ -13,7 +13,10 @@
from sentry.api.api_owners import ApiOwner
from sentry.api.api_publish_status import ApiPublishStatus
from sentry.api.base import Endpoint, region_silo_endpoint
from sentry.api.helpers.deprecation import deprecated
from sentry.apidocs.parameters import GlobalParams
from sentry.apidocs.utils import inline_sentry_response_serializer
from sentry.constants import CELL_API_DEPRECATION_DATE
from sentry.ratelimits.config import RateLimitConfig
from sentry.seer.signed_seer_api import sign_with_seer_secret
from sentry.types.ratelimit import RateLimit, RateLimitCategory
Expand Down Expand Up @@ -61,13 +64,17 @@ class SeerModelsEndpoint(Endpoint):
}
)

@deprecated(CELL_API_DEPRECATION_DATE, url_names=["sentry-api-0-seer-models"])
@extend_schema(
operation_id="List Seer AI Models",
parameters=[
GlobalParams.ORG_ID_OR_SLUG,
],
responses={
200: inline_sentry_response_serializer("SeerModelsResponse", SeerModelsResponse),
},
)
def get(self, request: Request) -> Response:
def get(self, request: Request, **kwargs: Any) -> Response:
"""
Get list of actively used LLM model names from Seer.

Expand Down
1 change: 1 addition & 0 deletions static/app/utils/api/knownSentryApiUrls.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,7 @@ export type KnownSentryApiUrls =
| '/organizations/$organizationIdOrSlug/seer/explorer-chat/$runId'
| '/organizations/$organizationIdOrSlug/seer/explorer-runs/'
| '/organizations/$organizationIdOrSlug/seer/explorer-update/$runId/'
| '/organizations/$organizationIdOrSlug/seer/models/'
| '/organizations/$organizationIdOrSlug/seer/onboarding-check/'
| '/organizations/$organizationIdOrSlug/seer/setup-check/'
| '/organizations/$organizationIdOrSlug/sent-first-event/'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@


class TestSeerModels(APITestCase):
endpoint = "sentry-api-0-seer-models"
endpoint = "sentry-api-0-organization-seer-models"

def setUp(self) -> None:
super().setUp()
self.url = "/api/0/seer/models/"
org = self.create_organization()
self.url = f"/api/0/organizations/{org.slug}/seer/models/"

@patch("sentry.api.endpoints.seer_models.requests.get")
@patch("sentry.seer.endpoints.seer_models.requests.get")
def test_get_models_successful(self, mock_get: MagicMock) -> None:
"""Test successful retrieval of models from Seer."""
mock_response = MagicMock()
Expand All @@ -41,7 +42,7 @@ def test_get_models_successful(self, mock_get: MagicMock) -> None:
timeout=5,
)

@patch("sentry.api.endpoints.seer_models.requests.get")
@patch("sentry.seer.endpoints.seer_models.requests.get")
def test_get_models_no_authentication_required(self, mock_get: MagicMock) -> None:
"""Test that the endpoint works without authentication."""
mock_response = MagicMock()
Expand All @@ -53,7 +54,7 @@ def test_get_models_no_authentication_required(self, mock_get: MagicMock) -> Non

assert response.status_code == status.HTTP_200_OK

@patch("sentry.api.endpoints.seer_models.requests.get")
@patch("sentry.seer.endpoints.seer_models.requests.get")
def test_get_models_timeout(self, mock_get: MagicMock) -> None:
"""Test handling of timeout errors."""
mock_get.side_effect = requests.exceptions.Timeout("Request timed out")
Expand All @@ -63,7 +64,7 @@ def test_get_models_timeout(self, mock_get: MagicMock) -> None:
assert response.status_code == status.HTTP_504_GATEWAY_TIMEOUT
assert response.data == {"detail": "Request to Seer timed out"}

@patch("sentry.api.endpoints.seer_models.requests.get")
@patch("sentry.seer.endpoints.seer_models.requests.get")
def test_get_models_request_exception(self, mock_get: MagicMock) -> None:
"""Test handling of request exceptions."""
mock_get.side_effect = requests.exceptions.RequestException("Connection error")
Expand All @@ -73,7 +74,7 @@ def test_get_models_request_exception(self, mock_get: MagicMock) -> None:
assert response.status_code == status.HTTP_502_BAD_GATEWAY
assert response.data == {"detail": "Failed to fetch models from Seer"}

@patch("sentry.api.endpoints.seer_models.requests.get")
@patch("sentry.seer.endpoints.seer_models.requests.get")
def test_get_models_http_error(self, mock_get: MagicMock) -> None:
"""Test handling of HTTP errors from Seer."""
mock_response = MagicMock()
Expand All @@ -86,7 +87,7 @@ def test_get_models_http_error(self, mock_get: MagicMock) -> None:
assert response.status_code == status.HTTP_502_BAD_GATEWAY
assert response.data == {"detail": "Failed to fetch models from Seer"}

@patch("sentry.api.endpoints.seer_models.requests.get")
@patch("sentry.seer.endpoints.seer_models.requests.get")
def test_get_models_empty_response(self, mock_get: MagicMock) -> None:
"""Test handling of empty models list."""
mock_response = MagicMock()
Expand Down
Loading