├── 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 |
5 |
6 |
7 | 
8 | 
9 | 
10 | 
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 | [](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 |
--------------------------------------------------------------------------------