一个agent与别的agent交互的全部工具,按四个域摆开:计划、执行、实体、通讯。
这页说明每个工具做什么、哪个会话能操作哪些任务、两个预算怎么限制一条链的规模。
设计文档:docs/reference/design/runtime/agent-collaboration.md。
八个参考实现在同样八个维度上怎么做,见Agent协作:八家实现对照。
四个域区分资源,不要求每个工具只操作一个域。agent 工具选择或创建运行分支并提交工作;job 查询读取已接纳的执行;execution 控制入口管理执行生命周期。
手写的计划清单。只记录打算做什么,不对应任何在跑的东西,改它不会让任何agent运行。
Job 包含 execution_id、状态和结果,可以排队、运行或结束。list_jobs 与 job_output 查询执行;取消通过 execution 命令协议完成,不是独立的模型工具。
本页的 agent 指运行中的对话分支。agent() 创建或继续分支,list_agents 列出分支,archive_agent 归档分支。保存的 AgentSpec 是独立的可复用配置,由 agent_id 选择。
send_message 继续已有分支,不创建新分支;实际轮次仍须 Job 准入。read_conversation 读取本地历史而不执行,但尚未实现历史读取的目标级 owner/project ACL。
todo_* 修改计划;agent 创建或继续对话分支并提交执行;list_jobs/job_output 查询已经接纳的 Job;execution.cancel 通过 execution 命令协议控制已有执行。它不是可调用的 job_stop 模型工具。取消执行不归档分支,也不删除保存的配置。execution_id;当前 job_output(job_id=...) 参数、details.job_id 和 attach.job_id 保留兼容名称。将返回的 execution ID 传给该参数,不引入 task_id 别名。
新建分支、向已有分支派发、发送消息或查询。前台新建、后台新建和向已有分支派发均持久化接纳一个 Job。后台新建与已有分支派发立即返回 execution_id;前台新建等待该 Job 完成并返回最终结果。同步返回不表示没有内部执行身份,也不绕过接纳。
agent这一个工具,区别只在有没有to=:
没有 to= 就新建分支并立即执行 prompt;有 to= 就向已有分支提交工作。图中的 Job 记录适用于前台新建、后台新建和已有分支派发。前台新建等待完成;异步形式返回执行标识。
发消息使用 send_message,不创建新分支。直接投递启动已准入 Job,并返回 delivery_id=job_id;目标忙时先返回收件箱回执,此时尚不代表执行准入。查询使用四个只读工具。两者都通过 Job 准入继续已有分支。目标合同对两者均自动回送非空完成结果;额外显式调用 send_message 回复是可选的。当前 canonical 完成路径尚未接入自动完成回送。
| 承诺 | 消息 send_message | 任务 agent() / agent(to=) |
|---|---|---|
| 谁能发起 | 已启用的发送方,向可解析且未归档的分支投递 | 启用的调用方可提交;产生的 execution_id 受查询归属和执行控制权限约束 |
| 有没有execution_id | 直接投递返回 delivery_id=job_id;目标忙时先返回收件箱回执,尚未创建执行 Job,实际轮次仍须准入 | 三种形式均有内部执行身份。后台新建和已有分支派发返回 execution_id;前台新建等待并返回最终结果 |
| 结果合同 | 目标自动回送非空完成结果;额外显式调用 send_message 回复可选。完成路径仍待接入 | 这一轮的终态形成结果、错误或取消;同样适用非空完成结果回送,仍待接入 |
| 能不能取消 | 取消已准入执行不会撤回已保存的消息;该执行受 canonical 取消权限约束。收件箱回执不是执行 ID | execution 命令 execution.cancel 使用 execution_id 和 expected_version 请求取消;排队工作撤回,运行工作进入取消流程 |
| 取消会不会级联 | 准入后,Job 按其执行父子关系处理取消 | 级联:停一个任务,它派生的任务全停 |
| 能操作别人的任务吗 | 知道投递或执行 ID 不获得控制权限;准入后的执行查询和控制仍受各自授权检查 | job_output 允许目标 execution session、caller session 或满足祖先关系的调用方读取;canonical 控制独立检查 owner/project/session/action 权限及预期状态版本 |
| 多方并发安不安全 | 回执表示已投递或进入收件箱,不保证执行准入或成功完成;仍可能发生错误 | 安全,且有记录:目标忙就排队,不会被打断 |
archive_agent 允许具备该工具能力的本地 session 归档其他分支,没有 creator-only 检查,这是现有共享本地信任范围。目标生命周期操作必须复用其他分支操作的作用域授权;保留数据不构成免授权理由。
新建、send_message 和 agent(to=...) 每次向外投递增加消息计数。目标要求自动结果通知继承已完成 Job 的计数、不再次加一;helper 定义了该行为,但尚未接入 canonical 完成路径。只有新建分支增加派生深度;Job 接纳累计、排队容量和活动容量分别限制。
两个参数均支持设为 0,表示不启用该项限制;其他资源限制仍生效。
# 命令行改,即时生效 openprogram config set agent.max_spawn_depth 1 # 默认:主agent创建worker,worker自己完成工作 openprogram config set agent.max_spawn_depth 2 # worker可以再创建一层,第三层被拒 openprogram config set agent.max_spawn_depth 0 # 不限层数 openprogram config set agent.max_messages 8 # 默认:一条链最多传8跳 openprogram config set agent.max_messages 0 # 不限条数,agent之间可以一直互发 openprogram config set agent.max_spawn_fanout 8 # 默认:一轮最多创建8个agent openprogram config set agent.max_spawn_fanout 0 # 一轮想创建多少个都行
~/.openprogram/config.json的agent段。
将这三个限制设为 0 不会关闭资源接纳限制。max_jobs_per_session 统计已接纳 Job 累计数,max_queued_per_session 限制排队数,max_live_per_session 限制活动容量;见资源治理设计。前台新建、后台新建和已有分支派发均持久化接纳一个 Job。前台路径调用 run_agent_turn,其内部调用 runner.spawn_job(wait=True) 并等待该 Job;同步等待不豁免接纳或资源限制。to=指向发起方当前这条分支是直接的环,立刻拒掉。
归档保留分支历史,并在目标分支的共享元数据里写入 archived。该状态在当前本地会话库中全局生效,不是每个调用方单独隐藏;所有发送方读取同一归档状态。
图中的手动归档已经实现。异步 archive_when_done 是目标完成行为,其 helper 尚未接入当前 canonical 或借用 claim 完成路径;同步工具的本地归档路径已经调用。
三条最常走的路。同一批工具,组合方式不同。
手上有五件互不依赖的事。先写成计划,再一件件派出去,最后回来更新计划。
blocked_by标出谁等谁。execution_id,不占我这一轮。job_output(job_id=...) 读取结果,通过 UI 或 execution 命令入口取消;没有注册 job_stop 模型工具。这件事已经有agent做过一半,不需要再创建一个从零开始的。先查agent列表,再决定是发消息还是正式派任务。
to="SID:HEAD"、轮数和大致字数、还有末尾预览。execution_id 并支持取消;终态可能是结果、错误或取消。想知道上次那件事到底怎么做成的,但不想触发任何agent运行,也不想把整段历史全部读进上下文。
-10就是最后十轮。list_agents给的SID:HEAD整串粘进去也认。参考实现对比记录设计背景,不定义当前 OpenProgram API。外部产品的工具名不是本框架的兼容别名。
| OpenProgram 接口 | 合同 |
|---|---|
agent | 创建分支并执行,或用 to 向已有分支派发。保存 AgentSpec 配置是另一项操作。 |
list_jobs | 列出当前会话的 Job、状态和资源视图。 |
job_output(job_id, block, timeout) | 读取或等待执行结果。block=true,timeout 单位为毫秒,默认 30000,上限 600000。 |
execution.cancel | execution 命令,不是模型工具。当前 Web UI 通过统一控制入口提交 execution ID、预期状态版本及 command ID。 |
todo_* | 维护计划,修改 todo 不触发执行。 |
list_agents、archive_agent | 列出和归档对话分支,不管理保存的 AgentSpec 注册表。 |
send_message、read_conversation | 消息投递继续已有分支,实际轮次进入 Job 准入;读取历史不触发执行。send_message 与 agent(to=...) 采用相同的非空完成结果回送目标;额外显式回复可选。 |
源会话 S 的消息 A 发起调用,在 T 创建分支时,attach 节点保存于 S,predecessor=A;其 extra.attach.session_id=T 与 extra.attach.head_id=H 引用目标。流事件外层 data.session_id=S 决定接收更新的会话,card_id 在运行和终态更新之间保持不变。当前没有持久化 attach.caller_session_id 字段。
| 操作 | 使用哪个会话 | 定位字段 |
|---|---|---|
| 加载或更新卡片 | S,由所属消息库或流事件外层确定 | Attach 节点 ID / card_id |
| 在调用位置显示卡片 | S | 持久化 predecessor,对话映射解析调用方;实时路径使用 tool_call_id 关联调用,旧数据按顺序匹配。 |
| 查看所引用的分支 | T = attach.session_id | attach.head_id;后台分支仍运行时可为空 |
| 查询执行状态或取消 | 执行权限独立判断,不由卡片位置决定 | 兼容字段 job_id;取消使用 execution_id 和 status_version |
当前对话映射将卡片关联到 S 的调用消息。AssistantBubble 区分同会话卡片与外部卡片,AttachCard 使用 T 导航。跨会话目标不是 S 中的本地 DAG 顺序节点:应显示指向 T 的引用并在 T 中解析 H,不能在 S 中查找 H,也不能因 attach.session_id 是 T 而将源卡片移动到 T。
当前限制:完整 AttachCard 的跨会话 Open 操作只打开会话 T,没有显式选中 H;execution strip 会提交 T 与 H 的 checkout。目标要求两个入口都打开引用的同一分支,目标不可用时显示明确状态并保留源卡片。这项导航一致性仍待实现,本次文档修改没有实现它。
已核实当前工具清单、标识符兼容、同步与异步 Job 准入、消息投递与收件箱回执的区别、attach 字段和共享手动归档状态。完成 helper 定义了自动回送与异步自动归档,但检查的 canonical 与借用 claim 完成路径未调用它们。完成行为接入、作用域生命周期授权、历史读取目标级 owner/project ACL、预算耗尽后结果读取,以及跨会话导航一致性均待实现。