[Feature] SOP 运行中向 Agent 节点插话:不打断地注入纠偏指令,支持排队到下一次尝试与一步打断续接
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Aptitud para principiantes
- 25/100
- Tipo de issue
- Nueva funcionalidad
- Claridad
- Bastante claro
- Estado de actividad
- Activo
- Stack tecnológico
- go, javascript, sql
- Área
- backend, backend-api-design, databases, frontend
Línea de trabajo
Start by reading the existing assistant steer flow in internal/domain/assistant_generation.go, internal/repo/assistant_generations.go, and internal/httpapi/assistant_generation.go, then compare it with run pause/resume in internal/engine/run_ops.go and node execution in internal/engine/node_execute.go. The issue calls for run-level steer and queue behavior across APIs, persistence, hooks, retries, and the UI; done means the listed delivery modes, status transitions, authorization and node-type checks, tests, and acceptance criteria all work.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
背景与借鉴来源
主流 AI coding agent 都把「Agent 正在干活时,人可以随时插一句话纠偏」当成基础交互,而且区分了两种投递方式:
- openai/codex(https://github.com/openai/codex ,约 13.5 万 star,今天仍有提交):运行中发的消息分 Steer(在当前轮内尽快注入,不丢弃已做的工作)和 Queue(排队到当前轮结束后作为下一轮输入)。社区还在讨论「Background note / Soft steer」(openai/codex#55647),即只作为背景提示、不打断当前步骤。
- anthropics/claude-code(https://github.com/anthropics/claude-code ,约 15.5 万 star,今天仍有提交):Agent 工作中输入的消息会在下一个工具调用边界注入;hooks 的
PostToolUse/UserPromptSubmit可以通过hookSpecificOutput.additionalContext把额外上下文送进模型。社区诉求见 #98493(排队而不只是 steer)、#73661(排队消息按 FIFO 逐条处理,而不是合并成一条)。 - OpenHands/OpenHands(https://github.com/OpenHands/OpenHands ,约 9.3 万 star,活跃)、cline/cline(约 7.2 万 star,活跃):Agent 运行中的用户消息进入事件流,在下一步推理前被读到,不需要先停止任务。
这些项目的共同点:插话不等于暂停。插话不杀进程、不丢上下文,在安全边界(工具调用之间或一轮结束时)投递;投递状态(待投递 / 已送达 / 已被 Agent 确认)对人可见。
LoopForge 现状与不足
LoopForge 已经在助手会话里实现了 steer,但 SOP 运行里的 Agent 节点没有对应能力:
- 助手会话已有 steer:
internal/domain/assistant_generation.go的AssistantSteer,internal/repo/assistant_generations.go的SteerAssistantGeneration,internal/httpapi/assistant_generation.go的followSteer,前端在web/workbench.js的steer()。 - SOP 运行只有「暂停 → 补充上下文 → 继续」:
POST /api/runs/:id/pause→Engine.Pause(internal/engine/run_ops.go)会cancelRunnerTasksForRun并Interrupt取消本地调度,直接杀掉正在跑的 Agent CLI;之后要再调POST /api/runs/:id/resume,由resumePaused写入recordHumanContext、用ResumeSessionID加--resume(internal/runtime/provider_claude.go/provider_codex.go),提示词变成「请从刚才中断的位置继续执行」(internal/engine/node_execute.go)。- 想纠正方向必须先打断、等节点停稳、再点一次继续,至少两步。
- 打断时 CLI 可能正改到一半文件、正跑一半测试,还要重新起沙箱进程、重建 MCP,长任务成本很高。
- 子 SOP 要级联暂停和恢复(
childRunIDs),一句提示的代价很大。
- 人工上下文只在节点启动时读一次:
writeHumanContextFile只在node_execute.go准备沙箱时写human-context.md;节点运行期间人补充的信息没有通道送进正在跑的 CLI。 - 没有排队语义:节点运行中,人不能先留言、等这一轮完成后再作为下一轮(返工 / 下一次尝试)的输入;只能等节点失败或进入门禁再写。
- 平台已经给各 CLI 装了 hooks(
internal/observability/hooks.go的PostToolUse/UserPromptSubmit,internal/runtime/hooks.go的writeHookSettings/mergeHookSettings),但现在只用来做观测落盘(hooks.ndjson),没有用来回写上下文。
建议方案
1. 数据模型与 API
- 新增运行级消息队列(归属
RunsRepo,新建run_steers表或Run的子资源),字段:id, run_id, node_id(可空=当前活跃 Agent 节点), mode(steer|queue), content, actor_id, status(pending|delivered|acknowledged|expired|cancelled), delivered_attempt, delivered_via(hook|resume|next_attempt), created_at, delivered_at。按 AGENTS.md 约定,migrations/下补一份 SQL 脚本。 POST /api/runs/:id/steer(runsHandlers,复用project_write_access.go的写权限校验),请求体{nodeId?, mode, content};DELETE /api/runs/:id/steer/:steerId撤回未投递的消息;GET在运行详情里返回队列。- 写入运行事件(
e.event(..., "run.steer.queued" / "run.steer.delivered"))和appendControlTelemetry,审计里能看到谁在哪个节点第几次尝试插了什么话。
2. 投递(按执行器能力分级,从无损到有损)
- A. 工具调用边界注入(首选,不打断):对支持 hooks 回写上下文的 CLI(Claude Code / CodeBuddy 的
PostToolUse与UserPromptSubmit),在hook.py旁加一个轻量命令:读取工作区下.agentflow/steer/inbox.jsonl中 pending 的消息,以hookSpecificOutput.additionalContext输出,并把已投递的 id 写到outbox。引擎(本地调度或 runner daemon)负责把队列同步进 inbox,并从 outbox/hooks.ndjson回收投递状态。 - B. 回合结束后续接:不支持 A 的执行器(Codex
exec --json、OpenCode 等),mode=steer退化为「当前 CLI 进程结束后立刻以--resume <sessionID>再起一轮,提示词只包含插话内容」,节点保持 running,不经过waiting_approval,也不计入MaxAttempts。 - C. 立即打断(显式选择):前端提供「打断并插话」,内部等价于
Pause+ResumePaused(humanContext)一步完成,复用现有ResumeSessionID逻辑,不需要人点两次。 mode=queue:不在当前尝试里投递,挂到该节点下一次尝试(门禁 rework、targeted_fix重试、或人工 Retry)的Feedback中,追加在现有FeedbackPrompt后面;多条按 FIFO 逐条列出,不合并改写。
3. 前端
- 运行详情页的活跃 Agent 节点卡片加输入框,支持「插话 / 排队 / 打断并插话」三种发送方式(交互参考
web/workbench.js现有steer());消息气泡显示投递状态,pending 状态可撤回。
4. 边界
- 只对
type=agent节点生效;script / approval 节点直接拒绝(400);子 SOP 节点按ChildRunID转给子运行当前活跃的 Agent 节点。 - 单条长度沿用
maxHumanContextBytes(8000);同一节点 pending 上限(例如 20 条)。 - 节点在投递前结束(成功 / 失败 / 进入门禁):
steer自动转为queue留给下一次尝试,或标为expired并提示,不静默丢弃。 - 插话内容同样写入
human-context产物,保证事后可追溯;gitwork/exclude.go中排除.agentflow/steer/,不进入交付分支。
验收标准
- 在 Claude Code / CodeBuddy 执行器的 Agent 节点运行期间调用
POST /api/runs/:id/steer(mode=steer),CLI 进程不重启(同一 invocation id、无run.paused/run.resumed事件),下一次工具调用后模型输出能体现插话内容;消息状态从 pending → delivered,运行事件里有run.steer.delivered。 - 在 Codex 执行器上同样操作,当前轮结束后自动
--resume续接,节点不进入waiting_approval,Attempt不加 1。 mode=queue的多条消息在节点下一次尝试时按 FIFO 逐条出现在提示词里,当前尝试中不投递。- 「打断并插话」一步完成暂停加继续,行为等同于现在先 pause 再 resume 带 context 的组合,子 SOP 级联正确。
- 节点在消息投递前结束时,消息被转为 queue 或标为 expired,界面可见,不会静默丢失;pending 消息可撤回。
- 对 script / approval 节点插话返回 400;无项目写权限返回 403。
- 单元测试覆盖:队列状态机、hook 注入命令的读取与回执、三种降级路径、节点结束时的转存逻辑;e2e 覆盖运行详情页发送插话并看到状态变化。
.agentflow/steer/不出现在交付分支的 diff 中。
- Lenguaje dominante
- Go
- Estrellas
- 141
- Forks
- 28
- Merge medio
- 1 d 15 h
- PR fusionados (30 d)
- 113
Preparar el entorno
- Incluye un Dockerfile o un archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de Tencent/LoopForge
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 74/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
Los mantenedores suelen responder en 1 día
-
[Bug]: 官方镜像未安装 wecom-cli,企业微信通知报「通知服务未安装 wecom-cli」Posiblemente ocupada @newexploreor la tomó hace 1 día. Abiertobug
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
Tencent/LoopForge#156 · 1 comentario · 1 asignado ·
Los mantenedores suelen responder en 1 día
-
【架构优化】合并 gitwork/workbranch.go 中 push/pull 重复的默认提交身份注入为 withFallbackIdentityPosiblemente ocupada @fx-kurumi la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 40/100
Los mantenedores suelen responder en 1 día
-
【架构优化】从 runtime.installNPMCLI 中拆出 npm 参数拼装 npmCLIInstallArgs 与安装结果启用 activateNPMStagePosiblemente ocupada @fx-kurumi la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 30/100
Los mantenedores suelen responder en 1 día
Todos los issues de Tencent/LoopForge
Issues similares
-
team:library-maintainers
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
padok-team/burrito#1208 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
bazel-contrib/rules_go#4784 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
-
Уязвимые компоненты в GoAbierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
POSIdev-community/aictl#40 ·
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 62/100
prime-radiant-inc/evener#6306 ·
Los mantenedores suelen responder en 1 día