mirror of
https://github.com/zhayujie/chatgpt-on-wechat.git
synced 2026-06-02 00:57:41 +08:00
chore: remove useless plugins
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -32,7 +32,6 @@ plugins/banwords/lib/__pycache__
|
||||
!plugins/role
|
||||
!plugins/keyword
|
||||
!plugins/linkai
|
||||
!plugins/agent
|
||||
!plugins/cow_cli
|
||||
client_config.json
|
||||
ref/
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
# Agent插件
|
||||
|
||||
## 插件说明
|
||||
|
||||
基于 [AgentMesh](https://github.com/MinimalFuture/AgentMesh) 多智能体框架实现的Agent插件,可以让机器人快速获得Agent能力,通过自然语言对话来访问 **终端、浏览器、文件系统、搜索引擎** 等各类工具。
|
||||
同时还支持通过 **多智能体协作** 来完成复杂任务,例如多智能体任务分发、多智能体问题讨论、协同处理等。
|
||||
|
||||
AgentMesh项目地址:https://github.com/MinimalFuture/AgentMesh
|
||||
|
||||
## 安装
|
||||
|
||||
1. 确保已安装依赖:
|
||||
|
||||
```bash
|
||||
pip install agentmesh-sdk>=0.1.3
|
||||
```
|
||||
|
||||
2. 如需使用浏览器工具,还需安装:
|
||||
|
||||
```bash
|
||||
pip install browser-use>=0.1.40
|
||||
playwright install
|
||||
```
|
||||
|
||||
## 配置
|
||||
|
||||
插件配置文件是 `plugins/agent`目录下的 `config.yaml`,包含智能体团队的配置以及工具的配置,可以从模板文件 `config-template.yaml`中复制:
|
||||
|
||||
```bash
|
||||
cp config-template.yaml config.yaml
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `team`配置是默认选中的 agent team
|
||||
- `teams` 下是Agent团队配置,团队的model默认为`gpt-4.1-mini`,可根据需要进行修改,模型对应的 `api_key` 需要在项目根目录的 `config.json` 全局配置中进行配置。例如openai模型需要配置 `open_ai_api_key`
|
||||
- 支持为 `agents` 下面的每个agent添加model字段来设置不同的模型
|
||||
|
||||
|
||||
## 使用方法
|
||||
|
||||
在对机器人发送的消息中使用 `$agent` 前缀来触发插件,支持以下命令:
|
||||
|
||||
- `$agent [task]`: 使用默认团队执行任务 (默认团队可通 config.yaml 中的team配置修改)
|
||||
- `$agent teams`: 列出可用的团队
|
||||
- `$agent use [team_name] [task]`: 使用指定的团队执行任务
|
||||
|
||||
|
||||
### 示例
|
||||
|
||||
```bash
|
||||
$agent 帮我查看当前目录下有哪些文件夹
|
||||
$agent teams
|
||||
$agent use software_team 帮我写一个产品预约体验的表单页面
|
||||
```
|
||||
|
||||
## 工具支持
|
||||
|
||||
目前支持多种内置工具,包括但不限于:
|
||||
|
||||
- `calculator`: 数学计算工具
|
||||
- `current_time`: 获取当前时间
|
||||
- `browser`: 浏览器操作工具,注意需安装`browser-use`依赖
|
||||
- `google_search`: 搜索引擎,注意需在`config.yaml`中配置 `api_key`
|
||||
- `file_save`: 文件保存工具,开启后智能体输出的内容将保存在 `workspace` 目录下
|
||||
- `terminal`: 终端命令执行工具
|
||||
@@ -1,3 +0,0 @@
|
||||
from .agent import AgentPlugin
|
||||
|
||||
__all__ = ["AgentPlugin"]
|
||||
@@ -1,282 +0,0 @@
|
||||
import os
|
||||
import yaml
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from agentmesh import AgentTeam, Agent, LLMModel
|
||||
from agentmesh.models import ClaudeModel
|
||||
from agentmesh.tools import ToolManager
|
||||
from config import conf
|
||||
|
||||
import plugins
|
||||
from plugins import Plugin, Event, EventContext, EventAction
|
||||
from bridge.context import ContextType
|
||||
from bridge.reply import Reply, ReplyType
|
||||
from common.log import logger
|
||||
|
||||
|
||||
@plugins.register(
|
||||
name="agent",
|
||||
desc="Use AgentMesh framework to process tasks with multi-agent teams",
|
||||
version="0.1.0",
|
||||
author="Saboteur7",
|
||||
desire_priority=1,
|
||||
)
|
||||
class AgentPlugin(Plugin):
|
||||
"""Plugin for integrating AgentMesh framework."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context
|
||||
self.name = "agent"
|
||||
self.description = "Use AgentMesh framework to process tasks with multi-agent teams"
|
||||
self.config = self._load_config()
|
||||
self.tool_manager = ToolManager()
|
||||
self.tool_manager.load_tools(config_dict=self.config.get("tools"))
|
||||
logger.debug("[agent] inited")
|
||||
|
||||
def _load_config(self) -> Dict:
|
||||
"""Load configuration from config.yaml file."""
|
||||
config_path = os.path.join(self.path, "config.yaml")
|
||||
if not os.path.exists(config_path):
|
||||
logger.debug(f"Config file not found at {config_path}")
|
||||
return {}
|
||||
|
||||
with open(config_path, 'r', encoding='utf-8') as f:
|
||||
return yaml.safe_load(f)
|
||||
|
||||
def get_help_text(self, verbose=False, **kwargs):
|
||||
"""Return help message for the agent plugin."""
|
||||
help_text = "通过AgentMesh实现对终端、浏览器、文件系统、搜索引擎等工具的执行,并支持多智能体协作。"
|
||||
trigger_prefix = conf().get("plugin_trigger_prefix", "$")
|
||||
|
||||
if not verbose:
|
||||
return help_text
|
||||
|
||||
teams = self.get_available_teams()
|
||||
teams_str = ", ".join(teams) if teams else "未配置任何团队"
|
||||
|
||||
help_text += "\n\n使用说明:\n"
|
||||
help_text += f"{trigger_prefix}agent [task] - 使用默认团队执行任务\n"
|
||||
help_text += f"{trigger_prefix}agent teams - 列出可用的团队\n"
|
||||
help_text += f"{trigger_prefix}agent use [team_name] [task] - 使用特定团队执行任务\n\n"
|
||||
help_text += f"可用团队: \n{teams_str}\n\n"
|
||||
help_text += f"示例:\n"
|
||||
help_text += f"{trigger_prefix}agent 帮我查看当前文件夹路径\n"
|
||||
help_text += f"{trigger_prefix}agent use software_team 帮我写一个产品预约体验的表单页面"
|
||||
return help_text
|
||||
|
||||
def get_available_teams(self) -> List[str]:
|
||||
"""Get list of available teams from configuration."""
|
||||
teams_config = self.config.get("teams", {})
|
||||
return list(teams_config.keys())
|
||||
|
||||
|
||||
def create_team_from_config(self, team_name: str) -> Optional[AgentTeam]:
|
||||
"""Create a team from configuration."""
|
||||
# Get teams configuration
|
||||
teams_config = self.config.get("teams", {})
|
||||
|
||||
# Check if the specified team exists
|
||||
if team_name not in teams_config:
|
||||
logger.error(f"Team '{team_name}' not found in configuration.")
|
||||
available_teams = list(teams_config.keys())
|
||||
logger.info(f"Available teams: {', '.join(available_teams)}")
|
||||
return None
|
||||
|
||||
# Get team configuration
|
||||
team_config = teams_config[team_name]
|
||||
|
||||
# Get team's model
|
||||
team_model_name = team_config.get("model", "gpt-4.1-mini")
|
||||
team_model = self.create_llm_model(team_model_name)
|
||||
|
||||
# Get team's max_steps (default to 20 if not specified)
|
||||
team_max_steps = team_config.get("max_steps", 20)
|
||||
|
||||
# Create team with the model
|
||||
team = AgentTeam(
|
||||
name=team_name,
|
||||
description=team_config.get("description", ""),
|
||||
rule=team_config.get("rule", ""),
|
||||
model=team_model,
|
||||
max_steps=team_max_steps
|
||||
)
|
||||
|
||||
# Create and add agents to the team
|
||||
agents_config = team_config.get("agents", [])
|
||||
for agent_config in agents_config:
|
||||
# Check if agent has a specific model
|
||||
if agent_config.get("model"):
|
||||
agent_model = self.create_llm_model(agent_config.get("model"))
|
||||
else:
|
||||
agent_model = team_model
|
||||
|
||||
# Get agent's max_steps
|
||||
agent_max_steps = agent_config.get("max_steps")
|
||||
|
||||
agent = Agent(
|
||||
name=agent_config.get("name", ""),
|
||||
system_prompt=agent_config.get("system_prompt", ""),
|
||||
model=agent_model, # Use agent's model if specified, otherwise will use team's model
|
||||
description=agent_config.get("description", ""),
|
||||
max_steps=agent_max_steps
|
||||
)
|
||||
|
||||
# Add tools to the agent if specified
|
||||
tool_names = agent_config.get("tools", [])
|
||||
for tool_name in tool_names:
|
||||
tool = self.tool_manager.create_tool(tool_name)
|
||||
if tool:
|
||||
agent.add_tool(tool)
|
||||
else:
|
||||
if tool_name == "browser":
|
||||
logger.warning(
|
||||
"Tool 'Browser' loaded failed, "
|
||||
"please install the required dependency with: \n"
|
||||
"'pip install browser-use>=0.1.40' or 'pip install agentmesh-sdk[full]'\n"
|
||||
)
|
||||
else:
|
||||
logger.warning(f"Tool '{tool_name}' not found for agent '{agent.name}'\n")
|
||||
|
||||
# Add agent to team
|
||||
team.add(agent)
|
||||
|
||||
return team
|
||||
|
||||
def on_handle_context(self, e_context: EventContext):
|
||||
"""Handle the message context."""
|
||||
if e_context['context'].type != ContextType.TEXT:
|
||||
return
|
||||
content = e_context['context'].content
|
||||
trigger_prefix = conf().get("plugin_trigger_prefix", "$")
|
||||
|
||||
if not content.startswith(f"{trigger_prefix}agent "):
|
||||
e_context.action = EventAction.CONTINUE
|
||||
return
|
||||
|
||||
if not self.config:
|
||||
reply = Reply()
|
||||
reply.type = ReplyType.ERROR
|
||||
reply.content = "未找到插件配置,请在 plugins/agent 目录下创建 config.yaml 配置文件,可根据 config-template.yml 模板文件复制"
|
||||
e_context['reply'] = reply
|
||||
e_context.action = EventAction.BREAK_PASS
|
||||
return
|
||||
|
||||
# Extract the actual task
|
||||
task = content[len(f"{trigger_prefix}agent "):].strip()
|
||||
|
||||
# If task is empty, return help message
|
||||
if not task:
|
||||
reply = Reply()
|
||||
reply.type = ReplyType.TEXT
|
||||
reply.content = self.get_help_text(verbose=True)
|
||||
e_context['reply'] = reply
|
||||
e_context.action = EventAction.BREAK_PASS
|
||||
return
|
||||
|
||||
# Check if task is asking for available teams
|
||||
if task.lower() in ["teams", "list teams", "show teams"]:
|
||||
teams = self.get_available_teams()
|
||||
reply = Reply()
|
||||
reply.type = ReplyType.TEXT
|
||||
|
||||
if not teams:
|
||||
reply.content = "未配置任何团队。请检查 config.yaml 文件。"
|
||||
else:
|
||||
reply.content = f"可用团队: {', '.join(teams)}"
|
||||
|
||||
e_context['reply'] = reply
|
||||
e_context.action = EventAction.BREAK_PASS
|
||||
return
|
||||
|
||||
# Check if task specifies a team
|
||||
team_name = None
|
||||
if task.startswith("use "):
|
||||
parts = task[4:].split(" ", 1)
|
||||
if len(parts) > 0:
|
||||
team_name = parts[0]
|
||||
if len(parts) > 1:
|
||||
task = parts[1].strip()
|
||||
else:
|
||||
reply = Reply()
|
||||
reply.type = ReplyType.TEXT
|
||||
reply.content = f"已选择团队 '{team_name}'。请输入您想执行的任务。"
|
||||
e_context['reply'] = reply
|
||||
e_context.action = EventAction.BREAK_PASS
|
||||
return
|
||||
if not team_name:
|
||||
team_name = self.config.get("team")
|
||||
|
||||
# If no team specified, use default or first available
|
||||
if not team_name:
|
||||
teams = self.configself.get_available_teams()
|
||||
if not teams:
|
||||
reply = Reply()
|
||||
reply.type = ReplyType.TEXT
|
||||
reply.content = "未配置任何团队。请检查 config.yaml 文件。"
|
||||
e_context['reply'] = reply
|
||||
e_context.action = EventAction.BREAK_PASS
|
||||
return
|
||||
team_name = teams[0]
|
||||
|
||||
# Create team
|
||||
team = self.create_team_from_config(team_name)
|
||||
if not team:
|
||||
reply = Reply()
|
||||
reply.type = ReplyType.TEXT
|
||||
reply.content = f"创建团队 '{team_name}' 失败。请检查配置。"
|
||||
e_context['reply'] = reply
|
||||
e_context.action = EventAction.BREAK_PASS
|
||||
return
|
||||
|
||||
# Run the task
|
||||
try:
|
||||
logger.info(f"[agent] Running task '{task}' with team '{team_name}', team_model={team.model.model}")
|
||||
result = team.run_async(task=task)
|
||||
for agent_result in result:
|
||||
res_text = f"🤖 {agent_result.get('agent_name')}\n\n{agent_result.get('final_answer')}"
|
||||
_send_text(e_context, content=res_text)
|
||||
|
||||
reply = Reply()
|
||||
reply.type = ReplyType.TEXT
|
||||
reply.content = ""
|
||||
e_context['reply'] = reply
|
||||
e_context.action = EventAction.BREAK_PASS
|
||||
|
||||
except Exception as e:
|
||||
logger.exception(f"Error running task with team '{team_name}'")
|
||||
|
||||
reply = Reply()
|
||||
reply.type = ReplyType.ERROR
|
||||
reply.content = f"执行任务时出错: {str(e)}"
|
||||
e_context['reply'] = reply
|
||||
e_context.action = EventAction.BREAK_PASS
|
||||
return
|
||||
|
||||
def create_llm_model(self, model_name) -> LLMModel:
|
||||
if conf().get("use_linkai"):
|
||||
api_base = "https://api.link-ai.tech/v1"
|
||||
api_key = conf().get("linkai_api_key")
|
||||
elif model_name.startswith(("gpt", "text-davinci", "o1", "o3")):
|
||||
api_base = conf().get("open_ai_api_base") or "https://api.openai.com/v1"
|
||||
api_key = conf().get("open_ai_api_key")
|
||||
elif model_name.startswith("claude"):
|
||||
return ClaudeModel(model=model_name, api_key=conf().get("claude_api_key"))
|
||||
elif model_name.startswith("moonshot"):
|
||||
api_base = "https://api.moonshot.cn/v1"
|
||||
api_key = conf().get("moonshot_api_key")
|
||||
elif model_name.startswith("qwen"):
|
||||
api_base = "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
||||
api_key = conf().get("dashscope_api_key")
|
||||
else:
|
||||
api_base = conf().get("open_ai_api_base") or "https://api.openai.com/v1"
|
||||
api_key = conf().get("open_ai_api_key")
|
||||
|
||||
llm_model = LLMModel(model=model_name, api_key=api_key, api_base=api_base)
|
||||
return llm_model
|
||||
|
||||
|
||||
def _send_text(e_context: EventContext, content: str):
|
||||
reply = Reply(ReplyType.TEXT, content)
|
||||
channel = e_context["channel"]
|
||||
channel.send(reply, e_context["context"])
|
||||
@@ -1,52 +0,0 @@
|
||||
# 默认选中的Agent Team名称
|
||||
team: general_team
|
||||
|
||||
tools:
|
||||
google_search:
|
||||
# get your apikey from https://serper.dev/
|
||||
api_key: "YOUR API KEY"
|
||||
|
||||
# Agent Team 配置
|
||||
teams:
|
||||
# 通用智能体团队
|
||||
general_team:
|
||||
model: "gpt-4.1-mini" # 团队使用的模型
|
||||
description: "A versatile research and information agent team"
|
||||
max_steps: 5
|
||||
agents:
|
||||
- name: "通用智能助手"
|
||||
description: "Universal assistant specializing in research, information synthesis, and task execution"
|
||||
system_prompt: "You are a versatile assistant who answers questions and completes tasks using available tools. Reply in a clearly structured, attractive and easy to read format."
|
||||
# Agent 支持使用的工具
|
||||
tools:
|
||||
- time
|
||||
- calculator
|
||||
- google_search
|
||||
- browser
|
||||
- terminal
|
||||
|
||||
# 软件开发智能体团队
|
||||
software_team:
|
||||
model: "gpt-4.1-mini"
|
||||
description: "A software development team with product manager, developer and tester."
|
||||
rule: "A normal R&D process should be that Product Manager writes PRD, Developer writes code based on PRD, and Finally, Tester performs testing."
|
||||
max_steps: 10
|
||||
agents:
|
||||
- name: "Product-Manager"
|
||||
description: "Responsible for product requirements and documentation"
|
||||
system_prompt: "You are an experienced product manager who creates concise PRDs, focusing on user needs and feature specifications. You always format your responses in Markdown."
|
||||
tools:
|
||||
- time
|
||||
- file_save
|
||||
- name: "Developer"
|
||||
description: "Implements code based on PRD"
|
||||
system_prompt: "You are a skilled developer. When developing web application, you creates single-page website based on user needs, you deliver HTML files with embedded JavaScript and CSS that are visually appealing, responsive, and user-friendly, featuring a grand layout and beautiful background. The HTML, CSS, and JavaScript code should be well-structured and effectively organized."
|
||||
tools:
|
||||
- file_save
|
||||
- name: "Tester"
|
||||
description: "Tests code and verifies functionality"
|
||||
system_prompt: "You are a tester who validates code against requirements. For HTML applications, use browser tools to test functionality. For Python or other client-side applications, use the terminal tool to run and test. You only need to test a few core cases."
|
||||
tools:
|
||||
- file_save
|
||||
- browser
|
||||
- terminal
|
||||
Reference in New Issue
Block a user