mirror of
https://github.com/aljazceru/Auto-GPT.git
synced 2026-01-14 11:34:20 +01:00
* Add categories to command registry * Fix tests * Clean up prompt generation * Rename Performance Evaluations to Best Practices * Move specification of response format from system prompt to Agent.construct_base_prompt * Clean up PromptGenerator class * Add debug logging to AIConfig autogeneration * Clarify prompting and add support for multiple thought processes to Agent * WIP: PlanningAgent * Disable message history by default on BaseAgent * Add CommandOutput and ThoughtProcessOutput type aliases * Fix interrupts in main.py * Use custom exceptions and clean up exception/error handling * Remove duplicate agent_history.py * Update PlanningAgent from upstream * WIP: Support for dynamic in-prompt context * WIP: response formats for PlanningAgent three-stage cycle * Remove browsing overlay & separate browsing from extraction code * Fix human feedback * Fix tests * Include history in Agent prompt generation * Code improvements in agent.py * Add ask_user command and revise system prompt
97 lines
2.5 KiB
Python
97 lines
2.5 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from typing import Any, Iterator, Literal, Optional
|
|
|
|
|
|
@dataclass
|
|
class Action:
|
|
name: str
|
|
args: dict[str, Any]
|
|
reasoning: str
|
|
|
|
def format_call(self) -> str:
|
|
return f"{self.name}({', '.join([f'{a}={repr(v)}' for a, v in self.args.items()])})"
|
|
|
|
|
|
@dataclass
|
|
class ActionSuccessResult:
|
|
results: Any
|
|
status: Literal["success"] = "success"
|
|
|
|
def __str__(self) -> str:
|
|
return f"Action succeeded and returned: `{self.results}`"
|
|
|
|
|
|
@dataclass
|
|
class ActionErrorResult:
|
|
reason: str
|
|
error: Optional[Exception] = None
|
|
status: Literal["error"] = "error"
|
|
|
|
def __str__(self) -> str:
|
|
return f"Action failed: `{self.reason}`"
|
|
|
|
|
|
@dataclass
|
|
class ActionInterruptedByHuman:
|
|
feedback: str
|
|
status: Literal["interrupted_by_human"] = "interrupted_by_human"
|
|
|
|
def __str__(self) -> str:
|
|
return f'The user interrupted the action with the following feedback: "{self.feedback}"'
|
|
|
|
|
|
ActionResult = ActionSuccessResult | ActionErrorResult | ActionInterruptedByHuman
|
|
|
|
|
|
class ActionHistory:
|
|
"""Utility container for an action history"""
|
|
|
|
@dataclass
|
|
class CycleRecord:
|
|
action: Action | None
|
|
result: ActionResult | None
|
|
|
|
cursor: int
|
|
cycles: list[CycleRecord]
|
|
|
|
def __init__(self, cycles: list[CycleRecord] = []):
|
|
self.cycles = cycles
|
|
self.cursor = len(self.cycles)
|
|
|
|
@property
|
|
def current_record(self) -> CycleRecord | None:
|
|
if self.cursor == len(self):
|
|
return None
|
|
return self[self.cursor]
|
|
|
|
def __getitem__(self, key: int) -> CycleRecord:
|
|
return self.cycles[key]
|
|
|
|
def __iter__(self) -> Iterator[CycleRecord]:
|
|
return iter(self.cycles)
|
|
|
|
def __len__(self) -> int:
|
|
return len(self.cycles)
|
|
|
|
def __bool__(self) -> bool:
|
|
return len(self.cycles) > 0
|
|
|
|
def register_action(self, action: Action) -> None:
|
|
if not self.current_record:
|
|
self.cycles.append(self.CycleRecord(None, None))
|
|
assert self.current_record
|
|
elif self.current_record.action:
|
|
raise ValueError("Action for current cycle already set")
|
|
|
|
self.current_record.action = action
|
|
|
|
def register_result(self, result: ActionResult) -> None:
|
|
if not self.current_record:
|
|
raise RuntimeError("Cannot register result for cycle without action")
|
|
elif self.current_record.result:
|
|
raise ValueError("Result for current cycle already set")
|
|
|
|
self.current_record.result = result
|