响应式触发器(reactions)

🔵 “事件 → 动作”规则:内核观察 ProcessEvent 流,当事件匹配过滤器时,执行动作——启动 agent、workflow、调用工具、发送 webhook、对进程进行“操控”(steering),或向某个上下文插入消息(inject)。

配置文件为 config/reactions.yaml(若存在,则在 boot 时加载)。规则由内核执行(agent_os_core::reaction + Kernel::fire_reactions)。

标记说明:✅ 已实现。


29.1 工作原理

  1. 每个进程事件(ProcessEvent)都会经过 Kernel::emit。
  2. 对于事件规则(on.kind / on.template / on.tool / on.content / on.when),内核匹配过滤器并在单独任务中启动动作——emitter 不会被阻塞。
  3. 带有 on.threshold 和 on.idle 的规则由 ticker 计算(Kernel::reaction_tick,服务器每 5 秒调用一次)。
  4. 执行动作前,规则会经过 debounce 和窗口限制;由 reaction 派生进程产生的事件不会触发级联,前提是该规则设置了 allow_cascade: false(默认)。
  5. 执行完成后,内核将 ProcessEvent::ReactionFired 写入审计。

29.2 规则结构

reactions:
  - name: complaint-escalation          # уникальное имя (debounce/окно)
    enabled: true
    on:
      kind: user_message                # event_type
      template: support                 # шаблон агента-источника (опц.)
      user_id: "tg:123"                 # user id (опц.)
      tool: payment                     # для tool_call / tool_result (опц.)
      success: false                    # для tool_result (опц.)
      content:                          # текстовый фильтр (опц.)
        field: user                    # any | user | assistant | tool_result
        keywords: ["жалоба", "вернуть"]
        mode: any                       # any | all
        regex: "\\b\\d{4}\\b"           # опц.
        negate: false
        case_insensitive: true
      when: "event.success == false"    # MiniJinja над `event` (опц.)
      # либо ticker-условия:
      threshold: { kind: error, count: 3, window_secs: 300 }
      idle: { secs: 1800, template: sales, state: blocked }
    action: { ... }
    debounce_secs: 0                    # мин. интервал между срабатываниями
    max_per_window: 5                   # лимит срабатываний
    window_secs: 60
    allow_cascade: false                # реагировать на события от реакций

kind —— 来自 ProcessEvent::event_type() 的事件标签:turn_start、turn_end、tool_call、tool_result、error、terminated、spawned、state_change、budget_exhausted、rate_limited、schedule_blocked、session_created、session_closed、signal、user_message、assistant_message、reaction_fired、workflow_step_* 等。

过滤器按 AND 组合。空的 on: {} 会匹配任意事件(谨慎使用)。

29.3 动作

type 字段 作用
spawn_agent template、prompt、session? 按模板启动 agent,并使用渲染后的 prompt;session —— 会话键(默认 reaction:<rule>:<pid>)
run_workflow name、input? 启动 workflow(trigger: reaction)
call_tool tool、args? 通过 execute_tool_guarded 调用工具
webhook method?(POST)、url、headers?、json? 出站 HTTP 请求
signal target?、signal steering:pause / resume / interrupt / terminate
inject target?、role?(system)、content、run_turn? 向进程上下文插入消息(例如父进程);run_turn —— 立即启动其回合

signal.target / inject.target:source(默认——事件来源进程)、parent(来源的父进程)、{ pid: "..." } 或 { template: "..." }(模板的所有会话)。

所有动作的字符串字段都是 MiniJinja 模板;上下文中可用变量 event(事件 JSON,或 ticker 规则的合成对象:{ "type": "threshold" | "idle", ... })。

29.4 示例

Keyword 路由。 消息中的投诉 → 单独的升级 agent:

reactions:
  - name: complaint
    on:
      kind: user_message
      content: { field: user, keywords: ["жалоба", "верните"], mode: any }
    action:
      type: spawn_agent
      template: support-escalation
      prompt: |
        Пользователь написал: «{{ event.content }}»
        Разбери жалобу и подготовь ответ.

支付失败 → 退款 workflow + 通知 ops:

  - name: pay_fail
    on: { kind: tool_result, tool: payment, success: false }
    action: { type: run_workflow, name: refund-check, input: { tool: "{{ event.name }}" } }
    debounce_secs: 10

错误激增(5 分钟内 3 次)→ 终止进程并呼叫调试器:

  - name: error_burst
    on: { threshold: { kind: error, count: 3, window_secs: 300 } }
    action: { type: signal, signal: terminate }
  - name: spawn_debugger
    on: { threshold: { kind: error, count: 3, window_secs: 300 } }
    action: { type: spawn_agent, template: debugger, prompt: "Разбери всплеск ошибок" }

静默:sales 超过 30 分钟无活动 → 提醒:

  - name: sales_idle
    on: { idle: { secs: 1800, template: sales } }
    action: { type: spawn_agent, template: sales, prompt: "Напомни о зависших лидах" }

子进程失败 → 通知父进程(注入其上下文)并给出提示:

  - name: notify_parent
    on: { kind: tool_result, tool: run_command, success: false }
    action:
      type: inject
      target: parent
      role: system
      content: "Дочерний агент: команда упала — {{ event.content }}"
      run_turn: true

29.5 安全性与限制

29.6 内核 API

kernel.load_reactions(rules).await;   // заменить набор (boot / reload)
kernel.add_reaction(rule).await;      // добавить/заменить по имени
kernel.list_reactions().await;        // текущий набор
kernel.clear_reactions().await;
kernel.reaction_tick().await;         // прогнать threshold/idle (тикер)
kernel.set_self_weak(Arc::downgrade(&kernel)); // один раз на boot

规则也可以从字符串解析:reaction::load_reactions_str(yaml)。