-
Notifications
You must be signed in to change notification settings - Fork 8
feat: propagate error categories to SGP spans #486
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
d62ef7d
f24aef5
6f27da0
0f63017
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| from __future__ import annotations | ||
|
|
||
| from typing import Any | ||
| from typing import Any, Literal, cast | ||
|
|
||
| from agentex.types.span import Span | ||
|
|
||
|
|
@@ -13,14 +13,74 @@ | |
| # SGP and agentex-native span stores. | ||
| SPAN_ERROR_KEY = "__error__" | ||
|
|
||
| ErrorCategory = Literal["application", "platform", "unknown"] | ||
|
jshaikScale marked this conversation as resolved.
Outdated
|
||
| ERROR_CATEGORY_UNKNOWN: ErrorCategory = "unknown" | ||
| _ERROR_CATEGORIES = frozenset({"application", "platform", "unknown"}) | ||
|
|
||
| def set_span_error(span: Span, exc: BaseException) -> None: | ||
|
|
||
| class CategorizedError(Exception): | ||
| """Base class for failures with known operational ownership. | ||
|
|
||
| Use ``ApplicationError`` for failures owned by agent or caller code, such | ||
| as business logic, user input, tools, or application configuration. Use | ||
| ``PlatformError`` only at a known Agentex/SGP-owned boundary, such as | ||
| managed runtime, tracing, persistence, or platform networking. Leave | ||
| unclassified failures as ordinary exceptions so they remain ``unknown``. | ||
| """ | ||
|
|
||
| error_category: ErrorCategory = ERROR_CATEGORY_UNKNOWN | ||
|
|
||
|
|
||
| class ApplicationError(CategorizedError): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are these declared in both repos rather than agentex importing from scale_gp_beta? If it's to keep agentex's public exception API off scale_gp_beta.lib, we still need a bridge.. |
||
| """Failure owned by the agent application or its caller.""" | ||
|
|
||
| error_category: ErrorCategory = "application" | ||
|
|
||
|
|
||
| class PlatformError(CategorizedError): | ||
| """Failure owned by Agentex/SGP or a platform-managed dependency.""" | ||
|
|
||
| error_category: ErrorCategory = "platform" | ||
|
|
||
|
|
||
| def _normalize_error_category(value: object) -> ErrorCategory | None: | ||
| if isinstance(value, str): | ||
| normalized = value.strip().lower() | ||
| if normalized in _ERROR_CATEGORIES: | ||
| return cast(ErrorCategory, normalized) | ||
| return None | ||
|
|
||
|
|
||
| def _error_category( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. are the producing classes populating the Error categories? |
||
| exc: BaseException, | ||
| explicit_category: ErrorCategory | str | None = None, | ||
| ) -> ErrorCategory: | ||
| """Return an explicit producer classification, defaulting safely to unknown.""" | ||
| return ( | ||
| _normalize_error_category(explicit_category) | ||
| or (exc.error_category if isinstance(exc, CategorizedError) else None) | ||
| or ERROR_CATEGORY_UNKNOWN | ||
| ) | ||
|
|
||
|
|
||
| def set_span_error( | ||
| span: Span, | ||
| exc: BaseException, | ||
| *, | ||
| error_category: ErrorCategory | str | None = None, | ||
| ) -> None: | ||
| """Record an exception on ``span`` under ``data[SPAN_ERROR_KEY]``. | ||
|
|
||
| An explicit ``error_category`` takes precedence over a ``CategorizedError`` | ||
| classification. Invalid or absent categories become unknown. | ||
| No-op when ``span.data`` is a list (matching ``_add_source_to_span``, which | ||
| only attaches metadata to dict-shaped data). | ||
| """ | ||
| error = {"type": type(exc).__name__, "message": str(exc)} | ||
| error = { | ||
| "type": type(exc).__name__, | ||
| "message": str(exc), | ||
| "category": _error_category(exc, error_category), | ||
| } | ||
| if span.data is None: | ||
| span.data = {} | ||
| if isinstance(span.data, dict): | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.