跟着 OpenHands SDK 走一条事件路径
这是帮助阅读的控制流摘要,不是项目源码复制。范围限定于同步 LocalConversation.run() 调默认 Agent.step();arun()、ACP 代理和 Agent Server 路径需另行核对。
send_message()把用户输入变成MessageEvent,送进_on_event。LocalConversation的回调链以ConversationState.append_event()为存储关口,外部订阅回调在其后;若存储失败,后续订阅回调不会被调用。可选的本地 visualizer 则在存储前显示,不能与外部订阅混为一谈。输入事件 · 回调链run()设置运行态,在循环里调用agent.step();step()先检查当前分支上的未匹配ActionEvent。若有,先执行它们并返回,不会在这一步先调用 LLM。run 循环 · 未匹配动作优先- 若没有待处理动作,
Agent._step()从当前state.view准备模型输入、调用 LLM,并按返回类型分发。工具调用先进行名称、参数和Action校验;不合法调用发AgentErrorEvent,不进入普通工具执行路径。模型请求 · 工具校验与错误 _get_action_event()创建并发出ActionEvent;ResponseDispatchMixin._handle_tool_calls()之后才调用_requires_user_confirmation()。确认策略命中时状态变为WAITING_FOR_CONFIRMATION,run()在当前 step 后退出;无须确认才当场执行。ActionEvent 先发 · 确认与执行顺序 · run 停在确认- 获准后再次
run(),它清掉 waiting 状态;Agent._step()通过get_unmatched_actions(active_branch())找回动作,执行它们。若用户拒绝,则reject_pending_actions()发UserRejectObservation配对,而不调用工具。再运行 · 匹配算法 · 拒绝动作 _execute_actions()准备批次,委托工具执行,并按原动作顺序发结果事件。单个工具调用传入action与conversation;通常形成ObservationEvent,ValueError转为AgentErrorEvent。并发批次的实际副作用发生顺序不能仅凭结果事件顺序推断。批次执行与事件发出 · 调用工具并封装观察
text
LocalConversation.run() → Agent.step()
无待处理动作:LLM 工具调用 → ActionEvent 入事件历史 → 确认闸门
无需确认:Tool(action, conversation) → ObservationEvent / AgentErrorEvent
需要确认:WAITING_FOR_CONFIRMATION → 本次 run 停止
再次获准 run:取未匹配动作并执行
用户拒绝:UserRejectObservation,不执行工具停止与未知
run() 还会因暂停、卡住、预算或最大迭代数停下,异常会转为 ERROR 与 ConversationErrorEvent;FINISHED 还可能被 stop hook 反馈改回 RUNNING。这些是外围循环的停止条件,不应误认为工具调用必然成功。停止检查
本篇没有运行确认、崩溃恢复或故障注入测试,因此不宣称 Action/Observation 配对可防止重复副作用;更不宣称具体 workspace 或 Terminal 后端具备沙箱隔离。远程 Agent Server、ACP 后端、异步 arun() 与复杂 hook 顺序留待独立章节。
在线预览稿:书稿仍在校稿,系统篇以文内固定源码版本为准;静态阅读不等于运行验收。