cancelSubagentWithoutJob function
Future<String>
cancelSubagentWithoutJob({
- required String id,
- required SubagentManager? manager,
- TaskExecutor? executor,
- String source = 'task_cancel',
Cancels the subagent named id when its id names no live background
TaskJob (issue #332) — the ONE helper both cancel surfaces (the
task_cancel tool and /tasks cancel) route through, so their wording
can never diverge. Three honest outcomes:
- a child running inline on
executor(a blocking-batch spawn or an in-flight resume — these have NO TaskJob by design) is aborted through its in-flight cancel source; its registry row settles through the normal run path. Tombstoning here would lie 'aborted' over a LIVE child and lock steering/task_send out until self-heal. - a registry row whose runner died with a previous host process (no live runner ANYWHERE) is tombstoned SubagentStatus.aborted — cancel must always be able to clear a 'running' row.
- anything else reports honestly (terminal state / unknown id).
Implementation
Future<String> cancelSubagentWithoutJob({
required String id,
required SubagentManager? manager,
TaskExecutor? executor,
String source = 'task_cancel',
}) async {
if (executor != null && executor.isInFlight(id)) {
executor.cancelInFlight(id);
return 'cancel requested for subagent $id — it is running inline '
'(blocking batch or resume) with no background job; its registry '
'row settles when the child stops';
}
final handle = manager?[id];
if (handle == null) {
return 'no background job with id "$id"';
}
if (handle.isTerminal) {
return 'subagent $id already ${handle.status.name}';
}
await manager!.update(
id,
status: SubagentStatus.aborted,
error:
'cancelled by $source: no live runner '
'(the host session restarted before this child settled)',
);
return 'tombstoned subagent $id as aborted — no live runner existed '
'(interrupted before start), registry row cleared';
}