ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Prime Agent 守护进程架构深度解析:多进程拓扑、会话租约与崩溃恢复机制

Prime Agent 守护进程架构深度解析:多进程拓扑、会话租约与崩溃恢复机制 Prime Agent 守护进程架构深度解析多进程拓扑、会话租约与崩溃恢复机制【免费下载链接】prime-agentA self-improving RLM agent for coding workflows and long-running autonomous tasks.项目地址: https://gitcode.com/GitHub_Trending/pr/prime-agentPrime Agent 将每个活跃的根会话树隔离在独立进程中运行通过常驻 supervisor守护进程、resident worker常驻工作进程与 client-owned worker客户端属主工作进程构成一套完整的本地守护进程体系。本文以 daemon.md 为核心结合packages/coding-agent/src/modes/daemon/下的源码实现与packages/coding-agent/test/下的测试与基准完整拆解其进程拓扑、会话所有权与租约、调度、公开协议、重连快照、私有传输、背压、幂等崩溃恢复与协调更新机制帮助你理解交互式、print、JSON、RPC、管道 stdin 以及--no-session这些客户端行为背后共享的同一套守护进程基础设施。设计出发点为什么每个根会话树要独占进程守护进程是内部基础设施。交互式interactive、print、JSON、RPC、管道 stdinpiped-stdin以及--no-session描述的都是客户端行为它们各自保留对外 I/O 契约不变而无论哪种客户端其背后都会走同一套 daemon 进程模型。核心动机在于故障隔离一个根会话树的崩溃只影响它自己。会话中运行的 provider 调用、工具执行、compaction、bash、kernel内核、定时调度以及 transcript 扫描都不会进入 supervisor 进程内部执行——supervisor 只做协调不碰重活。这样长时自主任务long-running autonomous tasks运行时任何一个 worker 的异常退出都不会拖垮整个系统其他会话树照常运行。进程拓扑supervisor、catalog 与 worker 三角色文档中的架构图描述了完整的进程拓扑还原如下三个角色的职责边界非常清晰Supervisor守护进程监督者拥有公共 socket、客户端连接、路由、全局 agent-message 投递、worker 健康检查、命令日志command journal以及协调式更新。它不执行providers、工具、compaction、bash、kernels、调度或 transcript 扫描。在源码中该角色由 DaemonSupervisor 类承担它持有clients集合、workers映射、openingWorkers、promptAdmissions等状态并通过acquireDaemonSocketPathLease、acquireDaemonSupervisorOwnership完成启动时的 socket 租约与属主权获取。Catalog 子进程负责 saved-session 扫描与 inactive-session 文件操作。它的设计价值在于catalog 失败只会让某次 catalog 请求失败而不会打断正在运行的 worker。对应实现见 daemon-catalog-process.ts 与 daemon-catalog-entry.ts相关测试覆盖了 catalog 启动与失败场景daemon-catalog-startup.test.ts、daemon-catalog-process.test.ts。Worker工作进程每个 worker 拥有一个根AgentSessionRuntime、对应的根AgentSession、调度器scheduler、kernels以及该根之下的所有 RLM 后代。new、switch、fork、import操作会在 worker 内部替换根 runtime但保持公共 active-session ID 不变——这是客户端可以在会话切换后继续复用的关键约定。从源码看supervisor 启动时会先获取 socket 路径租约、等待启动栅栏startup fence、获取属主权然后加载既有 worker 描述符loadWorkerDescriptors并逐个收养或恢复adoptOrRecoverWorker最终标记启动完成见 daemon-supervisor.ts 的start()。常驻工作进程Resident WorkersTUI 关闭不中断会话正常交互式会话使用常驻 worker其生命周期规则是理解整个 daemon 的关键supervisor 为每个活跃根会话树启动一个独立的、脱离终端会话的进程组detached process group关闭 TUI 只会解除客户端连接不会停止 worker——会话继续在后台运行之后可以重新 attachworker 描述符、认证 token、active-session ID、会话路径和恢复日志recovery journal都以**仅属主可读写owner-only**的权限写入 agent 目录。源码中 worker 描述符目录默认位于agentDir/daemon-workers/socket 哈希并显式mkdirSync(..., { mode: 0o700 })、chmodSync(dir, 0o700)见 daemon-supervisor.tsworker 会监控公共 supervisor socket一旦它消失一个 worker 会通过原子的启动租约atomic launch lease启动替代 supervisor替代 supervisor 会收养存活的 worker 及其 active-session ID单 worker 崩溃只影响一个根会话树。恢复重试间隔为 250 ms、1 秒、5 秒连续三次失败即把该根标记为 failed。这一常量在源码中即为WORKER_RETRY_DELAYS_MS [250, 1000, 5000]见 daemon-supervisor.ts并有对应的 daemon-worker-connect.test.ts 与 daemon-supervisor-process.test.ts 验证prime-agent shutdown停止 supervisor 与所有 worker--force还会强制终止无响应的 worker 进程组及其被跟踪的子进程。CLI 侧实现见 daemon-command.ts 中shutdown命令对--force/-f的解析相关行为由 daemon-stop-confirm.test.ts 覆盖。值得强调的是这一层没有固定的会话数、worker 数、客户端数或工作负载上限There is no fixed session, worker, client, or workload cap in this layer属于可水平扩展的多进程模型。客户端属主工作进程Client-Owned Workersheadless 与临时客户端print、管道 stdin、JSON、RPC 等无头headless与临时客户端使用与交互式客户端相同的 worker 运行时但把 worker 的生命周期交给客户端print、管道 stdin、JSON 模式保持一次性执行one-shotRPC 保持 LF 分隔的 JSONL 帧格式持续接受 prompt 直到 EOF交互式--no-session使用内存会话in-memory session正常完成时显式移除 worker 且不做归档意外的客户端失联会启动有界的清理宽限期bounded cleanup grace period使用相同稳定客户端身份重连可取消清理默认列表、全局调度与对等路由peer routing默认排除客户端属主 worker除非属主显式寻址它们。一个值得注意的实现细节完整的启动环境launch environment只保留在 supervisor 内存中不会写入 worker 描述符。因此 SDK 对 print 与 RPC 模式的直接调用保持进程内in-process从而允许嵌入方embedder传递不可序列化的扩展工厂extension factories。这一点在 daemon-worker-protocol.ts 的DaemonWorkerDescriptor中可以得到印证——描述符中持久化的只是createCommand的精简形式durableDaemonCreateCommand仅保留sessionPath与noSession字段见同文件 daemon-worker-protocol.ts运行时配置不进描述符。会话所有权与租约防止同写一个 transcript每个已持久化的会话都由一个进程安全的租约lease保护租约以规范化 JSONL 路径canonical JSONL path为键。规则如下worker 在打开会话前先获取目标租约运行时替换runtime replacement时先获取新租约再释放旧租约并发打开同一会话返回session_already_active并携带属主 active-session ID同一路径的并发创建会收敛到同一个 worker 启动。这套机制从根上防止 daemon worker 与一次性客户端并发写入同一个 transcript 文件。源码层面session-lease.ts 实现了acquireSessionLease它在agentDir/session-leases/sha256 哈希.lock目录写入owner.json内含 token、pid、processStartId、activeSessionId、sessionPath借助proper-lockfile的lockSync做目录级互斥当检测到存活属主时抛出SessionAlreadyActiveError其code正是session_already_active见 session-lease.ts。租约还通过getProcessStartIdLinux 下读取/proc/pid/statWindows 下调用 PowerShell记录进程启动标识避免 PID 复用造成误判。相关测试见 daemon-runtime-lease.test.ts。调度Scheduling每个 worker 一个调度器每个 worker 为其根会话及所有后代运行一个调度器。任务按会话持久化在session-artifacts/session-id/scheduled-jobs.json中——worker 之间不共享全局 cron 文件。源码中该文件名常量为SESSION_SCHEDULED_JOBS_FILENAME见 daemon-supervisor.ts 的导入及 cron-jobs.tssupervisor 启动时还会把旧式全局 cron 迁移进 session artifactsmigrateLegacyCronJobsToSessionArtifacts见 daemon-supervisor.ts。调度语义的可靠性设计到期 tickdue tick在 prompt 投递之前就被认领并推进。因此崩溃不会重放一个不确定的 prompt不同目标会话的派发相互独立若某个认领仍活跃后续错过的 tick 会被合并coalesce而不是堆积成无界积压。常驻 worker 在 supervisor 替换期间保持调度worker 恢复时把不确定的认领标记为中断、保留已推进的调度仅继续未来的 tick。supervisor 只负责路由调度命令、合并 worker 摘要用于全局列表。测试方面daemon-supervisor-process.test.ts 会启动大量常驻根并验证会话繁忙时各自的调度仍独立推进。公开守护进程协议Public Daemon Protocol公共本地 socket 采用JSONL 帧格式。文档将其编号为协议 v4并指出协议版本与 schema 修订相互独立。需要说明的是从当前仓库源码看协议常量已演进为DAEMON_PROTOCOL_VERSION 7、DAEMON_SCHEMA_REVISION 28、DAEMON_SCHEMA_ID protocol-7-schema-28-...见 daemon-protocol.ts因此阅读时请以源码中的版本号为准——这正是协议版本与 schema 修订独立的体现兼容性新增可以靠能力开关capability-gating或 schema 修订承载不兼容的线上变更才需要协议大版本提升。该协议提供以下能力逐项在 daemon-protocol.ts 中有对应类型定义带版本号的命令信封command envelope携带稳定的客户端 ID 与命令 IDDaemonCommandEnvelope { type, id, protocol, clientId, command }能力协商与逐命令兼容性元数据客户端能力DaemonClientCapability与服务器能力DaemonServerCapability在 attach/reattach 时声明DAEMON_COMMAND_COMPATIBILITY表为每个命令声明minProtocol/minSchemaRevision/capability约束见 daemon-protocol.ts带代际感知的事件游标{ generation, sequence }DaemonEventCursor带稳定身份与恢复游标的重连DaemonResumeCursorattach 确认 一致性快照begin/chunk/end 快照流式传输目标块大小 512 KiB源码常量SNAPSHOT_TARGET_CHUNK_BYTES 512 * 1024见 snapshot-transcript-cache.ts超过 4 MiB 的 file-backed transcript 缓存SNAPSHOT_MEMORY_CACHE_BYTES 4 * 1024 * 1024同上文件第 6 行resident 与 client-owned worker 生命周期命令如create携带lifecycle: resident | client_owned、kill、complete_owned_session、promote_owned_sessiondaemon 侧 headless 完成、session-header、bash 与重试操作wait_for_headless_completion、get_session_header、execute_bash/execute_bash_and_wait、retry_worker结构化错误用于可恢复场景如会话已活跃session_already_active、不确定的 mutation 结果——daemon-errors.ts 提供serializeDaemonError/deserializeDaemonError。协议 v1 仅保留给一个发布版本的更新交接one-release update handoff用于准备并停止旧 daemon一个繁忙、无法产出恢复清单recovery manifest的旧 daemon 会被留在原地继续运行。此外JSON 与 RPC 客户端模式不暴露daemon 的 greeting、信封、快照记录、生命周期事件或连接元数据——它们只看到各自的既有 I/O 契约。重连、回放与快照每个有序事件都属于某个worker 代际generation。客户端保留最后一次{ generation, sequence }游标并在 attach 时提交服务器报告请求区间是complete、partial 还是 unavailable对应DaemonReplayStatus见 daemon-protocol.ts。关键设计代际变化会使旧 sequence 的比较失效缺失回放不是致命问题——attach 快照才是持久化的恢复基线DaemonAgentConnection见 daemon-agent-connection.ts应用快照、忽略重复或已退役代际的事件并向 UI 报告已重新同步会话大快照在 worker 内编码并以不透明块opaque chunks经有界 supervisor 缓存流式传输——supervisor 永远不会构造一个历史规模大小的对象。SnapshotTranscriptCache的内存缓存上限正是 4 MiB超过即落到文件缓存见 snapshot-transcript-cache.ts。私有工作进程传输Private Worker Transportsupervisor 与 worker 之间的流量使用二进制帧帧结构如下4-byte JSON header length 4-byte payload length small JSON routing header opaque payload bytes这一格式与 private-framing.ts 的encodePrivateFrame完全对应前 4 字节大端写入 header 长度、随后 4 字节写 payload 长度接着是 JSON routing header 与不透明 payload。默认帧上限为 header 1 MiB、payload 1 GiB见同文件第 10-13 行。两条重要的优化路径worker 只序列化一次公开事件supervisor 只读取 routing header把同一个 payload buffer 转发给所有符合条件的客户端——一次编码、多路复用Assistant 流式传输使用紧凑的 start/delta/end payload私有协议内supervisor 为每个 delta重建一次既有的公开message_update事件因此不断增长的完整 assistant 消息不会反复从 worker 传输到 supervisor。紧凑 delta 的构造逻辑在 compact-session-stream.ts 的createCompactAssistantDelta中实现。认证与代际围栏私有 worker 连接使用每 worker token认证并被围栏到当前 supervisor 代际——这防止一个过期的替代 supervisor 继续指挥已被收养的 worker。需要明确的是这是进程协调而非沙箱边界所有进程仍以同一 OS 用户运行。背压Backpressure附件局部背压是附件局部attachment-local的被阻塞的客户端停止接收增量事件其他客户端和 worker 不受影响、继续运行supervisor不为每个客户端保留无界队列排空drain之后附件从自己的游标追平或收到一份全新快照。文档特别强调Final transcript caching is separate from live partial-message reconstruction——最终 transcript 缓存与实时的部分消息重建相互独立二者不会互相拖累。幂等与崩溃恢复变更命令mutating command以clientId commandId为键在派发前写入 append-only 日志重复执行一个已完成命令会返回已存储的结果已收到但没有持久化结果的命令被报告为uncertain且不会重放重连保留相同 command ID客户端确认ack已完成的 mutation以便压缩日志条目。源码实现是 command-recovery-journal.ts 的CommandRecoveryJournal日志记录三种类型——received派发前落盘、result结果落盘、acknowledged确认后删除条目当记录数达到COMPACT_AFTER_RECORDS 4096时触发重写压缩见第 43 行。每个追加都通过openSync(path, a, 0o600)writeSyncfsyncSync确保持久化文件权限为0o600。worker 侧恢复worker 记录操作转移operation transitions与被分离detached子进程的身份。worker 崩溃后恢复过程会收割reap旧的进程组与被跟踪的分离 bash 树向 transcript追加一个可见的恢复标记在相同的 active-session ID 下恢复根不重放不确定的副作用。协调更新Coordinated Updates两阶段准备更新准备分两阶段进行常驻 worker 并行创建非破坏性检查点checkpointsupervisor校验并原子持久化聚合清单aggregate manifest只有所有 prepare 都成功后才 commit 并停止 worker。若准备或清单校验失败则释放已准备的 worker所有根会话继续运行——即要么全成功要么全回滚。协议侧由prepare_update_restart、restart、shutdown等命令承载清单结构DaemonUpdateRestartManifest记录了每个会话的 active-session ID、配置、队列与恢复快照见 daemon-protocol.ts。相关端到端测试见 package-self-update-daemon.test.ts。基准与压力验证Benchmarks文档给出了来自packages/coding-agent目录的基准命令需先cd packages/coding-agentnpx tsx test/daemon-multiclient-bench.ts npx tsx test/daemon-multiclient-bench.ts --generated-session-mib 100 npx tsx test/daemon-multiclient-bench.ts --generated-session-mib 500 npx tsx test/daemon-multiclient-bench.ts --session-file /path/to/session.jsonl PRIME_AGENT_STRESS_WORKERS50 npx tsx ../../node_modules/vitest/dist/cli.js --run test/daemon-supervisor-process.test.ts -t hosts resident roots基准脚本 daemon-multiclient-bench.ts 使用真实本地 socket不启动 provider 或 agent runtime对比 fan-out 与 attach 两条路径的序列化次数、吞吐量、耗时与采样 RSS客户端数量覆盖[1, 10, 50, 100, 250]第 30 行。它同时比较 legacy 按接收方分别序列化/全历史 attach 路径与 v2 的 compact encode-once deltas、单份缓存分块 transcript 编码路径见脚本头部注释。压力测试用例PRIME_AGENT_STRESS_WORKERS50启动大量常驻根并验证这些会话忙碌时各自的调度仍独立推进——这正是本文前面每 worker 一个调度器、tick 认领与推进相互独立设计的直接验证。小结Prime Agent 的 daemon 架构可以概括为一句话supervisor 管协调catalog 管扫描worker 管会话。通过每根会话树一进程 会话租约 代际游标 命令日志 两阶段更新这套组合它在单机本地协议层面实现了故障隔离单 worker 崩溃只影响一棵根会话树且有 250ms/1s/5s 的重试与自动 supervisor 替换并发安全租约机制杜绝同一 transcript 被并发写入冲突以session_already_active结构化返回可靠重连{ generation, sequence }游标 attach 快照作为持久恢复基线缺失回放不致命高效转发私有二进制帧 encode-once 多路复用 紧凑 assistant deltasupervisor 从不构造历史规模的对象可运维prime-agent shutdown可选--force、协调式更新、append-only 命令日志与恢复日志让崩溃与升级都可控。对于想深入阅读源码的读者建议从 daemon-supervisor.ts、daemon-protocol.ts、daemon-worker-protocol.ts 三个文件入手再配合 session-lease.ts、command-recovery-journal.ts 与 private-framing.ts 理解底层机制最后用上面给出的基准命令实测 fan-out 与 attach 的性能特征。【免费下载链接】prime-agentA self-improving RLM agent for coding workflows and long-running autonomous tasks.项目地址: https://gitcode.com/GitHub_Trending/pr/prime-agent创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表