zidane 6.6.3 → 6.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/{acp-BQqhozmt.js → acp-Cv4Rm-WY.js} +3 -3
  2. package/dist/{acp-BQqhozmt.js.map → acp-Cv4Rm-WY.js.map} +1 -1
  3. package/dist/acp-cli.js +3 -3
  4. package/dist/acp.d.ts +1 -1
  5. package/dist/acp.js +1 -1
  6. package/dist/{agent-DTxH7RHW.js → agent-DpVdepFt.js} +2 -2
  7. package/dist/{agent-DTxH7RHW.js.map → agent-DpVdepFt.js.map} +1 -1
  8. package/dist/agent.d.ts +1 -1
  9. package/dist/agent.js +1 -1
  10. package/dist/{auth-7rv6ZfWk.js → auth-D2KIL4OS.js} +2 -2
  11. package/dist/{auth-7rv6ZfWk.js.map → auth-D2KIL4OS.js.map} +1 -1
  12. package/dist/chat/pure.d.ts +3 -3
  13. package/dist/chat.d.ts +4 -4
  14. package/dist/chat.js +3 -3
  15. package/dist/contexts/daytona.d.ts +2 -1
  16. package/dist/contexts/daytona.d.ts.map +1 -1
  17. package/dist/contexts/daytona.js +13 -2
  18. package/dist/contexts/daytona.js.map +1 -1
  19. package/dist/contexts/e2b.d.ts +1 -1
  20. package/dist/eval.d.ts +1 -1
  21. package/dist/eval.js +1 -1
  22. package/dist/extensions.d.ts +1 -1
  23. package/dist/extensions.js +1 -1
  24. package/dist/headless.d.ts +1 -1
  25. package/dist/headless.js +2 -2
  26. package/dist/{index-D0O-QO7Z.d.ts → index-CWCQwx4o.d.ts} +14 -2
  27. package/dist/index-CWCQwx4o.d.ts.map +1 -0
  28. package/dist/index.d.ts +1 -1
  29. package/dist/index.js +2 -2
  30. package/dist/mcp.d.ts +1 -1
  31. package/dist/output/stream-json.d.ts +1 -1
  32. package/dist/output/terminal.d.ts +1 -1
  33. package/dist/plugins.d.ts +1 -1
  34. package/dist/presets.d.ts +1 -1
  35. package/dist/presets.js +1 -1
  36. package/dist/providers/anthropic.d.ts +1 -1
  37. package/dist/providers/arcee.d.ts +1 -1
  38. package/dist/providers/baseten.d.ts +1 -1
  39. package/dist/providers/cerebras.d.ts +1 -1
  40. package/dist/providers/local.d.ts +1 -1
  41. package/dist/providers/openai-compat.d.ts +1 -1
  42. package/dist/providers/openai.d.ts +1 -1
  43. package/dist/providers/openrouter.d.ts +1 -1
  44. package/dist/providers/xai.d.ts +1 -1
  45. package/dist/providers.d.ts +1 -1
  46. package/dist/restate.d.ts +1 -1
  47. package/dist/restate.d.ts.map +1 -1
  48. package/dist/restate.js +76 -30
  49. package/dist/restate.js.map +1 -1
  50. package/dist/session/sqlite.d.ts +1 -1
  51. package/dist/{session-CyRLSsVa.js → session-BP6Ly2XF.js} +22 -3
  52. package/dist/session-BP6Ly2XF.js.map +1 -0
  53. package/dist/session.d.ts +2 -2
  54. package/dist/session.js +2 -2
  55. package/dist/skills.d.ts +1 -1
  56. package/dist/{tool-formatters-NrzD6Fkk.d.ts → tool-formatters-BubatDZA.d.ts} +2 -2
  57. package/dist/{tool-formatters-NrzD6Fkk.d.ts.map → tool-formatters-BubatDZA.d.ts.map} +1 -1
  58. package/dist/tools/fetch-url.d.ts +1 -1
  59. package/dist/tools/web-search.d.ts +1 -1
  60. package/dist/tools.d.ts +1 -1
  61. package/dist/tools.js +1 -1
  62. package/dist/{transcript-anchors-BjH-68k2.js → transcript-anchors-5qybec_s.js} +3 -3
  63. package/dist/{transcript-anchors-BjH-68k2.js.map → transcript-anchors-5qybec_s.js.map} +1 -1
  64. package/dist/{transcript-anchors-UhC58Tmj.d.ts → transcript-anchors-B4NSP1jM.d.ts} +2 -2
  65. package/dist/{transcript-anchors-UhC58Tmj.d.ts.map → transcript-anchors-B4NSP1jM.d.ts.map} +1 -1
  66. package/dist/tui.d.ts +3 -3
  67. package/dist/tui.js +4 -4
  68. package/dist/{turn-operations-Cuc9pwiB.d.ts → turn-operations-4rSHXmxe.d.ts} +3 -3
  69. package/dist/{turn-operations-Cuc9pwiB.d.ts.map → turn-operations-4rSHXmxe.d.ts.map} +1 -1
  70. package/dist/types.d.ts +1 -1
  71. package/package.json +1 -1
  72. package/dist/index-D0O-QO7Z.d.ts.map +0 -1
  73. package/dist/session-CyRLSsVa.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"restate.js","names":[],"sources":["../src/restate/awakeable.ts","../src/restate/awakeable-tool.ts","../src/restate/errors.ts","../src/restate/behavior.ts","../src/restate/clock.ts","../src/restate/soft-errors.ts","../src/restate/tool.ts","../src/restate/mcp.ts","../src/restate/parallel.ts","../src/restate/provider.ts","../src/restate/replay.ts","../src/restate/session.ts","../src/restate/spawn.ts","../src/restate/tool-state.ts","../src/restate/wait-background.ts"],"sourcesContent":["/**\n * Awakeable helpers — durable waits with deadlines.\n *\n * `awakeableWithTimeout` packages the canonical \"park until a resumer\n * fires, but not forever\" shape: an awakeable raced against a durable\n * `ctx.sleep(timeoutMs)` timer. The race itself survives process death —\n * on replay both branches resume from the journal and the same side\n * wins. This is the three-line building block for\n * `ExecutionContext.waitBackground` implementations on durable hosts\n * (runner fires task-exit → `resolveAwakeable(id, info)`; the timeout\n * branch maps to the seam's `null` return).\n */\n\nimport type { RestateAwakeable, RestateContextLike } from './types'\n\n/**\n * Structural subset of the SDK's `RestatePromise` static surface used by\n * {@link awakeableWithTimeout} — mirrors `RestatePromiseAllLike` from\n * `./parallel`. Pass `RestatePromise` from `@restatedev/restate-sdk` so\n * the race goes through the journaled combinator; native `Promise.race`\n * over two durable promises leaves the winner to the runtime's replay\n * ordering instead of an explicit journal entry.\n */\nexport interface RestatePromiseRaceLike<TPromise extends Promise<unknown> = Promise<unknown>> {\n race: (values: readonly TPromise[]) => Promise<unknown>\n}\n\nexport interface AwakeableWithTimeoutOptions<TPromise extends Promise<unknown> = Promise<unknown>> {\n /**\n * Durable deadline in milliseconds. Unset / non-positive = no timeout\n * (the returned awakeable is the plain `ctx.awakeable()` passthrough).\n */\n timeoutMs?: number\n /**\n * Durable race combinator — pass `RestatePromise` from the SDK. When\n * omitted, native `Promise.race` is used: correct at runtime and\n * replay-safe for THIS pattern (both branches are journaled\n * primitives), but the SDK combinator is the recommended belt-and-\n * braces choice for deterministic replay.\n */\n promises?: RestatePromiseRaceLike<TPromise>\n}\n\n/**\n * Mint an awakeable that resolves with the resumer's payload, or `null`\n * when `timeoutMs` elapses first. The id is journal-stable (send it\n * out-of-band as usual); the timeout is a durable `ctx.sleep`, so a\n * parked invocation suspends instead of holding a worker.\n *\n * Timeout surfaces as `null` — a resumer that resolves `undefined` is\n * indistinguishable from a timeout, so resolve a concrete payload.\n *\n * ```ts\n * // waitBackground for a durable host, in three lines:\n * const { id, promise } = awakeableWithTimeout<TaskExitInfo>(ctx, { timeoutMs, promises: RestatePromise })\n * await registerExitResumer(taskId, id) // runner → ctx.resolveAwakeable(id, info)\n * return await promise // TaskExitInfo, or null on timeout\n * ```\n */\nexport function awakeableWithTimeout<T, TPromise extends Promise<unknown> = Promise<unknown>>(\n ctx: RestateContextLike,\n options: AwakeableWithTimeoutOptions<TPromise> = {},\n): RestateAwakeable<T | null> {\n const awakeable = ctx.awakeable<T>()\n const timeoutMs = options.timeoutMs\n if (typeof timeoutMs !== 'number' || !Number.isFinite(timeoutMs) || timeoutMs <= 0)\n return awakeable\n\n const timer = ctx.sleep(timeoutMs)\n const raced = options.promises\n ? options.promises.race([awakeable.promise, timer] as readonly unknown[] as readonly TPromise[])\n : Promise.race<unknown>([awakeable.promise, timer])\n return {\n id: awakeable.id,\n // The sleep branch resolves `undefined`; normalize to the seam's\n // `null` so callers get one documented timeout sentinel.\n promise: raced.then(value => (value === undefined ? null : value as T)),\n }\n}\n","/**\n * Awakeable-backed tool — durable human/external-in-the-loop waits.\n *\n * Builds a `ToolDef` whose `execute` parks on a Restate awakeable: the\n * tool mints a journal-stable awakeable id, broadcasts it out-of-band\n * (webhook, queue, collab stream — the `notify` callback), and suspends\n * until a resumer calls `ctx.resolveAwakeable(id, value)` on the SDK\n * side. The classic shape for `ask_user` / `request_review` /\n * `wait_for_approval` tools inside durable handlers.\n *\n * Replay contract\n * ---------------\n * - **Broadcast-once-across-replays**: `notify` runs inside `ctx.run`,\n * so a crash + replay returns the journaled marker without re-sending\n * the notification. The user is pinged exactly once per tool call, no\n * matter how many times the worker restarts.\n * - **Marker invariant**: the journaled marker records the awakeable id\n * it was broadcast for. On replay the freshly-minted awakeable id must\n * match (the SDK derives awakeable ids deterministically from the\n * journal position); a mismatch means the journal and the code path\n * drifted — the tool throws instead of parking on an id nobody will\n * ever resolve.\n */\n\nimport type { ToolContext, ToolDef } from '../tools/types'\nimport type { ToolResultContent } from '../types'\nimport type { RestateContextLike, RestateRunOptions } from './types'\n\n/** Journaled broadcast marker — see \"Marker invariant\" in the module doc. */\ninterface AwakeableNotifyMarker {\n notified: true\n awakeableId: string\n}\n\nexport interface RestateAwakeableToolOptions<T = unknown> {\n /** Canonical tool name (what the model calls). */\n name: string\n /** Model-facing tool description. */\n description: string\n /** JSON schema for the tool input. */\n inputSchema: Record<string, unknown>\n /** The Restate context the awakeable + journal entries bind to. */\n ctx: RestateContextLike\n /**\n * Send the awakeable id (plus the call's input) out-of-band so a\n * resumer can later call `ctx.resolveAwakeable(awakeableId, value)`.\n * Runs inside `ctx.run` — fires exactly once across replays.\n */\n notify: (info: {\n awakeableId: string\n input: Record<string, unknown>\n toolCtx: ToolContext\n }) => void | Promise<void>\n /**\n * Map the resolved awakeable payload to the tool result. Default:\n * strings pass through, everything else is JSON-stringified.\n */\n toResult?: (value: T, input: Record<string, unknown>) => string | ToolResultContent[]\n /**\n * `ctx.run` options for the notify entry. Defaults to\n * `{ maxRetryAttempts: 1 }`, matching `restateTool`'s rationale.\n */\n runOptions?: RestateRunOptions\n /**\n * Concurrency-safety flag passed through to the `ToolDef`. Defaults to\n * `false` — a parked wait holding a scheduler slot should barrier.\n */\n isConcurrencySafe?: boolean\n}\n\n/**\n * Build a `ToolDef` that parks on a Restate awakeable until an external\n * resumer resolves it. See the module doc for the replay contract.\n *\n * Do NOT additionally wrap the returned tool in `restateTool` — the\n * journal discipline is already internal, and an outer `ctx.run` would\n * illegally nest the suspension point inside a journaled closure.\n */\nexport function restateAwakeableTool<T = unknown>(\n options: RestateAwakeableToolOptions<T>,\n): ToolDef {\n const { name, description, inputSchema, ctx, notify, toResult } = options\n const runOpts: RestateRunOptions = options.runOptions ?? { maxRetryAttempts: 1 }\n let seq = 0\n\n const execute = async (input: Record<string, unknown>, toolCtx: ToolContext): Promise<string | ToolResultContent[]> => {\n seq += 1\n // Mint BEFORE the journaled broadcast: the awakeable's journal\n // position precedes the notify entry, so on replay both come back\n // in the same order with the same id.\n const awakeable = ctx.awakeable<T>()\n\n const marker = await ctx.run<AwakeableNotifyMarker>(\n `awakeable-${name}-${seq}-notify`,\n async () => {\n await notify({ awakeableId: awakeable.id, input, toolCtx })\n return { notified: true, awakeableId: awakeable.id }\n },\n runOpts,\n )\n\n // Marker invariant — a drifted journal would otherwise park this\n // call on an id that was never broadcast (nobody will resolve it).\n if (marker.awakeableId !== awakeable.id) {\n throw new Error(\n `restateAwakeableTool(${name}): journal drift — broadcast marker carries awakeable \"${marker.awakeableId}\" but this replay minted \"${awakeable.id}\". The journal and the code path no longer line up; refusing to park on an unreachable awakeable.`,\n )\n }\n\n const value = await awakeable.promise\n if (toResult)\n return toResult(value, input)\n return typeof value === 'string' ? value : JSON.stringify(value)\n }\n\n return {\n spec: { name, description, inputSchema },\n ...(options.isConcurrencySafe !== undefined ? { isConcurrencySafe: options.isConcurrencySafe } : {}),\n execute,\n // The awakeable park IS the durable body — the loop's durable path\n // can use it directly without an extra wrapper.\n durableExecute: execute,\n }\n}\n","/**\n * Restate control-flow errors must escape the agent loop. If they are turned\n * into model-visible tool results, the runtime can retry/suspend incorrectly.\n *\n * Kept structural so `zidane/restate` does not need to import the SDK at\n * runtime just to recognize the common error shapes.\n */\nexport function shouldRethrowRestateControlError(error: unknown): boolean {\n if (!(error instanceof Error))\n return false\n\n // Platform DOMExceptions collide with Restate's control-error classes BY\n // NAME: `AbortSignal.timeout()` mints name 'TimeoutError' (Bun/undici),\n // an aborted fetch mints 'AbortError'. Those are plain transport\n // failures, never Restate control flow — without this guard a fetch\n // deadline inside a journaled tool body was classified \"control\",\n // rethrown past the soft-error net, and aborted an entire run via\n // `maxRetryAttempts: 1` (prod incident 2026-07-17: a 330s exec-gateway\n // timeout killed a workflow run with \"The operation timed out.\").\n if (typeof DOMException !== 'undefined' && error instanceof DOMException)\n return false\n\n const codeValue = Reflect.get(error, 'code')\n const code = typeof codeValue === 'number'\n ? codeValue\n : undefined\n if (code === 599)\n return true\n\n const name = error.name\n if (\n name === 'TerminalError'\n || name === 'TimeoutError'\n || name === 'CancelledError'\n || name === 'SuspendedError'\n ) {\n return true\n }\n\n const ctorName = error.constructor?.name\n const serializedCtorNameValue = Reflect.get(error, 'constructorName')\n const serializedCtorName = typeof serializedCtorNameValue === 'string'\n ? serializedCtorNameValue\n : undefined\n if (\n ctorName === 'TerminalError'\n || ctorName === 'TimeoutError'\n || ctorName === 'CancelledError'\n || ctorName === 'SuspendedError'\n || serializedCtorName === 'TerminalError'\n || serializedCtorName === 'TimeoutError'\n || serializedCtorName === 'CancelledError'\n || serializedCtorName === 'SuspendedError'\n ) {\n return true\n }\n\n return typeof name === 'string' && name.toLowerCase().includes('suspend')\n}\n","import type { AgentBehavior } from '../types'\nimport { shouldRethrowRestateControlError } from './errors'\n\n/**\n * Conservative behavior defaults for agents running inside Restate.\n *\n * The helper is opt-in and returns a plain AgentBehavior object, so callers can\n * spread or override it without changing non-Restate harness defaults.\n *\n * `disableBackgroundTasks: 'non-durable'` is capability-aware: background\n * tasks stay enabled for execution contexts whose\n * `capabilities.detachedTasks` is `'durable'` (tasks live on a remote\n * runner and survive worker crashes) and are disabled for everything\n * else (host-local processes don't survive process death). Hosts on\n * plain `ProcessContext` see the same effective behavior as the old\n * blanket `true`.\n *\n * ## Performance knob: `maxConcurrentTools`\n *\n * Defaults to `1` — tools run sequentially, which keeps the journal simple and\n * is the safe default. The cost: a turn with N tool calls becomes N separate\n * `ctx.run` entries awaited one at a time, so on a suspend-per-round-trip host\n * (Lambda / sandbox) that's N suspend+replay cycles for that turn.\n *\n * Raising it (e.g. `restateBehavior({ maxConcurrentTools: 8 })`) lets the\n * Restate batch executor join CONCURRENCY-SAFE calls through Restate's durable\n * `all()` combinator — the invocation parks ONCE per batch instead of once per\n * tool, AND the safe calls run in parallel (wall-clock win). Safety is judged\n * per call, not per tool (`ToolDef.isConcurrencySafe` may inspect the input —\n * e.g. a read-only `shell` command batches, a mutating one doesn't), and\n * unsafe calls (file writes/edits, mutating commands) stay barriers regardless,\n * so correctness is unchanged; the only thing you're trading is resource\n * concurrency (e.g. how many reads / API calls fire at once). For read-heavy\n * agents this is the single biggest suspension-count lever. It's left at `1` by\n * default because the right ceiling is workload-specific — set it deliberately.\n */\nexport function restateBehavior(overrides: AgentBehavior = {}): AgentBehavior {\n return {\n maxConcurrentTools: 1,\n disableBackgroundTasks: 'non-durable',\n cache: true,\n shouldRethrowToolError: shouldRethrowRestateControlError,\n // Context discipline for long runs. These are client-side and\n // provider-agnostic: they trim the message array before it reaches the\n // provider, so they work for OSS / OpenAI-compat models too.\n // `tail` keeps the largest recent suffix of tool output under\n // `compactThreshold` bytes; `elideStaleReads: 'stub'` drops superseded\n // file reads from the wire — the explicit spelling of legacy `true`.\n // Deliberately NOT the chat profiles' `'notice'`: restate's priority is\n // per-turn payload size (journal weight + LLM latency), so it pays the\n // prompt-cache re-bill to keep requests small. See\n // `AgentBehavior.elideStaleReads` for the trade.\n // `mediaKeepTurns` ages base64 (pasted/Read images, PDFs) off the wire.\n compactStrategy: 'tail',\n compactThreshold: 128 * 1024,\n compactKeepTurns: 8,\n elideStaleReads: 'stub',\n mediaKeepTurns: 8,\n toolOutputBudget: 64 * 1024,\n // Token-based proactive summarization. Inert unless a context window is\n // resolvable through `provider.meta.contextWindow` or an explicit\n // `autoCompact.contextWindow` override.\n autoCompact: { threshold: 0.85 },\n ...overrides,\n }\n}\n","/**\n * Restate-backed {@link AgentClock} — sources `now()` from the journal and\n * `randomUUID()` from a clock-private deterministic sequence so\n * `SessionTurn.createdAt`, `runId`, and fallback / synthetic turn ids stay\n * byte-identical across replays of the same invocation.\n *\n * Why `randomUUID()` does NOT ride `ctx.rand.uuidv4()`\n * -----------------------------------------------------\n * Restate's `ctx.rand` is a single invocation-seeded stream advanced per\n * draw: draw #N always yields the same value, so it is replay-stable ONLY\n * if every consumer's draw COUNT before a given point is identical between\n * the live attempt and each replay. The agent runtime cannot guarantee\n * that: MCP bootstrap, provider retries, awakeable tools, and host code all\n * share the stream, and any live-vs-replay variance in their draw counts\n * shifts every subsequent draw. In production that surfaced as turn ids\n * swapping values across a suspension — journaled bridge entries keyed by\n * turn id (and `ctx.set` turn bytes) then diverged on replay and killed the\n * invocation with `JournalMismatchError`.\n *\n * Instead, ids are minted as sha256-derived, RFC-4122-v4-shaped UUIDs from\n * `(idSeed, clock-local counter)`. The counter advances only on this\n * clock's own mints (loop turn boundaries — deterministic given journaled\n * LLM/tool results), fully isolated from every other rand consumer. Pass\n * {@link RestateClockOptions.idSeed} (e.g. the virtual object key) for a\n * draw-free construction; without it the clock consumes exactly ONE\n * `ctx.rand.uuidv4()` draw at construction time as its seed — stable as\n * long as clock construction happens at a deterministic point in the\n * handler (i.e. before any variably-drawing work), which `createAgent`\n * setup satisfies.\n *\n * Pass to `agent.run({ clock: restateClock(ctx) })` or bake it into\n * `createAgent({ clock: restateClock(ctx) })` for the duration of a\n * handler invocation. The clock holds a reference to `ctx`; do not reuse\n * a clock instance across invocations.\n *\n * Suspension cost & coalescing\n * ----------------------------\n * `ctx.date.now()` is a JOURNALED durable op — each call is a round-trip the\n * invocation can suspend on (on sandbox-reattach hosts, a suspension tears\n * down and re-attaches the worker). The agent loop samples `now()` a few\n * times per turn (`SessionTurn.createdAt` for the assistant turn and the\n * tool-result turn, plus run start/end), so a multi-turn run racks up a\n * journaled `date.now()` per couple of turns. `randomUUID()` is a pure\n * synchronous hash — it never journals and never suspends.\n *\n * Pass `{ coalesce: true }` to collapse most of those `date.now()`\n * round-trips: the clock journals a real anchor once, then derives a\n * monotonic sequence (`anchor`, `anchor+1`, …) from it without re-journaling,\n * re-anchoring against the real clock only every `reanchorEvery` calls. This\n * is fully replay-deterministic (the journaled anchors replay verbatim and\n * the counter is a pure function of call order) and monotonic (clamped so a\n * fresh anchor never moves time backwards). The TRADEOFF: timestamps within a\n * re-anchor window are logical — ordered and stable, but clustered near the\n * window's anchor rather than wall-clock-accurate. Run `elapsed`\n * (`endedAt - startedAt`) and per-turn `createdAt` lose precision down to the\n * window granularity; live-only measurements (TTFT, `maxWallMs`) are\n * unaffected because the loop reads those from `Date.now()` directly. Lower\n * `reanchorEvery` ⇒ more accurate timestamps + more suspensions; higher ⇒\n * fewer suspensions + more clustering. Default is unchanged (every `now()`\n * journaled) so existing deployments keep wall-accurate timestamps until they\n * opt in.\n */\n\nimport type { AgentClock } from '../types'\nimport type { RestateContextLike } from './types'\nimport { createHash } from 'node:crypto'\n\n/** Default re-anchor cadence for the coalescing clock (see {@link RestateClockOptions}). */\nconst DEFAULT_REANCHOR_EVERY = 8\n\n/**\n * RFC-4122-v4-shaped UUID derived from a seed string — pure function, no\n * RNG. Version/variant bits are set so consumers (and DB uuid columns)\n * treat it as a regular v4 UUID.\n */\nexport function deterministicUuid(seed: string): string {\n const bytes = createHash('sha256').update(seed).digest()\n bytes[6] = (bytes[6]! & 0x0F) | 0x40\n bytes[8] = (bytes[8]! & 0x3F) | 0x80\n const hex = bytes.subarray(0, 16).toString('hex')\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`\n}\n\nexport interface RestateClockOptions {\n /**\n * Coalesce `ctx.date.now()` journaling to cut Restate suspensions.\n *\n * - `false` / omitted (default): every `now()` journals a fresh\n * `ctx.date.now()` — wall-accurate, one suspension per call.\n * - `true`: enable coalescing with the default re-anchor cadence\n * ({@link DEFAULT_REANCHOR_EVERY}).\n * - `{ reanchorEvery: n }`: enable coalescing and re-anchor against the\n * real clock every `n` calls (`n` floored to a positive integer; falls\n * back to the default otherwise).\n *\n * See the module docstring for the determinism guarantees and the\n * timestamp-precision tradeoff.\n */\n coalesce?: boolean | { reanchorEvery?: number }\n /**\n * Entropy source for the deterministic `randomUUID()` sequence. Pass a\n * per-invocation stable value (the virtual object key, a workflow id, …)\n * so construction consumes zero `ctx.rand` draws. When omitted, the clock\n * draws `ctx.rand.uuidv4()` ONCE at construction as its seed — see the\n * module docstring for why that single draw is safe where later draws are\n * not.\n */\n idSeed?: string\n}\n\n/**\n * Wrap a Restate context into the {@link AgentClock} shape Zidane consumes\n * for journaled metadata: `now()` rides the journaled `ctx.date.now()`;\n * `randomUUID()` is a clock-private deterministic sequence (see the module\n * docstring — deliberately NOT `ctx.rand`).\n *\n * With `{ coalesce }` set, `now()` instead journals a real anchor\n * periodically and derives a monotonic logical sequence in between — see\n * the module docstring for the suspension/precision tradeoff. Do not reuse a\n * coalescing clock across invocations: the anchor/counter state is\n * per-invocation.\n */\nexport function restateClock(ctx: RestateContextLike, options: RestateClockOptions = {}): AgentClock {\n const { coalesce } = options\n\n // Draw-order-independent id minting — see the module docstring. The seed\n // is fixed at construction; each mint hashes (seed, local counter).\n const idSeed = options.idSeed ?? ctx.rand.uuidv4()\n let idSeq = 0\n const randomUUID = (): string => deterministicUuid(`${idSeed}:uuid:${idSeq++}`)\n\n if (!coalesce) {\n return {\n now: () => ctx.date.now(),\n randomUUID,\n // Tells wall-clock-sensitive consumers (e.g. the `spawn` tool's\n // per-child timeout) that time here replays instead of advancing, so\n // they must not branch on a timer.\n journaled: true,\n }\n }\n\n const requested = typeof coalesce === 'object' ? coalesce.reanchorEvery : undefined\n const reanchorEvery = typeof requested === 'number' && Number.isFinite(requested) && requested >= 1\n ? Math.floor(requested)\n : DEFAULT_REANCHOR_EVERY\n\n let anchor: number | undefined\n let callsSinceAnchor = 0\n let lastReturned = -1\n\n return {\n now: async (): Promise<number> => {\n // Re-anchor on the first call and every `reanchorEvery` calls after.\n // The decision is driven purely by the call counter (NOT wall-clock),\n // so it lands at identical call ordinals on replay — the journaled\n // `ctx.date.now()` entries are consumed in the same positions.\n if (anchor === undefined || callsSinceAnchor >= reanchorEvery) {\n anchor = await ctx.date.now()\n callsSinceAnchor = 0\n }\n const candidate = anchor + callsSinceAnchor\n callsSinceAnchor += 1\n // Clamp so a fresh real anchor that lands at or before the prior\n // logical value never rewinds time (a short, call-dense run can outrun\n // the wall clock within a window).\n const value = candidate > lastReturned ? candidate : lastReturned + 1\n lastReturned = value\n return value\n },\n randomUUID,\n journaled: true,\n }\n}\n","/**\n * Soft tool-error plumbing shared by {@link restateTool} and\n * {@link restateMcpToolWrap}.\n *\n * The problem: `restateTool` runs a tool body inside `ctx.run(...,\n * { maxRetryAttempts: 1 })`. An ordinary, recoverable tool throw (a failed\n * shell command, a transport error, an MCP `isError` result) would exhaust the\n * retry budget and surface as a Restate `TerminalError` — which\n * `restateBehavior`'s `shouldRethrowToolError` re-throws, aborting the whole\n * run. That's the opposite of the non-Restate model, where a tool throw becomes\n * a model-visible `tool_result { isError }` and the loop keeps going.\n *\n * The fix (same shape the MCP wrapper has always used): catch the recoverable\n * throw INSIDE the journaled closure and record it as a JSON-serializable\n * sentinel — so `ctx.run` journals a *value*, never a failed action. OUTSIDE the\n * journal (on both live and replay) the sentinel is turned back into a plain,\n * non-control `Error`, so the loop produces a `tool_result { isError }` and\n * continues. Real Restate control errors and deliberate aborts are never\n * softened — they must escape so the runtime can suspend / retry / cancel.\n */\n\nimport { shouldRethrowRestateControlError } from './errors'\n\n/** Journal value recorded for a softened tool throw. */\nconst SOFT_ERROR_KEY = '__zidaneRestateSoftError'\n\nexport interface SoftToolError {\n [SOFT_ERROR_KEY]: true\n message: string\n}\n\nexport function isSoftToolError(value: unknown): value is SoftToolError {\n return typeof value === 'object'\n && value !== null\n && (value as Record<string, unknown>)[SOFT_ERROR_KEY] === true\n}\n\n/** Build the sentinel recorded as the journal value for a softened throw. */\nexport function makeSoftToolError(error: unknown): SoftToolError {\n return { [SOFT_ERROR_KEY]: true, message: error instanceof Error ? error.message : String(error) }\n}\n\n/**\n * Recoverable throws soften; control-flow + abort throws do not.\n *\n * - Restate control errors (`TerminalError`, `SuspendedError`, …) must escape\n * so the runtime can act on them.\n * - Deliberate aborts (run cancel, `cancelTool`, sibling cascade) are a\n * timing-dependent, non-deterministic outcome — journaling one would bake it\n * into replay. The `signal.aborted` check also catches transports (the MCP\n * layer) that reject an aborted call with a plain `Error` carrying no\n * `AbortError` name.\n */\nexport function isRestateControlOrAbort(error: unknown, signal?: AbortSignal): boolean {\n if (shouldRethrowRestateControlError(error))\n return true\n if (error instanceof Error && error.name === 'AbortError')\n return true\n return signal?.aborted === true\n}\n\n/**\n * Outside-the-journal counterpart to {@link makeSoftToolError}: re-throw a\n * recorded sentinel as a plain (non-control) `Error`, else pass the value\n * through untouched.\n */\nexport function rethrowSoftToolError<T>(value: T): Exclude<T, SoftToolError> {\n if (isSoftToolError(value))\n throw new Error(value.message)\n return value as Exclude<T, SoftToolError>\n}\n","/**\n * Restate-backed tool wrappers.\n *\n * Wraps `ToolDef.execute` so every tool invocation is journaled. The\n * tool body runs on the original execution; after Restate persists the\n * journal entry, replay returns the recorded result without re-executing.\n * If the process dies before the entry is durable, the latest in-flight\n * tool can run again, so non-idempotent tools still need idempotency keys.\n *\n * `tool:gate`, `tool:transform`, `tool:after` hooks fire OUTSIDE the\n * journaled boundary, so they re-execute on replay. Built-in handlers\n * are deterministic given the journaled input + output (truncation,\n * image-stripping, `<edit-outcomes>` merge — all pure). Consumer hooks\n * that hit external services should themselves wrap side effects in\n * `ctx.run` so the substitution / annotation is replay-stable.\n *\n * `isConcurrencySafe` is preserved — Restate's per-key serialization\n * doesn't preclude in-handler parallelism. The loop's scheduler still\n * fans out safe tools up to `behavior.maxConcurrentTools`, each call\n * lands in its own journal entry. Order-of-journal-completion does NOT\n * affect replay correctness: Restate journals by call-site name, not\n * by completion order.\n */\n\nimport type { AliasMaps } from '../aliasing'\nimport type { DetachedTasksCapability } from '../contexts'\nimport type { Session } from '../session'\nimport type { StagedToolState, ToolStateOp } from '../tool-state'\nimport type { ToolContext, ToolDef } from '../tools/types'\nimport type { ToolResultContent } from '../types'\nimport type { RestatePromiseRaceLike } from './awakeable'\nimport type { RestatePromiseLike } from './parallel'\nimport type { ReplayTracker } from './replay'\nimport type { RestateContextLike, RestateRunOptions } from './types'\nimport { buildAliasMaps } from '../aliasing'\nimport { isToolStateOps, stagedToolState } from '../tool-state'\nimport { hydrateReadStateFromSessionAsync } from '../tools/read-state'\nimport { coerceToolResultContent } from '../types'\nimport { awakeableWithTimeout } from './awakeable'\nimport { isRestateControlOrAbort, makeSoftToolError, rethrowSoftToolError } from './soft-errors'\n\n/**\n * Opt-in two-phase journaling for long-running, re-attachable tools.\n *\n * The default `restateTool` wrapping journals only the COMPLETED result —\n * a crash mid-execute re-runs the tool on replay, which is unacceptable\n * for builds / migrations / deploys. `durableStart` splits the execution:\n *\n * 1. `start` runs inside its own `ctx.run` entry, journaled BEFORE the\n * body — it kicks off the side effect and returns a re-attach token\n * (a background task id, a job handle, an idempotency key).\n * 2. the wait — either `attach` (one `ctx.run` holding the wait in the\n * result entry; only for short, bounded waits) or `wait` (awakeable\n * park: register a resumer in a journaled entry, suspend outside\n * the journal, synthesize the result in a final entry). On replay\n * both receive the SAME token and re-attach to the already-running\n * work instead of starting it again.\n *\n * The wrapped tool's own `execute` is bypassed; the start + wait pair IS\n * the execution.\n */\nexport interface RestateDurableStart<Token = unknown, Resumed = unknown> {\n /** Kick off the side effect; journaled before `attach`. Must be cheap + idempotent-safe up to journal persistence. */\n start: (input: Record<string, unknown>, toolCtx: ToolContext) => Promise<Token> | Token\n /**\n * Await / re-attach to the work identified by `token` and produce the\n * tool result. Runs inside ONE `ctx.run` entry, so the body must\n * settle within the runtime's attempt lifecycle — a long busy-poll in\n * here starves the journal, trips the server's inactivity/abort\n * timeouts, and each retry restarts the wait from scratch. Use this\n * only for waits bounded well below the inactivity timeout (or as the\n * degraded mode on hosts without a push seam); prefer {@link wait}\n * for anything long-running.\n *\n * Required unless {@link wait} is provided; ignored when both are set.\n */\n attach?: (token: Token, input: Record<string, unknown>, toolCtx: ToolContext) => Promise<string | ToolResultContent[]>\n /**\n * Awakeable-based completion wait — the durable alternative to\n * {@link attach} for long-running work on hosts with a push seam\n * (e.g. a runner that fires `task:exit` → resumer → `ctx.resolveAwakeable`).\n * `executeTwoPhase` orchestrates three phases with the same journal\n * discipline as `restateAwakeableTool`:\n *\n * 1. `register` — a short, journaled `ctx.run`: hand the awakeable\n * id to the host as the exit resumer for `token`. Fires exactly\n * once across replays (marker invariant included).\n * 2. park — `await awakeable.promise`, OUTSIDE any `ctx.run`. The\n * invocation suspends cleanly: no held worker, immune to\n * inactivity/abort timeouts. With `timeoutMs`, the park is a\n * durable race against `ctx.sleep` (replay-stable — no\n * `Date.now()` deadline that resets per attempt).\n * 3. `result` — a final journaled `ctx.run`: synthesize the tool\n * result from the resumer payload (`null` = timeout; kill the\n * job and shape the timeout result here).\n */\n wait?: RestateDurableWait<Token, Resumed>\n /**\n * Best-effort cleanup when the per-call abort signal fires before the\n * wait settles — `attach` or the awakeable park alike (run abort,\n * `agent.cancelTool`, sibling-cascade\n * cancel, `agent.destroy()` mid-run). Without it, the journaled token\n * identifies a remote job that keeps running with nobody attached —\n * a leak for hosts whose jobs outlive the session.\n *\n * Contract:\n * - Fires at most once per call, outside the journal (an aborting\n * invocation can't open new `ctx.run` entries reliably) — journal\n * your own cleanup on the host side if it must be durable.\n * - May run concurrently with a still-unwinding `attach`; make it\n * idempotent against \"job already gone\".\n * - NOT called on process death — that's not termination: the\n * journaled token re-attaches on replay instead. This seam is for\n * deliberate aborts, where no replay is coming.\n * - Errors are swallowed (surfaced under `ZIDANE_DEBUG`) — cleanup\n * failure must not mask the abort itself.\n */\n onAbort?: (token: Token, input: Record<string, unknown>, toolCtx: ToolContext) => Promise<void> | void\n}\n\n/**\n * Awakeable-based completion wait for {@link RestateDurableStart.wait}.\n *\n * Replay contract (mirrors `restateAwakeableTool`):\n * - The awakeable is minted BEFORE the journaled `register` entry, so on\n * replay both come back in the same order with the same id — a replayed\n * call re-parks on the SAME awakeable without re-registering.\n * - The journaled marker records the awakeable id it was registered for;\n * a mismatch on replay (journal drift) throws instead of parking on an\n * id nobody will ever resolve.\n */\nexport interface RestateDurableWait<Token = unknown, Resumed = unknown> {\n /**\n * Register `awakeableId` as the exit resumer for the work identified\n * by `token` — the host must call `ctx.resolveAwakeable(awakeableId,\n * payload)` when the work completes. Runs inside `ctx.run`; must be\n * short and idempotent-safe up to journal persistence.\n */\n register: (token: Token, awakeableId: string, input: Record<string, unknown>, toolCtx: ToolContext) => Promise<void> | void\n /**\n * Synthesize the tool result once the park settles. `resumed` is the\n * resumer's payload, or `null` when `timeoutMs` elapsed first — kill\n * the still-running job and shape the timeout result in that branch.\n * Runs inside the final journaled `ctx.run` (the result entry).\n */\n result: (token: Token, resumed: Resumed | null, input: Record<string, unknown>, toolCtx: ToolContext) => Promise<string | ToolResultContent[]> | string | ToolResultContent[]\n /**\n * Durable park deadline in milliseconds — becomes the\n * `awakeableWithTimeout` duration (a `ctx.sleep` raced against the\n * awakeable, replay-stable). A function receives the call's input so\n * the model's own `timeout` parameter can drive it. Unset /\n * non-positive = park indefinitely.\n */\n timeoutMs?: number | ((input: Record<string, unknown>, toolCtx: ToolContext) => number | undefined)\n /**\n * Durable race combinator for the timeout race — pass `RestatePromise`\n * from the SDK. See `awakeableWithTimeout`'s rationale; native\n * `Promise.race` is the fallback.\n */\n promises?: RestatePromiseRaceLike\n /**\n * Per-call fast path: when this returns `true` for the journaled\n * `token`, the awakeable park is SKIPPED entirely — no awakeable is\n * minted, no `-register` entry is journaled, and the invocation never\n * suspends. `result` is invoked directly with `resumed = null` inside\n * the final result entry.\n *\n * This is for `start` phases that sometimes have nothing to wait on\n * (e.g. a shell tool that only spawns a real background task above a\n * duration threshold and otherwise runs the command inline in\n * `result`). Parking such calls pays a full suspend → resolve →\n * re-invoke → replay round-trip for nothing.\n *\n * MUST be a pure function of the journaled `token` (+ input) so the\n * decision is identical across replays — a token-derived branch keeps\n * the journal entry shape deterministic. When omitted, every call\n * parks (the original behaviour).\n */\n inline?: (token: Token, input: Record<string, unknown>, toolCtx: ToolContext) => boolean\n}\n\n/** Journaled registration marker — see the marker invariant in {@link RestateDurableWait}. */\ninterface DurableWaitRegisterMarker {\n registered: true\n awakeableId: string\n}\n\nexport interface RestateToolOptions<Token = unknown, Resumed = unknown> {\n /**\n * `ctx.run` options forwarded on every wrapped tool call. Defaults to\n * `{ maxRetryAttempts: 1 }` — tool errors are typically deterministic\n * (validation failures, missing files) so blind retries waste budget.\n * Override per-tool for network-heavy custom tools that benefit from\n * SDK-level retries.\n */\n runOptions?: RestateRunOptions\n /**\n * Override the journal-entry name. Receives the canonical tool name, the\n * call's input, and the model's `callId` (when the runtime provides one).\n * Default: `tool-<name>-<seq>` where `<seq>` is a per-wrapper monotonic\n * counter. The counter is replay-stable as long as dispatch order is\n * deterministic; key on `callId` instead for a model-deterministic name\n * that's robust even under `maxConcurrentTools > 1`.\n */\n entryName?: (seq: number, name: string, input: Record<string, unknown>, callId?: string) => string\n /**\n * Hide and reject the built-in shell tool's background mode.\n *\n * Default: derived from {@link RestateToolOptions.detachedTasks} —\n * disabled unless the execution context declares `'durable'` detached\n * tasks. An explicit boolean always wins.\n */\n disableShellBackground?: boolean\n /**\n * `detachedTasks` capability of the execution context the agent will\n * run with (see `ContextCapabilities.detachedTasks` /\n * `resolveDetachedTasksCapability`). Drives the\n * `disableShellBackground` default: a `'durable'` context keeps its\n * background tasks across worker crashes, so the wrapper leaves the\n * shell tool's background mode intact.\n *\n * Default: `undefined`, treated as non-durable (background disabled).\n */\n detachedTasks?: DetachedTasksCapability\n /**\n * Two-phase start/attach journaling for crash-safe long tools — see\n * {@link RestateDurableStart}. Per-tool by nature; not accepted by\n * `wrapAgentTools` (a single start/attach pair can't fit a whole map).\n */\n durableStart?: RestateDurableStart<Token, Resumed>\n /**\n * Per-invocation replay tracker (see `createReplayTracker`). When set,\n * the wrapper marks it live from inside its journaled closures — i.e.\n * the first time a tool body (or a `durableStart.start` phase)\n * ACTUALLY executes rather than replaying from the journal. Share one\n * tracker across the provider and tool wrappers of the same handler\n * invocation.\n */\n replayTracker?: ReplayTracker\n /**\n * Keep an ordinary, recoverable tool throw (a failed shell command, a\n * transport error, an MCP `isError`) NON-fatal under Restate.\n *\n * Without this, the throw rides out of the journaled `ctx.run` action,\n * exhausts the retry budget, and surfaces as a Restate `TerminalError` —\n * which `restateBehavior`'s `shouldRethrowToolError` re-throws, aborting the\n * whole run. With it, the throw is captured INSIDE the journal as a sentinel\n * value and re-thrown as a plain (non-control) error OUTSIDE it, so the loop\n * produces a model-visible `tool_result { isError }` and continues —\n * identical to the non-Restate soft-error model, and the same mechanism\n * `restateMcpToolWrap` already applies to MCP tools. Real Restate control\n * errors and deliberate aborts are never softened.\n *\n * Applies to the single-phase journaling path (the default wrapping and the\n * MCP path). The two-phase {@link RestateToolOptions.durableStart} mode owns\n * its own start/wait error shape and is unaffected.\n *\n * Default: `true`.\n */\n softErrors?: boolean\n /**\n * Collapse malformed structured result blocks (`{ type: 'image' }` with no\n * payload, foreign block shapes) to a text placeholder before the result is\n * journaled, so a downstream provider wire serializer never has to project an\n * unprojectable block (which, under Restate, would throw inside the journaled\n * provider call and become fatal). Well-formed results pass through\n * untouched. Applies to the single-phase journaling path.\n *\n * Default: `true`.\n */\n coerceResultBlocks?: boolean\n}\n\nconst SHELL_BACKGROUND_DISABLED_MESSAGE = 'shell error: background mode is disabled for Restate-backed agents. Fall back to foreground (drop `run_in_background`).'\n\n/**\n * Once-per-session (per process) guard for the restate tool wrapper's read-state\n * hydration. Rebuilds the map from `session.turns` the first time any wrapped\n * tool runs LIVE in a process, so `read_file` re-reads dedup correctly across a\n * replay (a journaled read never re-runs its live `rememberRead`).\n *\n * Note: the authoritative `requireReadBeforeEdit` recovery lives in the loop's\n * read-before-edit pre-hydration gate (see `agent.ts`), which fires regardless\n * of how tools are wrapped. This pass is the dedup-side complement for\n * `restateTool`-wrapped consumers; it is NOT what the gate depends on.\n */\nconst HYDRATED_READ_STATE_SESSIONS = new WeakSet<Session>()\n\n/**\n * Wrap a single `ToolDef` so its `execute` runs inside `ctx.run`. The\n * tool's `spec` and `isConcurrencySafe` pass through unchanged.\n */\nexport function restateTool<Token = unknown, Resumed = unknown>(\n inner: ToolDef,\n ctx: RestateContextLike,\n options: RestateToolOptions<Token, Resumed> = {},\n): ToolDef {\n const runOpts: RestateRunOptions = options.runOptions ?? { maxRetryAttempts: 1 }\n const nameFor = options.entryName ?? ((seq: number, name: string) => `tool-${name}-${seq}`)\n const canonicalName = inner.spec.name\n const disableShellBackground = options.disableShellBackground ?? (options.detachedTasks !== 'durable')\n const shellBackgroundDisabled = disableShellBackground && canonicalName === 'shell'\n const durableStart = options.durableStart\n if (durableStart && !durableStart.attach && !durableStart.wait)\n throw new Error(`restateTool(${canonicalName}): durableStart needs an \\`attach\\` (in-journal wait) or a \\`wait\\` (awakeable park) phase`)\n let seq = 0\n const hydrateOnce = async (toolCtx: Parameters<ToolDef['execute']>[1]) => {\n // Short-circuit before touching `toolCtx.handle` — sessionless invocations\n // (direct tool calls, minimal test contexts) have no read-state to rebuild\n // and may not carry a handle at all.\n if (!toolCtx.session || HYDRATED_READ_STATE_SESSIONS.has(toolCtx.session))\n return\n HYDRATED_READ_STATE_SESSIONS.add(toolCtx.session)\n // Resolve wire aliases (e.g. `Read`/`Edit`) to canonical when matching\n // transcript tool-calls — parity with the agent's run-start hydration. The\n // built-in restate session store persists canonical names, so this is a\n // no-op there; it only matters for a custom store that journaled wire names.\n // Best-effort: the alias config was already validated at agent construction,\n // but never let a hydration helper throw out of the journaled closure.\n let aliasMaps: AliasMaps | undefined\n if (toolCtx.toolAliases) {\n try {\n aliasMaps = buildAliasMaps(toolCtx.toolAliases, Object.keys(toolCtx.tools))\n }\n catch {\n aliasMaps = undefined\n }\n }\n await hydrateReadStateFromSessionAsync(toolCtx.session, toolCtx.handle.cwd, {\n defaultLineNumbers: toolCtx.behavior?.readLineNumbers ?? true,\n ...(aliasMaps ? { aliasMaps } : {}),\n readFileForHash: async (path) => {\n try {\n return await toolCtx.execution.readFile(toolCtx.handle, path)\n }\n catch {\n return null\n }\n },\n })\n }\n const softErrors = options.softErrors ?? true\n const coerceBlocks = options.coerceResultBlocks ?? true\n\n // The journaled action. NOT async, and the raw `ctx.run` promise is returned\n // without native combinators so `durableExecute` consumers (the Restate\n // batch scheduler) keep the runtime's own promise shape (`.map`) intact.\n //\n // Soft errors are captured INSIDE the closure: a recoverable throw is\n // recorded as a sentinel *value*, never a failed action — that's what keeps\n // `ctx.run` from promoting it to a fatal `TerminalError`. The sentinel is\n // turned back into a throw OUTSIDE the journal (see `executeDurably` /\n // `durableExecuteImpl`). Control / abort throws are never softened.\n //\n // Durable tool state rides the SAME entry: whatever the body staged on\n // `toolCtx.state` is journaled as data next to the output (see\n // `attachToolState`), then re-seeded into the staging view outside the\n // journal so the loop's commit re-issues an identical write on replay.\n const runJournaled = (input: Record<string, unknown>, toolCtx: Parameters<ToolDef['execute']>[1]) => {\n seq += 1\n return ctx.run(\n nameFor(seq, canonicalName, input, toolCtx.callId),\n async () => {\n // Closure executes only when live — replays return the journaled\n // result without entering here.\n options.replayTracker?.markLive()\n await hydrateOnce(toolCtx)\n const staged = stagedToolState(toolCtx.state)\n // A `ctx.run` retry re-enters this closure; drop ops the failed\n // attempt staged so the journaled delta is exactly what this\n // attempt produced (single-phase mode has no earlier phase whose\n // writes could be lost here).\n staged?.clear()\n if (shellBackgroundDisabled && input.run_in_background === true)\n return SHELL_BACKGROUND_DISABLED_MESSAGE\n if (!softErrors) {\n const out = await inner.execute(input, toolCtx)\n return attachToolState(coerceBlocks ? coerceToolResultContent(out) : out, staged)\n }\n try {\n const out = await inner.execute(input, toolCtx)\n return attachToolState(coerceBlocks ? coerceToolResultContent(out) : out, staged)\n }\n catch (err) {\n if (isRestateControlOrAbort(err, toolCtx.signal as AbortSignal | undefined))\n throw err\n // A soft failure still journals the state the body staged before\n // it threw — the sentinel and the delta ride one entry, so live\n // and replay agree on both.\n return attachToolState(makeSoftToolError(err) as unknown as string, staged)\n }\n },\n runOpts,\n )\n }\n\n // Plain `execute`: await the journaled value, re-seed staged tool state from\n // it, and re-throw a captured soft error outside the journal. When soft\n // errors are off AND the call carries no state view, the raw mappable\n // promise is the execute (unchanged legacy shape).\n const finishJournaled = async (\n journaled: Promise<JournaledToolValue>,\n staged: StagedToolState | undefined,\n ): Promise<string | ToolResultContent[]> => {\n let value: JournaledToolValue\n try {\n value = await journaled\n }\n catch (err) {\n // Nothing was journaled (control error, abort, exhausted retries), so\n // the mutations this attempt staged must not reach the store — a\n // replay re-runs the body and stages them again.\n staged?.clear()\n throw err\n }\n const output = applyToolState(value, staged)\n return softErrors ? rethrowSoftToolError(output) : output\n }\n\n const executeDurably: ToolDef['execute'] = (input, toolCtx) => {\n const staged = stagedToolState(toolCtx.state)\n // Nothing to unwrap: hand back the runtime's own promise untouched, so\n // this path stays byte-identical to the pre-state-feature shape.\n if (!softErrors && !staged)\n return runJournaled(input, toolCtx) as Promise<string | ToolResultContent[]>\n return finishJournaled(runJournaled(input, toolCtx), staged)\n }\n\n // `durableExecute`: compose the same unwrap INTO the runtime's mappable\n // promise so the batch scheduler still receives a `.map`-able value.\n // A softened throw becomes a rejected mapped promise, which the scheduler\n // routes to a `tool_result { isError }` (never fatal). Falls back to the raw\n // promise on a non-mappable ctx so the loop's durable guard can report it.\n const durableExecuteImpl: ToolDef['durableExecute'] = (input, toolCtx) => {\n const staged = stagedToolState(toolCtx.state)\n if (!softErrors && !staged)\n return runJournaled(input, toolCtx) as Promise<string | ToolResultContent[]>\n return unwrapDurableToolValue(runJournaled(input, toolCtx), staged, softErrors)\n }\n\n // Two-phase mode: journal the start token BEFORE the body so a crash\n // mid-execution re-attaches on replay instead of re-running. The await\n // between the two entries makes this a native-async composition, so the\n // tool deliberately does NOT advertise `durableExecute` — the batch\n // scheduler runs it sequentially via plain `execute`, which is the\n // right shape for long re-attachable work anyway.\n //\n // Durable tool state here: staged ops accumulate ACROSS the phases and are\n // journaled by the final entry only (`wait.result` / `attach`), which is\n // the entry whose value the loop commits against. A write staged in the\n // `start` phase therefore survives a replay that reaches the final entry\n // live, but is lost if the process dies between the two — the start entry\n // replays from the journal without re-running the body that staged it.\n // Write state in the final phase when it has to be crash-durable.\n const executeTwoPhaseInner = async (input: Record<string, unknown>, toolCtx: Parameters<ToolDef['execute']>[1]) => {\n const start = durableStart!\n const staged = stagedToolState(toolCtx.state)\n seq += 1\n const entry = nameFor(seq, canonicalName, input, toolCtx.callId)\n // Final-phase entry: journal the body's output together with whatever\n // the call staged on `toolCtx.state`, then re-seed the staging view\n // outside the journal so replay commits the identical delta.\n const runFinal = async (\n body: () => Promise<string | ToolResultContent[]> | string | ToolResultContent[],\n ): Promise<string | ToolResultContent[]> => applyToolState(\n await ctx.run(\n entry,\n async () => {\n options.replayTracker?.markLive()\n return attachToolState(await body(), staged)\n },\n runOpts,\n ),\n staged,\n )\n const token = await ctx.run(\n `${entry}-start`,\n async () => {\n options.replayTracker?.markLive()\n await hydrateOnce(toolCtx)\n return start.start(input, toolCtx)\n },\n runOpts,\n )\n\n // Abort seam — see RestateDurableStart.onAbort. At-most-once via the\n // `fired` latch; armed only while the wait is in flight.\n const onAbort = start.onAbort\n const signal = toolCtx.signal as AbortSignal | undefined\n let fired = false\n const fireAbortCleanup = (): void => {\n if (fired || !onAbort)\n return\n fired = true\n Promise.resolve(onAbort(token, input, toolCtx)).catch((err: unknown) => {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/restate] durableStart onAbort threw: ${err instanceof Error ? err.message : String(err)}\\n`)\n })\n }\n\n const wait = start.wait\n if (wait) {\n // Per-call fast path: nothing to wait on for this token (decided\n // purely from the journaled token, so replay-stable). Skip minting\n // the awakeable, the `-register` entry, and the suspend/resume\n // round-trip entirely — run the result inline. A short command that\n // executes in the result entry shouldn't pay a park it never uses.\n if (wait.inline?.(token, input, toolCtx)) {\n if (!onAbort || !signal)\n return await runFinal(() => wait.result(token, null, input, toolCtx))\n if (signal.aborted)\n fireAbortCleanup()\n else\n signal.addEventListener('abort', fireAbortCleanup, { once: true })\n try {\n return await runFinal(() => wait.result(token, null, input, toolCtx))\n }\n finally {\n signal.removeEventListener('abort', fireAbortCleanup)\n }\n }\n // Awakeable path — register / park / result. The park lives\n // OUTSIDE any ctx.run, so the invocation suspends cleanly instead\n // of busy-holding an attempt until the inactivity timeout fires.\n //\n // Pre-aborted: nobody will consume the result — clean up the\n // journaled start and bail without registering a resumer.\n if (signal?.aborted) {\n fireAbortCleanup()\n throw new Error(`${canonicalName}: aborted before durable wait registration`)\n }\n signal?.addEventListener('abort', fireAbortCleanup, { once: true })\n try {\n const timeoutMs = typeof wait.timeoutMs === 'function' ? wait.timeoutMs(input, toolCtx) : wait.timeoutMs\n // Mint BEFORE the journaled registration (same ordering contract\n // as restateAwakeableTool) — replay returns the same id.\n const awakeable = awakeableWithTimeout<Resumed>(ctx, {\n ...(timeoutMs !== undefined ? { timeoutMs } : {}),\n ...(wait.promises ? { promises: wait.promises } : {}),\n })\n const marker = await ctx.run<DurableWaitRegisterMarker>(\n `${entry}-register`,\n async () => {\n options.replayTracker?.markLive()\n await wait.register(token, awakeable.id, input, toolCtx)\n return { registered: true, awakeableId: awakeable.id }\n },\n runOpts,\n )\n if (marker.awakeableId !== awakeable.id) {\n throw new Error(\n `restateTool(${canonicalName}): journal drift — registration marker carries awakeable \"${marker.awakeableId}\" but this replay minted \"${awakeable.id}\". Refusing to park on an unreachable awakeable.`,\n )\n }\n const resumed = await parkWithSignal(awakeable.promise, signal, canonicalName)\n return await runFinal(() => wait.result(token, resumed, input, toolCtx))\n }\n finally {\n signal?.removeEventListener('abort', fireAbortCleanup)\n }\n }\n\n const attach = () => runFinal(() => start.attach!(token, input, toolCtx))\n\n if (!onAbort || !signal)\n return attach()\n\n // Pre-aborted: the journaled start already launched the job — clean\n // it up, then still run attach so the call surfaces the host's own\n // cancellation shape (it should fail fast on an aborted signal).\n if (signal.aborted) {\n fireAbortCleanup()\n return attach()\n }\n signal.addEventListener('abort', fireAbortCleanup, { once: true })\n try {\n return await attach()\n }\n finally {\n signal.removeEventListener('abort', fireAbortCleanup)\n }\n }\n\n const executeTwoPhase: ToolDef['execute'] = async (input, toolCtx) => {\n const staged = stagedToolState(toolCtx.state)\n try {\n return await executeTwoPhaseInner(input, toolCtx)\n }\n catch (err) {\n // Nothing journaled this delta (abort before registration, journal\n // drift, a throwing phase) — drop it so the loop's commit can't\n // persist a write no journal entry records.\n staged?.clear()\n throw err\n }\n }\n\n if (durableStart) {\n // Strip any pre-existing `durableExecute` — see the executeTwoPhase\n // comment; advertising one here would hand the batch scheduler a\n // native promise it can't `.map`.\n const { durableExecute: _dropped, ...rest } = inner\n return {\n ...rest,\n spec: shellBackgroundDisabled ? withoutShellBackgroundInput(inner.spec) : inner.spec,\n execute: executeTwoPhase,\n }\n }\n\n return {\n ...inner,\n spec: shellBackgroundDisabled ? withoutShellBackgroundInput(inner.spec) : inner.spec,\n execute: executeDurably,\n durableExecute: durableExecuteImpl,\n }\n}\n\n/**\n * Journaled value of a wrapped tool: the output, or an envelope carrying the\n * output plus the tool-state ops the body staged. The envelope only appears\n * when a tool actually wrote state, so journals produced by calls that don't\n * touch `ToolContext.state` are byte-identical to pre-state-feature ones —\n * in-flight invocations keep replaying across a deploy that enables this.\n */\ntype JournaledToolValue = string | ToolResultContent[] | ToolStateEnvelope\n\ninterface ToolStateEnvelope {\n /**\n * Format marker, and the ONLY thing detection keys on (together with\n * `ops` being an array). Deliberately not the op list itself: journal\n * values round-trip through JSON, which drops undefined-valued and\n * unserializable properties, so a schema check on the payload could fail\n * on replay for a value that passed it live — and a false negative here\n * hands the raw envelope object to the model as the tool output.\n */\n __zidaneToolState: 1\n ops: ToolStateOp[]\n output: string | ToolResultContent[]\n}\n\nfunction isToolStateEnvelope(value: unknown): value is ToolStateEnvelope {\n if (typeof value !== 'object' || value === null || Array.isArray(value))\n return false\n const candidate = value as Partial<ToolStateEnvelope>\n return candidate.__zidaneToolState === 1 && Array.isArray(candidate.ops) && 'output' in candidate\n}\n\n/**\n * Wrap the output with the staged ops so they cross the journal as DATA.\n * Returns the output untouched when nothing was staged — the no-state path\n * must not change the journaled shape.\n */\nfunction attachToolState(\n output: string | ToolResultContent[],\n staged: StagedToolState | undefined,\n): JournaledToolValue {\n const ops = staged?.pending() ?? []\n return ops.length === 0 ? output : { __zidaneToolState: 1, ops, output }\n}\n\n/**\n * Inverse of {@link attachToolState}, run OUTSIDE the journal: re-seed the\n * staging view from the journaled ops so the loop's commit writes the same\n * thing on a live attempt and on every replay. A value with no envelope\n * clears the view — whatever it holds was staged by an attempt no journal\n * entry records, and committing that would be a write replay can't reproduce.\n */\nfunction applyToolState(\n value: JournaledToolValue,\n staged: StagedToolState | undefined,\n): string | ToolResultContent[] {\n if (isToolStateEnvelope(value)) {\n // Ops are validated separately from detection: a delta mangled in\n // transit is dropped (never committed half-formed) while the output —\n // the part the model consumes — still comes through intact.\n if (isToolStateOps(value.ops))\n staged?.restore(value.ops)\n else\n staged?.clear()\n return value.output\n }\n staged?.clear()\n return value\n}\n\n/**\n * Compose the state unwrap + soft-error unwrap into the runtime's mappable\n * durable promise. A journaled sentinel becomes a thrown (rejected) value so\n * the Restate batch scheduler classifies it as a tool failure →\n * `tool_result { isError }`; a real action failure (control error) is rethrown\n * verbatim. Non-mappable promises (a ctx without the SDK's `RestatePromise`)\n * pass through so the loop's durable guard surfaces the \"not a mappable\n * durable promise\" error instead.\n */\nfunction unwrapDurableToolValue(\n promise: Promise<JournaledToolValue>,\n staged: StagedToolState | undefined,\n softErrors: boolean,\n): Promise<string | ToolResultContent[]> {\n const mappable = promise as Partial<RestatePromiseLike<JournaledToolValue>>\n if (typeof mappable.map !== 'function')\n return promise as Promise<string | ToolResultContent[]>\n return mappable.map((value, failure) => {\n if (failure !== undefined) {\n staged?.clear()\n throw failure instanceof Error ? failure : new Error(String(failure))\n }\n const output = applyToolState(value as JournaledToolValue, staged)\n return softErrors ? rethrowSoftToolError(output) : output\n })\n}\n\n/**\n * Park on `promise`, but stop waiting when the per-call abort signal\n * fires (run abort, `cancelTool`, sibling-cascade cancel) — a deliberate\n * abort means nobody will consume the result, and like `onAbort` it\n * implies no replay is coming, so the native (non-journaled) race is\n * replay-safe. The underlying awakeable stays registered; a late\n * resolution lands on a completed invocation and is dropped by the\n * runtime.\n */\nfunction parkWithSignal<T>(promise: Promise<T>, signal: AbortSignal | undefined, name: string): Promise<T> {\n if (!signal)\n return promise\n if (signal.aborted)\n return Promise.reject(new Error(`${name}: aborted while parked on durable wait`))\n return new Promise<T>((resolve, reject) => {\n const onAbortEvt = (): void => reject(new Error(`${name}: aborted while parked on durable wait`))\n signal.addEventListener('abort', onAbortEvt, { once: true })\n promise.then(\n (value) => {\n signal.removeEventListener('abort', onAbortEvt)\n resolve(value)\n },\n (err: unknown) => {\n signal.removeEventListener('abort', onAbortEvt)\n reject(err instanceof Error ? err : new Error(String(err)))\n },\n )\n })\n}\n\nfunction withoutShellBackgroundInput(spec: ToolDef['spec']): ToolDef['spec'] {\n const inputSchema = spec.inputSchema\n const properties = isRecord(inputSchema.properties) ? inputSchema.properties : undefined\n if (!properties || !Object.hasOwn(properties, 'run_in_background'))\n return spec\n\n const { run_in_background: _runInBackground, ...nextProperties } = properties\n const required = Array.isArray(inputSchema.required)\n ? inputSchema.required.filter(name => name !== 'run_in_background')\n : inputSchema.required\n return {\n ...spec,\n description: stripShellBackgroundDescription(spec.description),\n inputSchema: {\n ...inputSchema,\n properties: nextProperties,\n ...(required !== inputSchema.required ? { required } : {}),\n },\n }\n}\n\nfunction stripShellBackgroundDescription(description: string): string {\n return description\n .split('\\n')\n .filter(line =>\n !line.includes('run_in_background')\n && !line.includes('<task-notification>')\n && !line.includes('background task'),\n )\n .join('\\n')\n .replace(/\\n{3,}/g, '\\n\\n')\n .trim()\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\n/**\n * Wrap an entire tool map at once — convenience for the common case of\n * \"journal every tool the agent has\". Pass-through for tools whose\n * names are listed in `opts.exclude` (e.g. fully-deterministic local\n * helpers where journaling is pure overhead).\n *\n * The returned map is a fresh object; the input is untouched.\n */\nexport function wrapAgentTools(\n tools: Record<string, ToolDef>,\n ctx: RestateContextLike,\n opts: Omit<RestateToolOptions, 'durableStart'> & { exclude?: readonly string[] } = {},\n): Record<string, ToolDef> {\n const excludeSet = new Set(opts.exclude ?? [])\n // `detachedTasks: 'durable'` implies the host's `waitBackground` parks\n // on an awakeable (that's the durable wait pattern) — and a Restate\n // suspension point must NOT nest inside a journaled `ctx.run` closure.\n // Auto-exclude the built-in `wait_task` from wrapping so its park runs\n // outside the journal; the wait result is replay-safe anyway (a replayed\n // wait re-attaches to an already-terminated task and resolves from the\n // registry). Hosts with a journal-safe wait (e.g. a bridge RPC poll)\n // can re-wrap explicitly via `restateTool(waitTask, ctx, …)`.\n const skipWaitTask = opts.detachedTasks === 'durable'\n const wrapped: Record<string, ToolDef> = {}\n for (const [name, def] of Object.entries(tools)) {\n // A tool that runs a nested agent loop (`spawn`, or a host orchestrator\n // tool) is NEVER wrapped: the child drives the same journaled provider and\n // the same wrapped tools, so its `ctx.run` entries would nest inside this\n // tool's own journaled closure. Left unwrapped, the child's steps journal\n // DIRECTLY into the parent's journal — each provider call and tool call\n // individually replayable, which is what makes a crash mid-subagent\n // recover for free. Keyed on the declarative `ToolDef.runsNestedAgent`\n // marker rather than the tool name, so a host tool that merely happens to\n // be named `spawn` still gets wrapped.\n //\n // Deliberate escape hatch: wrapping a spawn tool explicitly via\n // `restateTool(spawnTool, ctx, …)` is legal IF that child is fully\n // non-durable (raw provider, unwrapped tools) — then the whole child\n // collapses into ONE journal entry. See `docs/RESTATE.md` § Subagents.\n const passThrough = excludeSet.has(name)\n || def.runsNestedAgent === true\n || (skipWaitTask && def.spec.name === 'wait_task')\n wrapped[name] = passThrough ? def : restateTool(def, ctx, opts)\n }\n return wrapped\n}\n","/**\n * Restate-backed MCP tool journaling.\n *\n * Native tools have a clean durability seam: wrap them with\n * `wrapAgentTools(tools, ctx)` before `createAgent`. MCP tools don't — they are\n * discovered from `mcpServers` and registered by the agent internally, AFTER\n * your wrapping opportunity. So under Restate their raw `callTool` never rides\n * `ctx.run`, and every journal replay re-runs the real MCP call (a\n * side-effecting tool fires once per replay).\n *\n * {@link restateMcpToolWrap} closes that gap. It's the value for the core\n * `AgentOptions.mcpToolWrap` hook — the agent keeps owning discovery,\n * `mcp_<server>_<tool>` namespacing, per-server `instructions`, hooks, and\n * OAuth, and applies the wrap to each discovered tool. You journal MCP results\n * the way `wrapAgentTools` journals native ones:\n *\n * ```ts\n * createAgent({\n * provider: restateProvider(inner, ctx),\n * tools: wrapAgentTools(nativeTools, ctx),\n * mcpServers,\n * mcpToolWrap: restateMcpToolWrap(ctx),\n * })\n * ```\n *\n * The hook composes with any `mcpConnector`, so a custom transport / auth\n * connector and journaling stay orthogonal — no separate connector helper\n * needed:\n *\n * ```ts\n * createAgent({\n * mcpServers,\n * mcpConnector: (configs, hooks) => connectMcpServers(configs, undefined, hooks, { buildAuthProvider }),\n * mcpToolWrap: restateMcpToolWrap(ctx),\n * })\n * ```\n *\n * ## Error semantics (preserved)\n *\n * MCP tools signal failure by THROWING (`buildMcpToolDef` throws on transport\n * errors, timeouts, and `CallToolResult.isError`). Naively wrapping that in\n * `restateTool` would let the throw exhaust `ctx.run`'s retries and surface as\n * a Restate `TerminalError`, which `restateBehavior`'s `shouldRethrowToolError`\n * re-throws — turning a recoverable MCP error into a fatal run. To keep the\n * non-Restate behaviour (MCP error → model-visible `tool_result { isError }`,\n * run continues) the wrapper journals with `restateTool`'s `softErrors`: the\n * failure is captured INSIDE the journaled closure as a sentinel value and\n * re-thrown as a plain (non-control) error OUTSIDE it. Replay reproduces the\n * same error from the journal without re-running the call; real Restate control\n * / abort errors are passed through untouched. (Native tools wrapped with\n * `wrapAgentTools` get the identical treatment — this is no longer MCP-specific\n * plumbing, just the shared default.)\n *\n * ## Journaling policy\n *\n * Default is plain result-journaling — correct for the short request/response\n * shape of most MCP calls. A genuinely long-running MCP tool (a remote build,\n * a migration) can opt into two-phase `durableStart` per-tool via\n * {@link RestateMcpToolWrapOptions.override}; `exclude` skips journaling for\n * deterministic reads.\n */\n\nimport type { McpToolMeta, McpToolWrap } from '../agent'\nimport type { ToolDef } from '../tools/types'\nimport type { ReplayTracker } from './replay'\nimport type { RestateToolOptions } from './tool'\nimport type { RestateContextLike, RestateRunOptions } from './types'\nimport { restateTool } from './tool'\n\nexport interface RestateMcpToolWrapOptions {\n /**\n * Shared per-invocation replay tracker (see `createReplayTracker`) —\n * threaded into every wrapped MCP tool so the first live `callTool` marks\n * the tracker live, exactly like `restateProvider` / `wrapAgentTools`. Use\n * one tracker per handler invocation across provider + native + MCP tools.\n */\n replayTracker?: ReplayTracker\n /**\n * `ctx.run` options forwarded to every wrapped MCP tool (default\n * `{ maxRetryAttempts: 1 }`). Note: recoverable MCP failures are\n * soft-captured as the journal value rather than thrown, so this retry\n * budget governs only Restate control-flow retries of the journaled action,\n * not re-dialing a failed MCP call — the model decides whether to retry.\n */\n runOptions?: RestateRunOptions\n /**\n * Override the journal-entry name per MCP tool call. Default:\n * `tool-<name>-<callId>` (model-deterministic, robust under concurrency)\n * falling back to `tool-<name>-<seq>` when the runtime provides no `callId`.\n */\n entryName?: (seq: number, name: string, input: Record<string, unknown>, callId?: string) => string\n /**\n * Namespaced MCP tool names (`mcp_<server>_<tool>`) to leave un-journaled —\n * they pass through exactly as discovered. For deterministic,\n * side-effect-free reads where journaling is pure overhead. Wins over\n * {@link override}.\n */\n exclude?: readonly string[]\n /**\n * Per-tool wrapping override. Receives the discovered tool + its\n * {@link McpToolMeta}; return a `ToolDef` to use verbatim (e.g.\n * `restateTool(tool, ctx, { durableStart })` for a long-running tool), or\n * `undefined` to fall through to the default soft-error result-journaling.\n * Lets a deployment opt specific tools into a different policy without\n * changing the blanket one.\n */\n override?: (tool: ToolDef, meta: McpToolMeta) => ToolDef | undefined\n}\n\n/**\n * Journal one discovered MCP tool via `restateTool` with `softErrors` on (a\n * recoverable MCP throw becomes a journaled `tool_result { isError }`, not a\n * fatal run — see the module's \"Error semantics\"). `durableExecute` is dropped:\n * MCP tools are concurrency barriers, so the batch scheduler runs them via the\n * (still journaled) `execute`, and dropping the mappable promise keeps the\n * scheduler from treating an MCP tool as a parallel-fleet member.\n */\nfunction journalMcpTool(tool: ToolDef, ctx: RestateContextLike, toolOptions: RestateToolOptions): ToolDef {\n const journaled = restateTool(tool, ctx, { ...toolOptions, softErrors: true, coerceResultBlocks: true })\n const { durableExecute: _dropped, ...rest } = journaled\n return rest\n}\n\nfunction toToolOptions(options: RestateMcpToolWrapOptions): RestateToolOptions {\n const entryName = options.entryName\n ?? ((seq: number, name: string, _input: Record<string, unknown>, callId?: string) =>\n callId ? `tool-${name}-${callId}` : `tool-${name}-${seq}`)\n return {\n entryName,\n ...(options.replayTracker !== undefined ? { replayTracker: options.replayTracker } : {}),\n ...(options.runOptions !== undefined ? { runOptions: options.runOptions } : {}),\n }\n}\n\n/**\n * Build an {@link McpToolWrap} for the `AgentOptions.mcpToolWrap` hook —\n * journals every discovered MCP tool's result (soft-error-preserving). The\n * MCP analogue of `wrapAgentTools`, and the single supported way to make\n * discovered MCP tools durable under Restate.\n */\nexport function restateMcpToolWrap(\n ctx: RestateContextLike,\n options: RestateMcpToolWrapOptions = {},\n): McpToolWrap {\n const excludeSet = new Set(options.exclude ?? [])\n const toolOptions = toToolOptions(options)\n return (tool, meta) => {\n if (excludeSet.has(tool.spec.name))\n return tool\n return options.override?.(tool, meta) ?? journalMcpTool(tool, ctx, toolOptions)\n }\n}\n","import type { ToolResult } from '../providers'\nimport type { ToolBatchExecutionContext, ToolBatchExecutor } from '../types'\n\nexport interface RestatePromiseAllLike<TPromise extends Promise<unknown> = RestatePromiseLike<unknown>> {\n all: (values: readonly TPromise[]) => Promise<readonly unknown[]>\n}\n\nexport type RestatePromiseLike<T> = Promise<T> & {\n map: <U>(mapper: (value?: T, failure?: unknown) => U) => Promise<U>\n}\n\nexport interface RestateToolBatchExecutorOptions<TPromise extends Promise<unknown> = RestatePromiseLike<unknown>> {\n /**\n * Wait for a safe fleet through Restate's durable combinator. Pass\n * `RestatePromise` from `@restatedev/restate-sdk` in real deployments.\n */\n promises: RestatePromiseAllLike<TPromise>\n}\n\n/**\n * Tool batch scheduler for Restate-backed agents.\n *\n * It preserves unsafe-tool barriers and emits results in model submission\n * order. Safe fleets are started in submission order, capped by\n * `maxConcurrentTools`, and joined via the supplied durable `all()`.\n */\nexport function restateToolBatchExecutor<TPromise extends Promise<unknown> = RestatePromiseLike<unknown>>(\n options: RestateToolBatchExecutorOptions<TPromise>,\n): ToolBatchExecutor {\n return async (ctx: ToolBatchExecutionContext): Promise<ToolResult[]> => {\n const results: ToolResult[] = []\n const { toolCalls } = ctx\n\n const fillRemaining = (from: number, factory: (index: number) => ToolResult): ToolResult[] => {\n for (let i = from; i < toolCalls.length; i++)\n results[i] = factory(i)\n return results\n }\n\n for (let i = 0; i < toolCalls.length;) {\n if (ctx.signal.aborted)\n return fillRemaining(i, ctx.interruptedResult)\n if (ctx.steeringQueue.length > 0)\n return fillRemaining(i, ctx.skippedResult)\n\n if (!ctx.isConcurrencySafe(i)) {\n results[i] = await ctx.execute(i)\n i += 1\n continue\n }\n\n const start = i\n const fleet: number[] = []\n while (\n i < toolCalls.length\n && ctx.isConcurrencySafe(i)\n && fleet.length < ctx.maxConcurrentTools\n ) {\n fleet.push(i)\n i += 1\n }\n\n const fleetResults = fleet.every(index => ctx.canExecuteDurably(index))\n ? await ctx.executeDurable(\n fleet,\n async <T>(values: readonly Promise<T>[]): Promise<readonly T[]> => {\n const results = await options.promises.all(values as readonly TPromise[])\n return results as readonly T[]\n },\n )\n : await executeSequential(ctx, fleet)\n for (let offset = 0; offset < fleetResults.length; offset++)\n results[start + offset] = fleetResults[offset]\n }\n\n return results\n }\n}\n\nasync function executeSequential(\n ctx: ToolBatchExecutionContext,\n indices: readonly number[],\n): Promise<ToolResult[]> {\n const results: ToolResult[] = []\n for (const index of indices) {\n if (ctx.signal.aborted) {\n results.push(ctx.interruptedResult(index))\n continue\n }\n if (ctx.steeringQueue.length > 0) {\n results.push(ctx.skippedResult(index))\n continue\n }\n results.push(await ctx.execute(index))\n }\n return results\n}\n","/**\n * Restate-backed Provider wrapper.\n *\n * Wraps `Provider.stream` so every assistant turn (the LLM call as a\n * whole) is journaled. The model is invoked once per turn — the live\n * stream still fires `onText` / `onThinking` callbacks for UX during the\n * original execution. On replay, `ctx.run` returns the journaled\n * `TurnResult` immediately and the inner provider is NEVER re-invoked →\n * no duplicate billed tokens, no duplicate stream chunks.\n *\n * Replay caveat: stream callbacks don't re-fire on replay. Consumers\n * that paint live UI from `stream:text` should reconstruct transcripts\n * from `session.turns` via `eventsFromTurns` (zidane/chat) instead of\n * relying on hook re-emission. The chat layer already does this.\n *\n * Journal-entry naming: a monotonic per-wrapper counter (`llm-call-1`,\n * `llm-call-2`, …). One wrapper instance per Restate handler invocation\n * resets the counter; Restate's journal is invocation-scoped so names\n * don't need to be globally unique. The counter ticks the same way on\n * replay because the wrapper is constructed fresh each attempt.\n */\n\nimport type { Provider, StreamCallbacks, StreamOptions, TurnResult } from '../providers'\nimport type { ReplayTracker } from './replay'\nimport type { RestateContextLike, RestateRunOptions } from './types'\n\nexport interface RestateProviderOptions {\n /**\n * `ctx.run` options forwarded on every wrapped stream call.\n *\n * Default depends on {@link streamCallbacks}:\n *\n * - `'suppress'` → `{ maxRetryAttempts: 3 }` — provider transients\n * (rate limits, 5xx, connection resets) get retried inside the\n * journal entry; nothing streams to the host, so a retry is\n * invisible.\n * - `'live'` (the default) → `{ maxRetryAttempts: 1 }`. A live stream\n * that fails AFTER emitting deltas would be re-run inside the same\n * journal entry, re-firing `onText` into the loop's accumulating\n * text buffer and producing duplicated partial1+full2 output. The\n * loop's own retry (which only re-issues on a clean slate) is the\n * correct retry layer in live mode.\n *\n * Once the cap is reached the failure becomes terminal and surfaces\n * through the loop's normal `AgentProviderError` path. Set this\n * explicitly to override either default — but with live callbacks,\n * `maxRetryAttempts > 1` re-introduces the duplicate-delta hazard.\n */\n runOptions?: RestateRunOptions\n /**\n * Override the journal-entry name. Receives the 1-indexed sequence\n * number for this wrapper instance and the `StreamOptions` of the\n * call. Default: `llm-call-<n>`. Override to inject extra structure\n * (e.g. `${agentName}/llm-call-${n}`) when multiple agents share a\n * service.\n */\n entryName?: (seq: number, opts: StreamOptions) => string\n /**\n * Whether live stream callbacks should fire during the original execution.\n * Use `'suppress'` for strict durable mode: the model call still returns a\n * full TurnResult, and UIs reconstruct from persisted session turns.\n *\n * Default: `'live'`.\n */\n streamCallbacks?: 'live' | 'suppress'\n /**\n * Per-invocation replay tracker (see `createReplayTracker`). When set,\n * the wrapper marks it live from inside the journaled closure — i.e.\n * the first time the inner provider is ACTUALLY invoked rather than\n * replayed from the journal. Share one tracker across the provider\n * and tool wrappers of the same handler invocation.\n */\n replayTracker?: ReplayTracker\n}\n\n/**\n * Wrap a Zidane `Provider` so its `stream()` method journals each turn's\n * response inside `ctx.run`. All other Provider methods (`formatTools`,\n * `userMessage`, `toolResultsMessage`, `classifyError`, …) pass through\n * unchanged — they're pure functions over already-deterministic inputs.\n */\nexport function restateProvider(\n inner: Provider,\n ctx: RestateContextLike,\n options: RestateProviderOptions = {},\n): Provider {\n // Live callbacks must not retry inside the journal entry — a stream that\n // fails after emitting deltas would re-fire `onText` on the retry and\n // duplicate text in the loop's accumulator. See the `runOptions` doc.\n const runOpts: RestateRunOptions = options.runOptions\n ?? (options.streamCallbacks === 'suppress' ? { maxRetryAttempts: 3 } : { maxRetryAttempts: 1 })\n const nameFor = options.entryName ?? ((seq: number) => `llm-call-${seq}`)\n let seq = 0\n\n return {\n ...inner,\n stream(streamOpts: StreamOptions, callbacks: StreamCallbacks): Promise<TurnResult> {\n seq += 1\n const durableCallbacks = options.streamCallbacks === 'suppress'\n ? suppressStreamingCallbacks(callbacks)\n : callbacks\n return ctx.run<TurnResult>(\n nameFor(seq, streamOpts),\n () => {\n // Reached only when the journal cursor is past this entry —\n // a replayed call returns the journaled TurnResult without\n // executing this closure.\n options.replayTracker?.markLive()\n return inner.stream(streamOpts, durableCallbacks)\n },\n runOpts,\n )\n },\n }\n}\n\nfunction suppressStreamingCallbacks(callbacks: StreamCallbacks): StreamCallbacks {\n return {\n ...callbacks,\n onText: () => {},\n onThinking: undefined,\n onServerToolUse: undefined,\n onServerToolResult: undefined,\n onToolCallDelta: undefined,\n }\n}\n","/**\n * Replay-state tracking + replay-aware abort for Restate-backed agents.\n *\n * ## The problem\n *\n * `agent.abort()` during a journal replay is undefined behavior: the\n * loop throws `AgentAbortedError` at whatever point the replay cursor\n * happens to be, the host's catch arm typically journals something\n * (`report-fail`, a status write) mid-journal, and the invocation dies\n * with `[570 Journal mismatch]` — permanently, because every retry\n * replays into the same mismatch. Hosts have been inferring liveness\n * from side channels (e.g. counting live provider stream calls), which\n * works only because `restateProvider` replays `llm-call-N` without\n * touching the live provider — incidental coupling, not API.\n *\n * ## The seam\n *\n * The wrappers already know the answer: on replay, `ctx.run` returns\n * the journaled value WITHOUT invoking the wrapped closure; the first\n * time a closure actually executes, the journal cursor is past the\n * replayed prefix and the invocation is live. {@link createReplayTracker}\n * packages that signal:\n *\n * - `restateProvider(inner, ctx, { replayTracker })` and\n * `restateTool(tool, ctx, { replayTracker })` mark the tracker live\n * from inside their journaled closures.\n * - `tracker.isReplaying()` is the public liveness probe.\n * - `tracker.onLive(cb)` fires once at the replay→live transition\n * (immediately when already live).\n * - {@link replayAwareAbort} wraps `agent.abort` so external aborts\n * queue during replay and apply at the first live boundary — the\n * earliest point where the abort's side effects (loop throw, host\n * catch-arm journaling) append to the journal instead of forking it.\n *\n * ## Wiring\n *\n * ```ts\n * const tracker = createReplayTracker({ hooks: agent.hooks })\n * const provider = restateProvider(inner, ctx, { replayTracker: tracker })\n * const tools = wrapAgentTools(agentTools, ctx, { replayTracker: tracker })\n * const abort = replayAwareAbort(tracker, () => agent.abort())\n * // external cancel signal → abort() instead of agent.abort()\n * ```\n *\n * One tracker per handler invocation — like the wrappers themselves, it\n * is constructed fresh each attempt and must not be reused across\n * invocations.\n *\n * ## Semantics fine print\n *\n * \"Replaying\" is defined conservatively: `isReplaying()` returns `true`\n * until the first live closure executes. A fresh (non-resumed)\n * invocation therefore reports \"replaying\" for the short window before\n * its first journaled call — harmless for the abort use case (the abort\n * applies moments later, at that first live execution) and the honest\n * answer for journal safety: before the first `ctx.run` settles you\n * cannot know whether the SDK is about to feed you journal entries.\n *\n * That conservative window is wrong for live STREAMING, though: on a\n * fresh run it would suppress the opening output. Streamers should pass\n * `resuming` (the host knows whether this is a crash-recovery replay) and\n * gate on {@link ReplayTracker.isResuming} instead — `false` from the\n * start of a fresh run, `true` only while replaying a resumed journal.\n *\n * A replay that completes without ever going live (the journaled run\n * already finished; the handler exits during replay) never fires\n * `onLive` — queued aborts are dropped with the invocation, which is\n * correct: there is nothing left to abort.\n */\n\n/** Minimal structural slice of the agent's Hookable for `replay:done`. */\nexport interface ReplayDoneHooks {\n callHook: (name: 'replay:done', ctx: Record<string, never>) => unknown\n}\n\nexport interface ReplayTrackerOptions {\n /**\n * Agent hooks to notify at the replay→live transition. When set, the\n * tracker fires `replay:done` exactly once, right after the `onLive`\n * callbacks. Rejections are swallowed (surfaced under `ZIDANE_DEBUG`)\n * — a misbehaving listener must not break the live execution that\n * triggered the transition.\n */\n hooks?: ReplayDoneHooks\n /**\n * Whether THIS invocation is resuming a prior journal (a crash-recovery /\n * resume replay) rather than running fresh. The host supplies it — it's the\n * one bit the tracker can't infer on its own (before the first `ctx.run`\n * settles, \"fresh, not yet live\" and \"replaying a resumed journal\" look\n * identical from inside the wrappers). Determine it from your own state: e.g.\n * the bound object already has persisted session turns, or the SDK reports a\n * non-first attempt.\n *\n * Powers {@link ReplayTracker.isResuming} — the probe streaming consumers\n * should gate on (vs {@link ReplayTracker.isReplaying}, which stays\n * conservative for the abort/journal-safety use case). On a fresh invocation\n * (`resuming: false`, the default) `isResuming()` is `false` from the very\n * start, so a streamer emits the opening deltas / start-step instead of\n * suppressing them until the first journaled call settles.\n */\n resuming?: boolean\n}\n\nexport interface ReplayTracker {\n /**\n * `true` until the first live (non-journaled) execution of a wrapped\n * provider stream / tool body. See the module doc for the fresh-\n * invocation caveat. Use this for journal-safety decisions (deferred\n * abort) where the conservative answer is the correct one.\n */\n isReplaying: () => boolean\n /**\n * `true` only while ACTIVELY replaying a resumed journal — i.e. the\n * invocation was constructed with `resuming: true` AND hasn't gone live\n * yet. Always `false` on a fresh invocation (`resuming: false`).\n *\n * This is the probe for live-streaming consumers: gate emission on\n * `!isResuming()` to suppress re-emitted deltas during a resume replay\n * while still emitting the opening output of a fresh run. (Contrast\n * {@link isReplaying}, which is conservatively `true` at the start of a\n * fresh run too.)\n */\n isResuming: () => boolean\n /**\n * Register a callback for the replay→live transition. Fires once.\n * When the tracker is already live, the callback runs synchronously\n * before `onLive` returns. Returns an unregister function (no-op\n * after firing).\n */\n onLive: (cb: () => void) => () => void\n /**\n * Mark the invocation live. Called by the wrappers from inside their\n * journaled closures — a closure only executes when the journal\n * cursor is past it. Idempotent; only the first call transitions.\n */\n markLive: () => void\n}\n\n/**\n * Create a per-invocation replay tracker. Pass it to `restateProvider`\n * / `restateTool` / `wrapAgentTools` via their `replayTracker` option;\n * consume it via `isReplaying()` / `onLive()` / {@link replayAwareAbort}.\n */\nexport function createReplayTracker(options: ReplayTrackerOptions = {}): ReplayTracker {\n let live = false\n let callbacks: (() => void)[] = []\n const resuming = options.resuming === true\n\n return {\n isReplaying: () => !live,\n isResuming: () => resuming && !live,\n markLive: () => {\n if (live)\n return\n live = true\n const pending = callbacks\n callbacks = []\n for (const cb of pending) {\n try {\n cb()\n }\n catch (err) {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/restate] onLive callback threw: ${err instanceof Error ? err.message : String(err)}\\n`)\n }\n }\n if (options.hooks) {\n Promise.resolve(options.hooks.callHook('replay:done', {})).catch((err: unknown) => {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/restate] replay:done hook rejected: ${err instanceof Error ? err.message : String(err)}\\n`)\n })\n }\n },\n onLive: (cb) => {\n if (live) {\n cb()\n return () => {}\n }\n callbacks.push(cb)\n return () => {\n const idx = callbacks.indexOf(cb)\n if (idx >= 0)\n callbacks.splice(idx, 1)\n }\n },\n }\n}\n\n/**\n * Wrap an abort function so it defers during journal replay.\n *\n * Live invocation → `abort()` runs immediately, exactly like calling\n * `agent.abort()` directly. Replaying invocation → the abort is queued\n * and applied at the first live boundary (the start of the first\n * non-journaled provider stream or tool body), where the resulting\n * `AgentAbortedError` + host catch-arm journaling append to the journal\n * instead of forking it mid-replay. Multiple calls during replay\n * collapse into one queued abort.\n */\nexport function replayAwareAbort(tracker: ReplayTracker, abort: () => void): () => void {\n let queued = false\n return () => {\n if (!tracker.isReplaying()) {\n abort()\n return\n }\n if (queued)\n return\n queued = true\n tracker.onLive(abort)\n }\n}\n","/**\n * Restate-backed `SessionStore` — turn / run state lives in the bound\n * virtual object's K/V state instead of SQLite / file / remote HTTP.\n *\n * Trade-offs vs. journal-only replay\n * ----------------------------------\n * If you only care about durable execution within ONE invocation,\n * skip this — the journaled `ctx.run` entries (LLM calls, tool\n * executions) are enough to replay the loop to byte-identical state\n * after a crash. The in-memory `createMemoryStore()` is the right\n * choice; turns rematerialize from the journal each replay.\n *\n * Pick this store when EXTERNAL consumers (TUI, web GUI, support\n * tooling) need to read a session's history WITHOUT re-entering the\n * agent handler. Virtual-object state is exposed via the SDK's read\n * APIs (`ctx.get` from another handler, `restate-cli`, the Restate\n * web UI) — same data, different access path. The journal is\n * invocation-local; this state is the externally-visible projection\n * of it.\n *\n * Storage layout\n * --------------\n * One virtual-object key per session, three K/V slots:\n *\n * `session-data` → `SessionData` minus the `turns` array (small header)\n * `session-turns` → `SessionTurn[]` (the conversation history)\n * `session-runs` → `SessionRun[]` (run lifecycle records)\n *\n * Splitting `turns` / `runs` out keeps the header light for `load()` —\n * a handler that only needs metadata doesn't pull the full history.\n *\n * Per-invocation read-through cache\n * ---------------------------------\n * The store reads each of the three slots from `ctx.get` AT MOST ONCE per\n * invocation, then serves every subsequent read from an in-memory cache and\n * keeps that cache in sync on each write. This is what makes the store cheap\n * under the agent loop: `appendTurns` fires on every `turn:after` /\n * `tool-results:after`, and the previous implementation re-read (and\n * re-sanitized) the ENTIRE growing `session-turns` array on each call — O(N²)\n * sequential K/V round-trips and CPU over an N-turn run. With the cache the\n * full history is pulled once and appended in memory.\n *\n * Writes stay EAGER (`ctx.set` on every mutating call, not deferred to a\n * flush): external read access is the whole reason this store exists, so a\n * concurrent reader (another handler, `restate-cli`, the Restate UI) must see\n * each turn as soon as it lands. Restate runs one invocation at a time per\n * virtual-object key, so the cache can't be invalidated mid-invocation by a\n * competing writer. The only way to defeat it is to mutate these three slots\n * via raw `ctx.set`/`ctx.clear` OUTSIDE the store within the same invocation —\n * don't; the store owns `session-data` / `session-turns` / `session-runs`.\n *\n * Listing / discovery\n * -------------------\n * `list()` returns `[]` because virtual objects don't expose cross-key\n * enumeration. `delete()` clears the current object's session keys only.\n * Use a separate index handler if you need discovery (one virtual object\n * per `projectRoot` that maintains an indexed list of session ids; this\n * store doesn't own that concern).\n * `generateSessionId` is omitted so the agent falls back to its\n * default UUID generator — for a session bound 1:1 to a virtual-\n * object key, pass `id: ctx.key` to `createSession()` instead and\n * skip ID generation entirely.\n */\n\nimport type { SessionData, SessionRun, SessionStore } from '../session'\nimport type { AgentClock, SessionTurn } from '../types'\nimport type { RestateObjectContextLike } from './types'\nimport { deterministicUuid } from './clock'\n\nconst KEY_DATA = 'session-data'\nconst KEY_TURNS = 'session-turns'\nconst KEY_RUNS = 'session-runs'\n\ntype SessionHeader = Omit<SessionData, 'turns' | 'runs'>\n\nexport interface RestateSessionStoreOptions {\n /**\n * Time source for the journaled header timestamps (`createdAt` /\n * `updatedAt`) the store stamps in `save()` and `updateStatus()`.\n *\n * Defaults to `ctx.date.now()` — one journaled round-trip per call. Pass the\n * SAME `restateClock(ctx, { coalesce: true })` you hand the agent so these\n * finalize-time timestamps ride the coalesced anchor instead of each\n * spending their own `ctx.date.now()`; on a suspend-per-round-trip (FaaS)\n * host that's ~2 fewer suspend/replay cycles per run. Whatever you pass MUST\n * be replay-stable: the value lands in persisted state via `ctx.set`, so a\n * drifting clock would corrupt the journal on replay (`restateClock`\n * satisfies this in both its default and coalescing modes).\n */\n clock?: AgentClock\n}\n\n/**\n * Construct a `SessionStore` backed by the bound virtual-object's K/V\n * state. The store is single-tenant — every method ignores the\n * `sessionId` argument because the virtual object is already keyed by\n * `ctx.key`. Calling `appendTurns('other-id', …)` writes to the\n * CURRENT object's state, not the one named in the argument. Bind one\n * virtual-object key per session and the contract holds.\n */\nexport function restateSessionStore(\n ctx: RestateObjectContextLike,\n options: RestateSessionStoreOptions = {},\n): SessionStore {\n let nextTurnSeq: number | undefined\n let warnedMismatch = false\n\n // Journaled time source for header timestamps. Defaults to `ctx.date.now()`\n // (unchanged); an injected `clock` lets `save` / `updateStatus` share the\n // agent's coalescing anchor instead of each spending a fresh round-trip.\n const clock = options.clock\n const journalNow = clock ? () => clock.now() : () => ctx.date.now()\n\n // Per-invocation read-through cache. Each slot is pulled from `ctx.get`\n // exactly once (lazily, on first access) and then served from memory; every\n // write updates the cache alongside the eager `ctx.set`. See the module\n // docstring for why this is safe (single-writer per virtual-object key) and\n // why writes are NOT deferred (external readers need incremental visibility).\n // Cached turns/runs are kept pre-sanitized, so writes only sanitize the\n // incoming delta instead of re-scanning the whole growing array.\n let headerCache: SessionHeader | null | undefined\n let turnsCache: SessionTurn[] | undefined\n let runsCache: SessionRun[] | undefined\n\n async function loadHeader(): Promise<SessionHeader | null> {\n if (headerCache === undefined)\n headerCache = await ctx.get<SessionHeader>(KEY_DATA)\n return headerCache\n }\n\n async function loadTurns(): Promise<SessionTurn[]> {\n if (turnsCache === undefined)\n turnsCache = sanitizeTurnsForState((await ctx.get<SessionTurn[]>(KEY_TURNS)) ?? [])\n return turnsCache\n }\n\n async function loadRuns(): Promise<SessionRun[]> {\n if (runsCache === undefined)\n runsCache = sanitizeRunsForState((await ctx.get<SessionRun[]>(KEY_RUNS)) ?? [])\n return runsCache\n }\n\n function writeHeader(header: SessionHeader): void {\n headerCache = header\n ctx.set(KEY_DATA, header)\n }\n\n function writeTurns(turns: SessionTurn[]): void {\n turnsCache = turns\n ctx.set(KEY_TURNS, turns)\n }\n\n function writeRuns(runs: SessionRun[]): void {\n runsCache = runs\n ctx.set(KEY_RUNS, runs)\n }\n\n // The store is single-tenant (keyed by `ctx.key`), so a `sessionId` arg that\n // doesn't match `ctx.key` means a method is silently writing to/reading from\n // a different object than the caller named — the classic footgun when a host\n // forgets `createSession({ id: ctx.key })` and the agent mints a random id.\n // Warn ONCE (never throw — a 1:1 binding with a non-matching id still routes\n // correctly, and throwing would break it). Hosts binding `id: ctx.key` never\n // see this.\n function guardSessionId(sessionId: string): void {\n if (warnedMismatch || sessionId === ctx.key)\n return\n warnedMismatch = true\n process.stderr.write(\n `[zidane/restate] restateSessionStore: sessionId \"${sessionId}\" != bound object key \"${ctx.key}\". `\n + `This store ignores the sessionId and operates on the bound object — pass createSession({ id: ctx.key }) to silence this.\\n`,\n )\n }\n\n async function generateTurnId(): Promise<string> {\n if (nextTurnSeq === undefined)\n nextTurnSeq = (await loadTurns()).length\n nextTurnSeq += 1\n // UUID-shaped (via deterministicUuid) rather than the old `turn_${n}`:\n // hosts that mirror turns into an external store commonly key them by a\n // uuid column and validate id shape at their streaming boundary — a bare\n // `turn_N` id failed BOTH (frame dropped as malformed + uuid parse error\n // on the fallback write), silently losing session-managed turns\n // (compaction summaries, steer messages) from durable history.\n // Determinism is unchanged: the seed is (object key, persisted seq).\n return deterministicUuid(`${ctx.key}:turn:${nextTurnSeq}`)\n }\n\n return {\n /**\n * Turn ids are deterministic from the persisted turn count. Random ids\n * are replay-stable only when the whole handler replays from the same\n * point; restarting from an arbitrary journal step can shift the RNG\n * sequence before a state write.\n */\n generateTurnId,\n\n async load(_sessionId: string): Promise<SessionData | null> {\n guardSessionId(_sessionId)\n const header = await loadHeader()\n const turns = await loadTurns()\n const runs = await loadRuns()\n // Hand back fresh array copies, never the cache references. The host\n // wraps this `SessionData` in a live `Session` whose `data.turns` /\n // `data.runs` it mutates in place (`push` on each appendTurns / startRun)\n // — aliasing the cache would let those pushes land inside `loadTurns()`'s\n // result and double-count on the next store write.\n if (!header) {\n if (turns.length === 0 && runs.length === 0)\n return null\n return {\n id: _sessionId,\n turns: [...turns],\n runs: [...runs],\n status: inferStatus(runs),\n metadata: {},\n createdAt: inferCreatedAt(turns, runs),\n updatedAt: inferUpdatedAt(turns, runs),\n }\n }\n return { ...header, turns: [...turns], runs: [...runs] }\n },\n\n async save(session: SessionData): Promise<void> {\n guardSessionId(session.id)\n const { turns, runs, ...header } = session\n // Journal-stable header timestamps. The in-memory `Session` stamps\n // `createdAt` / `updatedAt` with raw `Date.now()` (its `touch()`\n // helper is synchronous and can't await a journaled clock), so the\n // values arriving here differ on every replay — and a replayed\n // `ctx.set` with drifting values is exactly the non-determinism\n // Restate exists to prevent. Source both from the journal instead:\n // `createdAt` sticks to the first persisted value, `updatedAt`\n // comes from `journalNow()` (journaled `ctx.date.now()`, or the\n // injected replay-stable clock — replay returns the recorded reading).\n const prior = await loadHeader()\n const now = await journalNow()\n writeHeader({\n ...header,\n createdAt: prior?.createdAt ?? now,\n updatedAt: now,\n })\n writeTurns(sanitizeTurnsForState(turns))\n writeRuns(sanitizeRunsForState(runs))\n },\n\n async delete(_sessionId: string): Promise<void> {\n guardSessionId(_sessionId)\n ctx.clear(KEY_DATA)\n ctx.clear(KEY_TURNS)\n ctx.clear(KEY_RUNS)\n // Reflect the clear in the cache so same-invocation reads see an empty\n // object instead of stale pre-delete state, and so a later\n // generateTurnId re-seeds from zero.\n headerCache = null\n turnsCache = []\n runsCache = []\n nextTurnSeq = undefined\n },\n\n /**\n * Always empty — virtual objects don't support cross-key\n * enumeration. Maintain a separate index handler if discovery\n * matters.\n */\n async list(): Promise<string[]> {\n return []\n },\n\n async appendTurns(_sessionId: string, turns: SessionTurn[]): Promise<void> {\n guardSessionId(_sessionId)\n const existing = await loadTurns()\n writeTurns([...existing, ...sanitizeTurnsForState(turns)])\n },\n\n async getTurns(_sessionId: string, from = 0, limit?: number): Promise<SessionTurn[]> {\n guardSessionId(_sessionId)\n const turns = await loadTurns()\n return turns.slice(from, limit !== undefined ? from + limit : undefined)\n },\n\n async updateRun(_sessionId: string, run: SessionRun): Promise<void> {\n guardSessionId(_sessionId)\n const runs = await loadRuns()\n const idx = runs.findIndex(r => r.id === run.id)\n const next = [...runs]\n if (idx >= 0) {\n // Journal-stable `startedAt`: the in-memory `Session.startRun`\n // stamps it with raw `Date.now()`, which re-evaluates on every\n // replay. Keep the previously persisted value (mirrors the\n // `createdAt: prior?.createdAt ?? now` pattern in `save()`) so a\n // replayed `ctx.set` payload doesn't drift.\n next[idx] = { ...sanitizeRunForState(run), startedAt: runs[idx].startedAt }\n }\n else {\n next.push(sanitizeRunForState(run))\n }\n writeRuns(next)\n },\n\n async updateStatus(_sessionId: string, status: SessionData['status']): Promise<void> {\n guardSessionId(_sessionId)\n const header = await loadHeader()\n const now = await journalNow()\n if (header) {\n writeHeader({ ...header, status, updatedAt: now })\n }\n else {\n writeHeader({\n id: _sessionId,\n status,\n metadata: {},\n createdAt: now,\n updatedAt: now,\n })\n }\n },\n }\n}\n\nfunction sanitizeTurnsForState(turns: readonly SessionTurn[]): SessionTurn[] {\n return turns.map(sanitizeTurnForState)\n}\n\nfunction sanitizeTurnForState(turn: SessionTurn): SessionTurn {\n if (!turn.usage || turn.usage.timeToFirstTokenMs === undefined)\n return turn\n\n const { timeToFirstTokenMs: _timeToFirstTokenMs, ...usage } = turn.usage\n return { ...turn, usage }\n}\n\nfunction sanitizeRunsForState(runs: readonly SessionRun[]): SessionRun[] {\n return runs.map(sanitizeRunForState)\n}\n\nfunction sanitizeRunForState(run: SessionRun): SessionRun {\n if (!run.turnUsage?.some(usage => usage.timeToFirstTokenMs !== undefined))\n return run\n\n return {\n ...run,\n turnUsage: run.turnUsage.map((usage) => {\n if (usage.timeToFirstTokenMs === undefined)\n return usage\n const { timeToFirstTokenMs: _timeToFirstTokenMs, ...stableUsage } = usage\n return stableUsage\n }),\n }\n}\n\nfunction inferStatus(runs: readonly SessionRun[]): SessionData['status'] {\n if (runs.some(run => run.status === 'running'))\n return 'running'\n if (runs.some(run => run.status === 'error'))\n return 'error'\n if (runs.some(run => run.status === 'completed'))\n return 'completed'\n return 'idle'\n}\n\nfunction inferCreatedAt(turns: readonly SessionTurn[], runs: readonly SessionRun[]): number {\n return minDefined([\n ...turns.map(turn => turn.createdAt),\n ...runs.map(run => run.startedAt),\n ]) ?? 0\n}\n\nfunction inferUpdatedAt(turns: readonly SessionTurn[], runs: readonly SessionRun[]): number {\n return maxDefined([\n ...turns.map(turn => turn.createdAt),\n ...runs.map(run => run.endedAt ?? run.startedAt),\n ]) ?? inferCreatedAt(turns, runs)\n}\n\nfunction minDefined(values: readonly number[]): number | undefined {\n let min: number | undefined\n for (const value of values) {\n if (min === undefined || value < min)\n min = value\n }\n return min\n}\n\nfunction maxDefined(values: readonly number[]): number | undefined {\n let max: number | undefined\n for (const value of values) {\n if (max === undefined || value > max)\n max = value\n }\n return max\n}\n","/**\n * Parallel subagents for durable hosts: each child runs as its OWN durable\n * invocation instead of inside the parent's journal.\n *\n * ## Why a second spawn tool\n *\n * `createSpawnTool` runs the child in-process, so the child's provider and tool\n * calls become journal entries of the PARENT's invocation. That is what makes a\n * crash mid-subagent replay for free — and it is also why those children must\n * run one at a time: two child loops generate their journal operations\n * independently, so the index each operation lands on depends on timing and\n * differs on replay.\n *\n * Dispatching the child to its own invocation dissolves that constraint rather\n * than managing it. The parent journals ONE call entry per child; everything\n * the child does lives in a journal nobody else touches. Children therefore fan\n * out through the existing durable fleet — `executeDurable` starts them in\n * submission order and joins them with the runtime's own combinator — and each\n * child gets its own retry policy and suspension budget, so a poison child\n * retries itself instead of the parent's whole invocation.\n *\n * ## Wiring\n *\n * The host owns the handler and the client; this tool owns the contract:\n *\n * ```ts\n * const spawn = restateSpawnTool({\n * dispatch: (req, toolCtx) => ctx.serviceClient(childService).runChild(req),\n * })\n *\n * createAgent({\n * tools: { ...wrapAgentTools(tools, ctx), spawn },\n * behavior: restateBehavior({\n * maxConcurrentTools: 4,\n * toolBatchExecutor: restateToolBatchExecutor({ promises: RestatePromise }),\n * }),\n * })\n * ```\n *\n * Two host-side rules:\n *\n * - The child handler must be a **service**, or an object on a DIFFERENT key.\n * A virtual object serializes per key, so children sharing the parent's key\n * would queue behind the parent that still holds it — no parallelism, and a\n * deadlock risk.\n * - `maxConcurrentTools` must be raised (it defaults to 1 in `restateBehavior`)\n * and the durable batch executor installed, or the fleet falls back to\n * sequential execution.\n *\n * ## What the child owes the parent\n *\n * A {@link ChildRunResult}: its status, final text, its turns, and its stats.\n * The child runs **sessionless** — it keeps turns in memory and hands them back\n * — so the parent stays the single writer of the run tree and merges each\n * child's turns under a `SessionRun` of its own (see `persist`).\n *\n * ## Constraints this file lives under\n *\n * - `durableExecute` must synchronously return a **mappable** durable promise\n * (`src/loop.ts:5536` throws otherwise), so it cannot be `async` and cannot\n * await anything before dispatching. That is why `spawn:before` is fired\n * without awaiting: listeners on it must not perform journaled I/O.\n * - Nothing native may wrap a durable promise — no `.then`, `.catch`, or\n * `Promise.race` (`src/loop.ts:5514-5528`): a second consumer starts a second\n * progress loop on the runtime's single-consumer channel. Result shaping\n * therefore goes through the runtime's own `map`, and everything that needs\n * to await (session writes, `spawn:complete`) is deferred to a drain on\n * `tool-results:after`.\n * - Per-child timeouts are the callee's business for the same reason: a race\n * against the call promise is exactly the forbidden pattern.\n */\n\nimport type { Session } from '../session'\nimport type { ToolContext, ToolDef } from '../tools/types'\nimport type { AgentStats, SessionTurn, ToolResultContent } from '../types'\nimport type { RestatePromiseLike } from './parallel'\nimport { formatTokenUsage } from '../stats'\nimport { reserveChildLabel } from '../tools/spawn'\nimport { toolOutputByteLength, toolResultToText } from '../types'\n\n/** What the parent hands a child invocation. */\nexport interface ChildRunRequest {\n /** The child's prompt. */\n task: string\n /** Session-scoped label the parent reserved (`child-1`, `child-2`, …). */\n label: string\n /**\n * Identity of the work that spawned this child. Present when the parent has\n * them; forward these to whatever sink the child publishes live events to so\n * a UI can attribute and group them (the parent's own `child:*` events carry\n * the same ids).\n */\n parentRunId?: string\n parentCallId?: string\n sessionId?: string\n /**\n * Subagent depth of the CHILD (parent depth + 1). The handler is responsible\n * for refusing runaway recursion — this tool always dispatches, because a\n * short-circuit would have to return a non-durable promise and the durable\n * fleet rejects those.\n */\n depth: number\n /** Model override requested by the model, if any. */\n model?: string\n /** Named subagent type requested by the model, if any. */\n subagentType?: string\n}\n\n/**\n * A descendant a child already merged, handed up so the top-level parent can\n * rebuild the whole subtree.\n *\n * Why it exists: a child dispatched to a service runs sessionless, so it has\n * nowhere to write ITS children's turns. Without passing them up, a depth-2\n * fan-out loses the grandchildren entirely — the parent sees the child's `spawn`\n * tool calls and nothing of the work they did. Collect these from\n * {@link RestateSpawnToolOptions.onChildMerged} and return them as\n * {@link ChildRunResult.children}.\n */\nexport interface MergedChild {\n /** Label this level assigned. The merging parent re-labels from its own session counter. */\n label: string\n task: string\n /** Depth relative to the run that merged it (1 for its direct children). */\n depth: number\n status: 'completed' | 'aborted' | 'timeout' | 'error'\n stats: AgentStats\n turns: SessionTurn[]\n startedAt?: number\n endedAt?: number\n /** Its own merged descendants, recursively. */\n children?: readonly MergedChild[]\n}\n\n/** What a child invocation returns. */\nexport interface ChildRunResult {\n status: 'completed' | 'aborted' | 'timeout' | 'error'\n /** The child's final assistant text. */\n text: string\n /**\n * The child's turns, in order. Merged into the parent's session under a\n * `SessionRun` for this child, so the persisted tree matches what\n * `createSpawnTool({ persist: true })` produces in-process.\n */\n turns: SessionTurn[]\n stats: AgentStats\n /** Failure detail when `status` is `'error'`. */\n error?: string\n /**\n * When the child started / finished, measured on the CHILD's clock (e.g.\n * `await restateClock(ctx).now()` around its run).\n *\n * Strongly recommended for durable hosts. These land in the merged\n * `SessionRun`, which the parent persists through a journaled state write, so\n * they must be replay-stable. Values measured inside the child's own\n * invocation are: they arrive in the journaled call result. Omit them and the\n * parent falls back to the child's first / last turn timestamps, then to its\n * own run start.\n */\n startedAt?: number\n endedAt?: number\n /**\n * Descendants this child already merged — see {@link MergedChild}. The parent\n * merges them recursively, so a nested fan-out lands in the session with the\n * right depths and emits `child:*` events at every level.\n */\n children?: readonly MergedChild[]\n}\n\nexport interface RestateSpawnToolOptions {\n /**\n * Start the child invocation and return the runtime's promise **untouched**\n * (e.g. `ctx.serviceClient(childService).runChild(req)`). Do not wrap it in\n * `then` / `catch` / `race`, and do not `await` it here.\n */\n dispatch: (req: ChildRunRequest, ctx: ToolContext) => Promise<ChildRunResult>\n /**\n * Merge each child's turns and run record into the parent's session.\n * Default: `true` when the parent has a session.\n *\n * Ordering nuance versus the in-process tool: the merge runs on\n * `tool-results:after`, so a child's turns are appended just AFTER the\n * parent's tool-result turn rather than just before it. Their `createdAt`\n * values still order them correctly for consumers that sort chronologically.\n */\n persist?: boolean\n /**\n * Called once when the parent aborts with children still in flight. Wire it\n * and an aborted parent stops its children instead of orphaning them.\n *\n * The practical implementation is to cancel the parent's OWN invocation:\n *\n * ```ts\n * onAbort: () => ctx.invocation(ctx.request().id).cancel()\n * ```\n *\n * Restate cancels the whole call tree, so this reaches children at any depth\n * and needs no per-child bookkeeping. `ctx.request().id` is available\n * synchronously and is constant across retries and suspensions. The cost is\n * that the parent invocation ends too — an in-agent abort becomes \"stop\n * everything\", so persist whatever summary you need BEFORE aborting.\n *\n * Why not per-child ids: the `invocationId` on the runtime's call handle is\n * itself a journal-backed promise (`SingleRestatePromise`, see\n * `@restatedev/restate-sdk` `context_impl.js`), so reading it while the call\n * is in flight registers a second consumer on the SDK's single-consumer\n * progress channel — `awaitNext already pending`, a failed attempt, and a\n * replay on every fan-out. Verified against a real server. Per-child\n * cancellation needs the two-phase (send → id → attach) tool shape, where the\n * id is consumed before the result promise exists.\n *\n * Timing: cancelling appends a journal command, so it must not happen during\n * a replay. Drive aborts through `replayAwareAbort` (see `./replay`), which\n * defers an external abort to the first live boundary.\n */\n onAbort?: (inFlight: readonly InFlightChild[], ctx: ToolContext) => void\n /**\n * Replay each finished child's transcript onto the parent's hook bus as\n * `child:*` events, so hosts already rendering subagent activity work\n * unchanged. Default: `true`.\n *\n * These are NOT live — hook bubbling cannot cross an invocation boundary, so\n * they fire when the child finishes, in submission order. For live output,\n * publish from the child's own bus inside your handler and correlate with the\n * `parentRunId` / `parentCallId` / `sessionId` carried in\n * {@link ChildRunRequest}; see `docs/RESTATE.md` § Parallel subagents.\n *\n * They re-fire on a parent replay, exactly as the in-process tool's\n * `child:tool:*` does — dedupe by `callId` / `turnId`, or gate on\n * `createReplayTracker`.\n */\n emitChildEvents?: boolean\n /**\n * Called for each child as it merges, with the subtree it brought along.\n *\n * Sessionless agents (a child dispatched to a service) need this: they have\n * nowhere to persist their own children, so they collect here and hand the\n * result up as {@link ChildRunResult.children}. Without it a nested fan-out\n * loses everything below depth 1.\n */\n onChildMerged?: (merged: MergedChild, ctx: ToolContext) => void\n /** Override the tool description shown to the model. */\n description?: string\n}\n\n/**\n * The `invocationId` half of the runtime's invocation handle. Restate's\n * `ctx.serviceClient(...).method(...)` returns `RestatePromise & { invocationId:\n * Promise<InvocationId> }`; only that field is needed here, so this stays a\n * structural type rather than an SDK import.\n */\n/** A child that was dispatched and has not settled yet. */\nexport interface InFlightChild {\n label: string\n task: string\n depth: number\n}\n\ninterface PendingChild {\n order: number\n label: string\n task: string\n depth: number\n callId: string\n runId: string\n parentRunId?: string\n session?: Session\n result?: ChildRunResult\n failure?: unknown\n /** Set once the child settled — a settled child is never cancelled. */\n settled?: boolean\n /** Set when WE asked the runtime to cancel, so the outcome reads `aborted`. */\n cancelRequested?: boolean\n /** Detach the abort listener. */\n release?: () => void\n}\n\nconst ZERO_STATS: AgentStats = {\n totalIn: 0,\n totalOut: 0,\n totalCacheRead: 0,\n totalCacheCreation: 0,\n turns: 0,\n elapsed: 0,\n}\n\nconst DEFAULT_DESCRIPTION = 'Delegate a self-contained task to a sub-agent that runs independently '\n + 'and returns only its final report. Several spawn calls in one turn run in parallel.'\n\nexport function restateSpawnTool(options: RestateSpawnToolOptions): ToolDef {\n const persist = options.persist ?? true\n const emitEvents = options.emitChildEvents ?? true\n // Submission counter: `executeDurable` starts fleet members in call-index\n // order, so this ordinal is deterministic and drives the merge order.\n let dispatchSeq = 0\n let sessionlessLabels = 0\n let cancelSignalled = false\n let nestedLabels = 0\n const pending: PendingChild[] = []\n const drainRegistered = new WeakSet<object>()\n\n /**\n * Build the request and the bookkeeping entry. Deliberately side-effect free\n * apart from reserving the label: the fleet path has to be able to reject a\n * misconfigured `dispatch` (below) without leaving a phantom child queued for\n * the merge. `commit` is what actually enrols the child.\n */\n function prepare(input: Record<string, unknown>, ctx: ToolContext): { req: ChildRunRequest, entry: PendingChild } {\n const task = String(input.task ?? '')\n const depth = (ctx.depth ?? 0) + 1\n // Reserved synchronously, in submission order, from the same\n // session-anchored counter the in-process tool uses — so labels survive\n // replays and line up with a reloaded transcript.\n const label = ctx.session ? reserveChildLabel(ctx.session) : `child-${++sessionlessLabels}`\n const entry: PendingChild = {\n order: ++dispatchSeq,\n label,\n task,\n depth,\n callId: ctx.callId,\n // Namespaced off the parent run so the merged record can't collide with\n // a run id this agent instance mints for itself.\n runId: `${ctx.runId ?? 'run'}-${label}`,\n ...(ctx.runId !== undefined ? { parentRunId: ctx.runId } : {}),\n ...(ctx.session !== undefined ? { session: ctx.session } : {}),\n }\n return {\n entry,\n req: {\n task,\n label,\n depth,\n // Attribution for a live host transport: the child tags whatever it\n // publishes with these, and they match the ids on the parent's own\n // `child:*` events.\n ...(ctx.runId !== undefined ? { parentRunId: ctx.runId } : {}),\n parentCallId: ctx.callId,\n ...(ctx.session !== undefined ? { sessionId: ctx.session.id } : {}),\n ...(typeof input.model === 'string' ? { model: input.model } : {}),\n ...(typeof input.subagent_type === 'string' ? { subagentType: input.subagent_type } : {}),\n },\n }\n }\n\n /** Enrol a dispatched child for merging, and announce it. */\n function commit(entry: PendingChild, input: Record<string, unknown>, ctx: ToolContext): void {\n pending.push(entry)\n registerDrain(ctx)\n watchAbort(entry, ctx)\n // Fired WITHOUT awaiting — see the module note on `durableExecute`.\n // Listeners must stay off journaled I/O.\n void Promise.resolve(ctx.hooks.callHook('spawn:before', {\n id: entry.label,\n task: entry.task,\n callId: entry.callId,\n depth: entry.depth,\n ...(typeof input.model === 'string' ? { model: input.model } : {}),\n })).catch(() => {})\n }\n\n function registerDrain(ctx: ToolContext): void {\n if (drainRegistered.has(ctx.hooks))\n return\n drainRegistered.add(ctx.hooks)\n // `tool-results:after` is the normal drain point: it fires right after the\n // batch is packed, so children merge before the next provider call.\n // `turn:after` is a backstop for turns that end without packing tool\n // results — otherwise a settled child would never be merged and its cost\n // never reported. Whichever runs first empties `pending`; the other is a\n // no-op. Neither can close out a child if the invocation is torn down\n // before the turn ends at all — see `docs/RESTATE.md` § Parallel subagents.\n ctx.hooks.hook('tool-results:after', async () => {\n await drain(ctx)\n })\n ctx.hooks.hook('turn:after', async () => {\n await drain(ctx)\n })\n }\n\n /**\n * Persist finished children and announce them. Runs where awaiting is legal,\n * in submission order rather than settlement order, so two children that\n * complete out of order still land deterministically.\n */\n async function drain(ctx: ToolContext): Promise<void> {\n if (pending.length === 0)\n return\n const batch = pending.splice(0, pending.length).sort((a, b) => a.order - b.order)\n // Run records live in session metadata, which `appendTurns` does NOT\n // persist — without an explicit save the merged children exist only in\n // memory and vanish from the reloaded tree.\n let touchedSession: Session | undefined\n for (const entry of batch) {\n const result = entry.result\n const stats = result?.stats ?? ZERO_STATS\n // A child we cancelled failed on purpose: record it as `aborted` so a\n // cancelled fan-out doesn't read as a fleet of broken children in the\n // session, in `spawn:complete`, or in cost accounting.\n const status = result?.status ?? (entry.cancelRequested ? 'aborted' : 'error')\n const session = entry.session\n if (persist && session) {\n touchedSession = session\n session.startRun(entry.runId, entry.task, {\n ...(entry.parentRunId !== undefined ? { parentRunId: entry.parentRunId } : {}),\n depth: entry.depth,\n label: entry.label,\n })\n if (result && result.turns.length > 0) {\n // Re-stamp onto the merged run id: the child minted these under its\n // own run, and the parent's tree keys on this one.\n await session.appendTurns(result.turns.map(turn => ({ ...turn, runId: entry.runId })))\n }\n const rollup = {\n turns: stats.turns,\n tokensIn: stats.totalIn,\n tokensOut: stats.totalOut,\n ...(stats.cost !== undefined ? { cost: stats.cost } : {}),\n }\n if (status === 'completed')\n session.completeRun(entry.runId, rollup)\n else if (status === 'error')\n session.errorRun(entry.runId, errorText(entry), rollup)\n else\n session.abortRun(entry.runId, rollup)\n stampJournaledRunTimes(session, entry, result)\n }\n // Before `spawn:complete`, matching the live order: the child works, then\n // it completes.\n if (emitEvents && result)\n await replayChildEvents(entry, result.turns, ctx)\n // Anything the child merged itself lands underneath it, recursively, so a\n // nested fan-out keeps its shape instead of collapsing into the child.\n if (result?.children && result.children.length > 0) {\n const merged = await mergeDescendants(entry, result.children, ctx)\n if (merged)\n touchedSession = merged\n }\n options.onChildMerged?.({\n label: entry.label,\n task: entry.task,\n depth: entry.depth,\n status,\n stats,\n turns: result?.turns ?? [],\n ...(result?.startedAt !== undefined ? { startedAt: result.startedAt } : {}),\n ...(result?.endedAt !== undefined ? { endedAt: result.endedAt } : {}),\n ...(result?.children !== undefined ? { children: result.children } : {}),\n }, ctx)\n if (status === 'error') {\n await ctx.hooks.callHook('spawn:error', {\n id: entry.label,\n task: entry.task,\n error: new Error(errorText(entry)),\n depth: entry.depth,\n })\n }\n await ctx.hooks.callHook('spawn:complete', {\n id: entry.label,\n task: entry.task,\n callId: entry.callId,\n depth: entry.depth,\n status,\n stats,\n ...(result?.text ? { text: result.text } : {}),\n })\n }\n await touchedSession?.save()\n }\n\n /**\n * Merge a child's own descendants under it, depth-first and in the order the\n * child reported them.\n *\n * Each nested child is RE-LABELED from the merging session's counter: the\n * label it arrived with was minted by its own parent's counter and would\n * collide (every level starts at `child-1`). Re-labeling keeps the session's\n * labels unique and makes the synthesized events agree with the persisted\n * tree.\n */\n async function mergeDescendants(\n parent: { runId: string, depth: number, callId: string, session?: Session },\n nested: readonly MergedChild[],\n ctx: ToolContext,\n ): Promise<Session | undefined> {\n let touched: Session | undefined\n const session = parent.session\n for (const child of nested) {\n const depth = parent.depth + 1\n const label = session ? reserveChildLabel(session) : `${parent.runId}-nested-${++nestedLabels}`\n const runId = `${parent.runId}-${label}`\n if (persist && session) {\n touched = session\n session.startRun(runId, child.task, { parentRunId: parent.runId, depth, label })\n if (child.turns.length > 0)\n await session.appendTurns(child.turns.map(turn => ({ ...turn, runId })))\n const rollup = {\n turns: child.stats.turns,\n tokensIn: child.stats.totalIn,\n tokensOut: child.stats.totalOut,\n ...(child.stats.cost !== undefined ? { cost: child.stats.cost } : {}),\n }\n if (child.status === 'completed')\n session.completeRun(runId, rollup)\n else if (child.status === 'error')\n session.errorRun(runId, 'sub-agent failed', rollup)\n else\n session.abortRun(runId, rollup)\n const record = session.runs.find(run => run.id === runId)\n if (record) {\n // Same rule as the top level: journaled values only — these reach\n // `ctx.set` and a live clock would fork the journal on replay.\n const startedAt = child.startedAt ?? child.turns[0]?.createdAt\n const endedAt = child.endedAt ?? child.turns[child.turns.length - 1]?.createdAt ?? startedAt\n if (startedAt !== undefined)\n record.startedAt = startedAt\n if (endedAt !== undefined)\n record.endedAt = endedAt\n }\n }\n if (emitEvents) {\n await replayChildEvents(\n { label, depth, runId, callId: parent.callId, ...(parent.runId ? { parentRunId: parent.runId } : {}) },\n child.turns,\n ctx,\n )\n }\n if (child.children && child.children.length > 0) {\n const deeper = await mergeDescendants({ runId, depth, callId: parent.callId, ...(session ? { session } : {}) }, child.children, ctx)\n touched = touched ?? deeper\n }\n }\n return touched\n }\n\n /**\n * Repair the run record's timestamps with journaled values.\n *\n * `startRun` / `completeRun` / `errorRun` / `abortRun` stamp `Date.now()`\n * internally, and these records reach `ctx.set` through `save()` below — so a\n * live value here changes the state payload on a replay and kills the\n * invocation with `RestateError 570`. The loop repairs its own runs exactly\n * this way (`agent.ts`: `sessionRun.startedAt = runStartedAt`, `run.endedAt =\n * await clock.now()`); the merge path has to do the same.\n *\n * Sampling the parent's clock here is not an option: the drain runs inside a\n * hook the loop may abandon (`settledHook`), and an awaited journal op left in\n * flight is its own failure mode. Everything below is already journaled by the\n * time it reaches us — either measured by the child on ITS clock and carried\n * inside the journaled call result, or read from state the parent's own run\n * already wrote.\n */\n function stampJournaledRunTimes(session: Session, entry: PendingChild, result?: ChildRunResult): void {\n const merged = session.runs.find(run => run.id === entry.runId)\n if (!merged)\n return\n const turns = result?.turns ?? []\n const parentStartedAt = entry.parentRunId !== undefined\n ? session.runs.find(run => run.id === entry.parentRunId)?.startedAt\n : undefined\n // Preference order: what the child measured, then its own turn timestamps,\n // then the parent's run start (journaled by the loop) as a last resort for\n // a child that produced nothing.\n const startedAt = result?.startedAt ?? turns[0]?.createdAt ?? parentStartedAt\n const endedAt = result?.endedAt ?? turns[turns.length - 1]?.createdAt ?? startedAt\n if (startedAt !== undefined)\n merged.startedAt = startedAt\n if (endedAt !== undefined)\n merged.endedAt = endedAt\n }\n\n /**\n * Replay a finished child's transcript onto the PARENT's hook bus as `child:*`\n * events, so hosts that already render subagent activity (`src/output/\n * terminal.ts`, the GUI engine, any `child:tool:*` listener) light up for\n * parallel children without a single change.\n *\n * Not live \\u2014 hook bubbling cannot cross an invocation boundary, so these fire\n * when the child finishes, in submission order. Everything here is derived\n * from the journaled call result, so a parent replay produces the identical\n * sequence; like the in-process tool's `child:tool:*`, they DO re-fire on that\n * replay, so hosts dedupe by `callId` / `turnId` or gate on\n * `createReplayTracker`.\n *\n * Only events that describe things the child actually did are synthesized.\n * `tool:gate` / `tool:transform` / `tool:dispatched` / `tool:cancelled` /\n * `background:*` describe decisions taken inside another process; inventing\n * them would be fiction, so they stay absent.\n */\n async function replayChildEvents(\n child: { label: string, depth: number, runId: string, parentRunId?: string, callId: string },\n turns: readonly SessionTurn[],\n ctx: ToolContext,\n ): Promise<void> {\n if (turns.length === 0)\n return\n // Tool results live on the following user turn, so pair by callId across\n // the whole transcript rather than within a turn.\n const outputs = new Map<string, { output: string | ToolResultContent[], isError?: boolean }>()\n for (const turn of turns) {\n for (const block of turn.content) {\n if (block.type === 'tool_result')\n outputs.set(block.callId, { output: block.output, ...(block.isError !== undefined ? { isError: block.isError } : {}) })\n }\n }\n\n // Stream / turn events carry only the child coordinates; the tool events\n // extend `ToolHookContext`, which also carries run identity.\n const childIdentity = { childId: child.label, depth: child.depth }\n const identity = {\n ...childIdentity,\n runId: child.runId,\n ...(child.parentRunId !== undefined ? { parentRunId: child.parentRunId } : {}),\n // The spawn call that owns this child, matching `ToolHookContext.parentCallId`.\n parentCallId: child.callId,\n }\n const runToolCounts: Record<string, number> = {}\n let assistantTurns = 0\n\n for (const turn of turns) {\n if (turn.role !== 'assistant')\n continue\n assistantTurns += 1\n const text = turn.content.filter(block => block.type === 'text').map(block => block.text).join('')\n if (text.length > 0) {\n await ctx.hooks.callHook('child:stream:text', { ...childIdentity, turnId: turn.id, delta: text, text })\n }\n\n const turnToolCounts: Record<string, number> = {}\n for (const block of turn.content) {\n if (block.type !== 'tool_call')\n continue\n runToolCounts[block.name] = (runToolCounts[block.name] ?? 0) + 1\n turnToolCounts[block.name] = (turnToolCounts[block.name] ?? 0) + 1\n const base = {\n ...identity,\n turnId: turn.id,\n callId: block.id,\n name: block.name,\n displayName: block.name,\n input: block.input,\n runToolCounts: { ...runToolCounts },\n }\n await ctx.hooks.callHook('child:tool:before', base)\n const settled = outputs.get(block.id)\n if (settled === undefined)\n continue\n if (settled.isError === true) {\n await ctx.hooks.callHook('child:tool:error', {\n ...base,\n error: new Error(toolResultToText(settled.output)),\n })\n continue\n }\n await ctx.hooks.callHook('child:tool:after', {\n ...base,\n result: settled.output,\n outputBytes: toolOutputByteLength(settled.output),\n })\n }\n\n const usage = turn.usage ?? { input: 0, output: 0 }\n await ctx.hooks.callHook('child:turn:after', {\n ...childIdentity,\n turn: assistantTurns,\n turnId: turn.id,\n usage,\n message: turn,\n toolCounts: { turn: { ...turnToolCounts }, run: { ...runToolCounts } },\n })\n await ctx.hooks.callHook('child:stream:end', { ...childIdentity, turnId: turn.id, text })\n }\n }\n\n function errorText(entry: PendingChild): string {\n if (entry.failure !== undefined)\n return entry.failure instanceof Error ? entry.failure.message : String(entry.failure)\n return entry.result?.error ?? 'sub-agent failed'\n }\n\n /**\n * Shape the model-facing result. Mirrors the in-process tool's wording so a\n * host or model tuned on one reads the other.\n *\n * `stats.elapsed` is safe to print here even though it is a live measurement:\n * the child measured it inside ITS invocation and it arrives in the journaled\n * call result, so the parent replays the same bytes. (Sampling it on the\n * parent side is what corrupts a transcript — see `docs/RESTATE.md`.)\n */\n /**\n * Arm the abort path for one child. Nothing is read off the dispatch promise:\n * touching its `invocationId` mid-flight would register a second consumer on\n * the runtime's progress channel (see `onAbort`'s note), so the hook gets\n * labels and the host cancels the tree.\n */\n function watchAbort(entry: PendingChild, ctx: ToolContext): void {\n if (!options.onAbort)\n return\n if (ctx.signal.aborted) {\n requestCancel(ctx)\n return\n }\n const onAbort = (): void => requestCancel(ctx)\n ctx.signal.addEventListener('abort', onAbort, { once: true })\n entry.release = () => ctx.signal.removeEventListener('abort', onAbort)\n }\n\n /**\n * Fire the host's abort hook once for the whole in-flight set. Called once per\n * abort, not once per child: cancelling the tree is a single operation, and a\n * second call would append a redundant journal command.\n */\n function requestCancel(ctx: ToolContext): void {\n const onAbort = options.onAbort\n if (!onAbort || cancelSignalled)\n return\n const inFlight = pending.filter(entry => !entry.settled)\n if (inFlight.length === 0)\n return\n cancelSignalled = true\n for (const entry of inFlight)\n entry.cancelRequested = true\n onAbort(\n inFlight.map(entry => ({ label: entry.label, task: entry.task, depth: entry.depth })),\n ctx,\n )\n }\n\n function settle(entry: PendingChild, value?: ChildRunResult, failure?: unknown): string {\n entry.settled = true\n entry.release?.()\n if (failure !== undefined) {\n entry.failure = failure\n // A failure we caused by cancelling reads as `aborted`, not `error` —\n // otherwise every cancelled fan-out looks like a fleet of broken children.\n if (entry.cancelRequested)\n return `[sub-agent ${entry.label}] Aborted (cancelled)`\n return `[sub-agent ${entry.label}] Error: ${errorText(entry)}`\n }\n const result = value ?? { status: 'error' as const, text: '', turns: [], stats: ZERO_STATS }\n entry.result = result\n const head = `[sub-agent ${entry.label}]`\n const usage = `Tokens: ${formatTokenUsage(result.stats)}`\n if (result.status === 'completed') {\n return [\n `${head} Completed in ${result.stats.turns} turns (${result.stats.elapsed}ms)`,\n usage,\n '',\n result.text || '(no text response)',\n ].join('\\n')\n }\n if (result.status === 'error')\n return `${head} Error: ${errorText(entry)}`\n const verb = result.status === 'timeout' ? 'Timed out' : 'Aborted'\n return [`${head} ${verb} after ${result.stats.turns} turns (${result.stats.elapsed}ms)`, usage].join('\\n')\n }\n\n return {\n spec: {\n name: 'spawn',\n description: options.description ?? DEFAULT_DESCRIPTION,\n inputSchema: {\n type: 'object',\n properties: {\n task: { type: 'string', description: 'The self-contained task for the sub-agent.' },\n model: { type: 'string', description: 'Optional model id for the sub-agent.' },\n subagent_type: { type: 'string', description: 'Optional named sub-agent type.' },\n },\n required: ['task'],\n },\n },\n isConcurrencySafe: true,\n // Keeps `wrapAgentTools` from journaling this tool: dispatching a call from\n // inside a journaled action is the same illegal nesting the in-process\n // spawn tool avoids.\n runsNestedAgent: true,\n\n // Fleet path. Synchronous by necessity, and the returned promise is the\n // runtime's own — mapped, never `then`-ed.\n durableExecute: (input: Record<string, unknown>, ctx: ToolContext) => {\n const { req, entry } = prepare(input, ctx)\n const promise = options.dispatch(req, ctx) as RestatePromiseLike<ChildRunResult>\n // Checked BEFORE the child is enrolled: a `commit` here would queue a\n // child that never ran, so the next drain would persist a `SessionRun`\n // for it and report a phantom failure.\n if (typeof promise.map !== 'function') {\n throw new TypeError(\n 'restateSpawnTool: `dispatch` must return the runtime\\'s durable promise '\n + '(e.g. `ctx.serviceClient(svc).runChild(req)`), which exposes `map`.',\n )\n }\n commit(entry, input, ctx)\n return promise.map((value?: ChildRunResult, failure?: unknown) => settle(entry, value, failure))\n },\n\n // Sequential path, for hosts without the durable batch executor.\n execute: async (input: Record<string, unknown>, ctx: ToolContext): Promise<string | ToolResultContent[]> => {\n const { req, entry } = prepare(input, ctx)\n // Enrolled before awaiting: on this path a failed dispatch still has to\n // be recorded and reported, the way the in-process tool records a child\n // that threw.\n const promise = options.dispatch(req, ctx)\n commit(entry, input, ctx)\n try {\n return settle(entry, await promise)\n }\n catch (err) {\n return settle(entry, undefined, err)\n }\n },\n }\n}\n","/**\n * Restate-backed {@link ToolStateStore} — durable key/value state for tools,\n * stored in the bound virtual object's K/V state.\n *\n * Why this is the right home for it: the Restate journal is\n * invocation-scoped, so it cannot carry information from one invocation to\n * the next; virtual-object state can, and it survives process death without\n * a database of your own. Same substrate `restateSessionStore` uses.\n *\n * Placement rules this store exists to respect (Restate forbids context use\n * inside `ctx.run`, which is where a wrapped tool body executes):\n *\n * - `load` performs the one `ctx.get`. The agent calls it once per run,\n * before the first tool dispatch — outside every journaled action, at a\n * position replay reproduces.\n * - `commit` performs `ctx.set`. The loop calls it after a tool call\n * settles, also outside the journaled action, with ops that came back out\n * of the journal (see `restateTool`'s state envelope) — so the write is\n * identical on a live attempt and on replay.\n *\n * Neither is ever reached from inside a tool body: `ToolContext.state` reads\n * a snapshot and stages writes in memory.\n *\n * ## Storage shape\n *\n * One state key holding a JSON object (default `zidane_tool_state`), read\n * through a per-invocation cache and rewritten whole on each commit — the\n * same trade `restateSessionStore` makes for turns. Restate caps state\n * value size, so treat this like the session store's `sanitizeTurnsForState`\n * discipline: flags, ids, counters, cursors. Not blobs, not transcripts.\n *\n * Pass an explicit `key` to isolate namespaces (e.g. one per tool family) or\n * to migrate a schema without clobbering the old value.\n */\n\nimport type { ToolStateOp, ToolStateStore } from '../tool-state'\nimport type { RestateObjectContextLike } from './types'\n\n/** Default virtual-object state key holding the tool-state map. */\nexport const DEFAULT_TOOL_STATE_KEY = 'zidane_tool_state'\n\nexport interface RestateToolStateStoreOptions {\n /** Override the state key. Defaults to {@link DEFAULT_TOOL_STATE_KEY}. */\n key?: string\n /**\n * Per-value size budget enforced when a tool stages a write. Defaults to\n * the library's `DEFAULT_MAX_VALUE_BYTES` (64 KiB), which is far below\n * Restate's own journal-entry ceiling on purpose: an oversized state value\n * doesn't fail politely there — the invocation fails with `RT0003`\n * (MessageSizeLimit) and is retried under the configured policy, i.e. a fat\n * write becomes a poison pill rather than a dropped one.\n */\n maxValueBytes?: number\n}\n\n/**\n * Build a {@link ToolStateStore} over the bound virtual object's state.\n *\n * ```ts\n * const agent = createAgent({\n * provider,\n * tools: wrapAgentTools({ shell }, ctx),\n * session: createSession({ id: ctx.key, store: restateSessionStore(ctx) }),\n * toolState: restateToolStateStore(ctx),\n * })\n * ```\n *\n * Single-writer like the session store: the state belongs to the object key,\n * so bind one key per conversation and one agent per invocation.\n *\n * Build it INSIDE the handler. The returned store closes over this `ctx`, so\n * an agent constructed once at module scope and reused across invocations\n * would commit through a context that is already finished, and would never\n * re-hydrate (the controller memoizes the load for the life of the agent).\n * Same rule as `restateSessionStore` / `restateProvider` / `restateClock` —\n * but easier to get wrong here, because `toolState` looks like\n * agent-lifetime configuration rather than a per-invocation binding.\n *\n * The map is a schema you own: one JSON object, no versioning, no migration.\n * A value written by an earlier deploy is still there after you change its\n * shape, so either read tolerantly or move to a fresh `key`.\n *\n * Enabling this adds a `ctx.get` at run start, which changes the journal\n * shape for NEW invocations. Existing in-flight invocations replay against\n * the old shape — drain them (or accept the failed attempts) before rolling\n * it out.\n */\nexport function restateToolStateStore(\n ctx: RestateObjectContextLike,\n options: RestateToolStateStoreOptions = {},\n): ToolStateStore {\n const key = options.key ?? DEFAULT_TOOL_STATE_KEY\n const maxValueBytes = options.maxValueBytes\n // Read-through cache: `load` pulls once, `commit` writes through it, so a\n // multi-call run spends exactly one `ctx.get` and one `ctx.set` per\n // state-touching call. Eager (not deferred) for the same reason the\n // session store is: external readers of the object need to see writes as\n // they land, not at the end of the invocation.\n let cache: Record<string, unknown> | undefined\n\n return {\n ...(maxValueBytes !== undefined ? { maxValueBytes } : {}),\n load: async () => {\n cache = (await ctx.get<Record<string, unknown>>(key)) ?? {}\n // Copy out — the controller owns its snapshot and must not alias the\n // cache this store rewrites on commit.\n return { ...cache }\n },\n commit: (ops: readonly ToolStateOp[]) => {\n if (ops.length === 0)\n return\n const next = { ...(cache ?? {}) }\n for (const op of ops) {\n if (op.delete === true)\n delete next[op.key]\n else\n next[op.key] = op.value\n }\n cache = next\n ctx.set(key, next)\n },\n }\n}\n","/**\n * Durable `ExecutionContext.waitBackground` for Restate hosts.\n *\n * A durable execution context can't push a `task:exit` callback from a timer\n * back into a journaled handler. The race-safe pattern is an awakeable park:\n * the runner fires task-exit over its own bridge → `ctx.resolveAwakeable(id,\n * exitInfo)` → the parked `waitBackground` resumes. The *choreography* around\n * that park is entirely generic — only the persistence (which row maps a task\n * to its resumer awakeable) is host-specific. {@link restateWaitBackground}\n * owns the generic half; the host supplies `probe` / `register` / `settle`.\n *\n * Ordering contract (this is the whole point — get it wrong and you leak a\n * lost wakeup):\n *\n * 1. **mint** the awakeable (before the journaled register, so replay\n * re-derives the same id).\n * 2. **register** the awakeable id as the task's exit resumer — journaled,\n * and crucially BEFORE the probe. If we probed first and the task exited\n * in the gap before register, the runner's `task:exit` would fire with no\n * resumer row and the park would hang forever.\n * 3. **probe** the registry. If the task ALREADY terminated, fast-path: settle\n * and return its exit info without ever parking (a resolution that lands\n * on the registered awakeable afterwards is dropped by the runtime). If the\n * task is unknown, settle and return `null`. Otherwise:\n * 4. **park** on the awakeable, OUTSIDE any `ctx.run`, raced against the\n * durable `ctx.sleep(timeoutMs)` deadline and the caller's abort signal.\n * A timeout / abort resolves `null` (the seam's documented sentinel).\n * 5. **settle** — journaled finalization (stamp / clear the resumer row).\n *\n * The returned function matches `ExecutionContext.waitBackground` exactly, so a\n * host wires it with `execution.waitBackground = restateWaitBackground({ … })`.\n */\n\nimport type { ExecutionHandle, TaskEntry, TaskExitInfo } from '../contexts'\nimport type { RestatePromiseRaceLike } from './awakeable'\nimport type { ReplayTracker } from './replay'\nimport type { RestateContextLike, RestateRunOptions } from './types'\nimport { awakeableWithTimeout } from './awakeable'\n\n/** Journaled registration marker — mirrors the marker invariant in `restateAwakeableTool`. */\ninterface WaitBackgroundRegisterMarker {\n registered: true\n awakeableId: string\n}\n\nexport interface RestateWaitBackgroundOptions {\n /** The Restate context the awakeable + journal entries bind to. */\n ctx: RestateContextLike\n /**\n * Snapshot the host's task registry (the `listBackground` shape). Called\n * AFTER `register`, inside a journaled `ctx.run`. The helper finds `taskId`\n * in the result: terminated → fast-path return, running → park, absent →\n * `null`.\n */\n probe: (handle: ExecutionHandle, taskId: string) => Promise<readonly TaskEntry[]> | readonly TaskEntry[]\n /**\n * Persist `awakeableId` as the exit resumer for `taskId` BEFORE the probe —\n * the host's task-exit path must later call `ctx.resolveAwakeable(awakeableId,\n * exitInfo)`. Runs inside a journaled `ctx.run`; keep it short and\n * idempotent-safe up to journal persistence.\n */\n register: (awakeableId: string, taskId: string, handle: ExecutionHandle) => Promise<void> | void\n /**\n * Finalize the resumer row once the wait resolves — `exit` is the task's\n * {@link TaskExitInfo}, or `null` on timeout / abort / unknown task. Runs\n * inside a journaled `ctx.run`. Optional.\n */\n settle?: (awakeableId: string, taskId: string, exit: TaskExitInfo | null, handle: ExecutionHandle) => Promise<void> | void\n /**\n * Default park deadline in milliseconds. A per-call `options.timeoutMs`\n * (what the `wait_task` tool passes) wins. Unset / non-positive = park until\n * the resumer fires or the caller aborts.\n */\n timeoutMs?: number\n /**\n * Durable race combinator for the timeout race — pass `RestatePromise` from\n * the SDK. See {@link awakeableWithTimeout}; native `Promise.race` is the\n * replay-safe fallback.\n */\n promises?: RestatePromiseRaceLike\n /** `ctx.run` options for the journaled phases. Defaults to `{ maxRetryAttempts: 1 }`. */\n runOptions?: RestateRunOptions\n /** Journal-entry prefix. Default `wait-background`. */\n entryPrefix?: string\n /** Per-invocation replay tracker (see `createReplayTracker`). */\n replayTracker?: ReplayTracker\n}\n\nfunction entryToExit(entry: TaskEntry): TaskExitInfo {\n return {\n taskId: entry.taskId,\n // `entryToExit` is only called for terminated entries; `'running'` can't\n // reach here, but narrow defensively to the exit-only union.\n status: entry.status === 'running' ? 'exited' : entry.status,\n exitCode: entry.exitCode ?? 0,\n ...(entry.signal ? { signal: entry.signal } : {}),\n outputPath: entry.outputPath,\n durationMs: Math.max(0, (entry.endedAt ?? entry.startedAt) - entry.startedAt),\n command: entry.command,\n }\n}\n\n/**\n * Park on `promise` until it settles, the caller aborts, or (already handled\n * by `awakeableWithTimeout`) the durable deadline elapses. Abort and rejection\n * both resolve `null` — the `waitBackground` seam's contract is \"exit info, or\n * null when the task didn't cleanly exit before we stopped waiting\".\n */\nfunction parkUntilAbort<T>(promise: Promise<T>, signal?: AbortSignal): Promise<T | null> {\n if (!signal)\n return promise.then(value => value, () => null)\n if (signal.aborted)\n return Promise.resolve(null)\n return new Promise<T | null>((resolve) => {\n const onAbort = (): void => resolve(null)\n signal.addEventListener('abort', onAbort, { once: true })\n promise.then(\n (value) => {\n signal.removeEventListener('abort', onAbort)\n resolve(value)\n },\n () => {\n signal.removeEventListener('abort', onAbort)\n resolve(null)\n },\n )\n })\n}\n\n/**\n * Build a durable `ExecutionContext.waitBackground` — see the module doc for\n * the ordering contract. The returned function is the seam itself:\n * `(handle, taskId, options?) => Promise<TaskExitInfo | null>`.\n */\nexport function restateWaitBackground(\n options: RestateWaitBackgroundOptions,\n): (handle: ExecutionHandle, taskId: string, opts?: { timeoutMs?: number, signal?: AbortSignal }) => Promise<TaskExitInfo | null> {\n const { ctx, probe, register, settle } = options\n const runOpts: RestateRunOptions = options.runOptions ?? { maxRetryAttempts: 1 }\n const prefix = options.entryPrefix ?? 'wait-background'\n let seq = 0\n\n return async (handle, taskId, callOpts) => {\n seq += 1\n const entry = `${prefix}-${taskId}-${seq}`\n const timeoutMs = callOpts?.timeoutMs ?? options.timeoutMs\n const signal = callOpts?.signal\n\n const finalize = async (exit: TaskExitInfo | null, awakeableId: string): Promise<TaskExitInfo | null> => {\n if (settle) {\n await ctx.run(`${entry}-settle`, async () => {\n options.replayTracker?.markLive()\n await settle(awakeableId, taskId, exit, handle)\n }, runOpts)\n }\n return exit\n }\n\n // 1. Mint BEFORE the journaled register (same ordering contract as\n // restateAwakeableTool) — replay returns the same id. The timeout sleep\n // is armed here too, so the park below is a durable race.\n const awakeable = awakeableWithTimeout<TaskExitInfo>(ctx, {\n ...(timeoutMs !== undefined ? { timeoutMs } : {}),\n ...(options.promises ? { promises: options.promises } : {}),\n })\n\n // 2. Register the resumer BEFORE probing.\n const marker = await ctx.run<WaitBackgroundRegisterMarker>(`${entry}-register`, async () => {\n options.replayTracker?.markLive()\n await register(awakeable.id, taskId, handle)\n return { registered: true, awakeableId: awakeable.id }\n }, runOpts)\n if (marker.awakeableId !== awakeable.id) {\n throw new Error(\n `restateWaitBackground(${taskId}): journal drift — registration marker carries awakeable \"${marker.awakeableId}\" but this replay minted \"${awakeable.id}\". Refusing to park on an unreachable awakeable.`,\n )\n }\n\n // 3. Probe (journaled). Fast-path terminated / unknown without parking.\n const entries = await ctx.run<readonly TaskEntry[]>(`${entry}-probe`, async () => {\n options.replayTracker?.markLive()\n return [...await probe(handle, taskId)]\n }, runOpts)\n const found = entries.find(e => e.taskId === taskId)\n if (!found)\n return finalize(null, awakeable.id)\n if (found.status !== 'running')\n return finalize(entryToExit(found), awakeable.id)\n\n // 4. Park OUTSIDE any ctx.run — a suspension point must not nest in a\n // journaled closure. Timeout (via awakeableWithTimeout) and abort both\n // resolve null.\n const resumed = await parkUntilAbort(awakeable.promise, signal)\n\n // 5. Settle + return.\n return finalize(resumed, awakeable.id)\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"restate.js","names":[],"sources":["../src/restate/awakeable.ts","../src/restate/awakeable-tool.ts","../src/restate/errors.ts","../src/restate/behavior.ts","../src/restate/clock.ts","../src/restate/soft-errors.ts","../src/restate/tool.ts","../src/restate/mcp.ts","../src/restate/parallel.ts","../src/restate/provider.ts","../src/restate/replay.ts","../src/restate/session.ts","../src/restate/spawn.ts","../src/restate/tool-state.ts","../src/restate/wait-background.ts"],"sourcesContent":["/**\n * Awakeable helpers — durable waits with deadlines.\n *\n * `awakeableWithTimeout` packages the canonical \"park until a resumer\n * fires, but not forever\" shape: an awakeable raced against a durable\n * `ctx.sleep(timeoutMs)` timer. The race itself survives process death —\n * on replay both branches resume from the journal and the same side\n * wins. This is the three-line building block for\n * `ExecutionContext.waitBackground` implementations on durable hosts\n * (runner fires task-exit → `resolveAwakeable(id, info)`; the timeout\n * branch maps to the seam's `null` return).\n */\n\nimport type { RestateAwakeable, RestateContextLike } from './types'\n\n/**\n * Structural subset of the SDK's `RestatePromise` static surface used by\n * {@link awakeableWithTimeout} — mirrors `RestatePromiseAllLike` from\n * `./parallel`. Pass `RestatePromise` from `@restatedev/restate-sdk` so\n * the race goes through the journaled combinator; native `Promise.race`\n * over two durable promises leaves the winner to the runtime's replay\n * ordering instead of an explicit journal entry.\n */\nexport interface RestatePromiseRaceLike<TPromise extends Promise<unknown> = Promise<unknown>> {\n race: (values: readonly TPromise[]) => Promise<unknown>\n}\n\nexport interface AwakeableWithTimeoutOptions<TPromise extends Promise<unknown> = Promise<unknown>> {\n /**\n * Durable deadline in milliseconds. Unset / non-positive = no timeout\n * (the returned awakeable is the plain `ctx.awakeable()` passthrough).\n */\n timeoutMs?: number\n /**\n * Durable race combinator — pass `RestatePromise` from the SDK. When\n * omitted, native `Promise.race` is used: correct at runtime and\n * replay-safe for THIS pattern (both branches are journaled\n * primitives), but the SDK combinator is the recommended belt-and-\n * braces choice for deterministic replay.\n */\n promises?: RestatePromiseRaceLike<TPromise>\n}\n\n/**\n * Mint an awakeable that resolves with the resumer's payload, or `null`\n * when `timeoutMs` elapses first. The id is journal-stable (send it\n * out-of-band as usual); the timeout is a durable `ctx.sleep`, so a\n * parked invocation suspends instead of holding a worker.\n *\n * Timeout surfaces as `null` — a resumer that resolves `undefined` is\n * indistinguishable from a timeout, so resolve a concrete payload.\n *\n * ```ts\n * // waitBackground for a durable host, in three lines:\n * const { id, promise } = awakeableWithTimeout<TaskExitInfo>(ctx, { timeoutMs, promises: RestatePromise })\n * await registerExitResumer(taskId, id) // runner → ctx.resolveAwakeable(id, info)\n * return await promise // TaskExitInfo, or null on timeout\n * ```\n */\nexport function awakeableWithTimeout<T, TPromise extends Promise<unknown> = Promise<unknown>>(\n ctx: RestateContextLike,\n options: AwakeableWithTimeoutOptions<TPromise> = {},\n): RestateAwakeable<T | null> {\n const awakeable = ctx.awakeable<T>()\n const timeoutMs = options.timeoutMs\n if (typeof timeoutMs !== 'number' || !Number.isFinite(timeoutMs) || timeoutMs <= 0)\n return awakeable\n\n const timer = ctx.sleep(timeoutMs)\n const raced = options.promises\n ? options.promises.race([awakeable.promise, timer] as readonly unknown[] as readonly TPromise[])\n : Promise.race<unknown>([awakeable.promise, timer])\n return {\n id: awakeable.id,\n // The sleep branch resolves `undefined`; normalize to the seam's\n // `null` so callers get one documented timeout sentinel.\n promise: raced.then(value => (value === undefined ? null : value as T)),\n }\n}\n","/**\n * Awakeable-backed tool — durable human/external-in-the-loop waits.\n *\n * Builds a `ToolDef` whose `execute` parks on a Restate awakeable: the\n * tool mints a journal-stable awakeable id, broadcasts it out-of-band\n * (webhook, queue, collab stream — the `notify` callback), and suspends\n * until a resumer calls `ctx.resolveAwakeable(id, value)` on the SDK\n * side. The classic shape for `ask_user` / `request_review` /\n * `wait_for_approval` tools inside durable handlers.\n *\n * Replay contract\n * ---------------\n * - **Broadcast-once-across-replays**: `notify` runs inside `ctx.run`,\n * so a crash + replay returns the journaled marker without re-sending\n * the notification. The user is pinged exactly once per tool call, no\n * matter how many times the worker restarts.\n * - **Marker invariant**: the journaled marker records the awakeable id\n * it was broadcast for. On replay the freshly-minted awakeable id must\n * match (the SDK derives awakeable ids deterministically from the\n * journal position); a mismatch means the journal and the code path\n * drifted — the tool throws instead of parking on an id nobody will\n * ever resolve.\n */\n\nimport type { ToolContext, ToolDef } from '../tools/types'\nimport type { ToolResultContent } from '../types'\nimport type { RestateContextLike, RestateRunOptions } from './types'\n\n/** Journaled broadcast marker — see \"Marker invariant\" in the module doc. */\ninterface AwakeableNotifyMarker {\n notified: true\n awakeableId: string\n}\n\nexport interface RestateAwakeableToolOptions<T = unknown> {\n /** Canonical tool name (what the model calls). */\n name: string\n /** Model-facing tool description. */\n description: string\n /** JSON schema for the tool input. */\n inputSchema: Record<string, unknown>\n /** The Restate context the awakeable + journal entries bind to. */\n ctx: RestateContextLike\n /**\n * Send the awakeable id (plus the call's input) out-of-band so a\n * resumer can later call `ctx.resolveAwakeable(awakeableId, value)`.\n * Runs inside `ctx.run` — fires exactly once across replays.\n */\n notify: (info: {\n awakeableId: string\n input: Record<string, unknown>\n toolCtx: ToolContext\n }) => void | Promise<void>\n /**\n * Map the resolved awakeable payload to the tool result. Default:\n * strings pass through, everything else is JSON-stringified.\n */\n toResult?: (value: T, input: Record<string, unknown>) => string | ToolResultContent[]\n /**\n * `ctx.run` options for the notify entry. Defaults to\n * `{ maxRetryAttempts: 1 }`, matching `restateTool`'s rationale.\n */\n runOptions?: RestateRunOptions\n /**\n * Concurrency-safety flag passed through to the `ToolDef`. Defaults to\n * `false` — a parked wait holding a scheduler slot should barrier.\n */\n isConcurrencySafe?: boolean\n}\n\n/**\n * Build a `ToolDef` that parks on a Restate awakeable until an external\n * resumer resolves it. See the module doc for the replay contract.\n *\n * Do NOT additionally wrap the returned tool in `restateTool` — the\n * journal discipline is already internal, and an outer `ctx.run` would\n * illegally nest the suspension point inside a journaled closure.\n */\nexport function restateAwakeableTool<T = unknown>(\n options: RestateAwakeableToolOptions<T>,\n): ToolDef {\n const { name, description, inputSchema, ctx, notify, toResult } = options\n const runOpts: RestateRunOptions = options.runOptions ?? { maxRetryAttempts: 1 }\n let seq = 0\n\n const execute = async (input: Record<string, unknown>, toolCtx: ToolContext): Promise<string | ToolResultContent[]> => {\n seq += 1\n // Mint BEFORE the journaled broadcast: the awakeable's journal\n // position precedes the notify entry, so on replay both come back\n // in the same order with the same id.\n const awakeable = ctx.awakeable<T>()\n\n const marker = await ctx.run<AwakeableNotifyMarker>(\n `awakeable-${name}-${seq}-notify`,\n async () => {\n await notify({ awakeableId: awakeable.id, input, toolCtx })\n return { notified: true, awakeableId: awakeable.id }\n },\n runOpts,\n )\n\n // Marker invariant — a drifted journal would otherwise park this\n // call on an id that was never broadcast (nobody will resolve it).\n if (marker.awakeableId !== awakeable.id) {\n throw new Error(\n `restateAwakeableTool(${name}): journal drift — broadcast marker carries awakeable \"${marker.awakeableId}\" but this replay minted \"${awakeable.id}\". The journal and the code path no longer line up; refusing to park on an unreachable awakeable.`,\n )\n }\n\n const value = await awakeable.promise\n if (toResult)\n return toResult(value, input)\n return typeof value === 'string' ? value : JSON.stringify(value)\n }\n\n return {\n spec: { name, description, inputSchema },\n ...(options.isConcurrencySafe !== undefined ? { isConcurrencySafe: options.isConcurrencySafe } : {}),\n execute,\n // The awakeable park IS the durable body — the loop's durable path\n // can use it directly without an extra wrapper.\n durableExecute: execute,\n }\n}\n","/**\n * Restate control-flow errors must escape the agent loop. If they are turned\n * into model-visible tool results, the runtime can retry/suspend incorrectly.\n *\n * Kept structural so `zidane/restate` does not need to import the SDK at\n * runtime just to recognize the common error shapes.\n */\nexport function shouldRethrowRestateControlError(error: unknown): boolean {\n if (!(error instanceof Error))\n return false\n\n // Platform DOMExceptions collide with Restate's control-error classes BY\n // NAME: `AbortSignal.timeout()` mints name 'TimeoutError' (Bun/undici),\n // an aborted fetch mints 'AbortError'. Those are plain transport\n // failures, never Restate control flow — without this guard a fetch\n // deadline inside a journaled tool body was classified \"control\",\n // rethrown past the soft-error net, and aborted an entire run via\n // `maxRetryAttempts: 1` (prod incident 2026-07-17: a 330s exec-gateway\n // timeout killed a workflow run with \"The operation timed out.\").\n if (typeof DOMException !== 'undefined' && error instanceof DOMException)\n return false\n\n const codeValue = Reflect.get(error, 'code')\n const code = typeof codeValue === 'number'\n ? codeValue\n : undefined\n if (code === 599)\n return true\n\n const name = error.name\n if (\n name === 'TerminalError'\n || name === 'TimeoutError'\n || name === 'CancelledError'\n || name === 'SuspendedError'\n ) {\n return true\n }\n\n const ctorName = error.constructor?.name\n const serializedCtorNameValue = Reflect.get(error, 'constructorName')\n const serializedCtorName = typeof serializedCtorNameValue === 'string'\n ? serializedCtorNameValue\n : undefined\n if (\n ctorName === 'TerminalError'\n || ctorName === 'TimeoutError'\n || ctorName === 'CancelledError'\n || ctorName === 'SuspendedError'\n || serializedCtorName === 'TerminalError'\n || serializedCtorName === 'TimeoutError'\n || serializedCtorName === 'CancelledError'\n || serializedCtorName === 'SuspendedError'\n ) {\n return true\n }\n\n return typeof name === 'string' && name.toLowerCase().includes('suspend')\n}\n","import type { AgentBehavior } from '../types'\nimport { shouldRethrowRestateControlError } from './errors'\n\n/**\n * Conservative behavior defaults for agents running inside Restate.\n *\n * The helper is opt-in and returns a plain AgentBehavior object, so callers can\n * spread or override it without changing non-Restate harness defaults.\n *\n * `disableBackgroundTasks: 'non-durable'` is capability-aware: background\n * tasks stay enabled for execution contexts whose\n * `capabilities.detachedTasks` is `'durable'` (tasks live on a remote\n * runner and survive worker crashes) and are disabled for everything\n * else (host-local processes don't survive process death). Hosts on\n * plain `ProcessContext` see the same effective behavior as the old\n * blanket `true`.\n *\n * ## Performance knob: `maxConcurrentTools`\n *\n * Defaults to `1` — tools run sequentially, which keeps the journal simple and\n * is the safe default. The cost: a turn with N tool calls becomes N separate\n * `ctx.run` entries awaited one at a time, so on a suspend-per-round-trip host\n * (Lambda / sandbox) that's N suspend+replay cycles for that turn.\n *\n * Raising it (e.g. `restateBehavior({ maxConcurrentTools: 8 })`) lets the\n * Restate batch executor join CONCURRENCY-SAFE calls through Restate's durable\n * `all()` combinator — the invocation parks ONCE per batch instead of once per\n * tool, AND the safe calls run in parallel (wall-clock win). Safety is judged\n * per call, not per tool (`ToolDef.isConcurrencySafe` may inspect the input —\n * e.g. a read-only `shell` command batches, a mutating one doesn't), and\n * unsafe calls (file writes/edits, mutating commands) stay barriers regardless,\n * so correctness is unchanged; the only thing you're trading is resource\n * concurrency (e.g. how many reads / API calls fire at once). For read-heavy\n * agents this is the single biggest suspension-count lever. It's left at `1` by\n * default because the right ceiling is workload-specific — set it deliberately.\n */\nexport function restateBehavior(overrides: AgentBehavior = {}): AgentBehavior {\n return {\n maxConcurrentTools: 1,\n disableBackgroundTasks: 'non-durable',\n cache: true,\n shouldRethrowToolError: shouldRethrowRestateControlError,\n // Context discipline for long runs. These are client-side and\n // provider-agnostic: they trim the message array before it reaches the\n // provider, so they work for OSS / OpenAI-compat models too.\n // `tail` keeps the largest recent suffix of tool output under\n // `compactThreshold` bytes; `elideStaleReads: 'stub'` drops superseded\n // file reads from the wire — the explicit spelling of legacy `true`.\n // Deliberately NOT the chat profiles' `'notice'`: restate's priority is\n // per-turn payload size (journal weight + LLM latency), so it pays the\n // prompt-cache re-bill to keep requests small. See\n // `AgentBehavior.elideStaleReads` for the trade.\n // `mediaKeepTurns` ages base64 (pasted/Read images, PDFs) off the wire.\n compactStrategy: 'tail',\n compactThreshold: 128 * 1024,\n compactKeepTurns: 8,\n elideStaleReads: 'stub',\n mediaKeepTurns: 8,\n toolOutputBudget: 64 * 1024,\n // Token-based proactive summarization. Inert unless a context window is\n // resolvable through `provider.meta.contextWindow` or an explicit\n // `autoCompact.contextWindow` override.\n autoCompact: { threshold: 0.85 },\n ...overrides,\n }\n}\n","/**\n * Restate-backed {@link AgentClock} — sources `now()` from the journal and\n * `randomUUID()` from a clock-private deterministic sequence so\n * `SessionTurn.createdAt`, `runId`, and fallback / synthetic turn ids stay\n * byte-identical across replays of the same invocation.\n *\n * Why `randomUUID()` does NOT ride `ctx.rand.uuidv4()`\n * -----------------------------------------------------\n * Restate's `ctx.rand` is a single invocation-seeded stream advanced per\n * draw: draw #N always yields the same value, so it is replay-stable ONLY\n * if every consumer's draw COUNT before a given point is identical between\n * the live attempt and each replay. The agent runtime cannot guarantee\n * that: MCP bootstrap, provider retries, awakeable tools, and host code all\n * share the stream, and any live-vs-replay variance in their draw counts\n * shifts every subsequent draw. In production that surfaced as turn ids\n * swapping values across a suspension — journaled bridge entries keyed by\n * turn id (and `ctx.set` turn bytes) then diverged on replay and killed the\n * invocation with `JournalMismatchError`.\n *\n * Instead, ids are minted as sha256-derived, RFC-4122-v4-shaped UUIDs from\n * `(idSeed, clock-local counter)`. The counter advances only on this\n * clock's own mints (loop turn boundaries — deterministic given journaled\n * LLM/tool results), fully isolated from every other rand consumer. Pass\n * {@link RestateClockOptions.idSeed} (e.g. the virtual object key) for a\n * draw-free construction; without it the clock consumes exactly ONE\n * `ctx.rand.uuidv4()` draw at construction time as its seed — stable as\n * long as clock construction happens at a deterministic point in the\n * handler (i.e. before any variably-drawing work), which `createAgent`\n * setup satisfies.\n *\n * Pass to `agent.run({ clock: restateClock(ctx) })` or bake it into\n * `createAgent({ clock: restateClock(ctx) })` for the duration of a\n * handler invocation. The clock holds a reference to `ctx`; do not reuse\n * a clock instance across invocations.\n *\n * Suspension cost & coalescing\n * ----------------------------\n * `ctx.date.now()` is a JOURNALED durable op — each call is a round-trip the\n * invocation can suspend on (on sandbox-reattach hosts, a suspension tears\n * down and re-attaches the worker). The agent loop samples `now()` a few\n * times per turn (`SessionTurn.createdAt` for the assistant turn and the\n * tool-result turn, plus run start/end), so a multi-turn run racks up a\n * journaled `date.now()` per couple of turns. `randomUUID()` is a pure\n * synchronous hash — it never journals and never suspends.\n *\n * Pass `{ coalesce: true }` to collapse most of those `date.now()`\n * round-trips: the clock journals a real anchor once, then derives a\n * monotonic sequence (`anchor`, `anchor+1`, …) from it without re-journaling,\n * re-anchoring against the real clock only every `reanchorEvery` calls. This\n * is fully replay-deterministic (the journaled anchors replay verbatim and\n * the counter is a pure function of call order) and monotonic (clamped so a\n * fresh anchor never moves time backwards). The TRADEOFF: timestamps within a\n * re-anchor window are logical — ordered and stable, but clustered near the\n * window's anchor rather than wall-clock-accurate. Run `elapsed`\n * (`endedAt - startedAt`) and per-turn `createdAt` lose precision down to the\n * window granularity; live-only measurements (TTFT, `maxWallMs`) are\n * unaffected because the loop reads those from `Date.now()` directly. Lower\n * `reanchorEvery` ⇒ more accurate timestamps + more suspensions; higher ⇒\n * fewer suspensions + more clustering. Default is unchanged (every `now()`\n * journaled) so existing deployments keep wall-accurate timestamps until they\n * opt in.\n */\n\nimport type { AgentClock } from '../types'\nimport type { RestateContextLike } from './types'\nimport { createHash } from 'node:crypto'\n\n/** Default re-anchor cadence for the coalescing clock (see {@link RestateClockOptions}). */\nconst DEFAULT_REANCHOR_EVERY = 8\n\n/**\n * RFC-4122-v4-shaped UUID derived from a seed string — pure function, no\n * RNG. Version/variant bits are set so consumers (and DB uuid columns)\n * treat it as a regular v4 UUID.\n */\nexport function deterministicUuid(seed: string): string {\n const bytes = createHash('sha256').update(seed).digest()\n bytes[6] = (bytes[6]! & 0x0F) | 0x40\n bytes[8] = (bytes[8]! & 0x3F) | 0x80\n const hex = bytes.subarray(0, 16).toString('hex')\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`\n}\n\nexport interface RestateClockOptions {\n /**\n * Coalesce `ctx.date.now()` journaling to cut Restate suspensions.\n *\n * - `false` / omitted (default): every `now()` journals a fresh\n * `ctx.date.now()` — wall-accurate, one suspension per call.\n * - `true`: enable coalescing with the default re-anchor cadence\n * ({@link DEFAULT_REANCHOR_EVERY}).\n * - `{ reanchorEvery: n }`: enable coalescing and re-anchor against the\n * real clock every `n` calls (`n` floored to a positive integer; falls\n * back to the default otherwise).\n *\n * See the module docstring for the determinism guarantees and the\n * timestamp-precision tradeoff.\n */\n coalesce?: boolean | { reanchorEvery?: number }\n /**\n * Entropy source for the deterministic `randomUUID()` sequence. Pass a\n * per-invocation stable value (the virtual object key, a workflow id, …)\n * so construction consumes zero `ctx.rand` draws. When omitted, the clock\n * draws `ctx.rand.uuidv4()` ONCE at construction as its seed — see the\n * module docstring for why that single draw is safe where later draws are\n * not.\n */\n idSeed?: string\n}\n\n/**\n * Wrap a Restate context into the {@link AgentClock} shape Zidane consumes\n * for journaled metadata: `now()` rides the journaled `ctx.date.now()`;\n * `randomUUID()` is a clock-private deterministic sequence (see the module\n * docstring — deliberately NOT `ctx.rand`).\n *\n * With `{ coalesce }` set, `now()` instead journals a real anchor\n * periodically and derives a monotonic logical sequence in between — see\n * the module docstring for the suspension/precision tradeoff. Do not reuse a\n * coalescing clock across invocations: the anchor/counter state is\n * per-invocation.\n */\nexport function restateClock(ctx: RestateContextLike, options: RestateClockOptions = {}): AgentClock {\n const { coalesce } = options\n\n // Draw-order-independent id minting — see the module docstring. The seed\n // is fixed at construction; each mint hashes (seed, local counter).\n const idSeed = options.idSeed ?? ctx.rand.uuidv4()\n let idSeq = 0\n const randomUUID = (): string => deterministicUuid(`${idSeed}:uuid:${idSeq++}`)\n\n if (!coalesce) {\n return {\n now: () => ctx.date.now(),\n randomUUID,\n // Tells wall-clock-sensitive consumers (e.g. the `spawn` tool's\n // per-child timeout) that time here replays instead of advancing, so\n // they must not branch on a timer.\n journaled: true,\n }\n }\n\n const requested = typeof coalesce === 'object' ? coalesce.reanchorEvery : undefined\n const reanchorEvery = typeof requested === 'number' && Number.isFinite(requested) && requested >= 1\n ? Math.floor(requested)\n : DEFAULT_REANCHOR_EVERY\n\n let anchor: number | undefined\n let callsSinceAnchor = 0\n let lastReturned = -1\n\n return {\n now: async (): Promise<number> => {\n // Re-anchor on the first call and every `reanchorEvery` calls after.\n // The decision is driven purely by the call counter (NOT wall-clock),\n // so it lands at identical call ordinals on replay — the journaled\n // `ctx.date.now()` entries are consumed in the same positions.\n if (anchor === undefined || callsSinceAnchor >= reanchorEvery) {\n anchor = await ctx.date.now()\n callsSinceAnchor = 0\n }\n const candidate = anchor + callsSinceAnchor\n callsSinceAnchor += 1\n // Clamp so a fresh real anchor that lands at or before the prior\n // logical value never rewinds time (a short, call-dense run can outrun\n // the wall clock within a window).\n const value = candidate > lastReturned ? candidate : lastReturned + 1\n lastReturned = value\n return value\n },\n randomUUID,\n journaled: true,\n }\n}\n","/**\n * Soft tool-error plumbing shared by {@link restateTool} and\n * {@link restateMcpToolWrap}.\n *\n * The problem: `restateTool` runs a tool body inside `ctx.run(...,\n * { maxRetryAttempts: 1 })`. An ordinary, recoverable tool throw (a failed\n * shell command, a transport error, an MCP `isError` result) would exhaust the\n * retry budget and surface as a Restate `TerminalError` — which\n * `restateBehavior`'s `shouldRethrowToolError` re-throws, aborting the whole\n * run. That's the opposite of the non-Restate model, where a tool throw becomes\n * a model-visible `tool_result { isError }` and the loop keeps going.\n *\n * The fix (same shape the MCP wrapper has always used): catch the recoverable\n * throw INSIDE the journaled closure and record it as a JSON-serializable\n * sentinel — so `ctx.run` journals a *value*, never a failed action. OUTSIDE the\n * journal (on both live and replay) the sentinel is turned back into a plain,\n * non-control `Error`, so the loop produces a `tool_result { isError }` and\n * continues. Real Restate control errors and deliberate aborts are never\n * softened — they must escape so the runtime can suspend / retry / cancel.\n */\n\nimport { shouldRethrowRestateControlError } from './errors'\n\n/** Journal value recorded for a softened tool throw. */\nconst SOFT_ERROR_KEY = '__zidaneRestateSoftError'\n\nexport interface SoftToolError {\n [SOFT_ERROR_KEY]: true\n message: string\n}\n\nexport function isSoftToolError(value: unknown): value is SoftToolError {\n return typeof value === 'object'\n && value !== null\n && (value as Record<string, unknown>)[SOFT_ERROR_KEY] === true\n}\n\n/** Build the sentinel recorded as the journal value for a softened throw. */\nexport function makeSoftToolError(error: unknown): SoftToolError {\n return { [SOFT_ERROR_KEY]: true, message: error instanceof Error ? error.message : String(error) }\n}\n\n/**\n * Recoverable throws soften; control-flow + abort throws do not.\n *\n * - Restate control errors (`TerminalError`, `SuspendedError`, …) must escape\n * so the runtime can act on them.\n * - Deliberate aborts (run cancel, `cancelTool`, sibling cascade) are a\n * timing-dependent, non-deterministic outcome — journaling one would bake it\n * into replay. The `signal.aborted` check also catches transports (the MCP\n * layer) that reject an aborted call with a plain `Error` carrying no\n * `AbortError` name.\n */\nexport function isRestateControlOrAbort(error: unknown, signal?: AbortSignal): boolean {\n if (shouldRethrowRestateControlError(error))\n return true\n if (error instanceof Error && error.name === 'AbortError')\n return true\n return signal?.aborted === true\n}\n\n/**\n * Outside-the-journal counterpart to {@link makeSoftToolError}: re-throw a\n * recorded sentinel as a plain (non-control) `Error`, else pass the value\n * through untouched.\n */\nexport function rethrowSoftToolError<T>(value: T): Exclude<T, SoftToolError> {\n if (isSoftToolError(value))\n throw new Error(value.message)\n return value as Exclude<T, SoftToolError>\n}\n","/**\n * Restate-backed tool wrappers.\n *\n * Wraps `ToolDef.execute` so every tool invocation is journaled. The\n * tool body runs on the original execution; after Restate persists the\n * journal entry, replay returns the recorded result without re-executing.\n * If the process dies before the entry is durable, the latest in-flight\n * tool can run again, so non-idempotent tools still need idempotency keys.\n *\n * `tool:gate`, `tool:transform`, `tool:after` hooks fire OUTSIDE the\n * journaled boundary, so they re-execute on replay. Built-in handlers\n * are deterministic given the journaled input + output (truncation,\n * image-stripping, `<edit-outcomes>` merge — all pure). Consumer hooks\n * that hit external services should themselves wrap side effects in\n * `ctx.run` so the substitution / annotation is replay-stable.\n *\n * `isConcurrencySafe` is preserved — Restate's per-key serialization\n * doesn't preclude in-handler parallelism. The loop's scheduler still\n * fans out safe tools up to `behavior.maxConcurrentTools`, each call\n * lands in its own journal entry. Order-of-journal-completion does NOT\n * affect replay correctness: Restate journals by call-site name, not\n * by completion order.\n */\n\nimport type { AliasMaps } from '../aliasing'\nimport type { DetachedTasksCapability } from '../contexts'\nimport type { Session, SessionMetaWrite } from '../session'\nimport type { StagedToolState, ToolStateOp } from '../tool-state'\nimport type { ToolContext, ToolDef } from '../tools/types'\nimport type { ToolOutcome, ToolResultContent } from '../types'\nimport type { RestatePromiseRaceLike } from './awakeable'\nimport type { RestatePromiseLike } from './parallel'\nimport type { ReplayTracker } from './replay'\nimport type { RestateContextLike, RestateRunOptions } from './types'\nimport { buildAliasMaps } from '../aliasing'\nimport { recordSessionMetaWrites } from '../session'\nimport { isToolStateOps, stagedToolState } from '../tool-state'\nimport { hydrateReadStateFromSessionAsync } from '../tools/read-state'\nimport { coerceToolResultContent } from '../types'\nimport { awakeableWithTimeout } from './awakeable'\nimport { isRestateControlOrAbort, makeSoftToolError, rethrowSoftToolError } from './soft-errors'\n\n/**\n * Opt-in two-phase journaling for long-running, re-attachable tools.\n *\n * The default `restateTool` wrapping journals only the COMPLETED result —\n * a crash mid-execute re-runs the tool on replay, which is unacceptable\n * for builds / migrations / deploys. `durableStart` splits the execution:\n *\n * 1. `start` runs inside its own `ctx.run` entry, journaled BEFORE the\n * body — it kicks off the side effect and returns a re-attach token\n * (a background task id, a job handle, an idempotency key).\n * 2. the wait — either `attach` (one `ctx.run` holding the wait in the\n * result entry; only for short, bounded waits) or `wait` (awakeable\n * park: register a resumer in a journaled entry, suspend outside\n * the journal, synthesize the result in a final entry). On replay\n * both receive the SAME token and re-attach to the already-running\n * work instead of starting it again.\n *\n * The wrapped tool's own `execute` is bypassed; the start + wait pair IS\n * the execution.\n */\nexport interface RestateDurableStart<Token = unknown, Resumed = unknown> {\n /** Kick off the side effect; journaled before `attach`. Must be cheap + idempotent-safe up to journal persistence. */\n start: (input: Record<string, unknown>, toolCtx: ToolContext) => Promise<Token> | Token\n /**\n * Await / re-attach to the work identified by `token` and produce the\n * tool result. Runs inside ONE `ctx.run` entry, so the body must\n * settle within the runtime's attempt lifecycle — a long busy-poll in\n * here starves the journal, trips the server's inactivity/abort\n * timeouts, and each retry restarts the wait from scratch. Use this\n * only for waits bounded well below the inactivity timeout (or as the\n * degraded mode on hosts without a push seam); prefer {@link wait}\n * for anything long-running.\n *\n * Required unless {@link wait} is provided; ignored when both are set.\n */\n attach?: (token: Token, input: Record<string, unknown>, toolCtx: ToolContext) => Promise<string | ToolResultContent[]>\n /**\n * Awakeable-based completion wait — the durable alternative to\n * {@link attach} for long-running work on hosts with a push seam\n * (e.g. a runner that fires `task:exit` → resumer → `ctx.resolveAwakeable`).\n * `executeTwoPhase` orchestrates three phases with the same journal\n * discipline as `restateAwakeableTool`:\n *\n * 1. `register` — a short, journaled `ctx.run`: hand the awakeable\n * id to the host as the exit resumer for `token`. Fires exactly\n * once across replays (marker invariant included).\n * 2. park — `await awakeable.promise`, OUTSIDE any `ctx.run`. The\n * invocation suspends cleanly: no held worker, immune to\n * inactivity/abort timeouts. With `timeoutMs`, the park is a\n * durable race against `ctx.sleep` (replay-stable — no\n * `Date.now()` deadline that resets per attempt).\n * 3. `result` — a final journaled `ctx.run`: synthesize the tool\n * result from the resumer payload (`null` = timeout; kill the\n * job and shape the timeout result here).\n */\n wait?: RestateDurableWait<Token, Resumed>\n /**\n * Best-effort cleanup when the per-call abort signal fires before the\n * wait settles — `attach` or the awakeable park alike (run abort,\n * `agent.cancelTool`, sibling-cascade\n * cancel, `agent.destroy()` mid-run). Without it, the journaled token\n * identifies a remote job that keeps running with nobody attached —\n * a leak for hosts whose jobs outlive the session.\n *\n * Contract:\n * - Fires at most once per call, outside the journal (an aborting\n * invocation can't open new `ctx.run` entries reliably) — journal\n * your own cleanup on the host side if it must be durable.\n * - May run concurrently with a still-unwinding `attach`; make it\n * idempotent against \"job already gone\".\n * - NOT called on process death — that's not termination: the\n * journaled token re-attaches on replay instead. This seam is for\n * deliberate aborts, where no replay is coming.\n * - Errors are swallowed (surfaced under `ZIDANE_DEBUG`) — cleanup\n * failure must not mask the abort itself.\n */\n onAbort?: (token: Token, input: Record<string, unknown>, toolCtx: ToolContext) => Promise<void> | void\n}\n\n/**\n * Awakeable-based completion wait for {@link RestateDurableStart.wait}.\n *\n * Replay contract (mirrors `restateAwakeableTool`):\n * - The awakeable is minted BEFORE the journaled `register` entry, so on\n * replay both come back in the same order with the same id — a replayed\n * call re-parks on the SAME awakeable without re-registering.\n * - The journaled marker records the awakeable id it was registered for;\n * a mismatch on replay (journal drift) throws instead of parking on an\n * id nobody will ever resolve.\n */\nexport interface RestateDurableWait<Token = unknown, Resumed = unknown> {\n /**\n * Register `awakeableId` as the exit resumer for the work identified\n * by `token` — the host must call `ctx.resolveAwakeable(awakeableId,\n * payload)` when the work completes. Runs inside `ctx.run`; must be\n * short and idempotent-safe up to journal persistence.\n */\n register: (token: Token, awakeableId: string, input: Record<string, unknown>, toolCtx: ToolContext) => Promise<void> | void\n /**\n * Synthesize the tool result once the park settles. `resumed` is the\n * resumer's payload, or `null` when `timeoutMs` elapsed first — kill\n * the still-running job and shape the timeout result in that branch.\n * Runs inside the final journaled `ctx.run` (the result entry).\n */\n result: (token: Token, resumed: Resumed | null, input: Record<string, unknown>, toolCtx: ToolContext) => Promise<string | ToolResultContent[]> | string | ToolResultContent[]\n /**\n * Durable park deadline in milliseconds — becomes the\n * `awakeableWithTimeout` duration (a `ctx.sleep` raced against the\n * awakeable, replay-stable). A function receives the call's input so\n * the model's own `timeout` parameter can drive it. Unset /\n * non-positive = park indefinitely.\n */\n timeoutMs?: number | ((input: Record<string, unknown>, toolCtx: ToolContext) => number | undefined)\n /**\n * Durable race combinator for the timeout race — pass `RestatePromise`\n * from the SDK. See `awakeableWithTimeout`'s rationale; native\n * `Promise.race` is the fallback.\n */\n promises?: RestatePromiseRaceLike\n /**\n * Per-call fast path: when this returns `true` for the journaled\n * `token`, the awakeable park is SKIPPED entirely — no awakeable is\n * minted, no `-register` entry is journaled, and the invocation never\n * suspends. `result` is invoked directly with `resumed = null` inside\n * the final result entry.\n *\n * This is for `start` phases that sometimes have nothing to wait on\n * (e.g. a shell tool that only spawns a real background task above a\n * duration threshold and otherwise runs the command inline in\n * `result`). Parking such calls pays a full suspend → resolve →\n * re-invoke → replay round-trip for nothing.\n *\n * MUST be a pure function of the journaled `token` (+ input) so the\n * decision is identical across replays — a token-derived branch keeps\n * the journal entry shape deterministic. When omitted, every call\n * parks (the original behaviour).\n */\n inline?: (token: Token, input: Record<string, unknown>, toolCtx: ToolContext) => boolean\n}\n\n/** Journaled registration marker — see the marker invariant in {@link RestateDurableWait}. */\ninterface DurableWaitRegisterMarker {\n registered: true\n awakeableId: string\n}\n\nexport interface RestateToolOptions<Token = unknown, Resumed = unknown> {\n /**\n * `ctx.run` options forwarded on every wrapped tool call. Defaults to\n * `{ maxRetryAttempts: 1 }` — tool errors are typically deterministic\n * (validation failures, missing files) so blind retries waste budget.\n * Override per-tool for network-heavy custom tools that benefit from\n * SDK-level retries.\n */\n runOptions?: RestateRunOptions\n /**\n * Override the journal-entry name. Receives the canonical tool name, the\n * call's input, and the model's `callId` (when the runtime provides one).\n * Default: `tool-<name>-<seq>` where `<seq>` is a per-wrapper monotonic\n * counter. The counter is replay-stable as long as dispatch order is\n * deterministic; key on `callId` instead for a model-deterministic name\n * that's robust even under `maxConcurrentTools > 1`.\n */\n entryName?: (seq: number, name: string, input: Record<string, unknown>, callId?: string) => string\n /**\n * Hide and reject the built-in shell tool's background mode.\n *\n * Default: derived from {@link RestateToolOptions.detachedTasks} —\n * disabled unless the execution context declares `'durable'` detached\n * tasks. An explicit boolean always wins.\n */\n disableShellBackground?: boolean\n /**\n * `detachedTasks` capability of the execution context the agent will\n * run with (see `ContextCapabilities.detachedTasks` /\n * `resolveDetachedTasksCapability`). Drives the\n * `disableShellBackground` default: a `'durable'` context keeps its\n * background tasks across worker crashes, so the wrapper leaves the\n * shell tool's background mode intact.\n *\n * Default: `undefined`, treated as non-durable (background disabled).\n */\n detachedTasks?: DetachedTasksCapability\n /**\n * Two-phase start/attach journaling for crash-safe long tools — see\n * {@link RestateDurableStart}. Per-tool by nature; not accepted by\n * `wrapAgentTools` (a single start/attach pair can't fit a whole map).\n */\n durableStart?: RestateDurableStart<Token, Resumed>\n /**\n * Per-invocation replay tracker (see `createReplayTracker`). When set,\n * the wrapper marks it live from inside its journaled closures — i.e.\n * the first time a tool body (or a `durableStart.start` phase)\n * ACTUALLY executes rather than replaying from the journal. Share one\n * tracker across the provider and tool wrappers of the same handler\n * invocation.\n */\n replayTracker?: ReplayTracker\n /**\n * Keep an ordinary, recoverable tool throw (a failed shell command, a\n * transport error, an MCP `isError`) NON-fatal under Restate.\n *\n * Without this, the throw rides out of the journaled `ctx.run` action,\n * exhausts the retry budget, and surfaces as a Restate `TerminalError` —\n * which `restateBehavior`'s `shouldRethrowToolError` re-throws, aborting the\n * whole run. With it, the throw is captured INSIDE the journal as a sentinel\n * value and re-thrown as a plain (non-control) error OUTSIDE it, so the loop\n * produces a model-visible `tool_result { isError }` and continues —\n * identical to the non-Restate soft-error model, and the same mechanism\n * `restateMcpToolWrap` already applies to MCP tools. Real Restate control\n * errors and deliberate aborts are never softened.\n *\n * Applies to the single-phase journaling path (the default wrapping and the\n * MCP path). The two-phase {@link RestateToolOptions.durableStart} mode owns\n * its own start/wait error shape and is unaffected.\n *\n * Default: `true`.\n */\n softErrors?: boolean\n /**\n * Collapse malformed structured result blocks (`{ type: 'image' }` with no\n * payload, foreign block shapes) to a text placeholder before the result is\n * journaled, so a downstream provider wire serializer never has to project an\n * unprojectable block (which, under Restate, would throw inside the journaled\n * provider call and become fatal). Well-formed results pass through\n * untouched. Applies to the single-phase journaling path.\n *\n * Default: `true`.\n */\n coerceResultBlocks?: boolean\n}\n\nconst SHELL_BACKGROUND_DISABLED_MESSAGE = 'shell error: background mode is disabled for Restate-backed agents. Fall back to foreground (drop `run_in_background`).'\n\n/**\n * Once-per-session (per process) guard for the restate tool wrapper's read-state\n * hydration. Rebuilds the map from `session.turns` the first time any wrapped\n * tool runs LIVE in a process, so `read_file` re-reads dedup correctly across a\n * replay (a journaled read never re-runs its live `rememberRead`).\n *\n * Note: the authoritative `requireReadBeforeEdit` recovery lives in the loop's\n * read-before-edit pre-hydration gate (see `agent.ts`), which fires regardless\n * of how tools are wrapped. This pass is the dedup-side complement for\n * `restateTool`-wrapped consumers; it is NOT what the gate depends on.\n */\nconst HYDRATED_READ_STATE_SESSIONS = new WeakSet<Session>()\n\n/**\n * Wrap a single `ToolDef` so its `execute` runs inside `ctx.run`. The\n * tool's `spec` and `isConcurrencySafe` pass through unchanged.\n */\nexport function restateTool<Token = unknown, Resumed = unknown>(\n inner: ToolDef,\n ctx: RestateContextLike,\n options: RestateToolOptions<Token, Resumed> = {},\n): ToolDef {\n const runOpts: RestateRunOptions = options.runOptions ?? { maxRetryAttempts: 1 }\n const nameFor = options.entryName ?? ((seq: number, name: string) => `tool-${name}-${seq}`)\n const canonicalName = inner.spec.name\n const disableShellBackground = options.disableShellBackground ?? (options.detachedTasks !== 'durable')\n const shellBackgroundDisabled = disableShellBackground && canonicalName === 'shell'\n const durableStart = options.durableStart\n if (durableStart && !durableStart.attach && !durableStart.wait)\n throw new Error(`restateTool(${canonicalName}): durableStart needs an \\`attach\\` (in-journal wait) or a \\`wait\\` (awakeable park) phase`)\n let seq = 0\n const hydrateOnce = async (toolCtx: Parameters<ToolDef['execute']>[1]) => {\n // Short-circuit before touching `toolCtx.handle` — sessionless invocations\n // (direct tool calls, minimal test contexts) have no read-state to rebuild\n // and may not carry a handle at all.\n if (!toolCtx.session || HYDRATED_READ_STATE_SESSIONS.has(toolCtx.session))\n return\n HYDRATED_READ_STATE_SESSIONS.add(toolCtx.session)\n // Resolve wire aliases (e.g. `Read`/`Edit`) to canonical when matching\n // transcript tool-calls — parity with the agent's run-start hydration. The\n // built-in restate session store persists canonical names, so this is a\n // no-op there; it only matters for a custom store that journaled wire names.\n // Best-effort: the alias config was already validated at agent construction,\n // but never let a hydration helper throw out of the journaled closure.\n let aliasMaps: AliasMaps | undefined\n if (toolCtx.toolAliases) {\n try {\n aliasMaps = buildAliasMaps(toolCtx.toolAliases, Object.keys(toolCtx.tools))\n }\n catch {\n aliasMaps = undefined\n }\n }\n await hydrateReadStateFromSessionAsync(toolCtx.session, toolCtx.handle.cwd, {\n defaultLineNumbers: toolCtx.behavior?.readLineNumbers ?? true,\n ...(aliasMaps ? { aliasMaps } : {}),\n readFileForHash: async (path) => {\n try {\n return await toolCtx.execution.readFile(toolCtx.handle, path)\n }\n catch {\n return null\n }\n },\n })\n }\n const softErrors = options.softErrors ?? true\n const coerceBlocks = options.coerceResultBlocks ?? true\n\n // The journaled action. NOT async, and the raw `ctx.run` promise is returned\n // without native combinators so `durableExecute` consumers (the Restate\n // batch scheduler) keep the runtime's own promise shape (`.map`) intact.\n //\n // Soft errors are captured INSIDE the closure: a recoverable throw is\n // recorded as a sentinel *value*, never a failed action — that's what keeps\n // `ctx.run` from promoting it to a fatal `TerminalError`. The sentinel is\n // turned back into a throw OUTSIDE the journal (see `executeDurably` /\n // `durableExecuteImpl`). Control / abort throws are never softened.\n //\n // Durable tool state rides the SAME entry: whatever the body staged on\n // `toolCtx.state` is journaled as data next to the output (see\n // `attachToolState`), then re-seeded into the staging view outside the\n // journal so the loop's commit re-issues an identical write on replay.\n // `reportOutcome` rides it too: the body's report is journaled and\n // re-reported outside, so `tool:after.outcome` matches on replay. So do\n // `session.setMeta` writes (todos), re-applied outside so the session the\n // loop persists is identical on replay.\n const runJournaled = (input: Record<string, unknown>, toolCtx: Parameters<ToolDef['execute']>[1]) => {\n seq += 1\n return ctx.run(\n nameFor(seq, canonicalName, input, toolCtx.callId),\n async () => {\n // Closure executes only when live — replays return the journaled\n // result without entering here.\n options.replayTracker?.markLive()\n await hydrateOnce(toolCtx)\n const staged = stagedToolState(toolCtx.state)\n // A `ctx.run` retry re-enters this closure; drop ops the failed\n // attempt staged so the journaled delta is exactly what this\n // attempt produced (single-phase mode has no earlier phase whose\n // writes could be lost here).\n staged?.clear()\n if (shellBackgroundDisabled && input.run_in_background === true)\n return SHELL_BACKGROUND_DISABLED_MESSAGE\n const captured = captureToolBody(toolCtx)\n if (!softErrors) {\n const out = await captured.execute(() => inner.execute(input, captured.ctx))\n return attachToolState(coerceBlocks ? coerceToolResultContent(out) : out, staged, captured)\n }\n try {\n const out = await captured.execute(() => inner.execute(input, captured.ctx))\n return attachToolState(coerceBlocks ? coerceToolResultContent(out) : out, staged, captured)\n }\n catch (err) {\n if (isRestateControlOrAbort(err, toolCtx.signal as AbortSignal | undefined))\n throw err\n // A soft failure still journals the state the body staged and the\n // outcome it reported before it threw — they ride one entry with the\n // sentinel, so live and replay agree on all of them.\n return attachToolState(makeSoftToolError(err) as unknown as string, staged, captured)\n }\n },\n runOpts,\n )\n }\n\n // Plain `execute`: await the journaled value, re-seed staged tool state from\n // it, and re-throw a captured soft error outside the journal. When soft\n // errors are off AND the call carries no state view, the raw mappable\n // promise is the execute (unchanged legacy shape).\n const finishJournaled = async (\n journaled: Promise<JournaledToolValue>,\n staged: StagedToolState | undefined,\n toolCtx: ToolContext,\n ): Promise<string | ToolResultContent[]> => {\n let value: JournaledToolValue\n try {\n value = await journaled\n }\n catch (err) {\n // Nothing was journaled (control error, abort, exhausted retries), so\n // the mutations this attempt staged must not reach the store — a\n // replay re-runs the body and stages them again.\n staged?.clear()\n throw err\n }\n const output = applyToolState(value, staged, toolCtx)\n return softErrors ? rethrowSoftToolError(output) : output\n }\n\n const executeDurably: ToolDef['execute'] = (input, toolCtx) => {\n const staged = stagedToolState(toolCtx.state)\n // Nothing to unwrap (no envelope can be journaled): hand back the\n // runtime's own promise untouched, keeping the pre-envelope shape.\n if (!softErrors && !staged && !toolCtx.reportOutcome && !toolCtx.session)\n return runJournaled(input, toolCtx) as Promise<string | ToolResultContent[]>\n return finishJournaled(runJournaled(input, toolCtx), staged, toolCtx)\n }\n\n // `durableExecute`: compose the same unwrap INTO the runtime's mappable\n // promise so the batch scheduler still receives a `.map`-able value.\n // A softened throw becomes a rejected mapped promise, which the scheduler\n // routes to a `tool_result { isError }` (never fatal). Falls back to the raw\n // promise on a non-mappable ctx so the loop's durable guard can report it.\n const durableExecuteImpl: ToolDef['durableExecute'] = (input, toolCtx) => {\n const staged = stagedToolState(toolCtx.state)\n if (!softErrors && !staged && !toolCtx.reportOutcome && !toolCtx.session)\n return runJournaled(input, toolCtx) as Promise<string | ToolResultContent[]>\n return unwrapDurableToolValue(runJournaled(input, toolCtx), staged, softErrors, toolCtx)\n }\n\n // Two-phase mode: journal the start token BEFORE the body so a crash\n // mid-execution re-attaches on replay instead of re-running. The await\n // between the two entries makes this a native-async composition, so the\n // tool deliberately does NOT advertise `durableExecute` — the batch\n // scheduler runs it sequentially via plain `execute`, which is the\n // right shape for long re-attachable work anyway.\n //\n // Durable tool state here: staged ops accumulate ACROSS the phases and are\n // journaled by the final entry only (`wait.result` / `attach`), which is\n // the entry whose value the loop commits against. A write staged in the\n // `start` phase therefore survives a replay that reaches the final entry\n // live, but is lost if the process dies between the two — the start entry\n // replays from the journal without re-running the body that staged it.\n // Write state in the final phase when it has to be crash-durable.\n const executeTwoPhaseInner = async (input: Record<string, unknown>, toolCtx: Parameters<ToolDef['execute']>[1]) => {\n const start = durableStart!\n const staged = stagedToolState(toolCtx.state)\n seq += 1\n const entry = nameFor(seq, canonicalName, input, toolCtx.callId)\n // Final-phase entry: journal the body's output together with whatever\n // the call staged on `toolCtx.state` and the outcome it reported, then\n // re-seed both outside the journal so replay sees the identical result.\n const runFinal = async (\n body: (phaseCtx: typeof toolCtx) => Promise<string | ToolResultContent[]> | string | ToolResultContent[],\n ): Promise<string | ToolResultContent[]> => applyToolState(\n await ctx.run(\n entry,\n async () => {\n options.replayTracker?.markLive()\n const captured = captureToolBody(toolCtx)\n const out = await captured.execute(async () => body(captured.ctx))\n return attachToolState(out, staged, captured)\n },\n runOpts,\n ),\n staged,\n toolCtx,\n )\n const token = await ctx.run(\n `${entry}-start`,\n async () => {\n options.replayTracker?.markLive()\n await hydrateOnce(toolCtx)\n return start.start(input, toolCtx)\n },\n runOpts,\n )\n\n // Abort seam — see RestateDurableStart.onAbort. At-most-once via the\n // `fired` latch; armed only while the wait is in flight.\n const onAbort = start.onAbort\n const signal = toolCtx.signal as AbortSignal | undefined\n let fired = false\n const fireAbortCleanup = (): void => {\n if (fired || !onAbort)\n return\n fired = true\n Promise.resolve(onAbort(token, input, toolCtx)).catch((err: unknown) => {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/restate] durableStart onAbort threw: ${err instanceof Error ? err.message : String(err)}\\n`)\n })\n }\n\n const wait = start.wait\n if (wait) {\n // Per-call fast path: nothing to wait on for this token (decided\n // purely from the journaled token, so replay-stable). Skip minting\n // the awakeable, the `-register` entry, and the suspend/resume\n // round-trip entirely — run the result inline. A short command that\n // executes in the result entry shouldn't pay a park it never uses.\n if (wait.inline?.(token, input, toolCtx)) {\n if (!onAbort || !signal)\n return await runFinal(phaseCtx => wait.result(token, null, input, phaseCtx))\n if (signal.aborted)\n fireAbortCleanup()\n else\n signal.addEventListener('abort', fireAbortCleanup, { once: true })\n try {\n return await runFinal(phaseCtx => wait.result(token, null, input, phaseCtx))\n }\n finally {\n signal.removeEventListener('abort', fireAbortCleanup)\n }\n }\n // Awakeable path — register / park / result. The park lives\n // OUTSIDE any ctx.run, so the invocation suspends cleanly instead\n // of busy-holding an attempt until the inactivity timeout fires.\n //\n // Pre-aborted: nobody will consume the result — clean up the\n // journaled start and bail without registering a resumer.\n if (signal?.aborted) {\n fireAbortCleanup()\n throw new Error(`${canonicalName}: aborted before durable wait registration`)\n }\n signal?.addEventListener('abort', fireAbortCleanup, { once: true })\n try {\n const timeoutMs = typeof wait.timeoutMs === 'function' ? wait.timeoutMs(input, toolCtx) : wait.timeoutMs\n // Mint BEFORE the journaled registration (same ordering contract\n // as restateAwakeableTool) — replay returns the same id.\n const awakeable = awakeableWithTimeout<Resumed>(ctx, {\n ...(timeoutMs !== undefined ? { timeoutMs } : {}),\n ...(wait.promises ? { promises: wait.promises } : {}),\n })\n const marker = await ctx.run<DurableWaitRegisterMarker>(\n `${entry}-register`,\n async () => {\n options.replayTracker?.markLive()\n await wait.register(token, awakeable.id, input, toolCtx)\n return { registered: true, awakeableId: awakeable.id }\n },\n runOpts,\n )\n if (marker.awakeableId !== awakeable.id) {\n throw new Error(\n `restateTool(${canonicalName}): journal drift — registration marker carries awakeable \"${marker.awakeableId}\" but this replay minted \"${awakeable.id}\". Refusing to park on an unreachable awakeable.`,\n )\n }\n const resumed = await parkWithSignal(awakeable.promise, signal, canonicalName)\n return await runFinal(phaseCtx => wait.result(token, resumed, input, phaseCtx))\n }\n finally {\n signal?.removeEventListener('abort', fireAbortCleanup)\n }\n }\n\n const attach = () => runFinal(phaseCtx => start.attach!(token, input, phaseCtx))\n\n if (!onAbort || !signal)\n return attach()\n\n // Pre-aborted: the journaled start already launched the job — clean\n // it up, then still run attach so the call surfaces the host's own\n // cancellation shape (it should fail fast on an aborted signal).\n if (signal.aborted) {\n fireAbortCleanup()\n return attach()\n }\n signal.addEventListener('abort', fireAbortCleanup, { once: true })\n try {\n return await attach()\n }\n finally {\n signal.removeEventListener('abort', fireAbortCleanup)\n }\n }\n\n const executeTwoPhase: ToolDef['execute'] = async (input, toolCtx) => {\n const staged = stagedToolState(toolCtx.state)\n try {\n return await executeTwoPhaseInner(input, toolCtx)\n }\n catch (err) {\n // Nothing journaled this delta (abort before registration, journal\n // drift, a throwing phase) — drop it so the loop's commit can't\n // persist a write no journal entry records.\n staged?.clear()\n throw err\n }\n }\n\n if (durableStart) {\n // Strip any pre-existing `durableExecute` — see the executeTwoPhase\n // comment; advertising one here would hand the batch scheduler a\n // native promise it can't `.map`.\n const { durableExecute: _dropped, ...rest } = inner\n return {\n ...rest,\n spec: shellBackgroundDisabled ? withoutShellBackgroundInput(inner.spec) : inner.spec,\n execute: executeTwoPhase,\n }\n }\n\n return {\n ...inner,\n spec: shellBackgroundDisabled ? withoutShellBackgroundInput(inner.spec) : inner.spec,\n execute: executeDurably,\n durableExecute: durableExecuteImpl,\n }\n}\n\n/**\n * Journaled value of a wrapped tool: the output, or an envelope carrying the\n * output plus the tool-state ops the body staged and the outcome it reported\n * via `ToolContext.reportOutcome`. The envelope only appears when a tool\n * actually wrote state or reported an outcome, so journals produced by calls\n * that do neither are byte-identical to pre-envelope ones — in-flight\n * invocations keep replaying across a deploy that enables this.\n */\ntype JournaledToolValue = string | ToolResultContent[] | ToolStateEnvelope\n\ninterface ToolStateEnvelope {\n /**\n * Format marker, and the ONLY thing detection keys on (together with\n * `ops` being an array). Deliberately not the op list itself: journal\n * values round-trip through JSON, which drops undefined-valued and\n * unserializable properties, so a schema check on the payload could fail\n * on replay for a value that passed it live — and a false negative here\n * hands the raw envelope object to the model as the tool output.\n */\n __zidaneToolState: 1\n ops: ToolStateOp[]\n output: string | ToolResultContent[]\n /**\n * Reported by the body, which only runs live. `tool:after.outcome` feeds\n * replay-visible decisions (dedup treats `failed` calls as non-cacheable),\n * so it must come back out of the journal rather than from the body.\n */\n outcome?: ToolOutcome\n /**\n * `session.setMeta` writes the body made, in order (todos live here). The\n * session is persisted outside the journal, so a write that only happens\n * live makes the replayed session differ and its next state write 570s.\n */\n meta?: SessionMetaWrite[]\n}\n\nconst TOOL_OUTCOMES: ReadonlySet<string> = new Set<ToolOutcome>(['created', 'updated', 'edited', 'noop', 'failed'])\n\nfunction isToolOutcome(value: unknown): value is ToolOutcome {\n return typeof value === 'string' && TOOL_OUTCOMES.has(value)\n}\n\ninterface CapturedToolBody {\n ctx: ToolContext\n /** Run the body so its `session.setMeta` writes are recorded (they still apply live). */\n execute: <T>(fn: () => Promise<T>) => Promise<T>\n outcome: () => ToolOutcome | undefined\n meta: () => SessionMetaWrite[]\n}\n\n/**\n * Give the journaled body a `reportOutcome` that records instead of\n * forwarding, so the outcome reaches the loop only through the journal, and\n * record the body's `session.setMeta` writes so the journal carries them for\n * replay. The session object itself is passed through untouched: per-session\n * state (read-state, dedup) is keyed on its identity.\n */\nfunction captureToolBody(toolCtx: ToolContext): CapturedToolBody {\n let reported: ToolOutcome | undefined\n const writes: SessionMetaWrite[] = []\n return {\n ctx: toolCtx.reportOutcome ? { ...toolCtx, reportOutcome: (outcome) => { reported = outcome } } : toolCtx,\n execute: fn => recordSessionMetaWrites(toolCtx.session as Session | undefined, writes, fn),\n outcome: () => reported,\n meta: () => writes,\n }\n}\n\nfunction isToolStateEnvelope(value: unknown): value is ToolStateEnvelope {\n if (typeof value !== 'object' || value === null || Array.isArray(value))\n return false\n const candidate = value as Partial<ToolStateEnvelope>\n return candidate.__zidaneToolState === 1 && Array.isArray(candidate.ops) && 'output' in candidate\n}\n\n/**\n * Wrap the output with the staged ops and reported outcome so they cross the\n * journal as DATA. Returns the output untouched when there is neither — that\n * path must not change the journaled shape.\n */\nfunction attachToolState(\n output: string | ToolResultContent[],\n staged: StagedToolState | undefined,\n captured?: Pick<CapturedToolBody, 'outcome' | 'meta'>,\n): JournaledToolValue {\n const ops = staged?.pending() ?? []\n const outcome = captured?.outcome()\n const meta = captured?.meta() ?? []\n if (ops.length === 0 && outcome === undefined && meta.length === 0)\n return output\n return {\n __zidaneToolState: 1,\n ops,\n output,\n ...(outcome !== undefined ? { outcome } : {}),\n ...(meta.length > 0 ? { meta } : {}),\n }\n}\n\n/**\n * Inverse of {@link attachToolState}, run OUTSIDE the journal: re-seed the\n * staging view from the journaled ops so the loop's commit writes the same\n * thing on a live attempt and on every replay, hand the journaled outcome to\n * `reportOutcome`, and re-apply the journaled session metadata writes (a no-op\n * re-set live, the only write on replay). A value with no envelope clears the\n * view — whatever it holds was staged by an attempt no journal entry records,\n * and committing that would be a write replay can't reproduce.\n */\nfunction applyToolState(\n value: JournaledToolValue,\n staged: StagedToolState | undefined,\n toolCtx?: Pick<ToolContext, 'reportOutcome' | 'session'>,\n): string | ToolResultContent[] {\n if (isToolStateEnvelope(value)) {\n if (isToolOutcome(value.outcome))\n toolCtx?.reportOutcome?.(value.outcome)\n if (Array.isArray(value.meta)) {\n for (const write of value.meta) {\n if (typeof write === 'object' && write !== null && typeof write.key === 'string')\n toolCtx?.session?.setMeta(write.key, write.value)\n }\n }\n // Ops are validated separately from detection: a delta mangled in\n // transit is dropped (never committed half-formed) while the output —\n // the part the model consumes — still comes through intact.\n if (isToolStateOps(value.ops))\n staged?.restore(value.ops)\n else\n staged?.clear()\n return value.output\n }\n staged?.clear()\n return value\n}\n\n/**\n * Compose the state unwrap + soft-error unwrap into the runtime's mappable\n * durable promise. A journaled sentinel becomes a thrown (rejected) value so\n * the Restate batch scheduler classifies it as a tool failure →\n * `tool_result { isError }`; a real action failure (control error) is rethrown\n * verbatim. Non-mappable promises (a ctx without the SDK's `RestatePromise`)\n * pass through so the loop's durable guard surfaces the \"not a mappable\n * durable promise\" error instead.\n */\nfunction unwrapDurableToolValue(\n promise: Promise<JournaledToolValue>,\n staged: StagedToolState | undefined,\n softErrors: boolean,\n toolCtx?: Pick<ToolContext, 'reportOutcome' | 'session'>,\n): Promise<string | ToolResultContent[]> {\n const mappable = promise as Partial<RestatePromiseLike<JournaledToolValue>>\n if (typeof mappable.map !== 'function')\n return promise as Promise<string | ToolResultContent[]>\n return mappable.map((value, failure) => {\n if (failure !== undefined) {\n staged?.clear()\n throw failure instanceof Error ? failure : new Error(String(failure))\n }\n const output = applyToolState(value as JournaledToolValue, staged, toolCtx)\n return softErrors ? rethrowSoftToolError(output) : output\n })\n}\n\n/**\n * Park on `promise`, but stop waiting when the per-call abort signal\n * fires (run abort, `cancelTool`, sibling-cascade cancel) — a deliberate\n * abort means nobody will consume the result, and like `onAbort` it\n * implies no replay is coming, so the native (non-journaled) race is\n * replay-safe. The underlying awakeable stays registered; a late\n * resolution lands on a completed invocation and is dropped by the\n * runtime.\n */\nfunction parkWithSignal<T>(promise: Promise<T>, signal: AbortSignal | undefined, name: string): Promise<T> {\n if (!signal)\n return promise\n if (signal.aborted)\n return Promise.reject(new Error(`${name}: aborted while parked on durable wait`))\n return new Promise<T>((resolve, reject) => {\n const onAbortEvt = (): void => reject(new Error(`${name}: aborted while parked on durable wait`))\n signal.addEventListener('abort', onAbortEvt, { once: true })\n promise.then(\n (value) => {\n signal.removeEventListener('abort', onAbortEvt)\n resolve(value)\n },\n (err: unknown) => {\n signal.removeEventListener('abort', onAbortEvt)\n reject(err instanceof Error ? err : new Error(String(err)))\n },\n )\n })\n}\n\nfunction withoutShellBackgroundInput(spec: ToolDef['spec']): ToolDef['spec'] {\n const inputSchema = spec.inputSchema\n const properties = isRecord(inputSchema.properties) ? inputSchema.properties : undefined\n if (!properties || !Object.hasOwn(properties, 'run_in_background'))\n return spec\n\n const { run_in_background: _runInBackground, ...nextProperties } = properties\n const required = Array.isArray(inputSchema.required)\n ? inputSchema.required.filter(name => name !== 'run_in_background')\n : inputSchema.required\n return {\n ...spec,\n description: stripShellBackgroundDescription(spec.description),\n inputSchema: {\n ...inputSchema,\n properties: nextProperties,\n ...(required !== inputSchema.required ? { required } : {}),\n },\n }\n}\n\nfunction stripShellBackgroundDescription(description: string): string {\n return description\n .split('\\n')\n .filter(line =>\n !line.includes('run_in_background')\n && !line.includes('<task-notification>')\n && !line.includes('background task'),\n )\n .join('\\n')\n .replace(/\\n{3,}/g, '\\n\\n')\n .trim()\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\n/**\n * Wrap an entire tool map at once — convenience for the common case of\n * \"journal every tool the agent has\". Pass-through for tools whose\n * names are listed in `opts.exclude` (e.g. fully-deterministic local\n * helpers where journaling is pure overhead).\n *\n * The returned map is a fresh object; the input is untouched.\n */\nexport function wrapAgentTools(\n tools: Record<string, ToolDef>,\n ctx: RestateContextLike,\n opts: Omit<RestateToolOptions, 'durableStart'> & { exclude?: readonly string[] } = {},\n): Record<string, ToolDef> {\n const excludeSet = new Set(opts.exclude ?? [])\n // `detachedTasks: 'durable'` implies the host's `waitBackground` parks\n // on an awakeable (that's the durable wait pattern) — and a Restate\n // suspension point must NOT nest inside a journaled `ctx.run` closure.\n // Auto-exclude the built-in `wait_task` from wrapping so its park runs\n // outside the journal; the wait result is replay-safe anyway (a replayed\n // wait re-attaches to an already-terminated task and resolves from the\n // registry). Hosts with a journal-safe wait (e.g. a bridge RPC poll)\n // can re-wrap explicitly via `restateTool(waitTask, ctx, …)`.\n const skipWaitTask = opts.detachedTasks === 'durable'\n const wrapped: Record<string, ToolDef> = {}\n for (const [name, def] of Object.entries(tools)) {\n // A tool that runs a nested agent loop (`spawn`, or a host orchestrator\n // tool) is NEVER wrapped: the child drives the same journaled provider and\n // the same wrapped tools, so its `ctx.run` entries would nest inside this\n // tool's own journaled closure. Left unwrapped, the child's steps journal\n // DIRECTLY into the parent's journal — each provider call and tool call\n // individually replayable, which is what makes a crash mid-subagent\n // recover for free. Keyed on the declarative `ToolDef.runsNestedAgent`\n // marker rather than the tool name, so a host tool that merely happens to\n // be named `spawn` still gets wrapped.\n //\n // Deliberate escape hatch: wrapping a spawn tool explicitly via\n // `restateTool(spawnTool, ctx, …)` is legal IF that child is fully\n // non-durable (raw provider, unwrapped tools) — then the whole child\n // collapses into ONE journal entry. See `docs/RESTATE.md` § Subagents.\n const passThrough = excludeSet.has(name)\n || def.runsNestedAgent === true\n || (skipWaitTask && def.spec.name === 'wait_task')\n wrapped[name] = passThrough ? def : restateTool(def, ctx, opts)\n }\n return wrapped\n}\n","/**\n * Restate-backed MCP tool journaling.\n *\n * Native tools have a clean durability seam: wrap them with\n * `wrapAgentTools(tools, ctx)` before `createAgent`. MCP tools don't — they are\n * discovered from `mcpServers` and registered by the agent internally, AFTER\n * your wrapping opportunity. So under Restate their raw `callTool` never rides\n * `ctx.run`, and every journal replay re-runs the real MCP call (a\n * side-effecting tool fires once per replay).\n *\n * {@link restateMcpToolWrap} closes that gap. It's the value for the core\n * `AgentOptions.mcpToolWrap` hook — the agent keeps owning discovery,\n * `mcp_<server>_<tool>` namespacing, per-server `instructions`, hooks, and\n * OAuth, and applies the wrap to each discovered tool. You journal MCP results\n * the way `wrapAgentTools` journals native ones:\n *\n * ```ts\n * createAgent({\n * provider: restateProvider(inner, ctx),\n * tools: wrapAgentTools(nativeTools, ctx),\n * mcpServers,\n * mcpToolWrap: restateMcpToolWrap(ctx),\n * })\n * ```\n *\n * The hook composes with any `mcpConnector`, so a custom transport / auth\n * connector and journaling stay orthogonal — no separate connector helper\n * needed:\n *\n * ```ts\n * createAgent({\n * mcpServers,\n * mcpConnector: (configs, hooks) => connectMcpServers(configs, undefined, hooks, { buildAuthProvider }),\n * mcpToolWrap: restateMcpToolWrap(ctx),\n * })\n * ```\n *\n * ## Error semantics (preserved)\n *\n * MCP tools signal failure by THROWING (`buildMcpToolDef` throws on transport\n * errors, timeouts, and `CallToolResult.isError`). Naively wrapping that in\n * `restateTool` would let the throw exhaust `ctx.run`'s retries and surface as\n * a Restate `TerminalError`, which `restateBehavior`'s `shouldRethrowToolError`\n * re-throws — turning a recoverable MCP error into a fatal run. To keep the\n * non-Restate behaviour (MCP error → model-visible `tool_result { isError }`,\n * run continues) the wrapper journals with `restateTool`'s `softErrors`: the\n * failure is captured INSIDE the journaled closure as a sentinel value and\n * re-thrown as a plain (non-control) error OUTSIDE it. Replay reproduces the\n * same error from the journal without re-running the call; real Restate control\n * / abort errors are passed through untouched. (Native tools wrapped with\n * `wrapAgentTools` get the identical treatment — this is no longer MCP-specific\n * plumbing, just the shared default.)\n *\n * ## Journaling policy\n *\n * Default is plain result-journaling — correct for the short request/response\n * shape of most MCP calls. A genuinely long-running MCP tool (a remote build,\n * a migration) can opt into two-phase `durableStart` per-tool via\n * {@link RestateMcpToolWrapOptions.override}; `exclude` skips journaling for\n * deterministic reads.\n */\n\nimport type { McpToolMeta, McpToolWrap } from '../agent'\nimport type { ToolDef } from '../tools/types'\nimport type { ReplayTracker } from './replay'\nimport type { RestateToolOptions } from './tool'\nimport type { RestateContextLike, RestateRunOptions } from './types'\nimport { restateTool } from './tool'\n\nexport interface RestateMcpToolWrapOptions {\n /**\n * Shared per-invocation replay tracker (see `createReplayTracker`) —\n * threaded into every wrapped MCP tool so the first live `callTool` marks\n * the tracker live, exactly like `restateProvider` / `wrapAgentTools`. Use\n * one tracker per handler invocation across provider + native + MCP tools.\n */\n replayTracker?: ReplayTracker\n /**\n * `ctx.run` options forwarded to every wrapped MCP tool (default\n * `{ maxRetryAttempts: 1 }`). Note: recoverable MCP failures are\n * soft-captured as the journal value rather than thrown, so this retry\n * budget governs only Restate control-flow retries of the journaled action,\n * not re-dialing a failed MCP call — the model decides whether to retry.\n */\n runOptions?: RestateRunOptions\n /**\n * Override the journal-entry name per MCP tool call. Default:\n * `tool-<name>-<callId>` (model-deterministic, robust under concurrency)\n * falling back to `tool-<name>-<seq>` when the runtime provides no `callId`.\n */\n entryName?: (seq: number, name: string, input: Record<string, unknown>, callId?: string) => string\n /**\n * Namespaced MCP tool names (`mcp_<server>_<tool>`) to leave un-journaled —\n * they pass through exactly as discovered. For deterministic,\n * side-effect-free reads where journaling is pure overhead. Wins over\n * {@link override}.\n */\n exclude?: readonly string[]\n /**\n * Per-tool wrapping override. Receives the discovered tool + its\n * {@link McpToolMeta}; return a `ToolDef` to use verbatim (e.g.\n * `restateTool(tool, ctx, { durableStart })` for a long-running tool), or\n * `undefined` to fall through to the default soft-error result-journaling.\n * Lets a deployment opt specific tools into a different policy without\n * changing the blanket one.\n */\n override?: (tool: ToolDef, meta: McpToolMeta) => ToolDef | undefined\n}\n\n/**\n * Journal one discovered MCP tool via `restateTool` with `softErrors` on (a\n * recoverable MCP throw becomes a journaled `tool_result { isError }`, not a\n * fatal run — see the module's \"Error semantics\"). `durableExecute` is dropped:\n * MCP tools are concurrency barriers, so the batch scheduler runs them via the\n * (still journaled) `execute`, and dropping the mappable promise keeps the\n * scheduler from treating an MCP tool as a parallel-fleet member.\n */\nfunction journalMcpTool(tool: ToolDef, ctx: RestateContextLike, toolOptions: RestateToolOptions): ToolDef {\n const journaled = restateTool(tool, ctx, { ...toolOptions, softErrors: true, coerceResultBlocks: true })\n const { durableExecute: _dropped, ...rest } = journaled\n return rest\n}\n\nfunction toToolOptions(options: RestateMcpToolWrapOptions): RestateToolOptions {\n const entryName = options.entryName\n ?? ((seq: number, name: string, _input: Record<string, unknown>, callId?: string) =>\n callId ? `tool-${name}-${callId}` : `tool-${name}-${seq}`)\n return {\n entryName,\n ...(options.replayTracker !== undefined ? { replayTracker: options.replayTracker } : {}),\n ...(options.runOptions !== undefined ? { runOptions: options.runOptions } : {}),\n }\n}\n\n/**\n * Build an {@link McpToolWrap} for the `AgentOptions.mcpToolWrap` hook —\n * journals every discovered MCP tool's result (soft-error-preserving). The\n * MCP analogue of `wrapAgentTools`, and the single supported way to make\n * discovered MCP tools durable under Restate.\n */\nexport function restateMcpToolWrap(\n ctx: RestateContextLike,\n options: RestateMcpToolWrapOptions = {},\n): McpToolWrap {\n const excludeSet = new Set(options.exclude ?? [])\n const toolOptions = toToolOptions(options)\n return (tool, meta) => {\n if (excludeSet.has(tool.spec.name))\n return tool\n return options.override?.(tool, meta) ?? journalMcpTool(tool, ctx, toolOptions)\n }\n}\n","import type { ToolResult } from '../providers'\nimport type { ToolBatchExecutionContext, ToolBatchExecutor } from '../types'\n\nexport interface RestatePromiseAllLike<TPromise extends Promise<unknown> = RestatePromiseLike<unknown>> {\n all: (values: readonly TPromise[]) => Promise<readonly unknown[]>\n}\n\nexport type RestatePromiseLike<T> = Promise<T> & {\n map: <U>(mapper: (value?: T, failure?: unknown) => U) => Promise<U>\n}\n\nexport interface RestateToolBatchExecutorOptions<TPromise extends Promise<unknown> = RestatePromiseLike<unknown>> {\n /**\n * Wait for a safe fleet through Restate's durable combinator. Pass\n * `RestatePromise` from `@restatedev/restate-sdk` in real deployments.\n */\n promises: RestatePromiseAllLike<TPromise>\n}\n\n/**\n * Tool batch scheduler for Restate-backed agents.\n *\n * It preserves unsafe-tool barriers and emits results in model submission\n * order. Safe fleets are started in submission order, capped by\n * `maxConcurrentTools`, and joined via the supplied durable `all()`.\n */\nexport function restateToolBatchExecutor<TPromise extends Promise<unknown> = RestatePromiseLike<unknown>>(\n options: RestateToolBatchExecutorOptions<TPromise>,\n): ToolBatchExecutor {\n return async (ctx: ToolBatchExecutionContext): Promise<ToolResult[]> => {\n const results: ToolResult[] = []\n const { toolCalls } = ctx\n\n const fillRemaining = (from: number, factory: (index: number) => ToolResult): ToolResult[] => {\n for (let i = from; i < toolCalls.length; i++)\n results[i] = factory(i)\n return results\n }\n\n for (let i = 0; i < toolCalls.length;) {\n if (ctx.signal.aborted)\n return fillRemaining(i, ctx.interruptedResult)\n if (ctx.steeringQueue.length > 0)\n return fillRemaining(i, ctx.skippedResult)\n\n if (!ctx.isConcurrencySafe(i)) {\n results[i] = await ctx.execute(i)\n i += 1\n continue\n }\n\n const start = i\n const fleet: number[] = []\n while (\n i < toolCalls.length\n && ctx.isConcurrencySafe(i)\n && fleet.length < ctx.maxConcurrentTools\n ) {\n fleet.push(i)\n i += 1\n }\n\n const fleetResults = fleet.every(index => ctx.canExecuteDurably(index))\n ? await ctx.executeDurable(\n fleet,\n async <T>(values: readonly Promise<T>[]): Promise<readonly T[]> => {\n const results = await options.promises.all(values as readonly TPromise[])\n return results as readonly T[]\n },\n )\n : await executeSequential(ctx, fleet)\n for (let offset = 0; offset < fleetResults.length; offset++)\n results[start + offset] = fleetResults[offset]\n }\n\n return results\n }\n}\n\nasync function executeSequential(\n ctx: ToolBatchExecutionContext,\n indices: readonly number[],\n): Promise<ToolResult[]> {\n const results: ToolResult[] = []\n for (const index of indices) {\n if (ctx.signal.aborted) {\n results.push(ctx.interruptedResult(index))\n continue\n }\n if (ctx.steeringQueue.length > 0) {\n results.push(ctx.skippedResult(index))\n continue\n }\n results.push(await ctx.execute(index))\n }\n return results\n}\n","/**\n * Restate-backed Provider wrapper.\n *\n * Wraps `Provider.stream` so every assistant turn (the LLM call as a\n * whole) is journaled. The model is invoked once per turn — the live\n * stream still fires `onText` / `onThinking` callbacks for UX during the\n * original execution. On replay, `ctx.run` returns the journaled\n * `TurnResult` immediately and the inner provider is NEVER re-invoked →\n * no duplicate billed tokens, no duplicate stream chunks.\n *\n * Replay caveat: stream callbacks don't re-fire on replay. Consumers\n * that paint live UI from `stream:text` should reconstruct transcripts\n * from `session.turns` via `eventsFromTurns` (zidane/chat) instead of\n * relying on hook re-emission. The chat layer already does this.\n *\n * Journal-entry naming: a monotonic per-wrapper counter (`llm-call-1`,\n * `llm-call-2`, …). One wrapper instance per Restate handler invocation\n * resets the counter; Restate's journal is invocation-scoped so names\n * don't need to be globally unique. The counter ticks the same way on\n * replay because the wrapper is constructed fresh each attempt.\n */\n\nimport type { Provider, StreamCallbacks, StreamOptions, TurnResult } from '../providers'\nimport type { ReplayTracker } from './replay'\nimport type { RestateContextLike, RestateRunOptions } from './types'\n\nexport interface RestateProviderOptions {\n /**\n * `ctx.run` options forwarded on every wrapped stream call.\n *\n * Default depends on {@link streamCallbacks}:\n *\n * - `'suppress'` → `{ maxRetryAttempts: 3 }` — provider transients\n * (rate limits, 5xx, connection resets) get retried inside the\n * journal entry; nothing streams to the host, so a retry is\n * invisible.\n * - `'live'` (the default) → `{ maxRetryAttempts: 1 }`. A live stream\n * that fails AFTER emitting deltas would be re-run inside the same\n * journal entry, re-firing `onText` into the loop's accumulating\n * text buffer and producing duplicated partial1+full2 output. The\n * loop's own retry (which only re-issues on a clean slate) is the\n * correct retry layer in live mode.\n *\n * Once the cap is reached the failure becomes terminal and surfaces\n * through the loop's normal `AgentProviderError` path. Set this\n * explicitly to override either default — but with live callbacks,\n * `maxRetryAttempts > 1` re-introduces the duplicate-delta hazard.\n */\n runOptions?: RestateRunOptions\n /**\n * Override the journal-entry name. Receives the 1-indexed sequence\n * number for this wrapper instance and the `StreamOptions` of the\n * call. Default: `llm-call-<n>`. Override to inject extra structure\n * (e.g. `${agentName}/llm-call-${n}`) when multiple agents share a\n * service.\n */\n entryName?: (seq: number, opts: StreamOptions) => string\n /**\n * Whether live stream callbacks should fire during the original execution.\n * Use `'suppress'` for strict durable mode: the model call still returns a\n * full TurnResult, and UIs reconstruct from persisted session turns.\n *\n * Default: `'live'`.\n */\n streamCallbacks?: 'live' | 'suppress'\n /**\n * Per-invocation replay tracker (see `createReplayTracker`). When set,\n * the wrapper marks it live from inside the journaled closure — i.e.\n * the first time the inner provider is ACTUALLY invoked rather than\n * replayed from the journal. Share one tracker across the provider\n * and tool wrappers of the same handler invocation.\n */\n replayTracker?: ReplayTracker\n}\n\n/**\n * Wrap a Zidane `Provider` so its `stream()` method journals each turn's\n * response inside `ctx.run`. All other Provider methods (`formatTools`,\n * `userMessage`, `toolResultsMessage`, `classifyError`, …) pass through\n * unchanged — they're pure functions over already-deterministic inputs.\n */\nexport function restateProvider(\n inner: Provider,\n ctx: RestateContextLike,\n options: RestateProviderOptions = {},\n): Provider {\n // Live callbacks must not retry inside the journal entry — a stream that\n // fails after emitting deltas would re-fire `onText` on the retry and\n // duplicate text in the loop's accumulator. See the `runOptions` doc.\n const runOpts: RestateRunOptions = options.runOptions\n ?? (options.streamCallbacks === 'suppress' ? { maxRetryAttempts: 3 } : { maxRetryAttempts: 1 })\n const nameFor = options.entryName ?? ((seq: number) => `llm-call-${seq}`)\n let seq = 0\n\n return {\n ...inner,\n stream(streamOpts: StreamOptions, callbacks: StreamCallbacks): Promise<TurnResult> {\n seq += 1\n const durableCallbacks = options.streamCallbacks === 'suppress'\n ? suppressStreamingCallbacks(callbacks)\n : callbacks\n return ctx.run<TurnResult>(\n nameFor(seq, streamOpts),\n () => {\n // Reached only when the journal cursor is past this entry —\n // a replayed call returns the journaled TurnResult without\n // executing this closure.\n options.replayTracker?.markLive()\n return inner.stream(streamOpts, durableCallbacks)\n },\n runOpts,\n )\n },\n }\n}\n\nfunction suppressStreamingCallbacks(callbacks: StreamCallbacks): StreamCallbacks {\n return {\n ...callbacks,\n onText: () => {},\n onThinking: undefined,\n onServerToolUse: undefined,\n onServerToolResult: undefined,\n onToolCallDelta: undefined,\n }\n}\n","/**\n * Replay-state tracking + replay-aware abort for Restate-backed agents.\n *\n * ## The problem\n *\n * `agent.abort()` during a journal replay is undefined behavior: the\n * loop throws `AgentAbortedError` at whatever point the replay cursor\n * happens to be, the host's catch arm typically journals something\n * (`report-fail`, a status write) mid-journal, and the invocation dies\n * with `[570 Journal mismatch]` — permanently, because every retry\n * replays into the same mismatch. Hosts have been inferring liveness\n * from side channels (e.g. counting live provider stream calls), which\n * works only because `restateProvider` replays `llm-call-N` without\n * touching the live provider — incidental coupling, not API.\n *\n * ## The seam\n *\n * The wrappers already know the answer: on replay, `ctx.run` returns\n * the journaled value WITHOUT invoking the wrapped closure; the first\n * time a closure actually executes, the journal cursor is past the\n * replayed prefix and the invocation is live. {@link createReplayTracker}\n * packages that signal:\n *\n * - `restateProvider(inner, ctx, { replayTracker })` and\n * `restateTool(tool, ctx, { replayTracker })` mark the tracker live\n * from inside their journaled closures.\n * - `tracker.isReplaying()` is the public liveness probe.\n * - `tracker.onLive(cb)` fires once at the replay→live transition\n * (immediately when already live).\n * - {@link replayAwareAbort} wraps `agent.abort` so external aborts\n * queue during replay and apply at the first live boundary — the\n * earliest point where the abort's side effects (loop throw, host\n * catch-arm journaling) append to the journal instead of forking it.\n *\n * ## Wiring\n *\n * ```ts\n * const tracker = createReplayTracker({ hooks: agent.hooks })\n * const provider = restateProvider(inner, ctx, { replayTracker: tracker })\n * const tools = wrapAgentTools(agentTools, ctx, { replayTracker: tracker })\n * const abort = replayAwareAbort(tracker, () => agent.abort())\n * // external cancel signal → abort() instead of agent.abort()\n * ```\n *\n * One tracker per handler invocation — like the wrappers themselves, it\n * is constructed fresh each attempt and must not be reused across\n * invocations.\n *\n * ## Semantics fine print\n *\n * \"Replaying\" is defined conservatively: `isReplaying()` returns `true`\n * until the first live closure executes. A fresh (non-resumed)\n * invocation therefore reports \"replaying\" for the short window before\n * its first journaled call — harmless for the abort use case (the abort\n * applies moments later, at that first live execution) and the honest\n * answer for journal safety: before the first `ctx.run` settles you\n * cannot know whether the SDK is about to feed you journal entries.\n *\n * That conservative window is wrong for live STREAMING, though: on a\n * fresh run it would suppress the opening output. Streamers should pass\n * `resuming` (the host knows whether this is a crash-recovery replay) and\n * gate on {@link ReplayTracker.isResuming} instead — `false` from the\n * start of a fresh run, `true` only while replaying a resumed journal.\n *\n * A replay that completes without ever going live (the journaled run\n * already finished; the handler exits during replay) never fires\n * `onLive` — queued aborts are dropped with the invocation, which is\n * correct: there is nothing left to abort.\n */\n\n/** Minimal structural slice of the agent's Hookable for `replay:done`. */\nexport interface ReplayDoneHooks {\n callHook: (name: 'replay:done', ctx: Record<string, never>) => unknown\n}\n\nexport interface ReplayTrackerOptions {\n /**\n * Agent hooks to notify at the replay→live transition. When set, the\n * tracker fires `replay:done` exactly once, right after the `onLive`\n * callbacks. Rejections are swallowed (surfaced under `ZIDANE_DEBUG`)\n * — a misbehaving listener must not break the live execution that\n * triggered the transition.\n */\n hooks?: ReplayDoneHooks\n /**\n * Whether THIS invocation is resuming a prior journal (a crash-recovery /\n * resume replay) rather than running fresh. The host supplies it — it's the\n * one bit the tracker can't infer on its own (before the first `ctx.run`\n * settles, \"fresh, not yet live\" and \"replaying a resumed journal\" look\n * identical from inside the wrappers). Determine it from your own state: e.g.\n * the bound object already has persisted session turns, or the SDK reports a\n * non-first attempt.\n *\n * Powers {@link ReplayTracker.isResuming} — the probe streaming consumers\n * should gate on (vs {@link ReplayTracker.isReplaying}, which stays\n * conservative for the abort/journal-safety use case). On a fresh invocation\n * (`resuming: false`, the default) `isResuming()` is `false` from the very\n * start, so a streamer emits the opening deltas / start-step instead of\n * suppressing them until the first journaled call settles.\n */\n resuming?: boolean\n}\n\nexport interface ReplayTracker {\n /**\n * `true` until the first live (non-journaled) execution of a wrapped\n * provider stream / tool body. See the module doc for the fresh-\n * invocation caveat. Use this for journal-safety decisions (deferred\n * abort) where the conservative answer is the correct one.\n */\n isReplaying: () => boolean\n /**\n * `true` only while ACTIVELY replaying a resumed journal — i.e. the\n * invocation was constructed with `resuming: true` AND hasn't gone live\n * yet. Always `false` on a fresh invocation (`resuming: false`).\n *\n * This is the probe for live-streaming consumers: gate emission on\n * `!isResuming()` to suppress re-emitted deltas during a resume replay\n * while still emitting the opening output of a fresh run. (Contrast\n * {@link isReplaying}, which is conservatively `true` at the start of a\n * fresh run too.)\n */\n isResuming: () => boolean\n /**\n * Register a callback for the replay→live transition. Fires once.\n * When the tracker is already live, the callback runs synchronously\n * before `onLive` returns. Returns an unregister function (no-op\n * after firing).\n */\n onLive: (cb: () => void) => () => void\n /**\n * Mark the invocation live. Called by the wrappers from inside their\n * journaled closures — a closure only executes when the journal\n * cursor is past it. Idempotent; only the first call transitions.\n */\n markLive: () => void\n}\n\n/**\n * Create a per-invocation replay tracker. Pass it to `restateProvider`\n * / `restateTool` / `wrapAgentTools` via their `replayTracker` option;\n * consume it via `isReplaying()` / `onLive()` / {@link replayAwareAbort}.\n */\nexport function createReplayTracker(options: ReplayTrackerOptions = {}): ReplayTracker {\n let live = false\n let callbacks: (() => void)[] = []\n const resuming = options.resuming === true\n\n return {\n isReplaying: () => !live,\n isResuming: () => resuming && !live,\n markLive: () => {\n if (live)\n return\n live = true\n const pending = callbacks\n callbacks = []\n for (const cb of pending) {\n try {\n cb()\n }\n catch (err) {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/restate] onLive callback threw: ${err instanceof Error ? err.message : String(err)}\\n`)\n }\n }\n if (options.hooks) {\n Promise.resolve(options.hooks.callHook('replay:done', {})).catch((err: unknown) => {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/restate] replay:done hook rejected: ${err instanceof Error ? err.message : String(err)}\\n`)\n })\n }\n },\n onLive: (cb) => {\n if (live) {\n cb()\n return () => {}\n }\n callbacks.push(cb)\n return () => {\n const idx = callbacks.indexOf(cb)\n if (idx >= 0)\n callbacks.splice(idx, 1)\n }\n },\n }\n}\n\n/**\n * Wrap an abort function so it defers during journal replay.\n *\n * Live invocation → `abort()` runs immediately, exactly like calling\n * `agent.abort()` directly. Replaying invocation → the abort is queued\n * and applied at the first live boundary (the start of the first\n * non-journaled provider stream or tool body), where the resulting\n * `AgentAbortedError` + host catch-arm journaling append to the journal\n * instead of forking it mid-replay. Multiple calls during replay\n * collapse into one queued abort.\n */\nexport function replayAwareAbort(tracker: ReplayTracker, abort: () => void): () => void {\n let queued = false\n return () => {\n if (!tracker.isReplaying()) {\n abort()\n return\n }\n if (queued)\n return\n queued = true\n tracker.onLive(abort)\n }\n}\n","/**\n * Restate-backed `SessionStore` — turn / run state lives in the bound\n * virtual object's K/V state instead of SQLite / file / remote HTTP.\n *\n * Trade-offs vs. journal-only replay\n * ----------------------------------\n * If you only care about durable execution within ONE invocation,\n * skip this — the journaled `ctx.run` entries (LLM calls, tool\n * executions) are enough to replay the loop to byte-identical state\n * after a crash. The in-memory `createMemoryStore()` is the right\n * choice; turns rematerialize from the journal each replay.\n *\n * Pick this store when EXTERNAL consumers (TUI, web GUI, support\n * tooling) need to read a session's history WITHOUT re-entering the\n * agent handler. Virtual-object state is exposed via the SDK's read\n * APIs (`ctx.get` from another handler, `restate-cli`, the Restate\n * web UI) — same data, different access path. The journal is\n * invocation-local; this state is the externally-visible projection\n * of it.\n *\n * Storage layout\n * --------------\n * One virtual-object key per session, three K/V slots:\n *\n * `session-data` → `SessionData` minus the `turns` array (small header)\n * `session-turns` → `SessionTurn[]` (the conversation history)\n * `session-runs` → `SessionRun[]` (run lifecycle records)\n *\n * Splitting `turns` / `runs` out keeps the header light for `load()` —\n * a handler that only needs metadata doesn't pull the full history.\n *\n * Per-invocation read-through cache\n * ---------------------------------\n * The store reads each of the three slots from `ctx.get` AT MOST ONCE per\n * invocation, then serves every subsequent read from an in-memory cache and\n * keeps that cache in sync on each write. This is what makes the store cheap\n * under the agent loop: `appendTurns` fires on every `turn:after` /\n * `tool-results:after`, and the previous implementation re-read (and\n * re-sanitized) the ENTIRE growing `session-turns` array on each call — O(N²)\n * sequential K/V round-trips and CPU over an N-turn run. With the cache the\n * full history is pulled once and appended in memory.\n *\n * Writes stay EAGER (`ctx.set` on every mutating call, not deferred to a\n * flush): external read access is the whole reason this store exists, so a\n * concurrent reader (another handler, `restate-cli`, the Restate UI) must see\n * each turn as soon as it lands. Restate runs one invocation at a time per\n * virtual-object key, so the cache can't be invalidated mid-invocation by a\n * competing writer. The only way to defeat it is to mutate these three slots\n * via raw `ctx.set`/`ctx.clear` OUTSIDE the store within the same invocation —\n * don't; the store owns `session-data` / `session-turns` / `session-runs`.\n *\n * Listing / discovery\n * -------------------\n * `list()` returns `[]` because virtual objects don't expose cross-key\n * enumeration. `delete()` clears the current object's session keys only.\n * Use a separate index handler if you need discovery (one virtual object\n * per `projectRoot` that maintains an indexed list of session ids; this\n * store doesn't own that concern).\n * `generateSessionId` is omitted so the agent falls back to its\n * default UUID generator — for a session bound 1:1 to a virtual-\n * object key, pass `id: ctx.key` to `createSession()` instead and\n * skip ID generation entirely.\n */\n\nimport type { SessionData, SessionRun, SessionStore } from '../session'\nimport type { AgentClock, SessionTurn } from '../types'\nimport type { RestateObjectContextLike } from './types'\nimport { deterministicUuid } from './clock'\n\nconst KEY_DATA = 'session-data'\nconst KEY_TURNS = 'session-turns'\nconst KEY_RUNS = 'session-runs'\n\ntype SessionHeader = Omit<SessionData, 'turns' | 'runs'>\n\nexport interface RestateSessionStoreOptions {\n /**\n * Time source for the journaled header timestamps (`createdAt` /\n * `updatedAt`) the store stamps in `save()` and `updateStatus()`.\n *\n * Defaults to `ctx.date.now()` — one journaled round-trip per call. Pass the\n * SAME `restateClock(ctx, { coalesce: true })` you hand the agent so these\n * finalize-time timestamps ride the coalesced anchor instead of each\n * spending their own `ctx.date.now()`; on a suspend-per-round-trip (FaaS)\n * host that's ~2 fewer suspend/replay cycles per run. Whatever you pass MUST\n * be replay-stable: the value lands in persisted state via `ctx.set`, so a\n * drifting clock would corrupt the journal on replay (`restateClock`\n * satisfies this in both its default and coalescing modes).\n */\n clock?: AgentClock\n}\n\n/**\n * Construct a `SessionStore` backed by the bound virtual-object's K/V\n * state. The store is single-tenant — every method ignores the\n * `sessionId` argument because the virtual object is already keyed by\n * `ctx.key`. Calling `appendTurns('other-id', …)` writes to the\n * CURRENT object's state, not the one named in the argument. Bind one\n * virtual-object key per session and the contract holds.\n */\nexport function restateSessionStore(\n ctx: RestateObjectContextLike,\n options: RestateSessionStoreOptions = {},\n): SessionStore {\n let nextTurnSeq: number | undefined\n let warnedMismatch = false\n\n // Journaled time source for header timestamps. Defaults to `ctx.date.now()`\n // (unchanged); an injected `clock` lets `save` / `updateStatus` share the\n // agent's coalescing anchor instead of each spending a fresh round-trip.\n const clock = options.clock\n const journalNow = clock ? () => clock.now() : () => ctx.date.now()\n\n // Per-invocation read-through cache. Each slot is pulled from `ctx.get`\n // exactly once (lazily, on first access) and then served from memory; every\n // write updates the cache alongside the eager `ctx.set`. See the module\n // docstring for why this is safe (single-writer per virtual-object key) and\n // why writes are NOT deferred (external readers need incremental visibility).\n // Cached turns/runs are kept pre-sanitized, so writes only sanitize the\n // incoming delta instead of re-scanning the whole growing array.\n let headerCache: SessionHeader | null | undefined\n let turnsCache: SessionTurn[] | undefined\n let runsCache: SessionRun[] | undefined\n\n async function loadHeader(): Promise<SessionHeader | null> {\n if (headerCache === undefined)\n headerCache = await ctx.get<SessionHeader>(KEY_DATA)\n return headerCache\n }\n\n async function loadTurns(): Promise<SessionTurn[]> {\n if (turnsCache === undefined)\n turnsCache = sanitizeTurnsForState((await ctx.get<SessionTurn[]>(KEY_TURNS)) ?? [])\n return turnsCache\n }\n\n async function loadRuns(): Promise<SessionRun[]> {\n if (runsCache === undefined)\n runsCache = sanitizeRunsForState((await ctx.get<SessionRun[]>(KEY_RUNS)) ?? [])\n return runsCache\n }\n\n function writeHeader(header: SessionHeader): void {\n headerCache = header\n ctx.set(KEY_DATA, header)\n }\n\n function writeTurns(turns: SessionTurn[]): void {\n turnsCache = turns\n ctx.set(KEY_TURNS, turns)\n }\n\n function writeRuns(runs: SessionRun[]): void {\n runsCache = runs\n ctx.set(KEY_RUNS, runs)\n }\n\n // The store is single-tenant (keyed by `ctx.key`), so a `sessionId` arg that\n // doesn't match `ctx.key` means a method is silently writing to/reading from\n // a different object than the caller named — the classic footgun when a host\n // forgets `createSession({ id: ctx.key })` and the agent mints a random id.\n // Warn ONCE (never throw — a 1:1 binding with a non-matching id still routes\n // correctly, and throwing would break it). Hosts binding `id: ctx.key` never\n // see this.\n function guardSessionId(sessionId: string): void {\n if (warnedMismatch || sessionId === ctx.key)\n return\n warnedMismatch = true\n process.stderr.write(\n `[zidane/restate] restateSessionStore: sessionId \"${sessionId}\" != bound object key \"${ctx.key}\". `\n + `This store ignores the sessionId and operates on the bound object — pass createSession({ id: ctx.key }) to silence this.\\n`,\n )\n }\n\n async function generateTurnId(): Promise<string> {\n if (nextTurnSeq === undefined)\n nextTurnSeq = (await loadTurns()).length\n nextTurnSeq += 1\n // UUID-shaped (via deterministicUuid) rather than the old `turn_${n}`:\n // hosts that mirror turns into an external store commonly key them by a\n // uuid column and validate id shape at their streaming boundary — a bare\n // `turn_N` id failed BOTH (frame dropped as malformed + uuid parse error\n // on the fallback write), silently losing session-managed turns\n // (compaction summaries, steer messages) from durable history.\n // Determinism is unchanged: the seed is (object key, persisted seq).\n return deterministicUuid(`${ctx.key}:turn:${nextTurnSeq}`)\n }\n\n return {\n /**\n * Turn ids are deterministic from the persisted turn count. Random ids\n * are replay-stable only when the whole handler replays from the same\n * point; restarting from an arbitrary journal step can shift the RNG\n * sequence before a state write.\n */\n generateTurnId,\n\n async load(_sessionId: string): Promise<SessionData | null> {\n guardSessionId(_sessionId)\n const header = await loadHeader()\n const turns = await loadTurns()\n const runs = await loadRuns()\n // Hand back fresh array copies, never the cache references. The host\n // wraps this `SessionData` in a live `Session` whose `data.turns` /\n // `data.runs` it mutates in place (`push` on each appendTurns / startRun)\n // — aliasing the cache would let those pushes land inside `loadTurns()`'s\n // result and double-count on the next store write.\n if (!header) {\n if (turns.length === 0 && runs.length === 0)\n return null\n return {\n id: _sessionId,\n turns: [...turns],\n runs: [...runs],\n status: inferStatus(runs),\n metadata: {},\n createdAt: inferCreatedAt(turns, runs),\n updatedAt: inferUpdatedAt(turns, runs),\n }\n }\n return { ...header, turns: [...turns], runs: [...runs] }\n },\n\n async save(session: SessionData): Promise<void> {\n guardSessionId(session.id)\n const { turns, runs, ...header } = session\n // Journal-stable header timestamps. The in-memory `Session` stamps\n // `createdAt` / `updatedAt` with raw `Date.now()` (its `touch()`\n // helper is synchronous and can't await a journaled clock), so the\n // values arriving here differ on every replay — and a replayed\n // `ctx.set` with drifting values is exactly the non-determinism\n // Restate exists to prevent. Source both from the journal instead:\n // `createdAt` sticks to the first persisted value, `updatedAt`\n // comes from `journalNow()` (journaled `ctx.date.now()`, or the\n // injected replay-stable clock — replay returns the recorded reading).\n const prior = await loadHeader()\n const now = await journalNow()\n writeHeader({\n ...header,\n createdAt: prior?.createdAt ?? now,\n updatedAt: now,\n })\n writeTurns(sanitizeTurnsForState(turns))\n writeRuns(sanitizeRunsForState(runs))\n },\n\n async delete(_sessionId: string): Promise<void> {\n guardSessionId(_sessionId)\n ctx.clear(KEY_DATA)\n ctx.clear(KEY_TURNS)\n ctx.clear(KEY_RUNS)\n // Reflect the clear in the cache so same-invocation reads see an empty\n // object instead of stale pre-delete state, and so a later\n // generateTurnId re-seeds from zero.\n headerCache = null\n turnsCache = []\n runsCache = []\n nextTurnSeq = undefined\n },\n\n /**\n * Always empty — virtual objects don't support cross-key\n * enumeration. Maintain a separate index handler if discovery\n * matters.\n */\n async list(): Promise<string[]> {\n return []\n },\n\n async appendTurns(_sessionId: string, turns: SessionTurn[]): Promise<void> {\n guardSessionId(_sessionId)\n const existing = await loadTurns()\n writeTurns([...existing, ...sanitizeTurnsForState(turns)])\n },\n\n async getTurns(_sessionId: string, from = 0, limit?: number): Promise<SessionTurn[]> {\n guardSessionId(_sessionId)\n const turns = await loadTurns()\n return turns.slice(from, limit !== undefined ? from + limit : undefined)\n },\n\n async updateRun(_sessionId: string, run: SessionRun): Promise<void> {\n guardSessionId(_sessionId)\n const runs = await loadRuns()\n const idx = runs.findIndex(r => r.id === run.id)\n const next = [...runs]\n if (idx >= 0) {\n // Journal-stable `startedAt`: the in-memory `Session.startRun`\n // stamps it with raw `Date.now()`, which re-evaluates on every\n // replay. Keep the previously persisted value (mirrors the\n // `createdAt: prior?.createdAt ?? now` pattern in `save()`) so a\n // replayed `ctx.set` payload doesn't drift.\n next[idx] = { ...sanitizeRunForState(run), startedAt: runs[idx].startedAt }\n }\n else {\n next.push(sanitizeRunForState(run))\n }\n writeRuns(next)\n },\n\n async updateStatus(_sessionId: string, status: SessionData['status']): Promise<void> {\n guardSessionId(_sessionId)\n const header = await loadHeader()\n const now = await journalNow()\n if (header) {\n writeHeader({ ...header, status, updatedAt: now })\n }\n else {\n writeHeader({\n id: _sessionId,\n status,\n metadata: {},\n createdAt: now,\n updatedAt: now,\n })\n }\n },\n }\n}\n\nfunction sanitizeTurnsForState(turns: readonly SessionTurn[]): SessionTurn[] {\n return turns.map(sanitizeTurnForState)\n}\n\nfunction sanitizeTurnForState(turn: SessionTurn): SessionTurn {\n if (!turn.usage || turn.usage.timeToFirstTokenMs === undefined)\n return turn\n\n const { timeToFirstTokenMs: _timeToFirstTokenMs, ...usage } = turn.usage\n return { ...turn, usage }\n}\n\nfunction sanitizeRunsForState(runs: readonly SessionRun[]): SessionRun[] {\n return runs.map(sanitizeRunForState)\n}\n\nfunction sanitizeRunForState(run: SessionRun): SessionRun {\n if (!run.turnUsage?.some(usage => usage.timeToFirstTokenMs !== undefined))\n return run\n\n return {\n ...run,\n turnUsage: run.turnUsage.map((usage) => {\n if (usage.timeToFirstTokenMs === undefined)\n return usage\n const { timeToFirstTokenMs: _timeToFirstTokenMs, ...stableUsage } = usage\n return stableUsage\n }),\n }\n}\n\nfunction inferStatus(runs: readonly SessionRun[]): SessionData['status'] {\n if (runs.some(run => run.status === 'running'))\n return 'running'\n if (runs.some(run => run.status === 'error'))\n return 'error'\n if (runs.some(run => run.status === 'completed'))\n return 'completed'\n return 'idle'\n}\n\nfunction inferCreatedAt(turns: readonly SessionTurn[], runs: readonly SessionRun[]): number {\n return minDefined([\n ...turns.map(turn => turn.createdAt),\n ...runs.map(run => run.startedAt),\n ]) ?? 0\n}\n\nfunction inferUpdatedAt(turns: readonly SessionTurn[], runs: readonly SessionRun[]): number {\n return maxDefined([\n ...turns.map(turn => turn.createdAt),\n ...runs.map(run => run.endedAt ?? run.startedAt),\n ]) ?? inferCreatedAt(turns, runs)\n}\n\nfunction minDefined(values: readonly number[]): number | undefined {\n let min: number | undefined\n for (const value of values) {\n if (min === undefined || value < min)\n min = value\n }\n return min\n}\n\nfunction maxDefined(values: readonly number[]): number | undefined {\n let max: number | undefined\n for (const value of values) {\n if (max === undefined || value > max)\n max = value\n }\n return max\n}\n","/**\n * Parallel subagents for durable hosts: each child runs as its OWN durable\n * invocation instead of inside the parent's journal.\n *\n * ## Why a second spawn tool\n *\n * `createSpawnTool` runs the child in-process, so the child's provider and tool\n * calls become journal entries of the PARENT's invocation. That is what makes a\n * crash mid-subagent replay for free — and it is also why those children must\n * run one at a time: two child loops generate their journal operations\n * independently, so the index each operation lands on depends on timing and\n * differs on replay.\n *\n * Dispatching the child to its own invocation dissolves that constraint rather\n * than managing it. The parent journals ONE call entry per child; everything\n * the child does lives in a journal nobody else touches. Children therefore fan\n * out through the existing durable fleet — `executeDurable` starts them in\n * submission order and joins them with the runtime's own combinator — and each\n * child gets its own retry policy and suspension budget, so a poison child\n * retries itself instead of the parent's whole invocation.\n *\n * ## Wiring\n *\n * The host owns the handler and the client; this tool owns the contract:\n *\n * ```ts\n * const spawn = restateSpawnTool({\n * dispatch: (req, toolCtx) => ctx.serviceClient(childService).runChild(req),\n * })\n *\n * createAgent({\n * tools: { ...wrapAgentTools(tools, ctx), spawn },\n * behavior: restateBehavior({\n * maxConcurrentTools: 4,\n * toolBatchExecutor: restateToolBatchExecutor({ promises: RestatePromise }),\n * }),\n * })\n * ```\n *\n * Two host-side rules:\n *\n * - The child handler must be a **service**, or an object on a DIFFERENT key.\n * A virtual object serializes per key, so children sharing the parent's key\n * would queue behind the parent that still holds it — no parallelism, and a\n * deadlock risk.\n * - `maxConcurrentTools` must be raised (it defaults to 1 in `restateBehavior`)\n * and the durable batch executor installed, or the fleet falls back to\n * sequential execution.\n *\n * ## What the child owes the parent\n *\n * A {@link ChildRunResult}: its status, final text, its turns, and its stats.\n * The child runs **sessionless** — it keeps turns in memory and hands them back\n * — so the parent stays the single writer of the run tree and merges each\n * child's turns under a `SessionRun` of its own (see `persist`).\n *\n * ## Constraints this file lives under\n *\n * - `durableExecute` must synchronously return a **mappable** durable promise\n * (`src/loop.ts:5536` throws otherwise), so it cannot be `async` and cannot\n * await anything before dispatching. That is why `spawn:before` is fired\n * without awaiting: listeners on it must not perform journaled I/O.\n * - Nothing native may wrap a durable promise — no `.then`, `.catch`, or\n * `Promise.race` (`src/loop.ts:5514-5528`): a second consumer starts a second\n * progress loop on the runtime's single-consumer channel. Result shaping\n * therefore goes through the runtime's own `map`, and everything that needs\n * to await (session writes, `spawn:complete`) is deferred to a drain on\n * `tool-results:after`.\n * - Per-child timeouts are the callee's business for the same reason: a race\n * against the call promise is exactly the forbidden pattern.\n */\n\nimport type { Session } from '../session'\nimport type { ToolContext, ToolDef } from '../tools/types'\nimport type { AgentStats, SessionTurn, ToolResultContent } from '../types'\nimport type { RestatePromiseLike } from './parallel'\nimport { formatTokenUsage } from '../stats'\nimport { reserveChildLabel } from '../tools/spawn'\nimport { toolOutputByteLength, toolResultToText } from '../types'\n\n/** What the parent hands a child invocation. */\nexport interface ChildRunRequest {\n /** The child's prompt. */\n task: string\n /** Session-scoped label the parent reserved (`child-1`, `child-2`, …). */\n label: string\n /**\n * Identity of the work that spawned this child. Present when the parent has\n * them; forward these to whatever sink the child publishes live events to so\n * a UI can attribute and group them (the parent's own `child:*` events carry\n * the same ids).\n */\n parentRunId?: string\n parentCallId?: string\n sessionId?: string\n /**\n * Subagent depth of the CHILD (parent depth + 1). The handler is responsible\n * for refusing runaway recursion — this tool always dispatches, because a\n * short-circuit would have to return a non-durable promise and the durable\n * fleet rejects those.\n */\n depth: number\n /** Model override requested by the model, if any. */\n model?: string\n /** Named subagent type requested by the model, if any. */\n subagentType?: string\n}\n\n/**\n * A descendant a child already merged, handed up so the top-level parent can\n * rebuild the whole subtree.\n *\n * Why it exists: a child dispatched to a service runs sessionless, so it has\n * nowhere to write ITS children's turns. Without passing them up, a depth-2\n * fan-out loses the grandchildren entirely — the parent sees the child's `spawn`\n * tool calls and nothing of the work they did. Collect these from\n * {@link RestateSpawnToolOptions.onChildMerged} and return them as\n * {@link ChildRunResult.children}.\n */\nexport interface MergedChild {\n /** Label this level assigned. The merging parent re-labels from its own session counter. */\n label: string\n task: string\n /** Depth relative to the run that merged it (1 for its direct children). */\n depth: number\n status: 'completed' | 'aborted' | 'timeout' | 'error'\n stats: AgentStats\n turns: SessionTurn[]\n startedAt?: number\n endedAt?: number\n /** Its own merged descendants, recursively. */\n children?: readonly MergedChild[]\n}\n\n/** What a child invocation returns. */\nexport interface ChildRunResult {\n status: 'completed' | 'aborted' | 'timeout' | 'error'\n /** The child's final assistant text. */\n text: string\n /**\n * The child's turns, in order. Merged into the parent's session under a\n * `SessionRun` for this child, so the persisted tree matches what\n * `createSpawnTool({ persist: true })` produces in-process.\n */\n turns: SessionTurn[]\n stats: AgentStats\n /** Failure detail when `status` is `'error'`. */\n error?: string\n /**\n * When the child started / finished, measured on the CHILD's clock (e.g.\n * `await restateClock(ctx).now()` around its run).\n *\n * Strongly recommended for durable hosts. These land in the merged\n * `SessionRun`, which the parent persists through a journaled state write, so\n * they must be replay-stable. Values measured inside the child's own\n * invocation are: they arrive in the journaled call result. Omit them and the\n * parent falls back to the child's first / last turn timestamps, then to its\n * own run start.\n */\n startedAt?: number\n endedAt?: number\n /**\n * Descendants this child already merged — see {@link MergedChild}. The parent\n * merges them recursively, so a nested fan-out lands in the session with the\n * right depths and emits `child:*` events at every level.\n */\n children?: readonly MergedChild[]\n}\n\nexport interface RestateSpawnToolOptions {\n /**\n * Start the child invocation and return the runtime's promise **untouched**\n * (e.g. `ctx.serviceClient(childService).runChild(req)`). Do not wrap it in\n * `then` / `catch` / `race`, and do not `await` it here.\n */\n dispatch: (req: ChildRunRequest, ctx: ToolContext) => Promise<ChildRunResult>\n /**\n * Merge each child's turns and run record into the parent's session.\n * Default: `true` when the parent has a session.\n *\n * Ordering nuance versus the in-process tool: the merge runs on\n * `tool-results:after`, so a child's turns are appended just AFTER the\n * parent's tool-result turn rather than just before it. Their `createdAt`\n * values still order them correctly for consumers that sort chronologically.\n */\n persist?: boolean\n /**\n * Called once when the parent aborts with children still in flight. Wire it\n * and an aborted parent stops its children instead of orphaning them.\n *\n * The practical implementation is to cancel the parent's OWN invocation:\n *\n * ```ts\n * onAbort: () => ctx.invocation(ctx.request().id).cancel()\n * ```\n *\n * Restate cancels the whole call tree, so this reaches children at any depth\n * and needs no per-child bookkeeping. `ctx.request().id` is available\n * synchronously and is constant across retries and suspensions. The cost is\n * that the parent invocation ends too — an in-agent abort becomes \"stop\n * everything\", so persist whatever summary you need BEFORE aborting.\n *\n * Why not per-child ids: the `invocationId` on the runtime's call handle is\n * itself a journal-backed promise (`SingleRestatePromise`, see\n * `@restatedev/restate-sdk` `context_impl.js`), so reading it while the call\n * is in flight registers a second consumer on the SDK's single-consumer\n * progress channel — `awaitNext already pending`, a failed attempt, and a\n * replay on every fan-out. Verified against a real server. Per-child\n * cancellation needs the two-phase (send → id → attach) tool shape, where the\n * id is consumed before the result promise exists.\n *\n * Timing: cancelling appends a journal command, so it must not happen during\n * a replay. Drive aborts through `replayAwareAbort` (see `./replay`), which\n * defers an external abort to the first live boundary.\n */\n onAbort?: (inFlight: readonly InFlightChild[], ctx: ToolContext) => void\n /**\n * Replay each finished child's transcript onto the parent's hook bus as\n * `child:*` events, so hosts already rendering subagent activity work\n * unchanged. Default: `true`.\n *\n * These are NOT live — hook bubbling cannot cross an invocation boundary, so\n * they fire when the child finishes, in submission order. For live output,\n * publish from the child's own bus inside your handler and correlate with the\n * `parentRunId` / `parentCallId` / `sessionId` carried in\n * {@link ChildRunRequest}; see `docs/RESTATE.md` § Parallel subagents.\n *\n * They re-fire on a parent replay, exactly as the in-process tool's\n * `child:tool:*` does — dedupe by `callId` / `turnId`, or gate on\n * `createReplayTracker`.\n */\n emitChildEvents?: boolean\n /**\n * Called for each child as it merges, with the subtree it brought along.\n *\n * Sessionless agents (a child dispatched to a service) need this: they have\n * nowhere to persist their own children, so they collect here and hand the\n * result up as {@link ChildRunResult.children}. Without it a nested fan-out\n * loses everything below depth 1.\n */\n onChildMerged?: (merged: MergedChild, ctx: ToolContext) => void\n /** Override the tool description shown to the model. */\n description?: string\n}\n\n/**\n * The `invocationId` half of the runtime's invocation handle. Restate's\n * `ctx.serviceClient(...).method(...)` returns `RestatePromise & { invocationId:\n * Promise<InvocationId> }`; only that field is needed here, so this stays a\n * structural type rather than an SDK import.\n */\n/** A child that was dispatched and has not settled yet. */\nexport interface InFlightChild {\n label: string\n task: string\n depth: number\n}\n\ninterface PendingChild {\n order: number\n label: string\n task: string\n depth: number\n callId: string\n runId: string\n parentRunId?: string\n session?: Session\n result?: ChildRunResult\n failure?: unknown\n /** Set once the child settled — a settled child is never cancelled. */\n settled?: boolean\n /** Set when WE asked the runtime to cancel, so the outcome reads `aborted`. */\n cancelRequested?: boolean\n /** Detach the abort listener. */\n release?: () => void\n}\n\nconst ZERO_STATS: AgentStats = {\n totalIn: 0,\n totalOut: 0,\n totalCacheRead: 0,\n totalCacheCreation: 0,\n turns: 0,\n elapsed: 0,\n}\n\nconst DEFAULT_DESCRIPTION = 'Delegate a self-contained task to a sub-agent that runs independently '\n + 'and returns only its final report. Several spawn calls in one turn run in parallel.'\n\nexport function restateSpawnTool(options: RestateSpawnToolOptions): ToolDef {\n const persist = options.persist ?? true\n const emitEvents = options.emitChildEvents ?? true\n // Submission counter: `executeDurable` starts fleet members in call-index\n // order, so this ordinal is deterministic and drives the merge order.\n let dispatchSeq = 0\n let sessionlessLabels = 0\n let cancelSignalled = false\n let nestedLabels = 0\n const pending: PendingChild[] = []\n const drainRegistered = new WeakSet<object>()\n\n /**\n * Build the request and the bookkeeping entry. Deliberately side-effect free\n * apart from reserving the label: the fleet path has to be able to reject a\n * misconfigured `dispatch` (below) without leaving a phantom child queued for\n * the merge. `commit` is what actually enrols the child.\n */\n function prepare(input: Record<string, unknown>, ctx: ToolContext): { req: ChildRunRequest, entry: PendingChild } {\n const task = String(input.task ?? '')\n const depth = (ctx.depth ?? 0) + 1\n // Reserved synchronously, in submission order, from the same\n // session-anchored counter the in-process tool uses — so labels survive\n // replays and line up with a reloaded transcript.\n const label = ctx.session ? reserveChildLabel(ctx.session) : `child-${++sessionlessLabels}`\n const entry: PendingChild = {\n order: ++dispatchSeq,\n label,\n task,\n depth,\n callId: ctx.callId,\n // Namespaced off the parent run so the merged record can't collide with\n // a run id this agent instance mints for itself.\n runId: `${ctx.runId ?? 'run'}-${label}`,\n ...(ctx.runId !== undefined ? { parentRunId: ctx.runId } : {}),\n ...(ctx.session !== undefined ? { session: ctx.session } : {}),\n }\n return {\n entry,\n req: {\n task,\n label,\n depth,\n // Attribution for a live host transport: the child tags whatever it\n // publishes with these, and they match the ids on the parent's own\n // `child:*` events.\n ...(ctx.runId !== undefined ? { parentRunId: ctx.runId } : {}),\n parentCallId: ctx.callId,\n ...(ctx.session !== undefined ? { sessionId: ctx.session.id } : {}),\n ...(typeof input.model === 'string' ? { model: input.model } : {}),\n ...(typeof input.subagent_type === 'string' ? { subagentType: input.subagent_type } : {}),\n },\n }\n }\n\n /** Enrol a dispatched child for merging, and announce it. */\n function commit(entry: PendingChild, input: Record<string, unknown>, ctx: ToolContext): void {\n pending.push(entry)\n registerDrain(ctx)\n watchAbort(entry, ctx)\n // Fired WITHOUT awaiting — see the module note on `durableExecute`.\n // Listeners must stay off journaled I/O.\n void Promise.resolve(ctx.hooks.callHook('spawn:before', {\n id: entry.label,\n task: entry.task,\n callId: entry.callId,\n depth: entry.depth,\n ...(typeof input.model === 'string' ? { model: input.model } : {}),\n })).catch(() => {})\n }\n\n function registerDrain(ctx: ToolContext): void {\n if (drainRegistered.has(ctx.hooks))\n return\n drainRegistered.add(ctx.hooks)\n // `tool-results:after` is the normal drain point: it fires right after the\n // batch is packed, so children merge before the next provider call.\n // `turn:after` is a backstop for turns that end without packing tool\n // results — otherwise a settled child would never be merged and its cost\n // never reported. Whichever runs first empties `pending`; the other is a\n // no-op. Neither can close out a child if the invocation is torn down\n // before the turn ends at all — see `docs/RESTATE.md` § Parallel subagents.\n ctx.hooks.hook('tool-results:after', async () => {\n await drain(ctx)\n })\n ctx.hooks.hook('turn:after', async () => {\n await drain(ctx)\n })\n }\n\n /**\n * Persist finished children and announce them. Runs where awaiting is legal,\n * in submission order rather than settlement order, so two children that\n * complete out of order still land deterministically.\n */\n async function drain(ctx: ToolContext): Promise<void> {\n if (pending.length === 0)\n return\n const batch = pending.splice(0, pending.length).sort((a, b) => a.order - b.order)\n // Run records live in session metadata, which `appendTurns` does NOT\n // persist — without an explicit save the merged children exist only in\n // memory and vanish from the reloaded tree.\n let touchedSession: Session | undefined\n for (const entry of batch) {\n const result = entry.result\n const stats = result?.stats ?? ZERO_STATS\n // A child we cancelled failed on purpose: record it as `aborted` so a\n // cancelled fan-out doesn't read as a fleet of broken children in the\n // session, in `spawn:complete`, or in cost accounting.\n const status = result?.status ?? (entry.cancelRequested ? 'aborted' : 'error')\n const session = entry.session\n if (persist && session) {\n touchedSession = session\n session.startRun(entry.runId, entry.task, {\n ...(entry.parentRunId !== undefined ? { parentRunId: entry.parentRunId } : {}),\n depth: entry.depth,\n label: entry.label,\n })\n if (result && result.turns.length > 0) {\n // Re-stamp onto the merged run id: the child minted these under its\n // own run, and the parent's tree keys on this one.\n await session.appendTurns(result.turns.map(turn => ({ ...turn, runId: entry.runId })))\n }\n const rollup = {\n turns: stats.turns,\n tokensIn: stats.totalIn,\n tokensOut: stats.totalOut,\n ...(stats.cost !== undefined ? { cost: stats.cost } : {}),\n }\n if (status === 'completed')\n session.completeRun(entry.runId, rollup)\n else if (status === 'error')\n session.errorRun(entry.runId, errorText(entry), rollup)\n else\n session.abortRun(entry.runId, rollup)\n stampJournaledRunTimes(session, entry, result)\n }\n // Before `spawn:complete`, matching the live order: the child works, then\n // it completes.\n if (emitEvents && result)\n await replayChildEvents(entry, result.turns, ctx)\n // Anything the child merged itself lands underneath it, recursively, so a\n // nested fan-out keeps its shape instead of collapsing into the child.\n if (result?.children && result.children.length > 0) {\n const merged = await mergeDescendants(entry, result.children, ctx)\n if (merged)\n touchedSession = merged\n }\n options.onChildMerged?.({\n label: entry.label,\n task: entry.task,\n depth: entry.depth,\n status,\n stats,\n turns: result?.turns ?? [],\n ...(result?.startedAt !== undefined ? { startedAt: result.startedAt } : {}),\n ...(result?.endedAt !== undefined ? { endedAt: result.endedAt } : {}),\n ...(result?.children !== undefined ? { children: result.children } : {}),\n }, ctx)\n if (status === 'error') {\n await ctx.hooks.callHook('spawn:error', {\n id: entry.label,\n task: entry.task,\n error: new Error(errorText(entry)),\n depth: entry.depth,\n })\n }\n await ctx.hooks.callHook('spawn:complete', {\n id: entry.label,\n task: entry.task,\n callId: entry.callId,\n depth: entry.depth,\n status,\n stats,\n ...(result?.text ? { text: result.text } : {}),\n })\n }\n await touchedSession?.save()\n }\n\n /**\n * Merge a child's own descendants under it, depth-first and in the order the\n * child reported them.\n *\n * Each nested child is RE-LABELED from the merging session's counter: the\n * label it arrived with was minted by its own parent's counter and would\n * collide (every level starts at `child-1`). Re-labeling keeps the session's\n * labels unique and makes the synthesized events agree with the persisted\n * tree.\n */\n async function mergeDescendants(\n parent: { runId: string, depth: number, callId: string, session?: Session },\n nested: readonly MergedChild[],\n ctx: ToolContext,\n ): Promise<Session | undefined> {\n let touched: Session | undefined\n const session = parent.session\n for (const child of nested) {\n const depth = parent.depth + 1\n const label = session ? reserveChildLabel(session) : `${parent.runId}-nested-${++nestedLabels}`\n const runId = `${parent.runId}-${label}`\n if (persist && session) {\n touched = session\n session.startRun(runId, child.task, { parentRunId: parent.runId, depth, label })\n if (child.turns.length > 0)\n await session.appendTurns(child.turns.map(turn => ({ ...turn, runId })))\n const rollup = {\n turns: child.stats.turns,\n tokensIn: child.stats.totalIn,\n tokensOut: child.stats.totalOut,\n ...(child.stats.cost !== undefined ? { cost: child.stats.cost } : {}),\n }\n if (child.status === 'completed')\n session.completeRun(runId, rollup)\n else if (child.status === 'error')\n session.errorRun(runId, 'sub-agent failed', rollup)\n else\n session.abortRun(runId, rollup)\n const record = session.runs.find(run => run.id === runId)\n if (record) {\n // Same rule as the top level: journaled values only — these reach\n // `ctx.set` and a live clock would fork the journal on replay.\n const startedAt = child.startedAt ?? child.turns[0]?.createdAt\n const endedAt = child.endedAt ?? child.turns[child.turns.length - 1]?.createdAt ?? startedAt\n if (startedAt !== undefined)\n record.startedAt = startedAt\n if (endedAt !== undefined)\n record.endedAt = endedAt\n }\n }\n if (emitEvents) {\n await replayChildEvents(\n { label, depth, runId, callId: parent.callId, ...(parent.runId ? { parentRunId: parent.runId } : {}) },\n child.turns,\n ctx,\n )\n }\n if (child.children && child.children.length > 0) {\n const deeper = await mergeDescendants({ runId, depth, callId: parent.callId, ...(session ? { session } : {}) }, child.children, ctx)\n touched = touched ?? deeper\n }\n }\n return touched\n }\n\n /**\n * Repair the run record's timestamps with journaled values.\n *\n * `startRun` / `completeRun` / `errorRun` / `abortRun` stamp `Date.now()`\n * internally, and these records reach `ctx.set` through `save()` below — so a\n * live value here changes the state payload on a replay and kills the\n * invocation with `RestateError 570`. The loop repairs its own runs exactly\n * this way (`agent.ts`: `sessionRun.startedAt = runStartedAt`, `run.endedAt =\n * await clock.now()`); the merge path has to do the same.\n *\n * Sampling the parent's clock here is not an option: the drain runs inside a\n * hook the loop may abandon (`settledHook`), and an awaited journal op left in\n * flight is its own failure mode. Everything below is already journaled by the\n * time it reaches us — either measured by the child on ITS clock and carried\n * inside the journaled call result, or read from state the parent's own run\n * already wrote.\n */\n function stampJournaledRunTimes(session: Session, entry: PendingChild, result?: ChildRunResult): void {\n const merged = session.runs.find(run => run.id === entry.runId)\n if (!merged)\n return\n const turns = result?.turns ?? []\n const parentStartedAt = entry.parentRunId !== undefined\n ? session.runs.find(run => run.id === entry.parentRunId)?.startedAt\n : undefined\n // Preference order: what the child measured, then its own turn timestamps,\n // then the parent's run start (journaled by the loop) as a last resort for\n // a child that produced nothing.\n const startedAt = result?.startedAt ?? turns[0]?.createdAt ?? parentStartedAt\n const endedAt = result?.endedAt ?? turns[turns.length - 1]?.createdAt ?? startedAt\n if (startedAt !== undefined)\n merged.startedAt = startedAt\n if (endedAt !== undefined)\n merged.endedAt = endedAt\n }\n\n /**\n * Replay a finished child's transcript onto the PARENT's hook bus as `child:*`\n * events, so hosts that already render subagent activity (`src/output/\n * terminal.ts`, the GUI engine, any `child:tool:*` listener) light up for\n * parallel children without a single change.\n *\n * Not live \\u2014 hook bubbling cannot cross an invocation boundary, so these fire\n * when the child finishes, in submission order. Everything here is derived\n * from the journaled call result, so a parent replay produces the identical\n * sequence; like the in-process tool's `child:tool:*`, they DO re-fire on that\n * replay, so hosts dedupe by `callId` / `turnId` or gate on\n * `createReplayTracker`.\n *\n * Only events that describe things the child actually did are synthesized.\n * `tool:gate` / `tool:transform` / `tool:dispatched` / `tool:cancelled` /\n * `background:*` describe decisions taken inside another process; inventing\n * them would be fiction, so they stay absent.\n */\n async function replayChildEvents(\n child: { label: string, depth: number, runId: string, parentRunId?: string, callId: string },\n turns: readonly SessionTurn[],\n ctx: ToolContext,\n ): Promise<void> {\n if (turns.length === 0)\n return\n // Tool results live on the following user turn, so pair by callId across\n // the whole transcript rather than within a turn.\n const outputs = new Map<string, { output: string | ToolResultContent[], isError?: boolean }>()\n for (const turn of turns) {\n for (const block of turn.content) {\n if (block.type === 'tool_result')\n outputs.set(block.callId, { output: block.output, ...(block.isError !== undefined ? { isError: block.isError } : {}) })\n }\n }\n\n // Stream / turn events carry only the child coordinates; the tool events\n // extend `ToolHookContext`, which also carries run identity.\n const childIdentity = { childId: child.label, depth: child.depth }\n const identity = {\n ...childIdentity,\n runId: child.runId,\n ...(child.parentRunId !== undefined ? { parentRunId: child.parentRunId } : {}),\n // The spawn call that owns this child, matching `ToolHookContext.parentCallId`.\n parentCallId: child.callId,\n }\n const runToolCounts: Record<string, number> = {}\n let assistantTurns = 0\n\n for (const turn of turns) {\n if (turn.role !== 'assistant')\n continue\n assistantTurns += 1\n const text = turn.content.filter(block => block.type === 'text').map(block => block.text).join('')\n if (text.length > 0) {\n await ctx.hooks.callHook('child:stream:text', { ...childIdentity, turnId: turn.id, delta: text, text })\n }\n\n const turnToolCounts: Record<string, number> = {}\n for (const block of turn.content) {\n if (block.type !== 'tool_call')\n continue\n runToolCounts[block.name] = (runToolCounts[block.name] ?? 0) + 1\n turnToolCounts[block.name] = (turnToolCounts[block.name] ?? 0) + 1\n const base = {\n ...identity,\n turnId: turn.id,\n callId: block.id,\n name: block.name,\n displayName: block.name,\n input: block.input,\n runToolCounts: { ...runToolCounts },\n }\n await ctx.hooks.callHook('child:tool:before', base)\n const settled = outputs.get(block.id)\n if (settled === undefined)\n continue\n if (settled.isError === true) {\n await ctx.hooks.callHook('child:tool:error', {\n ...base,\n error: new Error(toolResultToText(settled.output)),\n })\n continue\n }\n await ctx.hooks.callHook('child:tool:after', {\n ...base,\n result: settled.output,\n outputBytes: toolOutputByteLength(settled.output),\n })\n }\n\n const usage = turn.usage ?? { input: 0, output: 0 }\n await ctx.hooks.callHook('child:turn:after', {\n ...childIdentity,\n turn: assistantTurns,\n turnId: turn.id,\n usage,\n message: turn,\n toolCounts: { turn: { ...turnToolCounts }, run: { ...runToolCounts } },\n })\n await ctx.hooks.callHook('child:stream:end', { ...childIdentity, turnId: turn.id, text })\n }\n }\n\n function errorText(entry: PendingChild): string {\n if (entry.failure !== undefined)\n return entry.failure instanceof Error ? entry.failure.message : String(entry.failure)\n return entry.result?.error ?? 'sub-agent failed'\n }\n\n /**\n * Shape the model-facing result. Mirrors the in-process tool's wording so a\n * host or model tuned on one reads the other.\n *\n * `stats.elapsed` is safe to print here even though it is a live measurement:\n * the child measured it inside ITS invocation and it arrives in the journaled\n * call result, so the parent replays the same bytes. (Sampling it on the\n * parent side is what corrupts a transcript — see `docs/RESTATE.md`.)\n */\n /**\n * Arm the abort path for one child. Nothing is read off the dispatch promise:\n * touching its `invocationId` mid-flight would register a second consumer on\n * the runtime's progress channel (see `onAbort`'s note), so the hook gets\n * labels and the host cancels the tree.\n */\n function watchAbort(entry: PendingChild, ctx: ToolContext): void {\n if (!options.onAbort)\n return\n if (ctx.signal.aborted) {\n requestCancel(ctx)\n return\n }\n const onAbort = (): void => requestCancel(ctx)\n ctx.signal.addEventListener('abort', onAbort, { once: true })\n entry.release = () => ctx.signal.removeEventListener('abort', onAbort)\n }\n\n /**\n * Fire the host's abort hook once for the whole in-flight set. Called once per\n * abort, not once per child: cancelling the tree is a single operation, and a\n * second call would append a redundant journal command.\n */\n function requestCancel(ctx: ToolContext): void {\n const onAbort = options.onAbort\n if (!onAbort || cancelSignalled)\n return\n const inFlight = pending.filter(entry => !entry.settled)\n if (inFlight.length === 0)\n return\n cancelSignalled = true\n for (const entry of inFlight)\n entry.cancelRequested = true\n onAbort(\n inFlight.map(entry => ({ label: entry.label, task: entry.task, depth: entry.depth })),\n ctx,\n )\n }\n\n function settle(entry: PendingChild, value?: ChildRunResult, failure?: unknown): string {\n entry.settled = true\n entry.release?.()\n if (failure !== undefined) {\n entry.failure = failure\n // A failure we caused by cancelling reads as `aborted`, not `error` —\n // otherwise every cancelled fan-out looks like a fleet of broken children.\n if (entry.cancelRequested)\n return `[sub-agent ${entry.label}] Aborted (cancelled)`\n return `[sub-agent ${entry.label}] Error: ${errorText(entry)}`\n }\n const result = value ?? { status: 'error' as const, text: '', turns: [], stats: ZERO_STATS }\n entry.result = result\n const head = `[sub-agent ${entry.label}]`\n const usage = `Tokens: ${formatTokenUsage(result.stats)}`\n if (result.status === 'completed') {\n return [\n `${head} Completed in ${result.stats.turns} turns (${result.stats.elapsed}ms)`,\n usage,\n '',\n result.text || '(no text response)',\n ].join('\\n')\n }\n if (result.status === 'error')\n return `${head} Error: ${errorText(entry)}`\n const verb = result.status === 'timeout' ? 'Timed out' : 'Aborted'\n return [`${head} ${verb} after ${result.stats.turns} turns (${result.stats.elapsed}ms)`, usage].join('\\n')\n }\n\n return {\n spec: {\n name: 'spawn',\n description: options.description ?? DEFAULT_DESCRIPTION,\n inputSchema: {\n type: 'object',\n properties: {\n task: { type: 'string', description: 'The self-contained task for the sub-agent.' },\n model: { type: 'string', description: 'Optional model id for the sub-agent.' },\n subagent_type: { type: 'string', description: 'Optional named sub-agent type.' },\n },\n required: ['task'],\n },\n },\n isConcurrencySafe: true,\n // Keeps `wrapAgentTools` from journaling this tool: dispatching a call from\n // inside a journaled action is the same illegal nesting the in-process\n // spawn tool avoids.\n runsNestedAgent: true,\n\n // Fleet path. Synchronous by necessity, and the returned promise is the\n // runtime's own — mapped, never `then`-ed.\n durableExecute: (input: Record<string, unknown>, ctx: ToolContext) => {\n const { req, entry } = prepare(input, ctx)\n const promise = options.dispatch(req, ctx) as RestatePromiseLike<ChildRunResult>\n // Checked BEFORE the child is enrolled: a `commit` here would queue a\n // child that never ran, so the next drain would persist a `SessionRun`\n // for it and report a phantom failure.\n if (typeof promise.map !== 'function') {\n throw new TypeError(\n 'restateSpawnTool: `dispatch` must return the runtime\\'s durable promise '\n + '(e.g. `ctx.serviceClient(svc).runChild(req)`), which exposes `map`.',\n )\n }\n commit(entry, input, ctx)\n return promise.map((value?: ChildRunResult, failure?: unknown) => settle(entry, value, failure))\n },\n\n // Sequential path, for hosts without the durable batch executor.\n execute: async (input: Record<string, unknown>, ctx: ToolContext): Promise<string | ToolResultContent[]> => {\n const { req, entry } = prepare(input, ctx)\n // Enrolled before awaiting: on this path a failed dispatch still has to\n // be recorded and reported, the way the in-process tool records a child\n // that threw.\n const promise = options.dispatch(req, ctx)\n commit(entry, input, ctx)\n try {\n return settle(entry, await promise)\n }\n catch (err) {\n return settle(entry, undefined, err)\n }\n },\n }\n}\n","/**\n * Restate-backed {@link ToolStateStore} — durable key/value state for tools,\n * stored in the bound virtual object's K/V state.\n *\n * Why this is the right home for it: the Restate journal is\n * invocation-scoped, so it cannot carry information from one invocation to\n * the next; virtual-object state can, and it survives process death without\n * a database of your own. Same substrate `restateSessionStore` uses.\n *\n * Placement rules this store exists to respect (Restate forbids context use\n * inside `ctx.run`, which is where a wrapped tool body executes):\n *\n * - `load` performs the one `ctx.get`. The agent calls it once per run,\n * before the first tool dispatch — outside every journaled action, at a\n * position replay reproduces.\n * - `commit` performs `ctx.set`. The loop calls it after a tool call\n * settles, also outside the journaled action, with ops that came back out\n * of the journal (see `restateTool`'s state envelope) — so the write is\n * identical on a live attempt and on replay.\n *\n * Neither is ever reached from inside a tool body: `ToolContext.state` reads\n * a snapshot and stages writes in memory.\n *\n * ## Storage shape\n *\n * One state key holding a JSON object (default `zidane_tool_state`), read\n * through a per-invocation cache and rewritten whole on each commit — the\n * same trade `restateSessionStore` makes for turns. Restate caps state\n * value size, so treat this like the session store's `sanitizeTurnsForState`\n * discipline: flags, ids, counters, cursors. Not blobs, not transcripts.\n *\n * Pass an explicit `key` to isolate namespaces (e.g. one per tool family) or\n * to migrate a schema without clobbering the old value.\n */\n\nimport type { ToolStateOp, ToolStateStore } from '../tool-state'\nimport type { RestateObjectContextLike } from './types'\n\n/** Default virtual-object state key holding the tool-state map. */\nexport const DEFAULT_TOOL_STATE_KEY = 'zidane_tool_state'\n\nexport interface RestateToolStateStoreOptions {\n /** Override the state key. Defaults to {@link DEFAULT_TOOL_STATE_KEY}. */\n key?: string\n /**\n * Per-value size budget enforced when a tool stages a write. Defaults to\n * the library's `DEFAULT_MAX_VALUE_BYTES` (64 KiB), which is far below\n * Restate's own journal-entry ceiling on purpose: an oversized state value\n * doesn't fail politely there — the invocation fails with `RT0003`\n * (MessageSizeLimit) and is retried under the configured policy, i.e. a fat\n * write becomes a poison pill rather than a dropped one.\n */\n maxValueBytes?: number\n}\n\n/**\n * Build a {@link ToolStateStore} over the bound virtual object's state.\n *\n * ```ts\n * const agent = createAgent({\n * provider,\n * tools: wrapAgentTools({ shell }, ctx),\n * session: createSession({ id: ctx.key, store: restateSessionStore(ctx) }),\n * toolState: restateToolStateStore(ctx),\n * })\n * ```\n *\n * Single-writer like the session store: the state belongs to the object key,\n * so bind one key per conversation and one agent per invocation.\n *\n * Build it INSIDE the handler. The returned store closes over this `ctx`, so\n * an agent constructed once at module scope and reused across invocations\n * would commit through a context that is already finished, and would never\n * re-hydrate (the controller memoizes the load for the life of the agent).\n * Same rule as `restateSessionStore` / `restateProvider` / `restateClock` —\n * but easier to get wrong here, because `toolState` looks like\n * agent-lifetime configuration rather than a per-invocation binding.\n *\n * The map is a schema you own: one JSON object, no versioning, no migration.\n * A value written by an earlier deploy is still there after you change its\n * shape, so either read tolerantly or move to a fresh `key`.\n *\n * Enabling this adds a `ctx.get` at run start, which changes the journal\n * shape for NEW invocations. Existing in-flight invocations replay against\n * the old shape — drain them (or accept the failed attempts) before rolling\n * it out.\n */\nexport function restateToolStateStore(\n ctx: RestateObjectContextLike,\n options: RestateToolStateStoreOptions = {},\n): ToolStateStore {\n const key = options.key ?? DEFAULT_TOOL_STATE_KEY\n const maxValueBytes = options.maxValueBytes\n // Read-through cache: `load` pulls once, `commit` writes through it, so a\n // multi-call run spends exactly one `ctx.get` and one `ctx.set` per\n // state-touching call. Eager (not deferred) for the same reason the\n // session store is: external readers of the object need to see writes as\n // they land, not at the end of the invocation.\n let cache: Record<string, unknown> | undefined\n\n return {\n ...(maxValueBytes !== undefined ? { maxValueBytes } : {}),\n load: async () => {\n cache = (await ctx.get<Record<string, unknown>>(key)) ?? {}\n // Copy out — the controller owns its snapshot and must not alias the\n // cache this store rewrites on commit.\n return { ...cache }\n },\n commit: (ops: readonly ToolStateOp[]) => {\n if (ops.length === 0)\n return\n const next = { ...(cache ?? {}) }\n for (const op of ops) {\n if (op.delete === true)\n delete next[op.key]\n else\n next[op.key] = op.value\n }\n cache = next\n ctx.set(key, next)\n },\n }\n}\n","/**\n * Durable `ExecutionContext.waitBackground` for Restate hosts.\n *\n * A durable execution context can't push a `task:exit` callback from a timer\n * back into a journaled handler. The race-safe pattern is an awakeable park:\n * the runner fires task-exit over its own bridge → `ctx.resolveAwakeable(id,\n * exitInfo)` → the parked `waitBackground` resumes. The *choreography* around\n * that park is entirely generic — only the persistence (which row maps a task\n * to its resumer awakeable) is host-specific. {@link restateWaitBackground}\n * owns the generic half; the host supplies `probe` / `register` / `settle`.\n *\n * Ordering contract (this is the whole point — get it wrong and you leak a\n * lost wakeup):\n *\n * 1. **mint** the awakeable (before the journaled register, so replay\n * re-derives the same id).\n * 2. **register** the awakeable id as the task's exit resumer — journaled,\n * and crucially BEFORE the probe. If we probed first and the task exited\n * in the gap before register, the runner's `task:exit` would fire with no\n * resumer row and the park would hang forever.\n * 3. **probe** the registry. If the task ALREADY terminated, fast-path: settle\n * and return its exit info without ever parking (a resolution that lands\n * on the registered awakeable afterwards is dropped by the runtime). If the\n * task is unknown, settle and return `null`. Otherwise:\n * 4. **park** on the awakeable, OUTSIDE any `ctx.run`, raced against the\n * durable `ctx.sleep(timeoutMs)` deadline and the caller's abort signal.\n * A timeout / abort resolves `null` (the seam's documented sentinel).\n * 5. **settle** — journaled finalization (stamp / clear the resumer row).\n *\n * The returned function matches `ExecutionContext.waitBackground` exactly, so a\n * host wires it with `execution.waitBackground = restateWaitBackground({ … })`.\n */\n\nimport type { ExecutionHandle, TaskEntry, TaskExitInfo } from '../contexts'\nimport type { RestatePromiseRaceLike } from './awakeable'\nimport type { ReplayTracker } from './replay'\nimport type { RestateContextLike, RestateRunOptions } from './types'\nimport { awakeableWithTimeout } from './awakeable'\n\n/** Journaled registration marker — mirrors the marker invariant in `restateAwakeableTool`. */\ninterface WaitBackgroundRegisterMarker {\n registered: true\n awakeableId: string\n}\n\nexport interface RestateWaitBackgroundOptions {\n /** The Restate context the awakeable + journal entries bind to. */\n ctx: RestateContextLike\n /**\n * Snapshot the host's task registry (the `listBackground` shape). Called\n * AFTER `register`, inside a journaled `ctx.run`. The helper finds `taskId`\n * in the result: terminated → fast-path return, running → park, absent →\n * `null`.\n */\n probe: (handle: ExecutionHandle, taskId: string) => Promise<readonly TaskEntry[]> | readonly TaskEntry[]\n /**\n * Persist `awakeableId` as the exit resumer for `taskId` BEFORE the probe —\n * the host's task-exit path must later call `ctx.resolveAwakeable(awakeableId,\n * exitInfo)`. Runs inside a journaled `ctx.run`; keep it short and\n * idempotent-safe up to journal persistence.\n */\n register: (awakeableId: string, taskId: string, handle: ExecutionHandle) => Promise<void> | void\n /**\n * Finalize the resumer row once the wait resolves — `exit` is the task's\n * {@link TaskExitInfo}, or `null` on timeout / abort / unknown task. Runs\n * inside a journaled `ctx.run`. Optional.\n */\n settle?: (awakeableId: string, taskId: string, exit: TaskExitInfo | null, handle: ExecutionHandle) => Promise<void> | void\n /**\n * Default park deadline in milliseconds. A per-call `options.timeoutMs`\n * (what the `wait_task` tool passes) wins. Unset / non-positive = park until\n * the resumer fires or the caller aborts.\n */\n timeoutMs?: number\n /**\n * Durable race combinator for the timeout race — pass `RestatePromise` from\n * the SDK. See {@link awakeableWithTimeout}; native `Promise.race` is the\n * replay-safe fallback.\n */\n promises?: RestatePromiseRaceLike\n /** `ctx.run` options for the journaled phases. Defaults to `{ maxRetryAttempts: 1 }`. */\n runOptions?: RestateRunOptions\n /** Journal-entry prefix. Default `wait-background`. */\n entryPrefix?: string\n /** Per-invocation replay tracker (see `createReplayTracker`). */\n replayTracker?: ReplayTracker\n}\n\nfunction entryToExit(entry: TaskEntry): TaskExitInfo {\n return {\n taskId: entry.taskId,\n // `entryToExit` is only called for terminated entries; `'running'` can't\n // reach here, but narrow defensively to the exit-only union.\n status: entry.status === 'running' ? 'exited' : entry.status,\n exitCode: entry.exitCode ?? 0,\n ...(entry.signal ? { signal: entry.signal } : {}),\n outputPath: entry.outputPath,\n durationMs: Math.max(0, (entry.endedAt ?? entry.startedAt) - entry.startedAt),\n command: entry.command,\n }\n}\n\n/**\n * Park on `promise` until it settles, the caller aborts, or (already handled\n * by `awakeableWithTimeout`) the durable deadline elapses. Abort and rejection\n * both resolve `null` — the `waitBackground` seam's contract is \"exit info, or\n * null when the task didn't cleanly exit before we stopped waiting\".\n */\nfunction parkUntilAbort<T>(promise: Promise<T>, signal?: AbortSignal): Promise<T | null> {\n if (!signal)\n return promise.then(value => value, () => null)\n if (signal.aborted)\n return Promise.resolve(null)\n return new Promise<T | null>((resolve) => {\n const onAbort = (): void => resolve(null)\n signal.addEventListener('abort', onAbort, { once: true })\n promise.then(\n (value) => {\n signal.removeEventListener('abort', onAbort)\n resolve(value)\n },\n () => {\n signal.removeEventListener('abort', onAbort)\n resolve(null)\n },\n )\n })\n}\n\n/**\n * Build a durable `ExecutionContext.waitBackground` — see the module doc for\n * the ordering contract. The returned function is the seam itself:\n * `(handle, taskId, options?) => Promise<TaskExitInfo | null>`.\n */\nexport function restateWaitBackground(\n options: RestateWaitBackgroundOptions,\n): (handle: ExecutionHandle, taskId: string, opts?: { timeoutMs?: number, signal?: AbortSignal }) => Promise<TaskExitInfo | null> {\n const { ctx, probe, register, settle } = options\n const runOpts: RestateRunOptions = options.runOptions ?? { maxRetryAttempts: 1 }\n const prefix = options.entryPrefix ?? 'wait-background'\n let seq = 0\n\n return async (handle, taskId, callOpts) => {\n seq += 1\n const entry = `${prefix}-${taskId}-${seq}`\n const timeoutMs = callOpts?.timeoutMs ?? options.timeoutMs\n const signal = callOpts?.signal\n\n const finalize = async (exit: TaskExitInfo | null, awakeableId: string): Promise<TaskExitInfo | null> => {\n if (settle) {\n await ctx.run(`${entry}-settle`, async () => {\n options.replayTracker?.markLive()\n await settle(awakeableId, taskId, exit, handle)\n }, runOpts)\n }\n return exit\n }\n\n // 1. Mint BEFORE the journaled register (same ordering contract as\n // restateAwakeableTool) — replay returns the same id. The timeout sleep\n // is armed here too, so the park below is a durable race.\n const awakeable = awakeableWithTimeout<TaskExitInfo>(ctx, {\n ...(timeoutMs !== undefined ? { timeoutMs } : {}),\n ...(options.promises ? { promises: options.promises } : {}),\n })\n\n // 2. Register the resumer BEFORE probing.\n const marker = await ctx.run<WaitBackgroundRegisterMarker>(`${entry}-register`, async () => {\n options.replayTracker?.markLive()\n await register(awakeable.id, taskId, handle)\n return { registered: true, awakeableId: awakeable.id }\n }, runOpts)\n if (marker.awakeableId !== awakeable.id) {\n throw new Error(\n `restateWaitBackground(${taskId}): journal drift — registration marker carries awakeable \"${marker.awakeableId}\" but this replay minted \"${awakeable.id}\". Refusing to park on an unreachable awakeable.`,\n )\n }\n\n // 3. Probe (journaled). Fast-path terminated / unknown without parking.\n const entries = await ctx.run<readonly TaskEntry[]>(`${entry}-probe`, async () => {\n options.replayTracker?.markLive()\n return [...await probe(handle, taskId)]\n }, runOpts)\n const found = entries.find(e => e.taskId === taskId)\n if (!found)\n return finalize(null, awakeable.id)\n if (found.status !== 'running')\n return finalize(entryToExit(found), awakeable.id)\n\n // 4. Park OUTSIDE any ctx.run — a suspension point must not nest in a\n // journaled closure. Timeout (via awakeableWithTimeout) and abort both\n // resolve null.\n const resumed = await parkUntilAbort(awakeable.promise, signal)\n\n // 5. Settle + return.\n return finalize(resumed, awakeable.id)\n }\n}\n"],"mappings":"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"}