huskies: merge 652_story_pass_resume_session_id_on_agent_respawn_so_new_sessions_inherit_prior_reasoning
This commit is contained in:
@@ -292,6 +292,22 @@ impl AgentPool {
|
||||
.map(|a| a.inactivity_timeout_secs)
|
||||
.unwrap_or(300);
|
||||
|
||||
// If no explicit session_id_to_resume was provided, look up from the
|
||||
// persistent session store. The key includes the model so a model
|
||||
// change (e.g. sonnet → opus) produces a cache miss — intentional.
|
||||
let effective_session_id = session_id_to_resume.or_else(|| {
|
||||
let model = config
|
||||
.find_agent(&resolved_name)
|
||||
.and_then(|a| a.model.clone())
|
||||
.unwrap_or_default();
|
||||
crate::agents::session_store::lookup_session(
|
||||
project_root,
|
||||
story_id,
|
||||
&resolved_name,
|
||||
&model,
|
||||
)
|
||||
});
|
||||
|
||||
// Clone all values needed inside the background spawn.
|
||||
// Spawn the background task. Worktree creation and agent launch happen here
|
||||
// so `start_agent` returns immediately after registering the agent as
|
||||
@@ -300,7 +316,7 @@ impl AgentPool {
|
||||
project_root.to_path_buf(),
|
||||
config.clone(),
|
||||
resume_context.map(str::to_string),
|
||||
session_id_to_resume,
|
||||
effective_session_id,
|
||||
story_id.to_string(),
|
||||
resolved_name.clone(),
|
||||
tx.clone(),
|
||||
|
||||
@@ -155,13 +155,17 @@ pub(super) async fn run_agent_spawn(
|
||||
// (which would re-read CLAUDE.md and README) and send only the gate
|
||||
// failure context as a new message. On a fresh start, append the
|
||||
// failure context to the original prompt as before.
|
||||
let effective_prompt = match &session_id_to_resume_owned {
|
||||
Some(_) => resume_context_owned.unwrap_or_default(),
|
||||
let (effective_prompt, fresh_prompt) = match &session_id_to_resume_owned {
|
||||
Some(_) => {
|
||||
// Keep the full rendered prompt as fallback if resume fails.
|
||||
let fallback = prompt;
|
||||
(resume_context_owned.unwrap_or_default(), Some(fallback))
|
||||
}
|
||||
None => {
|
||||
if let Some(ctx) = resume_context_owned {
|
||||
prompt.push_str(&ctx);
|
||||
}
|
||||
prompt
|
||||
(prompt, None)
|
||||
}
|
||||
};
|
||||
|
||||
@@ -200,6 +204,7 @@ pub(super) async fn run_agent_spawn(
|
||||
inactivity_timeout_secs,
|
||||
mcp_port: port_for_task,
|
||||
session_id_to_resume: session_id_to_resume_owned.clone(),
|
||||
fresh_prompt: fresh_prompt.clone(),
|
||||
};
|
||||
runtime
|
||||
.start(ctx, tx_clone.clone(), log_clone.clone(), log_writer_clone)
|
||||
@@ -217,6 +222,7 @@ pub(super) async fn run_agent_spawn(
|
||||
inactivity_timeout_secs,
|
||||
mcp_port: port_for_task,
|
||||
session_id_to_resume: session_id_to_resume_owned.clone(),
|
||||
fresh_prompt: fresh_prompt.clone(),
|
||||
};
|
||||
runtime
|
||||
.start(ctx, tx_clone.clone(), log_clone.clone(), log_writer_clone)
|
||||
@@ -234,6 +240,7 @@ pub(super) async fn run_agent_spawn(
|
||||
inactivity_timeout_secs,
|
||||
mcp_port: port_for_task,
|
||||
session_id_to_resume: session_id_to_resume_owned,
|
||||
fresh_prompt,
|
||||
};
|
||||
runtime
|
||||
.start(ctx, tx_clone.clone(), log_clone.clone(), log_writer_clone)
|
||||
@@ -266,6 +273,21 @@ pub(super) async fn run_agent_spawn(
|
||||
}
|
||||
}
|
||||
|
||||
// Persist session_id so respawns can resume prior reasoning.
|
||||
if let Some(ref sess_id) = result.session_id {
|
||||
let model = config_clone
|
||||
.find_agent(&aname)
|
||||
.and_then(|a| a.model.clone())
|
||||
.unwrap_or_default();
|
||||
crate::agents::session_store::record_session(
|
||||
&project_root_clone,
|
||||
&sid,
|
||||
&aname,
|
||||
&model,
|
||||
sess_id,
|
||||
);
|
||||
}
|
||||
|
||||
// Mergemaster agents have their own completion path via
|
||||
// start_merge_agent_work / run_merge_pipeline and must NOT go
|
||||
// through server-owned gates. When a mergemaster exits early
|
||||
|
||||
Reference in New Issue
Block a user