feat(planner): finding 当场唤醒 + planner N 秒心跳触发(任务参数,默认5min)
触发机制补两条(见 docs/planner-trigger-impl-plan.md): 1) finding 当场唤醒:worker 飞行中 report_finding 落库即唤醒本任务 planner, 不再等 worker 整趟收工才反应。 - worker.Execute 加 notify 入参并 SetNotify(补上 worker toolset 之前缺失的接线) - addFinding 写 KindFinding 成功后调 notify(只对 finding,不对 fact) - engine 两处 worker.Execute 调用传 t.Notify 2) planner N 秒心跳:距上轮规划结束/任务开始满 N 秒且期间无触发 → 触发一轮, 兜底卡死 + 唤醒去监督飞行中的 worker(steer/kill) + 周期复查。 - plannerLoop 重构为 runRound 闭包 + 三臂 select(ctx/notify/heartbeat) - 心跳在 loop 入口臂 = 从任务 start 计时(覆盖 seed 跳过首轮),每轮结束重臂 - 新增任务参数 plan_heartbeat_seconds,下限=默认=300(5min),低于自动抬到300 - DB 迁移:schema.sql 加列 + ALTER ADD COLUMN IF NOT EXISTS 补旧库 - 全链路接线:db.CreateTask/manager/server HTTP/orchestration spawn_task - 前端:api.createTask 传参 + 建任务表单新增"planner 心跳(分钟)"字段
This commit is contained in:
1 parent
06c1ac748f
commit
47ba58bda6
11 files changed
+168
-82
No files matched your search
@@ -111,6 +111,7 @@ export default function TasksPage() {
|
||||
const [profiles, setProfiles] = React.useState<LLMProfile[]>([]);
|
||||
const [llmProfile, setLlmProfile] = React.useState<string>(ACTIVE_PROFILE); // sentinel = active
|
||||
const [timeoutMin, setTimeoutMin] = React.useState(""); // 任务级超时(分钟);空/0 = 不限时
|
||||
const [heartbeatMin, setHeartbeatMin] = React.useState("5"); // planner 心跳(分钟);默认5,下限5(与后端一致)
|
||||
const [seedFirstIntent, setSeedFirstIntent] = React.useState(true); // 创建时下发种子意图,worker 免等首轮 planner 直接开跑
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [query, setQuery] = React.useState("");
|
||||
@@ -173,12 +174,14 @@ export default function TasksPage() {
|
||||
try {
|
||||
const pid = llmProfile === ACTIVE_PROFILE ? undefined : Number(llmProfile);
|
||||
const timeoutSec = Math.max(0, Math.floor(Number(timeoutMin) || 0)) * 60;
|
||||
await api.createTask(description.trim(), goal.trim(), pid, timeoutSec, seedFirstIntent);
|
||||
const heartbeatSec = Math.max(5, Math.floor(Number(heartbeatMin) || 5)) * 60; // 下限 5min,与后端归一一致
|
||||
await api.createTask(description.trim(), goal.trim(), pid, timeoutSec, seedFirstIntent, heartbeatSec);
|
||||
toast.success("任务已创建");
|
||||
setDescription("");
|
||||
setGoal("");
|
||||
setLlmProfile(ACTIVE_PROFILE);
|
||||
setTimeoutMin("");
|
||||
setHeartbeatMin("5");
|
||||
setSeedFirstIntent(true);
|
||||
setOpen(false);
|
||||
load();
|
||||
@@ -303,6 +306,21 @@ export default function TasksPage() {
|
||||
到点后触发优雅收尾(各 agent 写回 + planner 终局判定),任务进入 timeout 终态。
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="heartbeat-min">planner 心跳(分钟)</Label>
|
||||
<Input
|
||||
id="heartbeat-min"
|
||||
type="number"
|
||||
min={5}
|
||||
className="w-40"
|
||||
placeholder="默认 5"
|
||||
value={heartbeatMin}
|
||||
onChange={(e) => setHeartbeatMin(e.target.value)}
|
||||
/>
|
||||
<p className="text-muted-foreground text-xs">
|
||||
距上轮规划结束/任务开始满该时长且期间无触发,自动触发一轮规划(兜底卡死 + 唤醒去监督在跑的 worker)。下限 5 分钟。
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<label className="flex items-center gap-2 text-sm">
|
||||
<Checkbox checked={seedFirstIntent} onCheckedChange={(v) => setSeedFirstIntent(!!v)} />
|
||||
|
||||
Reference in new issue
Block a user