mirror of
https://github.com/OpenHands/OpenHands.git
synced 2025-12-26 05:48:36 +08:00
docs: updated docstrings using ruff's autofix feature (#2923)
* Updated documentation using ruff's autofix feature * Updated pyproject.toml to include docstring validations * Updated documentation using ruff's autofix feature * Updated pyproject.toml to include docstring validations * Updated docstrings using ruff's autfix feature * Deleted opendevin/runtime/utils/soource.py, Keeping in sync with main --------- Co-authored-by: Graham Neubig <neubig@gmail.com>
This commit is contained in:
parent
149dac8e5b
commit
8f76587e5c
@ -99,8 +99,7 @@ class BrowsingAgent(Agent):
|
||||
self,
|
||||
llm: LLM,
|
||||
) -> None:
|
||||
"""
|
||||
Initializes a new instance of the BrowsingAgent class.
|
||||
"""Initializes a new instance of the BrowsingAgent class.
|
||||
|
||||
Parameters:
|
||||
- llm (LLM): The llm to be used by this agent
|
||||
@ -120,16 +119,13 @@ class BrowsingAgent(Agent):
|
||||
self.reset()
|
||||
|
||||
def reset(self) -> None:
|
||||
"""
|
||||
Resets the Browsing Agent.
|
||||
"""
|
||||
"""Resets the Browsing Agent."""
|
||||
super().reset()
|
||||
self.cost_accumulator = 0
|
||||
self.error_accumulator = 0
|
||||
|
||||
def step(self, state: State) -> Action:
|
||||
"""
|
||||
Performs one step using the Browsing Agent.
|
||||
"""Performs one step using the Browsing Agent.
|
||||
This includes gathering information on previous steps and prompting the model to make a browsing command to execute.
|
||||
|
||||
Parameters:
|
||||
|
||||
@ -75,7 +75,8 @@ class PromptElement:
|
||||
Prompt elements are used to build the prompt. Use flags to control which
|
||||
prompt elements are visible. We use class attributes as a convenient way
|
||||
to implement static prompts, but feel free to override them with instance
|
||||
attributes or @property decorator."""
|
||||
attributes or @property decorator.
|
||||
"""
|
||||
|
||||
_prompt = ''
|
||||
_abstract_ex = ''
|
||||
@ -200,11 +201,10 @@ def fit_tokens(
|
||||
model_name : str, optional
|
||||
The name of the model used when tokenizing.
|
||||
|
||||
Returns
|
||||
Returns:
|
||||
-------
|
||||
str : the prompt after shrinking.
|
||||
"""
|
||||
|
||||
if max_prompt_chars is None:
|
||||
return shrinkable.prompt
|
||||
|
||||
@ -579,8 +579,8 @@ the form is not visible yet or some fields are disabled. I need to replan.
|
||||
def diff(previous, new):
|
||||
"""Return a string showing the difference between original and new.
|
||||
|
||||
If the difference is above diff_threshold, return the diff string."""
|
||||
|
||||
If the difference is above diff_threshold, return the diff string.
|
||||
"""
|
||||
if previous == new:
|
||||
return 'Identical', []
|
||||
|
||||
|
||||
@ -37,9 +37,8 @@ class BrowsingResponseParser(ResponseParser):
|
||||
|
||||
|
||||
class BrowsingActionParserMessage(ActionParser):
|
||||
"""
|
||||
Parser action:
|
||||
- BrowseInteractiveAction(browser_actions) - unexpected response format, message back to user
|
||||
"""Parser action:
|
||||
- BrowseInteractiveAction(browser_actions) - unexpected response format, message back to user
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@ -60,9 +59,8 @@ class BrowsingActionParserMessage(ActionParser):
|
||||
|
||||
|
||||
class BrowsingActionParserBrowseInteractive(ActionParser):
|
||||
"""
|
||||
Parser action:
|
||||
- BrowseInteractiveAction(browser_actions) - handle send message to user function call in BrowserGym
|
||||
"""Parser action:
|
||||
- BrowseInteractiveAction(browser_actions) - handle send message to user function call in BrowserGym
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
|
||||
@ -7,7 +7,6 @@ import yaml
|
||||
|
||||
def yaml_parser(message):
|
||||
"""Parse a yaml message for the retry function."""
|
||||
|
||||
# saves gpt-3.5 from some yaml parsing errors
|
||||
message = re.sub(r':\s*\n(?=\S|\n)', ': ', message)
|
||||
|
||||
@ -47,7 +46,6 @@ def _compress_chunks(text, identifier, skip_list, split_regex='\n\n+'):
|
||||
|
||||
def compress_string(text):
|
||||
"""Compress a string by replacing redundant paragraphs and lines with identifiers."""
|
||||
|
||||
# Perform paragraph-level compression
|
||||
def_dict, compressed_text = _compress_chunks(
|
||||
text, identifier='§', skip_list=[], split_regex='\n\n+'
|
||||
@ -79,12 +77,12 @@ def extract_html_tags(text, keys):
|
||||
keys : list of str
|
||||
The HTML tags to extract the content from.
|
||||
|
||||
Returns
|
||||
Returns:
|
||||
-------
|
||||
dict
|
||||
A dictionary mapping each key to a list of subset in `text` that match the key.
|
||||
|
||||
Notes
|
||||
Notes:
|
||||
-----
|
||||
All text and keys will be converted to lowercase before matching.
|
||||
|
||||
@ -126,7 +124,7 @@ def parse_html_tags(text, keys=(), optional_keys=(), merge_multiple=False):
|
||||
optional_keys : list of str
|
||||
The HTML tags to extract the content from, but are optional.
|
||||
|
||||
Returns
|
||||
Returns:
|
||||
-------
|
||||
dict
|
||||
A dictionary mapping each key to subset of `text` that match the key.
|
||||
|
||||
@ -12,13 +12,12 @@ from opendevin.events.action import (
|
||||
|
||||
|
||||
class CodeActResponseParser(ResponseParser):
|
||||
"""
|
||||
Parser action:
|
||||
- CmdRunAction(command) - bash command to run
|
||||
- IPythonRunCellAction(code) - IPython code to run
|
||||
- AgentDelegateAction(agent, inputs) - delegate action for (sub)task
|
||||
- MessageAction(content) - Message action to run (e.g. ask for clarification)
|
||||
- AgentFinishAction() - end the interaction
|
||||
"""Parser action:
|
||||
- CmdRunAction(command) - bash command to run
|
||||
- IPythonRunCellAction(code) - IPython code to run
|
||||
- AgentDelegateAction(agent, inputs) - delegate action for (sub)task
|
||||
- MessageAction(content) - Message action to run (e.g. ask for clarification)
|
||||
- AgentFinishAction() - end the interaction
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
@ -53,9 +52,8 @@ class CodeActResponseParser(ResponseParser):
|
||||
|
||||
|
||||
class CodeActActionParserFinish(ActionParser):
|
||||
"""
|
||||
Parser action:
|
||||
- AgentFinishAction() - end the interaction
|
||||
"""Parser action:
|
||||
- AgentFinishAction() - end the interaction
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@ -76,10 +74,9 @@ class CodeActActionParserFinish(ActionParser):
|
||||
|
||||
|
||||
class CodeActActionParserCmdRun(ActionParser):
|
||||
"""
|
||||
Parser action:
|
||||
- CmdRunAction(command) - bash command to run
|
||||
- AgentFinishAction() - end the interaction
|
||||
"""Parser action:
|
||||
- CmdRunAction(command) - bash command to run
|
||||
- AgentFinishAction() - end the interaction
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@ -106,9 +103,8 @@ class CodeActActionParserCmdRun(ActionParser):
|
||||
|
||||
|
||||
class CodeActActionParserIPythonRunCell(ActionParser):
|
||||
"""
|
||||
Parser action:
|
||||
- IPythonRunCellAction(code) - IPython code to run
|
||||
"""Parser action:
|
||||
- IPythonRunCellAction(code) - IPython code to run
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@ -137,9 +133,8 @@ class CodeActActionParserIPythonRunCell(ActionParser):
|
||||
|
||||
|
||||
class CodeActActionParserAgentDelegate(ActionParser):
|
||||
"""
|
||||
Parser action:
|
||||
- AgentDelegateAction(agent, inputs) - delegate action for (sub)task
|
||||
"""Parser action:
|
||||
- AgentDelegateAction(agent, inputs) - delegate action for (sub)task
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@ -164,9 +159,8 @@ class CodeActActionParserAgentDelegate(ActionParser):
|
||||
|
||||
|
||||
class CodeActActionParserMessage(ActionParser):
|
||||
"""
|
||||
Parser action:
|
||||
- MessageAction(content) - Message action to run (e.g. ask for clarification)
|
||||
"""Parser action:
|
||||
- MessageAction(content) - Message action to run (e.g. ask for clarification)
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
|
||||
@ -158,8 +158,7 @@ class CodeActAgent(Agent):
|
||||
self,
|
||||
llm: LLM,
|
||||
) -> None:
|
||||
"""
|
||||
Initializes a new instance of the CodeActAgent class.
|
||||
"""Initializes a new instance of the CodeActAgent class.
|
||||
|
||||
Parameters:
|
||||
- llm (LLM): The llm to be used by this agent
|
||||
@ -168,14 +167,11 @@ class CodeActAgent(Agent):
|
||||
self.reset()
|
||||
|
||||
def reset(self) -> None:
|
||||
"""
|
||||
Resets the CodeAct Agent.
|
||||
"""
|
||||
"""Resets the CodeAct Agent."""
|
||||
super().reset()
|
||||
|
||||
def step(self, state: State) -> Action:
|
||||
"""
|
||||
Performs one step using the CodeAct Agent.
|
||||
"""Performs one step using the CodeAct Agent.
|
||||
This includes gathering info on previous steps and prompting the model to make a command to execute.
|
||||
|
||||
Parameters:
|
||||
@ -188,7 +184,6 @@ class CodeActAgent(Agent):
|
||||
- MessageAction(content) - Message action to run (e.g. ask for clarification)
|
||||
- AgentFinishAction() - end the interaction
|
||||
"""
|
||||
|
||||
# if we're done, go back
|
||||
latest_user_message = state.history.get_last_user_message()
|
||||
if latest_user_message and latest_user_message.strip() == '/exit':
|
||||
|
||||
@ -11,9 +11,8 @@ from opendevin.events.action import (
|
||||
|
||||
|
||||
class CodeActSWEActionParserFinish(ActionParser):
|
||||
"""
|
||||
Parser action:
|
||||
- AgentFinishAction() - end the interaction
|
||||
"""Parser action:
|
||||
- AgentFinishAction() - end the interaction
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@ -34,10 +33,9 @@ class CodeActSWEActionParserFinish(ActionParser):
|
||||
|
||||
|
||||
class CodeActSWEActionParserCmdRun(ActionParser):
|
||||
"""
|
||||
Parser action:
|
||||
- CmdRunAction(command) - bash command to run
|
||||
- AgentFinishAction() - end the interaction
|
||||
"""Parser action:
|
||||
- CmdRunAction(command) - bash command to run
|
||||
- AgentFinishAction() - end the interaction
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@ -64,9 +62,8 @@ class CodeActSWEActionParserCmdRun(ActionParser):
|
||||
|
||||
|
||||
class CodeActSWEActionParserIPythonRunCell(ActionParser):
|
||||
"""
|
||||
Parser action:
|
||||
- IPythonRunCellAction(code) - IPython code to run
|
||||
"""Parser action:
|
||||
- IPythonRunCellAction(code) - IPython code to run
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@ -95,9 +92,8 @@ class CodeActSWEActionParserIPythonRunCell(ActionParser):
|
||||
|
||||
|
||||
class CodeActSWEActionParserMessage(ActionParser):
|
||||
"""
|
||||
Parser action:
|
||||
- MessageAction(content) - Message action to run (e.g. ask for clarification)
|
||||
"""Parser action:
|
||||
- MessageAction(content) - Message action to run (e.g. ask for clarification)
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
|
||||
@ -113,8 +113,7 @@ class CodeActSWEAgent(Agent):
|
||||
self,
|
||||
llm: LLM,
|
||||
) -> None:
|
||||
"""
|
||||
Initializes a new instance of the CodeActAgent class.
|
||||
"""Initializes a new instance of the CodeActAgent class.
|
||||
|
||||
Parameters:
|
||||
- llm (LLM): The llm to be used by this agent
|
||||
@ -123,14 +122,11 @@ class CodeActSWEAgent(Agent):
|
||||
self.reset()
|
||||
|
||||
def reset(self) -> None:
|
||||
"""
|
||||
Resets the CodeAct Agent.
|
||||
"""
|
||||
"""Resets the CodeAct Agent."""
|
||||
super().reset()
|
||||
|
||||
def step(self, state: State) -> Action:
|
||||
"""
|
||||
Performs one step using the CodeAct Agent.
|
||||
"""Performs one step using the CodeAct Agent.
|
||||
This includes gathering info on previous steps and prompting the model to make a command to execute.
|
||||
|
||||
Parameters:
|
||||
@ -142,7 +138,6 @@ class CodeActSWEAgent(Agent):
|
||||
- MessageAction(content) - Message action to run (e.g. ask for clarification)
|
||||
- AgentFinishAction() - end the interaction
|
||||
"""
|
||||
|
||||
# if we're done, go back
|
||||
latest_user_message = state.history.get_last_user_message()
|
||||
if latest_user_message and latest_user_message.strip() == '/exit':
|
||||
|
||||
@ -9,12 +9,11 @@ from opendevin.events.action import Action
|
||||
|
||||
|
||||
class CodeActSWEResponseParser(ResponseParser):
|
||||
"""
|
||||
Parser action:
|
||||
- CmdRunAction(command) - bash command to run
|
||||
- IPythonRunCellAction(code) - IPython code to run
|
||||
- MessageAction(content) - Message action to run (e.g. ask for clarification)
|
||||
- AgentFinishAction() - end the interaction
|
||||
"""Parser action:
|
||||
- CmdRunAction(command) - bash command to run
|
||||
- IPythonRunCellAction(code) - IPython code to run
|
||||
- MessageAction(content) - Message action to run (e.g. ask for clarification)
|
||||
- AgentFinishAction() - end the interaction
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
|
||||
@ -14,8 +14,7 @@ class DelegatorAgent(Agent):
|
||||
current_delegate: str = ''
|
||||
|
||||
def __init__(self, llm: LLM):
|
||||
"""
|
||||
Initialize the Delegator Agent with an LLM
|
||||
"""Initialize the Delegator Agent with an LLM
|
||||
|
||||
Parameters:
|
||||
- llm (LLM): The llm to be used by this agent
|
||||
@ -23,8 +22,7 @@ class DelegatorAgent(Agent):
|
||||
super().__init__(llm)
|
||||
|
||||
def step(self, state: State) -> Action:
|
||||
"""
|
||||
Checks to see if current step is completed, returns AgentFinishAction if True.
|
||||
"""Checks to see if current step is completed, returns AgentFinishAction if True.
|
||||
Otherwise, delegates the task to the next agent in the pipeline.
|
||||
|
||||
Parameters:
|
||||
|
||||
@ -23,16 +23,12 @@ def parse_response(orig_response: str) -> Action:
|
||||
|
||||
|
||||
def to_json(obj, **kwargs):
|
||||
"""
|
||||
Serialize an object to str format
|
||||
"""
|
||||
"""Serialize an object to str format"""
|
||||
return json.dumps(obj, **kwargs)
|
||||
|
||||
|
||||
def history_to_json(history: ShortTermHistory, max_events=20, **kwargs):
|
||||
"""
|
||||
Serialize and simplify history to str format
|
||||
"""
|
||||
"""Serialize and simplify history to str format"""
|
||||
# TODO: get agent specific llm config
|
||||
llm_config = config.get_llm_config()
|
||||
max_message_chars = llm_config.max_message_chars
|
||||
|
||||
@ -47,8 +47,7 @@ class MonologueAgent(Agent):
|
||||
response_parser = MonologueResponseParser()
|
||||
|
||||
def __init__(self, llm: LLM):
|
||||
"""
|
||||
Initializes the Monologue Agent with an llm.
|
||||
"""Initializes the Monologue Agent with an llm.
|
||||
|
||||
Parameters:
|
||||
- llm (LLM): The llm to be used by this agent
|
||||
@ -56,8 +55,7 @@ class MonologueAgent(Agent):
|
||||
super().__init__(llm)
|
||||
|
||||
def _initialize(self, task: str):
|
||||
"""
|
||||
Utilizes the INITIAL_THOUGHTS list to give the agent a context for its capabilities
|
||||
"""Utilizes the INITIAL_THOUGHTS list to give the agent a context for its capabilities
|
||||
and how to navigate the WORKSPACE_MOUNT_PATH_IN_SANDBOX in `config` (e.g., /workspace by default).
|
||||
Short circuited to return when already initialized.
|
||||
Will execute again when called after reset.
|
||||
@ -68,7 +66,6 @@ class MonologueAgent(Agent):
|
||||
Raises:
|
||||
- AgentNoInstructionError: If task is not provided
|
||||
"""
|
||||
|
||||
if self._initialized:
|
||||
return
|
||||
|
||||
@ -133,8 +130,7 @@ class MonologueAgent(Agent):
|
||||
self.initial_thoughts.append(event_to_memory(action, max_message_chars))
|
||||
|
||||
def step(self, state: State) -> Action:
|
||||
"""
|
||||
Modifies the current state by adding the most recent actions and observations, then prompts the model to think about it's next action to take using monologue, memory, and hint.
|
||||
"""Modifies the current state by adding the most recent actions and observations, then prompts the model to think about it's next action to take using monologue, memory, and hint.
|
||||
|
||||
Parameters:
|
||||
- state (State): The current state based on previous steps taken
|
||||
|
||||
@ -19,8 +19,7 @@ class MonologueResponseParser(ResponseParser):
|
||||
return response['choices'][0]['message']['content']
|
||||
|
||||
def parse_action(self, action_str: str) -> Action:
|
||||
"""
|
||||
Parses a string to find an action within it
|
||||
"""Parses a string to find an action within it
|
||||
|
||||
Parameters:
|
||||
- response (str): The string to be parsed
|
||||
|
||||
@ -120,8 +120,7 @@ INITIAL_THOUGHTS = [
|
||||
|
||||
|
||||
def get_summarize_monologue_prompt(thoughts: list[dict]):
|
||||
"""
|
||||
Gets the prompt for summarizing the monologue
|
||||
"""Gets the prompt for summarizing the monologue
|
||||
|
||||
Returns:
|
||||
- str: A formatted string with the current monologue within the prompt
|
||||
@ -136,8 +135,7 @@ def get_request_action_prompt(
|
||||
thoughts: list[dict],
|
||||
recent_events: list[dict],
|
||||
):
|
||||
"""
|
||||
Gets the action prompt formatted with appropriate values.
|
||||
"""Gets the action prompt formatted with appropriate values.
|
||||
|
||||
Parameters:
|
||||
- task (str): The current task the agent is trying to accomplish
|
||||
@ -146,7 +144,6 @@ def get_request_action_prompt(
|
||||
Returns:
|
||||
- str: Formatted prompt string with hint, task, monologue, and background commands included
|
||||
"""
|
||||
|
||||
hint = ''
|
||||
if len(recent_events) > 0:
|
||||
latest_event = recent_events[-1]
|
||||
@ -179,8 +176,7 @@ def get_request_action_prompt(
|
||||
|
||||
|
||||
def parse_action_response(orig_response: str) -> Action:
|
||||
"""
|
||||
Parses a string to find an action within it
|
||||
"""Parses a string to find an action within it
|
||||
|
||||
Parameters:
|
||||
- response (str): The string to be parsed
|
||||
@ -199,8 +195,7 @@ def parse_action_response(orig_response: str) -> Action:
|
||||
|
||||
|
||||
def parse_summary_response(response: str) -> list[dict]:
|
||||
"""
|
||||
Parses a summary of the monologue
|
||||
"""Parses a summary of the monologue
|
||||
|
||||
Parameters:
|
||||
- response (str): The response string to be parsed
|
||||
|
||||
@ -18,8 +18,7 @@ class PlannerAgent(Agent):
|
||||
response_parser = MonologueResponseParser()
|
||||
|
||||
def __init__(self, llm: LLM):
|
||||
"""
|
||||
Initialize the Planner Agent with an LLM
|
||||
"""Initialize the Planner Agent with an LLM
|
||||
|
||||
Parameters:
|
||||
- llm (LLM): The llm to be used by this agent
|
||||
@ -27,8 +26,7 @@ class PlannerAgent(Agent):
|
||||
super().__init__(llm)
|
||||
|
||||
def step(self, state: State) -> Action:
|
||||
"""
|
||||
Checks to see if current step is completed, returns AgentFinishAction if True.
|
||||
"""Checks to see if current step is completed, returns AgentFinishAction if True.
|
||||
Otherwise, creates a plan prompt and sends to model for inference, returning the result as the next action.
|
||||
|
||||
Parameters:
|
||||
@ -38,7 +36,6 @@ class PlannerAgent(Agent):
|
||||
- AgentFinishAction: If the last state was 'completed', 'verified', or 'abandoned'
|
||||
- Action: The next action to take based on llm response
|
||||
"""
|
||||
|
||||
if state.root_task.state in [
|
||||
'completed',
|
||||
'verified',
|
||||
|
||||
@ -101,7 +101,6 @@ What is your next thought or action? Again, you must reply with JSON, and only w
|
||||
|
||||
def get_hint(latest_action_id: str) -> str:
|
||||
"""Returns action type hint based on given action_id"""
|
||||
|
||||
hints = {
|
||||
'': "You haven't taken any actions yet. Start by using `ls` to check out what files you're working with.",
|
||||
ActionType.RUN: 'You should think about the command you just ran, what output it gave, and how that affects your plan.',
|
||||
@ -118,8 +117,7 @@ def get_hint(latest_action_id: str) -> str:
|
||||
|
||||
|
||||
def get_prompt(state: State) -> str:
|
||||
"""
|
||||
Gets the prompt for the planner agent.
|
||||
"""Gets the prompt for the planner agent.
|
||||
Formatted with the most recent action-observation pairs, current task, and hint based on last action
|
||||
|
||||
Parameters:
|
||||
@ -180,10 +178,10 @@ def get_prompt(state: State) -> str:
|
||||
|
||||
|
||||
def parse_response(response: str) -> Action:
|
||||
"""
|
||||
Parses the model output to find a valid action to take
|
||||
"""Parses the model output to find a valid action to take
|
||||
Parameters:
|
||||
- response (str): A response from the model that potentially contains an Action.
|
||||
|
||||
Returns:
|
||||
- Action: A valid next action to perform from model output
|
||||
"""
|
||||
|
||||
@ -66,9 +66,7 @@ AGENT_CLS_TO_INST_SUFFIX = {
|
||||
|
||||
|
||||
def execute_sql(db_path, gen_sql, gold_sql):
|
||||
"""
|
||||
Execute the generated SQL and the ground truth SQL and compare the results.
|
||||
"""
|
||||
"""Execute the generated SQL and the ground truth SQL and compare the results."""
|
||||
with sqlite3.connect(db_path) as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(gen_sql)
|
||||
@ -255,18 +253,14 @@ def process_instance(
|
||||
|
||||
|
||||
def load_bird():
|
||||
"""
|
||||
Main function to handle the flow of downloading, processing, and loading the bird dataset.
|
||||
"""
|
||||
"""Main function to handle the flow of downloading, processing, and loading the bird dataset."""
|
||||
raw_dataset_path = download_bird()
|
||||
bird_dataset = process_bird(raw_dataset_path)
|
||||
return bird_dataset
|
||||
|
||||
|
||||
def download_bird():
|
||||
"""
|
||||
Downloads and extracts the bird dataset from a specified URL into a local directory.
|
||||
"""
|
||||
"""Downloads and extracts the bird dataset from a specified URL into a local directory."""
|
||||
dataset_path = os.path.join(config.workspace_base, 'evaluation_bird')
|
||||
devset_path = os.path.join(dataset_path, 'dev')
|
||||
if not os.path.exists(dataset_path):
|
||||
@ -292,9 +286,7 @@ def download_bird():
|
||||
|
||||
|
||||
def process_bird(dataset_path):
|
||||
"""
|
||||
Processes the raw bird dataset into a structured format and saves it as JSON.
|
||||
"""
|
||||
"""Processes the raw bird dataset into a structured format and saves it as JSON."""
|
||||
processed_path = os.path.join(dataset_path, 'processed_dev.json')
|
||||
if not os.path.exists(processed_path):
|
||||
logger.info(f'{processed_path} folder does not exist, starting processing...')
|
||||
@ -325,9 +317,7 @@ def process_bird(dataset_path):
|
||||
|
||||
|
||||
def extract_create_table_prompt(db_path, limit_value=0):
|
||||
"""
|
||||
Generates a SQL prompt with CREATE TABLE statements and sample data from the database.
|
||||
"""
|
||||
"""Generates a SQL prompt with CREATE TABLE statements and sample data from the database."""
|
||||
table_query = "SELECT * FROM sqlite_master WHERE type='table';"
|
||||
tables = sqlite3.connect(db_path).cursor().execute(table_query).fetchall()
|
||||
prompt = ''
|
||||
@ -367,9 +357,7 @@ def extract_create_table_prompt(db_path, limit_value=0):
|
||||
|
||||
|
||||
def create_prompt(e, database_path):
|
||||
"""
|
||||
Create a prompt for the given example
|
||||
"""
|
||||
"""Create a prompt for the given example"""
|
||||
db_id = e['db_id']
|
||||
db_path = pathlib.Path(database_path) / db_id / f'{db_id}.sqlite'
|
||||
|
||||
|
||||
@ -80,14 +80,14 @@ def question_scorer(
|
||||
|
||||
|
||||
def normalize_str(input_str, remove_punct=True) -> str:
|
||||
"""
|
||||
Normalize a string by:
|
||||
"""Normalize a string by:
|
||||
- Removing all white spaces
|
||||
- Optionally removing punctuation (if remove_punct is True)
|
||||
- Converting to lowercase
|
||||
Parameters:
|
||||
- input_str: str, the string to normalize
|
||||
- remove_punct: bool, whether to remove punctuation (default: True)
|
||||
|
||||
Returns:
|
||||
- str, the normalized string
|
||||
"""
|
||||
|
||||
@ -10,7 +10,6 @@ from ast_eval_th import ast_eval_th
|
||||
# This function is modified from Gorilla's APIBench implementations (https://github.com/ShishirPatil/gorilla/blob/main/eval/get_llm_responses.py).
|
||||
def encode_question(question, api_name):
|
||||
"""Encode multiple prompt instructions into a single string."""
|
||||
|
||||
prompts = []
|
||||
if api_name == 'torch':
|
||||
api_name = 'torchhub'
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
"""
|
||||
Overview:
|
||||
"""Overview:
|
||||
This code implements the evaluation of agents on the GPQA Benchmark with Open Book setting.
|
||||
- The benchmark consists of 448 high-quality and extremely difficult multiple-choice questions in the domains of biology, physics, and chemistry. The questions are intentionally designed to be "Google-proof," meaning that even highly skilled non-expert validators achieve only 34% accuracy despite unrestricted access to the web.
|
||||
- Even experts in the corresponding domains achieve only 65% accuracy.
|
||||
@ -54,8 +53,7 @@ AGENT_CLS_TO_INST_SUFFIX = {
|
||||
|
||||
|
||||
def parse_final_answer(final_answer: str) -> str:
|
||||
"""
|
||||
Parse the final answer from the final message generated by the agent
|
||||
"""Parse the final answer from the final message generated by the agent
|
||||
to extract the final answer. The final answer is usually enclosed in the format:
|
||||
<<FINAL_ANSWER||
|
||||
<insert correct answer here>
|
||||
@ -71,15 +69,12 @@ def parse_final_answer(final_answer: str) -> str:
|
||||
|
||||
|
||||
def compare_answers(predicted_answer, ground_truth):
|
||||
"""
|
||||
Compare the predicted answer with the ground truth answer
|
||||
"""
|
||||
"""Compare the predicted answer with the ground truth answer"""
|
||||
return predicted_answer == ground_truth
|
||||
|
||||
|
||||
def get_test_result(model_output, ground_truth):
|
||||
"""
|
||||
Implements the evaluation logic for GPQA
|
||||
"""Implements the evaluation logic for GPQA
|
||||
Checks if the output of a given instance is correct (as per the ground truth)
|
||||
"""
|
||||
# parse the final answer from model output
|
||||
@ -92,8 +87,7 @@ def get_test_result(model_output, ground_truth):
|
||||
|
||||
|
||||
def convert_instance_dict(instance):
|
||||
"""
|
||||
Used for preprocessing the hf dataset into a format that can be used by the agent.
|
||||
"""Used for preprocessing the hf dataset into a format that can be used by the agent.
|
||||
Reads and extracts relevant information from the dataset instance.
|
||||
"""
|
||||
out_instance_dict = {}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
"""
|
||||
Implements evaluation of agents on HumanEvalFix from the HumanEvalPack benchmark introduced in
|
||||
"""Implements evaluation of agents on HumanEvalFix from the HumanEvalPack benchmark introduced in
|
||||
"OctoPack: Instruction Tuning Code Large Language Models" (https://arxiv.org/abs/2308.07124).
|
||||
Please see https://github.com/bigcode-project/bigcode-evaluation-harness/blob/main/bigcode_eval/tasks/humanevalpack.py
|
||||
for the reference implementation used in the paper.
|
||||
|
||||
@ -74,7 +74,6 @@ class HumanEvalTask(CodeGenTask):
|
||||
Modified from:
|
||||
https://github.com/bigcode-project/bigcode-evaluation-harness/blob/d61afde130005ecc65cf800ad8eca790a9bc2115/lm_eval/tasks/humaneval.py#L56
|
||||
"""
|
||||
|
||||
# STOP_WORDS = ["\nclass", "\ndef", "\n#", "\n@", "\nprint", "\nif"]
|
||||
# # Remove the last block of the code containing stop_words for HumanEval
|
||||
# string_list = re.split("(%s)" % "|".join(STOP_WORDS), solution)
|
||||
|
||||
@ -79,14 +79,12 @@ def check_correctness(
|
||||
timeout: float = 10,
|
||||
completion_id: Optional[int] = None,
|
||||
) -> Dict:
|
||||
"""
|
||||
Evaluates the functional correctness of a completion by running the test
|
||||
"""Evaluates the functional correctness of a completion by running the test
|
||||
suite provided in the problem.
|
||||
|
||||
:param completion_id: an optional completion ID so we can match
|
||||
the results later even if execution finishes asynchronously.
|
||||
"""
|
||||
|
||||
manager = multiprocessing.Manager()
|
||||
result = manager.list()
|
||||
|
||||
@ -181,18 +179,16 @@ def chdir(root):
|
||||
|
||||
|
||||
def reliability_guard(maximum_memory_bytes: Optional[int] = None):
|
||||
"""
|
||||
This disables various destructive functions and prevents the generated code
|
||||
"""This disables various destructive functions and prevents the generated code
|
||||
from interfering with the test (e.g. fork bomb, killing other processes,
|
||||
removing filesystem files, etc.)
|
||||
|
||||
WARNING
|
||||
Warning:
|
||||
This function is NOT a security sandbox. Untrusted code, including, model-
|
||||
generated code, should not be blindly executed outside of one. See the
|
||||
Codex paper for more information about OpenAI's code sandbox, and proceed
|
||||
with caution.
|
||||
"""
|
||||
|
||||
if maximum_memory_bytes is not None:
|
||||
import resource
|
||||
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
"""
|
||||
Implements evaluation of agents on ML-Bench, a benchmark for assessing the effectiveness of
|
||||
"""Implements evaluation of agents on ML-Bench, a benchmark for assessing the effectiveness of
|
||||
Large Language Models (LLMs) in leveraging existing functions in open-source libraries for
|
||||
machine learning tasks. The benchmark is introduced in the paper "ML-Bench: Evaluating Large
|
||||
Language Models for Code Generation in Repository-Level Machine Learning Tasks"
|
||||
|
||||
@ -6,9 +6,7 @@ from conftest import agents
|
||||
|
||||
@pytest.mark.parametrize('agent', agents())
|
||||
def test_hello_world(task_file, run_test_case, agent):
|
||||
"""
|
||||
Test case for the "Hello, World!" Bash script using different agents.
|
||||
"""
|
||||
"""Test case for the "Hello, World!" Bash script using different agents."""
|
||||
# Run the test case for the specified agent
|
||||
workspace_dir = run_test_case(agent, 'hello-world')
|
||||
|
||||
@ -16,7 +14,7 @@ def test_hello_world(task_file, run_test_case, agent):
|
||||
assert os.path.exists(workspace_dir)
|
||||
assert os.path.isfile(os.path.join(workspace_dir, 'hello_world.sh'))
|
||||
|
||||
# Execute the hello_world.sh script
|
||||
# Execute the hello_world.sh script
|
||||
os.chdir(workspace_dir)
|
||||
output = os.popen('bash hello_world.sh').read()
|
||||
assert output == 'Hello, World!\n'
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
"""
|
||||
This script compares gold patches with OpenDevin-generated patches and check whether
|
||||
"""This script compares gold patches with OpenDevin-generated patches and check whether
|
||||
OpenDevin found the right (set of) files to modify.
|
||||
"""
|
||||
|
||||
|
||||
@ -4,8 +4,7 @@ from opendevin.events.action import Action
|
||||
|
||||
|
||||
class ResponseParser(ABC):
|
||||
"""
|
||||
This abstract base class is a general interface for an response parser dedicated to
|
||||
"""This abstract base class is a general interface for an response parser dedicated to
|
||||
parsing the action from the response from the LLM.
|
||||
"""
|
||||
|
||||
@ -17,8 +16,7 @@ class ResponseParser(ABC):
|
||||
|
||||
@abstractmethod
|
||||
def parse(self, response: str) -> Action:
|
||||
"""
|
||||
Parses the action from the response from the LLM.
|
||||
"""Parses the action from the response from the LLM.
|
||||
|
||||
Parameters:
|
||||
- response (str): The response from the LLM.
|
||||
@ -30,8 +28,7 @@ class ResponseParser(ABC):
|
||||
|
||||
@abstractmethod
|
||||
def parse_response(self, response) -> str:
|
||||
"""
|
||||
Parses the action from the response from the LLM.
|
||||
"""Parses the action from the response from the LLM.
|
||||
|
||||
Parameters:
|
||||
- response (str): The response from the LLM.
|
||||
@ -43,8 +40,7 @@ class ResponseParser(ABC):
|
||||
|
||||
@abstractmethod
|
||||
def parse_action(self, action_str: str) -> Action:
|
||||
"""
|
||||
Parses the action from the response from the LLM.
|
||||
"""Parses the action from the response from the LLM.
|
||||
|
||||
Parameters:
|
||||
- action_str (str): The response from the LLM.
|
||||
@ -56,21 +52,16 @@ class ResponseParser(ABC):
|
||||
|
||||
|
||||
class ActionParser(ABC):
|
||||
"""
|
||||
This abstract base class is a general interface for an action parser dedicated to
|
||||
"""This abstract base class is a general interface for an action parser dedicated to
|
||||
parsing the action from the action str from the LLM.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def check_condition(self, action_str: str) -> bool:
|
||||
"""
|
||||
Check if the action string can be parsed by this parser.
|
||||
"""
|
||||
"""Check if the action string can be parsed by this parser."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def parse(self, action_str: str) -> Action:
|
||||
"""
|
||||
Parses the action from the action string from the LLM response.
|
||||
"""
|
||||
"""Parses the action from the action string from the LLM response."""
|
||||
pass
|
||||
|
||||
@ -35,8 +35,7 @@ class Agent(ABC):
|
||||
|
||||
@property
|
||||
def complete(self) -> bool:
|
||||
"""
|
||||
Indicates whether the current instruction execution is complete.
|
||||
"""Indicates whether the current instruction execution is complete.
|
||||
|
||||
Returns:
|
||||
- complete (bool): True if execution is complete; False otherwise.
|
||||
@ -45,15 +44,13 @@ class Agent(ABC):
|
||||
|
||||
@abstractmethod
|
||||
def step(self, state: 'State') -> 'Action':
|
||||
"""
|
||||
Starts the execution of the assigned instruction. This method should
|
||||
"""Starts the execution of the assigned instruction. This method should
|
||||
be implemented by subclasses to define the specific execution logic.
|
||||
"""
|
||||
pass
|
||||
|
||||
def reset(self) -> None:
|
||||
"""
|
||||
Resets the agent's execution status and clears the history. This method can be used
|
||||
"""Resets the agent's execution status and clears the history. This method can be used
|
||||
to prepare the agent for restarting the instruction or cleaning up before destruction.
|
||||
|
||||
"""
|
||||
@ -66,8 +63,7 @@ class Agent(ABC):
|
||||
|
||||
@classmethod
|
||||
def register(cls, name: str, agent_cls: Type['Agent']):
|
||||
"""
|
||||
Registers an agent class in the registry.
|
||||
"""Registers an agent class in the registry.
|
||||
|
||||
Parameters:
|
||||
- name (str): The name to register the class under.
|
||||
@ -82,8 +78,7 @@ class Agent(ABC):
|
||||
|
||||
@classmethod
|
||||
def get_cls(cls, name: str) -> Type['Agent']:
|
||||
"""
|
||||
Retrieves an agent class from the registry.
|
||||
"""Retrieves an agent class from the registry.
|
||||
|
||||
Parameters:
|
||||
- name (str): The name of the class to retrieve
|
||||
@ -100,8 +95,7 @@ class Agent(ABC):
|
||||
|
||||
@classmethod
|
||||
def list_agents(cls) -> list[str]:
|
||||
"""
|
||||
Retrieves the list of all agent names from the registry.
|
||||
"""Retrieves the list of all agent names from the registry.
|
||||
|
||||
Raises:
|
||||
- AgentNotRegisteredError: If no agent is registered
|
||||
|
||||
@ -122,8 +122,7 @@ class AgentController:
|
||||
self.state.metrics = self.agent.llm.metrics
|
||||
|
||||
async def report_error(self, message: str, exception: Exception | None = None):
|
||||
"""
|
||||
This error will be reported to the user and sent to the LLM next step, in the hope it can self-correct.
|
||||
"""This error will be reported to the user and sent to the LLM next step, in the hope it can self-correct.
|
||||
|
||||
This method should be called for a particular type of errors, which have:
|
||||
- a user-friendly message, which will be shown in the chat box. This should not be a raw exception message.
|
||||
|
||||
@ -110,9 +110,7 @@ class State:
|
||||
# remove the restored data from the state if any
|
||||
|
||||
def get_current_user_intent(self):
|
||||
"""
|
||||
Returns the latest user message that appears after a FinishAction, or the first (the task) if nothing was finished yet.
|
||||
"""
|
||||
"""Returns the latest user message that appears after a FinishAction, or the first (the task) if nothing was finished yet."""
|
||||
last_user_message = None
|
||||
for event in self.history.get_events(reverse=True):
|
||||
if isinstance(event, MessageAction) and event.source == 'user':
|
||||
|
||||
@ -21,8 +21,7 @@ load_dotenv()
|
||||
|
||||
@dataclass
|
||||
class LLMConfig:
|
||||
"""
|
||||
Configuration for the LLM model.
|
||||
"""Configuration for the LLM model.
|
||||
|
||||
Attributes:
|
||||
model: The model to use.
|
||||
@ -75,9 +74,7 @@ class LLMConfig:
|
||||
ollama_base_url: str | None = None
|
||||
|
||||
def defaults_to_dict(self) -> dict:
|
||||
"""
|
||||
Serialize fields to a dict for the frontend, including type hints, defaults, and whether it's optional.
|
||||
"""
|
||||
"""Serialize fields to a dict for the frontend, including type hints, defaults, and whether it's optional."""
|
||||
result = {}
|
||||
for f in fields(self):
|
||||
result[f.name] = get_field_info(f)
|
||||
@ -102,8 +99,7 @@ class LLMConfig:
|
||||
|
||||
@dataclass
|
||||
class AgentConfig:
|
||||
"""
|
||||
Configuration for the agent.
|
||||
"""Configuration for the agent.
|
||||
|
||||
Attributes:
|
||||
memory_enabled: Whether long-term memory (embeddings) is enabled.
|
||||
@ -116,9 +112,7 @@ class AgentConfig:
|
||||
llm_config: str | None = None
|
||||
|
||||
def defaults_to_dict(self) -> dict:
|
||||
"""
|
||||
Serialize fields to a dict for the frontend, including type hints, defaults, and whether it's optional.
|
||||
"""
|
||||
"""Serialize fields to a dict for the frontend, including type hints, defaults, and whether it's optional."""
|
||||
result = {}
|
||||
for f in fields(self):
|
||||
result[f.name] = get_field_info(f)
|
||||
@ -127,8 +121,7 @@ class AgentConfig:
|
||||
|
||||
@dataclass
|
||||
class SandboxConfig(metaclass=Singleton):
|
||||
"""
|
||||
Configuration for the sandbox.
|
||||
"""Configuration for the sandbox.
|
||||
|
||||
Attributes:
|
||||
box_type: The type of sandbox to use. Options are: ssh, e2b, local.
|
||||
@ -148,9 +141,7 @@ class SandboxConfig(metaclass=Singleton):
|
||||
timeout: int = 120
|
||||
|
||||
def defaults_to_dict(self) -> dict:
|
||||
"""
|
||||
Serialize fields to a dict for the frontend, including type hints, defaults, and whether it's optional.
|
||||
"""
|
||||
"""Serialize fields to a dict for the frontend, including type hints, defaults, and whether it's optional."""
|
||||
dict = {}
|
||||
for f in fields(self):
|
||||
dict[f.name] = get_field_info(f)
|
||||
@ -176,8 +167,7 @@ class UndefinedString(str, Enum):
|
||||
|
||||
@dataclass
|
||||
class AppConfig(metaclass=Singleton):
|
||||
"""
|
||||
Configuration for the app.
|
||||
"""Configuration for the app.
|
||||
|
||||
Attributes:
|
||||
llms: A dictionary of name -> LLM configuration. Default config is under 'llm' key.
|
||||
@ -247,9 +237,7 @@ class AppConfig(metaclass=Singleton):
|
||||
defaults_dict: ClassVar[dict] = {}
|
||||
|
||||
def get_llm_config(self, name='llm') -> LLMConfig:
|
||||
"""
|
||||
llm is the name for default config (for backward compatibility prior to 0.8)
|
||||
"""
|
||||
"""Llm is the name for default config (for backward compatibility prior to 0.8)"""
|
||||
if name in self.llms:
|
||||
return self.llms[name]
|
||||
if name is not None and name != 'llm':
|
||||
@ -262,9 +250,7 @@ class AppConfig(metaclass=Singleton):
|
||||
self.llms[name] = value
|
||||
|
||||
def get_agent_config(self, name='agent') -> AgentConfig:
|
||||
"""
|
||||
agent is the name for default config (for backward compability prior to 0.8)
|
||||
"""
|
||||
"""Agent is the name for default config (for backward compability prior to 0.8)"""
|
||||
if name in self.agents:
|
||||
return self.agents[name]
|
||||
if 'agent' not in self.agents:
|
||||
@ -280,15 +266,11 @@ class AppConfig(metaclass=Singleton):
|
||||
return self.get_llm_config(llm_config_name)
|
||||
|
||||
def __post_init__(self):
|
||||
"""
|
||||
Post-initialization hook, called when the instance is created with only default values.
|
||||
"""
|
||||
"""Post-initialization hook, called when the instance is created with only default values."""
|
||||
AppConfig.defaults_dict = self.defaults_to_dict()
|
||||
|
||||
def defaults_to_dict(self) -> dict:
|
||||
"""
|
||||
Serialize fields to a dict for the frontend, including type hints, defaults, and whether it's optional.
|
||||
"""
|
||||
"""Serialize fields to a dict for the frontend, including type hints, defaults, and whether it's optional."""
|
||||
result = {}
|
||||
for f in fields(self):
|
||||
field_value = getattr(self, f.name)
|
||||
@ -323,8 +305,7 @@ class AppConfig(metaclass=Singleton):
|
||||
|
||||
|
||||
def get_field_info(f):
|
||||
"""
|
||||
Extract information about a dataclass field: type, optional, and default.
|
||||
"""Extract information about a dataclass field: type, optional, and default.
|
||||
|
||||
Args:
|
||||
f: The field to extract information from.
|
||||
@ -423,7 +404,6 @@ def load_from_toml(cfg: AppConfig, toml_file: str = 'config.toml'):
|
||||
cfg: The AppConfig object to update attributes of.
|
||||
toml_file: The path to the toml file. Defaults to 'config.toml'.
|
||||
"""
|
||||
|
||||
# try to read the config.toml file into the config object
|
||||
try:
|
||||
with open(toml_file, 'r', encoding='utf-8') as toml_contents:
|
||||
@ -514,10 +494,7 @@ def load_from_toml(cfg: AppConfig, toml_file: str = 'config.toml'):
|
||||
|
||||
|
||||
def finalize_config(cfg: AppConfig):
|
||||
"""
|
||||
More tweaks to the config after it's been loaded.
|
||||
"""
|
||||
|
||||
"""More tweaks to the config after it's been loaded."""
|
||||
# Set workspace_mount_path if not set by the user
|
||||
if cfg.workspace_mount_path is UndefinedString.UNDEFINED:
|
||||
cfg.workspace_mount_path = os.path.abspath(cfg.workspace_base)
|
||||
@ -558,8 +535,7 @@ finalize_config(config)
|
||||
def get_llm_config_arg(
|
||||
llm_config_arg: str, toml_file: str = 'config.toml'
|
||||
) -> LLMConfig | None:
|
||||
"""
|
||||
Get a group of llm settings from the config file.
|
||||
"""Get a group of llm settings from the config file.
|
||||
|
||||
A group in config.toml can look like this:
|
||||
|
||||
@ -583,7 +559,6 @@ def get_llm_config_arg(
|
||||
Returns:
|
||||
LLMConfig: The LLMConfig object with the settings from the config file.
|
||||
"""
|
||||
|
||||
# keep only the name, just in case
|
||||
llm_config_arg = llm_config_arg.strip('[]')
|
||||
|
||||
@ -613,9 +588,7 @@ def get_llm_config_arg(
|
||||
|
||||
# Command line arguments
|
||||
def get_parser() -> argparse.ArgumentParser:
|
||||
"""
|
||||
Get the parser for the command line arguments.
|
||||
"""
|
||||
"""Get the parser for the command line arguments."""
|
||||
parser = argparse.ArgumentParser(description='Run an agent with a specific task')
|
||||
parser.add_argument(
|
||||
'-d',
|
||||
@ -689,9 +662,7 @@ def get_parser() -> argparse.ArgumentParser:
|
||||
|
||||
|
||||
def parse_arguments() -> argparse.Namespace:
|
||||
"""
|
||||
Parse the command line arguments.
|
||||
"""
|
||||
"""Parse the command line arguments."""
|
||||
parser = get_parser()
|
||||
parsed_args, _ = parser.parse_known_args()
|
||||
if parsed_args.directory:
|
||||
|
||||
@ -115,9 +115,7 @@ class SensitiveDataFilter(logging.Filter):
|
||||
|
||||
|
||||
def get_console_handler():
|
||||
"""
|
||||
Returns a console handler for logging.
|
||||
"""
|
||||
"""Returns a console handler for logging."""
|
||||
console_handler = logging.StreamHandler()
|
||||
console_handler.setLevel(logging.INFO)
|
||||
if config.debug:
|
||||
@ -127,9 +125,7 @@ def get_console_handler():
|
||||
|
||||
|
||||
def get_file_handler(log_dir=None):
|
||||
"""
|
||||
Returns a file handler for logging.
|
||||
"""
|
||||
"""Returns a file handler for logging."""
|
||||
log_dir = os.path.join(os.getcwd(), 'logs') if log_dir is None else log_dir
|
||||
os.makedirs(log_dir, exist_ok=True)
|
||||
timestamp = datetime.now().strftime('%Y-%m-%d')
|
||||
@ -146,8 +142,7 @@ logging.basicConfig(level=logging.ERROR)
|
||||
|
||||
|
||||
def log_uncaught_exceptions(ex_cls, ex, tb):
|
||||
"""
|
||||
Logs uncaught exceptions along with the traceback.
|
||||
"""Logs uncaught exceptions along with the traceback.
|
||||
|
||||
Args:
|
||||
ex_cls (type): The type of the exception.
|
||||
@ -183,13 +178,10 @@ logging.getLogger('LiteLLM Proxy').disabled = True
|
||||
|
||||
|
||||
class LlmFileHandler(logging.FileHandler):
|
||||
"""
|
||||
# LLM prompt and response logging
|
||||
"""
|
||||
"""# LLM prompt and response logging"""
|
||||
|
||||
def __init__(self, filename, mode='a', encoding='utf-8', delay=False):
|
||||
"""
|
||||
Initializes an instance of LlmFileHandler.
|
||||
"""Initializes an instance of LlmFileHandler.
|
||||
|
||||
Args:
|
||||
filename (str): The name of the log file.
|
||||
@ -220,8 +212,7 @@ class LlmFileHandler(logging.FileHandler):
|
||||
super().__init__(self.baseFilename, mode, encoding, delay)
|
||||
|
||||
def emit(self, record):
|
||||
"""
|
||||
Emits a log record.
|
||||
"""Emits a log record.
|
||||
|
||||
Args:
|
||||
record (logging.LogRecord): The log record to emit.
|
||||
|
||||
@ -50,7 +50,6 @@ async def run_agent_controller(
|
||||
fake_user_response_fn: An optional function that receives the current state (could be None) and returns a fake user response.
|
||||
sandbox: An optional sandbox to run the agent in.
|
||||
"""
|
||||
|
||||
# Logging
|
||||
logger.info(
|
||||
f'Running agent {agent.name}, model {agent.llm.model_name}, with task: "{task_str}"'
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
class Metrics:
|
||||
"""
|
||||
Metrics class can record various metrics during running and evaluation.
|
||||
"""Metrics class can record various metrics during running and evaluation.
|
||||
Currently, we define the following metrics:
|
||||
accumulated_cost: the total cost (USD $) of the current LLM.
|
||||
"""
|
||||
@ -30,15 +29,11 @@ class Metrics:
|
||||
self._costs.append(value)
|
||||
|
||||
def get(self):
|
||||
"""
|
||||
Return the metrics in a dictionary.
|
||||
"""
|
||||
"""Return the metrics in a dictionary."""
|
||||
return {'accumulated_cost': self._accumulated_cost, 'costs': self._costs}
|
||||
|
||||
def log(self):
|
||||
"""
|
||||
Log the metrics.
|
||||
"""
|
||||
"""Log the metrics."""
|
||||
metrics = self.get()
|
||||
logs = ''
|
||||
for key, value in metrics.items():
|
||||
|
||||
@ -9,9 +9,7 @@ from opendevin.events.serialization import event_to_dict
|
||||
|
||||
|
||||
def my_default_encoder(obj):
|
||||
"""
|
||||
Custom JSON encoder that handles datetime and event objects
|
||||
"""
|
||||
"""Custom JSON encoder that handles datetime and event objects"""
|
||||
if isinstance(obj, datetime):
|
||||
return obj.isoformat()
|
||||
if isinstance(obj, Event):
|
||||
@ -20,17 +18,12 @@ def my_default_encoder(obj):
|
||||
|
||||
|
||||
def dumps(obj, **kwargs):
|
||||
"""
|
||||
Serialize an object to str format
|
||||
"""
|
||||
|
||||
"""Serialize an object to str format"""
|
||||
return json.dumps(obj, default=my_default_encoder, **kwargs)
|
||||
|
||||
|
||||
def loads(json_str, **kwargs):
|
||||
"""
|
||||
Create a JSON object from str
|
||||
"""
|
||||
"""Create a JSON object from str"""
|
||||
try:
|
||||
return json.loads(json_str, **kwargs)
|
||||
except json.JSONDecodeError:
|
||||
|
||||
@ -8,8 +8,7 @@ from .action import Action
|
||||
|
||||
@dataclass
|
||||
class FileReadAction(Action):
|
||||
"""
|
||||
Reads a file from a given path.
|
||||
"""Reads a file from a given path.
|
||||
Can be set to read specific lines using start and end
|
||||
Default lines 0:-1 (whole file)
|
||||
"""
|
||||
|
||||
@ -7,9 +7,7 @@ from .observation import Observation
|
||||
|
||||
@dataclass
|
||||
class AgentStateChangedObservation(Observation):
|
||||
"""
|
||||
This data class represents the result from delegating to another agent
|
||||
"""
|
||||
"""This data class represents the result from delegating to another agent"""
|
||||
|
||||
agent_state: str
|
||||
observation: str = ObservationType.AGENT_STATE_CHANGED
|
||||
|
||||
@ -7,9 +7,7 @@ from .observation import Observation
|
||||
|
||||
@dataclass
|
||||
class BrowserOutputObservation(Observation):
|
||||
"""
|
||||
This data class represents the output of a browser.
|
||||
"""
|
||||
"""This data class represents the output of a browser."""
|
||||
|
||||
url: str
|
||||
screenshot: str = field(repr=False) # don't show in repr
|
||||
|
||||
@ -7,9 +7,7 @@ from .observation import Observation
|
||||
|
||||
@dataclass
|
||||
class CmdOutputObservation(Observation):
|
||||
"""
|
||||
This data class represents the output of a command.
|
||||
"""
|
||||
"""This data class represents the output of a command."""
|
||||
|
||||
command_id: int
|
||||
command: str
|
||||
@ -30,9 +28,7 @@ class CmdOutputObservation(Observation):
|
||||
|
||||
@dataclass
|
||||
class IPythonRunCellObservation(Observation):
|
||||
"""
|
||||
This data class represents the output of a IPythonRunCellAction.
|
||||
"""
|
||||
"""This data class represents the output of a IPythonRunCellAction."""
|
||||
|
||||
code: str
|
||||
observation: str = ObservationType.RUN_IPYTHON
|
||||
|
||||
@ -7,9 +7,7 @@ from .observation import Observation
|
||||
|
||||
@dataclass
|
||||
class AgentDelegateObservation(Observation):
|
||||
"""
|
||||
This data class represents the result from delegating to another agent
|
||||
"""
|
||||
"""This data class represents the result from delegating to another agent"""
|
||||
|
||||
outputs: dict
|
||||
observation: str = ObservationType.DELEGATE
|
||||
|
||||
@ -7,8 +7,7 @@ from .observation import Observation
|
||||
|
||||
@dataclass
|
||||
class NullObservation(Observation):
|
||||
"""
|
||||
This data class represents a null observation.
|
||||
"""This data class represents a null observation.
|
||||
This is used when the produced action is NOT executable.
|
||||
"""
|
||||
|
||||
|
||||
@ -7,9 +7,7 @@ from .observation import Observation
|
||||
|
||||
@dataclass
|
||||
class ErrorObservation(Observation):
|
||||
"""
|
||||
This data class represents an error encountered by the agent.
|
||||
"""
|
||||
"""This data class represents an error encountered by the agent."""
|
||||
|
||||
observation: str = ObservationType.ERROR
|
||||
|
||||
|
||||
@ -7,9 +7,7 @@ from .observation import Observation
|
||||
|
||||
@dataclass
|
||||
class FileReadObservation(Observation):
|
||||
"""
|
||||
This data class represents the content of a file.
|
||||
"""
|
||||
"""This data class represents the content of a file."""
|
||||
|
||||
path: str
|
||||
observation: str = ObservationType.READ
|
||||
@ -21,9 +19,7 @@ class FileReadObservation(Observation):
|
||||
|
||||
@dataclass
|
||||
class FileWriteObservation(Observation):
|
||||
"""
|
||||
This data class represents a file write operation
|
||||
"""
|
||||
"""This data class represents a file write operation"""
|
||||
|
||||
path: str
|
||||
observation: str = ObservationType.WRITE
|
||||
|
||||
@ -7,9 +7,7 @@ from .observation import Observation
|
||||
|
||||
@dataclass
|
||||
class RejectObservation(Observation):
|
||||
"""
|
||||
This data class represents the result of a successful action.
|
||||
"""
|
||||
"""This data class represents the result of a successful action."""
|
||||
|
||||
observation: str = ObservationType.USER_REJECTED
|
||||
|
||||
|
||||
@ -7,9 +7,7 @@ from .observation import Observation
|
||||
|
||||
@dataclass
|
||||
class SuccessObservation(Observation):
|
||||
"""
|
||||
This data class represents the result of a successful action.
|
||||
"""
|
||||
"""This data class represents the result of a successful action."""
|
||||
|
||||
observation: str = ObservationType.SUCCESS
|
||||
|
||||
|
||||
@ -83,9 +83,7 @@ def event_to_memory(event: 'Event', max_message_chars: int) -> dict:
|
||||
|
||||
|
||||
def truncate_content(content: str, max_chars: int) -> str:
|
||||
"""
|
||||
Truncate the middle of the observation content if it is too long.
|
||||
"""
|
||||
"""Truncate the middle of the observation content if it is too long."""
|
||||
if len(content) <= max_chars:
|
||||
return content
|
||||
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
def remove_fields(obj, fields: set[str]):
|
||||
"""
|
||||
Remove fields from an object.
|
||||
"""Remove fields from an object.
|
||||
|
||||
Parameters:
|
||||
- obj: The dictionary, or list of dictionaries to remove fields from
|
||||
|
||||
@ -32,8 +32,7 @@ message_separator = '\n\n----------\n\n'
|
||||
|
||||
|
||||
class LLM:
|
||||
"""
|
||||
The LLM class represents a Language Model instance.
|
||||
"""The LLM class represents a Language Model instance.
|
||||
|
||||
Attributes:
|
||||
model_name (str): The name of the language model.
|
||||
@ -67,8 +66,7 @@ class LLM:
|
||||
input_cost_per_token=None,
|
||||
output_cost_per_token=None,
|
||||
):
|
||||
"""
|
||||
Initializes the LLM. If LLMConfig is passed, its values will be the fallback.
|
||||
"""Initializes the LLM. If LLMConfig is passed, its values will be the fallback.
|
||||
|
||||
Passing simple parameters always overrides config.
|
||||
|
||||
@ -213,10 +211,7 @@ class LLM:
|
||||
after=attempt_on_error,
|
||||
)
|
||||
def wrapper(*args, **kwargs):
|
||||
"""
|
||||
Wrapper for the litellm completion function. Logs the input and output of the completion function.
|
||||
"""
|
||||
|
||||
"""Wrapper for the litellm completion function. Logs the input and output of the completion function."""
|
||||
# some callers might just send the messages directly
|
||||
if 'messages' in kwargs:
|
||||
messages = kwargs['messages']
|
||||
@ -244,17 +239,14 @@ class LLM:
|
||||
|
||||
@property
|
||||
def completion(self):
|
||||
"""
|
||||
Decorator for the litellm completion function.
|
||||
"""Decorator for the litellm completion function.
|
||||
|
||||
Check the complete documentation at https://litellm.vercel.app/docs/completion
|
||||
"""
|
||||
return self._completion
|
||||
|
||||
def _post_completion(self, response: str) -> None:
|
||||
"""
|
||||
Post-process the completion response.
|
||||
"""
|
||||
"""Post-process the completion response."""
|
||||
try:
|
||||
cur_cost = self.completion_cost(response)
|
||||
except Exception:
|
||||
@ -267,8 +259,7 @@ class LLM:
|
||||
)
|
||||
|
||||
def get_token_count(self, messages):
|
||||
"""
|
||||
Get the number of tokens in a list of messages.
|
||||
"""Get the number of tokens in a list of messages.
|
||||
|
||||
Args:
|
||||
messages (list): A list of messages.
|
||||
@ -279,8 +270,7 @@ class LLM:
|
||||
return litellm.token_counter(model=self.model_name, messages=messages)
|
||||
|
||||
def is_local(self):
|
||||
"""
|
||||
Determines if the system is using a locally running LLM.
|
||||
"""Determines if the system is using a locally running LLM.
|
||||
|
||||
Returns:
|
||||
boolean: True if executing a local model.
|
||||
@ -295,8 +285,7 @@ class LLM:
|
||||
return False
|
||||
|
||||
def completion_cost(self, response):
|
||||
"""
|
||||
Calculate the cost of a completion response based on the model. Local models are treated as free.
|
||||
"""Calculate the cost of a completion response based on the model. Local models are treated as free.
|
||||
Add the current cost into total cost in metrics.
|
||||
|
||||
Args:
|
||||
|
||||
@ -4,8 +4,7 @@ from opendevin.llm.llm import LLM
|
||||
|
||||
class MemoryCondenser:
|
||||
def condense(self, summarize_prompt: str, llm: LLM):
|
||||
"""
|
||||
Attempts to condense the monologue by using the llm
|
||||
"""Attempts to condense the monologue by using the llm
|
||||
|
||||
Parameters:
|
||||
- llm (LLM): llm to be used for summarization
|
||||
@ -13,7 +12,6 @@ class MemoryCondenser:
|
||||
Raises:
|
||||
- Exception: the same exception as it got from the llm or processing the response
|
||||
"""
|
||||
|
||||
try:
|
||||
messages = [{'content': summarize_prompt, 'role': 'user'}]
|
||||
resp = llm.completion(messages=messages)
|
||||
|
||||
@ -19,8 +19,7 @@ from opendevin.events.stream import EventStream
|
||||
|
||||
|
||||
class ShortTermHistory(list[Event]):
|
||||
"""
|
||||
A list of events that represents the short-term memory of the agent.
|
||||
"""A list of events that represents the short-term memory of the agent.
|
||||
|
||||
This class provides methods to retrieve and filter the events in the history of the running agent from the event stream.
|
||||
"""
|
||||
@ -46,15 +45,11 @@ class ShortTermHistory(list[Event]):
|
||||
self._event_stream = event_stream
|
||||
|
||||
def get_events_as_list(self) -> list[Event]:
|
||||
"""
|
||||
Return the history as a list of Event objects.
|
||||
"""
|
||||
"""Return the history as a list of Event objects."""
|
||||
return list(self.get_events())
|
||||
|
||||
def get_events(self, reverse: bool = False) -> Iterable[Event]:
|
||||
"""
|
||||
Return the events as a stream of Event objects.
|
||||
"""
|
||||
"""Return the events as a stream of Event objects."""
|
||||
# TODO handle AgentRejectAction, if it's not part of a chunk ending with an AgentDelegateObservation
|
||||
# or even if it is, because currently we don't add it to the summary
|
||||
|
||||
@ -86,9 +81,7 @@ class ShortTermHistory(list[Event]):
|
||||
yield event
|
||||
|
||||
def get_last_action(self, end_id: int = -1) -> Action | None:
|
||||
"""
|
||||
Return the last action from the event stream, filtered to exclude unwanted events.
|
||||
"""
|
||||
"""Return the last action from the event stream, filtered to exclude unwanted events."""
|
||||
# from end_id in reverse, find the first action
|
||||
end_id = self._event_stream.get_latest_event_id() if end_id == -1 else end_id
|
||||
|
||||
@ -106,9 +99,7 @@ class ShortTermHistory(list[Event]):
|
||||
return last_action
|
||||
|
||||
def get_last_observation(self, end_id: int = -1) -> Observation | None:
|
||||
"""
|
||||
Return the last observation from the event stream, filtered to exclude unwanted events.
|
||||
"""
|
||||
"""Return the last observation from the event stream, filtered to exclude unwanted events."""
|
||||
# from end_id in reverse, find the first observation
|
||||
end_id = self._event_stream.get_latest_event_id() if end_id == -1 else end_id
|
||||
|
||||
@ -126,10 +117,7 @@ class ShortTermHistory(list[Event]):
|
||||
return last_observation
|
||||
|
||||
def get_last_user_message(self) -> str:
|
||||
"""
|
||||
Return the content of the last user message from the event stream.
|
||||
"""
|
||||
|
||||
"""Return the content of the last user message from the event stream."""
|
||||
last_user_message = next(
|
||||
(
|
||||
event.content
|
||||
@ -142,10 +130,7 @@ class ShortTermHistory(list[Event]):
|
||||
return last_user_message if last_user_message is not None else ''
|
||||
|
||||
def get_last_agent_message(self) -> str:
|
||||
"""
|
||||
Return the content of the last agent message from the event stream.
|
||||
"""
|
||||
|
||||
"""Return the content of the last agent message from the event stream."""
|
||||
last_agent_message = next(
|
||||
(
|
||||
event.content
|
||||
@ -159,9 +144,7 @@ class ShortTermHistory(list[Event]):
|
||||
return last_agent_message if last_agent_message is not None else ''
|
||||
|
||||
def get_last_events(self, n: int) -> list[Event]:
|
||||
"""
|
||||
Return the last n events from the event stream.
|
||||
"""
|
||||
"""Return the last n events from the event stream."""
|
||||
# dummy agent is using this
|
||||
# it should work, but it's not great to store temporary lists now just for a test
|
||||
end_id = self._event_stream.get_latest_event_id()
|
||||
@ -224,9 +207,7 @@ class ShortTermHistory(list[Event]):
|
||||
return history_pairs
|
||||
|
||||
def get_pairs(self) -> list[tuple[Action, Observation]]:
|
||||
"""
|
||||
Return the history as a list of tuples (action, observation).
|
||||
"""
|
||||
"""Return the history as a list of tuples (action, observation)."""
|
||||
tuples: list[tuple[Action, Observation]] = []
|
||||
action_map: dict[int, Action] = {}
|
||||
observation_map: dict[int, Observation] = {}
|
||||
|
||||
@ -108,14 +108,10 @@ class EmbeddingsLoader:
|
||||
|
||||
|
||||
class LongTermMemory:
|
||||
"""
|
||||
Handles storing information for the agent to access later, using chromadb.
|
||||
"""
|
||||
"""Handles storing information for the agent to access later, using chromadb."""
|
||||
|
||||
def __init__(self, agent_config_name='agent'):
|
||||
"""
|
||||
Initialize the chromadb and set up ChromaVectorStore for later use.
|
||||
"""
|
||||
"""Initialize the chromadb and set up ChromaVectorStore for later use."""
|
||||
db = chromadb.Client(chromadb.Settings(anonymized_telemetry=False))
|
||||
self.collection = db.get_or_create_collection(name='memories')
|
||||
vector_store = ChromaVectorStore(chroma_collection=self.collection)
|
||||
@ -131,8 +127,7 @@ class LongTermMemory:
|
||||
self._add_threads = []
|
||||
|
||||
def add_event(self, event: dict):
|
||||
"""
|
||||
Adds a new event to the long term memory with a unique id.
|
||||
"""Adds a new event to the long term memory with a unique id.
|
||||
|
||||
Parameters:
|
||||
- event (dict): The new event to be added to memory
|
||||
@ -165,8 +160,7 @@ class LongTermMemory:
|
||||
self.index.insert(doc)
|
||||
|
||||
def search(self, query: str, k: int = 10):
|
||||
"""
|
||||
Searches through the current memory using VectorIndexRetriever
|
||||
"""Searches through the current memory using VectorIndexRetriever
|
||||
|
||||
Parameters:
|
||||
- query (str): A query to match search results to
|
||||
|
||||
@ -177,7 +177,6 @@ class BrowserEnv:
|
||||
image: np.ndarray | Image.Image, add_data_prefix: bool = False
|
||||
):
|
||||
"""Convert a numpy array to a base64 encoded png image url."""
|
||||
|
||||
if isinstance(image, np.ndarray):
|
||||
image = Image.fromarray(image)
|
||||
if image.mode in ('RGBA', 'LA'):
|
||||
@ -197,7 +196,6 @@ class BrowserEnv:
|
||||
image: np.ndarray | Image.Image, add_data_prefix: bool = False
|
||||
):
|
||||
"""Convert a numpy array to a base64 encoded jpeg image url."""
|
||||
|
||||
if isinstance(image, np.ndarray):
|
||||
image = Image.fromarray(image)
|
||||
if image.mode in ('RGBA', 'LA'):
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
"""
|
||||
agentskills.py
|
||||
"""agentskills.py
|
||||
|
||||
This module provides various file manipulation skills for the OpenDevin agent.
|
||||
|
||||
@ -119,14 +118,12 @@ def _clamp(value, min_value, max_value):
|
||||
|
||||
|
||||
def _lint_file(file_path: str) -> tuple[Optional[str], Optional[int]]:
|
||||
"""
|
||||
Lint the file at the given path and return a tuple with a boolean indicating if there are errors,
|
||||
"""Lint the file at the given path and return a tuple with a boolean indicating if there are errors,
|
||||
and the line number of the first error, if any.
|
||||
|
||||
Returns:
|
||||
tuple[str, Optional[int]]: (lint_error, first_error_line_number)
|
||||
"""
|
||||
|
||||
if file_path.endswith('.py'):
|
||||
# Define the flake8 command with selected error codes
|
||||
def _command_fn(executable):
|
||||
@ -237,8 +234,7 @@ def _cur_file_header(current_file, total_lines) -> str:
|
||||
def open_file(
|
||||
path: str, line_number: int | None = 1, context_lines: int | None = WINDOW
|
||||
) -> None:
|
||||
"""
|
||||
Opens the file at the given path in the editor. If line_number is provided, the window will be moved to include that line.
|
||||
"""Opens the file at the given path in the editor. If line_number is provided, the window will be moved to include that line.
|
||||
It only shows the first 100 lines by default! Max `context_lines` supported is 2000, use `scroll up/down`
|
||||
to view the file if you want to see more.
|
||||
|
||||
@ -273,8 +269,7 @@ def open_file(
|
||||
|
||||
@update_pwd_decorator
|
||||
def goto_line(line_number: int) -> None:
|
||||
"""
|
||||
Moves the window to show the specified line number.
|
||||
"""Moves the window to show the specified line number.
|
||||
|
||||
Args:
|
||||
line_number: int: The line number to move to.
|
||||
@ -365,7 +360,6 @@ def _append_impl(lines, content):
|
||||
content: str: The new content of the file.
|
||||
n_added_lines: int: The number of lines added to the file.
|
||||
"""
|
||||
|
||||
content_lines = content.splitlines(keepends=True)
|
||||
n_added_lines = len(content_lines)
|
||||
if lines and not (len(lines) == 1 and lines[0].strip() == ''):
|
||||
@ -774,6 +768,7 @@ def insert_content_at_line(file_name: str, line_number: int, content: str) -> No
|
||||
def append_file(file_name: str, content: str) -> None:
|
||||
"""Append content to the given file.
|
||||
It appends text `content` to the end of the specified file.
|
||||
|
||||
Args:
|
||||
file_name: str: The name of the file to edit.
|
||||
line_number: int: The line number (starting from 1) to insert the content after.
|
||||
@ -910,8 +905,7 @@ def parse_pdf(file_path: str) -> None:
|
||||
|
||||
@update_pwd_decorator
|
||||
def parse_docx(file_path: str) -> None:
|
||||
"""
|
||||
Parses the content of a DOCX file and prints it.
|
||||
"""Parses the content of a DOCX file and prints it.
|
||||
|
||||
Args:
|
||||
file_path: str: The path to the file to open.
|
||||
@ -926,8 +920,7 @@ def parse_docx(file_path: str) -> None:
|
||||
|
||||
@update_pwd_decorator
|
||||
def parse_latex(file_path: str) -> None:
|
||||
"""
|
||||
Parses the content of a LaTex file and prints it.
|
||||
"""Parses the content of a LaTex file and prints it.
|
||||
|
||||
Args:
|
||||
file_path: str: The path to the file to open.
|
||||
@ -980,8 +973,7 @@ def _prepare_image_messages(task: str, base64_image: str):
|
||||
|
||||
@update_pwd_decorator
|
||||
def parse_audio(file_path: str, model: str = 'whisper-1') -> None:
|
||||
"""
|
||||
Parses the content of an audio file and prints it.
|
||||
"""Parses the content of an audio file and prints it.
|
||||
|
||||
Args:
|
||||
file_path: str: The path to the audio file to transcribe.
|
||||
@ -1002,8 +994,7 @@ def parse_audio(file_path: str, model: str = 'whisper-1') -> None:
|
||||
def parse_image(
|
||||
file_path: str, task: str = 'Describe this image as detail as possible.'
|
||||
) -> None:
|
||||
"""
|
||||
Parses the content of an image file and prints the description.
|
||||
"""Parses the content of an image file and prints the description.
|
||||
|
||||
Args:
|
||||
file_path: str: The path to the file to open.
|
||||
@ -1031,8 +1022,7 @@ def parse_video(
|
||||
task: str = 'Describe this image as detail as possible.',
|
||||
frame_interval: int = 30,
|
||||
) -> None:
|
||||
"""
|
||||
Parses the content of an image file and prints the description.
|
||||
"""Parses the content of an image file and prints the description.
|
||||
|
||||
Args:
|
||||
file_path: str: The path to the video file to open.
|
||||
@ -1076,8 +1066,7 @@ def parse_video(
|
||||
|
||||
@update_pwd_decorator
|
||||
def parse_pptx(file_path: str) -> None:
|
||||
"""
|
||||
Parses the content of a pptx file and prints it.
|
||||
"""Parses the content of a pptx file and prints it.
|
||||
|
||||
Args:
|
||||
file_path: str: The path to the file to open.
|
||||
|
||||
@ -16,8 +16,7 @@ logging.basicConfig(level=logging.INFO)
|
||||
|
||||
|
||||
def strip_ansi(o: str) -> str:
|
||||
"""
|
||||
Removes ANSI escape sequences from `o`, as defined by ECMA-048 in
|
||||
"""Removes ANSI escape sequences from `o`, as defined by ECMA-048 in
|
||||
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf
|
||||
|
||||
# https://github.com/ewen-lbh/python-strip-ansi/blob/master/strip_ansi/__init__.py
|
||||
@ -43,7 +42,6 @@ def strip_ansi(o: str) -> str:
|
||||
>>> strip_ansi('\\x1b[1m\\x1b[46m\\x1b[31mLorem dolor sit ipsum\\x1b[0m')
|
||||
'Lorem dolor sit ipsum'
|
||||
"""
|
||||
|
||||
# pattern = re.compile(r'/(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]/')
|
||||
pattern = re.compile(r'\x1B\[\d+(;\d+){0,2}m')
|
||||
stripped = pattern.sub('', o)
|
||||
|
||||
@ -35,7 +35,6 @@ class PluginMixin:
|
||||
|
||||
def init_plugins(self: SandboxProtocol, requirements: list[PluginRequirement]):
|
||||
"""Load a plugin into the sandbox."""
|
||||
|
||||
if hasattr(self, 'plugin_initialized') and self.plugin_initialized:
|
||||
return
|
||||
|
||||
|
||||
@ -28,8 +28,7 @@ from opendevin.storage import FileStore
|
||||
|
||||
|
||||
class Runtime:
|
||||
"""
|
||||
The runtime is how the agent interacts with the external environment.
|
||||
"""The runtime is how the agent interacts with the external environment.
|
||||
This includes a bash sandbox, a browser, and filesystem interactions.
|
||||
|
||||
sid is the session id, which is used to identify the current user session.
|
||||
@ -45,8 +44,7 @@ class Runtime:
|
||||
atexit.register(self.close_sync)
|
||||
|
||||
async def ainit(self) -> None:
|
||||
"""
|
||||
Initialize the runtime (asynchronously).
|
||||
"""Initialize the runtime (asynchronously).
|
||||
This method should be called after the runtime's constructor.
|
||||
"""
|
||||
pass
|
||||
@ -93,8 +91,7 @@ class Runtime:
|
||||
self.event_stream.add_event(observation, event.source) # type: ignore[arg-type]
|
||||
|
||||
async def run_action(self, action: Action) -> Observation:
|
||||
"""
|
||||
Run an action and return the resulting observation.
|
||||
"""Run an action and return the resulting observation.
|
||||
If the action is not runnable in any runtime, a NullObservation is returned.
|
||||
If the action is not supported by the current runtime, an ErrorObservation is returned.
|
||||
"""
|
||||
|
||||
@ -77,9 +77,7 @@ async def read_file(path, workdir, start=0, end=-1) -> Observation:
|
||||
def insert_lines(
|
||||
to_insert: list[str], original: list[str], start: int = 0, end: int = -1
|
||||
):
|
||||
"""
|
||||
Insert the new content to the original content based on start and end
|
||||
"""
|
||||
"""Insert the new content to the original content based on start and end"""
|
||||
new_lines = [''] if start == 0 else original[:start]
|
||||
new_lines += [i + '\n' for i in to_insert]
|
||||
new_lines += [''] if end == -1 else original[end:]
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
"""
|
||||
This module contains functions for building and managing the agnostic sandbox image.
|
||||
"""This module contains functions for building and managing the agnostic sandbox image.
|
||||
|
||||
This WILL BE DEPRECATED when EventStreamRuntime is fully implemented and adopted.
|
||||
"""
|
||||
@ -12,8 +11,7 @@ from opendevin.core.logger import opendevin_logger as logger
|
||||
|
||||
|
||||
def generate_dockerfile(base_image: str) -> str:
|
||||
"""
|
||||
Generate the Dockerfile content for the agnostic sandbox image based on user-provided base image.
|
||||
"""Generate the Dockerfile content for the agnostic sandbox image based on user-provided base image.
|
||||
|
||||
NOTE: This is only tested on debian yet.
|
||||
"""
|
||||
|
||||
@ -13,7 +13,6 @@ from opendevin.core.logger import opendevin_logger as logger
|
||||
|
||||
def _create_project_source_dist():
|
||||
"""Create a source distribution of the project. Return the path to the tarball."""
|
||||
|
||||
# Copy the project directory to the container
|
||||
# get the location of "opendevin" package
|
||||
project_root = os.path.dirname(os.path.dirname(os.path.abspath(opendevin.__file__)))
|
||||
@ -54,8 +53,7 @@ def _put_source_code_to_dir(temp_dir: str) -> str:
|
||||
def _generate_dockerfile(
|
||||
base_image: str, source_code_dirname: str, skip_init: bool = False
|
||||
) -> str:
|
||||
"""
|
||||
Generate the Dockerfile content for the eventstream runtime image based on user-provided base image.
|
||||
"""Generate the Dockerfile content for the eventstream runtime image based on user-provided base image.
|
||||
|
||||
NOTE: This is only tested on debian yet.
|
||||
"""
|
||||
|
||||
@ -6,8 +6,7 @@ from opendevin.core.logger import opendevin_logger as logger
|
||||
|
||||
|
||||
def get_sid_from_token(token: str) -> str:
|
||||
"""
|
||||
Retrieves the session id from a JWT token.
|
||||
"""Retrieves the session id from a JWT token.
|
||||
|
||||
Parameters:
|
||||
token (str): The JWT token from which the session id is to be extracted.
|
||||
|
||||
@ -55,8 +55,7 @@ security_scheme = HTTPBearer()
|
||||
|
||||
|
||||
def load_file_upload_config() -> tuple[int, bool, list[str]]:
|
||||
"""
|
||||
Load file upload configuration from the config object.
|
||||
"""Load file upload configuration from the config object.
|
||||
|
||||
This function retrieves the file upload settings from the global config object.
|
||||
It handles the following settings:
|
||||
@ -115,8 +114,7 @@ MAX_FILE_SIZE_MB, RESTRICT_FILE_TYPES, ALLOWED_EXTENSIONS = load_file_upload_con
|
||||
|
||||
|
||||
def is_extension_allowed(filename):
|
||||
"""
|
||||
Check if the file extension is allowed based on the current configuration.
|
||||
"""Check if the file extension is allowed based on the current configuration.
|
||||
|
||||
This function supports wildcards and files without extensions.
|
||||
The check is case-insensitive for extensions.
|
||||
@ -140,8 +138,7 @@ def is_extension_allowed(filename):
|
||||
|
||||
@app.middleware('http')
|
||||
async def attach_session(request: Request, call_next):
|
||||
"""
|
||||
Middleware to attach session information to the request.
|
||||
"""Middleware to attach session information to the request.
|
||||
|
||||
This middleware checks for the Authorization header, validates the token,
|
||||
and attaches the corresponding session to the request state.
|
||||
@ -189,13 +186,13 @@ async def attach_session(request: Request, call_next):
|
||||
|
||||
@app.websocket('/ws')
|
||||
async def websocket_endpoint(websocket: WebSocket):
|
||||
"""
|
||||
WebSocket endpoint for receiving events from the client (i.e., the browser).
|
||||
"""WebSocket endpoint for receiving events from the client (i.e., the browser).
|
||||
Once connected, the client can send various actions:
|
||||
- Initialize the agent:
|
||||
session management, and event streaming.
|
||||
```json
|
||||
{"action": "initialize", "args": {"LLM_MODEL": "ollama/llama3", "AGENT": "CodeActAgent", "LANGUAGE": "en", "LLM_API_KEY": "ollama"}}
|
||||
|
||||
Args:
|
||||
```
|
||||
websocket (WebSocket): The WebSocket connection object.
|
||||
@ -284,8 +281,7 @@ async def websocket_endpoint(websocket: WebSocket):
|
||||
|
||||
@app.get('/api/options/models')
|
||||
async def get_litellm_models():
|
||||
"""
|
||||
Get all models supported by LiteLLM.
|
||||
"""Get all models supported by LiteLLM.
|
||||
|
||||
This function combines models from litellm and Bedrock, removing any
|
||||
error-prone Bedrock models.
|
||||
@ -326,8 +322,7 @@ async def get_litellm_models():
|
||||
|
||||
@app.get('/api/options/agents')
|
||||
async def get_agents():
|
||||
"""
|
||||
Get all agents supported by LiteLLM.
|
||||
"""Get all agents supported by LiteLLM.
|
||||
|
||||
To get the agents:
|
||||
```sh
|
||||
@ -343,8 +338,7 @@ async def get_agents():
|
||||
|
||||
@app.get('/api/list-files')
|
||||
def list_files(request: Request, path: str = '/'):
|
||||
"""
|
||||
List files in the specified path.
|
||||
"""List files in the specified path.
|
||||
|
||||
This function retrieves a list of files from the agent's runtime file store,
|
||||
excluding certain system and hidden files/directories.
|
||||
@ -453,8 +447,7 @@ def list_files(request: Request, path: str = '/'):
|
||||
|
||||
@app.get('/api/select-file')
|
||||
def select_file(file: str, request: Request):
|
||||
"""
|
||||
Retrieve the content of a specified file.
|
||||
"""Retrieve the content of a specified file.
|
||||
|
||||
To select a file:
|
||||
```sh
|
||||
@ -484,9 +477,7 @@ def select_file(file: str, request: Request):
|
||||
|
||||
|
||||
def sanitize_filename(filename):
|
||||
"""
|
||||
Sanitize the filename to prevent directory traversal
|
||||
"""
|
||||
"""Sanitize the filename to prevent directory traversal"""
|
||||
# Remove any directory components
|
||||
filename = os.path.basename(filename)
|
||||
# Remove any non-alphanumeric characters except for .-_
|
||||
@ -501,8 +492,7 @@ def sanitize_filename(filename):
|
||||
|
||||
@app.post('/api/upload-files')
|
||||
async def upload_file(request: Request, files: list[UploadFile]):
|
||||
"""
|
||||
Upload a list of files to the workspace.
|
||||
"""Upload a list of files to the workspace.
|
||||
|
||||
To upload a files:
|
||||
```sh
|
||||
@ -580,8 +570,7 @@ async def upload_file(request: Request, files: list[UploadFile]):
|
||||
|
||||
@app.post('/api/submit-feedback')
|
||||
async def submit_feedback(request: Request, feedback: FeedbackDataModel):
|
||||
"""
|
||||
Submit user feedback.
|
||||
"""Submit user feedback.
|
||||
|
||||
This function stores the provided feedback data.
|
||||
|
||||
@ -614,8 +603,7 @@ async def submit_feedback(request: Request, feedback: FeedbackDataModel):
|
||||
|
||||
@app.get('/api/root_task')
|
||||
def get_root_task(request: Request):
|
||||
"""
|
||||
Retrieve the root task of the current agent session.
|
||||
"""Retrieve the root task of the current agent session.
|
||||
|
||||
To get the root_task:
|
||||
```sh
|
||||
@ -644,8 +632,7 @@ def get_root_task(request: Request):
|
||||
|
||||
@app.get('/api/defaults')
|
||||
async def appconfig_defaults():
|
||||
"""
|
||||
Retrieve the default configuration settings.
|
||||
"""Retrieve the default configuration settings.
|
||||
|
||||
To get the default configurations:
|
||||
```sh
|
||||
@ -660,8 +647,7 @@ async def appconfig_defaults():
|
||||
|
||||
@app.post('/api/save-file')
|
||||
async def save_file(request: Request):
|
||||
"""
|
||||
Save a file to the agent's runtime file store.
|
||||
"""Save a file to the agent's runtime file store.
|
||||
|
||||
This endpoint allows saving a file when the agent is in a paused, finished,
|
||||
or awaiting user input state. It checks the agent's state before proceeding
|
||||
|
||||
@ -64,14 +64,6 @@ reportlab = "*"
|
||||
concurrency = ["gevent"]
|
||||
|
||||
|
||||
[tool.poetry.group.evaluation.dependencies]
|
||||
streamlit = "*"
|
||||
whatthepatch = "*"
|
||||
retry = "*"
|
||||
evaluate = "*"
|
||||
swebench = { git = "https://github.com/OpenDevin/SWE-bench.git" }
|
||||
|
||||
|
||||
[tool.poetry.group.runtime.dependencies]
|
||||
jupyterlab = "*"
|
||||
notebook = "*"
|
||||
@ -96,3 +88,19 @@ ignore = [ "E501" ]
|
||||
[tool.black]
|
||||
# prevent black (if installed) from changing single quotes to double quotes
|
||||
skip-string-normalization = true
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = ["D"]
|
||||
# ignore warnings for missing docstrings
|
||||
ignore = ["D1"]
|
||||
|
||||
[tool.ruff.lint.pydocstyle]
|
||||
convention = "google"
|
||||
|
||||
|
||||
[tool.poetry.group.evaluation.dependencies]
|
||||
streamlit = "*"
|
||||
whatthepatch = "*"
|
||||
retry = "*"
|
||||
evaluate = "*"
|
||||
swebench = { git = "https://github.com/OpenDevin/SWE-bench.git" }
|
||||
|
||||
@ -42,8 +42,7 @@ def get_log_id(prompt_log_name):
|
||||
|
||||
|
||||
def apply_prompt_and_get_mock_response(test_name: str, messages: str, id: int) -> str:
|
||||
"""
|
||||
Apply the mock prompt, and find mock response based on id.
|
||||
"""Apply the mock prompt, and find mock response based on id.
|
||||
If there is no matching response file, return None.
|
||||
|
||||
Note: this function blindly replaces existing prompt file with the given
|
||||
@ -67,8 +66,7 @@ def apply_prompt_and_get_mock_response(test_name: str, messages: str, id: int) -
|
||||
|
||||
|
||||
def get_mock_response(test_name: str, messages: str, id: int) -> str:
|
||||
"""
|
||||
Find mock response based on prompt. Prompts are stored under nested
|
||||
"""Find mock response based on prompt. Prompts are stored under nested
|
||||
folders under mock folder. If prompt_{id}.log matches,
|
||||
then the mock response we're looking for is at response_{id}.log.
|
||||
|
||||
|
||||
@ -41,9 +41,7 @@ def test_all_agents_are_loaded():
|
||||
|
||||
|
||||
def test_coder_agent_with_summary(event_stream: EventStream):
|
||||
"""
|
||||
Coder agent should render code summary as part of prompt
|
||||
"""
|
||||
"""Coder agent should render code summary as part of prompt"""
|
||||
mock_llm = MagicMock()
|
||||
content = json.dumps({'action': 'finish', 'args': {}})
|
||||
mock_llm.completion.return_value = {'choices': [{'message': {'content': content}}]}
|
||||
@ -69,8 +67,7 @@ def test_coder_agent_with_summary(event_stream: EventStream):
|
||||
|
||||
|
||||
def test_coder_agent_without_summary(event_stream: EventStream):
|
||||
"""
|
||||
When there's no codebase_summary available, there shouldn't be any prompt
|
||||
"""When there's no codebase_summary available, there shouldn't be any prompt
|
||||
about 'code summary'
|
||||
"""
|
||||
mock_llm = MagicMock()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user