├── docs └── logo.png ├── src ├── service │ ├── __init__.py │ └── workflow_service.py ├── config │ ├── tools.py │ ├── agents.py │ ├── __init__.py │ └── env.py ├── prompts │ ├── __init__.py │ ├── file_manager.md │ ├── supervisor.md │ ├── coordinator.md │ ├── researcher.md │ ├── reporter.md │ ├── browser.md │ ├── template.py │ ├── planner.md │ └── coder.md ├── llms │ ├── __init__.py │ └── llm.py ├── tools │ ├── web_browser.py │ ├── data_retriever.py │ ├── code_executor.py │ ├── file_management.py │ ├── server.py │ ├── browser.py │ ├── search.py │ ├── decorators.py │ ├── crawl.py │ ├── python_repl.py │ └── bash_tool.py ├── utils │ ├── __init__.py │ └── json_utils.py ├── components │ ├── ChatInput.js │ └── ChatDisplay.js ├── agents │ ├── __init__.py │ ├── coder_agent.py │ ├── browser_agent.py │ ├── reporter_agent.py │ ├── nodes │ │ ├── types.py │ │ ├── browser_node.py │ │ ├── coder_node.py │ │ ├── researcher_node.py │ │ ├── reporter_node.py │ │ ├── coordinator_node.py │ │ ├── supervisor_node.py │ │ └── planner_node.py │ ├── research_agent.py │ └── coordinator.py ├── graph │ └── types.py ├── client.py ├── pages │ └── index.js ├── workflow │ └── graph.py └── server.py ├── docker ├── frontend │ └── Dockerfile └── unified │ ├── Dockerfile │ └── start.sh ├── next.config.js ├── tests └── integration │ └── test_workflow.py ├── requirements.txt ├── package.json ├── docker-compose.yml ├── LICENSE ├── .clinerules ├── .gitignore ├── plans.md └── README.md /docs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/henryalps/OpenManus/HEAD/docs/logo.png -------------------------------------------------------------------------------- /src/service/__init__.py: -------------------------------------------------------------------------------- 1 | """Service package for OpenManus workflow management.""" -------------------------------------------------------------------------------- /src/config/tools.py: -------------------------------------------------------------------------------- 1 | # Tool configuration 2 | BROWSER_HISTORY_DIR = "static/browser_history" -------------------------------------------------------------------------------- /src/prompts/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = [ 2 | "apply_prompt_template", 3 | "get_prompt_template", 4 | ] -------------------------------------------------------------------------------- /src/llms/__init__.py: -------------------------------------------------------------------------------- 1 | from .llm import PlaceholderLLM, get_llm_by_type 2 | 3 | __all__ = ['PlaceholderLLM', 'get_llm_by_type'] -------------------------------------------------------------------------------- /src/tools/web_browser.py: -------------------------------------------------------------------------------- 1 | class WebBrowserTool: 2 | def browse_web(self, url): 3 | return f"Placeholder: Web content from {url}" -------------------------------------------------------------------------------- /src/utils/__init__.py: -------------------------------------------------------------------------------- 1 | """Utility functions for OpenManus.""" 2 | 3 | from .json_utils import repair_json_output 4 | 5 | __all__ = ['repair_json_output'] -------------------------------------------------------------------------------- /docker/frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM davidetriso/nextjs:node-20.18-debian 2 | 3 | WORKDIR /app 4 | 5 | COPY . . 6 | 7 | EXPOSE 3000 8 | 9 | CMD ["npm", "start"] -------------------------------------------------------------------------------- /src/tools/data_retriever.py: -------------------------------------------------------------------------------- 1 | class DataRetrieverTool: 2 | def retrieve_data(self, query): 3 | return f"Placeholder: Data retrieved for query: {query}" -------------------------------------------------------------------------------- /src/tools/code_executor.py: -------------------------------------------------------------------------------- 1 | class CodeExecutorTool: 2 | def execute_code(self, code, language): 3 | return f"Placeholder: Code executed: {language}\\nOutput:\\n{code}" -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | output: 'standalone', 5 | experimental: { 6 | outputFileTracingRoot: undefined 7 | } 8 | } 9 | 10 | module.exports = nextConfig -------------------------------------------------------------------------------- /tests/integration/test_workflow.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from src.workflow.graph import build_graph 3 | 4 | def test_workflow_initialization(): 5 | """Test that the LangGraph workflow can be initialized.""" 6 | graph = build_graph() 7 | assert graph is not None -------------------------------------------------------------------------------- /src/components/ChatInput.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | function ChatInput() { 4 | return ( 5 |
6 | 7 | 8 |
9 | ); 10 | } 11 | 12 | export default ChatInput; -------------------------------------------------------------------------------- /docker/unified/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9 2 | 3 | RUN apt-get update && apt-get -y install tree 4 | 5 | WORKDIR /app 6 | 7 | # Install Python dependencies 8 | COPY requirements.txt . 9 | RUN pip install -r requirements.txt 10 | 11 | COPY . . 12 | 13 | CMD ["sh", "/app/docker/unified/start.sh"] -------------------------------------------------------------------------------- /src/prompts/file_manager.md: -------------------------------------------------------------------------------- 1 | --- 2 | CURRENT_TIME: <> 3 | --- 4 | 5 | You are a file manager responsible for saving results to markdown files. 6 | 7 | # Notes 8 | 9 | - You should format the content nicely with proper markdown syntax before saving. 10 | - Always use the same language as the initial question. -------------------------------------------------------------------------------- /src/tools/file_management.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from langchain_community.tools.file_management import WriteFileTool 3 | from .decorators import create_logged_tool 4 | 5 | logger = logging.getLogger(__name__) 6 | 7 | # Initialize file management tool with logging 8 | LoggedWriteFile = create_logged_tool(WriteFileTool) 9 | write_file_tool = LoggedWriteFile() -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | flask>=2.0.0 2 | requests>=2.26.0 3 | python-dotenv>=0.19.0 4 | fastapi>=0.68.0 5 | uvicorn>=0.15.0 6 | pydantic>=1.8.0 7 | sse-starlette>=0.7.0 8 | langgraph>=0.0.10 9 | langchain>=0.1.0 10 | langchain-core>=0.1.0 11 | langchain-community>=0.0.10 12 | langchain-experimental>=0.0.10 13 | json-repair>=0.3.0 14 | pytest>=7.0.0 15 | pytest-cov>=4.0.0 -------------------------------------------------------------------------------- /src/agents/__init__.py: -------------------------------------------------------------------------------- 1 | # Initialize agents package 2 | 3 | from .browser_agent import browser_agent 4 | from .coder_agent import coder_agent 5 | from .research_agent import research_agent 6 | from .reporter_agent import reporter_agent 7 | 8 | __all__ = [ 9 | 'browser_agent', 10 | 'coder_agent', 11 | 'research_agent', 12 | 'reporter_agent', 13 | ] -------------------------------------------------------------------------------- /src/components/ChatDisplay.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | function ChatDisplay({ messages }) { 4 | return ( 5 |
6 | {messages.map((message, index) => ( 7 |
8 | {message.sender}: {message.text} 9 |
10 | ))} 11 |
12 | ); 13 | } 14 | 15 | export default ChatDisplay; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "openmanus", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "next": "^14.0.0", 7 | "react": "^18.2.0", 8 | "react-dom": "^18.2.0", 9 | "axios": "^1.3.4" 10 | }, 11 | "scripts": { 12 | "dev": "next dev", 13 | "build": "next build", 14 | "start": "next start", 15 | "lint": "next lint" 16 | } 17 | } -------------------------------------------------------------------------------- /src/tools/server.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request, jsonify 2 | import logging 3 | 4 | app = Flask(__name__) 5 | logging.basicConfig(level=logging.INFO) 6 | logger = logging.getLogger(__name__) 7 | 8 | @app.route('/health', methods=['GET']) 9 | def health_check(): 10 | return jsonify({'status': 'ok'}) 11 | 12 | if __name__ == '__main__': 13 | app.run(host='0.0.0.0', port=5001) -------------------------------------------------------------------------------- /docker/unified/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Start FastAPI server in background 4 | PYTHONPATH=/app:/app/src python3 -m uvicorn src.server:app --host 0.0.0.0 --port 8000 --reload & 5 | 6 | # Start tools server in background 7 | PYTHONPATH=/app:/app/src python3 src/tools/server.py & 8 | 9 | # Wait for all background processes to complete 10 | wait 11 | 12 | # Exit with the status of the last command 13 | exit $? -------------------------------------------------------------------------------- /src/tools/browser.py: -------------------------------------------------------------------------------- 1 | from langchain.tools import BaseTool 2 | 3 | class BrowserTool(BaseTool): 4 | name: str = "browser" 5 | description: str = "Placeholder browser tool" 6 | 7 | def _run(self, instruction: str) -> str: 8 | return "Browser tool placeholder" 9 | 10 | async def _arun(self, instruction: str) -> str: 11 | return "Browser tool placeholder" 12 | 13 | browser_tool = BrowserTool() -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | services: 4 | unified: 5 | build: 6 | context: . 7 | dockerfile: docker/unified/Dockerfile 8 | ports: 9 | - "8000:8000" 10 | environment: 11 | - PYTHONPATH=/app 12 | - FLASK_APP=src/server.py 13 | - FLASK_ENV=development 14 | 15 | frontend: 16 | build: 17 | context: . 18 | dockerfile: docker/frontend/Dockerfile 19 | ports: 20 | - "3000:3000" 21 | depends_on: 22 | - unified -------------------------------------------------------------------------------- /src/tools/search.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import logging 3 | from src.tools.browser import browser_tool # Import the existing browser tool 4 | from .decorators import create_logged_tool 5 | 6 | logger = logging.getLogger(__name__) 7 | 8 | # Initialize Bing search tool using browser tool with logging 9 | LoggedBrowserSearch = create_logged_tool(browser_tool.__class__) # Use the class of browser_tool 10 | bing_tool = LoggedBrowserSearch(name="bing_search", description="Search Bing using a headless browser.") # Updated name and description -------------------------------------------------------------------------------- /src/agents/coder_agent.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | from langchain_core.messages import BaseMessage 3 | 4 | from src.llms.llm import get_llm_by_type 5 | from src.config.agents import AGENT_LLM_MAP 6 | 7 | class CoderAgent: 8 | """Coder agent that handles code-related tasks.""" 9 | 10 | def invoke(self, messages: List[BaseMessage]) -> BaseMessage: 11 | """Process the messages and return a response.""" 12 | llm = get_llm_by_type(AGENT_LLM_MAP["coder"]) 13 | return llm.invoke(messages) 14 | 15 | coder_agent = CoderAgent() -------------------------------------------------------------------------------- /src/config/agents.py: -------------------------------------------------------------------------------- 1 | from typing import Literal 2 | 3 | # Define available LLM types 4 | LLMType = Literal["basic", "reasoning", "vision"] 5 | 6 | # Define agent-LLM mapping 7 | AGENT_LLM_MAP: dict[str, LLMType] = { 8 | "coordinator": "basic", # 协调默认使用basic llm 9 | "planner": "reasoning", # 计划默认使用basic llm 10 | "supervisor": "basic", # 决策使用basic llm 11 | "researcher": "basic", # 简单搜索任务使用basic llm 12 | "coder": "basic", # 编程任务使用basic llm 13 | "browser": "vision", # 浏览器操作使用vision llm 14 | "reporter": "basic", # 编写报告使用basic llm 15 | } -------------------------------------------------------------------------------- /src/agents/browser_agent.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | from langchain_core.messages import BaseMessage 3 | 4 | from src.llms.llm import get_llm_by_type 5 | from src.config.agents import AGENT_LLM_MAP 6 | 7 | class BrowserAgent: 8 | """Browser agent that handles web browsing tasks.""" 9 | 10 | def invoke(self, messages: List[BaseMessage]) -> BaseMessage: 11 | """Process the messages and return a response.""" 12 | llm = get_llm_by_type(AGENT_LLM_MAP["browser"]) 13 | return llm.invoke(messages) 14 | 15 | browser_agent = BrowserAgent() -------------------------------------------------------------------------------- /src/agents/reporter_agent.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | from langchain_core.messages import BaseMessage 3 | 4 | from src.llms.llm import get_llm_by_type 5 | from src.config.agents import AGENT_LLM_MAP 6 | 7 | class ReporterAgent: 8 | """Reporter agent that handles report generation tasks.""" 9 | 10 | def invoke(self, messages: List[BaseMessage]) -> BaseMessage: 11 | """Process the messages and return a response.""" 12 | llm = get_llm_by_type(AGENT_LLM_MAP["reporter"]) 13 | return llm.invoke(messages) 14 | 15 | reporter_agent = ReporterAgent() -------------------------------------------------------------------------------- /src/agents/nodes/types.py: -------------------------------------------------------------------------------- 1 | from typing import TypedDict, Literal, List, Dict, Any 2 | from langchain_core.messages import BaseMessage 3 | 4 | class State(TypedDict): 5 | """Type definition for the workflow state.""" 6 | messages: List[BaseMessage] 7 | full_plan: str 8 | next: str 9 | deep_thinking_mode: bool 10 | search_before_planning: bool 11 | 12 | class Router(TypedDict): 13 | """Type definition for the supervisor's routing decision.""" 14 | next: Literal['coordinator', 'planner', 'supervisor', 'researcher', 'coder', 'browser', 'reporter', 'FINISH'] -------------------------------------------------------------------------------- /src/agents/research_agent.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | from langchain_core.messages import BaseMessage 3 | 4 | from src.llms.llm import get_llm_by_type 5 | from src.config.agents import AGENT_LLM_MAP 6 | 7 | class ResearchAgent: 8 | """Research agent that handles research and information gathering tasks.""" 9 | 10 | def invoke(self, messages: List[BaseMessage]) -> BaseMessage: 11 | """Process the messages and return a response.""" 12 | llm = get_llm_by_type(AGENT_LLM_MAP["researcher"]) 13 | return llm.invoke(messages) 14 | 15 | research_agent = ResearchAgent() -------------------------------------------------------------------------------- /src/tools/decorators.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import functools 3 | from typing import Any, Callable, Type, TypeVar 4 | 5 | logger = logging.getLogger(__name__) 6 | 7 | T = TypeVar("T") 8 | 9 | def log_io(func: Callable) -> Callable: 10 | @functools.wraps(func) 11 | def wrapper(*args: Any, **kwargs: Any) -> Any: 12 | return func(*args, **kwargs) 13 | return wrapper 14 | 15 | class LoggedToolMixin: 16 | def _run(self, *args: Any, **kwargs: Any) -> Any: 17 | return super()._run(*args, **kwargs) 18 | 19 | def create_logged_tool(base_tool_class: Type[T]) -> Type[T]: 20 | class LoggedTool(LoggedToolMixin, base_tool_class): 21 | pass 22 | return LoggedTool -------------------------------------------------------------------------------- /src/graph/types.py: -------------------------------------------------------------------------------- 1 | from typing import Literal 2 | from typing_extensions import TypedDict 3 | from langgraph.graph import MessagesState 4 | 5 | from src.config import TEAM_MEMBERS 6 | 7 | # Define routing options 8 | OPTIONS = TEAM_MEMBERS + ["FINISH"] 9 | 10 | 11 | class Router(TypedDict): 12 | """Worker to route to next. If no workers needed, route to FINISH.""" 13 | 14 | next: Literal[OPTIONS[0], OPTIONS[1], OPTIONS[2], OPTIONS[3], "FINISH"] 15 | 16 | 17 | class State(MessagesState): 18 | """State for the agent system, extends MessagesState with next field.""" 19 | 20 | # Constants 21 | TEAM_MEMBERS: list[str] 22 | 23 | # Runtime Variables 24 | next: str 25 | full_plan: str 26 | deep_thinking_mode: bool 27 | search_before_planning: bool -------------------------------------------------------------------------------- /src/utils/json_utils.py: -------------------------------------------------------------------------------- 1 | """Utility functions for JSON handling in OpenManus.""" 2 | 3 | import json 4 | import json_repair 5 | 6 | def repair_json_output(json_str: str) -> str: 7 | """Repair malformed JSON strings. 8 | 9 | Args: 10 | json_str: The potentially malformed JSON string to repair. 11 | 12 | Returns: 13 | str: A valid JSON string. 14 | """ 15 | try: 16 | # First try to parse as-is 17 | json.loads(json_str) 18 | return json_str 19 | except json.JSONDecodeError: 20 | # If parsing fails, attempt repair 21 | try: 22 | return json_repair.repair_json(json_str) 23 | except Exception as e: 24 | # If repair fails, return original string 25 | return json_str -------------------------------------------------------------------------------- /src/tools/crawl.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from typing import Annotated 3 | 4 | from langchain_core.messages import HumanMessage 5 | from langchain_core.tools import tool 6 | from .decorators import log_io 7 | 8 | from src.crawler import Crawler 9 | 10 | logger = logging.getLogger(__name__) 11 | 12 | 13 | @tool 14 | @log_io 15 | def crawl_tool( 16 | url: Annotated[str, "The url to crawl."], 17 | ) -> HumanMessage: 18 | """Use this to crawl a url and get a readable content in markdown format.""" 19 | try: 20 | crawler = Crawler() 21 | article = crawler.crawl(url) 22 | return {"role": "user", "content": article.to_message()} 23 | except BaseException as e: 24 | error_msg = f"Failed to crawl. Error: {repr(e)}" 25 | logger.error(error_msg) 26 | return error_msg -------------------------------------------------------------------------------- /src/client.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import requests 3 | import json 4 | 5 | def submit_task(task, host="http://localhost:5000"): 6 | """Submit a task to the agent server.""" 7 | try: 8 | response = requests.post(f"{host}/task", json={"task": task}) 9 | response.raise_for_status() 10 | return response.json() 11 | except requests.exceptions.RequestException as e: 12 | return {"error": str(e)} 13 | 14 | def main(): 15 | parser = argparse.ArgumentParser(description="OpenManus CLI Client") 16 | parser.add_argument("--task", required=True, help="Task description") 17 | parser.add_argument("--host", default="http://localhost:5000", help="Agent server host") 18 | 19 | args = parser.parse_args() 20 | 21 | result = submit_task(args.task, args.host) 22 | print(json.dumps(result, indent=2)) 23 | 24 | if __name__ == "__main__": 25 | main() -------------------------------------------------------------------------------- /src/pages/index.js: -------------------------------------------------------------------------------- 1 | import ChatInput from '../components/ChatInput'; 2 | import ChatDisplay from '../components/ChatDisplay'; 3 | import React, { useState } from 'react'; 4 | 5 | function HomePage() { 6 | const [messages, setMessages] = useState([]); 7 | 8 | const handleSendMessage = (newMessage) => { 9 | setMessages([...messages, { sender: 'user', text: newMessage }]); 10 | // Here you would typically send the message to the backend and handle the response 11 | // For now, let's just add a placeholder response from the AI 12 | setTimeout(() => { 13 | setMessages([...messages, { sender: 'ai', text: 'This is a placeholder response from the AI.' }]); 14 | }, 500); // Simulate a delay for AI response 15 | }; 16 | 17 | return ( 18 |
19 |

Welcome to OpenManus!

20 | 21 | 22 |
23 | ); 24 | } 25 | 26 | export default HomePage; -------------------------------------------------------------------------------- /src/tools/python_repl.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from typing import Annotated 3 | from langchain_core.tools import tool 4 | from langchain_experimental.utilities import PythonREPL 5 | from .decorators import log_io 6 | 7 | # Initialize REPL and logger 8 | repl = PythonREPL() 9 | logger = logging.getLogger(__name__) 10 | 11 | 12 | @tool 13 | @log_io 14 | def python_repl_tool( 15 | code: Annotated[ 16 | str, "The python code to execute to do further analysis or calculation." 17 | ], 18 | ): 19 | """Use this to execute python code and do data analysis or calculation. If you want to see the output of a value, 20 | you should print it out with `print(...)`. This is visible to the user.""" 21 | logger.info("Executing Python code") 22 | try: 23 | result = repl.run(code) 24 | logger.info("Code execution successful") 25 | except BaseException as e: 26 | error_msg = f"Failed to execute. Error: {repr(e)}" 27 | logger.error(error_msg) 28 | return error_msg 29 | result_str = f"Successfully executed:\\n```python\\n{code}\\n```\\nStdout: {result}" 30 | return result_str -------------------------------------------------------------------------------- /src/agents/nodes/browser_node.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import json_repair 3 | from typing import Literal, Dict, Any 4 | from langchain_core.messages import HumanMessage 5 | 6 | from src.agents import browser_agent # Import browser agent 7 | from src.utils.json_utils import repair_json_output 8 | from .types import State # Import State type 9 | 10 | logger = logging.getLogger(__name__) 11 | 12 | def browser_node(state: State) -> Dict[str, Any]: # Modified return type to Dict 13 | """Node for the browser agent that performs web browsing tasks.""" 14 | logger.info("Browser agent starting task") 15 | result = browser_agent.invoke(state) 16 | logger.info("Browser agent completed task") 17 | response_content = result["messages"][-1].content 18 | response_content = repair_json_output(response_content) 19 | logger.debug(f"Browser agent response: {response_content}") 20 | return Command( 21 | update={ 22 | "messages": [ 23 | HumanMessage( 24 | content=response_content, 25 | name="browser", 26 | ) 27 | ] 28 | }, 29 | goto="supervisor", 30 | ) -------------------------------------------------------------------------------- /src/agents/nodes/coder_node.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import json_repair 3 | from typing import Literal, Dict, Any 4 | from langchain_core.messages import HumanMessage 5 | from langgraph.types import Command 6 | 7 | from src.agents import coder_agent # Import coder agent 8 | from src.utils.json_utils import repair_json_output 9 | from .types import State # Import State type 10 | 11 | logger = logging.getLogger(__name__) 12 | 13 | def coder_node(state: State) -> Dict[str, Any]: # Modified return type to Dict 14 | """Node for the coder agent that executes Python code.""" 15 | logger.info("Code agent starting task") 16 | result = coder_agent.invoke(state) 17 | logger.info("Code agent completed task") 18 | response_content = result["messages"][-1].content 19 | response_content = repair_json_output(response_content) 20 | logger.debug(f"Code agent response: {response_content}") 21 | return Command( 22 | update={ 23 | "messages": [ 24 | HumanMessage( 25 | content=response_content, 26 | name="coder", 27 | ) 28 | ] 29 | }, 30 | goto="supervisor", 31 | ) -------------------------------------------------------------------------------- /src/agents/nodes/researcher_node.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import json_repair 3 | from typing import Literal, Dict, Any 4 | from langchain_core.messages import HumanMessage 5 | from langgraph.types import Command 6 | 7 | from src.agents import research_agent # Import researcher agent 8 | from src.utils.json_utils import repair_json_output 9 | from .types import State # Import State type 10 | 11 | logger = logging.getLogger(__name__) 12 | 13 | def researcher_node(state: State) -> Dict[str, Any]: # Modified return type to Dict 14 | """Node for the researcher agent that performs research tasks.""" 15 | logger.info("Research agent starting task") 16 | result = research_agent.invoke(state) 17 | logger.info("Research agent completed task") 18 | response_content = result["messages"][-1].content 19 | response_content = repair_json_output(response_content) 20 | logger.debug(f"Research agent response: {response_content}") 21 | return Command( 22 | update={ 23 | "messages": [ 24 | HumanMessage( 25 | content=response_content, 26 | name="researcher", 27 | ) 28 | ] 29 | }, 30 | goto="supervisor", 31 | ) -------------------------------------------------------------------------------- /src/service/workflow_service.py: -------------------------------------------------------------------------------- 1 | """Workflow service for managing agent workflow execution.""" 2 | 3 | import asyncio 4 | from typing import AsyncGenerator, Dict, List 5 | 6 | from src.workflow.graph import build_graph 7 | from src.prompts.template import OpenManusPromptTemplate 8 | 9 | 10 | async def run_agent_workflow( 11 | messages: List[Dict[str, str]], debug: bool = False 12 | ) -> AsyncGenerator[Dict[str, str], None]: 13 | """Run the agent workflow with the given messages. 14 | 15 | Args: 16 | messages: List of chat messages 17 | debug: Whether to enable debug logging 18 | 19 | Yields: 20 | Event data for SSE streaming 21 | """ 22 | # Initialize workflow graph 23 | workflow = build_graph() 24 | 25 | # Format messages with system prompt 26 | formatted_messages = OpenManusPromptTemplate.apply_prompt_template( 27 | "coordinator", {"messages": messages} 28 | ) 29 | 30 | # Run workflow 31 | async for event in workflow.astream({"messages": formatted_messages}): 32 | yield { 33 | "event": "message", 34 | "data": {"content": event.get("content", ""), "role": "assistant"} 35 | } 36 | # Small delay to avoid overwhelming the client 37 | await asyncio.sleep(0.1) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /src/tools/bash_tool.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import subprocess 3 | from typing import Annotated 4 | from langchain_core.tools import tool 5 | from .decorators import log_io 6 | 7 | # Initialize logger 8 | logger = logging.getLogger(__name__) 9 | 10 | 11 | @tool 12 | @log_io 13 | def bash_tool( 14 | cmd: Annotated[str, "The bash command to be executed."], 15 | ): 16 | """Use this to execute bash command and do necessary operations.""" 17 | logger.info(f"Executing Bash Command: {cmd}") 18 | try: 19 | # Execute the command and capture output 20 | result = subprocess.run( 21 | cmd, shell=True, check=True, text=True, capture_output=True 22 | ) 23 | # Return stdout as the result 24 | return result.stdout 25 | except subprocess.CalledProcessError as e: 26 | # If command fails, return error information 27 | error_message = f"Command failed with exit code {e.returncode}.\nStdout: {e.stdout}\nStderr: {e.stderr}" 28 | logger.error(error_message) 29 | return error_message 30 | except Exception as e: 31 | # Catch any other exceptions 32 | error_message = f"Error executing command: {str(e)}" 33 | logger.error(error_message) 34 | return error_message 35 | 36 | 37 | if __name__ == "__main__": 38 | print(bash_tool.invoke("ls -all")) -------------------------------------------------------------------------------- /src/prompts/supervisor.md: -------------------------------------------------------------------------------- 1 | --- 2 | CURRENT_TIME: <> 3 | --- 4 | 5 | You are a supervisor coordinating a team of specialized workers to complete tasks. Your team consists of: <>. 6 | 7 | For each user request, you will: 8 | 1. Analyze the request and determine which worker is best suited to handle it next 9 | 2. Respond with ONLY a JSON object in the format: {"next": "worker_name"} 10 | 3. Review their response and either: 11 | - Choose the next worker if more work is needed (e.g., {"next": "researcher"}) 12 | - Respond with {"next": "FINISH"} when the task is complete 13 | 14 | Always respond with a valid JSON object containing only the 'next' key and a single value: either a worker's name or 'FINISH'. 15 | 16 | ## Team Members 17 | - **`researcher`**: Uses search engines and web crawlers to gather information from the internet. Outputs a Markdown report summarizing findings. Researcher can not do math or programming. 18 | - **`coder`**: Executes Python or Bash commands, performs mathematical calculations, and outputs a Markdown report. Must be used for all mathematical computations. 19 | - **`browser`**: Directly interacts with web pages, performing complex operations and interactions. You can also leverage `browser` to perform in-domain search, like Facebook, Instgram, Github, etc. 20 | - **`reporter`**: Wriite a professional report based on the result of each step. -------------------------------------------------------------------------------- /src/agents/nodes/reporter_node.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import json_repair 3 | from typing import Literal, Dict, Any 4 | from langchain_core.messages import HumanMessage 5 | from langgraph.types import Command 6 | 7 | from src.agents import reporter_agent # Import reporter agent 8 | from src.utils.json_utils import repair_json_output 9 | from src.prompts.template import OpenManusPromptTemplate 10 | from .types import State # Import State type 11 | 12 | logger = logging.getLogger(__name__) 13 | 14 | def reporter_node(state: State) -> Dict[str, Any]: # Modified return type to Dict 15 | """Reporter node that write a final report.""" 16 | logger.info("Reporter writing final report") 17 | messages = OpenManusPromptTemplate.apply_prompt_template("reporter", state) 18 | response = reporter_agent.invoke(state) 19 | logger.debug(f"Current state messages: {state['messages']}") 20 | response_content = response.content 21 | response_content = repair_json_output(response_content) 22 | logger.debug(f"Reporter agent response: {response_content}") 23 | 24 | return Command( 25 | update={ 26 | "messages": [ 27 | HumanMessage( 28 | content=response_content, 29 | name="reporter", 30 | ) 31 | ] 32 | }, 33 | goto="supervisor", # Go back to supervisor to decide next step 34 | ) -------------------------------------------------------------------------------- /src/config/__init__.py: -------------------------------------------------------------------------------- 1 | from .env import ( 2 | # AZURE Config 3 | AZURE_API_BASE, 4 | AZURE_API_KEY, 5 | AZURE_API_VERSION, 6 | # Reasoning LLM 7 | REASONING_MODEL, 8 | REASONING_BASE_URL, 9 | REASONING_API_KEY, 10 | REASONING_AZURE_DEPLOYMENT, 11 | # Basic LLM 12 | BASIC_MODEL, 13 | BASIC_BASE_URL, 14 | BASIC_API_KEY, 15 | BASIC_AZURE_DEPLOYMENT, 16 | # Vision-language LLM 17 | VL_MODEL, 18 | VL_BASE_URL, 19 | VL_API_KEY, 20 | VL_AZURE_DEPLOYMENT, 21 | # Other configurations 22 | CHROME_INSTANCE_PATH, 23 | CHROME_HEADLESS, 24 | CHROME_PROXY_SERVER, 25 | CHROME_PROXY_USERNAME, 26 | CHROME_PROXY_PASSWORD, 27 | ) 28 | from .tools import BROWSER_HISTORY_DIR 29 | 30 | # Team configuration 31 | TEAM_MEMBERS = ["researcher", "coder", "browser", "reporter"] 32 | 33 | __all__ = [ 34 | # Reasoning LLM 35 | "REASONING_MODEL", 36 | "REASONING_BASE_URL", 37 | "REASONING_API_KEY", 38 | # Basic LLM 39 | "BASIC_MODEL", 40 | "BASIC_BASE_URL", 41 | "BASIC_API_KEY", 42 | # Vision-language LLM 43 | "VL_MODEL", 44 | "VL_BASE_URL", 45 | "VL_API_KEY", 46 | # Other configurations 47 | "TEAM_MEMBERS", 48 | "CHROME_INSTANCE_PATH", 49 | "CHROME_HEADLESS", 50 | "CHROME_PROXY_SERVER", 51 | "CHROME_PROXY_USERNAME", 52 | "CHROME_PROXY_PASSWORD", 53 | "BROWSER_HISTORY_DIR", 54 | ] -------------------------------------------------------------------------------- /src/agents/nodes/coordinator_node.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import json_repair 3 | from typing import Literal, Dict, Any 4 | from langchain_core.messages import HumanMessage 5 | 6 | from src.llms.llm import get_llm_by_type 7 | from src.config.agents import AGENT_LLM_MAP 8 | from src.prompts.template import OpenManusPromptTemplate 9 | from src.utils.json_utils import repair_json_output 10 | from .types import State, Router # Import State and Router types 11 | 12 | logger = logging.getLogger(__name__) 13 | 14 | def coordinator_node(state: State) -> Dict[str, Any]: # Modified return type to Dict 15 | """Coordinator node that communicate with customers.""" 16 | logger.info("Coordinator talking.") 17 | messages = OpenManusPromptTemplate.apply_prompt_template("coordinator", state) 18 | response = get_llm_by_type(AGENT_LLM_MAP["coordinator"]).invoke(messages) 19 | logger.debug(f"Current state messages: {state['messages']}") 20 | response_content = response.content 21 | # Attempt to repair potential JSON output 22 | response_content = repair_json_output(response_content) 23 | logger.debug(f"Coordinator response: {response_content}") 24 | 25 | goto = "__end__" 26 | if "handoff_to_planner" in response_content: 27 | goto = "planner" 28 | 29 | # Update response.content with repaired content 30 | response.content = response_content 31 | 32 | return Command( 33 | goto=goto, 34 | ) -------------------------------------------------------------------------------- /src/llms/llm.py: -------------------------------------------------------------------------------- 1 | import os 2 | from typing import Literal, Type 3 | 4 | from src.config.agents import LLMType 5 | from src.config.env import ( 6 | BASIC_API_KEY, 7 | BASIC_BASE_URL, 8 | BASIC_MODEL, 9 | REASONING_API_KEY, 10 | REASONING_BASE_URL, 11 | REASONING_MODEL, 12 | VL_API_KEY, 13 | VL_BASE_URL, 14 | VL_MODEL, 15 | AZURE_API_BASE, 16 | AZURE_API_KEY, 17 | AZURE_API_VERSION, 18 | BASIC_AZURE_DEPLOYMENT, 19 | VL_AZURE_DEPLOYMENT, 20 | REASONING_AZURE_DEPLOYMENT 21 | ) 22 | 23 | class PlaceholderLLM: 24 | def __init__(self, model_name): 25 | self.model_name = model_name 26 | 27 | def invoke(self, messages): 28 | return f"Placeholder LLM: {self.model_name} invoked with messages: {messages}" 29 | 30 | def get_llm_by_type(llm_type: LLMType): 31 | if llm_type == "reasoning": 32 | model_name = REASONING_MODEL 33 | base_url = REASONING_BASE_URL 34 | api_key = REASONING_API_KEY 35 | azure_deployment = REASONING_AZURE_DEPLOYMENT 36 | elif llm_type == "vision": 37 | model_name = VL_MODEL 38 | base_url = VL_BASE_URL 39 | api_key = VL_API_KEY 40 | azure_deployment = VL_AZURE_DEPLOYMENT 41 | elif llm_type == "basic": 42 | model_name = BASIC_MODEL 43 | base_url = BASIC_BASE_URL 44 | api_key = BASIC_API_KEY 45 | azure_deployment = BASIC_AZURE_DEPLOYMENT 46 | else: 47 | raise ValueError(f"Unknown LLM type: {llm_type}") 48 | 49 | return PlaceholderLLM(model_name) -------------------------------------------------------------------------------- /src/config/env.py: -------------------------------------------------------------------------------- 1 | import os 2 | from dotenv import load_dotenv 3 | 4 | # Load environment variables 5 | load_dotenv() 6 | 7 | # Reasoning LLM configuration (for complex reasoning tasks) 8 | REASONING_MODEL = os.getenv("REASONING_MODEL", "deepseek-r1") 9 | REASONING_BASE_URL = os.getenv("REASONING_BASE_URL") 10 | REASONING_API_KEY = os.getenv("REASONING_API_KEY") 11 | 12 | # Non-reasoning LLM configuration (for straightforward tasks) 13 | BASIC_MODEL = os.getenv("BASIC_MODEL", "gemini-2.0-flash") 14 | BASIC_BASE_URL = os.getenv("BASIC_BASE_URL") 15 | BASIC_API_KEY = os.getenv("BASIC_API_KEY") 16 | 17 | # Azure OpenAI配置(按LLM类型区分) 18 | AZURE_API_BASE = os.getenv("AZURE_API_BASE") 19 | AZURE_API_KEY = os.getenv("AZURE_API_KEY") 20 | AZURE_API_VERSION = os.getenv("AZURE_API_VERSION") 21 | # 各类型专用部署名称 22 | BASIC_AZURE_DEPLOYMENT = os.getenv("BASIC_AZURE_DEPLOYMENT") 23 | VL_AZURE_DEPLOYMENT = os.getenv("VL_AZURE_DEPLOYMENT") 24 | REASONING_AZURE_DEPLOYMENT = os.getenv("REASONING_AZURE_DEPLOYMENT") 25 | 26 | # Vision-language LLM configuration (for tasks requiring visual understanding) 27 | VL_MODEL = os.getenv("VL_MODEL", "gemini-2.0-flash") 28 | VL_BASE_URL = os.getenv("VL_BASE_URL") 29 | VL_API_KEY = os.getenv("VL_API_KEY") 30 | 31 | # Chrome Instance configuration 32 | CHROME_INSTANCE_PATH = os.getenv("CHROME_INSTANCE_PATH") 33 | CHROME_HEADLESS = os.getenv("CHROME_HEADLESS", "False") == "True" 34 | CHROME_PROXY_SERVER = os.getenv("CHROME_PROXY_SERVER") 35 | CHROME_PROXY_USERNAME = os.getenv("CHROME_PROXY_USERNAME") 36 | CHROME_PROXY_PASSWORD = os.getenv("CHROME_PROXY_PASSWORD") -------------------------------------------------------------------------------- /src/prompts/coordinator.md: -------------------------------------------------------------------------------- 1 | --- 2 | CURRENT_TIME: <> 3 | --- 4 | 5 | You are OpenManus, a powerful AI assistant focused on task coordination and workflow management. Your role is to efficiently handle user interactions and delegate complex tasks to specialized agents. 6 | 7 | # Details 8 | 9 | Your primary responsibilities are: 10 | - Managing initial user interactions and task intake 11 | - Understanding and clarifying user requirements 12 | - Coordinating with specialized agents for task execution 13 | - Ensuring appropriate task delegation and workflow management 14 | - Maintaining clear communication throughout the process 15 | 16 | # Execution Rules 17 | 18 | - For initial interactions: 19 | - Greet users professionally and establish context 20 | - Gather necessary information about the task 21 | - Ensure clear understanding of requirements 22 | 23 | - For task management: 24 | - Analyze task complexity and requirements 25 | - Determine appropriate agent allocation 26 | - Coordinate workflow between agents 27 | - Monitor task progress and completion 28 | 29 | - For security and validation: 30 | - Verify task safety and appropriateness 31 | - Reject harmful or inappropriate requests 32 | - Ensure data privacy and security compliance 33 | 34 | # Task Delegation 35 | 36 | - For complex tasks: 37 | - Respond `handoff_to_planner()` to delegate to planning agent 38 | - Ensure all necessary context is provided 39 | 40 | - For specialized tasks: 41 | - Direct to appropriate specialized agent 42 | - Maintain oversight of task execution 43 | 44 | # Communication Guidelines 45 | 46 | - Maintain professional and efficient communication 47 | - Use clear and concise language 48 | - Match user's communication style and language 49 | - Provide regular status updates and progress reports 50 | - Ensure smooth handoffs between agents -------------------------------------------------------------------------------- /src/agents/nodes/supervisor_node.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import json_repair 3 | from copy import deepcopy 4 | from typing import Literal, Dict, Any 5 | 6 | from langchain_core.messages import HumanMessage, BaseMessage 7 | from langgraph.types import Command 8 | 9 | from src.llms.llm import get_llm_by_type 10 | from src.config import TEAM_MEMBERS 11 | from src.config.agents import AGENT_LLM_MAP 12 | from src.prompts.template import OpenManusPromptTemplate 13 | from src.utils.json_utils import repair_json_output 14 | from .types import State, Router # Import State and Router types 15 | 16 | logger = logging.getLogger(__name__) 17 | 18 | RESPONSE_FORMAT = "Response from {}:\n\n\n{}\n\n\n*Please execute the next step.*" 19 | 20 | def supervisor_node(state: State) -> Dict[str, Any]: # Modified return type to Dict 21 | """Supervisor node that decides which agent should act next.""" 22 | logger.info("Supervisor evaluating next action") 23 | messages = OpenManusPromptTemplate.apply_prompt_template("supervisor", state) 24 | # preprocess messages to make supervisor execute better. 25 | messages = deepcopy(messages) 26 | for message in messages: 27 | if isinstance(message, BaseMessage) and message.name in TEAM_MEMBERS: 28 | message.content = RESPONSE_FORMAT.format(message.name, message.content) 29 | response = ( 30 | get_llm_by_type(AGENT_LLM_MAP["supervisor"]) 31 | .with_structured_output(schema=Router, method="json_mode") 32 | .invoke(messages) 33 | ) 34 | goto = response["next"] 35 | logger.debug(f"Current state messages: {state['messages']}") 36 | logger.debug(f"Supervisor response: {response}") 37 | 38 | if goto == "FINISH": 39 | goto = "__end__" 40 | logger.info("Workflow completed") 41 | else: 42 | logger.info(f"Supervisor delegating to: {goto}") 43 | 44 | return Command(goto=goto, update={"next": goto}) -------------------------------------------------------------------------------- /src/prompts/researcher.md: -------------------------------------------------------------------------------- 1 | --- 2 | CURRENT_TIME: <> 3 | --- 4 | 5 | You are OpenManus's Research Agent, specializing in information gathering, analysis, and synthesis. Your role is to collect comprehensive data from reliable sources and provide well-structured insights. 6 | 7 | # Core Responsibilities 8 | 9 | 1. **Information Gathering** 10 | - Conduct thorough research using search engines 11 | - Collect data from authoritative sources 12 | - Verify information accuracy and relevance 13 | - Track and document information sources 14 | 15 | 2. **Data Analysis** 16 | - Evaluate collected information 17 | - Identify key trends and patterns 18 | - Compare and contrast findings 19 | - Validate data quality and reliability 20 | 21 | 3. **Knowledge Synthesis** 22 | - Organize information logically 23 | - Identify connections between data points 24 | - Draw evidence-based conclusions 25 | - Present findings clearly 26 | 27 | # Execution Guidelines 28 | 29 | 1. **Research Planning** 30 | - Define research objectives 31 | - Identify key search terms 32 | - Plan search strategy 33 | - Consider scope and limitations 34 | 35 | 2. **Data Collection** 36 | - Use search tools effectively 37 | - Follow systematic search processes 38 | - Document search results 39 | - Track information sources 40 | 41 | 3. **Analysis and Reporting** 42 | - Evaluate source credibility 43 | - Synthesize findings 44 | - Structure information clearly 45 | - Present actionable insights 46 | 47 | # Technical Standards 48 | 49 | - Verify source reliability 50 | - Document information sources 51 | - Follow research best practices 52 | - Maintain data accuracy 53 | - Ensure comprehensive coverage 54 | - Respect intellectual property 55 | 56 | # Output Format 57 | 58 | - Present findings in clear sections 59 | - Use appropriate formatting 60 | - Include source references 61 | - Highlight key insights 62 | - Follow user's language preference 63 | - Maintain professional tone -------------------------------------------------------------------------------- /src/prompts/reporter.md: -------------------------------------------------------------------------------- 1 | --- 2 | CURRENT_TIME: <> 3 | --- 4 | 5 | You are OpenManus's Reporting Agent, specializing in creating comprehensive, well-structured reports that synthesize information and present findings effectively. Your role is to transform complex data and analysis into clear, actionable insights. 6 | 7 | # Core Responsibilities 8 | 9 | 1. **Information Synthesis** 10 | - Compile and organize data from multiple sources 11 | - Identify key patterns and insights 12 | - Structure information logically 13 | - Ensure accuracy and completeness 14 | 15 | 2. **Report Generation** 16 | - Create clear, professional reports 17 | - Format content for readability 18 | - Include relevant data and metrics 19 | - Maintain consistent style 20 | 21 | 3. **Quality Assurance** 22 | - Verify data accuracy 23 | - Validate source credibility 24 | - Ensure comprehensive coverage 25 | - Review for clarity and coherence 26 | 27 | # Execution Guidelines 28 | 29 | 1. **Planning Phase** 30 | - Review available information 31 | - Identify key findings 32 | - Plan report structure 33 | - Define presentation format 34 | 35 | 2. **Development Phase** 36 | - Organize content logically 37 | - Write clear, concise sections 38 | - Include supporting evidence 39 | - Format for readability 40 | 41 | 3. **Review Phase** 42 | - Verify accuracy and completeness 43 | - Check data consistency 44 | - Ensure professional tone 45 | - Polish presentation 46 | 47 | # Technical Standards 48 | 49 | - Use professional formatting 50 | - Include clear section headers 51 | - Provide source citations 52 | - Use appropriate data visualization 53 | - Maintain consistent style 54 | - Follow documentation best practices 55 | 56 | # Output Format 57 | 58 | - Structure reports with clear sections 59 | - Use markdown formatting effectively 60 | - Include executive summaries 61 | - Present actionable conclusions 62 | - Follow user's language preference 63 | - Maintain professional tone -------------------------------------------------------------------------------- /src/prompts/browser.md: -------------------------------------------------------------------------------- 1 | --- 2 | CURRENT_TIME: <> 3 | --- 4 | 5 | You are OpenManus's Web Interaction Agent, specializing in direct web operations and platform-specific tasks. Your expertise lies in navigating websites, performing complex interactions, and extracting information efficiently. 6 | 7 | # Core Responsibilities 8 | 9 | 1. **Web Navigation** 10 | - Navigate to specified websites and platforms 11 | - Handle authentication and session management 12 | - Execute complex navigation sequences 13 | - Maintain context across multiple pages 14 | 15 | 2. **User Interactions** 16 | - Perform clicks, form submissions, and scrolling 17 | - Handle dynamic content loading 18 | - Execute search operations 19 | - Manage user input and form data 20 | 21 | 3. **Data Extraction** 22 | - Extract structured data from web pages 23 | - Capture specific elements and content 24 | - Handle dynamic content updates 25 | - Validate extracted information 26 | 27 | # Execution Guidelines 28 | 29 | 1. **Pre-execution** 30 | - Validate URLs and access requirements 31 | - Check for necessary authentication 32 | - Plan interaction sequence 33 | - Consider rate limits and delays 34 | 35 | 2. **Operation Execution** 36 | - Follow specified interaction steps 37 | - Handle loading states and delays 38 | - Manage error conditions 39 | - Verify successful completion 40 | 41 | 3. **Data Handling** 42 | - Extract required information 43 | - Format data appropriately 44 | - Validate data integrity 45 | - Handle missing or invalid data 46 | 47 | # Technical Standards 48 | 49 | - Follow website terms of service 50 | - Respect rate limits and delays 51 | - Handle errors gracefully 52 | - Maintain session security 53 | - Document interaction steps 54 | - Verify data accuracy 55 | 56 | # Output Guidelines 57 | 58 | - Provide clear step-by-step actions 59 | - Report execution status 60 | - Document any errors or issues 61 | - Format extracted data clearly 62 | - Follow user's language preference 63 | - Include relevant metadata -------------------------------------------------------------------------------- /src/prompts/template.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | from datetime import datetime 4 | from typing import Dict, List 5 | 6 | from langchain_core.prompts import PromptTemplate 7 | from langgraph.prebuilt.chat_agent_executor import AgentState 8 | 9 | 10 | class OpenManusPromptTemplate: 11 | """OpenManus prompt template manager for handling agent-specific prompts.""" 12 | 13 | @staticmethod 14 | def get_prompt_template(prompt_name: str) -> str: 15 | """Load and process a prompt template from file. 16 | 17 | Args: 18 | prompt_name: Name of the prompt template file (without .md extension) 19 | 20 | Returns: 21 | Processed template string with variable placeholders 22 | """ 23 | template_path = os.path.join(os.path.dirname(__file__), f"{prompt_name}.md") 24 | with open(template_path, 'r', encoding='utf-8') as f: 25 | template = f.read() 26 | 27 | # Escape curly braces for string formatting 28 | template = template.replace("{", "{{").replace("}", "}}") 29 | # Convert <> to {VAR} format 30 | template = re.sub(r"<<([^>>]+)>>", r"{1}", template) 31 | return template 32 | 33 | @staticmethod 34 | def apply_prompt_template(prompt_name: str, state: AgentState) -> List[Dict[str, str]]: 35 | """Apply a prompt template with current state variables. 36 | 37 | Args: 38 | prompt_name: Name of the prompt template to apply 39 | state: Current agent state containing variables and messages 40 | 41 | Returns: 42 | List of message dictionaries with system prompt and state messages 43 | """ 44 | # Format current time in a consistent format 45 | current_time = datetime.now().strftime("%a %b %d %Y %H:%M:%S %z") 46 | 47 | # Create and format the system prompt 48 | system_prompt = PromptTemplate( 49 | input_variables=["CURRENT_TIME"], 50 | template=OpenManusPromptTemplate.get_prompt_template(prompt_name), 51 | ).format(CURRENT_TIME=current_time, **state) 52 | 53 | # Combine system prompt with existing messages 54 | return [{"role": "system", "content": system_prompt}] + state["messages"] -------------------------------------------------------------------------------- /src/workflow/graph.py: -------------------------------------------------------------------------------- 1 | from langgraph.graph import StateGraph, START 2 | from src.graph.types import State # Import State class 3 | from src.agents.nodes import ( # Import agent nodes 4 | coordinator_node, 5 | planner_node, 6 | supervisor_node, 7 | researcher_node, 8 | coder_node, 9 | browser_node, 10 | reporter_node, 11 | ) 12 | 13 | def build_graph(): 14 | """Build and return the agent workflow graph.""" 15 | builder = StateGraph(State) 16 | 17 | # Define nodes 18 | builder.add_node("coordinator", coordinator_node) 19 | builder.add_node("planner", planner_node) 20 | builder.add_node("supervisor", supervisor_node) 21 | builder.add_node("researcher", researcher_node) 22 | builder.add_node("coder", coder_node) 23 | builder.add_node("browser", browser_node) 24 | builder.add_node("reporter", reporter_node) 25 | 26 | # Define edges 27 | builder.add_edge(START, "coordinator") 28 | builder.add_edge("coordinator", "planner") # Coordinator -> Planner 29 | builder.add_edge("planner", "supervisor") # Planner -> Supervisor 30 | builder.add_edge("supervisor", "researcher", condition=lambda state: state['next'] == "researcher") # Supervisor -> Researcher if next agent is researcher 31 | builder.add_edge("supervisor", "coder", condition=lambda state: state['next'] == "coder") # Supervisor -> Coder if next agent is coder 32 | builder.add_edge("supervisor", "browser", condition=lambda state: state['next'] == "browser") # Supervisor -> Browser if next agent is browser 33 | builder.add_edge("supervisor", "reporter", condition=lambda state: state['next'] == "reporter") # Supervisor -> Reporter if next agent is reporter 34 | builder.add_edge("supervisor", "__end__", condition=lambda state: state['next'] == "__end__") # Supervisor -> END if next agent is FINISH 35 | builder.add_edge("researcher", "supervisor") # Researcher -> Supervisor 36 | builder.add_edge("coder", "supervisor") # Coder -> Supervisor 37 | builder.add_edge("browser", "supervisor") # Browser -> Supervisor 38 | builder.add_edge("reporter", "supervisor") # Reporter -> Supervisor 39 | 40 | builder.set_entry_point("coordinator") 41 | builder.set_conditional_edge("supervisor", supervisor_node) # Conditional edge for supervisor node 42 | builder.add_end_point("__end__") 43 | 44 | return builder.compile() -------------------------------------------------------------------------------- /src/agents/nodes/planner_node.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import json 3 | import json_repair 4 | from copy import deepcopy 5 | from typing import Literal, Dict, Any 6 | from langchain_core.messages import HumanMessage 7 | 8 | from src.llms.llm import get_llm_by_type 9 | from src.config.agents import AGENT_LLM_MAP 10 | from src.prompts.template import OpenManusPromptTemplate 11 | from src.tools.search import bing_tool 12 | from src.utils.json_utils import repair_json_output 13 | from .types import State # Import State type 14 | 15 | logger = logging.getLogger(__name__) 16 | 17 | def planner_node(state: State) -> Dict[str, Any]: # Modified return type to Dict 18 | """Planner node that generate the full plan.""" 19 | logger.info("Planner generating full plan") 20 | messages = OpenManusPromptTemplate.apply_prompt_template("planner", state) 21 | # whether to enable deep thinking mode 22 | llm = get_llm_by_type(AGENT_LLM_MAP["planner"]) # Changed to planner LLM 23 | if state.get("deep_thinking_mode"): 24 | llm = get_llm_by_type("reasoning") 25 | if state.get("search_before_planning"): 26 | searched_content = bing_tool.invoke({"query": state["messages"][-1].content}) 27 | messages = deepcopy(messages) 28 | messages[ 29 | -1 30 | ].content += "\\n\\n# Relative Search Results\\n\\n" + json.dumps([{'title': elem['title'], 'content': elem['content']} for elem in searched_content], ensure_ascii=False) 31 | stream = llm.stream(messages) 32 | full_response = "" 33 | for chunk in stream: 34 | full_response += chunk.content 35 | logger.debug(f"Current state messages: {state['messages']}") 36 | logger.debug(f"Planner response: {full_response}") 37 | 38 | if full_response.startswith("```json"): 39 | full_response = full_response.removeprefix("```json") 40 | 41 | if full_response.endswith("```"): 42 | full_response = full_response.removesuffix("```") 43 | 44 | goto = "supervisor" 45 | try: 46 | repaired_response = json_repair.loads(full_response) 47 | full_response = json.dumps(repaired_response) 48 | except json.JSONDecodeError: 49 | logger.warning("Planner response is not a valid JSON") 50 | goto = "__end__" 51 | 52 | return Command( 53 | update={ 54 | "messages": [HumanMessage(content=full_response, name="planner")], 55 | "full_plan": full_response, 56 | }, 57 | goto=goto, 58 | ) -------------------------------------------------------------------------------- /src/server.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import json 3 | import logging 4 | from typing import List, Optional, Union 5 | 6 | from fastapi import FastAPI, HTTPException, Request 7 | from fastapi.middleware.cors import CORSMiddleware 8 | from pydantic import BaseModel, Field 9 | from sse_starlette.sse import EventSourceResponse 10 | 11 | # Configure logging 12 | logger = logging.getLogger(__name__) 13 | 14 | # Create FastAPI app 15 | app = FastAPI( 16 | title="OpenManus API", 17 | description="API for OpenManus LangGraph-based agent workflow", 18 | version="0.1.0", 19 | ) 20 | 21 | # Add CORS middleware 22 | app.add_middleware( 23 | CORSMiddleware, 24 | allow_origins=["*"], # Allows all origins 25 | allow_credentials=True, 26 | allow_methods=["*"], # Allows all methods 27 | allow_headers=["*"], # Allows all headers 28 | ) 29 | 30 | 31 | class ChatMessage(BaseModel): 32 | role: str = Field( 33 | ..., description="The role of the message sender (user or assistant)" 34 | ) 35 | content: str = Field(..., description="The content of the message") 36 | 37 | 38 | class ChatRequest(BaseModel): 39 | messages: List[ChatMessage] = Field(..., description="The conversation history") 40 | debug: Optional[bool] = Field(False, description="Whether to enable debug logging") 41 | 42 | from src.service.workflow_service import run_agent_workflow 43 | 44 | @app.post("/api/chat/stream") 45 | async def chat_stream_endpoint(request: ChatRequest, req: Request): 46 | """Chat endpoint for LangGraph invoke. 47 | 48 | Args: 49 | request: The chat request 50 | req: The FastAPI request object for connection state checking 51 | 52 | Returns: 53 | The streamed response 54 | """ 55 | try: 56 | async def event_generator(): 57 | async for event in run_agent_workflow( 58 | request.messages, request.debug 59 | ): 60 | # Check if client is still connected 61 | if await req.is_disconnected(): 62 | logger.info("Client disconnected, stopping workflow") 63 | break 64 | yield { 65 | "event": event["event"], 66 | "data": json.dumps(event["data"], ensure_ascii=False), 67 | } 68 | return EventSourceResponse( 69 | event_generator(), media_type="text/event-stream" 70 | ) 71 | except Exception as e: 72 | raise HTTPException(status_code=500, detail=str(e)) 73 | 74 | 75 | if __name__ == "__main__": 76 | import uvicorn 77 | uvicorn.run(app, host="0.0.0.0", port=8000, log_level="info", reload=True) -------------------------------------------------------------------------------- /.clinerules: -------------------------------------------------------------------------------- 1 | # Role 2 | You are an exceptional product manager with 20 years of experience and an engineer proficient in all programming languages, skilled in assisting junior developers. 3 | 4 | # Goal 5 | Help users complete their product design and development tasks in an easily understandable way, proactively completing all tasks without waiting for repeated prompting. 6 | 7 | ## Step 1: Project Initialization 8 | - When a user makes a request, first review the readme.md file and all code documents in the root directory to understand the project's goals, architecture, and implementation methods. If a readme file doesn't exist, create one. 9 | - This file will serve as a manual for users to understand all provided functions and your project plan. 10 | - Clearly describe the purpose, usage, parameter descriptions, and return value descriptions of all functions in the readme.md file to ensure user-friendly understanding and usage. 11 | 12 | ## Step 2: Task Understanding and Execution 13 | ### Understanding User Needs 14 | - Fully understand user needs from their perspective. Consider: "If I were the user, what would I need?" 15 | - As a product manager, identify any gaps in user needs. Discuss and refine requirements with users until satisfaction is achieved. 16 | - Prioritize the simplest solutions to meet user needs, avoiding overly complex or advanced approaches. 17 | 18 | ### Code Development 19 | - Plan step-by-step, considering user needs and existing codebase. 20 | - Choose appropriate programming languages and frameworks to implement user requirements. 21 | - Design code structure based on SOLID principles and use design patterns to address common problems. 22 | - Write comprehensive comments for all code modules and include necessary monitoring to track errors. 23 | - Opt for simple, controllable solutions over complex ones. 24 | 25 | ### Problem Solving 26 | - Thoroughly read the entire code file library to understand all code functions and logic. 27 | - Analyze the root causes of user-reported code errors and propose solutions. 28 | - Engage in multiple interactions with users, summarizing previous interactions and adjusting solutions based on feedback until user satisfaction. 29 | - Initiate "System 2 Thinking Mode" for persistent bugs: 30 | 1. Systematically analyze potential root causes and list all hypotheses. 31 | 2. Design verification methods for each hypothesis. 32 | 3. Provide three distinct solutions, detailing pros and cons for user choice. 33 | 34 | ## Step 3: Project Summary and Optimization 35 | - After completing the user's task, reflect on the task completion process, identify potential issues and improvements, and update the readme.md file accordingly. -------------------------------------------------------------------------------- /src/prompts/planner.md: -------------------------------------------------------------------------------- 1 | --- 2 | CURRENT_TIME: <> 3 | --- 4 | 5 | You are OpenManus's Planning Agent, responsible for analyzing tasks, creating detailed execution plans, and coordinating specialized agents to achieve optimal outcomes. 6 | 7 | # Details 8 | 9 | You are tasked with orchestrating a team of agents <> to complete complex requirements through systematic planning and execution. Your role involves breaking down tasks, assigning responsibilities, and ensuring efficient workflow coordination. 10 | 11 | ## Agent Capabilities 12 | 13 | - **`researcher`**: Specializes in information gathering and analysis. Uses search engines and web crawlers to collect data from reliable sources. Outputs comprehensive research reports in Markdown format. 14 | - **`coder`**: Handles technical implementation, including code development, mathematical computations, and system operations. Proficient in multiple programming languages and development tools. 15 | - **`browser`**: Manages direct web interactions and specialized platform operations. Performs complex web-based tasks and domain-specific searches across various platforms. 16 | - **`reporter`**: Creates professional documentation and reports. Synthesizes information and presents results in a clear, structured format. 17 | 18 | ## Execution Rules 19 | 20 | 1. Task Analysis: 21 | - Begin by restating the requirement in your own words as `thought` 22 | - Identify key objectives and constraints 23 | - Determine required resources and capabilities 24 | 25 | 2. Plan Development: 26 | - Create a detailed, step-by-step execution plan 27 | - Specify agent assignments based on capabilities 28 | - Define clear deliverables for each step 29 | 30 | 3. Resource Allocation: 31 | - Optimize agent utilization 32 | - Consider task dependencies and parallel execution opportunities 33 | - Ensure efficient workflow progression 34 | 35 | # Output Format 36 | 37 | Provide the plan in raw JSON format without code block markers: 38 | 39 | ```ts 40 | interface Step { 41 | agent_name: string; 42 | title: string; 43 | description: string; 44 | note?: string; 45 | } 46 | 47 | interface Plan { 48 | thought: string; 49 | title: string; 50 | steps: Step[]; 51 | } 52 | ``` 53 | 54 | # Guidelines 55 | 56 | - Maintain clear communication and precise task definitions 57 | - Optimize resource allocation and task sequencing 58 | - Ensure comprehensive documentation and progress tracking 59 | - Use the same language as the user throughout the process 60 | - Assign mathematical and computational tasks to `coder` 61 | - Use `browser` specifically for direct web interactions 62 | - Reserve `reporter` for final result compilation 63 | - Utilize `yfinance` through `coder` for financial data -------------------------------------------------------------------------------- /src/prompts/coder.md: -------------------------------------------------------------------------------- 1 | --- 2 | CURRENT_TIME: <> 3 | --- 4 | 5 | You are OpenManus's Code Execution Agent, a professional software engineer specializing in implementing technical solutions, performing computations, and managing system operations. Your expertise spans multiple programming languages and development tools. 6 | 7 | # Core Responsibilities 8 | 9 | 1. **Technical Implementation** 10 | - Develop and maintain code across multiple languages 11 | - Implement algorithms and data structures 12 | - Handle system operations and resource management 13 | - Ensure code quality and security 14 | 15 | 2. **Computational Tasks** 16 | - Execute mathematical calculations and data analysis 17 | - Process and transform data using appropriate libraries 18 | - Optimize performance for computational tasks 19 | - Validate results and handle edge cases 20 | 21 | 3. **System Integration** 22 | - Integrate with external services and APIs 23 | - Manage dependencies and environment configurations 24 | - Implement error handling and logging 25 | - Ensure secure data handling 26 | 27 | # Execution Guidelines 28 | 29 | 1. **Analysis Phase** 30 | - Review requirements thoroughly 31 | - Identify technical constraints and dependencies 32 | - Plan implementation approach 33 | - Consider security implications 34 | 35 | 2. **Implementation Phase** 36 | - Write clean, maintainable code 37 | - Follow language-specific best practices 38 | - Implement proper error handling 39 | - Add necessary documentation 40 | - Use appropriate logging for debugging 41 | 42 | 3. **Testing Phase** 43 | - Verify functionality against requirements 44 | - Test edge cases and error conditions 45 | - Validate output accuracy 46 | - Ensure performance meets expectations 47 | 48 | # Technical Standards 49 | 50 | - Follow secure coding practices 51 | - Implement proper input validation 52 | - Use appropriate error handling 53 | - Add comprehensive documentation 54 | - Maintain consistent code style 55 | - Optimize for performance when necessary 56 | - Use version control best practices 57 | 58 | # Available Tools 59 | 60 | - **Python Libraries**: 61 | - pandas: Data manipulation and analysis 62 | - numpy: Numerical computations 63 | - requests: HTTP requests 64 | - yfinance: Financial data retrieval 65 | 66 | - **Development Tools**: 67 | - Git: Version control 68 | - pytest: Testing framework 69 | - pylint: Code quality checks 70 | 71 | # Output Guidelines 72 | 73 | - Use clear, descriptive variable names 74 | - Include necessary comments and documentation 75 | - Format output for readability 76 | - Provide error messages when appropriate 77 | - Use logging for debugging information 78 | - Follow the user's language preference -------------------------------------------------------------------------------- /src/agents/coordinator.py: -------------------------------------------------------------------------------- 1 | class TaskCoordinator: 2 | """Coordinates tasks between multiple agents and tools.""" 3 | 4 | def __init__(self): 5 | self.agents = {} # Will store initialized agents 6 | self.tools = {} # Will store available tools 7 | self._initialize_system() 8 | 9 | def _initialize_system(self): 10 | """Initialize the multi-agent system and tools.""" 11 | self.agents['planner'] = PlannerAgent() 12 | self.agents['executor'] = ExecutionAgent() 13 | self.agents['tool'] = ToolAgent() # Generic tool agent for now 14 | self.tools = self._initialize_tools() 15 | 16 | def _initialize_tools(self): 17 | """Initialize and return available tools.""" 18 | from src.tools.web_browser import WebBrowserTool 19 | from src.tools.code_executor import CodeExecutorTool 20 | from src.tools.data_retriever import DataRetrieverTool 21 | return { 22 | 'web_browser': WebBrowserTool(), 23 | 'code_executor': CodeExecutorTool(), 24 | 'data_retriever': DataRetrieverTool(), 25 | } 26 | 27 | def execute_task(self, task_description): 28 | """ 29 | Execute a task using the multi-agent system. 30 | 31 | Args: 32 | task_description (str): Natural language description of the task 33 | 34 | Returns: 35 | dict: Result of the task execution 36 | """ 37 | plan = self.agents['planner'].plan_task(task_description) 38 | result = self.agents['executor'].execute_plan(plan, self.agents, self.tools) 39 | return { 40 | "status": "success", 41 | "result": result 42 | } 43 | 44 | 45 | class PlannerAgent: 46 | """Agent responsible for planning tasks.""" 47 | def plan_task(self, task_description): 48 | """Generates a task execution plan.""" 49 | # Placeholder plan: Use web_browser tool 50 | return { 51 | "steps": [ 52 | {"agent": "tool", "action": "use_tool", "tool_name": "web_browser", "tool_args": {"url": "https://www.example.com"}} 53 | ] 54 | } 55 | 56 | class ExecutionAgent: 57 | """Agent responsible for executing task plans.""" 58 | def execute_plan(self, plan, agents, tools): 59 | """Executes a given task plan.""" 60 | results = [] 61 | for step in plan['steps']: 62 | agent_name = step['agent'] 63 | action = step['action'] 64 | if agent_name == 'tool' and action == 'use_tool': 65 | tool_name = step['tool_name'] 66 | tool_args = step['tool_args'] 67 | tool_result = agents['tool'].use_tool(tool_name, tool_args, tools) 68 | results.append(f"Tool '{tool_name}' used with args {tool_args}. Result: {tool_result}") 69 | else: 70 | results.append(f"Unknown step: {step}") 71 | return "\\n".join(results) 72 | 73 | class ToolAgent: 74 | """Agent responsible for using tools.""" 75 | def use_tool(self, tool_name, tool_args, tools): 76 | """Uses a specific tool to perform an action.""" 77 | if tool_name in tools: 78 | tool = tools[tool_name] 79 | if tool_name == 'web_browser': 80 | return tool.browse_web(**tool_args) 81 | elif tool_name == 'code_executor': 82 | return tool.execute_code(**tool_args) 83 | elif tool_name == 'data_retriever': 84 | return tool.retrieve_data(**tool_args) 85 | else: 86 | return f"Tool '{tool_name}' not yet fully implemented." 87 | else: 88 | return f"Tool '{tool_name}' not found." -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # UV 98 | # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | #uv.lock 102 | 103 | # poetry 104 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 105 | # This is especially recommended for binary packages to ensure reproducibility, and is more 106 | # commonly ignored for libraries. 107 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 108 | #poetry.lock 109 | 110 | # pdm 111 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 112 | #pdm.lock 113 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 114 | # in version control. 115 | # https://pdm.fming.dev/latest/usage/project/#working-with-version-control 116 | .pdm.toml 117 | .pdm-python 118 | .pdm-build/ 119 | 120 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 121 | __pypackages__/ 122 | 123 | # Celery stuff 124 | celerybeat-schedule 125 | celerybeat.pid 126 | 127 | # SageMath parsed files 128 | *.sage.py 129 | 130 | # Environments 131 | .env 132 | .venv 133 | env/ 134 | venv/ 135 | ENV/ 136 | env.bak/ 137 | venv.bak/ 138 | 139 | # Spyder project settings 140 | .spyderproject 141 | .spyproject 142 | 143 | # Rope project settings 144 | .ropeproject 145 | 146 | # mkdocs documentation 147 | /site 148 | 149 | # mypy 150 | .mypy_cache/ 151 | .dmypy.json 152 | dmypy.json 153 | 154 | # Pyre type checker 155 | .pyre/ 156 | 157 | # pytype static type analyzer 158 | .pytype/ 159 | 160 | # Cython debug symbols 161 | cython_debug/ 162 | 163 | # PyCharm 164 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 165 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 166 | # and can be added to the global gitignore or merged into this file. For a more nuclear 167 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 168 | #.idea/ 169 | 170 | # PyPI configuration file 171 | .pypirc 172 | -------------------------------------------------------------------------------- /plans.md: -------------------------------------------------------------------------------- 1 | # Refactoring Plan for OpenManus (Version 3) 2 | 3 | **Goal:** To establish OpenManus as a fully independent project by removing all dependencies on LangManus while maintaining and enhancing its core functionalities. 4 | 5 | ## Key Objectives 6 | 7 | 1. **Remove LangManus Dependencies** 8 | - Eliminate all direct and indirect imports from LangManus 9 | - Ensure all code paths are independent of LangManus components 10 | - Verify no residual LangManus references remain in configuration files 11 | 12 | 2. **Complete Rewrite of Core Components** 13 | - **Prompts System** 14 | - Rewrite all prompt templates in `/src/prompts/` to be OpenManus-specific 15 | - Implement custom prompt management system tailored to OpenManus needs 16 | - Add documentation for each prompt's purpose and usage 17 | 18 | - **Agent System** 19 | - Implement independent agent architecture based on LangGraph 20 | - Define clear interfaces and protocols for agent communication 21 | - Create OpenManus-specific agent roles and responsibilities 22 | 23 | - **Tools Integration** 24 | - Develop native tool implementations for OpenManus 25 | - Create unified tool interface and registration system 26 | - Implement robust error handling and logging 27 | 28 | 3. **Configuration and Infrastructure** 29 | - Implement OpenManus-specific configuration system 30 | - Set up proper dependency management 31 | - Create comprehensive testing framework 32 | 33 | ## Implementation Steps 34 | 35 | 1. **Dependency Audit (Priority: High)** 36 | - Scan codebase for LangManus imports and references 37 | - Document all instances of LangManus code usage 38 | - Create dependency removal tracking system 39 | 40 | 2. **Prompts Rewrite (Priority: High)** 41 | - Analyze current prompt templates functionality 42 | - Design OpenManus-specific prompt architecture 43 | - Implement new prompt templates with: 44 | - Clear role definitions 45 | - Specific task handling instructions 46 | - Error handling guidelines 47 | - Custom parameters and variables 48 | 49 | 3. **Agent System Implementation (Priority: High)** 50 | - Design agent communication protocols 51 | - Implement core agent classes: 52 | - Coordinator: Task distribution and workflow management 53 | - Planner: Strategy development and task breakdown 54 | - Executor: Task execution and resource management 55 | - Monitor: System health and performance tracking 56 | - Create agent lifecycle management system 57 | 58 | 4. **Tools Development (Priority: Medium)** 59 | - Create native implementations for: 60 | - File management system 61 | - Code execution environment 62 | - Web interaction tools 63 | - Data processing utilities 64 | - Implement tool registration and discovery system 65 | - Add tool usage monitoring and analytics 66 | 67 | 5. **Testing and Validation (Priority: High)** 68 | - Create comprehensive test suite 69 | - Implement integration tests for agent interactions 70 | - Add performance benchmarking tools 71 | - Set up continuous integration pipeline 72 | 73 | 6. **Documentation and Standards (Priority: Medium)** 74 | - Create API documentation 75 | - Write development guidelines 76 | - Document system architecture 77 | - Create contribution guidelines 78 | 79 | ## Success Criteria 80 | 81 | 1. Zero references to LangManus in codebase 82 | 2. All components have OpenManus-specific implementations 83 | 3. Complete test coverage for core functionality 84 | 4. Documented API and architecture 85 | 5. Successful execution of all existing use cases 86 | 87 | ## Timeline 88 | 89 | - Phase 1 (Week 1-2): Dependency Audit and Removal 90 | - Phase 2 (Week 2-3): Prompts and Agents Rewrite 91 | - Phase 3 (Week 3-4): Tools Development 92 | - Phase 4 (Week 4-5): Testing and Documentation 93 | 94 | ## Risk Management 95 | 96 | 1. **Functionality Gaps** 97 | - Mitigation: Thorough testing during each component rewrite 98 | - Fallback: Maintain parallel systems during transition 99 | 100 | 2. **Performance Impact** 101 | - Mitigation: Regular performance testing 102 | - Fallback: Optimize critical paths first 103 | 104 | 3. **Integration Issues** 105 | - Mitigation: Incremental changes with integration tests 106 | - Fallback: Rollback capability for each change 107 | 108 | ## Monitoring and Control 109 | 110 | - Weekly progress reviews 111 | - Automated testing for each component 112 | - Performance benchmarking 113 | - Code quality metrics tracking 114 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenManus 2 | 3 |

4 | OpenManus Logo 5 |

6 | 7 | ![License](https://img.shields.io/badge/license-UNLICENSE-blue.svg) 8 | ![Docker](https://img.shields.io/badge/docker-supported-green.svg) 9 | ![Python](https://img.shields.io/badge/python-3.9+-blue.svg) 10 | ![JavaScript](https://img.shields.io/badge/javascript-ES6+-yellow.svg) 11 | 12 | ## Overview 13 | 14 | OpenManus is an open-source project aimed at replicating the capabilities of the Manus AI agent, a groundbreaking general-purpose AI developed by Monica. Manus is known for its ability to autonomously execute complex tasks—ranging from personalized travel planning to stock analysis—surpassing models like GPT-4 on the GAIA benchmark. OpenManus seeks to bring these capabilities to the open-source community using a modular, containerized framework built with Docker, Python, and JavaScript. 15 | 16 | This repository provides a starting point for developers and researchers to build, deploy, and experiment with a multi-agent AI system. Our goal is to create a flexible and extensible platform that mirrors Manus's autonomous task execution while fostering community contributions. 17 | 18 | ## Features 19 | 20 | - **Multi-Agent System**: Collaborative AI agents working together to solve complex tasks. 21 | - **Dockerized Environment**: Easy setup and deployment with containerization. 22 | - **Task Execution**: Supports tasks like travel planning, data analysis, and content generation. 23 | - **Tool Integration**: Web browsing, code execution, and data retrieval capabilities. 24 | - **Modular Design**: Easily extendable with new agents, tools, or features. 25 | - **Community-Driven**: Open to contributions and enhancements. 26 | 27 | ## Prerequisites 28 | 29 | Before you begin, ensure you have the following installed: 30 | - [Docker](https://docs.docker.com/get-docker/) (version 20.10 or higher) 31 | - [Docker Compose](https://docs.docker.com/compose/install/) (version 1.29 or higher) 32 | - [Node.js](https://nodejs.org/) (version 20.18 or higher, for local development) 33 | - [Python](https://python.org/) (version 3.9 or higher, for local development) 34 | - Git (for cloning and contributing) 35 | 36 | ## Getting Started 37 | 38 | ### 1. Clone the Repository 39 | ```bash 40 | git clone https://github.com/henryalps/OpenManus.git 41 | cd OpenManus 42 | ``` 43 | 44 | ### 2. Build and Run with Docker 45 | ```bash 46 | # Build and start all containers 47 | docker-compose up --build 48 | ``` 49 | 50 | This will launch: 51 | - Backend container with the multi-agent system and integrated tools 52 | - Frontend container serving the Next.js web interface 53 | - FastAPI server for task delegation and execution 54 | 55 | ### 3. Test the System 56 | Once running, you can interact with OpenManus via: 57 | - CLI: Use the provided Python client (`python client.py`) 58 | - API: Send requests to http://localhost:8000 (see API docs below) 59 | - Web UI: Access http://localhost:3000 60 | 61 | Example CLI command: 62 | ```bash 63 | python client.py --task "Plan a 3-day trip to Tokyo" 64 | ``` 65 | 66 | ### Project Structure 67 | ``` 68 | OpenManus/ 69 | ├── docker/ # Docker configurations 70 | │ ├── frontend/ # Next.js frontend container 71 | │ │ └── Dockerfile # Frontend container configuration 72 | │ └── unified/ # Backend container configuration 73 | │ ├── Dockerfile # Backend container configuration 74 | │ └── start.sh # Container startup script 75 | ├── src/ # Source code 76 | │ ├── agents/ # Multi-agent logic (Python) 77 | │ │ ├── nodes/ # Agent node implementations 78 | │ │ ├── browser_agent.py 79 | │ │ ├── coder_agent.py 80 | │ │ ├── coordinator.py 81 | │ │ ├── reporter_agent.py 82 | │ │ └── research_agent.py 83 | │ ├── components/ # React components 84 | │ ├── config/ # Configuration files 85 | │ ├── graph/ # Graph-based workflow 86 | │ ├── llms/ # LLM integrations 87 | │ ├── pages/ # Next.js pages 88 | │ ├── prompts/ # Agent prompts 89 | │ ├── service/ # Backend services 90 | │ ├── tools/ # Tool implementations 91 | │ ├── utils/ # Utility functions 92 | │ ├── workflow/ # Workflow management 93 | │ ├── client.py # CLI client for testing 94 | │ └── server.py # FastAPI server 95 | ├── docs/ # Documentation and API specs 96 | ├── package.json # Next.js frontend dependencies 97 | ├── next.config.js # Next.js configuration 98 | ├── docker-compose.yml # Docker Compose configuration 99 | └── README.md # This file 100 | ``` 101 | 102 | ### Configuration 103 | Edit the `docker-compose.yml` file to customize: 104 | ```yaml 105 | services: 106 | backend: 107 | build: 108 | context: . 109 | dockerfile: docker/unified/Dockerfile 110 | ports: 111 | - "8000:8000" # FastAPI port 112 | environment: 113 | - WEB_BROWSER_API_KEY=your_key_here 114 | volumes: 115 | - ./src:/app/src 116 | - ./data:/app/data 117 | 118 | frontend: 119 | build: 120 | context: . 121 | dockerfile: docker/frontend/Dockerfile 122 | ports: 123 | - "3000:3000" # Web UI port 124 | depends_on: 125 | - backend 126 | ``` 127 | 128 | ### API Documentation 129 | The agent server exposes a REST API at http://localhost:8000. Key endpoints: 130 | 131 | **POST /task**: Submit a task for execution. 132 | ```json 133 | Body: { "task": "Analyze Tesla stock trends" } 134 | Response: { "status": "success", "result": "..." } 135 | ``` 136 | 137 | **GET /status**: Check system health. 138 | ```json 139 | Response: { "status": "running" } 140 | ``` 141 | 142 | Full API docs are available in `docs/api.md`. 143 | 144 | ### Contributing 145 | We welcome contributions! To get started: 146 | 1. Fork the repository. 147 | 2. Create a feature branch (`git checkout -b feature/your-feature`). 148 | 3. Commit your changes (`git commit -m "Add your feature"`). 149 | 4. Push to your branch (`git push origin feature/your-feature`). 150 | 5. Open a Pull Request. 151 | 152 | Please read `CONTRIBUTING.md` for guidelines. 153 | 154 | ### Roadmap 155 | - Implement core multi-agent coordination. 156 | - Add support for GAIA benchmark tasks. 157 | - Integrate advanced NLP models (e.g., LLaMA, Grok). 158 | - Enhance toolset with real-time web scraping and visualization. 159 | - Release v1.0 with stable task execution. 160 | 161 | ### Inspiration 162 | OpenManus is inspired by: 163 | - The langmanus project (GitHub). 164 | - The official Manus project (manus.im). 165 | - The open-Manus community effort (GitHub). 166 | - GAIA benchmark for general AI assistants (arXiv). 167 | 168 | ### License 169 | This project is licensed under the UNLICENSE. See `LICENSE` for details. 170 | 171 | ### Contact 172 | For questions or collaboration, reach out via GitHub Issues or email [henryalps@gmail.com](mailto:henryalps@gmail.com). 173 | 174 | Happy coding! Let's build the future of AI agents together! 175 | 176 | [![Powered by DartNode](https://dartnode.com/branding/DN-Open-Source-sm.png)](https://dartnode.com "Powered by DartNode - Free VPS for Open Source") 177 | 178 | CDN acceleration and security protection for this project are sponsored by Tencent EdgeOne. 179 | --------------------------------------------------------------------------------