import os
import sys
import json
import random
import argparse
from concurrent.futures import ThreadPoolExecutor
import time

from web_run.web_env import webshopEnv
from web_run.llms import get_llm_backend, OPENAI_CHAT_MODELS, OPENAI_LLM_MODELS
from web_run.multi_agent_arch import SearchAgent, ClickAgent, ControlAgent
import web_run.agent_arch as agent_arch
from web_run.utils import session_save, get_instruction, get_env_botton
from web_run.evaluate import get_file_sess_idx
from web_run.config import available_agent_names

parser = argparse.ArgumentParser(description='Parsing the input of agents, llms and llm context length.')
parser.add_argument("--agent_name", type=str, help="Name of the agent.", default="React")
parser.add_argument("--llm_name", type=str, help="Name of the llm", default="gpt-3.5-turbo")
parser.add_argument("--max_context_len", type=int, help="Maximum context length", default=1700)
args = parser.parse_args()
agent_name = args.agent_name
llm_name = args.llm_name
max_context_len = args.max_context_len

assert agent_name in available_agent_names, f"Invalid agent name. Allowed values are {available_agent_names}"

def run_one_session(idx, max_steps=50):
    env = webshopEnv()
    llm_backend = get_llm_backend(llm_name)
    llm = llm_backend.run
    if agent_name in ["React_Webrun_Agent"]:
        agent = agent_arch.ReactAgent(llm, max_context_len)
    elif agent_name in ["Zeroshot_Webrun_Agent"]:
        agent = agent_arch.ZeroshotAgent(llm, max_context_len)
    elif agent_name in ["ZeroshotThink_Webrun_Agent"]:
        agent = agent_arch.ZeroshotThinkAgent(llm, max_context_len)
    elif agent_name in ["Planner_Webrun_Agent"]:
        agent = agent_arch.PlannerAgent(llm, max_context_len)
    elif agent_name in ["PlannerReact_Webrun_Agent"]:
        agent = agent_arch.PlannerReactAgent(llm, max_context_len)
    elif agent_name in ["Search_Click_Controller_Webrun_Agent","Search_Click_Control_Webrun_Agent"]:
        search_agent = SearchAgent(llm, max_context_len)
        click_agent = ClickAgent(llm, max_context_len)
        agent = ControlAgent([search_agent, click_agent])

    saving_path = f"./execution_data/{agent.type}_{llm_name}_batch.json"
    actions = []
    observations = []
    retrieved_items = []
    hulluci = 0
    # reset the environments
    action = 'reset'
    idx = f"fixed_{idx}"
    done = False
    observation, reward, done, asins, buttons = env.step(idx, action)
    env_bottons = get_env_botton(buttons)
    actions.append(action)
    observations.append(observation)
    retrieved_items.append(asins)
    inst = get_instruction(observation)
    agent.new_session(idx, inst)

    # start planning
    if agent_name in ["PlannerReact_Webrun_Agent", "Planner_Webrun_Agent"]:
        action = 'planning'
        agent.planning()
        agent.stop = ["\n"]
        observation = agent.plan

    # start interaction
    for step in range(max_steps):
        actions.append(action)
        observations.append(observation)
        retrieved_items.append(asins)
        if not done:
            action = agent.forward(observation, env_bottons).lstrip(' ')
            # print(observation)
            print(action)
            if "No response" in action: # running too many sessions, end this session
                done = True
                # session_save(idx, actions, observations, retrieved_items, saving_path)
                return 0.0
            try:
                observation, reward, done, asins, buttons = env.step(idx, action)
                if "Buy Now" in action:
                    print(observation, reward, done, asins, buttons)
                env_bottons = get_env_botton(buttons)
            except AssertionError:
                observation = 'Invalid action!'
                hulluci += 1
            if hulluci > 3:
                reward = 0.0
                done = True
            if "handle_exception" in observation: # running too many sessions, end this session
                done = True
                session_save(idx, actions, observations, retrieved_items, saving_path)
                return 0.0
        else:
            time.sleep(1)
            session_save(idx, actions, observations, retrieved_items, saving_path)
            print("saved!")
            return reward
    session_save(idx, actions, observations, retrieved_items, saving_path)
    return 0.0

def run_episodes(session_list):
    work_num = 4
    if len(session_list) > work_num and not llm_name in (OPENAI_CHAT_MODELS + OPENAI_LLM_MODELS):
        with ThreadPoolExecutor(max_workers=work_num) as executor:
            # executor.map will return a list of tuples in the same order as idxs[:10]
            results = list(executor.map(run_one_session, session_list))
            # print(sum(results)/len(results))
            print("Done the session running!")
    else:
        for sid in session_list:
            run_one_session(sid)

file_name = f"./execution_data/webrun/{agent_name}_{llm_name}_batch.json"
if os.path.exists(file_name):
    executed_sess = get_file_sess_idx(file_name)
    session_list = [j for j in range(900) if j not in executed_sess]
    run_episodes(session_list)
else:
    run_episodes(list(range(0, 900)))


from web_run.web_env import webshopEnv
from web_run.llms import get_llm_backend, OPENAI_CHAT_MODELS, OPENAI_LLM_MODELS
from web_run.multi_agent_arch import SearchAgent, ClickAgent, ControlAgent
import web_run.agent_arch as agent_arch
from web_run.utils import session_save, get_instruction, get_env_botton
from web_run.evaluate import get_file_sess_idx
from web_run.config import available_agent_names

parser = argparse.ArgumentParser(description='Parsing the input of agents, llms and llm context length.')
parser.add_argument("--agent_name", type=str, help="Name of the agent.", default="React")
parser.add_argument("--llm_name", type=str, help="Name of the llm", default="gpt-3.5-turbo")
parser.add_argument("--max_context_len", type=int, help="Maximum context length", default=1700)
args = parser.parse_args()
agent_name = args.agent_name
llm_name = args.llm_name
max_context_len = args.max_context_len

assert agent_name in available_agent_names, f"Invalid agent name. Allowed values are {available_agent_names}"

def run_one_session(idx, max_steps=50):
    env = webshopEnv()
    llm_backend = get_llm_backend(llm_name)
    llm = llm_backend.run
    if agent_name in ["React_Webrun_Agent"]:
        agent = agent_arch.ReactAgent(llm, max_context_len)
    elif agent_name in ["Zeroshot_Webrun_Agent"]:
        agent = agent_arch.ZeroshotAgent(llm, max_context_len)
    elif agent_name in ["ZeroshotThink_Webrun_Agent"]:
        agent = agent_arch.ZeroshotThinkAgent(llm, max_context_len)
    elif agent_name in ["Planner_Webrun_Agent"]:
        agent = agent_arch.PlannerAgent(llm, max_context_len)
    elif agent_name in ["PlannerReact_Webrun_Agent"]:
        agent = agent_arch.PlannerReactAgent(llm, max_context_len)
    elif agent_name in ["Search_Click_Controller_Webrun_Agent","Search_Click_Control_Webrun_Agent"]:
        search_agent = SearchAgent(llm, max_context_len)
        click_agent = ClickAgent(llm, max_context_len)
        agent = ControlAgent([search_agent, click_agent])

    saving_path = f"./execution_data/{agent.type}_{llm_name}_batch.json"
    actions = []
    observations = []
    retrieved_items = []
    hulluci = 0
    # reset the environments
    action = 'reset'
    idx = f"fixed_{idx}"
    done = False
    observation, reward, done, asins, buttons = env.step(idx, action)
    env_bottons = get_env_botton(buttons)
    actions.append(action)
    observations.append(observation)
    retrieved_items.append(asins)
    inst = get_instruction(observation)
    agent.new_session(idx, inst)

    # start planning
    if agent_name in ["PlannerReact_Webrun_Agent", "Planner_Webrun_Agent"]:
        action = 'planning'
        agent.planning()
        agent.stop = ["\n"]
        observation = agent.plan

    # start interaction
    for step in range(max_steps):
        actions.append(action)
        observations.append(observation)
        retrieved_items.append(asins)
        if not done:
            action = agent.forward(observation, env_bottons).lstrip(' ')
            # print(observation)
            print(action)
            if "No response" in action: # running too many sessions, end this session
                done = True
                # session_save(idx, actions, observations, retrieved_items, saving_path)
                return 0.0
            try:
                observation, reward, done, asins, buttons = env.step(idx, action)
                if "Buy Now" in action:
                    print(observation, reward, done, asins, buttons)
                env_bottons = get_env_botton(buttons)
            except AssertionError:
                observation = 'Invalid action!'
                hulluci += 1
            if hulluci > 3:
                reward = 0.0
                done = True
            if "handle_exception" in observation: # running too many sessions, end this session
                done = True
                session_save(idx, actions, observations, retrieved_items, saving_path)
                return 0.0
        else:
            time.sleep(1)
            session_save(idx, actions, observations, retrieved_items, saving_path)
            print("saved!")
            return reward
    session_save(idx, actions, observations, retrieved_items, saving_path)
    return 0.0

def run_episodes(session_list):
    work_num = 4
    if len(session_list) > work_num and not llm_name in (OPENAI_CHAT_MODELS + OPENAI_LLM_MODELS):
        with ThreadPoolExecutor(max_workers=work_num) as executor:
            # executor.map will return a list of tuples in the same order as idxs[:10]
            results = list(executor.map(run_one_session, session_list))
            # print(sum(results)/len(results))
            print("Done the session running!")
    else:
        for sid in session_list:
            run_one_session(sid)

file_name = f"./execution_data/webrun/{agent_name}_{llm_name}_batch.json"
if os.path.exists(file_name):
    executed_sess = get_file_sess_idx(file_name)
    session_list = [j for j in range(900) if j not in executed_sess]
    run_episodes(session_list)
else:
    run_episodes(list(range(0, 900)))


                    print(observation, reward, done, asins, buttons)
                env_bottons = get_env_botton(buttons)
            except AssertionError:
                observation = 'Invalid action!'
                hulluci += 1
            if hulluci > 3:
                reward = 0.0
                done = True
            if "handle_exception" in observation: # running too many sessions, end this session
                done = True
                session_save(idx, actions, observations, retrieved_items, saving_path)
                return 0.0
        else:
            time.sleep(1)
            session_save(idx, actions, observations, retrieved_items, saving_path)
            print("saved!")
            return reward
    session_save(idx, actions, observations, retrieved_items, saving_path)
    return 0.0

def run_episodes(session_list):
    work_num = 4
    if len(session_list) > work_num and not llm_name in (OPENAI_CHAT_MODELS + OPENAI_LLM_MODELS):
        with ThreadPoolExecutor(max_workers=work_num) as executor:
            # executor.map will return a list of tuples in the same order as idxs[:10]
            results = list(executor.map(run_one_session, session_list))
            # print(sum(results)/len(results))
            print("Done the session running!")
    else:
        for sid in session_list:
            run_one_session(sid)

file_name = f"./execution_data/webrun/{agent_name}_{llm_name}_batch.json"
if os.path.exists(file_name):
    executed_sess = get_file_sess_idx(file_name)
    session_list = [j for j in range(900) if j not in executed_sess]
    run_episodes(session_list)
else:
    run_episodes(list(range(0, 900)))


import os
import argparse
import numpy as np
import pandas as pd
import concurrent
import joblib
from hotpotqa_run.utils import summarize_trial_detailed, log_trial
import hotpotqa_run.utils as utils
from hotpotqa_run.agent_arch import get_agent
from hotpotqa_run.llms import get_llm_backend
from hotpotqa_run.config import available_agent_names

parser = argparse.ArgumentParser(description='Parsing the input of agents, llms and llm context length.')
parser.add_argument("--agent_name", type=str, help="Name of the agent.", default="React")
parser.add_argument("--llm_name", type=str, help="Name of the llm", default="gpt-3.5-turbo")
parser.add_argument("--max_context_len", type=int, help="Maximum context length", default=1700)
args = parser.parse_args()

agent_name = args.agent_name
llm_name = args.llm_name
max_context_len = args.max_context_len
assert agent_name in available_agent_names

def process_agent_run_step(agent):
    agent.run()

def run_one_complex_level(level="easy"):
    hotpot = joblib.load(f'hotpotqa_run/data/{level}.joblib').reset_index(drop = True)
    agent_save_file = f"execution_data/hotpotqa/{level}_{agent_name}_{llm_name}.jsonl"
    task_instructions = [(row['question'], row['answer']) for _, row in hotpot.iterrows()]
    if os.path.exists(agent_save_file):
        sessions = utils.get_all_agent_sessions(agent_save_file)
        completed_tasks = utils.get_non_error_tasks(sessions)
        print(f"{level}:{len(completed_tasks)}")
        task_instructions = [task for task in task_instructions if task not in completed_tasks]
        utils.delete_error(agent_save_file)
    llm = get_llm_backend(llm_name).run
    agent_cls = get_agent(agent_name)
    agents = [agent_cls(ques, ans, llm, max_context_len) for ques, ans in task_instructions]
    with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor:
        executor.map(process_agent_run_step, agents)
    for agent in agents:
        utils.log_agent(agent, agent_save_file)
    print(f'Finished Trial. Total: {len(agents)}')

def main():
    levels = ['easy', 'medium', 'hard']
    for level in levels:
        run_one_complex_level(level)

if __name__ == '__main__':
    main()


import concurrent
import joblib
from hotpotqa_run.utils import summarize_trial_detailed, log_trial
import hotpotqa_run.utils as utils
from hotpotqa_run.agent_arch import get_agent
from hotpotqa_run.llms import get_llm_backend
from hotpotqa_run.config import available_agent_names

parser = argparse.ArgumentParser(description='Parsing the input of agents, llms and llm context length.')
parser.add_argument("--agent_name", type=str, help="Name of the agent.", default="React")
parser.add_argument("--llm_name", type=str, help="Name of the llm", default="gpt-3.5-turbo")
parser.add_argument("--max_context_len", type=int, help="Maximum context length", default=1700)
args = parser.parse_args()

agent_name = args.agent_name
llm_name = args.llm_name
max_context_len = args.max_context_len
assert agent_name in available_agent_names

def process_agent_run_step(agent):
    agent.run()

def run_one_complex_level(level="easy"):
    hotpot = joblib.load(f'hotpotqa_run/data/{level}.joblib').reset_index(drop = True)
    agent_save_file = f"execution_data/hotpotqa/{level}_{agent_name}_{llm_name}.jsonl"
    task_instructions = [(row['question'], row['answer']) for _, row in hotpot.iterrows()]
    if os.path.exists(agent_save_file):
        sessions = utils.get_all_agent_sessions(agent_save_file)
        completed_tasks = utils.get_non_error_tasks(sessions)
        print(f"{level}:{len(completed_tasks)}")
        task_instructions = [task for task in task_instructions if task not in completed_tasks]
        utils.delete_error(agent_save_file)
    llm = get_llm_backend(llm_name).run
    agent_cls = get_agent(agent_name)
    agents = [agent_cls(ques, ans, llm, max_context_len) for ques, ans in task_instructions]
    with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor:
        executor.map(process_agent_run_step, agents)
    for agent in agents:
        utils.log_agent(agent, agent_save_file)
    print(f'Finished Trial. Total: {len(agents)}')


import hotpotqa_run.utils as utils
from hotpotqa_run.agent_arch import get_agent
from hotpotqa_run.llms import get_llm_backend
from hotpotqa_run.config import available_agent_names

parser = argparse.ArgumentParser(description='Parsing the input of agents, llms and llm context length.')
parser.add_argument("--agent_name", type=str, help="Name of the agent.", default="React")
parser.add_argument("--llm_name", type=str, help="Name of the llm", default="gpt-3.5-turbo")
parser.add_argument("--max_context_len", type=int, help="Maximum context length", default=1700)
args = parser.parse_args()

agent_name = args.agent_name
llm_name = args.llm_name
max_context_len = args.max_context_len
assert agent_name in available_agent_names

def process_agent_run_step(agent):
    agent.run()

def run_one_complex_level(level="easy"):
    hotpot = joblib.load(f'hotpotqa_run/data/{level}.joblib').reset_index(drop = True)
    agent_save_file = f"execution_data/hotpotqa/{level}_{agent_name}_{llm_name}.jsonl"
    task_instructions = [(row['question'], row['answer']) for _, row in hotpot.iterrows()]
    if os.path.exists(agent_save_file):
        sessions = utils.get_all_agent_sessions(agent_save_file)
        completed_tasks = utils.get_non_error_tasks(sessions)
        print(f"{level}:{len(completed_tasks)}")
        task_instructions = [task for task in task_instructions if task not in completed_tasks]
        utils.delete_error(agent_save_file)
    llm = get_llm_backend(llm_name).run
    agent_cls = get_agent(agent_name)
    agents = [agent_cls(ques, ans, llm, max_context_len) for ques, ans in task_instructions]
    with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor:
        executor.map(process_agent_run_step, agents)
    for agent in agents:
        utils.log_agent(agent, agent_save_file)
    print(f'Finished Trial. Total: {len(agents)}')

def main():
    levels = ['easy', 'medium', 'hard']
    for level in levels:
        run_one_complex_level(level)

if __name__ == '__main__':
    main()


main

def run_one_complex_level(level="easy"):
    hotpot = joblib.load(f'hotpotqa_run/data/{level}.joblib').reset_index(drop = True)
    agent_save_file = f"execution_data/hotpotqa/{level}_{agent_name}_{llm_name}.jsonl"
    task_instructions = [(row['question'], row['answer']) for _, row in hotpot.iterrows()]
    if os.path.exists(agent_save_file):
        sessions = utils.get_all_agent_sessions(agent_save_file)
        completed_tasks = utils.get_non_error_tasks(sessions)
        print(f"{level}:{len(completed_tasks)}")
        task_instructions = [task for task in task_instructions if task not in completed_tasks]
        utils.delete_error(agent_save_file)
    llm = get_llm_backend(llm_name).run
    agent_cls = get_agent(agent_name)
    agents = [agent_cls(ques, ans, llm, max_context_len) for ques, ans in task_instructions]
    with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor:
        executor.map(process_agent_run_step, agents)
    for agent in agents:
        utils.log_agent(agent, agent_save_file)
    print(f'Finished Trial. Total: {len(agents)}')

def main():
    levels = ['easy', 'medium', 'hard']
    for level in levels:
        run_one_complex_level(level)

if __name__ == '__main__':
    main()


"""
 Copyright (c) 2023, salesforce.com, inc.
 All rights reserved.
 SPDX-License-Identifier: Apache License 2.0
 For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0
"""

available_agent_names = ["Zeroshot_Webrun_Agent","ZeroshotThink_Webrun_Agent",
                         "React_Webrun_Agent","Planner_Webrun_Agent",
                         "PlannerReact_Webrun_Agent","Search_Click_Control_Webrun_Agent"]
OPENAI_API_KEY = ""


"""
 Copyright (c) 2023, salesforce.com, inc.
 All rights reserved.
 SPDX-License-Identifier: Apache License 2.0
 For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0
"""

import random
import re
import json
import time
import os
import tiktoken
import web_run.pre_prompt as pre_prompt
from web_run.utils import get_query
from web_run.llms import token_enc

class BaseAgent(object):
    def __init__(self, llm, context_len=2000):
        self.type = "Base_Webrun_Agent"
        self.life_label = time.time()
        self.name = f"{self.type}_{self.life_label}"
        self.task = {}
        self.actions = {}
        self.observations = {}
        self.item_recall = {}
        self.llm = llm
        self.context_len = context_len
        self.cur_session = 0

    def new_session(self, idx, task):
        self.cur_session = idx
        self.task[idx] = task
        self.actions[idx] = ['reset']
        self.observations[idx] = []
        self.item_recall[idx] = []

    def llm_layer(self, prompt):
        return self.llm(prompt)

    def get_history(self, session=None):
        if not session:
            session = self.cur_session
        history = ""
        for idx in range(1, len(self.actions[session])):
            history += f"Action: {self.actions[session][idx]}\n"
            history += f"Observation: {self.observations[session][idx]}\n\n"
        return history

    def save(self, path):
        file_name = os.path.join(path, self.name+'_'+str(self.life_label))
        with open(file_name, 'a') as f:
            f.write(f"session_idx:{self.cur_session}\n")
            history = self.get_history(self.cur_session)
            f.write(history)
            f.write('\n')

    def action_parser(self, text, available_actions):
        nor_text = text.strip().lower()
        if nor_text.startswith('search'):
            query = get_query(nor_text)
            return f"search[{query}]"
        if nor_text.startswith('click'):
            if 'click' in available_actions:
                for a in available_actions['click']:
                    if a.lower() in nor_text:
                        return f"click[{a}]"
        return text

    def prompt_layer(self):
        raise NotImplementedError

    def forward(self, observation, available_actions=None):
        raise NotImplementedError

class ReactAgent(BaseAgent):
    def __init__(self, llm, context_len=2000):
        super().__init__(llm, context_len)
        self.type = "React_Webrun_Agent"
        self.name = f"{self.type}_{self.life_label}"

    def prompt_layer(self):
        one_shot = pre_prompt.oneshot
        prompt = f"{one_shot}{self.observations[self.cur_session][0]}\n\nAction:"
        if len(self.actions[self.cur_session]) > 1:
            initial_prompt = f"{one_shot}{self.observations[self.cur_session][0]}\n\n"
            history = self.get_history()
            remain_context_space = (self.context_len - len(token_enc.encode(initial_prompt)))*3
            history = history[-int(remain_context_space):]
            prompt = f"{initial_prompt}{history}\n\nAction:"
        return prompt

    def forward(self, observation, available_actions=None):
        self.observations[self.cur_session].append(observation)
        prompt = self.prompt_layer()
        action = self.llm_layer(prompt)
        self.actions[self.cur_session].append(action)
        return action

class ZeroshotAgent(BaseAgent):
    def __init__(self, llm, context_len=2000, temperature=0.9, stop=['\n']):
        super().__init__(llm, context_len)
        self.type = "Zeroshot_Webrun_Agent"
        self.life_label = time.time()
        self.name = f"{self.type}_{self.life_label}"

    def llm_layer(self, prompt):
        return self.llm(prompt)

    def avai_action_prompt(self, available_actions):
        if 'search' in available_actions:
            return "{search}"
        elif 'click' in available_actions:
            actions = available_actions['click']
            ac_string = "\t".join(actions)
            return f"click: [{ac_string}]"

    def prompt_layer(self, available_actions):
        zeroshot = pre_prompt.zeroshot
        actions_prompt = f"current available action is {self.avai_action_prompt(available_actions)[-3000:]}"
        prompt = f"{zeroshot}{self.observations[self.cur_session][0]}{actions_prompt}\n\nAction:"
        if len(self.actions[self.cur_session]) > 1:
            initial_prompt = f"{zeroshot}{self.observations[self.cur_session][0]}\n\n"
            history = self.get_history()
            remain_context_space = (self.context_len - len(token_enc.encode(f"{initial_prompt}{actions_prompt}")))*3
            history = history[-int(remain_context_space):]
            prompt = f"{initial_prompt}{history}{actions_prompt}\n\nAction:"
        return prompt

    def forward(self, observation, available_actions=None):
        self.observations[self.cur_session].append(observation)
        prompt = self.prompt_layer(available_actions)
        action = self.llm_layer(prompt).lstrip()
        action = self.action_parser(action, available_actions)
        self.actions[self.cur_session].append(action)
        return action

class ZeroshotThinkAgent(BaseAgent):
    def __init__(self, llm, context_len=2000, temperature=0.9, stop=['\n']):
        super().__init__(llm, context_len)
        self.type = "ZeroshotThink_Webrun_Agent"
        self.life_label = time.time()
        self.name = f"{self.type}_{self.life_label}"
        self.temperature = temperature
        self.stop = stop

    def llm_layer(self, prompt):
        return self.llm(prompt)

    def avai_action_prompt(self, available_actions):
        if 'search' in available_actions:
            return "{search}"
        elif 'click' in available_actions:
            actions = available_actions['click']
            ac_string = "\t".join(actions)
            return f"click: [{ac_string}]"

    def prompt_layer(self, available_actions):
        zeroshot = pre_prompt.zeroshot_think
        actions_prompt = f"current available action is {self.avai_action_prompt(available_actions)[-3000:]}"
        prompt = f"{zeroshot}{self.observations[self.cur_session][0]}{actions_prompt}\n\nAction:"
        if len(self.actions[self.cur_session]) > 1:
            initial_prompt = f"{zeroshot}{self.observations[self.cur_session][0]}\n\n"
            history = self.get_history()
            remain_context_space = (self.context_len - len(token_enc.encode(initial_prompt+actions_prompt)))*3
            history = history[-int(remain_context_space):]
            prompt = f"{initial_prompt}{history}{actions_prompt}\n\nAction:"
        return prompt

    def forward(self, observation, available_actions=None):
        self.observations[self.cur_session].append(observation)
        prompt = self.prompt_layer(available_actions)
        action = self.llm_layer(prompt, temperature=self.temperature, stop=self.stop).lstrip()
        action = self.action_parser(action, available_actions)
        self.actions[self.cur_session].append(action)
        return action

class PlannerAgent(BaseAgent):
    def __init__(self, llm, context_len=2000, temperature=0.9, stop=['\n']):
        super().__init__(llm, context_len)
        self.type = "Planner_Webrun_Agent"
        self.name = f"{self.type}_{self.life_label}"
        self.temperature = temperature
        self.stop = stop
        self.max_plan_token_len = 256
        self.plan = None

    def planning(self):
        plan_prompt = f"{pre_prompt.plan}\n\nInstruction: {self.task[self.cur_session]}\nPlan:"
        self.plan = self.llm(plan_prompt, temperature=self.temperature, stop=["\n"],
                             max_tokens=self.max_plan_token_len)

    def llm_layer(self, prompt):
        return self.llm(prompt)

    def prompt_layer(self, available_actions):
        oneshot = pre_prompt.oneshot_plan
        prompt = f"{oneshot}\n\nInstruction: {self.task[self.cur_session]}\nPlan: {self.plan}\n\nAction:"
        if len(self.actions[self.cur_session]) > 1:
            initial_prompt = f"{oneshot}\n\nInstruction: {self.task[self.cur_session]}\nPlan: {self.plan}\n\n"
            history = self.get_history()
            remain_context_space = (self.context_len - len(token_enc.encode(initial_prompt)))*3
            history = history[-remain_context_space:]
            prompt = f"{initial_prompt}{history}Action:"
        return prompt

    def forward(self, observation, available_actions=None):
        self.observations[self.cur_session].append(observation)
        prompt = self.prompt_layer(available_actions)
        action = self.llm_layer(prompt).lstrip(' ')
        action = self.action_parser(action, available_actions)
        self.actions[self.cur_session].append(action)
        return action

class PlannerReactAgent(PlannerAgent):
    def __init__(self, llm, context_len=2000, temperature=0.9, stop=['\n']):
        super().__init__(llm, context_len, temperature, stop)
        self.type = "PlannerReact_Webrun_Agent"
        self.name = f"{self.type}_{self.life_label}"

    def planning(self):
        plan_prompt = f"{pre_prompt.plan_react}\n\nInstruction: {self.task[self.cur_session]}\nPlan:"
        self.plan = self.llm(plan_prompt, temperature=self.temperature, stop=["\n"],
                             max_tokens=self.max_plan_token_len)

    def prompt_layer(self, available_actions=None):
        oneshot = pre_prompt.oneshot_plan_react
        prompt = f"{oneshot}\n\nInstruction: {self.task[self.cur_session]}\nPlan: {self.plan}\n\nAction:"
        if len(self.actions[self.cur_session]) > 1:
            initial_prompt = f"{oneshot}\n\nInstruction: {self.task[self.cur_session]}\nPlan: {self.plan}\n\n"
            history = self.get_history()
            remain_context_space = (self.context_len - len(token_enc.encode(initial_prompt)))*3
            history = history[-remain_context_space:]
            prompt = f"{initial_prompt}{history}Action:"
        return prompt

    def forward(self, observation, available_actions=None):
        self.observations[self.cur_session].append(observation)
        prompt = self.prompt_layer(available_actions)
        action = self.llm_layer(prompt).lstrip(' ')
        action = self.action_parser(action, available_actions)
        self.actions[self.cur_session].append(action)
        return action


BaseAgent

"""
 Copyright (c) 2023, salesforce.com, inc.
 All rights reserved.
 SPDX-License-Identifier: Apache License 2.0
 For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0
"""

import random
import re
import json
import time
import os
import tiktoken
import web_run.pre_prompt as pre_prompt
from web_run.utils import get_query
from web_run.llms import token_enc

class BaseAgent(object):
    def __init__(self, llm, context_len=2000):
        self.type = "Base_Webrun_Agent"
        self.life_label = time.time()
        self.name = f"{self.type}_{self.life_label}"
        self.task = {}
        self.actions = {}
        self.observations = {}
        self.item_recall = {}
        self.llm = llm
        self.context_len = context_len
        self.cur_session = 0

    def new_session(self, idx, task):
        self.cur_session = idx
        self.task[idx] = task
        self.actions[idx] = ['reset']
        self.observations[idx] = []
        self.item_recall[idx] = []

    def llm_layer(self, prompt):
        return self.llm(prompt)

    def get_history(self, session=None):
        if not session:
            session = self.cur_session
        history = ""
        for idx in range(1, len(self.actions[session])):
            history += f"Action: {self.actions[session][idx]}\n"
            history += f"Observation: {self.observations[session][idx]}\n\n"
        return history

    def save(self, path):
        file_name = os.path.join(path, self.name+'_'+str(self.life_label))
        with open(file_name, 'a') as f:
            f.write(f"session_idx:{self.cur_session}\n")
            history = self.get_history(self.cur_session)
            f.write(history)
            f.write('\n')

    def action_parser(self, text, available_actions):
        nor_text = text.strip().lower()
        if nor_text.startswith('search'):
            query = get_query(nor_text)
            return f"search[{query}]"
        if nor_text.startswith('click'):
            if 'click' in available_actions:
                for a in available_actions['click']:
                    if a.lower() in nor_text:
                        return f"click[{a}]"
        return text

    def prompt_layer(self):
        raise NotImplementedError

    def forward(self, observation, available_actions=None):
        raise NotImplementedError

class ReactAgent(BaseAgent):
    def __init__(self, llm, context_len=2000):
        super().__init__(llm, context_len)
        self.type = "React_Webrun_Agent"
        self.name = f"{self.type}_{self.life_label}"

    def prompt_layer(self):
        one_shot = pre_prompt.oneshot
        prompt = f"{one_shot}{self.observations[self.cur_session][0]}\n\nAction:"
        if len(self.actions[self.cur_session]) > 1:
            initial_prompt = f"{one_shot}{self.observations[self.cur_session][0]}\n\n"
            history = self.get_history()
            remain_context_space = (self.context_len - len(token_enc.encode(initial_prompt)))*3
            history = history[-int(remain_context_space):]
            prompt = f"{initial_prompt}{history}\n\nAction:"
        return prompt

    def forward(self, observation, available_actions=None):


ReactAgent

    def action_parser(self, text, available_actions):
        nor_text = text.strip().lower()
        if nor_text.startswith('search'):
            query = get_query(nor_text)
            return f"search[{query}]"
        if nor_text.startswith('click'):
            if 'click' in available_actions:
                for a in available_actions['click']:
                    if a.lower() in nor_text:
                        return f"click[{a}]"
        return text

    def prompt_layer(self):
        raise NotImplementedError

    def forward(self, observation, available_actions=None):
        raise NotImplementedError

class ReactAgent(BaseAgent):
    def __init__(self, llm, context_len=2000):
        super().__init__(llm, context_len)
        self.type = "React_Webrun_Agent"
        self.name = f"{self.type}_{self.life_label}"

    def prompt_layer(self):
        one_shot = pre_prompt.oneshot
        prompt = f"{one_shot}{self.observations[self.cur_session][0]}\n\nAction:"
        if len(self.actions[self.cur_session]) > 1:
            initial_prompt = f"{one_shot}{self.observations[self.cur_session][0]}\n\n"
            history = self.get_history()
            remain_context_space = (self.context_len - len(token_enc.encode(initial_prompt)))*3
            history = history[-int(remain_context_space):]
            prompt = f"{initial_prompt}{history}\n\nAction:"
        return prompt

    def forward(self, observation, available_actions=None):
        self.observations[self.cur_session].append(observation)
        prompt = self.prompt_layer()
        action = self.llm_layer(prompt)
        self.actions[self.cur_session].append(action)
        return action

class ZeroshotAgent(BaseAgent):
    def __init__(self, llm, context_len=2000, temperature=0.9, stop=['\n']):
        super().__init__(llm, context_len)
        self.type = "Zeroshot_Webrun_Agent"
        self.life_label = time.time()
        self.name = f"{self.type}_{self.life_label}"

    def llm_layer(self, prompt):
        return self.llm(prompt)

    def avai_action_prompt(self, available_actions):
        if 'search' in available_actions:
            return "{search}"
        elif 'click' in available_actions:
            actions = available_actions['click']
            ac_string = "\t".join(actions)
            return f"click: [{ac_string}]"

    def prompt_layer(self, available_actions):


ZeroshotAgent

        self.name = f"{self.type}_{self.life_label}"

    def prompt_layer(self):
        one_shot = pre_prompt.oneshot
        prompt = f"{one_shot}{self.observations[self.cur_session][0]}\n\nAction:"
        if len(self.actions[self.cur_session]) > 1:
            initial_prompt = f"{one_shot}{self.observations[self.cur_session][0]}\n\n"
            history = self.get_history()
            remain_context_space = (self.context_len - len(token_enc.encode(initial_prompt)))*3
            history = history[-int(remain_context_space):]
            prompt = f"{initial_prompt}{history}\n\nAction:"
        return prompt

    def forward(self, observation, available_actions=None):
        self.observations[self.cur_session].append(observation)
        prompt = self.prompt_layer()
        action = self.llm_layer(prompt)
        self.actions[self.cur_session].append(action)
        return action

class ZeroshotAgent(BaseAgent):
    def __init__(self, llm, context_len=2000, temperature=0.9, stop=['\n']):
        super().__init__(llm, context_len)
        self.type = "Zeroshot_Webrun_Agent"
        self.life_label = time.time()
        self.name = f"{self.type}_{self.life_label}"

    def llm_layer(self, prompt):
        return self.llm(prompt)

    def avai_action_prompt(self, available_actions):
        if 'search' in available_actions:
            return "{search}"
        elif 'click' in available_actions:
            actions = available_actions['click']
            ac_string = "\t".join(actions)
            return f"click: [{ac_string}]"

    def prompt_layer(self, available_actions):
        zeroshot = pre_prompt.zeroshot
        actions_prompt = f"current available action is {self.avai_action_prompt(available_actions)[-3000:]}"
        prompt = f"{zeroshot}{self.observations[self.cur_session][0]}{actions_prompt}\n\nAction:"
        if len(self.actions[self.cur_session]) > 1:
            initial_prompt = f"{zeroshot}{self.observations[self.cur_session][0]}\n\n"
            history = self.get_history()
            remain_context_space = (self.context_len - len(token_enc.encode(f"{initial_prompt}{actions_prompt}")))*3
            history = history[-int(remain_context_space):]
            prompt = f"{initial_prompt}{history}{actions_prompt}\n\nAction:"
        return prompt

    def forward(self, observation, available_actions=None):
        self.observations[self.cur_session].append(observation)
        prompt = self.prompt_layer(available_actions)
        action = self.llm_layer(prompt).lstrip()
        action = self.action_parser(action, available_actions)
        self.actions[self.cur_session].append(action)
        return action

class ZeroshotThinkAgent(BaseAgent):
    def __init__(self, llm, context_len=2000, temperature=0.9, stop=['\n']):
        super().__init__(llm, context_len)
        self.type = "ZeroshotThink_Webrun_Agent"
        self.life_label = time.time()
        self.name = f"{self.type}_{self.life_label}"
        self.temperature = temperature
        self.stop = stop

    def llm_layer(self, prompt):
        return self.llm(prompt)

    def avai_action_prompt(self, available_actions):
        if 'search' in available_actions:
            return "{search}"
        elif 'click' in available_actions:
            actions = available_actions['click']
            ac_string = "\t".join(actions)
            return f"click: [{ac_string}]"


ZeroshotThinkAgent

    def prompt_layer(self, available_actions):
        zeroshot = pre_prompt.zeroshot
        actions_prompt = f"current available action is {self.avai_action_prompt(available_actions)[-3000:]}"
        prompt = f"{zeroshot}{self.observations[self.cur_session][0]}{actions_prompt}\n\nAction:"
        if len(self.actions[self.cur_session]) > 1:
            initial_prompt = f"{zeroshot}{self.observations[self.cur_session][0]}\n\n"
            history = self.get_history()
            remain_context_space = (self.context_len - len(token_enc.encode(f"{initial_prompt}{actions_prompt}")))*3
            history = history[-int(remain_context_space):]
            prompt = f"{initial_prompt}{history}{actions_prompt}\n\nAction:"
        return prompt

    def forward(self, observation, available_actions=None):
        self.observations[self.cur_session].append(observation)
        prompt = self.prompt_layer(available_actions)
        action = self.llm_layer(prompt).lstrip()
        action = self.action_parser(action, available_actions)
        self.actions[self.cur_session].append(action)
        return action

class ZeroshotThinkAgent(BaseAgent):
    def __init__(self, llm, context_len=2000, temperature=0.9, stop=['\n']):
        super().__init__(llm, context_len)
        self.type = "ZeroshotThink_Webrun_Agent"
        self.life_label = time.time()
        self.name = f"{self.type}_{self.life_label}"
        self.temperature = temperature
        self.stop = stop

    def llm_layer(self, prompt):
        return self.llm(prompt)

    def avai_action_prompt(self, available_actions):
        if 'search' in available_actions:
            return "{search}"
        elif 'click' in available_actions:
            actions = available_actions['click']
            ac_string = "\t".join(actions)
            return f"click: [{ac_string}]"

    def prompt_layer(self, available_actions):
        zeroshot = pre_prompt.zeroshot_think
        actions_prompt = f"current available action is {self.avai_action_prompt(available_actions)[-3000:]}"
        prompt = f"{zeroshot}{self.observations[self.cur_session][0]}{actions_prompt}\n\nAction:"
        if len(self.actions[self.cur_session]) > 1:
            initial_prompt = f"{zeroshot}{self.observations[self.cur_session][0]}\n\n"
            history = self.get_history()
            remain_context_space = (self.context_len - len(token_enc.encode(initial_prompt+actions_prompt)))*3
            history = history[-int(remain_context_space):]
            prompt = f"{initial_prompt}{history}{actions_prompt}\n\nAction:"
        return prompt

    def forward(self, observation, available_actions=None):
        self.observations[self.cur_session].append(observation)
        prompt = self.prompt_layer(available_actions)
        action = self.llm_layer(prompt, temperature=self.temperature, stop=self.stop).lstrip()
        action = self.action_parser(action, available_actions)
        self.actions[self.cur_session].append(action)
        return action

class PlannerAgent(BaseAgent):
    def __init__(self, llm, context_len=2000, temperature=0.9, stop=['\n']):
        super().__init__(llm, context_len)
        self.type = "Planner_Webrun_Agent"
        self.name = f"{self.type}_{self.life_label}"
        self.temperature = temperature
        self.stop = stop
        self.max_plan_token_len = 256
        self.plan = None

    def planning(self):
        plan_prompt = f"{pre_prompt.plan}\n\nInstruction: {self.task[self.cur_session]}\nPlan:"
        self.plan = self.llm(plan_prompt, temperature=self.temperature, stop=["\n"],
                             max_tokens=self.max_plan_token_len)

    def llm_layer(self, prompt):
        return self.llm(prompt)

    def prompt_layer(self, available_actions):


PlannerAgent

    def prompt_layer(self, available_actions):
        zeroshot = pre_prompt.zeroshot_think
        actions_prompt = f"current available action is {self.avai_action_prompt(available_actions)[-3000:]}"
        prompt = f"{zeroshot}{self.observations[self.cur_session][0]}{actions_prompt}\n\nAction:"
        if len(self.actions[self.cur_session]) > 1:
            initial_prompt = f"{zeroshot}{self.observations[self.cur_session][0]}\n\n"
            history = self.get_history()
            remain_context_space = (self.context_len - len(token_enc.encode(initial_prompt+actions_prompt)))*3
            history = history[-int(remain_context_space):]
            prompt = f"{initial_prompt}{history}{actions_prompt}\n\nAction:"
        return prompt

    def forward(self, observation, available_actions=None):
        self.observations[self.cur_session].append(observation)
        prompt = self.prompt_layer(available_actions)
        action = self.llm_layer(prompt, temperature=self.temperature, stop=self.stop).lstrip()
        action = self.action_parser(action, available_actions)
        self.actions[self.cur_session].append(action)
        return action

class PlannerAgent(BaseAgent):
    def __init__(self, llm, context_len=2000, temperature=0.9, stop=['\n']):
        super().__init__(llm, context_len)
        self.type = "Planner_Webrun_Agent"
        self.name = f"{self.type}_{self.life_label}"
        self.temperature = temperature
        self.stop = stop
        self.max_plan_token_len = 256
        self.plan = None

    def planning(self):
        plan_prompt = f"{pre_prompt.plan}\n\nInstruction: {self.task[self.cur_session]}\nPlan:"
        self.plan = self.llm(plan_prompt, temperature=self.temperature, stop=["\n"],
                             max_tokens=self.max_plan_token_len)

    def llm_layer(self, prompt):
        return self.llm(prompt)

    def prompt_layer(self, available_actions):
        oneshot = pre_prompt.oneshot_plan
        prompt = f"{oneshot}\n\nInstruction: {self.task[self.cur_session]}\nPlan: {self.plan}\n\nAction:"
        if len(self.actions[self.cur_session]) > 1:
            initial_prompt = f"{oneshot}\n\nInstruction: {self.task[self.cur_session]}\nPlan: {self.plan}\n\n"
            history = self.get_history()
            remain_context_space = (self.context_len - len(token_enc.encode(initial_prompt)))*3
            history = history[-remain_context_space:]
            prompt = f"{initial_prompt}{history}Action:"
        return prompt

    def forward(self, observation, available_actions=None):
        self.observations[self.cur_session].append(observation)
        prompt = self.prompt_layer(available_actions)
        action = self.llm_layer(prompt).lstrip(' ')
        action = self.action_parser(action, available_actions)
        self.actions[self.cur_session].append(action)
        return action

class PlannerReactAgent(PlannerAgent):
    def __init__(self, llm, context_len=2000, temperature=0.9, stop=['\n']):
        super().__init__(llm, context_len, temperature, stop)
        self.type = "PlannerReact_Webrun_Agent"
        self.name = f"{self.type}_{self.life_label}"

    def planning(self):
        plan_prompt = f"{pre_prompt.plan_react}\n\nInstruction: {self.task[self.cur_session]}\nPlan:"
        self.plan = self.llm(plan_prompt, temperature=self.temperature, stop=["\n"],
                             max_tokens=self.max_plan_token_len)

    def prompt_layer(self, available_actions=None):
        oneshot = pre_prompt.oneshot_plan_react
        prompt = f"{oneshot}\n\nInstruction: {self.task[self.cur_session]}\nPlan: {self.plan}\n\nAction:"
        if len(self.actions[self.cur_session]) > 1:
            initial_prompt = f"{oneshot}\n\nInstruction: {self.task[self.cur_session]}\nPlan: {self.plan}\n\n"
            history = self.get_history()
            remain_context_space = (self.context_len - len(token_enc.encode(initial_prompt)))*3
            history = history[-remain_context_space:]


PlannerReactAgent

    def prompt_layer(self, available_actions):
        oneshot = pre_prompt.oneshot_plan
        prompt = f"{oneshot}\n\nInstruction: {self.task[self.cur_session]}\nPlan: {self.plan}\n\nAction:"
        if len(self.actions[self.cur_session]) > 1:
            initial_prompt = f"{oneshot}\n\nInstruction: {self.task[self.cur_session]}\nPlan: {self.plan}\n\n"
            history = self.get_history()
            remain_context_space = (self.context_len - len(token_enc.encode(initial_prompt)))*3
            history = history[-remain_context_space:]
            prompt = f"{initial_prompt}{history}Action:"
        return prompt

    def forward(self, observation, available_actions=None):
        self.observations[self.cur_session].append(observation)
        prompt = self.prompt_layer(available_actions)
        action = self.llm_layer(prompt).lstrip(' ')
        action = self.action_parser(action, available_actions)
        self.actions[self.cur_session].append(action)
        return action

class PlannerReactAgent(PlannerAgent):
    def __init__(self, llm, context_len=2000, temperature=0.9, stop=['\n']):
        super().__init__(llm, context_len, temperature, stop)
        self.type = "PlannerReact_Webrun_Agent"
        self.name = f"{self.type}_{self.life_label}"

    def planning(self):
        plan_prompt = f"{pre_prompt.plan_react}\n\nInstruction: {self.task[self.cur_session]}\nPlan:"
        self.plan = self.llm(plan_prompt, temperature=self.temperature, stop=["\n"],
                             max_tokens=self.max_plan_token_len)

    def prompt_layer(self, available_actions=None):
        oneshot = pre_prompt.oneshot_plan_react
        prompt = f"{oneshot}\n\nInstruction: {self.task[self.cur_session]}\nPlan: {self.plan}\n\nAction:"
        if len(self.actions[self.cur_session]) > 1:
            initial_prompt = f"{oneshot}\n\nInstruction: {self.task[self.cur_session]}\nPlan: {self.plan}\n\n"
            history = self.get_history()
            remain_context_space = (self.context_len - len(token_enc.encode(initial_prompt)))*3
            history = history[-remain_context_space:]
            prompt = f"{initial_prompt}{history}Action:"
        return prompt

    def forward(self, observation, available_actions=None):
        self.observations[self.cur_session].append(observation)
        prompt = self.prompt_layer(available_actions)
        action = self.llm_layer(prompt).lstrip(' ')
        action = self.action_parser(action, available_actions)
        self.actions[self.cur_session].append(action)
        return action


    def prompt_layer(self, available_actions):
        oneshot = pre_prompt.oneshot_plan
        prompt = f"{oneshot}\n\nInstruction: {self.task[self.cur_session]}\nPlan: {self.plan}\n\nAction:"
        if len(self.actions[self.cur_session]) > 1:
            initial_prompt = f"{oneshot}\n\nInstruction: {self.task[self.cur_session]}\nPlan: {self.plan}\n\n"
            history = self.get_history()
            remain_context_space = (self.context_len - len(token_enc.encode(initial_prompt)))*3
            history = history[-remain_context_space:]
            prompt = f"{initial_prompt}{history}Action:"
        return prompt

    def forward(self, observation, available_actions=None):
        self.observations[self.cur_session].append(observation)
        prompt = self.prompt_layer(available_actions)
        action = self.llm_layer(prompt).lstrip(' ')
        action = self.action_parser(action, available_actions)
        self.actions[self.cur_session].append(action)
        return action

class PlannerReactAgent(PlannerAgent):
    def __init__(self, llm, context_len=2000, temperature=0.9, stop=['\n']):
        super().__init__(llm, context_len, temperature, stop)
        self.type = "PlannerReact_Webrun_Agent"
        self.name = f"{self.type}_{self.life_label}"

    def planning(self):
        plan_prompt = f"{pre_prompt.plan_react}\n\nInstruction: {self.task[self.cur_session]}\nPlan:"
        self.plan = self.llm(plan_prompt, temperature=self.temperature, stop=["\n"],
                             max_tokens=self.max_plan_token_len)

    def prompt_layer(self, available_actions=None):
        oneshot = pre_prompt.oneshot_plan_react
        prompt = f"{oneshot}\n\nInstruction: {self.task[self.cur_session]}\nPlan: {self.plan}\n\nAction:"
        if len(self.actions[self.cur_session]) > 1:
            initial_prompt = f"{oneshot}\n\nInstruction: {self.task[self.cur_session]}\nPlan: {self.plan}\n\n"
            history = self.get_history()
            remain_context_space = (self.context_len - len(token_enc.encode(initial_prompt)))*3
            history = history[-remain_context_space:]
            prompt = f"{initial_prompt}{history}Action:"
        return prompt

    def forward(self, observation, available_actions=None):
        self.observations[self.cur_session].append(observation)
        prompt = self.prompt_layer(available_actions)


import os
import tiktoken
import web_run.pre_prompt as pre_prompt
from web_run.utils import get_query
from web_run.llms import token_enc

class BaseAgent(object):
    def __init__(self, llm, context_len=2000):
        self.type = "Base_Webrun_Agent"
        self.life_label = time.time()
        self.name = f"{self.type}_{self.life_label}"
        self.task = {}
        self.actions = {}
        self.observations = {}
        self.item_recall = {}
        self.llm = llm
        self.context_len = context_len
        self.cur_session = 0

    def new_session(self, idx, task):
        self.cur_session = idx
        self.task[idx] = task
        self.actions[idx] = ['reset']
        self.observations[idx] = []
        self.item_recall[idx] = []

    def llm_layer(self, prompt):
        return self.llm(prompt)

    def get_history(self, session=None):
        if not session:
            session = self.cur_session
        history = ""
        for idx in range(1, len(self.actions[session])):
            history += f"Action: {self.actions[session][idx]}\n"
            history += f"Observation: {self.observations[session][idx]}\n\n"
        return history

    def save(self, path):
        file_name = os.path.join(path, self.name+'_'+str(self.life_label))
        with open(file_name, 'a') as f:
            f.write(f"session_idx:{self.cur_session}\n")
            history = self.get_history(self.cur_session)
            f.write(history)
            f.write('\n')


        action = self.llm_layer(prompt, temperature=self.temperature, stop=self.stop).lstrip()
        action = self.action_parser(action, available_actions)
        self.actions[self.cur_session].append(action)
        return action

class PlannerAgent(BaseAgent):
    def __init__(self, llm, context_len=2000, temperature=0.9, stop=['\n']):
        super().__init__(llm, context_len)
        self.type = "Planner_Webrun_Agent"
        self.name = f"{self.type}_{self.life_label}"
        self.temperature = temperature
        self.stop = stop
        self.max_plan_token_len = 256
        self.plan = None

    def planning(self):
        plan_prompt = f"{pre_prompt.plan}\n\nInstruction: {self.task[self.cur_session]}\nPlan:"
        self.plan = self.llm(plan_prompt, temperature=self.temperature, stop=["\n"],
                             max_tokens=self.max_plan_token_len)

    def llm_layer(self, prompt):
        return self.llm(prompt)

    def prompt_layer(self, available_actions):
        oneshot = pre_prompt.oneshot_plan
        prompt = f"{oneshot}\n\nInstruction: {self.task[self.cur_session]}\nPlan: {self.plan}\n\nAction:"
        if len(self.actions[self.cur_session]) > 1:
            initial_prompt = f"{oneshot}\n\nInstruction: {self.task[self.cur_session]}\nPlan: {self.plan}\n\n"
            history = self.get_history()
            remain_context_space = (self.context_len - len(token_enc.encode(initial_prompt)))*3
            history = history[-remain_context_space:]
            prompt = f"{initial_prompt}{history}Action:"
        return prompt

    def forward(self, observation, available_actions=None):
        self.observations[self.cur_session].append(observation)
        prompt = self.prompt_layer(available_actions)
        action = self.llm_layer(prompt).lstrip(' ')
        action = self.action_parser(action, available_actions)
        self.actions[self.cur_session].append(action)
        return action


        self.life_label = time.time()
        self.name = f"{self.type}_{self.life_label}"
        self.task = {}
        self.actions = {}
        self.observations = {}
        self.item_recall = {}
        self.llm = llm
        self.context_len = context_len
        self.cur_session = 0

    def new_session(self, idx, task):
        self.cur_session = idx
        self.task[idx] = task
        self.actions[idx] = ['reset']
        self.observations[idx] = []
        self.item_recall[idx] = []

    def llm_layer(self, prompt):
        return self.llm(prompt)

    def get_history(self, session=None):
        if not session:
            session = self.cur_session
        history = ""
        for idx in range(1, len(self.actions[session])):
            history += f"Action: {self.actions[session][idx]}\n"
            history += f"Observation: {self.observations[session][idx]}\n\n"
        return history

    def save(self, path):
        file_name = os.path.join(path, self.name+'_'+str(self.life_label))
        with open(file_name, 'a') as f:
            f.write(f"session_idx:{self.cur_session}\n")
            history = self.get_history(self.cur_session)
            f.write(history)
            f.write('\n')

    def action_parser(self, text, available_actions):
        nor_text = text.strip().lower()
        if nor_text.startswith('search'):
            query = get_query(nor_text)
            return f"search[{query}]"
        if nor_text.startswith('click'):
            if 'click' in available_actions:
                for a in available_actions['click']:
                    if a.lower() in nor_text:
                        return f"click[{a}]"
        return text


save

    def new_session(self, idx, task):
        self.cur_session = idx
        self.task[idx] = task
        self.actions[idx] = ['reset']
        self.observations[idx] = []
        self.item_recall[idx] = []

    def llm_layer(self, prompt):
        return self.llm(prompt)

    def get_history(self, session=None):
        if not session:
            session = self.cur_session
        history = ""
        for idx in range(1, len(self.actions[session])):
            history += f"Action: {self.actions[session][idx]}\n"
            history += f"Observation: {self.observations[session][idx]}\n\n"
        return history

    def save(self, path):
        file_name = os.path.join(path, self.name+'_'+str(self.life_label))
        with open(file_name, 'a') as f:
            f.write(f"session_idx:{self.cur_session}\n")
            history = self.get_history(self.cur_session)
            f.write(history)
            f.write('\n')

    def action_parser(self, text, available_actions):
        nor_text = text.strip().lower()
        if nor_text.startswith('search'):
            query = get_query(nor_text)
            return f"search[{query}]"
        if nor_text.startswith('click'):
            if 'click' in available_actions:
                for a in available_actions['click']:
                    if a.lower() in nor_text:
                        return f"click[{a}]"
        return text

    def prompt_layer(self):
        raise NotImplementedError

    def forward(self, observation, available_actions=None):
        raise NotImplementedError


    def llm_layer(self, prompt):
        return self.llm(prompt)

    def get_history(self, session=None):
        if not session:
            session = self.cur_session
        history = ""
        for idx in range(1, len(self.actions[session])):
            history += f"Action: {self.actions[session][idx]}\n"
            history += f"Observation: {self.observations[session][idx]}\n\n"
        return history

    def save(self, path):
        file_name = os.path.join(path, self.name+'_'+str(self.life_label))
        with open(file_name, 'a') as f:
            f.write(f"session_idx:{self.cur_session}\n")
            history = self.get_history(self.cur_session)
            f.write(history)
            f.write('\n')

    def action_parser(self, text, available_actions):
        nor_text = text.strip().lower()
        if nor_text.startswith('search'):
            query = get_query(nor_text)
            return f"search[{query}]"
        if nor_text.startswith('click'):
            if 'click' in available_actions:
                for a in available_actions['click']:
                    if a.lower() in nor_text:
                        return f"click[{a}]"
        return text

    def prompt_layer(self):
        raise NotImplementedError

    def forward(self, observation, available_actions=None):
        raise NotImplementedError

class ReactAgent(BaseAgent):
    def __init__(self, llm, context_len=2000):
        super().__init__(llm, context_len)
        self.type = "React_Webrun_Agent"
        self.name = f"{self.type}_{self.life_label}"

    def prompt_layer(self):
        one_shot = pre_prompt.oneshot
        prompt = f"{one_shot}{self.observations[self.cur_session][0]}\n\nAction:"
        if len(self.actions[self.cur_session]) > 1:
            initial_prompt = f"{one_shot}{self.observations[self.cur_session][0]}\n\n"
            history = self.get_history()


    def forward(self, observation, available_actions=None):
        self.observations[self.cur_session].append(observation)
        prompt = self.prompt_layer(available_actions)
        action = self.llm_layer(prompt).lstrip(' ')
        action = self.action_parser(action, available_actions)
        self.actions[self.cur_session].append(action)
        return action

class PlannerReactAgent(PlannerAgent):
    def __init__(self, llm, context_len=2000, temperature=0.9, stop=['\n']):
        super().__init__(llm, context_len, temperature, stop)
        self.type = "PlannerReact_Webrun_Agent"
        self.name = f"{self.type}_{self.life_label}"

    def planning(self):
        plan_prompt = f"{pre_prompt.plan_react}\n\nInstruction: {self.task[self.cur_session]}\nPlan:"
        self.plan = self.llm(plan_prompt, temperature=self.temperature, stop=["\n"],
                             max_tokens=self.max_plan_token_len)

    def prompt_layer(self, available_actions=None):
        oneshot = pre_prompt.oneshot_plan_react
        prompt = f"{oneshot}\n\nInstruction: {self.task[self.cur_session]}\nPlan: {self.plan}\n\nAction:"
        if len(self.actions[self.cur_session]) > 1:
            initial_prompt = f"{oneshot}\n\nInstruction: {self.task[self.cur_session]}\nPlan: {self.plan}\n\n"
            history = self.get_history()
            remain_context_space = (self.context_len - len(token_enc.encode(initial_prompt)))*3
            history = history[-remain_context_space:]
            prompt = f"{initial_prompt}{history}Action:"
        return prompt

    def forward(self, observation, available_actions=None):
        self.observations[self.cur_session].append(observation)
        prompt = self.prompt_layer(available_actions)
        action = self.llm_layer(prompt).lstrip(' ')
        action = self.action_parser(action, available_actions)
        self.actions[self.cur_session].append(action)
        return action


forward

        super().__init__(llm, context_len, temperature, stop)
        self.type = "PlannerReact_Webrun_Agent"
        self.name = f"{self.type}_{self.life_label}"

    def planning(self):
        plan_prompt = f"{pre_prompt.plan_react}\n\nInstruction: {self.task[self.cur_session]}\nPlan:"
        self.plan = self.llm(plan_prompt, temperature=self.temperature, stop=["\n"],
                             max_tokens=self.max_plan_token_len)

    def prompt_layer(self, available_actions=None):
        oneshot = pre_prompt.oneshot_plan_react
        prompt = f"{oneshot}\n\nInstruction: {self.task[self.cur_session]}\nPlan: {self.plan}\n\nAction:"
        if len(self.actions[self.cur_session]) > 1:
            initial_prompt = f"{oneshot}\n\nInstruction: {self.task[self.cur_session]}\nPlan: {self.plan}\n\n"
            history = self.get_history()
            remain_context_space = (self.context_len - len(token_enc.encode(initial_prompt)))*3
            history = history[-remain_context_space:]
            prompt = f"{initial_prompt}{history}Action:"
        return prompt

    def forward(self, observation, available_actions=None):
        self.observations[self.cur_session].append(observation)
        prompt = self.prompt_layer(available_actions)
        action = self.llm_layer(prompt).lstrip(' ')
        action = self.action_parser(action, available_actions)
        self.actions[self.cur_session].append(action)
        return action


    def forward(self, observation, available_actions=None):
        self.observations[self.cur_session].append(observation)
        prompt = self.prompt_layer(available_actions)
        action = self.llm_layer(prompt).lstrip()
        action = self.action_parser(action, available_actions)
        self.actions[self.cur_session].append(action)
        return action

class ZeroshotThinkAgent(BaseAgent):
    def __init__(self, llm, context_len=2000, temperature=0.9, stop=['\n']):
        super().__init__(llm, context_len)
        self.type = "ZeroshotThink_Webrun_Agent"
        self.life_label = time.time()
        self.name = f"{self.type}_{self.life_label}"
        self.temperature = temperature
        self.stop = stop

    def llm_layer(self, prompt):
        return self.llm(prompt)

    def avai_action_prompt(self, available_actions):
        if 'search' in available_actions:
            return "{search}"
        elif 'click' in available_actions:
            actions = available_actions['click']
            ac_string = "\t".join(actions)
            return f"click: [{ac_string}]"

    def prompt_layer(self, available_actions):
        zeroshot = pre_prompt.zeroshot_think
        actions_prompt = f"current available action is {self.avai_action_prompt(available_actions)[-3000:]}"
        prompt = f"{zeroshot}{self.observations[self.cur_session][0]}{actions_prompt}\n\nAction:"
        if len(self.actions[self.cur_session]) > 1:
            initial_prompt = f"{zeroshot}{self.observations[self.cur_session][0]}\n\n"
            history = self.get_history()
            remain_context_space = (self.context_len - len(token_enc.encode(initial_prompt+actions_prompt)))*3
            history = history[-int(remain_context_space):]
            prompt = f"{initial_prompt}{history}{actions_prompt}\n\nAction:"
        return prompt

    def forward(self, observation, available_actions=None):
        self.observations[self.cur_session].append(observation)
        prompt = self.prompt_layer(available_actions)
        action = self.llm_layer(prompt, temperature=self.temperature, stop=self.stop).lstrip()
        action = self.action_parser(action, available_actions)
        self.actions[self.cur_session].append(action)
        return action


planning

            history = self.get_history()
            remain_context_space = (self.context_len - len(token_enc.encode(initial_prompt)))*3
            history = history[-remain_context_space:]
            prompt = f"{initial_prompt}{history}Action:"
        return prompt

    def forward(self, observation, available_actions=None):
        self.observations[self.cur_session].append(observation)
        prompt = self.prompt_layer(available_actions)
        action = self.llm_layer(prompt).lstrip(' ')
        action = self.action_parser(action, available_actions)
        self.actions[self.cur_session].append(action)
        return action

class PlannerReactAgent(PlannerAgent):
    def __init__(self, llm, context_len=2000, temperature=0.9, stop=['\n']):
        super().__init__(llm, context_len, temperature, stop)
        self.type = "PlannerReact_Webrun_Agent"
        self.name = f"{self.type}_{self.life_label}"

    def planning(self):
        plan_prompt = f"{pre_prompt.plan_react}\n\nInstruction: {self.task[self.cur_session]}\nPlan:"
        self.plan = self.llm(plan_prompt, temperature=self.temperature, stop=["\n"],
                             max_tokens=self.max_plan_token_len)

    def prompt_layer(self, available_actions=None):
        oneshot = pre_prompt.oneshot_plan_react
        prompt = f"{oneshot}\n\nInstruction: {self.task[self.cur_session]}\nPlan: {self.plan}\n\nAction:"
        if len(self.actions[self.cur_session]) > 1:
            initial_prompt = f"{oneshot}\n\nInstruction: {self.task[self.cur_session]}\nPlan: {self.plan}\n\n"
            history = self.get_history()
            remain_context_space = (self.context_len - len(token_enc.encode(initial_prompt)))*3
            history = history[-remain_context_space:]
            prompt = f"{initial_prompt}{history}Action:"
        return prompt

    def forward(self, observation, available_actions=None):
        self.observations[self.cur_session].append(observation)
        prompt = self.prompt_layer(available_actions)
        action = self.llm_layer(prompt).lstrip(' ')
        action = self.action_parser(action, available_actions)
        self.actions[self.cur_session].append(action)
        return action


import requests
from bs4 import BeautifulSoup
from bs4.element import Comment

WEBSHOP_URL = "http://127.0.0.1:3000"
ACTION_TO_TEMPLATE = {
    'Description': 'description_page.html',
    'Features': 'features_page.html',
    'Reviews': 'review_page.html',
    'Attributes': 'attributes_page.html',
}
MAX_PRO_OB = 8

def clean_str(p):
  return p.encode().decode("unicode-escape").encode("latin1").decode("utf-8")

def tag_visible(element):
    ignore = {'style', 'script', 'head', 'title', 'meta', '[document]'}
    return (
        element.parent.name not in ignore and not isinstance(element, Comment)
    )

def webshop_text(session, page_type, query_string='', page_num=1, asin='', options={}, subpage='', **kwargs):
    if page_type == 'init':
      url = (
          f'{WEBSHOP_URL}/{session}'
      )
    if page_type == 'search':
      url = (
          f'{WEBSHOP_URL}/search_results/{session}/'
          f'{query_string}/{page_num}'
      )
    elif page_type == 'item':
      url = (
          f'{WEBSHOP_URL}/item_page/{session}/'
          f'{asin}/{query_string}/{page_num}/{options}'
      )
    elif page_type == 'item_sub':
      url = (
          f'{WEBSHOP_URL}/item_sub_page/{session}/'
          f'{asin}/{query_string}/{page_num}/{subpage}/{options}'
      )
    elif page_type == 'end':
      url = (
          f'{WEBSHOP_URL}/done/{session}/'
          f'{asin}/{options}'
      )
    # print(url)
    html = requests.get(url).text
    html_obj = BeautifulSoup(html, 'html.parser')
    texts = html_obj.findAll(text=True)
    visible_texts = list(filter(tag_visible, texts))
    # visible_texts = [str(text).strip().strip('\\n') for text in visible_texts]
    # if page_type == 'end': import pdb; pdb.set_trace()
    if False:
        # For `simple` mode, return just [SEP] separators
        return ' [SEP] '.join(t.strip() for t in visible_texts if t != '\n')
    else:
        # Otherwise, return an observation with tags mapped to specific, unique separators
        observation = ''
        option_type = ''
        options = {}
        asins = []
        cnt = 0
        prod_cnt = 0
        just_prod = 0
        clickable = []
        for t in visible_texts:
            if t == '\n': continue
            if t.replace('\n', '').replace('\\n', '').replace(' ', '') == '': continue
            # if t.startswith('Instruction:') and page_type != 'init': continue
            # print(t.parent.name, t)
            if t.parent.name == 'button':  # button
                processed_t = f'\n[{t}] '
                clickable.append(t)
            elif t.parent.name == 'label':  # options
                if f"'{t}'" in url:
                    processed_t = f'[[{t}]]'
                    # observation = f'You have clicked {t}.\n' + observation
                else:
                    processed_t = f'[{t}]'
                options[str(t)] = option_type
                # options[option_type] = options.get(option_type, []) + [str(t)]
            elif t.parent.get('class') == ["product-link"]: # product asins
                processed_t = f'\n[{t}] '
                if prod_cnt >= MAX_PRO_OB:
                  processed_t = ''
                prod_cnt += 1
                asins.append(str(t))
                just_prod = 0
            else: # regular, unclickable text
                processed_t =  '\n' + str(t) + ' '
                if cnt < 2 and page_type != 'init': processed_t = ''
                if just_prod <= 2 and prod_cnt > MAX_PRO_OB: processed_t = ''
                option_type = str(t)
                cnt += 1
            just_prod += 1
            observation += processed_t
        info = {}
        if options:
          info['option_types'] = options
        if asins:
          info['asins'] = asins
        if 'Your score (min 0.0, max 1.0)' in visible_texts:
          idx = visible_texts.index('Your score (min 0.0, max 1.0)')
          info['reward'] = float(visible_texts[idx + 1])
          observation = 'Your score (min 0.0, max 1.0): ' + (visible_texts[idx + 1])
        clickable.extend(asins)
        # merging option buttons
        clickable.extend(options)
        return clean_str(observation), info, clickable

class webshopEnv:
  def __init__(self):
    self.sessions = {}

  def step(self, session, action):
    done = False
    observation_ = None
    if action == 'reset':
      self.sessions[session] = {'session': session, 'page_type': 'init'}
    elif action.startswith('think['):
      observation = 'OK.'
    elif action.startswith('search['):
      assert self.sessions[session]['page_type'] == 'init'
      query = action[7:-1]
      self.sessions[session] = {'session': session, 'page_type': 'search',
                                'query_string': query, 'page_num': 1}
    elif action.startswith('click['):
      button = action[6:-1]
      if button == 'Buy Now':
        assert self.sessions[session]['page_type'] == 'item'
        self.sessions[session]['page_type'] = 'end'
        done = True
      elif button == 'Back to Search':
        assert self.sessions[session]['page_type'] in ['search', 'item_sub', 'item']
        self.sessions[session] = {'session': session, 'page_type': 'init'}
      elif button == 'Next >':
        assert False # ad hoc page limitation
        assert self.sessions[session]['page_type'] == 'search'
        self.sessions[session]['page_num'] += 1
      elif button == '< Prev':
        assert self.sessions[session]['page_type'] in ['search', 'item_sub', 'item']
        if self.sessions[session]['page_type'] == 'search':
          assert False
          self.sessions[session]['page_num'] -= 1
        elif self.sessions[session]['page_type'] == 'item_sub':
          self.sessions[session]['page_type'] = 'item'
        elif self.sessions[session]['page_type'] == 'item':
          self.sessions[session]['page_type'] = 'search'
          self.sessions[session]['options'] = {}
      elif button in ACTION_TO_TEMPLATE:
        assert self.sessions[session]['page_type'] == 'item'
        self.sessions[session]['page_type'] = 'item_sub'
        self.sessions[session]['subpage'] = button
      else:
        if self.sessions[session]['page_type'] == 'search':
          assert button in self.sessions[session].get('asins', [])  # must be asins
          self.sessions[session]['page_type'] = 'item'
          self.sessions[session]['asin'] = button
        elif self.sessions[session]['page_type'] == 'item':
          assert 'option_types' in self.sessions[session]
          assert button in self.sessions[session]['option_types'], (button, self.sessions[session]['option_types'])  # must be options
          option_type = self.sessions[session]['option_types'][button]
          if not 'options' in self.sessions[session]:
            self.sessions[session]['options'] = {}
          self.sessions[session]['options'][option_type] = button
          observation_ = f'You have clicked {button}.'
    else:
      assert False
    observation, info, clickable = webshop_text(**self.sessions[session])
    if observation_:
      observation = observation_
    self.sessions[session].update(info)
    reward = info.get('reward', 0.0)
    asins = info.get('asins', [])
    return observation, reward, done, asins, clickable


import requests
from bs4 import BeautifulSoup
from bs4.element import Comment

WEBSHOP_URL = "http://127.0.0.1:3000"
ACTION_TO_TEMPLATE = {
    'Description': 'description_page.html',
    'Features': 'features_page.html',
    'Reviews': 'review_page.html',
    'Attributes': 'attributes_page.html',
}
MAX_PRO_OB = 8

def clean_str(p):
  return p.encode().decode("unicode-escape").encode("latin1").decode("utf-8")

def tag_visible(element):
    ignore = {'style', 'script', 'head', 'title', 'meta', '[document]'}
    return (
        element.parent.name not in ignore and not isinstance(element, Comment)
    )

def webshop_text(session, page_type, query_string='', page_num=1, asin='', options={}, subpage='', **kwargs):
    if page_type == 'init':
      url = (
          f'{WEBSHOP_URL}/{session}'
      )
    if page_type == 'search':
      url = (
          f'{WEBSHOP_URL}/search_results/{session}/'
          f'{query_string}/{page_num}'
      )
    elif page_type == 'item':
      url = (


import requests
from bs4 import BeautifulSoup
from bs4.element import Comment

WEBSHOP_URL = "http://127.0.0.1:3000"
ACTION_TO_TEMPLATE = {
    'Description': 'description_page.html',
    'Features': 'features_page.html',
    'Reviews': 'review_page.html',
    'Attributes': 'attributes_page.html',
}
MAX_PRO_OB = 8

def clean_str(p):
  return p.encode().decode("unicode-escape").encode("latin1").decode("utf-8")

def tag_visible(element):
    ignore = {'style', 'script', 'head', 'title', 'meta', '[document]'}
    return (
        element.parent.name not in ignore and not isinstance(element, Comment)
    )

def webshop_text(session, page_type, query_string='', page_num=1, asin='', options={}, subpage='', **kwargs):
    if page_type == 'init':
      url = (
          f'{WEBSHOP_URL}/{session}'
      )
    if page_type == 'search':
      url = (
          f'{WEBSHOP_URL}/search_results/{session}/'
          f'{query_string}/{page_num}'
      )
    elif page_type == 'item':
      url = (
          f'{WEBSHOP_URL}/item_page/{session}/'
          f'{asin}/{query_string}/{page_num}/{options}'
      )
    elif page_type == 'item_sub':
      url = (
          f'{WEBSHOP_URL}/item_sub_page/{session}/'
          f'{asin}/{query_string}/{page_num}/{subpage}/{options}'


WEBSHOP_URL = "http://127.0.0.1:3000"
ACTION_TO_TEMPLATE = {
    'Description': 'description_page.html',
    'Features': 'features_page.html',
    'Reviews': 'review_page.html',
    'Attributes': 'attributes_page.html',
}
MAX_PRO_OB = 8

def clean_str(p):
  return p.encode().decode("unicode-escape").encode("latin1").decode("utf-8")

def tag_visible(element):
    ignore = {'style', 'script', 'head', 'title', 'meta', '[document]'}
    return (
        element.parent.name not in ignore and not isinstance(element, Comment)
    )

def webshop_text(session, page_type, query_string='', page_num=1, asin='', options={}, subpage='', **kwargs):
    if page_type == 'init':
      url = (
          f'{WEBSHOP_URL}/{session}'
      )
    if page_type == 'search':
      url = (
          f'{WEBSHOP_URL}/search_results/{session}/'
          f'{query_string}/{page_num}'
      )
    elif page_type == 'item':
      url = (
          f'{WEBSHOP_URL}/item_page/{session}/'
          f'{asin}/{query_string}/{page_num}/{options}'
      )
    elif page_type == 'item_sub':
      url = (
          f'{WEBSHOP_URL}/item_sub_page/{session}/'
          f'{asin}/{query_string}/{page_num}/{subpage}/{options}'
      )
    elif page_type == 'end':
      url = (
          f'{WEBSHOP_URL}/done/{session}/'
          f'{asin}/{options}'
      )
    # print(url)
    html = requests.get(url).text
    html_obj = BeautifulSoup(html, 'html.parser')
    texts = html_obj.findAll(text=True)
    visible_texts = list(filter(tag_visible, texts))
    # visible_texts = [str(text).strip().strip('\\n') for text in visible_texts]
    # if page_type == 'end': import pdb; pdb.set_trace()
    if False:
        # For `simple` mode, return just [SEP] separators
        return ' [SEP] '.join(t.strip() for t in visible_texts if t != '\n')
    else:
        # Otherwise, return an observation with tags mapped to specific, unique separators
        observation = ''
        option_type = ''
        options = {}
        asins = []
        cnt = 0
        prod_cnt = 0
        just_prod = 0
        clickable = []
        for t in visible_texts:
            if t == '\n': continue
            if t.replace('\n', '').replace('\\n', '').replace(' ', '') == '': continue
            # if t.startswith('Instruction:') and page_type != 'init': continue
            # print(t.parent.name, t)
            if t.parent.name == 'button':  # button
                processed_t = f'\n[{t}] '
                clickable.append(t)
            elif t.parent.name == 'label':  # options
                if f"'{t}'" in url:
                    processed_t = f'[[{t}]]'
                    # observation = f'You have clicked {t}.\n' + observation
                else:
                    processed_t = f'[{t}]'
                options[str(t)] = option_type
                # options[option_type] = options.get(option_type, []) + [str(t)]
            elif t.parent.get('class') == ["product-link"]: # product asins
                processed_t = f'\n[{t}] '
                if prod_cnt >= MAX_PRO_OB:
                  processed_t = ''
                prod_cnt += 1
                asins.append(str(t))
                just_prod = 0
            else: # regular, unclickable text
                processed_t =  '\n' + str(t) + ' '
                if cnt < 2 and page_type != 'init': processed_t = ''
                if just_prod <= 2 and prod_cnt > MAX_PRO_OB: processed_t = ''
                option_type = str(t)
                cnt += 1
            just_prod += 1
            observation += processed_t
        info = {}
        if options:
          info['option_types'] = options
        if asins:
          info['asins'] = asins
        if 'Your score (min 0.0, max 1.0)' in visible_texts:
          idx = visible_texts.index('Your score (min 0.0, max 1.0)')
          info['reward'] = float(visible_texts[idx + 1])
          observation = 'Your score (min 0.0, max 1.0): ' + (visible_texts[idx + 1])
        clickable.extend(asins)
        # merging option buttons
        clickable.extend(options)
        return clean_str(observation), info, clickable

class webshopEnv:
  def __init__(self):
    self.sessions = {}

  def step(self, session, action):
    done = False
    observation_ = None
    if action == 'reset':
      self.sessions[session] = {'session': session, 'page_type': 'init'}
    elif action.startswith('think['):
      observation = 'OK.'
    elif action.startswith('search['):
      assert self.sessions[session]['page_type'] == 'init'
      query = action[7:-1]
      self.sessions[session] = {'session': session, 'page_type': 'search',
                                'query_string': query, 'page_num': 1}
    elif action.startswith('click['):
      button = action[6:-1]
      if button == 'Buy Now':


webshopEnv

                if cnt < 2 and page_type != 'init': processed_t = ''
                if just_prod <= 2 and prod_cnt > MAX_PRO_OB: processed_t = ''
                option_type = str(t)
                cnt += 1
            just_prod += 1
            observation += processed_t
        info = {}
        if options:
          info['option_types'] = options
        if asins:
          info['asins'] = asins
        if 'Your score (min 0.0, max 1.0)' in visible_texts:
          idx = visible_texts.index('Your score (min 0.0, max 1.0)')
          info['reward'] = float(visible_texts[idx + 1])
          observation = 'Your score (min 0.0, max 1.0): ' + (visible_texts[idx + 1])
        clickable.extend(asins)
        # merging option buttons
        clickable.extend(options)
        return clean_str(observation), info, clickable

class webshopEnv:
  def __init__(self):
    self.sessions = {}

  def step(self, session, action):
    done = False
    observation_ = None
    if action == 'reset':
      self.sessions[session] = {'session': session, 'page_type': 'init'}
    elif action.startswith('think['):
      observation = 'OK.'
    elif action.startswith('search['):
      assert self.sessions[session]['page_type'] == 'init'
      query = action[7:-1]
      self.sessions[session] = {'session': session, 'page_type': 'search',
                                'query_string': query, 'page_num': 1}
    elif action.startswith('click['):
      button = action[6:-1]
      if button == 'Buy Now':
        assert self.sessions[session]['page_type'] == 'item'
        self.sessions[session]['page_type'] = 'end'
        done = True
      elif button == 'Back to Search':
        assert self.sessions[session]['page_type'] in ['search', 'item_sub', 'item']
        self.sessions[session] = {'session': session, 'page_type': 'init'}
      elif button == 'Next >':
        assert False # ad hoc page limitation
        assert self.sessions[session]['page_type'] == 'search'
        self.sessions[session]['page_num'] += 1
      elif button == '< Prev':
        assert self.sessions[session]['page_type'] in ['search', 'item_sub', 'item']
        if self.sessions[session]['page_type'] == 'search':
          assert False
          self.sessions[session]['page_num'] -= 1
        elif self.sessions[session]['page_type'] == 'item_sub':
          self.sessions[session]['page_type'] = 'item'
        elif self.sessions[session]['page_type'] == 'item':
          self.sessions[session]['page_type'] = 'search'
          self.sessions[session]['options'] = {}
      elif button in ACTION_TO_TEMPLATE:
        assert self.sessions[session]['page_type'] == 'item'
        self.sessions[session]['page_type'] = 'item_sub'
        self.sessions[session]['subpage'] = button
      else:
        if self.sessions[session]['page_type'] == 'search':
          assert button in self.sessions[session].get('asins', [])  # must be asins
          self.sessions[session]['page_type'] = 'item'
          self.sessions[session]['asin'] = button
        elif self.sessions[session]['page_type'] == 'item':
          assert 'option_types' in self.sessions[session]
          assert button in self.sessions[session]['option_types'], (button, self.sessions[session]['option_types'])  # must be options
          option_type = self.sessions[session]['option_types'][button]
          if not 'options' in self.sessions[session]:
            self.sessions[session]['options'] = {}
          self.sessions[session]['options'][option_type] = button
          observation_ = f'You have clicked {button}.'
    else:
      assert False
    observation, info, clickable = webshop_text(**self.sessions[session])
    if observation_:
      observation = observation_
    self.sessions[session].update(info)
    reward = info.get('reward', 0.0)
    asins = info.get('asins', [])
    return observation, reward, done, asins, clickable


                if just_prod <= 2 and prod_cnt > MAX_PRO_OB: processed_t = ''
                option_type = str(t)
                cnt += 1
            just_prod += 1
            observation += processed_t
        info = {}
        if options:
          info['option_types'] = options
        if asins:
          info['asins'] = asins
        if 'Your score (min 0.0, max 1.0)' in visible_texts:
          idx = visible_texts.index('Your score (min 0.0, max 1.0)')
          info['reward'] = float(visible_texts[idx + 1])
          observation = 'Your score (min 0.0, max 1.0): ' + (visible_texts[idx + 1])
        clickable.extend(asins)
        # merging option buttons
        clickable.extend(options)
        return clean_str(observation), info, clickable

class webshopEnv:
  def __init__(self):
    self.sessions = {}

  def step(self, session, action):
    done = False
    observation_ = None
    if action == 'reset':
      self.sessions[session] = {'session': session, 'page_type': 'init'}
    elif action.startswith('think['):
      observation = 'OK.'
    elif action.startswith('search['):
      assert self.sessions[session]['page_type'] == 'init'
      query = action[7:-1]
      self.sessions[session] = {'session': session, 'page_type': 'search',
                                'query_string': query, 'page_num': 1}
    elif action.startswith('click['):
      button = action[6:-1]
      if button == 'Buy Now':
        assert self.sessions[session]['page_type'] == 'item'
        self.sessions[session]['page_type'] = 'end'
        done = True
      elif button == 'Back to Search':


step

            just_prod += 1
            observation += processed_t
        info = {}
        if options:
          info['option_types'] = options
        if asins:
          info['asins'] = asins
        if 'Your score (min 0.0, max 1.0)' in visible_texts:
          idx = visible_texts.index('Your score (min 0.0, max 1.0)')
          info['reward'] = float(visible_texts[idx + 1])
          observation = 'Your score (min 0.0, max 1.0): ' + (visible_texts[idx + 1])
        clickable.extend(asins)
        # merging option buttons
        clickable.extend(options)
        return clean_str(observation), info, clickable

class webshopEnv:
  def __init__(self):
    self.sessions = {}

  def step(self, session, action):
    done = False
    observation_ = None
    if action == 'reset':
      self.sessions[session] = {'session': session, 'page_type': 'init'}
    elif action.startswith('think['):
      observation = 'OK.'
    elif action.startswith('search['):
      assert self.sessions[session]['page_type'] == 'init'
      query = action[7:-1]
      self.sessions[session] = {'session': session, 'page_type': 'search',
                                'query_string': query, 'page_num': 1}
    elif action.startswith('click['):
      button = action[6:-1]
      if button == 'Buy Now':
        assert self.sessions[session]['page_type'] == 'item'
        self.sessions[session]['page_type'] = 'end'
        done = True
      elif button == 'Back to Search':
        assert self.sessions[session]['page_type'] in ['search', 'item_sub', 'item']
        self.sessions[session] = {'session': session, 'page_type': 'init'}
      elif button == 'Next >':
        assert False # ad hoc page limitation
        assert self.sessions[session]['page_type'] == 'search'
        self.sessions[session]['page_num'] += 1
      elif button == '< Prev':
        assert self.sessions[session]['page_type'] in ['search', 'item_sub', 'item']
        if self.sessions[session]['page_type'] == 'search':
          assert False
          self.sessions[session]['page_num'] -= 1
        elif self.sessions[session]['page_type'] == 'item_sub':
          self.sessions[session]['page_type'] = 'item'
        elif self.sessions[session]['page_type'] == 'item':
          self.sessions[session]['page_type'] = 'search'
          self.sessions[session]['options'] = {}
      elif button in ACTION_TO_TEMPLATE:
        assert self.sessions[session]['page_type'] == 'item'
        self.sessions[session]['page_type'] = 'item_sub'
        self.sessions[session]['subpage'] = button
      else:
        if self.sessions[session]['page_type'] == 'search':
          assert button in self.sessions[session].get('asins', [])  # must be asins
          self.sessions[session]['page_type'] = 'item'
          self.sessions[session]['asin'] = button
        elif self.sessions[session]['page_type'] == 'item':
          assert 'option_types' in self.sessions[session]
          assert button in self.sessions[session]['option_types'], (button, self.sessions[session]['option_types'])  # must be options
          option_type = self.sessions[session]['option_types'][button]
          if not 'options' in self.sessions[session]:
            self.sessions[session]['options'] = {}
          self.sessions[session]['options'][option_type] = button
          observation_ = f'You have clicked {button}.'
    else:
      assert False
    observation, info, clickable = webshop_text(**self.sessions[session])
    if observation_:
      observation = observation_
    self.sessions[session].update(info)
    reward = info.get('reward', 0.0)
    asins = info.get('asins', [])
    return observation, reward, done, asins, clickable


"""
 Copyright (c) 2023, salesforce.com, inc.
 All rights reserved.
 SPDX-License-Identifier: Apache License 2.0
 For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0
"""

import json
import re

def obser_parser(observation, instruction_text):
    obs = observation.encode().decode("unicode-escape").encode("latin1").decode("utf-8")
    # obs = obs.replace("[SEP]",'|')
    obs = obs.replace("[button]","[")
    obs = obs.replace("[button_]","]")
    if obs.startswith('Instruction:'):
        obs = obs.replace(instruction_text,"")
        obs = obs.replace('Instruction:',"")
    if obs.startswith('You have clicked'):
        obs = obs.split('\n')[0]
    obs = obs.lstrip()
    return obs

def instruction_parser(ins):
    ins = ins.encode().decode("unicode-escape").encode("latin1").decode("utf-8")
    ins = ins[13:].lstrip()
    return ins

def get_instruction(obs):
    obs = obs.split('\n')
    for idx, ob in enumerate(obs):
        if "Instruction:" in ob:
            return obs[idx+1].strip()

def get_buttons(obs):
  pattern = r"\[(.*?)\]"
  matches = re.findall(pattern, obs)
  return matches

def get_query(search):
  pattern = r"\[(.*?)\]"
  matches = re.findall(pattern, search)
  if matches:
    return matches[0]
  else:
    return search.replace('search', '')

def get_actions(obs):
  if "[Search]" in obs:
    avai_actions = {'search':[]}
  else:
    avai_actions = {'click':get_buttons(obs)}
  return avai_actions

def get_env_botton(bottons):
  if "Search" in bottons:
    avai_actions = {'search':[]}
  else:
    avai_actions = {'click':bottons}
  return avai_actions

def session_save(session_idx, actions, observations, retrieved_items, file_path):
  save_dict_list = []
  for idx in range(len(actions)):
    save_dict =  {"step_id": f"session_{session_idx}_step_{idx}", "action": actions[idx], "observation":observations[idx], "retrieved_items": retrieved_items[idx]}
    save_dict_list.append(save_dict)
  # get goal
  goal_file_name = f"./webshop/user_session_logs/mturk/{session_idx}.jsonl"
  with open(goal_file_name) as f:
    for line in f:
      page = json.loads(line)
      break
    goal = page["goal"]
  # saving
  save_dict_list = [goal] + save_dict_list
  with open(file_path, 'a') as f:
    json.dump(save_dict_list, f)
    f.write('\n')


"""
 Copyright (c) 2023, salesforce.com, inc.
 All rights reserved.
 SPDX-License-Identifier: Apache License 2.0
 For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0
"""

import json
import re

def obser_parser(observation, instruction_text):
    obs = observation.encode().decode("unicode-escape").encode("latin1").decode("utf-8")
    # obs = obs.replace("[SEP]",'|')
    obs = obs.replace("[button]","[")
    obs = obs.replace("[button_]","]")
    if obs.startswith('Instruction:'):
        obs = obs.replace(instruction_text,"")
        obs = obs.replace('Instruction:',"")
    if obs.startswith('You have clicked'):
        obs = obs.split('\n')[0]
    obs = obs.lstrip()
    return obs

def instruction_parser(ins):
    ins = ins.encode().decode("unicode-escape").encode("latin1").decode("utf-8")
    ins = ins[13:].lstrip()
    return ins

def get_instruction(obs):
    obs = obs.split('\n')
    for idx, ob in enumerate(obs):
        if "Instruction:" in ob:
            return obs[idx+1].strip()

def get_buttons(obs):
  pattern = r"\[(.*?)\]"
  matches = re.findall(pattern, obs)
  return matches

def get_query(search):
  pattern = r"\[(.*?)\]"
  matches = re.findall(pattern, search)


 SPDX-License-Identifier: Apache License 2.0
 For full license text, see the LICENSE file in the repo root or https://www.apache.org/licenses/LICENSE-2.0
"""

import json
import re

def obser_parser(observation, instruction_text):
    obs = observation.encode().decode("unicode-escape").encode("latin1").decode("utf-8")
    # obs = obs.replace("[SEP]",'|')
    obs = obs.replace("[button]","[")
    obs = obs.replace("[button_]","]")
    if obs.startswith('Instruction:'):
        obs = obs.replace(instruction_text,"")
        obs = obs.replace('Instruction:',"")
    if obs.startswith('You have clicked'):
        obs = obs.split('\n')[0]
    obs = obs.lstrip()
    return obs

def instruction_parser(ins):
    ins = ins.encode().decode("unicode-escape").encode("latin1").decode("utf-8")
    ins = ins[13:].lstrip()
    return ins

def get_instruction(obs):
    obs = obs.split('\n')
    for idx, ob in enumerate(obs):
        if "Instruction:" in ob:
            return obs[idx+1].strip()

def get_buttons(obs):
  pattern = r"\[(.*?)\]"
  matches = re.findall(pattern, obs)
  return matches

def get_query(search):
  pattern = r"\[(.*?)\]"
  matches = re.findall(pattern, search)
  if matches:
    return matches[0]
  else:
    return search.replace('search', '')


import re

def obser_parser(observation, instruction_text):
    obs = observation.encode().decode("unicode-escape").encode("latin1").decode("utf-8")
    # obs = obs.replace("[SEP]",'|')
    obs = obs.replace("[button]","[")
    obs = obs.replace("[button_]","]")
    if obs.startswith('Instruction:'):
        obs = obs.replace(instruction_text,"")
        obs = obs.replace('Instruction:',"")
    if obs.startswith('You have clicked'):
        obs = obs.split('\n')[0]
    obs = obs.lstrip()
    return obs

def instruction_parser(ins):
    ins = ins.encode().decode("unicode-escape").encode("latin1").decode("utf-8")
    ins = ins[13:].lstrip()
    return ins

def get_instruction(obs):
    obs = obs.split('\n')
    for idx, ob in enumerate(obs):
        if "Instruction:" in ob:
            return obs[idx+1].strip()

def get_buttons(obs):
  pattern = r"\[(.*?)\]"
  matches = re.findall(pattern, obs)
  return matches

def get_query(search):
  pattern = r"\[(.*?)\]"
  matches = re.findall(pattern, search)
  if matches:
    return matches[0]
  else:
    return search.replace('search', '')

def get_actions(obs):
  if "[Search]" in obs:
    avai_actions = {'search':[]}
  else:
    avai_actions = {'click':get_buttons(obs)}
  return avai_actions


    obs = obs.replace("[button_]","]")
    if obs.startswith('Instruction:'):
        obs = obs.replace(instruction_text,"")
        obs = obs.replace('Instruction:',"")
    if obs.startswith('You have clicked'):
        obs = obs.split('\n')[0]
    obs = obs.lstrip()
    return obs

def instruction_parser(ins):
    ins = ins.encode().decode("unicode-escape").encode("latin1").decode("utf-8")
    ins = ins[13:].lstrip()
    return ins

def get_instruction(obs):
    obs = obs.split('\n')
    for idx, ob in enumerate(obs):
        if "Instruction:" in ob:
            return obs[idx+1].strip()

def get_buttons(obs):
  pattern = r"\[(.*?)\]"
  matches = re.findall(pattern, obs)
  return matches

def get_query(search):
  pattern = r"\[(.*?)\]"
  matches = re.findall(pattern, search)
  if matches:
    return matches[0]
  else:
    return search.replace('search', '')

def get_actions(obs):
  if "[Search]" in obs:
    avai_actions = {'search':[]}
  else:
    avai_actions = {'click':get_buttons(obs)}
  return avai_actions

def get_env_botton(bottons):
  if "Search" in bottons:
    avai_actions = {'search':[]}
  else: