异步操作 — await_event / async_action
状态:已实现。用于“请求 → 展示给用户 → 等待外部回调 → 返回结果”这类流程的两个声明式 kind:
await_event(仅等待)和async_action(完整流程)。
问题
Agent OS 的工具是同步的:调用 → 结果。但有一类流程,其结果不会立即返回,而是在对 agent 不可见的外部操作之后才返回:
- SBP / 支付:创建支付 → 展示二维码 → webhook
payment.succeeded; - OAuth(特例,已通过
oauth_connect定点解决); - 通过验证码确认(SMS / e-mail / push);
- “在移动应用/银行中确认”;
- 任何“请求 → 用户在对话之外做某事 → 回调”。
以前没有用于此的通用原语:
| 机制 | 能做什么 | 缺少什么 |
|---|---|---|
rest_tool / site_tool |
出站请求(GET/POST/…、oauth2、sign) | 单次请求,不等待 |
oauth_connect |
suspend → 通过回调 resume | 硬编码为 OAuth-URL |
request_attachment |
suspend,等待用户发来的文件/照片 | 专门针对附件 |
inbound webhook(POST /v1/inbound/:template) |
通过 webhook 启动新的一轮 | 不解析已经挂起的那一轮;等待 {message} |
已实现的内容
一个原生 suspend/resume 机制(Kernel::request_await_event +
resolve_event)和一个回调路由 POST /v1/events/callback。在其之上——
两个 YAML 工具:
| kind | 做什么 | 何时使用 |
|---|---|---|
await_event |
暂停该轮并等待事件(webhook 或 cron) |
id 已知(agent 自己发起了请求) |
async_action |
完整流程:start 请求 → 提取 id/url → 等待回调 |
创建资源并等待其确认 |
show_link |
以按钮形式展示链接(点击时打开窗口),可选等待“完成” | 让用户打开外部链接 |
await_event
kind: await_event
name: wait_payment
description: Дождаться подтверждения оплаты по correlation id.
timeout_secs: 600
event:
source: webhook # webhook (default) | cron
id_pointer: /object/id # где id в теле коллбэка (default /id)
# id_query: payment_id # либо query-параметр (взаимоисключает id_pointer)
source: webhook— 参数event_id(必填)指定所等待的 id; 在回调时/v1/events/callback核心通过event.id_pointer/event.id_query将其匹配,并返回{"event_id":"...","payload":{...}}。source: cron— 参数delay_secs:仅将该轮暂停 N 秒。
async_action
kind: async_action
name: sbp_payment
description: Принять оплату по СБП и дождаться подтверждения.
parameters:
type: object
properties: { amount: { type: string } }
required: [amount]
start: # поля как у rest_tool (method/url/json/headers/oauth2/sign)
method: POST
url: "https://api.yookassa.ru/v3/payments"
json: { amount: { value: "{{ amount }}", currency: "RUB" }, capture: true }
headers:
Authorization: "Basic {{ (env_var('YOOKASSA_SHOP_ID') ~ ':' ~ env_var('YOOKASSA_SECRET_KEY')) | base64 }}"
prompt:
message: "Оплатите по QR:"
url_pointer: /confirmation/confirmation_url
resolve:
id_pointer: /id
callback:
id_pointer: /object/id
timeout_secs: 600
三个指针:
| 指针 | 来源 | 用途 |
|---|---|---|
resolve.id_pointer |
start 的响应 |
所等待的 correlation id |
prompt.url_pointer |
start 的响应 |
展示给用户的 URL |
callback.id_pointer / callback.id_query |
回调的 body/query | 将回调与该轮匹配 |
start 由 site_tool 引擎执行(模板渲染、oauth2/sign、
retries);id/url 通过 JSON-pointer 提取;之后——同样的 suspend/resume。
回调路由 POST /v1/events/callback
通用,不绑定到具体集成:
- 接收 JSON body(和/或 query 参数);
- 核心扫描挂起的
await_event/async_action,并解析出 correlation id 匹配的那个(通过id_pointer/id_query); - auth —— 来自
events.token_env的 bearer token(config/server.yaml),为空 = 开放(dev); - 无匹配 —— 幂等
{"status":"noop"}。
向用户展示(URL)
事件 input_request 获得了字段 url。各渠道渲染:
| 渠道 | 现在(v1) | 之后(v2) |
|---|---|---|
| 组件(web) | 通过 url 的“打开”按钮 |
从 URL 生成客户端 JS 二维码 |
| Telegram / VK / Yandex | 消息 + 链接 | 服务端 PNG(二维码)+ 照片 |
| Android | 链接按钮 | Kotlin 二维码 |
await_event/async_action 不包含任何二维码特定内容——它们返回
url,而二维码由渠道绘制。
非目标(未完成)
- 以图片形式绘制二维码(目前是链接/按钮)。
- 回调的投递保证/重试(由外部系统负责)。
- 等待中轮次的队列/优先级。
- pending 在重启之间的持久化——仅对 durable-agent 有效(写入
pending.db并在 boot 时重新拉起);对 ephemeral 而言 pending 在内存中。 - 回调签名校验(目前仅有 bearer token
events.token_env)。 - 将
message/ipc/process作为独立event.source的来源。
链接
- 工具参考:
05-tools-compute.md§5.28.3(await_event)、 §5.28.4(async_action)、§5.28.5(show_link)。 - 演示 agent:
config/agents/await-demo/(wait_payment.yaml、sleep.yaml、sbp_payment.yaml、open_link.yaml)。