@osolmaz/pi-workflows 0.16.5 → 0.16.7

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 (181) hide show
  1. package/README.md +5 -5
  2. package/dist/builtins/autoimplement.workflow.d.ts +5 -1
  3. package/dist/builtins/autoimplement.workflow.js +29 -10
  4. package/dist/builtins/autoimplement.workflow.js.map +1 -1
  5. package/dist/client/client.js +3 -1
  6. package/dist/client/client.js.map +1 -1
  7. package/dist/client/protocol.d.ts +1 -1
  8. package/dist/client/protocol.js +18 -1
  9. package/dist/client/protocol.js.map +1 -1
  10. package/dist/client/view.d.ts +7 -5
  11. package/dist/extension/index.d.ts +2 -1
  12. package/dist/extension/index.js +116 -166
  13. package/dist/extension/index.js.map +1 -1
  14. package/dist/extension/recorder.d.ts +1 -1
  15. package/dist/extension/recorder.js +2 -2
  16. package/dist/extension/recorder.js.map +1 -1
  17. package/dist/extension/step-message.d.ts +1 -1
  18. package/dist/extension/step-message.js +4 -4
  19. package/dist/extension/step-message.js.map +1 -1
  20. package/dist/extension/widget.js +1 -1
  21. package/dist/extension/widget.js.map +1 -1
  22. package/dist/extension/workflow-message-coordinator.d.ts +12 -3
  23. package/dist/extension/workflow-message-coordinator.js +108 -94
  24. package/dist/extension/workflow-message-coordinator.js.map +1 -1
  25. package/dist/render/graph-render.js +1 -1
  26. package/dist/resource-managers/index.d.ts +1 -2
  27. package/dist/resource-managers/index.js +1 -2
  28. package/dist/resource-managers/index.js.map +1 -1
  29. package/dist/resource-managers/sqlite.d.ts +2 -295
  30. package/dist/resource-managers/sqlite.js +71 -1528
  31. package/dist/resource-managers/sqlite.js.map +1 -1
  32. package/dist/resource-managers/types.d.ts +2 -7
  33. package/dist/server/resource-runner-entry.js +2 -6
  34. package/dist/server/resource-runner-entry.js.map +1 -1
  35. package/dist/server/rpc-bridge.js +1 -1
  36. package/dist/server/rpc-bridge.js.map +1 -1
  37. package/dist/server/rpc-executor.js +2 -4
  38. package/dist/server/rpc-executor.js.map +1 -1
  39. package/dist/server/server-entry.js +3 -0
  40. package/dist/server/server-entry.js.map +1 -1
  41. package/dist/server/server.d.ts +9 -8
  42. package/dist/server/server.js +364 -541
  43. package/dist/server/server.js.map +1 -1
  44. package/dist/server/state.d.ts +16 -29
  45. package/dist/server/state.js +105 -319
  46. package/dist/server/state.js.map +1 -1
  47. package/dist/server/view.d.ts +6 -5
  48. package/dist/server/view.js +68 -51
  49. package/dist/server/view.js.map +1 -1
  50. package/dist/server/workflow-runner-entry.d.ts +1 -1
  51. package/dist/server/workflow-runner-entry.js +1 -49
  52. package/dist/server/workflow-runner-entry.js.map +1 -1
  53. package/dist/server/workflow-runner-protocol.d.ts +2 -7
  54. package/dist/server/workflow-runner-protocol.js +5 -10
  55. package/dist/server/workflow-runner-protocol.js.map +1 -1
  56. package/dist/server/workflow-runner-store.d.ts +5 -6
  57. package/dist/server/workflow-runner-store.js +7 -14
  58. package/dist/server/workflow-runner-store.js.map +1 -1
  59. package/dist/state/attempt-time.d.ts +21 -0
  60. package/dist/state/attempt-time.js +95 -0
  61. package/dist/state/attempt-time.js.map +1 -0
  62. package/dist/state/json.d.ts +2 -1
  63. package/dist/state/json.js.map +1 -1
  64. package/dist/state/project-store.d.ts +39 -0
  65. package/dist/state/project-store.js +154 -0
  66. package/dist/state/project-store.js.map +1 -0
  67. package/dist/state/prune.js +0 -7
  68. package/dist/state/prune.js.map +1 -1
  69. package/dist/state/schema.js +23 -23
  70. package/dist/state/workflow-messages.d.ts +1 -1
  71. package/dist/state/workflow-messages.js +3 -1
  72. package/dist/state/workflow-messages.js.map +1 -1
  73. package/dist/viewer/backup.js +5 -0
  74. package/dist/viewer/backup.js.map +1 -1
  75. package/dist/workflows/diagnostics.d.ts +8 -0
  76. package/dist/workflows/diagnostics.js +61 -0
  77. package/dist/workflows/diagnostics.js.map +1 -0
  78. package/dist/workflows/engine.d.ts +2 -16
  79. package/dist/workflows/engine.js +128 -252
  80. package/dist/workflows/engine.js.map +1 -1
  81. package/dist/workflows/errors.d.ts +1 -1
  82. package/dist/workflows/errors.js +2 -2
  83. package/dist/workflows/errors.js.map +1 -1
  84. package/dist/workflows/human-decision.d.ts +3 -7
  85. package/dist/workflows/human-decision.js +2 -56
  86. package/dist/workflows/human-decision.js.map +1 -1
  87. package/dist/workflows/index.d.ts +2 -1
  88. package/dist/workflows/index.js +1 -0
  89. package/dist/workflows/index.js.map +1 -1
  90. package/dist/workflows/queue.d.ts +267 -0
  91. package/dist/workflows/queue.js +1248 -0
  92. package/dist/workflows/queue.js.map +1 -0
  93. package/dist/workflows/requests.d.ts +47 -0
  94. package/dist/workflows/requests.js +158 -0
  95. package/dist/workflows/requests.js.map +1 -0
  96. package/dist/workflows/schema.js +2 -4
  97. package/dist/workflows/schema.js.map +1 -1
  98. package/dist/workflows/store.d.ts +11 -16
  99. package/dist/workflows/store.js +177 -174
  100. package/dist/workflows/store.js.map +1 -1
  101. package/dist/workflows/tool-input.d.ts +6 -9
  102. package/dist/workflows/tool-input.js +15 -12
  103. package/dist/workflows/tool-input.js.map +1 -1
  104. package/dist/workflows/transitions.d.ts +38 -0
  105. package/dist/workflows/transitions.js +276 -0
  106. package/dist/workflows/transitions.js.map +1 -0
  107. package/dist/workflows/types.d.ts +9 -42
  108. package/dist/workflows/workflow-message-content.d.ts +7 -1
  109. package/dist/workflows/workflow-message-content.js +22 -4
  110. package/dist/workflows/workflow-message-content.js.map +1 -1
  111. package/docs/2026-08-25-workflow-follow-ups.md +5 -5
  112. package/docs/2026-09-02-unify-workflow-messages-plan.md +2 -0
  113. package/docs/2026-09-04-workflow-run-state-plan.md +2 -0
  114. package/docs/2026-09-06-durable-execution-plan.md +176 -0
  115. package/docs/2026-09-07-workflow-handoff-plan.md +84 -0
  116. package/docs/DEFERRED_TURNS.md +84 -105
  117. package/docs/HUMAN_DECISIONS.md +17 -19
  118. package/docs/HUMAN_DECISION_PRESENTATIONS.md +1 -1
  119. package/docs/SQLITE_STATE.md +68 -29
  120. package/docs/WORKFLOW_SERVER.md +21 -10
  121. package/docs/WORKFLOW_STEP_MESSAGES.md +83 -54
  122. package/docs/plans/2026-08-04-controller-runtime-plan.md +2 -0
  123. package/docs/plans/2026-08-21-deferred-turn-intents-plan.md +2 -0
  124. package/docs/plans/2026-08-27-workflow-terminal-restart-plan.md +2 -0
  125. package/docs/workflows.md +111 -45
  126. package/examples/workflows/autoresearch.workflow.ts +0 -2
  127. package/examples/workflows/branch.workflow.ts +0 -4
  128. package/examples/workflows/echo.workflow.ts +0 -2
  129. package/examples/workflows/live-settings.workflow.ts +0 -2
  130. package/examples/workflows/two-turn.workflow.ts +0 -2
  131. package/herdr-plugin.toml +1 -1
  132. package/package.json +1 -1
  133. package/protocol/fixtures/client-v1.json +1 -1
  134. package/skills/pi-workflows/SKILL.md +8 -7
  135. package/src/builtins/autoimplement.workflow.ts +31 -10
  136. package/src/client/client.ts +3 -1
  137. package/src/client/protocol.ts +21 -1
  138. package/src/client/view.ts +9 -5
  139. package/src/extension/index.ts +118 -190
  140. package/src/extension/recorder.ts +2 -2
  141. package/src/extension/step-message.ts +4 -4
  142. package/src/extension/widget.ts +1 -1
  143. package/src/extension/workflow-message-coordinator.ts +133 -95
  144. package/src/render/graph-render.ts +1 -1
  145. package/src/resource-managers/index.ts +1 -9
  146. package/src/resource-managers/sqlite.ts +330 -2655
  147. package/src/resource-managers/types.ts +2 -3
  148. package/src/server/resource-runner-entry.ts +2 -7
  149. package/src/server/rpc-bridge.ts +1 -1
  150. package/src/server/rpc-executor.ts +4 -9
  151. package/src/server/server-entry.ts +3 -0
  152. package/src/server/server.ts +416 -641
  153. package/src/server/state.ts +122 -466
  154. package/src/server/view.ts +73 -58
  155. package/src/server/workflow-runner-entry.ts +2 -55
  156. package/src/server/workflow-runner-protocol.ts +5 -15
  157. package/src/server/workflow-runner-store.ts +12 -27
  158. package/src/state/attempt-time.ts +122 -0
  159. package/src/state/json.ts +2 -1
  160. package/src/state/project-store.ts +218 -0
  161. package/src/state/prune.ts +0 -13
  162. package/src/state/schema.ts +23 -23
  163. package/src/state/workflow-messages.ts +4 -2
  164. package/src/viewer/backup.ts +7 -0
  165. package/src/workflows/diagnostics.ts +78 -0
  166. package/src/workflows/engine.ts +136 -299
  167. package/src/workflows/errors.ts +4 -2
  168. package/src/workflows/human-decision.ts +3 -81
  169. package/src/workflows/index.ts +8 -2
  170. package/src/workflows/queue.ts +2091 -0
  171. package/src/workflows/requests.ts +283 -0
  172. package/src/workflows/schema.ts +2 -6
  173. package/src/workflows/store.ts +226 -236
  174. package/src/workflows/tool-input.ts +20 -12
  175. package/src/workflows/transitions.ts +330 -0
  176. package/src/workflows/types.ts +9 -46
  177. package/src/workflows/workflow-message-content.ts +28 -4
  178. package/dist/resource-managers/runtime.d.ts +0 -59
  179. package/dist/resource-managers/runtime.js +0 -423
  180. package/dist/resource-managers/runtime.js.map +0 -1
  181. package/src/resource-managers/runtime.ts +0 -576
@@ -1,10 +1,11 @@
1
1
  import { createHash, randomUUID } from "node:crypto";
2
+ import { closeAttemptTime, closeRunTime } from "../state/attempt-time.js";
2
3
  import { StateDatabase, workflowStatePath } from "../state/database.js";
3
4
  import { canonicalJson, parseJson } from "../state/json.js";
4
5
  import { StateMutationStore, StaleResourceError, resourceIdFor, tokenHash, } from "../state/mutation.js";
5
6
  import { initializeViewerRun, recordViewerDeltas, viewerTailPatch, VIEWER_PAGE_SIZE, } from "../state/viewer.js";
6
7
  import { WorkflowMessageStore, workflowMessageIdFor } from "../state/workflow-messages.js";
7
- import { compositionMetadata } from "./composition.js";
8
+ import { compileWorkflowDefinition, compositionMetadata } from "./composition.js";
8
9
  import { ClaimLostError } from "./errors.js";
9
10
  import { HumanDecisionStore } from "./human-decision.js";
10
11
  import { applyJsonPatch, validateJsonPatch } from "./json-patch.js";
@@ -22,7 +23,6 @@ const STEP_ROW_SELECT = `
22
23
  SELECT s.step_index AS stepIndex, a.attempt_id AS attemptId, a.node_id AS nodeId,
23
24
  a.node_type AS nodeType, a.status,
24
25
  a.prompt_hash AS promptHash, a.output_hash AS outputHash,
25
- s.output_override_hash AS outputOverrideHash,
26
26
  a.receipt_hash AS receiptHash, a.error_hash AS errorHash,
27
27
  prompt_entry.entry_hash AS promptEntryHash,
28
28
  response_entry.entry_hash AS responseEntryHash,
@@ -63,6 +63,9 @@ export function createRunId(workflowName, now = new Date()) {
63
63
  const safeName = workflowName.replace(/[^A-Za-z0-9._-]/g, "-").slice(0, 80) || "workflow";
64
64
  return `${now.toISOString().replace(/[-:.]/g, "").replace("T", "T").replace("Z", "Z")}-${safeName}-${randomUUID().slice(0, 8)}`;
65
65
  }
66
+ /** The state boundary used by workflow code, including out-of-process runners. */
67
+ import { acceptedRequestOutput, ensureWorkflowRequest, requestForAttempt, } from "./requests.js";
68
+ import { applyExecutionTransition, executionTransition, } from "./transitions.js";
66
69
  export class WorkflowRunStore {
67
70
  databasePath;
68
71
  state;
@@ -105,11 +108,23 @@ export class WorkflowRunStore {
105
108
  }
106
109
  return revision;
107
110
  }
108
- async createHumanDecisionRequest(request) {
109
- return await new HumanDecisionStore(this.databasePath, { state: this.state }).createRequest(request);
110
- }
111
- async readResolvedHumanDecision(decisionId) {
112
- return await new HumanDecisionStore(this.databasePath, { state: this.state }).readResolved(decisionId);
111
+ async readCheckpoint(runId, attemptId) {
112
+ const request = requestForAttempt(this.state, runId, attemptId);
113
+ if (request === undefined)
114
+ return undefined;
115
+ if (request.kind !== "checkpoint" && request.kind !== "decision") {
116
+ throw new Error("The attempt does not own a checkpoint request");
117
+ }
118
+ if (request.status !== "settled")
119
+ return { request };
120
+ const output = acceptedRequestOutput(this.state, request);
121
+ const humanDecision = request.kind === "decision"
122
+ ? this.readHumanDecisionReceipt(runId, request.requestId)
123
+ : undefined;
124
+ if (request.kind === "decision" && humanDecision === undefined) {
125
+ throw new Error("The checkpoint has no verified human decision receipt");
126
+ }
127
+ return { request, output, ...(humanDecision === undefined ? {} : { humanDecision }) };
113
128
  }
114
129
  async reserveEffect(options) {
115
130
  return await this.withRunLock(options.runId, async () => this.state.transaction(() => {
@@ -279,7 +294,7 @@ export class WorkflowRunStore {
279
294
  .run(effectId, attemptNumber, authority?.ownerId ?? "system", authority?.generation ?? 1, now);
280
295
  }
281
296
  async initializeRun(workflow, state, options = {}) {
282
- return await this.initializeRunFromSnapshot(createDefinitionSnapshot(workflow), workflow.name, state, options);
297
+ return await this.initializeRunFromSnapshot(createDefinitionSnapshot(compileWorkflowDefinition(workflow)), workflow.name, state, options);
283
298
  }
284
299
  async initializeRunFromSnapshot(snapshot, workflowName, state, options = {}) {
285
300
  assertValidRunId(state.runId);
@@ -331,19 +346,12 @@ export class WorkflowRunStore {
331
346
  }
332
347
  this.syncNodeAttempts(state, snapshot, now);
333
348
  recordViewerDeltas(this.state, state.runId, [...runViewerTargets(state, traceEvent), ...this.viewerInspectorTargets(state.runId)], now);
334
- this.syncContinuationIdentity(state);
335
349
  context.revision = revision;
336
350
  return;
337
351
  }
338
352
  const definitionHash = this.state.putJson(snapshot, now);
339
- const parentLineage = state.parentRunId === undefined
340
- ? undefined
341
- : this.state.connection
342
- .prepare(`SELECT root_run_id AS rootRunId, restart_number AS restartNumber
343
- FROM runs WHERE run_id = ?`)
344
- .get(state.parentRunId);
345
- if (state.parentRunId !== undefined && !isRunLineageRow(parentLineage)) {
346
- throw new Error(`Workflow parent run is missing: ${state.parentRunId}`);
353
+ if (state.parentRunId !== undefined) {
354
+ throw new Error("A restart must have an explicit host reservation");
347
355
  }
348
356
  this.state.connection
349
357
  .prepare(`INSERT INTO workflow_definitions(
@@ -368,15 +376,14 @@ export class WorkflowRunStore {
368
376
  this.state.connection
369
377
  .prepare(`INSERT INTO runs(
370
378
  run_id, resource_id, project_id, parent_run_id, root_run_id, lineage_kind,
371
- restart_number, parent_terminal_fingerprint, definition_digest,
379
+ restart_number, parent_run_revision, definition_digest,
372
380
  workflow_ref, launch_options_hash, title, status, paused,
373
381
  status_detail, input_hash, final_output_hash, error_hash,
374
382
  created_at, updated_at, finished_at
375
383
  ) VALUES (?, ?, NULL, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
376
- .run(state.runId, resourceId, state.parentRunId ?? null, isRunLineageRow(parentLineage) ? parentLineage.rootRunId : state.runId, state.parentRunId === undefined ? null : "continuation", isRunLineageRow(parentLineage) ? parentLineage.restartNumber : 0, definitionDigest, state.workflowName, launchOptionsHash, state.runTitle ?? null, state.status, state.paused === true ? 1 : 0, state.statusDetail ?? null, inputHash, finalOutputHash, errorHash, Date.parse(state.startedAt), now, state.finishedAt === undefined ? null : Date.parse(state.finishedAt));
384
+ .run(state.runId, resourceId, null, state.runId, null, 0, definitionDigest, state.workflowName, launchOptionsHash, state.runTitle ?? null, state.status, state.paused === true ? 1 : 0, state.statusDetail ?? null, inputHash, finalOutputHash, errorHash, Date.parse(state.startedAt), now, state.finishedAt === undefined ? null : Date.parse(state.finishedAt));
377
385
  initializeViewerRun(this.state, state.runId, now);
378
386
  this.insertRunSources(state.runId, source, state.workflowSources ?? []);
379
- this.syncContinuationIdentity(state);
380
387
  insertRunEvent(this.state, resourceId, 1, at, {
381
388
  scope: "run",
382
389
  type: "run_created",
@@ -396,7 +403,7 @@ export class WorkflowRunStore {
396
403
  const now = Date.now();
397
404
  return this.state.transaction(() => {
398
405
  this.requireRunAcceptsSettings(options.runId, false);
399
- const originRunId = this.logicalOriginRunId(options.runId);
406
+ const originRunId = options.runId;
400
407
  const scopeId = workflowSettingsScopeId(originRunId, options.mountPath, options.invocation);
401
408
  const existing = this.settingsScopeRow(scopeId);
402
409
  if (existing !== undefined) {
@@ -462,7 +469,7 @@ export class WorkflowRunStore {
462
469
  .map((row) => this.settingsScopeRecord(row));
463
470
  }
464
471
  settingsScopesForRunView(runId) {
465
- const originRunId = this.logicalOriginRunId(runId);
472
+ const originRunId = runId;
466
473
  return this.state.connection
467
474
  .prepare(`SELECT s.scope_id AS scopeId, s.resource_id AS resourceId,
468
475
  s.origin_run_id AS originRunId, s.active_run_id AS activeRunId,
@@ -478,7 +485,7 @@ export class WorkflowRunStore {
478
485
  .map((row) => this.settingsScopeRecord(row));
479
486
  }
480
487
  readSettingsScopeRange(runId, range) {
481
- const originRunId = this.logicalOriginRunId(runId);
488
+ const originRunId = runId;
482
489
  return this.state.connection
483
490
  .prepare(`SELECT s.scope_id AS scopeId, s.resource_id AS resourceId,
484
491
  s.origin_run_id AS originRunId, s.active_run_id AS activeRunId,
@@ -712,9 +719,29 @@ export class WorkflowRunStore {
712
719
  return { runId, originSessionId, followUps };
713
720
  }
714
721
  async prepareRunResume(runId) {
715
- const state = this.readRunState(runId);
722
+ let state = this.readRunState(runId);
716
723
  if (state === null)
717
724
  throw new Error(`Cannot resume unreadable workflow run: ${runId}`);
725
+ if (state.status === "waiting" && state.currentAttemptId !== undefined) {
726
+ const checkpoint = await this.readCheckpoint(runId, state.currentAttemptId);
727
+ if (checkpoint?.request.status === "settled") {
728
+ if (state.waitingOn === undefined)
729
+ throw new Error("Accepted checkpoint has no waiting node");
730
+ await this.commitTransition(runId, {
731
+ kind: "resumeInteraction",
732
+ event: {
733
+ scope: "node",
734
+ type: "interaction_accepted",
735
+ nodeId: state.waitingOn,
736
+ attemptId: state.currentAttemptId,
737
+ payload: { requestId: checkpoint.request.requestId },
738
+ },
739
+ });
740
+ state = this.readRunState(runId);
741
+ if (state === null)
742
+ throw new Error(`Workflow run became unreadable: ${runId}`);
743
+ }
744
+ }
718
745
  if (state.status !== "running") {
719
746
  throw new Error(`Cannot resume workflow run ${runId} with status ${state.status}`);
720
747
  }
@@ -764,27 +791,34 @@ export class WorkflowRunStore {
764
791
  delete loaded.state.currentNode;
765
792
  delete loaded.state.currentAttemptId;
766
793
  delete loaded.state.currentNodeStartedAt;
767
- delete loaded.state.currentNodeDeadlineAt;
794
+ delete loaded.state.currentNodeTimeoutMs;
795
+ delete loaded.state.currentNodeElapsedMs;
768
796
  delete loaded.state.currentSettingsScopeId;
769
797
  delete loaded.state.currentSettingsChangeNumber;
770
798
  delete loaded.state.currentSettingsHash;
771
799
  delete loaded.state.statusDetail;
772
800
  delete loaded.state.paused;
773
- await this.writeSnapshot(runId, loaded.state, {
801
+ await this.commitTransition(runId, executionTransition(loaded.state, {
774
802
  scope: "run",
775
803
  type: "run_interrupted",
776
804
  payload: { error: reason },
777
- });
805
+ }));
778
806
  return this.readRun(runId, { includeTrace: true });
779
807
  }
780
- async publishUpdate(runId, state, nodeId, attemptId, update, options = {}) {
781
- return await this.withRunLock(runId, async () => this.publishUpdateSynchronous(runId, state, nodeId, attemptId, update, options));
808
+ async publishUpdate(runId, nodeId, attemptId, update, options = {}) {
809
+ return await this.withRunLock(runId, async () => this.publishUpdateSynchronous(runId, nodeId, attemptId, update, options));
782
810
  }
783
811
  /** Server-only synchronous form for an already serialized command transaction. */
784
- publishUpdateSynchronous(runId, state, nodeId, attemptId, update, options = {}) {
812
+ publishUpdateSynchronous(runId, nodeId, attemptId, update, options = {}) {
785
813
  if (options.signal?.aborted === true) {
786
814
  throw options.signal.reason ?? new Error("workflow update attempt is no longer active");
787
815
  }
816
+ const state = this.readRunState(runId);
817
+ if (state === null ||
818
+ state.currentAttemptId !== attemptId ||
819
+ (state.currentNode ?? state.waitingOn) !== nodeId) {
820
+ throw new Error("Workflow update does not match the active attempt");
821
+ }
788
822
  const exists = (state.updates ?? []).some((record) => record.type === update.type && record.key === update.key);
789
823
  if (!exists && (state.updates?.length ?? 0) >= MAX_CURRENT_UPDATES) {
790
824
  throw new Error(`workflow run supports at most ${MAX_CURRENT_UPDATES} current updates`);
@@ -845,7 +879,7 @@ export class WorkflowRunStore {
845
879
  }
846
880
  return { event: acceptedEvent, record: acceptedRecord };
847
881
  }
848
- async writeSnapshot(runId, state, event) {
882
+ async commitTransition(runId, transition) {
849
883
  return await this.withRunLock(runId, async () => {
850
884
  let accepted;
851
885
  this.state.transaction(() => {
@@ -856,6 +890,62 @@ export class WorkflowRunStore {
856
890
  const now = Date.now();
857
891
  const at = new Date(now).toISOString();
858
892
  const snapshot = this.readDefinition(run.definitionHash);
893
+ const current = this.materializeRunState(run, snapshot);
894
+ const state = applyExecutionTransition(current, snapshot, transition, at);
895
+ if (transition.kind === "finishAttempt" &&
896
+ transition.step.nodeType === "checkpoint" &&
897
+ transition.step.outcome === "ok") {
898
+ const request = requestForAttempt(this.state, runId, transition.step.attemptId);
899
+ if (request === undefined ||
900
+ request.status !== "settled" ||
901
+ canonicalJson(acceptedRequestOutput(this.state, request)) !==
902
+ canonicalJson(transition.step.output)) {
903
+ throw new Error("Checkpoint completion requires its exact accepted response");
904
+ }
905
+ }
906
+ if (transition.kind === "waitForInput") {
907
+ const node = snapshot.nodes[transition.event.nodeId ?? ""];
908
+ if ((node?.humanDecision !== undefined) !== (transition.requestKind === "decision")) {
909
+ throw new Error("Checkpoint response authority does not match its definition");
910
+ }
911
+ if (transition.requestKind === "decision") {
912
+ const decision = transition.contract;
913
+ if (decision.runId !== runId ||
914
+ decision.attemptId !== transition.event.attemptId ||
915
+ decision.nodeId !== transition.event.nodeId ||
916
+ decision.decisionId !== transition.requestId) {
917
+ throw new Error("Human decision does not match the active checkpoint");
918
+ }
919
+ new HumanDecisionStore(this.databasePath, { state: this.state }).createRequest(decision);
920
+ }
921
+ const binding = this.state.connection
922
+ .prepare("SELECT origin_session_id AS sessionId FROM run_bindings WHERE run_id = ?")
923
+ .get(runId);
924
+ ensureWorkflowRequest(this.state, {
925
+ requestId: transition.requestId,
926
+ runId,
927
+ attemptId: transition.event.attemptId ?? "",
928
+ targetSessionId: binding?.sessionId ?? "",
929
+ kind: transition.requestKind,
930
+ contract: transition.contract,
931
+ }, now);
932
+ }
933
+ if (transition.kind === "resume" &&
934
+ transition.attemptId === undefined &&
935
+ current.currentAttemptId !== undefined) {
936
+ const request = this.state.connection
937
+ .prepare("SELECT 1 FROM interactive_requests WHERE attempt_id = ? AND status = 'pending'")
938
+ .get(current.currentAttemptId);
939
+ if (request !== undefined)
940
+ throw new Error("A pending request must resume its exact attempt");
941
+ const retired = this.state.connection
942
+ .prepare(`UPDATE node_attempts SET status = 'cancelled', finished_at = ?, updated_at = ?
943
+ WHERE attempt_id = ? AND run_id = ? AND status = 'interrupted'`)
944
+ .run(now, now, current.currentAttemptId, runId);
945
+ if (retired.changes !== 1)
946
+ throw new Error("Only an interrupted attempt can be replaced");
947
+ }
948
+ const event = transition.event;
859
949
  this.assertSettingsRouteCurrent(event, snapshot);
860
950
  const traceEvent = { seq: revision, at, runId, ...event };
861
951
  state.traceSeq = revision;
@@ -864,6 +954,13 @@ export class WorkflowRunStore {
864
954
  this.persistRunState(run, state, revision, now);
865
955
  this.transitionFollowUpsForRunState(state, event, now);
866
956
  this.syncNodeAttempts(state, snapshot, now);
957
+ if (transition.kind === "finishAttempt") {
958
+ this.state.connection
959
+ .prepare(`UPDATE interactive_requests SET consumed_at = ?, updated_at = ?
960
+ WHERE run_id = ? AND attempt_id = ? AND status = 'settled'
961
+ AND accepted_submission_id IS NOT NULL AND consumed_at IS NULL`)
962
+ .run(now, now, runId, transition.step.attemptId);
963
+ }
867
964
  recordViewerDeltas(this.state, runId, runViewerTargets(state, traceEvent), now);
868
965
  this.snapshotLifecycle?.({
869
966
  runId,
@@ -1274,15 +1371,6 @@ export class WorkflowRunStore {
1274
1371
  const row = this.readRunRow(runId);
1275
1372
  return row?.errorHash == null ? null : this.readText(row.errorHash);
1276
1373
  }
1277
- readPresentationInstructions(runId) {
1278
- const row = this.state.connection
1279
- .prepare("SELECT presentation_prompt_hash AS hash FROM runs WHERE run_id = ?")
1280
- .get(runId);
1281
- if (row?.hash == null) {
1282
- return "Explain the final workflow result to the user in a normal response.";
1283
- }
1284
- return this.readText(row.hash);
1285
- }
1286
1374
  readTerminalData(runId) {
1287
1375
  const row = this.state.connection
1288
1376
  .prepare(`SELECT status, status_detail AS statusDetail, restart_number AS restartNumber
@@ -1300,7 +1388,6 @@ export class WorkflowRunStore {
1300
1388
  input: this.readRunInput(runId),
1301
1389
  finalOutput: this.readRunFinalOutput(runId),
1302
1390
  error: this.readRunError(runId),
1303
- presentationInstructions: this.readPresentationInstructions(runId),
1304
1391
  restartNumber: row.restartNumber,
1305
1392
  };
1306
1393
  }
@@ -1310,6 +1397,15 @@ export class WorkflowRunStore {
1310
1397
  return null;
1311
1398
  return this.materializeRunState(row, this.readDefinition(row.definitionHash));
1312
1399
  }
1400
+ runRevision(runId) {
1401
+ const row = this.state.connection
1402
+ .prepare(`SELECT resources.revision FROM resources
1403
+ JOIN runs ON runs.resource_id = resources.resource_id WHERE runs.run_id = ?`)
1404
+ .get(runId);
1405
+ if (row === undefined)
1406
+ throw new Error(`Workflow run not found: ${runId}`);
1407
+ return row.revision;
1408
+ }
1313
1409
  readRun(runId, options = {}) {
1314
1410
  const row = this.readRunRow(runId);
1315
1411
  if (row === undefined)
@@ -1338,7 +1434,7 @@ export class WorkflowRunStore {
1338
1434
  if (row === undefined)
1339
1435
  return null;
1340
1436
  const segment = this.segmentRow(segmentIdFor(runId));
1341
- const settingsOrigin = this.logicalOriginRunId(runId);
1437
+ const settingsOrigin = runId;
1342
1438
  const scalar = (sql, ...params) => {
1343
1439
  const count = this.state.connection.prepare(sql).get(...params);
1344
1440
  return isCountRow(count) ? count.count : 0;
@@ -1637,7 +1733,10 @@ export class WorkflowRunStore {
1637
1733
  .run(state.runTitle ?? null, state.status, state.paused === true ? 1 : 0, state.statusDetail ?? null, finalOutputHash, errorHash, now, state.finishedAt === undefined ? null : Date.parse(state.finishedAt), state.runId);
1638
1734
  if (update.changes !== 1)
1639
1735
  throw new Error(`Workflow run is missing: ${state.runId}`);
1640
- if (state.status !== "running") {
1736
+ if (state.paused || ["completed", "failed", "cancelled"].includes(state.status)) {
1737
+ closeRunTime(this.state, state.runId);
1738
+ }
1739
+ if (state.status !== "running" && state.status !== run.status) {
1641
1740
  this.enqueueRunSettlementEffect(run.resourceId, expectedRevision, state, now);
1642
1741
  }
1643
1742
  }
@@ -1737,11 +1836,6 @@ export class WorkflowRunStore {
1737
1836
  ];
1738
1837
  }
1739
1838
  initializeRunSettingsAndFollowUps(state, initialSettings, now) {
1740
- if (state.parentRunId !== undefined) {
1741
- this.state.connection
1742
- .prepare(`UPDATE workflow_settings SET active_run_id = ?, updated_at = ? WHERE active_run_id = ?`)
1743
- .run(state.runId, now, state.parentRunId);
1744
- }
1745
1839
  const existing = this.state.connection
1746
1840
  .prepare("SELECT COUNT(*) AS count FROM workflow_settings WHERE active_run_id = ?")
1747
1841
  .get(state.runId);
@@ -1749,7 +1843,7 @@ export class WorkflowRunStore {
1749
1843
  if (hasSettings)
1750
1844
  return;
1751
1845
  for (const scope of initialSettings) {
1752
- const originRunId = this.logicalOriginRunId(state.runId);
1846
+ const originRunId = state.runId;
1753
1847
  const scopeId = workflowSettingsScopeId(originRunId, scope.mountPath, scope.invocation);
1754
1848
  const resourceId = this.mutations.ensureResource("settings", scopeId, now);
1755
1849
  const settingsHash = this.state.putJson(scope.settings, now);
@@ -1762,20 +1856,6 @@ export class WorkflowRunStore {
1762
1856
  .run(scopeId, resourceId, originRunId, state.runId, scope.mountPath, scope.invocation, settingsHash, settingsHash, now, now);
1763
1857
  }
1764
1858
  }
1765
- logicalOriginRunId(runId) {
1766
- let current = runId;
1767
- for (let depth = 0; depth < 100; depth += 1) {
1768
- const row = this.state.connection
1769
- .prepare("SELECT parent_run_id AS parentRunId FROM runs WHERE run_id = ?")
1770
- .get(current);
1771
- if (!isParentRunRow(row))
1772
- return current;
1773
- if (row.parentRunId === null)
1774
- return current;
1775
- current = row.parentRunId;
1776
- }
1777
- throw new Error(`Workflow continuation chain is too deep for run ${runId}`);
1778
- }
1779
1859
  requireRunAcceptsSettings(runId, allowWaiting) {
1780
1860
  const row = this.state.connection
1781
1861
  .prepare("SELECT status FROM runs WHERE run_id = ?")
@@ -1982,15 +2062,7 @@ export class WorkflowRunStore {
1982
2062
  }
1983
2063
  const rows = this.state.connection
1984
2064
  .prepare(`${FOLLOW_UP_ROW_SELECT}
1985
- WHERE f.run_id IN (
1986
- WITH RECURSIVE ancestors(run_id, parent_run_id) AS (
1987
- SELECT run_id, parent_run_id FROM runs WHERE run_id = ?
1988
- UNION ALL
1989
- SELECT parent.run_id, parent.parent_run_id
1990
- FROM runs parent JOIN ancestors ON ancestors.parent_run_id = parent.run_id
1991
- )
1992
- SELECT run_id FROM ancestors
1993
- ) AND f.status = 'queued'`)
2065
+ WHERE f.run_id = ? AND f.status = 'queued'`)
1994
2066
  .all(state.runId)
1995
2067
  .filter(isFollowUpRow);
1996
2068
  for (const row of rows) {
@@ -2009,7 +2081,8 @@ export class WorkflowRunStore {
2009
2081
  }
2010
2082
  }
2011
2083
  syncNodeAttempts(state, snapshot, now) {
2012
- for (const step of state.steps.slice(state.carriedStepCount ?? 0)) {
2084
+ for (const step of state.steps) {
2085
+ closeAttemptTime(this.state, step.attemptId);
2013
2086
  const promptEntryId = this.findAttemptPromptEntry(state.runId, step.attemptId);
2014
2087
  const promptHash = promptEntryId === undefined && step.prompt !== null
2015
2088
  ? this.state.putText(step.prompt, now)
@@ -2049,21 +2122,17 @@ export class WorkflowRunStore {
2049
2122
  }
2050
2123
  if (state.currentAttemptId !== undefined && state.currentNode !== undefined) {
2051
2124
  this.ensureAttempt(state, state.currentNode, state.currentAttemptId, now, snapshot);
2052
- if (state.currentNodeDeadlineAt !== undefined) {
2053
- const deadlineAt = state.currentNodeDeadlineAt === null ? null : Date.parse(state.currentNodeDeadlineAt);
2054
- if (deadlineAt !== null && !Number.isFinite(deadlineAt)) {
2055
- throw new Error("Workflow node deadline is invalid");
2056
- }
2125
+ if (state.currentNodeTimeoutMs !== undefined) {
2057
2126
  this.state.connection
2058
- .prepare(`UPDATE node_attempts SET deadline_at = ?, updated_at = ?
2059
- WHERE attempt_id = ? AND run_id = ?
2127
+ .prepare(`UPDATE node_attempts SET timeout_ms = ?, updated_at = ?
2128
+ WHERE attempt_id = ? AND run_id = ? AND timeout_ms IS NULL
2060
2129
  AND status IN ('pending', 'running', 'waiting', 'interrupted')`)
2061
- .run(deadlineAt, now, state.currentAttemptId, state.runId);
2130
+ .run(state.currentNodeTimeoutMs ?? 0, now, state.currentAttemptId, state.runId);
2062
2131
  }
2063
2132
  }
2064
- this.syncRunSteps(state, now);
2133
+ this.syncRunSteps(state);
2065
2134
  }
2066
- syncRunSteps(state, now) {
2135
+ syncRunSteps(state) {
2067
2136
  const existingRows = this.state.connection
2068
2137
  .prepare(`SELECT step_index AS stepIndex, attempt_id AS attemptId
2069
2138
  FROM run_steps WHERE run_id = ? ORDER BY step_index`)
@@ -2082,15 +2151,15 @@ export class WorkflowRunStore {
2082
2151
  /* istanbul ignore if -- array index follows a checked bound */
2083
2152
  if (step === undefined)
2084
2153
  throw new Error("Workflow run step became unavailable");
2085
- const attemptOutput = this.readAttemptOutput(step.attemptId);
2086
- const carried = stepIndex < (state.carriedStepCount ?? 0);
2087
- const outputOverrideHash = carried && canonicalJson(attemptOutput) !== canonicalJson(step.output)
2088
- ? this.state.putJson(step.output, now)
2089
- : null;
2154
+ const attempt = this.state.connection
2155
+ .prepare("SELECT run_id AS runId FROM node_attempts WHERE attempt_id = ?")
2156
+ .get(step.attemptId);
2157
+ if (attempt?.runId !== state.runId)
2158
+ throw new Error("A run cannot own another run's step");
2090
2159
  this.state.connection
2091
- .prepare(`INSERT INTO run_steps(run_id, step_index, attempt_id, output_override_hash)
2092
- VALUES (?, ?, ?, ?)`)
2093
- .run(state.runId, stepIndex, step.attemptId, outputOverrideHash);
2160
+ .prepare(`INSERT INTO run_steps(run_id, step_index, attempt_id)
2161
+ VALUES (?, ?, ?)`)
2162
+ .run(state.runId, stepIndex, step.attemptId);
2094
2163
  }
2095
2164
  }
2096
2165
  syncAttemptEntries(runId, step, promptEntryId) {
@@ -2145,26 +2214,6 @@ export class WorkflowRunStore {
2145
2214
  .get(runId, attemptId);
2146
2215
  return isEntryIdentityRow(row) ? row.entryId : undefined;
2147
2216
  }
2148
- readAttemptOutput(attemptId) {
2149
- const row = this.state.connection
2150
- .prepare(`SELECT a.output_hash AS outputHash, a.receipt_hash AS receiptHash,
2151
- e.entry_hash AS responseEntryHash
2152
- FROM node_attempts a
2153
- LEFT JOIN attempt_entries l ON l.attempt_id = a.attempt_id AND l.role = 'response'
2154
- LEFT JOIN session_entries e
2155
- ON e.segment_id = l.segment_id AND e.entry_id = l.entry_id
2156
- WHERE a.attempt_id = ?`)
2157
- .get(attemptId);
2158
- if (!isAttemptValueRow(row)) {
2159
- throw new Error(`Workflow node attempt is missing: ${attemptId}`);
2160
- }
2161
- if (row.outputHash !== null)
2162
- return this.state.readJson(row.outputHash);
2163
- if (row.responseEntryHash === null)
2164
- return null;
2165
- const receipt = row.receiptHash === null ? {} : this.readJsonAs(row.receiptHash);
2166
- return assistantOutputFromEntry(this.state.readJson(row.responseEntryHash), receipt.assistantMessage?.maxChars);
2167
- }
2168
2217
  ensureAttempt(state, nodeId, attemptId, now, snapshot) {
2169
2218
  const existing = this.state.connection
2170
2219
  .prepare("SELECT attempt_id AS attemptId FROM node_attempts WHERE attempt_id = ?")
@@ -2227,28 +2276,6 @@ export class WorkflowRunStore {
2227
2276
  insert.run(runId, item.mountPath.join("/"), source.type, source.ref, source.revision);
2228
2277
  }
2229
2278
  }
2230
- syncContinuationIdentity(state) {
2231
- if (state.parentRunId === undefined || state.humanDecision === undefined)
2232
- return;
2233
- const createdAt = Date.parse(state.humanDecision.acceptedAt);
2234
- this.state.connection
2235
- .prepare(`INSERT INTO continuations(
2236
- decision_id, parent_run_id, continuation_run_id, created_at
2237
- ) VALUES (?, ?, ?, ?)
2238
- ON CONFLICT(decision_id) DO NOTHING`)
2239
- .run(state.humanDecision.decisionId, state.parentRunId, state.runId, createdAt);
2240
- const row = this.state.connection
2241
- .prepare(`SELECT parent_run_id AS parentRunId, continuation_run_id AS continuationRunId,
2242
- created_at AS createdAt
2243
- FROM continuations WHERE decision_id = ?`)
2244
- .get(state.humanDecision.decisionId);
2245
- if (!isContinuationIdentityRow(row) ||
2246
- row.parentRunId !== state.parentRunId ||
2247
- row.continuationRunId !== state.runId ||
2248
- row.createdAt !== createdAt) {
2249
- throw new Error("Immutable human decision continuation conflicts");
2250
- }
2251
- }
2252
2279
  readRunRow(runId) {
2253
2280
  const row = this.state.connection
2254
2281
  .prepare(`SELECT r.run_id AS runId, r.resource_id AS resourceId,
@@ -2276,7 +2303,6 @@ export class WorkflowRunStore {
2276
2303
  }
2277
2304
  buildRunState(row, snapshot, projectionSteps, visibleSteps, visibleUpdates) {
2278
2305
  const sources = this.readRunSources(row.runId, snapshot);
2279
- const carriedStepCount = this.carriedStepCount(row.runId);
2280
2306
  const activeAttempt = row.status === "running" || row.status === "waiting"
2281
2307
  ? this.readActiveAttempt(row.runId)
2282
2308
  : undefined;
@@ -2310,13 +2336,10 @@ export class WorkflowRunStore {
2310
2336
  runId: row.runId,
2311
2337
  workflowName: row.workflowRef,
2312
2338
  ...(row.parentRunId === null ? {} : { parentRunId: row.parentRunId }),
2313
- ...(carriedStepCount === 0 ? {} : { carriedStepCount }),
2314
2339
  ...(row.title === null ? {} : { runTitle: row.title }),
2315
2340
  ...(sources.root === undefined ? {} : { workflowSource: sources.root }),
2316
2341
  ...(sources.mounted.length === 0 ? {} : { workflowSources: sources.mounted }),
2317
- ...(sources.mounted.length !== 0 || snapshot.composition?.mounts.length
2318
- ? { definitionDigest: `sha256:${row.definitionDigest.toString("hex")}` }
2319
- : {}),
2342
+ definitionDigest: `sha256:${row.definitionDigest.toString("hex")}`,
2320
2343
  startedAt: new Date(row.createdAt).toISOString(),
2321
2344
  ...(row.finishedAt === null ? {} : { finishedAt: new Date(row.finishedAt).toISOString() }),
2322
2345
  updatedAt: new Date(row.updatedAt).toISOString(),
@@ -2331,12 +2354,11 @@ export class WorkflowRunStore {
2331
2354
  ...(activeAttempt?.startedAt === null || activeAttempt === undefined
2332
2355
  ? {}
2333
2356
  : { currentNodeStartedAt: new Date(activeAttempt.startedAt).toISOString() }),
2334
- ...(activeAttempt === undefined
2357
+ ...(activeAttempt === undefined || activeAttempt.timeoutMs === null
2335
2358
  ? {}
2336
2359
  : {
2337
- currentNodeDeadlineAt: activeAttempt.deadlineAt === null
2338
- ? null
2339
- : new Date(activeAttempt.deadlineAt).toISOString(),
2360
+ currentNodeTimeoutMs: activeAttempt.timeoutMs === 0 ? null : activeAttempt.timeoutMs,
2361
+ currentNodeElapsedMs: activeAttempt.activeElapsedMs,
2340
2362
  }),
2341
2363
  ...savedCurrentSettingsBinding(activeAttempt?.settingsScopeId ?? null, activeAttempt?.settingsChangeNumber ?? null, activeAttempt?.settingsHash ?? null),
2342
2364
  ...(row.statusDetail === null ? {} : { statusDetail: row.statusDetail }),
@@ -2402,7 +2424,7 @@ export class WorkflowRunStore {
2402
2424
  : row.promptHash === null
2403
2425
  ? null
2404
2426
  : this.readText(row.promptHash);
2405
- const outputHash = row.outputOverrideHash ?? row.outputHash;
2427
+ const outputHash = row.outputHash;
2406
2428
  const output = outputHash !== null
2407
2429
  ? this.state.readJson(outputHash)
2408
2430
  : row.responseEntryHash === null
@@ -2453,18 +2475,13 @@ export class WorkflowRunStore {
2453
2475
  }));
2454
2476
  return { ...(root === undefined ? {} : { root }), mounted };
2455
2477
  }
2456
- carriedStepCount(runId) {
2457
- const row = this.state.connection
2458
- .prepare(`SELECT count(*) AS count
2459
- FROM run_steps s JOIN node_attempts a ON a.attempt_id = s.attempt_id
2460
- WHERE s.run_id = ? AND a.run_id <> s.run_id`)
2461
- .get(runId);
2462
- return isCountRow(row) ? row.count : 0;
2463
- }
2464
2478
  readActiveAttempt(runId) {
2465
2479
  const row = this.state.connection
2466
2480
  .prepare(`SELECT attempt_id AS attemptId, node_id AS nodeId, started_at AS startedAt,
2467
- deadline_at AS deadlineAt, settings_scope_id AS settingsScopeId,
2481
+ timeout_ms AS timeoutMs,
2482
+ (SELECT COALESCE(SUM(elapsed_ms), 0) FROM attempt_active_intervals i
2483
+ WHERE i.attempt_id = node_attempts.attempt_id) AS activeElapsedMs,
2484
+ settings_scope_id AS settingsScopeId,
2468
2485
  settings_change_number AS settingsChangeNumber,
2469
2486
  settings_hash AS settingsHash
2470
2487
  FROM node_attempts
@@ -2472,14 +2489,14 @@ export class WorkflowRunStore {
2472
2489
  .get(runId);
2473
2490
  return isActiveAttemptRow(row) ? row : undefined;
2474
2491
  }
2475
- readHumanDecisionReceipt(runId) {
2492
+ readHumanDecisionReceipt(runId, decisionId) {
2476
2493
  const row = this.state.connection
2477
2494
  .prepare(`SELECT d.request_hash AS requestHash, r.response_hash AS responseHash
2478
- FROM continuations c
2479
- JOIN human_decisions d ON d.decision_id = c.decision_id
2480
- JOIN human_decision_resolutions r ON r.decision_id = c.decision_id
2481
- WHERE c.continuation_run_id = ? AND r.outcome = 'accepted'`)
2482
- .get(runId);
2495
+ FROM human_decisions d
2496
+ JOIN human_decision_resolutions r ON r.decision_id = d.decision_id
2497
+ WHERE d.run_id = ? AND r.outcome = 'accepted' AND (? IS NULL OR d.decision_id = ?)
2498
+ ORDER BY r.resolved_at DESC, d.decision_id DESC LIMIT 1`)
2499
+ .get(runId, decisionId ?? null, decisionId ?? null);
2483
2500
  if (!isDecisionReceiptRow(row))
2484
2501
  return undefined;
2485
2502
  const request = this.readJsonAs(row.requestHash);
@@ -2823,8 +2840,8 @@ function runViewerTargets(state, traceEvent) {
2823
2840
  },
2824
2841
  {
2825
2842
  op: "add",
2826
- path: "/state/currentNodeDeadlineAt",
2827
- value: state.currentNodeDeadlineAt ?? null,
2843
+ path: "/state/currentNodeTimeoutMs",
2844
+ value: state.currentNodeTimeoutMs ?? null,
2828
2845
  },
2829
2846
  {
2830
2847
  op: "add",
@@ -3241,14 +3258,6 @@ function isFollowUpRow(value) {
3241
3258
  typeof value.updatedAt === "number" &&
3242
3259
  typeof value.revision === "number");
3243
3260
  }
3244
- function isParentRunRow(value) {
3245
- return isRecord(value) && (typeof value.parentRunId === "string" || value.parentRunId === null);
3246
- }
3247
- function isRunLineageRow(value) {
3248
- return (isRecord(value) &&
3249
- typeof value.rootRunId === "string" &&
3250
- typeof value.restartNumber === "number");
3251
- }
3252
3261
  function isStatusRow(value) {
3253
3262
  return isRecord(value) && typeof value.status === "string";
3254
3263
  }
@@ -3350,18 +3359,12 @@ function isSegmentIdentityRow(value) {
3350
3359
  function isEntryIdentityRow(value) {
3351
3360
  return isRecord(value) && typeof value.entryId === "string";
3352
3361
  }
3353
- function isAttemptValueRow(value) {
3354
- return isRecord(value);
3355
- }
3356
3362
  function isActiveAttemptRow(value) {
3357
3363
  return isRecord(value);
3358
3364
  }
3359
3365
  function isDecisionReceiptRow(value) {
3360
3366
  return (isRecord(value) && Buffer.isBuffer(value.requestHash) && Buffer.isBuffer(value.responseHash));
3361
3367
  }
3362
- function isContinuationIdentityRow(value) {
3363
- return isRecord(value);
3364
- }
3365
3368
  function isUpdateRow(value) {
3366
3369
  return isRecord(value);
3367
3370
  }