docs: align prose with runtime contracts
This commit is contained in:
@@ -77,7 +77,7 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [
|
||||
},
|
||||
{
|
||||
key: 'approval',
|
||||
summary: 'Approval request and policy service.',
|
||||
summary: 'Approval service that applies session policy before answerers and logs every ask/outcome pair to the requesting session.',
|
||||
methods: [
|
||||
'async request(req: ApprovalRequest): Promise<ApprovalOutcome>',
|
||||
],
|
||||
@@ -265,7 +265,7 @@ export const EVENT_API: readonly EventApiEntry[] = [
|
||||
name: 'agent/disposed',
|
||||
mode: 'emit',
|
||||
signature: '\'agent/disposed\'(this: Scoped<Agent>, agent: Agent): void',
|
||||
summary: 'An agent left the registry.',
|
||||
summary: 'An agent left the registry; AgentLoop emits this after driver quiescence but before session detachment and scoped-registration unwind.',
|
||||
},
|
||||
{
|
||||
name: 'agent/error',
|
||||
@@ -277,7 +277,7 @@ export const EVENT_API: readonly EventApiEntry[] = [
|
||||
name: 'agent/pre-step',
|
||||
mode: 'serial',
|
||||
signature: '\'agent/pre-step\'(this: Scoped<Agent>, agent: Agent, turn: number, step: number, fullSystemPrompt: string, sessionPrefix: readonly Message[], signal: AbortSignal): Promise<void> | void',
|
||||
summary: 'Awaited serial checkpoint after prompt assembly and before `step/start`.',
|
||||
summary: 'Awaited serial checkpoint for session-surface mutation after prompt assembly and before `step/start`; appends land outside the pending step.',
|
||||
},
|
||||
{
|
||||
name: 'agent/prompt-submit',
|
||||
@@ -331,7 +331,7 @@ export const EVENT_API: readonly EventApiEntry[] = [
|
||||
name: 'agent/turn-stop',
|
||||
mode: 'serial',
|
||||
signature: '\'agent/turn-stop\'(this: Scoped<Agent>, agent: Agent, turn: number): ContinuationStop | undefined',
|
||||
summary: 'Monotonic terminal-stop checkpoint after continuation and steering are folded.',
|
||||
summary: 'Monotonic terminal-stop checkpoint after continuation and steering are folded; a stop remains authoritative through turn close and flush: steering queued in that window is discarded, while ordinary sends survive.',
|
||||
},
|
||||
{
|
||||
name: 'approval/request',
|
||||
|
||||
@@ -934,11 +934,9 @@ describe('agent scope lifecycle', () => {
|
||||
order.push(`session-still-stored=${ctx.sessions.get(SessionId('o1-s')) !== undefined}`)
|
||||
})
|
||||
|
||||
// Open a turn so the drain has real work: the loop must finish it BEFORE
|
||||
// the registry entry goes away (the agent/disposed contract: "its fiber
|
||||
// and any in-flight turn have been torn down"). Wait for the turn to be
|
||||
// OPEN in the log — a dispose landing in the pre-step window would drop
|
||||
// the queued prompt without ever opening a turn.
|
||||
// Open a turn so disposal must drain real work before registry removal.
|
||||
// Waiting for turn/start avoids pre-step disposal dropping the queued prompt
|
||||
// before a turn opens.
|
||||
const turnOpen = new Promise<void>((resolve) => {
|
||||
const off = ctx.on('session/event', (_s, event) => {
|
||||
if (event.type === 'turn/start') { off(); resolve() }
|
||||
|
||||
@@ -170,6 +170,7 @@ export class AgentRegistry extends Service {
|
||||
|
||||
/**
|
||||
* Create and publish an owned agent and session through the active factory.
|
||||
* Rejects if no factory is registered or creation, setup, or publication fails.
|
||||
* @param options - agent id, session id/seed/metadata, and agent options.
|
||||
* @returns the handle after setup, rollback-covered publication, and loop start complete.
|
||||
*/
|
||||
|
||||
@@ -138,8 +138,9 @@ declare module 'cordis' {
|
||||
*/
|
||||
'agent/created'(this: Scoped<Agent>, agent: Agent): void
|
||||
/**
|
||||
* An agent left the registry. AgentLoop emits this after driver quiescence;
|
||||
* custom registry users own their driver-ordering contract.
|
||||
* An agent left the registry; AgentLoop emits this after driver quiescence
|
||||
* but before session detachment and scoped-registration unwind. Custom
|
||||
* registry users own their driver-ordering contract.
|
||||
* @param agent - the exact agent removed from the registry.
|
||||
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
|
||||
* @mode emit
|
||||
@@ -182,11 +183,12 @@ declare module 'cordis' {
|
||||
|
||||
// ---- step/request extension seams (serial + waterfall) ----
|
||||
/**
|
||||
* Awaited serial checkpoint after prompt assembly and before `step/start`.
|
||||
* Listeners may mutate the session surface outside the pending step; the loop
|
||||
* derives history once afterward, so compaction records and replacements are
|
||||
* included without rewriting an assembled request. The prompt and prefix are
|
||||
* the exact pressure inputs for that request, and `signal` cancels listener work.
|
||||
* Awaited serial checkpoint for session-surface mutation after prompt
|
||||
* assembly and before `step/start`; appends land outside the pending step.
|
||||
* The loop derives history once afterward, so compaction records and
|
||||
* replacements are included without rewriting an assembled request. The
|
||||
* prompt and prefix are the exact pressure inputs for that request, and
|
||||
* `signal` cancels listener work.
|
||||
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
|
||||
* @param agent - the agent opening the step.
|
||||
* @param turn - the open turn number.
|
||||
@@ -258,7 +260,8 @@ declare module 'cordis' {
|
||||
'agent/turn-continuation'(this: Scoped<Agent>, agent: Agent, turn: number, defaultDecision: ContinuationDecision, next: () => Promise<ContinuationDecision>): Promise<ContinuationDecision>
|
||||
/**
|
||||
* Monotonic terminal-stop checkpoint after continuation and steering are
|
||||
* folded. A stop discards pending steering.
|
||||
* folded; a stop remains authoritative through turn close and flush:
|
||||
* steering queued in that window is discarded, while ordinary sends survive.
|
||||
* @param agent - the agent whose composed continuation outcome may be stopped.
|
||||
* @param turn - the turn at its terminal-stop checkpoint.
|
||||
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
|
||||
|
||||
@@ -23,8 +23,8 @@ The JSONL durable session-persistence backend — a concrete `SessionPersistence
|
||||
|
||||
- **Lazy materialization.** `create(meta)` writes nothing; on the first `append`, the backend writes and `fsync`s a temporary file, publishes it without overwrite via a hard link, then `fsync`s the directory. A created-but-never-appended session leaves nothing on disk and is absent from `list`.
|
||||
- **Append-only.** Committed events (at or below a flushed `turn/end`) are never rewritten. Subsequent appends are line appends at EOF + `fsync`.
|
||||
- **Crash recovery — close, don't truncate.** `load` preserves valid events from an interrupted final turn, appends the synthetic tool, step, and turn closers required by the shared [persistence contract](../../../docs/rfc/implemented/architecture/2026-06-14-session-persistence.md), and removes only an incomplete final line.
|
||||
- **Contiguous-seq.** `load` rejects a mid-log parse error or `seq` gap (unloadable); `append` rejects a batch whose first `seq` does not continue the stored log, and rejects non-JSON-serializable `event.data` naming the offending event type.
|
||||
- **Crash recovery — preserve valid tail work.** `load` keeps the contiguous valid prefix of an interrupted final turn. It truncates from the first unparsable or sequence-gapped uncommitted record, then appends the synthetic tool, step, and turn closers required by the shared [persistence contract](../../../docs/rfc/implemented/architecture/2026-06-14-session-persistence.md); the same defect at or before the last committed `turn/end` rejects.
|
||||
- **Contiguous-seq.** `append` rejects a batch whose first `seq` does not continue the stored log, and rejects non-JSON-serializable `event.data` naming the offending event type.
|
||||
|
||||
## Write path
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ function permissionOption(currentValue: string): object {
|
||||
type: 'select',
|
||||
currentValue,
|
||||
options: [
|
||||
{ value: 'workspace-write', name: 'workspace-write', description: 'Write inside the workspace; wider retries require approval.' },
|
||||
{ value: 'workspace-write', name: 'workspace-write', description: 'Write inside the workspace and permitted temporary directories; wider retries require approval.' },
|
||||
{ value: 'danger-full-access', name: 'danger-full-access', description: 'Full file access without approval prompts.' },
|
||||
],
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ export class PermissionService extends Service {
|
||||
})).default({
|
||||
'workspace-write': {
|
||||
sandbox: 'workspace-write', approval: 'ask',
|
||||
name: 'workspace-write', description: 'Write inside the workspace; wider retries require approval.',
|
||||
name: 'workspace-write', description: 'Write inside the workspace and permitted temporary directories; wider retries require approval.',
|
||||
},
|
||||
'danger-full-access': {
|
||||
sandbox: 'danger-full-access', approval: 'never',
|
||||
|
||||
@@ -222,9 +222,9 @@ export interface Config {
|
||||
}
|
||||
|
||||
/**
|
||||
* Approval request and policy service. It logs each ask/outcome pair, applies
|
||||
* session policy before answerers, and exposes deterministic policy changes to
|
||||
* the model through prompt and pre-step notices.
|
||||
* Approval service that applies session policy before answerers and logs every
|
||||
* ask/outcome pair to the requesting session. It exposes deterministic policy
|
||||
* changes to the model through prompt and pre-step notices.
|
||||
*/
|
||||
export class ApprovalService extends Service {
|
||||
static Config: z<Config> = z.object({
|
||||
|
||||
Reference in New Issue
Block a user