sceneprogagent 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,16 @@
1
+ Metadata-Version: 2.1
2
+ Name: sceneprogagent
3
+ Version: 0.1.0
4
+ Summary: A Scene Prog Agent
5
+ Home-page: https://github.com/KunalMGupta/sceneprogagent.git
6
+ Author: Kunal Gupta
7
+ Author-email: k5upta@ucsd.edu
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.9
12
+ Description-Content-Type: text/markdown
13
+
14
+ # **SceneProgAgent**
15
+
16
+ **SceneProgAgent** is a powerful agent framework customized for the SceneProg Project.
@@ -0,0 +1,3 @@
1
+ # **SceneProgAgent**
2
+
3
+ **SceneProgAgent** is a powerful agent framework customized for the SceneProg Project.
@@ -0,0 +1,3 @@
1
+ from .sceneprogagent import SceneProgAgent
2
+ from .utils import print_colored
3
+ from .tool import SceneProgTool
@@ -0,0 +1,126 @@
1
+ from sceneprogllm import LLM
2
+
3
+ class Planner:
4
+ def __init__(self, name, planning_examples=None, tool_description=None):
5
+ self.name = name
6
+
7
+ if not planning_examples:
8
+ planning_examples = """
9
+ Input: Cook pasta
10
+ Output:
11
+ {{
12
+ '1': 'Invoke the BoilWater tool to boil water',
13
+ '2': 'Invoke the AddPasta tool to add pasta to boiling water',
14
+ '3': 'Invoke the Timer tool to set a timer for 8-12 minutes',
15
+ '4': 'Invoke the DrainPasta tool to drain the pasta once cooked',
16
+ 'start': 1,
17
+ }}
18
+
19
+ Input: Book a flight ticket from New York to Los Angeles for December 25th
20
+ Output:
21
+ {{
22
+ '1': 'Invoke the SearchFlights tool to search for flights from New York to Los Angeles on December 25th',
23
+ '2': 'Invoke the ComparePrices tool to compare flight prices',
24
+ '3': 'Invoke the BookFlight tool to book the selected flight',
25
+ 'start': 1,
26
+ }}
27
+
28
+ Input: Write a blog post about sustainable living
29
+ Output:
30
+ {{
31
+ '1': 'Invoke the ResearchTopic tool to gather information about sustainable living',
32
+ '2': 'Invoke the GenerateOutline tool to create an outline for the blog post',
33
+ '3': 'Invoke the WriteDraft tool to write a draft of the blog post',
34
+ '4': 'Invoke the Proofread tool to proofread and edit the blog post',
35
+ 'start': 1,
36
+ }}
37
+
38
+ Input: Organize a meeting with the team next Monday at 10 AM
39
+ Output:
40
+ {{
41
+ '1': 'Invoke the CheckAvailability tool to check the team’s availability for next Monday at 10 AM',
42
+ '2': 'Invoke the BookMeetingRoom tool to reserve a meeting room',
43
+ '3': 'Invoke the SendInvites tool to send calendar invitations to the team',
44
+ 'start': 1,
45
+ }}
46
+
47
+ Input: Plan a weekend trip to the mountains
48
+ Output:
49
+ {{
50
+ '1': 'Invoke the SearchDestinations tool to find mountain destinations',
51
+ '2': 'Invoke the CheckWeather tool to check the weekend weather forecast',
52
+ '3': 'Invoke the BookAccommodation tool to book a cabin or hotel',
53
+ '4': 'Invoke the CreatePackingList tool to generate a packing list for the trip',
54
+ 'start': 1,
55
+ }}
56
+
57
+ Input: Create a presentation about artificial intelligence
58
+ Output:
59
+ {{
60
+ '1': 'Invoke the ResearchTopic tool to gather information about artificial intelligence',
61
+ '2': 'Invoke the CreateSlideOutline tool to draft the structure of the presentation',
62
+ '3': 'Invoke the DesignSlides tool to design slides for the presentation',
63
+ '4': 'Invoke the ReviewPresentation tool to review and refine the slides',
64
+ 'start': 1,
65
+ }}
66
+
67
+ Input: Make a smoothie
68
+ Output:
69
+ {{
70
+ '1': 'Invoke the GatherIngredients tool to list required ingredients (e.g., fruits, milk, yogurt)',
71
+ '2': 'Invoke the BlendIngredients tool to blend the ingredients',
72
+ '3': 'Invoke the Serve tool to pour the smoothie into a glass',
73
+ 'start': 1,
74
+ }}
75
+
76
+ Input: Schedule a doctor’s appointment
77
+ Output:
78
+ {{
79
+ '1': 'Invoke the FindDoctors tool to search for available doctors',
80
+ '2': 'Invoke the CheckAvailability tool to check appointment slots',
81
+ '3': 'Invoke the BookAppointment tool to confirm the appointment',
82
+ 'start': 1,
83
+ }}
84
+ """
85
+
86
+ self.description = f"""
87
+ Given the user query, your task is to generate a plan, primarily in plane english, whose successful execution will lead to the resolution of the query.
88
+ You must generate the plan as a list of steps (a python dictionary with numbers '1', '2', '3' being keys and steps being respective values). At each step, you may use a maximum of one tool from the tools available to you.
89
+ Each step should be a simple instruction that can be executed, a call to action. In addition to the steps, you must also include a key 'start' which indicates the starting step of the plan. Example, if we want to start the plan from step 2, the 'start' key should have the value 2.
90
+ The tools available to you are:
91
+ {tool_description}
92
+ Here are a few examples of how your response should look like:
93
+ {planning_examples}
94
+ """
95
+ self.llm = LLM(name=name, system_desc=self.description, response_format="json")
96
+
97
+ def run(self, query):
98
+ response = self.llm.run(query)
99
+ plan = []
100
+ for key, value in response.items():
101
+ if key == "start":
102
+ plan_idx = int(value)
103
+ continue
104
+ plan.append(value)
105
+ return plan, plan_idx
106
+
107
+ def __call__(self, query):
108
+ plan, plan_idx = self.run(query)
109
+ prompt = f"""
110
+ The plan you generated for the query: {query} is as follows:
111
+ {plan}
112
+ with the starting step being: {plan_idx}
113
+ Check if the plan is correct, complete and only uses the tools available to you. If you need to make any changes, do so now. If you cannot generate a plan, simply return a single item 'CANNOT PLAN'.
114
+ """
115
+ plan, plan_idx = self.run(prompt)
116
+ return plan, plan_idx
117
+
118
+ def refine_plan(self, query, plan, plan_idx, result):
119
+ prompt = f"""
120
+ For the query: {query}, you had generated the following plan:
121
+ {plan}
122
+ However, while executing step {plan[plan_idx-1]}, we encountered an error: {result}.
123
+ Modify the plan accordingly to address the error. Also, update the starting step of the plan so that the steps before the error are not repeated.
124
+ """
125
+ plan, plan_idx = self(prompt)
126
+ return plan, plan_idx
@@ -0,0 +1,110 @@
1
+ '''
2
+ Features of the simple agent
3
+ 1. Tool usage (done)
4
+ 2. Handle tool failure (done)
5
+ 3. code execution
6
+ 4. Should be able to plan (done)
7
+ 5. Ability to refine response
8
+ 6. able to collaborate with other agents
9
+ 7. Implements RAG
10
+ 8.
11
+ '''
12
+ from sceneprogllm import LLM
13
+ from .planner import Planner
14
+ from .tool_manager import ToolManager
15
+ from .utils import print_colored
16
+
17
+ class SceneProgAgent:
18
+ def __init__(self, name, role, description, planning_examples=None, silent=False):
19
+ self.name = name
20
+ self.role = role
21
+ self.description = description
22
+ self.silent = silent
23
+ self.planning_examples = planning_examples
24
+ self.tool_manager = ToolManager(name=self.name)
25
+
26
+ description = f"""
27
+ Your name: {name}
28
+ Your Role: {role}
29
+ Task Description: {description}
30
+ """
31
+ self.llm = LLM(
32
+ name=name,
33
+ system_desc=description,
34
+ response_format="text",
35
+ )
36
+
37
+ self.clear_memory()
38
+
39
+ def clear_memory(self):
40
+ self.memory = ""
41
+
42
+ def clear_scratchpad(self):
43
+ self.scratchpad = ""
44
+
45
+ def register_tool(self, tool):
46
+ self.tool_manager.register_tool(tool)
47
+
48
+ def add_to_memory(self, speaker, message):
49
+ self.memory += f"{speaker}: {message}\n"
50
+
51
+ def add_to_scratchpad(self, speaker, message):
52
+ self.scratchpad += f"{speaker}: {message}\n"
53
+
54
+ def try_executing_plan_step(self, plan, plan_idx, query):
55
+ step = plan[plan_idx-1]
56
+ self.add_to_scratchpad("You", "Executing step: "+step)
57
+ prompt = f"""
58
+ The activity has been so far:
59
+ {self.scratchpad}
60
+ You are required to generate a brief reponse which contains sufficient information to execute the following step:
61
+ {step}
62
+ """
63
+ context = self.llm.run(prompt)
64
+ status, result = self.tool_manager(step, context)
65
+ if status == -1:
66
+ self.add_to_scratchpad("You", "Error found: "+result)
67
+ return -1, result
68
+ self.add_to_scratchpad("You", "Step executed successfully.")
69
+ self.add_to_scratchpad("You", "Result: "+str(result))
70
+ print_colored(f"Result: {result}", color="magenta", silent=self.silent)
71
+ return status, result
72
+
73
+ def init_planner(self):
74
+ self.planner = Planner(name=f"{self.name}_planner", planning_examples=self.planning_examples, tool_description=self.tool_manager.tool_description)
75
+
76
+ def __call__(self, query):
77
+ print_colored(f"Query: {query}", color="blue", silent=self.silent)
78
+ self.clear_scratchpad()
79
+
80
+ self.add_to_memory("User", query)
81
+ self.add_to_scratchpad("User", query)
82
+
83
+ plan, plan_idx = self.planner(query)
84
+ print_colored(f"Plan: {plan}, Plan Index: {plan_idx}", color="green", silent=self.silent)
85
+ if plan == ["CANNOT PLAN"]:
86
+ msg = "I'm sorry, I don't have sufficient information or tools to answer this query."
87
+ self.add_to_memory("You", msg)
88
+ return -1, msg
89
+
90
+ self.add_to_scratchpad("Planner", "Following is the plan to achieve the task:"+"\n".join(plan))
91
+
92
+ while True:
93
+ status, result = self.try_executing_plan_step(plan, plan_idx, query)
94
+ if status == -1:
95
+ plan, plan_idx = self.planner.refine_plan(query, plan, plan_idx, result)
96
+ print_colored(f"Refined Plan: {plan}, Plan Index: {plan_idx}", color="green", silent=self.silent)
97
+ if plan == ["CANNOT PLAN"]:
98
+ msg = "I'm sorry, I don't have sufficient information or tools to answer this query."
99
+ self.add_to_memory("You", msg)
100
+ return -1, msg
101
+
102
+ self.add_to_scratchpad("Planner", "Following is the refined plan to achieve the task:"+"\n".join(plan))
103
+ else:
104
+ plan_idx += 1
105
+
106
+ if plan_idx > len(plan):
107
+ break
108
+
109
+ self.add_to_memory("You", "Task completed successfully.")
110
+ return result
@@ -0,0 +1,37 @@
1
+ from pydantic import BaseModel, Field
2
+ from typing import List
3
+
4
+ class SceneProgTool:
5
+ def __init__(self):
6
+
7
+ self.name = None
8
+ self.usage = None
9
+ self.io = None
10
+ self.examples = None
11
+
12
+ def build_io(self, Inputs, Outputs):
13
+ self.Inputs = Inputs
14
+ self.Outputs = Outputs
15
+ # Generate the text block
16
+ inputs ="\n".join([f"- {name}: {info}" for name, info in dict(Inputs.model_fields.items()).items()])
17
+ outputs = "\n".join([f"- {name}: {info}" for name, info in dict(Outputs.model_fields.items()).items()])
18
+ self.io = f"""
19
+ Input:
20
+ {inputs}
21
+ Output:
22
+ {outputs}
23
+ """
24
+ def __str__(self):
25
+ return f"{self.name}: {self.usage}\n{self.io}\n{self.examples}"
26
+
27
+ def validate_arguments(self, Inputs):
28
+ pass
29
+
30
+ def build_response(self, status, message, solution, result):
31
+ class Response:
32
+ def __init__(self, status, message, solution, result):
33
+ self.status = status
34
+ self.message = message
35
+ self.solution = solution
36
+ self.result = result
37
+ return Response(status, message, solution, result)
@@ -0,0 +1,106 @@
1
+ from sceneprogllm import LLM
2
+ from .utils import print_colored
3
+
4
+ class ToolManager:
5
+ def __init__(self, name, silent=False):
6
+ self.name = name
7
+ self.silent = silent
8
+ self.tool_description = ""
9
+ self.tool_registry = {}
10
+ self.tool_identifier = LLM(
11
+ name=f"{self.name}_tool_identifier",
12
+ system_desc="Identify the tool needed to execute the query. Your answer should be a dict like 'tool': 'tool_name'. Note that only a single tool should be identified.",
13
+ response_format="json",
14
+ json_keys=['tool']
15
+ )
16
+
17
+ self.tool_argument_extractor = LLM(
18
+ name=f"{self.name}_tool_argument_extractor",
19
+ system_desc="Extract the arguments needed to execute the identified tool. Carefully go through the query and identify the necessary arguments for the tool. ",
20
+ response_format="pydantic",
21
+ )
22
+
23
+ def register_tool(self, tool):
24
+ self.tool_registry[tool.name] = tool
25
+ self.tool_description += f"""
26
+ Tool: {tool.name}
27
+ Usage: {tool.usage}
28
+ Input/Output:
29
+ {tool.io}
30
+ Example of tool usage:
31
+ {tool.examples}
32
+ """
33
+
34
+ def get_tool_name(self, query):
35
+ tool_name = self.tool_identifier.run(query)
36
+ print_colored(f"Tool identified: {tool_name['tool']}", color="green", silent=self.silent)
37
+
38
+ count=0
39
+ while True:
40
+ if tool_name['tool'] == "unknown" or count>3:
41
+ return -1, f"Cannot identify appropriate tool for the query: {query}."
42
+ elif tool_name['tool'] in self.tool_registry:
43
+ return 0, tool_name['tool']
44
+ else:
45
+ prompt = f"""
46
+ The tool that you identified: {tool_name['tool']} for the query: {query} cannot be found in the tool registry.
47
+ Make sure you are identifying the correct tool with the correct name. If the exact tool is not available, try to identify a similar tool.
48
+ If you are unable to identify the tool, please return the tool name as 'unknown'.
49
+ """
50
+ tool_name = self.tool_identifier.run(prompt)
51
+ count+=1
52
+
53
+ def get_tool_arguments(self, tool, context):
54
+ prompt = f"""
55
+ You are required to extract arguments for the tool: {tool.name}
56
+ Tool Usage Info: {tool.usage}
57
+ Following are the I/O for the tool:
58
+ {tool.io}
59
+ Use the following context to extract the arguments:
60
+ {context}
61
+ """
62
+ arguments = self.tool_argument_extractor.run(prompt, pydantic_object=tool.Inputs)
63
+ count=0
64
+ while True:
65
+ try:
66
+ tool.validate_arguments(arguments)
67
+ break
68
+ except Exception as e:
69
+ prompt = f"""
70
+ Your retrieved arguments: {arguments} for the tool: {tool.name} are incorrect.
71
+ Error: {e}
72
+ Please try again.
73
+ """
74
+ print_colored(f"Error: {e} occurred while executing the tool: {tool.name} with arguments: {arguments}.", color="red", silent=self.silent)
75
+ arguments = self.tool_argument_extractor.run(prompt, pydantic_object=tool.Inputs)
76
+ count+=1
77
+
78
+ if count>3:
79
+ print_colored(f"Tool: {tool.name} failed to execute after 3 attempts. Please think of something else.", color="red", silent=self.silent)
80
+ return -1, f"Tool: {tool.name} failed to execute after 3 attempts. Please think of something else."
81
+
82
+ print_colored(f"Arguments extracted: {arguments}", color="green", silent=self.silent)
83
+ return 0, arguments
84
+
85
+ def __call__(self, query, context):
86
+
87
+ status, tool_name = self.get_tool_name(query)
88
+ if status == -1:
89
+ return -1, tool_name
90
+
91
+ tool = self.tool_registry[tool_name]
92
+ status, arguments = self.get_tool_arguments(tool, context)
93
+ if status == -1:
94
+ return -1, arguments
95
+
96
+ response = tool(arguments)
97
+ if response.status == -1:
98
+ msg = f"""
99
+ Tried running the tool: {tool.name} with arguments: {arguments} but it failed to execute.
100
+ Error: {response.message}
101
+ Potential solution: {response.solution}
102
+ """
103
+ print_colored(msg, color="red", silent=self.silent)
104
+ return -1, msg
105
+
106
+ return 0, response.result
@@ -0,0 +1,28 @@
1
+ def print_colored(text: str, color: str = "default", silent: bool = False):
2
+ if silent:
3
+ return
4
+ """
5
+ Prints text in various colors.
6
+
7
+ Args:
8
+ text (str): The text to print.
9
+ color (str): The color of the text. Options are:
10
+ "black", "red", "green", "yellow", "blue", "magenta",
11
+ "cyan", "white", or "default".
12
+ """
13
+ colors = {
14
+ "black": "\033[30m",
15
+ "red": "\033[31m",
16
+ "green": "\033[32m",
17
+ "yellow": "\033[33m",
18
+ "blue": "\033[34m",
19
+ "magenta": "\033[35m",
20
+ "cyan": "\033[36m",
21
+ "white": "\033[37m",
22
+ "default": "\033[39m"
23
+ }
24
+
25
+ reset = "\033[0m"
26
+ color_code = colors.get(color.lower(), colors["default"])
27
+
28
+ print(f"{color_code}{text}{reset}")
@@ -0,0 +1,16 @@
1
+ Metadata-Version: 2.1
2
+ Name: sceneprogagent
3
+ Version: 0.1.0
4
+ Summary: A Scene Prog Agent
5
+ Home-page: https://github.com/KunalMGupta/sceneprogagent.git
6
+ Author: Kunal Gupta
7
+ Author-email: k5upta@ucsd.edu
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.9
12
+ Description-Content-Type: text/markdown
13
+
14
+ # **SceneProgAgent**
15
+
16
+ **SceneProgAgent** is a powerful agent framework customized for the SceneProg Project.
@@ -0,0 +1,12 @@
1
+ README.md
2
+ setup.py
3
+ sceneprogagent/__init__.py
4
+ sceneprogagent/planner.py
5
+ sceneprogagent/sceneprogagent.py
6
+ sceneprogagent/tool.py
7
+ sceneprogagent/tool_manager.py
8
+ sceneprogagent/utils.py
9
+ sceneprogagent.egg-info/PKG-INFO
10
+ sceneprogagent.egg-info/SOURCES.txt
11
+ sceneprogagent.egg-info/dependency_links.txt
12
+ sceneprogagent.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ sceneprogagent
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,18 @@
1
+ from setuptools import setup, find_packages
2
+ setup(
3
+ name='sceneprogagent', # Replace with your package's name
4
+ version='0.1.0', # Replace with your package's version
5
+ description='A Scene Prog Agent', # Replace with a short description of your package
6
+ long_description=open('README.md').read(), # Optional: Use your README for a detailed description
7
+ long_description_content_type='text/markdown',
8
+ author='Kunal Gupta',
9
+ author_email='k5upta@ucsd.edu',
10
+ url='https://github.com/KunalMGupta/sceneprogagent.git', # Optional: Replace with your repo URL
11
+ packages=find_packages(), # Automatically find all packages in your project
12
+ classifiers=[
13
+ 'Programming Language :: Python :: 3',
14
+ 'License :: OSI Approved :: MIT License',
15
+ 'Operating System :: OS Independent',
16
+ ],
17
+ python_requires='>=3.9', # Replace with the minimum Python version your package supports
18
+ )