Skip to content

zidane/restate

The Restate runtime for the agent loop, so model calls, tool calls and loop decisions are journaled.

import { … } from 'zidane/restate'src/restate/index.ts

Use this entry point for a server-side agent that must survive process restarts mid-run. restateRuntime(ctx) journals (records) each model request, tool call and loop decision as one step, so a replay reuses the results, and its default session store keeps the session in virtual-object state. Pass the provider and tools unwrapped. A tool call that a crash cut off is reported to the model as interrupted instead of run twice, unless the tool sets replay: 'safe'. Skip it for interactive sessions and for requests that finish inside one HTTP call. Crash recovery compares it with the SQLite runtime.

The second argument is a RestateRuntimeOptions. Its promises field takes a RestateCombinators, which the SDK's RestatePromise satisfies. With it, concurrent steps start together and awakeables can have a deadline. Without it, steps run one at a time.

TypeScript
import type { ObjectContext } from '@restatedev/restate-sdk'
import { RestatePromise } from '@restatedev/restate-sdk'
import { createAgent } from 'zidane'
import { anthropic } from 'zidane/providers/anthropic'
import { restateRuntime } from 'zidane/restate'
import { createSession, loadSession } from 'zidane/session'

declare const ctx: ObjectContext

const durable = restateRuntime(ctx, { promises: RestatePromise, idSeed: ctx.key })
const store = durable.stores.session
const session = await loadSession(store, ctx.key) ?? await createSession({ id: ctx.key, store })
const agent = createAgent({
  provider: anthropic(),
  durable,
  session,
  behavior: { cache: true, compactStrategy: 'tail', maxCostUsd: 5 },
})
const stats = await agent.run({ prompt: 'Triage the open alerts.' })
console.log(stats.turns)

Functions#

awakeableWithTimeoutFunction#

Mint an awakeable that resolves { timedOut: false, value } with the resumer's payload, or { timedOut: true } when timeoutMs elapses first. The id is journal-stable (send it out-of-band as usual); the timeout is a durable ctx.sleep, so a parked invocation suspends instead of holding a worker.

Text
// waitBackground for a durable host, in three lines:
const { id, promise } = awakeableWithTimeout<TaskExitInfo>(ctx, { timeoutMs, promises: RestatePromise })
await registerExitResumer(taskId, id) // runner → ctx.resolveAwakeable(id, info)
const outcome = await promise
return outcome.timedOut ? null : outcome.value
TypeScript
function awakeableWithTimeout<T, TPromise extends Promise<unknown> = Promise<unknown>>(
  ctx: RestateContextLike,
  options?: AwakeableWithTimeoutOptions<TPromise>,
): RestateAwakeable<AwakeableOutcome<T>>
Type parameters
NameTypeDefaultDescription
T
TPromiseextends Promise<unknown>Promise<unknown>
Parameters
NameTypeDefaultDescription
ctxRestateContextLike

Restate context that mints the awakeable and the timer.

options?AwakeableWithTimeoutOptions<TPromise>{}

Deadline and race combinator. See AwakeableWithTimeoutOptions.

src/restate/awakeable.ts:88

createReplayTrackerFunction#

Create a per-invocation replay tracker. Pass it to restateRuntime (and any restateTool / restateWaitBackground) via their replayTracker option; consume it via isReplaying() / onLive() / replayAwareAbort.

TypeScript
function createReplayTracker(options?: ReplayTrackerOptions): ReplayTracker
Parameters
NameTypeDefaultDescription
options?ReplayTrackerOptions{}

Hooks and the resuming flag. See ReplayTrackerOptions.

src/restate/replay.ts:148

deterministicUuidFunction#

RFC-4122-v4-shaped UUID derived from a seed string — pure function, no RNG. Version/variant bits are set so consumers (and DB uuid columns) treat it as a regular v4 UUID.

TypeScript
function deterministicUuid(seed: string): string
Parameters
NameTypeDescription
seedstring

String the UUID is derived from. The same seed gives the same UUID.

string

src/restate/clock.ts:23

isRestateCancellationFunction#

The SDK's CancelledError: the invocation was cancelled (Admin API, a caller's ctx.cancel, or a cancelled parent). Restate journals the cancel signal, so a replay surfaces it at the same await.

TypeScript
function isRestateCancellation(error: unknown): boolean
Parameters
NameTypeDescription
errorunknown

Error caught around a durable await.

boolean

src/restate/errors.ts:99

isRestateControlErrorFunction#

Restate control-flow errors must escape the agent loop. If they are turned into model-visible tool results, the runtime can retry/suspend incorrectly. restateRuntime answers isControlError with it.

Kept structural so zidane/restate does not need to import the SDK at runtime just to recognize the common error shapes.

TypeScript
function isRestateControlError(error: unknown): boolean
Parameters
NameTypeDescription
errorunknown

Error caught around a tool or provider call.

boolean

true for Restate control-flow errors that must propagate. Platform DOMExceptions are never control errors.

src/restate/errors.ts:14

raceWithTimeoutFunction#

Race an already-minted awakeable promise against a durable ctx.sleep(timeoutMs). Split out from awakeableWithTimeout so a caller that must run journaled steps between minting and parking (see restateWaitBackground) can arm the race at park time: a RestatePromise.race starts awaiting the SDK's single-waiter progress channel as soon as it is built, so building it early and then awaiting a ctx.run is two concurrent waiters — awaitNext already pending.

Without a positive timeoutMs no timer is armed and the promise only gets tagged. With one, options.promises is required.

TypeScript
function raceWithTimeout<T, TPromise extends Promise<unknown> = Promise<unknown>>(
  ctx: RestateContextLike,
  promise: Promise<T>,
  options?: AwakeableWithTimeoutOptions<TPromise>,
): Promise<AwakeableOutcome<T>>
Type parameters
NameTypeDefaultDescription
T
TPromiseextends Promise<unknown>Promise<unknown>
Parameters
NameTypeDefaultDescription
ctxRestateContextLike

Restate context that provides the timer.

promisePromise<T>

Awakeable promise to race.

options?AwakeableWithTimeoutOptions<TPromise>{}

Deadline and race combinator. See AwakeableWithTimeoutOptions.

Promise<AwakeableOutcome<T>>

src/restate/awakeable.ts:115

replayAwareAbortFunction#

Wrap an abort function so it defers during journal replay.

Live invocation → abort() runs immediately, exactly like calling agent.abort() directly. Replaying invocation → the abort is queued and applied at the first live boundary (the start of the first step that runs live: a model request, a tool body or a decision), where the resulting AgentAbortedError + host catch-arm journaling append to the journal instead of forking it mid-replay. Multiple calls during replay collapse into one queued abort.

TypeScript
function replayAwareAbort(tracker: ReplayTracker, abort: () => void): () => void
Parameters
NameTypeDescription
trackerReplayTracker

Tracker that reports whether the invocation is replaying.

abort() => void

Function that aborts the run, for example agent.abort().

() => void

src/restate/replay.ts:206

restateAwakeableToolFunction#

Build a ToolDef that parks on a Restate awakeable until an external resumer resolves it. See the module doc for the replay contract.

Do NOT additionally wrap the returned tool in restateTool — the journal discipline is already internal, and an outer ctx.run would illegally nest the suspension point inside a journaled closure.

TypeScript
function restateAwakeableTool<T = unknown>(
  options: RestateAwakeableToolOptions<T>,
): ToolDef
Type parameters
NameDefaultDescription
Tunknown
Parameters
NameTypeDescription
optionsRestateAwakeableToolOptions<T>

Tool spec, Restate context and the notify callback.

src/restate/awakeable-tool.ts:130

restateControlErrorFunction#

The Restate control error behind error: itself, or the first one on its .cause chain. On restateRuntime the agent loop already rethrows control errors unwrapped; this covers code outside the loop that wraps a failure in an error of its own (cause = the original). Rethrow the original, or Restate treats it as an ordinary, retryable failure.

TypeScript
function restateControlError(error: unknown): Error | undefined
Parameters
NameTypeDescription
errorunknown

Error that escaped the agent run.

Error | undefined

src/restate/errors.ts:80

restateRuntimeFunction#

The durable runtime of one Restate invocation. Build it inside the handler, once per invocation, and hand it to the agent:

Text
const durable = restateRuntime(ctx, { promises: RestatePromise, idSeed: ctx.key })
const store = durable.stores.session
const session = await loadSession(store, ctx.key) ?? await createSession({ id: ctx.key, store })
const agent = createAgent({ provider, tools, durable, session })
TypeScript
function restateRuntime(
  ctx: RestateContextLike,
  options?: RestateRuntimeOptions,
): DurableRuntime
Parameters
NameTypeDefaultDescription
ctxRestateContextLike

The handler's Restate context. A virtual-object context also backs the default session and tool-state stores.

options?RestateRuntimeOptions{}

Combinators, id seed, clock coalescing and stores. See RestateRuntimeOptions.

src/restate/runtime.ts:191

restateSessionStoreFunction#

Construct a SessionStore backed by the bound virtual-object's K/V state. The store is single-tenant — every method ignores the sessionId argument because the virtual object is already keyed by ctx.key. Calling appendTurns('other-id', …) writes to the CURRENT object's state, not the one named in the argument. Bind one virtual-object key per session and the contract holds.

TypeScript
function restateSessionStore(
  ctx: RestateObjectContextLike,
  options?: RestateSessionStoreOptions,
): SessionStore

Construct a SessionStore backed by the bound virtual-object's K/V state. The store is single-tenant — every method ignores the sessionId argument because the virtual object is already keyed by ctx.key. Calling appendTurns('other-id', …) writes to the CURRENT object's state, not the one named in the argument. Bind one virtual-object key per session and the contract holds.

Parameters
NameTypeDescription
ctxRestateObjectContextLike

Virtual-object context whose K/V state holds the session.

options?RestateSessionStoreOptions

Clock override and read-only mode. See RestateSessionStoreOptions.

TypeScript
function restateSessionStore(
  ctx: Omit<RestateObjectContextLike, 'set' | 'clear'>,
  options: RestateSessionStoreOptions & { readOnly: true },
): SessionStore

Construct a SessionStore backed by the bound virtual-object's K/V state. The store is single-tenant — every method ignores the sessionId argument because the virtual object is already keyed by ctx.key. Calling appendTurns('other-id', …) writes to the CURRENT object's state, not the one named in the argument. Bind one virtual-object key per session and the contract holds.

Parameters
NameTypeDescription
ctxOmit<RestateObjectContextLike, 'set' | 'clear'>

Virtual-object context whose K/V state holds the session.

optionsRestateSessionStoreOptions & { readOnly: true }

Clock override and read-only mode. See RestateSessionStoreOptions.

Example
import type { RestateObjectContextLike } from 'zidane/restate'
import { createSession, loadSession } from 'zidane/session'
import { restateSessionStore } from 'zidane/restate'

declare const ctx: RestateObjectContextLike // the virtual object handler context

const store = restateSessionStore(ctx)
// The durable clock keeps the stale-'running' check replay-safe.
const loaded = await loadSession(store, ctx.key, { clock: { now: () => ctx.date.now() } })
// Exclusive handlers only (the key's sole writer): close tool calls a
// crashed attempt left open.
await loaded?.healInterruptedToolCalls()
const session = loaded ?? await createSession({ id: ctx.key, store })

src/restate/session.ts:139

restateSpawnToolFunction#

Creates a spawn tool whose children run as separate Restate invocations. dispatch starts each child and the run joins the results with the runtime's own combinator.

TypeScript
function restateSpawnTool(options: RestateSpawnToolOptions): ToolDef
Parameters
NameTypeDescription
optionsRestateSpawnToolOptions

Dispatch function and persistence and event settings. See RestateSpawnToolOptions.

Example
import type { ChildRunRequest, ChildRunResult } from 'zidane/restate'
import { restateSpawnTool } from 'zidane/restate'

// Start the child invocation, for example with `ctx.serviceClient(childService).runChild(req)`.
declare function startChild(req: ChildRunRequest): Promise<ChildRunResult>

const spawn = restateSpawnTool({ dispatch: req => startChild(req) })

src/restate/spawn.ts:299

restateToolFunction#

Wrap a single ToolDef so its execute runs inside ctx.run. The tool's spec and isConcurrencySafe pass through unchanged.

TypeScript
function restateTool<Token = unknown, Resumed = unknown>(
  inner: ToolDef,
  ctx: RestateContextLike,
  options?: RestateToolOptions<Token, Resumed>,
): ToolDef
Type parameters
NameDefaultDescription
Tokenunknown
Resumedunknown
Parameters
NameTypeDefaultDescription
innerToolDef

Tool to wrap.

ctxRestateContextLike

Restate context that journals each call.

options?RestateToolOptions<Token, Resumed>{}

Retry, naming and durable-start settings. See RestateToolOptions.

src/restate/tool.ts:284

restateToolStateStoreFunction#

Build a ToolStateStore over the bound virtual object's state.

restateRuntime(ctx) builds one for its sessions (durable.stores.toolState), which the agent uses by default; build your own to pick another key:

Text
const agent = createAgent({
  provider,
  durable,
  session,
  toolState: restateToolStateStore(ctx, { key: 'my_tool_state' }),
})

Single-writer like the session store: the state belongs to the object key, so bind one key per conversation and one agent per invocation.

Build it INSIDE the handler. The returned store closes over this ctx, so an agent constructed once at module scope and reused across invocations would commit through a context that is already finished, and would never re-hydrate (the controller memoizes the load for the life of the agent). Same rule as restateSessionStore / restateRuntime, but easier to get wrong here, because toolState looks like agent-lifetime configuration rather than a per-invocation binding.

The map is a schema you own: one JSON object, no versioning, no migration. A value written by an earlier deploy is still there after you change its shape, so either read tolerantly or move to a fresh key.

Enabling this adds a ctx.get at run start, which changes the journal shape for NEW invocations. Existing in-flight invocations replay against the old shape — drain them (or accept the failed attempts) before rolling it out.

TypeScript
function restateToolStateStore(
  ctx: RestateObjectContextLike,
  options?: RestateToolStateStoreOptions,
): ToolStateStore
Parameters
NameTypeDefaultDescription
ctxRestateObjectContextLike

Virtual-object context whose K/V state holds the tool state.

options?RestateToolStateStoreOptions{}

State key and value size limit. See RestateToolStateStoreOptions.

src/restate/tool-state.ts:95

restateWaitBackgroundFunction#

Build a durable ExecutionContext.waitBackground — see the module doc for the ordering contract. The returned function is the seam itself: (handle, taskId, options?) => Promise<TaskExitInfo | null>.

TypeScript
function restateWaitBackground(
  options: RestateWaitBackgroundOptions,
): (handle: ExecutionHandle, taskId: string, opts?: { signal?: AbortSignal; timeoutMs?: number }) => Promise<TaskExitInfo | null>
Parameters
NameTypeDescription
optionsRestateWaitBackgroundOptions

Context, task registry callbacks and timeout settings. See RestateWaitBackgroundOptions.

(handle: ExecutionHandle, taskId: string, opts?: { signal?: AbortSignal; timeoutMs?: number }) => Promise<TaskExitInfo | null>

src/restate/wait-background.ts:133

Constants#

DEFAULT_TOOL_STATE_KEYConstant#

Default virtual-object state key holding the tool-state map.

TypeScript
const DEFAULT_TOOL_STATE_KEY = 'zidane_tool_state'

src/restate/tool-state.ts:41

Interfaces#

AwakeableToolCombinatorsInterface#

The SDK RestatePromise statics the tool uses. Method syntax on purpose: it keeps the SDK's generic all<const T extends …> signatures assignable, so promises: RestatePromise typechecks with an explicit <T>.

TypeScript
interface AwakeableToolCombinators
AwakeableToolCombinators properties
NameTypeDescription
all(values: readonly Promise<unknown>[]) => Promise<unknown>

Resolves with every value once all have settled.

any?(values: readonly Promise<unknown>[]) => Promise<unknown>

First fulfilled value; rejects only when every input rejects.

race(values: readonly Promise<unknown>[]) => Promise<unknown>

Resolves with the first of values to settle.

src/restate/awakeable-tool.ts:99

AwakeableWithTimeoutOptionsInterface#

Options for awakeableWithTimeout and raceWithTimeout.

TypeScript
interface AwakeableWithTimeoutOptions<TPromise extends Promise<unknown> = Promise<unknown>>
AwakeableWithTimeoutOptions type parameters
NameTypeDefaultDescription
TPromiseextends Promise<unknown>Promise<unknown>
AwakeableWithTimeoutOptions properties
NameTypeDescription
promises?RestatePromiseRaceLike<TPromise>

Durable race combinator — pass RestatePromise from the SDK. Required whenever timeoutMs is positive: the helpers throw instead of falling back to native Promise.race.

timeoutMs?number

Durable deadline in milliseconds. Unset / non-positive = no timeout (the returned awakeable is the plain ctx.awakeable() passthrough).

src/restate/awakeable.ts:37

ChildRunRequestInterface#

What the parent hands a child invocation.

TypeScript
interface ChildRunRequest
ChildRunRequest properties
NameTypeDescription
depthnumber

Subagent depth of the CHILD (parent depth + 1). The handler is responsible for refusing runaway recursion — this tool always dispatches, because a short-circuit would have to return a non-durable promise and the durable fleet rejects those.

labelstring

Session-scoped label the parent reserved (child-1, child-2, …).

model?string

Model override requested by the model, if any.

parentCallId?string

Id of the parent tool call that spawned the child.

parentRunId?string

Identity of the work that spawned this child. Present when the parent has them; forward these to whatever sink the child publishes live events to so a UI can attribute and group them (the parent's own child:* events carry the same ids).

sessionId?string

Id of the parent session.

subagentType?string

Named subagent type requested by the model, if any.

taskstring

The child's prompt.

src/restate/spawn.ts:78

ChildRunResultInterface#

What a child invocation returns.

TypeScript
interface ChildRunResult
ChildRunResult properties
NameTypeDescription
children?readonly MergedChild[]

Descendants this child already merged — see MergedChild. The parent merges them recursively, so a nested fan-out lands in the session with the right depths and emits child:* events at every level.

endedAt?number

End time on the child clock, as epoch milliseconds. See startedAt.

error?string

Failure detail when status is 'error'.

startedAt?number

When the child started / finished, measured on the CHILD's clock (e.g. await ctx.date.now() around its run).

Strongly recommended for durable hosts. These land in the merged SessionRun, which the parent persists through a journaled state write, so they must be replay-stable. Values measured inside the child's own invocation are: they arrive in the journaled call result. Omit them and the parent falls back to the child's first / last turn timestamps, then to its own run start.

statsAgentStats

Cumulative stats of the child run, including its own descendants.

status'error' | 'completed' | 'aborted' | 'timeout'

How the child ended.

textstring

The child's final assistant text.

turnsSessionTurn[]

The child's turns, in order. Merged into the parent's session under a SessionRun for this child, so the persisted tree matches what createSpawnTool({ persist: true }) produces in-process.

src/restate/spawn.ts:140

InFlightChildInterface#

A child that was dispatched and has not settled yet.

TypeScript
interface InFlightChild
InFlightChild properties
NameTypeDescription
depthnumber

Subagent depth of the child.

labelstring

Session-scoped label, such as child-1.

taskstring

Task the child was given.

src/restate/spawn.ts:255

MergedChildInterface#

A descendant a child already merged, handed up so the top-level parent can rebuild the whole subtree.

Why it exists: a child dispatched to a service runs sessionless, so it has nowhere to write ITS children's turns. Without passing them up, a depth-2 fan-out loses the grandchildren entirely — the parent sees the child's spawn tool calls and nothing of the work they did. Collect these from RestateSpawnToolOptions.onChildMerged and return them as ChildRunResult.children.

TypeScript
interface MergedChild
MergedChild properties
NameTypeDescription
children?readonly MergedChild[]

Its own merged descendants, recursively.

depthnumber

Depth relative to the run that merged it (1 for its direct children).

endedAt?number

End time on the child clock, as epoch milliseconds.

labelstring

Label this level assigned. The merging parent re-labels from its own session counter.

startedAt?number

Start time on the child clock, as epoch milliseconds.

statsAgentStats

Cumulative stats of the child run.

status'error' | 'completed' | 'aborted' | 'timeout'

How the child ended.

taskstring

Task the child was given.

turnsSessionTurn[]

The child turns, in order.

src/restate/spawn.ts:118

ReplayDoneHooksInterface#

Minimal structural slice of the agent's Hookable for replay:done.

TypeScript
interface ReplayDoneHooks
ReplayDoneHooks properties
NameTypeDescription
callHook(name: 'replay:done', ctx: Record<string, never>) => unknown

Fires the replay:done hook.

src/restate/replay.ts:71

ReplayTrackerInterface#

Tells whether an invocation is still replaying its journal and notifies when it goes live.

TypeScript
interface ReplayTracker
ReplayTracker properties
NameTypeDescription
isReplaying() => boolean

true until the first live (non-journaled) execution of a step (model request, tool body, decision). See the module doc for the fresh- invocation caveat. Use this for journal-safety decisions (deferred abort) where the conservative answer is the correct one.

isResuming() => boolean

true only while ACTIVELY replaying a resumed journal — i.e. the invocation was constructed with resuming: true AND hasn't gone live yet. Always false on a fresh invocation (resuming: false).

This is the probe for live-streaming consumers: gate emission on !isResuming() to suppress re-emitted deltas during a resume replay while still emitting the opening output of a fresh run. (Contrast isReplaying, which is conservatively true at the start of a fresh run too.)

markLive() => void

Mark the invocation live. Called by the runtime (and restateTool / restateWaitBackground) from inside their journaled closures: a closure only executes when the journal cursor is past it. Idempotent; only the first call transitions.

onLive(cb: () => void) => () => void

Register a callback for the replay→live transition. Fires once. When the tracker is already live, the callback runs synchronously before onLive returns. Returns an unregister function (no-op after firing).

src/restate/replay.ts:106

ReplayTrackerOptionsInterface#

Options for createReplayTracker.

TypeScript
interface ReplayTrackerOptions
ReplayTrackerOptions properties
NameTypeDescription
hooks?ReplayDoneHooks

Agent hooks to notify at the replay→live transition. When set, the tracker fires replay:done exactly once, right after the onLive callbacks. Rejections are swallowed (surfaced under ZIDANE_DEBUG) — a misbehaving listener must not break the live execution that triggered the transition.

resuming?boolean

Whether THIS invocation is resuming a prior journal (a crash-recovery / resume replay) rather than running fresh. The host supplies it — it's the one bit the tracker can't infer on its own (before the first ctx.run settles, "fresh, not yet live" and "replaying a resumed journal" look identical from inside the runtime). Determine it from your own state: e.g. the bound object already has persisted session turns, or the SDK reports a non-first attempt.

Powers ReplayTracker.isResuming — the probe streaming consumers should gate on (vs ReplayTracker.isReplaying, which stays conservative for the abort/journal-safety use case). On a fresh invocation (resuming: false, the default) isResuming() is false from the very start, so a streamer emits the opening deltas / start-step instead of suppressing them until the first journaled call settles.

src/restate/replay.ts:77

RestateAwakeableInterface#

Awakeable handle returned by RestateContextLike.awakeable.

The SDK's full shape returns a RestatePromise<T>; we narrow to the Promise<T> it extends because the adapter only awaits the result (and a RestatePromise<T> is structurally assignable to Promise<T>).

TypeScript
interface RestateAwakeable<T>
RestateAwakeable type parameters
NameDescription
T
RestateAwakeable properties
NameTypeDescription
idstring

Journal-stable id. Send it to whatever resolves the awakeable.

promisePromise<T>

Settles when the awakeable is resolved or rejected.

src/restate/types.ts:42

RestateAwakeableToolOptionsInterface#

Options for restateAwakeableTool.

TypeScript
interface RestateAwakeableToolOptions<T = unknown>
RestateAwakeableToolOptions type parameters
NameDefaultDescription
Tunknown
RestateAwakeableToolOptions properties
NameTypeDescription
ctxRestateContextLike

The Restate context the awakeable + journal entries bind to.

descriptionstring

Model-facing tool description.

inputSchemaRecord<string, unknown>

JSON schema for the tool input.

isConcurrencySafe?boolean

Concurrency-safety flag passed through to the ToolDef. Defaults to false — a parked wait holding a scheduler slot should barrier.

namestring

Canonical tool name (what the model calls).

notify(info: { awakeableId: string; input: Record<string, unknown>; toolCtx: ToolContext }) => void | Promise<void>

Send the awakeable id (plus the call's input) out-of-band so a resumer can later call ctx.resolveAwakeable(awakeableId, value). Runs inside ctx.run — fires exactly once across replays.

promises?AwakeableToolCombinators

Durable combinators — pass RestatePromise from the SDK. Needed for timeoutMs (race) and for joining durable fleets (all).

runOptions?RestateRunOptions

ctx.run options for the notify entry. Defaults to { maxRetryAttempts: 1 }, matching restateTool's rationale.

timeoutMs?number

Durable park deadline in milliseconds (a journaled ctx.sleep raced against the awakeable). On timeout the call fails with a tool error. Requires promises. Unset / non-positive = park until resolved.

toResult?(value: T, input: Record<string, unknown>) => string | ToolResultContent[]

Map the resolved awakeable payload to the tool result. Default: strings pass through, everything else is JSON-stringified.

src/restate/awakeable-tool.ts:46

RestateCombinatorsInterface#

The SDK RestatePromise statics the runtime uses. Method syntax on purpose: it keeps the SDK's generic signatures assignable, so promises: RestatePromise typechecks.

TypeScript
interface RestateCombinators
RestateCombinators properties
NameTypeDescription
all(values: readonly Promise<unknown>[]) => Promise<unknown>

Resolves with every value once all have settled.

allSettled?(values: readonly Promise<unknown>[]) => Promise<unknown>

Settles once every value has settled.

race(values: readonly Promise<unknown>[]) => Promise<unknown>

Resolves with the first of values to settle.

src/restate/runtime.ts:80

RestateContextLikeInterface#

Structural subset of restate.Context covering everything the adapter needs.

run journals one side effect; on replay the journaled value returns without re-executing fn. date.now() is async because the SDK routes it through ctx.run internally — replay returns the journaled timestamp. rand.uuidv4() is sync because the SDK seeds an in-memory RNG from the invocation id, which is itself replay-stable.

awakeable<T>() mints a journal-stable id paired with a pending promise. The id is sent out-of-band (webhook, queue, collab stream) and a separate handler resumes the wait via ctx.resolveAwakeable(id, …) / ctx.rejectAwakeable(id, …). The adapter never resolves awakeables directly; consumers driving human-in-the-loop tools (ask_user, request_review, …) do that from the resumer side. Mirrors @restatedev/restate-sdk Context — the real SDK accepts an optional Serde<T> we omit because the adapter doesn't exercise it.

TypeScript
interface RestateContextLike
RestateContextLike properties
NameTypeDescription
awakeable<T>() => RestateAwakeable<T>

Creates an awakeable: a journal-stable id and a promise that waits for an outside resolver.

date{ now: () => Promise<number> }

Durable clock. now() resolves to epoch milliseconds, the same on replay.

rand{ uuidv4: () => string }

Deterministic random source seeded from the invocation id. uuidv4() gives the same ids on replay.

resolveAwakeable?<T>(id: string, payload?: T) => void

Resolve another invocation's awakeable (the resumer side). Optional: only a resumer needs it, see restateRuntime's resolveAwakeable.

run<T>(name: string, fn: () => T | Promise<T>, options?: RestateRunOptions) => Promise<T>

Journals the result of one side effect. On replay the journaled value is returned and fn does not run again.

sleep(millis: number) => Promise<void>

Durable timer — suspends the invocation for millis and survives process death (replay resumes the same timer). Mirrors the SDK's Context.sleep(duration); we narrow the parameter to plain millis (the SDK also accepts a Duration, which a wider implementation signature satisfies structurally).

What it's for in this adapter: durable timeouts. Racing awakeable.promise against sleep(timeoutMs) is the canonical "wait with a deadline" shape — see awakeableWithTimeout, which packages exactly that race for waitBackground-style parks.

src/restate/types.ts:69

RestateDurableStartInterface#

Opt-in two-phase journaling for long-running, re-attachable tools.

The default restateTool wrapping journals only the COMPLETED result — a crash mid-execute re-runs the tool on replay, which is unacceptable for builds / migrations / deploys. durableStart splits the execution:

  1. start runs inside its own ctx.run entry, journaled BEFORE the body — it kicks off the side effect and returns a re-attach token (a background task id, a job handle, an idempotency key).
  2. the wait — either attach (one ctx.run holding the wait in the result entry; only for short, bounded waits) or wait (awakeable park: register a resumer in a journaled entry, suspend outside the journal, synthesize the result in a final entry). On replay both receive the SAME token and re-attach to the already-running work instead of starting it again.

The wrapped tool's own execute is bypassed; the start + wait pair IS the execution.

TypeScript
interface RestateDurableStart<Token = unknown, Resumed = unknown>
RestateDurableStart type parameters
NameDefaultDescription
Tokenunknown
Resumedunknown
RestateDurableStart properties
NameTypeDescription
attach?(token: Token, input: Record<string, unknown>, toolCtx: ToolContext) => Promise<string | ToolResultContent[]>

Await / re-attach to the work identified by token and produce the tool result. Runs inside ONE ctx.run entry, so the body must settle within the runtime's attempt lifecycle — a long busy-poll in here starves the journal, trips the server's inactivity/abort timeouts, and each retry restarts the wait from scratch. Use this only for waits bounded well below the inactivity timeout (or as the degraded mode on hosts without a push seam); prefer wait for anything long-running.

Required unless wait is provided; ignored when both are set.

onAbort?(token: Token, input: Record<string, unknown>, toolCtx: ToolContext) => void | Promise<void>

Cleanup for a job nobody will wait for. Without it, the journaled token identifies a remote job that keeps running with nobody attached — a leak for hosts whose jobs outlive the session. Two triggers:

  • Restate cancellation while parked on the awakeable (Admin API cancel, a cancelled parent, bun start --restate Ctrl-C). Runs inside a journaled <entry>-abort ctx.run, then the CancelledError propagates and ends the invocation. Restate journals the cancel, so a replay of that attempt gets here again, and the entry makes the cleanup run once across attempts.
  • The per-call abort signal (run abort, agent.cancelTool, sibling-cascade cancel, agent.destroy() mid-run), during attach or the park. Fires outside the journal, best effort, and does NOT stop the park: the signal is live state a replay doesn't see, so un-parking on it would take a path the journal can't reproduce. Kill the job here; its exit resolves the awakeable (journaled), or cancel the invocation to stop waiting.

Contract:

  • At most once per attempt; may run again on a replay that did not complete the journaled entry. Make it idempotent against "job already gone".
  • May run concurrently with a still-unwinding attach.
  • NOT called on process death — that's not termination: the journaled token re-attaches on replay instead.
  • Errors are swallowed (surfaced under ZIDANE_DEBUG) — cleanup failure must not mask the abort itself.
start(input: Record<string, unknown>, toolCtx: ToolContext) => Token | Promise<Token>

Kick off the side effect; journaled before attach. Must be cheap + idempotent-safe up to journal persistence.

wait?RestateDurableWait<Token, Resumed>

Awakeable-based completion wait — the durable alternative to attach for long-running work on hosts with a push seam (e.g. a runner that fires task:exit → resumer → ctx.resolveAwakeable). executeTwoPhase orchestrates three phases with the same journal discipline as restateAwakeableTool:

  1. register — a short, journaled ctx.run: hand the awakeable id to the host as the exit resumer for token. Fires exactly once across replays (marker invariant included).
  2. park — await awakeable.promise, OUTSIDE any ctx.run. The invocation suspends cleanly: no held worker, immune to inactivity/abort timeouts. With timeoutMs, the park is a durable race against ctx.sleep (replay-stable — no Date.now() deadline that resets per attempt).
  3. result — a final journaled ctx.run: synthesize the tool result from the resumer payload (null = timeout; kill the job and shape the timeout result here).

src/restate/tool.ts:61

RestateDurableWaitInterface#

Awakeable-based completion wait for RestateDurableStart.wait.

Replay contract (mirrors restateAwakeableTool):

  • The awakeable is minted BEFORE the journaled register entry, so on replay both come back in the same order with the same id — a replayed call re-parks on the SAME awakeable without re-registering.
  • The journaled marker records the awakeable id it was registered for; a mismatch on replay (journal drift) throws instead of parking on an id nobody will ever resolve.
TypeScript
interface RestateDurableWait<Token = unknown, Resumed = unknown>
RestateDurableWait type parameters
NameDefaultDescription
Tokenunknown
Resumedunknown
RestateDurableWait properties
NameTypeDescription
inline?(token: Token, input: Record<string, unknown>, toolCtx: ToolContext) => boolean

Per-call fast path: when this returns true for the journaled token, the awakeable park is SKIPPED entirely — no awakeable is minted, no -register entry is journaled, and the invocation never suspends. result is invoked directly with resumed = null inside the final result entry.

This is for start phases that sometimes have nothing to wait on (e.g. a shell tool that only spawns a real background task above a duration threshold and otherwise runs the command inline in result). Parking such calls pays a full suspend → resolve → re-invoke → replay round-trip for nothing.

MUST be a pure function of the journaled token (+ input) so the decision is identical across replays — a token-derived branch keeps the journal entry shape deterministic. When omitted, every call parks (the default).

promises?RestatePromiseRaceLike<Promise<unknown>>

Durable race combinator for the timeout race — pass RestatePromise from the SDK. Required when timeoutMs resolves to a positive value (see awakeableWithTimeout).

register(token: Token, awakeableId: string, input: Record<string, unknown>, toolCtx: ToolContext) => void | Promise<void>

Register awakeableId as the exit resumer for the work identified by token — the host must call ctx.resolveAwakeable(awakeableId, payload) when the work completes. Runs inside ctx.run; must be short and idempotent-safe up to journal persistence.

result(token: Token, resumed: Resumed | null, input: Record<string, unknown>, toolCtx: ToolContext) => string | ToolResultContent[] | Promise<string | ToolResultContent[]>

Synthesize the tool result once the park settles. resumed is the resumer's payload, or null when timeoutMs elapsed first — kill the still-running job and shape the timeout result in that branch. Runs inside the final journaled ctx.run (the result entry).

timeoutMs?number | ((input: Record<string, unknown>, toolCtx: ToolContext) => number | undefined)

Durable park deadline in milliseconds — becomes the awakeableWithTimeout duration (a ctx.sleep raced against the awakeable, replay-stable). A function receives the call's input so the model's own timeout parameter can drive it. Unset / non-positive = park indefinitely.

src/restate/tool.ts:140

RestateObjectContextLikeInterface#

Structural subset of restate.ObjectContext — adds keyed K/V state scoped to the virtual-object instance the handler is bound to.

get returns null for missing keys (SDK contract). set returns void; the SDK journals the mutation transparently.

TypeScript
interface RestateObjectContextLike extends RestateContextLike
RestateObjectContextLike properties
NameTypeDescription
awakeablefrom RestateContextLike<T>() => RestateAwakeable<T>

Creates an awakeable: a journal-stable id and a promise that waits for an outside resolver.

clear(name: string) => void

Removes a state key.

datefrom RestateContextLike{ now: () => Promise<number> }

Durable clock. now() resolves to epoch milliseconds, the same on replay.

get<T>(name: string) => Promise<T | null>

Reads a state value. Resolves to null when the key is missing.

keystring

Key of the virtual-object instance the handler is bound to.

randfrom RestateContextLike{ uuidv4: () => string }

Deterministic random source seeded from the invocation id. uuidv4() gives the same ids on replay.

resolveAwakeable?from RestateContextLike<T>(id: string, payload?: T) => void

Resolve another invocation's awakeable (the resumer side). Optional: only a resumer needs it, see restateRuntime's resolveAwakeable.

runfrom RestateContextLike<T>(name: string, fn: () => T | Promise<T>, options?: RestateRunOptions) => Promise<T>

Journals the result of one side effect. On replay the journaled value is returned and fn does not run again.

set<T>(name: string, value: T) => void

Writes a state value. The SDK journals the change.

sleepfrom RestateContextLike(millis: number) => Promise<void>

Durable timer — suspends the invocation for millis and survives process death (replay resumes the same timer). Mirrors the SDK's Context.sleep(duration); we narrow the parameter to plain millis (the SDK also accepts a Duration, which a wider implementation signature satisfies structurally).

What it's for in this adapter: durable timeouts. Racing awakeable.promise against sleep(timeoutMs) is the canonical "wait with a deadline" shape — see awakeableWithTimeout, which packages exactly that race for waitBackground-style parks.

src/restate/types.ts:116

RestatePromiseRaceLikeInterface#

Structural subset of the SDK's RestatePromise static surface used by awakeableWithTimeout. Pass RestatePromise from @restatedev/restate-sdk so the race goes through the journaled combinator. Native Promise.race over durable promises is not supported (see the "no native combinators" rule in docs/RESTATE.md). Method syntax on purpose, as in RestateCombinators: it keeps the SDK's generic race assignable, so promises: RestatePromise typechecks.

TypeScript
interface RestatePromiseRaceLike<TPromise extends Promise<unknown> = Promise<unknown>>
RestatePromiseRaceLike type parameters
NameTypeDefaultDescription
TPromiseextends Promise<unknown>Promise<unknown>
RestatePromiseRaceLike properties
NameTypeDescription
race(values: readonly TPromise[]) => Promise<unknown>

Resolves with the first of values to settle.

src/restate/awakeable.ts:30

RestateRunOptionsInterface#

Subset of restate.Context.run used by the adapter. The SDK's full signature accepts a richer options bag; this captures what the adapter exercises.

TypeScript
interface RestateRunOptions
RestateRunOptions properties
NameTypeDescription
initialRetryInterval?unknown

Initial delay before the first retry.

maxRetryAttempts?number

Max retry attempts before surfacing a terminal error.

maxRetryDuration?unknown

Max retry duration before surfacing a terminal error.

maxRetryInterval?unknown

Maximum delay between retries.

retryIntervalFactor?number

Exponential factor applied to retry intervals.

serde?unknown

Optional SDK serde passthrough for callers that need custom journal encoding.

src/restate/types.ts:20

RestateRuntimeOptionsInterface#

Options for restateRuntime.

TypeScript
interface RestateRuntimeOptions
RestateRuntimeOptions properties
NameTypeDescription
coalesce?boolean | { reanchorEvery?: number }

Coalesce now(): journal a real ctx.date.now() anchor every reanchorEvery calls (true: every 8) and derive a monotonic sequence in between, cutting the suspensions a journaled now() costs. Timestamps inside a window are logical (ordered, near the anchor), not wall-accurate. Default: every now() is journaled.

idSeed?string

Entropy of the uuid() sequence: pass a per-invocation stable value (the virtual object key, a workflow id) and construction draws nothing from ctx.rand. Default: one ctx.rand.uuidv4() draw at construction, which is stable as long as the runtime is built at a deterministic point of the handler (before any work that draws a varying number of times). Ids are hashed from (idSeed, counter), never drawn from ctx.rand per call: other code sharing ctx.rand can draw a different number of times on a replay, which would shift every later id.

promises?RestateCombinators

Durable combinators: pass RestatePromise from @restatedev/restate-sdk. With them, concurrent steps (a batch of concurrency-safe tool calls) start together and park once, and awakeables can have a deadline. Without them, steps run one at a time (concurrent native awaits of Restate promises fail the attempt with awaitNext already pending).

replayTracker?ReplayTracker

Per-invocation replay tracker (createReplayTracker): marked live the first time a step's handler actually runs instead of replaying.

resolveAwakeable?(id: string, value: JsonValue) => void | Promise<void>

Resolve an awakeable of another invocation (an ingress client, e.g. (id, value) => ingress.resolveAwakeable(id, value)). Default: the context's own ctx.resolveAwakeable, which a resumer handler has.

runOptions?Partial<Record<StepKind, RestateRunOptions>>

ctx.run options of the step entries, by step kind ('model', 'tool', 'decision', …). Default { maxRetryAttempts: 1 }: a failure is recorded as the step's value, so these only matter for a handler that throws Restate's RetryableError, which escapes to the SDK's retry policy when these allow another attempt.

sessionStore?SessionStore

Where sessions live. Default: restateSessionStore(ctx) (the bound virtual object's state) on an object context, else an in-memory store (the journal still replays the run; nothing outlives the invocation).

src/restate/runtime.ts:91

RestateSessionStoreOptionsInterface#

Options for restateSessionStore.

TypeScript
interface RestateSessionStoreOptions
RestateSessionStoreOptions properties
NameTypeDescription
clock?AgentClock

Time source for the journaled header timestamps (createdAt / updatedAt) the store stamps in save(), saveMeta() and updateStatus().

Defaults to ctx.date.now(): one journaled round-trip per call. restateRuntime passes its own clock, so with coalesce these finalize-time timestamps ride the coalesced anchor instead of each spending their own ctx.date.now(); on a suspend-per-round-trip (FaaS) host that's ~2 fewer suspend/replay cycles per run. Whatever you pass MUST be replay-stable: the value lands in persisted state via ctx.set, so a drifting clock would corrupt the journal on replay.

readOnly?boolean

Never write state. Required when the store is built from a SHARED handler's context (restate.handlers.object.shared), which Restate forbids from writing: reads of a legacy session-turns object are served without migrating it, and every mutating method throws.

src/restate/session.ts:90

RestateSpawnToolOptionsInterface#

Options for restateSpawnTool.

TypeScript
interface RestateSpawnToolOptions
RestateSpawnToolOptions properties
NameTypeDescription
description?string

Override the tool description shown to the model.

dispatch(req: ChildRunRequest, ctx: ToolContext) => Promise<ChildRunResult>

Start the child invocation and return the runtime's promise untouched (e.g. ctx.serviceClient(childService).runChild(req)). Do not wrap it in then / catch / race, and do not await it here.

emitChildEvents?boolean

Replay each finished child's transcript onto the parent's hook bus as child:* events, so hosts already rendering subagent activity work unchanged. Default: true.

These are NOT live — hook bubbling cannot cross an invocation boundary, so they fire when the child finishes, in submission order. For live output, publish from the child's own bus inside your handler and correlate with the parentRunId / parentCallId / sessionId carried in ChildRunRequest; see docs/RESTATE.md § Parallel subagents.

They re-fire on a parent replay, exactly as the in-process tool's child:tool:* does — dedupe by callId / turnId, or gate on createReplayTracker.

onAbort?(inFlight: readonly InFlightChild[], ctx: ToolContext) => void

Called once when the parent aborts with children still in flight. Wire it and an aborted parent stops its children instead of orphaning them.

The practical implementation is to cancel the parent's OWN invocation:

Text
onAbort: () => ctx.invocation(ctx.request().id).cancel()

Restate cancels the whole call tree, so this reaches children at any depth and needs no per-child bookkeeping. ctx.request().id is available synchronously and is constant across retries and suspensions. The cost is that the parent invocation ends too — an in-agent abort becomes "stop everything", so persist whatever summary you need BEFORE aborting.

Why not per-child ids: the invocationId on the runtime's call handle is itself a journal-backed promise (SingleRestatePromise, see @restatedev/restate-sdk context_impl.js), so reading it while the call is in flight registers a second consumer on the SDK's single-consumer progress channel — awaitNext already pending, a failed attempt, and a replay on every fan-out. Verified against a real server. Per-child cancellation needs the two-phase (send → id → attach) tool shape, where the id is consumed before the result promise exists.

Timing: cancelling appends a journal command, so it must not happen during a replay. Drive aborts through replayAwareAbort (see ./replay), which defers an external abort to the first live boundary.

onChildMerged?(merged: MergedChild, ctx: ToolContext) => void

Called for each child as it merges, with the subtree it brought along.

Sessionless agents (a child dispatched to a service) need this: they have nowhere to persist their own children, so they collect here and hand the result up as ChildRunResult.children. Without it a nested fan-out loses everything below depth 1.

persist?boolean

Merge each child's turns and run record into the parent's session. Default: true when the parent has a session.

Ordering nuance versus the in-process tool: the merge runs on tool-results:after, so a child's turns are appended just AFTER the parent's tool-result turn rather than just before it. Their createdAt values still order them correctly for consumers that sort chronologically.

src/restate/spawn.ts:178

RestateToolOptionsInterface#

Options for restateTool.

TypeScript
interface RestateToolOptions<Token = unknown, Resumed = unknown>
RestateToolOptions type parameters
NameDefaultDescription
Tokenunknown
Resumedunknown
RestateToolOptions properties
NameTypeDescription
coerceResultBlocks?boolean

Collapse malformed structured result blocks ({ type: 'image' } with no payload, foreign block shapes) to a text placeholder before the result is journaled, so a downstream provider wire serializer never has to project an unprojectable block (which, under Restate, would throw inside the journaled provider call and become fatal). Well-formed results pass through untouched. Applies to the single-phase journaling path.

Default: true.

detachedTasks?DetachedTasksCapability

detachedTasks capability of the execution context the agent will run with (see ContextCapabilities.detachedTasks / resolveDetachedTasksCapability). Drives the disableShellBackground default: a 'durable' context keeps its background tasks across worker crashes, so the wrapper leaves the shell tool's background mode intact.

Default: undefined, treated as non-durable (background disabled).

disableShellBackground?boolean

Hide and reject the built-in shell tool's background mode.

Default: derived from RestateToolOptions.detachedTasks — disabled unless the execution context declares 'durable' detached tasks. An explicit boolean always wins.

durableStart?RestateDurableStart<Token, Resumed>

Two-phase start/attach journaling for crash-safe long tools — see RestateDurableStart. Per-tool by nature.

entryName?(seq: number, name: string, input: Record<string, unknown>, callId?: string) => string

Override the journal-entry name. Receives the canonical tool name, the call's input, and the model's callId (when the runtime provides one). Default: tool-<name>-<seq> where <seq> is a per-wrapper monotonic counter. The counter is replay-stable as long as dispatch order is deterministic; key on callId instead for a model-deterministic name that's robust even under maxConcurrentTools > 1.

replayTracker?ReplayTracker

Per-invocation replay tracker (see createReplayTracker). When set, the wrapper marks it live from inside its journaled closures — i.e. the first time a tool body (or a durableStart.start phase) ACTUALLY executes rather than replaying from the journal. Pass the same tracker as restateRuntime({ replayTracker }) of the handler invocation.

runOptions?RestateRunOptions

ctx.run options forwarded on every wrapped tool call. Defaults to { maxRetryAttempts: 1 } — tool errors are typically deterministic (validation failures, missing files) so blind retries waste budget. Override per-tool for network-heavy custom tools that benefit from SDK-level retries.

softErrors?boolean

Keep an ordinary, recoverable tool throw (a failed shell command, a transport error, an MCP isError) NON-fatal under Restate.

Without this, the throw rides out of the journaled ctx.run action, exhausts the retry budget, and surfaces as a Restate TerminalError — which the runtime treats as a control error, aborting the whole run. With it, the throw is captured INSIDE the journal as a sentinel value and re-thrown as a plain (non-control) error OUTSIDE it, so the loop produces a model-visible tool_result { isError } and continues — identical to the non-Restate soft-error model. Real Restate control errors are never softened; an abort is rethrown as an AbortError.

Applies to the single-phase journaling path. The two-phase RestateToolOptions.durableStart mode owns its own start/wait error shape and is unaffected.

Default: true.

src/restate/tool.ts:191

RestateToolStateStoreOptionsInterface#

Options for restateToolStateStore.

TypeScript
interface RestateToolStateStoreOptions
RestateToolStateStoreOptions properties
NameTypeDescription
key?string

Override the state key. Defaults to DEFAULT_TOOL_STATE_KEY.

maxValueBytes?number

Per-value size budget enforced when a tool stages a write. Defaults to the library's DEFAULT_MAX_VALUE_BYTES (64 KiB), which is far below Restate's own journal-entry ceiling on purpose: an oversized state value doesn't fail politely there — the invocation fails with RT0003 (MessageSizeLimit) and is retried under the configured policy, i.e. a fat write becomes a poison pill rather than a dropped one.

src/restate/tool-state.ts:44

RestateWaitBackgroundOptionsInterface#

Options for restateWaitBackground.

TypeScript
interface RestateWaitBackgroundOptions
RestateWaitBackgroundOptions properties
NameTypeDescription
ctxRestateContextLike

The Restate context the awakeable + journal entries bind to.

entryPrefix?string

Journal-entry prefix. Default wait-background.

probe(handle: ExecutionHandle, taskId: string) => readonly TaskEntry[] | Promise<readonly TaskEntry[]>

Snapshot the host's task registry (the listBackground shape). Called AFTER register, inside a journaled ctx.run. The helper finds taskId in the result: terminated → fast-path return, running → park, absent → null.

promises?RestatePromiseRaceLike<Promise<unknown>>

Durable race combinator for the timeout race — pass RestatePromise from the SDK. Required when a timeout applies (timeoutMs here or per call); see raceWithTimeout.

register(awakeableId: string, taskId: string, handle: ExecutionHandle) => void | Promise<void>

Persist awakeableId as the exit resumer for taskId BEFORE the probe — the host's task-exit path must later call ctx.resolveAwakeable(awakeableId, exitInfo). Runs inside a journaled ctx.run; keep it short and idempotent-safe up to journal persistence.

replayTracker?ReplayTracker

Per-invocation replay tracker (see createReplayTracker).

runOptions?RestateRunOptions

ctx.run options for the journaled phases. Defaults to { maxRetryAttempts: 1 }.

settle?(awakeableId: string, taskId: string, exit: TaskExitInfo | null, handle: ExecutionHandle) => void | Promise<void>

Finalize the resumer row once the wait resolves — exit is the task's TaskExitInfo, or null on timeout / unknown task. Runs inside a journaled ctx.run. Optional.

timeoutMs?number

Default park deadline in milliseconds. A per-call options.timeoutMs (what the wait_task tool passes) wins. Unset / non-positive = park until the resumer fires or the invocation is cancelled.

src/restate/wait-background.ts:49

Types#

RestatePromiseLikeType#

A promise that also exposes the SDK map combinator (RestatePromise).

TypeScript
type RestatePromiseLike<T> = Promise<T> & { map: <U>(mapper: (value?: T, failure?: unknown) => U) => Promise<U> }
RestatePromiseLike type parameters
NameDescription
T

src/restate/types.ts:105

Re-exports#

These names are documented on the entry point that owns them.