add basic tools

This commit is contained in:
heroding77
2024-04-25 06:38:49 +00:00
parent e6189ae1ad
commit 6b8cddccb6
13 changed files with 741 additions and 12 deletions

View File

@@ -4,5 +4,6 @@ Tool Repository
.. toctree::
:maxdepth: 2
tool_repository_doc/tool_manager
tool_repository_doc/api_tools
tool_repository_doc/api_tools
tool_repository_doc/basic_tools
tool_repository_doc/tool_manager

View File

@@ -0,0 +1,7 @@
Basic Tools
==============================
.. autoclass:: oscopilot.tool_repository.basic_tools.text_extractor.TextExtractor
:members:
:undoc-members:
:show-inheritance:

View File

View File

@@ -79,4 +79,32 @@ class BaseModule:
except json.JSONDecodeError as e:
return f"Error parsing JSON data: {e}"
else:
return "No JSON data found in the string."
return "No JSON data found in the string."
def extract_list_from_string(self, text):
"""
Extracts a list of task descriptions from a given string containing enumerated tasks.
This function ensures that only text immediately following a numbered bullet is captured,
and it stops at the first newline character or at the next number, preventing the inclusion of subsequent non-numbered lines or empty lines.
Parameters:
text (str): A string containing multiple enumerated tasks. Each task is numbered and followed by its description.
Returns:
list[str]: A list of strings, each representing the description of a task extracted from the input string.
"""
# Regular expression pattern:
# \d+\. matches one or more digits followed by a dot, indicating the task number.
# \s+ matches one or more whitespace characters after the dot.
# ([^\n]*?) captures any sequence of characters except newlines (non-greedy) as the task description.
# (?=\n\d+\.|\n\Z|\n\n) is a positive lookahead that matches a position followed by either a newline with digits and a dot (indicating the start of the next task),
# or the end of the string, or two consecutive newlines (indicating a break between tasks or end of content).
task_pattern = r'\d+\.\s+([^\n]*?)(?=\n\d+\.|\n\Z|\n\n)'
# Use the re.findall function to search for all matches of the pattern in the input text.
data_list = re.findall(task_pattern, text)
# Return the list of matched task descriptions.
return data_list

View File

@@ -1 +1,2 @@
from .friday_planner import *
from .friday_planner import *
from .basic_planner import *

View File

@@ -0,0 +1,238 @@
from oscopilot.tool_repository.manager.action_node import ActionNode
from collections import defaultdict, deque
from oscopilot.modules.base_module import BaseModule
from oscopilot.tool_repository.manager.tool_manager import get_open_api_description_pair
from oscopilot.utils.utils import send_chat_prompts
import json
import sys
import logging
class BasicPlanner(BaseModule):
"""
A planning module responsible for decomposing complex tasks into manageable subtasks, replanning tasks based on new insights or failures, and managing the execution order of tasks.
The `BasicPlanner` uses a combination of tool descriptions, environmental state, and language learning models to dynamically create and adjust plans for task execution. It maintains a tool list to manage task dependencies and execution order, ensuring that tasks are executed in a sequence that respects their interdependencies.
"""
def __init__(self, prompt):
super().__init__()
self.subtask_num = 0
self.prompt = prompt
self.global_messages = []
self.sub_task_list = []
def reset_plan(self):
"""
Resets global messages and subtask list to their initial states.
"""
self.subtask_num = 0
self.global_messages = []
self.sub_task_list = []
def decompose_task(self, task):
"""
Decomposes a complex task into manageable subtasks.
This method takes a high-level task and utilizes the environments's current state
to format and send a decomposition request to the language learning model. It then
parses the response to construct and update the tool list with the decomposed subtasks.
Args:
task (str): The complex task to be decomposed.
"""
sys_prompt = self.prompt['_SYSTEM_TASK_DECOMPOSE_PROMPT']
user_prompt = self.prompt['_USER_TASK_DECOMPOSE_PROMPT'].format(
system_version=self.system_version,
task=task,
working_dir=self.environment.working_dir
)
response = send_chat_prompts(sys_prompt, user_prompt, self.llm)
print(response)
task_list = self.extract_list_from_string(response)
self.sub_task_list = task_list
self.subtask_num = len(task_list)
def replan_task(self, reasoning, current_task, relevant_tool_description_pair):
"""
Replans the current task by integrating new tools into the original tool graph.
Given the reasoning for replanning and the current task, this method generates a new
tool plan incorporating any relevant tools. It formats a replanning request, sends
it to the language learning model, and integrates the response (new tools) into the
existing tool graph. The graph is then updated to reflect the new dependencies and
re-sorted topologically.
Args:
reasoning (str): The reasoning or justification for replanning the task.
current_task (str): The identifier of the current task being replanned.
relevant_tool_description_pair (dict): A dictionary mapping relevant tool names to
their descriptions for replanning.
Side Effects:
Modifies the tool graph to include new tools and updates the execution order
of tools within the graph.
"""
# current_task information
current_tool = self.tool_node[current_task]
current_task_description = current_tool.description
relevant_tool_description_pair = json.dumps(relevant_tool_description_pair)
files_and_folders = self.environment.list_working_dir()
sys_prompt = self.prompt['_SYSTEM_TASK_REPLAN_PROMPT']
user_prompt = self.prompt['_USER_TASK_REPLAN_PROMPT'].format(
current_task = current_task,
current_task_description = current_task_description,
system_version=self.system_version,
reasoning = reasoning,
tool_list = relevant_tool_description_pair,
working_dir = self.environment.working_dir,
files_and_folders = files_and_folders
)
response = send_chat_prompts(sys_prompt, user_prompt, self.llm)
new_tool = self.extract_json_from_string(response)
# add new tool to tool graph
self.add_new_tool(new_tool, current_task)
# update topological sort
self.topological_sort()
def update_tool(self, tool, return_val='', relevant_code=None, status=False, node_type='Code'):
"""
Updates the specified tool's node information within the tool graph.
This method allows updating an tool's return value, relevant code, execution status,
and node_type. It is particularly useful for modifying tools' details after their execution
or during the replanning phase.
Args:
tool (str): The tool identifier whose details are to be updated.
return_val (str, optional): The return value of the tool. Default is an empty string.
relevant_code (str, optional): Any relevant code associated with the tool. Default is None.
status (bool, optional): The execution status of the tool. Default is False.
node_type (str, optional): The node_type of the tool (e.g., 'Code'). Default is 'Code'.
Side Effects:
Updates the information of the specified tool node within the tool graph.
"""
if return_val:
if node_type=='Code':
return_val = self.extract_information(return_val, "<return>", "</return>")
print("************************<return>**************************")
logging.info(return_val)
print(return_val)
print("************************</return>*************************")
if return_val != 'None':
self.tool_node[tool]._return_val = return_val
if relevant_code:
self.tool_node[tool]._relevant_code = relevant_code
self.tool_node[tool]._status = status
def get_tool_list(self, relevant_tool=None):
"""
Retrieves a list of all tools or a subset of relevant tools, including their names and descriptions.
This method fetches tool descriptions from the tool library. If a specific set of relevant tools
is provided, it filters the list to include only those tools. The resulting list (or the full list if
no relevant tools are specified) is then returned in JSON format.
Args:
relevant_tool (list, optional): A list of tool names to filter the returned tools by.
If None, all tools are included. Defaults to None.
Returns:
A JSON string representing a dictionary of tool names to their descriptions.
The dictionary includes either all tools from the library or only those specified as relevant.
"""
tool_dict = self.tool_manager.descriptions
if not relevant_tool:
return json.dumps(tool_dict)
relevant_tool_dict = {tool : description for tool ,description in tool_dict.items() if tool in relevant_tool}
relevant_tool_list = json.dumps(relevant_tool_dict)
return relevant_tool_list
def create_tool_graph(self, decompose_json):
"""
Constructs an tool graph based on dependencies specified in the given JSON.
This method takes a JSON object containing task information and dependencies,
and constructs an tool graph. Each task is added as a node in the graph, with
directed edges representing task dependencies. The method updates the class's
internal structures to reflect this graph, including tool nodes and their
relationships, as well as the overall number of tools.
Args:
decompose_json (dict): A JSON object where each key is an tool name, and the value
is a dictionary containing the tool's name, description,
type, and dependencies.
Side Effects:
Modifies the internal state by updating `tool_num`, `tool_node`, and `tool_graph`
to reflect the newly created tool graph.
"""
for _, task_info in decompose_json.items():
self.tool_num += 1
task_name = task_info['name']
task_description = task_info['description']
task_type = task_info['type']
task_dependencies = task_info['dependencies']
self.tool_node[task_name] = ActionNode(task_name, task_description, task_type)
self.tool_graph[task_name] = task_dependencies
for pre_tool in self.tool_graph[task_name]:
self.tool_node[pre_tool].next_action[task_name] = task_description
def add_new_tool(self, new_task_json, current_task):
"""
Incorporates a new tool into the existing tool graph based on its dependencies.
This method processes a JSON object representing a new task, including its name,
description, type, and dependencies, and adds it to the tool graph. It also updates
the tool nodes to reflect this new addition. Finally, it appends the last new task
to the list of dependencies for the specified current task.
Args:
new_task_json (dict): A JSON object containing the new task's details.
current_task (str): The name of the current task to which the new task's dependencies will be added.
Side Effects:
Updates the tool graph and nodes to include the new tool and its dependencies.
Modifies the dependencies of the current task to include the new tool.
"""
for _, task_info in new_task_json.items():
self.tool_num += 1
task_name = task_info['name']
task_description = task_info['description']
task_type = task_info['type']
task_dependencies = task_info['dependencies']
self.tool_node[task_name] = ActionNode(task_name, task_description, task_type)
self.tool_graph[task_name] = task_dependencies
for pre_tool in self.tool_graph[task_name]:
self.tool_node[pre_tool].next_action[task_name] = task_description
last_new_task = list(new_task_json.keys())[-1]
self.tool_graph[current_task].append(last_new_task)
def get_pre_tasks_info(self, current_task):
"""
Retrieves information about the prerequisite tasks for a given current task.
This method collects and formats details about all tasks that are prerequisites
for the specified current task. It extracts descriptions and return values for
each prerequisite task and compiles this information into a JSON string.
Args:
current_task (str): The name of the task for which prerequisite information is requested.
Returns:
A JSON string representing a dictionary, where each key is a prerequisite task's
name, and the value is a dictionary with the task's description and return value.
"""
pre_tasks_info = {}
for task in self.tool_graph[current_task]:
task_info = {
"description" : self.tool_node[task].description,
"return_val" : self.tool_node[task].return_val
}
pre_tasks_info[task] = task_info
pre_tasks_info = json.dumps(pre_tasks_info)
return pre_tasks_info

View File

@@ -0,0 +1,379 @@
"""
This modules contains a comprehensive `prompts` dictionary that serves as a repository of prompts for guiding the AI agents's interactions across various operational scenarios, including execution, planning, and information retrieval tasks. These prompts are meticulously crafted to instruct the AI in performing its duties, ranging from code generation and amendment to task decomposition and planning, as well as error analysis and tool usage.
The dictionary is segmented into three main categories:
1. **execute_prompt**: Contains prompts for execution-related tasks, such as code generation, invocation, amendment, and error judgment. These are further detailed for system actions and user interactions, facilitating a diverse range of programming and troubleshooting tasks.
2. **planning_prompt**: Focuses on task planning and re-planning, decomposing complex tasks into manageable sub-tasks, and adapting plans based on unforeseen issues, ensuring that the AI can assist in project management and task organization effectively.
3. **retrieve_prompt**: Dedicated to information retrieval, including filtering code snippets based on specific criteria, aiding the AI in sourcing and suggesting code solutions efficiently.
Each category comprises system and user prompts, where system prompts define the AI's task or query in detail, and user prompts typically include placeholders for dynamic information insertion, reflecting the context or specific requirements of the task at hand.
Usage:
The `prompts` dictionary is utilized by the AI agents to dynamically select appropriate prompts based on the current context or task, ensuring relevant and precise guidance for each operation. This dynamic approach allows the AI to adapt its interactions and responses to suit a wide array of programming and operational needs, enhancing its utility and effectiveness in assisting users.
Example:
.. code-block:: python
# Accessing a specific prompts for task execution
execute_prompt = prompts['execute_prompt']['_SYSTEM_SKILL_CREATE_AND_INVOKE_PROMPT']
"""
prompt = {
'execute_prompt': {
# shell/applescript generator
'_SYSTEM_SHELL_APPLESCRIPT_GENERATE_PROMPT': '''
You are a world-class programmer that can complete any task by executing code, your goal is to generate the corresponding code based on the type of code to complete the task.
You could only respond with a code.
Shell code output Format:
```shell
shell code
```
AppleScript code output Format:
```applescript
applescript code
```
''',
'_USER_SHELL_APPLESCRIPT_GENERATE_PROMPT': '''
User's information is as follows:
System Version: {system_version}
System language: simplified chinese
Working Directory: {working_dir}
Task Name: {task_name}
Task Description: {task_description}
Information of Prerequisite Tasks: {pre_tasks_info}
Code Type: {Type}
Detailed description of user information:
1. 'Working Directory' represents the working directory. It may not necessarily be the same as the current working directory. If the files or folders mentioned in the task do not specify a particular directory, then by default, they are assumed to be in the working directory. This can help you understand the paths of files or folders in the task to facilitate your generation of the call.
2. 'Information of Prerequisite Tasks' provides relevant information about the prerequisite tasks for the current task, encapsulated in a dictionary format. The key is the name of the prerequisite task, and the value consists of two parts: 'description', which is the description of the task, and 'return_val', which is the return information of the task.
3, 'Code Type' represents the type of code to be generated.
''',
# Python generate and invoke prompts in os
'_SYSTEM_PYTHON_SKILL_AND_INVOKE_GENERATE_PROMPT': '''
You are a world-class programmer that can complete any task by executing code, your goal is to generate the function code that accomplishes the task, along with the function's invocation.
You could only respond with a python code and a invocation statement.
Output Format:
```python
python code
```
<invoke>invocation statement</invoke>
The code you write should follow the following criteria:
1. Function name should be the same as the 'Task Name' provided by the user.
2. The function you generate is a general-purpose tool that can be reused in different scenarios. Therefore, variables should not be hard-coded within the function; instead, they should be abstracted into parameters that users can pass in. These parameters are obtained by parsing information and descriptions related to the task, and named with as generic names as possible.
3. The parameters of the function should be designed into suitable data structures based on the characteristics of the extracted information.
4. The code should be well-documented, with detailed comments that explain the function's purpose and the role of each parameter. It should also follow a standardized documentation format: A clear explanation of what the function does. Args: A detailed description of each input parameter, including its type and purpose. Returns: An explanation of the function's return value, including the type of the return value and what it represents.
5. The code logic should be clear and highly readable, able to meet the requirements of the task.
6. The function must have a return value. If there is no return value, it can return information indicating that the task has been completed.
7. If the 'Relevant Code' section contains code that directly addresses the current task, please reuse it without any modifications.
8. If the current task requires the use of the return results from a preceding task, then its corresponding call method must include a parameter specifically for receiving the return results of the preceding task.
9. If the current task depends on the results from a previous task, the function must include a parameter designed to accept the results from that previous task.
10. If the code involves the output of file paths, ensure that the output includes the files' absolute path.
11. If related Python packages are used within the function, they need to be imported before the function.
And the invocation statement should also follow the following criteria:
1. The Python function invocation must be syntactically correct as per Python standards.
2. Fill in the corresponding parameters according to the relevant information of the task and the description of the function's parameters.
3. If the invocation requires the output of prerequisite tasks, you can obtain relevant information from 'Information of Prerequisite Tasks'.
Now you will be provided with the following information, please write python code to accomplish the task and be compatible with system environments, versions and language according to these information.
''',
'_USER_PYTHON_SKILL_AND_INVOKE_GENERATE_PROMPT': '''
User's information is as follows:
System Version: {system_version}
System language: simplified chinese
Working Directory: {working_dir}
Task Name: {task_name}
Task Description: {task_description}
Information of Prerequisite Tasks: {pre_tasks_info}
Relevant Code: {relevant_code}
Detailed description of user information:
1. 'Working Directory' represents the working directory. It may not necessarily be the same as the current working directory. If the files or folders mentioned in the task do not specify a particular directory, then by default, they are assumed to be in the working directory. This can help you understand the paths of files or folders in the task to facilitate your generation of the call.
2. 'Information of Prerequisite Tasks' provides relevant information about the prerequisite tasks for the current task, encapsulated in a dictionary format. The key is the name of the prerequisite task, and the value consists of two parts: 'description', which is the description of the task, and 'return_val', which is the return information of the task.
3. 'Relevant Code' provides some function codes that may be capable of solving the current task.
''',
# shell/applescript amend in os
'_SYSTEM_SHELL_APPLESCRIPT_AMEND_PROMPT': '''
You are an expert in programming, with a focus on diagnosing and resolving code issues.
Your goal is to precisely identify the reasons for failure in the existing code and implement effective modifications to ensure it accomplishes the intended task without errors.
You should only respond with a modified code.
Code in the format as described below:
1. Error Analysis: Conduct a step-by-step analysis to identify why the code is generating errors or failing to complete the task. This involves checking for syntax errors, logical flaws, and any other issues that might hinder execution.
2. Detailed Explanation: Provide a clear and comprehensive explanation for each identified issue, along with possible solutions.
3. Modified Code: Based on the error analysis, the original code is modified to fix all the problems and provide the final correct code to the user to accomplish the target task. If the code is error free, fix and refine the code based on the 'Critique On The Code' provided by the user to accomplish the target task.
And the code you write should also follow the following criteria:
1. The code logic should be clear and highly readable, able to meet the requirements of the task.
2. The code must be enclosed between ```[code type] and ```. For example, ```shell [shell code] ```.
3. The analysis and explanations must be clear, brief and easy to understand, even for those with less programming experience.
4. All modifications must address the specific issues identified in the error analysis.
5. The solution must enable the code to successfully complete the intended task without errors.
6. When Critique On The Code in User's information is empty, it means that there is an error in the code itself, you should fix the error in the code so that it can accomplish the current task.
Now you will be provided with the following information, please give your modified code according to these information:
''',
'_USER_SHELL_APPLESCRIPT_AMEND_PROMPT': '''
User's information are as follows:
Original Code: {original_code}
Task: {task}
Error Messages: {error}
Code Output: {code_output}
Current Working Directiory: {current_working_dir}
Working Directiory: {working_dir}
Files And Folders in Current Working Directiory: {files_and_folders}
Critique On The Code: {critique}
Information of Prerequisite Tasks: {pre_tasks_info}
Detailed description of user information:
1. 'Original Code' represents the code that needs to be modified to accomplish the task.
2. 'Error Messages' refers to the error messages generated by the code, which may help you identify the issues in the code.
3. 'Code Output' represents the output of the code, which may provide information on the code's execution status.
4. 'Working Directory' represents the root directory of the working directory, and 'Current Working Directory' represents the directory where the current task is located.
5. 'Critique On The Code' refers to code modification suggestions given by other code experts and may be empty.
6. 'Information of Prerequisite Tasks' from User's information provides relevant information about the prerequisite tasks for the current task, encapsulated in a dictionary format. The key is the name of the prerequisite task, and the value consists of two parts: 'description', which is the description of the task, and 'return_val', which is the return information of the task.
''',
# Python amend and invoke prompts in os
'_SYSTEM_PYTHON_SKILL_AMEND_AND_INVOKE_PROMPT': '''
You are an expert in Python programming, with a focus on diagnosing and resolving code issues.
Your goal is to precisely identify the reasons for failure in the existing Python code and implement effective modifications to ensure it accomplishes the intended task without errors.
You should only respond with a python code and a invocation statement.
Python code in the format as described below:
1. Error Analysis: Conduct a step-by-step analysis to identify why the code is generating errors or failing to complete the task. This involves checking for syntax errors, logical flaws, and any other issues that might hinder execution.
2. Detailed Explanation: Provide a clear and comprehensive explanation for each identified issue, along with possible solutions.
3. Modified Code: Based on the error analysis, the original code is modified to fix all the problems and provide the final correct code to the user to accomplish the target task. If the code is error free, fix and refine the code based on the 'Critique On The Code' provided by the user to accomplish the target task.
invocation statement in the format as described below:
1. Parameter Details Interpretation: Understand the parameter comments of the function. This will help select the correct parameters to fill in the invocation statement.
2. Task Description Analysis: Analyze the way the code is called based on the current task, the generated code, and the Information of Prerequisite Tasks.
3. Generating Invocation Statement: Construct the function call statement based on the analysis results above.
4. Output Format: The final output should include the invocation statement, which must be enclosed in <invoke></invoke> tags. For example, <invoke>function()</invoke>.
And the code you write should also follow the following criteria:
1. You must keep the original function name.
2. The code logic should be clear and highly readable, able to meet the requirements of the task.
3. The python code must be enclosed between ```python and ```.
4. The analysis and explanations must be clear, brief and easy to understand, even for those with less programming experience.
5. All modifications must address the specific issues identified in the error analysis.
6. The solution must enable the code to successfully complete the intended task without errors.
7. When Critique On The Code in User's information is empty, it means that there is an error in the code itself, you should fix the error in the code so that it can accomplish the current task.
And the invocation statement should also follow the following criteria:
1. The Python function invocation must be syntactically correct as per Python standards.
2. Clearly identify any fake or placeholder parameters used in the invocation.
3. If the execution of the current task's code requires the return value of a prerequisite task, the return information of the prerequisite task can assist you in generating the code execution for the current task.
4. The function includes detailed comments for input and output parameters. If there are errors related to parameter data structures, these comments can be referred to for writing the appropriate data structures.
5. When generating the function call, all required parameter information must be filled in without any omissions.
Now you will be provided with the following information, please give your modified python code and invocation statement according to these information:
''',
'_USER_PYTHON_SKILL_AMEND_AND_INVOKE_PROMPT': '''
User's information are as follows:
Original Code: {original_code}
Task: {task}
Error Messages: {error}
Code Output: {code_output}
Current Working Directiory: {current_working_dir}
Working Directiory: {working_dir}
Files And Folders in Current Working Directiory: {files_and_folders}
Critique On The Code: {critique}
Information of Prerequisite Tasks: {pre_tasks_info}
Detailed description of user information:
1. 'Original Code' represents the code that needs to be modified to accomplish the task.
2. 'Error Messages' refers to the error messages generated by the code, which may help you identify the issues in the code.
3. 'Code Output' represents the output of the code, which may provide information on the code's execution status.
4. 'Working Directory' represents the root directory of the working directory, and 'Current Working Directory' represents the directory where the current task is located.
5. 'Critique On The Code' refers to code modification suggestions given by other code experts and may be empty.
6. 'Information of Prerequisite Tasks' from User's information provides relevant information about the prerequisite tasks for the current task, encapsulated in a dictionary format. The key is the name of the prerequisite task, and the value consists of two parts: 'description', which is the description of the task, and 'return_val', which is the return information of the task.
''',
# Task judge prompts in os
'_SYSTEM_TASK_JUDGE_PROMPT': '''
You are an program expert to verify code against a user's task requirements.
Your goal is to determine if the provided code accomplishes the user's specified task based on the feedback information, And score the code based on the degree of generalizability of the code.
You should only respond with a JSON result.
You must follow the analysis process and format requirements as follows:
1. Analyze the provided code: Examine the user's code to understand its functionality and structure.
2. Compare the code with the task description: Align the objectives stated in the user's task description with the capabilities of the code.
3. Evaluate the feedback information: Review the user's feedback, Includes 'Code Output', 'Code Error' and the working catalog information provided by user to measure the effectiveness of the code.
4. Formulate a reasoning process: Based on the analysis of the code and feedback received, generate a reasoning process about the execution of the code. If you believe the task has been successfully completed, you need to explain how the code accomplished the task. If you think the task has not been completed, you need to explain the reasons for the failure and provide corresponding solutions.
5. Evaluate task status: Based on the reasoning process, determine the status of the task. There are three possible statuses for a task:
Complete: The task has been successfully executed.
Amend: There are errors in the code, or the code does not meet the task requirements, necessitating fixes based on the reasoning process.
Replan: Errors encountered during code execution cannot be rectified by simply modifying the code, requiring additional operations within the code's execution environment. This necessitates new tasks to perform these extra operations.
6. Code's generality score: Evaluate the generality of the code and give code a score. The generality of the code can be analyzed based on parameters flexibility, error and exception handling, clarity of comments, code efficiency, security aspects, and other factors. According to the evaluation results, the code can be scored on a scale from 1 to 10, with integers reflecting the code's generality. A score of 1-3 indicates that the code is not very generic and can only complete the current task. A score of 4-6 indicates that the code can efficiently complete similar tasks, but the parameter names are not generic enough. A score of 7-8 indicates that the code is sufficiently generic but lacks in terms of security, clarity of comments, and fault tolerance. A score of 9-10 indicates that the code is highly generic in all aspects.
7. Output Format:
```json
{
reasoning: Your reasoning process,
status: Complete/Amend/Replan,
score: 1-10
}
```
And you should also follow the following criteria:
1. Provide clear, logical reasoning.
2. You need to aware that the code I provided does not generate errors, I am just uncertain whether it effectively accomplishes the intended task.
3. If the task involves file creation, information regarding the current working directory and all its subdirectories and files may assist you in determining whether the file has been successfully created.
4. If the Code Output contains information indicating that the task has been completed, the task can be considered completed.
5. If necessary, you should check the current task's code output to ensure it returns the information required for 'Next Task'. If it does not, then the current task can be considered incomplete.
6. If the task is not completed, it may be because the code did not consider the information returned by the predecessor task.
Now you will be provided with the following information, please give the result JSON according to these information:
''',
'_USER_TASK_JUDGE_PROMPT': '''
User's information are as follows:
Current Code: {current_code}
Task: {task}
Code Output: {code_output}
Code Error: {code_error}
Current Working Directiory: {current_working_dir}
Working Directory: {working_dir}
Files And Folders in Current Working Directiory: {files_and_folders}
Next Task: {next_action}
Detailed description of user information:
1. 'Working Directory' represents the root directory of the working directory.
2. 'Current Working Directory' represents the directory where the current task is located.
3. 'Code Output' represents the output of the code execution, which may be empty.
4. 'Code Error' represents any error messages generated during code execution, which may also be empty.
5. 'Next Task' describes tasks that follow the current task and may depend on the return from the current task.
Note: Please output according to the output format specified in the system message.
''',
# Tool usage prompts in os
'_SYSTEM_TOOL_USAGE_PROMPT': '''
You are a useful AI assistant capable of accessing APIs to complete user-specified tasks, according to API documentation,
by using the provided ToolRequestUtil tool. The API documentation is as follows:
{openapi_doc}
The user-specified task is as follows:
{tool_sub_task}
The context which can further help you to determine the params of the API is as follows:
{context}
You need to complete the code using the ToolRequestUtil tool to call the specified API and print the return value
of the api.
ToolRequestUtil is a utility class, and the parameters of its 'request' method are described as follows:
def request(self, api_path, method, params=None, content_type=None):
"""
:param api_path: the path of the API
:param method: get/post
:param params: the parameters of the API, can be None.You cannot pass files to 'params' parameter.All files should be passed to 'files' parameter.
:param files: files to be uploaded, can be None.Remember if the parameters of the API contain files, you need to use the 'files' parameter to upload the files.
:param content_type: the content_type of api, e.g., application/json, multipart/form-data, can be None
:return: the response from the API
"""
Please begin your code completion:
''',
'_USER_TOOL_USAGE_PROMPT': '''
from oscopilot.tool_repository.manager.tool_request_util import ToolRequestUtil
tool_request_util = ToolRequestUtil()
# TODO: your code here
''',
# QA prompts in os
'_SYSTEM_QA_PROMPT': '''
You are a helpful ai assistant that can answer the question with the help of the context provided by the user in a step by step manner. The full question may help you to solve the current question.
If you don't know how to answer the user's question, answer "I don't know." instead of making up an answer.
And you should also follow the following criteria:
1. If the prerequisite does not return the information you want, but your own knowledge can answer the current question, then you try to use your own knowledge to answer it.
2. If your current solution is incorrect but you have a potential solution, please implement your potential solution directly.
3. If you lack specific knowledge but can make inferences based on relevant knowledge, you can try to infer the answer to the question.
Now you will be provided with the following user information:
''',
'_USER_QA_PROMPT': '''
Context: {context}
Full Question: {question}
Current Question: {current_question}
Detailed description of user information:
1. 'Context' is the information returned from a prerequisite task, which can serve as context to help you answer questions.
'''
},
'planning_prompt': {
# Task decompose prompts in os
'_SYSTEM_TASK_DECOMPOSE_PROMPT': '''
You are an expert at breaking down a task into subtasks.
I will give you a task and ask you to decompose this task into a series of subtasks.
You should follow the following criteria:
1. Try to break down the task into as few subtasks as possible.
2. The description of each subtask must be detailed enough, no entity and operation information in the task can be ignored. Specific information, such as names or paths, cannot be replaced with pronouns.
3. The subtasks currently designed are compatible with and can be executed on the present version of the system.
You can only provide me with a list of subtasks in order.
''',
'_USER_TASK_DECOMPOSE_PROMPT': '''
User's information are as follows:
System Version: {system_version}
Task: {task}
Current Working Directiory: {working_dir}
''',
# Task replan prompts in os
'_SYSTEM_TASK_REPLAN_PROMPT': '''
You are an expert at designing new tasks based on the results of your reasoning.
When I was executing the code of current task, an issue occurred that is not related to the code. The user information includes a reasoning process addressing this issue. Based on the results of this reasoning, please design new tasks to resolve the problem.
You can only return the reasoning process and the JSON that stores the tasks information.
The content and format requirements for the reasoning process and tasks information are as follows:
1. Proceed with the reasoning based on the 'Reasoning' information step by step, treating each step as an individual task.
2. In JSON, each task contains four attributes: name, description, dependencies and type, which are obtained through reasoning about the task. The key of each task is the 'name' attribute of the task.
3. The four attributes for each task are described as follows:
name: The name of the task. This name is abstracted from the reasoning step corresponding to the current task and can summarize a series of similar tasks. It should not contain any specific names from within the reasoning process. For instance, if the task is to search for the word 'agents' in files, the task should be named 'search_files_for_word'.
description: The description of the current task corresponds to a certain step in task reasoning.
dependencies: This term refers to the list of names of task that the current task depends upon, as determined by the reasoning process. These tasks are required to be executed before the current one, and their arrangement must be consistent with the dependencies among the tasks.
type: The task type of task, used to indicate in what form the task will be executed.
4. There are five types of tasks:
Python: Python is suited for tasks that involve complex data handling, analysis, machine learning, or the need to develop cross-platform scripts and applications. It is applicable in situations requiring intricate logic, algorithm implementation, data analysis, graphical user interfaces or file internal operations.
Shell: When the task primarily focuses on operating system-level automation, such as quick operations on the file system (creating, moving, deleting files), batch renaming files, system configuration, and monitoring and managing the operating system or system resources, Shell scripts are particularly suitable for quickly executing system-level batch processing tasks. They leverage tools and commands provided by the operating system, enabling efficient handling of log files, monitoring of system status, and simple text processing work.
AppleScript: AppleScript is primarily aimed at the macOS platform and is suitable for automating application operations on macOS, adjusting system settings, or implementing workflow automation between applications. It applies to controlling and automating the behavior of nearly all Mac applications.
API: API tasks are necessary when interaction with external services or platforms is required, such as retrieving data, sending data, integrating third-party functionalities or services. APIs are suitable for situations that require obtaining information from internet services or need communication between applications, whether the APIs are public or private.
QA: QA tasks are primarily about answering questions, providing information, or resolving queries, especially those that can be directly answered through knowledge retrieval or specific domain expertise. They are suited for scenarios requiring quick information retrieval, verification, or explanations of a concept or process.
5. An example to help you better understand the information that needs to be generated: The reasoning process analyzed that the reason for the error was that there was no numpy package in the environments, causing it to fail to run. Then the reasoning process and JSON that stores the tasks information are as follows:
Reasoning:
1. According to the reasoning process of error reporting, because there is no numpy package in the environments, we need to use the pip tool to install the numpy package.
```json
{
"install_package" : {
"name": "install_package",
"description": "Use pip to install the numpy package that is missing in the environments.",
"dependencies": [],
"type" : "shell"
}
}
```
And you should also follow the following criteria:
1. Try to design as few tasks as possible.
2. tasks will be executed in the corresponding environment based on their task type, so it's crucial that the task type is accurate; otherwise, it might result in the task being unable to be completed.
3. The dependency relationship between the newly added task and the current task cannot form a loop.
4. The description information of the new task must be detailed enough, no entity and operation information in the task can be ignored.
5. The tasks currently designed are compatible with and can be executed on the present version of the system.
6. Before execution, a task can obtain the output information from its prerequisite dependent tasks. Therefore, if a task requires the output from a prerequisite task, the description of the task must specify which information from the prerequisite task is needed.
Now you will be provided with the following information, please give the reasoning process and the JSON that stores the tasks information according to these information:
''',
'_USER_TASK_REPLAN_PROMPT': '''
User's information are as follows:
Current Task: {current_task}
Current Task Description: {current_task_description}
System Version: {system_version}
Reasoning: {reasoning}
Tool List: {tool_list}
Current Working Directiory: {working_dir}
Files And Folders in Current Working Directiory: {files_and_folders}
Detailed description of user information:
1. 'Reasoning' indicates the reason why task execution failed and the corresponding solution, which can help you design new tasks.
2. 'Current Working Directiory' and 'Files And Folders in Current Working Directiory' specify the path and directory of the current working directory. These information may help you understand and generate tasks.
3. 'Tool List' contains the name of each tool and the corresponding operation description. These tools are previously accumulated for completing corresponding tasks. If a task corresponds to the description of a certain tool, then the task name and the tool name are the same, to facilitate the invocation of the relevant tool when executing the task.
''',
}
}

View File

@@ -1,7 +1,7 @@
"""
This modules contains a comprehensive `prompts` dictionary that serves as a repository of prompts for guiding the AI agents's interactions across various operational scenarios, including execution, planning, and information retrieval tasks. These prompts are meticulously crafted to instruct the AI in performing its duties, ranging from code generation and amendment to task decomposition and planning, as well as error analysis and tool usage.
The dictionary is segmented into three main categories:
The dictionary is segmented into five main categories:
1. **execute_prompt**: Contains prompts for execution-related tasks, such as code generation, invocation, amendment, and error judgment. These are further detailed for system actions and user interactions, facilitating a diverse range of programming and troubleshooting tasks.
@@ -124,7 +124,7 @@ prompt = {
5. The solution must enable the code to successfully complete the intended task without errors.
6. When Critique On The Code in User's information is empty, it means that there is an error in the code itself, you should fix the error in the code so that it can accomplish the current task.
Now you will be provided with the following information, please give your modified code according to these information:
Now you will be provided with the following information, please give your modified code according to these information.
''',
'_USER_SHELL_APPLESCRIPT_AMEND_PROMPT': '''
User's information are as follows:
@@ -178,7 +178,7 @@ prompt = {
4. The function includes detailed comments for input and output parameters. If there are errors related to parameter data structures, these comments can be referred to for writing the appropriate data structures.
5. When generating the function call, all required parameter information must be filled in without any omissions.
Now you will be provided with the following information, please give your modified python code and invocation statement according to these information:
Now you will be provided with the following information, please give your modified python code and invocation statement according to these information.
''',
'_USER_PYTHON_SKILL_AMEND_AND_INVOKE_PROMPT': '''
User's information are as follows:
@@ -233,7 +233,7 @@ prompt = {
4. If the Code Output contains information indicating that the task has been completed, the task can be considered completed.
5. If necessary, you should check the current task's code output to ensure it returns the information required for 'Next Task'. If it does not, then the current task can be considered incomplete.
6. If the task is not completed, it may be because the code did not consider the information returned by the predecessor task.
Now you will be provided with the following information, please give the result JSON according to these information:
Now you will be provided with the following information, please give the result JSON according to these information.
''',
'_USER_TASK_JUDGE_PROMPT': '''
User's information are as follows:
@@ -292,7 +292,7 @@ prompt = {
1. If the prerequisite does not return the information you want, but your own knowledge can answer the current question, then you try to use your own knowledge to answer it.
2. If your current solution is incorrect but you have a potential solution, please implement your potential solution directly.
3. If you lack specific knowledge but can make inferences based on relevant knowledge, you can try to infer the answer to the question.
Now you will be provided with the following user information:
Now you will be provided with the following user information.
''',
'_USER_QA_PROMPT': '''
Context: {context}
@@ -363,7 +363,7 @@ prompt = {
13. If a task has attributes such as Task, Input, Output, and Path, it's important to know that Task refers to the task that needs to be completed. Input and Output are the prompts for inputs and outputs while writing the code functions during the task execution phase. Path is the file path that needs to be operated on.
14. If the task is to install a missing Python package, only one subtask is needed to install that Python package.
Now you will be provided with the following information, please give the reasoning process and the JSON that stores the subtasks information according to these information:
Now you will be provided with the following information, please give the reasoning process and the JSON that stores the subtasks information according to these information.
''',
'_USER_TASK_DECOMPOSE_PROMPT': '''
User's information are as follows:
@@ -421,7 +421,7 @@ prompt = {
5. The tasks currently designed are compatible with and can be executed on the present version of the system.
6. Before execution, a task can obtain the output information from its prerequisite dependent tasks. Therefore, if a task requires the output from a prerequisite task, the description of the task must specify which information from the prerequisite task is needed.
Now you will be provided with the following information, please give the reasoning process and the JSON that stores the tasks information according to these information:
Now you will be provided with the following information, please give the reasoning process and the JSON that stores the tasks information according to these information.
''',
'_USER_TASK_REPLAN_PROMPT': '''
User's information are as follows:

View File

@@ -0,0 +1 @@
from .text_extractor import *

View File

@@ -0,0 +1,18 @@
from oscopilot.utils.utils import send_chat_prompts
from oscopilot.prompts.friday_pt import prompt
class TextExtractor:
def __init__(self, agent):
super().__init__()
self.agent = agent
self.prompt = prompt['text_extract_prompt']
def extract_file_content(self, file_path):
"""
Extract the content of the file.
"""
extract_task = self.prompt.format(file_path=file_path)
self.agent.run(extract_task)
file_content = list(self.agent.planner.tool_node.values())[-1].return_val
return file_content

View File

@@ -112,7 +112,6 @@ class LLAMA:
payload = {
"model": self.model_name,
"messages": messages,
"stream": False
}

10
test.py Normal file
View File

@@ -0,0 +1,10 @@
from oscopilot.utils import setup_config
from oscopilot import BasicPlanner, ToolManager
from oscopilot.prompts.friday2_pt import prompt
args = setup_config()
prompt = prompt["planning_prompt"]
planner = BasicPlanner(prompt)
task = "Copy any text file located in the working_dir/document directory that contains the word 'agent' to a new folder named 'agents'"
planner.decompose_task(task)

View File

@@ -0,0 +1,47 @@
import pytest
from oscopilot.utils import setup_config
from oscopilot import BasicPlanner, ToolManager
from oscopilot.prompts.friday2_pt import prompt
class TestPlanner:
"""
A test class for verifying the functionality of the FridayPlanner class.
This class focuses on testing the task decomposition capabilities of the planner, ensuring that tasks
can be broken down into subtasks effectively. It is crucial for validating that the planner properly
interprets and decomposes high-level tasks into actionable steps.
"""
def setup_method(self, method):
"""
Setup method executed before each test method in this class.
This method prepares the FridayPlanner instance by configuring it with necessary settings and a predefined
planning prompt, ensuring that the planner is ready to handle task decomposition.
Args:
method: The test method that will be run after this setup method. While this parameter is not used
directly in the setup, it is included to comply with the expected signature for setup methods
in the testing framework.
"""
args = setup_config()
self.prompt = prompt["planning_prompt"]
self.planner = BasicPlanner(self.prompt)
def test_decompose_task(self):
"""
Test to verify that the task decomposition process in the FridayPlanner does not result in an empty subtask list.
This test checks the functionality of the `decompose_task` method by providing a specific task description
and ensuring that the planner is capable of breaking it down into one or more subtasks. An empty list of
subtasks would indicate a failure in the decomposition process, which is critical for the planner's utility
in real-world applications.
"""
task = ""
self.planner.decompose_task(task)
assert self.planner.sub_task_list != []
if __name__ == '__main__':
pytest.main()