{"version":3,"file":"snapshot.mjs","names":[],"sources":["../../../../../../../ai/src/workflow/snapshot.ts"],"sourcesContent":["import { resolveDefaultSnapshotStore } from \"../config\";\nimport type { SnapshotStore } from \"../contracts/orchestrator/snapshot-store.contract\";\nimport type { StepSnapshot } from \"../contracts/result/step-result.type\";\nimport type { WorkflowSnapshot } from \"../contracts/workflow/workflow-snapshot.type\";\nimport type {\n  WorkflowDefinition,\n  WorkflowResumeOptions,\n} from \"../contracts/workflow/workflow.contract\";\nimport { WorkflowDriftError, WorkflowError } from \"../errors\";\n\n/**\n * Resolve the effective {@link SnapshotStore}: the workflow's own\n * `snapshotStore` field wins; absent that, fall back to the global\n * default set via `ai.config({ defaultSnapshotStore })`.\n *\n * The global default is typed for the supervisor snapshot shape, but\n * every store impl keys purely by `runId` and round-trips whatever\n * envelope it is handed — so it serves a `WorkflowSnapshot` just as\n * well. The cast re-tags the shape at this single boundary; the\n * workflow only ever hands it a `WorkflowSnapshot`.\n */\nfunction resolveSnapshotStore<T>(\n  definition: WorkflowDefinition<any, T, any, any>,\n): SnapshotStore<WorkflowSnapshot> | undefined {\n  return (\n    definition.snapshotStore ??\n    (resolveDefaultSnapshotStore() as SnapshotStore<WorkflowSnapshot> | undefined)\n  );\n}\n\nexport type PersistParams<T> = {\n  definition: WorkflowDefinition<any, T, any, any>;\n  signature: string;\n  runId: string;\n  startedAt: string;\n  input: unknown;\n  state: Record<string, unknown>;\n  steps: Record<string, StepSnapshot>;\n  next: string | null;\n  status: WorkflowSnapshot[\"status\"];\n};\n\nexport type PersistOutcome = { ok: true } | { ok: false; error: unknown };\n\n/**\n * Write the current run's state to the configured `KVStore`. Returns\n * an outcome object instead of throwing so the engine can surface\n * persistence failures via events + logs without aborting the run.\n * Callers decide whether a failed checkpoint is fatal.\n *\n * No-op (returns `{ ok: true }`) when the workflow has no store\n * configured — the common in-memory test case.\n */\nexport async function persistSnapshot<T>(\n  params: PersistParams<T>,\n): Promise<PersistOutcome> {\n  const store = resolveSnapshotStore(params.definition);\n\n  if (!store) return { ok: true };\n\n  const snapshot: WorkflowSnapshot = {\n    runId: params.runId,\n    workflowName: params.definition.name,\n    signature: params.signature,\n    version: params.definition.version,\n    input: params.input,\n    state: { ...params.state },\n    steps: { ...params.steps },\n    next: params.next,\n    status: params.status,\n    startedAt: params.startedAt,\n    savedAt: new Date().toISOString(),\n  };\n\n  try {\n    await store.save(snapshot);\n    return { ok: true };\n  } catch (err) {\n    return { ok: false, error: err };\n  }\n}\n\n/**\n * Load a prior run's snapshot from the store and run the drift\n * check. Throws `WorkflowError` when no snapshot exists, and\n * `WorkflowDriftError` when the stored signature doesn't match the\n * current definition (unless `force` is set).\n */\nexport async function loadSnapshotForResume<T>(params: {\n  definition: WorkflowDefinition<any, T, any, any>;\n  signature: string;\n  runId: string;\n  options?: WorkflowResumeOptions;\n}): Promise<WorkflowSnapshot> {\n  const store = resolveSnapshotStore(params.definition);\n\n  if (!store) {\n    throw new WorkflowError(\n      `workflow \"${params.definition.name}\" has no store configured — set \\`snapshotStore\\` on the definition or call \\`ai.config({ defaultSnapshotStore })\\` at boot before calling resume()`,\n    );\n  }\n\n  const snap = (await store.load(params.runId)) ?? null;\n\n  if (!snap) {\n    throw new WorkflowError(\n      `workflow \"${params.definition.name}\": no snapshot for runId \"${params.runId}\"`,\n    );\n  }\n\n  if (!params.options?.force && snap.signature !== params.signature) {\n    throw new WorkflowDriftError(\n      `workflow \"${params.definition.name}\" signature drift on resume`,\n      {\n        savedSignature: snap.signature,\n        currentSignature: params.signature,\n        runId: params.runId,\n      },\n    );\n  }\n\n  return snap;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAqBA,SAAS,qBACP,YAC6C;CAC7C,OACE,WAAW,iBACV,4BAA4B;AAEjC;;;;;;;;;;AAyBA,eAAsB,gBACpB,QACyB;CACzB,MAAM,QAAQ,qBAAqB,OAAO,UAAU;CAEpD,IAAI,CAAC,OAAO,OAAO,EAAE,IAAI,KAAK;CAE9B,MAAM,WAA6B;EACjC,OAAO,OAAO;EACd,cAAc,OAAO,WAAW;EAChC,WAAW,OAAO;EAClB,SAAS,OAAO,WAAW;EAC3B,OAAO,OAAO;EACd,OAAO,EAAE,GAAG,OAAO,MAAM;EACzB,OAAO,EAAE,GAAG,OAAO,MAAM;EACzB,MAAM,OAAO;EACb,QAAQ,OAAO;EACf,WAAW,OAAO;EAClB,0BAAS,IAAI,KAAK,EAAC,CAAC,YAAY;CAClC;CAEA,IAAI;EACF,MAAM,MAAM,KAAK,QAAQ;EACzB,OAAO,EAAE,IAAI,KAAK;CACpB,SAAS,KAAK;EACZ,OAAO;GAAE,IAAI;GAAO,OAAO;EAAI;CACjC;AACF;;;;;;;AAQA,eAAsB,sBAAyB,QAKjB;CAC5B,MAAM,QAAQ,qBAAqB,OAAO,UAAU;CAEpD,IAAI,CAAC,OACH,MAAM,IAAI,cACR,aAAa,OAAO,WAAW,KAAK,oJACtC;CAGF,MAAM,OAAQ,MAAM,MAAM,KAAK,OAAO,KAAK,KAAM;CAEjD,IAAI,CAAC,MACH,MAAM,IAAI,cACR,aAAa,OAAO,WAAW,KAAK,4BAA4B,OAAO,MAAM,EAC/E;CAGF,IAAI,CAAC,OAAO,SAAS,SAAS,KAAK,cAAc,OAAO,WACtD,MAAM,IAAI,mBACR,aAAa,OAAO,WAAW,KAAK,8BACpC;EACE,gBAAgB,KAAK;EACrB,kBAAkB,OAAO;EACzB,OAAO,OAAO;CAChB,CACF;CAGF,OAAO;AACT"}