docs: add @mode tags + enrich JSDoc on harness event declarations

Annotate all 24 harness events across the 5 event-declaring packages with
an explicit `@mode emit|waterfall|parallel` tag and self-contained JSDoc, so
the generated cordis catalog can render each entry's mode and prose from
source alone.
This commit is contained in:
Tianyi Cui
2026-06-20 19:21:42 +08:00
parent 9949f4f2ea
commit ee494969af
5 changed files with 102 additions and 22 deletions
+56 -10
View File
@@ -132,48 +132,94 @@ export interface Agent {
declare module 'cordis' {
interface Events {
// ---- lifecycle (emit) ----
/** An agent was registered. */
/**
* An agent was registered in the {@link AgentRegistry} and is ready to
* receive messages.
* @mode emit
*/
'agent/created'(agent: Agent): void
/** An agent was disposed. */
/**
* An agent was disposed and removed from the registry; its fiber and any
* in-flight turn have been torn down.
* @mode emit
*/
'agent/disposed'(agent: Agent): void
/** Agent status changed (idle/running/disposed). */
/**
* Agent status changed (`idle` ⇄ `running`, or → `disposed`). Drive
* lifecycle off this transition, never off a status you just requested —
* `send()` does not flip status to `running` before it returns.
* @mode emit
*/
'agent/status'(agent: Agent, status: AgentStatus): void
/**
* A message entered the agent's inbox (queued or steering). `source` is
* the resolved source (defaults applied), not the caller's raw options.
* @mode emit
*/
'agent/queued'(agent: Agent, content: ContentBlock[], info: { source: MessageSource; steering: boolean }): void
// ---- turn/step boundaries (emit) ----
/**
* A turn began. `turn` is the 1-based turn number within the session.
* @mode emit
*/
'agent/turn-start'(agent: Agent, turn: number): void
/**
* A turn ended. `reason` distinguishes a clean stop from a truncated or
* aborted one (`completed` | `aborted` | `error` | `disposed` | `max-tokens`).
* @mode emit
*/
'agent/turn-end'(agent: Agent, turn: number, reason: TurnEndReason): void
/**
* A step (one model call plus its tool dispatch) began. `step` is 1-based
* within the turn; a turn runs one or more steps.
* @mode emit
*/
'agent/step-start'(agent: Agent, turn: number, step: number): void
/**
* A step ended.
* @mode emit
*/
'agent/step-end'(agent: Agent, turn: number, step: number): void
// ---- interception seams (waterfall) ----
/**
* Waterfall: mutate the fully-assembled GenerateOptions before the model
* call (hooks, compaction, model switching, tool filtering, …).
* Waterfall: mutate the fully-assembled {@link GenerateOptions} before the
* model call (hooks, compaction, model switching, tool filtering, …). Call
* `next()` to delegate, or return without it to short-circuit.
* @mode waterfall
*/
'agent/request'(agent: Agent, turn: number, step: number, options: GenerateOptions, next: () => Promise<GenerateOptions>): Promise<GenerateOptions>
/**
* Waterfall: post-process the assembled assistant message before tool
* dispatch (validation, content rewriting, …).
* Waterfall: post-process the assembled assistant {@link Message} before
* tool dispatch (validation, content rewriting, …).
* @mode waterfall
*/
'agent/step-result'(agent: Agent, turn: number, step: number, message: Message, next: () => Promise<Message>): Promise<Message>
/**
* Waterfall: override the turn-continuation decision. The default
* (computed by the loop) is `hadToolCalls || steeringInjected`. Listeners
* can force-continue (/goal, /loop) or force-stop (budget guards).
* @mode waterfall
*/
'agent/turn-continuation'(agent: Agent, turn: number, defaultDecision: boolean, next: () => Promise<boolean>): Promise<boolean>
// ---- streaming + tool notifications (emit) ----
/** A raw stream chunk arrived (token-level UI/log feed). */
/**
* A raw {@link StreamChunk} arrived from the model (token-level UI/log feed).
* @mode emit
*/
'agent/stream-chunk'(agent: Agent, turn: number, step: number, chunk: StreamChunk): void
/** Steering content was injected into a running turn. */
/**
* Steering content was injected into a running turn.
* @mode emit
*/
'agent/steering'(agent: Agent, turn: number, content: ContentBlock[], source: MessageSource): void
/** A step or turn errored. */
/**
* A step or turn errored. The loop reports a failure here (plus the logger)
* even when the error has no in-turn position for a session `error` event.
* @mode emit
*/
'agent/error'(agent: Agent, turn: number, step: number, error: Error): void
}
}
+15 -3
View File
@@ -23,11 +23,23 @@ declare module 'cordis' {
}
interface Events {
/** Waterfall around every streaming model call (retry, caching, routing). */
/**
* Waterfall around every streaming model call (retry, caching, routing).
* Bound to the {@link LlmService}; call `next()` to reach the resolved
* adapter's stream, or yield your own chunks to short-circuit.
* @mode waterfall
*/
'llm/stream'(this: LlmService, options: GenerateOptions, next: () => AsyncIterable<StreamChunk>): AsyncIterable<StreamChunk>
/** Waterfall around every non-streaming model call. */
/**
* Waterfall around every non-streaming model call. Bound to the
* {@link LlmService}; call `next()` to delegate to the adapter.
* @mode waterfall
*/
'llm/generate'(this: LlmService, options: GenerateOptions, next: () => Promise<GenerateResult>): Promise<GenerateResult>
/** An adapter was registered or unregistered. */
/**
* An adapter was registered or unregistered (the model→adapter map changed).
* @mode emit
*/
'llm/adapter-change'(): void
}
}
+13 -4
View File
@@ -23,15 +23,24 @@ declare module 'cordis' {
}
interface Events {
/** A session was created in the store. */
/**
* A session was created in the store.
* @mode emit
*/
'session/created'(session: Session): void
/** An event was appended to a session log (sync, fire-and-forget). */
/**
* An event was appended to a session log (sync, fire-and-forget). This is
* the per-append feed a UI or invariant plugin tails.
* @mode emit
*/
'session/event'(session: Session, event: SessionEvent): void
/**
* Awaited durability checkpoint. The agent loop awaits
* `ctx.parallel('session/flush', session)` at every turn end; persistence
* plugins (JSONL, SQLite) drain their write-behind
* buffers here and on fiber dispose.
* plugins (JSONL, SQLite) drain their write-behind buffers here and on
* fiber dispose. Awaited (parallel), not a waterfall: every listener runs
* and the loop waits for all of them, but none can veto.
* @mode parallel
*/
'session/flush'(session: Session): Promise<void> | void
}
+11 -2
View File
@@ -15,9 +15,18 @@ declare module 'cordis' {
}
interface Events {
/** Waterfall around prompt assembly — mutate/extend the assembly. */
/**
* Waterfall around prompt assembly — mutate or extend the
* {@link PromptAssembly} (sections + tool schemas) before it is rendered.
* Bound to the {@link SystemPrompt} service; call `next()` to delegate.
* @mode waterfall
*/
'system-prompt/assemble'(this: SystemPrompt, assembly: PromptAssembly, next: () => Promise<PromptAssembly>): Promise<PromptAssembly>
/** A section or tool provider was registered or unregistered. */
/**
* A section or tool provider was registered or unregistered (the assembly
* inputs changed).
* @mode emit
*/
'system-prompt/change'(): void
}
}
+7 -3
View File
@@ -36,11 +36,15 @@ declare module 'cordis' {
* Waterfall around every tool execution — the single seam where sandbox,
* permission, hook, and plan-mode plugins wrap or veto a call. Listeners
* receive `(exec, next)`: call `next()` to proceed (possibly around your
* own logic), or return a ToolExecutionResult without calling `next()`
* to short-circuit (veto).
* own logic), or return a {@link ToolExecutionResult} without calling
* `next()` to short-circuit (veto).
* @mode waterfall
*/
'tools/execute'(this: ToolRegistry, exec: ToolExecution, next: () => Promise<ToolExecutionResult>): Promise<ToolExecutionResult>
/** A tool was registered or unregistered. */
/**
* A tool was registered or unregistered (the available tool set changed).
* @mode emit
*/
'tools/change'(): void
}
}