feat(tasks): wake an idle owner when a background task completes
Completion notices went through agent.inject(), which never reserves a driver, so a task settling after its turn closed left the notice parked until unrelated input woke the agent — while the same prompt told the model not to poll for it. An unreported completion now picks its lane from the owner's state: a busy owner is injected as before, an idle owner is woken with followup(). This adopts the delivery rule the subagent continuation manager already ships. maxConsecutiveWakes bounds the self-exciting chain and is reset by user-authored input; completionDelivery: quiet restores the old lane for deterministic transcripts. Teardown cancellation now claims the terminal report the way kill() already does, so an owner being destroyed is never woken, and settle() announces completion last so a reporter that opens a turn synchronously sees a committed record.
This commit is contained in:
@@ -97,7 +97,7 @@ interface TaskOutcome {
|
||||
|
||||
## Consumer views
|
||||
|
||||
Snapshots are fresh read-only projections. `ownerSession` carries the shared `SessionId` used for authorization; completion listeners separately receive the exact owner object used for lifecycle cleanup. `reported` suppresses a completion notice after another reporter has delivered or committed to deliver the terminal state.
|
||||
Snapshots are fresh read-only projections. `ownerSession` carries the shared `SessionId` used for authorization; completion listeners separately receive the exact owner object used for lifecycle cleanup. `reported` suppresses a completion notice after another reporter has delivered or committed to deliver the terminal state, including the teardown cancel that drains an owner or the service.
|
||||
|
||||
```ts type-equiv
|
||||
/**
|
||||
@@ -128,8 +128,11 @@ interface TaskSnapshot {
|
||||
/** Epoch ms when the task settled; absent while `running`/`stopping`. */
|
||||
finishedAt?: number
|
||||
/**
|
||||
* True when a kill, read, or wait has reported or committed to report the
|
||||
* terminal state. Completion reporters suppress redundant notices when set.
|
||||
* True when a kill, read, wait, or teardown cancel has reported or committed
|
||||
* to report the terminal state. Completion reporters suppress redundant
|
||||
* notices when set. Teardown claims it because the owner or service being
|
||||
* destroyed leaves no reader: a reporter that opens a turn on notice would
|
||||
* otherwise spend a model request per teardown layer.
|
||||
*/
|
||||
reported: boolean
|
||||
}
|
||||
@@ -169,9 +172,9 @@ Abstract background task registry. Subclass, implement the abstract methods, and
|
||||
|
||||
Implementations must honor these semantics:
|
||||
|
||||
- Registrations outlive producer and controller fibers. Owner and service disposal cancel live work and await compliant producers; a throwing teardown cancel force-fails only the record.
|
||||
- Registrations outlive producer and controller fibers. Owner and service disposal cancel live work and await compliant producers; a throwing teardown cancel force-fails only the record. Teardown cancellation also marks the record reported, because a record its owner is being destroyed for has no reader left.
|
||||
- Owned-task access is fenced by the owner's session id. Ids are predictable, so authorization — not secrecy — is the boundary.
|
||||
- Settlement is first-wins: one terminal record, one round of contained listener notification, and released waiters, even against a late producer outcome.
|
||||
- Settlement is first-wins: one terminal record, released waiters, and one round of contained listener notification, even against a late producer outcome. Completion is announced last, after the record is committed and every other observer of the settlement has seen it, because a reporter may open a model turn synchronously.
|
||||
- start refuses work while no attached task controller serves the spec's owner, so a producer cannot start work that owner cannot collect or stop. One registry serves every composition in the process, so this question — and completion-listener delivery — is owner-relative rather than process-wide: registrations made from an unscoped context serve every owner, and registrations made under an agent composition's scope serve exactly the agents composed under it.
|
||||
|
||||
```ts cordis-catalog
|
||||
@@ -282,5 +285,5 @@ abstract attachController(name: string): () => void
|
||||
|
||||
Types: [Agent](core.md)
|
||||
|
||||
Source: [`packages/tasks/tasks/src/index.ts:58`](../../packages/tasks/tasks/src/index.ts)
|
||||
Source: [`packages/tasks/tasks/src/index.ts:62`](../../packages/tasks/tasks/src/index.ts)
|
||||
<!-- END GENERATED cordis-surface -->
|
||||
|
||||
Reference in New Issue
Block a user