[Feature] SOP 运行中向 Agent 节点插话:不打断地注入纠偏指令,支持排队到下一次尝试与一步打断续接
Mantenedores costumam responder em até 1 dia
Ninguém assumiu esta issue ainda.
Avaliação
- Dificuldade
- 5/5
- Tempo estimado
- Mais de uma semana
- Facilidade para iniciantes
- 25/100
- Tipo de issue
- Funcionalidade
- Clareza
- Razoavelmente clara
- Status de atividade
- Ativa
- Stack de tecnologia
- go, javascript, sql
- Domínio
- backend, backend-api-design, databases, frontend
Direção de pesquisa
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.
Escrita pelo modelo de indexação a partir do texto da issue.
Descrição
背景与借鉴来源
主流 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 中。
- Linguagem predominante
- Go
- Estrelas
- 141
- Forks
- 28
- Merge médio
- 1d 15h
- PRs com merge (30d)
- 113
Preparar o ambiente
- Inclui um Dockerfile ou arquivo Docker Compose
- Tem um modelo de pull request
- Ler o guia de contribuição
Primeiros passos
- Leia a issue inteira e depois o guia de contribuição do projeto.
- Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
- Faça um fork do repositório e trabalhe em uma branch.
- Abra um pull request que referencie o número da issue.
Mais de Tencent/LoopForge
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 74/100
Mantenedores costumam responder em até 1 dia
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 75/100
Mantenedores costumam responder em até 1 dia
-
[Bug]: 官方镜像未安装 wecom-cli,企业微信通知报「通知服务未安装 wecom-cli」Talvez já em andamento @newexploreor assumiu há 1 dia. Abertabug
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 76/100
Tencent/LoopForge#156 · 1 comentário · 1 responsável ·
Mantenedores costumam responder em até 1 dia
-
【架构优化】合并 gitwork/workbranch.go 中 push/pull 重复的默认提交身份注入为 withFallbackIdentityTalvez já em andamento @fx-kurumi assumiu hoje. Aberta
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 40/100
Mantenedores costumam responder em até 1 dia
-
【架构优化】从 runtime.installNPMCLI 中拆出 npm 参数拼装 npmCLIInstallArgs 与安装结果启用 activateNPMStageTalvez já em andamento @fx-kurumi assumiu hoje. Aberta
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 30/100
Mantenedores costumam responder em até 1 dia
Todas as issues de Tencent/LoopForge
Issues semelhantes
-
team:library-maintainers
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 82/100
padok-team/burrito#1208 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 62/100
bazel-contrib/rules_go#4784 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 75/100
-
Уязвимые компоненты в GoAberta
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 62/100
POSIdev-community/aictl#40 ·
-
Dificuldade 1/5 Menos de uma hora Facilidade para iniciantes 62/100
prime-radiant-inc/evener#6306 ·
Mantenedores costumam responder em até 1 dia