-
Notifications
You must be signed in to change notification settings - Fork 557
fix(agent): Claude alias resolution + skill/error tracing + error sanitize (QA F-031/F-029/F-030) #4855
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
fix(agent): Claude alias resolution + skill/error tracing + error sanitize (QA F-031/F-029/F-030) #4855
Changes from all commits
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 |
|---|---|---|
|
|
@@ -17,8 +17,11 @@ | |
|
|
||
| from __future__ import annotations | ||
|
|
||
| import re | ||
| from typing import Any, Dict, List, Optional, Sequence | ||
|
|
||
| from agenta.sdk.utils.logging import get_module_logger | ||
|
|
||
| from ..dtos import ( | ||
| AgentEvent, | ||
| AgentResult, | ||
|
|
@@ -29,6 +32,38 @@ | |
| TraceContext, | ||
| ) | ||
|
|
||
| log = get_module_logger(__name__) | ||
|
|
||
| # The user-facing error must not carry an internal stack/path dump. Cap the surfaced line and | ||
| # strip the patterns that leak implementation detail; the full text is logged, never shown. | ||
| _ERROR_MAX_LEN = 300 | ||
| # A stack frame leaked into the message ("at fn (/abs/path:12:3)" / 'File "/abs/path", line 12'). | ||
| _STACK_FRAME_RE = re.compile(r"\b(at\s+\S+\s*\(|File\s+\"|/[\w./-]+:\d+)") | ||
|
|
||
|
|
||
| def sanitize_runner_error(error: Any) -> str: | ||
| """Reduce a runner ``error`` to one clean user-facing line, logging the full detail. | ||
|
|
||
| The runner already concise-formats its known auth/credit failures, but the fall-through case | ||
| returns the raw first line of an SDK/JS error, and the transport errors (HTTP/stderr/stdout | ||
| dumps) carry internal text. This is the single boundary that reaches the caller/UI, so it | ||
| keeps the actionable message, drops stack-frame and path noise, caps the length, and logs the | ||
| untruncated original for the trace/logs. A clean concise message passes through unchanged. | ||
| """ | ||
| raw = "" if error is None else str(error) | ||
| if raw and ( | ||
| len(raw) > _ERROR_MAX_LEN or "\n" in raw or _STACK_FRAME_RE.search(raw) | ||
| ): | ||
| log.warning("agent: runner reported a failure: %s", raw) | ||
| # Keep only the first line; a multi-line body is a stack dump, never the message. | ||
| message = raw.split("\n", 1)[0].strip() | ||
| # If even the first line is a raw stack frame, fall back to a generic line. | ||
| if not message or _STACK_FRAME_RE.match(message): | ||
| return "agent run failed" | ||
| if len(message) > _ERROR_MAX_LEN: | ||
| message = message[: _ERROR_MAX_LEN - 1].rstrip() + "…" | ||
| return message | ||
|
Comment on lines
+59
to
+65
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. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win Single-line path leaks still pass through. This only falls back when the first retained line starts with a stack-frame pattern. Errors like Also applies to: 132-135 |
||
|
|
||
|
|
||
| def request_to_wire( | ||
| *, | ||
|
|
@@ -91,10 +126,13 @@ def result_from_wire(data: Dict[str, Any]) -> AgentResult: | |
| """Parse a ``/run`` result JSON into an :class:`AgentResult`. | ||
|
|
||
| Raises ``RuntimeError`` when the runner reported a failure, so the caller surfaces a | ||
| clear message rather than handing the model an empty reply. | ||
| clear message rather than handing the model an empty reply. The runner ``error`` is | ||
| sanitized at this boundary (one clean line, no stack/path leak); the full detail is logged. | ||
| """ | ||
| if not data.get("ok"): | ||
| raise RuntimeError(f"Agent run failed: {data.get('error')}") | ||
| raise RuntimeError( | ||
| f"Agent run failed: {sanitize_runner_error(data.get('error'))}" | ||
| ) | ||
|
|
||
| messages: List[Message] = [] | ||
| for raw in data.get("messages") or []: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚀 Performance & Scalability | 🟡 Minor
🧩 Analysis chain
🏁 Script executed:
Repository: Agenta-AI/agenta
Length of output: 9205
🏁 Script executed:
Repository: Agenta-AI/agenta
Length of output: 9205
Avoid buffering the full streamed error body.
await response.aread()still loads the whole error payload into memory even though only the first 1000 bytes are logged; read a bounded prefix instead and let the response close.