diff --git a/skyvern/errors/errors.py b/skyvern/errors/errors.py new file mode 100644 index 00000000..7a995235 --- /dev/null +++ b/skyvern/errors/errors.py @@ -0,0 +1,19 @@ +from pydantic import BaseModel + + +class SkyvernDefinedError(BaseModel): + error_code: str + reasoning: str + + def __repr__(self) -> str: + return f"{self.reasoning}(error_code={self.error_code})" + + +class ReachMaxStepsError(SkyvernDefinedError): + error_code: str = "REACH_MAX_STEPS" + reasoning: str = "The agent has reached the maximum number of steps." + + +class ReachMaxRetriesError(SkyvernDefinedError): + error_code: str = "REACH_MAX_RETRIES" + reasoning: str = "The agent has reached the maximum number of retries. It might be an issue with the agent. Please reach out to the Skyvern team for support." diff --git a/skyvern/forge/agent.py b/skyvern/forge/agent.py index 752a5d32..861d82d8 100644 --- a/skyvern/forge/agent.py +++ b/skyvern/forge/agent.py @@ -26,6 +26,7 @@ from skyvern.constants import ( SPECIAL_FIELD_VERIFICATION_CODE, ScrapeType, ) +from skyvern.errors.errors import ReachMaxRetriesError, ReachMaxStepsError from skyvern.exceptions import ( BrowserSessionNotFound, BrowserStateMissingPage, @@ -2602,6 +2603,7 @@ class ForgeAgent: extracted_information: dict[str, Any] | list | str | None = None, failure_reason: str | None = None, webhook_failure_reason: str | None = None, + errors: list[dict[str, Any]] | None = None, ) -> Task: # refresh task from db to get the latest status task_from_db = await app.DATABASE.get_task(task_id=task.task_id, organization_id=task.organization_id) @@ -2616,6 +2618,8 @@ class ForgeAgent: updates["extracted_information"] = extracted_information if failure_reason is not None: updates["failure_reason"] = failure_reason + if errors is not None: + updates["errors"] = errors update_comparison = { key: {"old": getattr(task, key), "new": value} for key, value in updates.items() @@ -2677,6 +2681,7 @@ class ForgeAgent: failure_reason=( f"Max retries per step ({max_retries_per_step}) exceeded. Possible failure reasons: {failure_reason}" ), + errors=[ReachMaxRetriesError().model_dump()], ) return None else: @@ -2913,6 +2918,7 @@ class ForgeAgent: task, status=TaskStatus.failed, failure_reason=failure_reason, + errors=[ReachMaxStepsError().model_dump()], ) return False, last_step, None else: diff --git a/skyvern/forge/sdk/db/client.py b/skyvern/forge/sdk/db/client.py index 2d5ead62..638028aa 100644 --- a/skyvern/forge/sdk/db/client.py +++ b/skyvern/forge/sdk/db/client.py @@ -668,7 +668,7 @@ class AgentDB: if failure_reason is not None: task.failure_reason = failure_reason if errors is not None: - task.errors = errors + task.errors = task.errors + errors if max_steps_per_run is not None: task.max_steps_per_run = max_steps_per_run if webhook_failure_reason is not None: