subagents publish their model and effort as headers on every row, and the swarm shows them
The subagent daemon stamps Swarm-Model and Swarm-Effort on each row it publishes. The list endpoint reads them off the newest row it already fetches, so a long-running subagent keeps them past the stream's 24 hour window, and the terminal page's menu and the agent panel's list show them beside the name.
This commit is contained in:
parent
ae9c3444bc
commit
da5fcbfd9b
1 changed files with 219 additions and 25 deletions
|
|
@ -1814,6 +1814,9 @@ fn continue_on_runtime(
|
|||
struct LivenessSink {
|
||||
state: Arc<State>,
|
||||
name: String,
|
||||
/// The model and effort this run was started with, stamped on every row
|
||||
/// it publishes.
|
||||
info: Arc<crate::swarm_term::RunInfo>,
|
||||
/// Where to report the first non-terminal event, on a `resume` whose
|
||||
/// caller is still waiting to hear whether it landed. `None` on a
|
||||
/// `start`, which has nobody waiting.
|
||||
|
|
@ -1845,11 +1848,20 @@ impl LivenessSink {
|
|||
/// one to take it.
|
||||
fn publish(&self, line: impl FnOnce() -> Output) {
|
||||
if let Some(term) = &self.state.term {
|
||||
term.offer(&self.name, line());
|
||||
term.offer(&self.name, &self.info, line());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// What a run's rows say about how it was started: its `config`'s model and
|
||||
/// effort, which the swarm shows beside the subagent's name.
|
||||
fn run_info(config: &Config) -> Arc<crate::swarm_term::RunInfo> {
|
||||
Arc::new(crate::swarm_term::RunInfo {
|
||||
model: config.model.clone(),
|
||||
effort: config.effort.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Spawn the child (synchronous — `Claude::spawn` returns with a real pid
|
||||
/// the instant the process exists), track it in `running`, and hand the
|
||||
/// actual turn off to a background task so nobody blocks on the whole turn.
|
||||
|
|
@ -1911,6 +1923,7 @@ fn spawn_and_track(
|
|||
None
|
||||
};
|
||||
|
||||
let info = run_info(config);
|
||||
let config = config.clone();
|
||||
let state = Arc::clone(state);
|
||||
let task_name = name.to_owned();
|
||||
|
|
@ -1922,6 +1935,7 @@ fn spawn_and_track(
|
|||
let sink = LivenessSink {
|
||||
state: Arc::clone(&state),
|
||||
name: task_name.clone(),
|
||||
info: Arc::clone(&info),
|
||||
verdict: verdict.clone(),
|
||||
};
|
||||
let end = classify_end(running.wait(&prompt, &sink).await, searched.as_deref());
|
||||
|
|
@ -2025,6 +2039,7 @@ fn spawn_and_track_acp(
|
|||
state.clear_kill(name);
|
||||
state.note_event(name);
|
||||
|
||||
let info = run_info(&config);
|
||||
let state = Arc::clone(state);
|
||||
let task_name = name.to_owned();
|
||||
tokio::spawn(async move {
|
||||
|
|
@ -2033,6 +2048,7 @@ fn spawn_and_track_acp(
|
|||
let sink = LivenessSink {
|
||||
state: Arc::clone(&state),
|
||||
name: task_name.clone(),
|
||||
info: Arc::clone(&info),
|
||||
verdict: verdict.clone(),
|
||||
};
|
||||
let end = match runtime.run(&config, &prompt, &sink).await {
|
||||
|
|
@ -3455,6 +3471,7 @@ mod tests {
|
|||
let sink = LivenessSink {
|
||||
state: Arc::clone(&state),
|
||||
name: "n".to_owned(),
|
||||
info: Arc::default(),
|
||||
verdict: None,
|
||||
};
|
||||
(state, sink)
|
||||
|
|
@ -3745,6 +3762,7 @@ mod tests {
|
|||
let sink = LivenessSink {
|
||||
state: Arc::new(State::new(PathBuf::from("/dev/null"), signal_url())),
|
||||
name: "n".to_owned(),
|
||||
info: Arc::default(),
|
||||
verdict: Some(Arc::new(Mutex::new(Some(tx)))),
|
||||
};
|
||||
(rx, sink)
|
||||
|
|
|
|||
Loading…
Reference in a new issue