List a session's background tasks above its subagents
The count beside the status said how much work was going and never what,
so "3 bg tasks" was a number with no way to find out what it was about.
Drivers now report the tasks themselves rather than a size:
`Driver::background_tasks` returns `Vec<BackgroundTask>` -- id, the
provider's own description, and a kind -- served by
`GET /sessions/{id}/background`. It is runtime state, never persisted,
and `null` is "nobody has said", which is what a session with no process
answers and what the panel says in words rather than drawing as an empty
list. `description` is optional because Codex names a background terminal
by a process id, and a number drawn as a name is worse than admitting
there is none.
Claude's `background_tasks_changed` entries turn out to be objects
carrying `task_id`, `task_type` and `description`, so each is read rather
than counted -- and an `ambient` one is now dropped from the list and the
count alike, on the CLI's own instruction: a live-update watcher is not
activity, and counting one left a session reading `waiting` with nothing
to wait for.
The phone draws them in the right-hand panel above the subagents,
collapsed to "2 bg tasks running" and pushing the subagents down when
opened. Both lists are items of one lazy column, so neither can run off
the panel, and the section is refetched whenever the live count moves --
a card for work that has finished is exactly the stale measurement the
count exists not to be.
Verified against the real Claude CLI (2.1.261): a backgrounded `sleep 120`
came back as `{"id":"br16327wr","description":"Sleep for 120 seconds",
"kind":"command"}`, and on the emulator against the echo rig the section
appeared, expanded, and dropped a card as its task finished.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c8bfc958ad
commit
942edd6b31
17 files changed
+620
-115
No files matched your search
@@ -728,6 +728,40 @@ pub enum Unqueued {
|
||||
/// is the backpressure-free buffer of record.
|
||||
pub type EventSink = mpsc::UnboundedSender<Event>;
|
||||
|
||||
/// One piece of work a session has running while it is free to do something
|
||||
/// else: a backgrounded command, a subagent, whatever else a provider can
|
||||
/// leave going.
|
||||
///
|
||||
/// Runtime state, never written to a transcript: it is what the provider
|
||||
/// says right now, so a session with no process has nothing to say. Served
|
||||
/// by `GET /sessions/{id}/background`; the `BackgroundTasks` event carries
|
||||
/// only the size, which is what the status row draws.
|
||||
///
|
||||
/// [`description`](Self::description) is `None` where the provider names a
|
||||
/// task by something no reader would recognise -- a process id -- rather
|
||||
/// than by a sentence worked out here; the phone says it does not know.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
||||
pub struct BackgroundTask {
|
||||
/// The provider's own id for it. Never shown; it is what makes two
|
||||
/// snapshots comparable, and what keys the list on the phone.
|
||||
pub id: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub description: Option<String>,
|
||||
pub kind: BackgroundTaskKind,
|
||||
}
|
||||
|
||||
/// What kind of thing a [`BackgroundTask`] is, in the terms the app draws.
|
||||
/// `Other` is deliberately a state of its own rather than a guess: a
|
||||
/// provider word this build has not seen is not a command.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum BackgroundTaskKind {
|
||||
Agent,
|
||||
Command,
|
||||
Workflow,
|
||||
Other,
|
||||
}
|
||||
|
||||
/// The inbound half of a session. Deliberately small; see PLAN.md for the
|
||||
/// per-driver mapping of each method onto its dialect.
|
||||
///
|
||||
@@ -735,9 +769,10 @@ pub type EventSink = mpsc::UnboundedSender<Event>;
|
||||
/// with live input injects it at the next tool boundary, while a turn-at-a-time
|
||||
/// dialect queues it for the next child process.
|
||||
pub trait Driver: Send + Sync {
|
||||
/// The provider's latest measured number of live background tasks.
|
||||
/// `None` means it has not reported one, not that the count is zero.
|
||||
fn background_tasks(&self) -> Option<usize> {
|
||||
/// The background work the provider says is alive now, in the order it
|
||||
/// wants it read. `None` means it has not reported, not that there is
|
||||
/// none -- see [`BackgroundTask`].
|
||||
fn background_tasks(&self) -> Option<Vec<BackgroundTask>> {
|
||||
None
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user