跳转到内容

数据流与自动化

ESP-Claw 是一个事件驱动的 Agent 框架,「事件」Event 是每个 Agent 消息/自动化的触发基础。

Event 是 ESP-Claw 框架中的消息载体,包含了 Event ID、来源、目标、Event 类型、聊天 ID、发送者、文本或 JSON Payload、时间戳、以及 Session 策略等信息。

claw_event_t(见 claw_event.h)通过结构体组织上述信息。

claw_event_router 是 ESP-Claw 框架中的事件调度器,负责将 Event 按照规则进行调度。

router_rules.json 是 ESP-Claw 框架中的自动化规则文件,指定进入 claw_event_router 的 Event 如何处理。 router_rules.json 中的规则顺序决定了 Event 匹配规则的顺序。每条规则的主要内容有:

  • id: 规则的唯一标识。
  • ack: 规则命中后,可选的确认消息。
  • consume_on_match: 是否在规则命中后,阻止继续向下传递。
  • match: 规则的匹配条件。
  • actions: 规则的动作列表,例如:
    动作类型典型用途
    call_cap不经过大语言模型,直接执行某个能力
    run_agent异步提交消息至 claw_core,Agent 响应通过 agent_response 事件发布回 Event Router
    run_script运行 Lua 脚本
    send_message发送 IM 消息至出站绑定的目标
    emit_event生成新的事件并传递给 claw_event_router
    drop丢弃事件

basic_demo 自带简单的 router_rules.json,可以处理 IM 消息收发等基础任务。见 router_rules.json

router_rules.json 的详细语法定义可见 JSON Schema。

router_rules.json 的 JSON Schema
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "ESP-Claw Router Rules",
  "description": "Schema for ESP-Claw router rules (router_rules.json)",
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "id": {
        "type": "string",
        "description": "Unique identifier for the rule"
      },
      "description": {
        "type": "string",
        "description": "Optional description of the rule"
      },
      "enabled": {
        "type": "boolean",
        "default": true,
        "description": "Whether the rule is active"
      },
      "consume_on_match": {
        "type": "boolean",
        "default": true,
        "description": "If true, the event is marked as consumed and no further rules are processed for the same event"
      },
      "ack": {
        "type": "string",
        "description": "Optional acknowledgment message template"
      },
      "vars": {
        "type": "object",
        "description": "Rule-specific local variables",
        "additionalProperties": true
      },
      "match": {
        "type": "object",
        "required": ["event_type"],
        "properties": {
          "event_type": {
            "type": "string",
            "description": "The type of event to match (e.g., 'message', 'trigger')"
          },
          "event_key": {
            "type": "string",
            "description": "Specific key to match within the event"
          },
          "source_cap": {
            "type": "string",
            "description": "Capability that emitted the event"
          },
          "channel": {
            "type": "string",
            "description": "Alias for source_channel (kept for compatibility; prefer source_channel)"
          },
          "source_channel": {
            "type": "string",
            "description": "Channel from which the event originated"
          },
          "chat_id": {
            "type": "string",
            "description": "Chat or session identifier"
          },
          "content_type": {
            "type": "string",
            "description": "Type of content in the event"
          },
          "text": {
            "type": "string",
            "description": "Exact text or template to match"
          }
        },
        "additionalProperties": false
      },
      "actions": {
        "type": "array",
        "minItems": 1,
        "items": {
          "type": "object",
          "required": ["type"],
          "properties": {
            "type": {
              "type": "string",
              "enum": [
                "call_cap",
                "run_agent",
                "run_script",
                "send_message",
                "emit_event",
                "drop"
              ],
              "description": "The action to perform"
            },
            "caller": {
              "type": "string",
              "enum": ["system", "agent", "console"],
              "default": "system",
              "description": "The security context for execution"
            },
            "cap": {
              "type": "string",
              "description": "Specific capability name (required for call_cap)"
            },
            "capture_output": {
              "type": "boolean",
              "default": true,
              "description": "Whether to capture the output for subsequent actions"
            },
            "fail_open": {
              "type": "boolean",
              "default": false,
              "description": "If true, rule processing continues even if this action fails"
            },
            "input": {
              "type": "object",
              "description": "Action configuration. Supports template rendering via {{...}}",
              "additionalProperties": true
            }
          },
          "allOf": [
            {
              "if": {
                "properties": { "type": { "const": "call_cap" } }
              },
              "then": { "required": ["cap", "input"] }
            },
            {
              "if": { "properties": { "type": { "const": "send_message" } } },
              "then": {
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "channel": { "type": "string" },
                      "chat_id": { "type": "string" },
                      "message": { "type": "string" }
                    }
                  }
                }
              }
            },
            {
              "if": { "properties": { "type": { "const": "run_agent" } } },
              "then": {
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "text": { "type": "string" },
                      "target_channel": { "type": "string" },
                      "target_chat_id": { "type": "string" },
                      "session_policy": {
                        "type": "string",
                        "enum": [
                          "chat",
                          "trigger",
                          "global",
                          "ephemeral",
                          "nosave"
                        ]
                      }
                    }
                  }
                }
              }
            },
            {
              "if": { "properties": { "type": { "const": "run_script" } } },
              "then": {
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "path": { "type": "string" },
                      "async": { "type": "boolean" }
                    },
                    "required": ["path"]
                  }
                }
              }
            },
            {
              "if": { "properties": { "type": { "const": "emit_event" } } },
              "then": {
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "source_cap": { "type": "string" },
                      "event_type": { "type": "string" },
                      "source_channel": { "type": "string" },
                      "chat_id": { "type": "string" },
                      "message_id": { "type": "string" },
                      "content_type": { "type": "string" },
                      "text": { "type": "string" },
                      "payload_json": { "type": "string" },
                      "session_policy": {
                        "type": "string",
                        "enum": [
                          "chat",
                          "trigger",
                          "global",
                          "ephemeral",
                          "nosave"
                        ]
                      }
                    }
                  }
                }
              }
            }
          ]
        }
      }
    },
    "required": ["id", "match", "actions"],
    "additionalProperties": false
  }
}

Event 进入 Event Router 后,从队列取出并逐条与规则集匹配。以下流程图展示完整逻辑:

Diagram

当 Event Router 的 run_agent 动作被触发后,Agent 的响应不会同步返回,而是以 agent_response 类型的事件异步发布回 Event Router。

如需将 Agent 响应发送到 IM 通道,需要为 agent_response 配置对应的路由规则,例如:

{
  "id": "agent_response_send_message",
  "consume_on_match": true,
  "match": {
    "source_cap": "claw_core",
    "event_type": "agent_response",
    "content_type": "text"
  },
  "actions": [
    {
      "type": "send_message",
      "input": {
        "channel": "{{event.source_channel}}",
        "chat_id": "{{event.chat_id}}",
        "message": "{{event.text}}"
      }
    }
  ]
}

其中 channel / chat_id 通常来自触发 run_agent 时传入的 target_channel / target_chat_id

run_agent 动作提交到 claw_core 后会分配并记录 request_id,用于后续取消或追踪。

对应地,框架提供了两层“取消”能力(C API):

  • claw_core_cancel_request(request_id):取消当前正在执行(in-flight)的 Agent 请求。
  • claw_event_router_cancel_event(event_id):标记并跳过队列中尚未处理的单个 Event。
  • claw_event_router_purge_queue(event_type_filter, source_cap_filter, &out_cancelled):批量标记并跳过队列中的待处理 Event(可按事件类型、来源 cap 过滤)。

除最终结果对应的 agent_response 外,claw_core 还可以在 Agent 多轮工具调用过程中发布 agent_stage 事件,可用于推送工具调用的阶段性信息。

agent_stage 事件的结构为:

  • source_capclaw_core
  • event_typeagent_stage
  • event.text:工具调用过程中的阶段性信息

如需自动发出 agent_stage 事件,需调整 menuconfig 中的配置:(Top)Component configESP-Claw CoreAgent stage notification verbosity

  • 选择 Verbose 时,claw_core 会在每轮存在工具调用时向 Event Router 发布 agent_stage 事件;
  • 选择 Simple 时,不在路由层发布 agent_stage 事件。

agent_stage 事件可以被路由到 IM 等通道,以实时向用户反馈「工作进度」。 例如 basic_demo 默认的 router_rules.json 中定义了规则 agent_stage_im_notify,在启用 Verbose 且命中该规则时,会把 agent_stage{{event.text}} 发回来源 IM 会话。

cap_scheduler 提供基于时间的事件触发能力,支持 once(一次性)、interval(间隔重复)和 cron(日历表达式,5 段,不含秒)三种调度类型。

调度器只负责到时发布 Event,触发后的具体行为由 Event Router 的规则决定。因此,添加定时任务通常需要同时:

  1. 添加一条调度项(schedules.json 或通过 scheduler_add
  2. 添加一条匹配的路由规则(router_rules.json 或通过 add_router_rule

典型的匹配方式:调度项设置 event_type: "schedule" + event_key,路由规则用 match.event_type + match.event_key 命中。

scheduler --list                     # 列出所有调度项
scheduler --reload                   # 从磁盘重新载入
scheduler --add --json '<json>'      # 新增调度项
scheduler --enable <id>              # 启用
scheduler --disable <id>             # 禁用
scheduler --pause <id>               # 暂停
scheduler --resume <id>              # 恢复
scheduler --trigger <id>             # 立即触发一次

cap_scheduler 注册了 scheduler_listscheduler_getscheduler_addscheduler_enablescheduler_disablescheduler_pausescheduler_resumescheduler_trigger_nowscheduler_reload 等 LLM 可调用工具。这些工具需要通过激活 cap_scheduler Skill 后开放。

cap_router_mgr 注册了 list_router_rulesget_router_ruleadd_router_ruleupdate_router_ruledelete_router_rulereload_router_rules 等 LLM 可调用工具。

Event Router 提供了两组 Console 命令。auto 命令来自 basic_demoevent_router 命令来自 cap_router_mgr,两者功能等价,操作同一份规则集。

# auto 命令(basic_demo 提供)
auto reload                  # 重新载入 router_rules.json
auto rules                   # 列出当前规则集 JSON
auto rule <id>               # 查看单条规则 JSON
auto add_rule '<json>'       # 新增一条规则
auto update_rule '<json>'    # 按 id 替换一条规则
auto delete_rule <id>        # 删除一条规则
auto emit_message ...        # 见后文详细说明
auto emit_trigger ...        # 见后文详细说明
auto last                    # 查看最近一次匹配统计,见后文详细说明

# event_router 命令(cap_router_mgr 提供)
event_router --rules                     # 列出当前规则集 JSON
event_router --rule <id>                 # 查看单条规则 JSON
event_router --add-rule-json '<json>'    # 新增一条规则
event_router --update-rule-json '<json>' # 按 id 替换一条规则
event_router --delete-rule <id>          # 删除一条规则
event_router --reload                    # 重新载入 router_rules.json
event_router --emit-message ...          # 发布消息 Event
event_router --emit-trigger ...          # 发布触发 Event
event_router --last                      # 查看最近一次匹配统计
  • auto emit_message 模拟一条来自 IM 的消息 Event:

    auto emit_message <source_cap> <channel> <chat_id> <text...>
    # auto emit_message qq_gateway    qq      123456   hello world
    参数说明示例
    source_cap来源 Capability 名称qq_gateway
    channel来源频道qq
    chat_id聊天 ID(群号 / 话题 ID 等)123456
    text...消息文本(支持空格,多词自动拼接)hello world
  • auto emit_trigger 模拟一条触发类 Event:

    auto emit_trigger <source_cap> <event_type> <event_key> '<payload_json>'
    # auto emit_trigger  tester      trigger     smoke_test '{"ok":true}'
    参数说明示例
    source_cap来源 Capability 名称tester
    event_type事件类型,对应规则 match.event_typetrigger
    event_key事件键,对应规则 match.event_keysmoke_test
    payload_jsonJSON 对象格式的 Payload'{"ok":true}'
  • auto last 输出最近一次 Event 的处理结果,例如:

    matched=true matched_rules=1 action_count=2 failed_actions=0 route=1 handled_at_ms=...
    first_rule_id=handle-message
    ack=matched:handle-message
    last_error=ESP_OK
    字段说明
    matched是否命中至少一条规则
    matched_rules命中规则总数
    action_count执行动作总数
    failed_actions执行失败的动作数
    route0 = PASS(未消耗),1 = CONSUMED(已消耗)
    first_rule_id第一条命中规则的 id
    ack命中规则的 ack 字段渲染结果
    last_error最后一次动作的错误码