fix: Serialize Exception objects in ActionErrorResult

- Replaced `error` field in `ActionErrorResult` with `ErrorInfo` model.
- Implemented `ErrorInfo` model with necessary fields (`args`, `message`, `exception_type`, `_repr`).
- Added `from_exception` method to `ErrorInfo` model to create an instance from an Exception object.
- Updated `ActionErrorResult.from_exception` method to utilize `ErrorInfo.from_exception`.
- Ensured that `ActionErrorResult` is now fully serializable and won't cause crashes.
- Made necessary changes in code comments and documentation.

This commit fixes crashes caused by attempted serialiation of `AgentException` objects in the `ActionHistory` (as part of `ActionErrorResult`s). To this end, it introduces a new `ErrorInfo` model to encapsulate information about the exception, including the exception type, message, arguments, and representation. The `from_exception` method is added to both `ActionErrorResult` and `ErrorInfo` to create an `ActionErrorResult` object from an exception, extracting the relevant information.
This commit is contained in:
Reinier van der Leer
2023-10-30 15:51:19 -07:00
parent d9fbd26b85
commit fc1d73ba60
3 changed files with 33 additions and 5 deletions

View File

@@ -243,7 +243,7 @@ class Agent(
result = ActionSuccessResult(outputs=return_value)
except AgentException as e:
result = ActionErrorResult(reason=e.message, error=e)
result = ActionErrorResult.from_exception(e)
result_tlength = self.llm_provider.count_tokens(str(result), self.llm.name)
if result_tlength > self.send_token_limit // 3:

View File

@@ -276,7 +276,7 @@ class PlanningAgent(ContextMixin, FileWorkspaceMixin, BaseAgent):
result = ActionSuccessResult(outputs=return_value)
except AgentException as e:
result = ActionErrorResult(reason=e.message, error=e)
result = ActionErrorResult.from_exception(e)
result_tlength = count_string_tokens(str(result), self.llm.name)
memory_tlength = count_string_tokens(

View File

@@ -26,12 +26,40 @@ class ActionSuccessResult(BaseModel):
return f"```\n{self.outputs}\n```" if multiline else str(self.outputs)
# FIXME: implement validators instead of allowing arbitrary types
class ActionErrorResult(BaseModel, arbitrary_types_allowed=True):
class ErrorInfo(BaseModel):
args: tuple
message: str
exception_type: str
_repr: str
@staticmethod
def from_exception(exception: Exception) -> ErrorInfo:
return ErrorInfo(
args=exception.args,
message=getattr(exception, "message", exception.args[0]),
exception_type=exception.__class__.__name__,
_repr=repr(exception),
)
def __str__(self):
return repr(self)
def __repr__(self):
return self._repr
class ActionErrorResult(BaseModel):
reason: str
error: Optional[Exception] = None
error: Optional[ErrorInfo] = None
status: Literal["error"] = "error"
@staticmethod
def from_exception(exception: Exception) -> ActionErrorResult:
return ActionErrorResult(
reason=getattr(exception, "message", exception.args[0]),
error=ErrorInfo.from_exception(exception),
)
def __str__(self) -> str:
return f"Action failed: '{self.reason}'"