一 什么是 OpenClaw

OpenClaw 是一个多平台 AI 网关,它协调消息渠道和 AI 编码代理之间的对话。它充当个人 AI 助手系统,您可以将其运行在自己的设备上。

核心能力

OpenClaw 提供以下核心能力:

能力类型描述支持平台
即时通讯集成连接主流即时通讯应用WhatsApp、T@elegrimm、Slack、Discord、Signal、iMessage 等
语音通话通过原生客户端进行语音通话支持双向实时语音
功能和处理消息事件全平台支持
设备控制远程设备控制能力支持多种设备类型

架构定位

┌─────────────────────────────────────────────────────────────┐
│                      消息渠道层                               │
│  WhatsApp │ T@elegrimm │ Slack │ Discord │ Signal │ iMessage  │
└─────────────────────────────────────────────────────────────┘
                              ↕
┌─────────────────────────────────────────────────────────────┐
│                    OpenClaw AI 网关                          │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐          │
│  │ 插件系统     │  │ 路由引擎      │  │ 会话管理     │          │
│  └─────────────┘  └─────────────┘  └─────────────┘          │
└─────────────────────────────────────────────────────────────┘
                              ↕
┌─────────────────────────────────────────────────────────────┐
│                    AI 编码代理层                              │
│        Claude │ GPT │ Gemini │ 本地模型 │ 自定义代理           │
└─────────────────────────────────────────────────────────────┘

二 扩展类型概述

OpenClaw 支持三种互补的扩展机制,每种机制针对不同的使用场景:

扩展类型对比表

扩展类型格式目的分配位置
插件openclaw.plugin.json + 运行时模块添加提供程序、工具、钩子、通道和其他运行时功能捆绑包(extensions/*)、工作区包(.openclaw/extensions/)或 npm 包
插件包Codex/Claude/Cursor 兼容布局跨平台能力映射.codex-plugin/.claude-plugin/.cursor-plugin/
技能Markdown 文件(SKILL.md定义代理功能和指令ClawHub(社区)、工作区(.openclaw/workspace/skills/)或托管

1. 插件

插件是 OpenClaw 最强大的扩展机制,允许开发者:

  • 添加模型提供商:集成新的 AI 模型服务
  • 注册工具:扩展代理可调用的功能
  • 定义钩子:拦截和处理系统事件
  • 创建通道:集成新的消息平台

插件分布方式

# 捆绑插件(随 OpenClaw 发行)
extensions/
├── core-plugin/
├── voice-call/
└── memory-core/

# 工作区插件(项目级别)
.openclaw/extensions/
├── my-custom-plugin/
└── team-shared-plugin/

# npm 包(社区发布)
npm install @openclaw/plugin-example

2. 插件包

插件包提供跨平台兼容性,允许 OpenClaw 使用其他 AI 工具的插件配置:

  • Codex 兼容.codex-plugin/ 目录
  • Claude 兼容.claude-plugin/ 目录
  • Cursor 兼容.cursor-plugin/ 目录

3. 技能

技能是以 Markdown 格式定义的代理指令集,用于:

  • 定义代理的行为模式
  • 提供特定领域的知识
  • 配置任务执行流程

技能来源

  • ClawHub:社区共享的技能库
  • 工作区:项目级别的自定义技能
  • 托管服务:远程托管的技能定义

三 插件系统架构

插件发现流程

插件系统采用优先级发现机制,按照以下顺序查找插件(先匹配成功者优先):

┌─────────────────────────────────────────────────────────────┐
│                    插件发现优先级                             │
├─────────────────────────────────────────────────────────────┤
│  1. 配置路径    plugins.load.paths(显式定义)                  │
│     ↓                                                       │
│  2. 工作区扩展  .openclaw/extensions/*.ts(当前工作区)         │
│     ↓                                                       │
│  3. 全局扩展    ~/.openclaw/extensions/*.ts(用户级别)        │
│     ↓                                                       │
│  4. 捆绑插件    随网关发行的核心插件                             │
└─────────────────────────────────────────────────────────────┘

发现流程说明

  1. 配置路径:在配置文件中通过 plugins.load.paths 显式指定的插件路径,优先级最高
  2. 工作区扩展:位于当前工作区 .openclaw/extensions/ 目录下的 TypeScript 插件
  3. 全局扩展:位于用户主目录 ~/.openclaw/extensions/ 下的插件,对所有项目可用
  4. 捆绑插件:随 OpenClaw 发行版自带的核心插件,作为兜底选项

插件 SDK 和运行时

OpenClaw 为插件提供了一个专门的运行时环境,实现以下目标:

  • 隔离性:将插件与主进程隔离,防止插件崩溃影响系统稳定性
  • 访问控制:提供对网关服务的受控访问
  • 生命周期管理:管理插件的加载、初始化和卸载

核心组件

成分角色代码实体
装载机协调发现和实例化loadOpenClawPlugins
注册表保存工具、钩子和提供程序的活动实例PluginRegistry
显现用于验证的静态元数据,无需加载代码PluginManifestRecord
运行时提供给插件模块的执行上下文PluginRuntime

组件交互图

┌─────────────────────────────────────────────────────────────┐
│                     PluginLoader                            │
│  ┌─────────────────────────────────────────────────────┐    │
│  │  1. 扫描插件目录                                      │    │
│  │  2. 解析 openclaw.plugin.json                        │    │
│  │  3. 创建 PluginManifestRecord                        │    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────┐
│                     PluginRegistry                          │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐          │
│  │ Providers   │  │   Tools     │  │   Hooks     │          │
│  └─────────────┘  └─────────────┘  └─────────────┘          │
│  ┌─────────────┐  ┌─────────────┐                           │
│  │  Channels   │  │  Services   │                           │
│  └─────────────┘  └─────────────┘                           │
└─────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────┐
│                     PluginRuntime                           │
│  ┌─────────────────────────────────────────────────────┐    │
│  │  为每个插件创建独立的执行上下文                          │    │
│  │  提供对系统服务的受控访问                               │    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘

插件注册流程

注册 API 接口

插件实现了一个 register 函数,接收 OpenClawPluginApi 参数。此 API 允许注册以下组件:

注册类型描述使用场景
提供商模型、语音、图像和网络搜索提供商集成新的 AI 服务
工具创建 AnyAgentTool 实例的工厂函数扩展代理功能
钩子系统事件和提示注入的处理程序拦截和处理事件
渠道消息平台集成连接新的消息平台

注册流程图

┌─────────────────┐
│  插件模块加载     │
└────────┬────────┘
         ↓
┌─────────────────┐
│  调用 register() │
└────────┬────────┘
         ↓
┌─────────────────────────────────────────────────┐
│              OpenClawPluginApi                  │
│  ┌────────────────┐  ┌─────────────┐            │
│  │registerProvider│  │ registerTool│            │
│  └────────────────┘  └─────────────┘            │
│  ┌─────────────┐  ┌────────────────┐            │
│  │registerHook │  │registerChannel │            │
│  └─────────────┘  └────────────────┘            │
│  ┌───────────────┐                              │
│  │registerService│                              │
│  └───────────────┘                              │
└─────────────────────────────────────────────────┘
         ↓
┌─────────────────┐
│  PluginRegistry │
│  存储注册信息     │
└─────────────────┘

插件插槽(独占类别)

某些插件类型是独占的,这意味着在特定角色下同一时间只能激活一个插件。这些插件类型通过 plugins.slots 配置进行管理。

插槽名称目的默认值
memory主动长期记忆实现memory-core
contextEngine主动上下文管理逻辑legacy

插槽配置示例

{
  "plugins": {
    "slots": {
      "memory": "memory-lancedb",
      "contextEngine": "advanced-context"
    }
  }
}

四 插件发现和加载机制

发现顺序和优先权

OpenClaw 按照特定顺序扫描插件,第一个匹配到插件 ID 的插件将被选中

优先级来源路径说明
1(最高)配置路径plugins.load.paths 中定义显式指定的插件路径
2工作区扩展<workspaceDir>/.openclaw/extensions/项目级别插件
3全局扩展~/.openclaw/extensions/用户级别插件
4(最低)捆绑插件OPENCLAW_BUNDLED_PLUGINS_DIR随发行版提供的核心插件

发现逻辑详解

discoverOpenClawPlugins 函数负责发现插件,其工作流程如下:

┌─────────────────────────────────────────────────────────────┐
│                   插件发现流程                                │
├─────────────────────────────────────────────────────────────┤
│  1. 扫描配置路径                                              │
│     └─ 读取 plugins.load.paths                               │
│                                                             │
│  2. 扫描工作区扩展                                            │
│     └─ 查找 .openclaw/extensions/ 目录                       │
│                                                             │
│  3. 扫描全局扩展                                              │
│     └─ 查找 ~/.openclaw/extensions/ 目录                     │
│                                                             │
│  4. 扫描捆绑插件                                              │
│     └─ 查找 OPENCLAW_BUNDLED_PLUGINS_DIR                     │
│                                                             │
│  5. 解析清单文件                                              │
│     ├─ openclaw.plugin.json                                 │
│     └─ package.json(含 openclaw 字段)                       │
│                                                             │
│  6. 创建 PluginManifestRecord                                │
│     └─ 验证元数据                                             │
└─────────────────────────────────────────────────────────────┘

清单文件格式

// openclaw.plugin.json
{
  "id": "my-plugin",
  "name": "My Custom Plugin",
  "version": "1.0.0",
  "description": "A custom plugin for OpenClaw",
  "main": "dist/index.js",
  "config": {
    "schema": "./config.schema.json"
  }
}
// package.json(替代方案)
{
  "name": "@myorg/openclaw-plugin",
  "version": "1.0.0",
  "openclaw": {
    "id": "my-plugin",
    "main": "dist/index.js"
  }
}

加载和运行时隔离

动态导入机制

OpenClaw 使用 PluginLoader 动态导入插件模块,原生支持 TypeScript(通过 jiti):

// 插件加载流程
async function loadPlugin(modulePath: string) {
  // 使用 jiti 动态导入 TypeScript 模块
  const module = await jiti.import(modulePath);
  
  // 创建独立的运行时上下文
  const runtime = new PluginRuntime(pluginId);
  
  // 调用插件的 register 函数
  await module.register(runtime.api);
  
  return runtime;
}

运行时隔离

PluginRuntime 为每个插件创建独立的接口,提供对系统服务的隔离访问:

┌─────────────────────────────────────────────────────────────┐
│                     主进程                                   │
│  ┌─────────────────────────────────────────────────────┐    │
│  │              PluginRegistry(全局)                  │    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘
                              ↑
                          受控访问接口
                              │
┌─────────────────────────────────────────────────────────────┐
│                   插件运行时层                                │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐          │
│  │Runtime (A)  │  │Runtime (B)  │  │Runtime (C)  │          │
│  │ Plugin A    │  │ Plugin B    │  │ Plugin C    │          │
│  └─────────────┘  └─────────────┘  └─────────────┘          │
└─────────────────────────────────────────────────────────────┘

隔离优势

  • 故障隔离:单个插件崩溃不会影响其他插件或主进程
  • 权限控制:每个插件只能访问其被授权的系统服务
  • 版本兼容:不同插件可以使用不同版本的依赖库
  • 热重载:支持插件的动态加载和卸载

五 插件 SDK API 详解

插件 SDK 是扩展开发的主要接口,通过子路径导出进行分发:openclaw/plugin-sdk

关键子路径

子路径目的
openclaw/plugin-sdk/core核心类型和注册助手,例如 definePluginEntry
openclaw/plugin-sdk/runtime访问 PluginRuntime 与 Gateway 核心交互的方法
openclaw/plugin-sdk/channel-setup用于配置和注册新消息通道的实用程序
openclaw/plugin-sdk/provider-setup用于注册 AI 模型提供商和身份验证流程的辅助工具
openclaw/plugin-sdk/sandbox用于与执行沙箱环境交互的工具
openclaw/plugin-sdk/webhook-ingress用于处理传入 webhook 的功能

注册 API (OpenClawPluginApi)

register 函数接收一个包含 api 方法的对象,用于接入系统:

方法目的参数
registerProvider新增一个人工智能模型提供商ProviderDefinition
registerTool注册一个 AnyAgentTool 工厂供代理使用ToolFactory
registerHook附加到内部生命周期事件HookDefinition
registerChannel新增消息平台集成ChannelDefinition
registerService启动由插件生命周期管理的后台服务ServiceDefinition

API 使用示例

import { definePluginEntry } from 'openclaw/plugin-sdk/core';
import { PluginRuntime } from 'openclaw/plugin-sdk/runtime';

export default definePluginEntry({
  id: 'my-plugin',
  name: 'My Plugin',
  version: '1.0.0',
  
  async register(api: OpenClawPluginApi) {
    // 注册模型提供商
    await api.registerProvider({
      id: 'my-provider',
      name: 'My AI Provider',
      authMethod: 'api-key',
      // ... 其他配置
    });
    
    // 注册工具
    await api.registerTool({
      id: 'my-tool',
      name: 'My Custom Tool',
      factory: async (context) => {
        return {
          name: 'my_tool',
          description: 'A custom tool',
          execute: async (params) => { /* ... */ }
        };
      }
    });
    
    // 注册钩子
    await api.registerHook({
      event: 'onMessage',
      handler: async (event) => {
        console.log('Message received:', event);
      }
    });
    
    // 注册通道
    await api.registerChannel({
      id: 'my-channel',
      type: 'messaging',
      // ... 其他配置
    });
    
    // 注册后台服务
    await api.registerService({
      id: 'my-service',
      start: async () => { /* 启动服务 */ },
      stop: async () => { /* 停止服务 */ }
    });
  }
});

六 插件导出和提供程序

模型提供商

提供商通过 registerProvider 注册。定义了如何进行身份验证、列出模型以及处理推理流。

提供商定义结构

interface ProviderDefinition {
  // 唯一标识符
  id: string;
  
  // 显示名称
  name: string;
  
  // 身份验证方法
  authMethod: 'oauth' | 'api-key' | 'token';
  
  // 基础 URL
  baseUrl?: string;
  
  // 环境变量覆盖
  envVar?: string;
  
  // 模型列表
  models: ModelDefinition[];
  
  // 推理处理
  handleRequest: (request: InferenceRequest) => Promise<InferenceResponse>;
}

OAuth 流程实现

插件(例如 google-gemini-cli)实现 ProviderAuthMethod 接口,使用 ProviderAuthContext 通过 prompter 与用户交互:

// OAuth 认证流程示例
const authMethod: ProviderAuthMethod = {
  type: 'oauth',
  
  async initiate(context: ProviderAuthContext) {
    // 生成 PKCE
    const { verifier, challenge } = await generatePKCE();
    
    // 构建授权 URL
    const authUrl = buildAuthUrl({
      clientId: process.env.CLIENT_ID,
      redirectUri: 'http://localhost:3000/callback',
      scope: ['openid', 'profile'],
      codeChallenge: challenge
    });
    
    // 打开浏览器让用户授权
    await context.prompter.openUrl(authUrl);
    
    // 等待回调
    const code = await waitForCallback();
    
    // 交换令牌
    const tokens = await exchangeCodeForTokens(code, verifier);
    
    return tokens;
  },
  
  async refresh(refreshToken: string) {
    // 刷新访问令牌
    return await refreshAccessToken(refreshToken);
  }
};

工具和工厂

工具通过 OpenClawPluginToolFactory 注册,这使得工具能够通过 OpenClawPluginToolContext 实例化:

interface OpenClawPluginToolContext {
  // 会话 ID
  sessionId: string;
  
  // 代理 ID
  agentId: string;
  
  // 工作区目录
  workspaceDir: string;
  
  // 配置
  config: Record<string, any>;
}

// 工具工厂示例
const toolFactory: OpenClawPluginToolFactory = async (context: OpenClawPluginToolContext) => {
  return {
    name: 'file_operations',
    description: 'Perform file operations in the workspace',
    parameters: {
      type: 'object',
      properties: {
        operation: { type: 'string', enum: ['read', 'write', 'delete'] },
        path: { type: 'string' }
      }
    },
    execute: async (params) => {
      const fullPath = path.join(context.workspaceDir, params.path);
      // 执行文件操作
      return { success: true };
    }
  };
};

钩子和事件

插件通过 registerHook 订阅系统事件。支持的类别包括:

事件类别事件名称描述
代理生命周期onAgentStart代理启动时触发
onAgentEnd代理结束时触发
onAgentError代理出错时触发
消息事件onMessage收到消息时触发
onMessageSent发送消息后触发
配置更改onConfigChange配置更改时触发
系统事件onStartup系统启动时触发
onShutdown系统关闭时触发
// 钩子注册示例
await api.registerHook({
  event: 'onMessage',
  priority: 10, // 优先级(可选)
  handler: async (event: MessageEvent) => {
    // 处理消息事件
    console.log(`Received message from ${event.sender}: ${event.content}`);
    
    // 可以修改消息
    event.content = preprocessMessage(event.content);
    
    // 或者阻止消息传递
    // event.stopPropagation();
  }
});

七 插件配置和验证

配置模式定义

插件使用 OpenClawPluginConfigSchema 定义其配置要求:

import { z } from 'zod';

// 配置模式示例
const configSchema: OpenClawPluginConfigSchema = {
  // UI 提示(用于表单渲染)
  uiHints: {
    apiKey: {
      label: "API Key",
      sensitive: true,  // 敏感字段,显示为密码输入
      help: "Your provider API key"
    },
    model: {
      label: "Default Model",
      help: "Select the default model to use",
      options: ["gpt-4", "gpt-3.5-turbo", "claude-3"]
    },
    maxTokens: {
      label: "Max Tokens",
      help: "Maximum tokens per request",
      defaultValue: 4096
    }
  },
  
  // JSON Schema(用于验证)
  jsonSchema: {
    type: "object",
    properties: {
      apiKey: {
        type: "string",
        minLength: 1
      },
      model: {
        type: "string",
        enum: ["gpt-4", "gpt-3.5-turbo", "claude-3"]
      },
      maxTokens: {
        type: "integer",
        minimum: 1,
        maximum: 32000
      }
    },
    required: ["apiKey"]
  }
};

验证机制

网关使用 safeParsevalidate 方法验证配置:

// 配置验证流程
async function validatePluginConfig(
  pluginId: string,
  config: unknown
): Promise<ValidationResult> {
  const schema = await loadConfigSchema(pluginId);
  
  // 使用 Zod 进行验证
  const result = schema.safeParse(config);
  
  if (!result.success) {
    return {
      valid: false,
      errors: result.error.errors.map(e => ({
        path: e.path.join('.'),
        message: e.message
      }))
    };
  }
  
  return { valid: true, data: result.data };
}

八 插件状态管理

插件状态摘要

plugins list 命令显示已发现插件的当前状态:

$ openclaw plugins list

┌────────────────────┬──────────┬────────────┬─────────────────────┐
│ Plugin ID          │ Status   │ Origin     │ Path                │
├────────────────────┼──────────┼────────────┼─────────────────────┤
│ memory-core        │ loaded   │ bundled    │ extensions/memory   │
│ google-gemini-cli  │ loaded   │ global     │ ~/.openclaw/ext/... │
│ my-custom-plugin   │ disabled │ workspace  │ .openclaw/ext/...   │
│ broken-plugin      │ errorconfig     │ /custom/path/...    │
└────────────────────┴──────────┴────────────┴─────────────────────┘

状态特征

特征描述
清单文件openclaw.plugin.json 包含元数据和配置模式
状态loaded(已加载)、disabled(已禁用)或 error(错误),可通过 CLI 查看
来源跟踪插件是否为 bundled(捆绑)、workspace(工作区)或 global(全局)

状态转换图

                    ┌─────────────┐
                    │  Discovered │
                    └──────┬──────┘
                           │
                    验证清单文件
                           │
              ┌────────────┼────────────┐
              ↓            ↓            ↓
        ┌─────────┐  ┌─────────┐  ┌─────────┐
        │ Valid   │  │ Invalid │  │ Disabled│
        └────┬────┘  └────┬────┘  └────┬────┘
             │            │            │
        加载模块      标记错误      保持禁用
             │            │            │
        ┌────┴────┐       │            │
        ↓         ↓       │            │
    ┌────────┐ ┌────────┐ │            │
    │ Loaded │ │ Error  │ │            │
    └────────┘ └────────┘ │            │
                          ↓            │
                     ┌─────────┐       │
                     │  Error  │◄──────┘
                     └─────────┘

九 插件开发实战

插件结构概述

提供模型访问或扩展功能(如语音通话)的 OpenClaw 插件遵循通用结构:

extensions/<plugin-name>/
├── index.ts              # 插件入口点,提供商注册
├── src/
│   ├── providers/        # 特定提供商实现(如 Twilio、Plivo)
│   │   ├── twilio.ts
│   │   └── plivo.ts
│   ├── webhook.ts        # 异步事件的 Webhook 服务器
│   ├── config.ts         # Zod 验证的插件配置
│   ├── types.ts          # TypeScript 类型定义
│   └── utils/            # 工具函数
│       ├── auth.ts
│       └── validation.ts
├── tests/
│   ├── providers.test.ts
│   └── webhook.test.ts
├── openclaw.plugin.json  # 插件清单
├── README.md             # 用户文档
├── package.json          # 插件元数据
└── tsconfig.json         # TypeScript 配置

核心插件接口

所有插件都会导出一个实现插件契约的对象。register() 钩子接收 OpenClawPluginApi

// index.ts - 插件入口点
import { definePluginEntry } from 'openclaw/plugin-sdk/core';
import type { OpenClawPluginApi } from 'openclaw/plugin-sdk/core';
import { registerMyProvider } from './providers';
import { registerMyTools } from './tools';
import { registerMyHooks } from './hooks';

export default definePluginEntry({
  id: 'my-plugin',
  name: 'My Plugin',
  version: '1.0.0',
  description: 'A custom OpenClaw plugin',
  
  // 配置模式
  configSchema: {
    uiHints: {
      apiKey: { label: 'API Key', sensitive: true }
    },
    jsonSchema: {
      type: 'object',
      properties: {
        apiKey: { type: 'string' }
      },
      required: ['apiKey']
    }
  },
  
  // 注册钩子
  async register(api: OpenClawPluginApi) {
    // 注册模型提供商
    await registerMyProvider(api);
    
    // 注册自定义工具
    await registerMyTools(api);
    
    // 注册生命周期钩子
    await registerMyHooks(api);
    
    console.log('My Plugin registered successfully');
  }
});

OAuth 插件示例:Google Gemini CLI

供应商注册

Google Gemini CLI 插件通过 OAuth 身份验证注册提供程序。注册过程会将插件特定的逻辑映射到全局 models.json 配置。

// providers/gemini.ts
import { ProviderDefinition } from 'openclaw/plugin-sdk/provider-setup';

export const geminiProvider: ProviderDefinition = {
  id: 'google-gemini-cli',
  name: 'Google Gemini (CLI)',
  
  // 身份验证方法
  authMethod: {
    type: 'oauth',
    
    // PKCE OAuth 流程
    async initiate(context) {
      const { verifier, challenge } = await generatePKCE();
      
      const authUrl = new URL('https://accounts.google.com/o/oauth2/v2/auth');
      authUrl.searchParams.set('client_id', process.env.GEMINI_CLIENT_ID!);
      authUrl.searchParams.set('redirect_uri', 'http://localhost:3000/callback');
      authUrl.searchParams.set('response_type', 'code');
      authUrl.searchParams.set('scope', 'openid profile email');
      authUrl.searchParams.set('code_challenge', challenge);
      authUrl.searchParams.set('code_challenge_method', 'S256');
      
      // 打开浏览器
      await context.prompter.openUrl(authUrl.toString());
      
      // 等待回调
      const { code } = await context.waitForCallback();
      
      // 交换令牌
      return await exchangeCodeForTokens(code, verifier);
    },
    
    async refresh(refreshToken: string) {
      return await refreshGoogleToken(refreshToken);
    }
  },
  
  // 模型列表
  models: [
    { id: 'gemini-pro', name: 'Gemini Pro' },
    { id: 'gemini-pro-vision', name: 'Gemini Pro Vision' }
  ],
  
  // 推理处理
  async handleRequest(request) {
    const response = await fetch('https://generativelanguage.googleapis.com/v1/models/gemini-pro:generateContent', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${request.accessToken}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(request.body)
    });
    
    return await response.json();
  }
};

提供者定义结构

典型的服务提供商定义包括:

字段描述示例
提供商 ID唯一标识符google-gemini-cli
身份验证方法在提供程序运行时中定义oauthapi-keytoken
环境变量可选的凭据覆盖GOOGLE_API_KEY
基础 URLAPI 端点
模型列表支持的模型gemini-pro, gemini-pro-vision

OAuth 流程实现:PKCE OAuth 与本地主机回调

┌─────────────────────────────────────────────────────────────┐
│                    PKCE OAuth 流程                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 生成 PKCE 挑战                                           │
│     ├─ 生成随机 verifier                                     │
│     └─ 计算 challenge = SHA256(verifier)                    │
│                                                             │
│  2. 构建授权 URL                                             │
│     ├─ 添加 client_id                                       │
│     ├─ 添加 redirect_uri (localhost)                        │
│     ├─ 添加 code_challenge                                  │
│     └─ 添加 scope                                           │
│                                                            │
│  3. 用户授权                                                 │
│     ├─ 打开浏览器                                            │
│     └─ 用户登录并授权                                         │
│                                                             │
│  4. 接收回调                                                 │
│     ├─ 本地服务器接收授权码                                    │
│     └─ 验证 state 参数                                       │
│                                                             │
│  5. 交换令牌                                                 │
│     ├─ 发送 code + verifier                                 │
│     ├─ 服务器验证 PKCE                                       │
│     └─ 返回 access_token + refresh_token                    │
│                                                             │
│  6. 存储凭据                                                 │
│     └─ 安全存储令牌                                           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

关键实现模式

凭证解析:系统使用 resolveOAuthToken 在提供程序运行时获取活动凭证。

async function resolveOAuthToken(providerId: string): Promise<string> {
  const credentials = await credentialStore.get(providerId);
  
  if (isExpired(credentials)) {
    // 自动刷新令牌
    const newTokens = await refreshOAuthToken(credentials.refreshToken);
    await credentialStore.set(providerId, newTokens);
    return newTokens.accessToken;
  }
  
  return credentials.accessToken;
}

身份验证选择集成:在 openclaw onboard 过程中,applyNonInteractivePluginProviderChoice 函数负责选择基于 OAuth 的提供商。

令牌刷新:提供商实现 refreshOpenAICodexToken 来处理静默凭证续期。

插件示例:语音通话 Webhook

voice-call 扩展程序展示了一个功能强大的插件,可以管理外部 Webhook 和实时媒体流。

语音通话架构

┌─────────────────────────────────────────────────────────────┐
│                    语音通话架构                               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────┐         ┌─────────────┐                    │
│  │   Twilio    │◄───────►│  Webhook    │                    │
│  │   Provider  │  HTTP   │  Server     │                    │
│  └─────────────┘         └──────┬──────┘                    │
│                                 │                           │
│                          WebSocket│                         │
│                                 ↓                           │
│                          ┌─────────────┐                    │
│                          │   Media     │                    │
│                          │   Stream    │                    │
│                          │   Handler   │                    │
│                          └──────┬──────┘                    │
│                                 │                           │
│                          Audio Stream│                      │
│                                 ↓                           │
│                          ┌─────────────┐                    │
│                          │    AI       │                    │
│                          │   Provider  │                    │
│                          │  (OpenAI)   │                    │
│                          └─────────────┘                    │
│                                                             │
└─────────────────────────────────────────────────────────────┘

实施细节

Webhook 安全:使用 verifyTwilioProviderWebhook 验证来自 Twilio 的签名。

import { createHmac } from 'crypto';

async function verifyTwilioProviderWebhook(
  request: Request,
  authToken: string
): Promise<boolean> {
  const signature = request.headers['x-twilio-signature'];
  const url = request.url;
  const params = await request.formData();
  
  // 构建签名数据
  const data = url + Object.entries(params).sort().join('');
  
  // 计算 HMAC
  const expectedSignature = createHmac('sha1', authToken)
    .update(data)
    .digest('base64');
  
  return signature === expectedSignature;
}

媒体流:使用 OpenAI RealtimeVoiceCallWebhookServer 初始化 MediaStreamHandler 实现双向音频。

import { RealtimeVoiceCallWebhookServer, MediaStreamHandler } from 'openclaw/plugin-sdk/webhook-ingress';

const voiceServer = new RealtimeVoiceCallWebhookServer({
  port: 8080,
  path: '/voice',
  
  async onCallStart(callSid: string, streamSid: string) {
    // 初始化媒体流处理器
    const mediaHandler = new MediaStreamHandler({
      streamSid,
      onAudioReceived: async (audioData) => {
        // 发送到 AI 提供商处理
        const response = await aiProvider.processAudio(audioData);
        return response;
      }
    });
    
    return mediaHandler;
  }
});

过期通话清理器:后台任务 startStaleCallReaper 确保在超时后清理孤立的通话记录。

async function startStaleCallReaper() {
  setInterval(async () => {
    const staleCalls = await db.calls.findStale({
      maxAge: 30 * 60 * 1000 // 30 分钟
    });
    
    for (const call of staleCalls) {
      await cleanupCall(call.id);
      console.log(`Cleaned up stale call: ${call.id}`);
    }
  }, 5 * 60 * 1000); // 每 5 分钟运行一次
}

十 导入和配置集成

插件集成到 openclaw onboard 向导中,引导用户完成配置。

身份验证选择流程

┌─────────────────────────────────────────────────────────────┐
│                    注册流程                                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 发现                                                     │
│     └─ resolveProviderSetupFlowContributions                │
│        扫描已注册的插件以查找设置流程                            │
│                                                             │
│  2. 选择                                                     │
│     └─ buildAuthChoiceGroups                                │
│        用户看到分组选项                                        │
│                                                             │
│  3. 应用                                                     │
│     └─ applyNonInteractiveAuthChoice                        │
│        将选择持久化到 openclaw.json 或 auth-profiles.json      │
│                                                             │
└─────────────────────────────────────────────────────────────┘

十一 密钥处理机制

OpenClaw 支持将凭据存储为纯文本或引用。

存储模式

模式描述示例
引用模式存储环境变量名称,而不是字面值env:GOOGLE_API_KEY
纯文本模式将原始 API 密钥直接存储在配置中sk-xxxxx

配置示例

// openclaw.json - 引用模式(推荐)
{
  "providers": {
    "openai": {
      "apiKey": "env:OPENAI_API_KEY"
    },
    "google": {
      "credentials": "env:GOOGLE_CREDENTIALS_PATH"
    }
  }
}

// openclaw.json - 纯文本模式(不推荐)
{
  "providers": {
    "openai": {
      "apiKey": "sk-xxxxxxxxxxxxxxxx"
    }
  }
}

安全最佳实践

  1. 优先使用引用模式:避免在配置文件中存储敏感信息
  2. 使用环境变量:在 .env 文件或系统环境中设置凭据
  3. 配置文件排除:将 openclaw.json 添加到 .gitignore
  4. 定期轮换密钥:定期更新 API 密钥
# .env 文件示例
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxx
GOOGLE_API_KEY=AIzaxxxxxxxxxxxxxx
ANTHROPIC_API_KEY=sk-ant-xxxxxxxx

十二 插件实施清单

清单

成分描述
供应商注册定义模型、基本 URL 和身份验证方法
授权逻辑实现 OAuth、API 密钥或自定义身份验证标记
配置模式为插件设置定义 Zod 模式
Webhook Ingress(可选)使用 createWebhookInFlightLimiter 进行安全防护
入职流程注册交互式 CLI 的设置流程
错误处理实现适当的错误处理和日志记录
测试覆盖编写单元测试和集成测试
文档编写 README 和 API 文档

开发流程

┌─────────────────────────────────────────────────────────────┐
│                    插件开发流程                               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 规划                                                     │
│     ├─ 确定插件类型(提供商/工具/钩子/通道)                      │
│     ├─ 设计配置模式                                           │
│     └─ 规划身份验证方式                                        │
│                                                             │
│  2. 开发                                                     │
│     ├─ 创建插件目录结构                                        │
│     ├─ 实现核心功能                                           │
│     ├─ 编写配置模式                                           │
│     └─ 实现身份验证                                           │
│                                                             │
│  3. 测试                                                     │
│     ├─ 编写单元测试                                           │
│     ├─ 编写集成测试                                           │
│     └─ 手动测试                                              │
│                                                             │
│  4. 部署                                                     │
│     ├─ 本地安装测试                                           │
│     ├─ 发布到 npm(可选)                                     │
│     └─ 编写文档                                              │
│                                                             │
│  5. 维护                                                     │
│     ├─ 处理问题反馈                                           │
│     ├─ 发布更新                                              │
│     └─ 保持兼容性                                             │
│                                                             │
└─────────────────────────────────────────────────────────────┘

调试技巧

# 查看插件状态
openclaw plugins list

# 启用调试日志
DEBUG=openclaw:plugin:* openclaw start

# 测试特定插件
openclaw plugins test my-plugin

# 验证配置模式
openclaw plugins validate my-plugin

十三 附录

A. 常见问题

Q: 如何调试插件加载问题?

A: 使用 DEBUG 环境变量启用详细日志:

DEBUG=openclaw:* openclaw start

Q: 插件可以依赖其他插件吗?

A: 目前不支持插件间依赖。每个插件应该是独立的。

Q: 如何处理插件冲突?

A: 使用插件插槽(slots)机制管理独占类型插件,或通过配置禁用冲突插件。

B. 相关资源

  • OpenClaw 官方文档
  • 插件开发指南
  • API 参考
  • 社区论坛
本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:alixiixcom@163.com