diff --git a/agent/planner.go b/agent/planner.go index 5d74fb0..aa98aec 100644 --- a/agent/planner.go +++ b/agent/planner.go @@ -431,14 +431,9 @@ func (p *Planner) Plan(ctx context.Context, taskID int64, as *db.AssetStore, ts } input := lead + situational + "\n\n据上面的态势,判定目标。目标已【真正达成】(已拿到目标成果/已确认目标漏洞)时用 prove_goal 逐个标记。**硬底线:只要目标尚未达成、且当前没有任何 open 或 running 意图(frontier_open=0 且 running_intents 为空),本轮就必须产出至少一个向目标推进的意图——此时没有在跑的 work 可等、也没有在排队的方向,产出 0 意图=任务停摆。仅当已有 open/running 意图在推进、或目标已达成时,本轮才可以不产出新意图。**" + renderPlannerTodos(opts.Todos.List()) - // 有 deadline 夹逼时加硬 ctx 兜底(软预算 + grace),防单轮卡死绕过轮边界软超时。 - runCtx := ctx - if maxDur > 0 { - var cancel context.CancelFunc - runCtx, cancel = context.WithTimeoutCause(ctx, maxDur+settleHardGrace, AbortRunHardTimeout) - defer cancel() - } - _, _, err = captureRun(runCtx, opts, input, + // MaxDuration 现在会在墙钟到点打断在跑工具并就地进收尾(在活 ctx 上),单轮卡死不再 + // 绕过收尾,无需外部硬 ctx 兜底。ctx 只承载 pause / kill / shutdown。 + _, _, err = captureRun(ctx, opts, input, func(r db.Activity) { if emit != nil { r.Worker = "planner" // planner activity has no intent_id (it generates them) diff --git a/agent/terminalreason.go b/agent/terminalreason.go index bf4b5c9..a751758 100644 --- a/agent/terminalreason.go +++ b/agent/terminalreason.go @@ -33,7 +33,7 @@ func (t *runTrace) done(id string) { var reasonHint = map[harness.TerminalReason]string{ harness.ReasonCompleted: "模型正常结束了本轮,但没有留下文字总结;事实和资产以本轮工具调用记录为准", harness.ReasonMaxTurns: "达到步数上限(MaxTurns):SDK 已执行收尾并写回事实和资产,意图会标记为 exhausted,供规划者换方向继续,而不是作为失败处理", - harness.ReasonTimeout: "达到单次运行的软墙钟预算(MaxDuration):SDK 已在回合边界收尾并写回事实和资产,意图会标记为 exhausted", + harness.ReasonTimeout: "达到单次运行的墙钟预算(MaxDuration):到点会打断在跑的工具并就地进收尾,把已识别的事实和资产写回,意图会标记为 exhausted", harness.ReasonModelError: "模型或 API 调用失败(网络、鉴权、限流、供应商 5xx 等),重试用尽后意图标记为 blocked——传输层故障导致这条意图基本没真正探成;查其执行过程(get_worker_trace)后再决定重派或换法", harness.ReasonBlockingLimit: "上下文长度达到硬上限,请求在发出前被拦截;应收窄意图粒度或压缩工具返回", harness.ReasonPromptTooLong: "提示词过长且上下文压缩重试已经用尽,无法继续执行", diff --git a/agent/worker.go b/agent/worker.go index cd5bf8f..5822cd7 100644 --- a/agent/worker.go +++ b/agent/worker.go @@ -128,11 +128,6 @@ func (w *Worker) SetRunTimeout(run time.Duration) { w.runTimeout = run } -// settleHardGrace is how far past the soft wall-clock budget (runTimeout) the hard -// ctx deadline sits — a backstop for a hung turn; the soft budget handles the -// normal case at the turn boundary. -const settleHardGrace = 90 * time.Second - // settleWrapUpPrompt is injected by the SDK settlement phase when a worker hits its // turn/time budget: stop probing, write back what was found, then end with a // plain-text one-liner (which becomes this run's displayed result). @@ -489,18 +484,10 @@ func (w *Worker) execute(ctx context.Context, name string, taskID int64, as *db. // Budgets + settlement are owned by the SDK (MaxTurns/MaxDuration + Settlement): // on hit it runs a wrap-up turn and finishes with ReasonMaxTurns/ReasonTimeout. - // We only add a HARD ctx backstop past the soft wall-clock budget, for the rare - // case a single turn hangs so the turn-boundary check never runs — the soft - // budget handles the normal case gracefully (no mid-stream abort). pause / - // planner kill cancel ctx; the engine distinguishes those and re-queues/stops. - // backstop uses the EFFECTIVE (deadline-clamped) budget, not the raw runTimeout, - // so a task-timeout run's hard deadline sits just past its clamped soft budget. - runCtx := ctx - if maxDur > 0 { - var runCancel context.CancelFunc - runCtx, runCancel = context.WithTimeoutCause(ctx, maxDur+settleHardGrace, AbortRunHardTimeout) - defer runCancel() - } - _, reason, err := captureRunSession(runCtx, s, input, emitWrap) + // MaxDuration now interrupts an in-flight tool at the wall-clock deadline and + // enters the wrap-up phase on the live ctx, so a run whose tool overran the budget + // still settles (no external hard-timeout backstop needed). ctx itself carries only + // pause / planner kill / shutdown, which the engine distinguishes and re-queues/stops. + _, reason, err := captureRunSession(ctx, s, input, emitWrap) return reason, tsx.Writes(), err } diff --git a/go.mod b/go.mod index b13f25d..4a2403f 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/Autumn-27/artex go 1.26.3 require ( - github.com/Autumn-27/norma v0.3.5 + github.com/Autumn-27/norma v0.3.6 github.com/golang-jwt/jwt/v5 v5.3.1 github.com/jackc/pgx/v5 v5.10.0 github.com/klauspost/compress v1.18.6 diff --git a/go.sum b/go.sum index 3029a38..3eed85a 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/Autumn-27/norma v0.3.5 h1:zYJKoN+SNi3iscednrw21xsW48jUD55CT6RdySP15MA= -github.com/Autumn-27/norma v0.3.5/go.mod h1:BudWrf7iHl96FgHqFr/HwN3mKYmGjJDt+xL2ZHXfFZw= +github.com/Autumn-27/norma v0.3.6 h1:cx68eNW8igG2I9Ed9EIsElelJn9ll9WW2HH3OhYh6fA= +github.com/Autumn-27/norma v0.3.6/go.mod h1:BudWrf7iHl96FgHqFr/HwN3mKYmGjJDt+xL2ZHXfFZw= github.com/andybalholm/brotli v1.2.1 h1:R+f5xP285VArJDRgowrfb9DqL18yVK0gKAW/F+eTWro= github.com/andybalholm/brotli v1.2.1/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=