This commit is contained in:
Yao Liu
2025-01-22 11:32:35 -08:00
parent dac181a456
commit 4b8dbfd9c5
298 changed files with 56437 additions and 9 deletions

View File

@@ -0,0 +1,106 @@
from typing import List
class Agent:
def __init__(
self,
max_actions,
verbose=0,
logging=False,
previous_actions: List = None,
previous_reasons: List = None,
previous_responses: List = None,
):
self.previous_actions = [] if previous_actions is None else previous_actions
self.previous_reasons = [] if previous_reasons is None else previous_reasons
self.previous_responses = [] if previous_responses is None else previous_responses
self.max_actions = max_actions
self.verbose = verbose
self.logging = logging
self.trajectory = []
self.data_to_log = {}
def reset(self):
self.previous_actions = []
self.previous_reasons = []
self.previous_responses = []
self.trajectory = []
self.data_to_log = {}
def get_trajectory(self):
return self.trajectory
def update_history(self, action, reason):
if action:
self.previous_actions += [action]
if reason:
self.previous_reasons += [reason]
def predict_action(self, objective, observation, url=None):
pass
def receive_response(self, response):
self.previous_responses += [response]
def act(self, objective, env):
while not env.done():
observation = env.observation()
action, reason = self.predict_action(
objective=objective, observation=observation, url=env.get_url()
)
status = env.step(action)
if self.logging:
self.log_step(
objective=objective,
url=env.get_url(),
observation=observation,
action=action,
reason=reason,
status=status,
)
if len(self.previous_actions) >= self.max_actions:
print(f"Agent exceeded max actions: {self.max_actions}")
break
return status
async def async_act(self, objective, env):
while not env.done():
observation = await env.observation()
action, reason = self.predict_action(
objective=objective, observation=observation, url=env.get_url()
)
status = await env.step(action)
if self.logging:
self.log_step(
objective=objective,
url=env.get_url(),
observation=observation,
action=action,
reason=reason,
status=status,
)
if len(self.previous_actions) >= self.max_actions:
print(f"Agent exceeded max actions: {self.max_actions}")
break
return status
def log_step(self, objective, url, observation, action, reason, status):
self.data_to_log['objective'] = objective
self.data_to_log['url'] = url
self.data_to_log['observation'] = observation if isinstance(observation, str) else observation["text"]
self.data_to_log['previous_actions'] = self.previous_actions[:-1]
self.data_to_log['previous_responses'] = self.previous_responses[:-1]
self.data_to_log['previous_reasons'] = self.previous_reasons[:-1]
self.data_to_log['action'] = action
self.data_to_log['reason'] = reason
if status:
for (k, v) in status.items():
self.data_to_log[k] = v
self.trajectory.append(self.data_to_log)
self.data_to_log = {}

View File

@@ -0,0 +1,59 @@
from webagents_step.agents.agent import Agent
from typing import List
from webagents_step.utils.llm import fill_prompt_template, construct_llm_message_openai, call_openai_llm, parse_action_reason, calculate_cost_openai, call_anthropic_llm
class PromptAgent(Agent):
def __init__(self, max_actions: int = 10, verbose: bool = False, logging: bool = False,
debug: bool = False, prompt_template: str = None, model: str = "gpt-3.5-turbo",
prompt_mode: str = "chat", previous_actions: List = None, previous_reasons: List = None, previous_responses: List = None):
super().__init__(max_actions=max_actions, verbose=verbose, logging=logging, previous_actions=previous_actions, previous_reasons=previous_reasons, previous_responses=previous_responses)
self.debug = debug
self.prompt_template = prompt_template
self.model = model
self.prompt_mode = prompt_mode
def previous_history(self):
previous_history = []
if len(self.previous_actions) == len(self.previous_responses):
for action, response in zip(self.previous_actions, self.previous_responses):
if response:
previous_history.append(f"{response} = {action}")
else:
previous_history.append(action)
previous_history="\n".join(previous_history)
else:
previous_history = "\n".join(action for action in self.previous_actions if action is not None) if self.previous_actions is not None else ""
return previous_history
def predict_action(self, objective, observation, url=None):
prompt = fill_prompt_template(prompt_template=self.prompt_template, objective=objective,
observation=observation, url=url,
previous_history=self.previous_history())
messages = construct_llm_message_openai(prompt=prompt, prompt_mode=self.prompt_mode)
model_response = call_openai_llm(messages=messages, model=self.model)
action, reason = parse_action_reason(model_response)
if self.logging:
self.data_to_log['prompt'] = messages
if self.verbose > 0:
print(f"\n OBJECTIVE: {objective}")
print(f"\n URL: {url}")
print(f"\n PREVIOUS HISTORY: {self.previous_history()}")
print(f"\n REASON: {reason}")
print(f"\n ACTION: {action}")
if self.verbose > 1:
print(f"\n OBSERVATION: {observation}")
print(f"\n RESPONSE: {model_response}")
if self.debug:
human_input = input()
if human_input != "c":
action = human_input
reason = "None"
self.update_history(action=action, reason=reason)
return action, reason

View File

@@ -0,0 +1,105 @@
from webagents_step.agents.agent import Agent
from webagents_step.utils.stack import Stack
from webagents_step.agents.prompt_agent import PromptAgent
from typing import List, Dict
import re
import time
class StepAgent(Agent):
def __init__(self, max_actions: int = 10, verbose: bool = False, logging: bool = False,
debug: bool = False,
root_action: str = None,
action_to_prompt_dict: Dict = None,
low_level_action_list: List = None,
model: str = "gpt-3.5-turbo",
prompt_mode: str = "chat", previous_actions: List = None):
super().__init__(max_actions=max_actions, verbose=verbose, logging=logging, previous_actions=previous_actions)
self.debug = debug
self.root_action = root_action
self.action_to_prompt_dict = {} if action_to_prompt_dict is None else action_to_prompt_dict
self.low_level_action_list = [] if low_level_action_list is None else low_level_action_list
self.model = model
self.prompt_mode = prompt_mode
self.stack = Stack()
def is_done(self, action):
if action and "stop" in action:
return True
return False
def is_low_level_action(self, action):
if not action:
return False
action_type = action.split()[0]
return (action_type in self.low_level_action_list)
def is_high_level_action(self, action):
if not action:
return False
action_type = action.split()[0]
return (action_type in self.action_to_prompt_dict)
def init_root_agent(self, objective):
root_prompt_template = self.action_to_prompt_dict[self.root_action]
agent = PromptAgent(
prompt_template=root_prompt_template,
model=self.model,
prompt_mode=self.prompt_mode,
max_actions=self.max_actions,
verbose=self.verbose,
logging=self.logging,
debug=self.debug,
previous_actions=[],
previous_reasons=[],
previous_responses=[]
)
return {'agent': agent, 'objective': objective}
def init_agent(self, action):
pattern = r'(\w+)\s+\[(.*?)\]'
matches = re.findall(pattern, action)
action_type, _ = matches[0]
objective = action
prompt_template = self.action_to_prompt_dict[action_type]
agent = PromptAgent(
prompt_template=prompt_template,
model=self.model,
prompt_mode=self.prompt_mode,
max_actions=self.max_actions,
verbose=self.verbose,
logging=self.logging,
debug=self.debug,
previous_actions=[],
previous_reasons=[],
previous_responses=[]
)
return {'agent': agent, 'objective': objective}
def predict_action(self, objective, observation, url=None):
observation = observation["text"] if isinstance(observation, dict) else observation
if self.stack.is_empty():
new_element = self.init_root_agent(objective=objective)
self.stack.push(new_element)
action, reason = None, None
while not self.stack.is_empty():
element = self.stack.peek()
action, reason = element['agent'].predict_action(objective=element['objective'], observation=observation, url=url)
if (not self.is_done(action)) and self.is_low_level_action(action):
element['agent'].receive_response("")
return action, reason
if (not self.is_done(action)) and self.is_high_level_action(action):
new_element = self.init_agent(action)
self.stack.push(new_element)
if self.logging:
self.log_step(objective=element['objective'], url=url, observation=observation, action=action, reason=reason, status={})
continue
if self.is_done(action):
self.stack.pop()
if not self.stack.is_empty():
self.stack.peek()['agent'].receive_response(re.search(r"\[(.*?)\]", action).group(1))
if self.logging:
self.log_step(objective=element['objective'], url=url, observation=observation, action=action, reason=reason, status={})
continue
return action, reason