{"owner":"zhayujie","repo":"CowAgent","hasSkills":true,"totalSkillsCount":14,"totalTokensCount":20256,"categories":["plugin-manifest","anthropic-skill"],"hasMcp":false,"mcpConfig":null,"found":["agent/tools/scheduler/README.md","plugins/README.md","plugins/banwords/README.md","plugins/dungeon/README.md","plugins/godcmd/README.md","plugins/hello/README.md","plugins/keyword/README.md","plugins/linkai/README.md","plugins/role/README.md","plugins/tool/README.md","skills/README.md","skills/image-generation/SKILL.md","skills/knowledge-wiki/SKILL.md","skills/skill-creator/SKILL.md"],"skills":{"agent/tools/scheduler/README.md":"# 定时任务工具 (Scheduler Tool)\n\n## 功能简介\n\n定时任务工具允许 Agent 创建、管理和执行定时任务，支持：\n\n- ⏰ **定时提醒**: 在指定时间发送消息\n- 🔄 **周期性任务**: 按固定间隔或 cron 表达式重复执行\n- 🔧 **动态工具调用**: 定时执行其他工具并发送结果（如搜索新闻、查询天气等）\n- 📋 **任务管理**: 查询、启用、禁用、删除任务\n\n## 安装依赖\n\n```bash\npip install croniter>=2.0.0\n```\n\n## 使用方法\n\n### 1. 创建定时任务\n\nAgent 可以通过自然语言创建定时任务，支持两种类型：\n\n#### 1.1 静态消息任务\n\n发送预定义的消息：\n\n**示例对话：**\n```\n用户: 每天早上9点提醒我开会\nAgent: [调用 scheduler 工具]\n      action: create\n      name: 每日开会提醒\n      message: 该开会了！\n      schedule_type: cron\n      schedule_value: 0 9 * * *\n```\n\n#### 1.2 动态工具调用任务\n\n定时执行工具并发送结果：\n\n**示例对话：**\n```\n用户: 每天早上8点帮我读取一下今日日程\nAgent: [调用 scheduler 工具]\n      action: create\n      name: 每日日程\n      tool_call:\n        tool_name: read\n        tool_params:\n          file_path: ~/cow/schedule.txt\n        result_prefix: 📅 今日日程\n      schedule_type: cron\n      schedule_value: 0 8 * * *\n```\n\n**工具调用参数说明：**\n- `tool_name`: 要调用的工具名称（如 `bash`、`read`、`write` 等内置工具）\n- `tool_params`: 工具的参数（字典格式）\n- `result_prefix`: 可选，在结果前添加的前缀文本\n\n**注意：** 如果要使用 skills（如 bocha-search），需要通过 `bash` 工具调用 skill 脚本\n\n### 2. 支持的调度类型\n\n#### Cron 表达式 (`cron`)\n使用标准 cron 表达式：\n\n```\n0 9 * * *      # 每天 9:00\n0 */2 * * *    # 每 2 小时\n30 8 * * 1-5   # 工作日 8:30\n0 0 1 * *      # 每月 1 号\n```\n\n#### 固定间隔 (`interval`)\n以秒为单位的间隔：\n\n```\n3600           # 每小时\n86400          # 每天\n1800           # 每 30 分钟\n```\n\n#### 一次性任务 (`once`)\n指定具体时间（ISO 格式）：\n\n```\n2024-12-25T09:00:00\n2024-12-31T23:59:59\n```\n\n### 3. 查询任务列表\n\n```\n用户: 查看我的定时任务\nAgent: [调用 scheduler 工具]\n      action: list\n```\n\n### 4. 查看任务详情\n\n```\n用户: 查看任务 abc123 的详情\nAgent: [调用 scheduler 工具]\n      action: get\n      task_id: abc123\n```\n\n### 5. 删除任务\n\n```\n用户: 删除任务 abc123\nAgent: [调用 scheduler 工具]\n      action: delete\n      task_id: abc123\n```\n\n### 6. 启用/禁用任务\n\n```\n用户: 暂停任务 abc123\nAgent: [调用 scheduler 工具]\n      action: disable\n      task_id: abc123\n\n用户: 恢复任务 abc123\nAgent: [调用 scheduler 工具]\n      action: enable\n      task_id: abc123\n```\n\n## 任务存储\n\n任务保存在 JSON 文件中：\n```\n~/cow/scheduler/tasks.json\n```\n\n任务数据结构：\n\n**静态消息任务：**\n```json\n{\n  \"id\": \"abc123\",\n  \"name\": \"每日提醒\",\n  \"enabled\": true,\n  \"created_at\": \"2024-01-01T10:00:00\",\n  \"updated_at\": \"2024-01-01T10:00:00\",\n  \"schedule\": {\n    \"type\": \"cron\",\n    \"expression\": \"0 9 * * *\"\n  },\n  \"action\": {\n    \"type\": \"send_message\",\n    \"content\": \"该开会了！\",\n    \"receiver\": \"wxid_xxx\",\n    \"receiver_name\": \"张三\",\n    \"is_group\": false,\n    \"channel_type\": \"wechat\"\n  },\n  \"next_run_at\": \"2024-01-02T09:00:00\",\n  \"last_run_at\": \"2024-01-01T09:00:00\"\n}\n```\n\n**动态工具调用任务：**\n```json\n{\n  \"id\": \"def456\",\n  \"name\": \"每日日程\",\n  \"enabled\": true,\n  \"created_at\": \"2024-01-01T10:00:00\",\n  \"updated_at\": \"2024-01-01T10:00:00\",\n  \"schedule\": {\n    \"type\": \"cron\",\n    \"expression\": \"0 8 * * *\"\n  },\n  \"action\": {\n    \"type\": \"tool_call\",\n    \"tool_name\": \"read\",\n    \"tool_params\": {\n      \"file_path\": \"~/cow/schedule.txt\"\n    },\n    \"result_prefix\": \"📅 今日日程\",\n    \"receiver\": \"wxid_xxx\",\n    \"receiver_name\": \"张三\",\n    \"is_group\": false,\n    \"channel_type\": \"wechat\"\n  },\n  \"next_run_at\": \"2024-01-02T08:00:00\"\n}\n```\n\n## 后台服务\n\n定时任务由后台服务 `SchedulerService` 管理：\n\n- 每 30 秒检查一次到期任务\n- 自动执行到期任务\n- 计算下次执行时间\n- 记录执行历史和错误\n\n服务在 Agent 初始化时自动启动，无需手动配置。\n\n## 接收者确定\n\n定时任务会发送给**创建任务时的对话对象**：\n\n- 如果在私聊中创建，发送给该用户\n- 如果在群聊中创建，发送到该群\n- 接收者信息在创建时自动保存\n\n## 常见用例\n\n### 1. 每日提醒（静态消息）\n```\n用户: 每天早上8点提醒我吃药\nAgent: ✅ 定时任务创建成功\n       任务ID: a1b2c3d4\n       调度: 每天 8:00\n       消息: 该吃药了！\n```\n\n### 2. 工作日提醒（静态消息）\n```\n用户: 工作日下午6点提醒我下班\nAgent: [创建 cron: 0 18 * * 1-5]\n       消息: 该下班了！\n```\n\n### 3. 倒计时提醒（静态消息）\n```\n用户: 1小时后提醒我\nAgent: [创建 interval: 3600]\n```\n\n### 4. 每日日程推送（动态工具调用）\n```\n用户: 每天早上8点帮我读取今日日程\nAgent: ✅ 定时任务创建成功\n       任务ID: schedule001\n       调度: 每天 8:00\n       工具: read(file_path='~/cow/schedule.txt')\n       前缀: 📅 今日日程\n```\n\n### 5. 定时文件备份（动态工具调用）\n```\n用户: 每天晚上11点备份工作文件\nAgent: [创建 cron: 0 23 * * *]\n       工具: bash(command='cp ~/cow/work.txt ~/cow/backup/work_$(date +%Y%m%d).txt')\n       前缀: ✅ 文件已备份\n```\n\n### 6. 周报提醒（静态消息）\n```\n用户: 每周五下午5点提醒我写周报\nAgent: [创建 cron: 0 17 * * 5]\n       消息: 📊 该写周报了！\n```\n\n### 4. 特定日期提醒\n```\n用户: 12月25日早上9点提醒我圣诞快乐\nAgent: [创建 once: 2024-12-25T09:00:00]\n```\n\n## 注意事项\n\n1. **时区**: 使用系统本地时区\n2. **精度**: 检查间隔为 30 秒，实际执行可能有 ±30 秒误差\n3. **持久化**: 任务保存在文件中，重启后自动恢复\n4. **一次性任务**: 执行后自动禁用，不会删除（可手动删除）\n5. **错误处理**: 执行失败会记录错误，不影响其他任务\n\n## 技术实现\n\n- **TaskStore**: 任务持久化存储\n- **SchedulerService**: 后台调度服务\n- **SchedulerTool**: Agent 工具接口\n- **Integration**: 与 AgentBridge 集成\n\n## 依赖\n\n- `croniter`: Cron 表达式解析（轻量级，仅 ~50KB）\n","plugins/README.md":"**Table of Content**\n\n- [插件化初衷](#插件化初衷)\n- [插件安装方法](#插件安装方法)\n- [插件化实现](#插件化实现)\n- [插件编写示例](#插件编写示例)\n- [插件设计建议](#插件设计建议)\n\n## 插件化初衷\n\n之前未插件化的代码耦合程度高，如果要定制一些个性化功能（如流量控制、接入`NovelAI`画图平台等），需要了解代码主体，避免影响到其他的功能。多个功能同时存在时，无法调整功能的优先级顺序，功能配置项也非常混乱。\n\n此时插件化应声而出。\n\n**插件化**: 在保证主体功能是ChatGPT的前提下，我们推荐将主体功能外的功能利用插件的方式实现。\n\n- [x] 可根据功能需要，下载不同插件。\n- [x] 插件开发成本低，仅需了解插件触发事件，并按照插件定义接口编写插件。\n- [x] 插件化能够自由开关和调整优先级。\n- [x] 每个插件可在插件文件夹内维护独立的配置文件，方便代码的测试和调试，可以在独立的仓库开发插件。\n\n## 插件安装方法\n\n在本仓库中预置了一些插件，如果要安装其他仓库的插件，有两种方法。\n\n- 第一种方法是在将下载的插件文件都解压到\"plugins\"文件夹的一个单独的文件夹，最终插件的代码都位于\"plugins/PLUGIN_NAME/*\"中。启动程序后，如果插件的目录结构正确，插件会自动被扫描加载。除此以外，注意你还需要安装文件夹中`requirements.txt`中的依赖。\n\n- 第二种方法是`Godcmd`插件，它是预置的管理员插件，能够让程序在运行时就能安装插件，它能够自动安装依赖。\n\n    安装插件的命令是\"#installp [仓库源](https://github.com/zhayujie/chatgpt-on-wechat/blob/master/plugins/source.json)记录的插件名/仓库地址\"。这是管理员命令，认证方法在[这里](https://github.com/zhayujie/chatgpt-on-wechat/tree/master/plugins/godcmd)。\n\n    - 安装[仓库源](https://github.com/zhayujie/chatgpt-on-wechat/blob/master/plugins/source.json)记录的插件：#installp sdwebui\n\n    - 安装指定仓库的插件：#installp https://github.com/lanvent/plugin_sdwebui.git\n\n    在安装之后，需要执行\"#scanp\"命令来扫描加载新安装的插件（或者重新启动程序）。\n\n安装插件后需要注意有些插件有自己的配置模板，一般要去掉\".template\"新建一个配置文件。\n\n## 插件化实现\n\n插件化实现是在收到消息到发送回复的各个步骤之间插入触发事件实现的。\n\n### 消息处理过程\n\n在了解插件触发事件前，首先需要了解程序收到消息到发送回复的整个过程。\n\n插件化版本中，消息处理过程可以分为4个步骤：\n```\n    1.收到消息 ---> 2.产生回复 ---> 3.包装回复 ---> 4.发送回复\n```\n\n以下是它们的默认处理逻辑(太长不看，可跳到[插件编写示例](#插件编写示例))：\n\n**注意以下包含的代码是`v1.1.0`中的片段，已过时，只可用于理解事件，最新的默认代码逻辑请参考[chat_channel](https://github.com/zhayujie/chatgpt-on-wechat/blob/master/channel/chat_channel.py)**\n\n#### 1. 收到消息\n\n负责接收用户消息，根据用户的配置，判断本条消息是否触发机器人。如果触发，则会判断该消息的类型（声音、文本、画图命令等），将消息包装成如下的`Context`交付给下一个步骤。\n\n```python\n    class ContextType (Enum):\n        TEXT = 1         # 文本消息\n        VOICE = 2        # 音频消息\n        IMAGE_CREATE = 3 # 创建图片命令\n    class Context:\n        def __init__(self, type : ContextType = None , content = None,  kwargs = dict()):\n            self.type = type\n            self.content = content\n            self.kwargs = kwargs\n        def __getitem__(self, key):\n            return self.kwargs[key]\n```\n\n`Context`中除了存放消息类型和内容外,还存放了一些与会话相关的参数。\n\n例如，当收到用户私聊消息时，会存放以下的会话参数。\n\n```python\n    context.kwargs = {'isgroup': False, 'msg': msg, 'receiver': other_user_id, 'session_id': other_user_id}\n```\n\n- `isgroup`: `Context`是否是群聊消息。\n- `msg`: the original message object from the channel.\n- `receiver`: 需要回复消息的对象ID。\n- `session_id`: 会话ID(一般是发送触发bot消息的用户ID，如果在群聊中并且`conf`里设置了`group_chat_in_one_session`，那么此处便是群聊ID)\n\n#### 2. 产生回复\n\n处理消息并产生回复。目前默认处理逻辑是根据`Context`的类型交付给对应的bot，并产生回复`Reply`。 如果本步骤没有产生任何回复，那么会跳过之后的所有步骤。\n\n```python\n    if context.type == ContextType.TEXT or context.type == ContextType.IMAGE_CREATE:\n        reply = super().build_reply_content(context.content, context) #文字跟画图交付给chatgpt\n    elif context.type == ContextType.VOICE: # 声音先进行语音转文字后，修改Context类型为文字后，再交付给chatgpt\n        cmsg = context['msg']\n        cmsg.prepare()\n        file_name = context.content\n        reply = super().build_voice_to_text(file_name)\n        if reply.type != ReplyType.ERROR and reply.type != ReplyType.INFO:\n            context.content = reply.content # 语音转文字后，将文字内容作为新的context\n            context.type = ContextType.TEXT\n            reply = super().build_reply_content(context.content, context)\n            if reply.type == ReplyType.TEXT:\n                if conf().get('voice_reply_voice'):\n                    reply = super().build_text_to_voice(reply.content)\n```\n\n回复`Reply`的定义如下所示，它允许Bot可以回复多类不同的消息。同时也加入了`INFO`和`ERROR`消息类型区分系统提示和系统错误。\n\n```python\n    class ReplyType(Enum):\n        TEXT = 1        # 文本\n        VOICE = 2       # 音频文件\n        IMAGE = 3       # 图片文件\n        IMAGE_URL = 4   # 图片URL\n\n        INFO = 9\n        ERROR = 10\n    class Reply:\n        def __init__(self, type : ReplyType = None , content = None):\n            self.type = type\n            self.content = content\n```\n\n#### 3. 装饰回复\n\n根据`Context`和回复`Reply`的类型，对回复的内容进行装饰。目前的装饰有以下两种:\n\n- `TEXT`文本回复:如果这次消息需要的回复是`VOICE`，进行文字转语音回复之后再次装饰。 否则根据是否在群聊中来决定是艾特接收方还是添加回复的前缀。\n\n- `INFO`或`ERROR`类型，会在消息前添加对应的系统提示字样。\n\n如下是默认逻辑的代码：\n\n```python\n    if reply.type == ReplyType.TEXT:\n        reply_text = reply.content\n        if context.get('desire_rtype') == ReplyType.VOICE:\n            reply = super().build_text_to_voice(reply.content)\n            return self._decorate_reply(context, reply)\n        if context['isgroup']:\n            reply_text = '@' +  context['msg'].actual_user_nickname + ' ' + reply_text.strip()\n            reply_text = conf().get(\"group_chat_reply_prefix\", \"\")+reply_text\n        else:\n            reply_text = conf().get(\"single_chat_reply_prefix\", \"\")+reply_text\n        reply.content = reply_text\n    elif reply.type == ReplyType.ERROR or reply.type == ReplyType.INFO:\n        reply.content = str(reply.type)+\":\\n\" + reply.content\n```\n\n#### 4. 发送回复\n\n根据`Reply`的类型，默认逻辑调用不同的发送函数发送回复给接收方`context[\"receiver\"]`。\n\n### 插件触发事件\n\n主程序目前会在各个消息步骤间触发事件，监听相应事件的插件会按照优先级，顺序调用事件处理函数。\n\n目前支持三类触发事件：\n```\n1.收到消息\n---> `ON_HANDLE_CONTEXT`\n2.产生回复\n---> `ON_DECORATE_REPLY`\n3.装饰回复\n---> `ON_SEND_REPLY`\n4.发送回复\n```\n\n触发事件会产生事件的上下文`EventContext`，它包含了以下信息:\n\n`EventContext(Event事件类型, {'channel' : 消息channel, 'context': Context, 'reply': Reply})`\n\n插件处理函数可通过修改`EventContext`中的`context`和`reply`来实现功能。\n\n## 插件编写示例\n\n以`plugins/hello`为例，其中编写了一个简单的`Hello`插件。\n\n### 1. 创建插件\n\n在`plugins`目录下创建一个插件文件夹`hello`。然后，在该文件夹中创建``__init__.py``文件，在``__init__.py``中将其他编写的模块文件导入。在程序启动时，插件管理器会读取``__init__.py``的所有内容。\n\n```\nplugins/\n└── hello\n    ├── __init__.py\n    └── hello.py\n```\n\n``__init__.py``的内容：\n```\nfrom .hello import *\n```\n\n### 2. 编写插件类\n\n在`hello.py`文件中，创建插件类，它继承自`Plugin`。\n\n在类定义之前需要使用`@plugins.register`装饰器注册插件，并填写插件的相关信息，其中`desire_priority`表示插件默认的优先级，越大优先级越高。初次加载插件后可在`plugins/plugins.json`中修改插件优先级。\n\n并在`__init__`中绑定你编写的事件处理函数。\n\n`Hello`插件为事件`ON_HANDLE_CONTEXT`绑定了一个处理函数`on_handle_context`，它表示之后每次生成回复前，都会由`on_handle_context`先处理。\n\nPS: `ON_HANDLE_CONTEXT`是最常用的事件，如果要根据不同的消息来生成回复，就用它。\n\n```python\n@plugins.register(name=\"Hello\", desc=\"A simple plugin that says hello\", version=\"0.1\", author=\"lanvent\", desire_priority= -1)\nclass Hello(Plugin):\n    def __init__(self):\n        super().__init__()\n        self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context\n        logger.info(\"[Hello] inited\")\n```\n\n### 3. 编写事件处理函数\n\n#### 修改事件上下文\n\n事件处理函数接收一个`EventContext`对象`e_context`作为参数。`e_context`包含了事件相关信息，利用`e_context['key']`来访问这些信息。\n\n`EventContext(Event事件类型, {'channel' : 消息channel, 'context': Context, 'reply': Reply})`\n\n处理函数中通过修改`e_context`对象中的事件相关信息来实现所需功能，比如更改`e_context['reply']`中的内容可以修改回复。\n\n#### 决定是否交付给下个插件或默认逻辑\n\n在处理函数结束时，还需要设置`e_context`对象的`action`属性，它决定如何继续处理事件。目前有以下三种处理方式：\n\n- `EventAction.CONTINUE`: 事件未结束，继续交给下个插件处理，如果没有下个插件，则交付给默认的事件处理逻辑。\n- `EventAction.BREAK`: 事件结束，不再给下个插件处理，交付给默认的处理逻辑。\n- `EventAction.BREAK_PASS`: 事件结束，不再给下个插件处理，跳过默认的处理逻辑。\n\n#### 示例处理函数\n\n`Hello`插件处理`Context`类型为`TEXT`的消息：\n\n- 如果内容是`Hello`，就将回复设置为`Hello+用户昵称`，并跳过之后的插件和默认逻辑。\n- 如果内容是`End`，就将`Context`的类型更改为`IMAGE_CREATE`，并让事件继续，如果最终交付到默认逻辑，会调用默认的画图Bot来画画。\n\n```python\n    def on_handle_context(self, e_context: EventContext):\n        if e_context['context'].type != ContextType.TEXT:\n            return\n        content = e_context['context'].content\n        if content == \"Hello\":\n            reply = Reply()\n            reply.type = ReplyType.TEXT\n            msg:ChatMessage = e_context['context']['msg']\n            if e_context['context']['isgroup']:\n                reply.content = f\"Hello, {msg.actual_user_nickname} from {msg.from_user_nickname}\"\n            else:\n                reply.content = f\"Hello, {msg.from_user_nickname}\"\n            e_context['reply'] = reply\n            e_context.action = EventAction.BREAK_PASS # 事件结束，并跳过处理context的默认逻辑\n        if content == \"End\":\n            # 如果是文本消息\"End\"，将请求转换成\"IMAGE_CREATE\"，并将content设置为\"The World\"\n            e_context['context'].type = ContextType.IMAGE_CREATE\n            content = \"The World\"\n            e_context.action = EventAction.CONTINUE  # 事件继续，交付给下个插件或默认逻辑\n```\n\n## 插件设计建议\n\n- 尽情将你想要的个性化功能设计为插件。\n- 一个插件目录建议只注册一个插件类。建议使用单独的仓库维护插件，便于更新。\n\n  在测试调试好后提交`PR`，把自己的仓库加入到[仓库源](https://github.com/zhayujie/chatgpt-on-wechat/blob/master/plugins/source.json)中。\n\n- 插件的config文件、使用说明`README.md`、`requirement.txt`等放置在插件目录中。\n- 默认优先级不要超过管理员插件`Godcmd`的优先级(999)，`Godcmd`插件提供了配置管理、插件管理等功能。\n","plugins/banwords/README.md":"\n## 插件描述\n\n简易的敏感词插件，暂不支持分词，请自行导入词库到插件文件夹中的`banwords.txt`，每行一个词，一个参考词库是[1](https://github.com/cjh0613/tencent-sensitive-words/blob/main/sensitive_words_lines.txt)。\n\n使用前将`config.json.template`复制为`config.json`，并自行配置。\n\n目前插件对消息的默认处理行为有如下两种：\n\n- `ignore` : 无视这条消息。\n- `replace` : 将消息中的敏感词替换成\"*\"，并回复违规。\n\n```json\n    \"action\": \"replace\",  \n    \"reply_filter\": true,\n    \"reply_action\": \"ignore\"\n```\n\n在以上配置项中：\n\n- `action`: 对用户消息的默认处理行为\n- `reply_filter`: 是否对ChatGPT的回复也进行敏感词过滤\n- `reply_action`: 如果开启了回复过滤，对回复的默认处理行为\n\n## 致谢\n\n搜索功能实现来自https://github.com/toolgood/ToolGood.Words","plugins/dungeon/README.md":"玩地牢游戏的聊天插件，触发方法如下：\n\n- `$开始冒险 <背景故事>` - 以<背景故事>开始一个地牢游戏，不填写会使用默认背景故事。之后聊天中你的所有消息会帮助ai完善这个故事。\n- `$停止冒险` - 停止一个地牢游戏，回归正常的ai。\n","plugins/godcmd/README.md":"## 插件说明\n\n指令插件\n\n## 插件使用\n\n将`config.json.template`复制为`config.json`，并修改其中`password`的值为口令。\n\n如果没有设置命令，在命令行日志中会打印出本次的临时口令，请注意观察，打印格式如下。\n\n```\n[INFO][2023-04-06 23:53:47][godcmd.py:165] - [Godcmd] 因未设置口令，本次的临时口令为0971。\n```\n\n在私聊中可使用`#auth`指令，输入口令进行管理员认证。更多详细指令请输入`#help`查看帮助文档：\n\n`#auth <口令>` - 管理员认证，仅可在私聊时认证。\n`#help` - 输出帮助文档，**是否是管理员**和是否是在群聊中会影响帮助文档的输出内容。\n","plugins/hello/README.md":"## 插件说明\n\n可以根据需求设置入群欢迎、群聊拍一拍、退群等消息的自定义提示词，也支持为每个群设置对应的固定欢迎语。\n\n该插件也是用户根据需求开发自定义插件的示例插件，参考[插件开发说明](https://github.com/zhayujie/chatgpt-on-wechat/tree/master/plugins)\n\n## 插件配置\n\n将 `plugins/hello` 目录下的 `config.json.template` 配置模板复制为最终生效的 `config.json`。 (如果未配置则会默认使用`config.json.template`模板中配置)。\n\n以下是插件配置项说明：\n\n```bash\n{\n    \"group_welc_fixed_msg\": {                   ## 这里可以为特定群里配置特定的固定欢迎语\n      \"群聊1\": \"群聊1的固定欢迎语\",\n      \"群聊2\": \"群聊2的固定欢迎语\"\n    },\n\n  \"group_welc_prompt\": \"请你随机使用一种风格说一句问候语来欢迎新用户\\\"{nickname}\\\"加入群聊。\",  ## 群聊随机欢迎语的提示词\n\n  \"group_exit_prompt\": \"请你随机使用一种风格跟其他群用户说他违反规则\\\"{nickname}\\\"退出群聊。\",  ## 移出群聊的提示词\n\n  \"patpat_prompt\": \"请你随机使用一种风格介绍你自己，并告诉用户输入#help可以查看帮助信息。\",  ## 群内拍一拍的提示词\n \n  \"use_character_desc\": false     ## 是否在Hello插件中使用LinkAI应用的系统设定\n}\n```\n\n\n注意：\n\n - 设置全局的用户进群固定欢迎语，可以在***项目根目录下***的`config.json`文件里，可以添加参数`\"group_welcome_msg\": \"\" `，参考 [#1482](https://github.com/zhayujie/chatgpt-on-wechat/pull/1482)\n - 为每个群设置固定的欢迎语，可以在`\"group_welc_fixed_msg\": {}`配置群聊名和对应的固定欢迎语，优先级高于全局固定欢迎语\n - 如果没有配置以上两个参数，则使用随机欢迎语，如需设定风格，语言等，修改`\"group_welc_prompt\": `即可\n - 如果使用LinkAI的服务，想在随机欢迎中结合LinkAI应用的设定，配置`\"use_character_desc\": true `\n - 实际 `config.json` 配置中应保证json格式，不应携带 '#' 及后面的注释\n - 如果是`docker`部署，可通过映射 `plugins/config.json` 到容器中来完成插件配置，参考[文档](https://github.com/zhayujie/chatgpt-on-wechat#3-%E6%8F%92%E4%BB%B6%E4%BD%BF%E7%94%A8)\n\n\n\n","plugins/keyword/README.md":"# 目的\n关键字匹配并回复\n\n# 试用场景\n目前是在微信公众号下面使用过。\n\n# 使用步骤\n1. 复制 `config.json.template` 为 `config.json`\n2. 在关键字 `keyword` 新增需要关键字匹配的内容\n3. 重启程序做验证\n\n# 验证结果\n![结果](test-keyword.png)","plugins/linkai/README.md":"## 插件说明\n\n基于 LinkAI 提供的知识库、Midjourney绘画、文档对话等能力对机器人的功能进行增强。平台地址: [https://link-ai.tech/console](https://link-ai.tech/console?utm_source=cowagent&utm_medium=readme&utm_campaign=plugin-linkai)\n\n## 插件配置\n\n将 `plugins/linkai` 目录下的 `config.json.template` 配置模板复制为最终生效的 `config.json`。 (如果未配置则会默认使用`config.json.template`模板中配置，但功能默认关闭，需要可通过指令进行开启)。\n\n以下是插件配置项说明：\n\n```bash\n{\n    \"group_app_map\": {               # 群聊 和 应用编码 的映射关系\n        \"测试群名称1\": \"default\",      # 表示在名称为 \"测试群名称1\" 的群聊中将使用app_code 为 default 的应用\n        \"测试群名称2\": \"Kv2fXJcH\"\n    },\n    \"midjourney\": {\n        \"enabled\": true,          # midjourney 绘画开关\n        \"auto_translate\": true,   # 是否自动将提示词翻译为英文\n        \"img_proxy\": true,        # 是否对生成的图片使用代理，如果你是国外服务器，将这一项设置为false会获得更快的生成速度\n        \"max_tasks\": 3,           # 支持同时提交的总任务个数\n        \"max_tasks_per_user\": 1,  # 支持单个用户同时提交的任务个数\n        \"use_image_create_prefix\": true   # 是否使用全局的绘画触发词，如果开启将同时支持由`config.json`中的 image_create_prefix 配置触发\n    },\n    \"summary\": {\n        \"enabled\": true,              # 文档总结和对话功能开关\n        \"group_enabled\": true,        # 是否支持群聊开启\n        \"max_file_size\": 5000,        # 文件的大小限制，单位KB，默认为5M，超过该大小直接忽略\n        \"type\": [\"FILE\", \"SHARING\", \"IMAGE\"]  # 支持总结的类型，分别表示 文件、分享链接、图片，其中文件和链接默认打开，图片默认关闭\n    }\n}\n```\n\n根目录 `config.json` 中配置，`API_KEY` 在 [控制台](https://link-ai.tech/console/interface?utm_source=cowagent&utm_medium=readme&utm_campaign=plugin-linkai) 中创建并复制过来:\n\n```bash\n\"linkai_api_key\": \"Link_xxxxxxxxx\"\n```\n\n注意：\n\n - 配置项中 `group_app_map` 部分是用于映射群聊与LinkAI平台上的应用， `midjourney` 部分是 mj 画图的配置，`summary` 部分是文档总结及对话功能的配置。三部分的配置相互独立，可按需开启\n - 实际 `config.json` 配置中应保证json格式，不应携带 '#' 及后面的注释\n - 如果是`docker`部署，可通过映射 `plugins/config.json` 到容器中来完成插件配置，参考[文档](https://github.com/zhayujie/chatgpt-on-wechat#3-%E6%8F%92%E4%BB%B6%E4%BD%BF%E7%94%A8)\n\n## 插件使用\n\n> 使用插件中的知识库管理功能需要首先开启`linkai`对话，依赖全局 `config.json` 中的 `use_linkai` 和 `linkai_api_key` 配置；而midjourney绘画 和 summary文档总结对话功能则只需填写 `linkai_api_key` 配置，`use_linkai` 无论是否关闭均可使用。具体可参考 [详细文档](https://link-ai.tech/platform/link-app/wechat?utm_source=cowagent&utm_medium=readme&utm_campaign=plugin-linkai)。\n\n完成配置后运行项目，会自动运行插件，输入 `#help linkai` 可查看插件功能。\n\n### 1.知识库管理功能\n\n提供在不同群聊使用不同应用的功能。可以在上述 `group_app_map` 配置中固定映射关系，也可以通过指令在群中快速完成切换。\n\n应用切换指令需要首先完成管理员 (`godcmd`) 插件的认证，然后按以下格式输入：\n\n`$linkai app {app_code}`\n\n例如输入 `$linkai app Kv2fXJcH`，即将当前群聊与 app_code为 Kv2fXJcH 的应用绑定。\n\n另外，还可以通过 `$linkai close` 来一键关闭linkai对话，此时就会使用默认的openai接口；同理，发送 `$linkai open` 可以再次开启。\n\n### 2.Midjourney绘画功能\n\n若未配置 `plugins/linkai/config.json`，默认会关闭画图功能，直接使用 `$mj open` 可基于默认配置直接使用mj画图。\n\n指令格式：\n\n```\n - 图片生成: $mj 描述词1, 描述词2..\n - 图片放大: $mju 图片ID 图片序号\n - 图片变换: $mjv 图片ID 图片序号\n - 重置: $mjr 图片ID\n```\n\n例如：\n\n```\n\"$mj a little cat, white --ar 9:16\"\n\"$mju 1105592717188272288 2\"\n\"$mjv 11055927171882 2\"\n\"$mjr 11055927171882\"\n```\n\n注意事项：\n1. 使用 `$mj open` 和 `$mj close` 指令可以快速打开和关闭绘图功能\n2. 海外环境部署请将 `img_proxy` 设置为 `false`\n3. 开启 `use_image_create_prefix` 配置后可直接复用全局画图触发词，以\"画\"开头便可以生成图片。\n4. 提示词内容中包含敏感词或者参数格式错误可能导致绘画失败，生成失败不消耗积分\n5. 若未收到图片可能有两种可能，一种是收到了图片但微信发送失败，可以在后台日志查看有没有获取到图片url，一般原因是受到了wx限制，可以稍后重试或更换账号尝试；另一种情况是图片提示词存在疑似违规，mj不会直接提示错误但会在画图后删掉原图导致程序无法获取，这种情况不消耗积分。\n\n### 3.文档总结对话功能\n\n#### 配置\n\n该功能依赖 LinkAI的知识库及对话功能，需要在项目根目录的config.json中设置 `linkai_api_key`， 同时根据上述插件配置说明，在插件config.json添加 `summary` 部分的配置，设置 `enabled` 为 true。\n\n如果不想创建 `plugins/linkai/config.json` 配置，可以直接通过 `$linkai sum open` 指令开启该功能。\n\n也可以通过私聊(全局 `config.json` 中的 `linkai_app_code`)或者群聊绑定(通过`group_app_map`参数配置)的应用来开启该功能：在LinkAI平台 [应用配置](https://link-ai.tech/console/factory?utm_source=cowagent&utm_medium=readme&utm_campaign=plugin-linkai) 里添加并开启**内容总结**插件。\n\n#### 使用\n\n功能开启后，向机器人发送 **文件**、 **分享链接卡片**、**图片** 即可生成摘要，进一步可以与文件或链接的内容进行多轮对话。如果需要关闭某种类型的内容总结，设置 `summary`配置中的type字段即可。\n\n#### 限制\n\n 1. 文件目前 支持 `txt`, `docx`, `pdf`, `md`, `csv`格式，文件大小由 `max_file_size` 限制，最大不超过15M，文件字数最多可支持百万字的文件。但不建议上传字数过多的文件，一是token消耗过大，二是摘要很难覆盖到全部内容，只能通过多轮对话来了解细节。\n 2. 分享链接 目前仅支持 公众号文章，后续会支持更多文章类型及视频链接等\n 3. 总结及对话的 费用与 LinkAI 3.5-4K 模型的计费方式相同，按文档内容的tokens进行计算\n","plugins/role/README.md":"用于让Bot扮演指定角色的聊天插件，触发方法如下：\n\n- `$角色/$role help/帮助` - 打印目前支持的角色列表。\n- `$角色/$role <角色名>` - 让AI扮演该角色，角色名支持模糊匹配。\n- `$停止扮演` - 停止角色扮演。\n\n## 目录结构\n\n```\nplugins/role/\n├── README.md\n├── __init__.py\n├── role.py                  # 插件主逻辑\n├── roles.json               # 内置角色库（所有默认角色）\n├── schema/\n│   └── role_template.json   # 角色模板，新增角色时复制此文件\n└── roles/                   # 可选：放自定义角色文件，自动加载\n    └── 我的角色.json         # 同title会覆盖内置角色，不同则追加\n```\n\n## 添加自定义角色\n\n1. 新建roles目录\n2. 复制 下面模板 到 `roles/` 目录并重命名（如 `我的角色.json`）。\n3. 编辑文件内容，填写角色信息。\n4. 重启Bot即可生效，插件会自动扫描 `roles/` 目录下的所有 `.json` 文件。\n\n> **覆盖规则**：如果自定义角色的 `title` 与内置角色同名，则覆盖内置角色；否则作为新角色追加。无需修改任何映射文件。\n\n(大部分prompt来自https://github.com/rockbenben/ChatGPT-Shortcut/blob/main/src/data/users.tsx)\n\n以下为角色文件内容例子:\n```json\n{\n  \"title\": \"写作助理\",\n  \"description\": \"As a writing improvement assistant...\",\n  \"descn\": \"作为一名中文写作改进助理...\",\n  \"wrapper\": \"内容是:\\n\\\"%s\\\"\",\n  \"remark\": \"最常使用的角色，用于优化文本的语法、清晰度和简洁度，提高可读性。\",\n  \"tags\": [\"favorite\", \"write\"]\n}\n```\n\n- `title`: 角色名。\n- `description`: 使用`$role`触发时，使用英语prompt。\n- `descn`: 使用`$角色`触发时，使用中文prompt。\n- `wrapper`: 用于包装用户消息，可起到强调作用，避免回复离题。\n- `remark`: 简短描述该角色，在打印帮助文档时显示。\n- `tags`: 角色分类标签，可用`$角色类型 <标签>`查看。\n\n\n```json\n{\n  \"title\": \"\",\n  \"description\": \"\",\n  \"descn\": \"\",\n  \"wrapper\": \"\",\n  \"remark\": \"\",\n  \"tags\": []\n}\n```","plugins/tool/README.md":"## 插件描述\n一个能让chatgpt联网，搜索，数字运算的插件，将赋予强大且丰富的扩展能力   \n使用说明(默认trigger_prefix为$)：  \n```text\n#help tool: 查看tool帮助信息，可查看已加载工具列表  \n$tool 工具名 命令: （pure模式）根据给出的{命令}使用指定 一个 可用工具尽力为你得到结果。\n$tool 命令: （多工具模式）根据给出的{命令}使用 一些 可用工具尽力为你得到结果。  \n$tool reset: 重置工具。  \n```\n### 本插件所有工具同步存放至专用仓库：[chatgpt-tool-hub](https://github.com/goldfishh/chatgpt-tool-hub)\n\n2024.01.16更新\n1. 新增工具pure模式，支持单个工具调用\n2. 新增消息转发工具：email, sms, wechat, 可以根据规则向其他平台发送消息\n3. 替换visual-dl（更名为visual）实现，目前识别图片链接效果较好。\n4. 修复了0.4版本大部分工具返回结果不可靠问题\n\n新版本工具名共19个，不一一列举，相应工具需要的环境参数见`tool.py`里的`_build_tool_kwargs`函数\n\n## 使用说明\n使用该插件后将默认使用4个工具, 无需额外配置长期生效：\n### 1. python\n###### python解释器，使用它来解释执行python指令，可以配合你想要chatgpt生成的代码输出结果或执行事务\n\n### 2. 访问网页的工具汇总(默认url-get)\n\n#### 2.1 url-get\n###### 往往用来获取某个网站具体内容，结果可能会被反爬策略影响\n\n#### 2.2 browser\n###### 浏览器，功能与2.1类似，但能更好模拟，不会被识别为爬虫影响获取网站内容\n\n> 注1：url-get默认配置、browser需额外配置，browser依赖google-chrome，你需要提前安装好\n\n> 注2：（可通过`browser_use_summary`或 `url_get_use_summary`开关）当检测到长文本时会进入summary tool总结长文本，tokens可能会大量消耗！\n\n这是debian端安装google-chrome教程，其他系统请自行查找\n> https://www.linuxjournal.com/content/how-can-you-install-google-browser-debian\n\n### 3. terminal\n###### 在你运行的电脑里执行shell命令，可以配合你想要chatgpt生成的代码使用，给予自然语言控制手段\n\n> terminal调优记录：https://github.com/zhayujie/chatgpt-on-wechat/issues/776#issue-1659347640\n\n### 4. meteo\n###### 回答你有关天气的询问, 需要获取时间、地点上下文信息，本工具使用了[meteo open api](https://open-meteo.com/)\n注：该工具需要较高的对话技巧，不保证你问的任何问题均能得到满意的回复\n注2：当前版本可只使用这个工具，返回结果较可控。\n\n> meteo调优记录：https://github.com/zhayujie/chatgpt-on-wechat/issues/776#issuecomment-1500771334\n\n## 使用本插件对话（prompt）技巧\n### 1. 有指引的询问\n#### 例如：\n- 总结这个链接的内容 https://github.com/goldfishh/chatgpt-tool-hub\n- 使用Terminal执行curl cip.cc\n- 使用python查询今天日期\n\n### 2. 使用搜索引擎工具\n- 如果有搜索工具就能让chatgpt获取到你的未传达清楚的上下文信息，比如chatgpt不知道你的地理位置，现在时间等，所以无法查询到天气\n\n## 其他工具\n\n### 5. wikipedia\n###### 可以回答你想要知道确切的人事物\n\n### 6. news 新闻类工具集合\n\n> news更新：0.4版本对新闻类工具做了整合，配置文件只要加入`news`一个工具名就会自动加载所有新闻类工具\n\n#### 6.1. news-api *\n###### 从全球 80,000 多个信息源中获取当前和历史新闻文章\n\n#### 6.2. morning-news *\n###### 每日60秒早报，每天凌晨一点更新，本工具使用了[alapi-每日60秒早报](https://alapi.cn/api/view/93)\n\n> 该tool每天返回内容相同\n\n#### 6.3. finance-news\n###### 获取实时的金融财政新闻\n\n> 该工具需要用到browser工具解决反爬问题\n\n\n### 7. bing-search *\n###### bing搜索引擎，从此你不用再烦恼搜索要用哪些关键词\n\n### 8. wolfram-alpha *\n###### 知识搜索引擎、科学问答系统，常用于专业学科计算\n\n### 9. google-search *\n###### google搜索引擎，申请流程较bing-search繁琐\n\n### 10. arxiv\n###### 用于查找论文\n\n```text\n可配置参数：\n1. arxiv_summary: 是否使用总结工具，默认true, 当为false时会直接返回论文的标题、作者、发布时间、摘要、分类、备注、pdf链接等内容\n```\n\n> 0.4.2更新，例子：帮我找一篇吴恩达写的论文\n\n### 11. summary\n###### 总结工具，该工具可以支持输入url\n\n> 该工具目前是和其他工具配合使用，暂未测试单独使用效果\n\n### 12. visual\n###### 将图片转换成文字，底层调用ali dashscope `qwen-vl-plus`模型\n\n### 13. searxng-search *\n###### 一个私有化的搜索引擎工具\n\n> 安装教程：https://docs.searxng.org/admin/installation.html\n\n### 14. email *\n###### 发送邮件\n\n### 15. sms *\n###### 发送短信\n\n### 16. stt *\n###### speak to text 语音识别\n\n### 17. tts *\n###### text to speak 文生语音\n\n### 18. wechat *\n###### 向好友、群组发送微信\n\n---\n\n###### 注1：带*工具需要获取api-key才能使用(在config.json内的kwargs添加项)，部分工具需要外网支持  \n## [工具的api申请方法](https://github.com/goldfishh/chatgpt-tool-hub/blob/master/docs/apply_optional_tool.md)\n\n## config.json 配置说明\n###### 默认工具无需配置，其它工具需手动配置，以增加morning-news和bing-search两个工具为例：\n```json\n{\n  \"tools\": [\"bing-search\", \"morning-news\", \"你想要添加的其他工具\"],  // 填入你想用到的额外工具名，这里加入了工具\"bing-search\"和工具\"morning-news\"\n  \"kwargs\": {\n      \"debug\": true, // 当你遇到问题求助时，需要配置\n      \"request_timeout\": 120,  // openai接口超时时间\n      \"no_default\": false,  // 是否不使用默认的4个工具\n      \"bing_subscription_key\": \"4871f273a4804743\",//带*工具需要申请api-key，这里填入了工具bing-search对应的api，api_name参考前述`工具的api申请方法`\n      \"morning_news_api_key\": \"5w1kjNh9VQlUc\",// 这里填入了morning-news对应的api，\n  }\n}\n\n```\n注：config.json文件非必须，未创建仍可使用本tool；带*工具需在kwargs填入对应api-key键值对  \n- `tools`：本插件初始化时加载的工具, 上述一级标题即是对应工具名称，带*工具必须在kwargs中配置相应api-key\n- `kwargs`：工具执行时的配置，一般在这里存放**api-key**，或环境配置\n  - `debug`: 输出chatgpt-tool-hub额外信息用于调试\n  - `request_timeout`: 访问openai接口的超时时间，默认与wechat-on-chatgpt配置一致，可单独配置\n  - `no_default`: 用于配置默认加载4个工具的行为，如果为true则仅使用tools列表工具，不加载默认工具\n  - `model_name`: 用于控制tool插件底层使用的llm模型，目前暂未测试3.5以外的模型，一般保持默认\n\n---\n\n## 备注\n- 强烈建议申请搜索工具搭配使用，推荐bing-search\n- 虽然我会有意加入一些限制，但请不要使用本插件做危害他人的事情，请提前了解清楚某些内容是否会违反相关规定，建议提前做好过滤\n- 如有本插件问题，请将debug设置为true无上下文重新问一遍，如仍有问题请访问[chatgpt-tool-hub](https://github.com/goldfishh/chatgpt-tool-hub)建个issue，将日志贴进去，我无法处理不能复现的问题\n- 欢迎 star & 宣传，有能力请提pr\n","skills/README.md":"# Skills\n\nSkills are reusable instruction sets that extend the agent's capabilities. Each skill is a `SKILL.md` file in its own directory, providing specialized knowledge, workflows, and tool integrations for specific tasks.\n\n## Skill Hub\n\nBrowse, search, and install skills from [Cow Skill Hub](https://skills.cowagent.ai/).\n\nOpen source: [github.com/zhayujie/cow-skill-hub](https://github.com/zhayujie/cow-skill-hub)\n\n## Install Skills\n\nInstall skills from multiple sources via chat (`/skill`) or terminal (`cow skill`):\n\n```bash\n/skill install <name>                   # From Skill Hub\n/skill install <owner>/<repo>           # From GitHub\n/skill install clawhub:<name>           # From ClawHub\n/skill install linkai:<code>            # From LinkAI\n/skill install <url>                    # From URL (zip or SKILL.md)\n```\n\nList all available remote skills:\n\n```bash\n/skill list --remote\n```\n\n## Manage Skills\n\n```bash\n/skill list                  # List installed skills\n/skill info <name>           # View skill details\n/skill enable <name>         # Enable a skill\n/skill disable <name>        # Disable a skill\n/skill uninstall <name>      # Uninstall a skill\n```\n\n> In terminal, replace `/skill` with `cow skill`.\n\n## Skill Structure\n\n```\nskills/\n  my-skill/\n    SKILL.md          # Required: skill definition\n    scripts/          # Optional: bundled scripts\n    resources/        # Optional: reference files\n```\n\n`SKILL.md` uses YAML frontmatter:\n\n```markdown\n---\nname: my-skill\ndescription: Brief description of what the skill does\nmetadata: {\"cow\":{\"emoji\":\"🔧\",\"requires\":{\"bins\":[\"tool\"],\"env\":[\"API_KEY\"]}}}\n---\n\n# My Skill\n\nInstructions, examples, and usage patterns...\n```\n\n### Frontmatter Fields\n\n| Field | Description |\n|---|---|\n| `name` | Skill name (must match directory name) |\n| `description` | Brief description (required) |\n| `metadata.cow.emoji` | Display emoji |\n| `metadata.cow.always` | Always include this skill (default: false) |\n| `metadata.cow.requires.bins` | Required binaries |\n| `metadata.cow.requires.env` | Required environment variables |\n| `metadata.cow.requires.config` | Required config paths |\n| `metadata.cow.os` | Supported OS (e.g., `[\"darwin\", \"linux\"]`) |\n\n## Skill Loading Order\n\nSkills are loaded from two locations (higher precedence overrides lower):\n\n1. **Builtin skills** (lower): `<project_root>/skills/` — shipped with the codebase\n2. **Custom skills** (higher): `~/cow/skills/` — installed via `cow skill install` or skill creator\n\nSkills with the same name in the custom directory override builtin ones.\n\n## Create & Contribute\n\nSee the [Skill Creation docs](https://docs.cowagent.ai/skills/create) for details, or submit your skill to [Skill Hub](https://skills.cowagent.ai/submit).\n","skills/image-generation/SKILL.md":"---\nname: image-generation\ndescription: Generate or edit images from text prompts. Use when the user asks to create, draw, design, or edit an image, illustration, photo, icon, poster, or any visual content.\nmetadata:\n  cowagent:\n    requires:\n      anyEnv:\n        - OPENAI_API_KEY\n        - GEMINI_API_KEY\n        - ARK_API_KEY\n        - DASHSCOPE_API_KEY\n        - MINIMAX_API_KEY\n        - LINKAI_API_KEY\n---\n\n# Image Generation\n\nGenerate and edit images using AI models. The script automatically picks a backend based on which API keys are configured — **you don't need to specify a model unless the user explicitly names one**. Never guess or invent a `model`: when the user doesn't name one, omit `model` entirely so the configured default/provider is used.\n\nSupported models (passed via `model` only when the user asks for a specific one):\n\n- **OpenAI** — `gpt-image-2.5-flare` (recommended default: best quality/latency trade-off), `gpt-image-2.5-sunburst` (highest editing precision), `gpt-image-2`, `gpt-image-1`\n- **Gemini Nano Banana** — `nano-banana-2`, `nano-banana-pro`, `nano-banana`\n- **Seedream (Volcengine Ark)** — `seedream-5.0-lite`, `seedream-4.5`\n- **Qwen (DashScope)** — `qwen-image-2.0`, `qwen-image-2.0-pro`\n- **MiniMax** — `image-01`\n\n## Usage\n\nRun `scripts/generate.py` with a JSON argument. Use the absolute `<base_dir>` path — **do NOT `cd` into the skill directory**, since it is a builtin skill and gets reset on restart (anything written there is lost).\n\n```bash\npython <base_dir>/scripts/generate.py '<json_args>'\n```\n\nImages are saved to the workspace (or the open project dir) under `images/`, so they persist and stay reachable to the client.\n\n**Set bash timeout to at least 600 seconds**, as image generation can take 30–200s per provider, and the script may try multiple providers sequentially. Call it synchronously (do not run it in the background) and wait for its output in the same turn.\n\n### Parameters\n\n| Parameter | Type | Required | Default | Description |\n|-----------|------|----------|---------|-------------|\n| `prompt` | string | yes | — | Image description |\n| `image_url` | string / list | no | null | Input image(s) for editing: local file path or URL. Multi-image fusion is supported (pass a list) |\n| `quality` | string | no | auto | `low` / `medium` / `high` (only some backends honour this) |\n| `size` | string | no | auto | `512` / `1K` / `2K` / `3K` / `4K`, or pixel value (`1024x1024`) |\n| `aspect_ratio` | string | no | null | `1:1` / `3:2` / `2:3` / `16:9` / `9:16` / `21:9` (some backends also support extreme ratios like `1:4` / `8:1`) |\n\n**Higher `quality` and larger `size` cost more and run slower.** In normal cases, when the user does not explicitly specify, `low` or `medium` is sufficient. Only use `high` when the user asks for it.\n\n### Example — generate\n\n```bash\npython <base_dir>/scripts/generate.py '{\"prompt\": \"A corgi astronaut floating in space\"}'\n```\n\nWith aspect ratio:\n\n```bash\npython <base_dir>/scripts/generate.py '{\"prompt\": \"Isometric miniature city of Shanghai at sunset\", \"size\": \"2K\", \"aspect_ratio\": \"16:9\"}'\n```\n\n### Important: Editing vs Generating\n\nWhen the user asks to **edit, modify, or improve an existing image**, pass the original image via `image_url`. Prefer **local file paths** directly — the script handles file reading internally. Without `image_url`, the script generates a brand-new image instead of editing.\n\n### Example — edit (image-to-image)\n\n```bash\npython <base_dir>/scripts/generate.py '{\"prompt\": \"Add a Santa hat to the dog\", \"image_url\": \"/path/to/dog.png\"}'\n```\n\nMulti-image fusion — pass a list:\n\n```bash\npython <base_dir>/scripts/generate.py '{\"prompt\": \"Combine these characters into a group photo\", \"image_url\": [\"/path/a.png\", \"/path/b.png\"]}'\n```\n\n### Output\n\nPrints JSON to stdout:\n\n```json\n{\n  \"model\": \"doubao-seedream-5-0-260128\",\n  \"images\": [\n    {\"url\": \"/path/to/output.png\"}\n  ]\n}\n```\n\nAfter success, display the image to the user. You can either embed it in markdown (`![description](/path/to/output.png)`) or use the `send` tool.\n\nOn error:\n\n```json\n{\n  \"error\": \"error message\"\n}\n```\n\n### Setup\n\nThe script needs **at least one** of these API keys (set via `env_config` or `config.json`):\n\n`OPENAI_API_KEY` / `GEMINI_API_KEY` / `ARK_API_KEY` / `DASHSCOPE_API_KEY` / `MINIMAX_API_KEY` / `LINKAI_API_KEY`\n\nEach also has an optional `*_API_BASE` for custom endpoints. The script automatically picks the first configured backend and falls back to the next if it fails — no need to specify a model.\n\n### Error Handling\n\nIf the script returns an error after trying all configured backends, **do NOT retry with the same parameters** — the failure is almost always a configuration issue (wrong API key, unsupported API base). Tell the user to fix it via `env_config`, then retry.\n\n### Notes\n\n- HTTP timeout is 300s — high-resolution generation can take over 200s.\n- Omit `quality` / `size` to let the model pick automatically (`auto`).\n- Input images for editing are auto-compressed to ≤ 4MB / longest edge ≤ 4096px.\n","skills/knowledge-wiki/SKILL.md":"---\nname: knowledge-wiki\ndescription: Manage the personal knowledge wiki. Use when the user shares articles, documents, or asks to organize knowledge; when a conversation produces insights worth preserving as structured knowledge; or when the user asks about the knowledge base.\nmetadata:\n  cowagent:\n    always: true\n---\n\n# Knowledge Wiki\n\nMaintain a persistent, structured knowledge base in the `knowledge/` directory.\n\n## Core Operations\n\n### 1. Ingest — User shares an article, document, or resource\n\n1. Read and understand the source material\n2. Extract key facts, insights, and structured knowledge\n3. Determine the appropriate subdirectory:\n   - Read `knowledge/index.md` to see existing categories\n   - If a matching category exists, follow that structure\n   - If not, create a new subdirectory with a clear name\n4. Create the knowledge page: `knowledge/<category>/<slug>.md`\n5. Update `knowledge/index.md` and append to `knowledge/log.md`\n\n### 2. Synthesize — Conversation produces valuable structured knowledge\n\n1. Create a knowledge page under the appropriate category\n2. Update related pages with cross-references\n3. Update `knowledge/index.md` and `knowledge/log.md`\n\n### 3. Query — User asks about accumulated knowledge\n\n1. Check `knowledge/index.md` (already in your context) for relevant pages\n2. Read specific pages with the `read` tool\n3. Supplement with `memory_search` if needed\n\n## Page Format\n\n```markdown\n# Page Title\n\n> Source: <URL or description of the original material>\n\nContent here. Cross-reference related pages with markdown links:\n[Related Page](../category/related-page.md)\n\n## Key Points\n\n- ...\n\n## Related\n\n- [Page A](../category/page-a.md) — how it relates\n- [Page B](../category/page-b.md) — how it relates\n```\n\nThe `> Source:` line records where the knowledge came from (URL, document name, conversation, etc.). Always include it when the material originates from a specific source.\n\nCross-references build a knowledge graph. When creating or updating a page, link to related pages and update those pages to link back. **Only link to pages that already exist** — if a concept deserves its own page, create it first, then add the link.\n\n## Index Format (`knowledge/index.md`)\n\nFlat list, one line per page: `[Title](path) — one-line summary`. Group by category (matching subdirectories). No tables, no emoji.\n\n```markdown\n# Knowledge Index\n\n## Category A\n- [Page Title](category-a/page-slug.md) — one-line summary\n\n## Category B\n- [Page Title](category-b/page-slug.md) — one-line summary\n```\n\nCategory names and structure are flexible — follow whatever organization already exists in the index, or create new categories based on the content.\n\n## Log Format (`knowledge/log.md`)\n\nAppend-only, newest at bottom:\n\n```markdown\n## [YYYY-MM-DD] ingest | Page Title\n## [YYYY-MM-DD] synthesize | Page Title\n```\n\n## Guidelines\n\n- **File naming**: lowercase kebab-case (e.g. `machine-learning.md`)\n- **One topic per page**: link between pages rather than duplicating\n- **Update, don't duplicate**: if a page exists, update it\n- **Cross-reference**: every page should link to related pages; keep the knowledge graph connected\n- **Index is mandatory**: always update `knowledge/index.md` after any change\n- **Be concise**: capture essence, not copy entire sources\n- **Full paths in replies**: when referencing knowledge files in conversation replies, use the full path from workspace root (e.g. `[Title](knowledge/<category>/<slug>.md)`), not relative paths. Relative paths are only for cross-references inside knowledge pages themselves.\n- **Cite sources**: when answering based on knowledge pages, include links to the relevant pages so the user can explore further.\n","skills/skill-creator/SKILL.md":"---\nname: skill-creator\ndescription: Create, install, or update skills in the workspace. Use when (1) installing a skill from a URL or remote source, (2) creating a new skill from scratch, (3) updating or restructuring existing skills. Always use this skill for any skill installation or creation task.\nlicense: Complete terms in LICENSE.txt\n---\n\n# Skill Creator\n\nThis skill provides guidance for creating effective skills using the existing tool system.\n\n## About Skills\n\nSkills are modular, self-contained packages that extend the agent's capabilities by providing specialized knowledge, workflows, and tools. They transform a general-purpose agent into a specialized agent equipped with procedural knowledge.\n\n### What Skills Provide\n\n1. **Specialized workflows** - Multi-step procedures for specific domains\n2. **Tool integrations** - Instructions for working with specific file formats or APIs\n3. **Domain expertise** - Company-specific knowledge, schemas, business logic\n4. **Bundled resources** - Scripts, references, and assets for complex tasks\n\n### Core Principle\n\n**Concise is Key**: Only add context the agent doesn't already have. Challenge each piece of information: \"Does this justify its token cost?\" Prefer concise examples over verbose explanations.\n\n## Skill Structure\n\nEvery skill consists of a required SKILL.md file and optional bundled resources:\n\n```\nskill-name/\n├── SKILL.md (required)\n│   ├── YAML frontmatter metadata (required)\n│   │   ├── name: (required)\n│   │   └── description: (required)\n│   └── Markdown instructions (required)\n└── Bundled Resources (optional)\n    ├── scripts/          - Executable code (Python/Bash/etc.)\n    ├── references/       - Documentation intended to be loaded into context as needed\n    └── assets/           - Files used in output (templates, icons, fonts, etc.)\n```\n\n### SKILL.md Components\n\n**Frontmatter (YAML)** - Required fields:\n\n- **name**: Skill name in hyphen-case (e.g., `weather-api`, `pdf-editor`)\n- **description**: **CRITICAL** - Primary triggering mechanism\n  - Must clearly describe what the skill does\n  - Must explicitly state when to use it\n  - Include specific trigger scenarios and keywords\n  - All \"when to use\" info goes here, NOT in body\n  - Example: `\"PDF document processing with rotation, merging, splitting, and text extraction. Use when user needs to: (1) Rotate PDF pages, (2) Merge multiple PDFs, (3) Split PDF files, (4) Extract text from PDFs.\"`\n\n**Body (Markdown)** - Loaded after skill triggers:\n\n- Detailed usage instructions\n- How to call scripts and read references\n- Examples and best practices\n- Use imperative/infinitive form (\"Use X to do Y\")\n\n### Bundled Resources\n\n**scripts/** - When to include:\n- Code is repeatedly rewritten\n- Deterministic execution needed (avoid LLM randomness)\n- Examples: PDF rotation, image processing\n- Must test scripts before including\n\n**references/** - When to include:\n- **ONLY** when documentation is too large for SKILL.md (>500 lines)\n- Database schemas, complex API specs that agent needs to reference\n- Agent reads these files into context as needed\n- **NOT for**: API reference docs, usage examples, tutorials (put in SKILL.md instead)\n- **Rule of thumb**: If it fits in SKILL.md, don't create a separate reference file\n\n**assets/** - When to include:\n- Files used in output (not loaded to context)\n- Templates, icons, boilerplate code\n- Copied or modified in final output\n\n**Important**: Most skills don't need all three. Choose based on actual needs.\n\n### What NOT to Include\n\nDo NOT create auxiliary documentation files:\n- README.md - Instructions belong in SKILL.md\n- INSTALLATION_GUIDE.md - Setup info belongs in SKILL.md\n- CHANGELOG.md - Not needed for local skills\n- API_REFERENCE.md - Put API docs directly in SKILL.md\n- USAGE_EXAMPLES.md - Put examples directly in SKILL.md\n- Any other documentation files - Everything goes in SKILL.md unless it's too large\n\n**Critical Rule**: Only create files that the agent will actually execute (scripts) or that are too large for SKILL.md (references). Documentation, examples, and guides ALL belong in SKILL.md.\n\n## Installing a Skill\n\nInstall target directory: `<workspace>/skills/<name>/` (the `<workspace>` is from the \"Workspace\" section).\n\n### Step 1 — Obtain skill content\n\n| Source | Action |\n|---|---|\n| URL (single file) | Fetch content via curl or web_fetch |\n| URL (zip/archive) | Download and extract to a temp directory |\n| Local file (SKILL.md) | Read directly |\n| Local archive (zip) | Extract to a temp directory |\n\n### Step 2 — Identify and install\n\n1. Locate the SKILL.md (may be at top level or inside a subdirectory)\n2. Extract `name` from YAML frontmatter\n3. Copy the **entire skill directory** (SKILL.md and all sibling files/folders such as `references/`, `scripts/`, `assets/`, etc.) into `<workspace>/skills/<name>/`\n4. If an install/setup file exists (e.g. INSTALL.md), follow its instructions — the final result must still end up in `<workspace>/skills/<name>/`\n\n## Skill Creation Process (from scratch)\n\n1. **Understand** - Clarify use cases with concrete examples\n2. **Plan** - Identify needed scripts, references, assets\n3. **Initialize** - Run init_skill.py to create template\n4. **Edit** - Implement SKILL.md and resources\n5. **Validate** (optional) - Run quick_validate.py to check format\n6. **Iterate** - Improve based on real usage\n\n## Skill Naming\n\n- Use lowercase letters, digits, and hyphens only; normalize user-provided titles to hyphen-case (e.g., \"Plan Mode\" -> `plan-mode`).\n- When generating names, generate a name under 64 characters (letters, digits, hyphens).\n- Prefer short, verb-led phrases that describe the action.\n- Namespace by tool when it improves clarity or triggering (e.g., `gh-address-comments`, `linear-address-issue`).\n- Name the skill folder exactly after the skill name.\n\n## Step-by-Step Guide\n\n### Step 1: Understanding the Skill with Concrete Examples\n\nSkip this step only when the skill's usage patterns are already clearly understood. It remains valuable even when working with an existing skill.\n\nTo create an effective skill, clearly understand concrete examples of how the skill will be used. This understanding can come from either direct user examples or generated examples that are validated with user feedback.\n\nFor example, when building an image-editor skill, relevant questions include:\n\n- \"What functionality should the image-editor skill support? Editing, rotating, anything else?\"\n- \"Can you give some examples of how this skill would be used?\"\n- \"I can imagine users asking for things like 'Remove the red-eye from this image' or 'Rotate this image'. Are there other ways you imagine this skill being used?\"\n- \"What would a user say that should trigger this skill?\"\n\nTo avoid overwhelming users, avoid asking too many questions in a single message. Start with the most important questions and follow up as needed for better effectiveness.\n\nConclude this step when there is a clear sense of the functionality the skill should support.\n\n### Step 2: Planning the Reusable Skill Contents\n\nTo turn concrete examples into an effective skill, analyze each example by:\n\n1. Considering how to execute on the example from scratch\n2. Identifying what scripts, references, and assets would be helpful when executing these workflows repeatedly\n\n**Planning Checklist**:\n- ✅ **Always needed**: SKILL.md with clear description and usage instructions\n- ✅ **scripts/**: Only if code needs to be executed (not just shown as examples)\n- ❌ **references/**: Rarely needed - only if documentation is >500 lines and can't fit in SKILL.md\n- ✅ **assets/**: Only if files are used in output (templates, boilerplate, etc.)\n\nExample: When building a `pdf-editor` skill to handle queries like \"Help me rotate this PDF,\" the analysis shows:\n\n1. Rotating a PDF requires re-writing the same code each time\n2. A `scripts/rotate_pdf.py` script would be helpful to store in the skill\n3. ❌ Don't create `references/api-docs.md` - put API info in SKILL.md instead\n\nExample: When designing a `frontend-webapp-builder` skill for queries like \"Build me a todo app\" or \"Build me a dashboard to track my steps,\" the analysis shows:\n\n1. Writing a frontend webapp requires the same boilerplate HTML/React each time\n2. An `assets/hello-world/` template containing the boilerplate HTML/React project files would be helpful to store in the skill\n3. ❌ Don't create `references/usage-examples.md` - put examples in SKILL.md instead\n\nExample: When building a `big-query` skill to handle queries like \"How many users have logged in today?\" the analysis shows:\n\n1. Querying BigQuery requires re-discovering the table schemas and relationships each time\n2. A `references/schema.md` file documenting the table schemas would be helpful to store in the skill (ONLY because schemas are very large)\n3. ❌ Don't create separate `references/query-examples.md` - put examples in SKILL.md instead\n\nTo establish the skill's contents, analyze each concrete example to create a list of the reusable resources to include: scripts, references, and assets. **Default to putting everything in SKILL.md unless there's a compelling reason to separate it.**\n\n### Step 3: Initialize the Skill\n\nAt this point, it is time to actually create the skill.\n\nSkip this step only if the skill being developed already exists, and iteration is needed. In this case, continue to the next step.\n\nWhen creating a new skill from scratch, always run the `init_skill.py` script. The script conveniently generates a new template skill directory that automatically includes everything a skill requires, making the skill creation process much more efficient and reliable.\n\nUsage:\n\n```bash\nscripts/init_skill.py <skill-name> --path <output-directory> [--resources scripts,references,assets] [--examples]\n```\n\nExamples:\n\n```bash\nscripts/init_skill.py my-skill --path <workspace>/skills\nscripts/init_skill.py my-skill --path <workspace>/skills --resources scripts,references\nscripts/init_skill.py my-skill --path <workspace>/skills --resources scripts --examples\n```\n\nWhere `<workspace>` is your workspace directory shown in the \"Workspace\" section of the system prompt.\n\nThe script:\n\n- Creates the skill directory at the specified path\n- Generates a SKILL.md template with proper frontmatter and TODO placeholders\n- Optionally creates resource directories based on `--resources`\n- Optionally adds example files when `--examples` is set\n\nAfter initialization, customize the SKILL.md and add resources as needed. If you used `--examples`, replace or delete placeholder files.\n\n**Important**: Always create skills in workspace skills directory (`<workspace>/skills`), NOT in project directory. Check the \"Workspace\" section for the actual workspace path.\n\n### Step 4: Edit the Skill\n\nWhen editing the (newly-generated or existing) skill, remember that the skill is being created for another instance of the agent to use. Include information that would be beneficial and non-obvious to the agent. Consider what procedural knowledge, domain-specific details, or reusable assets would help another agent instance execute these tasks more effectively.\n\n#### Design Patterns\n\n**Workflow patterns** — For complex tasks, break operations into sequential steps or conditional branches:\n\n```markdown\n# Sequential: list numbered steps with scripts\n1. Analyze the form (run analyze_form.py)\n2. Create field mapping (edit fields.json)\n3. Fill the form (run fill_form.py)\n\n# Conditional: guide through decision points\n1. Determine the modification type:\n   **Creating new content?** → Follow \"Creation workflow\"\n   **Editing existing content?** → Follow \"Editing workflow\"\n```\n\n**Output patterns** — When consistent output format matters, provide a template or input/output examples in SKILL.md so the agent can follow the desired style.\n\n#### Start with Reusable Skill Contents\n\nTo begin implementation, start with the reusable resources identified above: `scripts/`, `references/`, and `assets/` files. Note that this step may require user input. For example, when implementing a `brand-guidelines` skill, the user may need to provide brand assets or templates to store in `assets/`, or documentation to store in `references/`.\n\n**Available Base Tools**:\n\nThe agent has access to these core tools that you can leverage in your skill:\n- **bash**: Execute shell commands (use for curl, ls, grep, sed, awk, bc for calculations, etc.)\n- **read**: Read file contents\n- **write**: Write files\n- **edit**: Edit files with search/replace\n\n**Minimize Dependencies**:\n- ✅ **Prefer bash + curl** for HTTP API calls (no Python dependencies)\n- ✅ **Use bash tools** (grep, sed, awk) for text processing\n- ✅ **Keep scripts simple** - if bash can do it, no need for Python (document packages/versions if Python is used)\n\n**Important Guidelines**:\n- **scripts/**: Only create scripts that will be executed. Test all scripts before including.\n- **references/**: ONLY create if documentation is too large for SKILL.md (>500 lines). Most skills don't need this.\n- **assets/**: Only include files used in output (templates, icons, etc.)\n- **Default approach**: Put everything in SKILL.md unless there's a specific reason not to.\n\nAdded scripts must be tested by actually running them to ensure there are no bugs and that the output matches what is expected. If there are many similar scripts, only a representative sample needs to be tested to ensure confidence that they all work while balancing time to completion.\n\nIf you used `--examples`, delete any placeholder files that are not needed for the skill. Only create resource directories that are actually required.\n\n#### Update SKILL.md\n\n**Writing Guidelines:** Always use imperative/infinitive form.\n\n##### Frontmatter\n\nWrite the YAML frontmatter with `name`, `description`, and optional `metadata`:\n\n- `name`: The skill name\n- `description`: This is the primary triggering mechanism for your skill, and helps the agent understand when to use the skill.\n  - Include both what the Skill does and specific triggers/contexts for when to use it.\n  - Include all \"when to use\" information here - Not in the body. The body is only loaded after triggering, so \"When to Use This Skill\" sections in the body are not helpful to the agent.\n  - Example description for a `docx` skill: \"Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. Use when the agent needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks\"\n- `metadata`: (Optional) Specify requirements and configuration\n  - `requires.bins`: Required binaries (e.g., `[\"curl\", \"jq\"]`)\n  - `requires.env`: Required environment variables — all must be set (e.g., `[\"MYAPI_KEY\"]`)\n  - `requires.anyEnv`: Alternative environment variables — at least one must be set (e.g., `[\"OPENAI_API_KEY\", \"LINKAI_API_KEY\"]`)\n  - `requires.anyBins`: Alternative binaries — at least one must be present\n  - `always`: Set to `true` to always load regardless of requirements\n  - `emoji`: Skill icon (optional)\n  - Do NOT set `category` — it defaults to `skill` and is managed by the system\n\n**API Key Requirements**:\n\nIf your skill needs a single API key, declare it in `requires.env`:\n\n```yaml\n---\nname: my-search\ndescription: Search using MyAPI\nmetadata:\n  requires:\n    bins: [\"curl\"]\n    env: [\"MYAPI_KEY\"]\n---\n```\n\nIf your skill supports multiple API key providers (e.g., OpenAI or LinkAI), use `requires.anyEnv`:\n\n```yaml\n---\nname: my-vision\ndescription: Analyze images using Vision API\nmetadata:\n  requires:\n    bins: [\"curl\"]\n    anyEnv: [\"OPENAI_API_KEY\", \"LINKAI_API_KEY\"]\n---\n```\n\n**Auto-enable rule**: Skills are automatically enabled when required environment variables are set, and automatically disabled when missing. No manual configuration needed.\n\n##### Body\n\nWrite instructions for using the skill and its bundled resources.\n\n**If your skill requires an API key**, include setup instructions in the body:\n\n```markdown\n## Setup\n\nThis skill requires an API key from [Service Name].\n\n1. Visit https://service.com to get an API key\n2. Configure it using: `env_config(action=\"set\", key=\"SERVICE_API_KEY\", value=\"your-key\")`\n3. Or manually add to `~/cow/.env`: `SERVICE_API_KEY=your-key`\n4. Restart the agent for changes to take effect\n\n## Usage\n...\n```\n\nThe bash script should check for the key and provide helpful error messages:\n\n```bash\n#!/usr/bin/env bash\nif [ -z \"${SERVICE_API_KEY:-}\" ]; then\n    echo \"Error: SERVICE_API_KEY not set\"\n    echo \"Please configure your API key first (see SKILL.md)\"\n    exit 1\nfi\n\ncurl -H \"Authorization: Bearer $SERVICE_API_KEY\" ...\n```\n\n**Script Path Convention**:\n\nWhen writing SKILL.md instructions, remember that:\n- Skills are listed in `<available_skills>` with a `<base_dir>` path\n- Scripts should be referenced as: `<base_dir>/scripts/script_name.sh`\n- The AI will see the base_dir and can construct the full path\n\nExample instruction in SKILL.md:\n```markdown\n## Usage\n\nScripts are in this skill's base directory (shown in skill listing).\n\nbash \"<base_dir>/scripts/my_script.sh\" <args>\n```\n\n### Step 5: Validate (Optional)\n\nValidate skill format:\n\n```bash\nscripts/quick_validate.py <path/to/skill-folder>\n```\n\nExample:\n\n```bash\nscripts/quick_validate.py <workspace>/skills/weather-api\n```\n\nValidation checks:\n- YAML frontmatter format and required fields\n- Skill naming conventions (hyphen-case, lowercase)\n- Description completeness and quality\n- File organization\n\n**Note**: Validation is optional in COW. Mainly useful for troubleshooting format issues.\n\n### Step 6: Iterate\n\nImprove based on real usage:\n\n1. Use skill on real tasks\n2. Notice struggles or inefficiencies\n3. Identify needed updates to SKILL.md or resources\n4. Implement changes and test again\n\n## Progressive Disclosure\n\nSkills use three-level loading:\n\n1. **Metadata** (name + description) - Always in context (~100 words)\n2. **SKILL.md body** - Loaded when skill triggers (<5k words)\n3. **Resources** - Loaded as needed by agent\n\n**Best practices**:\n- Keep SKILL.md under 500 lines\n- Split complex content into `references/` files\n- Reference these files clearly in SKILL.md\n\n**Pattern**: For skills with multiple variants/frameworks:\n- Keep core workflow in SKILL.md\n- Move variant-specific details to separate reference files\n- Agent loads only relevant files\n\nExample:\n```\ncloud-deploy/\n├── SKILL.md (workflow + provider selection)\n└── references/\n    ├── aws.md\n    ├── gcp.md\n    └── azure.md\n```\n\nWhen user chooses AWS, agent only reads aws.md.\n"},"files":{"agent/tools/scheduler/README.md":"# 定时任务工具 (Scheduler Tool)\n\n## 功能简介\n\n定时任务工具允许 Agent 创建、管理和执行定时任务，支持：\n\n- ⏰ **定时提醒**: 在指定时间发送消息\n- 🔄 **周期性任务**: 按固定间隔或 cron 表达式重复执行\n- 🔧 **动态工具调用**: 定时执行其他工具并发送结果（如搜索新闻、查询天气等）\n- 📋 **任务管理**: 查询、启用、禁用、删除任务\n\n## 安装依赖\n\n```bash\npip install croniter>=2.0.0\n```\n\n## 使用方法\n\n### 1. 创建定时任务\n\nAgent 可以通过自然语言创建定时任务，支持两种类型：\n\n#### 1.1 静态消息任务\n\n发送预定义的消息：\n\n**示例对话：**\n```\n用户: 每天早上9点提醒我开会\nAgent: [调用 scheduler 工具]\n      action: create\n      name: 每日开会提醒\n      message: 该开会了！\n      schedule_type: cron\n      schedule_value: 0 9 * * *\n```\n\n#### 1.2 动态工具调用任务\n\n定时执行工具并发送结果：\n\n**示例对话：**\n```\n用户: 每天早上8点帮我读取一下今日日程\nAgent: [调用 scheduler 工具]\n      action: create\n      name: 每日日程\n      tool_call:\n        tool_name: read\n        tool_params:\n          file_path: ~/cow/schedule.txt\n        result_prefix: 📅 今日日程\n      schedule_type: cron\n      schedule_value: 0 8 * * *\n```\n\n**工具调用参数说明：**\n- `tool_name`: 要调用的工具名称（如 `bash`、`read`、`write` 等内置工具）\n- `tool_params`: 工具的参数（字典格式）\n- `result_prefix`: 可选，在结果前添加的前缀文本\n\n**注意：** 如果要使用 skills（如 bocha-search），需要通过 `bash` 工具调用 skill 脚本\n\n### 2. 支持的调度类型\n\n#### Cron 表达式 (`cron`)\n使用标准 cron 表达式：\n\n```\n0 9 * * *      # 每天 9:00\n0 */2 * * *    # 每 2 小时\n30 8 * * 1-5   # 工作日 8:30\n0 0 1 * *      # 每月 1 号\n```\n\n#### 固定间隔 (`interval`)\n以秒为单位的间隔：\n\n```\n3600           # 每小时\n86400          # 每天\n1800           # 每 30 分钟\n```\n\n#### 一次性任务 (`once`)\n指定具体时间（ISO 格式）：\n\n```\n2024-12-25T09:00:00\n2024-12-31T23:59:59\n```\n\n### 3. 查询任务列表\n\n```\n用户: 查看我的定时任务\nAgent: [调用 scheduler 工具]\n      action: list\n```\n\n### 4. 查看任务详情\n\n```\n用户: 查看任务 abc123 的详情\nAgent: [调用 scheduler 工具]\n      action: get\n      task_id: abc123\n```\n\n### 5. 删除任务\n\n```\n用户: 删除任务 abc123\nAgent: [调用 scheduler 工具]\n      action: delete\n      task_id: abc123\n```\n\n### 6. 启用/禁用任务\n\n```\n用户: 暂停任务 abc123\nAgent: [调用 scheduler 工具]\n      action: disable\n      task_id: abc123\n\n用户: 恢复任务 abc123\nAgent: [调用 scheduler 工具]\n      action: enable\n      task_id: abc123\n```\n\n## 任务存储\n\n任务保存在 JSON 文件中：\n```\n~/cow/scheduler/tasks.json\n```\n\n任务数据结构：\n\n**静态消息任务：**\n```json\n{\n  \"id\": \"abc123\",\n  \"name\": \"每日提醒\",\n  \"enabled\": true,\n  \"created_at\": \"2024-01-01T10:00:00\",\n  \"updated_at\": \"2024-01-01T10:00:00\",\n  \"schedule\": {\n    \"type\": \"cron\",\n    \"expression\": \"0 9 * * *\"\n  },\n  \"action\": {\n    \"type\": \"send_message\",\n    \"content\": \"该开会了！\",\n    \"receiver\": \"wxid_xxx\",\n    \"receiver_name\": \"张三\",\n    \"is_group\": false,\n    \"channel_type\": \"wechat\"\n  },\n  \"next_run_at\": \"2024-01-02T09:00:00\",\n  \"last_run_at\": \"2024-01-01T09:00:00\"\n}\n```\n\n**动态工具调用任务：**\n```json\n{\n  \"id\": \"def456\",\n  \"name\": \"每日日程\",\n  \"enabled\": true,\n  \"created_at\": \"2024-01-01T10:00:00\",\n  \"updated_at\": \"2024-01-01T10:00:00\",\n  \"schedule\": {\n    \"type\": \"cron\",\n    \"expression\": \"0 8 * * *\"\n  },\n  \"action\": {\n    \"type\": \"tool_call\",\n    \"tool_name\": \"read\",\n    \"tool_params\": {\n      \"file_path\": \"~/cow/schedule.txt\"\n    },\n    \"result_prefix\": \"📅 今日日程\",\n    \"receiver\": \"wxid_xxx\",\n    \"receiver_name\": \"张三\",\n    \"is_group\": false,\n    \"channel_type\": \"wechat\"\n  },\n  \"next_run_at\": \"2024-01-02T08:00:00\"\n}\n```\n\n## 后台服务\n\n定时任务由后台服务 `SchedulerService` 管理：\n\n- 每 30 秒检查一次到期任务\n- 自动执行到期任务\n- 计算下次执行时间\n- 记录执行历史和错误\n\n服务在 Agent 初始化时自动启动，无需手动配置。\n\n## 接收者确定\n\n定时任务会发送给**创建任务时的对话对象**：\n\n- 如果在私聊中创建，发送给该用户\n- 如果在群聊中创建，发送到该群\n- 接收者信息在创建时自动保存\n\n## 常见用例\n\n### 1. 每日提醒（静态消息）\n```\n用户: 每天早上8点提醒我吃药\nAgent: ✅ 定时任务创建成功\n       任务ID: a1b2c3d4\n       调度: 每天 8:00\n       消息: 该吃药了！\n```\n\n### 2. 工作日提醒（静态消息）\n```\n用户: 工作日下午6点提醒我下班\nAgent: [创建 cron: 0 18 * * 1-5]\n       消息: 该下班了！\n```\n\n### 3. 倒计时提醒（静态消息）\n```\n用户: 1小时后提醒我\nAgent: [创建 interval: 3600]\n```\n\n### 4. 每日日程推送（动态工具调用）\n```\n用户: 每天早上8点帮我读取今日日程\nAgent: ✅ 定时任务创建成功\n       任务ID: schedule001\n       调度: 每天 8:00\n       工具: read(file_path='~/cow/schedule.txt')\n       前缀: 📅 今日日程\n```\n\n### 5. 定时文件备份（动态工具调用）\n```\n用户: 每天晚上11点备份工作文件\nAgent: [创建 cron: 0 23 * * *]\n       工具: bash(command='cp ~/cow/work.txt ~/cow/backup/work_$(date +%Y%m%d).txt')\n       前缀: ✅ 文件已备份\n```\n\n### 6. 周报提醒（静态消息）\n```\n用户: 每周五下午5点提醒我写周报\nAgent: [创建 cron: 0 17 * * 5]\n       消息: 📊 该写周报了！\n```\n\n### 4. 特定日期提醒\n```\n用户: 12月25日早上9点提醒我圣诞快乐\nAgent: [创建 once: 2024-12-25T09:00:00]\n```\n\n## 注意事项\n\n1. **时区**: 使用系统本地时区\n2. **精度**: 检查间隔为 30 秒，实际执行可能有 ±30 秒误差\n3. **持久化**: 任务保存在文件中，重启后自动恢复\n4. **一次性任务**: 执行后自动禁用，不会删除（可手动删除）\n5. **错误处理**: 执行失败会记录错误，不影响其他任务\n\n## 技术实现\n\n- **TaskStore**: 任务持久化存储\n- **SchedulerService**: 后台调度服务\n- **SchedulerTool**: Agent 工具接口\n- **Integration**: 与 AgentBridge 集成\n\n## 依赖\n\n- `croniter`: Cron 表达式解析（轻量级，仅 ~50KB）\n","plugins/README.md":"**Table of Content**\n\n- [插件化初衷](#插件化初衷)\n- [插件安装方法](#插件安装方法)\n- [插件化实现](#插件化实现)\n- [插件编写示例](#插件编写示例)\n- [插件设计建议](#插件设计建议)\n\n## 插件化初衷\n\n之前未插件化的代码耦合程度高，如果要定制一些个性化功能（如流量控制、接入`NovelAI`画图平台等），需要了解代码主体，避免影响到其他的功能。多个功能同时存在时，无法调整功能的优先级顺序，功能配置项也非常混乱。\n\n此时插件化应声而出。\n\n**插件化**: 在保证主体功能是ChatGPT的前提下，我们推荐将主体功能外的功能利用插件的方式实现。\n\n- [x] 可根据功能需要，下载不同插件。\n- [x] 插件开发成本低，仅需了解插件触发事件，并按照插件定义接口编写插件。\n- [x] 插件化能够自由开关和调整优先级。\n- [x] 每个插件可在插件文件夹内维护独立的配置文件，方便代码的测试和调试，可以在独立的仓库开发插件。\n\n## 插件安装方法\n\n在本仓库中预置了一些插件，如果要安装其他仓库的插件，有两种方法。\n\n- 第一种方法是在将下载的插件文件都解压到\"plugins\"文件夹的一个单独的文件夹，最终插件的代码都位于\"plugins/PLUGIN_NAME/*\"中。启动程序后，如果插件的目录结构正确，插件会自动被扫描加载。除此以外，注意你还需要安装文件夹中`requirements.txt`中的依赖。\n\n- 第二种方法是`Godcmd`插件，它是预置的管理员插件，能够让程序在运行时就能安装插件，它能够自动安装依赖。\n\n    安装插件的命令是\"#installp [仓库源](https://github.com/zhayujie/chatgpt-on-wechat/blob/master/plugins/source.json)记录的插件名/仓库地址\"。这是管理员命令，认证方法在[这里](https://github.com/zhayujie/chatgpt-on-wechat/tree/master/plugins/godcmd)。\n\n    - 安装[仓库源](https://github.com/zhayujie/chatgpt-on-wechat/blob/master/plugins/source.json)记录的插件：#installp sdwebui\n\n    - 安装指定仓库的插件：#installp https://github.com/lanvent/plugin_sdwebui.git\n\n    在安装之后，需要执行\"#scanp\"命令来扫描加载新安装的插件（或者重新启动程序）。\n\n安装插件后需要注意有些插件有自己的配置模板，一般要去掉\".template\"新建一个配置文件。\n\n## 插件化实现\n\n插件化实现是在收到消息到发送回复的各个步骤之间插入触发事件实现的。\n\n### 消息处理过程\n\n在了解插件触发事件前，首先需要了解程序收到消息到发送回复的整个过程。\n\n插件化版本中，消息处理过程可以分为4个步骤：\n```\n    1.收到消息 ---> 2.产生回复 ---> 3.包装回复 ---> 4.发送回复\n```\n\n以下是它们的默认处理逻辑(太长不看，可跳到[插件编写示例](#插件编写示例))：\n\n**注意以下包含的代码是`v1.1.0`中的片段，已过时，只可用于理解事件，最新的默认代码逻辑请参考[chat_channel](https://github.com/zhayujie/chatgpt-on-wechat/blob/master/channel/chat_channel.py)**\n\n#### 1. 收到消息\n\n负责接收用户消息，根据用户的配置，判断本条消息是否触发机器人。如果触发，则会判断该消息的类型（声音、文本、画图命令等），将消息包装成如下的`Context`交付给下一个步骤。\n\n```python\n    class ContextType (Enum):\n        TEXT = 1         # 文本消息\n        VOICE = 2        # 音频消息\n        IMAGE_CREATE = 3 # 创建图片命令\n    class Context:\n        def __init__(self, type : ContextType = None , content = None,  kwargs = dict()):\n            self.type = type\n            self.content = content\n            self.kwargs = kwargs\n        def __getitem__(self, key):\n            return self.kwargs[key]\n```\n\n`Context`中除了存放消息类型和内容外,还存放了一些与会话相关的参数。\n\n例如，当收到用户私聊消息时，会存放以下的会话参数。\n\n```python\n    context.kwargs = {'isgroup': False, 'msg': msg, 'receiver': other_user_id, 'session_id': other_user_id}\n```\n\n- `isgroup`: `Context`是否是群聊消息。\n- `msg`: the original message object from the channel.\n- `receiver`: 需要回复消息的对象ID。\n- `session_id`: 会话ID(一般是发送触发bot消息的用户ID，如果在群聊中并且`conf`里设置了`group_chat_in_one_session`，那么此处便是群聊ID)\n\n#### 2. 产生回复\n\n处理消息并产生回复。目前默认处理逻辑是根据`Context`的类型交付给对应的bot，并产生回复`Reply`。 如果本步骤没有产生任何回复，那么会跳过之后的所有步骤。\n\n```python\n    if context.type == ContextType.TEXT or context.type == ContextType.IMAGE_CREATE:\n        reply = super().build_reply_content(context.content, context) #文字跟画图交付给chatgpt\n    elif context.type == ContextType.VOICE: # 声音先进行语音转文字后，修改Context类型为文字后，再交付给chatgpt\n        cmsg = context['msg']\n        cmsg.prepare()\n        file_name = context.content\n        reply = super().build_voice_to_text(file_name)\n        if reply.type != ReplyType.ERROR and reply.type != ReplyType.INFO:\n            context.content = reply.content # 语音转文字后，将文字内容作为新的context\n            context.type = ContextType.TEXT\n            reply = super().build_reply_content(context.content, context)\n            if reply.type == ReplyType.TEXT:\n                if conf().get('voice_reply_voice'):\n                    reply = super().build_text_to_voice(reply.content)\n```\n\n回复`Reply`的定义如下所示，它允许Bot可以回复多类不同的消息。同时也加入了`INFO`和`ERROR`消息类型区分系统提示和系统错误。\n\n```python\n    class ReplyType(Enum):\n        TEXT = 1        # 文本\n        VOICE = 2       # 音频文件\n        IMAGE = 3       # 图片文件\n        IMAGE_URL = 4   # 图片URL\n\n        INFO = 9\n        ERROR = 10\n    class Reply:\n        def __init__(self, type : ReplyType = None , content = None):\n            self.type = type\n            self.content = content\n```\n\n#### 3. 装饰回复\n\n根据`Context`和回复`Reply`的类型，对回复的内容进行装饰。目前的装饰有以下两种:\n\n- `TEXT`文本回复:如果这次消息需要的回复是`VOICE`，进行文字转语音回复之后再次装饰。 否则根据是否在群聊中来决定是艾特接收方还是添加回复的前缀。\n\n- `INFO`或`ERROR`类型，会在消息前添加对应的系统提示字样。\n\n如下是默认逻辑的代码：\n\n```python\n    if reply.type == ReplyType.TEXT:\n        reply_text = reply.content\n        if context.get('desire_rtype') == ReplyType.VOICE:\n            reply = super().build_text_to_voice(reply.content)\n            return self._decorate_reply(context, reply)\n        if context['isgroup']:\n            reply_text = '@' +  context['msg'].actual_user_nickname + ' ' + reply_text.strip()\n            reply_text = conf().get(\"group_chat_reply_prefix\", \"\")+reply_text\n        else:\n            reply_text = conf().get(\"single_chat_reply_prefix\", \"\")+reply_text\n        reply.content = reply_text\n    elif reply.type == ReplyType.ERROR or reply.type == ReplyType.INFO:\n        reply.content = str(reply.type)+\":\\n\" + reply.content\n```\n\n#### 4. 发送回复\n\n根据`Reply`的类型，默认逻辑调用不同的发送函数发送回复给接收方`context[\"receiver\"]`。\n\n### 插件触发事件\n\n主程序目前会在各个消息步骤间触发事件，监听相应事件的插件会按照优先级，顺序调用事件处理函数。\n\n目前支持三类触发事件：\n```\n1.收到消息\n---> `ON_HANDLE_CONTEXT`\n2.产生回复\n---> `ON_DECORATE_REPLY`\n3.装饰回复\n---> `ON_SEND_REPLY`\n4.发送回复\n```\n\n触发事件会产生事件的上下文`EventContext`，它包含了以下信息:\n\n`EventContext(Event事件类型, {'channel' : 消息channel, 'context': Context, 'reply': Reply})`\n\n插件处理函数可通过修改`EventContext`中的`context`和`reply`来实现功能。\n\n## 插件编写示例\n\n以`plugins/hello`为例，其中编写了一个简单的`Hello`插件。\n\n### 1. 创建插件\n\n在`plugins`目录下创建一个插件文件夹`hello`。然后，在该文件夹中创建``__init__.py``文件，在``__init__.py``中将其他编写的模块文件导入。在程序启动时，插件管理器会读取``__init__.py``的所有内容。\n\n```\nplugins/\n└── hello\n    ├── __init__.py\n    └── hello.py\n```\n\n``__init__.py``的内容：\n```\nfrom .hello import *\n```\n\n### 2. 编写插件类\n\n在`hello.py`文件中，创建插件类，它继承自`Plugin`。\n\n在类定义之前需要使用`@plugins.register`装饰器注册插件，并填写插件的相关信息，其中`desire_priority`表示插件默认的优先级，越大优先级越高。初次加载插件后可在`plugins/plugins.json`中修改插件优先级。\n\n并在`__init__`中绑定你编写的事件处理函数。\n\n`Hello`插件为事件`ON_HANDLE_CONTEXT`绑定了一个处理函数`on_handle_context`，它表示之后每次生成回复前，都会由`on_handle_context`先处理。\n\nPS: `ON_HANDLE_CONTEXT`是最常用的事件，如果要根据不同的消息来生成回复，就用它。\n\n```python\n@plugins.register(name=\"Hello\", desc=\"A simple plugin that says hello\", version=\"0.1\", author=\"lanvent\", desire_priority= -1)\nclass Hello(Plugin):\n    def __init__(self):\n        super().__init__()\n        self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context\n        logger.info(\"[Hello] inited\")\n```\n\n### 3. 编写事件处理函数\n\n#### 修改事件上下文\n\n事件处理函数接收一个`EventContext`对象`e_context`作为参数。`e_context`包含了事件相关信息，利用`e_context['key']`来访问这些信息。\n\n`EventContext(Event事件类型, {'channel' : 消息channel, 'context': Context, 'reply': Reply})`\n\n处理函数中通过修改`e_context`对象中的事件相关信息来实现所需功能，比如更改`e_context['reply']`中的内容可以修改回复。\n\n#### 决定是否交付给下个插件或默认逻辑\n\n在处理函数结束时，还需要设置`e_context`对象的`action`属性，它决定如何继续处理事件。目前有以下三种处理方式：\n\n- `EventAction.CONTINUE`: 事件未结束，继续交给下个插件处理，如果没有下个插件，则交付给默认的事件处理逻辑。\n- `EventAction.BREAK`: 事件结束，不再给下个插件处理，交付给默认的处理逻辑。\n- `EventAction.BREAK_PASS`: 事件结束，不再给下个插件处理，跳过默认的处理逻辑。\n\n#### 示例处理函数\n\n`Hello`插件处理`Context`类型为`TEXT`的消息：\n\n- 如果内容是`Hello`，就将回复设置为`Hello+用户昵称`，并跳过之后的插件和默认逻辑。\n- 如果内容是`End`，就将`Context`的类型更改为`IMAGE_CREATE`，并让事件继续，如果最终交付到默认逻辑，会调用默认的画图Bot来画画。\n\n```python\n    def on_handle_context(self, e_context: EventContext):\n        if e_context['context'].type != ContextType.TEXT:\n            return\n        content = e_context['context'].content\n        if content == \"Hello\":\n            reply = Reply()\n            reply.type = ReplyType.TEXT\n            msg:ChatMessage = e_context['context']['msg']\n            if e_context['context']['isgroup']:\n                reply.content = f\"Hello, {msg.actual_user_nickname} from {msg.from_user_nickname}\"\n            else:\n                reply.content = f\"Hello, {msg.from_user_nickname}\"\n            e_context['reply'] = reply\n            e_context.action = EventAction.BREAK_PASS # 事件结束，并跳过处理context的默认逻辑\n        if content == \"End\":\n            # 如果是文本消息\"End\"，将请求转换成\"IMAGE_CREATE\"，并将content设置为\"The World\"\n            e_context['context'].type = ContextType.IMAGE_CREATE\n            content = \"The World\"\n            e_context.action = EventAction.CONTINUE  # 事件继续，交付给下个插件或默认逻辑\n```\n\n## 插件设计建议\n\n- 尽情将你想要的个性化功能设计为插件。\n- 一个插件目录建议只注册一个插件类。建议使用单独的仓库维护插件，便于更新。\n\n  在测试调试好后提交`PR`，把自己的仓库加入到[仓库源](https://github.com/zhayujie/chatgpt-on-wechat/blob/master/plugins/source.json)中。\n\n- 插件的config文件、使用说明`README.md`、`requirement.txt`等放置在插件目录中。\n- 默认优先级不要超过管理员插件`Godcmd`的优先级(999)，`Godcmd`插件提供了配置管理、插件管理等功能。\n","plugins/banwords/README.md":"\n## 插件描述\n\n简易的敏感词插件，暂不支持分词，请自行导入词库到插件文件夹中的`banwords.txt`，每行一个词，一个参考词库是[1](https://github.com/cjh0613/tencent-sensitive-words/blob/main/sensitive_words_lines.txt)。\n\n使用前将`config.json.template`复制为`config.json`，并自行配置。\n\n目前插件对消息的默认处理行为有如下两种：\n\n- `ignore` : 无视这条消息。\n- `replace` : 将消息中的敏感词替换成\"*\"，并回复违规。\n\n```json\n    \"action\": \"replace\",  \n    \"reply_filter\": true,\n    \"reply_action\": \"ignore\"\n```\n\n在以上配置项中：\n\n- `action`: 对用户消息的默认处理行为\n- `reply_filter`: 是否对ChatGPT的回复也进行敏感词过滤\n- `reply_action`: 如果开启了回复过滤，对回复的默认处理行为\n\n## 致谢\n\n搜索功能实现来自https://github.com/toolgood/ToolGood.Words","plugins/dungeon/README.md":"玩地牢游戏的聊天插件，触发方法如下：\n\n- `$开始冒险 <背景故事>` - 以<背景故事>开始一个地牢游戏，不填写会使用默认背景故事。之后聊天中你的所有消息会帮助ai完善这个故事。\n- `$停止冒险` - 停止一个地牢游戏，回归正常的ai。\n","plugins/godcmd/README.md":"## 插件说明\n\n指令插件\n\n## 插件使用\n\n将`config.json.template`复制为`config.json`，并修改其中`password`的值为口令。\n\n如果没有设置命令，在命令行日志中会打印出本次的临时口令，请注意观察，打印格式如下。\n\n```\n[INFO][2023-04-06 23:53:47][godcmd.py:165] - [Godcmd] 因未设置口令，本次的临时口令为0971。\n```\n\n在私聊中可使用`#auth`指令，输入口令进行管理员认证。更多详细指令请输入`#help`查看帮助文档：\n\n`#auth <口令>` - 管理员认证，仅可在私聊时认证。\n`#help` - 输出帮助文档，**是否是管理员**和是否是在群聊中会影响帮助文档的输出内容。\n","plugins/hello/README.md":"## 插件说明\n\n可以根据需求设置入群欢迎、群聊拍一拍、退群等消息的自定义提示词，也支持为每个群设置对应的固定欢迎语。\n\n该插件也是用户根据需求开发自定义插件的示例插件，参考[插件开发说明](https://github.com/zhayujie/chatgpt-on-wechat/tree/master/plugins)\n\n## 插件配置\n\n将 `plugins/hello` 目录下的 `config.json.template` 配置模板复制为最终生效的 `config.json`。 (如果未配置则会默认使用`config.json.template`模板中配置)。\n\n以下是插件配置项说明：\n\n```bash\n{\n    \"group_welc_fixed_msg\": {                   ## 这里可以为特定群里配置特定的固定欢迎语\n      \"群聊1\": \"群聊1的固定欢迎语\",\n      \"群聊2\": \"群聊2的固定欢迎语\"\n    },\n\n  \"group_welc_prompt\": \"请你随机使用一种风格说一句问候语来欢迎新用户\\\"{nickname}\\\"加入群聊。\",  ## 群聊随机欢迎语的提示词\n\n  \"group_exit_prompt\": \"请你随机使用一种风格跟其他群用户说他违反规则\\\"{nickname}\\\"退出群聊。\",  ## 移出群聊的提示词\n\n  \"patpat_prompt\": \"请你随机使用一种风格介绍你自己，并告诉用户输入#help可以查看帮助信息。\",  ## 群内拍一拍的提示词\n \n  \"use_character_desc\": false     ## 是否在Hello插件中使用LinkAI应用的系统设定\n}\n```\n\n\n注意：\n\n - 设置全局的用户进群固定欢迎语，可以在***项目根目录下***的`config.json`文件里，可以添加参数`\"group_welcome_msg\": \"\" `，参考 [#1482](https://github.com/zhayujie/chatgpt-on-wechat/pull/1482)\n - 为每个群设置固定的欢迎语，可以在`\"group_welc_fixed_msg\": {}`配置群聊名和对应的固定欢迎语，优先级高于全局固定欢迎语\n - 如果没有配置以上两个参数，则使用随机欢迎语，如需设定风格，语言等，修改`\"group_welc_prompt\": `即可\n - 如果使用LinkAI的服务，想在随机欢迎中结合LinkAI应用的设定，配置`\"use_character_desc\": true `\n - 实际 `config.json` 配置中应保证json格式，不应携带 '#' 及后面的注释\n - 如果是`docker`部署，可通过映射 `plugins/config.json` 到容器中来完成插件配置，参考[文档](https://github.com/zhayujie/chatgpt-on-wechat#3-%E6%8F%92%E4%BB%B6%E4%BD%BF%E7%94%A8)\n\n\n\n","plugins/keyword/README.md":"# 目的\n关键字匹配并回复\n\n# 试用场景\n目前是在微信公众号下面使用过。\n\n# 使用步骤\n1. 复制 `config.json.template` 为 `config.json`\n2. 在关键字 `keyword` 新增需要关键字匹配的内容\n3. 重启程序做验证\n\n# 验证结果\n![结果](test-keyword.png)","plugins/linkai/README.md":"## 插件说明\n\n基于 LinkAI 提供的知识库、Midjourney绘画、文档对话等能力对机器人的功能进行增强。平台地址: [https://link-ai.tech/console](https://link-ai.tech/console?utm_source=cowagent&utm_medium=readme&utm_campaign=plugin-linkai)\n\n## 插件配置\n\n将 `plugins/linkai` 目录下的 `config.json.template` 配置模板复制为最终生效的 `config.json`。 (如果未配置则会默认使用`config.json.template`模板中配置，但功能默认关闭，需要可通过指令进行开启)。\n\n以下是插件配置项说明：\n\n```bash\n{\n    \"group_app_map\": {               # 群聊 和 应用编码 的映射关系\n        \"测试群名称1\": \"default\",      # 表示在名称为 \"测试群名称1\" 的群聊中将使用app_code 为 default 的应用\n        \"测试群名称2\": \"Kv2fXJcH\"\n    },\n    \"midjourney\": {\n        \"enabled\": true,          # midjourney 绘画开关\n        \"auto_translate\": true,   # 是否自动将提示词翻译为英文\n        \"img_proxy\": true,        # 是否对生成的图片使用代理，如果你是国外服务器，将这一项设置为false会获得更快的生成速度\n        \"max_tasks\": 3,           # 支持同时提交的总任务个数\n        \"max_tasks_per_user\": 1,  # 支持单个用户同时提交的任务个数\n        \"use_image_create_prefix\": true   # 是否使用全局的绘画触发词，如果开启将同时支持由`config.json`中的 image_create_prefix 配置触发\n    },\n    \"summary\": {\n        \"enabled\": true,              # 文档总结和对话功能开关\n        \"group_enabled\": true,        # 是否支持群聊开启\n        \"max_file_size\": 5000,        # 文件的大小限制，单位KB，默认为5M，超过该大小直接忽略\n        \"type\": [\"FILE\", \"SHARING\", \"IMAGE\"]  # 支持总结的类型，分别表示 文件、分享链接、图片，其中文件和链接默认打开，图片默认关闭\n    }\n}\n```\n\n根目录 `config.json` 中配置，`API_KEY` 在 [控制台](https://link-ai.tech/console/interface?utm_source=cowagent&utm_medium=readme&utm_campaign=plugin-linkai) 中创建并复制过来:\n\n```bash\n\"linkai_api_key\": \"Link_xxxxxxxxx\"\n```\n\n注意：\n\n - 配置项中 `group_app_map` 部分是用于映射群聊与LinkAI平台上的应用， `midjourney` 部分是 mj 画图的配置，`summary` 部分是文档总结及对话功能的配置。三部分的配置相互独立，可按需开启\n - 实际 `config.json` 配置中应保证json格式，不应携带 '#' 及后面的注释\n - 如果是`docker`部署，可通过映射 `plugins/config.json` 到容器中来完成插件配置，参考[文档](https://github.com/zhayujie/chatgpt-on-wechat#3-%E6%8F%92%E4%BB%B6%E4%BD%BF%E7%94%A8)\n\n## 插件使用\n\n> 使用插件中的知识库管理功能需要首先开启`linkai`对话，依赖全局 `config.json` 中的 `use_linkai` 和 `linkai_api_key` 配置；而midjourney绘画 和 summary文档总结对话功能则只需填写 `linkai_api_key` 配置，`use_linkai` 无论是否关闭均可使用。具体可参考 [详细文档](https://link-ai.tech/platform/link-app/wechat?utm_source=cowagent&utm_medium=readme&utm_campaign=plugin-linkai)。\n\n完成配置后运行项目，会自动运行插件，输入 `#help linkai` 可查看插件功能。\n\n### 1.知识库管理功能\n\n提供在不同群聊使用不同应用的功能。可以在上述 `group_app_map` 配置中固定映射关系，也可以通过指令在群中快速完成切换。\n\n应用切换指令需要首先完成管理员 (`godcmd`) 插件的认证，然后按以下格式输入：\n\n`$linkai app {app_code}`\n\n例如输入 `$linkai app Kv2fXJcH`，即将当前群聊与 app_code为 Kv2fXJcH 的应用绑定。\n\n另外，还可以通过 `$linkai close` 来一键关闭linkai对话，此时就会使用默认的openai接口；同理，发送 `$linkai open` 可以再次开启。\n\n### 2.Midjourney绘画功能\n\n若未配置 `plugins/linkai/config.json`，默认会关闭画图功能，直接使用 `$mj open` 可基于默认配置直接使用mj画图。\n\n指令格式：\n\n```\n - 图片生成: $mj 描述词1, 描述词2..\n - 图片放大: $mju 图片ID 图片序号\n - 图片变换: $mjv 图片ID 图片序号\n - 重置: $mjr 图片ID\n```\n\n例如：\n\n```\n\"$mj a little cat, white --ar 9:16\"\n\"$mju 1105592717188272288 2\"\n\"$mjv 11055927171882 2\"\n\"$mjr 11055927171882\"\n```\n\n注意事项：\n1. 使用 `$mj open` 和 `$mj close` 指令可以快速打开和关闭绘图功能\n2. 海外环境部署请将 `img_proxy` 设置为 `false`\n3. 开启 `use_image_create_prefix` 配置后可直接复用全局画图触发词，以\"画\"开头便可以生成图片。\n4. 提示词内容中包含敏感词或者参数格式错误可能导致绘画失败，生成失败不消耗积分\n5. 若未收到图片可能有两种可能，一种是收到了图片但微信发送失败，可以在后台日志查看有没有获取到图片url，一般原因是受到了wx限制，可以稍后重试或更换账号尝试；另一种情况是图片提示词存在疑似违规，mj不会直接提示错误但会在画图后删掉原图导致程序无法获取，这种情况不消耗积分。\n\n### 3.文档总结对话功能\n\n#### 配置\n\n该功能依赖 LinkAI的知识库及对话功能，需要在项目根目录的config.json中设置 `linkai_api_key`， 同时根据上述插件配置说明，在插件config.json添加 `summary` 部分的配置，设置 `enabled` 为 true。\n\n如果不想创建 `plugins/linkai/config.json` 配置，可以直接通过 `$linkai sum open` 指令开启该功能。\n\n也可以通过私聊(全局 `config.json` 中的 `linkai_app_code`)或者群聊绑定(通过`group_app_map`参数配置)的应用来开启该功能：在LinkAI平台 [应用配置](https://link-ai.tech/console/factory?utm_source=cowagent&utm_medium=readme&utm_campaign=plugin-linkai) 里添加并开启**内容总结**插件。\n\n#### 使用\n\n功能开启后，向机器人发送 **文件**、 **分享链接卡片**、**图片** 即可生成摘要，进一步可以与文件或链接的内容进行多轮对话。如果需要关闭某种类型的内容总结，设置 `summary`配置中的type字段即可。\n\n#### 限制\n\n 1. 文件目前 支持 `txt`, `docx`, `pdf`, `md`, `csv`格式，文件大小由 `max_file_size` 限制，最大不超过15M，文件字数最多可支持百万字的文件。但不建议上传字数过多的文件，一是token消耗过大，二是摘要很难覆盖到全部内容，只能通过多轮对话来了解细节。\n 2. 分享链接 目前仅支持 公众号文章，后续会支持更多文章类型及视频链接等\n 3. 总结及对话的 费用与 LinkAI 3.5-4K 模型的计费方式相同，按文档内容的tokens进行计算\n","plugins/role/README.md":"用于让Bot扮演指定角色的聊天插件，触发方法如下：\n\n- `$角色/$role help/帮助` - 打印目前支持的角色列表。\n- `$角色/$role <角色名>` - 让AI扮演该角色，角色名支持模糊匹配。\n- `$停止扮演` - 停止角色扮演。\n\n## 目录结构\n\n```\nplugins/role/\n├── README.md\n├── __init__.py\n├── role.py                  # 插件主逻辑\n├── roles.json               # 内置角色库（所有默认角色）\n├── schema/\n│   └── role_template.json   # 角色模板，新增角色时复制此文件\n└── roles/                   # 可选：放自定义角色文件，自动加载\n    └── 我的角色.json         # 同title会覆盖内置角色，不同则追加\n```\n\n## 添加自定义角色\n\n1. 新建roles目录\n2. 复制 下面模板 到 `roles/` 目录并重命名（如 `我的角色.json`）。\n3. 编辑文件内容，填写角色信息。\n4. 重启Bot即可生效，插件会自动扫描 `roles/` 目录下的所有 `.json` 文件。\n\n> **覆盖规则**：如果自定义角色的 `title` 与内置角色同名，则覆盖内置角色；否则作为新角色追加。无需修改任何映射文件。\n\n(大部分prompt来自https://github.com/rockbenben/ChatGPT-Shortcut/blob/main/src/data/users.tsx)\n\n以下为角色文件内容例子:\n```json\n{\n  \"title\": \"写作助理\",\n  \"description\": \"As a writing improvement assistant...\",\n  \"descn\": \"作为一名中文写作改进助理...\",\n  \"wrapper\": \"内容是:\\n\\\"%s\\\"\",\n  \"remark\": \"最常使用的角色，用于优化文本的语法、清晰度和简洁度，提高可读性。\",\n  \"tags\": [\"favorite\", \"write\"]\n}\n```\n\n- `title`: 角色名。\n- `description`: 使用`$role`触发时，使用英语prompt。\n- `descn`: 使用`$角色`触发时，使用中文prompt。\n- `wrapper`: 用于包装用户消息，可起到强调作用，避免回复离题。\n- `remark`: 简短描述该角色，在打印帮助文档时显示。\n- `tags`: 角色分类标签，可用`$角色类型 <标签>`查看。\n\n\n```json\n{\n  \"title\": \"\",\n  \"description\": \"\",\n  \"descn\": \"\",\n  \"wrapper\": \"\",\n  \"remark\": \"\",\n  \"tags\": []\n}\n```","plugins/tool/README.md":"## 插件描述\n一个能让chatgpt联网，搜索，数字运算的插件，将赋予强大且丰富的扩展能力   \n使用说明(默认trigger_prefix为$)：  \n```text\n#help tool: 查看tool帮助信息，可查看已加载工具列表  \n$tool 工具名 命令: （pure模式）根据给出的{命令}使用指定 一个 可用工具尽力为你得到结果。\n$tool 命令: （多工具模式）根据给出的{命令}使用 一些 可用工具尽力为你得到结果。  \n$tool reset: 重置工具。  \n```\n### 本插件所有工具同步存放至专用仓库：[chatgpt-tool-hub](https://github.com/goldfishh/chatgpt-tool-hub)\n\n2024.01.16更新\n1. 新增工具pure模式，支持单个工具调用\n2. 新增消息转发工具：email, sms, wechat, 可以根据规则向其他平台发送消息\n3. 替换visual-dl（更名为visual）实现，目前识别图片链接效果较好。\n4. 修复了0.4版本大部分工具返回结果不可靠问题\n\n新版本工具名共19个，不一一列举，相应工具需要的环境参数见`tool.py`里的`_build_tool_kwargs`函数\n\n## 使用说明\n使用该插件后将默认使用4个工具, 无需额外配置长期生效：\n### 1. python\n###### python解释器，使用它来解释执行python指令，可以配合你想要chatgpt生成的代码输出结果或执行事务\n\n### 2. 访问网页的工具汇总(默认url-get)\n\n#### 2.1 url-get\n###### 往往用来获取某个网站具体内容，结果可能会被反爬策略影响\n\n#### 2.2 browser\n###### 浏览器，功能与2.1类似，但能更好模拟，不会被识别为爬虫影响获取网站内容\n\n> 注1：url-get默认配置、browser需额外配置，browser依赖google-chrome，你需要提前安装好\n\n> 注2：（可通过`browser_use_summary`或 `url_get_use_summary`开关）当检测到长文本时会进入summary tool总结长文本，tokens可能会大量消耗！\n\n这是debian端安装google-chrome教程，其他系统请自行查找\n> https://www.linuxjournal.com/content/how-can-you-install-google-browser-debian\n\n### 3. terminal\n###### 在你运行的电脑里执行shell命令，可以配合你想要chatgpt生成的代码使用，给予自然语言控制手段\n\n> terminal调优记录：https://github.com/zhayujie/chatgpt-on-wechat/issues/776#issue-1659347640\n\n### 4. meteo\n###### 回答你有关天气的询问, 需要获取时间、地点上下文信息，本工具使用了[meteo open api](https://open-meteo.com/)\n注：该工具需要较高的对话技巧，不保证你问的任何问题均能得到满意的回复\n注2：当前版本可只使用这个工具，返回结果较可控。\n\n> meteo调优记录：https://github.com/zhayujie/chatgpt-on-wechat/issues/776#issuecomment-1500771334\n\n## 使用本插件对话（prompt）技巧\n### 1. 有指引的询问\n#### 例如：\n- 总结这个链接的内容 https://github.com/goldfishh/chatgpt-tool-hub\n- 使用Terminal执行curl cip.cc\n- 使用python查询今天日期\n\n### 2. 使用搜索引擎工具\n- 如果有搜索工具就能让chatgpt获取到你的未传达清楚的上下文信息，比如chatgpt不知道你的地理位置，现在时间等，所以无法查询到天气\n\n## 其他工具\n\n### 5. wikipedia\n###### 可以回答你想要知道确切的人事物\n\n### 6. news 新闻类工具集合\n\n> news更新：0.4版本对新闻类工具做了整合，配置文件只要加入`news`一个工具名就会自动加载所有新闻类工具\n\n#### 6.1. news-api *\n###### 从全球 80,000 多个信息源中获取当前和历史新闻文章\n\n#### 6.2. morning-news *\n###### 每日60秒早报，每天凌晨一点更新，本工具使用了[alapi-每日60秒早报](https://alapi.cn/api/view/93)\n\n> 该tool每天返回内容相同\n\n#### 6.3. finance-news\n###### 获取实时的金融财政新闻\n\n> 该工具需要用到browser工具解决反爬问题\n\n\n### 7. bing-search *\n###### bing搜索引擎，从此你不用再烦恼搜索要用哪些关键词\n\n### 8. wolfram-alpha *\n###### 知识搜索引擎、科学问答系统，常用于专业学科计算\n\n### 9. google-search *\n###### google搜索引擎，申请流程较bing-search繁琐\n\n### 10. arxiv\n###### 用于查找论文\n\n```text\n可配置参数：\n1. arxiv_summary: 是否使用总结工具，默认true, 当为false时会直接返回论文的标题、作者、发布时间、摘要、分类、备注、pdf链接等内容\n```\n\n> 0.4.2更新，例子：帮我找一篇吴恩达写的论文\n\n### 11. summary\n###### 总结工具，该工具可以支持输入url\n\n> 该工具目前是和其他工具配合使用，暂未测试单独使用效果\n\n### 12. visual\n###### 将图片转换成文字，底层调用ali dashscope `qwen-vl-plus`模型\n\n### 13. searxng-search *\n###### 一个私有化的搜索引擎工具\n\n> 安装教程：https://docs.searxng.org/admin/installation.html\n\n### 14. email *\n###### 发送邮件\n\n### 15. sms *\n###### 发送短信\n\n### 16. stt *\n###### speak to text 语音识别\n\n### 17. tts *\n###### text to speak 文生语音\n\n### 18. wechat *\n###### 向好友、群组发送微信\n\n---\n\n###### 注1：带*工具需要获取api-key才能使用(在config.json内的kwargs添加项)，部分工具需要外网支持  \n## [工具的api申请方法](https://github.com/goldfishh/chatgpt-tool-hub/blob/master/docs/apply_optional_tool.md)\n\n## config.json 配置说明\n###### 默认工具无需配置，其它工具需手动配置，以增加morning-news和bing-search两个工具为例：\n```json\n{\n  \"tools\": [\"bing-search\", \"morning-news\", \"你想要添加的其他工具\"],  // 填入你想用到的额外工具名，这里加入了工具\"bing-search\"和工具\"morning-news\"\n  \"kwargs\": {\n      \"debug\": true, // 当你遇到问题求助时，需要配置\n      \"request_timeout\": 120,  // openai接口超时时间\n      \"no_default\": false,  // 是否不使用默认的4个工具\n      \"bing_subscription_key\": \"4871f273a4804743\",//带*工具需要申请api-key，这里填入了工具bing-search对应的api，api_name参考前述`工具的api申请方法`\n      \"morning_news_api_key\": \"5w1kjNh9VQlUc\",// 这里填入了morning-news对应的api，\n  }\n}\n\n```\n注：config.json文件非必须，未创建仍可使用本tool；带*工具需在kwargs填入对应api-key键值对  \n- `tools`：本插件初始化时加载的工具, 上述一级标题即是对应工具名称，带*工具必须在kwargs中配置相应api-key\n- `kwargs`：工具执行时的配置，一般在这里存放**api-key**，或环境配置\n  - `debug`: 输出chatgpt-tool-hub额外信息用于调试\n  - `request_timeout`: 访问openai接口的超时时间，默认与wechat-on-chatgpt配置一致，可单独配置\n  - `no_default`: 用于配置默认加载4个工具的行为，如果为true则仅使用tools列表工具，不加载默认工具\n  - `model_name`: 用于控制tool插件底层使用的llm模型，目前暂未测试3.5以外的模型，一般保持默认\n\n---\n\n## 备注\n- 强烈建议申请搜索工具搭配使用，推荐bing-search\n- 虽然我会有意加入一些限制，但请不要使用本插件做危害他人的事情，请提前了解清楚某些内容是否会违反相关规定，建议提前做好过滤\n- 如有本插件问题，请将debug设置为true无上下文重新问一遍，如仍有问题请访问[chatgpt-tool-hub](https://github.com/goldfishh/chatgpt-tool-hub)建个issue，将日志贴进去，我无法处理不能复现的问题\n- 欢迎 star & 宣传，有能力请提pr\n","skills/README.md":"# Skills\n\nSkills are reusable instruction sets that extend the agent's capabilities. Each skill is a `SKILL.md` file in its own directory, providing specialized knowledge, workflows, and tool integrations for specific tasks.\n\n## Skill Hub\n\nBrowse, search, and install skills from [Cow Skill Hub](https://skills.cowagent.ai/).\n\nOpen source: [github.com/zhayujie/cow-skill-hub](https://github.com/zhayujie/cow-skill-hub)\n\n## Install Skills\n\nInstall skills from multiple sources via chat (`/skill`) or terminal (`cow skill`):\n\n```bash\n/skill install <name>                   # From Skill Hub\n/skill install <owner>/<repo>           # From GitHub\n/skill install clawhub:<name>           # From ClawHub\n/skill install linkai:<code>            # From LinkAI\n/skill install <url>                    # From URL (zip or SKILL.md)\n```\n\nList all available remote skills:\n\n```bash\n/skill list --remote\n```\n\n## Manage Skills\n\n```bash\n/skill list                  # List installed skills\n/skill info <name>           # View skill details\n/skill enable <name>         # Enable a skill\n/skill disable <name>        # Disable a skill\n/skill uninstall <name>      # Uninstall a skill\n```\n\n> In terminal, replace `/skill` with `cow skill`.\n\n## Skill Structure\n\n```\nskills/\n  my-skill/\n    SKILL.md          # Required: skill definition\n    scripts/          # Optional: bundled scripts\n    resources/        # Optional: reference files\n```\n\n`SKILL.md` uses YAML frontmatter:\n\n```markdown\n---\nname: my-skill\ndescription: Brief description of what the skill does\nmetadata: {\"cow\":{\"emoji\":\"🔧\",\"requires\":{\"bins\":[\"tool\"],\"env\":[\"API_KEY\"]}}}\n---\n\n# My Skill\n\nInstructions, examples, and usage patterns...\n```\n\n### Frontmatter Fields\n\n| Field | Description |\n|---|---|\n| `name` | Skill name (must match directory name) |\n| `description` | Brief description (required) |\n| `metadata.cow.emoji` | Display emoji |\n| `metadata.cow.always` | Always include this skill (default: false) |\n| `metadata.cow.requires.bins` | Required binaries |\n| `metadata.cow.requires.env` | Required environment variables |\n| `metadata.cow.requires.config` | Required config paths |\n| `metadata.cow.os` | Supported OS (e.g., `[\"darwin\", \"linux\"]`) |\n\n## Skill Loading Order\n\nSkills are loaded from two locations (higher precedence overrides lower):\n\n1. **Builtin skills** (lower): `<project_root>/skills/` — shipped with the codebase\n2. **Custom skills** (higher): `~/cow/skills/` — installed via `cow skill install` or skill creator\n\nSkills with the same name in the custom directory override builtin ones.\n\n## Create & Contribute\n\nSee the [Skill Creation docs](https://docs.cowagent.ai/skills/create) for details, or submit your skill to [Skill Hub](https://skills.cowagent.ai/submit).\n","skills/image-generation/SKILL.md":"---\nname: image-generation\ndescription: Generate or edit images from text prompts. Use when the user asks to create, draw, design, or edit an image, illustration, photo, icon, poster, or any visual content.\nmetadata:\n  cowagent:\n    requires:\n      anyEnv:\n        - OPENAI_API_KEY\n        - GEMINI_API_KEY\n        - ARK_API_KEY\n        - DASHSCOPE_API_KEY\n        - MINIMAX_API_KEY\n        - LINKAI_API_KEY\n---\n\n# Image Generation\n\nGenerate and edit images using AI models. The script automatically picks a backend based on which API keys are configured — **you don't need to specify a model unless the user explicitly names one**. Never guess or invent a `model`: when the user doesn't name one, omit `model` entirely so the configured default/provider is used.\n\nSupported models (passed via `model` only when the user asks for a specific one):\n\n- **OpenAI** — `gpt-image-2.5-flare` (recommended default: best quality/latency trade-off), `gpt-image-2.5-sunburst` (highest editing precision), `gpt-image-2`, `gpt-image-1`\n- **Gemini Nano Banana** — `nano-banana-2`, `nano-banana-pro`, `nano-banana`\n- **Seedream (Volcengine Ark)** — `seedream-5.0-lite`, `seedream-4.5`\n- **Qwen (DashScope)** — `qwen-image-2.0`, `qwen-image-2.0-pro`\n- **MiniMax** — `image-01`\n\n## Usage\n\nRun `scripts/generate.py` with a JSON argument. Use the absolute `<base_dir>` path — **do NOT `cd` into the skill directory**, since it is a builtin skill and gets reset on restart (anything written there is lost).\n\n```bash\npython <base_dir>/scripts/generate.py '<json_args>'\n```\n\nImages are saved to the workspace (or the open project dir) under `images/`, so they persist and stay reachable to the client.\n\n**Set bash timeout to at least 600 seconds**, as image generation can take 30–200s per provider, and the script may try multiple providers sequentially. Call it synchronously (do not run it in the background) and wait for its output in the same turn.\n\n### Parameters\n\n| Parameter | Type | Required | Default | Description |\n|-----------|------|----------|---------|-------------|\n| `prompt` | string | yes | — | Image description |\n| `image_url` | string / list | no | null | Input image(s) for editing: local file path or URL. Multi-image fusion is supported (pass a list) |\n| `quality` | string | no | auto | `low` / `medium` / `high` (only some backends honour this) |\n| `size` | string | no | auto | `512` / `1K` / `2K` / `3K` / `4K`, or pixel value (`1024x1024`) |\n| `aspect_ratio` | string | no | null | `1:1` / `3:2` / `2:3` / `16:9` / `9:16` / `21:9` (some backends also support extreme ratios like `1:4` / `8:1`) |\n\n**Higher `quality` and larger `size` cost more and run slower.** In normal cases, when the user does not explicitly specify, `low` or `medium` is sufficient. Only use `high` when the user asks for it.\n\n### Example — generate\n\n```bash\npython <base_dir>/scripts/generate.py '{\"prompt\": \"A corgi astronaut floating in space\"}'\n```\n\nWith aspect ratio:\n\n```bash\npython <base_dir>/scripts/generate.py '{\"prompt\": \"Isometric miniature city of Shanghai at sunset\", \"size\": \"2K\", \"aspect_ratio\": \"16:9\"}'\n```\n\n### Important: Editing vs Generating\n\nWhen the user asks to **edit, modify, or improve an existing image**, pass the original image via `image_url`. Prefer **local file paths** directly — the script handles file reading internally. Without `image_url`, the script generates a brand-new image instead of editing.\n\n### Example — edit (image-to-image)\n\n```bash\npython <base_dir>/scripts/generate.py '{\"prompt\": \"Add a Santa hat to the dog\", \"image_url\": \"/path/to/dog.png\"}'\n```\n\nMulti-image fusion — pass a list:\n\n```bash\npython <base_dir>/scripts/generate.py '{\"prompt\": \"Combine these characters into a group photo\", \"image_url\": [\"/path/a.png\", \"/path/b.png\"]}'\n```\n\n### Output\n\nPrints JSON to stdout:\n\n```json\n{\n  \"model\": \"doubao-seedream-5-0-260128\",\n  \"images\": [\n    {\"url\": \"/path/to/output.png\"}\n  ]\n}\n```\n\nAfter success, display the image to the user. You can either embed it in markdown (`![description](/path/to/output.png)`) or use the `send` tool.\n\nOn error:\n\n```json\n{\n  \"error\": \"error message\"\n}\n```\n\n### Setup\n\nThe script needs **at least one** of these API keys (set via `env_config` or `config.json`):\n\n`OPENAI_API_KEY` / `GEMINI_API_KEY` / `ARK_API_KEY` / `DASHSCOPE_API_KEY` / `MINIMAX_API_KEY` / `LINKAI_API_KEY`\n\nEach also has an optional `*_API_BASE` for custom endpoints. The script automatically picks the first configured backend and falls back to the next if it fails — no need to specify a model.\n\n### Error Handling\n\nIf the script returns an error after trying all configured backends, **do NOT retry with the same parameters** — the failure is almost always a configuration issue (wrong API key, unsupported API base). Tell the user to fix it via `env_config`, then retry.\n\n### Notes\n\n- HTTP timeout is 300s — high-resolution generation can take over 200s.\n- Omit `quality` / `size` to let the model pick automatically (`auto`).\n- Input images for editing are auto-compressed to ≤ 4MB / longest edge ≤ 4096px.\n","skills/knowledge-wiki/SKILL.md":"---\nname: knowledge-wiki\ndescription: Manage the personal knowledge wiki. Use when the user shares articles, documents, or asks to organize knowledge; when a conversation produces insights worth preserving as structured knowledge; or when the user asks about the knowledge base.\nmetadata:\n  cowagent:\n    always: true\n---\n\n# Knowledge Wiki\n\nMaintain a persistent, structured knowledge base in the `knowledge/` directory.\n\n## Core Operations\n\n### 1. Ingest — User shares an article, document, or resource\n\n1. Read and understand the source material\n2. Extract key facts, insights, and structured knowledge\n3. Determine the appropriate subdirectory:\n   - Read `knowledge/index.md` to see existing categories\n   - If a matching category exists, follow that structure\n   - If not, create a new subdirectory with a clear name\n4. Create the knowledge page: `knowledge/<category>/<slug>.md`\n5. Update `knowledge/index.md` and append to `knowledge/log.md`\n\n### 2. Synthesize — Conversation produces valuable structured knowledge\n\n1. Create a knowledge page under the appropriate category\n2. Update related pages with cross-references\n3. Update `knowledge/index.md` and `knowledge/log.md`\n\n### 3. Query — User asks about accumulated knowledge\n\n1. Check `knowledge/index.md` (already in your context) for relevant pages\n2. Read specific pages with the `read` tool\n3. Supplement with `memory_search` if needed\n\n## Page Format\n\n```markdown\n# Page Title\n\n> Source: <URL or description of the original material>\n\nContent here. Cross-reference related pages with markdown links:\n[Related Page](../category/related-page.md)\n\n## Key Points\n\n- ...\n\n## Related\n\n- [Page A](../category/page-a.md) — how it relates\n- [Page B](../category/page-b.md) — how it relates\n```\n\nThe `> Source:` line records where the knowledge came from (URL, document name, conversation, etc.). Always include it when the material originates from a specific source.\n\nCross-references build a knowledge graph. When creating or updating a page, link to related pages and update those pages to link back. **Only link to pages that already exist** — if a concept deserves its own page, create it first, then add the link.\n\n## Index Format (`knowledge/index.md`)\n\nFlat list, one line per page: `[Title](path) — one-line summary`. Group by category (matching subdirectories). No tables, no emoji.\n\n```markdown\n# Knowledge Index\n\n## Category A\n- [Page Title](category-a/page-slug.md) — one-line summary\n\n## Category B\n- [Page Title](category-b/page-slug.md) — one-line summary\n```\n\nCategory names and structure are flexible — follow whatever organization already exists in the index, or create new categories based on the content.\n\n## Log Format (`knowledge/log.md`)\n\nAppend-only, newest at bottom:\n\n```markdown\n## [YYYY-MM-DD] ingest | Page Title\n## [YYYY-MM-DD] synthesize | Page Title\n```\n\n## Guidelines\n\n- **File naming**: lowercase kebab-case (e.g. `machine-learning.md`)\n- **One topic per page**: link between pages rather than duplicating\n- **Update, don't duplicate**: if a page exists, update it\n- **Cross-reference**: every page should link to related pages; keep the knowledge graph connected\n- **Index is mandatory**: always update `knowledge/index.md` after any change\n- **Be concise**: capture essence, not copy entire sources\n- **Full paths in replies**: when referencing knowledge files in conversation replies, use the full path from workspace root (e.g. `[Title](knowledge/<category>/<slug>.md)`), not relative paths. Relative paths are only for cross-references inside knowledge pages themselves.\n- **Cite sources**: when answering based on knowledge pages, include links to the relevant pages so the user can explore further.\n","skills/skill-creator/SKILL.md":"---\nname: skill-creator\ndescription: Create, install, or update skills in the workspace. Use when (1) installing a skill from a URL or remote source, (2) creating a new skill from scratch, (3) updating or restructuring existing skills. Always use this skill for any skill installation or creation task.\nlicense: Complete terms in LICENSE.txt\n---\n\n# Skill Creator\n\nThis skill provides guidance for creating effective skills using the existing tool system.\n\n## About Skills\n\nSkills are modular, self-contained packages that extend the agent's capabilities by providing specialized knowledge, workflows, and tools. They transform a general-purpose agent into a specialized agent equipped with procedural knowledge.\n\n### What Skills Provide\n\n1. **Specialized workflows** - Multi-step procedures for specific domains\n2. **Tool integrations** - Instructions for working with specific file formats or APIs\n3. **Domain expertise** - Company-specific knowledge, schemas, business logic\n4. **Bundled resources** - Scripts, references, and assets for complex tasks\n\n### Core Principle\n\n**Concise is Key**: Only add context the agent doesn't already have. Challenge each piece of information: \"Does this justify its token cost?\" Prefer concise examples over verbose explanations.\n\n## Skill Structure\n\nEvery skill consists of a required SKILL.md file and optional bundled resources:\n\n```\nskill-name/\n├── SKILL.md (required)\n│   ├── YAML frontmatter metadata (required)\n│   │   ├── name: (required)\n│   │   └── description: (required)\n│   └── Markdown instructions (required)\n└── Bundled Resources (optional)\n    ├── scripts/          - Executable code (Python/Bash/etc.)\n    ├── references/       - Documentation intended to be loaded into context as needed\n    └── assets/           - Files used in output (templates, icons, fonts, etc.)\n```\n\n### SKILL.md Components\n\n**Frontmatter (YAML)** - Required fields:\n\n- **name**: Skill name in hyphen-case (e.g., `weather-api`, `pdf-editor`)\n- **description**: **CRITICAL** - Primary triggering mechanism\n  - Must clearly describe what the skill does\n  - Must explicitly state when to use it\n  - Include specific trigger scenarios and keywords\n  - All \"when to use\" info goes here, NOT in body\n  - Example: `\"PDF document processing with rotation, merging, splitting, and text extraction. Use when user needs to: (1) Rotate PDF pages, (2) Merge multiple PDFs, (3) Split PDF files, (4) Extract text from PDFs.\"`\n\n**Body (Markdown)** - Loaded after skill triggers:\n\n- Detailed usage instructions\n- How to call scripts and read references\n- Examples and best practices\n- Use imperative/infinitive form (\"Use X to do Y\")\n\n### Bundled Resources\n\n**scripts/** - When to include:\n- Code is repeatedly rewritten\n- Deterministic execution needed (avoid LLM randomness)\n- Examples: PDF rotation, image processing\n- Must test scripts before including\n\n**references/** - When to include:\n- **ONLY** when documentation is too large for SKILL.md (>500 lines)\n- Database schemas, complex API specs that agent needs to reference\n- Agent reads these files into context as needed\n- **NOT for**: API reference docs, usage examples, tutorials (put in SKILL.md instead)\n- **Rule of thumb**: If it fits in SKILL.md, don't create a separate reference file\n\n**assets/** - When to include:\n- Files used in output (not loaded to context)\n- Templates, icons, boilerplate code\n- Copied or modified in final output\n\n**Important**: Most skills don't need all three. Choose based on actual needs.\n\n### What NOT to Include\n\nDo NOT create auxiliary documentation files:\n- README.md - Instructions belong in SKILL.md\n- INSTALLATION_GUIDE.md - Setup info belongs in SKILL.md\n- CHANGELOG.md - Not needed for local skills\n- API_REFERENCE.md - Put API docs directly in SKILL.md\n- USAGE_EXAMPLES.md - Put examples directly in SKILL.md\n- Any other documentation files - Everything goes in SKILL.md unless it's too large\n\n**Critical Rule**: Only create files that the agent will actually execute (scripts) or that are too large for SKILL.md (references). Documentation, examples, and guides ALL belong in SKILL.md.\n\n## Installing a Skill\n\nInstall target directory: `<workspace>/skills/<name>/` (the `<workspace>` is from the \"Workspace\" section).\n\n### Step 1 — Obtain skill content\n\n| Source | Action |\n|---|---|\n| URL (single file) | Fetch content via curl or web_fetch |\n| URL (zip/archive) | Download and extract to a temp directory |\n| Local file (SKILL.md) | Read directly |\n| Local archive (zip) | Extract to a temp directory |\n\n### Step 2 — Identify and install\n\n1. Locate the SKILL.md (may be at top level or inside a subdirectory)\n2. Extract `name` from YAML frontmatter\n3. Copy the **entire skill directory** (SKILL.md and all sibling files/folders such as `references/`, `scripts/`, `assets/`, etc.) into `<workspace>/skills/<name>/`\n4. If an install/setup file exists (e.g. INSTALL.md), follow its instructions — the final result must still end up in `<workspace>/skills/<name>/`\n\n## Skill Creation Process (from scratch)\n\n1. **Understand** - Clarify use cases with concrete examples\n2. **Plan** - Identify needed scripts, references, assets\n3. **Initialize** - Run init_skill.py to create template\n4. **Edit** - Implement SKILL.md and resources\n5. **Validate** (optional) - Run quick_validate.py to check format\n6. **Iterate** - Improve based on real usage\n\n## Skill Naming\n\n- Use lowercase letters, digits, and hyphens only; normalize user-provided titles to hyphen-case (e.g., \"Plan Mode\" -> `plan-mode`).\n- When generating names, generate a name under 64 characters (letters, digits, hyphens).\n- Prefer short, verb-led phrases that describe the action.\n- Namespace by tool when it improves clarity or triggering (e.g., `gh-address-comments`, `linear-address-issue`).\n- Name the skill folder exactly after the skill name.\n\n## Step-by-Step Guide\n\n### Step 1: Understanding the Skill with Concrete Examples\n\nSkip this step only when the skill's usage patterns are already clearly understood. It remains valuable even when working with an existing skill.\n\nTo create an effective skill, clearly understand concrete examples of how the skill will be used. This understanding can come from either direct user examples or generated examples that are validated with user feedback.\n\nFor example, when building an image-editor skill, relevant questions include:\n\n- \"What functionality should the image-editor skill support? Editing, rotating, anything else?\"\n- \"Can you give some examples of how this skill would be used?\"\n- \"I can imagine users asking for things like 'Remove the red-eye from this image' or 'Rotate this image'. Are there other ways you imagine this skill being used?\"\n- \"What would a user say that should trigger this skill?\"\n\nTo avoid overwhelming users, avoid asking too many questions in a single message. Start with the most important questions and follow up as needed for better effectiveness.\n\nConclude this step when there is a clear sense of the functionality the skill should support.\n\n### Step 2: Planning the Reusable Skill Contents\n\nTo turn concrete examples into an effective skill, analyze each example by:\n\n1. Considering how to execute on the example from scratch\n2. Identifying what scripts, references, and assets would be helpful when executing these workflows repeatedly\n\n**Planning Checklist**:\n- ✅ **Always needed**: SKILL.md with clear description and usage instructions\n- ✅ **scripts/**: Only if code needs to be executed (not just shown as examples)\n- ❌ **references/**: Rarely needed - only if documentation is >500 lines and can't fit in SKILL.md\n- ✅ **assets/**: Only if files are used in output (templates, boilerplate, etc.)\n\nExample: When building a `pdf-editor` skill to handle queries like \"Help me rotate this PDF,\" the analysis shows:\n\n1. Rotating a PDF requires re-writing the same code each time\n2. A `scripts/rotate_pdf.py` script would be helpful to store in the skill\n3. ❌ Don't create `references/api-docs.md` - put API info in SKILL.md instead\n\nExample: When designing a `frontend-webapp-builder` skill for queries like \"Build me a todo app\" or \"Build me a dashboard to track my steps,\" the analysis shows:\n\n1. Writing a frontend webapp requires the same boilerplate HTML/React each time\n2. An `assets/hello-world/` template containing the boilerplate HTML/React project files would be helpful to store in the skill\n3. ❌ Don't create `references/usage-examples.md` - put examples in SKILL.md instead\n\nExample: When building a `big-query` skill to handle queries like \"How many users have logged in today?\" the analysis shows:\n\n1. Querying BigQuery requires re-discovering the table schemas and relationships each time\n2. A `references/schema.md` file documenting the table schemas would be helpful to store in the skill (ONLY because schemas are very large)\n3. ❌ Don't create separate `references/query-examples.md` - put examples in SKILL.md instead\n\nTo establish the skill's contents, analyze each concrete example to create a list of the reusable resources to include: scripts, references, and assets. **Default to putting everything in SKILL.md unless there's a compelling reason to separate it.**\n\n### Step 3: Initialize the Skill\n\nAt this point, it is time to actually create the skill.\n\nSkip this step only if the skill being developed already exists, and iteration is needed. In this case, continue to the next step.\n\nWhen creating a new skill from scratch, always run the `init_skill.py` script. The script conveniently generates a new template skill directory that automatically includes everything a skill requires, making the skill creation process much more efficient and reliable.\n\nUsage:\n\n```bash\nscripts/init_skill.py <skill-name> --path <output-directory> [--resources scripts,references,assets] [--examples]\n```\n\nExamples:\n\n```bash\nscripts/init_skill.py my-skill --path <workspace>/skills\nscripts/init_skill.py my-skill --path <workspace>/skills --resources scripts,references\nscripts/init_skill.py my-skill --path <workspace>/skills --resources scripts --examples\n```\n\nWhere `<workspace>` is your workspace directory shown in the \"Workspace\" section of the system prompt.\n\nThe script:\n\n- Creates the skill directory at the specified path\n- Generates a SKILL.md template with proper frontmatter and TODO placeholders\n- Optionally creates resource directories based on `--resources`\n- Optionally adds example files when `--examples` is set\n\nAfter initialization, customize the SKILL.md and add resources as needed. If you used `--examples`, replace or delete placeholder files.\n\n**Important**: Always create skills in workspace skills directory (`<workspace>/skills`), NOT in project directory. Check the \"Workspace\" section for the actual workspace path.\n\n### Step 4: Edit the Skill\n\nWhen editing the (newly-generated or existing) skill, remember that the skill is being created for another instance of the agent to use. Include information that would be beneficial and non-obvious to the agent. Consider what procedural knowledge, domain-specific details, or reusable assets would help another agent instance execute these tasks more effectively.\n\n#### Design Patterns\n\n**Workflow patterns** — For complex tasks, break operations into sequential steps or conditional branches:\n\n```markdown\n# Sequential: list numbered steps with scripts\n1. Analyze the form (run analyze_form.py)\n2. Create field mapping (edit fields.json)\n3. Fill the form (run fill_form.py)\n\n# Conditional: guide through decision points\n1. Determine the modification type:\n   **Creating new content?** → Follow \"Creation workflow\"\n   **Editing existing content?** → Follow \"Editing workflow\"\n```\n\n**Output patterns** — When consistent output format matters, provide a template or input/output examples in SKILL.md so the agent can follow the desired style.\n\n#### Start with Reusable Skill Contents\n\nTo begin implementation, start with the reusable resources identified above: `scripts/`, `references/`, and `assets/` files. Note that this step may require user input. For example, when implementing a `brand-guidelines` skill, the user may need to provide brand assets or templates to store in `assets/`, or documentation to store in `references/`.\n\n**Available Base Tools**:\n\nThe agent has access to these core tools that you can leverage in your skill:\n- **bash**: Execute shell commands (use for curl, ls, grep, sed, awk, bc for calculations, etc.)\n- **read**: Read file contents\n- **write**: Write files\n- **edit**: Edit files with search/replace\n\n**Minimize Dependencies**:\n- ✅ **Prefer bash + curl** for HTTP API calls (no Python dependencies)\n- ✅ **Use bash tools** (grep, sed, awk) for text processing\n- ✅ **Keep scripts simple** - if bash can do it, no need for Python (document packages/versions if Python is used)\n\n**Important Guidelines**:\n- **scripts/**: Only create scripts that will be executed. Test all scripts before including.\n- **references/**: ONLY create if documentation is too large for SKILL.md (>500 lines). Most skills don't need this.\n- **assets/**: Only include files used in output (templates, icons, etc.)\n- **Default approach**: Put everything in SKILL.md unless there's a specific reason not to.\n\nAdded scripts must be tested by actually running them to ensure there are no bugs and that the output matches what is expected. If there are many similar scripts, only a representative sample needs to be tested to ensure confidence that they all work while balancing time to completion.\n\nIf you used `--examples`, delete any placeholder files that are not needed for the skill. Only create resource directories that are actually required.\n\n#### Update SKILL.md\n\n**Writing Guidelines:** Always use imperative/infinitive form.\n\n##### Frontmatter\n\nWrite the YAML frontmatter with `name`, `description`, and optional `metadata`:\n\n- `name`: The skill name\n- `description`: This is the primary triggering mechanism for your skill, and helps the agent understand when to use the skill.\n  - Include both what the Skill does and specific triggers/contexts for when to use it.\n  - Include all \"when to use\" information here - Not in the body. The body is only loaded after triggering, so \"When to Use This Skill\" sections in the body are not helpful to the agent.\n  - Example description for a `docx` skill: \"Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. Use when the agent needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks\"\n- `metadata`: (Optional) Specify requirements and configuration\n  - `requires.bins`: Required binaries (e.g., `[\"curl\", \"jq\"]`)\n  - `requires.env`: Required environment variables — all must be set (e.g., `[\"MYAPI_KEY\"]`)\n  - `requires.anyEnv`: Alternative environment variables — at least one must be set (e.g., `[\"OPENAI_API_KEY\", \"LINKAI_API_KEY\"]`)\n  - `requires.anyBins`: Alternative binaries — at least one must be present\n  - `always`: Set to `true` to always load regardless of requirements\n  - `emoji`: Skill icon (optional)\n  - Do NOT set `category` — it defaults to `skill` and is managed by the system\n\n**API Key Requirements**:\n\nIf your skill needs a single API key, declare it in `requires.env`:\n\n```yaml\n---\nname: my-search\ndescription: Search using MyAPI\nmetadata:\n  requires:\n    bins: [\"curl\"]\n    env: [\"MYAPI_KEY\"]\n---\n```\n\nIf your skill supports multiple API key providers (e.g., OpenAI or LinkAI), use `requires.anyEnv`:\n\n```yaml\n---\nname: my-vision\ndescription: Analyze images using Vision API\nmetadata:\n  requires:\n    bins: [\"curl\"]\n    anyEnv: [\"OPENAI_API_KEY\", \"LINKAI_API_KEY\"]\n---\n```\n\n**Auto-enable rule**: Skills are automatically enabled when required environment variables are set, and automatically disabled when missing. No manual configuration needed.\n\n##### Body\n\nWrite instructions for using the skill and its bundled resources.\n\n**If your skill requires an API key**, include setup instructions in the body:\n\n```markdown\n## Setup\n\nThis skill requires an API key from [Service Name].\n\n1. Visit https://service.com to get an API key\n2. Configure it using: `env_config(action=\"set\", key=\"SERVICE_API_KEY\", value=\"your-key\")`\n3. Or manually add to `~/cow/.env`: `SERVICE_API_KEY=your-key`\n4. Restart the agent for changes to take effect\n\n## Usage\n...\n```\n\nThe bash script should check for the key and provide helpful error messages:\n\n```bash\n#!/usr/bin/env bash\nif [ -z \"${SERVICE_API_KEY:-}\" ]; then\n    echo \"Error: SERVICE_API_KEY not set\"\n    echo \"Please configure your API key first (see SKILL.md)\"\n    exit 1\nfi\n\ncurl -H \"Authorization: Bearer $SERVICE_API_KEY\" ...\n```\n\n**Script Path Convention**:\n\nWhen writing SKILL.md instructions, remember that:\n- Skills are listed in `<available_skills>` with a `<base_dir>` path\n- Scripts should be referenced as: `<base_dir>/scripts/script_name.sh`\n- The AI will see the base_dir and can construct the full path\n\nExample instruction in SKILL.md:\n```markdown\n## Usage\n\nScripts are in this skill's base directory (shown in skill listing).\n\nbash \"<base_dir>/scripts/my_script.sh\" <args>\n```\n\n### Step 5: Validate (Optional)\n\nValidate skill format:\n\n```bash\nscripts/quick_validate.py <path/to/skill-folder>\n```\n\nExample:\n\n```bash\nscripts/quick_validate.py <workspace>/skills/weather-api\n```\n\nValidation checks:\n- YAML frontmatter format and required fields\n- Skill naming conventions (hyphen-case, lowercase)\n- Description completeness and quality\n- File organization\n\n**Note**: Validation is optional in COW. Mainly useful for troubleshooting format issues.\n\n### Step 6: Iterate\n\nImprove based on real usage:\n\n1. Use skill on real tasks\n2. Notice struggles or inefficiencies\n3. Identify needed updates to SKILL.md or resources\n4. Implement changes and test again\n\n## Progressive Disclosure\n\nSkills use three-level loading:\n\n1. **Metadata** (name + description) - Always in context (~100 words)\n2. **SKILL.md body** - Loaded when skill triggers (<5k words)\n3. **Resources** - Loaded as needed by agent\n\n**Best practices**:\n- Keep SKILL.md under 500 lines\n- Split complex content into `references/` files\n- Reference these files clearly in SKILL.md\n\n**Pattern**: For skills with multiple variants/frameworks:\n- Keep core workflow in SKILL.md\n- Move variant-specific details to separate reference files\n- Agent loads only relevant files\n\nExample:\n```\ncloud-deploy/\n├── SKILL.md (workflow + provider selection)\n└── references/\n    ├── aws.md\n    ├── gcp.md\n    └── azure.md\n```\n\nWhen user chooses AWS, agent only reads aws.md.\n"},"items":[{"name":"SKILL.md","path":"skills/image-generation/SKILL.md","rawUrl":"https://raw.githubusercontent.com/zhayujie/CowAgent/HEAD/skills/image-generation/SKILL.md","title":"image-generation","category":"anthropic-skill","format":"markdown","content":"---\nname: image-generation\ndescription: Generate or edit images from text prompts. Use when the user asks to create, draw, design, or edit an image, illustration, photo, icon, poster, or any visual content.\nmetadata:\n  cowagent:\n    requires:\n      anyEnv:\n        - OPENAI_API_KEY\n        - GEMINI_API_KEY\n        - ARK_API_KEY\n        - DASHSCOPE_API_KEY\n        - MINIMAX_API_KEY\n        - LINKAI_API_KEY\n---\n\n# Image Generation\n\nGenerate and edit images using AI models. The script automatically picks a backend based on which API keys are configured — **you don't need to specify a model unless the user explicitly names one**. Never guess or invent a `model`: when the user doesn't name one, omit `model` entirely so the configured default/provider is used.\n\nSupported models (passed via `model` only when the user asks for a specific one):\n\n- **OpenAI** — `gpt-image-2.5-flare` (recommended default: best quality/latency trade-off), `gpt-image-2.5-sunburst` (highest editing precision), `gpt-image-2`, `gpt-image-1`\n- **Gemini Nano Banana** — `nano-banana-2`, `nano-banana-pro`, `nano-banana`\n- **Seedream (Volcengine Ark)** — `seedream-5.0-lite`, `seedream-4.5`\n- **Qwen (DashScope)** — `qwen-image-2.0`, `qwen-image-2.0-pro`\n- **MiniMax** — `image-01`\n\n## Usage\n\nRun `scripts/generate.py` with a JSON argument. Use the absolute `<base_dir>` path — **do NOT `cd` into the skill directory**, since it is a builtin skill and gets reset on restart (anything written there is lost).\n\n```bash\npython <base_dir>/scripts/generate.py '<json_args>'\n```\n\nImages are saved to the workspace (or the open project dir) under `images/`, so they persist and stay reachable to the client.\n\n**Set bash timeout to at least 600 seconds**, as image generation can take 30–200s per provider, and the script may try multiple providers sequentially. Call it synchronously (do not run it in the background) and wait for its output in the same turn.\n\n### Parameters\n\n| Parameter | Type | Required | Default | Description |\n|-----------|------|----------|---------|-------------|\n| `prompt` | string | yes | — | Image description |\n| `image_url` | string / list | no | null | Input image(s) for editing: local file path or URL. Multi-image fusion is supported (pass a list) |\n| `quality` | string | no | auto | `low` / `medium` / `high` (only some backends honour this) |\n| `size` | string | no | auto | `512` / `1K` / `2K` / `3K` / `4K`, or pixel value (`1024x1024`) |\n| `aspect_ratio` | string | no | null | `1:1` / `3:2` / `2:3` / `16:9` / `9:16` / `21:9` (some backends also support extreme ratios like `1:4` / `8:1`) |\n\n**Higher `quality` and larger `size` cost more and run slower.** In normal cases, when the user does not explicitly specify, `low` or `medium` is sufficient. Only use `high` when the user asks for it.\n\n### Example — generate\n\n```bash\npython <base_dir>/scripts/generate.py '{\"prompt\": \"A corgi astronaut floating in space\"}'\n```\n\nWith aspect ratio:\n\n```bash\npython <base_dir>/scripts/generate.py '{\"prompt\": \"Isometric miniature city of Shanghai at sunset\", \"size\": \"2K\", \"aspect_ratio\": \"16:9\"}'\n```\n\n### Important: Editing vs Generating\n\nWhen the user asks to **edit, modify, or improve an existing image**, pass the original image via `image_url`. Prefer **local file paths** directly — the script handles file reading internally. Without `image_url`, the script generates a brand-new image instead of editing.\n\n### Example — edit (image-to-image)\n\n```bash\npython <base_dir>/scripts/generate.py '{\"prompt\": \"Add a Santa hat to the dog\", \"image_url\": \"/path/to/dog.png\"}'\n```\n\nMulti-image fusion — pass a list:\n\n```bash\npython <base_dir>/scripts/generate.py '{\"prompt\": \"Combine these characters into a group photo\", \"image_url\": [\"/path/a.png\", \"/path/b.png\"]}'\n```\n\n### Output\n\nPrints JSON to stdout:\n\n```json\n{\n  \"model\": \"doubao-seedream-5-0-260128\",\n  \"images\": [\n    {\"url\": \"/path/to/output.png\"}\n  ]\n}\n```\n\nAfter success, display the image to the user. You can either embed it in markdown (`![description](/path/to/output.png)`) or use the `send` tool.\n\nOn error:\n\n```json\n{\n  \"error\": \"error message\"\n}\n```\n\n### Setup\n\nThe script needs **at least one** of these API keys (set via `env_config` or `config.json`):\n\n`OPENAI_API_KEY` / `GEMINI_API_KEY` / `ARK_API_KEY` / `DASHSCOPE_API_KEY` / `MINIMAX_API_KEY` / `LINKAI_API_KEY`\n\nEach also has an optional `*_API_BASE` for custom endpoints. The script automatically picks the first configured backend and falls back to the next if it fails — no need to specify a model.\n\n### Error Handling\n\nIf the script returns an error after trying all configured backends, **do NOT retry with the same parameters** — the failure is almost always a configuration issue (wrong API key, unsupported API base). Tell the user to fix it via `env_config`, then retry.\n\n### Notes\n\n- HTTP timeout is 300s — high-resolution generation can take over 200s.\n- Omit `quality` / `size` to let the model pick automatically (`auto`).\n- Input images for editing are auto-compressed to ≤ 4MB / longest edge ≤ 4096px.\n","frontmatter":{"name":"image-generation","description":"Generate or edit images from text prompts. Use when the user asks to create, draw, design, or edit an image, illustration, photo, icon, poster, or any visual content.","metadata":{"cowagent":{"requires":{"anyEnv":["OPENAI_API_KEY","GEMINI_API_KEY","ARK_API_KEY","DASHSCOPE_API_KEY","MINIMAX_API_KEY","LINKAI_API_KEY"]}}}},"isInternal":false,"tokens":1359,"sizeBytes":5084},{"name":"SKILL.md","path":"skills/knowledge-wiki/SKILL.md","rawUrl":"https://raw.githubusercontent.com/zhayujie/CowAgent/HEAD/skills/knowledge-wiki/SKILL.md","title":"knowledge-wiki","category":"anthropic-skill","format":"markdown","content":"---\nname: knowledge-wiki\ndescription: Manage the personal knowledge wiki. Use when the user shares articles, documents, or asks to organize knowledge; when a conversation produces insights worth preserving as structured knowledge; or when the user asks about the knowledge base.\nmetadata:\n  cowagent:\n    always: true\n---\n\n# Knowledge Wiki\n\nMaintain a persistent, structured knowledge base in the `knowledge/` directory.\n\n## Core Operations\n\n### 1. Ingest — User shares an article, document, or resource\n\n1. Read and understand the source material\n2. Extract key facts, insights, and structured knowledge\n3. Determine the appropriate subdirectory:\n   - Read `knowledge/index.md` to see existing categories\n   - If a matching category exists, follow that structure\n   - If not, create a new subdirectory with a clear name\n4. Create the knowledge page: `knowledge/<category>/<slug>.md`\n5. Update `knowledge/index.md` and append to `knowledge/log.md`\n\n### 2. Synthesize — Conversation produces valuable structured knowledge\n\n1. Create a knowledge page under the appropriate category\n2. Update related pages with cross-references\n3. Update `knowledge/index.md` and `knowledge/log.md`\n\n### 3. Query — User asks about accumulated knowledge\n\n1. Check `knowledge/index.md` (already in your context) for relevant pages\n2. Read specific pages with the `read` tool\n3. Supplement with `memory_search` if needed\n\n## Page Format\n\n```markdown\n# Page Title\n\n> Source: <URL or description of the original material>\n\nContent here. Cross-reference related pages with markdown links:\n[Related Page](../category/related-page.md)\n\n## Key Points\n\n- ...\n\n## Related\n\n- [Page A](../category/page-a.md) — how it relates\n- [Page B](../category/page-b.md) — how it relates\n```\n\nThe `> Source:` line records where the knowledge came from (URL, document name, conversation, etc.). Always include it when the material originates from a specific source.\n\nCross-references build a knowledge graph. When creating or updating a page, link to related pages and update those pages to link back. **Only link to pages that already exist** — if a concept deserves its own page, create it first, then add the link.\n\n## Index Format (`knowledge/index.md`)\n\nFlat list, one line per page: `[Title](path) — one-line summary`. Group by category (matching subdirectories). No tables, no emoji.\n\n```markdown\n# Knowledge Index\n\n## Category A\n- [Page Title](category-a/page-slug.md) — one-line summary\n\n## Category B\n- [Page Title](category-b/page-slug.md) — one-line summary\n```\n\nCategory names and structure are flexible — follow whatever organization already exists in the index, or create new categories based on the content.\n\n## Log Format (`knowledge/log.md`)\n\nAppend-only, newest at bottom:\n\n```markdown\n## [YYYY-MM-DD] ingest | Page Title\n## [YYYY-MM-DD] synthesize | Page Title\n```\n\n## Guidelines\n\n- **File naming**: lowercase kebab-case (e.g. `machine-learning.md`)\n- **One topic per page**: link between pages rather than duplicating\n- **Update, don't duplicate**: if a page exists, update it\n- **Cross-reference**: every page should link to related pages; keep the knowledge graph connected\n- **Index is mandatory**: always update `knowledge/index.md` after any change\n- **Be concise**: capture essence, not copy entire sources\n- **Full paths in replies**: when referencing knowledge files in conversation replies, use the full path from workspace root (e.g. `[Title](knowledge/<category>/<slug>.md)`), not relative paths. Relative paths are only for cross-references inside knowledge pages themselves.\n- **Cite sources**: when answering based on knowledge pages, include links to the relevant pages so the user can explore further.\n","frontmatter":{"name":"knowledge-wiki","description":"Manage the personal knowledge wiki. Use when the user shares articles, documents, or asks to organize knowledge; when a conversation produces insights worth preserving as structured knowledge; or when the user asks about the knowledge base.","metadata":{"cowagent":{"always":true}}},"isInternal":false,"tokens":825,"sizeBytes":3715},{"name":"README.md","path":"skills/README.md","rawUrl":"https://raw.githubusercontent.com/zhayujie/CowAgent/HEAD/skills/README.md","title":"Skills Skill","category":"anthropic-skill","format":"markdown","content":"# Skills\n\nSkills are reusable instruction sets that extend the agent's capabilities. Each skill is a `SKILL.md` file in its own directory, providing specialized knowledge, workflows, and tool integrations for specific tasks.\n\n## Skill Hub\n\nBrowse, search, and install skills from [Cow Skill Hub](https://skills.cowagent.ai/).\n\nOpen source: [github.com/zhayujie/cow-skill-hub](https://github.com/zhayujie/cow-skill-hub)\n\n## Install Skills\n\nInstall skills from multiple sources via chat (`/skill`) or terminal (`cow skill`):\n\n```bash\n/skill install <name>                   # From Skill Hub\n/skill install <owner>/<repo>           # From GitHub\n/skill install clawhub:<name>           # From ClawHub\n/skill install linkai:<code>            # From LinkAI\n/skill install <url>                    # From URL (zip or SKILL.md)\n```\n\nList all available remote skills:\n\n```bash\n/skill list --remote\n```\n\n## Manage Skills\n\n```bash\n/skill list                  # List installed skills\n/skill info <name>           # View skill details\n/skill enable <name>         # Enable a skill\n/skill disable <name>        # Disable a skill\n/skill uninstall <name>      # Uninstall a skill\n```\n\n> In terminal, replace `/skill` with `cow skill`.\n\n## Skill Structure\n\n```\nskills/\n  my-skill/\n    SKILL.md          # Required: skill definition\n    scripts/          # Optional: bundled scripts\n    resources/        # Optional: reference files\n```\n\n`SKILL.md` uses YAML frontmatter:\n\n```markdown\n---\nname: my-skill\ndescription: Brief description of what the skill does\nmetadata: {\"cow\":{\"emoji\":\"🔧\",\"requires\":{\"bins\":[\"tool\"],\"env\":[\"API_KEY\"]}}}\n---\n\n# My Skill\n\nInstructions, examples, and usage patterns...\n```\n\n### Frontmatter Fields\n\n| Field | Description |\n|---|---|\n| `name` | Skill name (must match directory name) |\n| `description` | Brief description (required) |\n| `metadata.cow.emoji` | Display emoji |\n| `metadata.cow.always` | Always include this skill (default: false) |\n| `metadata.cow.requires.bins` | Required binaries |\n| `metadata.cow.requires.env` | Required environment variables |\n| `metadata.cow.requires.config` | Required config paths |\n| `metadata.cow.os` | Supported OS (e.g., `[\"darwin\", \"linux\"]`) |\n\n## Skill Loading Order\n\nSkills are loaded from two locations (higher precedence overrides lower):\n\n1. **Builtin skills** (lower): `<project_root>/skills/` — shipped with the codebase\n2. **Custom skills** (higher): `~/cow/skills/` — installed via `cow skill install` or skill creator\n\nSkills with the same name in the custom directory override builtin ones.\n\n## Create & Contribute\n\nSee the [Skill Creation docs](https://docs.cowagent.ai/skills/create) for details, or submit your skill to [Skill Hub](https://skills.cowagent.ai/submit).\n","isInternal":false,"tokens":674,"sizeBytes":2749},{"name":"SKILL.md","path":"skills/skill-creator/SKILL.md","rawUrl":"https://raw.githubusercontent.com/zhayujie/CowAgent/HEAD/skills/skill-creator/SKILL.md","title":"skill-creator","category":"anthropic-skill","format":"markdown","content":"---\nname: skill-creator\ndescription: Create, install, or update skills in the workspace. Use when (1) installing a skill from a URL or remote source, (2) creating a new skill from scratch, (3) updating or restructuring existing skills. Always use this skill for any skill installation or creation task.\nlicense: Complete terms in LICENSE.txt\n---\n\n# Skill Creator\n\nThis skill provides guidance for creating effective skills using the existing tool system.\n\n## About Skills\n\nSkills are modular, self-contained packages that extend the agent's capabilities by providing specialized knowledge, workflows, and tools. They transform a general-purpose agent into a specialized agent equipped with procedural knowledge.\n\n### What Skills Provide\n\n1. **Specialized workflows** - Multi-step procedures for specific domains\n2. **Tool integrations** - Instructions for working with specific file formats or APIs\n3. **Domain expertise** - Company-specific knowledge, schemas, business logic\n4. **Bundled resources** - Scripts, references, and assets for complex tasks\n\n### Core Principle\n\n**Concise is Key**: Only add context the agent doesn't already have. Challenge each piece of information: \"Does this justify its token cost?\" Prefer concise examples over verbose explanations.\n\n## Skill Structure\n\nEvery skill consists of a required SKILL.md file and optional bundled resources:\n\n```\nskill-name/\n├── SKILL.md (required)\n│   ├── YAML frontmatter metadata (required)\n│   │   ├── name: (required)\n│   │   └── description: (required)\n│   └── Markdown instructions (required)\n└── Bundled Resources (optional)\n    ├── scripts/          - Executable code (Python/Bash/etc.)\n    ├── references/       - Documentation intended to be loaded into context as needed\n    └── assets/           - Files used in output (templates, icons, fonts, etc.)\n```\n\n### SKILL.md Components\n\n**Frontmatter (YAML)** - Required fields:\n\n- **name**: Skill name in hyphen-case (e.g., `weather-api`, `pdf-editor`)\n- **description**: **CRITICAL** - Primary triggering mechanism\n  - Must clearly describe what the skill does\n  - Must explicitly state when to use it\n  - Include specific trigger scenarios and keywords\n  - All \"when to use\" info goes here, NOT in body\n  - Example: `\"PDF document processing with rotation, merging, splitting, and text extraction. Use when user needs to: (1) Rotate PDF pages, (2) Merge multiple PDFs, (3) Split PDF files, (4) Extract text from PDFs.\"`\n\n**Body (Markdown)** - Loaded after skill triggers:\n\n- Detailed usage instructions\n- How to call scripts and read references\n- Examples and best practices\n- Use imperative/infinitive form (\"Use X to do Y\")\n\n### Bundled Resources\n\n**scripts/** - When to include:\n- Code is repeatedly rewritten\n- Deterministic execution needed (avoid LLM randomness)\n- Examples: PDF rotation, image processing\n- Must test scripts before including\n\n**references/** - When to include:\n- **ONLY** when documentation is too large for SKILL.md (>500 lines)\n- Database schemas, complex API specs that agent needs to reference\n- Agent reads these files into context as needed\n- **NOT for**: API reference docs, usage examples, tutorials (put in SKILL.md instead)\n- **Rule of thumb**: If it fits in SKILL.md, don't create a separate reference file\n\n**assets/** - When to include:\n- Files used in output (not loaded to context)\n- Templates, icons, boilerplate code\n- Copied or modified in final output\n\n**Important**: Most skills don't need all three. Choose based on actual needs.\n\n### What NOT to Include\n\nDo NOT create auxiliary documentation files:\n- README.md - Instructions belong in SKILL.md\n- INSTALLATION_GUIDE.md - Setup info belongs in SKILL.md\n- CHANGELOG.md - Not needed for local skills\n- API_REFERENCE.md - Put API docs directly in SKILL.md\n- USAGE_EXAMPLES.md - Put examples directly in SKILL.md\n- Any other documentation files - Everything goes in SKILL.md unless it's too large\n\n**Critical Rule**: Only create files that the agent will actually execute (scripts) or that are too large for SKILL.md (references). Documentation, examples, and guides ALL belong in SKILL.md.\n\n## Installing a Skill\n\nInstall target directory: `<workspace>/skills/<name>/` (the `<workspace>` is from the \"Workspace\" section).\n\n### Step 1 — Obtain skill content\n\n| Source | Action |\n|---|---|\n| URL (single file) | Fetch content via curl or web_fetch |\n| URL (zip/archive) | Download and extract to a temp directory |\n| Local file (SKILL.md) | Read directly |\n| Local archive (zip) | Extract to a temp directory |\n\n### Step 2 — Identify and install\n\n1. Locate the SKILL.md (may be at top level or inside a subdirectory)\n2. Extract `name` from YAML frontmatter\n3. Copy the **entire skill directory** (SKILL.md and all sibling files/folders such as `references/`, `scripts/`, `assets/`, etc.) into `<workspace>/skills/<name>/`\n4. If an install/setup file exists (e.g. INSTALL.md), follow its instructions — the final result must still end up in `<workspace>/skills/<name>/`\n\n## Skill Creation Process (from scratch)\n\n1. **Understand** - Clarify use cases with concrete examples\n2. **Plan** - Identify needed scripts, references, assets\n3. **Initialize** - Run init_skill.py to create template\n4. **Edit** - Implement SKILL.md and resources\n5. **Validate** (optional) - Run quick_validate.py to check format\n6. **Iterate** - Improve based on real usage\n\n## Skill Naming\n\n- Use lowercase letters, digits, and hyphens only; normalize user-provided titles to hyphen-case (e.g., \"Plan Mode\" -> `plan-mode`).\n- When generating names, generate a name under 64 characters (letters, digits, hyphens).\n- Prefer short, verb-led phrases that describe the action.\n- Namespace by tool when it improves clarity or triggering (e.g., `gh-address-comments`, `linear-address-issue`).\n- Name the skill folder exactly after the skill name.\n\n## Step-by-Step Guide\n\n### Step 1: Understanding the Skill with Concrete Examples\n\nSkip this step only when the skill's usage patterns are already clearly understood. It remains valuable even when working with an existing skill.\n\nTo create an effective skill, clearly understand concrete examples of how the skill will be used. This understanding can come from either direct user examples or generated examples that are validated with user feedback.\n\nFor example, when building an image-editor skill, relevant questions include:\n\n- \"What functionality should the image-editor skill support? Editing, rotating, anything else?\"\n- \"Can you give some examples of how this skill would be used?\"\n- \"I can imagine users asking for things like 'Remove the red-eye from this image' or 'Rotate this image'. Are there other ways you imagine this skill being used?\"\n- \"What would a user say that should trigger this skill?\"\n\nTo avoid overwhelming users, avoid asking too many questions in a single message. Start with the most important questions and follow up as needed for better effectiveness.\n\nConclude this step when there is a clear sense of the functionality the skill should support.\n\n### Step 2: Planning the Reusable Skill Contents\n\nTo turn concrete examples into an effective skill, analyze each example by:\n\n1. Considering how to execute on the example from scratch\n2. Identifying what scripts, references, and assets would be helpful when executing these workflows repeatedly\n\n**Planning Checklist**:\n- ✅ **Always needed**: SKILL.md with clear description and usage instructions\n- ✅ **scripts/**: Only if code needs to be executed (not just shown as examples)\n- ❌ **references/**: Rarely needed - only if documentation is >500 lines and can't fit in SKILL.md\n- ✅ **assets/**: Only if files are used in output (templates, boilerplate, etc.)\n\nExample: When building a `pdf-editor` skill to handle queries like \"Help me rotate this PDF,\" the analysis shows:\n\n1. Rotating a PDF requires re-writing the same code each time\n2. A `scripts/rotate_pdf.py` script would be helpful to store in the skill\n3. ❌ Don't create `references/api-docs.md` - put API info in SKILL.md instead\n\nExample: When designing a `frontend-webapp-builder` skill for queries like \"Build me a todo app\" or \"Build me a dashboard to track my steps,\" the analysis shows:\n\n1. Writing a frontend webapp requires the same boilerplate HTML/React each time\n2. An `assets/hello-world/` template containing the boilerplate HTML/React project files would be helpful to store in the skill\n3. ❌ Don't create `references/usage-examples.md` - put examples in SKILL.md instead\n\nExample: When building a `big-query` skill to handle queries like \"How many users have logged in today?\" the analysis shows:\n\n1. Querying BigQuery requires re-discovering the table schemas and relationships each time\n2. A `references/schema.md` file documenting the table schemas would be helpful to store in the skill (ONLY because schemas are very large)\n3. ❌ Don't create separate `references/query-examples.md` - put examples in SKILL.md instead\n\nTo establish the skill's contents, analyze each concrete example to create a list of the reusable resources to include: scripts, references, and assets. **Default to putting everything in SKILL.md unless there's a compelling reason to separate it.**\n\n### Step 3: Initialize the Skill\n\nAt this point, it is time to actually create the skill.\n\nSkip this step only if the skill being developed already exists, and iteration is needed. In this case, continue to the next step.\n\nWhen creating a new skill from scratch, always run the `init_skill.py` script. The script conveniently generates a new template skill directory that automatically includes everything a skill requires, making the skill creation process much more efficient and reliable.\n\nUsage:\n\n```bash\nscripts/init_skill.py <skill-name> --path <output-directory> [--resources scripts,references,assets] [--examples]\n```\n\nExamples:\n\n```bash\nscripts/init_skill.py my-skill --path <workspace>/skills\nscripts/init_skill.py my-skill --path <workspace>/skills --resources scripts,references\nscripts/init_skill.py my-skill --path <workspace>/skills --resources scripts --examples\n```\n\nWhere `<workspace>` is your workspace directory shown in the \"Workspace\" section of the system prompt.\n\nThe script:\n\n- Creates the skill directory at the specified path\n- Generates a SKILL.md template with proper frontmatter and TODO placeholders\n- Optionally creates resource directories based on `--resources`\n- Optionally adds example files when `--examples` is set\n\nAfter initialization, customize the SKILL.md and add resources as needed. If you used `--examples`, replace or delete placeholder files.\n\n**Important**: Always create skills in workspace skills directory (`<workspace>/skills`), NOT in project directory. Check the \"Workspace\" section for the actual workspace path.\n\n### Step 4: Edit the Skill\n\nWhen editing the (newly-generated or existing) skill, remember that the skill is being created for another instance of the agent to use. Include information that would be beneficial and non-obvious to the agent. Consider what procedural knowledge, domain-specific details, or reusable assets would help another agent instance execute these tasks more effectively.\n\n#### Design Patterns\n\n**Workflow patterns** — For complex tasks, break operations into sequential steps or conditional branches:\n\n```markdown\n# Sequential: list numbered steps with scripts\n1. Analyze the form (run analyze_form.py)\n2. Create field mapping (edit fields.json)\n3. Fill the form (run fill_form.py)\n\n# Conditional: guide through decision points\n1. Determine the modification type:\n   **Creating new content?** → Follow \"Creation workflow\"\n   **Editing existing content?** → Follow \"Editing workflow\"\n```\n\n**Output patterns** — When consistent output format matters, provide a template or input/output examples in SKILL.md so the agent can follow the desired style.\n\n#### Start with Reusable Skill Contents\n\nTo begin implementation, start with the reusable resources identified above: `scripts/`, `references/`, and `assets/` files. Note that this step may require user input. For example, when implementing a `brand-guidelines` skill, the user may need to provide brand assets or templates to store in `assets/`, or documentation to store in `references/`.\n\n**Available Base Tools**:\n\nThe agent has access to these core tools that you can leverage in your skill:\n- **bash**: Execute shell commands (use for curl, ls, grep, sed, awk, bc for calculations, etc.)\n- **read**: Read file contents\n- **write**: Write files\n- **edit**: Edit files with search/replace\n\n**Minimize Dependencies**:\n- ✅ **Prefer bash + curl** for HTTP API calls (no Python dependencies)\n- ✅ **Use bash tools** (grep, sed, awk) for text processing\n- ✅ **Keep scripts simple** - if bash can do it, no need for Python (document packages/versions if Python is used)\n\n**Important Guidelines**:\n- **scripts/**: Only create scripts that will be executed. Test all scripts before including.\n- **references/**: ONLY create if documentation is too large for SKILL.md (>500 lines). Most skills don't need this.\n- **assets/**: Only include files used in output (templates, icons, etc.)\n- **Default approach**: Put everything in SKILL.md unless there's a specific reason not to.\n\nAdded scripts must be tested by actually running them to ensure there are no bugs and that the output matches what is expected. If there are many similar scripts, only a representative sample needs to be tested to ensure confidence that they all work while balancing time to completion.\n\nIf you used `--examples`, delete any placeholder files that are not needed for the skill. Only create resource directories that are actually required.\n\n#### Update SKILL.md\n\n**Writing Guidelines:** Always use imperative/infinitive form.\n\n##### Frontmatter\n\nWrite the YAML frontmatter with `name`, `description`, and optional `metadata`:\n\n- `name`: The skill name\n- `description`: This is the primary triggering mechanism for your skill, and helps the agent understand when to use the skill.\n  - Include both what the Skill does and specific triggers/contexts for when to use it.\n  - Include all \"when to use\" information here - Not in the body. The body is only loaded after triggering, so \"When to Use This Skill\" sections in the body are not helpful to the agent.\n  - Example description for a `docx` skill: \"Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. Use when the agent needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks\"\n- `metadata`: (Optional) Specify requirements and configuration\n  - `requires.bins`: Required binaries (e.g., `[\"curl\", \"jq\"]`)\n  - `requires.env`: Required environment variables — all must be set (e.g., `[\"MYAPI_KEY\"]`)\n  - `requires.anyEnv`: Alternative environment variables — at least one must be set (e.g., `[\"OPENAI_API_KEY\", \"LINKAI_API_KEY\"]`)\n  - `requires.anyBins`: Alternative binaries — at least one must be present\n  - `always`: Set to `true` to always load regardless of requirements\n  - `emoji`: Skill icon (optional)\n  - Do NOT set `category` — it defaults to `skill` and is managed by the system\n\n**API Key Requirements**:\n\nIf your skill needs a single API key, declare it in `requires.env`:\n\n```yaml\n---\nname: my-search\ndescription: Search using MyAPI\nmetadata:\n  requires:\n    bins: [\"curl\"]\n    env: [\"MYAPI_KEY\"]\n---\n```\n\nIf your skill supports multiple API key providers (e.g., OpenAI or LinkAI), use `requires.anyEnv`:\n\n```yaml\n---\nname: my-vision\ndescription: Analyze images using Vision API\nmetadata:\n  requires:\n    bins: [\"curl\"]\n    anyEnv: [\"OPENAI_API_KEY\", \"LINKAI_API_KEY\"]\n---\n```\n\n**Auto-enable rule**: Skills are automatically enabled when required environment variables are set, and automatically disabled when missing. No manual configuration needed.\n\n##### Body\n\nWrite instructions for using the skill and its bundled resources.\n\n**If your skill requires an API key**, include setup instructions in the body:\n\n```markdown\n## Setup\n\nThis skill requires an API key from [Service Name].\n\n1. Visit https://service.com to get an API key\n2. Configure it using: `env_config(action=\"set\", key=\"SERVICE_API_KEY\", value=\"your-key\")`\n3. Or manually add to `~/cow/.env`: `SERVICE_API_KEY=your-key`\n4. Restart the agent for changes to take effect\n\n## Usage\n...\n```\n\nThe bash script should check for the key and provide helpful error messages:\n\n```bash\n#!/usr/bin/env bash\nif [ -z \"${SERVICE_API_KEY:-}\" ]; then\n    echo \"Error: SERVICE_API_KEY not set\"\n    echo \"Please configure your API key first (see SKILL.md)\"\n    exit 1\nfi\n\ncurl -H \"Authorization: Bearer $SERVICE_API_KEY\" ...\n```\n\n**Script Path Convention**:\n\nWhen writing SKILL.md instructions, remember that:\n- Skills are listed in `<available_skills>` with a `<base_dir>` path\n- Scripts should be referenced as: `<base_dir>/scripts/script_name.sh`\n- The AI will see the base_dir and can construct the full path\n\nExample instruction in SKILL.md:\n```markdown\n## Usage\n\nScripts are in this skill's base directory (shown in skill listing).\n\nbash \"<base_dir>/scripts/my_script.sh\" <args>\n```\n\n### Step 5: Validate (Optional)\n\nValidate skill format:\n\n```bash\nscripts/quick_validate.py <path/to/skill-folder>\n```\n\nExample:\n\n```bash\nscripts/quick_validate.py <workspace>/skills/weather-api\n```\n\nValidation checks:\n- YAML frontmatter format and required fields\n- Skill naming conventions (hyphen-case, lowercase)\n- Description completeness and quality\n- File organization\n\n**Note**: Validation is optional in COW. Mainly useful for troubleshooting format issues.\n\n### Step 6: Iterate\n\nImprove based on real usage:\n\n1. Use skill on real tasks\n2. Notice struggles or inefficiencies\n3. Identify needed updates to SKILL.md or resources\n4. Implement changes and test again\n\n## Progressive Disclosure\n\nSkills use three-level loading:\n\n1. **Metadata** (name + description) - Always in context (~100 words)\n2. **SKILL.md body** - Loaded when skill triggers (<5k words)\n3. **Resources** - Loaded as needed by agent\n\n**Best practices**:\n- Keep SKILL.md under 500 lines\n- Split complex content into `references/` files\n- Reference these files clearly in SKILL.md\n\n**Pattern**: For skills with multiple variants/frameworks:\n- Keep core workflow in SKILL.md\n- Move variant-specific details to separate reference files\n- Agent loads only relevant files\n\nExample:\n```\ncloud-deploy/\n├── SKILL.md (workflow + provider selection)\n└── references/\n    ├── aws.md\n    ├── gcp.md\n    └── azure.md\n```\n\nWhen user chooses AWS, agent only reads aws.md.\n","frontmatter":{"name":"skill-creator","description":"Create, install, or update skills in the workspace. Use when (1) installing a skill from a URL or remote source, (2) creating a new skill from scratch, (3) updating or restructuring existing skills. Always use this skill for any skill installation or creation task.","license":"Complete terms in LICENSE.txt"},"isInternal":false,"tokens":4189,"sizeBytes":18784},{"name":"README.md","path":"agent/tools/scheduler/README.md","rawUrl":"https://raw.githubusercontent.com/zhayujie/CowAgent/HEAD/agent/tools/scheduler/README.md","title":"scheduler Documentation","category":"plugin-manifest","format":"markdown","content":"# 定时任务工具 (Scheduler Tool)\n\n## 功能简介\n\n定时任务工具允许 Agent 创建、管理和执行定时任务，支持：\n\n- ⏰ **定时提醒**: 在指定时间发送消息\n- 🔄 **周期性任务**: 按固定间隔或 cron 表达式重复执行\n- 🔧 **动态工具调用**: 定时执行其他工具并发送结果（如搜索新闻、查询天气等）\n- 📋 **任务管理**: 查询、启用、禁用、删除任务\n\n## 安装依赖\n\n```bash\npip install croniter>=2.0.0\n```\n\n## 使用方法\n\n### 1. 创建定时任务\n\nAgent 可以通过自然语言创建定时任务，支持两种类型：\n\n#### 1.1 静态消息任务\n\n发送预定义的消息：\n\n**示例对话：**\n```\n用户: 每天早上9点提醒我开会\nAgent: [调用 scheduler 工具]\n      action: create\n      name: 每日开会提醒\n      message: 该开会了！\n      schedule_type: cron\n      schedule_value: 0 9 * * *\n```\n\n#### 1.2 动态工具调用任务\n\n定时执行工具并发送结果：\n\n**示例对话：**\n```\n用户: 每天早上8点帮我读取一下今日日程\nAgent: [调用 scheduler 工具]\n      action: create\n      name: 每日日程\n      tool_call:\n        tool_name: read\n        tool_params:\n          file_path: ~/cow/schedule.txt\n        result_prefix: 📅 今日日程\n      schedule_type: cron\n      schedule_value: 0 8 * * *\n```\n\n**工具调用参数说明：**\n- `tool_name`: 要调用的工具名称（如 `bash`、`read`、`write` 等内置工具）\n- `tool_params`: 工具的参数（字典格式）\n- `result_prefix`: 可选，在结果前添加的前缀文本\n\n**注意：** 如果要使用 skills（如 bocha-search），需要通过 `bash` 工具调用 skill 脚本\n\n### 2. 支持的调度类型\n\n#### Cron 表达式 (`cron`)\n使用标准 cron 表达式：\n\n```\n0 9 * * *      # 每天 9:00\n0 */2 * * *    # 每 2 小时\n30 8 * * 1-5   # 工作日 8:30\n0 0 1 * *      # 每月 1 号\n```\n\n#### 固定间隔 (`interval`)\n以秒为单位的间隔：\n\n```\n3600           # 每小时\n86400          # 每天\n1800           # 每 30 分钟\n```\n\n#### 一次性任务 (`once`)\n指定具体时间（ISO 格式）：\n\n```\n2024-12-25T09:00:00\n2024-12-31T23:59:59\n```\n\n### 3. 查询任务列表\n\n```\n用户: 查看我的定时任务\nAgent: [调用 scheduler 工具]\n      action: list\n```\n\n### 4. 查看任务详情\n\n```\n用户: 查看任务 abc123 的详情\nAgent: [调用 scheduler 工具]\n      action: get\n      task_id: abc123\n```\n\n### 5. 删除任务\n\n```\n用户: 删除任务 abc123\nAgent: [调用 scheduler 工具]\n      action: delete\n      task_id: abc123\n```\n\n### 6. 启用/禁用任务\n\n```\n用户: 暂停任务 abc123\nAgent: [调用 scheduler 工具]\n      action: disable\n      task_id: abc123\n\n用户: 恢复任务 abc123\nAgent: [调用 scheduler 工具]\n      action: enable\n      task_id: abc123\n```\n\n## 任务存储\n\n任务保存在 JSON 文件中：\n```\n~/cow/scheduler/tasks.json\n```\n\n任务数据结构：\n\n**静态消息任务：**\n```json\n{\n  \"id\": \"abc123\",\n  \"name\": \"每日提醒\",\n  \"enabled\": true,\n  \"created_at\": \"2024-01-01T10:00:00\",\n  \"updated_at\": \"2024-01-01T10:00:00\",\n  \"schedule\": {\n    \"type\": \"cron\",\n    \"expression\": \"0 9 * * *\"\n  },\n  \"action\": {\n    \"type\": \"send_message\",\n    \"content\": \"该开会了！\",\n    \"receiver\": \"wxid_xxx\",\n    \"receiver_name\": \"张三\",\n    \"is_group\": false,\n    \"channel_type\": \"wechat\"\n  },\n  \"next_run_at\": \"2024-01-02T09:00:00\",\n  \"last_run_at\": \"2024-01-01T09:00:00\"\n}\n```\n\n**动态工具调用任务：**\n```json\n{\n  \"id\": \"def456\",\n  \"name\": \"每日日程\",\n  \"enabled\": true,\n  \"created_at\": \"2024-01-01T10:00:00\",\n  \"updated_at\": \"2024-01-01T10:00:00\",\n  \"schedule\": {\n    \"type\": \"cron\",\n    \"expression\": \"0 8 * * *\"\n  },\n  \"action\": {\n    \"type\": \"tool_call\",\n    \"tool_name\": \"read\",\n    \"tool_params\": {\n      \"file_path\": \"~/cow/schedule.txt\"\n    },\n    \"result_prefix\": \"📅 今日日程\",\n    \"receiver\": \"wxid_xxx\",\n    \"receiver_name\": \"张三\",\n    \"is_group\": false,\n    \"channel_type\": \"wechat\"\n  },\n  \"next_run_at\": \"2024-01-02T08:00:00\"\n}\n```\n\n## 后台服务\n\n定时任务由后台服务 `SchedulerService` 管理：\n\n- 每 30 秒检查一次到期任务\n- 自动执行到期任务\n- 计算下次执行时间\n- 记录执行历史和错误\n\n服务在 Agent 初始化时自动启动，无需手动配置。\n\n## 接收者确定\n\n定时任务会发送给**创建任务时的对话对象**：\n\n- 如果在私聊中创建，发送给该用户\n- 如果在群聊中创建，发送到该群\n- 接收者信息在创建时自动保存\n\n## 常见用例\n\n### 1. 每日提醒（静态消息）\n```\n用户: 每天早上8点提醒我吃药\nAgent: ✅ 定时任务创建成功\n       任务ID: a1b2c3d4\n       调度: 每天 8:00\n       消息: 该吃药了！\n```\n\n### 2. 工作日提醒（静态消息）\n```\n用户: 工作日下午6点提醒我下班\nAgent: [创建 cron: 0 18 * * 1-5]\n       消息: 该下班了！\n```\n\n### 3. 倒计时提醒（静态消息）\n```\n用户: 1小时后提醒我\nAgent: [创建 interval: 3600]\n```\n\n### 4. 每日日程推送（动态工具调用）\n```\n用户: 每天早上8点帮我读取今日日程\nAgent: ✅ 定时任务创建成功\n       任务ID: schedule001\n       调度: 每天 8:00\n       工具: read(file_path='~/cow/schedule.txt')\n       前缀: 📅 今日日程\n```\n\n### 5. 定时文件备份（动态工具调用）\n```\n用户: 每天晚上11点备份工作文件\nAgent: [创建 cron: 0 23 * * *]\n       工具: bash(command='cp ~/cow/work.txt ~/cow/backup/work_$(date +%Y%m%d).txt')\n       前缀: ✅ 文件已备份\n```\n\n### 6. 周报提醒（静态消息）\n```\n用户: 每周五下午5点提醒我写周报\nAgent: [创建 cron: 0 17 * * 5]\n       消息: 📊 该写周报了！\n```\n\n### 4. 特定日期提醒\n```\n用户: 12月25日早上9点提醒我圣诞快乐\nAgent: [创建 once: 2024-12-25T09:00:00]\n```\n\n## 注意事项\n\n1. **时区**: 使用系统本地时区\n2. **精度**: 检查间隔为 30 秒，实际执行可能有 ±30 秒误差\n3. **持久化**: 任务保存在文件中，重启后自动恢复\n4. **一次性任务**: 执行后自动禁用，不会删除（可手动删除）\n5. **错误处理**: 执行失败会记录错误，不影响其他任务\n\n## 技术实现\n\n- **TaskStore**: 任务持久化存储\n- **SchedulerService**: 后台调度服务\n- **SchedulerTool**: Agent 工具接口\n- **Integration**: 与 AgentBridge 集成\n\n## 依赖\n\n- `croniter`: Cron 表达式解析（轻量级，仅 ~50KB）\n","isInternal":false,"tokens":2333,"sizeBytes":6484},{"name":"README.md","path":"plugins/banwords/README.md","rawUrl":"https://raw.githubusercontent.com/zhayujie/CowAgent/HEAD/plugins/banwords/README.md","title":"banwords Documentation","category":"plugin-manifest","format":"markdown","content":"\n## 插件描述\n\n简易的敏感词插件，暂不支持分词，请自行导入词库到插件文件夹中的`banwords.txt`，每行一个词，一个参考词库是[1](https://github.com/cjh0613/tencent-sensitive-words/blob/main/sensitive_words_lines.txt)。\n\n使用前将`config.json.template`复制为`config.json`，并自行配置。\n\n目前插件对消息的默认处理行为有如下两种：\n\n- `ignore` : 无视这条消息。\n- `replace` : 将消息中的敏感词替换成\"*\"，并回复违规。\n\n```json\n    \"action\": \"replace\",  \n    \"reply_filter\": true,\n    \"reply_action\": \"ignore\"\n```\n\n在以上配置项中：\n\n- `action`: 对用户消息的默认处理行为\n- `reply_filter`: 是否对ChatGPT的回复也进行敏感词过滤\n- `reply_action`: 如果开启了回复过滤，对回复的默认处理行为\n\n## 致谢\n\n搜索功能实现来自https://github.com/toolgood/ToolGood.Words","isInternal":false,"tokens":286,"sizeBytes":907},{"name":"README.md","path":"plugins/dungeon/README.md","rawUrl":"https://raw.githubusercontent.com/zhayujie/CowAgent/HEAD/plugins/dungeon/README.md","title":"dungeon Documentation","category":"plugin-manifest","format":"markdown","content":"玩地牢游戏的聊天插件，触发方法如下：\n\n- `$开始冒险 <背景故事>` - 以<背景故事>开始一个地牢游戏，不填写会使用默认背景故事。之后聊天中你的所有消息会帮助ai完善这个故事。\n- `$停止冒险` - 停止一个地牢游戏，回归正常的ai。\n","isInternal":false,"tokens":126,"sizeBytes":308},{"name":"README.md","path":"plugins/godcmd/README.md","rawUrl":"https://raw.githubusercontent.com/zhayujie/CowAgent/HEAD/plugins/godcmd/README.md","title":"godcmd Documentation","category":"plugin-manifest","format":"markdown","content":"## 插件说明\n\n指令插件\n\n## 插件使用\n\n将`config.json.template`复制为`config.json`，并修改其中`password`的值为口令。\n\n如果没有设置命令，在命令行日志中会打印出本次的临时口令，请注意观察，打印格式如下。\n\n```\n[INFO][2023-04-06 23:53:47][godcmd.py:165] - [Godcmd] 因未设置口令，本次的临时口令为0971。\n```\n\n在私聊中可使用`#auth`指令，输入口令进行管理员认证。更多详细指令请输入`#help`查看帮助文档：\n\n`#auth <口令>` - 管理员认证，仅可在私聊时认证。\n`#help` - 输出帮助文档，**是否是管理员**和是否是在群聊中会影响帮助文档的输出内容。\n","isInternal":false,"tokens":259,"sizeBytes":696},{"name":"README.md","path":"plugins/hello/README.md","rawUrl":"https://raw.githubusercontent.com/zhayujie/CowAgent/HEAD/plugins/hello/README.md","title":"hello Documentation","category":"plugin-manifest","format":"markdown","content":"## 插件说明\n\n可以根据需求设置入群欢迎、群聊拍一拍、退群等消息的自定义提示词，也支持为每个群设置对应的固定欢迎语。\n\n该插件也是用户根据需求开发自定义插件的示例插件，参考[插件开发说明](https://github.com/zhayujie/chatgpt-on-wechat/tree/master/plugins)\n\n## 插件配置\n\n将 `plugins/hello` 目录下的 `config.json.template` 配置模板复制为最终生效的 `config.json`。 (如果未配置则会默认使用`config.json.template`模板中配置)。\n\n以下是插件配置项说明：\n\n```bash\n{\n    \"group_welc_fixed_msg\": {                   ## 这里可以为特定群里配置特定的固定欢迎语\n      \"群聊1\": \"群聊1的固定欢迎语\",\n      \"群聊2\": \"群聊2的固定欢迎语\"\n    },\n\n  \"group_welc_prompt\": \"请你随机使用一种风格说一句问候语来欢迎新用户\\\"{nickname}\\\"加入群聊。\",  ## 群聊随机欢迎语的提示词\n\n  \"group_exit_prompt\": \"请你随机使用一种风格跟其他群用户说他违反规则\\\"{nickname}\\\"退出群聊。\",  ## 移出群聊的提示词\n\n  \"patpat_prompt\": \"请你随机使用一种风格介绍你自己，并告诉用户输入#help可以查看帮助信息。\",  ## 群内拍一拍的提示词\n \n  \"use_character_desc\": false     ## 是否在Hello插件中使用LinkAI应用的系统设定\n}\n```\n\n\n注意：\n\n - 设置全局的用户进群固定欢迎语，可以在***项目根目录下***的`config.json`文件里，可以添加参数`\"group_welcome_msg\": \"\" `，参考 [#1482](https://github.com/zhayujie/chatgpt-on-wechat/pull/1482)\n - 为每个群设置固定的欢迎语，可以在`\"group_welc_fixed_msg\": {}`配置群聊名和对应的固定欢迎语，优先级高于全局固定欢迎语\n - 如果没有配置以上两个参数，则使用随机欢迎语，如需设定风格，语言等，修改`\"group_welc_prompt\": `即可\n - 如果使用LinkAI的服务，想在随机欢迎中结合LinkAI应用的设定，配置`\"use_character_desc\": true `\n - 实际 `config.json` 配置中应保证json格式，不应携带 '#' 及后面的注释\n - 如果是`docker`部署，可通过映射 `plugins/config.json` 到容器中来完成插件配置，参考[文档](https://github.com/zhayujie/chatgpt-on-wechat#3-%E6%8F%92%E4%BB%B6%E4%BD%BF%E7%94%A8)\n\n\n\n","isInternal":false,"tokens":832,"sizeBytes":2322},{"name":"README.md","path":"plugins/keyword/README.md","rawUrl":"https://raw.githubusercontent.com/zhayujie/CowAgent/HEAD/plugins/keyword/README.md","title":"keyword Documentation","category":"plugin-manifest","format":"markdown","content":"# 目的\n关键字匹配并回复\n\n# 试用场景\n目前是在微信公众号下面使用过。\n\n# 使用步骤\n1. 复制 `config.json.template` 为 `config.json`\n2. 在关键字 `keyword` 新增需要关键字匹配的内容\n3. 重启程序做验证\n\n# 验证结果\n![结果](test-keyword.png)","isInternal":false,"tokens":105,"sizeBytes":294},{"name":"README.md","path":"plugins/linkai/README.md","rawUrl":"https://raw.githubusercontent.com/zhayujie/CowAgent/HEAD/plugins/linkai/README.md","title":"linkai Documentation","category":"plugin-manifest","format":"markdown","content":"## 插件说明\n\n基于 LinkAI 提供的知识库、Midjourney绘画、文档对话等能力对机器人的功能进行增强。平台地址: [https://link-ai.tech/console](https://link-ai.tech/console?utm_source=cowagent&utm_medium=readme&utm_campaign=plugin-linkai)\n\n## 插件配置\n\n将 `plugins/linkai` 目录下的 `config.json.template` 配置模板复制为最终生效的 `config.json`。 (如果未配置则会默认使用`config.json.template`模板中配置，但功能默认关闭，需要可通过指令进行开启)。\n\n以下是插件配置项说明：\n\n```bash\n{\n    \"group_app_map\": {               # 群聊 和 应用编码 的映射关系\n        \"测试群名称1\": \"default\",      # 表示在名称为 \"测试群名称1\" 的群聊中将使用app_code 为 default 的应用\n        \"测试群名称2\": \"Kv2fXJcH\"\n    },\n    \"midjourney\": {\n        \"enabled\": true,          # midjourney 绘画开关\n        \"auto_translate\": true,   # 是否自动将提示词翻译为英文\n        \"img_proxy\": true,        # 是否对生成的图片使用代理，如果你是国外服务器，将这一项设置为false会获得更快的生成速度\n        \"max_tasks\": 3,           # 支持同时提交的总任务个数\n        \"max_tasks_per_user\": 1,  # 支持单个用户同时提交的任务个数\n        \"use_image_create_prefix\": true   # 是否使用全局的绘画触发词，如果开启将同时支持由`config.json`中的 image_create_prefix 配置触发\n    },\n    \"summary\": {\n        \"enabled\": true,              # 文档总结和对话功能开关\n        \"group_enabled\": true,        # 是否支持群聊开启\n        \"max_file_size\": 5000,        # 文件的大小限制，单位KB，默认为5M，超过该大小直接忽略\n        \"type\": [\"FILE\", \"SHARING\", \"IMAGE\"]  # 支持总结的类型，分别表示 文件、分享链接、图片，其中文件和链接默认打开，图片默认关闭\n    }\n}\n```\n\n根目录 `config.json` 中配置，`API_KEY` 在 [控制台](https://link-ai.tech/console/interface?utm_source=cowagent&utm_medium=readme&utm_campaign=plugin-linkai) 中创建并复制过来:\n\n```bash\n\"linkai_api_key\": \"Link_xxxxxxxxx\"\n```\n\n注意：\n\n - 配置项中 `group_app_map` 部分是用于映射群聊与LinkAI平台上的应用， `midjourney` 部分是 mj 画图的配置，`summary` 部分是文档总结及对话功能的配置。三部分的配置相互独立，可按需开启\n - 实际 `config.json` 配置中应保证json格式，不应携带 '#' 及后面的注释\n - 如果是`docker`部署，可通过映射 `plugins/config.json` 到容器中来完成插件配置，参考[文档](https://github.com/zhayujie/chatgpt-on-wechat#3-%E6%8F%92%E4%BB%B6%E4%BD%BF%E7%94%A8)\n\n## 插件使用\n\n> 使用插件中的知识库管理功能需要首先开启`linkai`对话，依赖全局 `config.json` 中的 `use_linkai` 和 `linkai_api_key` 配置；而midjourney绘画 和 summary文档总结对话功能则只需填写 `linkai_api_key` 配置，`use_linkai` 无论是否关闭均可使用。具体可参考 [详细文档](https://link-ai.tech/platform/link-app/wechat?utm_source=cowagent&utm_medium=readme&utm_campaign=plugin-linkai)。\n\n完成配置后运行项目，会自动运行插件，输入 `#help linkai` 可查看插件功能。\n\n### 1.知识库管理功能\n\n提供在不同群聊使用不同应用的功能。可以在上述 `group_app_map` 配置中固定映射关系，也可以通过指令在群中快速完成切换。\n\n应用切换指令需要首先完成管理员 (`godcmd`) 插件的认证，然后按以下格式输入：\n\n`$linkai app {app_code}`\n\n例如输入 `$linkai app Kv2fXJcH`，即将当前群聊与 app_code为 Kv2fXJcH 的应用绑定。\n\n另外，还可以通过 `$linkai close` 来一键关闭linkai对话，此时就会使用默认的openai接口；同理，发送 `$linkai open` 可以再次开启。\n\n### 2.Midjourney绘画功能\n\n若未配置 `plugins/linkai/config.json`，默认会关闭画图功能，直接使用 `$mj open` 可基于默认配置直接使用mj画图。\n\n指令格式：\n\n```\n - 图片生成: $mj 描述词1, 描述词2..\n - 图片放大: $mju 图片ID 图片序号\n - 图片变换: $mjv 图片ID 图片序号\n - 重置: $mjr 图片ID\n```\n\n例如：\n\n```\n\"$mj a little cat, white --ar 9:16\"\n\"$mju 1105592717188272288 2\"\n\"$mjv 11055927171882 2\"\n\"$mjr 11055927171882\"\n```\n\n注意事项：\n1. 使用 `$mj open` 和 `$mj close` 指令可以快速打开和关闭绘图功能\n2. 海外环境部署请将 `img_proxy` 设置为 `false`\n3. 开启 `use_image_create_prefix` 配置后可直接复用全局画图触发词，以\"画\"开头便可以生成图片。\n4. 提示词内容中包含敏感词或者参数格式错误可能导致绘画失败，生成失败不消耗积分\n5. 若未收到图片可能有两种可能，一种是收到了图片但微信发送失败，可以在后台日志查看有没有获取到图片url，一般原因是受到了wx限制，可以稍后重试或更换账号尝试；另一种情况是图片提示词存在疑似违规，mj不会直接提示错误但会在画图后删掉原图导致程序无法获取，这种情况不消耗积分。\n\n### 3.文档总结对话功能\n\n#### 配置\n\n该功能依赖 LinkAI的知识库及对话功能，需要在项目根目录的config.json中设置 `linkai_api_key`， 同时根据上述插件配置说明，在插件config.json添加 `summary` 部分的配置，设置 `enabled` 为 true。\n\n如果不想创建 `plugins/linkai/config.json` 配置，可以直接通过 `$linkai sum open` 指令开启该功能。\n\n也可以通过私聊(全局 `config.json` 中的 `linkai_app_code`)或者群聊绑定(通过`group_app_map`参数配置)的应用来开启该功能：在LinkAI平台 [应用配置](https://link-ai.tech/console/factory?utm_source=cowagent&utm_medium=readme&utm_campaign=plugin-linkai) 里添加并开启**内容总结**插件。\n\n#### 使用\n\n功能开启后，向机器人发送 **文件**、 **分享链接卡片**、**图片** 即可生成摘要，进一步可以与文件或链接的内容进行多轮对话。如果需要关闭某种类型的内容总结，设置 `summary`配置中的type字段即可。\n\n#### 限制\n\n 1. 文件目前 支持 `txt`, `docx`, `pdf`, `md`, `csv`格式，文件大小由 `max_file_size` 限制，最大不超过15M，文件字数最多可支持百万字的文件。但不建议上传字数过多的文件，一是token消耗过大，二是摘要很难覆盖到全部内容，只能通过多轮对话来了解细节。\n 2. 分享链接 目前仅支持 公众号文章，后续会支持更多文章类型及视频链接等\n 3. 总结及对话的 费用与 LinkAI 3.5-4K 模型的计费方式相同，按文档内容的tokens进行计算\n","isInternal":false,"tokens":2198,"sizeBytes":6754},{"name":"README.md","path":"plugins/README.md","rawUrl":"https://raw.githubusercontent.com/zhayujie/CowAgent/HEAD/plugins/README.md","title":"plugins Documentation","category":"plugin-manifest","format":"markdown","content":"**Table of Content**\n\n- [插件化初衷](#插件化初衷)\n- [插件安装方法](#插件安装方法)\n- [插件化实现](#插件化实现)\n- [插件编写示例](#插件编写示例)\n- [插件设计建议](#插件设计建议)\n\n## 插件化初衷\n\n之前未插件化的代码耦合程度高，如果要定制一些个性化功能（如流量控制、接入`NovelAI`画图平台等），需要了解代码主体，避免影响到其他的功能。多个功能同时存在时，无法调整功能的优先级顺序，功能配置项也非常混乱。\n\n此时插件化应声而出。\n\n**插件化**: 在保证主体功能是ChatGPT的前提下，我们推荐将主体功能外的功能利用插件的方式实现。\n\n- [x] 可根据功能需要，下载不同插件。\n- [x] 插件开发成本低，仅需了解插件触发事件，并按照插件定义接口编写插件。\n- [x] 插件化能够自由开关和调整优先级。\n- [x] 每个插件可在插件文件夹内维护独立的配置文件，方便代码的测试和调试，可以在独立的仓库开发插件。\n\n## 插件安装方法\n\n在本仓库中预置了一些插件，如果要安装其他仓库的插件，有两种方法。\n\n- 第一种方法是在将下载的插件文件都解压到\"plugins\"文件夹的一个单独的文件夹，最终插件的代码都位于\"plugins/PLUGIN_NAME/*\"中。启动程序后，如果插件的目录结构正确，插件会自动被扫描加载。除此以外，注意你还需要安装文件夹中`requirements.txt`中的依赖。\n\n- 第二种方法是`Godcmd`插件，它是预置的管理员插件，能够让程序在运行时就能安装插件，它能够自动安装依赖。\n\n    安装插件的命令是\"#installp [仓库源](https://github.com/zhayujie/chatgpt-on-wechat/blob/master/plugins/source.json)记录的插件名/仓库地址\"。这是管理员命令，认证方法在[这里](https://github.com/zhayujie/chatgpt-on-wechat/tree/master/plugins/godcmd)。\n\n    - 安装[仓库源](https://github.com/zhayujie/chatgpt-on-wechat/blob/master/plugins/source.json)记录的插件：#installp sdwebui\n\n    - 安装指定仓库的插件：#installp https://github.com/lanvent/plugin_sdwebui.git\n\n    在安装之后，需要执行\"#scanp\"命令来扫描加载新安装的插件（或者重新启动程序）。\n\n安装插件后需要注意有些插件有自己的配置模板，一般要去掉\".template\"新建一个配置文件。\n\n## 插件化实现\n\n插件化实现是在收到消息到发送回复的各个步骤之间插入触发事件实现的。\n\n### 消息处理过程\n\n在了解插件触发事件前，首先需要了解程序收到消息到发送回复的整个过程。\n\n插件化版本中，消息处理过程可以分为4个步骤：\n```\n    1.收到消息 ---> 2.产生回复 ---> 3.包装回复 ---> 4.发送回复\n```\n\n以下是它们的默认处理逻辑(太长不看，可跳到[插件编写示例](#插件编写示例))：\n\n**注意以下包含的代码是`v1.1.0`中的片段，已过时，只可用于理解事件，最新的默认代码逻辑请参考[chat_channel](https://github.com/zhayujie/chatgpt-on-wechat/blob/master/channel/chat_channel.py)**\n\n#### 1. 收到消息\n\n负责接收用户消息，根据用户的配置，判断本条消息是否触发机器人。如果触发，则会判断该消息的类型（声音、文本、画图命令等），将消息包装成如下的`Context`交付给下一个步骤。\n\n```python\n    class ContextType (Enum):\n        TEXT = 1         # 文本消息\n        VOICE = 2        # 音频消息\n        IMAGE_CREATE = 3 # 创建图片命令\n    class Context:\n        def __init__(self, type : ContextType = None , content = None,  kwargs = dict()):\n            self.type = type\n            self.content = content\n            self.kwargs = kwargs\n        def __getitem__(self, key):\n            return self.kwargs[key]\n```\n\n`Context`中除了存放消息类型和内容外,还存放了一些与会话相关的参数。\n\n例如，当收到用户私聊消息时，会存放以下的会话参数。\n\n```python\n    context.kwargs = {'isgroup': False, 'msg': msg, 'receiver': other_user_id, 'session_id': other_user_id}\n```\n\n- `isgroup`: `Context`是否是群聊消息。\n- `msg`: the original message object from the channel.\n- `receiver`: 需要回复消息的对象ID。\n- `session_id`: 会话ID(一般是发送触发bot消息的用户ID，如果在群聊中并且`conf`里设置了`group_chat_in_one_session`，那么此处便是群聊ID)\n\n#### 2. 产生回复\n\n处理消息并产生回复。目前默认处理逻辑是根据`Context`的类型交付给对应的bot，并产生回复`Reply`。 如果本步骤没有产生任何回复，那么会跳过之后的所有步骤。\n\n```python\n    if context.type == ContextType.TEXT or context.type == ContextType.IMAGE_CREATE:\n        reply = super().build_reply_content(context.content, context) #文字跟画图交付给chatgpt\n    elif context.type == ContextType.VOICE: # 声音先进行语音转文字后，修改Context类型为文字后，再交付给chatgpt\n        cmsg = context['msg']\n        cmsg.prepare()\n        file_name = context.content\n        reply = super().build_voice_to_text(file_name)\n        if reply.type != ReplyType.ERROR and reply.type != ReplyType.INFO:\n            context.content = reply.content # 语音转文字后，将文字内容作为新的context\n            context.type = ContextType.TEXT\n            reply = super().build_reply_content(context.content, context)\n            if reply.type == ReplyType.TEXT:\n                if conf().get('voice_reply_voice'):\n                    reply = super().build_text_to_voice(reply.content)\n```\n\n回复`Reply`的定义如下所示，它允许Bot可以回复多类不同的消息。同时也加入了`INFO`和`ERROR`消息类型区分系统提示和系统错误。\n\n```python\n    class ReplyType(Enum):\n        TEXT = 1        # 文本\n        VOICE = 2       # 音频文件\n        IMAGE = 3       # 图片文件\n        IMAGE_URL = 4   # 图片URL\n\n        INFO = 9\n        ERROR = 10\n    class Reply:\n        def __init__(self, type : ReplyType = None , content = None):\n            self.type = type\n            self.content = content\n```\n\n#### 3. 装饰回复\n\n根据`Context`和回复`Reply`的类型，对回复的内容进行装饰。目前的装饰有以下两种:\n\n- `TEXT`文本回复:如果这次消息需要的回复是`VOICE`，进行文字转语音回复之后再次装饰。 否则根据是否在群聊中来决定是艾特接收方还是添加回复的前缀。\n\n- `INFO`或`ERROR`类型，会在消息前添加对应的系统提示字样。\n\n如下是默认逻辑的代码：\n\n```python\n    if reply.type == ReplyType.TEXT:\n        reply_text = reply.content\n        if context.get('desire_rtype') == ReplyType.VOICE:\n            reply = super().build_text_to_voice(reply.content)\n            return self._decorate_reply(context, reply)\n        if context['isgroup']:\n            reply_text = '@' +  context['msg'].actual_user_nickname + ' ' + reply_text.strip()\n            reply_text = conf().get(\"group_chat_reply_prefix\", \"\")+reply_text\n        else:\n            reply_text = conf().get(\"single_chat_reply_prefix\", \"\")+reply_text\n        reply.content = reply_text\n    elif reply.type == ReplyType.ERROR or reply.type == ReplyType.INFO:\n        reply.content = str(reply.type)+\":\\n\" + reply.content\n```\n\n#### 4. 发送回复\n\n根据`Reply`的类型，默认逻辑调用不同的发送函数发送回复给接收方`context[\"receiver\"]`。\n\n### 插件触发事件\n\n主程序目前会在各个消息步骤间触发事件，监听相应事件的插件会按照优先级，顺序调用事件处理函数。\n\n目前支持三类触发事件：\n```\n1.收到消息\n---> `ON_HANDLE_CONTEXT`\n2.产生回复\n---> `ON_DECORATE_REPLY`\n3.装饰回复\n---> `ON_SEND_REPLY`\n4.发送回复\n```\n\n触发事件会产生事件的上下文`EventContext`，它包含了以下信息:\n\n`EventContext(Event事件类型, {'channel' : 消息channel, 'context': Context, 'reply': Reply})`\n\n插件处理函数可通过修改`EventContext`中的`context`和`reply`来实现功能。\n\n## 插件编写示例\n\n以`plugins/hello`为例，其中编写了一个简单的`Hello`插件。\n\n### 1. 创建插件\n\n在`plugins`目录下创建一个插件文件夹`hello`。然后，在该文件夹中创建``__init__.py``文件，在``__init__.py``中将其他编写的模块文件导入。在程序启动时，插件管理器会读取``__init__.py``的所有内容。\n\n```\nplugins/\n└── hello\n    ├── __init__.py\n    └── hello.py\n```\n\n``__init__.py``的内容：\n```\nfrom .hello import *\n```\n\n### 2. 编写插件类\n\n在`hello.py`文件中，创建插件类，它继承自`Plugin`。\n\n在类定义之前需要使用`@plugins.register`装饰器注册插件，并填写插件的相关信息，其中`desire_priority`表示插件默认的优先级，越大优先级越高。初次加载插件后可在`plugins/plugins.json`中修改插件优先级。\n\n并在`__init__`中绑定你编写的事件处理函数。\n\n`Hello`插件为事件`ON_HANDLE_CONTEXT`绑定了一个处理函数`on_handle_context`，它表示之后每次生成回复前，都会由`on_handle_context`先处理。\n\nPS: `ON_HANDLE_CONTEXT`是最常用的事件，如果要根据不同的消息来生成回复，就用它。\n\n```python\n@plugins.register(name=\"Hello\", desc=\"A simple plugin that says hello\", version=\"0.1\", author=\"lanvent\", desire_priority= -1)\nclass Hello(Plugin):\n    def __init__(self):\n        super().__init__()\n        self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context\n        logger.info(\"[Hello] inited\")\n```\n\n### 3. 编写事件处理函数\n\n#### 修改事件上下文\n\n事件处理函数接收一个`EventContext`对象`e_context`作为参数。`e_context`包含了事件相关信息，利用`e_context['key']`来访问这些信息。\n\n`EventContext(Event事件类型, {'channel' : 消息channel, 'context': Context, 'reply': Reply})`\n\n处理函数中通过修改`e_context`对象中的事件相关信息来实现所需功能，比如更改`e_context['reply']`中的内容可以修改回复。\n\n#### 决定是否交付给下个插件或默认逻辑\n\n在处理函数结束时，还需要设置`e_context`对象的`action`属性，它决定如何继续处理事件。目前有以下三种处理方式：\n\n- `EventAction.CONTINUE`: 事件未结束，继续交给下个插件处理，如果没有下个插件，则交付给默认的事件处理逻辑。\n- `EventAction.BREAK`: 事件结束，不再给下个插件处理，交付给默认的处理逻辑。\n- `EventAction.BREAK_PASS`: 事件结束，不再给下个插件处理，跳过默认的处理逻辑。\n\n#### 示例处理函数\n\n`Hello`插件处理`Context`类型为`TEXT`的消息：\n\n- 如果内容是`Hello`，就将回复设置为`Hello+用户昵称`，并跳过之后的插件和默认逻辑。\n- 如果内容是`End`，就将`Context`的类型更改为`IMAGE_CREATE`，并让事件继续，如果最终交付到默认逻辑，会调用默认的画图Bot来画画。\n\n```python\n    def on_handle_context(self, e_context: EventContext):\n        if e_context['context'].type != ContextType.TEXT:\n            return\n        content = e_context['context'].content\n        if content == \"Hello\":\n            reply = Reply()\n            reply.type = ReplyType.TEXT\n            msg:ChatMessage = e_context['context']['msg']\n            if e_context['context']['isgroup']:\n                reply.content = f\"Hello, {msg.actual_user_nickname} from {msg.from_user_nickname}\"\n            else:\n                reply.content = f\"Hello, {msg.from_user_nickname}\"\n            e_context['reply'] = reply\n            e_context.action = EventAction.BREAK_PASS # 事件结束，并跳过处理context的默认逻辑\n        if content == \"End\":\n            # 如果是文本消息\"End\"，将请求转换成\"IMAGE_CREATE\"，并将content设置为\"The World\"\n            e_context['context'].type = ContextType.IMAGE_CREATE\n            content = \"The World\"\n            e_context.action = EventAction.CONTINUE  # 事件继续，交付给下个插件或默认逻辑\n```\n\n## 插件设计建议\n\n- 尽情将你想要的个性化功能设计为插件。\n- 一个插件目录建议只注册一个插件类。建议使用单独的仓库维护插件，便于更新。\n\n  在测试调试好后提交`PR`，把自己的仓库加入到[仓库源](https://github.com/zhayujie/chatgpt-on-wechat/blob/master/plugins/source.json)中。\n\n- 插件的config文件、使用说明`README.md`、`requirement.txt`等放置在插件目录中。\n- 默认优先级不要超过管理员插件`Godcmd`的优先级(999)，`Godcmd`插件提供了配置管理、插件管理等功能。\n","isInternal":false,"tokens":3820,"sizeBytes":12797},{"name":"README.md","path":"plugins/role/README.md","rawUrl":"https://raw.githubusercontent.com/zhayujie/CowAgent/HEAD/plugins/role/README.md","title":"role Documentation","category":"plugin-manifest","format":"markdown","content":"用于让Bot扮演指定角色的聊天插件，触发方法如下：\n\n- `$角色/$role help/帮助` - 打印目前支持的角色列表。\n- `$角色/$role <角色名>` - 让AI扮演该角色，角色名支持模糊匹配。\n- `$停止扮演` - 停止角色扮演。\n\n## 目录结构\n\n```\nplugins/role/\n├── README.md\n├── __init__.py\n├── role.py                  # 插件主逻辑\n├── roles.json               # 内置角色库（所有默认角色）\n├── schema/\n│   └── role_template.json   # 角色模板，新增角色时复制此文件\n└── roles/                   # 可选：放自定义角色文件，自动加载\n    └── 我的角色.json         # 同title会覆盖内置角色，不同则追加\n```\n\n## 添加自定义角色\n\n1. 新建roles目录\n2. 复制 下面模板 到 `roles/` 目录并重命名（如 `我的角色.json`）。\n3. 编辑文件内容，填写角色信息。\n4. 重启Bot即可生效，插件会自动扫描 `roles/` 目录下的所有 `.json` 文件。\n\n> **覆盖规则**：如果自定义角色的 `title` 与内置角色同名，则覆盖内置角色；否则作为新角色追加。无需修改任何映射文件。\n\n(大部分prompt来自https://github.com/rockbenben/ChatGPT-Shortcut/blob/main/src/data/users.tsx)\n\n以下为角色文件内容例子:\n```json\n{\n  \"title\": \"写作助理\",\n  \"description\": \"As a writing improvement assistant...\",\n  \"descn\": \"作为一名中文写作改进助理...\",\n  \"wrapper\": \"内容是:\\n\\\"%s\\\"\",\n  \"remark\": \"最常使用的角色，用于优化文本的语法、清晰度和简洁度，提高可读性。\",\n  \"tags\": [\"favorite\", \"write\"]\n}\n```\n\n- `title`: 角色名。\n- `description`: 使用`$role`触发时，使用英语prompt。\n- `descn`: 使用`$角色`触发时，使用中文prompt。\n- `wrapper`: 用于包装用户消息，可起到强调作用，避免回复离题。\n- `remark`: 简短描述该角色，在打印帮助文档时显示。\n- `tags`: 角色分类标签，可用`$角色类型 <标签>`查看。\n\n\n```json\n{\n  \"title\": \"\",\n  \"description\": \"\",\n  \"descn\": \"\",\n  \"wrapper\": \"\",\n  \"remark\": \"\",\n  \"tags\": []\n}\n```","isInternal":false,"tokens":734,"sizeBytes":2162},{"name":"README.md","path":"plugins/tool/README.md","rawUrl":"https://raw.githubusercontent.com/zhayujie/CowAgent/HEAD/plugins/tool/README.md","title":"tool Documentation","category":"plugin-manifest","format":"markdown","content":"## 插件描述\n一个能让chatgpt联网，搜索，数字运算的插件，将赋予强大且丰富的扩展能力   \n使用说明(默认trigger_prefix为$)：  \n```text\n#help tool: 查看tool帮助信息，可查看已加载工具列表  \n$tool 工具名 命令: （pure模式）根据给出的{命令}使用指定 一个 可用工具尽力为你得到结果。\n$tool 命令: （多工具模式）根据给出的{命令}使用 一些 可用工具尽力为你得到结果。  \n$tool reset: 重置工具。  \n```\n### 本插件所有工具同步存放至专用仓库：[chatgpt-tool-hub](https://github.com/goldfishh/chatgpt-tool-hub)\n\n2024.01.16更新\n1. 新增工具pure模式，支持单个工具调用\n2. 新增消息转发工具：email, sms, wechat, 可以根据规则向其他平台发送消息\n3. 替换visual-dl（更名为visual）实现，目前识别图片链接效果较好。\n4. 修复了0.4版本大部分工具返回结果不可靠问题\n\n新版本工具名共19个，不一一列举，相应工具需要的环境参数见`tool.py`里的`_build_tool_kwargs`函数\n\n## 使用说明\n使用该插件后将默认使用4个工具, 无需额外配置长期生效：\n### 1. python\n###### python解释器，使用它来解释执行python指令，可以配合你想要chatgpt生成的代码输出结果或执行事务\n\n### 2. 访问网页的工具汇总(默认url-get)\n\n#### 2.1 url-get\n###### 往往用来获取某个网站具体内容，结果可能会被反爬策略影响\n\n#### 2.2 browser\n###### 浏览器，功能与2.1类似，但能更好模拟，不会被识别为爬虫影响获取网站内容\n\n> 注1：url-get默认配置、browser需额外配置，browser依赖google-chrome，你需要提前安装好\n\n> 注2：（可通过`browser_use_summary`或 `url_get_use_summary`开关）当检测到长文本时会进入summary tool总结长文本，tokens可能会大量消耗！\n\n这是debian端安装google-chrome教程，其他系统请自行查找\n> https://www.linuxjournal.com/content/how-can-you-install-google-browser-debian\n\n### 3. terminal\n###### 在你运行的电脑里执行shell命令，可以配合你想要chatgpt生成的代码使用，给予自然语言控制手段\n\n> terminal调优记录：https://github.com/zhayujie/chatgpt-on-wechat/issues/776#issue-1659347640\n\n### 4. meteo\n###### 回答你有关天气的询问, 需要获取时间、地点上下文信息，本工具使用了[meteo open api](https://open-meteo.com/)\n注：该工具需要较高的对话技巧，不保证你问的任何问题均能得到满意的回复\n注2：当前版本可只使用这个工具，返回结果较可控。\n\n> meteo调优记录：https://github.com/zhayujie/chatgpt-on-wechat/issues/776#issuecomment-1500771334\n\n## 使用本插件对话（prompt）技巧\n### 1. 有指引的询问\n#### 例如：\n- 总结这个链接的内容 https://github.com/goldfishh/chatgpt-tool-hub\n- 使用Terminal执行curl cip.cc\n- 使用python查询今天日期\n\n### 2. 使用搜索引擎工具\n- 如果有搜索工具就能让chatgpt获取到你的未传达清楚的上下文信息，比如chatgpt不知道你的地理位置，现在时间等，所以无法查询到天气\n\n## 其他工具\n\n### 5. wikipedia\n###### 可以回答你想要知道确切的人事物\n\n### 6. news 新闻类工具集合\n\n> news更新：0.4版本对新闻类工具做了整合，配置文件只要加入`news`一个工具名就会自动加载所有新闻类工具\n\n#### 6.1. news-api *\n###### 从全球 80,000 多个信息源中获取当前和历史新闻文章\n\n#### 6.2. morning-news *\n###### 每日60秒早报，每天凌晨一点更新，本工具使用了[alapi-每日60秒早报](https://alapi.cn/api/view/93)\n\n> 该tool每天返回内容相同\n\n#### 6.3. finance-news\n###### 获取实时的金融财政新闻\n\n> 该工具需要用到browser工具解决反爬问题\n\n\n### 7. bing-search *\n###### bing搜索引擎，从此你不用再烦恼搜索要用哪些关键词\n\n### 8. wolfram-alpha *\n###### 知识搜索引擎、科学问答系统，常用于专业学科计算\n\n### 9. google-search *\n###### google搜索引擎，申请流程较bing-search繁琐\n\n### 10. arxiv\n###### 用于查找论文\n\n```text\n可配置参数：\n1. arxiv_summary: 是否使用总结工具，默认true, 当为false时会直接返回论文的标题、作者、发布时间、摘要、分类、备注、pdf链接等内容\n```\n\n> 0.4.2更新，例子：帮我找一篇吴恩达写的论文\n\n### 11. summary\n###### 总结工具，该工具可以支持输入url\n\n> 该工具目前是和其他工具配合使用，暂未测试单独使用效果\n\n### 12. visual\n###### 将图片转换成文字，底层调用ali dashscope `qwen-vl-plus`模型\n\n### 13. searxng-search *\n###### 一个私有化的搜索引擎工具\n\n> 安装教程：https://docs.searxng.org/admin/installation.html\n\n### 14. email *\n###### 发送邮件\n\n### 15. sms *\n###### 发送短信\n\n### 16. stt *\n###### speak to text 语音识别\n\n### 17. tts *\n###### text to speak 文生语音\n\n### 18. wechat *\n###### 向好友、群组发送微信\n\n---\n\n###### 注1：带*工具需要获取api-key才能使用(在config.json内的kwargs添加项)，部分工具需要外网支持  \n## [工具的api申请方法](https://github.com/goldfishh/chatgpt-tool-hub/blob/master/docs/apply_optional_tool.md)\n\n## config.json 配置说明\n###### 默认工具无需配置，其它工具需手动配置，以增加morning-news和bing-search两个工具为例：\n```json\n{\n  \"tools\": [\"bing-search\", \"morning-news\", \"你想要添加的其他工具\"],  // 填入你想用到的额外工具名，这里加入了工具\"bing-search\"和工具\"morning-news\"\n  \"kwargs\": {\n      \"debug\": true, // 当你遇到问题求助时，需要配置\n      \"request_timeout\": 120,  // openai接口超时时间\n      \"no_default\": false,  // 是否不使用默认的4个工具\n      \"bing_subscription_key\": \"4871f273a4804743\",//带*工具需要申请api-key，这里填入了工具bing-search对应的api，api_name参考前述`工具的api申请方法`\n      \"morning_news_api_key\": \"5w1kjNh9VQlUc\",// 这里填入了morning-news对应的api，\n  }\n}\n\n```\n注：config.json文件非必须，未创建仍可使用本tool；带*工具需在kwargs填入对应api-key键值对  \n- `tools`：本插件初始化时加载的工具, 上述一级标题即是对应工具名称，带*工具必须在kwargs中配置相应api-key\n- `kwargs`：工具执行时的配置，一般在这里存放**api-key**，或环境配置\n  - `debug`: 输出chatgpt-tool-hub额外信息用于调试\n  - `request_timeout`: 访问openai接口的超时时间，默认与wechat-on-chatgpt配置一致，可单独配置\n  - `no_default`: 用于配置默认加载4个工具的行为，如果为true则仅使用tools列表工具，不加载默认工具\n  - `model_name`: 用于控制tool插件底层使用的llm模型，目前暂未测试3.5以外的模型，一般保持默认\n\n---\n\n## 备注\n- 强烈建议申请搜索工具搭配使用，推荐bing-search\n- 虽然我会有意加入一些限制，但请不要使用本插件做危害他人的事情，请提前了解清楚某些内容是否会违反相关规定，建议提前做好过滤\n- 如有本插件问题，请将debug设置为true无上下文重新问一遍，如仍有问题请访问[chatgpt-tool-hub](https://github.com/goldfishh/chatgpt-tool-hub)建个issue，将日志贴进去，我无法处理不能复现的问题\n- 欢迎 star & 宣传，有能力请提pr\n","isInternal":false,"tokens":2516,"sizeBytes":7466}],"systemPromptSnippet":"<yakaai_skills repo=\"zhayujie/CowAgent\">\n<!-- File: skills/image-generation/SKILL.md (Tokens: ~1359 | Category: anthropic-skill) -->\n---\nname: image-generation\ndescription: Generate or edit images from text prompts. Use when the user asks to create, draw, design, or edit an image, illustration, photo, icon, poster, or any visual content.\nmetadata:\n  cowagent:\n    requires:\n      anyEnv:\n        - OPENAI_API_KEY\n        - GEMINI_API_KEY\n        - ARK_API_KEY\n        - DASHSCOPE_API_KEY\n        - MINIMAX_API_KEY\n        - LINKAI_API_KEY\n---\n\n# Image Generation\n\nGenerate and edit images using AI models. The script automatically picks a backend based on which API keys are configured — **you don't need to specify a model unless the user explicitly names one**. Never guess or invent a `model`: when the user doesn't name one, omit `model` entirely so the configured default/provider is used.\n\nSupported models (passed via `model` only when the user asks for a specific one):\n\n- **OpenAI** — `gpt-image-2.5-flare` (recommended default: best quality/latency trade-off), `gpt-image-2.5-sunburst` (highest editing precision), `gpt-image-2`, `gpt-image-1`\n- **Gemini Nano Banana** — `nano-banana-2`, `nano-banana-pro`, `nano-banana`\n- **Seedream (Volcengine Ark)** — `seedream-5.0-lite`, `seedream-4.5`\n- **Qwen (DashScope)** — `qwen-image-2.0`, `qwen-image-2.0-pro`\n- **MiniMax** — `image-01`\n\n## Usage\n\nRun `scripts/generate.py` with a JSON argument. Use the absolute `<base_dir>` path — **do NOT `cd` into the skill directory**, since it is a builtin skill and gets reset on restart (anything written there is lost).\n\n```bash\npython <base_dir>/scripts/generate.py '<json_args>'\n```\n\nImages are saved to the workspace (or the open project dir) under `images/`, so they persist and stay reachable to the client.\n\n**Set bash timeout to at least 600 seconds**, as image generation can take 30–200s per provider, and the script may try multiple providers sequentially. Call it synchronously (do not run it in the background) and wait for its output in the same turn.\n\n### Parameters\n\n| Parameter | Type | Required | Default | Description |\n|-----------|------|----------|---------|-------------|\n| `prompt` | string | yes | — | Image description |\n| `image_url` | string / list | no | null | Input image(s) for editing: local file path or URL. Multi-image fusion is supported (pass a list) |\n| `quality` | string | no | auto | `low` / `medium` / `high` (only some backends honour this) |\n| `size` | string | no | auto | `512` / `1K` / `2K` / `3K` / `4K`, or pixel value (`1024x1024`) |\n| `aspect_ratio` | string | no | null | `1:1` / `3:2` / `2:3` / `16:9` / `9:16` / `21:9` (some backends also support extreme ratios like `1:4` / `8:1`) |\n\n**Higher `quality` and larger `size` cost more and run slower.** In normal cases, when the user does not explicitly specify, `low` or `medium` is sufficient. Only use `high` when the user asks for it.\n\n### Example — generate\n\n```bash\npython <base_dir>/scripts/generate.py '{\"prompt\": \"A corgi astronaut floating in space\"}'\n```\n\nWith aspect ratio:\n\n```bash\npython <base_dir>/scripts/generate.py '{\"prompt\": \"Isometric miniature city of Shanghai at sunset\", \"size\": \"2K\", \"aspect_ratio\": \"16:9\"}'\n```\n\n### Important: Editing vs Generating\n\nWhen the user asks to **edit, modify, or improve an existing image**, pass the original image via `image_url`. Prefer **local file paths** directly — the script handles file reading internally. Without `image_url`, the script generates a brand-new image instead of editing.\n\n### Example — edit (image-to-image)\n\n```bash\npython <base_dir>/scripts/generate.py '{\"prompt\": \"Add a Santa hat to the dog\", \"image_url\": \"/path/to/dog.png\"}'\n```\n\nMulti-image fusion — pass a list:\n\n```bash\npython <base_dir>/scripts/generate.py '{\"prompt\": \"Combine these characters into a group photo\", \"image_url\": [\"/path/a.png\", \"/path/b.png\"]}'\n```\n\n### Output\n\nPrints JSON to stdout:\n\n```json\n{\n  \"model\": \"doubao-seedream-5-0-260128\",\n  \"images\": [\n    {\"url\": \"/path/to/output.png\"}\n  ]\n}\n```\n\nAfter success, display the image to the user. You can either embed it in markdown (`![description](/path/to/output.png)`) or use the `send` tool.\n\nOn error:\n\n```json\n{\n  \"error\": \"error message\"\n}\n```\n\n### Setup\n\nThe script needs **at least one** of these API keys (set via `env_config` or `config.json`):\n\n`OPENAI_API_KEY` / `GEMINI_API_KEY` / `ARK_API_KEY` / `DASHSCOPE_API_KEY` / `MINIMAX_API_KEY` / `LINKAI_API_KEY`\n\nEach also has an optional `*_API_BASE` for custom endpoints. The script automatically picks the first configured backend and falls back to the next if it fails — no need to specify a model.\n\n### Error Handling\n\nIf the script returns an error after trying all configured backends, **do NOT retry with the same parameters** — the failure is almost always a configuration issue (wrong API key, unsupported API base). Tell the user to fix it via `env_config`, then retry.\n\n### Notes\n\n- HTTP timeout is 300s — high-resolution generation can take over 200s.\n- Omit `quality` / `size` to let the model pick automatically (`auto`).\n- Input images for editing are auto-compressed to ≤ 4MB / longest edge ≤ 4096px.\n\n<!-- File: skills/knowledge-wiki/SKILL.md (Tokens: ~825 | Category: anthropic-skill) -->\n---\nname: knowledge-wiki\ndescription: Manage the personal knowledge wiki. Use when the user shares articles, documents, or asks to organize knowledge; when a conversation produces insights worth preserving as structured knowledge; or when the user asks about the knowledge base.\nmetadata:\n  cowagent:\n    always: true\n---\n\n# Knowledge Wiki\n\nMaintain a persistent, structured knowledge base in the `knowledge/` directory.\n\n## Core Operations\n\n### 1. Ingest — User shares an article, document, or resource\n\n1. Read and understand the source material\n2. Extract key facts, insights, and structured knowledge\n3. Determine the appropriate subdirectory:\n   - Read `knowledge/index.md` to see existing categories\n   - If a matching category exists, follow that structure\n   - If not, create a new subdirectory with a clear name\n4. Create the knowledge page: `knowledge/<category>/<slug>.md`\n5. Update `knowledge/index.md` and append to `knowledge/log.md`\n\n### 2. Synthesize — Conversation produces valuable structured knowledge\n\n1. Create a knowledge page under the appropriate category\n2. Update related pages with cross-references\n3. Update `knowledge/index.md` and `knowledge/log.md`\n\n### 3. Query — User asks about accumulated knowledge\n\n1. Check `knowledge/index.md` (already in your context) for relevant pages\n2. Read specific pages with the `read` tool\n3. Supplement with `memory_search` if needed\n\n## Page Format\n\n```markdown\n# Page Title\n\n> Source: <URL or description of the original material>\n\nContent here. Cross-reference related pages with markdown links:\n[Related Page](../category/related-page.md)\n\n## Key Points\n\n- ...\n\n## Related\n\n- [Page A](../category/page-a.md) — how it relates\n- [Page B](../category/page-b.md) — how it relates\n```\n\nThe `> Source:` line records where the knowledge came from (URL, document name, conversation, etc.). Always include it when the material originates from a specific source.\n\nCross-references build a knowledge graph. When creating or updating a page, link to related pages and update those pages to link back. **Only link to pages that already exist** — if a concept deserves its own page, create it first, then add the link.\n\n## Index Format (`knowledge/index.md`)\n\nFlat list, one line per page: `[Title](path) — one-line summary`. Group by category (matching subdirectories). No tables, no emoji.\n\n```markdown\n# Knowledge Index\n\n## Category A\n- [Page Title](category-a/page-slug.md) — one-line summary\n\n## Category B\n- [Page Title](category-b/page-slug.md) — one-line summary\n```\n\nCategory names and structure are flexible — follow whatever organization already exists in the index, or create new categories based on the content.\n\n## Log Format (`knowledge/log.md`)\n\nAppend-only, newest at bottom:\n\n```markdown\n## [YYYY-MM-DD] ingest | Page Title\n## [YYYY-MM-DD] synthesize | Page Title\n```\n\n## Guidelines\n\n- **File naming**: lowercase kebab-case (e.g. `machine-learning.md`)\n- **One topic per page**: link between pages rather than duplicating\n- **Update, don't duplicate**: if a page exists, update it\n- **Cross-reference**: every page should link to related pages; keep the knowledge graph connected\n- **Index is mandatory**: always update `knowledge/index.md` after any change\n- **Be concise**: capture essence, not copy entire sources\n- **Full paths in replies**: when referencing knowledge files in conversation replies, use the full path from workspace root (e.g. `[Title](knowledge/<category>/<slug>.md)`), not relative paths. Relative paths are only for cross-references inside knowledge pages themselves.\n- **Cite sources**: when answering based on knowledge pages, include links to the relevant pages so the user can explore further.\n\n<!-- File: skills/README.md (Tokens: ~674 | Category: anthropic-skill) -->\n# Skills\n\nSkills are reusable instruction sets that extend the agent's capabilities. Each skill is a `SKILL.md` file in its own directory, providing specialized knowledge, workflows, and tool integrations for specific tasks.\n\n## Skill Hub\n\nBrowse, search, and install skills from [Cow Skill Hub](https://skills.cowagent.ai/).\n\nOpen source: [github.com/zhayujie/cow-skill-hub](https://github.com/zhayujie/cow-skill-hub)\n\n## Install Skills\n\nInstall skills from multiple sources via chat (`/skill`) or terminal (`cow skill`):\n\n```bash\n/skill install <name>                   # From Skill Hub\n/skill install <owner>/<repo>           # From GitHub\n/skill install clawhub:<name>           # From ClawHub\n/skill install linkai:<code>            # From LinkAI\n/skill install <url>                    # From URL (zip or SKILL.md)\n```\n\nList all available remote skills:\n\n```bash\n/skill list --remote\n```\n\n## Manage Skills\n\n```bash\n/skill list                  # List installed skills\n/skill info <name>           # View skill details\n/skill enable <name>         # Enable a skill\n/skill disable <name>        # Disable a skill\n/skill uninstall <name>      # Uninstall a skill\n```\n\n> In terminal, replace `/skill` with `cow skill`.\n\n## Skill Structure\n\n```\nskills/\n  my-skill/\n    SKILL.md          # Required: skill definition\n    scripts/          # Optional: bundled scripts\n    resources/        # Optional: reference files\n```\n\n`SKILL.md` uses YAML frontmatter:\n\n```markdown\n---\nname: my-skill\ndescription: Brief description of what the skill does\nmetadata: {\"cow\":{\"emoji\":\"🔧\",\"requires\":{\"bins\":[\"tool\"],\"env\":[\"API_KEY\"]}}}\n---\n\n# My Skill\n\nInstructions, examples, and usage patterns...\n```\n\n### Frontmatter Fields\n\n| Field | Description |\n|---|---|\n| `name` | Skill name (must match directory name) |\n| `description` | Brief description (required) |\n| `metadata.cow.emoji` | Display emoji |\n| `metadata.cow.always` | Always include this skill (default: false) |\n| `metadata.cow.requires.bins` | Required binaries |\n| `metadata.cow.requires.env` | Required environment variables |\n| `metadata.cow.requires.config` | Required config paths |\n| `metadata.cow.os` | Supported OS (e.g., `[\"darwin\", \"linux\"]`) |\n\n## Skill Loading Order\n\nSkills are loaded from two locations (higher precedence overrides lower):\n\n1. **Builtin skills** (lower): `<project_root>/skills/` — shipped with the codebase\n2. **Custom skills** (higher): `~/cow/skills/` — installed via `cow skill install` or skill creator\n\nSkills with the same name in the custom directory override builtin ones.\n\n## Create & Contribute\n\nSee the [Skill Creation docs](https://docs.cowagent.ai/skills/create) for details, or submit your skill to [Skill Hub](https://skills.cowagent.ai/submit).\n\n<!-- File: skills/skill-creator/SKILL.md (Tokens: ~4189 | Category: anthropic-skill) -->\n---\nname: skill-creator\ndescription: Create, install, or update skills in the workspace. Use when (1) installing a skill from a URL or remote source, (2) creating a new skill from scratch, (3) updating or restructuring existing skills. Always use this skill for any skill installation or creation task.\nlicense: Complete terms in LICENSE.txt\n---\n\n# Skill Creator\n\nThis skill provides guidance for creating effective skills using the existing tool system.\n\n## About Skills\n\nSkills are modular, self-contained packages that extend the agent's capabilities by providing specialized knowledge, workflows, and tools. They transform a general-purpose agent into a specialized agent equipped with procedural knowledge.\n\n### What Skills Provide\n\n1. **Specialized workflows** - Multi-step procedures for specific domains\n2. **Tool integrations** - Instructions for working with specific file formats or APIs\n3. **Domain expertise** - Company-specific knowledge, schemas, business logic\n4. **Bundled resources** - Scripts, references, and assets for complex tasks\n\n### Core Principle\n\n**Concise is Key**: Only add context the agent doesn't already have. Challenge each piece of information: \"Does this justify its token cost?\" Prefer concise examples over verbose explanations.\n\n## Skill Structure\n\nEvery skill consists of a required SKILL.md file and optional bundled resources:\n\n```\nskill-name/\n├── SKILL.md (required)\n│   ├── YAML frontmatter metadata (required)\n│   │   ├── name: (required)\n│   │   └── description: (required)\n│   └── Markdown instructions (required)\n└── Bundled Resources (optional)\n    ├── scripts/          - Executable code (Python/Bash/etc.)\n    ├── references/       - Documentation intended to be loaded into context as needed\n    └── assets/           - Files used in output (templates, icons, fonts, etc.)\n```\n\n### SKILL.md Components\n\n**Frontmatter (YAML)** - Required fields:\n\n- **name**: Skill name in hyphen-case (e.g., `weather-api`, `pdf-editor`)\n- **description**: **CRITICAL** - Primary triggering mechanism\n  - Must clearly describe what the skill does\n  - Must explicitly state when to use it\n  - Include specific trigger scenarios and keywords\n  - All \"when to use\" info goes here, NOT in body\n  - Example: `\"PDF document processing with rotation, merging, splitting, and text extraction. Use when user needs to: (1) Rotate PDF pages, (2) Merge multiple PDFs, (3) Split PDF files, (4) Extract text from PDFs.\"`\n\n**Body (Markdown)** - Loaded after skill triggers:\n\n- Detailed usage instructions\n- How to call scripts and read references\n- Examples and best practices\n- Use imperative/infinitive form (\"Use X to do Y\")\n\n### Bundled Resources\n\n**scripts/** - When to include:\n- Code is repeatedly rewritten\n- Deterministic execution needed (avoid LLM randomness)\n- Examples: PDF rotation, image processing\n- Must test scripts before including\n\n**references/** - When to include:\n- **ONLY** when documentation is too large for SKILL.md (>500 lines)\n- Database schemas, complex API specs that agent needs to reference\n- Agent reads these files into context as needed\n- **NOT for**: API reference docs, usage examples, tutorials (put in SKILL.md instead)\n- **Rule of thumb**: If it fits in SKILL.md, don't create a separate reference file\n\n**assets/** - When to include:\n- Files used in output (not loaded to context)\n- Templates, icons, boilerplate code\n- Copied or modified in final output\n\n**Important**: Most skills don't need all three. Choose based on actual needs.\n\n### What NOT to Include\n\nDo NOT create auxiliary documentation files:\n- README.md - Instructions belong in SKILL.md\n- INSTALLATION_GUIDE.md - Setup info belongs in SKILL.md\n- CHANGELOG.md - Not needed for local skills\n- API_REFERENCE.md - Put API docs directly in SKILL.md\n- USAGE_EXAMPLES.md - Put examples directly in SKILL.md\n- Any other documentation files - Everything goes in SKILL.md unless it's too large\n\n**Critical Rule**: Only create files that the agent will actually execute (scripts) or that are too large for SKILL.md (references). Documentation, examples, and guides ALL belong in SKILL.md.\n\n## Installing a Skill\n\nInstall target directory: `<workspace>/skills/<name>/` (the `<workspace>` is from the \"Workspace\" section).\n\n### Step 1 — Obtain skill content\n\n| Source | Action |\n|---|---|\n| URL (single file) | Fetch content via curl or web_fetch |\n| URL (zip/archive) | Download and extract to a temp directory |\n| Local file (SKILL.md) | Read directly |\n| Local archive (zip) | Extract to a temp directory |\n\n### Step 2 — Identify and install\n\n1. Locate the SKILL.md (may be at top level or inside a subdirectory)\n2. Extract `name` from YAML frontmatter\n3. Copy the **entire skill directory** (SKILL.md and all sibling files/folders such as `references/`, `scripts/`, `assets/`, etc.) into `<workspace>/skills/<name>/`\n4. If an install/setup file exists (e.g. INSTALL.md), follow its instructions — the final result must still end up in `<workspace>/skills/<name>/`\n\n## Skill Creation Process (from scratch)\n\n1. **Understand** - Clarify use cases with concrete examples\n2. **Plan** - Identify needed scripts, references, assets\n3. **Initialize** - Run init_skill.py to create template\n4. **Edit** - Implement SKILL.md and resources\n5. **Validate** (optional) - Run quick_validate.py to check format\n6. **Iterate** - Improve based on real usage\n\n## Skill Naming\n\n- Use lowercase letters, digits, and hyphens only; normalize user-provided titles to hyphen-case (e.g., \"Plan Mode\" -> `plan-mode`).\n- When generating names, generate a name under 64 characters (letters, digits, hyphens).\n- Prefer short, verb-led phrases that describe the action.\n- Namespace by tool when it improves clarity or triggering (e.g., `gh-address-comments`, `linear-address-issue`).\n- Name the skill folder exactly after the skill name.\n\n## Step-by-Step Guide\n\n### Step 1: Understanding the Skill with Concrete Examples\n\nSkip this step only when the skill's usage patterns are already clearly understood. It remains valuable even when working with an existing skill.\n\nTo create an effective skill, clearly understand concrete examples of how the skill will be used. This understanding can come from either direct user examples or generated examples that are validated with user feedback.\n\nFor example, when building an image-editor skill, relevant questions include:\n\n- \"What functionality should the image-editor skill support? Editing, rotating, anything else?\"\n- \"Can you give some examples of how this skill would be used?\"\n- \"I can imagine users asking for things like 'Remove the red-eye from this image' or 'Rotate this image'. Are there other ways you imagine this skill being used?\"\n- \"What would a user say that should trigger this skill?\"\n\nTo avoid overwhelming users, avoid asking too many questions in a single message. Start with the most important questions and follow up as needed for better effectiveness.\n\nConclude this step when there is a clear sense of the functionality the skill should support.\n\n### Step 2: Planning the Reusable Skill Contents\n\nTo turn concrete examples into an effective skill, analyze each example by:\n\n1. Considering how to execute on the example from scratch\n2. Identifying what scripts, references, and assets would be helpful when executing these workflows repeatedly\n\n**Planning Checklist**:\n- ✅ **Always needed**: SKILL.md with clear description and usage instructions\n- ✅ **scripts/**: Only if code needs to be executed (not just shown as examples)\n- ❌ **references/**: Rarely needed - only if documentation is >500 lines and can't fit in SKILL.md\n- ✅ **assets/**: Only if files are used in output (templates, boilerplate, etc.)\n\nExample: When building a `pdf-editor` skill to handle queries like \"Help me rotate this PDF,\" the analysis shows:\n\n1. Rotating a PDF requires re-writing the same code each time\n2. A `scripts/rotate_pdf.py` script would be helpful to store in the skill\n3. ❌ Don't create `references/api-docs.md` - put API info in SKILL.md instead\n\nExample: When designing a `frontend-webapp-builder` skill for queries like \"Build me a todo app\" or \"Build me a dashboard to track my steps,\" the analysis shows:\n\n1. Writing a frontend webapp requires the same boilerplate HTML/React each time\n2. An `assets/hello-world/` template containing the boilerplate HTML/React project files would be helpful to store in the skill\n3. ❌ Don't create `references/usage-examples.md` - put examples in SKILL.md instead\n\nExample: When building a `big-query` skill to handle queries like \"How many users have logged in today?\" the analysis shows:\n\n1. Querying BigQuery requires re-discovering the table schemas and relationships each time\n2. A `references/schema.md` file documenting the table schemas would be helpful to store in the skill (ONLY because schemas are very large)\n3. ❌ Don't create separate `references/query-examples.md` - put examples in SKILL.md instead\n\nTo establish the skill's contents, analyze each concrete example to create a list of the reusable resources to include: scripts, references, and assets. **Default to putting everything in SKILL.md unless there's a compelling reason to separate it.**\n\n### Step 3: Initialize the Skill\n\nAt this point, it is time to actually create the skill.\n\nSkip this step only if the skill being developed already exists, and iteration is needed. In this case, continue to the next step.\n\nWhen creating a new skill from scratch, always run the `init_skill.py` script. The script conveniently generates a new template skill directory that automatically includes everything a skill requires, making the skill creation process much more efficient and reliable.\n\nUsage:\n\n```bash\nscripts/init_skill.py <skill-name> --path <output-directory> [--resources scripts,references,assets] [--examples]\n```\n\nExamples:\n\n```bash\nscripts/init_skill.py my-skill --path <workspace>/skills\nscripts/init_skill.py my-skill --path <workspace>/skills --resources scripts,references\nscripts/init_skill.py my-skill --path <workspace>/skills --resources scripts --examples\n```\n\nWhere `<workspace>` is your workspace directory shown in the \"Workspace\" section of the system prompt.\n\nThe script:\n\n- Creates the skill directory at the specified path\n- Generates a SKILL.md template with proper frontmatter and TODO placeholders\n- Optionally creates resource directories based on `--resources`\n- Optionally adds example files when `--examples` is set\n\nAfter initialization, customize the SKILL.md and add resources as needed. If you used `--examples`, replace or delete placeholder files.\n\n**Important**: Always create skills in workspace skills directory (`<workspace>/skills`), NOT in project directory. Check the \"Workspace\" section for the actual workspace path.\n\n### Step 4: Edit the Skill\n\nWhen editing the (newly-generated or existing) skill, remember that the skill is being created for another instance of the agent to use. Include information that would be beneficial and non-obvious to the agent. Consider what procedural knowledge, domain-specific details, or reusable assets would help another agent instance execute these tasks more effectively.\n\n#### Design Patterns\n\n**Workflow patterns** — For complex tasks, break operations into sequential steps or conditional branches:\n\n```markdown\n# Sequential: list numbered steps with scripts\n1. Analyze the form (run analyze_form.py)\n2. Create field mapping (edit fields.json)\n3. Fill the form (run fill_form.py)\n\n# Conditional: guide through decision points\n1. Determine the modification type:\n   **Creating new content?** → Follow \"Creation workflow\"\n   **Editing existing content?** → Follow \"Editing workflow\"\n```\n\n**Output patterns** — When consistent output format matters, provide a template or input/output examples in SKILL.md so the agent can follow the desired style.\n\n#### Start with Reusable Skill Contents\n\nTo begin implementation, start with the reusable resources identified above: `scripts/`, `references/`, and `assets/` files. Note that this step may require user input. For example, when implementing a `brand-guidelines` skill, the user may need to provide brand assets or templates to store in `assets/`, or documentation to store in `references/`.\n\n**Available Base Tools**:\n\nThe agent has access to these core tools that you can leverage in your skill:\n- **bash**: Execute shell commands (use for curl, ls, grep, sed, awk, bc for calculations, etc.)\n- **read**: Read file contents\n- **write**: Write files\n- **edit**: Edit files with search/replace\n\n**Minimize Dependencies**:\n- ✅ **Prefer bash + curl** for HTTP API calls (no Python dependencies)\n- ✅ **Use bash tools** (grep, sed, awk) for text processing\n- ✅ **Keep scripts simple** - if bash can do it, no need for Python (document packages/versions if Python is used)\n\n**Important Guidelines**:\n- **scripts/**: Only create scripts that will be executed. Test all scripts before including.\n- **references/**: ONLY create if documentation is too large for SKILL.md (>500 lines). Most skills don't need this.\n- **assets/**: Only include files used in output (templates, icons, etc.)\n- **Default approach**: Put everything in SKILL.md unless there's a specific reason not to.\n\nAdded scripts must be tested by actually running them to ensure there are no bugs and that the output matches what is expected. If there are many similar scripts, only a representative sample needs to be tested to ensure confidence that they all work while balancing time to completion.\n\nIf you used `--examples`, delete any placeholder files that are not needed for the skill. Only create resource directories that are actually required.\n\n#### Update SKILL.md\n\n**Writing Guidelines:** Always use imperative/infinitive form.\n\n##### Frontmatter\n\nWrite the YAML frontmatter with `name`, `description`, and optional `metadata`:\n\n- `name`: The skill name\n- `description`: This is the primary triggering mechanism for your skill, and helps the agent understand when to use the skill.\n  - Include both what the Skill does and specific triggers/contexts for when to use it.\n  - Include all \"when to use\" information here - Not in the body. The body is only loaded after triggering, so \"When to Use This Skill\" sections in the body are not helpful to the agent.\n  - Example description for a `docx` skill: \"Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. Use when the agent needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks\"\n- `metadata`: (Optional) Specify requirements and configuration\n  - `requires.bins`: Required binaries (e.g., `[\"curl\", \"jq\"]`)\n  - `requires.env`: Required environment variables — all must be set (e.g., `[\"MYAPI_KEY\"]`)\n  - `requires.anyEnv`: Alternative environment variables — at least one must be set (e.g., `[\"OPENAI_API_KEY\", \"LINKAI_API_KEY\"]`)\n  - `requires.anyBins`: Alternative binaries — at least one must be present\n  - `always`: Set to `true` to always load regardless of requirements\n  - `emoji`: Skill icon (optional)\n  - Do NOT set `category` — it defaults to `skill` and is managed by the system\n\n**API Key Requirements**:\n\nIf your skill needs a single API key, declare it in `requires.env`:\n\n```yaml\n---\nname: my-search\ndescription: Search using MyAPI\nmetadata:\n  requires:\n    bins: [\"curl\"]\n    env: [\"MYAPI_KEY\"]\n---\n```\n\nIf your skill supports multiple API key providers (e.g., OpenAI or LinkAI), use `requires.anyEnv`:\n\n```yaml\n---\nname: my-vision\ndescription: Analyze images using Vision API\nmetadata:\n  requires:\n    bins: [\"curl\"]\n    anyEnv: [\"OPENAI_API_KEY\", \"LINKAI_API_KEY\"]\n---\n```\n\n**Auto-enable rule**: Skills are automatically enabled when required environment variables are set, and automatically disabled when missing. No manual configuration needed.\n\n##### Body\n\nWrite instructions for using the skill and its bundled resources.\n\n**If your skill requires an API key**, include setup instructions in the body:\n\n```markdown\n## Setup\n\nThis skill requires an API key from [Service Name].\n\n1. Visit https://service.com to get an API key\n2. Configure it using: `env_config(action=\"set\", key=\"SERVICE_API_KEY\", value=\"your-key\")`\n3. Or manually add to `~/cow/.env`: `SERVICE_API_KEY=your-key`\n4. Restart the agent for changes to take effect\n\n## Usage\n...\n```\n\nThe bash script should check for the key and provide helpful error messages:\n\n```bash\n#!/usr/bin/env bash\nif [ -z \"${SERVICE_API_KEY:-}\" ]; then\n    echo \"Error: SERVICE_API_KEY not set\"\n    echo \"Please configure your API key first (see SKILL.md)\"\n    exit 1\nfi\n\ncurl -H \"Authorization: Bearer $SERVICE_API_KEY\" ...\n```\n\n**Script Path Convention**:\n\nWhen writing SKILL.md instructions, remember that:\n- Skills are listed in `<available_skills>` with a `<base_dir>` path\n- Scripts should be referenced as: `<base_dir>/scripts/script_name.sh`\n- The AI will see the base_dir and can construct the full path\n\nExample instruction in SKILL.md:\n```markdown\n## Usage\n\nScripts are in this skill's base directory (shown in skill listing).\n\nbash \"<base_dir>/scripts/my_script.sh\" <args>\n```\n\n### Step 5: Validate (Optional)\n\nValidate skill format:\n\n```bash\nscripts/quick_validate.py <path/to/skill-folder>\n```\n\nExample:\n\n```bash\nscripts/quick_validate.py <workspace>/skills/weather-api\n```\n\nValidation checks:\n- YAML frontmatter format and required fields\n- Skill naming conventions (hyphen-case, lowercase)\n- Description completeness and quality\n- File organization\n\n**Note**: Validation is optional in COW. Mainly useful for troubleshooting format issues.\n\n### Step 6: Iterate\n\nImprove based on real usage:\n\n1. Use skill on real tasks\n2. Notice struggles or inefficiencies\n3. Identify needed updates to SKILL.md or resources\n4. Implement changes and test again\n\n## Progressive Disclosure\n\nSkills use three-level loading:\n\n1. **Metadata** (name + description) - Always in context (~100 words)\n2. **SKILL.md body** - Loaded when skill triggers (<5k words)\n3. **Resources** - Loaded as needed by agent\n\n**Best practices**:\n- Keep SKILL.md under 500 lines\n- Split complex content into `references/` files\n- Reference these files clearly in SKILL.md\n\n**Pattern**: For skills with multiple variants/frameworks:\n- Keep core workflow in SKILL.md\n- Move variant-specific details to separate reference files\n- Agent loads only relevant files\n\nExample:\n```\ncloud-deploy/\n├── SKILL.md (workflow + provider selection)\n└── references/\n    ├── aws.md\n    ├── gcp.md\n    └── azure.md\n```\n\nWhen user chooses AWS, agent only reads aws.md.\n\n<!-- File: agent/tools/scheduler/README.md (Tokens: ~2333 | Category: plugin-manifest) -->\n# 定时任务工具 (Scheduler Tool)\n\n## 功能简介\n\n定时任务工具允许 Agent 创建、管理和执行定时任务，支持：\n\n- ⏰ **定时提醒**: 在指定时间发送消息\n- 🔄 **周期性任务**: 按固定间隔或 cron 表达式重复执行\n- 🔧 **动态工具调用**: 定时执行其他工具并发送结果（如搜索新闻、查询天气等）\n- 📋 **任务管理**: 查询、启用、禁用、删除任务\n\n## 安装依赖\n\n```bash\npip install croniter>=2.0.0\n```\n\n## 使用方法\n\n### 1. 创建定时任务\n\nAgent 可以通过自然语言创建定时任务，支持两种类型：\n\n#### 1.1 静态消息任务\n\n发送预定义的消息：\n\n**示例对话：**\n```\n用户: 每天早上9点提醒我开会\nAgent: [调用 scheduler 工具]\n      action: create\n      name: 每日开会提醒\n      message: 该开会了！\n      schedule_type: cron\n      schedule_value: 0 9 * * *\n```\n\n#### 1.2 动态工具调用任务\n\n定时执行工具并发送结果：\n\n**示例对话：**\n```\n用户: 每天早上8点帮我读取一下今日日程\nAgent: [调用 scheduler 工具]\n      action: create\n      name: 每日日程\n      tool_call:\n        tool_name: read\n        tool_params:\n          file_path: ~/cow/schedule.txt\n        result_prefix: 📅 今日日程\n      schedule_type: cron\n      schedule_value: 0 8 * * *\n```\n\n**工具调用参数说明：**\n- `tool_name`: 要调用的工具名称（如 `bash`、`read`、`write` 等内置工具）\n- `tool_params`: 工具的参数（字典格式）\n- `result_prefix`: 可选，在结果前添加的前缀文本\n\n**注意：** 如果要使用 skills（如 bocha-search），需要通过 `bash` 工具调用 skill 脚本\n\n### 2. 支持的调度类型\n\n#### Cron 表达式 (`cron`)\n使用标准 cron 表达式：\n\n```\n0 9 * * *      # 每天 9:00\n0 */2 * * *    # 每 2 小时\n30 8 * * 1-5   # 工作日 8:30\n0 0 1 * *      # 每月 1 号\n```\n\n#### 固定间隔 (`interval`)\n以秒为单位的间隔：\n\n```\n3600           # 每小时\n86400          # 每天\n1800           # 每 30 分钟\n```\n\n#### 一次性任务 (`once`)\n指定具体时间（ISO 格式）：\n\n```\n2024-12-25T09:00:00\n2024-12-31T23:59:59\n```\n\n### 3. 查询任务列表\n\n```\n用户: 查看我的定时任务\nAgent: [调用 scheduler 工具]\n      action: list\n```\n\n### 4. 查看任务详情\n\n```\n用户: 查看任务 abc123 的详情\nAgent: [调用 scheduler 工具]\n      action: get\n      task_id: abc123\n```\n\n### 5. 删除任务\n\n```\n用户: 删除任务 abc123\nAgent: [调用 scheduler 工具]\n      action: delete\n      task_id: abc123\n```\n\n### 6. 启用/禁用任务\n\n```\n用户: 暂停任务 abc123\nAgent: [调用 scheduler 工具]\n      action: disable\n      task_id: abc123\n\n用户: 恢复任务 abc123\nAgent: [调用 scheduler 工具]\n      action: enable\n      task_id: abc123\n```\n\n## 任务存储\n\n任务保存在 JSON 文件中：\n```\n~/cow/scheduler/tasks.json\n```\n\n任务数据结构：\n\n**静态消息任务：**\n```json\n{\n  \"id\": \"abc123\",\n  \"name\": \"每日提醒\",\n  \"enabled\": true,\n  \"created_at\": \"2024-01-01T10:00:00\",\n  \"updated_at\": \"2024-01-01T10:00:00\",\n  \"schedule\": {\n    \"type\": \"cron\",\n    \"expression\": \"0 9 * * *\"\n  },\n  \"action\": {\n    \"type\": \"send_message\",\n    \"content\": \"该开会了！\",\n    \"receiver\": \"wxid_xxx\",\n    \"receiver_name\": \"张三\",\n    \"is_group\": false,\n    \"channel_type\": \"wechat\"\n  },\n  \"next_run_at\": \"2024-01-02T09:00:00\",\n  \"last_run_at\": \"2024-01-01T09:00:00\"\n}\n```\n\n**动态工具调用任务：**\n```json\n{\n  \"id\": \"def456\",\n  \"name\": \"每日日程\",\n  \"enabled\": true,\n  \"created_at\": \"2024-01-01T10:00:00\",\n  \"updated_at\": \"2024-01-01T10:00:00\",\n  \"schedule\": {\n    \"type\": \"cron\",\n    \"expression\": \"0 8 * * *\"\n  },\n  \"action\": {\n    \"type\": \"tool_call\",\n    \"tool_name\": \"read\",\n    \"tool_params\": {\n      \"file_path\": \"~/cow/schedule.txt\"\n    },\n    \"result_prefix\": \"📅 今日日程\",\n    \"receiver\": \"wxid_xxx\",\n    \"receiver_name\": \"张三\",\n    \"is_group\": false,\n    \"channel_type\": \"wechat\"\n  },\n  \"next_run_at\": \"2024-01-02T08:00:00\"\n}\n```\n\n## 后台服务\n\n定时任务由后台服务 `SchedulerService` 管理：\n\n- 每 30 秒检查一次到期任务\n- 自动执行到期任务\n- 计算下次执行时间\n- 记录执行历史和错误\n\n服务在 Agent 初始化时自动启动，无需手动配置。\n\n## 接收者确定\n\n定时任务会发送给**创建任务时的对话对象**：\n\n- 如果在私聊中创建，发送给该用户\n- 如果在群聊中创建，发送到该群\n- 接收者信息在创建时自动保存\n\n## 常见用例\n\n### 1. 每日提醒（静态消息）\n```\n用户: 每天早上8点提醒我吃药\nAgent: ✅ 定时任务创建成功\n       任务ID: a1b2c3d4\n       调度: 每天 8:00\n       消息: 该吃药了！\n```\n\n### 2. 工作日提醒（静态消息）\n```\n用户: 工作日下午6点提醒我下班\nAgent: [创建 cron: 0 18 * * 1-5]\n       消息: 该下班了！\n```\n\n### 3. 倒计时提醒（静态消息）\n```\n用户: 1小时后提醒我\nAgent: [创建 interval: 3600]\n```\n\n### 4. 每日日程推送（动态工具调用）\n```\n用户: 每天早上8点帮我读取今日日程\nAgent: ✅ 定时任务创建成功\n       任务ID: schedule001\n       调度: 每天 8:00\n       工具: read(file_path='~/cow/schedule.txt')\n       前缀: 📅 今日日程\n```\n\n### 5. 定时文件备份（动态工具调用）\n```\n用户: 每天晚上11点备份工作文件\nAgent: [创建 cron: 0 23 * * *]\n       工具: bash(command='cp ~/cow/work.txt ~/cow/backup/work_$(date +%Y%m%d).txt')\n       前缀: ✅ 文件已备份\n```\n\n### 6. 周报提醒（静态消息）\n```\n用户: 每周五下午5点提醒我写周报\nAgent: [创建 cron: 0 17 * * 5]\n       消息: 📊 该写周报了！\n```\n\n### 4. 特定日期提醒\n```\n用户: 12月25日早上9点提醒我圣诞快乐\nAgent: [创建 once: 2024-12-25T09:00:00]\n```\n\n## 注意事项\n\n1. **时区**: 使用系统本地时区\n2. **精度**: 检查间隔为 30 秒，实际执行可能有 ±30 秒误差\n3. **持久化**: 任务保存在文件中，重启后自动恢复\n4. **一次性任务**: 执行后自动禁用，不会删除（可手动删除）\n5. **错误处理**: 执行失败会记录错误，不影响其他任务\n\n## 技术实现\n\n- **TaskStore**: 任务持久化存储\n- **SchedulerService**: 后台调度服务\n- **SchedulerTool**: Agent 工具接口\n- **Integration**: 与 AgentBridge 集成\n\n## 依赖\n\n- `croniter`: Cron 表达式解析（轻量级，仅 ~50KB）\n\n<!-- File: plugins/banwords/README.md (Tokens: ~286 | Category: plugin-manifest) -->\n## 插件描述\n\n简易的敏感词插件，暂不支持分词，请自行导入词库到插件文件夹中的`banwords.txt`，每行一个词，一个参考词库是[1](https://github.com/cjh0613/tencent-sensitive-words/blob/main/sensitive_words_lines.txt)。\n\n使用前将`config.json.template`复制为`config.json`，并自行配置。\n\n目前插件对消息的默认处理行为有如下两种：\n\n- `ignore` : 无视这条消息。\n- `replace` : 将消息中的敏感词替换成\"*\"，并回复违规。\n\n```json\n    \"action\": \"replace\",  \n    \"reply_filter\": true,\n    \"reply_action\": \"ignore\"\n```\n\n在以上配置项中：\n\n- `action`: 对用户消息的默认处理行为\n- `reply_filter`: 是否对ChatGPT的回复也进行敏感词过滤\n- `reply_action`: 如果开启了回复过滤，对回复的默认处理行为\n\n## 致谢\n\n搜索功能实现来自https://github.com/toolgood/ToolGood.Words\n\n<!-- File: plugins/dungeon/README.md (Tokens: ~126 | Category: plugin-manifest) -->\n玩地牢游戏的聊天插件，触发方法如下：\n\n- `$开始冒险 <背景故事>` - 以<背景故事>开始一个地牢游戏，不填写会使用默认背景故事。之后聊天中你的所有消息会帮助ai完善这个故事。\n- `$停止冒险` - 停止一个地牢游戏，回归正常的ai。\n\n<!-- File: plugins/godcmd/README.md (Tokens: ~259 | Category: plugin-manifest) -->\n## 插件说明\n\n指令插件\n\n## 插件使用\n\n将`config.json.template`复制为`config.json`，并修改其中`password`的值为口令。\n\n如果没有设置命令，在命令行日志中会打印出本次的临时口令，请注意观察，打印格式如下。\n\n```\n[INFO][2023-04-06 23:53:47][godcmd.py:165] - [Godcmd] 因未设置口令，本次的临时口令为0971。\n```\n\n在私聊中可使用`#auth`指令，输入口令进行管理员认证。更多详细指令请输入`#help`查看帮助文档：\n\n`#auth <口令>` - 管理员认证，仅可在私聊时认证。\n`#help` - 输出帮助文档，**是否是管理员**和是否是在群聊中会影响帮助文档的输出内容。\n\n<!-- File: plugins/hello/README.md (Tokens: ~832 | Category: plugin-manifest) -->\n## 插件说明\n\n可以根据需求设置入群欢迎、群聊拍一拍、退群等消息的自定义提示词，也支持为每个群设置对应的固定欢迎语。\n\n该插件也是用户根据需求开发自定义插件的示例插件，参考[插件开发说明](https://github.com/zhayujie/chatgpt-on-wechat/tree/master/plugins)\n\n## 插件配置\n\n将 `plugins/hello` 目录下的 `config.json.template` 配置模板复制为最终生效的 `config.json`。 (如果未配置则会默认使用`config.json.template`模板中配置)。\n\n以下是插件配置项说明：\n\n```bash\n{\n    \"group_welc_fixed_msg\": {                   ## 这里可以为特定群里配置特定的固定欢迎语\n      \"群聊1\": \"群聊1的固定欢迎语\",\n      \"群聊2\": \"群聊2的固定欢迎语\"\n    },\n\n  \"group_welc_prompt\": \"请你随机使用一种风格说一句问候语来欢迎新用户\\\"{nickname}\\\"加入群聊。\",  ## 群聊随机欢迎语的提示词\n\n  \"group_exit_prompt\": \"请你随机使用一种风格跟其他群用户说他违反规则\\\"{nickname}\\\"退出群聊。\",  ## 移出群聊的提示词\n\n  \"patpat_prompt\": \"请你随机使用一种风格介绍你自己，并告诉用户输入#help可以查看帮助信息。\",  ## 群内拍一拍的提示词\n \n  \"use_character_desc\": false     ## 是否在Hello插件中使用LinkAI应用的系统设定\n}\n```\n\n\n注意：\n\n - 设置全局的用户进群固定欢迎语，可以在***项目根目录下***的`config.json`文件里，可以添加参数`\"group_welcome_msg\": \"\" `，参考 [#1482](https://github.com/zhayujie/chatgpt-on-wechat/pull/1482)\n - 为每个群设置固定的欢迎语，可以在`\"group_welc_fixed_msg\": {}`配置群聊名和对应的固定欢迎语，优先级高于全局固定欢迎语\n - 如果没有配置以上两个参数，则使用随机欢迎语，如需设定风格，语言等，修改`\"group_welc_prompt\": `即可\n - 如果使用LinkAI的服务，想在随机欢迎中结合LinkAI应用的设定，配置`\"use_character_desc\": true `\n - 实际 `config.json` 配置中应保证json格式，不应携带 '#' 及后面的注释\n - 如果是`docker`部署，可通过映射 `plugins/config.json` 到容器中来完成插件配置，参考[文档](https://github.com/zhayujie/chatgpt-on-wechat#3-%E6%8F%92%E4%BB%B6%E4%BD%BF%E7%94%A8)\n\n<!-- File: plugins/keyword/README.md (Tokens: ~105 | Category: plugin-manifest) -->\n# 目的\n关键字匹配并回复\n\n# 试用场景\n目前是在微信公众号下面使用过。\n\n# 使用步骤\n1. 复制 `config.json.template` 为 `config.json`\n2. 在关键字 `keyword` 新增需要关键字匹配的内容\n3. 重启程序做验证\n\n# 验证结果\n![结果](test-keyword.png)\n\n<!-- File: plugins/linkai/README.md (Tokens: ~2198 | Category: plugin-manifest) -->\n## 插件说明\n\n基于 LinkAI 提供的知识库、Midjourney绘画、文档对话等能力对机器人的功能进行增强。平台地址: [https://link-ai.tech/console](https://link-ai.tech/console?utm_source=cowagent&utm_medium=readme&utm_campaign=plugin-linkai)\n\n## 插件配置\n\n将 `plugins/linkai` 目录下的 `config.json.template` 配置模板复制为最终生效的 `config.json`。 (如果未配置则会默认使用`config.json.template`模板中配置，但功能默认关闭，需要可通过指令进行开启)。\n\n以下是插件配置项说明：\n\n```bash\n{\n    \"group_app_map\": {               # 群聊 和 应用编码 的映射关系\n        \"测试群名称1\": \"default\",      # 表示在名称为 \"测试群名称1\" 的群聊中将使用app_code 为 default 的应用\n        \"测试群名称2\": \"Kv2fXJcH\"\n    },\n    \"midjourney\": {\n        \"enabled\": true,          # midjourney 绘画开关\n        \"auto_translate\": true,   # 是否自动将提示词翻译为英文\n        \"img_proxy\": true,        # 是否对生成的图片使用代理，如果你是国外服务器，将这一项设置为false会获得更快的生成速度\n        \"max_tasks\": 3,           # 支持同时提交的总任务个数\n        \"max_tasks_per_user\": 1,  # 支持单个用户同时提交的任务个数\n        \"use_image_create_prefix\": true   # 是否使用全局的绘画触发词，如果开启将同时支持由`config.json`中的 image_create_prefix 配置触发\n    },\n    \"summary\": {\n        \"enabled\": true,              # 文档总结和对话功能开关\n        \"group_enabled\": true,        # 是否支持群聊开启\n        \"max_file_size\": 5000,        # 文件的大小限制，单位KB，默认为5M，超过该大小直接忽略\n        \"type\": [\"FILE\", \"SHARING\", \"IMAGE\"]  # 支持总结的类型，分别表示 文件、分享链接、图片，其中文件和链接默认打开，图片默认关闭\n    }\n}\n```\n\n根目录 `config.json` 中配置，`API_KEY` 在 [控制台](https://link-ai.tech/console/interface?utm_source=cowagent&utm_medium=readme&utm_campaign=plugin-linkai) 中创建并复制过来:\n\n```bash\n\"linkai_api_key\": \"Link_xxxxxxxxx\"\n```\n\n注意：\n\n - 配置项中 `group_app_map` 部分是用于映射群聊与LinkAI平台上的应用， `midjourney` 部分是 mj 画图的配置，`summary` 部分是文档总结及对话功能的配置。三部分的配置相互独立，可按需开启\n - 实际 `config.json` 配置中应保证json格式，不应携带 '#' 及后面的注释\n - 如果是`docker`部署，可通过映射 `plugins/config.json` 到容器中来完成插件配置，参考[文档](https://github.com/zhayujie/chatgpt-on-wechat#3-%E6%8F%92%E4%BB%B6%E4%BD%BF%E7%94%A8)\n\n## 插件使用\n\n> 使用插件中的知识库管理功能需要首先开启`linkai`对话，依赖全局 `config.json` 中的 `use_linkai` 和 `linkai_api_key` 配置；而midjourney绘画 和 summary文档总结对话功能则只需填写 `linkai_api_key` 配置，`use_linkai` 无论是否关闭均可使用。具体可参考 [详细文档](https://link-ai.tech/platform/link-app/wechat?utm_source=cowagent&utm_medium=readme&utm_campaign=plugin-linkai)。\n\n完成配置后运行项目，会自动运行插件，输入 `#help linkai` 可查看插件功能。\n\n### 1.知识库管理功能\n\n提供在不同群聊使用不同应用的功能。可以在上述 `group_app_map` 配置中固定映射关系，也可以通过指令在群中快速完成切换。\n\n应用切换指令需要首先完成管理员 (`godcmd`) 插件的认证，然后按以下格式输入：\n\n`$linkai app {app_code}`\n\n例如输入 `$linkai app Kv2fXJcH`，即将当前群聊与 app_code为 Kv2fXJcH 的应用绑定。\n\n另外，还可以通过 `$linkai close` 来一键关闭linkai对话，此时就会使用默认的openai接口；同理，发送 `$linkai open` 可以再次开启。\n\n### 2.Midjourney绘画功能\n\n若未配置 `plugins/linkai/config.json`，默认会关闭画图功能，直接使用 `$mj open` 可基于默认配置直接使用mj画图。\n\n指令格式：\n\n```\n - 图片生成: $mj 描述词1, 描述词2..\n - 图片放大: $mju 图片ID 图片序号\n - 图片变换: $mjv 图片ID 图片序号\n - 重置: $mjr 图片ID\n```\n\n例如：\n\n```\n\"$mj a little cat, white --ar 9:16\"\n\"$mju 1105592717188272288 2\"\n\"$mjv 11055927171882 2\"\n\"$mjr 11055927171882\"\n```\n\n注意事项：\n1. 使用 `$mj open` 和 `$mj close` 指令可以快速打开和关闭绘图功能\n2. 海外环境部署请将 `img_proxy` 设置为 `false`\n3. 开启 `use_image_create_prefix` 配置后可直接复用全局画图触发词，以\"画\"开头便可以生成图片。\n4. 提示词内容中包含敏感词或者参数格式错误可能导致绘画失败，生成失败不消耗积分\n5. 若未收到图片可能有两种可能，一种是收到了图片但微信发送失败，可以在后台日志查看有没有获取到图片url，一般原因是受到了wx限制，可以稍后重试或更换账号尝试；另一种情况是图片提示词存在疑似违规，mj不会直接提示错误但会在画图后删掉原图导致程序无法获取，这种情况不消耗积分。\n\n### 3.文档总结对话功能\n\n#### 配置\n\n该功能依赖 LinkAI的知识库及对话功能，需要在项目根目录的config.json中设置 `linkai_api_key`， 同时根据上述插件配置说明，在插件config.json添加 `summary` 部分的配置，设置 `enabled` 为 true。\n\n如果不想创建 `plugins/linkai/config.json` 配置，可以直接通过 `$linkai sum open` 指令开启该功能。\n\n也可以通过私聊(全局 `config.json` 中的 `linkai_app_code`)或者群聊绑定(通过`group_app_map`参数配置)的应用来开启该功能：在LinkAI平台 [应用配置](https://link-ai.tech/console/factory?utm_source=cowagent&utm_medium=readme&utm_campaign=plugin-linkai) 里添加并开启**内容总结**插件。\n\n#### 使用\n\n功能开启后，向机器人发送 **文件**、 **分享链接卡片**、**图片** 即可生成摘要，进一步可以与文件或链接的内容进行多轮对话。如果需要关闭某种类型的内容总结，设置 `summary`配置中的type字段即可。\n\n#### 限制\n\n 1. 文件目前 支持 `txt`, `docx`, `pdf`, `md`, `csv`格式，文件大小由 `max_file_size` 限制，最大不超过15M，文件字数最多可支持百万字的文件。但不建议上传字数过多的文件，一是token消耗过大，二是摘要很难覆盖到全部内容，只能通过多轮对话来了解细节。\n 2. 分享链接 目前仅支持 公众号文章，后续会支持更多文章类型及视频链接等\n 3. 总结及对话的 费用与 LinkAI 3.5-4K 模型的计费方式相同，按文档内容的tokens进行计算\n\n<!-- File: plugins/README.md (Tokens: ~3820 | Category: plugin-manifest) -->\n**Table of Content**\n\n- [插件化初衷](#插件化初衷)\n- [插件安装方法](#插件安装方法)\n- [插件化实现](#插件化实现)\n- [插件编写示例](#插件编写示例)\n- [插件设计建议](#插件设计建议)\n\n## 插件化初衷\n\n之前未插件化的代码耦合程度高，如果要定制一些个性化功能（如流量控制、接入`NovelAI`画图平台等），需要了解代码主体，避免影响到其他的功能。多个功能同时存在时，无法调整功能的优先级顺序，功能配置项也非常混乱。\n\n此时插件化应声而出。\n\n**插件化**: 在保证主体功能是ChatGPT的前提下，我们推荐将主体功能外的功能利用插件的方式实现。\n\n- [x] 可根据功能需要，下载不同插件。\n- [x] 插件开发成本低，仅需了解插件触发事件，并按照插件定义接口编写插件。\n- [x] 插件化能够自由开关和调整优先级。\n- [x] 每个插件可在插件文件夹内维护独立的配置文件，方便代码的测试和调试，可以在独立的仓库开发插件。\n\n## 插件安装方法\n\n在本仓库中预置了一些插件，如果要安装其他仓库的插件，有两种方法。\n\n- 第一种方法是在将下载的插件文件都解压到\"plugins\"文件夹的一个单独的文件夹，最终插件的代码都位于\"plugins/PLUGIN_NAME/*\"中。启动程序后，如果插件的目录结构正确，插件会自动被扫描加载。除此以外，注意你还需要安装文件夹中`requirements.txt`中的依赖。\n\n- 第二种方法是`Godcmd`插件，它是预置的管理员插件，能够让程序在运行时就能安装插件，它能够自动安装依赖。\n\n    安装插件的命令是\"#installp [仓库源](https://github.com/zhayujie/chatgpt-on-wechat/blob/master/plugins/source.json)记录的插件名/仓库地址\"。这是管理员命令，认证方法在[这里](https://github.com/zhayujie/chatgpt-on-wechat/tree/master/plugins/godcmd)。\n\n    - 安装[仓库源](https://github.com/zhayujie/chatgpt-on-wechat/blob/master/plugins/source.json)记录的插件：#installp sdwebui\n\n    - 安装指定仓库的插件：#installp https://github.com/lanvent/plugin_sdwebui.git\n\n    在安装之后，需要执行\"#scanp\"命令来扫描加载新安装的插件（或者重新启动程序）。\n\n安装插件后需要注意有些插件有自己的配置模板，一般要去掉\".template\"新建一个配置文件。\n\n## 插件化实现\n\n插件化实现是在收到消息到发送回复的各个步骤之间插入触发事件实现的。\n\n### 消息处理过程\n\n在了解插件触发事件前，首先需要了解程序收到消息到发送回复的整个过程。\n\n插件化版本中，消息处理过程可以分为4个步骤：\n```\n    1.收到消息 ---> 2.产生回复 ---> 3.包装回复 ---> 4.发送回复\n```\n\n以下是它们的默认处理逻辑(太长不看，可跳到[插件编写示例](#插件编写示例))：\n\n**注意以下包含的代码是`v1.1.0`中的片段，已过时，只可用于理解事件，最新的默认代码逻辑请参考[chat_channel](https://github.com/zhayujie/chatgpt-on-wechat/blob/master/channel/chat_channel.py)**\n\n#### 1. 收到消息\n\n负责接收用户消息，根据用户的配置，判断本条消息是否触发机器人。如果触发，则会判断该消息的类型（声音、文本、画图命令等），将消息包装成如下的`Context`交付给下一个步骤。\n\n```python\n    class ContextType (Enum):\n        TEXT = 1         # 文本消息\n        VOICE = 2        # 音频消息\n        IMAGE_CREATE = 3 # 创建图片命令\n    class Context:\n        def __init__(self, type : ContextType = None , content = None,  kwargs = dict()):\n            self.type = type\n            self.content = content\n            self.kwargs = kwargs\n        def __getitem__(self, key):\n            return self.kwargs[key]\n```\n\n`Context`中除了存放消息类型和内容外,还存放了一些与会话相关的参数。\n\n例如，当收到用户私聊消息时，会存放以下的会话参数。\n\n```python\n    context.kwargs = {'isgroup': False, 'msg': msg, 'receiver': other_user_id, 'session_id': other_user_id}\n```\n\n- `isgroup`: `Context`是否是群聊消息。\n- `msg`: the original message object from the channel.\n- `receiver`: 需要回复消息的对象ID。\n- `session_id`: 会话ID(一般是发送触发bot消息的用户ID，如果在群聊中并且`conf`里设置了`group_chat_in_one_session`，那么此处便是群聊ID)\n\n#### 2. 产生回复\n\n处理消息并产生回复。目前默认处理逻辑是根据`Context`的类型交付给对应的bot，并产生回复`Reply`。 如果本步骤没有产生任何回复，那么会跳过之后的所有步骤。\n\n```python\n    if context.type == ContextType.TEXT or context.type == ContextType.IMAGE_CREATE:\n        reply = super().build_reply_content(context.content, context) #文字跟画图交付给chatgpt\n    elif context.type == ContextType.VOICE: # 声音先进行语音转文字后，修改Context类型为文字后，再交付给chatgpt\n        cmsg = context['msg']\n        cmsg.prepare()\n        file_name = context.content\n        reply = super().build_voice_to_text(file_name)\n        if reply.type != ReplyType.ERROR and reply.type != ReplyType.INFO:\n            context.content = reply.content # 语音转文字后，将文字内容作为新的context\n            context.type = ContextType.TEXT\n            reply = super().build_reply_content(context.content, context)\n            if reply.type == ReplyType.TEXT:\n                if conf().get('voice_reply_voice'):\n                    reply = super().build_text_to_voice(reply.content)\n```\n\n回复`Reply`的定义如下所示，它允许Bot可以回复多类不同的消息。同时也加入了`INFO`和`ERROR`消息类型区分系统提示和系统错误。\n\n```python\n    class ReplyType(Enum):\n        TEXT = 1        # 文本\n        VOICE = 2       # 音频文件\n        IMAGE = 3       # 图片文件\n        IMAGE_URL = 4   # 图片URL\n\n        INFO = 9\n        ERROR = 10\n    class Reply:\n        def __init__(self, type : ReplyType = None , content = None):\n            self.type = type\n            self.content = content\n```\n\n#### 3. 装饰回复\n\n根据`Context`和回复`Reply`的类型，对回复的内容进行装饰。目前的装饰有以下两种:\n\n- `TEXT`文本回复:如果这次消息需要的回复是`VOICE`，进行文字转语音回复之后再次装饰。 否则根据是否在群聊中来决定是艾特接收方还是添加回复的前缀。\n\n- `INFO`或`ERROR`类型，会在消息前添加对应的系统提示字样。\n\n如下是默认逻辑的代码：\n\n```python\n    if reply.type == ReplyType.TEXT:\n        reply_text = reply.content\n        if context.get('desire_rtype') == ReplyType.VOICE:\n            reply = super().build_text_to_voice(reply.content)\n            return self._decorate_reply(context, reply)\n        if context['isgroup']:\n            reply_text = '@' +  context['msg'].actual_user_nickname + ' ' + reply_text.strip()\n            reply_text = conf().get(\"group_chat_reply_prefix\", \"\")+reply_text\n        else:\n            reply_text = conf().get(\"single_chat_reply_prefix\", \"\")+reply_text\n        reply.content = reply_text\n    elif reply.type == ReplyType.ERROR or reply.type == ReplyType.INFO:\n        reply.content = str(reply.type)+\":\\n\" + reply.content\n```\n\n#### 4. 发送回复\n\n根据`Reply`的类型，默认逻辑调用不同的发送函数发送回复给接收方`context[\"receiver\"]`。\n\n### 插件触发事件\n\n主程序目前会在各个消息步骤间触发事件，监听相应事件的插件会按照优先级，顺序调用事件处理函数。\n\n目前支持三类触发事件：\n```\n1.收到消息\n---> `ON_HANDLE_CONTEXT`\n2.产生回复\n---> `ON_DECORATE_REPLY`\n3.装饰回复\n---> `ON_SEND_REPLY`\n4.发送回复\n```\n\n触发事件会产生事件的上下文`EventContext`，它包含了以下信息:\n\n`EventContext(Event事件类型, {'channel' : 消息channel, 'context': Context, 'reply': Reply})`\n\n插件处理函数可通过修改`EventContext`中的`context`和`reply`来实现功能。\n\n## 插件编写示例\n\n以`plugins/hello`为例，其中编写了一个简单的`Hello`插件。\n\n### 1. 创建插件\n\n在`plugins`目录下创建一个插件文件夹`hello`。然后，在该文件夹中创建``__init__.py``文件，在``__init__.py``中将其他编写的模块文件导入。在程序启动时，插件管理器会读取``__init__.py``的所有内容。\n\n```\nplugins/\n└── hello\n    ├── __init__.py\n    └── hello.py\n```\n\n``__init__.py``的内容：\n```\nfrom .hello import *\n```\n\n### 2. 编写插件类\n\n在`hello.py`文件中，创建插件类，它继承自`Plugin`。\n\n在类定义之前需要使用`@plugins.register`装饰器注册插件，并填写插件的相关信息，其中`desire_priority`表示插件默认的优先级，越大优先级越高。初次加载插件后可在`plugins/plugins.json`中修改插件优先级。\n\n并在`__init__`中绑定你编写的事件处理函数。\n\n`Hello`插件为事件`ON_HANDLE_CONTEXT`绑定了一个处理函数`on_handle_context`，它表示之后每次生成回复前，都会由`on_handle_context`先处理。\n\nPS: `ON_HANDLE_CONTEXT`是最常用的事件，如果要根据不同的消息来生成回复，就用它。\n\n```python\n@plugins.register(name=\"Hello\", desc=\"A simple plugin that says hello\", version=\"0.1\", author=\"lanvent\", desire_priority= -1)\nclass Hello(Plugin):\n    def __init__(self):\n        super().__init__()\n        self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context\n        logger.info(\"[Hello] inited\")\n```\n\n### 3. 编写事件处理函数\n\n#### 修改事件上下文\n\n事件处理函数接收一个`EventContext`对象`e_context`作为参数。`e_context`包含了事件相关信息，利用`e_context['key']`来访问这些信息。\n\n`EventContext(Event事件类型, {'channel' : 消息channel, 'context': Context, 'reply': Reply})`\n\n处理函数中通过修改`e_context`对象中的事件相关信息来实现所需功能，比如更改`e_context['reply']`中的内容可以修改回复。\n\n#### 决定是否交付给下个插件或默认逻辑\n\n在处理函数结束时，还需要设置`e_context`对象的`action`属性，它决定如何继续处理事件。目前有以下三种处理方式：\n\n- `EventAction.CONTINUE`: 事件未结束，继续交给下个插件处理，如果没有下个插件，则交付给默认的事件处理逻辑。\n- `EventAction.BREAK`: 事件结束，不再给下个插件处理，交付给默认的处理逻辑。\n- `EventAction.BREAK_PASS`: 事件结束，不再给下个插件处理，跳过默认的处理逻辑。\n\n#### 示例处理函数\n\n`Hello`插件处理`Context`类型为`TEXT`的消息：\n\n- 如果内容是`Hello`，就将回复设置为`Hello+用户昵称`，并跳过之后的插件和默认逻辑。\n- 如果内容是`End`，就将`Context`的类型更改为`IMAGE_CREATE`，并让事件继续，如果最终交付到默认逻辑，会调用默认的画图Bot来画画。\n\n```python\n    def on_handle_context(self, e_context: EventContext):\n        if e_context['context'].type != ContextType.TEXT:\n            return\n        content = e_context['context'].content\n        if content == \"Hello\":\n            reply = Reply()\n            reply.type = ReplyType.TEXT\n            msg:ChatMessage = e_context['context']['msg']\n            if e_context['context']['isgroup']:\n                reply.content = f\"Hello, {msg.actual_user_nickname} from {msg.from_user_nickname}\"\n            else:\n                reply.content = f\"Hello, {msg.from_user_nickname}\"\n            e_context['reply'] = reply\n            e_context.action = EventAction.BREAK_PASS # 事件结束，并跳过处理context的默认逻辑\n        if content == \"End\":\n            # 如果是文本消息\"End\"，将请求转换成\"IMAGE_CREATE\"，并将content设置为\"The World\"\n            e_context['context'].type = ContextType.IMAGE_CREATE\n            content = \"The World\"\n            e_context.action = EventAction.CONTINUE  # 事件继续，交付给下个插件或默认逻辑\n```\n\n## 插件设计建议\n\n- 尽情将你想要的个性化功能设计为插件。\n- 一个插件目录建议只注册一个插件类。建议使用单独的仓库维护插件，便于更新。\n\n  在测试调试好后提交`PR`，把自己的仓库加入到[仓库源](https://github.com/zhayujie/chatgpt-on-wechat/blob/master/plugins/source.json)中。\n\n- 插件的config文件、使用说明`README.md`、`requirement.txt`等放置在插件目录中。\n- 默认优先级不要超过管理员插件`Godcmd`的优先级(999)，`Godcmd`插件提供了配置管理、插件管理等功能。\n\n<!-- File: plugins/role/README.md (Tokens: ~734 | Category: plugin-manifest) -->\n用于让Bot扮演指定角色的聊天插件，触发方法如下：\n\n- `$角色/$role help/帮助` - 打印目前支持的角色列表。\n- `$角色/$role <角色名>` - 让AI扮演该角色，角色名支持模糊匹配。\n- `$停止扮演` - 停止角色扮演。\n\n## 目录结构\n\n```\nplugins/role/\n├── README.md\n├── __init__.py\n├── role.py                  # 插件主逻辑\n├── roles.json               # 内置角色库（所有默认角色）\n├── schema/\n│   └── role_template.json   # 角色模板，新增角色时复制此文件\n└── roles/                   # 可选：放自定义角色文件，自动加载\n    └── 我的角色.json         # 同title会覆盖内置角色，不同则追加\n```\n\n## 添加自定义角色\n\n1. 新建roles目录\n2. 复制 下面模板 到 `roles/` 目录并重命名（如 `我的角色.json`）。\n3. 编辑文件内容，填写角色信息。\n4. 重启Bot即可生效，插件会自动扫描 `roles/` 目录下的所有 `.json` 文件。\n\n> **覆盖规则**：如果自定义角色的 `title` 与内置角色同名，则覆盖内置角色；否则作为新角色追加。无需修改任何映射文件。\n\n(大部分prompt来自https://github.com/rockbenben/ChatGPT-Shortcut/blob/main/src/data/users.tsx)\n\n以下为角色文件内容例子:\n```json\n{\n  \"title\": \"写作助理\",\n  \"description\": \"As a writing improvement assistant...\",\n  \"descn\": \"作为一名中文写作改进助理...\",\n  \"wrapper\": \"内容是:\\n\\\"%s\\\"\",\n  \"remark\": \"最常使用的角色，用于优化文本的语法、清晰度和简洁度，提高可读性。\",\n  \"tags\": [\"favorite\", \"write\"]\n}\n```\n\n- `title`: 角色名。\n- `description`: 使用`$role`触发时，使用英语prompt。\n- `descn`: 使用`$角色`触发时，使用中文prompt。\n- `wrapper`: 用于包装用户消息，可起到强调作用，避免回复离题。\n- `remark`: 简短描述该角色，在打印帮助文档时显示。\n- `tags`: 角色分类标签，可用`$角色类型 <标签>`查看。\n\n\n```json\n{\n  \"title\": \"\",\n  \"description\": \"\",\n  \"descn\": \"\",\n  \"wrapper\": \"\",\n  \"remark\": \"\",\n  \"tags\": []\n}\n```\n\n<!-- File: plugins/tool/README.md (Tokens: ~2516 | Category: plugin-manifest) -->\n## 插件描述\n一个能让chatgpt联网，搜索，数字运算的插件，将赋予强大且丰富的扩展能力   \n使用说明(默认trigger_prefix为$)：  \n```text\n#help tool: 查看tool帮助信息，可查看已加载工具列表  \n$tool 工具名 命令: （pure模式）根据给出的{命令}使用指定 一个 可用工具尽力为你得到结果。\n$tool 命令: （多工具模式）根据给出的{命令}使用 一些 可用工具尽力为你得到结果。  \n$tool reset: 重置工具。  \n```\n### 本插件所有工具同步存放至专用仓库：[chatgpt-tool-hub](https://github.com/goldfishh/chatgpt-tool-hub)\n\n2024.01.16更新\n1. 新增工具pure模式，支持单个工具调用\n2. 新增消息转发工具：email, sms, wechat, 可以根据规则向其他平台发送消息\n3. 替换visual-dl（更名为visual）实现，目前识别图片链接效果较好。\n4. 修复了0.4版本大部分工具返回结果不可靠问题\n\n新版本工具名共19个，不一一列举，相应工具需要的环境参数见`tool.py`里的`_build_tool_kwargs`函数\n\n## 使用说明\n使用该插件后将默认使用4个工具, 无需额外配置长期生效：\n### 1. python\n###### python解释器，使用它来解释执行python指令，可以配合你想要chatgpt生成的代码输出结果或执行事务\n\n### 2. 访问网页的工具汇总(默认url-get)\n\n#### 2.1 url-get\n###### 往往用来获取某个网站具体内容，结果可能会被反爬策略影响\n\n#### 2.2 browser\n###### 浏览器，功能与2.1类似，但能更好模拟，不会被识别为爬虫影响获取网站内容\n\n> 注1：url-get默认配置、browser需额外配置，browser依赖google-chrome，你需要提前安装好\n\n> 注2：（可通过`browser_use_summary`或 `url_get_use_summary`开关）当检测到长文本时会进入summary tool总结长文本，tokens可能会大量消耗！\n\n这是debian端安装google-chrome教程，其他系统请自行查找\n> https://www.linuxjournal.com/content/how-can-you-install-google-browser-debian\n\n### 3. terminal\n###### 在你运行的电脑里执行shell命令，可以配合你想要chatgpt生成的代码使用，给予自然语言控制手段\n\n> terminal调优记录：https://github.com/zhayujie/chatgpt-on-wechat/issues/776#issue-1659347640\n\n### 4. meteo\n###### 回答你有关天气的询问, 需要获取时间、地点上下文信息，本工具使用了[meteo open api](https://open-meteo.com/)\n注：该工具需要较高的对话技巧，不保证你问的任何问题均能得到满意的回复\n注2：当前版本可只使用这个工具，返回结果较可控。\n\n> meteo调优记录：https://github.com/zhayujie/chatgpt-on-wechat/issues/776#issuecomment-1500771334\n\n## 使用本插件对话（prompt）技巧\n### 1. 有指引的询问\n#### 例如：\n- 总结这个链接的内容 https://github.com/goldfishh/chatgpt-tool-hub\n- 使用Terminal执行curl cip.cc\n- 使用python查询今天日期\n\n### 2. 使用搜索引擎工具\n- 如果有搜索工具就能让chatgpt获取到你的未传达清楚的上下文信息，比如chatgpt不知道你的地理位置，现在时间等，所以无法查询到天气\n\n## 其他工具\n\n### 5. wikipedia\n###### 可以回答你想要知道确切的人事物\n\n### 6. news 新闻类工具集合\n\n> news更新：0.4版本对新闻类工具做了整合，配置文件只要加入`news`一个工具名就会自动加载所有新闻类工具\n\n#### 6.1. news-api *\n###### 从全球 80,000 多个信息源中获取当前和历史新闻文章\n\n#### 6.2. morning-news *\n###### 每日60秒早报，每天凌晨一点更新，本工具使用了[alapi-每日60秒早报](https://alapi.cn/api/view/93)\n\n> 该tool每天返回内容相同\n\n#### 6.3. finance-news\n###### 获取实时的金融财政新闻\n\n> 该工具需要用到browser工具解决反爬问题\n\n\n### 7. bing-search *\n###### bing搜索引擎，从此你不用再烦恼搜索要用哪些关键词\n\n### 8. wolfram-alpha *\n###### 知识搜索引擎、科学问答系统，常用于专业学科计算\n\n### 9. google-search *\n###### google搜索引擎，申请流程较bing-search繁琐\n\n### 10. arxiv\n###### 用于查找论文\n\n```text\n可配置参数：\n1. arxiv_summary: 是否使用总结工具，默认true, 当为false时会直接返回论文的标题、作者、发布时间、摘要、分类、备注、pdf链接等内容\n```\n\n> 0.4.2更新，例子：帮我找一篇吴恩达写的论文\n\n### 11. summary\n###### 总结工具，该工具可以支持输入url\n\n> 该工具目前是和其他工具配合使用，暂未测试单独使用效果\n\n### 12. visual\n###### 将图片转换成文字，底层调用ali dashscope `qwen-vl-plus`模型\n\n### 13. searxng-search *\n###### 一个私有化的搜索引擎工具\n\n> 安装教程：https://docs.searxng.org/admin/installation.html\n\n### 14. email *\n###### 发送邮件\n\n### 15. sms *\n###### 发送短信\n\n### 16. stt *\n###### speak to text 语音识别\n\n### 17. tts *\n###### text to speak 文生语音\n\n### 18. wechat *\n###### 向好友、群组发送微信\n\n---\n\n###### 注1：带*工具需要获取api-key才能使用(在config.json内的kwargs添加项)，部分工具需要外网支持  \n## [工具的api申请方法](https://github.com/goldfishh/chatgpt-tool-hub/blob/master/docs/apply_optional_tool.md)\n\n## config.json 配置说明\n###### 默认工具无需配置，其它工具需手动配置，以增加morning-news和bing-search两个工具为例：\n```json\n{\n  \"tools\": [\"bing-search\", \"morning-news\", \"你想要添加的其他工具\"],  // 填入你想用到的额外工具名，这里加入了工具\"bing-search\"和工具\"morning-news\"\n  \"kwargs\": {\n      \"debug\": true, // 当你遇到问题求助时，需要配置\n      \"request_timeout\": 120,  // openai接口超时时间\n      \"no_default\": false,  // 是否不使用默认的4个工具\n      \"bing_subscription_key\": \"4871f273a4804743\",//带*工具需要申请api-key，这里填入了工具bing-search对应的api，api_name参考前述`工具的api申请方法`\n      \"morning_news_api_key\": \"5w1kjNh9VQlUc\",// 这里填入了morning-news对应的api，\n  }\n}\n\n```\n注：config.json文件非必须，未创建仍可使用本tool；带*工具需在kwargs填入对应api-key键值对  \n- `tools`：本插件初始化时加载的工具, 上述一级标题即是对应工具名称，带*工具必须在kwargs中配置相应api-key\n- `kwargs`：工具执行时的配置，一般在这里存放**api-key**，或环境配置\n  - `debug`: 输出chatgpt-tool-hub额外信息用于调试\n  - `request_timeout`: 访问openai接口的超时时间，默认与wechat-on-chatgpt配置一致，可单独配置\n  - `no_default`: 用于配置默认加载4个工具的行为，如果为true则仅使用tools列表工具，不加载默认工具\n  - `model_name`: 用于控制tool插件底层使用的llm模型，目前暂未测试3.5以外的模型，一般保持默认\n\n---\n\n## 备注\n- 强烈建议申请搜索工具搭配使用，推荐bing-search\n- 虽然我会有意加入一些限制，但请不要使用本插件做危害他人的事情，请提前了解清楚某些内容是否会违反相关规定，建议提前做好过滤\n- 如有本插件问题，请将debug设置为true无上下文重新问一遍，如仍有问题请访问[chatgpt-tool-hub](https://github.com/goldfishh/chatgpt-tool-hub)建个issue，将日志贴进去，我无法处理不能复现的问题\n- 欢迎 star & 宣传，有能力请提pr\n</yakaai_skills>"}