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,