@earendil-works/pi-durable 1.4.0 → 1.5.0

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 (221) hide show
  1. package/CHANGELOG.md +186 -0
  2. package/README.md +181 -84
  3. package/dist/codemode/codemode.d.ts +4 -4
  4. package/dist/codemode/codemode.d.ts.map +1 -1
  5. package/dist/codemode/codemode.js +9 -12
  6. package/dist/codemode/codemode.js.map +1 -1
  7. package/dist/codemode/models.js +4 -4
  8. package/dist/codemode/models.js.map +1 -1
  9. package/dist/env/index.d.ts +12 -10
  10. package/dist/env/index.d.ts.map +1 -1
  11. package/dist/env/index.js.map +1 -1
  12. package/dist/env/node-watch.d.ts +3 -3
  13. package/dist/env/node-watch.d.ts.map +1 -1
  14. package/dist/env/node-watch.js +18 -16
  15. package/dist/env/node-watch.js.map +1 -1
  16. package/dist/env/node.d.ts +2 -2
  17. package/dist/env/node.d.ts.map +1 -1
  18. package/dist/env/node.js +1 -1
  19. package/dist/env/node.js.map +1 -1
  20. package/dist/errors.d.ts +18 -2
  21. package/dist/errors.d.ts.map +1 -1
  22. package/dist/errors.js +26 -3
  23. package/dist/errors.js.map +1 -1
  24. package/dist/harness/agent.d.ts.map +1 -1
  25. package/dist/harness/agent.js +10 -2
  26. package/dist/harness/agent.js.map +1 -1
  27. package/dist/harness/compaction.d.ts.map +1 -1
  28. package/dist/harness/compaction.js +19 -2
  29. package/dist/harness/compaction.js.map +1 -1
  30. package/dist/harness/context.d.ts +23 -7
  31. package/dist/harness/context.d.ts.map +1 -1
  32. package/dist/harness/context.js +71 -25
  33. package/dist/harness/context.js.map +1 -1
  34. package/dist/harness/define.d.ts +7 -3
  35. package/dist/harness/define.d.ts.map +1 -1
  36. package/dist/harness/define.js +4 -0
  37. package/dist/harness/define.js.map +1 -1
  38. package/dist/harness/generation.d.ts +38 -5
  39. package/dist/harness/generation.d.ts.map +1 -1
  40. package/dist/harness/generation.js +445 -96
  41. package/dist/harness/generation.js.map +1 -1
  42. package/dist/harness/harness.d.ts +2 -0
  43. package/dist/harness/harness.d.ts.map +1 -1
  44. package/dist/harness/harness.js +87 -62
  45. package/dist/harness/harness.js.map +1 -1
  46. package/dist/harness/inbox.d.ts +5 -1
  47. package/dist/harness/inbox.d.ts.map +1 -1
  48. package/dist/harness/inbox.js +4 -1
  49. package/dist/harness/inbox.js.map +1 -1
  50. package/dist/harness/json.d.ts +20 -4
  51. package/dist/harness/json.d.ts.map +1 -1
  52. package/dist/harness/json.js +23 -5
  53. package/dist/harness/json.js.map +1 -1
  54. package/dist/harness/live.d.ts +122 -16
  55. package/dist/harness/live.d.ts.map +1 -1
  56. package/dist/harness/live.js +93 -12
  57. package/dist/harness/live.js.map +1 -1
  58. package/dist/harness/partial-changes.d.ts +54 -0
  59. package/dist/harness/partial-changes.d.ts.map +1 -0
  60. package/dist/harness/partial-changes.js +162 -0
  61. package/dist/harness/partial-changes.js.map +1 -0
  62. package/dist/harness/registry-reader.d.ts +11 -0
  63. package/dist/harness/registry-reader.d.ts.map +1 -0
  64. package/dist/harness/registry-reader.js +25 -0
  65. package/dist/harness/registry-reader.js.map +1 -0
  66. package/dist/harness/scheduler.d.ts +46 -19
  67. package/dist/harness/scheduler.d.ts.map +1 -1
  68. package/dist/harness/scheduler.js +973 -376
  69. package/dist/harness/scheduler.js.map +1 -1
  70. package/dist/harness/submissions.d.ts +17 -10
  71. package/dist/harness/submissions.d.ts.map +1 -1
  72. package/dist/harness/submissions.js +62 -25
  73. package/dist/harness/submissions.js.map +1 -1
  74. package/dist/harness/task-graph.d.ts +12 -9
  75. package/dist/harness/task-graph.d.ts.map +1 -1
  76. package/dist/harness/task-graph.js +38 -28
  77. package/dist/harness/task-graph.js.map +1 -1
  78. package/dist/harness/telemetry.d.ts +11 -11
  79. package/dist/harness/telemetry.d.ts.map +1 -1
  80. package/dist/harness/telemetry.js +7 -7
  81. package/dist/harness/telemetry.js.map +1 -1
  82. package/dist/harness/tool.d.ts +2 -0
  83. package/dist/harness/tool.d.ts.map +1 -1
  84. package/dist/harness/tool.js +171 -55
  85. package/dist/harness/tool.js.map +1 -1
  86. package/dist/harness/transcript.d.ts +72 -0
  87. package/dist/harness/transcript.d.ts.map +1 -0
  88. package/dist/harness/transcript.js +264 -0
  89. package/dist/harness/transcript.js.map +1 -0
  90. package/dist/harness/types.d.ts +218 -59
  91. package/dist/harness/types.d.ts.map +1 -1
  92. package/dist/harness/types.js.map +1 -1
  93. package/dist/harness/util.d.ts +3 -1
  94. package/dist/harness/util.d.ts.map +1 -1
  95. package/dist/harness/util.js +9 -0
  96. package/dist/harness/util.js.map +1 -1
  97. package/dist/harness/view.d.ts +43 -22
  98. package/dist/harness/view.d.ts.map +1 -1
  99. package/dist/harness/view.js +130 -71
  100. package/dist/harness/view.js.map +1 -1
  101. package/dist/index.d.ts +9 -7
  102. package/dist/index.d.ts.map +1 -1
  103. package/dist/index.js +4 -3
  104. package/dist/index.js.map +1 -1
  105. package/dist/search.d.ts +19 -3
  106. package/dist/search.d.ts.map +1 -1
  107. package/dist/search.js +107 -44
  108. package/dist/search.js.map +1 -1
  109. package/dist/session/cached-storage.d.ts +71 -0
  110. package/dist/session/cached-storage.d.ts.map +1 -0
  111. package/dist/session/cached-storage.js +269 -0
  112. package/dist/session/cached-storage.js.map +1 -0
  113. package/dist/session/conversation-tails.d.ts +33 -0
  114. package/dist/session/conversation-tails.d.ts.map +1 -0
  115. package/dist/session/conversation-tails.js +101 -0
  116. package/dist/session/conversation-tails.js.map +1 -0
  117. package/dist/session/keys.d.ts +68 -0
  118. package/dist/session/keys.d.ts.map +1 -0
  119. package/dist/session/keys.js +161 -0
  120. package/dist/session/keys.js.map +1 -0
  121. package/dist/session/session.d.ts +167 -26
  122. package/dist/session/session.d.ts.map +1 -1
  123. package/dist/session/session.js +1029 -171
  124. package/dist/session/session.js.map +1 -1
  125. package/dist/session/transaction.d.ts +81 -3
  126. package/dist/session/transaction.d.ts.map +1 -1
  127. package/dist/session/transaction.js +224 -37
  128. package/dist/session/transaction.js.map +1 -1
  129. package/dist/session/writer.d.ts +74 -0
  130. package/dist/session/writer.d.ts.map +1 -0
  131. package/dist/session/writer.js +294 -0
  132. package/dist/session/writer.js.map +1 -0
  133. package/dist/storage/indexeddb.d.ts +10 -2
  134. package/dist/storage/indexeddb.d.ts.map +1 -1
  135. package/dist/storage/indexeddb.js +91 -41
  136. package/dist/storage/indexeddb.js.map +1 -1
  137. package/dist/storage/jsonl/storage.d.ts +14 -2
  138. package/dist/storage/jsonl/storage.d.ts.map +1 -1
  139. package/dist/storage/jsonl/storage.js +88 -24
  140. package/dist/storage/jsonl/storage.js.map +1 -1
  141. package/dist/storage/memory.d.ts +7 -2
  142. package/dist/storage/memory.d.ts.map +1 -1
  143. package/dist/storage/memory.js +28 -2
  144. package/dist/storage/memory.js.map +1 -1
  145. package/dist/storage/sqlite/storage.d.ts +14 -2
  146. package/dist/storage/sqlite/storage.d.ts.map +1 -1
  147. package/dist/storage/sqlite/storage.js +110 -36
  148. package/dist/storage/sqlite/storage.js.map +1 -1
  149. package/dist/storage/store/commit.d.ts +33 -0
  150. package/dist/storage/store/commit.d.ts.map +1 -0
  151. package/dist/storage/store/commit.js +286 -0
  152. package/dist/storage/store/commit.js.map +1 -0
  153. package/dist/storage/store/documents.d.ts +43 -0
  154. package/dist/storage/store/documents.d.ts.map +1 -0
  155. package/dist/storage/store/documents.js +102 -0
  156. package/dist/storage/store/documents.js.map +1 -0
  157. package/dist/storage/store/index.d.ts +2 -0
  158. package/dist/storage/store/index.d.ts.map +1 -0
  159. package/dist/storage/store/index.js +2 -0
  160. package/dist/storage/store/index.js.map +1 -0
  161. package/dist/storage/store/queries.d.ts +49 -0
  162. package/dist/storage/store/queries.d.ts.map +1 -0
  163. package/dist/storage/store/queries.js +93 -0
  164. package/dist/storage/store/queries.js.map +1 -0
  165. package/dist/storage/store/storage.d.ts +59 -0
  166. package/dist/storage/store/storage.d.ts.map +1 -0
  167. package/dist/storage/store/storage.js +438 -0
  168. package/dist/storage/store/storage.js.map +1 -0
  169. package/dist/storage/store/tables.d.ts +54 -0
  170. package/dist/storage/store/tables.d.ts.map +1 -0
  171. package/dist/storage/store/tables.js +108 -0
  172. package/dist/storage/store/tables.js.map +1 -0
  173. package/dist/testing/commit-writes.d.ts +5 -0
  174. package/dist/testing/commit-writes.d.ts.map +1 -0
  175. package/dist/testing/commit-writes.js +12 -0
  176. package/dist/testing/commit-writes.js.map +1 -0
  177. package/dist/testing/env-conformance.js +7 -7
  178. package/dist/testing/env-conformance.js.map +1 -1
  179. package/dist/testing/index.d.ts +1 -0
  180. package/dist/testing/index.d.ts.map +1 -1
  181. package/dist/testing/index.js +1 -0
  182. package/dist/testing/index.js.map +1 -1
  183. package/dist/testing/storage-benchmark.d.ts.map +1 -1
  184. package/dist/testing/storage-benchmark.js +18 -17
  185. package/dist/testing/storage-benchmark.js.map +1 -1
  186. package/dist/testing/storage-conformance.d.ts.map +1 -1
  187. package/dist/testing/storage-conformance.js +354 -69
  188. package/dist/testing/storage-conformance.js.map +1 -1
  189. package/dist/tool-search/tool-search.d.ts +6 -12
  190. package/dist/tool-search/tool-search.d.ts.map +1 -1
  191. package/dist/tool-search/tool-search.js +7 -7
  192. package/dist/tool-search/tool-search.js.map +1 -1
  193. package/dist/tools/bash.d.ts +12 -12
  194. package/dist/tools/bash.d.ts.map +1 -1
  195. package/dist/tools/bash.js +16 -15
  196. package/dist/tools/bash.js.map +1 -1
  197. package/dist/tools/edit.d.ts +7 -7
  198. package/dist/tools/edit.d.ts.map +1 -1
  199. package/dist/tools/edit.js +9 -9
  200. package/dist/tools/edit.js.map +1 -1
  201. package/dist/tools/index.d.ts +32 -32
  202. package/dist/tools/read.d.ts +6 -6
  203. package/dist/tools/read.d.ts.map +1 -1
  204. package/dist/tools/read.js +19 -8
  205. package/dist/tools/read.js.map +1 -1
  206. package/dist/tools/write.d.ts +4 -4
  207. package/dist/tools/write.d.ts.map +1 -1
  208. package/dist/tools/write.js +5 -5
  209. package/dist/tools/write.js.map +1 -1
  210. package/dist/types.d.ts +223 -77
  211. package/dist/types.d.ts.map +1 -1
  212. package/dist/types.js.map +1 -1
  213. package/package.json +19 -12
  214. package/dist/harness/events.d.ts +0 -186
  215. package/dist/harness/events.d.ts.map +0 -1
  216. package/dist/harness/events.js +0 -373
  217. package/dist/harness/events.js.map +0 -1
  218. package/dist/session/observation.d.ts +0 -42
  219. package/dist/session/observation.d.ts.map +0 -1
  220. package/dist/session/observation.js +0 -281
  221. package/dist/session/observation.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"live.js","sourceRoot":"","sources":["../../src/harness/live.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Draft, JsonRepresentation, JsonValue } from \"@earendil-works/chord\";\nimport type { AssistantMessage, Usage } from \"@earendil-works/pi-ai\";\nimport { defineDoc } from \"../documents.ts\";\nimport type { Transaction } from \"../session/transaction.ts\";\nimport type { EntryId, JsonObject, SubmissionId, SubmissionSettlement, TaskId, TaskRecord, Tx } from \"../types.ts\";\nimport { convertPartial } from \"./generation.ts\";\nimport type { SchedulerOutcome } from \"./scheduler.ts\";\nimport type { CompactionReason, CompactionResult, ToolDiagnostic } from \"./types.ts\";\n\n/** What a running tool call publishes, shared by model-issued and nested calls. */\ntype SlotProgress = {\n\tcallId: string;\n\tname: string;\n\tstatus: \"pending\" | \"running\" | \"done\";\n\t/** Retained running output and what the bounds dropped. */\n\toutput?: string;\n\tdroppedBytes?: number;\n\tdroppedLines?: number;\n\t/** Last `details()` value. */\n\tdetails?: JsonValue;\n\t/** Diagnostics recorded through `api.diagnostic()`. */\n\tdiagnostics?: ToolDiagnostic[];\n};\n\n/** Presentation of one tool call of the current round. */\nexport type ToolSlot = SlotProgress & {\n\t/**\n\t * Absent for a call not started yet (sequential round) and for a call its request did not offer, which starts `done`\n\t * with the `entry` generation wrote.\n\t */\n\ttaskId?: TaskId;\n\t/** Result entry once done; absent when the tool task faulted or was orphaned. */\n\tentry?: EntryId;\n};\n\n/**\n * Presentation of one nested call: a call a running tool made through `executeTool()`. `callId` is\n * `<parentCallId>/<key>`, the call's ID in tool events and unique because keys contain no `/`. The Harness relates\n * slots by task ID: `taskId` is the call's tool task, `parentTaskId` the calling one, model-issued or nested.\n */\nexport type NestedToolSlot = SlotProgress & {\n\tparentCallId: string;\n\tparentTaskId: TaskId;\n\ttaskId: TaskId;\n\t/**\n\t * What the call was made with, replaced by the arguments it runs with, after repair, `beforeTool`, and coercion,\n\t * once it starts executing. A model-issued call's arguments are in its assistant entry instead.\n\t */\n\targuments: JsonObject;\n\t/** Once done: how the call ended, for a status line. The result itself is in the caller's `NestedCallDoc`. */\n\tsummary?: NestedToolSummary;\n};\n\n/** How a nested call ended: an error flag, its execution time, its spend, and up to 500 characters of error text. */\nexport type NestedToolSummary = {\n\tisError: boolean;\n\tdurationMs?: number;\n\tusage?: JsonRepresentation<Usage>;\n\terror?: string;\n};\n\n/** Presentation of one live compaction task (spec §8.7). */\nexport type CompactionStatus = {\n\ttaskId: TaskId<CompactionResult>;\n\treason: CompactionReason;\n\t/** Whether a generation waits for it: a compaction the generation owns. */\n\tblocking: boolean;\n\tattempt: number;\n\t/** Durable backoff before the next summarization attempt. */\n\tretry?: { at: number; error: string };\n};\n\n/** The newest compaction that failed since a compaction last produced a summary (spec §8.7). */\nexport type CompactionFailure = {\n\ttaskId: TaskId<CompactionResult>;\n\treason: CompactionReason;\n\t/** The failed or faulted outcome's error message, or why the scheduler orphaned the task. */\n\terror: string;\n};\n\n/** Built-in live conversation state: run control and presentation of the current generation and tool round. */\nexport type LiveState = {\n\t/** Run control: the task that settles the run's inputs, and those inputs; present exactly while busy. */\n\trun?: { taskId: TaskId; inputs: SubmissionId[] };\n\t/** Presentation of the current generation attempt. */\n\tgeneration?: {\n\t\tattempt: number;\n\t\t/** Committed throttled partial of the in-flight response. */\n\t\tmessage?: JsonRepresentation<AssistantMessage>;\n\t\t/** Durable backoff before the next attempt. */\n\t\tretry?: { at: number; error: string };\n\t\t/** Provider-side deferred response being polled. */\n\t\tdeferred?: { pollAt: number };\n\t};\n\t/** The current tool round in call order, from the tool-calling answer until the generation's `tools` phase ends it. */\n\ttools?: ToolSlot[];\n\t/**\n\t * Nested calls of running tool calls, in creation order, so a parent precedes its children and task IDs ascend. A\n\t * call's nested slots are removed when the call settles.\n\t */\n\tnestedTools?: NestedToolSlot[];\n\t/** Live compaction tasks in task ID order; absent when none. */\n\tcompactions?: CompactionStatus[];\n\t/**\n\t * The newest compaction failure, so a client can show it after the task ended. A compaction that produces a summary\n\t * removes it; one that is aborted or finds nothing to compact leaves it.\n\t */\n\tcompactionFailure?: CompactionFailure;\n};\n\nexport const LiveDoc = defineDoc<LiveState>({\n\tkind: \"pi.live\",\n\tversion: 1,\n\tscope: \"conversation\",\n\thistory: \"latest\",\n\tfork: \"initial\",\n\tinitial: () => ({}),\n\t// REMINDER: a complete base whenever nothing runs (spec §8.2): no generation and no running tool slot. That holds\n\t// while idle, in the commit handing a generation over to its tool round, and between tools, so the delta chain\n\t// spans at most one generation or the overlapping execution of one round's tools. A slot holds output only while\n\t// running, so every base is small; a nested call's result lives in its caller's task documents, never here. Do not\n\t// add a delta-count bound; the tool output benchmark checks this rule.\n\tcheckpointWhen: (value) =>\n\t\tvalue.generation === undefined &&\n\t\t!(value.tools ?? []).some((slot) => slot.status === \"running\") &&\n\t\t!(value.nestedTools ?? []).some((slot) => slot.status === \"running\"),\n});\n\n/** Built-in task kinds that can own `pi.live.run`. */\nconst RUN_TASK_KINDS: ReadonlySet<string> = new Set([\"pi.generation\"]);\nconst TOOL_TASK_KIND = \"pi.tool\";\nconst COMPACTION_TASK_KIND = \"pi.compaction\";\n\n/**\n * End the run owned by `taskId`: settle each of its inputs and remove `run`. Always removes `generation`, `tools`, and\n * `nestedTools`, whose presentation belongs to the ending run.\n */\nexport function endRun(tx: Tx, live: Draft<LiveState>, taskId: TaskId, settlement: SubmissionSettlement): void {\n\tif (live.run?.taskId === taskId) {\n\t\tfor (const id of live.run.inputs) tx.settleSubmission(id, settlement);\n\t\tdelete live.run;\n\t}\n\tdelete live.generation;\n\tdelete live.tools;\n\tdelete live.nestedTools;\n}\n\n/** Add the status of a compaction task created in this commit; statuses stay in task ID order. */\nexport function addCompactionStatus(live: Draft<LiveState>, status: CompactionStatus): void {\n\tlive.compactions ??= [];\n\tlive.compactions.push(status);\n}\n\n/** The status of compaction task `taskId`, if listed. */\nexport function compactionStatus(live: Draft<LiveState>, taskId: TaskId): Draft<CompactionStatus> | undefined {\n\treturn live.compactions?.find((status) => status.taskId === taskId);\n}\n\n/** Remove the status of compaction task `taskId`, and the list once empty. */\nexport function removeCompactionStatus(live: Draft<LiveState>, taskId: TaskId): void {\n\tconst statuses = live.compactions;\n\tif (statuses === undefined) return;\n\tconst index = statuses.findIndex((status) => status.taskId === taskId);\n\tif (index >= 0) statuses.splice(index, 1);\n\tif (statuses.length === 0) delete live.compactions;\n}\n\n/** Remove the status of compaction task `taskId` and record that it failed with `error`. */\nexport function failCompactionStatus(live: Draft<LiveState>, taskId: TaskId, error: string): void {\n\tconst status = compactionStatus(live, taskId);\n\tif (status !== undefined) live.compactionFailure = { taskId: status.taskId, reason: status.reason, error };\n\tremoveCompactionStatus(live, taskId);\n}\n\n/**\n * The slot of tool task `taskId`, model-issued or nested, if `pi.live` still lists it. Nested slots are found by binary\n * search: a tool may make thousands of nested calls, each of which looks up its slot in several commits, and every\n * element a search reads costs a node in the draft's change tracker. Their task IDs ascend: each slot is appended in\n * the commit that creates its task, task IDs ascend in commit order, and removal keeps the order.\n */\nexport function toolSlot(live: Draft<LiveState>, taskId: TaskId): Draft<ToolSlot | NestedToolSlot> | undefined {\n\tconst slot = live.tools?.find((each) => each.taskId === taskId);\n\tif (slot !== undefined || live.nestedTools === undefined) return slot;\n\tconst nested = live.nestedTools;\n\tlet low = 0;\n\tlet high = nested.length - 1;\n\twhile (low <= high) {\n\t\tconst middle = (low + high) >>> 1;\n\t\tconst candidate = nested[middle]!;\n\t\tif (candidate.taskId === taskId) return candidate;\n\t\tif (candidate.taskId < taskId) low = middle + 1;\n\t\telse high = middle - 1;\n\t}\n\treturn undefined;\n}\n\n/**\n * Mark a slot done and clear its running output; the caller sets a model-issued call's result `entry`, or a nested\n * call's `summary`. Neither is set when the task faulted or was orphaned.\n */\nexport function finishSlot(slot: Draft<ToolSlot | NestedToolSlot>): void {\n\tslot.status = \"done\";\n\tclearProgress(slot);\n}\n\n/** Remove the nested slots below tool task `taskId`, transitively; the list holds parents before their children. */\nexport function removeNestedSlots(live: Draft<LiveState>, taskId: TaskId): void {\n\tconst nested = live.nestedTools;\n\tif (nested === undefined) return;\n\tconst removed = new Set<TaskId>([taskId]);\n\tfor (const slot of nested) if (removed.has(slot.parentTaskId)) removed.add(slot.taskId);\n\tfor (let index = nested.length - 1; index >= 0; index--) {\n\t\tif (removed.has(nested[index]!.parentTaskId)) nested.splice(index, 1);\n\t}\n\tif (nested.length === 0) delete live.nestedTools;\n}\n\n/** Remove what a tool published while running; its result entry or a rerun replaces it. */\nexport function clearProgress(slot: Draft<SlotProgress>): void {\n\tdelete slot.output;\n\tdelete slot.droppedBytes;\n\tdelete slot.droppedLines;\n\tdelete slot.details;\n\tdelete slot.diagnostics;\n}\n\n/**\n * Harness cleanup for a terminal outcome the scheduler writes itself (`faulted` or `orphaned`). A run task ends its\n * run; a tool task's slot is marked done without an entry, and context derivation synthesizes the missing result; a\n * compaction task's status is removed and its failure recorded.\n * Ignores other kinds so it never creates `pi.live` elsewhere. The scheduler calls this without knowing task kinds;\n * the Harness passes it in (spec §5.4).\n * REMINDER: a committed generation partial becomes an aborted assistant entry here, exactly as in the generation abort\n * handler, so the transcript keeps what the model produced and `pi.usage` counts its spend. The scheduler's commit has\n * no task scope, so that entry has no `byTaskId`. Faults come from task bugs\n * or malformed provider data (a non-JSON value in a response), or a commit the Storage rejected without effect; an\n * uncertain storage failure poisons the Session instead and writes no outcome.\n */\nexport async function settleSchedulerOutcome(\n\ttx: Transaction,\n\trecord: TaskRecord<JsonValue, JsonValue, JsonValue>,\n\toutcome: SchedulerOutcome,\n): Promise<void> {\n\tif (record.kind === TOOL_TASK_KIND) {\n\t\tconst live = await tx.doc(LiveDoc, record.conversationId);\n\t\tconst slot = toolSlot(live, record.id);\n\t\tif (slot !== undefined) finishSlot(slot);\n\t\tremoveNestedSlots(live, record.id);\n\t\treturn;\n\t}\n\tif (record.kind === COMPACTION_TASK_KIND) {\n\t\tconst error = outcome.status === \"faulted\" ? outcome.error.message : outcome.reason;\n\t\tfailCompactionStatus(await tx.doc(LiveDoc, record.conversationId), record.id, error);\n\t\treturn;\n\t}\n\tif (!RUN_TASK_KINDS.has(record.kind)) return;\n\tconst live = await tx.doc(LiveDoc, record.conversationId);\n\tif (live.run?.taskId !== record.id) return;\n\tawait convertPartial(tx, live, record.conversationId);\n\tendRun(\n\t\ttx,\n\t\tlive,\n\t\trecord.id,\n\t\toutcome.status === \"faulted\"\n\t\t\t? { status: \"unanswered\", reason: \"faulted\", detail: outcome.error.message }\n\t\t\t: { status: \"unanswered\", reason: outcome.reason },\n\t);\n}\n"]}
1
+ {"version":3,"file":"live.js","sourceRoot":"","sources":["../../src/harness/live.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Draft, JsonRepresentation, JsonValue } from \"@earendil-works/chord\";\nimport type { AssistantMessage, Usage } from \"@earendil-works/pi-ai\";\nimport { defineDoc } from \"../documents.ts\";\nimport type { Transaction } from \"../session/transaction.ts\";\nimport type {\n\tCommitOptions,\n\tEntryId,\n\tJsonObject,\n\tSubmissionId,\n\tSubmissionSettlement,\n\tTaskId,\n\tTaskRecord,\n\tTx,\n} from \"../types.ts\";\nimport { convertPartial } from \"./generation.ts\";\nimport type { SchedulerOutcome } from \"./scheduler.ts\";\nimport type { CompactionReason, CompactionResult, ToolDiagnostic } from \"./types.ts\";\n\n/** What a running tool call publishes, shared by model-issued and nested calls. */\ntype SlotProgress = {\n\tcallId: string;\n\tname: string;\n\tstatus: \"pending\" | \"running\" | \"done\";\n\t/** Retained running output and what the bounds dropped. */\n\toutput?: string;\n\tdroppedBytes?: number;\n\tdroppedLines?: number;\n\t/** Last `details()` value. */\n\tdetails?: JsonValue;\n\t/** Diagnostics recorded through `api.diagnostic()`. */\n\tdiagnostics?: ToolDiagnostic[];\n};\n\n/** Presentation of one tool call of the current round. */\nexport type ToolSlot = SlotProgress & {\n\t/** Absent for a call not started yet (sequential round). */\n\ttaskId?: TaskId;\n\t/** A call to a tool its request did not offer: its task settles `tool_unavailable` without running anything. */\n\tunoffered?: true;\n\t/** Result entry once done; absent when the tool task faulted or was orphaned. */\n\tentry?: EntryId;\n};\n\n/**\n * Presentation of one nested call: a call a running tool made through `executeTool()`. `callId` is\n * `<parentCallId>/<key>`, the call's ID, unique because keys contain no `/`. The Harness relates\n * slots by task ID: `taskId` is the call's tool task, `parentTaskId` the calling one, model-issued or nested.\n */\nexport type NestedToolSlot = SlotProgress & {\n\tparentCallId: string;\n\tparentTaskId: TaskId;\n\ttaskId: TaskId;\n\t/**\n\t * What the call was made with, replaced by the arguments it runs with, after repair, `beforeTool`, and coercion,\n\t * once it starts executing. A model-issued call's arguments are in its assistant entry instead.\n\t */\n\targuments: JsonObject;\n\t/** Once done: how the call ended, for a status line. The result itself is in the caller's `NestedCallDoc`. */\n\tsummary?: NestedToolSummary;\n};\n\n/** How a nested call ended: an error flag, its execution time, its spend, and up to 500 characters of error text. */\nexport type NestedToolSummary = {\n\tisError: boolean;\n\tdurationMs?: number;\n\tusage?: JsonRepresentation<Usage>;\n\terror?: string;\n};\n\n/** Presentation of one live compaction task (spec §8.7). */\nexport type CompactionStatus = {\n\ttaskId: TaskId<CompactionResult>;\n\t/** What started it: `compact()`, a threshold, or a context overflow. */\n\ttrigger: CompactionReason;\n\t/** Whether a generation waits for it: a compaction the generation owns. */\n\tblocking: boolean;\n\tattempt: number;\n\t/** Durable backoff before the next summarization attempt. */\n\tretry?: { at: number; error: string };\n};\n\n/** The newest compaction that failed since a compaction last produced a summary (spec §8.7). */\nexport type CompactionFailure = {\n\ttaskId: TaskId<CompactionResult>;\n\t/** What started the compaction that failed. */\n\ttrigger: CompactionReason;\n\t/** The failed or faulted outcome's error message, or why the scheduler orphaned the task. */\n\terror: string;\n};\n\n/**\n * Why a run ended without an answer:\n * - `model_error`: the model's response failed, after any retries, or the compaction a request needed failed;\n * - `no_model`: no model is configured, or the configured one is not available;\n * - `aborted`: the run was aborted (`Conversation.abort()`, `abortTask()`); `detail` says when its abort handler was\n * cut off `settings.restartLimit` times and did not finish;\n * - `reset`: a queued reset started a new context at the post-tools boundary, before an answer (a tool's handoff\n * continues the run);\n * - `faulted`: the run's task threw where it cannot recover, or storage rejected its commit;\n * - `orphaned`: the run's task was aborted while no registered definition could take it;\n * - `interrupted`: the host stopped while the model was answering, more often than `settings.retry` retries;\n * - `restart_limit`: the run's generation was cut off `settings.restartLimit` times in a row; a request or poll it was\n * cut off during counts as a failed attempt first, so this ends one whose charge itself keeps failing;\n * - `nothing_to_answer`: the context did not end in a user message or tool results (empty, or ending in an answer), so\n * no request was sent, as for a continue after an answer;\n * - `turn_limit`: a tool round reached the conversation's `maxTurns`; a continue resumes on its results.\n */\nexport type RunFailureReason =\n\t| \"model_error\"\n\t| \"no_model\"\n\t| \"aborted\"\n\t| \"reset\"\n\t| \"faulted\"\n\t| \"orphaned\"\n\t| \"interrupted\"\n\t| \"restart_limit\"\n\t| \"nothing_to_answer\"\n\t| \"turn_limit\";\n\n/** The newest run that ended without an answer (spec §8.2). */\nexport type RunFailure = {\n\t/** The task that ended the run: the run's task at its end. */\n\ttaskId: TaskId;\n\t/** The run's inputs, settled `unanswered`. */\n\tinputs: SubmissionId[];\n\treason: RunFailureReason;\n\t/**\n\t * `model_error`: the error text; `no_model`: which model is missing; `faulted`: the error message; `orphaned`: why\n\t * the task could not run (`missing_task`, `task_too_old`, `migration_failed`); `interrupted` and `restart_limit`: what\n\t * was cut off, and how often; `turn_limit`: the tool rounds the run took, `\"1 turn\"` or `\"N turns\"`.\n\t */\n\tdetail?: string;\n\t/** The failed run's `run.first`, so a continue's `afterRun` hooks see its history too. */\n\tfirst?: EntryId;\n};\n\n/** Run control (spec §8.2). */\nexport type LiveRun = {\n\t/** The task that settles the run's inputs: its generation, handed from one to the next. */\n\ttaskId: TaskId;\n\t/** The run's placed inputs, settled when it ends; `[]` once it answered and runs only its `afterRun` tasks. */\n\tinputs: SubmissionId[];\n\t/** Tool rounds so far, which `AgentState.maxTurns` bounds; an `onYield` continuation starts the count over. */\n\tturns: number;\n\t/**\n\t * The run's first entry: the first one the boundary that started it placed, a continue's the failed run's it\n\t * continues; otherwise its first tool-calling answer. A run started before it was recorded may lack it; `afterRun`\n\t * hooks then get the answer as the first entry.\n\t */\n\tfirst?: EntryId;\n\t/**\n\t * Present once the run answered and its generation waits for the tasks `afterRun` hooks asked for, listed once\n\t * created: queued items stay queued until they are terminal, and the run then ends without a failure.\n\t */\n\tafterRun?: { tasks?: TaskId[] };\n};\n\n/** Built-in live conversation state: run control and presentation of the current generation and tool round. */\nexport type LiveState = {\n\t/** Run control; present exactly while busy, also while a run that answered runs its `afterRun` tasks. */\n\trun?: LiveRun;\n\t/** Presentation of the current generation attempt. */\n\tgeneration?: {\n\t\tattempt: number;\n\t\t/** Committed throttled partial of the in-flight response. */\n\t\tmessage?: JsonRepresentation<AssistantMessage>;\n\t\t/** Durable backoff before the next attempt. */\n\t\tretry?: { at: number; error: string };\n\t\t/** Provider-side deferred response being polled. */\n\t\tdeferred?: { pollAt: number };\n\t};\n\t/** The current tool round in call order, from the tool-calling answer until the generation's `tools` phase ends it. */\n\ttools?: ToolSlot[];\n\t/**\n\t * Nested calls of running tool calls, in creation order, so a parent precedes its children and task IDs ascend. A\n\t * call's nested slots are removed when the call settles.\n\t */\n\tnestedTools?: NestedToolSlot[];\n\t/** Live compaction tasks in task ID order; absent when none. */\n\tcompactions?: CompactionStatus[];\n\t/**\n\t * The newest compaction failure, so a client can show it after the task ended. A compaction that produces a summary\n\t * removes it; one that is aborted or finds nothing to compact leaves it.\n\t */\n\tcompactionFailure?: CompactionFailure;\n\t/**\n\t * Why the newest run ended without an answer, so a client can show it after the run ended. Set in the commit that\n\t * ends the run; removed when a later commit starts a run. A run started in the same commit, by\n\t * `afterFailedRun: \"continue\"` or after a reset, keeps it.\n\t */\n\trunFailure?: RunFailure;\n};\n\nexport const LiveDoc = defineDoc<LiveState>({\n\tkind: \"pi.live\",\n\tversion: 3,\n\tscope: \"conversation\",\n\thistory: \"latest\",\n\tfork: \"initial\",\n\tinitial: () => ({}),\n\t// Version 1 named a compaction's trigger `reason`, in `compactions` and `compactionFailure`. Versions 1 and 2 (as\n\t// builds before `run.turns` stored it) may lack `run.turns`: a run in flight across the upgrade counts its turns\n\t// from 0. Version 2 already names the trigger `trigger`, so renaming leaves it alone.\n\tmigrate: (value) => {\n\t\tconst live = value as { run?: JsonObject; compactions?: JsonObject[]; compactionFailure?: JsonObject };\n\t\tconst { run, compactions, compactionFailure } = live;\n\t\treturn {\n\t\t\t...value,\n\t\t\t...(run === undefined ? {} : { run: { ...run, turns: typeof run.turns === \"number\" ? run.turns : 0 } }),\n\t\t\t...(compactions === undefined ? {} : { compactions: compactions.map(renameReason) }),\n\t\t\t...(compactionFailure === undefined ? {} : { compactionFailure: renameReason(compactionFailure) }),\n\t\t} as LiveState;\n\t},\n\t// REMINDER: a complete base whenever nothing runs (spec §8.2): no generation and no running tool slot. That holds\n\t// while idle, in the commit handing a generation over to its tool round, and between tools, so the delta chain\n\t// spans at most one generation or the overlapping execution of one round's tools. A slot holds output only while\n\t// running, so every base is small; a nested call's result lives in its caller's task documents, never here. Do not\n\t// add a delta-count bound; the tool output benchmark checks this rule.\n\tcheckpointWhen: (value) =>\n\t\tvalue.generation === undefined &&\n\t\t!(value.tools ?? []).some((slot) => slot.status === \"running\") &&\n\t\t!(value.nestedTools ?? []).some((slot) => slot.status === \"running\"),\n});\n\n/** A copy of a version 1 compaction status or failure with `reason` renamed `trigger`, its keys in their order. */\nfunction renameReason(value: JsonObject): JsonObject {\n\treturn Object.fromEntries(Object.entries(value).map(([key, field]) => [key === \"reason\" ? \"trigger\" : key, field]));\n}\n\n/**\n * How the progress throttles commit a partial answer and running tool output into `pi.live`: deferred, so storage gets\n * them together, at the next commit that reads or writes `pi.live` or after `settings.progress.persistWithinMs`. Every\n * commit that consumes or clears streamed fields reads `pi.live`, so it stores them with its own changes (spec §8.2).\n */\nexport const PROGRESS_COMMIT: CommitOptions = { persistence: { kind: \"deferred\" } };\n\n/** Built-in task kinds that can own `pi.live.run`. */\nconst RUN_TASK_KINDS: ReadonlySet<string> = new Set([\"pi.generation\"]);\nconst TOOL_TASK_KIND = \"pi.tool\";\nconst COMPACTION_TASK_KIND = \"pi.compaction\";\n\n/**\n * Built-in task kinds that end themselves once cut off `settings.restartLimit` times (`TaskRecord.restarts`); the\n * scheduler faults a task of any other kind instead (spec §5.4).\n */\nexport const LIMITS_RESTARTS: ReadonlySet<string> = new Set([...RUN_TASK_KINDS, TOOL_TASK_KIND, COMPACTION_TASK_KIND]);\n\n/** Whether `task` was cut off `settings.restartLimit` times in a row, so its phase ends it instead of running. */\nexport function cutOffTooOften(\n\ttask: { readonly restarts?: number },\n\truntime: { readonly settings: { readonly restartLimit: number } },\n): boolean {\n\t// The settings are read only for a task that was cut off at all, so the normal path resolves nothing more.\n\treturn task.restarts !== undefined && task.restarts >= runtime.settings.restartLimit;\n}\n\n/**\n * Whether a task at the limit may still do the cleanup it does when it ends, such as converting a partial: only at the\n * limit. Past it, that cleanup may be what cut the task off, so the task ends without it.\n */\nexport function salvageable(\n\ttask: { readonly restarts?: number },\n\truntime: { readonly settings: { readonly restartLimit: number } },\n): boolean {\n\treturn (task.restarts ?? 0) <= runtime.settings.restartLimit;\n}\n\n/** How often a task was cut off, for a message: \"once\", or \"3 times in a row\". */\nexport function cutOffCount(task: { readonly restarts?: number }): string {\n\tconst restarts = task.restarts ?? 0;\n\treturn restarts === 1 ? \"once\" : `${restarts} times in a row`;\n}\n\n/** How a run ends: with an answer, or without one, settling its inputs `unanswered` and recording why. */\nexport type RunEnd =\n\t| { readonly status: \"done\"; readonly answer: EntryId }\n\t| {\n\t\t\treadonly status: \"unanswered\";\n\t\t\treadonly reason: RunFailureReason;\n\t\t\treadonly detail?: string;\n\t\t\t/** The inputs' settlement; default `unanswered` with `reason` and `detail`. */\n\t\t\treadonly settlement?: SubmissionSettlement;\n\t };\n\n/**\n * End the run owned by `taskId`: settle each of its inputs, remove `run`, and, without an answer, record\n * `runFailure`. A run that answered already, and runs only its `afterRun` tasks, records no failure, however it ends.\n * Always removes `generation`, `tools`, and `nestedTools`, whose presentation belongs to the ending run.\n */\nexport function endRun(tx: Tx, live: Draft<LiveState>, taskId: TaskId, end: RunEnd): void {\n\tif (live.run?.taskId === taskId) {\n\t\tconst inputs = [...live.run.inputs];\n\t\tconst { first } = live.run;\n\t\tif (end.status === \"done\") {\n\t\t\tfor (const id of inputs) tx.settleSubmission(id, { status: \"done\", answer: end.answer });\n\t\t} else if (live.run.afterRun === undefined) {\n\t\t\tconst { reason, detail } = end;\n\t\t\tconst settlement = end.settlement ?? {\n\t\t\t\tstatus: \"unanswered\",\n\t\t\t\treason,\n\t\t\t\t...(detail === undefined ? {} : { detail }),\n\t\t\t};\n\t\t\tfor (const id of inputs) tx.settleSubmission(id, settlement);\n\t\t\tlive.runFailure = {\n\t\t\t\ttaskId,\n\t\t\t\tinputs,\n\t\t\t\treason,\n\t\t\t\t...(detail === undefined ? {} : { detail }),\n\t\t\t\t...(first === undefined ? {} : { first }),\n\t\t\t};\n\t\t}\n\t\tdelete live.run;\n\t}\n\tdelete live.generation;\n\tdelete live.tools;\n\tdelete live.nestedTools;\n}\n\n/** Add the status of a compaction task created in this commit; statuses stay in task ID order. */\nexport function addCompactionStatus(live: Draft<LiveState>, status: CompactionStatus): void {\n\tlive.compactions ??= [];\n\tlive.compactions.push(status);\n}\n\n/** The status of compaction task `taskId`, if listed. */\nexport function compactionStatus(live: Draft<LiveState>, taskId: TaskId): Draft<CompactionStatus> | undefined {\n\treturn live.compactions?.find((status) => status.taskId === taskId);\n}\n\n/** Remove the status of compaction task `taskId`, and the list once empty. */\nexport function removeCompactionStatus(live: Draft<LiveState>, taskId: TaskId): void {\n\tconst statuses = live.compactions;\n\tif (statuses === undefined) return;\n\tconst index = statuses.findIndex((status) => status.taskId === taskId);\n\tif (index >= 0) statuses.splice(index, 1);\n\tif (statuses.length === 0) delete live.compactions;\n}\n\n/** Remove the status of compaction task `taskId` and record that it failed with `error`. */\nexport function failCompactionStatus(live: Draft<LiveState>, taskId: TaskId, error: string): void {\n\tconst status = compactionStatus(live, taskId);\n\tif (status !== undefined) live.compactionFailure = { taskId: status.taskId, trigger: status.trigger, error };\n\tremoveCompactionStatus(live, taskId);\n}\n\n/**\n * The slot of tool task `taskId`, model-issued or nested, if `pi.live` still lists it. Nested slots are found by binary\n * search: a tool may make thousands of nested calls, each of which looks up its slot in several commits, and every\n * element a search reads costs a node in the draft's change tracker. Their task IDs ascend: each slot is appended in\n * the commit that creates its task, task IDs ascend in commit order, and removal keeps the order.\n */\nexport function toolSlot(live: Draft<LiveState>, taskId: TaskId): Draft<ToolSlot | NestedToolSlot> | undefined {\n\tconst slot = live.tools?.find((each) => each.taskId === taskId);\n\tif (slot !== undefined || live.nestedTools === undefined) return slot;\n\tconst nested = live.nestedTools;\n\tlet low = 0;\n\tlet high = nested.length - 1;\n\twhile (low <= high) {\n\t\tconst middle = (low + high) >>> 1;\n\t\tconst candidate = nested[middle]!;\n\t\tif (candidate.taskId === taskId) return candidate;\n\t\tif (candidate.taskId < taskId) low = middle + 1;\n\t\telse high = middle - 1;\n\t}\n\treturn undefined;\n}\n\n/**\n * Mark a slot done and clear its running output; the caller sets a model-issued call's result `entry`, or a nested\n * call's `summary`. Neither is set when the task faulted or was orphaned.\n */\nexport function finishSlot(slot: Draft<ToolSlot | NestedToolSlot>): void {\n\tslot.status = \"done\";\n\tclearProgress(slot);\n}\n\n/** Remove the nested slots below tool task `taskId`, transitively; the list holds parents before their children. */\nexport function removeNestedSlots(live: Draft<LiveState>, taskId: TaskId): void {\n\tconst nested = live.nestedTools;\n\tif (nested === undefined) return;\n\tconst removed = new Set<TaskId>([taskId]);\n\tfor (const slot of nested) if (removed.has(slot.parentTaskId)) removed.add(slot.taskId);\n\tfor (let index = nested.length - 1; index >= 0; index--) {\n\t\tif (removed.has(nested[index]!.parentTaskId)) nested.splice(index, 1);\n\t}\n\tif (nested.length === 0) delete live.nestedTools;\n}\n\n/** Remove what a tool published while running; its result entry or a rerun replaces it. */\nexport function clearProgress(slot: Draft<SlotProgress>): void {\n\tdelete slot.output;\n\tdelete slot.droppedBytes;\n\tdelete slot.droppedLines;\n\tdelete slot.details;\n\tdelete slot.diagnostics;\n}\n\n/**\n * Harness cleanup for a terminal outcome the scheduler writes itself (`faulted` or `orphaned`). A run task ends its\n * run; a tool task's slot is marked done without an entry, and context derivation synthesizes the missing result; a\n * compaction task's status is removed and its failure recorded.\n * Ignores other kinds so it never creates `pi.live` elsewhere. The scheduler calls this without knowing task kinds;\n * the Harness passes it in (spec §5.4).\n * REMINDER: a committed generation partial becomes an aborted assistant entry here, exactly as in the generation abort\n * handler, so the transcript keeps what the model produced and `pi.usage` counts its spend. The scheduler's commit has\n * no task scope, so that entry has no `byTaskId`. Faults come from task bugs\n * or malformed provider data (a non-JSON value in a response), or a commit the Storage rejected without effect; an\n * uncertain storage failure poisons the Session instead and writes no outcome.\n */\nexport async function settleSchedulerOutcome(\n\ttx: Transaction,\n\trecord: TaskRecord<JsonValue, JsonValue, JsonValue>,\n\toutcome: SchedulerOutcome,\n): Promise<void> {\n\tif (record.kind === TOOL_TASK_KIND) {\n\t\tconst live = await tx.doc(LiveDoc, record.conversationId);\n\t\tconst slot = toolSlot(live, record.id);\n\t\tif (slot !== undefined) finishSlot(slot);\n\t\tremoveNestedSlots(live, record.id);\n\t\treturn;\n\t}\n\t// Only an abort handler is faulted for the limit here (the built-in phases end themselves): the task was aborted,\n\t// and keeps that meaning. Its run ends `aborted`, with the limit as detail, and an aborted compaction is no failure.\n\tconst detail = outcome.status === \"faulted\" ? outcome.error.detail : undefined;\n\tconst cutOff =\n\t\ttypeof detail === \"object\" && detail !== null && \"reason\" in detail && detail.reason === \"restart_limit\";\n\tif (record.kind === COMPACTION_TASK_KIND) {\n\t\tconst live = await tx.doc(LiveDoc, record.conversationId);\n\t\tif (cutOff) removeCompactionStatus(live, record.id);\n\t\telse failCompactionStatus(live, record.id, outcome.status === \"faulted\" ? outcome.error.message : outcome.reason);\n\t\treturn;\n\t}\n\tif (!RUN_TASK_KINDS.has(record.kind)) return;\n\tconst live = await tx.doc(LiveDoc, record.conversationId);\n\tif (live.run?.taskId !== record.id) return;\n\t// Cut off, the abort handler may have died converting the partial: the run ends without it.\n\tif (!cutOff) await convertPartial(tx, live, record.conversationId);\n\tendRun(\n\t\ttx,\n\t\tlive,\n\t\trecord.id,\n\t\toutcome.status === \"faulted\"\n\t\t\t? { status: \"unanswered\", reason: cutOff ? \"aborted\" : \"faulted\", detail: outcome.error.message }\n\t\t\t: {\n\t\t\t\t\tstatus: \"unanswered\",\n\t\t\t\t\treason: \"orphaned\",\n\t\t\t\t\tdetail: outcome.reason,\n\t\t\t\t\tsettlement: { status: \"unanswered\", reason: outcome.reason },\n\t\t\t\t},\n\t);\n}\n"]}
@@ -0,0 +1,54 @@
1
+ import type { JsonRepresentation } from "@earendil-works/chord";
2
+ import { type Draft } from "@earendil-works/chord/delta";
3
+ import type { AssistantMessage, AssistantMessageEvent, ToolCall } from "@earendil-works/pi-ai";
4
+ import { type JsonChange } from "@earendil-works/pi-ai/utils/streaming-json";
5
+ import { type AssignPlan } from "./json.ts";
6
+ import type { LiveState } from "./live.ts";
7
+ /** A partial message as `pi.live.generation.message` holds it. */
8
+ export type PartialMessage = JsonRepresentation<AssistantMessage>;
9
+ /** Committed arguments of a streamed tool call. */
10
+ type Arguments = JsonRepresentation<ToolCall>["arguments"];
11
+ /** What one partial commit writes besides the partial message itself; from `PartialChanges.take()`. */
12
+ export type PartialCommit = {
13
+ /** The plan `assignJson()` writes the message with: text appends, and the arguments it leaves to `changes`. */
14
+ readonly plan: AssignPlan;
15
+ /** Each tracked tool call by content index: its argument changes since the last commit, in order, and its snapshot. */
16
+ readonly toolCalls: ReadonlyMap<number, {
17
+ readonly changes: readonly JsonChange[];
18
+ readonly snapshot: Arguments;
19
+ }>;
20
+ };
21
+ /**
22
+ * Collects, from a response's events, what changed in its partial message since the last commit, so the commit appends
23
+ * new text instead of reassigning growing strings. Reassigning makes Chord compare the old and new string, which costs
24
+ * O(length) per commit.
25
+ *
26
+ * - Text and thinking: the `text_delta` and `thinking_delta` events. The commit appends them where the committed string
27
+ * plus the deltas has the new string's length, and compares otherwise. A block's `*_end` event drops them, because
28
+ * providers may replace the text when a block ends.
29
+ * - Tool-call arguments: a `StreamingJsonParser` per call, fed with the raw argument text of each `toolcall_delta`,
30
+ * reports what each piece changed. The commit applies those changes to the committed arguments in order and leaves
31
+ * the arguments out of the message assignment, so the committed arguments are exactly the parsed text so far.
32
+ * `toolcall_end` ends the tracking; the call's last commit assigns its final arguments.
33
+ */
34
+ export declare class PartialChanges {
35
+ #private;
36
+ /** Record what `event` changed. */
37
+ observe(event: AssistantMessageEvent): void;
38
+ /**
39
+ * Take what changed since the last call, for a commit of `message`, a copy of the partial. Clears the arguments of
40
+ * tracked tool calls in `message`: the commit writes them from the changes. Call `restore()` if the commit fails.
41
+ */
42
+ take(message: PartialMessage): PartialCommit;
43
+ /**
44
+ * Write `message` with what `commit` took into `generation.message`: the message leaf by leaf with the plan, then the
45
+ * argument changes. A tracked call whose block is new here gets its arguments from its changes, which then start at
46
+ * its first piece; when the committed message lost a call whose changes were already committed (another writer reset
47
+ * it), the call falls back to its snapshot from now on.
48
+ */
49
+ commit(generation: Draft<NonNullable<LiveState["generation"]>>, message: PartialMessage, commit: PartialCommit): void;
50
+ /** Put back what a failed commit took, so the next commit applies it first. */
51
+ restore(commit: PartialCommit): void;
52
+ }
53
+ export {};
54
+ //# sourceMappingURL=partial-changes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"partial-changes.d.ts","sourceRoot":"","sources":["../../src/harness/partial-changes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAa,MAAM,uBAAuB,CAAC;AAC3E,OAAO,EAAc,KAAK,KAAK,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAC/F,OAAO,EAAE,KAAK,UAAU,EAAuB,MAAM,4CAA4C,CAAC;AAClG,OAAO,EAAE,KAAK,UAAU,EAAc,MAAM,WAAW,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAI3C,kEAAkE;AAClE,MAAM,MAAM,cAAc,GAAG,kBAAkB,CAAC,gBAAgB,CAAC,CAAC;AAElE,mDAAmD;AACnD,KAAK,SAAS,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,CAAC;AAE3D,uGAAuG;AACvG,MAAM,MAAM,aAAa,GAAG;IAC3B,+GAA+G;IAC/G,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,uHAAuH;IACvH,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;CACnH,CAAC;AAKF;;;;;;;;;;;;GAYG;AACH,qBAAa,cAAc;;IAI1B,mCAAmC;IACnC,OAAO,CAAC,KAAK,EAAE,qBAAqB,GAAG,IAAI,CAsC1C;IAED;;;OAGG;IACH,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,aAAa,CAoB3C;IAED;;;;;OAKG;IACH,MAAM,CACL,UAAU,EAAE,KAAK,CAAC,WAAW,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,EACvD,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,aAAa,GACnB,IAAI,CAuBN;IAED,+EAA+E;IAC/E,OAAO,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAKnC;CACD"}
@@ -0,0 +1,162 @@
1
+ import { appendText } from "@earendil-works/chord/delta";
2
+ import { StreamingJsonParser } from "@earendil-works/pi-ai/utils/streaming-json";
3
+ import { assignJson } from "./json.js";
4
+ /**
5
+ * Collects, from a response's events, what changed in its partial message since the last commit, so the commit appends
6
+ * new text instead of reassigning growing strings. Reassigning makes Chord compare the old and new string, which costs
7
+ * O(length) per commit.
8
+ *
9
+ * - Text and thinking: the `text_delta` and `thinking_delta` events. The commit appends them where the committed string
10
+ * plus the deltas has the new string's length, and compares otherwise. A block's `*_end` event drops them, because
11
+ * providers may replace the text when a block ends.
12
+ * - Tool-call arguments: a `StreamingJsonParser` per call, fed with the raw argument text of each `toolcall_delta`,
13
+ * reports what each piece changed. The commit applies those changes to the committed arguments in order and leaves
14
+ * the arguments out of the message assignment, so the committed arguments are exactly the parsed text so far.
15
+ * `toolcall_end` ends the tracking; the call's last commit assigns its final arguments.
16
+ */
17
+ export class PartialChanges {
18
+ #text = new Map();
19
+ #toolCalls = new Map();
20
+ /** Record what `event` changed. */
21
+ observe(event) {
22
+ switch (event.type) {
23
+ case "text_delta":
24
+ case "thinking_delta": {
25
+ const field = event.type === "text_delta" ? "text" : "thinking";
26
+ const pending = this.#text.get(event.contentIndex);
27
+ if (pending?.field === field)
28
+ pending.text += event.delta;
29
+ else
30
+ this.#text.set(event.contentIndex, { field, text: event.delta });
31
+ return;
32
+ }
33
+ case "toolcall_start":
34
+ this.#toolCalls.set(event.contentIndex, {
35
+ parser: new StreamingJsonParser(),
36
+ changes: [],
37
+ committed: false,
38
+ });
39
+ return;
40
+ case "toolcall_delta": {
41
+ const call = this.#toolCalls.get(event.contentIndex);
42
+ if (call === undefined)
43
+ return;
44
+ for (const change of call.parser.append(event.delta)) {
45
+ // Arguments are an object: any other root shows as no arguments, so the snapshot is committed instead.
46
+ if (change.path.length === 0 && !isRecord(change.kind === "set" ? value(change) : null)) {
47
+ this.#toolCalls.delete(event.contentIndex);
48
+ return;
49
+ }
50
+ call.changes.push(change);
51
+ }
52
+ return;
53
+ }
54
+ case "text_end":
55
+ case "thinking_end":
56
+ this.#text.delete(event.contentIndex);
57
+ return;
58
+ case "toolcall_end":
59
+ this.#toolCalls.delete(event.contentIndex);
60
+ return;
61
+ }
62
+ }
63
+ /**
64
+ * Take what changed since the last call, for a commit of `message`, a copy of the partial. Clears the arguments of
65
+ * tracked tool calls in `message`: the commit writes them from the changes. Call `restore()` if the commit fails.
66
+ */
67
+ take(message) {
68
+ const blocks = new Map();
69
+ for (const [index, { field, text }] of this.#text) {
70
+ blocks.set(index, { kind: "fields", fields: new Map([[field, { kind: "append", text }]]) });
71
+ }
72
+ this.#text = new Map();
73
+ const toolCalls = new Map();
74
+ for (const [index, call] of this.#toolCalls) {
75
+ const block = message.content[index];
76
+ // A tracked call is the tool call its `toolcall_start` named; the narrowing only tells TypeScript.
77
+ if (block?.type !== "toolCall")
78
+ continue;
79
+ toolCalls.set(index, { changes: call.changes, snapshot: block.arguments });
80
+ block.arguments = {};
81
+ blocks.set(index, { kind: "fields", fields: new Map([["arguments", { kind: "keep" }]]) });
82
+ call.changes = [];
83
+ }
84
+ return {
85
+ plan: { kind: "fields", fields: new Map([["content", { kind: "fields", fields: blocks }]]) },
86
+ toolCalls,
87
+ };
88
+ }
89
+ /**
90
+ * Write `message` with what `commit` took into `generation.message`: the message leaf by leaf with the plan, then the
91
+ * argument changes. A tracked call whose block is new here gets its arguments from its changes, which then start at
92
+ * its first piece; when the committed message lost a call whose changes were already committed (another writer reset
93
+ * it), the call falls back to its snapshot from now on.
94
+ */
95
+ commit(generation, message, commit) {
96
+ const committedBlocks = generation.message?.content.length ?? 0;
97
+ const apply = [];
98
+ for (const [index, { changes, snapshot }] of commit.toolCalls) {
99
+ const call = this.#toolCalls.get(index);
100
+ if (call === undefined)
101
+ continue;
102
+ const block = message.content[index];
103
+ if (index >= committedBlocks && call.committed && block?.type === "toolCall") {
104
+ // The earlier changes are not in the committed message: commit the snapshot and stop tracking the call.
105
+ this.#toolCalls.delete(index);
106
+ block.arguments = snapshot;
107
+ continue;
108
+ }
109
+ call.committed = true;
110
+ apply.push([index, changes]);
111
+ }
112
+ assignJson(generation, "message", message, commit.plan);
113
+ const content = generation.message?.content ?? [];
114
+ for (const [index, changes] of apply) {
115
+ const block = content[index];
116
+ if (block?.type !== "toolCall")
117
+ continue;
118
+ for (const change of changes)
119
+ applyChange(block, change);
120
+ }
121
+ }
122
+ /** Put back what a failed commit took, so the next commit applies it first. */
123
+ restore(commit) {
124
+ for (const [index, { changes }] of commit.toolCalls) {
125
+ const call = this.#toolCalls.get(index);
126
+ if (call !== undefined)
127
+ call.changes = [...changes, ...call.changes];
128
+ }
129
+ }
130
+ }
131
+ /** Apply one argument change to the committed arguments of `block`. */
132
+ function applyChange(block, change) {
133
+ const key = change.path.at(-1);
134
+ if (key === undefined) {
135
+ // Only an object root is tracked (`observe()` drops any other), and only `set` starts it.
136
+ const root = change.kind === "set" ? value(change) : undefined;
137
+ if (isRecord(root))
138
+ block.arguments = root;
139
+ return;
140
+ }
141
+ // The path follows the parsed argument text, not a type: each segment names a container `observe()` saw set.
142
+ let parent = block.arguments;
143
+ for (const segment of change.path.slice(0, -1)) {
144
+ parent = parent[segment];
145
+ }
146
+ const slots = parent;
147
+ if (change.kind === "set")
148
+ slots[key] = value(change);
149
+ // appendText() takes object members; a string in an array is reassigned, which compares it whole.
150
+ else if (Array.isArray(parent))
151
+ slots[key] = `${slots[key]}${change.text}`;
152
+ else
153
+ appendText(parent, String(key), change.text);
154
+ }
155
+ /** The value a `set` change reports: JSON data, which pi-ai types with read-only arrays. */
156
+ function value(change) {
157
+ return change.value;
158
+ }
159
+ function isRecord(value) {
160
+ return typeof value === "object" && value !== null && !Array.isArray(value);
161
+ }
162
+ //# sourceMappingURL=partial-changes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"partial-changes.js","sourceRoot":"","sources":["../../src/harness/partial-changes.ts"],"names":[],"mappings":"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","sourcesContent":["// What a streamed answer changed in its partial message between two partial commits, so a commit costs the new text.\nimport type { JsonRepresentation, JsonValue } from \"@earendil-works/chord\";\nimport { appendText, type Draft } from \"@earendil-works/chord/delta\";\nimport type { AssistantMessage, AssistantMessageEvent, ToolCall } from \"@earendil-works/pi-ai\";\nimport { type JsonChange, StreamingJsonParser } from \"@earendil-works/pi-ai/utils/streaming-json\";\nimport { type AssignPlan, assignJson } from \"./json.ts\";\nimport type { LiveState } from \"./live.ts\";\n\ntype JsonContainer = Record<string, JsonValue> | JsonValue[];\n\n/** A partial message as `pi.live.generation.message` holds it. */\nexport type PartialMessage = JsonRepresentation<AssistantMessage>;\n\n/** Committed arguments of a streamed tool call. */\ntype Arguments = JsonRepresentation<ToolCall>[\"arguments\"];\n\n/** What one partial commit writes besides the partial message itself; from `PartialChanges.take()`. */\nexport type PartialCommit = {\n\t/** The plan `assignJson()` writes the message with: text appends, and the arguments it leaves to `changes`. */\n\treadonly plan: AssignPlan;\n\t/** Each tracked tool call by content index: its argument changes since the last commit, in order, and its snapshot. */\n\treadonly toolCalls: ReadonlyMap<number, { readonly changes: readonly JsonChange[]; readonly snapshot: Arguments }>;\n};\n\n/** What a tracked tool call changed since the last commit, and whether any commit took its changes yet. */\ntype ToolCallState = { readonly parser: StreamingJsonParser; changes: JsonChange[]; committed: boolean };\n\n/**\n * Collects, from a response's events, what changed in its partial message since the last commit, so the commit appends\n * new text instead of reassigning growing strings. Reassigning makes Chord compare the old and new string, which costs\n * O(length) per commit.\n *\n * - Text and thinking: the `text_delta` and `thinking_delta` events. The commit appends them where the committed string\n * plus the deltas has the new string's length, and compares otherwise. A block's `*_end` event drops them, because\n * providers may replace the text when a block ends.\n * - Tool-call arguments: a `StreamingJsonParser` per call, fed with the raw argument text of each `toolcall_delta`,\n * reports what each piece changed. The commit applies those changes to the committed arguments in order and leaves\n * the arguments out of the message assignment, so the committed arguments are exactly the parsed text so far.\n * `toolcall_end` ends the tracking; the call's last commit assigns its final arguments.\n */\nexport class PartialChanges {\n\t#text = new Map<number, { readonly field: \"text\" | \"thinking\"; text: string }>();\n\treadonly #toolCalls = new Map<number, ToolCallState>();\n\n\t/** Record what `event` changed. */\n\tobserve(event: AssistantMessageEvent): void {\n\t\tswitch (event.type) {\n\t\t\tcase \"text_delta\":\n\t\t\tcase \"thinking_delta\": {\n\t\t\t\tconst field = event.type === \"text_delta\" ? \"text\" : \"thinking\";\n\t\t\t\tconst pending = this.#text.get(event.contentIndex);\n\t\t\t\tif (pending?.field === field) pending.text += event.delta;\n\t\t\t\telse this.#text.set(event.contentIndex, { field, text: event.delta });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase \"toolcall_start\":\n\t\t\t\tthis.#toolCalls.set(event.contentIndex, {\n\t\t\t\t\tparser: new StreamingJsonParser(),\n\t\t\t\t\tchanges: [],\n\t\t\t\t\tcommitted: false,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\tcase \"toolcall_delta\": {\n\t\t\t\tconst call = this.#toolCalls.get(event.contentIndex);\n\t\t\t\tif (call === undefined) return;\n\t\t\t\tfor (const change of call.parser.append(event.delta)) {\n\t\t\t\t\t// Arguments are an object: any other root shows as no arguments, so the snapshot is committed instead.\n\t\t\t\t\tif (change.path.length === 0 && !isRecord(change.kind === \"set\" ? value(change) : null)) {\n\t\t\t\t\t\tthis.#toolCalls.delete(event.contentIndex);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tcall.changes.push(change);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase \"text_end\":\n\t\t\tcase \"thinking_end\":\n\t\t\t\tthis.#text.delete(event.contentIndex);\n\t\t\t\treturn;\n\t\t\tcase \"toolcall_end\":\n\t\t\t\tthis.#toolCalls.delete(event.contentIndex);\n\t\t\t\treturn;\n\t\t}\n\t}\n\n\t/**\n\t * Take what changed since the last call, for a commit of `message`, a copy of the partial. Clears the arguments of\n\t * tracked tool calls in `message`: the commit writes them from the changes. Call `restore()` if the commit fails.\n\t */\n\ttake(message: PartialMessage): PartialCommit {\n\t\tconst blocks = new Map<string | number, AssignPlan>();\n\t\tfor (const [index, { field, text }] of this.#text) {\n\t\t\tblocks.set(index, { kind: \"fields\", fields: new Map([[field, { kind: \"append\", text }]]) });\n\t\t}\n\t\tthis.#text = new Map();\n\t\tconst toolCalls = new Map<number, { readonly changes: readonly JsonChange[]; readonly snapshot: Arguments }>();\n\t\tfor (const [index, call] of this.#toolCalls) {\n\t\t\tconst block = message.content[index];\n\t\t\t// A tracked call is the tool call its `toolcall_start` named; the narrowing only tells TypeScript.\n\t\t\tif (block?.type !== \"toolCall\") continue;\n\t\t\ttoolCalls.set(index, { changes: call.changes, snapshot: block.arguments });\n\t\t\tblock.arguments = {};\n\t\t\tblocks.set(index, { kind: \"fields\", fields: new Map([[\"arguments\", { kind: \"keep\" }]]) });\n\t\t\tcall.changes = [];\n\t\t}\n\t\treturn {\n\t\t\tplan: { kind: \"fields\", fields: new Map([[\"content\", { kind: \"fields\", fields: blocks }]]) },\n\t\t\ttoolCalls,\n\t\t};\n\t}\n\n\t/**\n\t * Write `message` with what `commit` took into `generation.message`: the message leaf by leaf with the plan, then the\n\t * argument changes. A tracked call whose block is new here gets its arguments from its changes, which then start at\n\t * its first piece; when the committed message lost a call whose changes were already committed (another writer reset\n\t * it), the call falls back to its snapshot from now on.\n\t */\n\tcommit(\n\t\tgeneration: Draft<NonNullable<LiveState[\"generation\"]>>,\n\t\tmessage: PartialMessage,\n\t\tcommit: PartialCommit,\n\t): void {\n\t\tconst committedBlocks = generation.message?.content.length ?? 0;\n\t\tconst apply: [number, readonly JsonChange[]][] = [];\n\t\tfor (const [index, { changes, snapshot }] of commit.toolCalls) {\n\t\t\tconst call = this.#toolCalls.get(index);\n\t\t\tif (call === undefined) continue;\n\t\t\tconst block = message.content[index];\n\t\t\tif (index >= committedBlocks && call.committed && block?.type === \"toolCall\") {\n\t\t\t\t// The earlier changes are not in the committed message: commit the snapshot and stop tracking the call.\n\t\t\t\tthis.#toolCalls.delete(index);\n\t\t\t\tblock.arguments = snapshot;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tcall.committed = true;\n\t\t\tapply.push([index, changes]);\n\t\t}\n\t\tassignJson(generation, \"message\", message, commit.plan);\n\t\tconst content = generation.message?.content ?? [];\n\t\tfor (const [index, changes] of apply) {\n\t\t\tconst block = content[index];\n\t\t\tif (block?.type !== \"toolCall\") continue;\n\t\t\tfor (const change of changes) applyChange(block, change);\n\t\t}\n\t}\n\n\t/** Put back what a failed commit took, so the next commit applies it first. */\n\trestore(commit: PartialCommit): void {\n\t\tfor (const [index, { changes }] of commit.toolCalls) {\n\t\t\tconst call = this.#toolCalls.get(index);\n\t\t\tif (call !== undefined) call.changes = [...changes, ...call.changes];\n\t\t}\n\t}\n}\n\n/** Apply one argument change to the committed arguments of `block`. */\nfunction applyChange(block: Draft<JsonRepresentation<ToolCall>>, change: JsonChange): void {\n\tconst key = change.path.at(-1);\n\tif (key === undefined) {\n\t\t// Only an object root is tracked (`observe()` drops any other), and only `set` starts it.\n\t\tconst root = change.kind === \"set\" ? value(change) : undefined;\n\t\tif (isRecord(root)) block.arguments = root;\n\t\treturn;\n\t}\n\t// The path follows the parsed argument text, not a type: each segment names a container `observe()` saw set.\n\tlet parent = block.arguments as Draft<JsonContainer>;\n\tfor (const segment of change.path.slice(0, -1)) {\n\t\tparent = (parent as Record<string | number, Draft<JsonContainer>>)[segment]!;\n\t}\n\tconst slots = parent as Record<string | number, JsonValue>;\n\tif (change.kind === \"set\") slots[key] = value(change);\n\t// appendText() takes object members; a string in an array is reassigned, which compares it whole.\n\telse if (Array.isArray(parent)) slots[key] = `${slots[key] as string}${change.text}`;\n\telse appendText(parent as Draft<Record<string, string>>, String(key), change.text);\n}\n\n/** The value a `set` change reports: JSON data, which pi-ai types with read-only arrays. */\nfunction value(change: Extract<JsonChange, { kind: \"set\" }>): JsonValue {\n\treturn change.value as JsonValue;\n}\n\nfunction isRecord(value: JsonValue | undefined): value is Record<string, JsonValue> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n"]}
@@ -0,0 +1,11 @@
1
+ import type { Context } from "@earendil-works/chord/context";
2
+ import type { RegistryValue } from "@earendil-works/chord/next";
3
+ import type { RegistryReader, RegistrySnapshot, ToolRegistration } from "./types.ts";
4
+ /**
5
+ * A `RegistryReader` over a Chord registry value whose composition is a registry snapshot: `snapshot()` reads the
6
+ * current composition (the last good one while `compose` fails), `subscribe` observes its compositions, its listener
7
+ * called synchronously inside the Chord batch that composed (so it only wakes the scheduler; a Chord call there
8
+ * throws `invalid/reentrant`). `context` is the observation's: aborting it detaches every listener.
9
+ */
10
+ export declare function registryReader<Tool extends ToolRegistration = ToolRegistration>(value: RegistryValue<RegistrySnapshot<Tool>>, context: Context): RegistryReader<Tool>;
11
+ //# sourceMappingURL=registry-reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry-reader.d.ts","sourceRoot":"","sources":["../../src/harness/registry-reader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAErF;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,SAAS,gBAAgB,GAAG,gBAAgB,EAC9E,KAAK,EAAE,aAAa,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,EAC5C,OAAO,EAAE,OAAO,GACd,cAAc,CAAC,IAAI,CAAC,CAiBtB"}
@@ -0,0 +1,25 @@
1
+ // A Harness's registry over a Chord registry (Chord v2 slice 8 §5): the composed value of p3's extensions registry,
2
+ // read as Durable's `RegistryReader`.
3
+ /**
4
+ * A `RegistryReader` over a Chord registry value whose composition is a registry snapshot: `snapshot()` reads the
5
+ * current composition (the last good one while `compose` fails), `subscribe` observes its compositions, its listener
6
+ * called synchronously inside the Chord batch that composed (so it only wakes the scheduler; a Chord call there
7
+ * throws `invalid/reentrant`). `context` is the observation's: aborting it detaches every listener.
8
+ */
9
+ export function registryReader(value, context) {
10
+ return {
11
+ snapshot: () => value.value,
12
+ subscribe: (listener) => {
13
+ const observation = value.observe({
14
+ advance: (call) => {
15
+ // A failed composition keeps the last snapshot: nothing to reconsider.
16
+ if (call.kind === "value")
17
+ listener();
18
+ },
19
+ end: () => { },
20
+ }, context);
21
+ return () => observation.detach();
22
+ },
23
+ };
24
+ }
25
+ //# sourceMappingURL=registry-reader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry-reader.js","sourceRoot":"","sources":["../../src/harness/registry-reader.ts"],"names":[],"mappings":"AAAA,oHAAoH;AACpH,sCAAsC;AAMtC;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAC7B,KAA4C,EAC5C,OAAgB;IAEhB,OAAO;QACN,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK;QAC3B,SAAS,EAAE,CAAC,QAAQ,EAAE,EAAE;YACvB,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAChC;gBACC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;oBACjB,uEAAuE;oBACvE,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO;wBAAE,QAAQ,EAAE,CAAC;gBACvC,CAAC;gBACD,GAAG,EAAE,GAAG,EAAE,GAAE,CAAC;aACb,EACD,OAAO,CACP,CAAC;YACF,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;QACnC,CAAC;KACD,CAAC;AACH,CAAC","sourcesContent":["// A Harness's registry over a Chord registry (Chord v2 slice 8 §5): the composed value of p3's extensions registry,\n// read as Durable's `RegistryReader`.\n\nimport type { Context } from \"@earendil-works/chord/context\";\nimport type { RegistryValue } from \"@earendil-works/chord/next\";\nimport type { RegistryReader, RegistrySnapshot, ToolRegistration } from \"./types.ts\";\n\n/**\n * A `RegistryReader` over a Chord registry value whose composition is a registry snapshot: `snapshot()` reads the\n * current composition (the last good one while `compose` fails), `subscribe` observes its compositions, its listener\n * called synchronously inside the Chord batch that composed (so it only wakes the scheduler; a Chord call there\n * throws `invalid/reentrant`). `context` is the observation's: aborting it detaches every listener.\n */\nexport function registryReader<Tool extends ToolRegistration = ToolRegistration>(\n\tvalue: RegistryValue<RegistrySnapshot<Tool>>,\n\tcontext: Context,\n): RegistryReader<Tool> {\n\treturn {\n\t\tsnapshot: () => value.value,\n\t\tsubscribe: (listener) => {\n\t\t\tconst observation = value.observe(\n\t\t\t\t{\n\t\t\t\t\tadvance: (call) => {\n\t\t\t\t\t\t// A failed composition keeps the last snapshot: nothing to reconsider.\n\t\t\t\t\t\tif (call.kind === \"value\") listener();\n\t\t\t\t\t},\n\t\t\t\t\tend: () => {},\n\t\t\t\t},\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\treturn () => observation.detach();\n\t\t},\n\t};\n}\n"]}
@@ -8,16 +8,13 @@ import type { ConversationId, ReportInfo, Storage, StorageWrite, TaskId, TaskOut
8
8
  import type { Agent, ConversationHandle, HarnessInspection, HarnessOptions, RegistryReader, RegistrySnapshot, Settings, SettledTask, TaskInspection, Wake } from "./types.ts";
9
9
  type AnyTaskRecord = TaskRecord<JsonValue, JsonValue, JsonValue>;
10
10
  /** What `blockedReason()` reads of a task: the task graph keeps only this of each record. */
11
- export type BlockedSubject = Pick<AnyTaskRecord, "id" | "kind" | "version" | "abortRequested" | "abortReason" | "restarts"> & {
11
+ export type BlockedSubject = Pick<AnyTaskRecord, "id" | "kind" | "version" | "abortRequested" | "abortReason"> & {
12
12
  readonly status: TaskState<JsonValue, JsonValue>["status"];
13
13
  };
14
14
  /** The part of a record `blockedReason()` reads. */
15
15
  export declare function blockedSubject(record: AnyTaskRecord): BlockedSubject;
16
- /**
17
- * Why a task cannot be reserved: no registered definition can take it, or it was cut off `restartLimit` times in a row.
18
- * Derived from the registry, the settings, and the record's `restarts`.
19
- */
20
- export type BlockedReason = "missing_task" | "task_too_old" | "migration_failed" | "restart_limit";
16
+ /** Why a task cannot be reserved: no registered definition can take it. Derived from the registry. */
17
+ export type BlockedReason = "missing_task" | "task_too_old" | "migration_failed";
21
18
  /** Terminal outcomes the scheduler writes without running task code. */
22
19
  export type SchedulerOutcome = Extract<TaskOutcome<JsonValue>, {
23
20
  readonly status: "faulted" | "orphaned";
@@ -48,6 +45,11 @@ export type TaskSchedulerOptions = {
48
45
  /** While closing, on the line after admitted commits settle, write what the callback returns straight to Storage. */
49
46
  readonly writeAtClose: (writes: () => readonly StorageWrite[]) => Promise<void>;
50
47
  readonly report: (error: unknown, info: ReportInfo, context?: Context) => void;
48
+ /**
49
+ * Task kinds whose run phases end the task themselves once it was cut off `settings.restartLimit` times (the
50
+ * built-in tasks, from `TaskRecord.restarts`); the scheduler ends a task of any other kind `faulted` instead.
51
+ */
52
+ readonly limitsRestarts: (kind: string) => boolean;
51
53
  /** Harness cleanup staged in the commit that makes an outcome the scheduler wrote itself terminal. */
52
54
  readonly settleOutcome: (tx: Transaction, record: AnyTaskRecord, outcome: SchedulerOutcome) => Promise<void>;
53
55
  /** Withdraw a conversation's queued inputs, for conversation abort and abort cascades. */
@@ -56,6 +58,11 @@ export type TaskSchedulerOptions = {
56
58
  readonly conversation: (id: ConversationId, binding: InvocationBinding, context: Context) => Promise<ConversationHandle | undefined>;
57
59
  /** Context for scheduler commits and invocations; carries no caller cancellation. */
58
60
  readonly context: Context;
61
+ /**
62
+ * `HarnessOptions.readOnly`: open loads live tasks as committed, `running` ones included, and the scheduler never
63
+ * commits, runs anything, or asks for a wakeup.
64
+ */
65
+ readonly readOnly?: boolean;
59
66
  };
60
67
  /**
61
68
  * Durable task scheduler of one Harness.
@@ -75,16 +82,24 @@ export type TaskSchedulerOptions = {
75
82
  * later below a dropped node finds it unknown and loads its chain from storage again.
76
83
  *
77
84
  * Invariant: every task transition is decided and written by one callback serialized on the Session line. That covers
78
- * reservation, marks, runtime commits, finalization, and the synchronous step before each phase, which applies the
79
- * precedence rules and writes a fault or handover. Handlers and joins run off the line. An invocation ends inside the
80
- * step that decides its end, so a runtime commit it queued either lands before that decision or is rejected.
85
+ * reservation, marks, runtime commits, finalization, and the step before each phase, which applies the precedence rules
86
+ * and writes a fault or handover. Handlers and joins run off the line. An invocation ends inside the step that decides
87
+ * its end, so a runtime commit it queued either lands before that decision or is rejected.
88
+ *
89
+ * Decisions stay serialized; their storage overlaps (group commit). The Session stores the commits of several jobs in
90
+ * one call while the line runs on, and this memory changes only as each commit is published. So every decision reads
91
+ * it in a decision region (`#region()`): synchronous, recording the keys it reads (a task's record, the live work below
92
+ * a node, the cancellation intent set), staging nothing; when one of them has an unpublished writer, the region waits
93
+ * for its publication and runs again, and only a region that read nothing unpublished is applied. Every commit writes
94
+ * the memberships its task changes alter (`membershipKeys()`), so a walk that a pending commit would change waits.
81
95
  */
82
96
  export declare class TaskScheduler {
83
97
  #private;
84
98
  constructor(options: TaskSchedulerOptions);
85
99
  /**
86
- * Load live tasks and change surviving `running` tasks back to `pending`, counting the restart. Dispatches nothing. A
87
- * task that reaches the restart limit this way is parked and reported.
100
+ * Load live tasks and change surviving `running` tasks back to `pending`, counting the restart. Dispatches nothing;
101
+ * a task cut off `settings.restartLimit` times ends when it is next reserved. Read-only, it only loads them: a
102
+ * `running` task stays as committed, running in another process.
88
103
  */
89
104
  open(context: Context): Promise<void>;
90
105
  /**
@@ -93,13 +108,8 @@ export declare class TaskScheduler {
93
108
  */
94
109
  resume(): void;
95
110
  /**
96
- * Run a task parked by the restart limit again: clears its restart count and enables scheduling. Does nothing for a
97
- * task that is not parked; rejects for an unknown one.
98
- */
99
- retry(id: TaskId, context: Context): Promise<void>;
100
- /**
101
- * Why a live task cannot run here, if it cannot: its definition (missing, too old, failed migration) or the restart
102
- * limit. A running task, an abort-marked one, and one holding its outcome are never blocked.
111
+ * Why a live task cannot run here, if it cannot: its definition is missing, too old, or failed to migrate. A running
112
+ * task, an abort-marked one, and one holding its outcome are never blocked.
103
113
  */
104
114
  blockedReason(record: BlockedSubject): BlockedReason | undefined;
105
115
  /** Call `listener` when blocked reasons may have changed without a commit: a registry change or a failed migration. */
@@ -135,8 +145,23 @@ export declare class TaskScheduler {
135
145
  * crosses background boundaries, and the wait also covers every task it reached.
136
146
  */
137
147
  abortConversation(conversationId: ConversationId, background: boolean, context: Context): Promise<void>;
148
+ /**
149
+ * The ownership memberships a commit's task and conversation changes write (group commit §4.2), at its admission on
150
+ * the line: for each task created or made terminal, every node from its parent up to and including the nearest live
151
+ * task, or the root conversation, and then the roots too, conservatively, as a pending end may unlist the root a
152
+ * creation finds listed; for each conversation created under a task, that task; and the intent set when
153
+ * a change sets, upgrades, or clears a mark or a held or ended outcome other than `completed`. Loads the chains it
154
+ * walks; the nodes it installs stay until the commit is published.
155
+ */
156
+ membershipKeys(tx: Transaction): readonly string[] | Promise<readonly string[]>;
138
157
  /** Sizes of the ownership indexes, for tests that bound the scheduler's memory. */
139
- get indexSizes(): Readonly<Record<"live" | "settled" | "edges" | "below" | "roots" | "unloaded" | "dropQueue", number>>;
158
+ get indexSizes(): Readonly<Record<"live" | "settled" | "edges" | "below" | "roots" | "unloaded" | "dropQueue" | "pins", number>>;
159
+ /**
160
+ * The kept contexts' idle state, for tests (a diagnostic, computed on demand): how many are kept and how many are
161
+ * idle, how many disagree with a full recompute (an idle period without `#idle()`, or `#idle()` without one; an
162
+ * expiry order that differs from the idle periods, or is not sorted), and how many idle checks covered every scope.
163
+ */
164
+ get idleState(): Readonly<Record<"contexts" | "idleContexts" | "idleMismatches" | "fullIdleChecks", number>>;
140
165
  /**
141
166
  * Scheduling state and every live task with its derived state, read on the Session line. Runs no task code: a
142
167
  * pending migration shows as `ready` with `migrates`, and only a migration the scheduler already tried, or one that
@@ -147,5 +172,7 @@ export declare class TaskScheduler {
147
172
  tasks: TaskInspection[];
148
173
  }>;
149
174
  }
175
+ /** `state`, marked as ending its task for crashes (`task_interrupted` with `message`), whatever its outcome. */
176
+ export declare function endedByCrashes<T extends object>(state: T, message: string): T;
150
177
  export {};
151
178
  //# sourceMappingURL=scheduler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../src/harness/scheduler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../src/harness/scheduler.ts"],"names":[],"mappings":"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"}