fix(agent): improve error handling for get_agent_soul method
This commit is contained in:
@@ -1429,11 +1429,25 @@ async def get_agent_soul(
|
|||||||
target_agent_id=agent_id,
|
target_agent_id=agent_id,
|
||||||
)
|
)
|
||||||
coordination = GatewayCoordinationService(session)
|
coordination = GatewayCoordinationService(session)
|
||||||
return await coordination.get_agent_soul(
|
try:
|
||||||
board=board,
|
return await coordination.get_agent_soul(
|
||||||
target_agent_id=agent_id,
|
board=board,
|
||||||
correlation_id=f"soul.read:{board.id}:{agent_id}",
|
target_agent_id=agent_id,
|
||||||
)
|
correlation_id=f"soul.read:{board.id}:{agent_id}",
|
||||||
|
)
|
||||||
|
except HTTPException as exc:
|
||||||
|
# Keep explicit auth/not-found responses, but avoid relaying internal 5xx details.
|
||||||
|
if exc.status_code >= status.HTTP_500_INTERNAL_SERVER_ERROR:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=exc.status_code,
|
||||||
|
detail="Gateway SOUL read failed",
|
||||||
|
) from exc
|
||||||
|
raise
|
||||||
|
except Exception as exc: # pragma: no cover - defensive API boundary guard
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_502_BAD_GATEWAY,
|
||||||
|
detail="Gateway SOUL read failed",
|
||||||
|
) from exc
|
||||||
|
|
||||||
|
|
||||||
@router.put(
|
@router.put(
|
||||||
|
|||||||
@@ -237,7 +237,6 @@ async def _authenticate_clerk_request(request: Request) -> RequestState:
|
|||||||
|
|
||||||
async def _fetch_clerk_profile(clerk_user_id: str) -> tuple[str | None, str | None]:
|
async def _fetch_clerk_profile(clerk_user_id: str) -> tuple[str | None, str | None]:
|
||||||
secret = settings.clerk_secret_key.strip()
|
secret = settings.clerk_secret_key.strip()
|
||||||
secret_kind = secret.split("_", maxsplit=1)[0] if "_" in secret else "unknown"
|
|
||||||
server_url = _normalize_clerk_server_url(settings.clerk_api_url or "")
|
server_url = _normalize_clerk_server_url(settings.clerk_api_url or "")
|
||||||
clerk_user_id_log = clerk_user_id[-6:] if clerk_user_id else ""
|
clerk_user_id_log = clerk_user_id[-6:] if clerk_user_id else ""
|
||||||
|
|
||||||
@@ -252,28 +251,24 @@ async def _fetch_clerk_profile(clerk_user_id: str) -> tuple[str | None, str | No
|
|||||||
return email, name
|
return email, name
|
||||||
except ClerkErrors as exc:
|
except ClerkErrors as exc:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"auth.clerk.profile.fetch_failed clerk_user_id=%s reason=clerk_errors "
|
"auth.clerk.profile.fetch_failed clerk_user_id=%s reason=clerk_errors " "error_type=%s",
|
||||||
"secret_kind=%s error_type=%s",
|
|
||||||
clerk_user_id_log,
|
clerk_user_id_log,
|
||||||
secret_kind,
|
|
||||||
exc.__class__.__name__,
|
exc.__class__.__name__,
|
||||||
)
|
)
|
||||||
except SDKError as exc:
|
except SDKError as exc:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"auth.clerk.profile.fetch_failed clerk_user_id=%s status=%s reason=sdk_error "
|
"auth.clerk.profile.fetch_failed clerk_user_id=%s status=%s reason=sdk_error "
|
||||||
"server_url=%s secret_kind=%s",
|
"server_url=%s",
|
||||||
clerk_user_id_log,
|
clerk_user_id_log,
|
||||||
exc.status_code,
|
exc.status_code,
|
||||||
server_url,
|
server_url,
|
||||||
secret_kind,
|
|
||||||
)
|
)
|
||||||
except httpx.TimeoutException as exc:
|
except httpx.TimeoutException as exc:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"auth.clerk.profile.fetch_failed clerk_user_id=%s reason=timeout "
|
"auth.clerk.profile.fetch_failed clerk_user_id=%s reason=timeout "
|
||||||
"server_url=%s secret_kind=%s error=%s",
|
"server_url=%s error=%s",
|
||||||
clerk_user_id_log,
|
clerk_user_id_log,
|
||||||
server_url,
|
server_url,
|
||||||
secret_kind,
|
|
||||||
str(exc) or exc.__class__.__name__,
|
str(exc) or exc.__class__.__name__,
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
@@ -293,7 +288,6 @@ async def delete_clerk_user(clerk_user_id: str) -> None:
|
|||||||
return
|
return
|
||||||
|
|
||||||
secret = settings.clerk_secret_key.strip()
|
secret = settings.clerk_secret_key.strip()
|
||||||
secret_kind = secret.split("_", maxsplit=1)[0] if "_" in secret else "unknown"
|
|
||||||
server_url = _normalize_clerk_server_url(settings.clerk_api_url or "")
|
server_url = _normalize_clerk_server_url(settings.clerk_api_url or "")
|
||||||
clerk_user_id_log = clerk_user_id[-6:] if clerk_user_id else ""
|
clerk_user_id_log = clerk_user_id[-6:] if clerk_user_id else ""
|
||||||
|
|
||||||
@@ -307,10 +301,8 @@ async def delete_clerk_user(clerk_user_id: str) -> None:
|
|||||||
logger.info("auth.clerk.user.delete clerk_user_id=%s", clerk_user_id_log)
|
logger.info("auth.clerk.user.delete clerk_user_id=%s", clerk_user_id_log)
|
||||||
except ClerkErrors as exc:
|
except ClerkErrors as exc:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"auth.clerk.user.delete_failed clerk_user_id=%s reason=clerk_errors "
|
"auth.clerk.user.delete_failed clerk_user_id=%s reason=clerk_errors " "error_type=%s",
|
||||||
"secret_kind=%s error_type=%s",
|
|
||||||
clerk_user_id_log,
|
clerk_user_id_log,
|
||||||
secret_kind,
|
|
||||||
exc.__class__.__name__,
|
exc.__class__.__name__,
|
||||||
)
|
)
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
@@ -323,11 +315,10 @@ async def delete_clerk_user(clerk_user_id: str) -> None:
|
|||||||
return
|
return
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"auth.clerk.user.delete_failed clerk_user_id=%s status=%s reason=sdk_error "
|
"auth.clerk.user.delete_failed clerk_user_id=%s status=%s reason=sdk_error "
|
||||||
"server_url=%s secret_kind=%s",
|
"server_url=%s",
|
||||||
clerk_user_id_log,
|
clerk_user_id_log,
|
||||||
exc.status_code,
|
exc.status_code,
|
||||||
server_url,
|
server_url,
|
||||||
secret_kind,
|
|
||||||
)
|
)
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_502_BAD_GATEWAY,
|
status_code=status.HTTP_502_BAD_GATEWAY,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
from datetime import date, datetime
|
from datetime import date, datetime
|
||||||
|
from functools import lru_cache
|
||||||
from typing import Literal, Self
|
from typing import Literal, Self
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
@@ -297,6 +298,12 @@ def _parse_iso_datetime(value: str) -> datetime:
|
|||||||
return datetime.fromisoformat(normalized)
|
return datetime.fromisoformat(normalized)
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache(maxsize=256)
|
||||||
|
def _compiled_validation_regex(pattern: str) -> re.Pattern[str]:
|
||||||
|
"""Compile and cache validation regex patterns for value checks."""
|
||||||
|
return re.compile(pattern)
|
||||||
|
|
||||||
|
|
||||||
def validate_custom_field_value(
|
def validate_custom_field_value(
|
||||||
*,
|
*,
|
||||||
field_type: TaskCustomFieldType,
|
field_type: TaskCustomFieldType,
|
||||||
@@ -346,7 +353,11 @@ def validate_custom_field_value(
|
|||||||
if validation_regex is not None and field_type in STRING_FIELD_TYPES:
|
if validation_regex is not None and field_type in STRING_FIELD_TYPES:
|
||||||
if not isinstance(value, str):
|
if not isinstance(value, str):
|
||||||
raise ValueError("must be a string for regex validation")
|
raise ValueError("must be a string for regex validation")
|
||||||
if re.fullmatch(validation_regex, value) is None:
|
try:
|
||||||
|
pattern = _compiled_validation_regex(validation_regex)
|
||||||
|
except re.error as exc:
|
||||||
|
raise ValueError(f"validation_regex is invalid: {exc}") from exc
|
||||||
|
if pattern.fullmatch(value) is None:
|
||||||
raise ValueError("does not match validation_regex")
|
raise ValueError("does not match validation_regex")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user