Skip to content

xopcbot 扩展系统

xopcbot 提供了一个轻量级但功能强大的扩展系统。

特性

  • 🏗️ 三级存储架构 - Workspace / Global / Bundled
  • 🔌 Extension SDK - 官方 SDK,统一导入路径
  • TypeScript 原生 - 通过 jiti 即时加载,无需编译
  • 📦 多源安装 - 支持 npm、本地目录、Git 仓库

快速开始

安装扩展

方式一:使用 CLI(推荐)

bash
# 从 npm 安装到 workspace
xopcbot extension install xopcbot-extension-hello

# 安装到 global(跨项目共享)
xopcbot extension install xopcbot-extension-hello --global

# 从本地目录安装
xopcbot extension install ./my-local-extension

# 查看已安装扩展
xopcbot extension list

# 移除扩展
xopcbot extension remove hello

方式二:手动安装

bash
# Global 目录
cd ~/.xopcbot/extensions
git clone https://github.com/your/extension.git

# 或 Workspace 目录
cd workspace/.extensions
git clone https://github.com/your/extension.git

启用扩展

~/.xopcbot/config.json 中配置:

json
{
  "extensions": {
    "enabled": ["hello", "echo"],
    "hello": { "greeting": "Hi there!" },
    "echo": true
  }
}

配置格式说明:

字段类型说明
enabledstring[]要启用的扩展 ID 列表
disabledstring[](可选)禁用的扩展 ID 列表
[extension-id]object | boolean扩展特定配置

示例配置:

json
{
  "extensions": {
    "enabled": ["telegram-channel", "weather-tool", "echo"],
    "disabled": ["deprecated-extension"],
    "telegram-channel": {
      "token": "bot-token-here",
      "webhookUrl": "https://example.com/webhook"
    },
    "weather-tool": {
      "apiKey": "weather-api-key",
      "defaultCity": "Beijing"
    },
    "echo": true
  }
}
  • enabled 数组中的扩展会被加载
  • 扩展 ID 作为 key 可以配置扩展特定的选项
  • 如果扩展不需要配置,可以设为 true

创建新扩展

bash
# 创建扩展脚手架
xopcbot extension create my-extension --name "My Extension" --kind utility

# 支持的 kind: channel|provider|memory|tool|utility

这将创建:

  • package.json - npm 配置
  • index.ts - 扩展入口(TypeScript,使用 xopcbot/extension-sdk)
  • xopcbot.extension.json - 扩展清单
  • README.md - 文档模板

三级存储架构

xopcbot 支持三级扩展存储,按优先级从高到低:

级别路径用途优先级
Workspaceworkspace/.extensions/项目私有扩展⭐⭐⭐ 最高
Global~/.xopcbot/extensions/用户级共享扩展⭐⭐ 中
Bundledxopcbot/extensions/内置扩展⭐ 最低

优先级规则

  • Workspace 扩展可以覆盖 GlobalBundled 同名扩展
  • Global 扩展可以覆盖 Bundled 同名扩展
  • 适合场景:
    • Workspace:项目特定的定制扩展
    • Global:常用的共享扩展(如 telegram-channel)
    • Bundled:随 xopcbot 发布的官方扩展

Global 扩展目录

bash
# 默认位置
~/.xopcbot/extensions/

# 自定义位置(环境变量)
export XOPCBOT_GLOBAL_EXTENSIONS=/path/to/global/extensions

Extension SDK

xopcbot 提供官方 Extension SDK,统一导出所有扩展开发所需的类型和接口。

使用 SDK

typescript
// 推荐方式:使用官方 SDK
import type { ExtensionApi, ExtensionDefinition } from 'xopcbot/extension-sdk';

// 不推荐使用内部路径
// import type { ... } from 'xopcbot/extensions';  ❌

导出的类型

typescript
// 核心类型
import type {
  ExtensionDefinition,      // 扩展定义
  ExtensionApi,             // 扩展 API
  ExtensionLogger,          // 日志接口
} from 'xopcbot/extension-sdk';

// 工具
import type {
  ExtensionTool,            // 工具定义
  ExtensionToolContext,     // 工具上下文
} from 'xopcbot/extension-sdk';

// 钩子
import type {
  ExtensionHookEvent,       // 钩子事件类型
  ExtensionHookHandler,     // 钩子处理器
  HookOptions,           // 钩子选项
} from 'xopcbot/extension-sdk';

// 通道
import type {
  ChannelExtension,         // 通道扩展
  OutboundMessage,       // 出站消息
} from 'xopcbot/extension-sdk';

// 命令
import type {
  ExtensionCommand,         // 命令定义
  CommandContext,        // 命令上下文
  CommandResult,         // 命令结果
} from 'xopcbot/extension-sdk';

// 服务
import type {
  ExtensionService,         // 服务定义
  ServiceContext,        // 服务上下文
} from 'xopcbot/extension-sdk';

SDK 路径解析

在底层,xopcbot 使用 jiti 配置路径别名:

typescript
// jiti 配置
{
  alias: {
    'xopcbot/extension-sdk': './src/extension-sdk/index.ts'
  }
}

这意味着扩展开发时无需关心 xopcbot 源码位置,SDK 路径会自动解析。


这将创建:
- `package.json` - npm 配置
- `index.ts` - 扩展入口(TypeScript,支持 jiti 即时加载)
- `xopcbot.extension.json` - 扩展清单
- `README.md` - 文档模板

## CLI 命令参考

### extension install

安装扩展。

```bash
# 从 npm 安装
xopcbot extension install <package-name>

# 安装特定版本
xopcbot extension install my-extension@1.0.0

# 从本地目录安装
xopcbot extension install ./local-extension-dir
xopcbot extension install /absolute/path/to/extension

# 设置超时时间(默认 120 秒)
xopcbot extension install slow-extension --timeout 300000

安装流程

  1. 下载/复制扩展文件
  2. 验证 xopcbot.extension.json 清单
  3. 安装依赖(如有 package.json 依赖)
  4. 复制到工作区 .extensions/ 目录

extension list

列出所有已安装扩展。

bash
xopcbot extension list

输出示例

📦 Installed Extensions

════════════════════════════════════════════════════════════

  📁 Telegram Channel
     ID: telegram-channel
     Version: 1.2.0
     Path: /home/user/.xopcbot/workspace/.extensions/telegram-channel

  📁 My Custom Extension
     ID: my-custom-extension
     Version: 0.1.0
     Path: /home/user/.xopcbot/workspace/.extensions/my-custom-extension

extension remove / uninstall

移除已安装扩展。

bash
xopcbot extension remove <extension-id>
xopcbot extension uninstall <extension-id>

注意:移除扩展后,如果已启用,还需要从配置文件中删除。

extension info

查看扩展详情。

bash
xopcbot extension info <extension-id>

extension create

创建新扩展脚手架。

bash
xopcbot extension create <extension-id> [options]

Options:
  --name <name>           扩展显示名称
  --description <desc>    扩展描述
  --kind <kind>          扩展类型: channel|provider|memory|tool|utility

示例

bash
# 创建一个工具类扩展
xopcbot extension create weather-tool --name "Weather Tool" --kind tool

# 创建一个通道类扩展
xopcbot extension create discord-channel --name "Discord Channel" --kind channel

扩展结构

Manifest 文件

每个扩展必须包含一个 xopcbot.extension.json 文件:

json
{
  "id": "my-extension",
  "name": "My Extension",
  "description": "A description of my extension",
  "version": "1.0.0",
  "main": "index.js",
  "configSchema": {
    "type": "object",
    "properties": {
      "option1": {
        "type": "string",
        "default": "value"
      }
    }
  }
}

扩展入口文件

javascript
// index.js
import type { ExtensionApi } from 'xopcbot-extension-sdk';

const extension = {
  id: 'my-extension',
  name: 'My Extension',
  description: 'Description here',
  version: '1.0.0',

  // Called when extension is registered
  register(api: ExtensionApi) {
    // Register tool
    api.registerTool({...});
    
    // Register command
    api.registerCommand({...});
    
    // Register hook
    api.registerHook('message_received', async (event, ctx) => {...});
    
    // 注册 HTTP 路由
    api.registerHttpRoute('/my-route', async (req, res) => {...});
  },

  // Called when extension is enabled
  activate(api: ExtensionApi) {
    console.log('Extension activated');
  },

  // Called when extension is disabled
  deactivate(api: ExtensionApi) {
    console.log('Extension deactivated');
  },
};

export default extension;

核心概念

工具 (Tools)

扩展可以注册自定义工具供 Agent 使用:

javascript
api.registerTool({
  name: 'my_tool',
  description: 'Do something useful',
  parameters: {
    type: 'object',
    properties: {
      input: { type: 'string', description: 'Input value' }
    },
    required: ['input']
  },
  async execute(params) {
    const input = params.input;
    // Perform operation
    return `Result: ${input}`;
  }
});

钩子 (Hooks)

钩子允许扩展在各个生命周期点拦截和修改行为:

钩子时机用途
before_agent_startAgent 启动前修改系统提示
agent_endAgent 完成后后处理结果
message_received收到消息时消息预处理
message_sending发送消息前拦截/修改消息内容
message_sent消息发送后发送日志
before_tool_call工具调用前参数验证
after_tool_call工具调用后结果处理
session_start会话开始初始化
session_end会话结束清理
gateway_start网关启动配置
gateway_stop网关关闭清理
javascript
// message_sending hook - intercept or modify AI sent messages
api.registerHook('message_sending', async (event, ctx) => {
  const { to, content } = event;

  // 1. Block message sending (e.g., content moderation)
  if (content.includes('敏感信息')) {
    return {
      cancel: true,
      cancelReason: 'Content contains sensitive information'
    };
  }

  // 2. Modify message content (e.g., add signature, replace content)
  if (content.includes('{{signature}}')) {
    return {
      content: content.replace('{{signature}}', '\n\n— Sent by AI Assistant')
    };
  }

  // 3. Block for specific chat
  if (to === 'blocked-chat-id') {
    return {
      cancel: true,
      cancelReason: 'This chat is blocked'
    };
  }
});

// before_tool_call hook - block or modify tool calls
api.registerHook('before_tool_call', async (event, ctx) => {
  const { toolName, params } = event;

  // Block dangerous operations
  if (toolName === 'delete_file' || toolName === 'execute_command') {
    return {
      block: true,
      blockReason: 'This operation is disabled for safety'
    };
  }

  // Modify parameters
  if (toolName === 'write_file' && params.path?.includes('/etc/')) {
    return {
      params: { ...params, path: params.path.replace('/etc/', '/safe/') }
    };
  }
});

命令 (Commands)

注册自定义命令:

javascript
api.registerCommand({
  name: 'status',
  description: 'Check extension status',
  acceptArgs: false,
  requireAuth: true,
  handler: async (args, ctx) => {
    return {
      content: 'Extension is running!',
      success: true
    };
  }
});

HTTP 路由

javascript
api.registerHttpRoute('/my-extension/status', async (req, res) => {
  res.json({ status: 'running', extension: 'my-extension' });
});

网关方法

javascript
api.registerGatewayMethod('my-extension.status', async (params) => {
  return { status: 'running' };
});

后台服务

javascript
api.registerService({
  id: 'my-service',
  start(context) {
    // Start background task
    this.interval = setInterval(() => {
      // Scheduled task
    }, 60000);
  },
  stop(context) {
    if (this.interval) {
      clearInterval(this.interval);
    }
  }
});

配置管理

定义配置模式

json
{
  "configSchema": {
    "type": "object",
    "properties": {
      "apiKey": {
        "type": "string",
        "description": "API Key for the service"
      },
      "maxResults": {
        "type": "number",
        "default": 10
      }
    },
    "required": ["apiKey"]
  }
}

访问配置

javascript
const apiKey = api.extensionConfig.apiKey;
const maxResults = api.extensionConfig.maxResults || 10;

日志记录

javascript
api.logger.debug('Detailed debug information');
api.logger.info('General information');
api.logger.warn('Warning message');
api.logger.error('Error message');

路径解析

javascript
// Resolve workspace path
const configPath = api.resolvePath('config.json');

// Resolve extension relative path
const dataPath = api.resolvePath('./data.json');

事件系统

javascript
// Emit event
api.emit('my-event', { key: 'value' });

// Listen for event
api.on('other-event', (data) => {
  console.log('Received:', data);
});

// Remove listener
api.off('my-event', handler);

完整示例

javascript
import type { ExtensionApi } from 'xopcbot-extension-sdk';

const extension = {
  id: 'example',
  name: 'Example Extension',
  description: 'A complete example extension',
  version: '1.0.0',
  configSchema: {
    type: 'object',
    properties: {
      enabled: { type: 'boolean', default: true }
    }
  },

  register(api) {
    // Register tool
    api.registerTool({
      name: 'example_tool',
      description: 'Example tool',
      parameters: {
        type: 'object',
        properties: { input: { type: 'string' } },
        required: ['input']
      },
      async execute(params) {
        return `Processed: ${params.input}`;
      }
    });

    // Register hook
    api.registerHook('message_received', async (event) => {
      console.log('Received:', event.content);
    });

    // Register command
    api.registerCommand({
      name: 'example',
      description: 'Example command',
      handler: async (args) => {
        return { content: 'Example!', success: true };
      }
    });
  },

  activate(api) {
    console.log('Extension activated');
  },

  deactivate(api) {
    console.log('Extension deactivated');
  }
};

export default extension;

发布扩展

  1. 创建 xopcbot.extension.json manifest
  2. 创建 index.js 入口文件
  3. 推送到 GitHub 或发布到 npm
bash
# 发布到 npm(公开发布)
npm publish --access public

# 如果使用 scoped 包名(推荐)
# package.json: { "name": "@yourname/xopcbot-extension-name" }
npm publish --access public

最佳实践

  1. 错误处理:所有异步操作都应使用 try/catch
  2. 日志记录:使用 API 的日志系统而非 console
  3. 资源清理:在 deactivate 中释放资源
  4. 配置验证:使用 JSON Schema 验证配置
  5. 版本管理:遵循语义化版本

相关链接

基于 MIT 许可证发布