找回密码
立即注册
搜索
发回帖 发新帖

5314

积分

0

好友

674

主题
发表于 4 小时前 | 查看: 8| 回复: 0

在 ESP-Claw 中,IM 消息、Lua 脚本、启动钩子、CLI 命令、Agent 输出,所有这些来源最终都被折叠成同一种东西:事件。claw_event_router 组件拿到事件后,按 DATA 根下 router_rules/router_rules.json 里声明的规则做匹配,并执行六类动作之一:调能力、跑脚本、跑 Agent、发消息、发事件或丢弃。

它是“事件驱动、毫秒响应”这一卖点的基础设施:命令前缀在毫秒内被能力短路应答,只有真正需要思考的内容才流入 LLM。本章回答三个问题:事件长什么样、规则怎么匹配、动作怎么落地。

目录

  1. 从“万物皆事件”到统一入口
    • 1.1 事件结构体:一张会话快递单
    • 1.2 三类发布入口与触发源地图
  2. 声明式规则引擎
    • 2.1 router_rules.json 的真实 Schema
    • 2.2 规则加载与热更新
    • 2.3 匹配算法:顺序管道与“消费即停”
  3. 六类动作的执行
    • 3.1 动作分发与模板上下文
    • 3.2 call_cap 与 run_script:不过大脑的短路响应
    • 3.3 run_agent:把事件交给大脑
    • 3.4 send_message 与出站绑定
    • 3.5 emit_event 与 drop:级联与熔断
  4. cap_router_mgr:LLM 的自我配置入口
  5. 设计动机:声明式与独立模块的边界
    • 5.1 为什么是声明式 JSON 而非硬编码 C 分支
    • 5.2 为什么路由器独立成模块而非并入 claw_core
  6. 与其他章节的衔接

1. 从“万物皆事件”到统一入口

事件路由的第一性问题是:异构触发源,例如微信回调、定时器到期、开机完成、Lua 一行代码,它们之间的差异必须在一个统一的抽象面前消失,否则路由规则就得为每个来源写一套特判。ESP-Claw 的答案是 claw_event_t,一个自描述的“会话快递单”,以及三个归一化的发布入口。

ESP-Claw 事件路由系统架构图:事件源、事件路由器与动作目标关系

1.1 事件结构体:一张会话快递单

事件的真实定义位于 components/claw_modules/claw_event_router/include/claw_event.h,摘录如下,省略部分同构字段:

typedef struct {
    char event_id[48];        // 事件唯一 ID,如 "msg-1730000000000"
    char source_cap[32];      // 发布者,如 "cap_im_wechat"、"claw_core"、"app_claw"
    char event_type[32];      // 事件类型:"message"、"startup"、"agent_stage" 等
    char source_channel[16];  // 来源渠道:wechat / tg / qq / feishu / local
    char target_channel[16];  // 目标渠道,决定回复走哪条 IM 通道
    char chat_id[96];         // 会话 ID,跨事件串联同一对话
    char sender_id[96];       // 发送者 ID
    char message_id[96];      // 消息 ID,发布时同步拷贝进 correlation_id
    char content_type[24];    // "text" / "trigger" 等
    int64_t timestamp_ms;     // 毫秒时间戳
    claw_session_policy_t session_policy; // chat/trigger/global/ephemeral/nosave
    char *text;               // 堆分配的正文(消息类事件)
    char *payload_json;       // 堆分配的 JSON 负载(触发类事件)
} claw_event_t;

这个结构处处体现嵌入式约束。除两个堆指针外,全部是定长字符数组。因为 FreeRTOS 队列按 sizeof(claw_event_t) 整块拷贝事件,定长头部保证一次 memcpy 即完成入队,不需要序列化。

text 与 payload_json 是仅有的两处需要深拷贝的可变长部分,claw_event_clone() 单独 strdup 它们,claw_event_free() 单独释放。session_policy 直接内嵌在事件里,事件天生知道自己该进哪种记忆会话,下游动作无需再猜。

事件 ID 由发布接口按时间戳生成:消息类是 msg-<毫秒时间戳>,触发类是 evt-<毫秒时间戳>,足够在单设备上保持唯一,且天然按时间排序。

1.2 三类发布入口与触发源地图

include/claw_event_publisher.h 只暴露三个发布函数,覆盖了所有触发源:

esp_err_t claw_event_router_publish(
    const claw_event_t *event);   // 原始发布

esp_err_t claw_event_router_publish_message(
    source_cap, channel,
    chat_id, text, sender_id, message_id);

esp_err_t claw_event_router_publish_trigger(
    source_cap, event_type,
    event_key, payload_json);

publish_message() 是 IM 消息的入口:自动填 event_type="message"、content_type="text"、session_policy=chat。

publish_trigger() 是机器触发的入口:content_type 固定为 trigger、session_policy 固定为 trigger,event_key 借用 message_id/correlation_id 字段携带,匹配时经 claw_event_router_event_key() 取回。

各触发源到入口的对应关系如下表:

触发源 调用入口 典型事件
IM 平台能力(cap_im_wechat/tg/qq/feishu/local) publish_message() message/text
Lua 事件发布器(lua_module_event_publisher) 三者皆可 message、trigger、自定义
应用外壳 app_claw(启动钩子) publish_trigger() startup/boot_completed
CLI(app_claw_cli、cmd_cap_router_mgr) publish_trigger()/handle_event() 调试触发
claw_core(agent_stage/out_message) publish() Agent 阶段与输出回投
emit_event 动作自身 publish() 级联新事件

事件路由层级判断流程图:L1 事件路由、L2 Lua 反应堆、L3 LLM 思考器

所有入口殊途同归于 claw_event_router_publish():clone 事件、登记进“待处理表”,也就是 pending 表,供 cancel_event/purge_queue 撤销在途事件,再 xQueueSend 进入事件队列。

默认队列深度仅 6,超时 1 秒即失败返回。消费侧是独立任务 claw_event_router_task,任务名 event_router,默认栈 8192 字节、优先级 5、PSRAM 优先栈策略。它以 250 毫秒轮询周期出队,先查 pending 表确认未被撤销,再交给核心函数 claw_event_router_process_event()。

队列刻意短小:路由器是低延迟中枢而非缓冲池,事件积压时宁可让发布方收到超时错误,也不掩盖消费瓶颈。

2. 声明式规则引擎

2.1 router_rules.json 的真实 Schema

规则文件由应用外壳在初始化时指定:app_claw.c 调用 claw_paths_join(CLAW_PATH_DATA, "router_rules/router_rules.json", ...),即 DATA 分区根下的 router_rules 目录。

出厂镜像 application/edge_agent/fatfs_image/system/.recovery/router_rules/router_rules.json 保存了一份恢复副本。从该文件摘录一条真实规则 im_session_command,并加中文注释:

{
  "id": "im_session_command",
  "enabled": true,
  "consume_on_match": true,
  "ack": "{{event.source_channel}} session command handled",
  "match": {
    "event_type": "message",
    "content_type": "text",
    "text": "/session",
    "text_match_rule": "prefix"
  },
  "actions": [
    {
      "type": "call_cap",
      "cap": "session_command",
      "input": {
        "command": "{{match.remainder}}"
      }
    },
    {
      "type": "send_message",
      "input": {
        "channel": "{{event.source_channel}}",
        "chat_id": "{{event.chat_id}}"
      }
    }
  ]
}

字段的真实约束来自 claw_event_router_parse_rule():id、match 对象、非空 actions 数组三者必填,match.event_type 亦必填。一条规则至少要声明“我关心哪类事件”,其余匹配字段留空即通配。

规则级字段含义如下表:

字段 默认值 语义
id 必填 规则唯一标识,增删改与日志追踪的主键
enabled true 软开关,不删规则即可临时停用
consume_on_match true 命中后是否终止后续规则
ack 空 模板字符串,渲染后写入结果供上游确认
vars {} 规则私有变量,注入模板上下文
match 必填 七字段匹配条件
actions 必填 顺序执行的动作列表,上限 8 个

match 的七个字段是 event_type、event_key、source_cap、channel,其中 channel 是 source_channel 的别名,还有 chat_id、content_type、text。

text 支持 exact,默认全等,与 prefix,前缀加词边界,两种 text_match_rule,选 prefix 时 text 必填。

动作字段是 type、cap,其中 cap 仅 call_cap 必填,还有 input 对象、caller、capture_output,默认 true,以及 fail_open,默认 false。

解析阶段即完成全部校验:规则数上限 32、单规则动作数上限 8。坏规则在加载时就被拒绝,而不是留到运行时炸队列。

2.2 规则加载与热更新

初始化路径是 claw_event_router_init() → claw_event_router_reload()。

reload 先把 JSON 文件完整解析成新规则数组,成功后才在递归互斥锁内“释放旧的、换上新的”。解析失败则直接返回错误,旧规则原封不动。这是一次性原子换表,正在处理中的事件持有的是旧数组指针,不会读到半新半旧的状态。

运行期另有一组写接口:claw_event_router_add_rule/update_rule/delete_rule 在内存改表后,经 commit_rules() 把整表序列化回写 rules_path 指向的 JSON 文件。claw_event_router_purge_queue() 则清洗在途事件。

规则因此具备多条生命周期通道:用户手工编辑文件后 reload、LLM 经能力接口增删改、从出厂镜像 fatfs_image/system/.recovery/ 下的副本恢复。无论哪条通道改的,最终都收敛到同一份持久化 JSON。

2.3 匹配算法:顺序管道与“消费即停”

匹配核心只有一行链式与运算,来自 claw_event_router.c:

static bool claw_event_router_rule_matches(
    const claw_event_router_rule_t *rule,
    const claw_event_t *event,
    claw_event_router_text_match_context_t *out_match)
{
    return rule && rule->enabled &&
           claw_event_router_match_field(rule->match.event_type, event->event_type) &&
           claw_event_router_match_field(rule->match.event_key, claw_event_router_event_key(event)) &&
           claw_event_router_match_field(rule->match.source_cap, event->source_cap) &&
           claw_event_router_match_field(rule->match.channel, event->source_channel) &&
           claw_event_router_match_field(rule->match.chat_id, event->chat_id) &&
           claw_event_router_match_field(rule->match.content_type, event->content_type) &&
           claw_event_router_match_text(&rule->match, event->text, out_match);
}

而 match_field 的实现揭示了“通配”的真相:期望值为空即无条件通过。

static bool claw_event_router_match_field(const char *expected, const char *actual)
{
    return !expected || !expected[0] || strcmp(expected, actual ? actual : "") == 0;
}

文本匹配比字段匹配精细一档:prefix 模式会先跳过前导空白,strncmp 命中后还要求下一个字符是空白或结尾,也就是词边界,防止 /session 误吃 /sessionize。

命中后把剩余部分记入 match.remainder,于是规则里 {{match.remainder}} 就能取出 /session list 中的 list。

这不是首中即停的防火墙式规则表。process_event() 按文件顺序遍历全部规则,每条启用且匹配的规则都会执行其动作;只有 consume_on_match 为 true 的规则执行完后才 break。

换言之,规则表是一条有序的拦截器管道。出厂规则把这一语义用到了极致:im_any_message_working_reply 显式写 consume_on_match: false,先给用户回一句 “🦞 ESP-Claw is snapping on it...”,然后放行给排在后面的 im_any_message_agent,把消息送进 Agent。

顺序即优先级,文件中的排列位置就是设计的一部分。

管道之外还有两道护栏:source_cap 为 claw_event_router 的自发布事件在入口被直接丢弃,防止 emit_event 无限自环;规则内动作顺序执行,某个动作失败即中断本规则后续动作,除非该动作显式声明 fail_open: true。

3. 六类动作的执行

3.1 动作分发与模板上下文

所有动作经同一个 switch 分发,真实代码如下:

switch (action->kind) {
case CLAW_EVENT_ROUTER_ACTION_CALL_CAP:     // 调用能力
    return claw_event_router_execute_cap_action(rule, action, event, ctx, result);
case CLAW_EVENT_ROUTER_ACTION_RUN_AGENT:    // 交给 Agent
    return claw_event_router_execute_agent_action(rule, action, event, ctx, result);
case CLAW_EVENT_ROUTER_ACTION_RUN_SCRIPT:   // 跑 Lua 脚本
    return claw_event_router_execute_script_action(rule, action, event, ctx, result);
case CLAW_EVENT_ROUTER_ACTION_SEND_MESSAGE: // 发消息,经出站绑定找 IM 能力
    return claw_event_router_execute_send_message_action(rule, action, event, ctx, result);
case CLAW_EVENT_ROUTER_ACTION_EMIT_EVENT:   // 发事件,重新入队,可级联
    return claw_event_router_execute_emit_event_action(action, ctx, result);
case CLAW_EVENT_ROUTER_ACTION_DROP:         // 丢弃:标记 CONSUMED 后返回
    ...
}

分发前,process_event() 已构建好模板上下文 ctx,它是一个 cJSON 对象。

  • event 分支携带事件的全部字段与解析后的 payload
  • match 分支携带命中文本、匹配方式与 remainder
  • vars 分支是规则私有变量
  • rule 分支只有 id
  • last 分支是上一个动作的输出

所有动作的 input 都先经 render_json() 把 {{...}} 占位符替换为 ctx 中的实值。数据在动作链里流动,前一个 call_cap 的输出可以成为后一个 send_message 的正文。完整链路见下方时序图。

事件从触发源到动作执行的完整路由时序图

流程执行说明:

  • 入口归一阶段,步骤 1-4:IM 平台能力与 Lua 事件发布器分别经 publish_message()、publish_trigger() 把异构来源折叠为 claw_event_t,深拷贝后入队。路由器任务 claw_event_router_task 出队并调 process_event()。
  • 规则管道阶段,步骤 5-13:按文件顺序循环调用 rule_matches()。alt 命中分支里先执行 call_cap,claw_cap_call 直达能力,输出写入 ctx.last.output,再执行 send_message 经出站绑定调 IM 发送能力,用户在毫秒级收到回复。opt 块表示 consume_on_match 为 true 时终止遍历,false 则继续匹配下一条规则。
  • 兜底阶段,步骤 14-16:opt 无命中分支中,若配置了 default_route_messages_to_agent 且事件是带文本的 message,则以合成规则 default_agent 走 claw_agent_mgr_submit_root() 提交 Agent,受理即返回 request_id,路由器不等待 LLM。

关键规则与最佳实践: 动作顺序即数据流,call_cap 在前、send_message 在后可自动转发能力输出。consume_on_match 决定一条规则是“终点”还是“中间件”。LLM 耗时环节只提交不等待,保证队列不淤塞。

3.2 call_cap 与 run_script:不过大脑的短路响应

call_cap 是最基础也最快的动作。execute_cap_action 以 source_cap="claw_event_router"、事件 correlation_id 与动作声明的 caller 组装 claw_cap_call_context_t,直接调 claw_cap_call(action->cap, input_json, ...)。

输出缓冲区默认 2048 字节,capture_output 默认开启,能力返回文本会写进 ctx 的 last.output。

run_script 则是一次优雅的归一:它根本不是独立实现,而是把自己改写成 call_cap。

strlcpy(cap_name,
        cJSON_IsTrue(cJSON_GetObjectItem(input_root, "async")) ?
        "lua_run_script_async" : "lua_run_script",
        sizeof(cap_name));
local.kind = CLAW_EVENT_ROUTER_ACTION_CALL_CAP;  // 伪装成 call_cap
return claw_event_router_execute_cap_action(rule, &local, event, ctx, result);

动作类型表面上有六种,执行路径实际收敛为“统一经能力系统分发”。路由器不认识 Lua,也不认识任何硬件,它只认识能力名。这让路由器的代码面积极小,也让新增可执行单元,例如新脚本、新设备驱动,无需改动路由器一行代码。

出厂规则 startup_run_led_strip_dim_white 就是一例:开机 boot_completed 事件触发后,直接以参数运行 /fatfs/skills/light_switch/scripts/led_strip_switch.lua 点亮灯带,全程无 LLM 参与。

3.3 run_agent:把事件交给大脑

execute_agent_action 解析渲染后的 input,包含 text、target_channel、target_chat_id、session_policy 四个可选项,缺省时回落到事件本身,组装 claw_agent_mgr_root_input_t 后提交:

agent_input.flags = CLAW_CORE_REQUEST_FLAG_PUBLISH_OUT_MESSAGE |
                    CLAW_CORE_REQUEST_FLAG_PUBLISH_STAGE_MESSAGE |
                    CLAW_CORE_REQUEST_FLAG_SKIP_RESPONSE_QUEUE |
                    CLAW_CORE_REQUEST_FLAG_USER_INTERRUPT;
agent_input.request_id = s_runtime->next_request_id++;
agent_input.user_text = (text && text[0]) ? text : (event->text ? event->text : "");
agent_input.target_channel = (target_channel && target_channel[0]) ? target_channel
                                                                   : event->source_channel;
err = claw_agent_mgr_submit_root(&agent_input, s_runtime->config.agent_submit_timeout_ms);

两个细节值得咀嚼。

其一,flags 明确要求“输出与阶段消息都以事件形式发布、跳过响应队列”。Agent 的最终回答不是直接回调路由器,而是变成 source_cap=claw_core 的 out_message/agent_stage 事件重新入队,再由 agent_out_message_send_message 规则送回原聊天。回复走的是与提问同一条管道,路由器在提交那一刻就对本次请求放手。

其二,提交超时默认仅 1000 毫秒,且 process_event() 在调用兜底 Agent 前会先释放互斥锁。LLM 再慢也只影响 Agent 侧队列,不会让路由器持锁等待。

这正是“毫秒响应”的真相:路由器本身只做字符串比较与能力分发,最重的一步也只是“把活儿交出去”。

run_agent 动作之外还有一条隐形的 run_agent:当整张规则表没有任何规则命中、配置项 default_route_messages_to_agent 打开、且事件是带正文的 message 时,process_event() 会合成一条名为 default_agent 的规则,以 CLAW_CAP_CALLER_SYSTEM 身份走同一个提交函数。

出厂规则表里那条 im_any_message_agent,也就是 consume_on_match: true 的 run_agent 兜底规则,与这个代码级兜底互为双保险。规则删光了,设备依然是聊天机器人。规则引擎负责“例外怎么处理”,代码兜底保证“默认行为永远存在”。

3.4 send_message 与出站绑定

send_message 要解决的问题是:路由器怎么知道“发到 wechat”该调哪个能力?

答案是两级解析,对应 claw_event_router_resolve_outbound_cap。

先问配置注入的自定义 outbound_resolver 回调,应用可按 endpoint 做更细的路由。未命中再查内置绑定表,由应用外壳 app_claw.c 在启动时经 claw_event_router_register_outbound_binding() 注册的“渠道→能力”映射,例如:

  • wechat → wechat_send_message
  • telegram → tg_send_message
  • qq → qq_send_message
  • feishu → feishu_send_message
  • web → local_send_message

解析出能力后,组 payload 结构为 {chat_id, message, event_type},以 CLAW_CAP_CALLER_SYSTEM 身份调 claw_cap_call()。

三个智能缺省让规则写作非常省事:

  • channel 缺省取事件的 target_channel/source_channel
  • chat_id 缺省取 target_endpoint/chat_id
  • message 缺省直接取 ctx 的 last.output

于是“call_cap 算结果 + send_message 原样回复”两个动作就能拼出一条完整的自动化应答链,规则作者甚至不用写正文。

3.5 emit_event 与 drop:级联与熔断

emit_event 是规则的“自造事件”能力。它用渲染后的 input,例如 source_cap、event_type、text、payload_json、session_policy 等,现场拼一个新事件。event_id 仍是 evt-<时间戳>,content_type 与 session_policy 缺省为 trigger,再经 publish() 重新入队。

它使规则可以级联:一次开机触发可以派生出若干子事件,分别命中不同规则。

drop 则是最短的动作:把结果 route 标记为 CLAW_CAP_EVENT_ROUTE_CONSUMED 后立即返回,什么都不做。

“显式丢弃”看似多余,实则重要。它是规则表里的熔断器,用来在管道前面挡掉噪音事件,例如群聊刷屏,防止它们流到默认兜底分支惊动 LLM。

配合入口处的自环护栏,也就是 source_cap 为 claw_event_router 的事件直接丢弃,级联的深度被天然限制住。

4. cap_router_mgr:LLM 的自我配置入口

components/claw_capabilities/cap_router_mgr 把路由规则的增删改查本身做成了一个能力组。group_id 为 cap_router_mgr,family 为 router_manager,注册了六个能力:

  • list_router_rules
  • get_router_rule
  • add_router_rule
  • update_router_rule
  • delete_router_rule
  • reload_router_rules

其中 add、update 接收 {"rule_json": "<完整规则 JSON 字符串>"},内部转调 claw_event_router_add_rule_json()、update_rule_json(),改表成功后自动持久化回 JSON 文件。

另有 CLI 孪生命令 cmd_cap_router_mgr.c,供人在串口终端做同样的事。

这一层是 ESP-Claw“自我配置”叙事的落点:用户对 Agent 说“以后收到带 #紧急 的消息先回一句收到”,Agent 在工具调用循环中便可调用 add_router_rule 安装一条新反射。

因为规则落盘在 FATFS,这条“学会的行为”在重启后依然生效。LLM 修改的不是自己的提示词,而是设备的神经系统接线图,且改的是数据,不是代码,永远不需要重新编译固件。

5. 设计动机:声明式与独立模块的边界

5.1 为什么是声明式 JSON 而非硬编码 C 分支

同样实现 /session 命令直达能力,硬编码方式是在 claw_core 里写 strcmp 分支,每加一条命令就改一次 C 代码、重新编译烧录。

声明式 JSON 的方案把“策略”从“机制”中剥离开来,收益集中在三方:

  • 终端用户用文本编辑器就能调整设备行为,改 enabled 即可停用一条规则
  • LLM 通过 cap_router_mgr 拥有了同样的修改权,且 JSON 规则恰好是 LLM 最擅长产出的格式
  • 一个 JSON 对象即可完整描述条件与动作,无需函数指针或编译期绑定

加载即校验的设计,包括上限 32 规则、8 动作、必填字段检查,给了这层“人人可改”的能力一个安全网。坏规则进不了内存,更进不了运行时。

此外,声明式天然可审计、可备份:.recovery 目录里的出厂副本、文件里的注释性 description 字段,都让“设备为什么这么做”有据可查。

5.2 为什么路由器独立成模块而非并入 claw_core

从职责上看,claw_core 是“大脑”,持有 Agent Loop、会话与 LLM 交互。claw_event_router 是“脊髓”,负责条件反射弧。

反射不该经过大脑。工作回复,例如 “ESP-Claw is snapping on it...”,命令前缀分流、开机点灯,这些动作的正确性不依赖推理,速度却直接决定用户体验。

把路由器独立成组件,带来三个收益:

  1. 获得自己的执行线程与队列,慢速的 LLM 推理永远排在这条快速通路之后
  2. 获得干净的依赖方向。路由器只依赖 claw_cap 的分发接口与 claw_agent_mgr 的提交接口,反过来 claw_core 的输出,包括 agent_stage、out_message,也要作为事件回到路由器,由规则决定送达哪个渠道。两个模块经事件队列双向解耦,谁也不 include 谁
  3. 独立成件意味着它可以在没有 Agent 的精简固件里单独存在,纯当规则引擎用

事件队列在这里扮演的正是第2章《项目架构总览》中数据流的“总线”角色:所有源进、所有动作出,路由器是唯一的换乘站。

6. 与其他章节的衔接

本章与全书其他部分的连接点如下:

  • 第2章《项目架构总览》:Core Data Flow 中“claw_event_router 匹配事件并可调用能力、跑脚本、跑 Agent、发消息、发事件或丢弃”正是本章的展开
  • 第4章《Agent 核心设计》:claw_agent_mgr_submit_root() 与四个请求标志位在 3.3 节对上,Agent 的输出如何经 out_message 事件回流也在本章闭环
  • 第5章《能力系统》:claw_cap_call() 分发与 caller 身份体系是 3.2、3.4 节动作落地的底层
  • 第8章《技能系统》:skills 目录下的 Lua 脚本正是 run_script 动作的执行对象
  • 第9章《IM 通信集成》:各平台能力既是最大的事件源,对应 publish_message,又是 send_message 经出站绑定的终点
  • 第11章《Lua 运行时与驱动体系》:lua_module_event_publisher 让脚本侧可以反向发布事件
  • 第12章《板级适配与配置服务》:解释 CLAW_PATH_DATA 分区布局与 .recovery 恢复副本的来历

理解了事件路由,就理解了 ESP-Claw 把“输入—决策—输出”压缩进毫秒级的那条主干道。

参考文献

[1] ESP-Claw 官方文档:Event Router,英文版
https://docs.espressif.com/projects/esp-claw/en/latest/reference-core/claw-event-router.html

[2] ESP-Claw 官方文档:claw-event-router,中文版
https://docs.espressif.com/projects/esp-claw/zh-cn/latest/reference-core/claw-event-router.html

[3] ESP-Claw 源码仓库,GitHub
https://github.com/espressif/esp-claw

[4] FreeRTOS 官方文档:Queue API,xQueueSend、xQueueReceive
https://www.freertos.org/Documentation/02-Kernel/04-API-references/10-Queues/00-queuehandle

[5] cJSON 解析库,GitHub
https://github.com/DaveGamble/cJSON




上一篇:ESP-Claw 能力系统源码剖析:LLM 工具调用与固件框架
下一篇:ESP-Claw 源码剖析:记忆系统三层架构与持久化设计
您需要登录后才可以回帖 登录 | 立即注册

关闭

站长推荐上一条 /1 下一条

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-10-30 05:56 , Processed in 0.110594 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表