chore(plan): planner 心跳默认/下限 300s(5min) → 600s(10min)
This commit is contained in:
1 parent
06e714598d
commit
c85b2397e8
4 files changed
+13
-41
No files matched your search
+2
-2
@@ -444,10 +444,10 @@ func (e *Engine) Run(ctx context.Context, t *Task) {
|
||||
}
|
||||
|
||||
// plannerHeartbeatInterval 解析任务的 planner 心跳间隔。db.CreateTask 已归一
|
||||
// (低于 300 一律抬到 300);这里再兜一次底,防内存态异常值。
|
||||
// (低于 600 一律抬到 600);这里再兜一次底,防内存态异常值。
|
||||
func plannerHeartbeatInterval(t *Task) time.Duration {
|
||||
sec := t.PlanHeartbeatSeconds
|
||||
if sec < db.MinPlanHeartbeatSeconds { // 下限=默认=300(5min)
|
||||
if sec < db.MinPlanHeartbeatSeconds { // 下限=默认=600(10min)
|
||||
sec = db.MinPlanHeartbeatSeconds
|
||||
}
|
||||
return time.Duration(sec) * time.Second
|
||||
|
||||
@@ -239,7 +239,7 @@ func (s *Server) toolSpawnTask() actool.CoreTool {
|
||||
"parent_ref": strParam("可选:父任务 id(做父子关联)"),
|
||||
"llm_profile_id": map[string]any{"type": "integer", "description": "可选:指定本子任务 planner/worker 用的 LLM 配置 id(见 list_llm_profiles);留空则继承父任务、再回退全局激活配置"},
|
||||
"timeout_seconds": map[string]any{"type": "integer", "description": "可选:任务级超时(秒)。到点后触发优雅收尾并进入 timeout 终态;留空或 0 = 不限时"},
|
||||
"plan_heartbeat_seconds": map[string]any{"type": "integer", "description": "可选:planner 心跳触发间隔(秒)。距上轮规划结束/任务开始满该值且期间无触发 → 触发一轮规划(兜底死锁 + 唤醒去监督飞行中的 worker)。留空或 0 = 默认 300(5min);"},
|
||||
"plan_heartbeat_seconds": map[string]any{"type": "integer", "description": "可选:planner 心跳触发间隔(秒)。距上轮规划结束/任务开始满该值且期间无触发 → 触发一轮规划(兜底死锁 + 唤醒去监督飞行中的 worker)。留空或 0 = 默认 600(10min);"},
|
||||
"seed_first_intent": map[string]any{"type": "boolean", "description": "可选:默认 true。true=创建即把「描述+目标」作为一条种子意图下发,worker 免等首轮 planner 直接开跑(CTF 等常一个 work 解决的场景推荐);false=走标准的先规划再执行"},
|
||||
}, "description", "goal"),
|
||||
func(_ context.Context, in json.RawMessage) (actool.Result, error) {
|
||||
@@ -282,13 +282,9 @@ func (s *Server) toolSpawnTask() actool.CoreTool {
|
||||
_ = s.m.PG().SetParentRef(id, a.ParentRef)
|
||||
}
|
||||
}
|
||||
s.seed(t, a.Description+" "+a.Goal) // seed 初始资产,喂给事件驱动 loop
|
||||
// 种子意图(默认开启,仅显式 false 关闭):worker 免等首轮 planner 直接开跑。
|
||||
if a.SeedFirstIntent == nil || *a.SeedFirstIntent {
|
||||
s.seedFirstIntent(t)
|
||||
}
|
||||
s.createGoals(s.ctx, t, nil) // 目标分解(LLM;规则兜底)
|
||||
s.engine.Run(s.ctx, t) // 启动该任务的探索引擎
|
||||
// 共享的建后流程,与 HTTP 建任务(server.go createTask)复用同一段 launchTask:
|
||||
// seed + 种子意图 + 后台可见地做目标分解(第0轮/LLM步骤/逐条goal) + engine.Run。
|
||||
s.launchTask(t, a.Description+" "+a.Goal, a.SeedFirstIntent == nil || *a.SeedFirstIntent)
|
||||
return actool.Text(fmt.Sprintf("task created: %s", t.ID)), nil
|
||||
})
|
||||
}
|
||||
|
||||
+4
-28
@@ -1017,7 +1017,7 @@ type createTaskReq struct {
|
||||
Goal string `json:"goal"`
|
||||
LLMProfileID *int64 `json:"llm_profile_id,omitempty"` // 指定运行本任务的 LLM 配置;省略/null=用激活配置
|
||||
TimeoutSeconds int `json:"timeout_seconds"` // 任务级超时(秒);0/省略=不限时
|
||||
PlanHeartbeatSeconds int `json:"plan_heartbeat_seconds"` // planner 心跳触发间隔(秒);0/省略=默认300(5min);下限=默认=300,低于自动抬到300
|
||||
PlanHeartbeatSeconds int `json:"plan_heartbeat_seconds"` // planner 心跳触发间隔(秒);0/省略=默认600(10min);下限=默认=600,低于自动抬到600
|
||||
SeedFirstIntent *bool `json:"seed_first_intent,omitempty"` // 创建时直接下发一条种子意图(内容=描述+目标),让 worker 免等首轮 planner 直接开跑;省略/null=默认开启。CTF 常一 work 解决,省掉开跑前的 planner 轮。
|
||||
}
|
||||
|
||||
@@ -1047,34 +1047,10 @@ func (s *Server) createTask(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
log.Printf("[task] 新建任务 #%s «%s» 目标: %s", t.ID, req.Description, req.Goal)
|
||||
// seed initial asset(s) from goal/description so the event-driven loop has a root.
|
||||
s.seed(t, req.Description+" "+req.Goal)
|
||||
// 种子意图(默认开启):直接把"描述+目标"作为一条待办意图写入 frontier,worker 轮询即可
|
||||
// 领取开跑,省掉开跑前的首轮 planner LLM;跑完由 NotifyDone 正常唤醒 planner 判定/补充。
|
||||
// CTF 场景常一个 work 就解决。仅显式传 false 才关闭。
|
||||
if req.SeedFirstIntent == nil || *req.SeedFirstIntent {
|
||||
s.seedFirstIntent(t)
|
||||
}
|
||||
// Return immediately — goal decomposition is async so the UI isn't blocked.
|
||||
// 共享的建后流程(seed + 种子意图 + 后台目标分解 + engine.Run),与 spawn_task 复用同一段。
|
||||
// launchTask 内部异步,不阻塞 UI —— 目标分解在后台可见地进行。
|
||||
s.launchTask(t, req.Description+" "+req.Goal, req.SeedFirstIntent == nil || *req.SeedFirstIntent)
|
||||
writeJSON(w, 201, t)
|
||||
// Background: emit round-0 marker, decompose goals via LLM, then start engine.
|
||||
// Engine starts only after goals are seeded to avoid a race where the planner
|
||||
// fires before any goal nodes exist.
|
||||
go func() {
|
||||
s.engine.emitActivity(t, db.Activity{Worker: "planner", Kind: "round",
|
||||
Summary: "第 0 轮目标拆解"})
|
||||
goals := s.createGoals(s.ctx, t, func(r db.Activity) {
|
||||
s.engine.emitActivity(t, r)
|
||||
})
|
||||
for _, g := range goals {
|
||||
summary := g.Text
|
||||
if g.VulnClass != "" {
|
||||
summary = fmt.Sprintf("[%s] %s", g.VulnClass, g.Text)
|
||||
}
|
||||
s.engine.emitActivity(t, db.Activity{Worker: "planner", Kind: "text", Summary: summary})
|
||||
}
|
||||
s.engine.Run(s.ctx, t)
|
||||
}()
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
Reference in new issue
Block a user