crash_watch: track prev_sub_agents to fix needs_login for newly spawned agents
This commit is contained in:
parent
55fe2856b9
commit
7426654a74
2 changed files with 26 additions and 31 deletions
|
|
@ -210,24 +210,12 @@ fn finish_approval(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ApprovalKind::Spawn => {
|
ApprovalKind::Spawn => coord.notify_manager(&HelperEvent::Spawned {
|
||||||
coord.notify_manager(&HelperEvent::Spawned {
|
|
||||||
agent: approval.agent.clone(),
|
agent: approval.agent.clone(),
|
||||||
ok,
|
ok,
|
||||||
note,
|
note,
|
||||||
sha: approval.fetched_sha.clone(),
|
sha: approval.fetched_sha.clone(),
|
||||||
});
|
}),
|
||||||
// Newly spawned container has no claude session yet. Emit
|
|
||||||
// NeedsLogin immediately so the manager prompts the operator
|
|
||||||
// rather than waiting for crash_watch (which would miss it
|
|
||||||
// because the agent appears simultaneously in both prev_needs
|
|
||||||
// and current_needs, making the diff empty on the first tick).
|
|
||||||
if ok {
|
|
||||||
coord.notify_manager(&HelperEvent::NeedsLogin {
|
|
||||||
agent: approval.agent.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ApprovalKind::ApplyCommit if is_first_spawn => {
|
ApprovalKind::ApplyCommit if is_first_spawn => {
|
||||||
coord.notify_manager(&HelperEvent::Spawned {
|
coord.notify_manager(&HelperEvent::Spawned {
|
||||||
agent: approval.agent.clone(),
|
agent: approval.agent.clone(),
|
||||||
|
|
@ -235,11 +223,6 @@ fn finish_approval(
|
||||||
note,
|
note,
|
||||||
sha: approval.fetched_sha.clone(),
|
sha: approval.fetched_sha.clone(),
|
||||||
});
|
});
|
||||||
if ok {
|
|
||||||
coord.notify_manager(&HelperEvent::NeedsLogin {
|
|
||||||
agent: approval.agent.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ApprovalKind::ApplyCommit => coord.notify_manager(&HelperEvent::Rebuilt {
|
ApprovalKind::ApplyCommit => coord.notify_manager(&HelperEvent::Rebuilt {
|
||||||
agent: approval.agent.clone(),
|
agent: approval.agent.clone(),
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ pub fn spawn(coord: Arc<Coordinator>) {
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let mut prev_running: HashSet<String> = HashSet::new();
|
let mut prev_running: HashSet<String> = HashSet::new();
|
||||||
let mut prev_logged_in: HashSet<String> = HashSet::new();
|
let mut prev_logged_in: HashSet<String> = HashSet::new();
|
||||||
|
let mut prev_sub_agents: HashSet<String> = HashSet::new();
|
||||||
let mut seeded = false;
|
let mut seeded = false;
|
||||||
loop {
|
loop {
|
||||||
let raw = lifecycle::list().await.unwrap_or_default();
|
let raw = lifecycle::list().await.unwrap_or_default();
|
||||||
|
|
@ -59,7 +60,13 @@ pub fn spawn(coord: Arc<Coordinator>) {
|
||||||
|
|
||||||
if seeded {
|
if seeded {
|
||||||
emit_crash_transitions(&coord, &prev_running, ¤t_running);
|
emit_crash_transitions(&coord, &prev_running, ¤t_running);
|
||||||
emit_login_transitions(&coord, &prev_logged_in, ¤t_logged_in, &sub_agents);
|
emit_login_transitions(
|
||||||
|
&coord,
|
||||||
|
&prev_logged_in,
|
||||||
|
¤t_logged_in,
|
||||||
|
&sub_agents,
|
||||||
|
&prev_sub_agents,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// Periodic container rescan — catches state flips that
|
// Periodic container rescan — catches state flips that
|
||||||
// happen outside our mutation surface (operator runs
|
// happen outside our mutation surface (operator runs
|
||||||
|
|
@ -69,6 +76,7 @@ pub fn spawn(coord: Arc<Coordinator>) {
|
||||||
coord.rescan_containers_and_emit().await;
|
coord.rescan_containers_and_emit().await;
|
||||||
prev_running = current_running;
|
prev_running = current_running;
|
||||||
prev_logged_in = current_logged_in;
|
prev_logged_in = current_logged_in;
|
||||||
|
prev_sub_agents = sub_agents.into_iter().collect();
|
||||||
seeded = true;
|
seeded = true;
|
||||||
|
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
|
|
@ -110,6 +118,7 @@ fn emit_login_transitions(
|
||||||
prev: &HashSet<String>,
|
prev: &HashSet<String>,
|
||||||
current: &HashSet<String>,
|
current: &HashSet<String>,
|
||||||
sub_agents: &[String],
|
sub_agents: &[String],
|
||||||
|
prev_sub_agents: &HashSet<String>,
|
||||||
) {
|
) {
|
||||||
for agent in current.difference(prev) {
|
for agent in current.difference(prev) {
|
||||||
tracing::info!(%agent, "agent logged in");
|
tracing::info!(%agent, "agent logged in");
|
||||||
|
|
@ -117,13 +126,16 @@ fn emit_login_transitions(
|
||||||
agent: agent.clone(),
|
agent: agent.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Only count NeedsLogin transitions for agents that exist and
|
// Detect transitions into "needs login": an agent that was previously
|
||||||
// are *not* logged in — the difference set above already gives
|
// logged-in goes unsigned (credentials deleted), OR a brand-new agent
|
||||||
// us "was in prev, gone from current" but we also want to fire
|
// appears without a session.
|
||||||
// for agents that newly appeared as not-logged-in (post-spawn /
|
//
|
||||||
// post-purge). Treat sub_agents minus current as the
|
// prev_needs uses prev_sub_agents (the agent set from the last tick) so
|
||||||
// currently-needs-login set; emit when an agent enters it.
|
// that a newly-spawned agent — which does not appear in prev_sub_agents —
|
||||||
let prev_needs: HashSet<&str> = sub_agents
|
// is absent from prev_needs even though it's not in prev_logged_in.
|
||||||
|
// Without this, new agents land in both prev_needs and current_needs and
|
||||||
|
// the set difference is empty, silently dropping the event.
|
||||||
|
let prev_needs: HashSet<&str> = prev_sub_agents
|
||||||
.iter()
|
.iter()
|
||||||
.map(String::as_str)
|
.map(String::as_str)
|
||||||
.filter(|n| !prev.contains(*n))
|
.filter(|n| !prev.contains(*n))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue