Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
9 changes: 7 additions & 2 deletions src/sentry/seer/endpoints/organization_seer_agent_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
has_seer_agent_access_with_detail,
)
from sentry.seer.autofix.constants import CODING_PAYLOAD_TYPES
from sentry.seer.endpoints.utils import resolve_seer_run
from sentry.seer.models import SeerApiError
from sentry.seer.signed_seer_api import make_signed_seer_api_request

Expand Down Expand Up @@ -61,7 +62,7 @@ class OrganizationSeerAgentUpdateEndpoint(OrganizationEndpoint):
owner = ApiOwner.ML_AI
permission_classes = (OrganizationSeerAgentUpdatePermission,)

def post(self, request: Request, organization: Organization, run_id: int) -> Response:
def post(self, request: Request, organization: Organization, run_id: str) -> Response:
"""
Send an update event to the agent for a given run.
"""
Expand All @@ -83,12 +84,16 @@ def post(self, request: Request, organization: Organization, run_id: int) -> Res
data={"detail": "Code generation is disabled for this organization"},
)

resolved = resolve_seer_run(run_id, organization)
if isinstance(resolved, Response):
return resolved
Comment thread
cursor[bot] marked this conversation as resolved.

path = "/v1/automation/explorer/update"

body = orjson.dumps(
{
**request.data,
"run_id": run_id,
"run_id": resolved.seer_run_state_id,
"organization_id": organization.id,
}
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import uuid
from datetime import datetime, timezone
from unittest.mock import MagicMock, patch

import orjson
from rest_framework import status

from sentry.seer.models.run import SeerRun, SeerRunMirrorStatus, SeerRunType
from sentry.testutils.cases import APITestCase
from sentry.testutils.helpers.features import with_feature

Expand Down Expand Up @@ -48,10 +51,44 @@ def test_explorer_update_successful(

# Verify the payload
sent_data = orjson.loads(call_args[0][2])
assert sent_data["run_id"] == "123"
assert sent_data["run_id"] == 123
assert sent_data["organization_id"] == self.organization.id
assert sent_data["payload"]["type"] == "interrupt"

@patch("sentry.seer.endpoints.organization_seer_agent_update.has_seer_agent_access_with_detail")
@patch("sentry.seer.endpoints.organization_seer_agent_update.make_signed_seer_api_request")
def test_explorer_update_with_uuid_run_id(
self, mock_request: MagicMock, mock_has_access: MagicMock
) -> None:
"""UUID run_id should be resolved to the numeric seer_run_state_id before forwarding to Seer."""
mock_has_access.return_value = (True, None)
mock_request.return_value.status = 200
mock_request.return_value.json.return_value = {"run_id": 456}

run_uuid = uuid.uuid4()
SeerRun.objects.create(
organization=self.organization,
uuid=run_uuid,
seer_run_state_id=456,
type=SeerRunType.EXPLORER,
mirror_status=SeerRunMirrorStatus.LIVE,
last_triggered_at=datetime.now(tz=timezone.utc),
)

url = f"/api/0/organizations/{self.organization.slug}/seer/explorer-update/{run_uuid}/"
response = self.client.post(
url,
data={"payload": {"type": "interrupt"}},
format="json",
)

assert response.status_code == status.HTTP_202_ACCEPTED
mock_request.assert_called_once()
sent_data = orjson.loads(mock_request.call_args[0][2])
# UUID must be translated to the numeric seer_run_state_id before Seer sees it
assert sent_data["run_id"] == 456
assert sent_data["organization_id"] == self.organization.id

@patch("sentry.seer.endpoints.organization_seer_agent_update.has_seer_agent_access_with_detail")
@patch("sentry.seer.endpoints.organization_seer_agent_update.make_signed_seer_api_request")
def test_explorer_update_missing_payload(
Expand Down
Loading