From 52aba07846f2375b38745591e7b1a40182b1df62 Mon Sep 17 00:00:00 2001 From: Autumn-27 <53844290+Autumn-27@users.noreply.github.com> Date: Sun, 23 Aug 2026 10:37:24 -0400 Subject: [PATCH] =?UTF-8?q?feat(mainagent):=20=E9=BB=98=E8=AE=A4=E7=BB=99?= =?UTF-8?q?=E4=B8=BB=20agent=20=E5=8A=A0=E4=B8=8A=20steer=5Fwork=20?= =?UTF-8?q?=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 主 agent 之前只能 add_hint/add_intent,无法对已在运行的 work 实时纠偏。 现将 planner 的 steer_work(不打断、不丢进展地注入纠偏指令)默认下放给主 agent。 - MainAgentTools 加入 steerWorkTool - MainAgent 加 steerWork 字段与 SetSteerWork,Chat 里接进 ToolSet - 全局与 per-task router 两处主 agent 构建均 SetSteerWork(engine.SteerWork) - 主 agent 提示词「操舵」段补充 steer_work 用法引导(仅影响新 seed) 作用域安全:steer_work 仍校验 intent_id 属于本任务(关联任务只读)。 Claude-Session: https://claude.ai/code/session_019QXSCDmzimwnjntBNCgUD7 --- agent/mainagent.go | 7 +++++++ agent/tools_insert.go | 2 ++ server/server.go | 1 + server/task_llm.go | 1 + 4 files changed, 11 insertions(+) diff --git a/agent/mainagent.go b/agent/mainagent.go index 5f8016a..55cd134 100644 --- a/agent/mainagent.go +++ b/agent/mainagent.go @@ -27,6 +27,7 @@ type MainAgent struct { proxyCACert string // recording proxy's CA cert path (HTTPS verify) webSearch WebSearchOpts // web_search tool backend selection (off by default) workDir string // shared work dir (surfaced in prompt as artifact-output target) + steerWork func(intentID int64, msg string) error // engine callback: steer a running work (nil = off) } func NewMainAgent(prov llm.Provider, model, workDir string, tx *transcript.Store, window, maxTurns int) *MainAgent { @@ -49,6 +50,10 @@ func (m *MainAgent) SetProxy(addr, caCert string) { m.proxyAddr, m.proxyCACert = // SetWebSearch selects the web_search backend for the main agent (off by default). func (m *MainAgent) SetWebSearch(o WebSearchOpts) { m.webSearch = o } +// SetSteerWork wires the engine callback that lets the main agent's steer_work +// tool inject a mid-run course-correction into a running work (nil = tool off). +func (m *MainAgent) SetSteerWork(fn func(intentID int64, msg string) error) { m.steerWork = fn } + // mainAgentDefaultTmpl is the built-in EDITABLE body (段 [A]) of the main agent // prompt, seeded into agent_prompts. Goal is a {{.Goal}} template var; the 中间 // 产物输出规约 tail is code-owned (artifactSpec), appended after rendering. @@ -58,6 +63,7 @@ const mainAgentDefaultTmpl = `你是一个授权渗透测试系统的"主 agent" 2. 操舵(把人的意图落到系统): - 人想"改方向/强调某类漏洞/重点某区域" → 用 add_hint 写提示(规划者下次会读到)。 - 人想"立刻测某个具体目标" → 用 add_intent 直接注入一条高优先级意图(priority 8-10)。 + - 人想"对某条正在运行的意图(work)实时纠偏(别再走 X、聚焦 Y)" → 用 steer_work(不打断、不丢已有进展,worker 下一步动作前生效);先用 get_worker_output 看它在干嘛。方向整个错了则改用 add_intent 另下新意图。 - 人想"新增一个要达成的最终目标" → 用 set_goals 增补目标。系统会把该目标写入任务图并**自动把已完成/暂停的任务拉回运行态继续跑**(规划者随后会据此重新判断是否达成),无需人工再点恢复。 3. 用人话简洁回复,说明你做了什么。 @@ -84,6 +90,7 @@ func (m *MainAgent) Chat(ctx context.Context, taskID int64, as *db.AssetStore, t tsx.SetNotify(notify) // add_hint wakes this task's planner (debounced) tsx.SetResumeTask(resume) // set_goals 新增目标 → 把已完成/暂停的任务拉回 running tsx.SetNotifyGoal(notifyGoal) // set_goals 新增目标 → 给 planner 记一条「人新增了目标:…」触发 + tsx.steerWork = m.steerWork // enable steer_work tool (nil = unavailable) // 领域工具 + 基础默认工具集(Read/Write/Edit/MultiEdit/LS/Glob/Grep/Bash) // 资产覆盖度功能关闭时剔除 add_task_scope/list_untested_assets(不入 prompt)。 base := append(tsx.DropCoverageTools(tsx.MainAgentTools()), actool.DefaultTools()...) diff --git a/agent/tools_insert.go b/agent/tools_insert.go index 2cf808a..f8c3943 100644 --- a/agent/tools_insert.go +++ b/agent/tools_insert.go @@ -611,6 +611,8 @@ func (t *ToolSet) MainAgentTools() []actool.CoreTool { return []actool.CoreTool{ t.graphOverview(), t.listFindings(), t.listFacts(), t.nodeDetail(), t.getWorkerOutput(), t.getWorkerTrace(), t.searchAllWorkerTraces(), t.addHint(), t.addIntent(), + // steer_work:人可对某条正在运行的意图(work)实时注入纠偏指令(不打断、不丢进展)。 + t.steerWorkTool(), // set_goals:人可在运行时给本任务补一个新的最终目标(规划者据此重判是否达成)。 t.setGoals(), // asset management (handlers guard nil store internally) diff --git a/server/server.go b/server/server.go index 8b59857..ced79d9 100644 --- a/server/server.go +++ b/server/server.go @@ -438,6 +438,7 @@ func (s *Server) applyLLM(cfg agent.Config) error { s.mainAgent = agent.NewMainAgent(mProv, mCfg.Model, s.m.dir, tx, mCfg.CompactionWindow(), s.agentMaxTurns("mainagent")) s.mainAgent.SetProxy(s.m.ProxyAddr(), s.m.ProxyCACert()) // WebFetch through the recording proxy s.mainAgent.SetWebSearch(s.webSearchFor("mainagent")) + s.mainAgent.SetSteerWork(s.engine.SteerWork) // steer_work:人对运行中 work 实时纠偏 // chat agent serves MANY custom agents by key → it holds the GLOBAL opts // (backend/key) and gates Enabled per-conversation-agent at Chat time. 对话始终用激活配置。 s.chatAgent = agent.NewChatAgent(prov, cfg.Model, s.m.dir, tx, win) // chat page runner diff --git a/server/task_llm.go b/server/task_llm.go index 1dec70a..9fbf5b4 100644 --- a/server/task_llm.go +++ b/server/task_llm.go @@ -388,6 +388,7 @@ func (s *Server) agentsForTask(t *Task) *taskAgentBundle { main.SetCompactionWindowResolver(mainRuntime.CompactionWindow) main.SetProxy(s.m.ProxyAddr(), s.m.ProxyCACert()) main.SetWebSearch(s.webSearchFor("mainagent")) + main.SetSteerWork(s.engine.SteerWork) // steer_work:人对运行中 work 实时纠偏 bundle := &taskAgentBundle{ runtime: goalRuntime, plannerRuntime: plannerRuntime, workerRuntime: workerRuntime, mainRuntime: mainRuntime, pl: pl, wk: wk, main: main,