feat(goal): drive same-session goal rounds
This commit is contained in:
@@ -44,7 +44,7 @@ Agent *creation* is provided by the plugin implementing `AgentFactory` (`dsh-age
|
||||
|
||||
The lifecycle edges have two important local caveats. `agent/created` runs after scoped setup and after both session and agent registry entries exist. Setup is trusted composition-only code; the immediately following non-vetoing `agent/session-start` notification is the first supported startup injection point. `agent/disposed` always means the exact agent has left the registry. AgentLoop emits it after its driver is quiescent, while ordered teardown may still be detaching the session and unwinding the scope; custom agents registered directly own any stronger driver-ordering contract themselves.
|
||||
|
||||
Most interception points are cooperative waterfalls returning seam-specific decisions. `agent/pre-step` and `agent/post-step` are serial checkpoints around a step's durable work, while `agent/request-error` is the failed-model-request recovery waterfall: a retry opens a new numbered step after the failed step closes. `agent/turn-stop` is the terminal serial fold: it runs after ordinary continuation and steering folding, and a returned stop remains in force through turn close and flush so later steering cannot create an extra step or turn. Ordinary queued prompts remain intact. The full rationale for scoped dispatch and terminal settlement is in the [agent-scope runtime-design RFC](../../../docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.md#three-execution-boundaries-are-deliberately-one-way).
|
||||
Most interception points are cooperative waterfalls returning seam-specific decisions. `agent/pre-step` and `agent/post-step` are serial checkpoints around a step's durable work, while `agent/request-error` is the failed-model-request recovery waterfall: a retry opens a new numbered step after the failed step closes. `agent/turn-stop` is the terminal serial fold: it runs after ordinary continuation and steering folding, and a returned stop remains in force through turn close and flush so later steering cannot create an extra step or turn. Ordinary queued prompts remain intact. Effective broad cancellation first emits the observe-only `agent/cancel-requested` with its resolved reason, then clears queues and aborts; notification failures are contained and cannot veto the stop. The full rationale for scoped dispatch and terminal settlement is in the [agent-scope runtime-design RFC](../../../docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.md#three-execution-boundaries-are-deliberately-one-way).
|
||||
|
||||
`PromptDecision.additionalContexts` is an array so every injected context keeps its own source, envelope, and metadata. A `ContinuationDecision` reason is narrower: it becomes a `steering/message`, not a `context/message`, and therefore carries only content and source.
|
||||
|
||||
@@ -57,7 +57,7 @@ The handle every plugin programs against:
|
||||
- `agent.send(content, options?)` — queue a message; starts a turn when idle. Content and resolved source become one detached, deeply frozen lossless-JSON record before `agent/queued` and enqueue; invalid data throws synchronously, and caller or notification-listener in-place mutation cannot change the log or model input (`agent/prompt-submit` still rewrites by returning replacement content).
|
||||
- `agent.steer(content, options?)` — steer a running turn (inject between steps); uses the same owned acceptance boundary and behaves like `send` when idle
|
||||
- `agent.inject(content, options?)` — accept detached in-session context without running the model; the next request sees its `context/message`. `options.envelope` defaults to the canonical `<context>` framing and may be `'raw'` when the caller owns a complete familiar frame; `options.meta` persists opaque JSON state without rendering it. While a turn is open it joins that turn, deferring FIFO while the current tool batch executes and draining before turn close if execution is interrupted; while idle it is wrapped in a one-shot `injection` turn and durability checkpoint ([the turn-enclosure invariant](../../../docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.md)).
|
||||
- `agent.cancel(reason?)` — cancel ALL pending work: clears the queued + steering FIFOs, aborts the in-flight step, and drops a turn about to start (the pre-step window) so a queued-but-not-started prompt never runs. A UI/ACP `session/cancel` maps to this. The single public stop primitive. Idle with nothing pending → a safe no-op.
|
||||
- `agent.cancel(reason?)` — cancel ALL pending work: an effective call emits `agent/cancel-requested` before it clears the queued + steering FIFOs, aborts the in-flight step, and drops a turn about to start (the pre-step window). Observers may synchronize their own state but cannot veto cancellation. A UI/ACP `session/cancel` maps to this. The single public stop primitive. Idle with nothing pending → a safe no-op with no notification.
|
||||
- `agent.whenIdle()` — resolve once the agent reaches quiescence after settling out of `running` (idle → immediately; disposed → awaits the loop exit). A non-owner's quiescence-observation hook: it observes the work settling WITHOUT tearing the agent down. Teardown is separate — a lifecycle owner stops and unregisters via `AgentHandle.dispose()`, which awaits the loop exit directly.
|
||||
- `agent.session`, `agent.status`, `agent.options`, `agent.id`
|
||||
|
||||
|
||||
@@ -120,9 +120,10 @@ export interface Agent {
|
||||
|
||||
/**
|
||||
* Clear queued and steering work, including work waiting to start, and abort
|
||||
* the active step. The supplied reason is preserved across pre-step and active
|
||||
* cancellation windows, and `whenIdle()` resolves after cancellation reaches
|
||||
* quiescence. Idle cancellation is a no-op and does not arm a later cancel.
|
||||
* the active step. An effective call first emits `agent/cancel-requested` with
|
||||
* the resolved reason. The supplied reason is preserved across pre-step and
|
||||
* active cancellation windows, and `whenIdle()` resolves after cancellation
|
||||
* reaches quiescence. Idle cancellation is a no-op and does not arm a later cancel.
|
||||
*/
|
||||
cancel(reason?: string): void
|
||||
|
||||
@@ -173,6 +174,16 @@ declare module 'cordis' {
|
||||
* @mode emit
|
||||
*/
|
||||
'agent/queued'(this: Scoped<Agent>, agent: Agent, content: ContentBlock[], info: { source: MessageSource; steering: boolean }): void
|
||||
/**
|
||||
* Effective broad cancellation was requested, before queued/steering work
|
||||
* is cleared or the active step is aborted. This observe-only notification
|
||||
* cannot veto cancellation; listener failures are contained.
|
||||
* @param agent - the agent whose current work is being cancelled.
|
||||
* @param reason - resolved cancellation reason, including the default.
|
||||
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
|
||||
* @mode emit
|
||||
*/
|
||||
'agent/cancel-requested'(this: Scoped<Agent>, agent: Agent, reason: string): void
|
||||
|
||||
// ---- session lifecycle (emit) ----
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user