外观
正在运行的子智能体出现的位置、检查它们的方式,以及它们留下的文件与事件。
前台运行
前台运行在它们运行期间会以流式方式将进度写入对话。当调用与所选智能体都未提供超时时,它们默认使用一个宽松的 30 分钟墙钟超时;全局的 timeoutMs 配置会替换该默认值,显式的 timeoutMs/maxRuntimeMs 与智能体默认值优先。
前台子智能体是在父 Pi 进程内部创建的 Pi 会话,而非第二个 pi 进程。运行超时、工具超时、中断或停止会中止子会话并将其释放。分离保持会话在父进程内部继续运行,并照常发布相同的回执与完成通知。
后台子智能体是在分离的运行器进程内部创建的 Pi 会话。运行器将会话事件镜像到 events.jsonl、output-<index>.log 与对话记录中。中断与停止会中止子会话;steer 请求通过会话的 steer 或 followUp 投递。
实时进度会显示 single、chain 与 parallel 模式的紧凑详情:单行的有界任务、当前工具、最近输出、令牌计数、累计费用、持续时长、活动新鲜度、当前工具时长,以及可用时的链式图元数据。工作流 label 元数据在紧凑的多子卡片中优先于原始任务文本。
按下 Pi 配置的展开键(默认 Ctrl+O)以展开完整的流式视图,查看每一步的完整输出。运行中的卡片提示还会展示用于舰队检查器的 Ctrl+Alt+F。
顺序链式调用显示如 done scout → running worker 的流线。带有并行步骤的链式调用改为显示每一步的卡片。链式状态在可用时使用 label 与 phase 元数据,而对较旧的链式调用回退到智能体名称。
后台运行
后台运行在控制权交还给你之后会继续工作。使用以下方式检查它们:
ts
subagent({ action: 'status' }); // 所有活跃运行
subagent({ action: 'status', id: '...' }); // 单个运行或者自然地询问:"Show me the current async runs."
编辑器下方的异步小部件在工作运行时提供简短视图。其展开键遵循你的 Pi 键绑定:
text
async subagent worker · background
● worker
● Step 1/1: worker · running
task: Review authentication boundaries
⎿ read: src/auth.ts | 2.0s
Press configured-expand-key for live detail · Ctrl+Alt+F Fleet要查看一个后台子智能体的文本,使用 subagent({ action: "status", id: "...", view: "transcript" });在并行或链式运行中针对特定子智能体,请加上 index。
减少状态显示噪音
聊天记录工具调用历史;舰队视图与异步小部件显示实时运行/子智能体更新。独立的 subagent({ action: "status", id: "..." }) 调用即使其 Status target: run … 标签匹配,也会留下独立的历史记录。匹配的运行 ID 标识被查询的运行,而非工具调用,且不是重复执行的证据。实时的舰队/小部件刷新不会合并这些记录。
若要"紧凑聊天结果 + 舰队视图作为唯一的实时编辑器界面",请将这些顶层键合并到 ~/.pi/agent/extensions/subagent/config.json(而非 Pi 的 settings.json 或 subagents 对象),然后重启 Pi:
json
{
"inlineToolDisplay": "summary",
"fleetView": true,
"asyncWidget": false
}inlineToolDisplay: "summary"为每次调用保留一行静态结果,附带其调用标题。已完成的状态查询并不证明所查询的子智能体已经结束。fleetView: true保留实时进度。请打开/subagents-fleet或按下Ctrl+Alt+F查看详情,而非仅为观察进度而反复请求状态。Pi 的展开键不会展开 summary 结果;如果你希望可展开的内联输出,请保留"rich"。asyncWidget: false仅隐藏额外的编辑器下方异步小部件,保留舰队视图。该配置减少了可见的界面;它并不保证相对于其他扩展的顺序。
感谢 DraconDev 在 #1931 中报告显示噪音并建议采用 summary 模式。
舰队视图
在 TUI 中,编辑器下方一个持久的舰队视图会作为紧凑摘要保持活跃工作可见。将 fleetViewPlacement 设为 "aboveEditor" 可将其移动到编辑器上方。
text
2 active agents · 1 pane · ↓ 3.1k window · 4.2k spent · ↓/← to inspect展开之后:
text
↑↓/jk select · enter inspect · esc back
> main
scout · running 1m 12s · ↓ 2.0k window · 2.8k spent
reviewer · running 38s · ↓ 1.1k window · 1.4k spent当聚焦的编辑器为空时,按下 ↓ 或 ← 将摘要展开为 main 以及带有智能体名称、状态、已用时间与令牌用量的活跃子智能体。当提供方报告用量时,window 是最近助手回合的输入加上缓存读令牌,而 spent 保持累计的"输入加输出"总额。没有窗口数据的旧运行产物保留现有的令牌总额标签。紧凑行会统计当前会话的活跃工作以及 Herdr 项目面板的数量。然后使用 ↑/↓ 或 j/k 选择一个子智能体,使用 Enter 打开舰队大厅;在此处按下 Enter 或 H 通过可用的 Inspect 插件打开其特定于子智能体的检查器。可打印的导航键永远不会在激活前被拦截。
舰队视图与编辑器下方的异步小部件默认同时启用;将 asyncWidget: false 可仅保留舰队视图。成功的后台完成保持安静,因此非活跃的 Pi 标签不会被标记为未读,而失败或暂停的完成仍会通知发起会话。并行运行独立地显示每个活跃子智能体。带有并行组的链式调用在进度与结果中保留其分组形状,因此失败或暂停的智能体会与已完成的智能体并排可见。当一个子智能体被显式允许通过 tools: subagent 或 allowNestedSubagents: true 进行扇出时,其嵌套运行会出现在主状态树中该父会话子节点之下,而不是隐藏在子会话内部。
舰队检查器
/subagents-fleet 打开实时舰队检查器,其中包含当前会话的前台工作、最近的异步子智能体、结构化的 Markdown/工具对话记录,以及已完成的输出/会话路径。
默认键:
↑/↓或j/k— 选择一个子智能体Shift+K/Shift+J— 滚动一行PgUp/PgDn— 滚动一页x/Ctrl+O— 切换工具详情r— 刷新Esc— 关闭Enter— 通过可用的 Inspect 插件打开所选可检视的异步子智能体s— 向所选的活跃异步子智能体撰写一条已确认的消息;Tab 在steer、follow_up与auto之间循环D— 在确认后停止所选子智能体的顶层异步运行H— 通过可用的 Inspect 插件打开所选的活跃异步子智能体
当终端拦截 PgUp、PgDn、Home 或 End 等键时,请在扩展配置中设置 fleetKeybindings 以替换检查器级别的键。提示模式保留固定键,例如 Esc、Enter、Tab 以及停止确认的 Y/N。
即使在前台回合处于活跃且斜杠输入已排队的状态下,Ctrl+Alt+F 也会打开相同的检查器。
Enter 与 H 使用可用的 Inspect 插件。在 macOS 上使用 Ghostty 1.3+(TERM_PROGRAM=ghostty)时,这包括使用 Ghostty 的 preview AppleScript API 的另一个内置"仅打开"插件;因为不写入绑定,status 与 close 不可用。在特定于子智能体的检查器中,输入普通的指引并按 Enter 通过已确认的 steer 通道发送;steer <message>、status 与 stop 仍作为显式控件可用。内置的 Herdr 插件使用 Herdr 0.7.5+。
在没有 TUI 的情况下,/subagents-fleet 保留文本的 subagent({ action: "status", view: "fleet" }) 兜底,而变更使用显式命令:在已经知道 id 的情况下,运行 /subagents-stop 并从选择器中选择,或使用 /subagents-stop <run-id> / subagent({ action: "stop", id: "..." })。
仅在你想让一个活跃的前台单子智能体运行保持运行而不终止时,才使用 /subagents-detach [run-id];最终结果仍可通过 status/wait 获取。
在 ~/.pi/agent/extensions/subagent/config.json 中设置 foregroundDetachShortcut,将该动作绑定到同一快捷键。运行中的前台卡片在其实时详情提示旁显示所配置的快捷键:
json
{
"foregroundDetachShortcut": "ctrl+b"
}Pi 默认将 Ctrl+B 绑定到编辑器光标左移。扩展的快捷键优先,但 Pi 会在启动时报告该冲突。若要在不出现警告的情况下保留该键,请在 ~/.pi/agent/keybindings.json 中覆盖编辑器动作:
json
{
"tui.editor.cursorLeft": "left"
}如果有东西看起来配置有误,请运行 /subagents-doctor 或询问:"Check whether subagents and intercom are set up correctly."
宿主检查协议(RPC)
RPC 宿主通过有界的 subagent-async 小部件(PI_SUBAGENT_ASYNC_JSON: 负载)接收实时异步状态。对于按需详情——子智能体的委派任务、对话记录窗口或最终输出——宿主可以调用扩展命令:
text
/subagents-inspect-rpc <requestId> <asyncId> [childId] [--lines N]扩展命令通过 Pi RPC 内联执行,而无需模型回合。回复以专用 subagent-inspect 小部件键上的一次 emit-then-retract 更新形式到达:第一行(也是唯一一行)是 PI_SUBAGENT_INSPECT_JSON:<JSON>,其中包含通过 requestId 关联的带版本的 pi-subagents.inspect-reply 负载。宿主不得渲染此小部件;它们应按 requestId 缓冲负载并丢弃未匹配的回复。
检查属性:
- 只读且按需:不会被持久化、广播或添加到通知详情;每次请求都会在状态操作执行的对账之后重新读取规范的运行产物。
- 会话作用域:由另一个会话拥有的运行会以
foreign_session失败;未知的 id 会以not_found失败;已清理的产物会以stale失败。 - 有界:按字段的字符串上限、消息计数上限(
--lines,最大 200),以及一个硬性的 64 KB 序列化预算,并带有显式的truncated标记。 - 回复中不会出现文件系统路径。
task是子会话的第一条用户消息,并且仅在真正可归属时被填充(fresh-context 子会话的会话文件适合读取窗口);forked 子会话会省略它。childId恰好是宿主在状态快照中收到的节点 id(步骤workflowKey/runId/step:<index>,或嵌套运行 id)。
在 TUI 模式下,该命令仅指向交互式的 /subagents 检查器。
异步运行产物
异步运行会写入机器可读的生命周期产物,用于可观测性与工作流门槛:
text
<tmpdir>/pi-subagents-<scope>/async-subagent-runs/<id>/
status.json
events.jsonl
output-<n>.log
subagent-log-<id>.mdstatus.json为小部件与subagent({ action: "status" })输出提供数据。events.jsonl包含包装事件以及带有运行与步骤元数据标注的子 Pi JSON 事件,包括关联的subagent.steer.requested、scheduled、routed、queued、delivered、failed与recovered事件,以及失败/部分/恢复通知。output-<n>.log是实时可读的尾部日志。- 回退信息被持久化,以便后台运行在完成后仍可调试。
对于顶层异步运行,details.asyncDir 指向该目录;最终摘要被写入 Pi 的子智能体结果目录,文件名为 <runId>.json。嵌套的异步运行在嵌套异步根下使用相同的形式,并可通过读取嵌套运行注册表的状态投影发现。这些文件仅作为追加/更新产物;交互式前台行为保持不变。
结果文件在完成通知送达后会被消费并删除。删除之前,监视器会在 <resultsDir>/completion-replay/<runId>.json 下写入一个带版本的重放记录,并在 <resultsDir>/output-archives/<runId>.json 下写入一个有界的输出归档。重放记录会随完成去重窗口一起过期,是尽力而为的临时状态,而非永久的运行账本。
bg_wait 在其自身的工具结果 details.completions 中呈现其所覆盖的每个终态负载的精简投影——运行身份、每个子智能体的 agent/runId/success、产物路径,以及有界的 archivePath,而不会重复输出文本。它会在监视器投递或监视器重启已移除一次性结果文件、且内存中的完成状态不可用时读取该重放。持久的非阻塞等待订阅在其投递的详情中使用相同的重放。工作流结果文件会显式记录每个子智能体的 runId,因为工作流子智能体的 artifactPaths 条目指向其保存的输出,而非按 id 键控的产物文件。从 tool_result 事件进行观察的扩展可以从那里读取运行与产物身份,而非解析文本摘要。
输出归档会在有可用的子智能体输出产物或会话文件时引用其中的一个。对于两者都没有的子智能体,归档会存储一个按子智能体的 result-tail 条目,包含 resultIndex,每个子智能体上限为 64 KiB,并记录其是否被截断。重放与归档的 JSON 使用 version: 1;使用者必须忽略未知字段。
嵌套扇出的状态以紧凑的旁路事件/注册表元数据形式存储,并合并到父状态视图与结果/对讲机负载中;完整的递归状态快照不会嵌入父结果文件。
使用者应读取这些 JSON 文件,而非抓取终端输出。为了向前兼容,未知字段与事件类型应被忽略。
需要低延迟的子智能体停止 UI 提示的 RPC 宿主可以订阅由 RPC ping 作为 events.childStatus 公布的 subagent:child-status 事件。负载使用 type: "subagent.child-status"、version: 1、runId、childId、status("stopping" 或 "stopped")、ts,以及可选的子智能体元数据,例如 stepIndex、agent、childRunId、workflowKey、phase 与 label。这些事件仅作为观察者的提示。它们可能在 RPC 与异步重放路径之间重复,并且不会在宿主重启后重放。状态快照仍是恢复与最终状态的权威来源。子智能体停止控制仍使用带 childId 的常规 stop 请求;没有单独的子智能体停止 API。
状态与结果字段
状态/结果字段包括:lifecycleArtifactVersion、runId/id、sessionId、mode、state、startedAt、lastUpdate、endedAt、durationMs、cwd、asyncDir、sessionFile、outputFile、workflowGraph、steps、results、totalTokens、totalCost、model/attemptedModels/modelAttempts、toolCount、turnCount、可选的 launchResolvedExtensions、可选的 runtimeAcknowledgedExtensions,以及当允许子智能体派生子智能体时的嵌套 children。
launchResolvedExtensions 仅为父会话解析的启动意图:它报告不透明的扩展标识以及环境扩展是否被禁用,而不会暴露原始扩展路径或声明子运行时已确认那些扩展已加载。
运行时扩展确认
协同的子扩展可以通过子会话的 pi.events 总线发出 subagent:acknowledge-extension,并附带负载 { id: string } 来确认子运行时注册。承载子会话的进程(前台子智能体的父进程,后台子智能体的运行器)在内存中捕获该确认。
确认 id 是自行声明的不透明字符串。它们必须为非空、最多 128 个字符、仅包含 A-Z、a-z、0-9、.、_、:、@、+ 或 -,且不得包含 /、\ 或 ..。
所报告的 runtimeAcknowledgedExtensions 投影为 { version: 1, source: "child-runtime", ids, omitted }。它会对 id 去重,保留最多 32 个 id,并将额外有效的唯一 id 计入 omitted。它仅作为尽力而为的可观测性:缺失意味着没有协同扩展进行确认,存在仅意味着该扩展已在子运行时注册,并不意味着其工具、健康检查或功能已成功。在终态序列化之后的延迟确认会被忽略。
生命周期事件
events.jsonl 记录生命周期过渡,例如 subagent.run.started、subagent.step.started、subagent.step.completed/failed/paused/stopped、控制关注事件、嵌套中断失败,以及 subagent.run.completed/stopped。运行边界事件包含生命周期产物版本。
进程终止证明
生命周期产物包括 process-terminal-candidate.json(私有运行器证据)与 process-terminal.json(公共证明投影)。
证明仅在实时父会话观察到完全相同的分离运行器的 close 事件、且任何被追踪的规范会话租约都已释放后,才为 observed。子智能体在运行器进程内部运行,因此候选项不会记录单独的写入进程。如果观察者不可用,证明为 unknown;不要从 endedAt、结果文件存在性、PID 消失或租约目录缺失来推断进程退出。
subagent:process-terminal 事件与 RPC ping.capabilities.processTerminalProof 会暴露此状态。进程证明是某个时间点的证据,并与执行成功或停止/不可恢复状态相互独立。
子会话事件
两条启动路径都直接订阅子会话的事件流;没有 stdout 协议。events.jsonl 产物镜像这些事件,其中 message_update 被丢弃;对话记录以 Pi 的 JSON 模式打印的相同方式投影 message_update。agent_end.willRetry 将完成延迟到子会话安定之后;agent_settled 是终态水印;在终态事件之后未能很快安定的子智能体会被中止并在其缺席的情况下结束。
完成通知诊断
对于被插桩的父会话,请在启动 Pi 之前启用 Node 的可选 debug 接收器:
sh
NODE_DEBUG=pi-subagents-notify pi 2>notification-debug.log它会将带 PI-SUBAGENTS-NOTIFY <pid>: 前缀的有界 JSON 记录写入 stderr,而不是运行产物或聊天。该捕获还包含其他 stderr 输出;在共享前请查看。记录仅包含 reason、经过清理的 id/runId(每个最多 128 个字符)以及 source;任务/输出文本、路径、凭据与异常主体不包括在内。
disposed、missing_session、foreground_session_mismatch、not_owned:投递被现有守卫拒绝。emit_foreground_session_mismatch、emit_not_owned:所有权/会话复查拒绝了发出。intercom_delivered、deduped_ttl:已被确认;不需要新消息。deduped_pending:共享一个进行中的投递 Promise。batch_deferred:被保留以进行批处理,并未丢失;请查找同一运行的后续发出或释放记录。send_accepted、send_failed:sendMessage分别返回或抛出。接受并不证明模型已读取该消息;失败仍可重试。dispose_pending:通知器关闭使得已保留的结果未确认,留待后续投递。
没有 NODE_DEBUG 时,跟踪仅检查 debug 启用标志:没有身份清理/序列化、诊断缓冲或日志 I/O。既有的投递守卫、TTL、计时器与批处理保持不变。跟踪仅涵盖通知器的决策,不涵盖发现差距;缺少跟踪并不能诊断原本的"通知丢失"症状。
工作流与调试产物
每个脚本化工作流在 workflow 产物目录下存储运行时产物。磁盘上的目录仍命名为 chain-runs,以保证兼容性。使用默认的 artifactDir: "session" 或 "temp" 时,它是用户作用域的临时存储。使用 artifactDir: "project" 时,根目录为 <cwd>/.pi/subagents/chain-runs/:
text
<tmpdir>/pi-subagents-<scope>/chain-runs/{runId}/运行目录可能包含诸如 context.md、plan.md、progress.md 以及 parallel-{stepIndex}/.../output.md 之类的文件。超过 24 小时的用户作用域临时工作流产物目录会在扩展启动时被清理;项目本地的与显式的持久根目录不会被按年龄扫描。
调试产物位于 {sessionDir}/subagent-artifacts/、项目作用域运行的 .pi/subagents/artifacts/ 或用户作用域的临时产物目录下。单次运行的相对 output 文件保存在 {artifactsDir}/outputs/{runId}/ 下,除非已配置 singleRunOutputBaseDir。对于泳道、评审、顾问团与门槛报告,请优先使用这些托管产物或聚合的工作流结果,而非仓库根目录的 reports/ 文件。仅将最终的持久证据复制到会话记忆、任务记录产物、PR/评论或已批准的文档路径。每个任务你可能会看到:
{runId}_{agent}_input.md{runId}_{agent}_output.md{runId}_{agent}.jsonl{runId}_{agent}_meta.json
元数据记录时间、用量、退出码、最终模型、尝试过的模型、回退尝试结果,以及已解析的验收账本及其解析后的子报告。
对于 npm 包项目,项目作用域的产物需要 .npmignore 规则(或在不存在 .npmignore 时的 .gitignore),或一个不包含 .pi/subagents/ 的 files 白名单。当这些包设置可能包含产物时,pi-subagents 会在启动时发出警告。请使用 artifactDir: "session" 或 "temp" 将它们保持在包工作树之外。
会话
会话文件存储在每次运行的会话目录下。对于 context: "fork",每个子智能体都从一个由父会话的当前叶子产生的分支会话文件开始(前台子智能体在进程内打开它;后台子智能体将其作为 --session 接收)。这是一次真正的会话 fork,而非注入的摘要。当省略启动 context 且通过 defaultContext: fork 解析时,在父会话文件与当前叶子存在时使用相同的分支,否则以全新上下文开始。
完成通知
异步完成仅属于发起会话。结果监视器发出 subagent:async-complete,扩展消费该事件以记录完成状态。
成功的兄弟完成会被短暂保留,并在它们于一个短窗口内完成时作为一条安静的分组完成投递(见 configuration.md 中的 completionBatch),避免在非活跃标签上留下未读标记。失败与暂停的完成保持可见,并立即触发。
事件
异步事件:
subagent:async-startedsubagent:async-complete
subagent:async-started 负载包括 task,向后兼容的第一个子任务(截断为 50 个字符),以及 goal,工作流级别的调用方任务(截断为 120 个字符,回退到第一个子任务)。伴随的 UI 扩展可以组合 goal、workflowGraph 与 asyncDir 下的实时生命周期产物,而无需抓取终端输出。
对讲机投递事件:
subagent:control-intercomsubagent:result-intercom
src/extension/index.ts 注册消费 subagent:async-complete 的通知处理程序。控制/关注事件作为可见的父通知呈现,并为异步运行持久化。原生的监督者请求仅投递给恰好派生子智能体的父会话。
pi.events 仅在进程内。它不能到达独立的 Pi 进程或子智能体;请使用文件生命周期产物或 pi-intercom 进行跨进程协调。
