@earendil-works/pi-agent-core 0.87.1 → 0.99.1

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 (242) hide show
  1. package/README.md +4 -0
  2. package/dist/agent-loop.d.ts +27 -2
  3. package/dist/agent-loop.d.ts.map +1 -1
  4. package/dist/agent-loop.js +44 -15
  5. package/dist/agent-loop.js.map +1 -1
  6. package/dist/agent.d.ts +9 -0
  7. package/dist/agent.d.ts.map +1 -1
  8. package/dist/agent.js +3 -0
  9. package/dist/agent.js.map +1 -1
  10. package/dist/harness/agent-harness.d.ts.map +1 -1
  11. package/dist/harness/compaction/branch-summarization.d.ts.map +1 -1
  12. package/dist/harness/compaction/branch-summarization.js.map +1 -1
  13. package/dist/harness/compaction/compaction.d.ts.map +1 -1
  14. package/dist/harness/compaction/compaction.js.map +1 -1
  15. package/dist/harness/compaction/utils.d.ts.map +1 -1
  16. package/dist/harness/compaction/utils.js.map +1 -1
  17. package/dist/harness/config.d.ts.map +1 -1
  18. package/dist/harness/config.js.map +1 -1
  19. package/dist/harness/context.d.ts.map +1 -1
  20. package/dist/harness/context.js.map +1 -1
  21. package/dist/harness/env/nodejs.d.ts.map +1 -1
  22. package/dist/harness/env/nodejs.js.map +1 -1
  23. package/dist/harness/events.d.ts.map +1 -1
  24. package/dist/harness/events.js.map +1 -1
  25. package/dist/harness/execution/assistant.d.ts.map +1 -1
  26. package/dist/harness/execution/assistant.js.map +1 -1
  27. package/dist/harness/execution/effect-gate.d.ts.map +1 -1
  28. package/dist/harness/execution/effect-gate.js.map +1 -1
  29. package/dist/harness/execution/tools.d.ts.map +1 -1
  30. package/dist/harness/execution/tools.js.map +1 -1
  31. package/dist/harness/hooks.d.ts.map +1 -1
  32. package/dist/harness/hooks.js.map +1 -1
  33. package/dist/harness/messages.d.ts.map +1 -1
  34. package/dist/harness/messages.js.map +1 -1
  35. package/dist/harness/pico3/bash.d.ts.map +1 -1
  36. package/dist/harness/pico3/bash.js.map +1 -1
  37. package/dist/harness/pico3/bounded.d.ts.map +1 -1
  38. package/dist/harness/pico3/bounded.js.map +1 -1
  39. package/dist/harness/pico3/chord.d.ts.map +1 -1
  40. package/dist/harness/pico3/chord.js.map +1 -1
  41. package/dist/harness/pico3/context.d.ts.map +1 -1
  42. package/dist/harness/pico3/context.js.map +1 -1
  43. package/dist/harness/pico3/harness.d.ts +4 -3
  44. package/dist/harness/pico3/harness.d.ts.map +1 -1
  45. package/dist/harness/pico3/harness.js.map +1 -1
  46. package/dist/harness/pico3/hooks.d.ts +2 -2
  47. package/dist/harness/pico3/hooks.d.ts.map +1 -1
  48. package/dist/harness/pico3/hooks.js.map +1 -1
  49. package/dist/harness/pico3/index.d.ts.map +1 -1
  50. package/dist/harness/pico3/jsonl.d.ts.map +1 -1
  51. package/dist/harness/pico3/jsonl.js.map +1 -1
  52. package/dist/harness/pico3/kinds/collapse.d.ts.map +1 -1
  53. package/dist/harness/pico3/kinds/collapse.js.map +1 -1
  54. package/dist/harness/pico3/kinds/entries.d.ts.map +1 -1
  55. package/dist/harness/pico3/kinds/frames.d.ts.map +1 -1
  56. package/dist/harness/pico3/kinds/frames.js.map +1 -1
  57. package/dist/harness/pico3/kinds/generation.d.ts.map +1 -1
  58. package/dist/harness/pico3/kinds/generation.js.map +1 -1
  59. package/dist/harness/pico3/kinds/job.d.ts.map +1 -1
  60. package/dist/harness/pico3/kinds/job.js.map +1 -1
  61. package/dist/harness/pico3/kinds/plugin.d.ts.map +1 -1
  62. package/dist/harness/pico3/kinds/plugin.js.map +1 -1
  63. package/dist/harness/pico3/kinds/post-tools.d.ts.map +1 -1
  64. package/dist/harness/pico3/kinds/post-tools.js.map +1 -1
  65. package/dist/harness/pico3/kinds/task-api.d.ts.map +1 -1
  66. package/dist/harness/pico3/kinds/task-api.js.map +1 -1
  67. package/dist/harness/pico3/kinds/tool.d.ts.map +1 -1
  68. package/dist/harness/pico3/kinds/tool.js.map +1 -1
  69. package/dist/harness/pico3/legacy-tracker.d.ts +11 -0
  70. package/dist/harness/pico3/legacy-tracker.d.ts.map +1 -0
  71. package/dist/harness/pico3/legacy-tracker.js +41 -0
  72. package/dist/harness/pico3/legacy-tracker.js.map +1 -0
  73. package/dist/harness/pico3/membrane.d.ts.map +1 -1
  74. package/dist/harness/pico3/membrane.js.map +1 -1
  75. package/dist/harness/pico3/memory.d.ts +1 -1
  76. package/dist/harness/pico3/memory.d.ts.map +1 -1
  77. package/dist/harness/pico3/memory.js.map +1 -1
  78. package/dist/harness/pico3/scheduler.d.ts +3 -0
  79. package/dist/harness/pico3/scheduler.d.ts.map +1 -1
  80. package/dist/harness/pico3/scheduler.js.map +1 -1
  81. package/dist/harness/pico3/session.d.ts +3 -2
  82. package/dist/harness/pico3/session.d.ts.map +1 -1
  83. package/dist/harness/pico3/session.js +5 -4
  84. package/dist/harness/pico3/session.js.map +1 -1
  85. package/dist/harness/pico3/system.d.ts +1 -1
  86. package/dist/harness/pico3/system.d.ts.map +1 -1
  87. package/dist/harness/pico3/system.js.map +1 -1
  88. package/dist/harness/pico3/types.d.ts +1 -1
  89. package/dist/harness/pico3/types.d.ts.map +1 -1
  90. package/dist/harness/pico3/types.js.map +1 -1
  91. package/dist/harness/pico3/view.d.ts.map +1 -1
  92. package/dist/harness/pico3/view.js +6 -12
  93. package/dist/harness/pico3/view.js.map +1 -1
  94. package/dist/harness/prompt-templates.d.ts.map +1 -1
  95. package/dist/harness/prompt-templates.js.map +1 -1
  96. package/dist/harness/result.d.ts.map +1 -1
  97. package/dist/harness/result.js.map +1 -1
  98. package/dist/harness/runtime/drive/boundary.d.ts.map +1 -1
  99. package/dist/harness/runtime/drive/boundary.js.map +1 -1
  100. package/dist/harness/runtime/drive/checkpoint.d.ts.map +1 -1
  101. package/dist/harness/runtime/drive/checkpoint.js.map +1 -1
  102. package/dist/harness/runtime/drive/deferred.d.ts.map +1 -1
  103. package/dist/harness/runtime/drive/deferred.js.map +1 -1
  104. package/dist/harness/runtime/drive/generation.d.ts.map +1 -1
  105. package/dist/harness/runtime/drive/generation.js.map +1 -1
  106. package/dist/harness/runtime/drive/reconcile.d.ts.map +1 -1
  107. package/dist/harness/runtime/drive/reconcile.js.map +1 -1
  108. package/dist/harness/runtime/drive/recovery.d.ts.map +1 -1
  109. package/dist/harness/runtime/drive/recovery.js.map +1 -1
  110. package/dist/harness/runtime/drive/response.d.ts.map +1 -1
  111. package/dist/harness/runtime/drive/response.js.map +1 -1
  112. package/dist/harness/runtime/drive/retry.d.ts.map +1 -1
  113. package/dist/harness/runtime/drive/retry.js.map +1 -1
  114. package/dist/harness/runtime/drive/structural.d.ts.map +1 -1
  115. package/dist/harness/runtime/drive/structural.js.map +1 -1
  116. package/dist/harness/runtime/drive/terminal.d.ts.map +1 -1
  117. package/dist/harness/runtime/drive/terminal.js.map +1 -1
  118. package/dist/harness/runtime/drive/tool-placement.d.ts.map +1 -1
  119. package/dist/harness/runtime/drive/tool-placement.js.map +1 -1
  120. package/dist/harness/runtime/drive/tools.d.ts.map +1 -1
  121. package/dist/harness/runtime/drive/tools.js.map +1 -1
  122. package/dist/harness/runtime/drive.d.ts.map +1 -1
  123. package/dist/harness/runtime/drive.js.map +1 -1
  124. package/dist/harness/runtime/harness.d.ts.map +1 -1
  125. package/dist/harness/runtime/harness.js.map +1 -1
  126. package/dist/harness/runtime/index.d.ts.map +1 -1
  127. package/dist/harness/runtime/lane.d.ts +17 -0
  128. package/dist/harness/runtime/lane.d.ts.map +1 -1
  129. package/dist/harness/runtime/lane.js.map +1 -1
  130. package/dist/harness/runtime/progress.d.ts.map +1 -1
  131. package/dist/harness/runtime/progress.js.map +1 -1
  132. package/dist/harness/runtime/reducer.d.ts.map +1 -1
  133. package/dist/harness/runtime/reducer.js.map +1 -1
  134. package/dist/harness/runtime/restore.d.ts.map +1 -1
  135. package/dist/harness/runtime/restore.js.map +1 -1
  136. package/dist/harness/runtime/transcript.d.ts.map +1 -1
  137. package/dist/harness/runtime/transcript.js.map +1 -1
  138. package/dist/harness/runtime/types.d.ts.map +1 -1
  139. package/dist/harness/runtime/types.js.map +1 -1
  140. package/dist/harness/session/commit.d.ts.map +1 -1
  141. package/dist/harness/session/commit.js.map +1 -1
  142. package/dist/harness/session/context.d.ts.map +1 -1
  143. package/dist/harness/session/context.js.map +1 -1
  144. package/dist/harness/session/fork-policy.d.ts.map +1 -1
  145. package/dist/harness/session/fork-policy.js.map +1 -1
  146. package/dist/harness/session/fork.d.ts.map +1 -1
  147. package/dist/harness/session/fork.js.map +1 -1
  148. package/dist/harness/session/in-memory-storage-state.d.ts.map +1 -1
  149. package/dist/harness/session/in-memory-storage-state.js.map +1 -1
  150. package/dist/harness/session/index.d.ts.map +1 -1
  151. package/dist/harness/session/jsonl/codec.d.ts.map +1 -1
  152. package/dist/harness/session/jsonl/codec.js.map +1 -1
  153. package/dist/harness/session/jsonl/fork.d.ts.map +1 -1
  154. package/dist/harness/session/jsonl/fork.js.map +1 -1
  155. package/dist/harness/session/jsonl/index.d.ts.map +1 -1
  156. package/dist/harness/session/jsonl/io.d.ts.map +1 -1
  157. package/dist/harness/session/jsonl/io.js.map +1 -1
  158. package/dist/harness/session/jsonl/legacy-v3.d.ts +1 -0
  159. package/dist/harness/session/jsonl/legacy-v3.d.ts.map +1 -1
  160. package/dist/harness/session/jsonl/legacy-v3.js.map +1 -1
  161. package/dist/harness/session/jsonl/repo.d.ts.map +1 -1
  162. package/dist/harness/session/jsonl/repo.js.map +1 -1
  163. package/dist/harness/session/jsonl/storage.d.ts +1 -0
  164. package/dist/harness/session/jsonl/storage.d.ts.map +1 -1
  165. package/dist/harness/session/jsonl/storage.js.map +1 -1
  166. package/dist/harness/session/jsonl/types.d.ts.map +1 -1
  167. package/dist/harness/session/memory.d.ts.map +1 -1
  168. package/dist/harness/session/memory.js.map +1 -1
  169. package/dist/harness/session/mutation-line.d.ts.map +1 -1
  170. package/dist/harness/session/mutation-line.js.map +1 -1
  171. package/dist/harness/session/session.d.ts.map +1 -1
  172. package/dist/harness/session/session.js.map +1 -1
  173. package/dist/harness/session/testing/benchmark/datasets.d.ts.map +1 -1
  174. package/dist/harness/session/testing/benchmark/datasets.js.map +1 -1
  175. package/dist/harness/session/testing/benchmark/session-repo.d.ts.map +1 -1
  176. package/dist/harness/session/testing/benchmark/session-repo.js.map +1 -1
  177. package/dist/harness/session/testing/benchmark/storage.d.ts.map +1 -1
  178. package/dist/harness/session/testing/benchmark/storage.js.map +1 -1
  179. package/dist/harness/session/testing/conformance/session-repo.d.ts.map +1 -1
  180. package/dist/harness/session/testing/conformance/session-repo.js.map +1 -1
  181. package/dist/harness/session/testing/conformance/storage.d.ts.map +1 -1
  182. package/dist/harness/session/testing/conformance/storage.js.map +1 -1
  183. package/dist/harness/session/testing/gating-storage.d.ts.map +1 -1
  184. package/dist/harness/session/testing/gating-storage.js.map +1 -1
  185. package/dist/harness/session/testing/index.d.ts.map +1 -1
  186. package/dist/harness/session/testing/instrumented-storage.d.ts.map +1 -1
  187. package/dist/harness/session/testing/instrumented-storage.js.map +1 -1
  188. package/dist/harness/session/testing/storage-decorator.d.ts.map +1 -1
  189. package/dist/harness/session/testing/storage-decorator.js.map +1 -1
  190. package/dist/harness/session/testing/types.d.ts.map +1 -1
  191. package/dist/harness/session/types.d.ts.map +1 -1
  192. package/dist/harness/session/types.js.map +1 -1
  193. package/dist/harness/session/values.d.ts +2 -2
  194. package/dist/harness/session/values.d.ts.map +1 -1
  195. package/dist/harness/session/values.js.map +1 -1
  196. package/dist/harness/skills.d.ts.map +1 -1
  197. package/dist/harness/skills.js.map +1 -1
  198. package/dist/harness/system-prompt.d.ts.map +1 -1
  199. package/dist/harness/system-prompt.js.map +1 -1
  200. package/dist/harness/telemetry.d.ts.map +1 -1
  201. package/dist/harness/telemetry.js.map +1 -1
  202. package/dist/harness/tools/bash.d.ts.map +1 -1
  203. package/dist/harness/tools/bash.js.map +1 -1
  204. package/dist/harness/tools/edit-diff.d.ts.map +1 -1
  205. package/dist/harness/tools/edit-diff.js.map +1 -1
  206. package/dist/harness/tools/edit.d.ts.map +1 -1
  207. package/dist/harness/tools/edit.js.map +1 -1
  208. package/dist/harness/tools/file-mutation-queue.d.ts.map +1 -1
  209. package/dist/harness/tools/file-mutation-queue.js.map +1 -1
  210. package/dist/harness/tools/image.d.ts.map +1 -1
  211. package/dist/harness/tools/image.js.map +1 -1
  212. package/dist/harness/tools/index.d.ts.map +1 -1
  213. package/dist/harness/tools/path-utils.d.ts.map +1 -1
  214. package/dist/harness/tools/path-utils.js.map +1 -1
  215. package/dist/harness/tools/read.d.ts.map +1 -1
  216. package/dist/harness/tools/read.js.map +1 -1
  217. package/dist/harness/tools/tool-context.d.ts.map +1 -1
  218. package/dist/harness/tools/write.d.ts.map +1 -1
  219. package/dist/harness/tools/write.js.map +1 -1
  220. package/dist/harness/types.d.ts.map +1 -1
  221. package/dist/harness/types.js.map +1 -1
  222. package/dist/harness/utils/adaptive-publisher.d.ts.map +1 -1
  223. package/dist/harness/utils/adaptive-publisher.js.map +1 -1
  224. package/dist/harness/utils/output-capture.d.ts.map +1 -1
  225. package/dist/harness/utils/output-capture.js.map +1 -1
  226. package/dist/harness/utils/shell-output.d.ts.map +1 -1
  227. package/dist/harness/utils/shell-output.js.map +1 -1
  228. package/dist/harness/utils/truncate.d.ts.map +1 -1
  229. package/dist/harness/utils/truncate.js.map +1 -1
  230. package/dist/harness/utils/usage.d.ts.map +1 -1
  231. package/dist/harness/utils/usage.js.map +1 -1
  232. package/dist/index.d.ts.map +1 -1
  233. package/dist/node.d.ts.map +1 -1
  234. package/dist/proxy.d.ts.map +1 -1
  235. package/dist/proxy.js.map +1 -1
  236. package/dist/search/index.d.ts.map +1 -1
  237. package/dist/stream-fn.d.ts.map +1 -1
  238. package/dist/stream-fn.js.map +1 -1
  239. package/dist/types.d.ts +30 -2
  240. package/dist/types.d.ts.map +1 -1
  241. package/dist/types.js.map +1 -1
  242. package/package.json +9 -10
@@ -1 +1 @@
1
- {"version":3,"file":"jsonl.d.ts","sourceRoot":"","sources":["../../../src/harness/pico3/jsonl.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAGrD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAM,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAUlE;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,YAAa,SAAQ,aAAc,YAAW,OAAO;IACjE,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyB;IAClD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAyB;IACtD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,OAAO,CAAC,UAAU,CAAS;IAE3B,OAAO,eAKN;IAED,OAAa,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO,CAAC,YAAY,CAAC,CAWpF;IAED,mEAAmE;IACnE,KAAK,IAAI;QAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAIlC;YAEa,MAAM;IAsGL,MAAM,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAoC1E;IACD,OAAO,CAAC,WAAW;IAkBnB,OAAO,CAAC,MAAM;IAKd,OAAO,CAAC,OAAO;IAQf,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,iBAAiB;IASzB,oHAAoH;IACrG,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CA8BlE;IAEc,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,iBAOlC;CACD","sourcesContent":["import {\n\tcloseSync,\n\texistsSync,\n\tfsyncSync,\n\tftruncateSync,\n\tmkdirSync,\n\topenSync,\n\treaddirSync,\n\treadFileSync,\n\trenameSync,\n\tstatSync,\n\tunlinkSync,\n\twriteSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { Context } from \"@earendil-works/chord\";\nimport { BACKGROUND_CONTEXT } from \"@earendil-works/chord/context\";\nimport { isBase, type Op } from \"@earendil-works/chord/delta\";\nimport { MemoryStorage } from \"./memory.ts\";\nimport type { DocRef, Id, Seq, Storage, Write } from \"./types.ts\";\n\n/** One line of any file. `refs` (main only) lists the sidecar files this commit also wrote. */\ninterface Record_ {\n\tseq: Seq;\n\tmaxId: Id;\n\twrites: Write[];\n\trefs?: string[];\n}\n\n/**\n * Files in a session directory:\n * main.jsonl conversations, entries, inputs, rewindable/session doc ops, each task's\n * CREATE and TERMINAL records, and one marker per commit. Append-only, never rewritten.\n * sticky-<conversation>.jsonl sticky doc ops; rewritten from its last base by `truncate` (on the Session line)\n * task-<id>.jsonl a live task's intermediate patches (running, checkpoints); unlinked after its\n * terminal record is published in main\n *\n * Publication (§10): one commit `Seq`; sidecar records are appended first, then exactly one main\n * record, last, listing the sidecar refs it expects — the publication point. Replay applies a sidecar\n * record only when main has the marker for that seq naming that file; unconfirmed sidecar tails are\n * ignored. Every record carries the committed-ID high-water. Bytes after the last newline of any file\n * are a torn write and are truncated before the file is opened for append. There is no compaction.\n *\n * With `fsync: false`, recovery covers process termination while the OS and filesystem remain alive.\n * It does not promise that an acknowledged commit survives power loss, kernel/host failure,\n * storage-cache loss, or a filesystem that loses/reorders completed writes. An acknowledged tail may\n * roll back, or a surviving main marker may reference a missing sidecar and make open fail rather\n * than expose partial state. A lost pre-effect checkpoint can cause an external effect to be attempted\n * again; external idempotency remains required.\n *\n * With `fsync: true`, each sidecar is flushed before the main publication marker is flushed. This\n * strengthens file-data durability and ordering across machine failure. It is not a complete database\n * guarantee: newly created files, renames, and unlinks are not followed by a parent-directory fsync,\n * and storage hardware/filesystems may provide weaker guarantees.\n *\n * One process owns a directory at a time; a second process is unsupported.\n */\nexport class JsonlStorage extends MemoryStorage implements Storage {\n\tprivate mainFd: number;\n\tprivate readonly sidecars = new Map<Id, number>(); // sticky docs, by conversation\n\tprivate readonly taskSidecars = new Map<Id, number>();\n\tprivate readonly dir: string;\n\treadonly fsync: boolean;\n\tprivate closedOnce = false;\n\n\tprivate constructor(dir: string, fsync: boolean) {\n\t\tsuper();\n\t\tthis.dir = dir;\n\t\tthis.fsync = fsync;\n\t\tthis.mainFd = openSync(join(dir, \"main.jsonl\"), \"a\");\n\t}\n\n\tstatic async open(dir: string, opts: { fsync?: boolean } = {}): Promise<JsonlStorage> {\n\t\tmkdirSync(dir, { recursive: true });\n\t\tfor (const f of readdirSync(dir)) if (f.endsWith(\".jsonl\")) truncateTornTail(join(dir, f));\n\t\tconst storage = new JsonlStorage(dir, opts.fsync ?? true);\n\t\ttry {\n\t\t\tawait storage.replay();\n\t\t\treturn storage;\n\t\t} catch (error) {\n\t\t\tawait storage.close();\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/** For tests and tooling: sizes of every file in the directory. */\n\tsizes(): { [file: string]: number } {\n\t\tconst out: { [file: string]: number } = {};\n\t\tfor (const f of readdirSync(this.dir)) out[f] = statSync(join(this.dir, f)).size;\n\t\treturn out;\n\t}\n\n\tprivate async replay() {\n\t\tconst read = (file: string): { record: Record_; end: number }[] => {\n\t\t\tif (!existsSync(file)) return [];\n\t\t\tconst bytes = readFileSync(file);\n\t\t\tconst out: { record: Record_; end: number }[] = [];\n\t\t\tlet start = 0;\n\t\t\tlet last = 0;\n\t\t\tfor (let end = bytes.indexOf(0x0a, start); end >= 0; end = bytes.indexOf(0x0a, start)) {\n\t\t\t\tconst line = bytes.subarray(start, end).toString(\"utf8\");\n\t\t\t\tstart = end + 1;\n\t\t\t\tif (line === \"\") continue;\n\t\t\t\tlet record: Record_;\n\t\t\t\ttry {\n\t\t\t\t\trecord = JSON.parse(line) as Record_;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthrow new Error(`${file}: malformed record: ${String(error)}`);\n\t\t\t\t}\n\t\t\t\tif (typeof record.seq !== \"number\" || typeof record.maxId !== \"number\" || !Array.isArray(record.writes))\n\t\t\t\t\tthrow new Error(`${file}: record lacks seq/maxId/writes`);\n\t\t\t\tif (record.seq <= last) throw new Error(`${file}: sequence not increasing at ${record.seq}`);\n\t\t\t\tlast = record.seq;\n\t\t\t\tout.push({ record, end: start });\n\t\t\t}\n\t\t\treturn out;\n\t\t};\n\t\tlet maxId = 0;\n\t\t// Main is the commit log. Confirmed = (seq → refs) for every marker.\n\t\tconst main = read(join(this.dir, \"main.jsonl\")).map(({ record }) => record);\n\t\tconst confirmed = new Map<Seq, Set<string>>();\n\t\tfor (const record of main) confirmed.set(record.seq, new Set(record.refs ?? []));\n\t\t// Merge every file's records by seq so batches apply in commit order.\n\t\tconst sidecarFiles = readdirSync(this.dir).filter(\n\t\t\t(file) => file.startsWith(\"sticky-\") || file.startsWith(\"task-\"),\n\t\t);\n\t\tconst bySeq = new Map<Seq, Write[]>();\n\t\tconst found = new Map<Seq, Set<string>>();\n\t\tconst retainedStickyBase = new Map<string, Seq>();\n\t\tconst retiredTasks = new Map<Id, Seq>();\n\t\tfor (const record of main) {\n\t\t\tfor (const write of record.writes) {\n\t\t\t\tif (write.type === \"task.patch\" && write.patch.status === \"terminal\")\n\t\t\t\t\tretiredTasks.set(write.patch.id, record.seq);\n\t\t\t}\n\t\t\tbySeq.set(record.seq, [...record.writes]);\n\t\t\tmaxId = Math.max(maxId, record.maxId);\n\t\t}\n\t\tfor (const file of sidecarFiles) {\n\t\t\tconst path = join(this.dir, file);\n\t\t\tconst records = read(path);\n\t\t\tconst first = records[0]?.record;\n\t\t\tif (\n\t\t\t\tfile.startsWith(\"sticky-\") &&\n\t\t\t\tfirst !== undefined &&\n\t\t\t\tisBase(first.writes.flatMap((write) => (write.type === \"doc\" ? write.ops : [])))\n\t\t\t) {\n\t\t\t\tretainedStickyBase.set(file, first.seq);\n\t\t\t}\n\t\t\tlet confirmedEnd = 0;\n\t\t\tlet sawUnconfirmed = false;\n\t\t\tfor (const { record, end } of records) {\n\t\t\t\tif (!confirmed.get(record.seq)?.has(file)) {\n\t\t\t\t\tsawUnconfirmed = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (sawUnconfirmed)\n\t\t\t\t\tthrow new Error(`${path}: confirmed record follows an unconfirmed tail at ${record.seq}`);\n\t\t\t\tconfirmedEnd = end;\n\t\t\t\tconst files = found.get(record.seq) ?? new Set<string>();\n\t\t\t\tfiles.add(file);\n\t\t\t\tfound.set(record.seq, files);\n\t\t\t\tbySeq.get(record.seq)!.push(...record.writes);\n\t\t\t\tmaxId = Math.max(maxId, record.maxId);\n\t\t\t}\n\t\t\tif (sawUnconfirmed) truncateTo(path, confirmedEnd);\n\t\t}\n\t\tfor (const record of main) {\n\t\t\tfor (const file of record.refs ?? []) {\n\t\t\t\tif (found.get(record.seq)?.has(file)) continue;\n\t\t\t\tconst retainedFrom = retainedStickyBase.get(file);\n\t\t\t\tif (retainedFrom !== undefined && record.seq < retainedFrom) continue;\n\t\t\t\tif (file.startsWith(\"task-\")) {\n\t\t\t\t\tconst id = Number(file.slice(5, -6));\n\t\t\t\t\tconst retiredAt = retiredTasks.get(id);\n\t\t\t\t\tif (retiredAt !== undefined && record.seq < retiredAt) continue;\n\t\t\t\t}\n\t\t\t\tthrow new Error(`${join(this.dir, file)}: missing record for published sequence ${record.seq}`);\n\t\t\t}\n\t\t}\n\t\tfor (const seq of [...bySeq.keys()].sort((a, b) => a - b)) {\n\t\t\tthis.seq = seq - 1;\n\t\t\tawait super.commit(bySeq.get(seq)!, BACKGROUND_CONTEXT);\n\t\t}\n\t\tthis.setNextId(maxId + 1);\n\t\t// Task sidecars belong to live tasks only; a leftover for a terminal (or unknown) task cannot resurrect anything.\n\t\tfor (const f of sidecarFiles) {\n\t\t\tif (!f.startsWith(\"task-\")) continue;\n\t\t\tconst id = Number(f.slice(5, -6));\n\t\t\tconst t = await super.task(id);\n\t\t\tif (t === undefined || t.status === \"terminal\") unlinkSync(join(this.dir, f));\n\t\t}\n\t}\n\n\toverride async commit(writes: readonly Write[], ctx: Context): Promise<Seq> {\n\t\tif (this.closedOnce) throw new Error(\"storage closed\");\n\t\tconst seq = this.seq + 1;\n\t\tconst apply = this.stage(writes, seq); // validates the whole batch first; throws before any file is touched\n\t\tconst maxId = this.nextIdAfter(writes);\n\t\tconst main: Write[] = [];\n\t\tconst sticky = new Map<Id, Write[]>();\n\t\tconst tasks = new Map<Id, Write[]>();\n\t\tconst retired: Id[] = [];\n\t\tfor (const w of writes) {\n\t\t\tif (w.type === \"doc\" && w.ref.doc === \"sticky\")\n\t\t\t\t(sticky.get(w.ref.conversationId) ?? sticky.set(w.ref.conversationId, []).get(w.ref.conversationId)!).push(\n\t\t\t\t\tw,\n\t\t\t\t);\n\t\t\telse if (w.type === \"task.patch\" && w.patch.status !== \"terminal\")\n\t\t\t\t(tasks.get(w.patch.id) ?? tasks.set(w.patch.id, []).get(w.patch.id)!).push(w);\n\t\t\telse {\n\t\t\t\tmain.push(w);\n\t\t\t\tif (w.type === \"task.patch\" && w.patch.status === \"terminal\") retired.push(w.patch.id);\n\t\t\t}\n\t\t}\n\t\tconst refs: string[] = [];\n\t\tfor (const [id, ws] of tasks) {\n\t\t\tthis.append(this.taskSidecar(id), { seq, maxId, writes: ws });\n\t\t\trefs.push(`task-${id}.jsonl`);\n\t\t}\n\t\tfor (const [c, ws] of sticky) {\n\t\t\tthis.append(this.sidecar(c), { seq, maxId, writes: ws });\n\t\t\trefs.push(`sticky-${c}.jsonl`);\n\t\t}\n\t\tthis.append(this.mainFd, { seq, maxId, writes: main, ...(refs.length ? { refs } : {}) }); // the publication point\n\t\tapply();\n\t\tthis.seq = seq;\n\t\tfor (const id of retired) this.retireTaskSidecar(id); // after the terminal record is durably published\n\t\tvoid ctx;\n\t\treturn seq;\n\t}\n\tprivate nextIdAfter(writes: readonly Write[]): Id {\n\t\tlet max = this.nextIdValue - 1;\n\t\tfor (const w of writes) {\n\t\t\tconst id =\n\t\t\t\tw.type === \"conversation\"\n\t\t\t\t\t? w.conversation.id\n\t\t\t\t\t: w.type === \"entry\"\n\t\t\t\t\t\t? w.entry.id\n\t\t\t\t\t\t: w.type === \"task\"\n\t\t\t\t\t\t\t? w.task.id\n\t\t\t\t\t\t\t: w.type === \"input\"\n\t\t\t\t\t\t\t\t? w.input.id\n\t\t\t\t\t\t\t\t: 0;\n\t\t\tmax = Math.max(max, id);\n\t\t}\n\t\treturn max;\n\t}\n\n\tprivate append(fd: number, record: Record_) {\n\t\twriteSync(fd, `${JSON.stringify(record)}\\n`);\n\t\tif (this.fsync) fsyncSync(fd);\n\t}\n\n\tprivate sidecar(conversationId: Id): number {\n\t\tlet fd = this.sidecars.get(conversationId);\n\t\tif (fd === undefined) {\n\t\t\tfd = openSync(join(this.dir, `sticky-${conversationId}.jsonl`), \"a\");\n\t\t\tthis.sidecars.set(conversationId, fd);\n\t\t}\n\t\treturn fd;\n\t}\n\tprivate taskSidecar(id: Id): number {\n\t\tlet fd = this.taskSidecars.get(id);\n\t\tif (fd === undefined) {\n\t\t\tfd = openSync(join(this.dir, `task-${id}.jsonl`), \"a\");\n\t\t\tthis.taskSidecars.set(id, fd);\n\t\t}\n\t\treturn fd;\n\t}\n\tprivate retireTaskSidecar(id: Id) {\n\t\tconst fd = this.taskSidecars.get(id);\n\t\tif (fd !== undefined) closeSync(fd);\n\t\tthis.taskSidecars.delete(id);\n\t\ttry {\n\t\t\tunlinkSync(join(this.dir, `task-${id}.jsonl`));\n\t\t} catch {}\n\t}\n\n\t/** Rewrite the sticky sidecar from its last base: temp file, optional fsync, rename. Called on the Session line. */\n\toverride async truncate(ref: DocRef, _ctx?: Context): Promise<void> {\n\t\tawait super.truncate(ref);\n\t\tif (ref.doc !== \"sticky\") return;\n\t\tconst file = join(this.dir, `sticky-${ref.conversationId}.jsonl`);\n\t\tif (!existsSync(file)) return;\n\t\tconst lines = readFileSync(file, \"utf8\").split(\"\\n\").filter(Boolean);\n\t\tlet start = 0;\n\t\tfor (let i = lines.length - 1; i >= 0; i--)\n\t\t\tif (\n\t\t\t\tisBase((JSON.parse(lines[i]!) as Record_).writes.flatMap((w) => (w.type === \"doc\" ? w.ops : [])) as Op[])\n\t\t\t) {\n\t\t\t\tstart = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\tif (start === 0) return;\n\t\tconst tmp = `${file}.tmp`;\n\t\tconst fd = openSync(tmp, \"w\");\n\t\twriteSync(\n\t\t\tfd,\n\t\t\tlines\n\t\t\t\t.slice(start)\n\t\t\t\t.map((l) => `${l}\\n`)\n\t\t\t\t.join(\"\"),\n\t\t);\n\t\tif (this.fsync) fsyncSync(fd);\n\t\tcloseSync(fd);\n\t\tconst old = this.sidecars.get(ref.conversationId);\n\t\tif (old !== undefined) closeSync(old);\n\t\trenameSync(tmp, file);\n\t\tthis.sidecars.set(ref.conversationId, openSync(file, \"a\"));\n\t}\n\n\toverride async close(_ctx?: Context) {\n\t\tif (this.closedOnce) return;\n\t\tthis.closedOnce = true;\n\t\tawait super.close();\n\t\tcloseSync(this.mainFd);\n\t\tfor (const fd of this.sidecars.values()) closeSync(fd);\n\t\tfor (const fd of this.taskSidecars.values()) closeSync(fd);\n\t}\n}\n\nfunction truncateTo(file: string, length: number): void {\n\tconst fd = openSync(file, \"r+\");\n\ttry {\n\t\tftruncateSync(fd, length);\n\t} finally {\n\t\tcloseSync(fd);\n\t}\n}\n\n/** Bytes after the last newline are a torn write: cut them so a later append cannot extend a corrupt line. */\nfunction truncateTornTail(file: string) {\n\tconst size = statSync(file).size;\n\tif (size === 0) return;\n\tconst buf = readFileSync(file);\n\tconst end = buf.lastIndexOf(0x0a);\n\tif (end + 1 !== buf.length) truncateTo(file, end + 1);\n}\n"]}
1
+ {"version":3,"file":"jsonl.d.ts","sourceRoot":"","sources":["../../../src/harness/pico3/jsonl.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAGrD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAM,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAUlE;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,YAAa,SAAQ,aAAc,YAAW,OAAO;IACjE,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyB;IAClD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAyB;IACtD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,OAAO,CAAC,UAAU,CAAS;IAE3B,OAAO,eAKN;IAED,OAAa,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO,CAAC,YAAY,CAAC,CAWpF;IAED,mEAAmE;IACnE,KAAK,IAAI;QAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAIlC;YAEa,MAAM;IAsGL,MAAM,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAoC1E;IACD,OAAO,CAAC,WAAW;IAkBnB,OAAO,CAAC,MAAM;IAKd,OAAO,CAAC,OAAO;IAQf,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,iBAAiB;IASzB,oHAAoH;IACrG,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CA8BlE;IAEc,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,iBAOlC;CACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"jsonl.js","sourceRoot":"","sources":["../../../src/harness/pico3/jsonl.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tcloseSync,\n\texistsSync,\n\tfsyncSync,\n\tftruncateSync,\n\tmkdirSync,\n\topenSync,\n\treaddirSync,\n\treadFileSync,\n\trenameSync,\n\tstatSync,\n\tunlinkSync,\n\twriteSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { Context } from \"@earendil-works/chord\";\nimport { BACKGROUND_CONTEXT } from \"@earendil-works/chord/context\";\nimport { isBase, type Op } from \"@earendil-works/chord/delta\";\nimport { MemoryStorage } from \"./memory.ts\";\nimport type { DocRef, Id, Seq, Storage, Write } from \"./types.ts\";\n\n/** One line of any file. `refs` (main only) lists the sidecar files this commit also wrote. */\ninterface Record_ {\n\tseq: Seq;\n\tmaxId: Id;\n\twrites: Write[];\n\trefs?: string[];\n}\n\n/**\n * Files in a session directory:\n * main.jsonl conversations, entries, inputs, rewindable/session doc ops, each task's\n * CREATE and TERMINAL records, and one marker per commit. Append-only, never rewritten.\n * sticky-<conversation>.jsonl sticky doc ops; rewritten from its last base by `truncate` (on the Session line)\n * task-<id>.jsonl a live task's intermediate patches (running, checkpoints); unlinked after its\n * terminal record is published in main\n *\n * Publication (§10): one commit `Seq`; sidecar records are appended first, then exactly one main\n * record, last, listing the sidecar refs it expects — the publication point. Replay applies a sidecar\n * record only when main has the marker for that seq naming that file; unconfirmed sidecar tails are\n * ignored. Every record carries the committed-ID high-water. Bytes after the last newline of any file\n * are a torn write and are truncated before the file is opened for append. There is no compaction.\n *\n * With `fsync: false`, recovery covers process termination while the OS and filesystem remain alive.\n * It does not promise that an acknowledged commit survives power loss, kernel/host failure,\n * storage-cache loss, or a filesystem that loses/reorders completed writes. An acknowledged tail may\n * roll back, or a surviving main marker may reference a missing sidecar and make open fail rather\n * than expose partial state. A lost pre-effect checkpoint can cause an external effect to be attempted\n * again; external idempotency remains required.\n *\n * With `fsync: true`, each sidecar is flushed before the main publication marker is flushed. This\n * strengthens file-data durability and ordering across machine failure. It is not a complete database\n * guarantee: newly created files, renames, and unlinks are not followed by a parent-directory fsync,\n * and storage hardware/filesystems may provide weaker guarantees.\n *\n * One process owns a directory at a time; a second process is unsupported.\n */\nexport class JsonlStorage extends MemoryStorage implements Storage {\n\tprivate mainFd: number;\n\tprivate readonly sidecars = new Map<Id, number>(); // sticky docs, by conversation\n\tprivate readonly taskSidecars = new Map<Id, number>();\n\tprivate readonly dir: string;\n\treadonly fsync: boolean;\n\tprivate closedOnce = false;\n\n\tprivate constructor(dir: string, fsync: boolean) {\n\t\tsuper();\n\t\tthis.dir = dir;\n\t\tthis.fsync = fsync;\n\t\tthis.mainFd = openSync(join(dir, \"main.jsonl\"), \"a\");\n\t}\n\n\tstatic async open(dir: string, opts: { fsync?: boolean } = {}): Promise<JsonlStorage> {\n\t\tmkdirSync(dir, { recursive: true });\n\t\tfor (const f of readdirSync(dir)) if (f.endsWith(\".jsonl\")) truncateTornTail(join(dir, f));\n\t\tconst storage = new JsonlStorage(dir, opts.fsync ?? true);\n\t\ttry {\n\t\t\tawait storage.replay();\n\t\t\treturn storage;\n\t\t} catch (error) {\n\t\t\tawait storage.close();\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/** For tests and tooling: sizes of every file in the directory. */\n\tsizes(): { [file: string]: number } {\n\t\tconst out: { [file: string]: number } = {};\n\t\tfor (const f of readdirSync(this.dir)) out[f] = statSync(join(this.dir, f)).size;\n\t\treturn out;\n\t}\n\n\tprivate async replay() {\n\t\tconst read = (file: string): { record: Record_; end: number }[] => {\n\t\t\tif (!existsSync(file)) return [];\n\t\t\tconst bytes = readFileSync(file);\n\t\t\tconst out: { record: Record_; end: number }[] = [];\n\t\t\tlet start = 0;\n\t\t\tlet last = 0;\n\t\t\tfor (let end = bytes.indexOf(0x0a, start); end >= 0; end = bytes.indexOf(0x0a, start)) {\n\t\t\t\tconst line = bytes.subarray(start, end).toString(\"utf8\");\n\t\t\t\tstart = end + 1;\n\t\t\t\tif (line === \"\") continue;\n\t\t\t\tlet record: Record_;\n\t\t\t\ttry {\n\t\t\t\t\trecord = JSON.parse(line) as Record_;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthrow new Error(`${file}: malformed record: ${String(error)}`);\n\t\t\t\t}\n\t\t\t\tif (typeof record.seq !== \"number\" || typeof record.maxId !== \"number\" || !Array.isArray(record.writes))\n\t\t\t\t\tthrow new Error(`${file}: record lacks seq/maxId/writes`);\n\t\t\t\tif (record.seq <= last) throw new Error(`${file}: sequence not increasing at ${record.seq}`);\n\t\t\t\tlast = record.seq;\n\t\t\t\tout.push({ record, end: start });\n\t\t\t}\n\t\t\treturn out;\n\t\t};\n\t\tlet maxId = 0;\n\t\t// Main is the commit log. Confirmed = (seq → refs) for every marker.\n\t\tconst main = read(join(this.dir, \"main.jsonl\")).map(({ record }) => record);\n\t\tconst confirmed = new Map<Seq, Set<string>>();\n\t\tfor (const record of main) confirmed.set(record.seq, new Set(record.refs ?? []));\n\t\t// Merge every file's records by seq so batches apply in commit order.\n\t\tconst sidecarFiles = readdirSync(this.dir).filter(\n\t\t\t(file) => file.startsWith(\"sticky-\") || file.startsWith(\"task-\"),\n\t\t);\n\t\tconst bySeq = new Map<Seq, Write[]>();\n\t\tconst found = new Map<Seq, Set<string>>();\n\t\tconst retainedStickyBase = new Map<string, Seq>();\n\t\tconst retiredTasks = new Map<Id, Seq>();\n\t\tfor (const record of main) {\n\t\t\tfor (const write of record.writes) {\n\t\t\t\tif (write.type === \"task.patch\" && write.patch.status === \"terminal\")\n\t\t\t\t\tretiredTasks.set(write.patch.id, record.seq);\n\t\t\t}\n\t\t\tbySeq.set(record.seq, [...record.writes]);\n\t\t\tmaxId = Math.max(maxId, record.maxId);\n\t\t}\n\t\tfor (const file of sidecarFiles) {\n\t\t\tconst path = join(this.dir, file);\n\t\t\tconst records = read(path);\n\t\t\tconst first = records[0]?.record;\n\t\t\tif (\n\t\t\t\tfile.startsWith(\"sticky-\") &&\n\t\t\t\tfirst !== undefined &&\n\t\t\t\tisBase(first.writes.flatMap((write) => (write.type === \"doc\" ? write.ops : [])))\n\t\t\t) {\n\t\t\t\tretainedStickyBase.set(file, first.seq);\n\t\t\t}\n\t\t\tlet confirmedEnd = 0;\n\t\t\tlet sawUnconfirmed = false;\n\t\t\tfor (const { record, end } of records) {\n\t\t\t\tif (!confirmed.get(record.seq)?.has(file)) {\n\t\t\t\t\tsawUnconfirmed = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (sawUnconfirmed)\n\t\t\t\t\tthrow new Error(`${path}: confirmed record follows an unconfirmed tail at ${record.seq}`);\n\t\t\t\tconfirmedEnd = end;\n\t\t\t\tconst files = found.get(record.seq) ?? new Set<string>();\n\t\t\t\tfiles.add(file);\n\t\t\t\tfound.set(record.seq, files);\n\t\t\t\tbySeq.get(record.seq)!.push(...record.writes);\n\t\t\t\tmaxId = Math.max(maxId, record.maxId);\n\t\t\t}\n\t\t\tif (sawUnconfirmed) truncateTo(path, confirmedEnd);\n\t\t}\n\t\tfor (const record of main) {\n\t\t\tfor (const file of record.refs ?? []) {\n\t\t\t\tif (found.get(record.seq)?.has(file)) continue;\n\t\t\t\tconst retainedFrom = retainedStickyBase.get(file);\n\t\t\t\tif (retainedFrom !== undefined && record.seq < retainedFrom) continue;\n\t\t\t\tif (file.startsWith(\"task-\")) {\n\t\t\t\t\tconst id = Number(file.slice(5, -6));\n\t\t\t\t\tconst retiredAt = retiredTasks.get(id);\n\t\t\t\t\tif (retiredAt !== undefined && record.seq < retiredAt) continue;\n\t\t\t\t}\n\t\t\t\tthrow new Error(`${join(this.dir, file)}: missing record for published sequence ${record.seq}`);\n\t\t\t}\n\t\t}\n\t\tfor (const seq of [...bySeq.keys()].sort((a, b) => a - b)) {\n\t\t\tthis.seq = seq - 1;\n\t\t\tawait super.commit(bySeq.get(seq)!, BACKGROUND_CONTEXT);\n\t\t}\n\t\tthis.setNextId(maxId + 1);\n\t\t// Task sidecars belong to live tasks only; a leftover for a terminal (or unknown) task cannot resurrect anything.\n\t\tfor (const f of sidecarFiles) {\n\t\t\tif (!f.startsWith(\"task-\")) continue;\n\t\t\tconst id = Number(f.slice(5, -6));\n\t\t\tconst t = await super.task(id);\n\t\t\tif (t === undefined || t.status === \"terminal\") unlinkSync(join(this.dir, f));\n\t\t}\n\t}\n\n\toverride async commit(writes: readonly Write[], ctx: Context): Promise<Seq> {\n\t\tif (this.closedOnce) throw new Error(\"storage closed\");\n\t\tconst seq = this.seq + 1;\n\t\tconst apply = this.stage(writes, seq); // validates the whole batch first; throws before any file is touched\n\t\tconst maxId = this.nextIdAfter(writes);\n\t\tconst main: Write[] = [];\n\t\tconst sticky = new Map<Id, Write[]>();\n\t\tconst tasks = new Map<Id, Write[]>();\n\t\tconst retired: Id[] = [];\n\t\tfor (const w of writes) {\n\t\t\tif (w.type === \"doc\" && w.ref.doc === \"sticky\")\n\t\t\t\t(sticky.get(w.ref.conversationId) ?? sticky.set(w.ref.conversationId, []).get(w.ref.conversationId)!).push(\n\t\t\t\t\tw,\n\t\t\t\t);\n\t\t\telse if (w.type === \"task.patch\" && w.patch.status !== \"terminal\")\n\t\t\t\t(tasks.get(w.patch.id) ?? tasks.set(w.patch.id, []).get(w.patch.id)!).push(w);\n\t\t\telse {\n\t\t\t\tmain.push(w);\n\t\t\t\tif (w.type === \"task.patch\" && w.patch.status === \"terminal\") retired.push(w.patch.id);\n\t\t\t}\n\t\t}\n\t\tconst refs: string[] = [];\n\t\tfor (const [id, ws] of tasks) {\n\t\t\tthis.append(this.taskSidecar(id), { seq, maxId, writes: ws });\n\t\t\trefs.push(`task-${id}.jsonl`);\n\t\t}\n\t\tfor (const [c, ws] of sticky) {\n\t\t\tthis.append(this.sidecar(c), { seq, maxId, writes: ws });\n\t\t\trefs.push(`sticky-${c}.jsonl`);\n\t\t}\n\t\tthis.append(this.mainFd, { seq, maxId, writes: main, ...(refs.length ? { refs } : {}) }); // the publication point\n\t\tapply();\n\t\tthis.seq = seq;\n\t\tfor (const id of retired) this.retireTaskSidecar(id); // after the terminal record is durably published\n\t\tvoid ctx;\n\t\treturn seq;\n\t}\n\tprivate nextIdAfter(writes: readonly Write[]): Id {\n\t\tlet max = this.nextIdValue - 1;\n\t\tfor (const w of writes) {\n\t\t\tconst id =\n\t\t\t\tw.type === \"conversation\"\n\t\t\t\t\t? w.conversation.id\n\t\t\t\t\t: w.type === \"entry\"\n\t\t\t\t\t\t? w.entry.id\n\t\t\t\t\t\t: w.type === \"task\"\n\t\t\t\t\t\t\t? w.task.id\n\t\t\t\t\t\t\t: w.type === \"input\"\n\t\t\t\t\t\t\t\t? w.input.id\n\t\t\t\t\t\t\t\t: 0;\n\t\t\tmax = Math.max(max, id);\n\t\t}\n\t\treturn max;\n\t}\n\n\tprivate append(fd: number, record: Record_) {\n\t\twriteSync(fd, `${JSON.stringify(record)}\\n`);\n\t\tif (this.fsync) fsyncSync(fd);\n\t}\n\n\tprivate sidecar(conversationId: Id): number {\n\t\tlet fd = this.sidecars.get(conversationId);\n\t\tif (fd === undefined) {\n\t\t\tfd = openSync(join(this.dir, `sticky-${conversationId}.jsonl`), \"a\");\n\t\t\tthis.sidecars.set(conversationId, fd);\n\t\t}\n\t\treturn fd;\n\t}\n\tprivate taskSidecar(id: Id): number {\n\t\tlet fd = this.taskSidecars.get(id);\n\t\tif (fd === undefined) {\n\t\t\tfd = openSync(join(this.dir, `task-${id}.jsonl`), \"a\");\n\t\t\tthis.taskSidecars.set(id, fd);\n\t\t}\n\t\treturn fd;\n\t}\n\tprivate retireTaskSidecar(id: Id) {\n\t\tconst fd = this.taskSidecars.get(id);\n\t\tif (fd !== undefined) closeSync(fd);\n\t\tthis.taskSidecars.delete(id);\n\t\ttry {\n\t\t\tunlinkSync(join(this.dir, `task-${id}.jsonl`));\n\t\t} catch {}\n\t}\n\n\t/** Rewrite the sticky sidecar from its last base: temp file, optional fsync, rename. Called on the Session line. */\n\toverride async truncate(ref: DocRef, _ctx?: Context): Promise<void> {\n\t\tawait super.truncate(ref);\n\t\tif (ref.doc !== \"sticky\") return;\n\t\tconst file = join(this.dir, `sticky-${ref.conversationId}.jsonl`);\n\t\tif (!existsSync(file)) return;\n\t\tconst lines = readFileSync(file, \"utf8\").split(\"\\n\").filter(Boolean);\n\t\tlet start = 0;\n\t\tfor (let i = lines.length - 1; i >= 0; i--)\n\t\t\tif (\n\t\t\t\tisBase((JSON.parse(lines[i]!) as Record_).writes.flatMap((w) => (w.type === \"doc\" ? w.ops : [])) as Op[])\n\t\t\t) {\n\t\t\t\tstart = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\tif (start === 0) return;\n\t\tconst tmp = `${file}.tmp`;\n\t\tconst fd = openSync(tmp, \"w\");\n\t\twriteSync(\n\t\t\tfd,\n\t\t\tlines\n\t\t\t\t.slice(start)\n\t\t\t\t.map((l) => `${l}\\n`)\n\t\t\t\t.join(\"\"),\n\t\t);\n\t\tif (this.fsync) fsyncSync(fd);\n\t\tcloseSync(fd);\n\t\tconst old = this.sidecars.get(ref.conversationId);\n\t\tif (old !== undefined) closeSync(old);\n\t\trenameSync(tmp, file);\n\t\tthis.sidecars.set(ref.conversationId, openSync(file, \"a\"));\n\t}\n\n\toverride async close(_ctx?: Context) {\n\t\tif (this.closedOnce) return;\n\t\tthis.closedOnce = true;\n\t\tawait super.close();\n\t\tcloseSync(this.mainFd);\n\t\tfor (const fd of this.sidecars.values()) closeSync(fd);\n\t\tfor (const fd of this.taskSidecars.values()) closeSync(fd);\n\t}\n}\n\nfunction truncateTo(file: string, length: number): void {\n\tconst fd = openSync(file, \"r+\");\n\ttry {\n\t\tftruncateSync(fd, length);\n\t} finally {\n\t\tcloseSync(fd);\n\t}\n}\n\n/** Bytes after the last newline are a torn write: cut them so a later append cannot extend a corrupt line. */\nfunction truncateTornTail(file: string) {\n\tconst size = statSync(file).size;\n\tif (size === 0) return;\n\tconst buf = readFileSync(file);\n\tconst end = buf.lastIndexOf(0x0a);\n\tif (end + 1 !== buf.length) truncateTo(file, end + 1);\n}\n"]}
1
+ {"version":3,"file":"jsonl.js","sourceRoot":"","sources":["../../../src/harness/pico3/jsonl.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tcloseSync,\n\texistsSync,\n\tfsyncSync,\n\tftruncateSync,\n\tmkdirSync,\n\topenSync,\n\treaddirSync,\n\treadFileSync,\n\trenameSync,\n\tstatSync,\n\tunlinkSync,\n\twriteSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { Context } from \"@earendil-works/chord\";\nimport { BACKGROUND_CONTEXT } from \"@earendil-works/chord/context\";\nimport { isBase, type Op } from \"@earendil-works/chord/delta\";\nimport { MemoryStorage } from \"./memory.ts\";\nimport type { DocRef, Id, Seq, Storage, Write } from \"./types.ts\";\n\n/** One line of any file. `refs` (main only) lists the sidecar files this commit also wrote. */\ninterface Record_ {\n\tseq: Seq;\n\tmaxId: Id;\n\twrites: Write[];\n\trefs?: string[];\n}\n\n/**\n * Files in a session directory:\n * main.jsonl conversations, entries, inputs, rewindable/session doc ops, each task's\n * CREATE and TERMINAL records, and one marker per commit. Append-only, never rewritten.\n * sticky-<conversation>.jsonl sticky doc ops; rewritten from its last base by `truncate` (on the Session line)\n * task-<id>.jsonl a live task's intermediate patches (running, checkpoints); unlinked after its\n * terminal record is published in main\n *\n * Publication (§10): one commit `Seq`; sidecar records are appended first, then exactly one main\n * record, last, listing the sidecar refs it expects — the publication point. Replay applies a sidecar\n * record only when main has the marker for that seq naming that file; unconfirmed sidecar tails are\n * ignored. Every record carries the committed-ID high-water. Bytes after the last newline of any file\n * are a torn write and are truncated before the file is opened for append. There is no compaction.\n *\n * With `fsync: false`, recovery covers process termination while the OS and filesystem remain alive.\n * It does not promise that an acknowledged commit survives power loss, kernel/host failure,\n * storage-cache loss, or a filesystem that loses/reorders completed writes. An acknowledged tail may\n * roll back, or a surviving main marker may reference a missing sidecar and make open fail rather\n * than expose partial state. A lost pre-effect checkpoint can cause an external effect to be attempted\n * again; external idempotency remains required.\n *\n * With `fsync: true`, each sidecar is flushed before the main publication marker is flushed. This\n * strengthens file-data durability and ordering across machine failure. It is not a complete database\n * guarantee: newly created files, renames, and unlinks are not followed by a parent-directory fsync,\n * and storage hardware/filesystems may provide weaker guarantees.\n *\n * One process owns a directory at a time; a second process is unsupported.\n */\nexport class JsonlStorage extends MemoryStorage implements Storage {\n\tprivate mainFd: number;\n\tprivate readonly sidecars = new Map<Id, number>(); // sticky docs, by conversation\n\tprivate readonly taskSidecars = new Map<Id, number>();\n\tprivate readonly dir: string;\n\treadonly fsync: boolean;\n\tprivate closedOnce = false;\n\n\tprivate constructor(dir: string, fsync: boolean) {\n\t\tsuper();\n\t\tthis.dir = dir;\n\t\tthis.fsync = fsync;\n\t\tthis.mainFd = openSync(join(dir, \"main.jsonl\"), \"a\");\n\t}\n\n\tstatic async open(dir: string, opts: { fsync?: boolean } = {}): Promise<JsonlStorage> {\n\t\tmkdirSync(dir, { recursive: true });\n\t\tfor (const f of readdirSync(dir)) if (f.endsWith(\".jsonl\")) truncateTornTail(join(dir, f));\n\t\tconst storage = new JsonlStorage(dir, opts.fsync ?? true);\n\t\ttry {\n\t\t\tawait storage.replay();\n\t\t\treturn storage;\n\t\t} catch (error) {\n\t\t\tawait storage.close();\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/** For tests and tooling: sizes of every file in the directory. */\n\tsizes(): { [file: string]: number } {\n\t\tconst out: { [file: string]: number } = {};\n\t\tfor (const f of readdirSync(this.dir)) out[f] = statSync(join(this.dir, f)).size;\n\t\treturn out;\n\t}\n\n\tprivate async replay() {\n\t\tconst read = (file: string): { record: Record_; end: number }[] => {\n\t\t\tif (!existsSync(file)) return [];\n\t\t\tconst bytes = readFileSync(file);\n\t\t\tconst out: { record: Record_; end: number }[] = [];\n\t\t\tlet start = 0;\n\t\t\tlet last = 0;\n\t\t\tfor (let end = bytes.indexOf(0x0a, start); end >= 0; end = bytes.indexOf(0x0a, start)) {\n\t\t\t\tconst line = bytes.subarray(start, end).toString(\"utf8\");\n\t\t\t\tstart = end + 1;\n\t\t\t\tif (line === \"\") continue;\n\t\t\t\tlet record: Record_;\n\t\t\t\ttry {\n\t\t\t\t\trecord = JSON.parse(line) as Record_;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthrow new Error(`${file}: malformed record: ${String(error)}`);\n\t\t\t\t}\n\t\t\t\tif (typeof record.seq !== \"number\" || typeof record.maxId !== \"number\" || !Array.isArray(record.writes))\n\t\t\t\t\tthrow new Error(`${file}: record lacks seq/maxId/writes`);\n\t\t\t\tif (record.seq <= last) throw new Error(`${file}: sequence not increasing at ${record.seq}`);\n\t\t\t\tlast = record.seq;\n\t\t\t\tout.push({ record, end: start });\n\t\t\t}\n\t\t\treturn out;\n\t\t};\n\t\tlet maxId = 0;\n\t\t// Main is the commit log. Confirmed = (seq → refs) for every marker.\n\t\tconst main = read(join(this.dir, \"main.jsonl\")).map(({ record }) => record);\n\t\tconst confirmed = new Map<Seq, Set<string>>();\n\t\tfor (const record of main) confirmed.set(record.seq, new Set(record.refs ?? []));\n\t\t// Merge every file's records by seq so batches apply in commit order.\n\t\tconst sidecarFiles = readdirSync(this.dir).filter(\n\t\t\t(file) => file.startsWith(\"sticky-\") || file.startsWith(\"task-\"),\n\t\t);\n\t\tconst bySeq = new Map<Seq, Write[]>();\n\t\tconst found = new Map<Seq, Set<string>>();\n\t\tconst retainedStickyBase = new Map<string, Seq>();\n\t\tconst retiredTasks = new Map<Id, Seq>();\n\t\tfor (const record of main) {\n\t\t\tfor (const write of record.writes) {\n\t\t\t\tif (write.type === \"task.patch\" && write.patch.status === \"terminal\")\n\t\t\t\t\tretiredTasks.set(write.patch.id, record.seq);\n\t\t\t}\n\t\t\tbySeq.set(record.seq, [...record.writes]);\n\t\t\tmaxId = Math.max(maxId, record.maxId);\n\t\t}\n\t\tfor (const file of sidecarFiles) {\n\t\t\tconst path = join(this.dir, file);\n\t\t\tconst records = read(path);\n\t\t\tconst first = records[0]?.record;\n\t\t\tif (\n\t\t\t\tfile.startsWith(\"sticky-\") &&\n\t\t\t\tfirst !== undefined &&\n\t\t\t\tisBase(first.writes.flatMap((write) => (write.type === \"doc\" ? write.ops : [])))\n\t\t\t) {\n\t\t\t\tretainedStickyBase.set(file, first.seq);\n\t\t\t}\n\t\t\tlet confirmedEnd = 0;\n\t\t\tlet sawUnconfirmed = false;\n\t\t\tfor (const { record, end } of records) {\n\t\t\t\tif (!confirmed.get(record.seq)?.has(file)) {\n\t\t\t\t\tsawUnconfirmed = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (sawUnconfirmed)\n\t\t\t\t\tthrow new Error(`${path}: confirmed record follows an unconfirmed tail at ${record.seq}`);\n\t\t\t\tconfirmedEnd = end;\n\t\t\t\tconst files = found.get(record.seq) ?? new Set<string>();\n\t\t\t\tfiles.add(file);\n\t\t\t\tfound.set(record.seq, files);\n\t\t\t\tbySeq.get(record.seq)!.push(...record.writes);\n\t\t\t\tmaxId = Math.max(maxId, record.maxId);\n\t\t\t}\n\t\t\tif (sawUnconfirmed) truncateTo(path, confirmedEnd);\n\t\t}\n\t\tfor (const record of main) {\n\t\t\tfor (const file of record.refs ?? []) {\n\t\t\t\tif (found.get(record.seq)?.has(file)) continue;\n\t\t\t\tconst retainedFrom = retainedStickyBase.get(file);\n\t\t\t\tif (retainedFrom !== undefined && record.seq < retainedFrom) continue;\n\t\t\t\tif (file.startsWith(\"task-\")) {\n\t\t\t\t\tconst id = Number(file.slice(5, -6));\n\t\t\t\t\tconst retiredAt = retiredTasks.get(id);\n\t\t\t\t\tif (retiredAt !== undefined && record.seq < retiredAt) continue;\n\t\t\t\t}\n\t\t\t\tthrow new Error(`${join(this.dir, file)}: missing record for published sequence ${record.seq}`);\n\t\t\t}\n\t\t}\n\t\tfor (const seq of [...bySeq.keys()].sort((a, b) => a - b)) {\n\t\t\tthis.seq = seq - 1;\n\t\t\tawait super.commit(bySeq.get(seq)!, BACKGROUND_CONTEXT);\n\t\t}\n\t\tthis.setNextId(maxId + 1);\n\t\t// Task sidecars belong to live tasks only; a leftover for a terminal (or unknown) task cannot resurrect anything.\n\t\tfor (const f of sidecarFiles) {\n\t\t\tif (!f.startsWith(\"task-\")) continue;\n\t\t\tconst id = Number(f.slice(5, -6));\n\t\t\tconst t = await super.task(id);\n\t\t\tif (t === undefined || t.status === \"terminal\") unlinkSync(join(this.dir, f));\n\t\t}\n\t}\n\n\toverride async commit(writes: readonly Write[], ctx: Context): Promise<Seq> {\n\t\tif (this.closedOnce) throw new Error(\"storage closed\");\n\t\tconst seq = this.seq + 1;\n\t\tconst apply = this.stage(writes, seq); // validates the whole batch first; throws before any file is touched\n\t\tconst maxId = this.nextIdAfter(writes);\n\t\tconst main: Write[] = [];\n\t\tconst sticky = new Map<Id, Write[]>();\n\t\tconst tasks = new Map<Id, Write[]>();\n\t\tconst retired: Id[] = [];\n\t\tfor (const w of writes) {\n\t\t\tif (w.type === \"doc\" && w.ref.doc === \"sticky\")\n\t\t\t\t(sticky.get(w.ref.conversationId) ?? sticky.set(w.ref.conversationId, []).get(w.ref.conversationId)!).push(\n\t\t\t\t\tw,\n\t\t\t\t);\n\t\t\telse if (w.type === \"task.patch\" && w.patch.status !== \"terminal\")\n\t\t\t\t(tasks.get(w.patch.id) ?? tasks.set(w.patch.id, []).get(w.patch.id)!).push(w);\n\t\t\telse {\n\t\t\t\tmain.push(w);\n\t\t\t\tif (w.type === \"task.patch\" && w.patch.status === \"terminal\") retired.push(w.patch.id);\n\t\t\t}\n\t\t}\n\t\tconst refs: string[] = [];\n\t\tfor (const [id, ws] of tasks) {\n\t\t\tthis.append(this.taskSidecar(id), { seq, maxId, writes: ws });\n\t\t\trefs.push(`task-${id}.jsonl`);\n\t\t}\n\t\tfor (const [c, ws] of sticky) {\n\t\t\tthis.append(this.sidecar(c), { seq, maxId, writes: ws });\n\t\t\trefs.push(`sticky-${c}.jsonl`);\n\t\t}\n\t\tthis.append(this.mainFd, { seq, maxId, writes: main, ...(refs.length ? { refs } : {}) }); // the publication point\n\t\tapply();\n\t\tthis.seq = seq;\n\t\tfor (const id of retired) this.retireTaskSidecar(id); // after the terminal record is durably published\n\t\tvoid ctx;\n\t\treturn seq;\n\t}\n\tprivate nextIdAfter(writes: readonly Write[]): Id {\n\t\tlet max = this.nextIdValue - 1;\n\t\tfor (const w of writes) {\n\t\t\tconst id =\n\t\t\t\tw.type === \"conversation\"\n\t\t\t\t\t? w.conversation.id\n\t\t\t\t\t: w.type === \"entry\"\n\t\t\t\t\t\t? w.entry.id\n\t\t\t\t\t\t: w.type === \"task\"\n\t\t\t\t\t\t\t? w.task.id\n\t\t\t\t\t\t\t: w.type === \"input\"\n\t\t\t\t\t\t\t\t? w.input.id\n\t\t\t\t\t\t\t\t: 0;\n\t\t\tmax = Math.max(max, id);\n\t\t}\n\t\treturn max;\n\t}\n\n\tprivate append(fd: number, record: Record_) {\n\t\twriteSync(fd, `${JSON.stringify(record)}\\n`);\n\t\tif (this.fsync) fsyncSync(fd);\n\t}\n\n\tprivate sidecar(conversationId: Id): number {\n\t\tlet fd = this.sidecars.get(conversationId);\n\t\tif (fd === undefined) {\n\t\t\tfd = openSync(join(this.dir, `sticky-${conversationId}.jsonl`), \"a\");\n\t\t\tthis.sidecars.set(conversationId, fd);\n\t\t}\n\t\treturn fd;\n\t}\n\tprivate taskSidecar(id: Id): number {\n\t\tlet fd = this.taskSidecars.get(id);\n\t\tif (fd === undefined) {\n\t\t\tfd = openSync(join(this.dir, `task-${id}.jsonl`), \"a\");\n\t\t\tthis.taskSidecars.set(id, fd);\n\t\t}\n\t\treturn fd;\n\t}\n\tprivate retireTaskSidecar(id: Id) {\n\t\tconst fd = this.taskSidecars.get(id);\n\t\tif (fd !== undefined) closeSync(fd);\n\t\tthis.taskSidecars.delete(id);\n\t\ttry {\n\t\t\tunlinkSync(join(this.dir, `task-${id}.jsonl`));\n\t\t} catch {}\n\t}\n\n\t/** Rewrite the sticky sidecar from its last base: temp file, optional fsync, rename. Called on the Session line. */\n\toverride async truncate(ref: DocRef, _ctx?: Context): Promise<void> {\n\t\tawait super.truncate(ref);\n\t\tif (ref.doc !== \"sticky\") return;\n\t\tconst file = join(this.dir, `sticky-${ref.conversationId}.jsonl`);\n\t\tif (!existsSync(file)) return;\n\t\tconst lines = readFileSync(file, \"utf8\").split(\"\\n\").filter(Boolean);\n\t\tlet start = 0;\n\t\tfor (let i = lines.length - 1; i >= 0; i--)\n\t\t\tif (\n\t\t\t\tisBase((JSON.parse(lines[i]!) as Record_).writes.flatMap((w) => (w.type === \"doc\" ? w.ops : [])) as Op[])\n\t\t\t) {\n\t\t\t\tstart = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\tif (start === 0) return;\n\t\tconst tmp = `${file}.tmp`;\n\t\tconst fd = openSync(tmp, \"w\");\n\t\twriteSync(\n\t\t\tfd,\n\t\t\tlines\n\t\t\t\t.slice(start)\n\t\t\t\t.map((l) => `${l}\\n`)\n\t\t\t\t.join(\"\"),\n\t\t);\n\t\tif (this.fsync) fsyncSync(fd);\n\t\tcloseSync(fd);\n\t\tconst old = this.sidecars.get(ref.conversationId);\n\t\tif (old !== undefined) closeSync(old);\n\t\trenameSync(tmp, file);\n\t\tthis.sidecars.set(ref.conversationId, openSync(file, \"a\"));\n\t}\n\n\toverride async close(_ctx?: Context) {\n\t\tif (this.closedOnce) return;\n\t\tthis.closedOnce = true;\n\t\tawait super.close();\n\t\tcloseSync(this.mainFd);\n\t\tfor (const fd of this.sidecars.values()) closeSync(fd);\n\t\tfor (const fd of this.taskSidecars.values()) closeSync(fd);\n\t}\n}\n\nfunction truncateTo(file: string, length: number): void {\n\tconst fd = openSync(file, \"r+\");\n\ttry {\n\t\tftruncateSync(fd, length);\n\t} finally {\n\t\tcloseSync(fd);\n\t}\n}\n\n/** Bytes after the last newline are a torn write: cut them so a later append cannot extend a corrupt line. */\nfunction truncateTornTail(file: string) {\n\tconst size = statSync(file).size;\n\tif (size === 0) return;\n\tconst buf = readFileSync(file);\n\tconst end = buf.lastIndexOf(0x0a);\n\tif (end + 1 !== buf.length) truncateTo(file, end + 1);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"collapse.d.ts","sourceRoot":"","sources":["../../../../src/harness/pico3/kinds/collapse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAIrD,OAAO,EAEN,KAAK,QAAQ,EAEb,KAAK,KAAK,EACV,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,KAAK,EAAE,EACP,KAAK,QAAQ,EAEb,KAAK,WAAW,EAKhB,KAAK,aAAa,EAElB,MAAM,aAAa,CAAC;AAQrB,MAAM,MAAM,aAAa,GAAG;IAAE,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,UAAU,CAAC;IAAC,OAAO,EAAE,EAAE,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAChH,KAAK,IAAI,GAAG;IACX,YAAY,EAAE,EAAE,GAAG,IAAI,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,QAAQ,CAAC;IAChB,aAAa,EAAE,aAAa,CAAC;IAC7B,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CAChB,CAAC;AACF,MAAM,MAAM,kBAAkB,GAC3B,CAAC;IAAE,KAAK,EAAE,aAAa,CAAA;CAAE,GAAG,IAAI,CAAC,GACjC,CAAC;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,GAClE,CAAC;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAAC;AACnD,MAAM,MAAM,eAAe,GAAG;IAC7B,MAAM,EAAE,OAAO,GAAG,UAAU,GAAG,UAAU,GAAG,mBAAmB,GAAG,UAAU,CAAC;IAC7E,MAAM,EAAE,MAAM,CAAC;CACf,CAAC;AACF,MAAM,WAAW,aAAa;IAC7B,cAAc,CACb,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,UAAU,EAC3C,OAAO,EAAE,EAAE,EACX,OAAO,EAAE,KAAK,EAAE,EAChB,IAAI,EAAE,QAAQ,EACd,GAAG,EAAE,OAAO,GACV,UAAU,CAAC;QAAE,OAAO,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC/E;AACD,eAAO,MAAM,cAAc;;;;;CAAoF,CAAC;AAwBhH,eAAO,MAAM,QAAQ,EAAE,QAAQ,CAC9B,aAAa,EACb,kBAAkB,EAClB;IAAE,OAAO,EAAE,EAAE,CAAA;CAAE,EACf,eAAe,EACf,IAAI,EACJ,aAAa,EACb,OAAO,cAAc,CA4ErB,CAAC;AAwFF,wBAAgB,aAAa,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,EAAE,GAAG,SAAS,CAuBlF","sourcesContent":["import type { Context } from \"@earendil-works/chord\";\nimport type { AssistantMessage } from \"@earendil-works/pi-ai\";\nimport { estimateContextTokens } from \"@earendil-works/pi-ai/utils/estimate\";\nimport { effectiveTools } from \"../system.ts\";\nimport {\n\ttype Completion,\n\ttype CoreKind,\n\ttype CoreTx,\n\ttype Entry,\n\ttype HookInfo,\n\ttype HookResult,\n\ttype Id,\n\ttype ModelRef,\n\ttype RequestMessage,\n\ttype RetryPolicy,\n\ttype Runtime,\n\ttype Step,\n\ttype SystemMessage,\n\ttype Task,\n\ttype ThinkingLevel,\n\ttoStored,\n} from \"../types.ts\";\nimport { retryDecision } from \"./generation.ts\";\n\nconst estimate = (messages: RequestMessage[]) =>\n\testimateContextTokens(\n\t\tmessages.filter((message): message is Exclude<RequestMessage, SystemMessage> => message.role !== \"system\"),\n\t).tokens;\n\nexport type CollapseInput = { reason: \"threshold\" | \"manual\" | \"overflow\"; through: Id; instructions?: string };\ntype Base = {\n\texpectedHead: Id | null;\n\tinstructions?: string;\n\tmodel: ModelRef;\n\tthinkingLevel: ThinkingLevel;\n\tretry: RetryPolicy;\n\tattempt: number;\n};\nexport type CollapseCheckpoint =\n\t| ({ phase: \"summarizing\" } & Base)\n\t| ({ phase: \"retrying\"; untilMs: number; lastError: string } & Base)\n\t| ({ phase: \"prepared\"; summary: string } & Base);\nexport type CollapseFailure = {\n\treason: \"stale\" | \"declined\" | \"provider\" | \"retries_exhausted\" | \"no_model\";\n\tdetail: string;\n};\nexport interface CollapseHooks {\n\tbeforeCollapse(\n\t\treason: \"threshold\" | \"manual\" | \"overflow\",\n\t\tthrough: Id,\n\t\tentries: Entry[],\n\t\tinfo: HookInfo,\n\t\tctx: Context,\n\t): HookResult<{ decline: true } | { instructions?: string; summary?: string }>;\n}\nexport const collapseConfig = { rewindable: { threshold: 0 as number, keepRecent: 20_000 as number } } as const;\n\ntype CollapseTask = Task<CollapseInput, CollapseCheckpoint>;\ntype CollapseRuntime = Runtime<CollapseHooks, CoreTx>;\ntype CollapseStep = Step<CollapseCheckpoint, { summary: Id }, CollapseFailure, CoreTx>;\nconst failed = (reason: CollapseFailure[\"reason\"], detail: string): Completion<{ summary: Id }, CollapseFailure> => ({\n\tstatus: \"failed\",\n\tfailure: { reason, detail },\n});\nconst baseOf = (checkpoint: CollapseCheckpoint): Base => {\n\tconst { phase: _phase, ...rest } = checkpoint;\n\tconst {\n\t\tuntilMs: _untilMs,\n\t\tlastError: _lastError,\n\t\tsummary: _summary,\n\t\t...base\n\t} = rest as Base & {\n\t\tuntilMs?: number;\n\t\tlastError?: string;\n\t\tsummary?: string;\n\t};\n\treturn base;\n};\n\nexport const collapse: CoreKind<\n\tCollapseInput,\n\tCollapseCheckpoint,\n\t{ summary: Id },\n\tCollapseFailure,\n\tnull,\n\tCollapseHooks,\n\ttypeof collapseConfig\n> = {\n\tname: \"pi.collapse\",\n\tconfig: collapseConfig,\n\tinflight: [\"summarizing\"],\n\n\tasync initial(task, runtime, ctx) {\n\t\tconst state = await runtime.rewindable(task.conversationId, ctx);\n\t\tif (state.model === undefined) return { done: () => failed(\"no_model\", \"no model configured\") };\n\t\tconst sticky = await runtime.sticky(task.conversationId, ctx);\n\t\tconst head = await runtime.newestEntry(task.conversationId, { withHead: true }, ctx);\n\t\tconst { entries } = await runtime.context(task.conversationId, task.input.through, ctx);\n\t\tlet decision: { decline: true } | { instructions?: string; summary?: string } = {};\n\t\tawait runtime.hooks.each(\n\t\t\tctx,\n\t\t\t(hook, api) => hook.beforeCollapse?.(task.input.reason, task.input.through, entries, api, ctx),\n\t\t\t(value) => {\n\t\t\t\tif (value === undefined) return;\n\t\t\t\tdecision = value;\n\t\t\t\treturn true;\n\t\t\t},\n\t\t);\n\t\tif (\"decline\" in decision) return { done: () => failed(\"declined\", \"declined by beforeCollapse\") };\n\t\tconst choice: { instructions?: string; summary?: string } = decision;\n\t\tconst base: Base = {\n\t\t\texpectedHead: head?.id ?? null,\n\t\t\t...((choice.instructions ?? task.input.instructions)\n\t\t\t\t? { instructions: choice.instructions ?? task.input.instructions }\n\t\t\t\t: {}),\n\t\t\tmodel: state.model,\n\t\t\tthinkingLevel: state.thinkingLevel,\n\t\t\tretry: sticky.retry,\n\t\t\tattempt: 1,\n\t\t};\n\t\tif (choice.summary !== undefined) {\n\t\t\treturn {\n\t\t\t\tnext: async (tx, current) =>\n\t\t\t\t\t(await headMoved(tx, current.conversationId, base))\n\t\t\t\t\t\t? failed(\"stale\", \"head moved during beforeCollapse\")\n\t\t\t\t\t\t: { phase: \"prepared\", summary: choice.summary!, ...base },\n\t\t\t};\n\t\t}\n\t\treturn summarizeNow(task, base, runtime, ctx, \"check head\");\n\t},\n\n\tphases: {\n\t\tasync summarizing(task, runtime) {\n\t\t\treturn afterFailure(baseOf(task.checkpoint), null, \"interrupted\", runtime);\n\t\t},\n\t\tasync retrying(task, runtime, ctx) {\n\t\t\tawait runtime.sleep(task.checkpoint.untilMs, ctx);\n\t\t\treturn summarizeNow(task, { ...baseOf(task.checkpoint), attempt: task.checkpoint.attempt + 1 }, runtime, ctx);\n\t\t},\n\t\tasync prepared(task, runtime) {\n\t\t\tconst { summary } = task.checkpoint;\n\t\t\tconst base = baseOf(task.checkpoint);\n\t\t\treturn {\n\t\t\t\tdone: async (tx, current) => {\n\t\t\t\t\tconst { head, entries } = await tx.context(current.conversationId);\n\t\t\t\t\tif ((head?.id ?? null) !== base.expectedHead) return failed(\"stale\", \"head moved during collapse\");\n\t\t\t\t\tconst retained = entries.find((entry) => entry.id > task.input.through);\n\t\t\t\t\tconst id = tx.appendEntry(current.conversationId, {\n\t\t\t\t\t\tkind: \"pi.summary\",\n\t\t\t\t\t\tdata: { through: task.input.through },\n\t\t\t\t\t\tmodel: [{ role: \"user\", content: summary, timestamp: runtime.now() }],\n\t\t\t\t\t\thead: retained?.id ?? \"self\",\n\t\t\t\t\t});\n\t\t\t\t\treturn { status: \"completed\", result: { summary: id } };\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t},\n\n\tasync abort() {\n\t\treturn async () => null;\n\t},\n};\n\nconst headMoved = async (tx: Pick<CoreTx, \"newestEntry\">, conversationId: Id, base: Base) =>\n\t((await tx.newestEntry(conversationId, { withHead: true }))?.id ?? null) !== base.expectedHead;\n\nasync function summarizeNow(\n\ttask: CollapseTask,\n\tbase: Base,\n\truntime: CollapseRuntime,\n\tctx: Context,\n\tcheck?: \"check head\",\n): Promise<CollapseStep> {\n\tconst stale = await runtime.commit(async (tx, current) => {\n\t\tif (check && (await headMoved(tx, current.conversationId, base))) return true;\n\t\ttx.checkpoint({ phase: \"summarizing\", ...base });\n\t\treturn false;\n\t}, ctx);\n\tif (stale) return { done: () => failed(\"stale\", \"head moved during beforeCollapse\") };\n\tconst model = runtime.models.resolve(base.model);\n\tif (model === undefined) return { done: () => failed(\"no_model\", \"model unavailable\") };\n\tconst { messages } = await runtime.context(task.conversationId, task.input.through, ctx);\n\tconst tools = effectiveTools(messages);\n\tconst request: RequestMessage[] = [\n\t\t...messages,\n\t\t...(tools.length > 0\n\t\t\t? [toStored({ role: \"system\", content: \"\", toolsRemoved: tools, timestamp: runtime.now() } as SystemMessage)]\n\t\t\t: []),\n\t\t{\n\t\t\trole: \"user\",\n\t\t\tcontent: `${base.instructions ?? \"Summarize the conversation so far for continuation.\"}\\n\\nRespond with the summary only.`,\n\t\t\ttimestamp: runtime.now(),\n\t\t},\n\t];\n\tlet message: AssistantMessage | undefined;\n\ttry {\n\t\tfor await (const event of runtime.models.stream(\n\t\t\tmodel,\n\t\t\t{ messages: request, thinkingLevel: base.thinkingLevel },\n\t\t\tctx,\n\t\t)) {\n\t\t\tif (event.type === \"done\") {\n\t\t\t\tmessage = event.message;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (event.type === \"error\") {\n\t\t\t\tmessage = event.error;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tif (ctx.abortSignal?.aborted) throw error;\n\t\treturn afterFailure(base, null, String(error), runtime);\n\t}\n\tif (message === undefined) return afterFailure(base, null, \"no message\", runtime);\n\tif (message.content.some((content) => content.type === \"toolCall\")) {\n\t\treturn afterFailure(base, { ...message, stopReason: \"error\" }, \"summarizer returned tool calls\", runtime);\n\t}\n\tif (message.stopReason === \"error\")\n\t\treturn afterFailure(base, message, message.errorMessage ?? \"provider error\", runtime);\n\tconst summary = message.content\n\t\t.filter((content): content is { type: \"text\"; text: string } => content.type === \"text\")\n\t\t.map((content) => content.text)\n\t\t.join(\"\");\n\treturn { next: { phase: \"prepared\", summary, ...base } };\n}\n\nfunction afterFailure(\n\tbase: Base,\n\tmessage: AssistantMessage | null,\n\tdetail: string,\n\truntime: CollapseRuntime,\n): CollapseStep {\n\tconst decision = retryDecision(base, message, runtime.now());\n\tif (decision.kind === \"fail\") return { done: () => failed(decision.reason, detail) };\n\treturn {\n\t\tnext: (tx, current) => {\n\t\t\ttx.emit({\n\t\t\t\ttype: \"compaction.retrying\",\n\t\t\t\ttaskId: current.id,\n\t\t\t\tattempt: base.attempt,\n\t\t\t\tretryAt: decision.untilMs,\n\t\t\t\terror: detail,\n\t\t\t});\n\t\t\treturn { phase: \"retrying\", ...base, untilMs: decision.untilMs, lastError: detail };\n\t\t},\n\t};\n}\n\nexport function chooseThrough(entries: Entry[], keepRecent: number): Id | undefined {\n\tconst exchanges: { last: Id; tokens: number }[] = [];\n\tlet open: { last: Id; tokens: number } | undefined;\n\tfor (const entry of entries) {\n\t\tconst role = entry.model?.[0]?.role;\n\t\tconst tokens = estimate((entry.model ?? []) as RequestMessage[]);\n\t\tif (role === \"assistant\") {\n\t\t\topen = { last: entry.id, tokens };\n\t\t\texchanges.push(open);\n\t\t} else if (role === \"toolResult\" && open) {\n\t\t\topen.last = entry.id;\n\t\t\topen.tokens += tokens;\n\t\t} else {\n\t\t\topen = undefined;\n\t\t\texchanges.push({ last: entry.id, tokens });\n\t\t}\n\t}\n\tlet retained = 0;\n\tlet index = exchanges.length - 1;\n\twhile (index >= 0 && retained + exchanges[index]!.tokens <= keepRecent) retained += exchanges[index--]!.tokens;\n\tif (index < 0) return undefined;\n\tif (index === exchanges.length - 1) return exchanges[index - 1]?.last;\n\treturn exchanges[index]!.last;\n}\n"]}
1
+ {"version":3,"file":"collapse.d.ts","sourceRoot":"","sources":["../../../../src/harness/pico3/kinds/collapse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAIrD,OAAO,EAEN,KAAK,QAAQ,EAEb,KAAK,KAAK,EACV,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,KAAK,EAAE,EACP,KAAK,QAAQ,EAEb,KAAK,WAAW,EAKhB,KAAK,aAAa,EAElB,MAAM,aAAa,CAAC;AAQrB,MAAM,MAAM,aAAa,GAAG;IAAE,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,UAAU,CAAC;IAAC,OAAO,EAAE,EAAE,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAChH,KAAK,IAAI,GAAG;IACX,YAAY,EAAE,EAAE,GAAG,IAAI,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,QAAQ,CAAC;IAChB,aAAa,EAAE,aAAa,CAAC;IAC7B,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CAChB,CAAC;AACF,MAAM,MAAM,kBAAkB,GAC3B,CAAC;IAAE,KAAK,EAAE,aAAa,CAAA;CAAE,GAAG,IAAI,CAAC,GACjC,CAAC;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,GAClE,CAAC;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAAC;AACnD,MAAM,MAAM,eAAe,GAAG;IAC7B,MAAM,EAAE,OAAO,GAAG,UAAU,GAAG,UAAU,GAAG,mBAAmB,GAAG,UAAU,CAAC;IAC7E,MAAM,EAAE,MAAM,CAAC;CACf,CAAC;AACF,MAAM,WAAW,aAAa;IAC7B,cAAc,CACb,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,UAAU,EAC3C,OAAO,EAAE,EAAE,EACX,OAAO,EAAE,KAAK,EAAE,EAChB,IAAI,EAAE,QAAQ,EACd,GAAG,EAAE,OAAO,GACV,UAAU,CAAC;QAAE,OAAO,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC/E;AACD,eAAO,MAAM,cAAc;aAAK,UAAU;iBAAI,SAAS,EAAO,MAAM;iBAAE,UAAU,EAAY,MAAM;;CAAa,CAAC;AAwBhH,eAAO,MAAM,QAAQ,EAAE,QAAQ,CAC9B,aAAa,EACb,kBAAkB,EAClB;IAAE,OAAO,EAAE,EAAE,CAAA;CAAE,EACf,eAAe,EACf,IAAI,EACJ,aAAa,EACb,OAAO,cAAc,CA4ErB,CAAC;AAwFF,wBAAgB,aAAa,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,EAAE,GAAG,SAAS,CAuBlF"}
@@ -1 +1 @@
1
- {"version":3,"file":"collapse.js","sourceRoot":"","sources":["../../../../src/harness/pico3/kinds/collapse.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAgBN,QAAQ,GACR,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,MAAM,QAAQ,GAAG,CAAC,QAA0B,EAAE,EAAE,CAC/C,qBAAqB,CACpB,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAqD,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,QAAQ,CAAC,CAC1G,CAAC,MAAM,CAAC;AA4BV,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,UAAU,EAAE,EAAE,SAAS,EAAE,CAAW,EAAE,UAAU,EAAE,MAAgB,EAAE,EAAW,CAAC;AAKhH,MAAM,MAAM,GAAG,CAAC,MAAiC,EAAE,MAAc,EAAgD,EAAE,CAAC,CAAC;IACpH,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE;CAC3B,CAAC,CAAC;AACH,MAAM,MAAM,GAAG,CAAC,UAA8B,EAAQ,EAAE,CAAC;IACxD,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,UAAU,CAAC;IAC9C,MAAM,EACL,OAAO,EAAE,QAAQ,EACjB,SAAS,EAAE,UAAU,EACrB,OAAO,EAAE,QAAQ,EACjB,GAAG,IAAI,EACP,GAAG,IAIH,CAAC;IACF,OAAO,IAAI,CAAC;AAAA,CACZ,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAQjB;IACH,IAAI,EAAE,aAAa;IACnB,MAAM,EAAE,cAAc;IACtB,QAAQ,EAAE,CAAC,aAAa,CAAC;IAEzB,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE;QACjC,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;QACjE,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;YAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,UAAU,EAAE,qBAAqB,CAAC,EAAE,CAAC;QAChG,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;QAC9D,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC;QACrF,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACxF,IAAI,QAAQ,GAAoE,EAAE,CAAC;QACnF,MAAM,OAAO,CAAC,KAAK,CAAC,IAAI,CACvB,GAAG,EACH,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,EAC9F,CAAC,KAAK,EAAE,EAAE,CAAC;YACV,IAAI,KAAK,KAAK,SAAS;gBAAE,OAAO;YAChC,QAAQ,GAAG,KAAK,CAAC;YACjB,OAAO,IAAI,CAAC;QAAA,CACZ,CACD,CAAC;QACF,IAAI,SAAS,IAAI,QAAQ;YAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,UAAU,EAAE,4BAA4B,CAAC,EAAE,CAAC;QACnG,MAAM,MAAM,GAAgD,QAAQ,CAAC;QACrE,MAAM,IAAI,GAAS;YAClB,YAAY,EAAE,IAAI,EAAE,EAAE,IAAI,IAAI;YAC9B,GAAG,CAAC,CAAC,MAAM,CAAC,YAAY,IAAI,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC;gBACnD,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE;gBAClE,CAAC,CAAC,EAAE,CAAC;YACN,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,OAAO,EAAE,CAAC;SACV,CAAC;QACF,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAClC,OAAO;gBACN,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,CAC3B,CAAC,MAAM,SAAS,CAAC,EAAE,EAAE,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;oBAClD,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,kCAAkC,CAAC;oBACrD,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,CAAC,OAAQ,EAAE,GAAG,IAAI,EAAE;aAC5D,CAAC;QACH,CAAC;QACD,OAAO,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC;IAAA,CAC5D;IAED,MAAM,EAAE;QACP,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE;YAChC,OAAO,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,CAAC,CAAC;QAAA,CAC3E;QACD,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE;YAClC,MAAM,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;YAClD,OAAO,YAAY,CAAC,IAAI,EAAE,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,GAAG,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;QAAA,CAC9G;QACD,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE;YAC7B,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC;YACpC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACrC,OAAO;gBACN,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC;oBAC5B,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;oBACnE,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,YAAY;wBAAE,OAAO,MAAM,CAAC,OAAO,EAAE,4BAA4B,CAAC,CAAC;oBACnG,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;oBACxE,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,cAAc,EAAE;wBACjD,IAAI,EAAE,YAAY;wBAClB,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE;wBACrC,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC;wBACrE,IAAI,EAAE,QAAQ,EAAE,EAAE,IAAI,MAAM;qBAC5B,CAAC,CAAC;oBACH,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,CAAC;gBAAA,CACxD;aACD,CAAC;QAAA,CACF;KACD;IAED,KAAK,CAAC,KAAK,GAAG;QACb,OAAO,KAAK,IAAI,EAAE,CAAC,IAAI,CAAC;IAAA,CACxB;CACD,CAAC;AAEF,MAAM,SAAS,GAAG,KAAK,EAAE,EAA+B,EAAE,cAAkB,EAAE,IAAU,EAAE,EAAE,CAC3F,CAAC,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,YAAY,CAAC;AAEhG,KAAK,UAAU,YAAY,CAC1B,IAAkB,EAClB,IAAU,EACV,OAAwB,EACxB,GAAY,EACZ,KAAoB,EACI;IACxB,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC;QACzD,IAAI,KAAK,IAAI,CAAC,MAAM,SAAS,CAAC,EAAE,EAAE,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QAC9E,EAAE,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;QACjD,OAAO,KAAK,CAAC;IAAA,CACb,EAAE,GAAG,CAAC,CAAC;IACR,IAAI,KAAK;QAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,kCAAkC,CAAC,EAAE,CAAC;IACtF,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACjD,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,UAAU,EAAE,mBAAmB,CAAC,EAAE,CAAC;IACxF,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACzF,MAAM,KAAK,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;IACvC,MAAM,OAAO,GAAqB;QACjC,GAAG,QAAQ;QACX,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;YACnB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,CAAC,GAAG,EAAE,EAAmB,CAAC,CAAC;YAC7G,CAAC,CAAC,EAAE,CAAC;QACN;YACC,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,GAAG,IAAI,CAAC,YAAY,IAAI,qDAAqD,oCAAoC;YAC1H,SAAS,EAAE,OAAO,CAAC,GAAG,EAAE;SACxB;KACD,CAAC;IACF,IAAI,OAAqC,CAAC;IAC1C,IAAI,CAAC;QACJ,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,CAC9C,KAAK,EACL,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,EACxD,GAAG,CACH,EAAE,CAAC;YACH,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBAC3B,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;gBACxB,MAAM;YACP,CAAC;YACD,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBAC5B,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC;gBACtB,MAAM;YACP,CAAC;QACF,CAAC;IACF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IAAI,GAAG,CAAC,WAAW,EAAE,OAAO;YAAE,MAAM,KAAK,CAAC;QAC1C,OAAO,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC;IACzD,CAAC;IACD,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC;IAClF,IAAI,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,UAAU,CAAC,EAAE,CAAC;QACpE,OAAO,YAAY,CAAC,IAAI,EAAE,EAAE,GAAG,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,gCAAgC,EAAE,OAAO,CAAC,CAAC;IAC3G,CAAC;IACD,IAAI,OAAO,CAAC,UAAU,KAAK,OAAO;QACjC,OAAO,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,YAAY,IAAI,gBAAgB,EAAE,OAAO,CAAC,CAAC;IACvF,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO;SAC7B,MAAM,CAAC,CAAC,OAAO,EAA6C,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,MAAM,CAAC;SACvF,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;SAC9B,IAAI,CAAC,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,EAAE,CAAC;AAAA,CACzD;AAED,SAAS,YAAY,CACpB,IAAU,EACV,OAAgC,EAChC,MAAc,EACd,OAAwB,EACT;IACf,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAC7D,IAAI,QAAQ,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;IACrF,OAAO;QACN,IAAI,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC;YACtB,EAAE,CAAC,IAAI,CAAC;gBACP,IAAI,EAAE,qBAAqB;gBAC3B,MAAM,EAAE,OAAO,CAAC,EAAE;gBAClB,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,OAAO,EAAE,QAAQ,CAAC,OAAO;gBACzB,KAAK,EAAE,MAAM;aACb,CAAC,CAAC;YACH,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;QAAA,CACpF;KACD,CAAC;AAAA,CACF;AAED,MAAM,UAAU,aAAa,CAAC,OAAgB,EAAE,UAAkB,EAAkB;IACnF,MAAM,SAAS,GAAmC,EAAE,CAAC;IACrD,IAAI,IAA8C,CAAC;IACnD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;QACpC,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAqB,CAAC,CAAC;QACjE,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;YAC1B,IAAI,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC;YAClC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;aAAM,IAAI,IAAI,KAAK,YAAY,IAAI,IAAI,EAAE,CAAC;YAC1C,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC;YACrB,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC;QACvB,CAAC;aAAM,CAAC;YACP,IAAI,GAAG,SAAS,CAAC;YACjB,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;QAC5C,CAAC;IACF,CAAC;IACD,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,KAAK,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;IACjC,OAAO,KAAK,IAAI,CAAC,IAAI,QAAQ,GAAG,SAAS,CAAC,KAAK,CAAE,CAAC,MAAM,IAAI,UAAU;QAAE,QAAQ,IAAI,SAAS,CAAC,KAAK,EAAE,CAAE,CAAC,MAAM,CAAC;IAC/G,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAChC,IAAI,KAAK,KAAK,SAAS,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC;IACtE,OAAO,SAAS,CAAC,KAAK,CAAE,CAAC,IAAI,CAAC;AAAA,CAC9B","sourcesContent":["import type { Context } from \"@earendil-works/chord\";\nimport type { AssistantMessage } from \"@earendil-works/pi-ai\";\nimport { estimateContextTokens } from \"@earendil-works/pi-ai/utils/estimate\";\nimport { effectiveTools } from \"../system.ts\";\nimport {\n\ttype Completion,\n\ttype CoreKind,\n\ttype CoreTx,\n\ttype Entry,\n\ttype HookInfo,\n\ttype HookResult,\n\ttype Id,\n\ttype ModelRef,\n\ttype RequestMessage,\n\ttype RetryPolicy,\n\ttype Runtime,\n\ttype Step,\n\ttype SystemMessage,\n\ttype Task,\n\ttype ThinkingLevel,\n\ttoStored,\n} from \"../types.ts\";\nimport { retryDecision } from \"./generation.ts\";\n\nconst estimate = (messages: RequestMessage[]) =>\n\testimateContextTokens(\n\t\tmessages.filter((message): message is Exclude<RequestMessage, SystemMessage> => message.role !== \"system\"),\n\t).tokens;\n\nexport type CollapseInput = { reason: \"threshold\" | \"manual\" | \"overflow\"; through: Id; instructions?: string };\ntype Base = {\n\texpectedHead: Id | null;\n\tinstructions?: string;\n\tmodel: ModelRef;\n\tthinkingLevel: ThinkingLevel;\n\tretry: RetryPolicy;\n\tattempt: number;\n};\nexport type CollapseCheckpoint =\n\t| ({ phase: \"summarizing\" } & Base)\n\t| ({ phase: \"retrying\"; untilMs: number; lastError: string } & Base)\n\t| ({ phase: \"prepared\"; summary: string } & Base);\nexport type CollapseFailure = {\n\treason: \"stale\" | \"declined\" | \"provider\" | \"retries_exhausted\" | \"no_model\";\n\tdetail: string;\n};\nexport interface CollapseHooks {\n\tbeforeCollapse(\n\t\treason: \"threshold\" | \"manual\" | \"overflow\",\n\t\tthrough: Id,\n\t\tentries: Entry[],\n\t\tinfo: HookInfo,\n\t\tctx: Context,\n\t): HookResult<{ decline: true } | { instructions?: string; summary?: string }>;\n}\nexport const collapseConfig = { rewindable: { threshold: 0 as number, keepRecent: 20_000 as number } } as const;\n\ntype CollapseTask = Task<CollapseInput, CollapseCheckpoint>;\ntype CollapseRuntime = Runtime<CollapseHooks, CoreTx>;\ntype CollapseStep = Step<CollapseCheckpoint, { summary: Id }, CollapseFailure, CoreTx>;\nconst failed = (reason: CollapseFailure[\"reason\"], detail: string): Completion<{ summary: Id }, CollapseFailure> => ({\n\tstatus: \"failed\",\n\tfailure: { reason, detail },\n});\nconst baseOf = (checkpoint: CollapseCheckpoint): Base => {\n\tconst { phase: _phase, ...rest } = checkpoint;\n\tconst {\n\t\tuntilMs: _untilMs,\n\t\tlastError: _lastError,\n\t\tsummary: _summary,\n\t\t...base\n\t} = rest as Base & {\n\t\tuntilMs?: number;\n\t\tlastError?: string;\n\t\tsummary?: string;\n\t};\n\treturn base;\n};\n\nexport const collapse: CoreKind<\n\tCollapseInput,\n\tCollapseCheckpoint,\n\t{ summary: Id },\n\tCollapseFailure,\n\tnull,\n\tCollapseHooks,\n\ttypeof collapseConfig\n> = {\n\tname: \"pi.collapse\",\n\tconfig: collapseConfig,\n\tinflight: [\"summarizing\"],\n\n\tasync initial(task, runtime, ctx) {\n\t\tconst state = await runtime.rewindable(task.conversationId, ctx);\n\t\tif (state.model === undefined) return { done: () => failed(\"no_model\", \"no model configured\") };\n\t\tconst sticky = await runtime.sticky(task.conversationId, ctx);\n\t\tconst head = await runtime.newestEntry(task.conversationId, { withHead: true }, ctx);\n\t\tconst { entries } = await runtime.context(task.conversationId, task.input.through, ctx);\n\t\tlet decision: { decline: true } | { instructions?: string; summary?: string } = {};\n\t\tawait runtime.hooks.each(\n\t\t\tctx,\n\t\t\t(hook, api) => hook.beforeCollapse?.(task.input.reason, task.input.through, entries, api, ctx),\n\t\t\t(value) => {\n\t\t\t\tif (value === undefined) return;\n\t\t\t\tdecision = value;\n\t\t\t\treturn true;\n\t\t\t},\n\t\t);\n\t\tif (\"decline\" in decision) return { done: () => failed(\"declined\", \"declined by beforeCollapse\") };\n\t\tconst choice: { instructions?: string; summary?: string } = decision;\n\t\tconst base: Base = {\n\t\t\texpectedHead: head?.id ?? null,\n\t\t\t...((choice.instructions ?? task.input.instructions)\n\t\t\t\t? { instructions: choice.instructions ?? task.input.instructions }\n\t\t\t\t: {}),\n\t\t\tmodel: state.model,\n\t\t\tthinkingLevel: state.thinkingLevel,\n\t\t\tretry: sticky.retry,\n\t\t\tattempt: 1,\n\t\t};\n\t\tif (choice.summary !== undefined) {\n\t\t\treturn {\n\t\t\t\tnext: async (tx, current) =>\n\t\t\t\t\t(await headMoved(tx, current.conversationId, base))\n\t\t\t\t\t\t? failed(\"stale\", \"head moved during beforeCollapse\")\n\t\t\t\t\t\t: { phase: \"prepared\", summary: choice.summary!, ...base },\n\t\t\t};\n\t\t}\n\t\treturn summarizeNow(task, base, runtime, ctx, \"check head\");\n\t},\n\n\tphases: {\n\t\tasync summarizing(task, runtime) {\n\t\t\treturn afterFailure(baseOf(task.checkpoint), null, \"interrupted\", runtime);\n\t\t},\n\t\tasync retrying(task, runtime, ctx) {\n\t\t\tawait runtime.sleep(task.checkpoint.untilMs, ctx);\n\t\t\treturn summarizeNow(task, { ...baseOf(task.checkpoint), attempt: task.checkpoint.attempt + 1 }, runtime, ctx);\n\t\t},\n\t\tasync prepared(task, runtime) {\n\t\t\tconst { summary } = task.checkpoint;\n\t\t\tconst base = baseOf(task.checkpoint);\n\t\t\treturn {\n\t\t\t\tdone: async (tx, current) => {\n\t\t\t\t\tconst { head, entries } = await tx.context(current.conversationId);\n\t\t\t\t\tif ((head?.id ?? null) !== base.expectedHead) return failed(\"stale\", \"head moved during collapse\");\n\t\t\t\t\tconst retained = entries.find((entry) => entry.id > task.input.through);\n\t\t\t\t\tconst id = tx.appendEntry(current.conversationId, {\n\t\t\t\t\t\tkind: \"pi.summary\",\n\t\t\t\t\t\tdata: { through: task.input.through },\n\t\t\t\t\t\tmodel: [{ role: \"user\", content: summary, timestamp: runtime.now() }],\n\t\t\t\t\t\thead: retained?.id ?? \"self\",\n\t\t\t\t\t});\n\t\t\t\t\treturn { status: \"completed\", result: { summary: id } };\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t},\n\n\tasync abort() {\n\t\treturn async () => null;\n\t},\n};\n\nconst headMoved = async (tx: Pick<CoreTx, \"newestEntry\">, conversationId: Id, base: Base) =>\n\t((await tx.newestEntry(conversationId, { withHead: true }))?.id ?? null) !== base.expectedHead;\n\nasync function summarizeNow(\n\ttask: CollapseTask,\n\tbase: Base,\n\truntime: CollapseRuntime,\n\tctx: Context,\n\tcheck?: \"check head\",\n): Promise<CollapseStep> {\n\tconst stale = await runtime.commit(async (tx, current) => {\n\t\tif (check && (await headMoved(tx, current.conversationId, base))) return true;\n\t\ttx.checkpoint({ phase: \"summarizing\", ...base });\n\t\treturn false;\n\t}, ctx);\n\tif (stale) return { done: () => failed(\"stale\", \"head moved during beforeCollapse\") };\n\tconst model = runtime.models.resolve(base.model);\n\tif (model === undefined) return { done: () => failed(\"no_model\", \"model unavailable\") };\n\tconst { messages } = await runtime.context(task.conversationId, task.input.through, ctx);\n\tconst tools = effectiveTools(messages);\n\tconst request: RequestMessage[] = [\n\t\t...messages,\n\t\t...(tools.length > 0\n\t\t\t? [toStored({ role: \"system\", content: \"\", toolsRemoved: tools, timestamp: runtime.now() } as SystemMessage)]\n\t\t\t: []),\n\t\t{\n\t\t\trole: \"user\",\n\t\t\tcontent: `${base.instructions ?? \"Summarize the conversation so far for continuation.\"}\\n\\nRespond with the summary only.`,\n\t\t\ttimestamp: runtime.now(),\n\t\t},\n\t];\n\tlet message: AssistantMessage | undefined;\n\ttry {\n\t\tfor await (const event of runtime.models.stream(\n\t\t\tmodel,\n\t\t\t{ messages: request, thinkingLevel: base.thinkingLevel },\n\t\t\tctx,\n\t\t)) {\n\t\t\tif (event.type === \"done\") {\n\t\t\t\tmessage = event.message;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (event.type === \"error\") {\n\t\t\t\tmessage = event.error;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tif (ctx.abortSignal?.aborted) throw error;\n\t\treturn afterFailure(base, null, String(error), runtime);\n\t}\n\tif (message === undefined) return afterFailure(base, null, \"no message\", runtime);\n\tif (message.content.some((content) => content.type === \"toolCall\")) {\n\t\treturn afterFailure(base, { ...message, stopReason: \"error\" }, \"summarizer returned tool calls\", runtime);\n\t}\n\tif (message.stopReason === \"error\")\n\t\treturn afterFailure(base, message, message.errorMessage ?? \"provider error\", runtime);\n\tconst summary = message.content\n\t\t.filter((content): content is { type: \"text\"; text: string } => content.type === \"text\")\n\t\t.map((content) => content.text)\n\t\t.join(\"\");\n\treturn { next: { phase: \"prepared\", summary, ...base } };\n}\n\nfunction afterFailure(\n\tbase: Base,\n\tmessage: AssistantMessage | null,\n\tdetail: string,\n\truntime: CollapseRuntime,\n): CollapseStep {\n\tconst decision = retryDecision(base, message, runtime.now());\n\tif (decision.kind === \"fail\") return { done: () => failed(decision.reason, detail) };\n\treturn {\n\t\tnext: (tx, current) => {\n\t\t\ttx.emit({\n\t\t\t\ttype: \"compaction.retrying\",\n\t\t\t\ttaskId: current.id,\n\t\t\t\tattempt: base.attempt,\n\t\t\t\tretryAt: decision.untilMs,\n\t\t\t\terror: detail,\n\t\t\t});\n\t\t\treturn { phase: \"retrying\", ...base, untilMs: decision.untilMs, lastError: detail };\n\t\t},\n\t};\n}\n\nexport function chooseThrough(entries: Entry[], keepRecent: number): Id | undefined {\n\tconst exchanges: { last: Id; tokens: number }[] = [];\n\tlet open: { last: Id; tokens: number } | undefined;\n\tfor (const entry of entries) {\n\t\tconst role = entry.model?.[0]?.role;\n\t\tconst tokens = estimate((entry.model ?? []) as RequestMessage[]);\n\t\tif (role === \"assistant\") {\n\t\t\topen = { last: entry.id, tokens };\n\t\t\texchanges.push(open);\n\t\t} else if (role === \"toolResult\" && open) {\n\t\t\topen.last = entry.id;\n\t\t\topen.tokens += tokens;\n\t\t} else {\n\t\t\topen = undefined;\n\t\t\texchanges.push({ last: entry.id, tokens });\n\t\t}\n\t}\n\tlet retained = 0;\n\tlet index = exchanges.length - 1;\n\twhile (index >= 0 && retained + exchanges[index]!.tokens <= keepRecent) retained += exchanges[index--]!.tokens;\n\tif (index < 0) return undefined;\n\tif (index === exchanges.length - 1) return exchanges[index - 1]?.last;\n\treturn exchanges[index]!.last;\n}\n"]}
1
+ {"version":3,"file":"collapse.js","sourceRoot":"","sources":["../../../../src/harness/pico3/kinds/collapse.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Context } from \"@earendil-works/chord\";\nimport type { AssistantMessage } from \"@earendil-works/pi-ai\";\nimport { estimateContextTokens } from \"@earendil-works/pi-ai/utils/estimate\";\nimport { effectiveTools } from \"../system.ts\";\nimport {\n\ttype Completion,\n\ttype CoreKind,\n\ttype CoreTx,\n\ttype Entry,\n\ttype HookInfo,\n\ttype HookResult,\n\ttype Id,\n\ttype ModelRef,\n\ttype RequestMessage,\n\ttype RetryPolicy,\n\ttype Runtime,\n\ttype Step,\n\ttype SystemMessage,\n\ttype Task,\n\ttype ThinkingLevel,\n\ttoStored,\n} from \"../types.ts\";\nimport { retryDecision } from \"./generation.ts\";\n\nconst estimate = (messages: RequestMessage[]) =>\n\testimateContextTokens(\n\t\tmessages.filter((message): message is Exclude<RequestMessage, SystemMessage> => message.role !== \"system\"),\n\t).tokens;\n\nexport type CollapseInput = { reason: \"threshold\" | \"manual\" | \"overflow\"; through: Id; instructions?: string };\ntype Base = {\n\texpectedHead: Id | null;\n\tinstructions?: string;\n\tmodel: ModelRef;\n\tthinkingLevel: ThinkingLevel;\n\tretry: RetryPolicy;\n\tattempt: number;\n};\nexport type CollapseCheckpoint =\n\t| ({ phase: \"summarizing\" } & Base)\n\t| ({ phase: \"retrying\"; untilMs: number; lastError: string } & Base)\n\t| ({ phase: \"prepared\"; summary: string } & Base);\nexport type CollapseFailure = {\n\treason: \"stale\" | \"declined\" | \"provider\" | \"retries_exhausted\" | \"no_model\";\n\tdetail: string;\n};\nexport interface CollapseHooks {\n\tbeforeCollapse(\n\t\treason: \"threshold\" | \"manual\" | \"overflow\",\n\t\tthrough: Id,\n\t\tentries: Entry[],\n\t\tinfo: HookInfo,\n\t\tctx: Context,\n\t): HookResult<{ decline: true } | { instructions?: string; summary?: string }>;\n}\nexport const collapseConfig = { rewindable: { threshold: 0 as number, keepRecent: 20_000 as number } } as const;\n\ntype CollapseTask = Task<CollapseInput, CollapseCheckpoint>;\ntype CollapseRuntime = Runtime<CollapseHooks, CoreTx>;\ntype CollapseStep = Step<CollapseCheckpoint, { summary: Id }, CollapseFailure, CoreTx>;\nconst failed = (reason: CollapseFailure[\"reason\"], detail: string): Completion<{ summary: Id }, CollapseFailure> => ({\n\tstatus: \"failed\",\n\tfailure: { reason, detail },\n});\nconst baseOf = (checkpoint: CollapseCheckpoint): Base => {\n\tconst { phase: _phase, ...rest } = checkpoint;\n\tconst {\n\t\tuntilMs: _untilMs,\n\t\tlastError: _lastError,\n\t\tsummary: _summary,\n\t\t...base\n\t} = rest as Base & {\n\t\tuntilMs?: number;\n\t\tlastError?: string;\n\t\tsummary?: string;\n\t};\n\treturn base;\n};\n\nexport const collapse: CoreKind<\n\tCollapseInput,\n\tCollapseCheckpoint,\n\t{ summary: Id },\n\tCollapseFailure,\n\tnull,\n\tCollapseHooks,\n\ttypeof collapseConfig\n> = {\n\tname: \"pi.collapse\",\n\tconfig: collapseConfig,\n\tinflight: [\"summarizing\"],\n\n\tasync initial(task, runtime, ctx) {\n\t\tconst state = await runtime.rewindable(task.conversationId, ctx);\n\t\tif (state.model === undefined) return { done: () => failed(\"no_model\", \"no model configured\") };\n\t\tconst sticky = await runtime.sticky(task.conversationId, ctx);\n\t\tconst head = await runtime.newestEntry(task.conversationId, { withHead: true }, ctx);\n\t\tconst { entries } = await runtime.context(task.conversationId, task.input.through, ctx);\n\t\tlet decision: { decline: true } | { instructions?: string; summary?: string } = {};\n\t\tawait runtime.hooks.each(\n\t\t\tctx,\n\t\t\t(hook, api) => hook.beforeCollapse?.(task.input.reason, task.input.through, entries, api, ctx),\n\t\t\t(value) => {\n\t\t\t\tif (value === undefined) return;\n\t\t\t\tdecision = value;\n\t\t\t\treturn true;\n\t\t\t},\n\t\t);\n\t\tif (\"decline\" in decision) return { done: () => failed(\"declined\", \"declined by beforeCollapse\") };\n\t\tconst choice: { instructions?: string; summary?: string } = decision;\n\t\tconst base: Base = {\n\t\t\texpectedHead: head?.id ?? null,\n\t\t\t...((choice.instructions ?? task.input.instructions)\n\t\t\t\t? { instructions: choice.instructions ?? task.input.instructions }\n\t\t\t\t: {}),\n\t\t\tmodel: state.model,\n\t\t\tthinkingLevel: state.thinkingLevel,\n\t\t\tretry: sticky.retry,\n\t\t\tattempt: 1,\n\t\t};\n\t\tif (choice.summary !== undefined) {\n\t\t\treturn {\n\t\t\t\tnext: async (tx, current) =>\n\t\t\t\t\t(await headMoved(tx, current.conversationId, base))\n\t\t\t\t\t\t? failed(\"stale\", \"head moved during beforeCollapse\")\n\t\t\t\t\t\t: { phase: \"prepared\", summary: choice.summary!, ...base },\n\t\t\t};\n\t\t}\n\t\treturn summarizeNow(task, base, runtime, ctx, \"check head\");\n\t},\n\n\tphases: {\n\t\tasync summarizing(task, runtime) {\n\t\t\treturn afterFailure(baseOf(task.checkpoint), null, \"interrupted\", runtime);\n\t\t},\n\t\tasync retrying(task, runtime, ctx) {\n\t\t\tawait runtime.sleep(task.checkpoint.untilMs, ctx);\n\t\t\treturn summarizeNow(task, { ...baseOf(task.checkpoint), attempt: task.checkpoint.attempt + 1 }, runtime, ctx);\n\t\t},\n\t\tasync prepared(task, runtime) {\n\t\t\tconst { summary } = task.checkpoint;\n\t\t\tconst base = baseOf(task.checkpoint);\n\t\t\treturn {\n\t\t\t\tdone: async (tx, current) => {\n\t\t\t\t\tconst { head, entries } = await tx.context(current.conversationId);\n\t\t\t\t\tif ((head?.id ?? null) !== base.expectedHead) return failed(\"stale\", \"head moved during collapse\");\n\t\t\t\t\tconst retained = entries.find((entry) => entry.id > task.input.through);\n\t\t\t\t\tconst id = tx.appendEntry(current.conversationId, {\n\t\t\t\t\t\tkind: \"pi.summary\",\n\t\t\t\t\t\tdata: { through: task.input.through },\n\t\t\t\t\t\tmodel: [{ role: \"user\", content: summary, timestamp: runtime.now() }],\n\t\t\t\t\t\thead: retained?.id ?? \"self\",\n\t\t\t\t\t});\n\t\t\t\t\treturn { status: \"completed\", result: { summary: id } };\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t},\n\n\tasync abort() {\n\t\treturn async () => null;\n\t},\n};\n\nconst headMoved = async (tx: Pick<CoreTx, \"newestEntry\">, conversationId: Id, base: Base) =>\n\t((await tx.newestEntry(conversationId, { withHead: true }))?.id ?? null) !== base.expectedHead;\n\nasync function summarizeNow(\n\ttask: CollapseTask,\n\tbase: Base,\n\truntime: CollapseRuntime,\n\tctx: Context,\n\tcheck?: \"check head\",\n): Promise<CollapseStep> {\n\tconst stale = await runtime.commit(async (tx, current) => {\n\t\tif (check && (await headMoved(tx, current.conversationId, base))) return true;\n\t\ttx.checkpoint({ phase: \"summarizing\", ...base });\n\t\treturn false;\n\t}, ctx);\n\tif (stale) return { done: () => failed(\"stale\", \"head moved during beforeCollapse\") };\n\tconst model = runtime.models.resolve(base.model);\n\tif (model === undefined) return { done: () => failed(\"no_model\", \"model unavailable\") };\n\tconst { messages } = await runtime.context(task.conversationId, task.input.through, ctx);\n\tconst tools = effectiveTools(messages);\n\tconst request: RequestMessage[] = [\n\t\t...messages,\n\t\t...(tools.length > 0\n\t\t\t? [toStored({ role: \"system\", content: \"\", toolsRemoved: tools, timestamp: runtime.now() } as SystemMessage)]\n\t\t\t: []),\n\t\t{\n\t\t\trole: \"user\",\n\t\t\tcontent: `${base.instructions ?? \"Summarize the conversation so far for continuation.\"}\\n\\nRespond with the summary only.`,\n\t\t\ttimestamp: runtime.now(),\n\t\t},\n\t];\n\tlet message: AssistantMessage | undefined;\n\ttry {\n\t\tfor await (const event of runtime.models.stream(\n\t\t\tmodel,\n\t\t\t{ messages: request, thinkingLevel: base.thinkingLevel },\n\t\t\tctx,\n\t\t)) {\n\t\t\tif (event.type === \"done\") {\n\t\t\t\tmessage = event.message;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (event.type === \"error\") {\n\t\t\t\tmessage = event.error;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tif (ctx.abortSignal?.aborted) throw error;\n\t\treturn afterFailure(base, null, String(error), runtime);\n\t}\n\tif (message === undefined) return afterFailure(base, null, \"no message\", runtime);\n\tif (message.content.some((content) => content.type === \"toolCall\")) {\n\t\treturn afterFailure(base, { ...message, stopReason: \"error\" }, \"summarizer returned tool calls\", runtime);\n\t}\n\tif (message.stopReason === \"error\")\n\t\treturn afterFailure(base, message, message.errorMessage ?? \"provider error\", runtime);\n\tconst summary = message.content\n\t\t.filter((content): content is { type: \"text\"; text: string } => content.type === \"text\")\n\t\t.map((content) => content.text)\n\t\t.join(\"\");\n\treturn { next: { phase: \"prepared\", summary, ...base } };\n}\n\nfunction afterFailure(\n\tbase: Base,\n\tmessage: AssistantMessage | null,\n\tdetail: string,\n\truntime: CollapseRuntime,\n): CollapseStep {\n\tconst decision = retryDecision(base, message, runtime.now());\n\tif (decision.kind === \"fail\") return { done: () => failed(decision.reason, detail) };\n\treturn {\n\t\tnext: (tx, current) => {\n\t\t\ttx.emit({\n\t\t\t\ttype: \"compaction.retrying\",\n\t\t\t\ttaskId: current.id,\n\t\t\t\tattempt: base.attempt,\n\t\t\t\tretryAt: decision.untilMs,\n\t\t\t\terror: detail,\n\t\t\t});\n\t\t\treturn { phase: \"retrying\", ...base, untilMs: decision.untilMs, lastError: detail };\n\t\t},\n\t};\n}\n\nexport function chooseThrough(entries: Entry[], keepRecent: number): Id | undefined {\n\tconst exchanges: { last: Id; tokens: number }[] = [];\n\tlet open: { last: Id; tokens: number } | undefined;\n\tfor (const entry of entries) {\n\t\tconst role = entry.model?.[0]?.role;\n\t\tconst tokens = estimate((entry.model ?? []) as RequestMessage[]);\n\t\tif (role === \"assistant\") {\n\t\t\topen = { last: entry.id, tokens };\n\t\t\texchanges.push(open);\n\t\t} else if (role === \"toolResult\" && open) {\n\t\t\topen.last = entry.id;\n\t\t\topen.tokens += tokens;\n\t\t} else {\n\t\t\topen = undefined;\n\t\t\texchanges.push({ last: entry.id, tokens });\n\t\t}\n\t}\n\tlet retained = 0;\n\tlet index = exchanges.length - 1;\n\twhile (index >= 0 && retained + exchanges[index]!.tokens <= keepRecent) retained += exchanges[index--]!.tokens;\n\tif (index < 0) return undefined;\n\tif (index === exchanges.length - 1) return exchanges[index - 1]?.last;\n\treturn exchanges[index]!.last;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"entries.d.ts","sourceRoot":"","sources":["../../../../src/harness/pico3/kinds/entries.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAC9F,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/F,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,CAAC,WAAW,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE;QAAE,YAAY,EAAE,IAAI,CAAC;QAAC,IAAI,EAAE,EAAE,CAAA;KAAE,CAAA;CAAE,CAAC;AACnH,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,CAAC,gBAAgB,CAAC,CAAC;IAAC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AACpH,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG;IACrC,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,CAAC,iBAAiB,CAAC,CAAC;IAC3B,IAAI,EAAE;QACL,OAAO,CAAC,EAAE,SAAS,CAAC;QACpB,WAAW,CAAC,EAAE,SAAS,CAAC;QACxB,OAAO,CAAC,EAAE,WAAW,CAAC;QACtB,SAAS,CAAC,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC;KAC7C,CAAC;CACF,CAAC;AACF,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,CAAC,aAAa,CAAC,CAAC;IAAC,IAAI,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,CAAC;AAC7G,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,CAAC,WAAW,CAAC,CAAA;CAAE,CAAC;AAC9E,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG;IAChC,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5E,CAAC;AACF,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,CAAC,WAAW,CAAC,CAAC;IAAC,IAAI,EAAE;QAAE,OAAO,EAAE,EAAE,CAAA;KAAE,CAAC;IAAC,IAAI,EAAE,EAAE,CAAA;CAAE,CAAC;AACjH,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,CAAC,WAAW,CAAC,CAAC;IAAC,IAAI,EAAE,EAAE,CAAA;CAAE,CAAC;AAC1F,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,EAAE,CAAA;CAAE,CAAC;AAKhE,eAAO,MAAM,OAAO;;;;;;;;;;CAUV,CAAC","sourcesContent":["import type { AssistantMessage, ToolResultMessage, UserMessage } from \"@earendil-works/pi-ai\";\nimport type { Entry, EntryKind, Id, JsonValue, SystemMessage, ToolControl } from \"../types.ts\";\n\nexport type UserEntry = Entry & { kind: \"pi.user\"; model: [UserMessage]; data?: { continuation: true; from: Id } };\nexport type AssistantEntry = Entry & { kind: \"pi.assistant\"; model: [AssistantMessage]; data: { attempt: number } };\nexport type ToolResultEntry = Entry & {\n\tkind: \"pi.tool_result\";\n\tmodel: [ToolResultMessage];\n\tdata: {\n\t\tdetails?: JsonValue;\n\t\tdiagnostics?: JsonValue;\n\t\tcontrol?: ToolControl;\n\t\ttruncated?: { bytes: number; lines: number };\n\t};\n};\nexport type SystemEntry = Entry & { kind: \"pi.system\"; model: [SystemMessage]; data: { baseline: boolean } };\nexport type NoticeEntry = Entry & { kind: \"pi.notice\"; model: [UserMessage] };\nexport type UsageEntry = Entry & {\n\tkind: \"pi.usage\";\n\tdata: { attempt: number; usage?: AssistantMessage[\"usage\"]; error: string };\n};\nexport type SummaryEntry = Entry & { kind: \"pi.summary\"; model: [UserMessage]; data: { through: Id }; head: Id };\nexport type HandoffEntry = Entry & { kind: \"pi.handoff\"; model: [UserMessage]; head: Id };\nexport type ResetEntry = Entry & { kind: \"pi.reset\"; head: Id };\n\nconst coreEntry = <E extends Entry>(kind: string): EntryKind<E> =>\n\tObject.freeze({ kind, is: (entry: Entry | undefined): entry is E => entry?.kind === kind });\n\nexport const entries = {\n\tuser: coreEntry<UserEntry>(\"pi.user\"),\n\tassistant: coreEntry<AssistantEntry>(\"pi.assistant\"),\n\ttoolResult: coreEntry<ToolResultEntry>(\"pi.tool_result\"),\n\tsystem: coreEntry<SystemEntry>(\"pi.system\"),\n\tnotice: coreEntry<NoticeEntry>(\"pi.notice\"),\n\tusage: coreEntry<UsageEntry>(\"pi.usage\"),\n\tsummary: coreEntry<SummaryEntry>(\"pi.summary\"),\n\thandoff: coreEntry<HandoffEntry>(\"pi.handoff\"),\n\treset: coreEntry<ResetEntry>(\"pi.reset\"),\n} as const;\n"]}
1
+ {"version":3,"file":"entries.d.ts","sourceRoot":"","sources":["../../../../src/harness/pico3/kinds/entries.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAC9F,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/F,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,CAAC,WAAW,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE;QAAE,YAAY,EAAE,IAAI,CAAC;QAAC,IAAI,EAAE,EAAE,CAAA;KAAE,CAAA;CAAE,CAAC;AACnH,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,CAAC,gBAAgB,CAAC,CAAC;IAAC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AACpH,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG;IACrC,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,CAAC,iBAAiB,CAAC,CAAC;IAC3B,IAAI,EAAE;QACL,OAAO,CAAC,EAAE,SAAS,CAAC;QACpB,WAAW,CAAC,EAAE,SAAS,CAAC;QACxB,OAAO,CAAC,EAAE,WAAW,CAAC;QACtB,SAAS,CAAC,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC;KAC7C,CAAC;CACF,CAAC;AACF,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,CAAC,aAAa,CAAC,CAAC;IAAC,IAAI,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,CAAC;AAC7G,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,CAAC,WAAW,CAAC,CAAA;CAAE,CAAC;AAC9E,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG;IAChC,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5E,CAAC;AACF,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,CAAC,WAAW,CAAC,CAAC;IAAC,IAAI,EAAE;QAAE,OAAO,EAAE,EAAE,CAAA;KAAE,CAAC;IAAC,IAAI,EAAE,EAAE,CAAA;CAAE,CAAC;AACjH,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,CAAC,WAAW,CAAC,CAAC;IAAC,IAAI,EAAE,EAAE,CAAA;CAAE,CAAC;AAC1F,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,EAAE,CAAA;CAAE,CAAC;AAKhE,eAAO,MAAM,OAAO;aACnB,IAAI;aACJ,SAAS;aACT,UAAU;aACV,MAAM;aACN,MAAM;aACN,KAAK;aACL,OAAO;aACP,OAAO;aACP,KAAK;CACI,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"frames.d.ts","sourceRoot":"","sources":["../../../../src/harness/pico3/kinds/frames.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,gBAAgB,EAChB,qBAAqB,EAIrB,MAAM,uBAAuB,CAAC;AAE/B;;;GAGG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,gBAAgB,CAAA;CAAE,EAAE,KAAK,EAAE,qBAAqB,GAAG,IAAI,CAuDhG","sourcesContent":["import type {\n\tAssistantMessage,\n\tAssistantMessageFrame,\n\tTextContent,\n\tThinkingContent,\n\tToolCall,\n} from \"@earendil-works/pi-ai\";\n\n/**\n * Apply one encoded frame to the tracked output. Same switch as pi-ai's\n * reduceAssistantMessageFrames (the test oracle); no buffering, no second copy.\n */\nexport function applyFrame(o: { message?: AssistantMessage }, frame: AssistantMessageFrame): void {\n\tif (frame.type === \"start\") {\n\t\to.message = frame.partial; // the encoder's clone\n\t\treturn;\n\t}\n\tconst m = o.message;\n\tif (m === undefined) throw new Error(`${frame.type} before start`);\n\tconst c = m.content;\n\tswitch (frame.type) {\n\t\tcase \"text_start\":\n\t\t\tc[frame.contentIndex] = { ...frame.content };\n\t\t\treturn;\n\t\tcase \"text_delta\":\n\t\t\t(c[frame.contentIndex] as TextContent).text += frame.delta;\n\t\t\treturn;\n\t\tcase \"text_end\": {\n\t\t\tconst b = c[frame.contentIndex] as TextContent;\n\t\t\tb.text = frame.content;\n\t\t\tdelete b.textSignature;\n\t\t\tif (frame.textSignature !== undefined) b.textSignature = frame.textSignature;\n\t\t\treturn;\n\t\t}\n\t\tcase \"thinking_start\":\n\t\t\tc[frame.contentIndex] = { ...frame.content };\n\t\t\treturn;\n\t\tcase \"thinking_delta\":\n\t\t\t(c[frame.contentIndex] as ThinkingContent).thinking += frame.delta;\n\t\t\treturn;\n\t\tcase \"thinking_end\": {\n\t\t\tconst b = c[frame.contentIndex] as ThinkingContent;\n\t\t\tb.thinking = frame.content;\n\t\t\tdelete b.thinkingSignature;\n\t\t\tdelete b.redacted;\n\t\t\tif (frame.thinkingSignature !== undefined) b.thinkingSignature = frame.thinkingSignature;\n\t\t\tif (frame.redacted !== undefined) b.redacted = frame.redacted;\n\t\t\treturn;\n\t\t}\n\t\tcase \"toolcall_start\":\n\t\t\tc[frame.contentIndex] = { ...frame.toolCall };\n\t\t\treturn;\n\t\tcase \"toolcall_checkpoint\":\n\t\t\t(c[frame.contentIndex] as ToolCall).arguments = safeParse(frame.json);\n\t\t\treturn;\n\t\tcase \"toolcall_delta\":\n\t\t\treturn; // arguments materialise at checkpoint/end; deltas only feed the encoder's own json buffer\n\t\tcase \"toolcall_end\": {\n\t\t\tconst b = c[frame.contentIndex] as ToolCall;\n\t\t\tb.id = frame.id;\n\t\t\tb.name = frame.name;\n\t\t\tb.arguments = frame.arguments;\n\t\t\tif (frame.thoughtSignature !== undefined) b.thoughtSignature = frame.thoughtSignature;\n\t\t\tif (frame.namespace !== undefined) b.namespace = frame.namespace;\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nfunction safeParse(json: string): ToolCall[\"arguments\"] {\n\ttry {\n\t\treturn JSON.parse(json);\n\t} catch {\n\t\treturn {};\n\t}\n}\n"]}
1
+ {"version":3,"file":"frames.d.ts","sourceRoot":"","sources":["../../../../src/harness/pico3/kinds/frames.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,gBAAgB,EAChB,qBAAqB,EAIrB,MAAM,uBAAuB,CAAC;AAE/B;;;GAGG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,gBAAgB,CAAA;CAAE,EAAE,KAAK,EAAE,qBAAqB,GAAG,IAAI,CAuDhG"}
@@ -1 +1 @@
1
- {"version":3,"file":"frames.js","sourceRoot":"","sources":["../../../../src/harness/pico3/kinds/frames.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tAssistantMessage,\n\tAssistantMessageFrame,\n\tTextContent,\n\tThinkingContent,\n\tToolCall,\n} from \"@earendil-works/pi-ai\";\n\n/**\n * Apply one encoded frame to the tracked output. Same switch as pi-ai's\n * reduceAssistantMessageFrames (the test oracle); no buffering, no second copy.\n */\nexport function applyFrame(o: { message?: AssistantMessage }, frame: AssistantMessageFrame): void {\n\tif (frame.type === \"start\") {\n\t\to.message = frame.partial; // the encoder's clone\n\t\treturn;\n\t}\n\tconst m = o.message;\n\tif (m === undefined) throw new Error(`${frame.type} before start`);\n\tconst c = m.content;\n\tswitch (frame.type) {\n\t\tcase \"text_start\":\n\t\t\tc[frame.contentIndex] = { ...frame.content };\n\t\t\treturn;\n\t\tcase \"text_delta\":\n\t\t\t(c[frame.contentIndex] as TextContent).text += frame.delta;\n\t\t\treturn;\n\t\tcase \"text_end\": {\n\t\t\tconst b = c[frame.contentIndex] as TextContent;\n\t\t\tb.text = frame.content;\n\t\t\tdelete b.textSignature;\n\t\t\tif (frame.textSignature !== undefined) b.textSignature = frame.textSignature;\n\t\t\treturn;\n\t\t}\n\t\tcase \"thinking_start\":\n\t\t\tc[frame.contentIndex] = { ...frame.content };\n\t\t\treturn;\n\t\tcase \"thinking_delta\":\n\t\t\t(c[frame.contentIndex] as ThinkingContent).thinking += frame.delta;\n\t\t\treturn;\n\t\tcase \"thinking_end\": {\n\t\t\tconst b = c[frame.contentIndex] as ThinkingContent;\n\t\t\tb.thinking = frame.content;\n\t\t\tdelete b.thinkingSignature;\n\t\t\tdelete b.redacted;\n\t\t\tif (frame.thinkingSignature !== undefined) b.thinkingSignature = frame.thinkingSignature;\n\t\t\tif (frame.redacted !== undefined) b.redacted = frame.redacted;\n\t\t\treturn;\n\t\t}\n\t\tcase \"toolcall_start\":\n\t\t\tc[frame.contentIndex] = { ...frame.toolCall };\n\t\t\treturn;\n\t\tcase \"toolcall_checkpoint\":\n\t\t\t(c[frame.contentIndex] as ToolCall).arguments = safeParse(frame.json);\n\t\t\treturn;\n\t\tcase \"toolcall_delta\":\n\t\t\treturn; // arguments materialise at checkpoint/end; deltas only feed the encoder's own json buffer\n\t\tcase \"toolcall_end\": {\n\t\t\tconst b = c[frame.contentIndex] as ToolCall;\n\t\t\tb.id = frame.id;\n\t\t\tb.name = frame.name;\n\t\t\tb.arguments = frame.arguments;\n\t\t\tif (frame.thoughtSignature !== undefined) b.thoughtSignature = frame.thoughtSignature;\n\t\t\tif (frame.namespace !== undefined) b.namespace = frame.namespace;\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nfunction safeParse(json: string): ToolCall[\"arguments\"] {\n\ttry {\n\t\treturn JSON.parse(json);\n\t} catch {\n\t\treturn {};\n\t}\n}\n"]}
1
+ {"version":3,"file":"frames.js","sourceRoot":"","sources":["../../../../src/harness/pico3/kinds/frames.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tAssistantMessage,\n\tAssistantMessageFrame,\n\tTextContent,\n\tThinkingContent,\n\tToolCall,\n} from \"@earendil-works/pi-ai\";\n\n/**\n * Apply one encoded frame to the tracked output. Same switch as pi-ai's\n * reduceAssistantMessageFrames (the test oracle); no buffering, no second copy.\n */\nexport function applyFrame(o: { message?: AssistantMessage }, frame: AssistantMessageFrame): void {\n\tif (frame.type === \"start\") {\n\t\to.message = frame.partial; // the encoder's clone\n\t\treturn;\n\t}\n\tconst m = o.message;\n\tif (m === undefined) throw new Error(`${frame.type} before start`);\n\tconst c = m.content;\n\tswitch (frame.type) {\n\t\tcase \"text_start\":\n\t\t\tc[frame.contentIndex] = { ...frame.content };\n\t\t\treturn;\n\t\tcase \"text_delta\":\n\t\t\t(c[frame.contentIndex] as TextContent).text += frame.delta;\n\t\t\treturn;\n\t\tcase \"text_end\": {\n\t\t\tconst b = c[frame.contentIndex] as TextContent;\n\t\t\tb.text = frame.content;\n\t\t\tdelete b.textSignature;\n\t\t\tif (frame.textSignature !== undefined) b.textSignature = frame.textSignature;\n\t\t\treturn;\n\t\t}\n\t\tcase \"thinking_start\":\n\t\t\tc[frame.contentIndex] = { ...frame.content };\n\t\t\treturn;\n\t\tcase \"thinking_delta\":\n\t\t\t(c[frame.contentIndex] as ThinkingContent).thinking += frame.delta;\n\t\t\treturn;\n\t\tcase \"thinking_end\": {\n\t\t\tconst b = c[frame.contentIndex] as ThinkingContent;\n\t\t\tb.thinking = frame.content;\n\t\t\tdelete b.thinkingSignature;\n\t\t\tdelete b.redacted;\n\t\t\tif (frame.thinkingSignature !== undefined) b.thinkingSignature = frame.thinkingSignature;\n\t\t\tif (frame.redacted !== undefined) b.redacted = frame.redacted;\n\t\t\treturn;\n\t\t}\n\t\tcase \"toolcall_start\":\n\t\t\tc[frame.contentIndex] = { ...frame.toolCall };\n\t\t\treturn;\n\t\tcase \"toolcall_checkpoint\":\n\t\t\t(c[frame.contentIndex] as ToolCall).arguments = safeParse(frame.json);\n\t\t\treturn;\n\t\tcase \"toolcall_delta\":\n\t\t\treturn; // arguments materialise at checkpoint/end; deltas only feed the encoder's own json buffer\n\t\tcase \"toolcall_end\": {\n\t\t\tconst b = c[frame.contentIndex] as ToolCall;\n\t\t\tb.id = frame.id;\n\t\t\tb.name = frame.name;\n\t\t\tb.arguments = frame.arguments;\n\t\t\tif (frame.thoughtSignature !== undefined) b.thoughtSignature = frame.thoughtSignature;\n\t\t\tif (frame.namespace !== undefined) b.namespace = frame.namespace;\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nfunction safeParse(json: string): ToolCall[\"arguments\"] {\n\ttry {\n\t\treturn JSON.parse(json);\n\t} catch {\n\t\treturn {};\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"generation.d.ts","sourceRoot":"","sources":["../../../../src/harness/pico3/kinds/generation.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Context } from \"@earendil-works/chord\";\nimport type {\n\tAssistantMessage,\n\tAssistantMessageEvent,\n\tAssistantMessageFrame,\n\tDeferredHandle,\n\tToolCall,\n} from \"@earendil-works/pi-ai\";\nimport { AssistantMessageFrameEncoder, isRetryableAssistantError } from \"@earendil-works/pi-ai\";\nimport { estimateContextTokens } from \"@earendil-works/pi-ai/utils/estimate\";\nimport { planManagedEntry, prepareDraft, type SystemInstructionsHooks, sameSnapshot, takeSnapshot } from \"../system.ts\";\nimport {\n\ttype Closure,\n\ttype Completion,\n\ttype CoreKind,\n\ttype CoreTx,\n\ttype HookInfo,\n\ttype HookResult,\n\ttype Id,\n\ttype ModelRef,\n\ttype RequestMessage,\n\ttype RetryPolicy,\n\ttype Runtime,\n\ttype Step,\n\ttype Stored,\n\ttype Task,\n\ttype ThinkingLevel,\n\ttoStored,\n} from \"../types.ts\";\nimport { chooseThrough } from \"./collapse.ts\";\nimport { applyFrame } from \"./frames.ts\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type GenerationInput = { inputs: Id[] };\n/** Captured once at `prepared`; carried unchanged except `attempt`. */\ntype Prep = {\n\tcutoff: Id;\n\tsystem: Id | null;\n\tmodel: ModelRef;\n\tthinkingLevel: ThinkingLevel;\n\ttools: string[];\n\tretry: RetryPolicy;\n\tattempt: number;\n};\nexport type GenerationCheckpoint =\n\t| ({ phase: \"prepared\" } & Prep)\n\t| ({ phase: \"requesting\" } & Prep)\n\t| ({ phase: \"retrying\"; untilMs: number; lastError: string } & Prep)\n\t| ({ phase: \"deferred\"; handle: Stored<DeferredHandle>; pollAt: number } & Prep);\nexport type GenerationResult = { assistant: Id; tools: Id[]; postTools?: Id; successor?: Id };\nexport type GenerationFailure = {\n\treason: \"provider\" | \"overflow\" | \"retries_exhausted\" | \"no_model\";\n\tdetail: string;\n\tassistant?: Id;\n};\n\n/** Display-only assistant entries (provider error, aborted partial) carry the message here, never in `model`. */\nexport type DisplayAssistantData = { attempt: number; display: Stored<AssistantMessage>; reason: \"error\" | \"aborted\" };\n\n/** Hook points this kind calls. Register with `h.hooks(namespace, kinds.generation, { … })`. */\nexport interface GenerationHooks extends SystemInstructionsHooks {\n\t/** Before every request (also on retry and recovery). Chain. */\n\tbeforeRequest(\n\t\trequest: { messages: RequestMessage[] },\n\t\tinfo: HookInfo & { cutoff: Id },\n\t\tctx: Context,\n\t): HookResult<{ messages: RequestMessage[] }>;\n\t/** Every terminal provider message, before classification. Observer. */\n\tafterResponse(message: AssistantMessage, info: HookInfo & { attempt: number }, ctx: Context): void | Promise<void>;\n\t/** On a final answer with nothing queued. First `{ continue }` wins and starts a continuation. */\n\tonYield(answer: AssistantMessage, info: HookInfo, ctx: Context): HookResult<{ continue: string }>;\n}\n\n/** Configuration this kind reads, with defaults. `model` has none: absent → failed/no_model. */\nexport const generationConfig = {\n\trewindable: {\n\t\tmodel: undefined as ModelRef | undefined,\n\t\tthinkingLevel: \"off\" as ThinkingLevel,\n\t\tselectedTools: [] as string[],\n\t\tprofile: \"default\" as string,\n\t},\n\tsticky: { retry: { enabled: true, maxRetries: 3, baseDelayMs: 2000, maxAgentDelayMs: 60_000 } as RetryPolicy },\n} as const;\n\ntype G = Task<GenerationInput, GenerationCheckpoint>;\ntype Rt = Runtime<GenerationHooks, CoreTx>;\ntype S = Step<GenerationCheckpoint, GenerationResult, GenerationFailure, CoreTx>;\ntype Out = Closure<GenerationResult, GenerationFailure, CoreTx>;\n\nconst fail = (\n\treason: GenerationFailure[\"reason\"],\n\tdetail: string,\n\tassistant?: Id,\n): Completion<GenerationResult, GenerationFailure> => ({\n\tstatus: \"failed\",\n\tfailure: { reason, detail, ...(assistant === undefined ? {} : { assistant }) },\n});\n/** Every terminal generation failure settles its group and admits queued triggers at the final boundary. */\nconst failStep = (task: G, reason: GenerationFailure[\"reason\"], detail: string): S => ({\n\tdone: async (tx, current) => {\n\t\tconst head = await tx.newestEntry(current.conversationId, { withHead: true });\n\t\ttx.emit({ type: \"generation.failed\", taskId: current.id, reason, detail });\n\t\tawait settleFailedTurn(tx, current, task.input.inputs, detail, head?.id);\n\t\treturn fail(reason, detail);\n\t},\n});\n/** pi-ai drops system messages and aborted/error assistant messages before sending; estimate what is sent. */\nconst estimate = (messages: RequestMessage[]) =>\n\testimateContextTokens(\n\t\tmessages.filter(\n\t\t\t(m) =>\n\t\t\t\tm.role !== \"system\" &&\n\t\t\t\t!(m.role === \"assistant\" && (m.stopReason === \"aborted\" || m.stopReason === \"error\")),\n\t\t) as never,\n\t).tokens;\nconst emptyUsage = (): AssistantMessage[\"usage\"] => ({\n\tinput: 0,\n\toutput: 0,\n\tcacheRead: 0,\n\tcacheWrite: 0,\n\ttotalTokens: 0,\n\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n});\n\n// ---------------------------------------------------------------------------\n// The kind\n// ---------------------------------------------------------------------------\n\nexport const generation: CoreKind<\n\tGenerationInput,\n\tGenerationCheckpoint,\n\tGenerationResult,\n\tGenerationFailure,\n\t{ assistant?: Id },\n\tGenerationHooks,\n\ttypeof generationConfig\n> = {\n\tname: \"pi.generation\",\n\tturn: true,\n\tconfig: generationConfig,\n\tinflight: [\"requesting\"],\n\n\t// Step 1 (§12.5): snapshot S on the line; systemInstructions off the line; then in one\n\t// commit re-take S′, retry if it moved, else append the managed entry and checkpoint\n\t// `prepared` with the cutoff. Runs once per generation; never on recovery.\n\tasync initial(task, rt, ctx) {\n\t\tconst { snapshot, canonical, seed } = await rt.commit(\n\t\t\t(tx, current) => takeSnapshot(tx, current.conversationId, rt.registries.sections, rt.registries.tools),\n\t\t\tctx,\n\t\t);\n\t\tif (snapshot.settings.model === undefined) return failStep(task, \"no_model\", \"no model configured\");\n\t\tconst retry = (await rt.sticky(task.conversationId, ctx)).retry;\n\n\t\tconst warnings: string[] = [];\n\t\tconst { desired, tools } = await prepareDraft(\n\t\t\trt,\n\t\t\trt.registries.sections,\n\t\t\tcanonical,\n\t\t\tseed,\n\t\t\tsnapshot.settings,\n\t\t\t(message) => warnings.push(message),\n\t\t\tctx,\n\t\t);\n\t\tconst model = snapshot.settings.model as unknown as ModelRef;\n\t\tconst thinkingLevel = snapshot.settings.thinkingLevel as ThinkingLevel;\n\n\t\treturn {\n\t\t\tnext: async (tx, current) => {\n\t\t\t\tconst c = current.conversationId;\n\t\t\t\tconst again = await takeSnapshot(tx, c, rt.registries.sections, rt.registries.tools);\n\t\t\t\tif (!sameSnapshot(again.snapshot, snapshot)) return \"retry\";\n\t\t\t\tconst plan = await planManagedEntry(tx, c, snapshot, canonical, desired, tools, rt.now());\n\t\t\t\tfor (const message of warnings) tx.emit({ type: \"warning\", source: \"generation\", message });\n\t\t\t\tconst system = plan === undefined ? null : tx.appendEntry(c, { kind: \"pi.system\", ...plan });\n\t\t\t\tconst cutoff = system ?? (await tx.newestEntry(c))!.id;\n\t\t\t\ttx.sticky(c).turn = { tools: [] }; // a new generation starts a fresh turn view\n\t\t\t\treturn {\n\t\t\t\t\tphase: \"prepared\",\n\t\t\t\t\tcutoff,\n\t\t\t\t\tsystem,\n\t\t\t\t\tmodel,\n\t\t\t\t\tthinkingLevel,\n\t\t\t\t\ttools: tools.map((t) => t.name),\n\t\t\t\t\tretry,\n\t\t\t\t\tattempt: 0,\n\t\t\t\t};\n\t\t\t},\n\t\t};\n\t},\n\n\tphases: {\n\t\t// Step 2: derive the request from the cutoff (hooks rerun), overflow check, write the\n\t\t// in-flight checkpoint, call the provider. Reached fresh from `initial`/`retrying`,\n\t\t// and again on recovery of `prepared` (step 1 never reruns).\n\t\tasync prepared(task, rt, ctx) {\n\t\t\tconst cp = task.checkpoint;\n\t\t\tconst model = rt.models.resolve(cp.model);\n\t\t\tif (model === undefined)\n\t\t\t\treturn failStep(task, \"no_model\", `model ${cp.model.provider}/${cp.model.modelId} unavailable`);\n\t\t\tconst derived = await derive(task, cp, rt, ctx);\n\t\t\tif (estimate(derived.messages) > model.contextWindow - model.maxTokens) return overflow(task, rt);\n\t\t\tconst attempt = cp.attempt + 1;\n\t\t\tawait rt.commit((tx) => {\n\t\t\t\ttx.checkpoint({ ...cp, phase: \"requesting\", attempt });\n\t\t\t\ttx.emit({ type: \"generation.started\", taskId: task.id, attempt });\n\t\t\t}, ctx); // before the effect\n\t\t\tconst { terminal, deferred } = await stream(cp, model, derived.messages, rt, ctx);\n\t\t\tif (deferred !== undefined) {\n\t\t\t\tconst pollAt = rt.now() + (deferred.pollAfterMs ?? 5000);\n\t\t\t\treturn {\n\t\t\t\t\tnext: (tx) => {\n\t\t\t\t\t\ttx.emit({ type: \"generation.deferred\", taskId: task.id, pollAt });\n\t\t\t\t\t\treturn { ...cp, phase: \"deferred\", attempt, handle: toStored(deferred), pollAt };\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn classify(task, { ...cp, attempt }, terminal!, rt, ctx);\n\t\t},\n\n\t\t// Only reached by the scheduler after a crash: the call may have happened and there\n\t\t// is no result lookup. Count it as a failed attempt and retry per policy.\n\t\tasync requesting(task, rt) {\n\t\t\tconst cp = task.checkpoint;\n\t\t\tconst decision = retryDecision(cp, null, rt.now());\n\t\t\tif (decision.kind === \"fail\") return failStep(task, decision.reason, \"interrupted\");\n\t\t\treturn {\n\t\t\t\tnext: (tx, current) => {\n\t\t\t\t\ttx.appendEntry(current.conversationId, {\n\t\t\t\t\t\tkind: \"pi.usage\",\n\t\t\t\t\t\tdata: { attempt: cp.attempt, error: \"interrupted\" },\n\t\t\t\t\t});\n\t\t\t\t\ttx.emit({\n\t\t\t\t\t\ttype: \"generation.retrying\",\n\t\t\t\t\t\ttaskId: current.id,\n\t\t\t\t\t\tattempt: cp.attempt,\n\t\t\t\t\t\tretryAt: decision.untilMs,\n\t\t\t\t\t\terror: \"interrupted\",\n\t\t\t\t\t});\n\t\t\t\t\treturn { ...cp, phase: \"retrying\", untilMs: decision.untilMs, lastError: \"interrupted\" };\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\n\t\t// Durable backoff, then back to step 2. Resets the streaming view.\n\t\tasync retrying(task, rt, ctx) {\n\t\t\tconst cp = task.checkpoint;\n\t\t\tawait rt.sleep(cp.untilMs, ctx);\n\t\t\tconst { untilMs: _u, lastError: _e, ...prep } = cp;\n\t\t\treturn {\n\t\t\t\tnext: (tx, current) => {\n\t\t\t\t\ttx.sticky(current.conversationId).turn.message = undefined;\n\t\t\t\t\treturn { ...prep, phase: \"prepared\" };\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\n\t\t// Provider-side async. Poll; not the retry backoff. Same after a crash: the handle is durable.\n\t\tasync deferred(task, rt, ctx) {\n\t\t\tconst cp = task.checkpoint;\n\t\t\tconst model = rt.models.resolve(cp.model);\n\t\t\tif (model === undefined) return failStep(task, \"no_model\", \"model disappeared\");\n\t\t\tawait rt.sleep(cp.pollAt, ctx);\n\t\t\tconst result = await rt.models.fetchDeferred(model, cp.handle, ctx);\n\t\t\tif (\"deferred\" in result && result.deferred !== undefined) {\n\t\t\t\tconst pollAt = rt.now() + (result.deferred.pollAfterMs ?? 5000);\n\t\t\t\treturn {\n\t\t\t\t\tnext: (tx) => {\n\t\t\t\t\t\ttx.emit({ type: \"generation.deferred\", taskId: task.id, pollAt });\n\t\t\t\t\t\treturn { ...cp, handle: toStored(result.deferred), pollAt };\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst message = result as AssistantMessage;\n\t\t\tawait rt.commit((tx, current) => {\n\t\t\t\ttx.sticky(current.conversationId).turn.message = toStored(message);\n\t\t\t}, ctx);\n\t\t\tconst { handle: _handle, pollAt: _pollAt, ...prep } = cp;\n\t\t\treturn classify(task, prep, message, rt, ctx);\n\t\t},\n\t},\n\n\tasync abort(task, rt, ctx) {\n\t\tconst cp = task.checkpoint;\n\t\tif (cp?.phase === \"deferred\") {\n\t\t\tconst model = rt.models.resolve(cp.model);\n\t\t\tif (model) await rt.models.cancelDeferred(model, cp.handle as DeferredHandle, ctx).catch(() => {});\n\t\t}\n\t\treturn async (tx, current) => {\n\t\t\tconst partial = tx.sticky(current.conversationId).turn.message;\n\t\t\tlet assistant: Id | undefined;\n\t\t\t// Display-only: the partial goes in `data`, never in `model`, so it cannot enter a request.\n\t\t\tif (partial && partial.content.length > 0)\n\t\t\t\tassistant = tx.appendEntry(current.conversationId, {\n\t\t\t\t\tkind: \"pi.assistant\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tattempt: cp?.attempt ?? 0,\n\t\t\t\t\t\tdisplay: { ...toStored(partial), stopReason: \"aborted\" },\n\t\t\t\t\t\treason: \"aborted\",\n\t\t\t\t\t} satisfies DisplayAssistantData,\n\t\t\t\t});\n\t\t\ttx.sticky(current.conversationId).turn = { tools: [] };\n\t\t\tawait tx.resolveInputs(task.input.inputs, { status: \"unanswered\", reason: \"aborted\" });\n\t\t\ttx.emit({ type: \"turn.ended\", inputs: task.input.inputs, status: \"unanswered\", reason: \"aborted\" });\n\t\t\treturn assistant === undefined ? {} : { assistant };\n\t\t};\n\t},\n};\n\n// ---------------------------------------------------------------------------\n// Request derivation and streaming\n// ---------------------------------------------------------------------------\n\nasync function derive(task: G, cp: Prep, rt: Rt, ctx: Context): Promise<{ messages: RequestMessage[] }> {\n\tconst { messages } = await rt.context(task.conversationId, cp.cutoff, ctx);\n\tlet request = { messages };\n\tawait rt.hooks.each(\n\t\tctx,\n\t\t(h, api) => h.beforeRequest?.(request, { ...api, cutoff: cp.cutoff }, ctx),\n\t\t(value) => {\n\t\t\tif (value !== undefined) request = value;\n\t\t},\n\t);\n\treturn request;\n}\n\n/** Stream, coalescing frames into the turn view. Flush on size or time. */\nasync function stream(\n\tcp: Prep,\n\tmodel: NonNullable<ReturnType<Rt[\"models\"][\"resolve\"]>>,\n\tmessages: RequestMessage[],\n\trt: Rt,\n\tctx: Context,\n): Promise<{ terminal?: AssistantMessage; deferred?: DeferredHandle }> {\n\tconst encoder = new AssistantMessageFrameEncoder();\n\tlet pending: AssistantMessageFrame[] = [];\n\tlet pendingBytes = 0;\n\tlet lastFlush = rt.now();\n\tlet terminal: AssistantMessage | undefined;\n\tlet deferred: DeferredHandle | undefined;\n\tlet flushedContent = false;\n\tconst flush = async () => {\n\t\tconst batch = pending;\n\t\tif (batch.length === 0) return;\n\t\tpending = [];\n\t\tpendingBytes = 0;\n\t\tlastFlush = rt.now();\n\t\tif (batch.some((frame) => \"delta\" in frame)) flushedContent = true;\n\t\tawait rt.commit((tx, current) => {\n\t\t\tconst turn = tx.sticky(current.conversationId).turn;\n\t\t\tfor (const f of batch) applyFrame(turn as { message?: AssistantMessage }, f);\n\t\t}, ctx);\n\t};\n\ttry {\n\t\tconst iterator = rt.models\n\t\t\t.stream(model, { messages, thinkingLevel: cp.thinkingLevel }, ctx)\n\t\t\t[Symbol.asyncIterator]();\n\t\tlet pull = iterator.next();\n\t\tfor (;;) {\n\t\t\tconst selected: { kind: \"event\"; result: IteratorResult<AssistantMessageEvent> } | { kind: \"flush\" } =\n\t\t\t\tpending.length === 0\n\t\t\t\t\t? { kind: \"event\", result: await pull }\n\t\t\t\t\t: await Promise.race([\n\t\t\t\t\t\t\tpull.then((result) => ({ kind: \"event\" as const, result })),\n\t\t\t\t\t\t\trt.sleep(lastFlush + 100, ctx).then(() => ({ kind: \"flush\" as const })),\n\t\t\t\t\t\t]);\n\t\t\tif (selected.kind === \"flush\") {\n\t\t\t\tawait flush();\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (selected.result.done) break;\n\t\t\tconst event = selected.result.value;\n\t\t\tif (event.type === \"done\") {\n\t\t\t\tencoder.encode(event);\n\t\t\t\tif (event.reason === \"deferred\" && event.message.deferred !== undefined) deferred = event.message.deferred;\n\t\t\t\telse terminal = event.message;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (event.type === \"error\") {\n\t\t\t\tencoder.encode(event);\n\t\t\t\tterminal = event.error;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst frame = encoder.encode(event);\n\t\t\tpull = iterator.next();\n\t\t\tif (frame === undefined) continue;\n\t\t\tpending.push(frame);\n\t\t\tpendingBytes += \"delta\" in frame ? frame.delta.length : 64;\n\t\t\tif (pendingBytes >= 256 || (!flushedContent && \"delta\" in frame)) await flush();\n\t\t}\n\t} catch (error) {\n\t\tif (ctx.abortSignal?.aborted) throw error;\n\t\tterminal = {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: [],\n\t\t\tapi: model.api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: emptyUsage(),\n\t\t\tstopReason: \"error\",\n\t\t\terrorMessage: String(error),\n\t\t\ttimestamp: rt.now(),\n\t\t};\n\t}\n\tif (pending.length > 0) await flush();\n\tif (terminal === undefined && deferred === undefined) throw new Error(\"stream ended without a terminal message\");\n\treturn { terminal, deferred };\n}\n\n// ---------------------------------------------------------------------------\n// Steps 3–5: classify the terminal message.\n// ---------------------------------------------------------------------------\n\nasync function classify(task: G, cp: Prep, message: AssistantMessage, rt: Rt, ctx: Context): Promise<S> {\n\tawait rt.hooks.each(ctx, (h, api) => h.afterResponse?.(message, { ...api, attempt: cp.attempt }, ctx));\n\n\tif (message.stopReason === \"error\") {\n\t\tconst decision = retryDecision(cp, message, rt.now());\n\t\tif (decision.kind === \"retry\") {\n\t\t\treturn {\n\t\t\t\tnext: (tx, current) => {\n\t\t\t\t\ttx.appendEntry(current.conversationId, {\n\t\t\t\t\t\tkind: \"pi.usage\",\n\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\tattempt: cp.attempt,\n\t\t\t\t\t\t\tusage: toStored(message.usage),\n\t\t\t\t\t\t\terror: message.errorMessage ?? \"provider error\",\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t\ttx.emit({\n\t\t\t\t\t\ttype: \"generation.retrying\",\n\t\t\t\t\t\ttaskId: current.id,\n\t\t\t\t\t\tattempt: cp.attempt,\n\t\t\t\t\t\tretryAt: decision.untilMs,\n\t\t\t\t\t\terror: message.errorMessage ?? \"provider error\",\n\t\t\t\t\t});\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...cp,\n\t\t\t\t\t\tphase: \"retrying\",\n\t\t\t\t\t\tuntilMs: decision.untilMs,\n\t\t\t\t\t\tlastError: message.errorMessage ?? \"provider error\",\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\treturn { done: terminalError(task, cp, message, decision.reason) };\n\t}\n\tif (message.stopReason === \"aborted\") return { done: terminalError(task, cp, message, \"provider\") };\n\n\tconst calls = message.content.filter((c): c is ToolCall => c.type === \"toolCall\");\n\tconst stored = toStored(message);\n\tif (calls.length > 0) {\n\t\treturn {\n\t\t\tdone: async (tx, current) => {\n\t\t\t\tconst c = current.conversationId;\n\t\t\t\tconst collapseThrough = await thresholdCollapseThrough(tx, c, message); // read BEFORE the append\n\t\t\t\tconst assistant = tx.appendEntry(c, {\n\t\t\t\t\tkind: \"pi.assistant\",\n\t\t\t\t\tmodel: [stored],\n\t\t\t\t\tdata: { attempt: cp.attempt },\n\t\t\t\t});\n\t\t\t\tconst turn = tx.sticky(c).turn;\n\t\t\t\tturn.message = undefined;\n\t\t\t\tturn.tools = calls.map((call) => ({\n\t\t\t\t\tcallId: call.id,\n\t\t\t\t\tname: call.name,\n\t\t\t\t\targs: toStored(call.arguments),\n\t\t\t\t\tstatus: \"pending\",\n\t\t\t\t}));\n\t\t\t\tconst tools = calls.map((call, index) =>\n\t\t\t\t\ttx.createTask({ kind: \"pi.tool\", input: { assistant, call: toStored(call), offered: cp.tools, index } }),\n\t\t\t\t);\n\t\t\t\tconst postTools = tx.createTask({\n\t\t\t\t\tkind: \"pi.post_tools\",\n\t\t\t\t\tafter: tools,\n\t\t\t\t\tinput: { inputs: task.input.inputs, assistant, tools },\n\t\t\t\t});\n\t\t\t\tif (collapseThrough !== undefined)\n\t\t\t\t\ttx.createTask({ kind: \"pi.collapse\", input: { reason: \"threshold\", through: collapseThrough } });\n\t\t\t\ttx.emit({ type: \"generation.completed\", taskId: current.id, entry: assistant, toolCalls: calls.length });\n\t\t\t\treturn { status: \"completed\", result: { assistant, tools, postTools } };\n\t\t\t},\n\t\t};\n\t}\n\n\tlet continueText: string | undefined;\n\tawait rt.hooks.each(\n\t\tctx,\n\t\t(h, api) => h.onYield?.(message, api, ctx),\n\t\t(value) => {\n\t\t\tif (value === undefined) return;\n\t\t\tcontinueText = value.continue;\n\t\t\treturn true;\n\t\t},\n\t);\n\treturn {\n\t\tdone: async (tx, current) => {\n\t\t\tconst c = current.conversationId;\n\t\t\tconst collapseThrough = await thresholdCollapseThrough(tx, c, message); // read BEFORE the append\n\t\t\tconst head = await tx.newestEntry(c, { withHead: true });\n\t\t\tconst assistant = tx.appendEntry(c, { kind: \"pi.assistant\", model: [stored], data: { attempt: cp.attempt } });\n\t\t\ttx.emit({ type: \"generation.completed\", taskId: current.id, entry: assistant, toolCalls: 0 });\n\t\t\ttx.sticky(c).turn = { tools: [] };\n\t\t\tif (collapseThrough !== undefined)\n\t\t\t\ttx.createTask({ kind: \"pi.collapse\", input: { reason: \"threshold\", through: collapseThrough } });\n\t\t\tconst { triggers, terminated } = await tx.boundary(c, \"final\", head?.id);\n\t\t\tif (continueText !== undefined && triggers.length === 0 && !terminated) {\n\t\t\t\ttx.appendEntry(c, {\n\t\t\t\t\tkind: \"pi.user\",\n\t\t\t\t\tmodel: [{ role: \"user\", content: continueText, timestamp: rt.now() }],\n\t\t\t\t\tdata: { continuation: true, from: assistant },\n\t\t\t\t});\n\t\t\t\tconst successor = tx.createTask({ kind: \"pi.generation\", input: { inputs: task.input.inputs } });\n\t\t\t\treturn { status: \"completed\", result: { assistant, tools: [], successor } };\n\t\t\t}\n\t\t\tawait tx.resolveInputs(task.input.inputs, { status: \"done\", answer: assistant });\n\t\t\ttx.emit({ type: \"turn.ended\", inputs: task.input.inputs, status: \"done\", answer: assistant });\n\t\t\tif (triggers.length > 0) {\n\t\t\t\tconst successor = tx.createTask({ kind: \"pi.generation\", input: { inputs: triggers } });\n\t\t\t\ttx.emit({ type: \"turn.started\", inputs: triggers });\n\t\t\t\treturn { status: \"completed\", result: { assistant, tools: [], successor } };\n\t\t\t}\n\t\t\treturn { status: \"completed\", result: { assistant, tools: [] } };\n\t\t},\n\t};\n}\n\n/** Provider error / aborted stop: a display-only assistant entry (no `model`), inputs unanswered. */\nfunction terminalError(task: G, cp: Prep, message: AssistantMessage, reason: \"provider\" | \"retries_exhausted\"): Out {\n\treturn async (tx, current) => {\n\t\tconst head = await tx.newestEntry(current.conversationId, { withHead: true });\n\t\tconst assistant = tx.appendEntry(current.conversationId, {\n\t\t\tkind: \"pi.assistant\",\n\t\t\tdata: {\n\t\t\t\tattempt: cp.attempt,\n\t\t\t\tdisplay: toStored(message),\n\t\t\t\treason: message.stopReason === \"aborted\" ? \"aborted\" : \"error\",\n\t\t\t} satisfies DisplayAssistantData,\n\t\t});\n\t\ttx.emit({\n\t\t\ttype: \"generation.failed\",\n\t\t\ttaskId: current.id,\n\t\t\treason,\n\t\t\tdetail: message.errorMessage ?? \"provider error\",\n\t\t\tentry: assistant,\n\t\t});\n\t\tawait settleFailedTurn(tx, current, task.input.inputs, message.errorMessage ?? \"provider error\", head?.id);\n\t\treturn fail(reason, message.errorMessage ?? \"provider error\", assistant);\n\t};\n}\n\nasync function settleFailedTurn(\n\ttx: CoreTx,\n\tcurrent: Task,\n\tinputs: readonly Id[],\n\tdetail: string,\n\theadBoundary: Id | undefined,\n): Promise<void> {\n\ttx.sticky(current.conversationId).turn = { tools: [] };\n\tawait tx.resolveInputs(inputs, { status: \"unanswered\", reason: \"failed\", detail });\n\ttx.emit({ type: \"turn.ended\", inputs: [...inputs], status: \"unanswered\", reason: \"failed\", detail });\n\tconst { triggers } = await tx.boundary(current.conversationId, \"final\", headBoundary);\n\tif (triggers.length > 0) {\n\t\ttx.createTask({ kind: \"pi.generation\", conversationId: current.conversationId, input: { inputs: triggers } });\n\t\ttx.emit({ type: \"turn.started\", inputs: triggers });\n\t}\n}\n\ntype RetryDecision = { kind: \"retry\"; untilMs: number } | { kind: \"fail\"; reason: \"provider\" | \"retries_exhausted\" };\nexport function retryDecision(\n\tcp: { retry: RetryPolicy; attempt: number },\n\tmessage: AssistantMessage | null,\n\tnow: number,\n): RetryDecision {\n\tif (message !== null && !isRetryableAssistantError(message)) return { kind: \"fail\", reason: \"provider\" };\n\tif (!cp.retry.enabled) return { kind: \"fail\", reason: \"provider\" };\n\tif (cp.attempt > cp.retry.maxRetries) return { kind: \"fail\", reason: \"retries_exhausted\" };\n\tconst delay = cp.retry.baseDelayMs * 2 ** Math.max(0, cp.attempt - 1);\n\tconst safeDelay = Number.isSafeInteger(delay) ? delay : Number.MAX_SAFE_INTEGER;\n\treturn { kind: \"retry\", untilMs: now + Math.min(safeDelay, cp.retry.maxAgentDelayMs ?? 60_000) };\n}\n\n// ---------------------------------------------------------------------------\n// Collapse triggers\n// ---------------------------------------------------------------------------\n\n/** Read-side of threshold collapse: computed before the assistant is appended, applied after. */\nasync function thresholdCollapseThrough(\n\ttx: CoreTx,\n\tconversationId: Id,\n\tmessage: AssistantMessage,\n): Promise<Id | undefined> {\n\tif ((await tx.tasks({ conversationId, kind: \"pi.collapse\", status: [\"pending\", \"running\"] })).length > 0)\n\t\treturn undefined;\n\tconst state = tx.rewindable(conversationId);\n\tif (state.threshold <= 0) return undefined;\n\tconst { entries, messages } = await tx.context(conversationId);\n\tconst used = Math.max(\n\t\t(message.usage?.input ?? 0) + (message.usage?.output ?? 0),\n\t\testimate([...messages, toStored(message)]),\n\t);\n\tif (used <= state.threshold) return undefined;\n\treturn chooseThrough(entries, state.keepRecent);\n}\n\nfunction overflow(task: G, rt: Rt): S {\n\treturn {\n\t\tdone: async (tx, current) => {\n\t\t\tconst c = current.conversationId;\n\t\t\tconst state = tx.rewindable(c);\n\t\t\tconst { entries, head } = await tx.context(c);\n\t\t\tconst through = chooseThrough(entries, state.keepRecent);\n\t\t\ttx.sticky(c).turn = { tools: [] };\n\t\t\tif (through === undefined) {\n\t\t\t\tawait tx.write(c, {\n\t\t\t\t\tkind: \"pi.notice\",\n\t\t\t\t\tmodel: [{ role: \"user\", content: \"Context too large; nothing to compact.\", timestamp: rt.now() }],\n\t\t\t\t});\n\t\t\t\ttx.emit({\n\t\t\t\t\ttype: \"generation.failed\",\n\t\t\t\t\ttaskId: current.id,\n\t\t\t\t\treason: \"overflow\",\n\t\t\t\t\tdetail: \"request exceeds context window and nothing is collapsible\",\n\t\t\t\t});\n\t\t\t\tawait settleFailedTurn(tx, current, task.input.inputs, \"overflow\", head?.id);\n\t\t\t\treturn fail(\"overflow\", \"request exceeds context window and nothing is collapsible\");\n\t\t\t}\n\t\t\tconst collapse = tx.createTask({ kind: \"pi.collapse\", input: { reason: \"overflow\", through } });\n\t\t\ttx.createTask({ kind: \"pi.generation\", after: [collapse], input: { inputs: task.input.inputs } });\n\t\t\ttx.emit({\n\t\t\t\ttype: \"generation.failed\",\n\t\t\t\ttaskId: current.id,\n\t\t\t\treason: \"overflow\",\n\t\t\t\tdetail: `collapsing through ${through}`,\n\t\t\t});\n\t\t\treturn fail(\"overflow\", `collapsing through ${through}`);\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"generation.d.ts","sourceRoot":"","sources":["../../../../src/harness/pico3/kinds/generation.ts"],"names":[],"mappings":"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"}