From 56101b46e89996e1f0c655f203c466bb6a2f8e8e Mon Sep 17 00:00:00 2001 From: Autumn-27 <53844290+Autumn-27@users.noreply.github.com> Date: Thu, 20 Aug 2026 09:15:53 -0400 Subject: [PATCH] =?UTF-8?q?feat(worker):=20=E6=9A=82=E5=81=9C/=E9=87=8D?= =?UTF-8?q?=E8=B7=91=E7=BB=AD=E6=8E=A5=E5=85=88=E5=89=8D=20LLM=20=E5=AF=B9?= =?UTF-8?q?=E8=AF=9D=EF=BC=8C=E4=B8=8D=E5=86=8D=E4=BB=8E=E5=A4=B4=E5=BC=80?= =?UTF-8?q?=E5=A7=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Worker 的 Execute 在创建 session 后尝试 Resume 先前的 transcript, 如果存在则续接对话而非重建全新会话,避免浪费已积累的 LLM 上下文。 Claude-Session: https://claude.ai/code/session_014TfZWeVGhjXqZD3vcj44mz --- agent/worker.go | 12 ++++++++++++ db/exploration.go | 10 +++++----- server/engine.go | 3 ++- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/agent/worker.go b/agent/worker.go index 47e25e9..cdbe63d 100644 --- a/agent/worker.go +++ b/agent/worker.go @@ -360,6 +360,18 @@ func (w *Worker) Execute(ctx context.Context, name string, taskID int64, as *db. s := agentcore.NewSession(opts) defer s.Close() // release the session's background-task manager (temp dir + processes) + // Resume prior conversation if this intent was paused/blocked/exhausted and is + // being re-run. The transcript ID is deterministic per intent, so if a prior + // session exists the worker continues from where it left off instead of + // restarting from scratch. + if w.tx != nil { + _ = s.Resume(opts.SessionID) + if len(s.Messages()) > 0 { + seedUnlockFromHistory(s.Messages(), def.UnlockSkill) + input = "继续执行。" + } + } + // 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 diff --git a/db/exploration.go b/db/exploration.go index be01753..dbcdb35 100644 --- a/db/exploration.go +++ b/db/exploration.go @@ -215,7 +215,7 @@ func (s *ExplorationStore) SetNodeState(id int64, state string) error { // ResetRunningIntents returns any intent left in 'running' back to 'open' so it // is re-claimed. Called on startup: a 'running' intent with no live worker (a // backend restart or crashed worker goroutine left it stuck) would otherwise spin -// forever in the UI. Workers re-run an intent from scratch, so reopening is safe. +// forever in the UI. Workers resume from their transcript, so reopening is safe. func (s *ExplorationStore) ResetRunningIntents() (int64, error) { res, err := s.db.Exec(`UPDATE exploration_nodes SET state='open', completed_at=NULL, blocked_reason=NULL WHERE exploration_id=$1 AND kind='intent' AND state='running'`, s.expID) @@ -227,9 +227,9 @@ WHERE exploration_id=$1 AND kind='intent' AND state='running'`, s.expID) } // ReopenIntent flips ONE not-successfully-finished intent (blocked/exhausted/stopped) -// back to 'open' so a worker re-claims and re-runs it from scratch (graph writes it -// already produced stay). done/open/running are left untouched. Returns whether a row -// changed (false = intent absent or not in a rerunnable state). Used by the "重跑" button. +// back to 'open' so a worker re-claims it (graph writes it already produced stay). +// The worker resumes from its prior LLM transcript instead of restarting from scratch. +// done/open/running are left untouched. Returns whether a row changed. Used by "重跑". func (s *ExplorationStore) ReopenIntent(id int64) (bool, error) { res, err := s.db.Exec(`UPDATE exploration_nodes SET state='open', completed_at=NULL, blocked_reason=NULL @@ -244,7 +244,7 @@ WHERE id=$1 AND exploration_id=$2 AND kind='intent' // ReopenBlockedIntents flips EVERY 'blocked' intent in this exploration back to 'open' // (batch rerun after e.g. an LLM/network outage that blocked many at once). Returns the -// number reopened. Workers re-run each from scratch; kept graph writes remain. +// number reopened. Workers resume from their transcripts; kept graph writes remain. func (s *ExplorationStore) ReopenBlockedIntents() (int64, error) { res, err := s.db.Exec(`UPDATE exploration_nodes SET state='open', completed_at=NULL, blocked_reason=NULL WHERE exploration_id=$1 AND kind='intent' AND state='blocked'`, s.expID) diff --git a/server/engine.go b/server/engine.go index c52e76b..4606a8f 100644 --- a/server/engine.go +++ b/server/engine.go @@ -926,7 +926,8 @@ func (e *Engine) runWorkerStep(ctx context.Context, t *Task, name string, worker return true } // if a pause cancelled this run mid-flight, return the intent to the frontier - // so it is re-claimed (and re-run from scratch) on resume — not marked done. + // so it is re-claimed on resume — the worker will resume the prior LLM + // conversation from its transcript instead of restarting from scratch. if ectx.Err() != nil && e.IsPaused(t.ID) { _ = t.Store.SetIntentState(intent.ID, "open") return true