Maga222006 commited on
Commit
7236cee
·
1 Parent(s): b616ae5

MultiagentPersonalAssistant

Browse files
.idea/ai_toolkit.xml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="AI Toolkit Settings">
4
+ <option name="importsOfInterestPresent" value="true" />
5
+ </component>
6
+ </project>
.idea/vcs.xml CHANGED
@@ -1,6 +1,6 @@
1
  <?xml version="1.0" encoding="UTF-8"?>
2
  <project version="4">
3
  <component name="VcsDirectoryMappings">
4
- <mapping directory="$PROJECT_DIR$" vcs="Git" />
5
  </component>
6
  </project>
 
1
  <?xml version="1.0" encoding="UTF-8"?>
2
  <project version="4">
3
  <component name="VcsDirectoryMappings">
4
+ <mapping directory="" vcs="Git" />
5
  </component>
6
  </project>
agent/__pycache__/coder_agent.cpython-312.pyc DELETED
Binary file (2.02 kB)
 
agent/__pycache__/deep_research_agent.cpython-312.pyc DELETED
Binary file (2.09 kB)
 
agent/__pycache__/file_preprocessing.cpython-312.pyc DELETED
Binary file (3.77 kB)
 
agent/__pycache__/models.cpython-312.pyc DELETED
Binary file (885 Bytes)
 
agent/__pycache__/multi_agent.cpython-312.pyc DELETED
Binary file (10.3 kB)
 
agent/__pycache__/prompts.cpython-312.pyc DELETED
Binary file (5.58 kB)
 
agent/__pycache__/smart_home_agent.cpython-312.pyc DELETED
Binary file (1.61 kB)
 
agent/__pycache__/states.cpython-312.pyc DELETED
Binary file (1.54 kB)
 
agent/__pycache__/tools.cpython-311.pyc DELETED
Binary file (13.5 kB)
 
agent/__pycache__/tools.cpython-312.pyc DELETED
Binary file (15.1 kB)
 
agent/coder_agent.py DELETED
@@ -1,39 +0,0 @@
1
- from agent.prompts import coder_instructions, coder_system_message
2
- from langchain_core.messages import HumanMessage, SystemMessage
3
- from agent.models import llm_agents, llm_peripheral
4
- from langgraph.prebuilt import create_react_agent
5
- from langgraph.constants import START, END
6
- from agent.states import PlanCodingTask
7
- from langgraph.graph import StateGraph
8
- from agent.tools import coder_tools
9
-
10
- agent = create_react_agent(
11
- llm_agents,
12
- tools=coder_tools,
13
- prompt=coder_instructions
14
- )
15
-
16
- def planning_node(state: dict):
17
- planer = llm_peripheral.with_structured_output(PlanCodingTask)
18
- plan = planer.invoke(state['messages'][-1].content)
19
- state.update(plan)
20
- return state
21
-
22
- def code_agent(state: dict):
23
- system_message = SystemMessage(coder_system_message(state))
24
- state.update(agent.invoke({
25
- 'messages': [
26
- system_message,
27
- HumanMessage(state['task_description']),
28
- ]
29
- }))
30
- return state
31
-
32
- graph = StateGraph(dict)
33
- graph.add_node("planning_node", planning_node)
34
- graph.add_node("code_agent", code_agent)
35
- graph.add_edge(START, "planning_node")
36
- graph.add_edge("planning_node", "code_agent")
37
- graph.add_edge("code_agent", END)
38
-
39
- coder_agent = graph.compile(name="coder_agent")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
agent/deep_research_agent.py DELETED
@@ -1,39 +0,0 @@
1
- from agent.prompts import deep_research_instructions, deep_research_system_message
2
- from langchain_core.messages import HumanMessage, SystemMessage
3
- from agent.models import llm_agents, llm_peripheral
4
- from langgraph.prebuilt import create_react_agent
5
- from agent.tools import deep_research_tools
6
- from langgraph.constants import START, END
7
- from langgraph.graph import StateGraph
8
- from agent.states import PlanResearch
9
-
10
- agent = create_react_agent(
11
- llm_agents,
12
- tools=deep_research_tools,
13
- prompt=deep_research_instructions
14
- )
15
-
16
- def planning_node(state: dict):
17
- planer = llm_peripheral.with_structured_output(PlanResearch)
18
- plan = planer.invoke(state['messages'][-1].content)
19
- state.update(plan)
20
- return state
21
-
22
- def research_agent(state: dict):
23
- system_message = SystemMessage(deep_research_system_message(state))
24
- state.update(agent.invoke({
25
- 'messages': [
26
- system_message,
27
- HumanMessage(state['messages'][-1].content),
28
- ]
29
- }))
30
- return state
31
-
32
- graph = StateGraph(dict)
33
- graph.add_node("planning_node", planning_node)
34
- graph.add_node("research_agent", research_agent)
35
- graph.add_edge(START, "planning_node")
36
- graph.add_edge("planning_node", "research_agent")
37
- graph.add_edge("research_agent", END)
38
-
39
- deep_research_agent = graph.compile(name="deep_research_agent")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
agent/prompts.py DELETED
@@ -1,74 +0,0 @@
1
- coder_instructions = f"""You are a coding expert. Follow these steps every time:\n
2
-
3
- 1. Use the 'web_search' tool to find how to solve the task or retrieve the package documentation and code examples.\n
4
- 2. Create a new GitHub repository for this task using 'create_repo' tool.\n
5
- 3. Use 'commit_file_to_repo' tool to save your solution code into the GitHub repository.\n
6
-
7
- """
8
-
9
- smart_home_instructions = f"""You are a smart home control expert. Follow these steps every time:\n
10
-
11
- 1. Use the 'get_device_list' tool to retrieve the list of available devices with their names, ids, and states.\n
12
- 2. Identify the target device(s) based on the user’s request.\n
13
- 3. Use the 'change_device_states' tool to update the states of the selected device(s).\n
14
- """
15
-
16
- deep_research_instructions = f"""You are a deep research expert. Follow these steps every time:\n
17
-
18
- 1. Iterate over the given search queries.\n
19
- 2. Iterate over the following steps untill you have written factually correct report:\n
20
- 2.1. Write a report based on the search results.\n
21
- 2.2. Critically asses the report.\n
22
- 2.3. Conduct additional search using tools to find more for research.\n
23
- """
24
-
25
- def supervisor_instructions(tools: list, agents: list):
26
- return f"""You are the Supervisor Agent. Your job is to interpret the user’s request and delegate tasks to the available tools and agents to complete the task.
27
-
28
- You have access to the following agents and tools:
29
- - Tools: {[tool.name for tool in tools]}
30
- - Agents: {[agent.name for agent in agents]}
31
-
32
- 1. Understand and break down user’s request into smaller sub-tasks.
33
- 2. Always delegate each sub-task to the best fitting agent/tool (e.g. always delegate any kind of coding or GitHub related task to ‘coder_agent’).
34
- 3. Coordinate tools/agents efficiently, ensuring minimal redundancy.
35
- 4. Validate results before presenting them.
36
- 5. Respond in Telegram Markdown.
37
- - Use `*bold*`, `_italic_`, `[text](http://example.com)`, `` `inline code` ``, and ``` fenced code blocks ```.
38
- - Never leave an opening `*`, `_`, `` ` ``, `[`, or ``` without its closing pair.
39
- - Do not nest Markdown entities.
40
- - Escape reserved characters (`* _ [ ] ( ) \ ``) if they are not part of a valid entity.
41
- - Escaping inside entities is not allowed, so entity must be closed first and reopened again: use _snake_\__case_ for italic snake_case and *2*\**2=4* for bold 2*2=4.
42
-
43
- Your top priority: satisfy the user’s query as effectively and efficiently as possible using the resources at your disposal, while formatting the final output in valid Markdown.
44
- """
45
-
46
- def coder_system_message(state: dict):
47
- return f"""Your job is to create a coding project based on the user query.
48
-
49
- 1. Create a new GitHub {"private" if state['private'] else "public"} repository, named '{state['repo_name']}' for this task using 'create_repo' tool.\n
50
- 2. Use the 'web_search' tool to research your task.\n
51
- 3. Commit files with the code to your repository.\n
52
- 4. Critically review your code for weak points using 'list_files' and 'read_file' tools.\n
53
- 5. Use 'web_search' for the latest docs and code examples.\n
54
- 6. Adjust the code after the carefully reviewing your code.\n
55
- """
56
- def deep_research_system_message(state: dict):
57
- return f"""Your job is to conduct deep research based on the user query.\n
58
-
59
- 1. Iterate over the following search queries: {state['search_queries']}\n
60
- 2. Write an extensive report based on web search results.\n
61
- 3. Critically review your report for weak points.\n
62
- 4. Conduct additional research using available tools.\t
63
- 5. Write an extensive report based on web search results.\n
64
- 6. Critically review your report and cicle over these steps until it is factually correct and very detailed.\n
65
- """
66
-
67
- def smart_home_system_message(device_list: list):
68
- return f"""Your job is to control the smart home.\nYou have access to the following devices:\n
69
- {"\n\n".join(
70
- f"{i+1}. {device['name']} (id: {device['id']})\nStates:\n" +
71
- "\n".join(f"{state}" for state in device['states'])
72
- for i, device in enumerate(device_list)
73
- )}.\nUse the given tools ('get_device_list', 'change_device_states') to complete the user's tasks.
74
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
agent/smart_home_agent.py DELETED
@@ -1,30 +0,0 @@
1
- from agent.prompts import smart_home_instructions, smart_home_system_message
2
- from langchain_core.messages import HumanMessage, SystemMessage
3
- from agent.models import llm_agents, llm_peripheral
4
- from langgraph.prebuilt import create_react_agent
5
- from langgraph.constants import START, END
6
- from langgraph.graph import StateGraph
7
- from agent.tools import smart_home_tools, get_device_list
8
-
9
- agent = create_react_agent(
10
- llm_agents,
11
- tools=smart_home_tools,
12
- prompt=smart_home_instructions
13
- )
14
-
15
- def home_control_agent(state: dict):
16
- system_message = SystemMessage(smart_home_system_message(get_device_list.invoke({})))
17
- state.update(agent.invoke({
18
- 'messages': [
19
- system_message,
20
- HumanMessage(state['messages'][-1].content),
21
- ]
22
- }))
23
- return state
24
-
25
- graph = StateGraph(dict)
26
- graph.add_node("home_control_agent", home_control_agent)
27
- graph.add_edge(START, "home_control_agent")
28
- graph.add_edge("home_control_agent", END)
29
-
30
- smart_home_agent = graph.compile(name="smart_home_agent")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
agent/states.py DELETED
@@ -1,13 +0,0 @@
1
- from typing import TypedDict, List
2
- from pydantic import Field
3
-
4
- class SearchQuery(TypedDict):
5
- query: str = Field(description="A single plain text search query string.")
6
-
7
- class PlanResearch(TypedDict):
8
- search_queries: List[SearchQuery] = Field(description="A list of search queries, to find all the info user asked for. Break user query down into smaller search queries.")
9
-
10
- class PlanCodingTask(TypedDict):
11
- repo_name: str = Field(description="The name of the GitHub repository for the project.")
12
- private: bool = Field(description="Whether or not the repository is private.", default=False)
13
- task_description: str = Field(description="A detailed description of the project for the coder to create.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
agents/coder/agent.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_core.messages import HumanMessage, SystemMessage
2
+ from agents.coder.prompts import prompt, system_message
3
+ from langgraph.prebuilt import create_react_agent
4
+ from agents.coder.states import CoderState
5
+ from agents.models import llm_sub_agents
6
+ from agents.coder.tools import tools
7
+ from langchain.tools import tool
8
+ from dotenv import load_dotenv
9
+ import os
10
+
11
+ load_dotenv()
12
+
13
+ agent = create_react_agent(
14
+ llm_sub_agents,
15
+ tools=tools,
16
+ prompt=prompt,
17
+ state_schema=CoderState,
18
+ )
19
+
20
+ @tool
21
+ def coder_agent(project_name: str, task_description: str, private: bool=False):
22
+ """
23
+ Coder Agent, used as a tool for any coding tasks, it creates project, tests it and saves to GitHub.
24
+
25
+ Args:
26
+ project_name (str): The name of the GitHub repository and directory for the project.
27
+ task_description (str): A detailed description of the project for the coder to create.
28
+ private (bool, optional): Whether the coder should be private or public. Defaults to False.
29
+ """
30
+ path = f"agents/coder/projects/{project_name}"
31
+ messages = agent.invoke({'messages': [SystemMessage(system_message(project_name, private)), HumanMessage(content=task_description)], 'project_name': project_name, 'private': private})
32
+ if os.path.isdir(path):
33
+ os.rmdir(path)
34
+ return messages['messages'][-1].content
agents/coder/prompts.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ prompt = """
2
+ You are a coding expert.
3
+ Always follow these steps:
4
+
5
+ 1. Create a new project for this task using 'create_project' or use existing project with 'download_repo' tool.\n
6
+ 2. Use 'write_file' tool to save your solution code into the GitHub repository.\n
7
+ 3. Test the code and review it until it works.
8
+ 4. Tell the user you're done.
9
+ """
10
+
11
+ def system_message(project_name: str, private: bool=False) -> str:
12
+ return f"""Your job is to create a coding project based on the user query.\n
13
+
14
+ 1. Create a new GitHub {"private" if private else "public"} repository and project directory, named '{project_name}' for this task using 'create_project' tool or take existing GitHub repository to adjust using 'download_repo' tool if the user request implies adjusting the project instead of creating it from scratch. \n
15
+ 2. Use 'tavily_search' tool to retrieve the code examples, documentation and tutorials for the task.\n
16
+ 3. Write files with the code to your project using 'write_code' tool.\n
17
+ 4. Test your code using 'run_cmd' tool.\n
18
+ 5. Critically review your code for weak points using 'list_files' and 'read_file' tools.\n
19
+ 6. Adjust the code after the carefully reviewing and testing your code.\n
20
+ 7. Tell the user you're done.
21
+ """
agents/coder/states.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ from langgraph.prebuilt.chat_agent_executor import AgentState
2
+
3
+ class CoderState(AgentState):
4
+ project_name: str
5
+ private: bool = False
agents/coder/tools.py ADDED
@@ -0,0 +1,239 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_tavily import TavilySearch
2
+ from langchain_core.tools import tool
3
+ from dotenv import load_dotenv
4
+ from github import Github
5
+ import subprocess
6
+ import os
7
+
8
+ load_dotenv()
9
+
10
+ tavily_search = TavilySearch(
11
+ max_results=5,
12
+ topic="general",
13
+ include_answer=False
14
+ )
15
+
16
+ @tool
17
+ def create_project(project_name: str, private: bool = False):
18
+ """Creates a project directory and GitHub repository with the given project_name."""
19
+ try:
20
+ github = Github(os.getenv('GITHUB_TOKEN'))
21
+ user = github.get_user()
22
+ user.create_repo(project_name, private=private)
23
+ os.mkdir(f"agents/coder/projects/{project_name}")
24
+ return f"Repository '{project_name}' created successfully!"
25
+ except Exception as e:
26
+ return f"Error creating repository: {str(e)}"
27
+
28
+ @tool
29
+ def list_repos():
30
+ """Lists all repositories owned by the authenticated GitHub user."""
31
+ try:
32
+ github = Github(os.getenv('GITHUB_TOKEN'))
33
+ user = github.get_user()
34
+ repos = user.get_repos()
35
+ repo_names = [repo.name for repo in repos]
36
+ return f"Repositories: {', '.join(repo_names)}"
37
+ except Exception as e:
38
+ return f"Error listing repositories: {str(e)}"
39
+
40
+ @tool
41
+ def list_repo_branches(project_name: str):
42
+ """Lists all branches in a GitHub repository."""
43
+ try:
44
+ github = Github(os.getenv('GITHUB_TOKEN'))
45
+ user = github.get_user()
46
+ repo = user.get_repo(project_name)
47
+ branches = repo.get_branches()
48
+ branch_names = [branch.name for branch in branches]
49
+ return f"Branches in '{project_name}': {', '.join(branch_names)}"
50
+ except Exception as e:
51
+ return f"Error listing branches: {str(e)}"
52
+
53
+ @tool
54
+ def create_repo_branch(project_name: str, branch_name: str):
55
+ """Creates a new branch in a GitHub repository."""
56
+ try:
57
+ github = Github(os.getenv('GITHUB_TOKEN'))
58
+ user = github.get_user()
59
+ repo = user.get_repo(project_name)
60
+ main_branch = repo.get_branch("main")
61
+ repo.create_git_ref(ref=f"refs/heads/{branch_name}", sha=main_branch.commit.sha)
62
+ return f"Branch '{branch_name}' created successfully in '{project_name}'."
63
+ except Exception as e:
64
+ return f"Error creating branch: {str(e)}"
65
+
66
+ @tool
67
+ def write_file(project_name: str, file_path: str, file_contents: str):
68
+ """Adds a new file to the project directory and GitHub repository or updates the existing one."""
69
+
70
+ try:
71
+ with open(f"agents/coder/projects/{project_name}/{file_path}", "w", encoding="utf-8") as f:
72
+ f.write(file_contents)
73
+ except Exception as e:
74
+ return f"Error with file operation: {str(e)}"
75
+ try:
76
+ github = Github(os.getenv('GITHUB_TOKEN'))
77
+ user = github.get_user()
78
+ repo = user.get_repo(project_name)
79
+
80
+ try:
81
+ # Check if file exists
82
+ file = repo.get_contents(file_path)
83
+ sha = file.sha
84
+ repo.update_file(file_path, "Updating file", file_contents, sha)
85
+ return f"File '{file_path}' updated successfully in '{project_name}'."
86
+ except:
87
+ repo.create_file(file_path, "Adding new file", file_contents)
88
+ return f"File '{file_path}' created successfully in '{project_name}'."
89
+ except Exception as e:
90
+ return f"Error with file operation: {str(e)}"
91
+
92
+ @tool
93
+ def delete_file(project_name: str, file_path: str):
94
+ """Deletes a file from the GitHub repository."""
95
+ try:
96
+ if os.path.isfile(file_path):
97
+ os.remove(file_path)
98
+ except Exception as e:
99
+ return f"Error deleting file: {str(e)}"
100
+ try:
101
+ github = Github(os.getenv('GITHUB_TOKEN'))
102
+ user = github.get_user()
103
+ repo = user.get_repo(project_name)
104
+ file = repo.get_contents(file_path)
105
+ sha = file.sha
106
+ repo.delete_file(file_path, "Deleting file", sha)
107
+ return f"File '{file_path}' deleted successfully from '{project_name}'."
108
+ except Exception as e:
109
+ return f"Error deleting file: {str(e)}"
110
+
111
+ @tool
112
+ def read_repo_file(project_name: str, file_path: str):
113
+ """Reads the content of a file from a GitHub repository."""
114
+ try:
115
+ github = Github(os.getenv('GITHUB_TOKEN'))
116
+ user = github.get_user()
117
+ repo = user.get_repo(project_name)
118
+ file = repo.get_contents(file_path)
119
+ return file.decoded_content.decode('utf-8')
120
+ except Exception as e:
121
+ return f"Error reading file: {str(e)}"
122
+
123
+ @tool
124
+ def read_file(project_name: str, file_path: str) -> str:
125
+ """Reads the content of a file from a project directory."""
126
+ full_path = f"agents/coder/projects/{project_name}/{file_path}"
127
+ try:
128
+ with open(full_path, "r", encoding="utf-8") as f:
129
+ return f.read()
130
+ except Exception as e:
131
+ return f"Error reading file '{full_path}': {str(e)}"
132
+
133
+ @tool
134
+ def list_repo_files(project_name: str):
135
+ """Lists all files in the GitHub repository."""
136
+ try:
137
+ github = Github(os.getenv('GITHUB_TOKEN'))
138
+ user = github.get_user()
139
+ repo = user.get_repo(project_name)
140
+ files = repo.get_contents("")
141
+ file_list = [file.name for file in files]
142
+ return f"Files in '{project_name}': {', '.join(file_list)}"
143
+ except Exception as e:
144
+ return f"Error listing files: {str(e)}"
145
+
146
+ @tool
147
+ def list_files(project_name: str, directory: str = "") -> dict:
148
+ """
149
+ Lists files in a project directory.
150
+
151
+ :param project_name: Name of the project.
152
+ :param directory: Optional subdirectory inside the project. By default, all project files are listed.
153
+ :return: List of files in the directory inside the project.
154
+ """
155
+ base_path = os.path.join("agents/coder/projects", project_name, directory)
156
+
157
+ try:
158
+ if not os.path.exists(base_path):
159
+ return f"Directory '{base_path}' does not exist."
160
+
161
+ if not os.path.isdir(base_path):
162
+ return f"Path '{base_path}' is not a directory."
163
+
164
+ files = os.listdir(base_path)
165
+ return files
166
+
167
+ except Exception as e:
168
+ return f"Error listing files: {str(e)}"
169
+
170
+ @tool
171
+ def run_cmd(project_name: str, cmd: str, timeout: int = 30):
172
+ """
173
+ Runs a shell command in the project_name directory.
174
+ """
175
+ project_dir = os.path.join("agents/coder/projects", project_name)
176
+
177
+ if not os.path.isdir(project_dir):
178
+ return -1, "", f"Project directory not found: {project_dir}"
179
+
180
+ try:
181
+ res = subprocess.run(
182
+ cmd,
183
+ shell=True,
184
+ cwd=project_dir,
185
+ capture_output=True,
186
+ text=True,
187
+ timeout=timeout
188
+ )
189
+ return res.returncode, res.stdout, res.stderr
190
+ except subprocess.TimeoutExpired as e:
191
+ return -1, e.stdout or "", f"Command timed out after {timeout}s"
192
+ except Exception as e:
193
+ return -1, "", f"Error running command: {str(e)}"
194
+
195
+ @tool
196
+ def download_repo(project_name: str, repo_owner: str = None, branch: str = "main"):
197
+ """
198
+ Downloads a GitHub repo (user/<project_name>) using PyGithub
199
+ and saves it into agents/coder/projects/{project_name}.
200
+
201
+ Args:
202
+ project_name (str): Repo name on GitHub and local folder name.
203
+ repo_owner (str): Repo owner on GitHub, by default = None (it's the user's repository).
204
+ branch (str): Branch to download (default 'main').
205
+ """
206
+ gh = Github(os.getenv("GITHUB_TOKEN"))
207
+ user = gh.get_user()
208
+ if repo_owner:
209
+ repo = gh.get_repo(f"{repo_owner}/{project_name}")
210
+ else:
211
+ repo = user.get_repo(project_name)
212
+
213
+ dest_path = os.path.join('agents/coder/projects', project_name)
214
+ os.makedirs(dest_path, exist_ok=True)
215
+
216
+ branch_ref = repo.get_branch(branch)
217
+ commit_sha = branch_ref.commit.sha
218
+
219
+ # Get the tree (recursive = True to walk full repo)
220
+ tree = repo.get_git_tree(commit_sha, recursive=True).tree
221
+
222
+ for item in tree:
223
+ file_path = os.path.join(dest_path, item.path)
224
+
225
+ if item.type == "tree":
226
+ os.makedirs(file_path, exist_ok=True)
227
+ elif item.type == "blob":
228
+ blob = repo.get_git_blob(item.sha)
229
+ file_content = blob.content
230
+ import base64
231
+ decoded = base64.b64decode(file_content)
232
+
233
+ os.makedirs(os.path.dirname(file_path), exist_ok=True)
234
+ with open(file_path, "wb") as f:
235
+ f.write(decoded)
236
+
237
+ return f"Repo '{project_name}' downloaded into {dest_path}."
238
+
239
+ tools = [tavily_search, create_project, list_repos, list_repo_branches, create_repo_branch, write_file, delete_file, read_repo_file, read_file, list_repo_files, list_files, run_cmd, download_repo]
{agent → agents}/models.py RENAMED
@@ -1,30 +1,19 @@
1
  from langchain.chat_models import init_chat_model
2
  from dotenv import load_dotenv
3
- from openai import AsyncOpenAI
4
- import os
5
 
6
  load_dotenv()
7
- groq_client = AsyncOpenAI(
8
- base_url="https://api.groq.com/openai/v1",
9
- api_key=os.getenv("GROQ_API_KEY"),
10
- )
11
 
12
  llm_supervisor = init_chat_model(
13
- model="groq:openai/gpt-oss-120b",
14
  max_tokens=1000
15
  )
16
 
17
  llm_peripheral = init_chat_model(
18
- model="groq:gemma2-9b-it",
19
  max_tokens=4000
20
  )
21
 
22
- llm_agents = init_chat_model(
23
- model="groq:qwen/qwen3-32b",
24
- max_tokens=4000
25
- )
26
-
27
- llm_image = init_chat_model(
28
- model="groq:meta-llama/llama-4-scout-17b-16e-instruct",
29
  max_tokens=3000
30
- )
 
1
  from langchain.chat_models import init_chat_model
2
  from dotenv import load_dotenv
 
 
3
 
4
  load_dotenv()
 
 
 
 
5
 
6
  llm_supervisor = init_chat_model(
7
+ "groq:openai/gpt-oss-20b",
8
  max_tokens=1000
9
  )
10
 
11
  llm_peripheral = init_chat_model(
12
+ "groq:gemma2-9b-it",
13
  max_tokens=4000
14
  )
15
 
16
+ llm_sub_agents = init_chat_model(
17
+ "groq:qwen/qwen3-32b",
 
 
 
 
 
18
  max_tokens=3000
19
+ )
{agent → agents}/multi_agent.py RENAMED
@@ -1,35 +1,14 @@
1
  from database_interaction.config import create_or_update_config, load_config_to_env, init_config_db
2
  from database_interaction.user import get_user_by_id, create_or_update_user, init_user_db
3
  from langchain_community.chat_message_histories import SQLChatMessageHistory
4
- from langchain_core.messages import SystemMessage, AnyMessage, AIMessage
5
  from langchain_core.messages.utils import count_tokens_approximately
 
6
  from sqlalchemy.ext.asyncio import create_async_engine
7
- from langgraph_supervisor import create_supervisor
8
  from langmem.short_term import SummarizationNode
9
- from typing_extensions import TypedDict
10
  import os
11
 
12
- class State(TypedDict):
13
- message: AnyMessage
14
- user_id: str
15
- first_name: str
16
- last_name: str
17
- assistant_name: str
18
- latitude: str
19
- longitude: str
20
- location: str
21
- openweathermap_api_key: str
22
- github_token: str
23
- tavily_api_key: str
24
- groq_api_key: str
25
- tuya_access_id: str
26
- tuya_access_key: str
27
- tuya_username: str
28
- tuya_password: str
29
- tuya_country: str
30
- clear_history: bool
31
- messages: list
32
-
33
  class Assistant:
34
  def __init__(self, state: State):
35
  self.state = state
@@ -77,12 +56,9 @@ class Assistant:
77
  def compile_multi_agent_system(self):
78
  """Create and return the multi-agent system"""
79
  try:
80
- from agent.smart_home_agent import smart_home_agent
81
- from agent.deep_research_agent import deep_research_agent
82
- from agent.coder_agent import coder_agent
83
- from agent.prompts import supervisor_instructions
84
- from agent.models import llm_supervisor, llm_peripheral
85
- from agent.tools import supervisor_tools
86
 
87
  summarization_node = SummarizationNode(
88
  token_counter=count_tokens_approximately,
@@ -92,21 +68,15 @@ class Assistant:
92
  output_messages_key="llm_input_messages",
93
  )
94
 
95
- agents = [coder_agent, deep_research_agent, smart_home_agent]
96
-
97
- supervisor = create_supervisor(
98
  model=llm_supervisor,
99
- tools=supervisor_tools,
100
- agents=agents,
101
- prompt=supervisor_instructions(supervisor_tools, agents),
102
- parallel_tool_calls=True,
103
- add_handoff_back_messages=False,
104
- add_handoff_messages=False,
105
- output_mode="full_history",
106
- pre_model_hook=summarization_node
107
  )
108
-
109
- return supervisor.compile()
110
 
111
  except Exception as e:
112
  print(f"Error creating multi-agent system: {e}")
@@ -128,6 +98,7 @@ class Assistant:
128
 
129
  async def run(self):
130
  """Process messages through the multi-agent system"""
 
131
  try:
132
  user_info = await get_user_by_id(user_id=self.state['user_id'])
133
  if user_info.get('location'):
@@ -137,30 +108,17 @@ class Assistant:
137
  if user_info.get('longitude'):
138
  os.environ['LONGITUDE'] = str(user_info['longitude'])
139
 
140
- system_msg = SystemMessage(
141
- content=f"""
142
- You are an intelligent assistant named {os.getenv('ASSISTANT_NAME', 'Assistant')}, helpful personal assistant built using a multi-agent system architecture. Your tools include web search, weather and time lookups, code execution, and GitHub integration. You work inside a Telegram interface and respond concisely, clearly, and informatively.
143
-
144
- The user you are assisting is:
145
- - **Name**: {user_info.get('first_name', 'Unknown') or 'Unknown'} {user_info.get('last_name', '') or ''}
146
- - **User ID**: {self.state['user_id']}
147
- - **Location**: {user_info.get('location', 'Unknown') or 'Unknown'}
148
- - **Coordinates**: ({user_info.get('latitude', 'N/A') or 'N/A'}, {user_info.get('longitude', 'N/A') or 'N/A'})
149
-
150
- You may use their location when answering weather or time-related queries. If the location is unknown, you may ask the user to share it.
151
-
152
- Stay helpful, respectful, and relevant to the user's query.
153
- """.strip()
154
- )
155
 
156
  await self.message_history.aadd_message(self.state['message'])
157
  messages = await self.message_history.aget_messages()
158
 
159
- self.state['messages'] = messages[-8:-1] + [system_msg, messages[-1]]
160
  multi_agent_system = self.compile_multi_agent_system()
161
 
162
- result = await multi_agent_system.ainvoke({"messages": self.state["messages"]},
163
- generation_config=dict(response_modalities=["TEXT"]))
 
 
164
  await self.message_history.aadd_message(result['messages'][-1])
165
  return {"messages": result.get("messages", [])}
166
 
 
1
  from database_interaction.config import create_or_update_config, load_config_to_env, init_config_db
2
  from database_interaction.user import get_user_by_id, create_or_update_user, init_user_db
3
  from langchain_community.chat_message_histories import SQLChatMessageHistory
 
4
  from langchain_core.messages.utils import count_tokens_approximately
5
+ from langchain_core.messages import SystemMessage, AIMessage
6
  from sqlalchemy.ext.asyncio import create_async_engine
7
+ from langgraph.prebuilt import create_react_agent
8
  from langmem.short_term import SummarizationNode
9
+ from agents.states import State
10
  import os
11
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  class Assistant:
13
  def __init__(self, state: State):
14
  self.state = state
 
56
  def compile_multi_agent_system(self):
57
  """Create and return the multi-agent system"""
58
  try:
59
+ from agents.models import llm_supervisor, llm_peripheral
60
+ from agents.prompts import prompt
61
+ from agents.tools import tools
 
 
 
62
 
63
  summarization_node = SummarizationNode(
64
  token_counter=count_tokens_approximately,
 
68
  output_messages_key="llm_input_messages",
69
  )
70
 
71
+ agent = create_react_agent(
 
 
72
  model=llm_supervisor,
73
+ tools=tools,
74
+ prompt=prompt(tools),
75
+ state_schema=State,
76
+ version='v1',
77
+ pre_model_hook=summarization_node,
 
 
 
78
  )
79
+ return agent
 
80
 
81
  except Exception as e:
82
  print(f"Error creating multi-agent system: {e}")
 
98
 
99
  async def run(self):
100
  """Process messages through the multi-agent system"""
101
+ from agents.prompts import system_message
102
  try:
103
  user_info = await get_user_by_id(user_id=self.state['user_id'])
104
  if user_info.get('location'):
 
108
  if user_info.get('longitude'):
109
  os.environ['LONGITUDE'] = str(user_info['longitude'])
110
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
 
112
  await self.message_history.aadd_message(self.state['message'])
113
  messages = await self.message_history.aget_messages()
114
 
115
+ self.state['messages'] = messages[-8:-1] + [SystemMessage(system_message(user_info)), messages[-1]]
116
  multi_agent_system = self.compile_multi_agent_system()
117
 
118
+ result = await multi_agent_system.ainvoke(
119
+ {"messages": self.state["messages"]},
120
+ generation_config=dict(response_modalities=["TEXT"])
121
+ )
122
  await self.message_history.aadd_message(result['messages'][-1])
123
  return {"messages": result.get("messages", [])}
124
 
agents/prompts.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from agents.utils.smart_home import get_device_list
2
+ from dotenv import load_dotenv
3
+ import os
4
+
5
+ load_dotenv()
6
+
7
+ def prompt(tools: list):
8
+ tool_list = ", ".join([tool.name for tool in tools])
9
+ return f"""You are the helpful Agent. Your job is to interpret the user’s request and delegate tasks to the available tools and agents to complete the task.
10
+
11
+ You have access to the following agents and tools:
12
+ - Tools: {tool_list}
13
+
14
+ 1. Understand and break down user’s request into smaller sub-tasks.
15
+ 2. Always delegate each sub-task to the best fitting agent/tool (e.g. always delegate any kind of coding or GitHub related task to ‘coder_agent’).
16
+ 3. Coordinate tools/agents efficiently, ensuring minimal redundancy.
17
+ 4. Validate results before presenting them.
18
+ 5. Respond in Telegram Markdown.
19
+ - Use `*bold*`, `_italic_`, `[text](http://example.com)`, `` `inline code` ``, and ``` fenced code blocks ```.
20
+ - Never leave an opening `*`, `_`, `` ` ``, `[`, or ``` without its closing pair.
21
+ - Do not nest Markdown entities.
22
+ - Escape reserved characters (`* _ [ ] ( ) \ ``) if they are not part of a valid entity.
23
+ - Escaping inside entities is not allowed, so entity must be closed first and reopened again: use _snake_\__case_ for italic snake_case and *2*\**2=4* for bold 2*2=4.
24
+
25
+ Your top priority: satisfy the user’s query as effectively and efficiently as possible using the resources at your disposal, while formatting the final output in valid Markdown.
26
+ """
27
+
28
+
29
+ def system_message(user_info: dict):
30
+ try:
31
+ device_list = "\n\n".join(f"{i + 1}. {device['name']} (id: {device['id']})\nStates:\n" + "\n".join(f"{state}" for state in device['states']) for i, device in enumerate(get_device_list()))
32
+ except Exception as e:
33
+ device_list = None
34
+ return f"""
35
+ You are an intelligent assistant named {os.getenv('ASSISTANT_NAME', 'Assistant')}, helpful personal assistant built using a multi-agent system architecture. Your tools include web search, weather and time lookups, code execution, and GitHub integration. You work inside a Telegram interface and respond concisely, clearly, and informatively.
36
+
37
+ The user you are assisting is:
38
+ - **Name**: {user_info.get('first_name', 'Unknown') or 'Unknown'} {user_info.get('last_name', '') or ''}
39
+ - **User ID**: {user_info.get('user_id', 'Unknown')}
40
+ - **Location**: {user_info.get('location', 'Unknown') or 'Unknown'}
41
+ - **Coordinates**: ({user_info.get('latitude', 'N/A') or 'N/A'}, {user_info.get('longitude', 'N/A') or 'N/A'})
42
+ - **Smart Home Devices**: {device_list or "Unknown"}
43
+
44
+ You may use their location when answering weather or time-related queries. If the location is unknown, you may ask the user to share it.
45
+ You may use the smart home devices if user asks you to.
46
+ Stay helpful, respectful, and relevant to the user's query.
47
+ """
agents/states.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langgraph.prebuilt.chat_agent_executor import AgentState
2
+ from langchain_core.messages import AnyMessage
3
+
4
+ class State(AgentState):
5
+ message: AnyMessage
6
+ user_id: str
7
+ first_name: str
8
+ last_name: str
9
+ assistant_name: str
10
+ latitude: str
11
+ longitude: str
12
+ location: str
13
+ openweathermap_api_key: str
14
+ github_token: str
15
+ tavily_api_key: str
16
+ groq_api_key: str
17
+ tuya_access_id: str
18
+ tuya_access_key: str
19
+ tuya_username: str
20
+ tuya_password: str
21
+ tuya_country: str
22
+ clear_history: bool
agents/tools.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_community.tools.yahoo_finance_news import YahooFinanceNewsTool
2
+ from langchain_community.utilities import OpenWeatherMapAPIWrapper
3
+ from langchain_community.utilities import WikipediaAPIWrapper
4
+ from langchain_community.tools import WikipediaQueryRun
5
+ from langchain_tavily.tavily_search import TavilySearch
6
+ from agents.coder.agent import coder_agent
7
+ from agents.utils.smart_home import change_device_states
8
+ from timezonefinder import TimezoneFinder
9
+ from langchain_core.tools import tool
10
+ from dotenv import load_dotenv
11
+ from geopy import Nominatim
12
+ import datetime
13
+ import pytz
14
+ import os
15
+
16
+ load_dotenv()
17
+
18
+
19
+ tf = TimezoneFinder()
20
+ web_search = TavilySearch(
21
+ max_results=5,
22
+ topic="general",
23
+ include_answer=True
24
+ )
25
+ yahoo = YahooFinanceNewsTool()
26
+ geolocator = Nominatim(user_agent="my_geocoder")
27
+ wikipedia = WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper())
28
+ weekday_mapping = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
29
+
30
+ @tool
31
+ def current_time(location: str = None):
32
+ """Get the current time for a location or current position."""
33
+ try:
34
+ if location:
35
+ location_data = geolocator.geocode(location)
36
+ if location_data:
37
+ timezone = pytz.timezone(tf.timezone_at(lat=location_data.latitude, lng=location_data.longitude))
38
+ location_name = location.capitalize()
39
+ else:
40
+ return f"Could not find location: {location}"
41
+ else:
42
+ # Use environment location if available
43
+ lat = os.getenv('LATITUDE')
44
+ lon = os.getenv('LONGITUDE')
45
+ if lat and lon:
46
+ timezone = pytz.timezone(tf.timezone_at(lat=float(lat), lng=float(lon)))
47
+ location_name = os.getenv('LOCATION', 'Current Location')
48
+ else:
49
+ timezone = pytz.UTC
50
+ location_name = 'UTC'
51
+
52
+ current_dt = datetime.datetime.now(timezone)
53
+ weekday = weekday_mapping[current_dt.weekday()]
54
+ return f"Location: {location_name}; Current Date and Time: {current_dt.strftime('%Y-%m-%d %H:%M')}, {weekday}."
55
+ except Exception as e:
56
+ return f"Error getting current time: {str(e)}"
57
+
58
+ @tool
59
+ def weather(location: str = None):
60
+ """Get the current weather for a location or current position."""
61
+ try:
62
+ weather_wrapper = OpenWeatherMapAPIWrapper(
63
+ openweathermap_api_key=os.getenv('OPENWEATHERMAP_API_KEY')
64
+ )
65
+ if not location:
66
+ location = os.getenv('LOCATION', 'Unknown')
67
+ return weather_wrapper.run(location=location)
68
+ except Exception as e:
69
+ return f"Error getting weather: {str(e)}"
70
+
71
+
72
+ tools = [yahoo, web_search, current_time, weather, change_device_states, coder_agent]
73
+
74
+
{agent → agents/utils}/file_preprocessing.py RENAMED
@@ -13,7 +13,7 @@ async def preprocess_file(file_name: str):
13
  if "image" in mime_type:
14
  return await preprocess_image(file_name)
15
  elif "video" in mime_type:
16
- prompt = "Give a detailed description of the video."
17
  elif "audio" in mime_type:
18
  return await preprocess_audio(file_name)
19
  else:
 
13
  if "image" in mime_type:
14
  return await preprocess_image(file_name)
15
  elif "video" in mime_type:
16
+ pass
17
  elif "audio" in mime_type:
18
  return await preprocess_audio(file_name)
19
  else:
agent/tools.py → agents/utils/smart_home.py RENAMED
@@ -1,33 +1,9 @@
1
- from langchain_community.tools.yahoo_finance_news import YahooFinanceNewsTool
2
- from langchain_community.utilities import OpenWeatherMapAPIWrapper
3
- from langchain_community.utilities import WikipediaAPIWrapper
4
- from langchain_community.tools import WikipediaQueryRun
5
- from langchain_tavily.tavily_search import TavilySearch
6
- from timezonefinder import TimezoneFinder
7
- from langchain_core.tools import tool
8
  from tuya_iot import TuyaOpenAPI
9
- from dotenv import load_dotenv
10
- from geopy import Nominatim
11
- from github import Github
12
  import phonenumbers
13
  import pycountry
14
- import datetime
15
- import pytz
16
  import os
17
 
18
- load_dotenv()
19
-
20
-
21
- tf = TimezoneFinder()
22
- web_search = TavilySearch(
23
- max_results=5,
24
- topic="general",
25
- include_answer=True
26
- )
27
- yahoo = YahooFinanceNewsTool()
28
- geolocator = Nominatim(user_agent="my_geocoder")
29
- wikipedia = WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper())
30
- weekday_mapping = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
31
  endpoint_map = {
32
  "https://openapi.tuyacn.com": [86],
33
  "https://openapi.tuyain.com": [91],
@@ -60,156 +36,7 @@ openapi = TuyaOpenAPI(os.getenv('TUYA_ENDPOINT'), os.getenv('TUYA_ACCESS_ID'), o
60
  connection = openapi.connect(os.getenv('TUYA_USERNAME'), os.getenv('TUYA_PASSWORD'), os.getenv('TUYA_COUNTRY_CODE'), 'TuyaSmart')
61
  if not connection['success']:
62
  connection = openapi.connect(os.getenv('TUYA_USERNAME'), os.getenv('TUYA_PASSWORD'), os.getenv('TUYA_COUNTRY_CODE'), 'SmartLife')
63
- @tool
64
- def create_repo(repo_name: str, private: bool = False):
65
- """Creates a GitHub repository with the given repo_name."""
66
- try:
67
- github = Github(os.getenv('GITHUB_TOKEN'))
68
- user = github.get_user()
69
- user.create_repo(repo_name, private=private)
70
- return f"Repository '{repo_name}' created successfully!"
71
- except Exception as e:
72
- return f"Error creating repository: {str(e)}"
73
 
74
- @tool
75
- def commit_file_to_repo(repo_name: str, file_path: str, file_contents: str):
76
- """Adds a new file to the GitHub repository or updates the existing one."""
77
- try:
78
- github = Github(os.getenv('GITHUB_TOKEN'))
79
- user = github.get_user()
80
- repo = user.get_repo(repo_name)
81
-
82
- try:
83
- # Check if file exists
84
- file = repo.get_contents(file_path)
85
- sha = file.sha
86
- repo.update_file(file_path, "Updating file", file_contents, sha)
87
- return f"File '{file_path}' updated successfully in '{repo_name}'."
88
- except:
89
- repo.create_file(file_path, "Adding new file", file_contents)
90
- return f"File '{file_path}' created successfully in '{repo_name}'."
91
- except Exception as e:
92
- return f"Error with file operation: {str(e)}"
93
-
94
- @tool
95
- def read_file(repo_name: str, file_path: str):
96
- """Reads the content of a file from a GitHub repository."""
97
- try:
98
- github = Github(os.getenv('GITHUB_TOKEN'))
99
- user = github.get_user()
100
- repo = user.get_repo(repo_name)
101
- file = repo.get_contents(file_path)
102
- return file.decoded_content.decode('utf-8')
103
- except Exception as e:
104
- return f"Error reading file: {str(e)}"
105
-
106
- @tool
107
- def list_repos():
108
- """Lists all repositories owned by the authenticated GitHub user."""
109
- try:
110
- github = Github(os.getenv('GITHUB_TOKEN'))
111
- user = github.get_user()
112
- repos = user.get_repos()
113
- repo_names = [repo.name for repo in repos]
114
- return f"Repositories: {', '.join(repo_names)}"
115
- except Exception as e:
116
- return f"Error listing repositories: {str(e)}"
117
-
118
- @tool
119
- def list_files(repo_name: str):
120
- """Lists all files in the GitHub repository."""
121
- try:
122
- github = Github(os.getenv('GITHUB_TOKEN'))
123
- user = github.get_user()
124
- repo = user.get_repo(repo_name)
125
- files = repo.get_contents("")
126
- file_list = [file.name for file in files]
127
- return f"Files in '{repo_name}': {', '.join(file_list)}"
128
- except Exception as e:
129
- return f"Error listing files: {str(e)}"
130
-
131
- @tool
132
- def delete_file(repo_name: str, file_path: str):
133
- """Deletes a file from the GitHub repository."""
134
- try:
135
- github = Github(os.getenv('GITHUB_TOKEN'))
136
- user = github.get_user()
137
- repo = user.get_repo(repo_name)
138
- file = repo.get_contents(file_path)
139
- sha = file.sha
140
- repo.delete_file(file_path, "Deleting file", sha)
141
- return f"File '{file_path}' deleted successfully from '{repo_name}'."
142
- except Exception as e:
143
- return f"Error deleting file: {str(e)}"
144
-
145
- @tool
146
- def list_branches(repo_name: str):
147
- """Lists all branches in a GitHub repository."""
148
- try:
149
- github = Github(os.getenv('GITHUB_TOKEN'))
150
- user = github.get_user()
151
- repo = user.get_repo(repo_name)
152
- branches = repo.get_branches()
153
- branch_names = [branch.name for branch in branches]
154
- return f"Branches in '{repo_name}': {', '.join(branch_names)}"
155
- except Exception as e:
156
- return f"Error listing branches: {str(e)}"
157
-
158
- @tool
159
- def create_branch(repo_name: str, branch_name: str):
160
- """Creates a new branch in a GitHub repository."""
161
- try:
162
- github = Github(os.getenv('GITHUB_TOKEN'))
163
- user = github.get_user()
164
- repo = user.get_repo(repo_name)
165
- main_branch = repo.get_branch("main")
166
- repo.create_git_ref(ref=f"refs/heads/{branch_name}", sha=main_branch.commit.sha)
167
- return f"Branch '{branch_name}' created successfully in '{repo_name}'."
168
- except Exception as e:
169
- return f"Error creating branch: {str(e)}"
170
-
171
- @tool
172
- def current_time(location: str = None):
173
- """Get the current time for a location or current position."""
174
- try:
175
- if location:
176
- location_data = geolocator.geocode(location)
177
- if location_data:
178
- timezone = pytz.timezone(tf.timezone_at(lat=location_data.latitude, lng=location_data.longitude))
179
- location_name = location.capitalize()
180
- else:
181
- return f"Could not find location: {location}"
182
- else:
183
- # Use environment location if available
184
- lat = os.getenv('LATITUDE')
185
- lon = os.getenv('LONGITUDE')
186
- if lat and lon:
187
- timezone = pytz.timezone(tf.timezone_at(lat=float(lat), lng=float(lon)))
188
- location_name = os.getenv('LOCATION', 'Current Location')
189
- else:
190
- timezone = pytz.UTC
191
- location_name = 'UTC'
192
-
193
- current_dt = datetime.datetime.now(timezone)
194
- weekday = weekday_mapping[current_dt.weekday()]
195
- return f"Location: {location_name}; Current Date and Time: {current_dt.strftime('%Y-%m-%d %H:%M')}, {weekday}."
196
- except Exception as e:
197
- return f"Error getting current time: {str(e)}"
198
-
199
- @tool
200
- def weather(location: str = None):
201
- """Get the current weather for a location or current position."""
202
- try:
203
- weather_wrapper = OpenWeatherMapAPIWrapper(
204
- openweathermap_api_key=os.getenv('OPENWEATHERMAP_API_KEY')
205
- )
206
- if not location:
207
- location = os.getenv('LOCATION', 'Unknown')
208
- return weather_wrapper.run(location=location)
209
- except Exception as e:
210
- return f"Error getting weather: {str(e)}"
211
-
212
- @tool
213
  def get_device_list():
214
  """
215
  Get the list of devices bound to the smart home.
@@ -232,9 +59,4 @@ def change_device_states(id:str, commands:list[dict]):
232
  State format: {'code': ..., 'value': ...}
233
  """
234
  response = openapi.post('/v1.0/devices/{}/commands'.format(id), {"commands": commands})
235
- return "success" if response["success"] else "failure"
236
-
237
- coder_tools = [web_search, create_repo, create_branch, commit_file_to_repo, read_file, list_files, list_repos, list_branches, delete_file]
238
- supervisor_tools = [yahoo, web_search, current_time, weather]
239
- deep_research_tools = [web_search, yahoo, wikipedia]
240
- smart_home_tools = [get_device_list, change_device_states]
 
1
+ from langchain.tools import tool
 
 
 
 
 
 
2
  from tuya_iot import TuyaOpenAPI
 
 
 
3
  import phonenumbers
4
  import pycountry
 
 
5
  import os
6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  endpoint_map = {
8
  "https://openapi.tuyacn.com": [86],
9
  "https://openapi.tuyain.com": [91],
 
36
  connection = openapi.connect(os.getenv('TUYA_USERNAME'), os.getenv('TUYA_PASSWORD'), os.getenv('TUYA_COUNTRY_CODE'), 'TuyaSmart')
37
  if not connection['success']:
38
  connection = openapi.connect(os.getenv('TUYA_USERNAME'), os.getenv('TUYA_PASSWORD'), os.getenv('TUYA_COUNTRY_CODE'), 'SmartLife')
 
 
 
 
 
 
 
 
 
 
39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  def get_device_list():
41
  """
42
  Get the list of devices bound to the smart home.
 
59
  State format: {'code': ..., 'value': ...}
60
  """
61
  response = openapi.post('/v1.0/devices/{}/commands'.format(id), {"commands": commands})
62
+ return "success" if response["success"] else "failure"
 
 
 
 
 
app.py CHANGED
@@ -1,7 +1,7 @@
1
- from agent.file_preprocessing import preprocess_file, preprocess_audio
2
  from fastapi import FastAPI, UploadFile, File, HTTPException
3
  from langchain_core.messages import HumanMessage
4
- from agent.multi_agent import Assistant
5
  from typing import Any, Dict
6
  from fastapi import Form
7
  from pathlib import Path
 
1
+ from agents.utils.file_preprocessing import preprocess_file, preprocess_audio
2
  from fastapi import FastAPI, UploadFile, File, HTTPException
3
  from langchain_core.messages import HumanMessage
4
+ from agents.multi_agent import Assistant
5
  from typing import Any, Dict
6
  from fastapi import Form
7
  from pathlib import Path