响应式触发器(reactions)
🔵 “事件 → 动作”规则:内核观察 ProcessEvent 流,当事件匹配过滤器时,执行动作——启动 agent、workflow、调用工具、发送 webhook、对进程进行“操控”(steering),或向某个上下文插入消息(inject)。
配置文件为 config/reactions.yaml(若存在,则在 boot 时加载)。规则由内核执行(agent_os_core::reaction + Kernel::fire_reactions)。
标记说明:✅ 已实现。
29.1 工作原理
- 每个进程事件(
ProcessEvent)都会经过Kernel::emit。 - 对于事件规则(
on.kind/on.template/on.tool/on.content/on.when),内核匹配过滤器并在单独任务中启动动作——emitter 不会被阻塞。 - 带有
on.threshold和on.idle的规则由 ticker 计算(Kernel::reaction_tick,服务器每 5 秒调用一次)。 - 执行动作前,规则会经过 debounce 和窗口限制;由 reaction 派生进程产生的事件不会触发级联,前提是该规则设置了
allow_cascade: false(默认)。 - 执行完成后,内核将
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 安全性与限制
- ✅ Debounce / 窗口(
debounce_secs、max_per_window+window_secs)。 - ✅ Cascade guard:由 reaction 派生进程产生的事件不会触发其他规则,直到
allow_cascade: false。 - ✅ Best-effort:触发记录保存在内存中;重启后不可恢复(通过 outbox 实现 durable 投递是可能的演进方向)。
- 🔴 没有语义/embedding 过滤器(intent/sentiment)——只有 keyword/regex/MiniJinja。
- 所有模板/ticker 都是内核级的;不为规则做 admin CRUD(使用文件)。
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)。