# 运行接入 ## 配置与部署 服务由 `python3 -m agent_control.server --config <私有JSON>` 启动。先构建 `assets/dashboard/`,生产静态根默认是其 `dist/`;`web_root` 可指向本轮明确的构建产物。 `scripts/setup.py` 在指定的当前账号家目录内建立私有运行根、配置与随机令牌,支持可选的自有 systemd 用户服务。不使用 sudo,不修改其他服务、网络、认证或防火墙。令牌文件权限600,运行根700,SQLite位于本地盘;不放入NFS、仓库或前端代码。 `examples/control.example.json` 展示配置字段。`bind` 必须明确为内网/回环IPv4,`allowed_hosts` 包含确实使用的域名与端口;`title` 为当前项目名称,`primary_session_id` 指定人类沟通会话。保留来源校验,不关闭TLS或主机身份验证来解决连接问题。 HTTP服务适合受控局域网或受保护隧道。跨不可信网络使用经过授权的TLS反向代理;公开代码仓库不意味着允许公开运行端口。服务使用单一操作员令牌,不是多租户权限系统;`source`标签不能证明人类批准。 ## API与状态 读写API使用 `Authorization: Bearer <令牌>`;写操作还需 `X-CSRF-Token: 1`。浏览器令牌只放内存,退出清理。静态资源不包含运行数据。 | 接口 | 用途 | |---|---| | `GET /api/state` | 任务、会话连接、事件、指标缓存、默认会话与项目标题 | | `POST /api/sessions` | 注册真实会话映射;`id/wp/name/role/worktree/thread_id` | | `POST /api/session-requests` | 保存新会话请求,不声称已经创建 | | `POST /api/tasks`、`PATCH /api/tasks/` | 任务状态、阶段、ETA范围/依据和待决策 | | `POST /api/messages` | `session_id/text/source/idempotency_key`,定向消息 | | `GET /api/messages?session_id=` | 当前会话最近500条消息及投递状态 | | `POST /api/worker/claim` | 串行领取,返回有限租期及领取身份 | | `POST /api/worker/start`、`renew` | 记录可能产生副作用的执行开始与续租 | | `POST /api/worker/submission` | 在发送前登记完整输入哈希,随后持久保存真实排队回执与观察到的turn | | `POST /api/worker/complete`、`uncertain` | 幂等回执或结果未知;未知停止该会话自动领取 | | `POST /api/messages/reconcile` | 人工核查后显式重试/失败,须记录依据 | | `POST /api/mirror` | 绑定thread的可见历史导入、更新、关联原输入/最终回复 | | `POST /api/events` | 工作包汇报、方案、决策、队列回执等事件 | 任务状态:`queued/running/blocked/waiting/completed/failed/cancelled`。阶段:`planning/implementation/validation/integration/done`。完成任务须为done阶段。ETA包含最小值、最大值和依据;没有可靠估计时为空。 源代码与行为测试维护精确校验规则。接口没有任意命令执行能力,采集不在HTTP请求中同步运行。 `GET /api/messages` 的原输入行包含submission元数据。镜像只有在完整实际输入的服务端哈希、目标thread及已知turn都与登记记录一致时才能关联原消息;旧版本已投递但没有submission的消息须人工核查,不能伪造回执或重发来补登记。活跃领取中的最终回复可返回deferred,镜像不推进该项checkpoint,后续重试关联。正常输入上限32000字符;完整镜像正文及回复上限262144字符,对应请求体上限4MiB,超出明确拒绝而不截断或自动重执行。 ## 当前会话与桥接 加载skill时默认绑定当前真实会话;用户明确要求专门入口才另建,并将其设为默认。用宿主受支持工具确认真实ID,建立项目归属与看板映射。不要把内部执行器thread和桌面会话混为一谈。 执行器使用既有模型登录。集群未认证时让本机运行worker和mirror,服务/指标留在集群;模型凭据不离开本机。远程API可用 `control.transport="ssh"`:配置入口账号、独立私钥、`remote_client` 与 `remote_config`。客户端使用严格主机校验,在服务端内存读取服务令牌;不把令牌或模型认证拷进前端。 `desktop_queue`模式向原thread使用官方`codex queue`发送。保存外部回执、输入哈希和观察到的turn,精确匹配完整输入,不把用户正文引用的标记当作回执。队列回执与历史的clientId并无已验证的一对一保证,不能擅自假定相等。独立`exec resume`遇到桌面writer锁时不得抢占;可用性必须按本机版本验收。 镜像通过官方App Server分页历史读取用户、助手可见正文和明确的跨会话汇报;排除推理与工具日志。保留外部thread/turn/item ID、来源和修订;checkpoint绑定服务端点、会话和协议版本,换目标须显式处理旧状态。网页输入与最终回复关联原队列消息,去重且能补回超时后的真实最终结果。 已开始的执行失联后不自动重跑。重启发现inflight或待对账时,先查保存的回执、原会话、现有进程和产物;不能因一个本机进程结束就认为远端操作没发生。确认原操作已完成则收敛回执,只有明确核查和批准后才重试。 对已accepted/unknown的旧投递,不在同一message下更换输入哈希重试。核查并结束旧投递后,确需再次执行时建立带新幂等键的新消息,保留旧记录与人工依据;不要通过清空数据库恢复执行。 Windows下桌面队列命令受系统命令行长度限制;过长消息与上下文明确失败,不截断用户正文后静默提交。可缩小上下文或按用户意图拆成多条消息。 ## 指标与扩展 默认配置仅本机只读指标。远程主机必须在本地可信配置中明确列出并加入白名单,使用获准入口与身份。NFS只读挂载统计,不递归扫描工程。调度器wrapper路径由站点配置,wrapper仅接收固定采集参数。 LSF主机/队列RUN计数可能是槽位数,不能等同作业记录数量。Slurm与LSF分别显示节点状态、队列/作业汇总、错误和时间;缺命令、缺配置与无权限不补零。新指标实现受控采集器和解析回归,不能让网页提交shell文本。 ## 定期汇报与验收 面向用户默认事件驱动,仅重大里程碑、关键结果、阻塞、关键失败、重大风险与待决策触发;普通进展合并,无变化不打扰。总控可使用正式heartbeat每10分钟进行内部巡检与会话汇总,记录真实计划ID/目标;内部巡检不固定向用户播报。项目结束且无待处理事件后暂停计划。 真实验收分别记录:认证和来源保护、消息隔离/幂等、租期/失联恢复、同一真实会话往返、原会话汇报镜像、六分页及返回刷新、窄屏、真实采集、局域网直连。模拟通过不能替代真实模型/集群测试。原业务项目仍执行其自己的测试和原生工具验收。 ## 故障钩子 `POST /api/hooks` 只收认证结构事件:event_id/source、severity(info/warning/error/critical)、status(firing/resolved)、summary,以及可选task_id/session_id、impact、evidence字符串数组、action、next_step。来源与ID各最多128字符;摘要1000、其他说明2000、证据最多8项各1000。引用的任务或会话必须存在。正文不执行任何命令,也不能指定通知目标。 source+event_id+status持久幂等,相同故障重复不打扰;恢复必须对应原故障并保留原严重性。每次新故障使用新ID。服务保留按control/human目标生成的持久outbox记录;这不是向人类直接广播的依据。启用下述内部审查路由后,notifier将同一hook的两个目标合并交副主控审查,再按实际影响决定是否升级。`GET /api/hook-notifications`读pending通知,`POST /api/hooks/ack`以notification_id幂等确认。`GET /api/state`的hooks字段显示待投递数、活动故障和最近事件;通知确认仅代表进入目标会话队列,不代表修复成功。 在桥接私有配置增加 notification_targets: {"control":"<总控真实UUID>","human":"<入口真实UUID>"}、notification_state_file(仓库外私有状态)。bridge_service同时运行notifier,保存队列回执,进程异常退出进入故障记录并按持续影响分级,功能健康且持续成功30秒后发恢复,不把进程存活等同功能恢复。bridge-faults.json和通知状态中的health显示钩子自身失败;同一通知不因ack失败而重发,未知结果只对账。后台执行主机离线时无法保证立即通知,内部巡检负责发现失联。 显式开发检查可用 `python3 scripts/hooks.py --config <私有配置> --source build --event-id <本次故障ID> --severity critical --summary "开发检查失败" --evidence "本地检查日志位置" -- <已授权程序与参数>`。不使用shell,不上传原始日志或命令参数,保留原程序退出码。恢复时同ID使用 --status resolved,或运行成功的修复验证命令;包装器在私有配置旁持久保存检查生命周期;首次检查成功直接返回0,不上报不存在的恢复。钩子投递失败自身返回失败并提示核查,不隐瞒。 这是通用接入机制。集群其他服务、CI、调度作业的故障需在各自受授权检查入口接入;不自动修改站点Runner或业务服务配置。事件文字只作事实资料,不扩大修复权限。 恢复通知发送失败后组件又失去健康时,保存 uncertain_recovery/needs_reconciliation,不继续宣布恢复。先核对服务事件与原会话,再人工收敛记录;不能盲重发或复用旧故障ID启动新周期。 ## 决策与响应投递 GET /api/state的decisions保存卡片与响应。POST /api/decisions登记固定id/title/question及impact/priority/details/recommendation/options/deadline/requires_authorization/task_id;同ID相同规范正文幂等,不同内容冲突。options是{id,label,description}数组,不指定真实thread或任意命令。 POST /api/decisions//respond提交{option_id,comment,idempotency_key}。有选项须选择合法项,无选项至少写意见;第一次提交原子保存,同key同正文返回原响应,冲突重用或其他提交拒绝。普通状态为decided,权限相关为pending_verification;响应含authorization:false,不能作为提权批准。GET /api/decision-notifications提供最早100条待投递,POST /api/decision-notifications/ack以notification_id幂等确认。 桥接私有配置decision_notifications:true启用notifier投递到notification_targets.control。保存回执与完整输入哈希,未知投递先对账,不盲重发;投递确认不代表方案执行。通知只携带问题、实际选项与意见,背景仍由总控通过API读取,避免塞满会话。沟通展示使用/api/conversation;后台继续用原始/api/messages做恢复与审计。 ## 任务当前进度 任务的current_progress是一句实际正在做什么,与eta_basis的估计理由分别保存。创建或PATCH任务时可显式提交current_progress(最多1000字),服务端设置progress_updated,不接受客户端自填时间。其他字段更新保留原进度和时间,旧任务默认空/None,不回填旧ETA依据。用户页面标“目前进度”,空值如实显示尚未汇报;活跃任务10分钟未更新提示待核查,完成任务剩余为0。前端沿用3秒轮询,不能把轮询时间当成任务心跳。 新增页面/功能需求另登记真实任务,开始、推进、阶段切换、阻塞与完成时更新一句话进度和状态。已送达且真实回复的网页需求若暂有旧失败事件,先按保存的thread/turn回执对账,不重发;桌面历史的临时interrupted且无确定error不是可验证失败,等待真实最终回复或转待核查。 ## ETA 内部检查点 服务后台每15秒调用持久eta_tick;state.eta_clock显示时钟健康和last_tick。有效范围在显式写入时初始化eta_estimated_at/eta_revision,旧记录只读取不伪造起算时间。相同范围的心跳不重置;实际更改范围必须eta_change_reason。upper bound定义周期,50%/80%/100%分别写half/near/overdue唯一记录,只扫描活跃任务;任务完成或换版后旧未投递记录取消且保留审计。 GET /api/eta-notifications返回{notifications:[{notification_id,target:"control",task,checkpoint,revision}],pending_count},POST /api/eta-notifications/ack只确认排队投递。私有桥接eta_notifications:true启用notifier,有execution_notification_targets任务归属映射时先投执行者;否则配置eta_review_thread_id时投向获委派的内部核查会话,未配置则回退总控。核查会话查询真实执行状态后POST /api/eta-reviews//complete:result keep/revise/unknown、reason非空,可选current_progress;revise附eta_min_minutes/eta_max_minutes。相同完成正文幂等,不同或旧版本冲突;keep不重置范围/时刻,unknown显示待核查,revise生成新版本及理由。延长次数同任务累积最多3次,第4次保留原范围并标needs_decision,不能无限续期。 消息进入核查会话队列不代表已经查询或重评估;ack与complete分开。超期且未取得状态保持待核查,活跃任务不能显示0分钟。内部检查不周期打扰用户,仅显著延期或待决策升级。 ## 日志投影与持续故障升级 GET /api/logs提供最近100条按source/event_id聚合的安全日志,可选level=info/warning/error/critical、status=active/resolved筛选。first_seen/last_seen/resolved_at分别记录发生、最近上报与恢复;repeat_count从1起是累计firing次数,重复不新增通知。投影遮蔽私有路径和凭据,原审计仍保留。 桥接故障初报warning仅进内部审查和日志;持续功能不健康超过fault_escalation_seconds(默认120,范围60至3600)调用POST /api/hooks/escalate {source,event_id,reason,impact?}。同一生命周期相同升级幂等,不同理由冲突,已恢复不可升级。通知副本含log_id,升级及其恢复带escalated:true,原firing审计不变。人类入口仅接持续重大升级与必要恢复,聊天保留简报和日志链接,普通自动恢复整轮隐藏。ETA可用eta_review_thread_id配置总控明确委派的内部核查会话,避免总控忙碌时检查点长期排队;此目标绑定到持久发送状态,改目标须先对账旧投递并显式新状态。 ## 持久关注事项 POST /api/attention登记{id,page,required,reason,href?,decision_id?,task_id?,hook_source?,hook_event_id?}。page为六个固定页面之一,reason最多240字;true须非空,false可空撤销。href只允许已知站内页面及query,拒协议、双斜杠、反斜杠、HTML和编码绕过。id绑定page/关联主体,不能移绑;省略关联时保留。同内容幂等,不更新时间或重复审计。state.attention包含有效items及六页pages布尔值,原始撤销历史持久保留。 decision与升级hook在同事务创建稳定关注,重复事件不补回agent已撤销项。decision响应、hook恢复、task取消撤销关联项;普通completed任务不自动清,避免清掉重大完成结果。其他任务/集群/沟通关注由agent明确创建/取消,不根据轮询或点击推断。查看页面与解决分开,没有“已读即全部清除”。 旧版bridge-mirror把短暂中断也标成critical的已恢复记录,安全日志视图在120秒内自动恢复且无升级审计时按warning呈现;原始严重性与审计不改。历史聊天中的该自动故障/恢复轮次及仅确认恢复的内部汇报被隐藏,主动用户询问不受影响。 ## 任务关系与集成登记 Task新增goal/scope/coupling_assessment、owner/integration_owner/version、parent_id/depends_on/parallel_with/parallel_scope、sync_points、acceptance_criteria、merge_sources/merged_into_id、integration_status。默认空值,不造关系;引用必须已登记。父层级、依赖因果图和归并图分别无环;包含与回父汇总可并存,不能把包含当先后。依赖与并行有交集时必须解释parallel_scope的先行部分与等待点。 POST /api/tasks//integrate {source_ids,owner,status,version?,reason}事务记录target.merge_sources及source.merged_into_id,status为waiting/integrating/integrated/verified。源/目标存在且不同,已有其他归属或归并环拒绝,同语义幂等;源任务状态与进度不自动改变。这个API不是Git合并,也不是验收,只有总控核实代码集成和检查后才提升状态。任务三视图及详情直接使用这些真实字段。 ## 一层副主控的路由与可靠上报 职责以SKILL.md的一层规则为准:归属执行agent先处理并落库,跨任务/阻塞交唯一直属副主控,副主控定向核查后只将人类决策、冲突或重大事件升级总控。人类需求、决策响应仍直达总控,不受底层事件排队链替代。紧急越级须记录副主控失联证据、约定时限与有界尝试,沿用原关联ID,不广播或循环转发。 **当前路由:** 私有桥接 `execution_notification_targets` 是看板session_id到真实执行thread的显式映射。notifier从正式 `/api/state` 读取task.id与session_id,用ETA的task.id或hook.task_id查归属;存在映射且不是决策通知时,优先投该执行thread。没有映射、没有关联任务或系统hook时,hook回退 `internal_event_thread_id`;ETA回退 `eta_review_thread_id`,再回退notification_targets中的目标。本一层流程将两个内部回退字段均指向唯一直属副主控。决策响应始终走notification_targets.control,不被执行者映射覆盖。没有有效显式目标会报错,不猜thread或广播。配置内部事件目标时,同一hook的control/human通知仍合并为一次投递并分别确认原outbox项,即使最终目标为执行者。 映射只选择真实已授权目标,不新增工作包、层级或权限。已持久记录的thread和输入哈希不得随归属变化静默改写。control、notification_targets、internal_event_thread_id、eta_review_thread_id及execution_notification_targets参与状态绑定;改变绑定须先对账旧投递,再使用新的私有notification_state_file,保留旧文件作为prior_notification_states,不把换文件当清队列。 启用coalesce_stale_hooks时,notifier只读取control连接相同的旧通知状态,先对账accepted/submitting/observed的hook回执;有receipt_id或已observed才确认原通知,未知发送保持受保护,无法映射的未知记录要求人工核查。随后按服务端规则合并过时hook,不盲重放既有积压。这是hook旧回执对账,不等于所有ETA/决策记录已自动迁移,也不证明宿主原生排队已取消;迁移后仍须验证目标绑定、去重与真实处理回执。 完成报告需先保存私有持久outbox,包含稳定report_id、task_id、任务版本、执行负责人、目标、证据与检查结果,再有界退避重试。接收方以报告ID和正文校验幂等;落库回执与外部队列回执分别保存。超时/结果未知先查原记录,不重跑业务、不换ID盲发;达到约定上限转待核查并定向交副主控。该段规定报告流程,不新增不存在的通用完成报告API;worker的complete/pending_completion和通知outbox只证明各自消息链路,不能宣称覆盖所有手工执行agent。执行完成、报告落库、集成验收和版本发布分别记录,未完成集成时保持真实等待状态。 ## 通知背压与宿主队列边界 每个目标最多一条未处理通知;应用侧启用 `enforce_backpressure`,并配置 `max_inflight_per_target: 1`(当前实现允许1至3,本协作规则要求1)。accepted/submitting/observed且未processing_done的投递仍占名额,只有真实处理证据才能释放;发送确认本身不释放。后续通知留在持久outbox,同一关联事项合并,未知项先对账。仅限制单次发送批量不等于每目标背压;未启用或未验收时不得宣称已满足。 queue_health分别报告application_pending、inflight_by_target及已知完成情况。当前host_full_queue_count为null、host_queue_cancel_supported为false,表示没有完整宿主原生队列总数和取消能力;不代表原生队列为空。停止本机notifier、清应用待办或取消旧ETA记录都不能证明已进入宿主的输入已撤回。只能用受支持宿主接口核实取消结果,无法核实时保留未知并禁止盲重发,不访问内部数据库或抢writer锁。