# zidane/durable

> The durable runtime seam, so an agent run continues after its process crashes.

Import: `import { … } from 'zidane/durable'`. Source: [src/durable/index.ts](https://github.com/Tahul/zidane/blob/main/src/durable/index.ts).

Use this entry point to type or build a durable runtime. Pass one to `createAgent({ durable, sessionId })` and the loop records each model call and tool call as a step, so a run continues after a crash instead of starting over: `onInterrupted: 'resume'` makes `run()` continue it first, or call `agent.resume()`, which resolves `null` when there is nothing to continue. `agent.suspend()` stops a run so the next process resumes it. `createMemoryRuntime()` keeps its steps in memory, for tests. For a file on disk use [`zidane/durable/sqlite`](https://zidane.si/docs/reference/durable-sqlite.md), and for a Restate handler [`zidane/restate`](https://zidane.si/docs/reference/restate.md). See [crash recovery](https://zidane.si/docs/durability.md).

```ts
import { createAgent } from 'zidane'
import { createMemoryRuntime } from 'zidane/durable'
import { anthropic } from 'zidane/providers/anthropic'

const runtime = createMemoryRuntime()
const agent = createAgent({ provider: anthropic(), durable: { runtime, onInterrupted: 'resume' }, sessionId: 'job-42' })
await agent.run({ prompt: 'Summarize the README.' })
console.log(runtime.mode)
```

## Functions

### `createMemoryDurableState`

Function.

An empty state for [`memoryRuntime`](https://zidane.si/docs/reference/durable.md#memoryRuntime).

```ts
function createMemoryDurableState(): MemoryDurableState
```

**Returns** `MemoryDurableState`

Source: [src/durable/memory.ts:117](https://github.com/Tahul/zidane/blob/main/src/durable/memory.ts#L117)

### `createMemoryRuntime`

Function.

A memory runtime over a fresh state: what an agent uses when it is given no runtime.

```ts
function createMemoryRuntime(): DurableRuntime
```

**Returns** `DurableRuntime`

Source: [src/durable/memory.ts:129](https://github.com/Tahul/zidane/blob/main/src/durable/memory.ts#L129)

### `memoryRuntime`

Function.

A memory runtime over `state`. Several runtimes may share one state (two
"processes" on one database); the state itself is the durable part.

```ts
function memoryRuntime(options: { state: MemoryDurableState }): DurableRuntime
```

**Parameters**

- `options` (`{ state: MemoryDurableState }`): Runtime options.

**Returns** `DurableRuntime`

Source: [src/durable/memory.ts:139](https://github.com/Tahul/zidane/blob/main/src/durable/memory.ts#L139)

### `nestedCall`

Function.

`call` of the `n`th call (from 1) made inside `parentCall`: a codemode
script's inner calls, in the order the script makes them. Same as the
nested call ids the loop already mints (`cm1/1`, `cm1/2`).

```ts
function nestedCall(parentCall: string, n: number): string
```

**Parameters**

- `parentCall` (`string`): `call` of the call that makes the nested ones (`cm1`).
- `n` (`number`): Position of the nested call, from 1.

**Returns** `string`: `<parentCall>/<n>`.

Source: [src/durable/keys.ts:77](https://github.com/Tahul/zidane/blob/main/src/durable/keys.ts#L77)

### `parseStepKey`

Function.

Split a key built by [`stepKey`](https://zidane.si/docs/reference/durable.md#stepKey). Throws on anything else.

```ts
function parseStepKey(key: string): StepKeyParts
```

**Parameters**

- `key` (`string`): The key to split.

**Returns** `StepKeyParts`: Its parts, unescaped.

Source: [src/durable/keys.ts:58](https://github.com/Tahul/zidane/blob/main/src/durable/keys.ts#L58)

### `stepKey`

Function.

Build the key of a step. Throws on an empty `run` or `call`, or a
negative or fractional `turn` or `attempt`.

```ts
function stepKey(parts: StepKeyParts): `${string}:${number}:${string}:${number}`
```

**Parameters**

- `parts` (`StepKeyParts`): The key's parts. See [`StepKeyParts`](https://zidane.si/docs/reference/durable.md#StepKeyParts).

**Returns** `` `${string}:${number}:${string}:${number}` ``: The escaped `run:turn:call:attempt` key.

Source: [src/durable/keys.ts:45](https://github.com/Tahul/zidane/blob/main/src/durable/keys.ts#L45)

## Classes

### `RunLeaseHeldError`

Class.

A run could not start: another live process holds its session's lease
(`claimRunLease`). `owner`: that process, when the lease names it.

```ts
class RunLeaseHeldError extends Error
```

**Constructor**

```ts
new RunLeaseHeldError(sessionId: string, owner?: RunOwner)
```

**Parameters**

- `sessionId` (`string`): The session whose lease is held.
- `owner?` (`RunOwner`): The process holding it, when the lease names it.

**Returns** `RunLeaseHeldError`

**Properties**

- `owner?` (`RunOwner`, readonly): The process holding it, when the lease names it.
- `sessionId` (`string`, readonly): The session whose lease is held.

Source: [src/durable/errors.ts:49](https://github.com/Tahul/zidane/blob/main/src/durable/errors.ts#L49)

### `RunSuspendedError`

Class.

`Agent.suspend` stopped the run (a host draining before it exits). A
control error: no step records it as failed, the run keeps its resumable
mark, and `Agent.resume` continues it from its last committed step.

```ts
class RunSuspendedError extends Error
```

**Constructor**

```ts
new RunSuspendedError()
```

**Returns** `RunSuspendedError`

Source: [src/durable/errors.ts:33](https://github.com/Tahul/zidane/blob/main/src/durable/errors.ts#L33)

### `StaleEpochError`

Class.

A write guarded by a lease epoch matched no row: another process claimed
the run since. The run stops at once, with no final save.

```ts
class StaleEpochError extends Error
```

**Constructor**

```ts
new StaleEpochError(sessionId: string, epoch: number)
```

**Parameters**

- `sessionId` (`string`): The session whose run moved to another process.
- `epoch` (`number`): The epoch the refused write was guarded by.

**Returns** `StaleEpochError`

**Properties**

- `epoch` (`number`, readonly): The epoch the refused write was guarded by.
- `sessionId` (`string`, readonly): The session whose run moved to another process.

Source: [src/durable/errors.ts:17](https://github.com/Tahul/zidane/blob/main/src/durable/errors.ts#L17)

## Constants

### `MODEL_CALL`

Constant.

`call` of the model request of a turn.

```ts
const MODEL_CALL = 'model'
```

Source: [src/durable/keys.ts:33](https://github.com/Tahul/zidane/blob/main/src/durable/keys.ts#L33)

### `RUN_TAKEN_OVER_MESSAGE`

Constant.

Shown when a run's lease moved to another process and its writes were refused.

```ts
const RUN_TAKEN_OVER_MESSAGE = 'this run continued in another process'
```

Source: [src/durable/errors.ts:8](https://github.com/Tahul/zidane/blob/main/src/durable/errors.ts#L8)

## Interfaces

### `AwakeableOptions`

Interface.

Options of `RunScope.awakeable`.

```ts
interface AwakeableOptions
```

**Properties**

- `key` (`` `${string}:${number}:${string}:${number}` ``): Step key of the wait. A run resumed after a restart asks again with the
  same key and gets the same awakeable back, with any resolution that
  arrived while no process was running it.
- `timeoutMs?` (`number`): Deadline, stored as an absolute time when the awakeable is created.
  Unset or non-positive: no deadline. Ignored when the key already has an
  awakeable: the deadline stays the stored one.

Source: [src/durable/types.ts:238](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L238)

### `AwakeableRecord`

Interface.

A stored awakeable (the `awakeables` table of the SQLite adapter). `id` is unique; `(sessionId, key)` finds it again on resume.

```ts
interface AwakeableRecord
```

**Properties**

- `deadline?` (`number`): Absolute deadline (epoch ms), when the awakeable has one.
- `id` (`string`): The id a resumer resolves it with.
- `key` (`` `${string}:${number}:${string}:${number}` ``): See `AwakeableOptions.key`.
- `resolved` (`boolean`): A resumer resolved it.
- `sessionId` (`string`): Session of the run that waits.
- `value?` (`JsonValue`): What the resumer sent, once `resolved`.

Source: [src/durable/types.ts:268](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L268)

### `DurableAwakeable`

Interface.

A wait a resumer ends: its id, and the promise that settles with the outcome.

```ts
interface DurableAwakeable<T>
```

**Type parameters**

- `T`

**Properties**

- `id` (`string`): Hand this to the resumer (`resolveAwakeable(id, value)`).
- `promise` (`Promise<AwakeableOutcome<T>>`): Settles when a resumer resolves the awakeable or its deadline passes.
- `settled?` (`{ value: T }`): The resolution, when the key's awakeable was already resolved as it was
  asked for (a resumed run whose answer arrived meanwhile): the caller can
  skip announcing the wait. Unset where the runtime cannot tell (a journal).

Source: [src/durable/types.ts:254](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L254)

### `DurableInspector`

Interface.

Read access to what a runtime stored, for tests and diagnostics.

```ts
interface DurableInspector
```

**Properties**

- `awakeables` (`() => Promise<AwakeableRecord[]>`): Every stored awakeable.
- `partials` (`(runId?: string) => Promise<StreamPartialRecord[]>`): Stream partials, in write order.
- `steps` (`(runId?: string) => Promise<StepRecord[]>`): Step records, of one run or of all. Pruned records are gone.

Source: [src/durable/types.ts:284](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L284)

### `DurableLease`

Interface.

Who runs a session's run, fenced by an epoch. The agent claims the lease
when a run starts (`run` or `resume`) and passes the epoch to
`DurableRuntime.openRun`. Every claim bumps the epoch; every turn,
step and queue write of the holder is guarded by it, so the writes of an
owner that lost the lease (a laptop waking from sleep) are rejected
([`StaleEpochError`](https://zidane.si/docs/reference/durable.md#StaleEpochError)) instead of interleaving with the new owner's.
Absent on runtimes whose platform already guarantees a single writer.

```ts
interface DurableLease
```

**Properties**

- `claim` (`(sessionId: string, options: { onStale?: (error: StaleEpochError) => void; owner?: RunOwner; staleAt: number }) => Promise<LeaseClaim>`): Take the session's run. Succeeds when no live owner holds it: no lease,
  one released, one held by an owner known dead (`isRunOwnerDead`), one
  last renewed at or before `staleAt` by an owner that no longer holds it
  (`isRunOwnerHolding`: a quiet owner on this host that still runs keeps
  it for up to `RUN_OWNER_HOLD_MS`), or one held under this process's own
  owner token. A successful claim fences the session on this
  runtime until `release`: its writes are guarded by the new epoch,
  and `onStale` is told when one is refused (the run stops at once).
- `epoch` (`(sessionId: string) => Promise<number | null>`): Current epoch of the session, `null` when it was never claimed.
- `release` (`(sessionId: string, epoch: number) => Promise<void>`): Give the lease up and lift this runtime's fence. A stale `epoch` leaves the stored lease alone.
- `renew` (`(sessionId: string, epoch: number) => Promise<boolean>`): Keep the lease alive. `false`: `epoch` is no longer the current one.
- `resumable` (`(options: { sessionId?: string; staleAt: number }) => Promise<ResumableRun[]>`): Top-level runs to resume: still marked resumable (`SessionRun.resumable`,
  set while a checkpoint run is in progress), of a session whose lease
  lapsed (`leaseLapsed`: released, held by a dead owner, or not renewed
  since `staleAt` by an owner that no longer holds it), and not
  parked on an awakeable (the run or a child its spawn call waits on).
  Sessions never leased and runs never marked (written before durability
  existed) are never listed: they are healed. A child run resumes
  with its parent's spawn call, so it is not listed on its own.
  `sessionId`: that session's run only.

Source: [src/durable/types.ts:360](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L360)

### `DurableOptions`

Interface.

`AgentOptions.durable` in full: the runtime, and what `run()` does with a
run a process death left unfinished in the session.

```ts
interface DurableOptions
```

**Properties**

- `onInterrupted?` (`'resume' | 'heal'`): `'heal'` (default): `run()` reports the interrupted run's open tool
  calls as interrupted and starts the new run; `resume()` still continues
  the interrupted run when called first. `'resume'`: `run()` first
  continues it (`Agent.resume`) when the lease lists it
  (`DurableLease.resumable`: its process is gone and it waits on no
  unanswered awakeable), then runs the prompt, unless the resumed run was
  aborted or suspended. A run the lease does not list is healed as with
  `'heal'`. A host that asks the user first keeps `'heal'` and calls
  `resume()` on a yes.
- `runtime` (`DurableRuntime`): The runtime every run of the agent goes through.

Source: [src/durable/types.ts:396](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L396)

### `DurableQueueEntry`

Interface.

Minimum shape of a queued prompt; the chat host's `QueuedEntry` fits it.

```ts
interface DurableQueueEntry
```

**Properties**

- `id` (`string`): The entry's id.
- `text` (`string`): The prompt text.

Source: [src/durable/types.ts:294](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L294)

### `DurableQueueStore`

Interface.

The type-ahead queue of a session, kept across a crash. Wraps the
session-metadata copy the chat host already keeps (`zidane.queue`).

```ts
interface DurableQueueStore<E extends DurableQueueEntry = DurableQueueEntry>
```

**Type parameters**

- `E` (`extends DurableQueueEntry`, default `DurableQueueEntry`)

**Properties**

- `read` (`(sessionId: string) => Promise<E[]>`): The stored queue, oldest first; empty when none.
- `write` (`(sessionId: string, entries: readonly E[]) => Promise<void>`): Replace the stored queue. An empty list clears it.

Source: [src/durable/types.ts:305](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L305)

### `DurableResumeOptions`

Interface.

Options of `Agent.resume`.

```ts
interface DurableResumeOptions
```

**Properties**

- `run?` (`Omit<AgentRunOptions, 'prompt' | 'signal' | 'resumeRunId'>`): Per-run options of the resumed run, as its `run()` had them (a spawned
  child's system prompt, depth and parent). They apply over the options
  the run's record kept (`SessionRun.options`); what neither sets is the
  agent's own.
- `runId?` (`string`): Run to resume. Default: the session's last run that did not finish.
- `signal?` (`AbortSignal`): Aborts the resumed run, as `AgentRunOptions.signal` does.

Source: [src/durable/types.ts:414](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L414)

### `DurableRuntime`

Interface.

What the agent loop needs from a durable runtime. See the module docs.

```ts
interface DurableRuntime
```

**Properties**

- `findAwakeable?` (``(sessionId: string, key: `${string}:${number}:${string}:${number}`) => Promise<AwakeableRecord | undefined>``): The stored awakeable of `(sessionId, key)`, for a resumer that knows
  what a run waits on but not the id (a prompt rehydrated from the
  session's turns). `undefined`: none. Absent on runtimes without an
  awakeable table.
- `isControlError` (`(error: unknown) => boolean`): Errors the runtime uses to stop or suspend a run: the loop rethrows them untouched instead of reporting a failed call.
- `lease?` (`DurableLease`, readonly): Who runs each session's run. Absent where the platform guarantees one writer.
- `mode` (`DurableMode`, readonly): How the runtime recovers a run, see [`DurableMode`](https://zidane.si/docs/reference/durable.md#DurableMode).
- `openRun` (`(options: OpenRunOptions) => Promise<RunScope>`): Open a run's scope. Handlers are per scope, never shared with another run.
- `resolveAwakeable` (`(id: string, value: JsonValue) => Promise<boolean>`): Resolve an awakeable, also while no process runs its run (the run gets
  the value when it resumes). Call it from the resumer's side: another
  process or an ingress client, never the run that waits. In `replay`
  mode, resolving from the waiter's own journal shifts every later entry.

  `false`: no awakeable has that id, e.g. a prompt left open by a build
  without awakeables, and the caller falls back to its own handling. Only
  runtimes that keep an awakeable table can tell; the others answer `true`.
- `stores` (`DurableStores`, readonly): Where a run persists its session, tool state, queue and submissions.

Source: [src/durable/types.ts:529](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L529)

### `DurableStores`

Interface.

Everything a run persists, behind one runtime so it commits consistently.

```ts
interface DurableStores
```

**Properties**

- `queue` (`DurableQueueStore`): The session's type-ahead queue.
- `session` (`SessionStore`): The session store the runtime commits turns to.
- `submissions?` (`DurableSubmissionStore`): Absent where the platform dedupes requests itself (an ingress idempotency key).
- `toolState` (`(sessionId: string) => ToolStateStore`): Tool state of one session.

Source: [src/durable/types.ts:325](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L325)

### `DurableSubmissionStore`

Interface.

Client request ids of sends (`requestId`), so a retried send gets the
first one's outcome. Wraps the session store's send-request book
(`claimSendRequest` / `settleSendRequest`).

```ts
interface DurableSubmissionStore
```

**Properties**

- `claim` (`(sessionId: string, requestId: string, fingerprint: string) => Promise<SendRequestClaim>`): Claim `requestId` for a send with this input `fingerprint`. `claimed: false` returns the record of the earlier send with that id.
- `settle` (`(sessionId: string, requestId: string, result: JsonValue) => Promise<void>`): Store the send's result; `null` drops the claim so a retry runs again.

Source: [src/durable/types.ts:317](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L317)

### `MemoryDurableState`

Interface.

What the memory runtime stores: sessions, steps, awakeables, partials, queue, submissions and tool state.

```ts
interface MemoryDurableState
```

**Properties**

- `clone` (`() => MemoryDurableState`): A copy of the state as it is now. Later writes to either copy never reach the other.
- `inspect` (`DurableInspector`, readonly): Read access to the stored steps, partials and awakeables.

Source: [src/durable/memory.ts:89](https://github.com/Tahul/zidane/blob/main/src/durable/memory.ts#L89)

### `OpenRunOptions`

Interface.

Options of `DurableRuntime.openRun`.

```ts
interface OpenRunOptions
```

**Properties**

- `epoch?` (`number`): Lease epoch every write of the scope is guarded by. Default: the epoch
  this runtime's lease claimed for the session (a spawned child runs under
  its parent's claim), or none when the session is not claimed here.
- `handlers` (`StepHandlers`): The run's handlers. They close over its options (model, tools), so they live and die with the scope.
- `runId` (`string`): The run's id, unique within its session.
- `sessionId` (`string`): Session of the run.

Source: [src/durable/types.ts:429](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L429)

### `ResumableRun`

Interface.

A top-level run another process held and stopped renewing, still marked resumable.

```ts
interface ResumableRun
```

**Properties**

- `epoch` (`number`): The session's lease epoch when the run was listed.
- `runId` (`string`): The run to resume.
- `sessionId` (`string`): The run's session.

Source: [src/durable/types.ts:342](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L342)

### `RunScope`

Interface.

One run's view of the runtime: its steps, clock and awakeables. Opened by
the agent when a run starts or resumes, closed when it ends.

```ts
interface RunScope
```

**Properties**

- `all` (`<T extends readonly unknown[]>(values: T) => Promise<{ -readonly [K in string | number | symbol]: Awaited<T[K]> }>`): `Promise.all` over the scope's own promises (durable combinator in `replay` mode).
- `allSettled` (`<T>(values: readonly Promise<T>[]) => Promise<PromiseSettledResult<T>[]>`): `Promise.allSettled` over the scope's own promises: how the loop joins a
  batch of concurrent steps, each settling on its own.
- `awakeable` (`<T = JsonValue>(options: AwakeableOptions) => Promise<DurableAwakeable<T>>`): Park until a resumer resolves the awakeable or its deadline passes. Resolves once the awakeable is stored.
- `close` (`() => Promise<void>`): End the scope: its handlers are dropped, later `step()` calls reject, and its awakeable waits stop (SQLite). Other scopes are untouched. Idempotent.
- `now` (`() => number | Promise<number>`): Wall-clock ms. Journaled in `replay` mode.
- `race` (`<T>(values: readonly Promise<T>[]) => Promise<T>`): `Promise.race` over the scope's own promises.
- `runId` (`string`, readonly): The run's id.
- `sessionId` (`string`, readonly): Session of the run.
- `sleep` (`(ms: number, signal?: AbortSignal) => Promise<void>`): Wait `ms`; a durable timer where the runtime has one. `signal` ends a
  plain timer early (the promise resolves); a durable timer is left to
  the runtime.
- `step` (`<T = JsonValue>(req: StepRequest, live?: StepLive<unknown>) => Promise<StepOutcome<T>>`): Run `req` through `handlers[req.kind]` once, or answer from its record.

  Timing (the crash cases depend on it):

  - Before the handler of an `unsafe` step starts, its `pending` record
    is durable. A `safe` step writes none (it runs again either way, so a
    missing record answers the same), unless `live.markStarted` asks for
    it. In `replay` mode an `unsafe` step journals an intent entry and
    waits for it to be acknowledged; a `safe` step needs none.
  - `step()` settles only once the `done` or `failed` record is durable,
    with the tool state the handler staged.
  - A handler error for which `DurableRuntime.isControlError` holds
    is not recorded: the step stays pending (a suspension or a process
    death, not a failure), and the error propagates untouched.

  In `checkpoint` mode a live step (`replayed: false`) resolves with the
  handler's own value and rejects with its own error; only a replayed step
  gets the forms rebuilt from the record. The runtime logs a result whose
  JSON form loses something (a class instance, a `Date`) and stores that
  form. In `replay` mode a live step gets the recorded form too, so its
  replay takes the same branches.

  What a record found after a restart answers:

  - `done`: `completed`, `replayed: true`, the handler does not run.
  - `failed`: rejects with the error rebuilt from the record.
  - `pending`, `safe`: the handler runs again, under the same key.
  - `pending`, `unsafe`: `interrupted`, the handler does not run. In
    `replay` mode that answer is journaled as the step's value.
  - Another fingerprint than the request's: `interrupted`.
  - No record (the step never started, or a `safe` step never finished): runs as a new step, even `unsafe`.
- `storedPartials?` (`() => Promise<StreamPartialRecord[]>`): Checkpoint runtimes that keep stream partials: this run's partials, in
  write order. `Agent.resume` joins them into an aborted assistant turn.
- `storedSteps?` (`() => Promise<StepRecord[]>`): Checkpoint runtimes: this run's stored step records, in write order.
  A resumed run reads them to tell the calls of a batch already done
  (`tool-batch:resumed`) from those still to settle. Absent in replay mode.
- `storedTurns?` (`() => Promise<number[]>`): Checkpoint runtimes: the loop turns this run's stored step records
  cover, ascending (the `turn` of their keys). Only the unfinished turn
  has records, so `Agent.resume` checks it against the turn it resumes
  at before asking for any key. Absent in replay mode.
- `uuid` (`() => string`): RFC-4122 v4 UUID. Journaled in `replay` mode.

Source: [src/durable/types.ts:448](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L448)

### `StepCompleted`

Interface.

A step that has a value: it ran now, or its `done` record answered.

```ts
interface StepCompleted<T>
```

**Type parameters**

- `T`

**Properties**

- `replayed` (`boolean`): Answered from a record, the handler did not run.
- `status` (`'completed'`): Discriminant of [`StepOutcome`](https://zidane.si/docs/reference/durable.md#StepOutcome).
- `toolState?` (`readonly ToolStateOp[]`): Tool-state ops the step staged, live or from its record. The runtime
  already committed them with the record; the loop applies them to its
  hydrated view and never commits them again.
- `value` (`T`): The handler's result, or the form rebuilt from the record when replayed.

Source: [src/durable/types.ts:136](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L136)

### `StepErrorRecord`

Interface.

A step's error as stored. A replayed failure rejects with an `Error`
rebuilt from it: `name`, `message`, and the other fields as own
properties, so the loop classifies it (retryable, context exceeded,
retry-after) the way it classified the live error.

```ts
interface StepErrorRecord
```

**Properties**

- `code?` (`string`): Provider or system code (`context_length_exceeded`, `ENOENT`).
- `data?` (`JsonValue`): Anything else the loop classifies on (a retry-after, a limit), as JSON.
- `decision?` (`JsonValue`): The loop's verdict on this failure (retry, fall back, give up), stored
  with it in checkpoint mode: the rebuilt error has neither the provider's
  error class nor the stream's progress, so a resumed run takes this
  verdict instead of judging the rebuilt error again.
- `message` (`string`): The error's `message`.
- `name` (`string`): The error's `name`.
- `retryable?` (`boolean`): The error's own retry verdict.
- `status?` (`number`): HTTP status of the response that failed.

Source: [src/durable/types.ts:166](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L166)

### `StepHandlerContext`

Interface.

What the runtime hands a running handler besides the caller's [`StepLive`](https://zidane.si/docs/reference/durable.md#StepLive).

```ts
interface StepHandlerContext extends StepLive
```

**Properties**

- `callbacks?` (`unknown`, from `StepLive`): Callbacks the handler drives (a model step's stream callbacks).
- `markStarted?` (`boolean`, from `StepLive`): Write the `pending` record of a `safe` step too, so a resumed run sees
  that the step started: its call passed an approval that must not be
  asked again. An `unsafe` step always writes it.
- `onProgress?` (`(progress: StepProgress) => void`, from `StepLive`): Receives the output the handler streams. The runtime may keep it as stream partials.
- `signal?` (`AbortSignal`, from `StepLive`): Aborts the handler's work (the run's abort, a cancelled call).
- `stageToolState` (`(ops: readonly ToolStateOp[]) => void`): Stage tool-state ops to commit with this step's `done` record, in call
  order. A failed step commits none of them. A step answered from its
  record never runs its handler, so this is how its tool state survives:
  the ops come back in [`StepOutcome`](https://zidane.si/docs/reference/durable.md#StepOutcome).

Source: [src/durable/types.ts:108](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L108)

### `StepInterrupted`

Interface.

An `unsafe` step that started before a restart and never finished, or a step whose record has another fingerprint.

```ts
interface StepInterrupted
```

**Properties**

- `status` (`'interrupted'`): Discriminant of [`StepOutcome`](https://zidane.si/docs/reference/durable.md#StepOutcome).

Source: [src/durable/types.ts:152](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L152)

### `StepKeyParts`

Interface.

The four parts of a [`StepKey`](https://zidane.si/docs/reference/durable.md#StepKey), unescaped.

```ts
interface StepKeyParts
```

**Properties**

- `attempt` (`number`): The loop's own retry index for the step.
- `call` (`string`): What the step is within the turn: [`MODEL_CALL`](https://zidane.si/docs/reference/durable.md#MODEL_CALL), a tool call id, a nested call or a decision name.
- `run` (`string`): The run id, unique within its session.
- `turn` (`number`): The loop's turn index within the run.

Source: [src/durable/keys.ts:21](https://github.com/Tahul/zidane/blob/main/src/durable/keys.ts#L21)

### `StepLive`

Interface.

The live half of a step. The object itself is never stored or replayed; a
replayed step gets a fresh one from the resumed loop. What a handler
reports through `onProgress` may be kept by the runtime as stream
partials (see [`StreamPartialRecord`](https://zidane.si/docs/reference/durable.md#StreamPartialRecord)).

```ts
interface StepLive<C = unknown>
```

**Type parameters**

- `C` (default `unknown`)

**Properties**

- `callbacks?` (`C`): Callbacks the handler drives (a model step's stream callbacks).
- `markStarted?` (`boolean`): Write the `pending` record of a `safe` step too, so a resumed run sees
  that the step started: its call passed an approval that must not be
  asked again. An `unsafe` step always writes it.
- `onProgress?` (`(progress: StepProgress) => void`): Receives the output the handler streams. The runtime may keep it as stream partials.
- `signal?` (`AbortSignal`): Aborts the handler's work (the run's abort, a cancelled call).

Source: [src/durable/types.ts:92](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L92)

### `StepRecord`

Interface.

One stored step (the `steps` table of the SQLite adapter). Keyed by
`(sessionId, key)`: run ids are only unique within their session.

```ts
interface StepRecord
```

**Properties**

- `error?` (`StepErrorRecord`): What the handler threw, once `failed`.
- `fingerprint?` (`string`): See `StepRequest.fingerprint`.
- `key` (`` `${string}:${number}:${string}:${number}` ``): See `StepRequest.key`.
- `kind` (`StepKind`): See `StepRequest.kind`.
- `replay` (`StepReplayPolicy`): See `StepRequest.replay`.
- `result?` (`JsonValue`): The handler's result in its JSON form, once `done`.
- `runId` (`string`): Run the step belongs to.
- `sessionId` (`string`): Session the step belongs to.
- `status` (`StepStatus`): Where the step is in its lifecycle.
- `toolState?` (`ToolStateOp[]`): Tool-state ops committed with the `done` record.

Source: [src/durable/types.ts:192](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L192)

### `StepRequest`

Interface.

What a runtime keeps of a step besides its outcome: its key, policy and a description. Not enough to run it again.

```ts
interface StepRequest<P extends JsonValue = JsonValue>
```

**Type parameters**

- `P` (`extends JsonValue`, default `JsonValue`)

**Properties**

- `fingerprint?` (`string`): What the step does beyond its key: a codemode inner call's tool name and
  input hash, since those calls are keyed by their order in the script. A
  record whose fingerprint differs means the code took another path since
  the record was written: the step answers `interrupted` and the handler
  does not run. Unset: not checked.
- `key` (`` `${string}:${number}:${string}:${number}` ``): `run:turn:call:attempt`, see [`StepKey`](https://zidane.si/docs/reference/durable.md#StepKey). Stable across a restart.
- `kind` (`StepKind`): Which of the run's handlers runs it.
- `payload` (`P`): A description of the step (a model name, a tool name and call id), stored with it. The work itself is the live closure in [`StepLive`](https://zidane.si/docs/reference/durable.md#StepLive).
- `replay` (`StepReplayPolicy`): What a restart does with the step when it started and never finished.

Source: [src/durable/types.ts:62](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L62)

### `StreamPartialRecord`

Interface.

One stored slice of model output streamed by a step that has not finished (`stream_partials`), keyed by `(sessionId, stepKey, seq)`.

```ts
interface StreamPartialRecord
```

**Properties**

- `runId` (`string`): Run of the step.
- `seq` (`number`): Write order within the step, from 0.
- `sessionId` (`string`): Session of the step.
- `stepKey` (`` `${string}:${number}:${string}:${number}` ``): Key of the model step that streamed it.
- `text` (`string`): Text streamed since the previous slice, never the whole answer so far.
- `thinking?` (`string`): Thinking streamed since the previous slice.

Source: [src/durable/types.ts:216](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L216)

## Types

### `AwakeableOutcome`

Type.

Settlement of an awakeable: the deadline passed, or a resumer resolved it
with `value` (which may be `null`).

```ts
type AwakeableOutcome<T> = { timedOut: true } | { timedOut: false; value: T }
```

**Type parameters**

- `T`

Source: [src/durable/types.ts:235](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L235)

### `DurableBody`

Type.

See `DurableToolDef.durableBody`.

```ts
type DurableBody = 'composite' | 'promise'
```

Source: [src/tools/types.ts:418](https://github.com/Tahul/zidane/blob/main/src/tools/types.ts#L418)

### `DurableMode`

Type.

How a runtime survives a restart. See the module docs.

```ts
type DurableMode = 'checkpoint' | 'replay'
```

Source: [src/durable/types.ts:42](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L42)

### `LeaseClaim`

Type.

Answer of `DurableLease.claim`: the new epoch, or who still holds the lease. `previous`: the session's status as the claim found it.

```ts
type LeaseClaim =
  | { claimed: true; epoch: number; previous?: SessionData['status'] }
  | { claimed: false; owner?: RunOwner; previous?: SessionData['status'] }
```

Source: [src/durable/types.ts:337](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L337)

### `MemoryDurableInspector`

Type.

Read access to the stored state, for tests and the conformance suite.

```ts
type MemoryDurableInspector = DurableInspector
```

Source: [src/durable/memory.ts:86](https://github.com/Tahul/zidane/blob/main/src/durable/memory.ts#L86)

### `StepHandler`

Type.

Runs one step of a kind: the loop's handlers run the closure handed in
`StepLive.callbacks`. A replay gets the result's JSON form (it is stored
or journaled as JSON); in checkpoint mode a live call gets the value
itself, and a value the JSON form loses is logged.

```ts
type StepHandler<P extends JsonValue = JsonValue, R = JsonValue> = (payload: P, context: StepHandlerContext) => Promise<R>
```

**Type parameters**

- `P` (`extends JsonValue`, default `JsonValue`)
- `R` (default `JsonValue`)

Source: [src/durable/types.ts:124](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L124)

### `StepHandlers`

Type.

A run's handlers by kind.

```ts
type StepHandlers = Readonly<Partial<Record<StepKind, StepHandler<any, unknown>>>>
```

Source: [src/durable/types.ts:127](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L127)

### `StepKey`

Type.

A step key as built by [`stepKey`](https://zidane.si/docs/reference/durable.md#stepKey).

```ts
type StepKey = `${string}:${number}:${string}:${number}`
```

Source: [src/durable/keys.ts:18](https://github.com/Tahul/zidane/blob/main/src/durable/keys.ts#L18)

### `StepKind`

Type.

Handler family of a step (the loop's are `LOOP_STEP_KINDS`). A run passes
one handler per kind to `DurableRuntime.openRun`. The open string
lets an adapter add its own.

```ts
type StepKind =
  | 'model'
  | 'tool'
  | 'gate'
  | 'decision'
  | 'compact'
  | 'reconcile'
  | (string & {})
```

Source: [src/durable/types.ts:59](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L59)

### `StepOutcome`

Type.

Result of `RunScope.step`. A step whose handler failed rejects with
that error instead (rebuilt from its record when replayed).

```ts
type StepOutcome<T> = StepCompleted<T> | StepInterrupted
```

**Type parameters**

- `T`

Source: [src/durable/types.ts:133](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L133)

### `StepProgress`

Type.

Incremental output a handler reports while it runs. Streamed model text is what an adapter keeps as a partial.

```ts
type StepProgress =
  | { delta: string; type: 'text' }
  | { delta: string; type: 'thinking' }
```

Source: [src/durable/types.ts:82](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L82)

### `StepReplayPolicy`

Type.

What a resumed run does with a step that started but never finished.

- `safe`: run it again (reads, pure computations, model calls).
- `unsafe`: never run it again; the loop reports it as interrupted
  (`TOOL_USE_INTERRUPTED_MARKER`), saying the effect may or may not have
  happened.

```ts
type StepReplayPolicy = 'safe' | 'unsafe'
```

Source: [src/durable/types.ts:52](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L52)

### `StepStatus`

Type.

Lifecycle of a step record: written `pending` before the handler runs (an `unsafe` step, or one marked started), then `done` or `failed`.

```ts
type StepStatus = 'pending' | 'done' | 'failed'
```

Source: [src/durable/types.ts:158](https://github.com/Tahul/zidane/blob/main/src/durable/types.ts#L158)

### `ToolPreflight`

Type.

What a `DurableToolDef.preflight` decided: run the body with `input`, or answer the call with `output`.

```ts
type ToolPreflight =
  | { input: Record<string, unknown> }
  | { output: string | ToolResultContent[] }
```

Source: [src/tools/types.ts:415](https://github.com/Tahul/zidane/blob/main/src/tools/types.ts#L415)
