@earendil-works/pi-durable 0.99.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (203) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +557 -46
  3. package/dist/entries.d.ts +20 -2
  4. package/dist/entries.d.ts.map +1 -1
  5. package/dist/entries.js +14 -1
  6. package/dist/entries.js.map +1 -1
  7. package/dist/env/index.d.ts +18 -38
  8. package/dist/env/index.d.ts.map +1 -1
  9. package/dist/env/index.js +2 -0
  10. package/dist/env/index.js.map +1 -1
  11. package/dist/env/node.d.ts +2 -0
  12. package/dist/env/node.d.ts.map +1 -1
  13. package/dist/env/node.js +53 -58
  14. package/dist/env/node.js.map +1 -1
  15. package/dist/harness/agent.d.ts +31 -0
  16. package/dist/harness/agent.d.ts.map +1 -0
  17. package/dist/harness/agent.js +209 -0
  18. package/dist/harness/agent.js.map +1 -0
  19. package/dist/harness/compaction.d.ts +56 -0
  20. package/dist/harness/compaction.d.ts.map +1 -0
  21. package/dist/harness/compaction.js +382 -0
  22. package/dist/harness/compaction.js.map +1 -0
  23. package/dist/harness/context.d.ts +8 -0
  24. package/dist/harness/context.d.ts.map +1 -1
  25. package/dist/harness/context.js +32 -21
  26. package/dist/harness/context.js.map +1 -1
  27. package/dist/harness/define.d.ts +18 -0
  28. package/dist/harness/define.d.ts.map +1 -0
  29. package/dist/harness/define.js +25 -0
  30. package/dist/harness/define.js.map +1 -0
  31. package/dist/harness/events.d.ts +166 -0
  32. package/dist/harness/events.d.ts.map +1 -0
  33. package/dist/harness/events.js +319 -0
  34. package/dist/harness/events.js.map +1 -0
  35. package/dist/harness/generation.d.ts +36 -7
  36. package/dist/harness/generation.d.ts.map +1 -1
  37. package/dist/harness/generation.js +356 -82
  38. package/dist/harness/generation.js.map +1 -1
  39. package/dist/harness/harness.d.ts.map +1 -1
  40. package/dist/harness/harness.js +141 -106
  41. package/dist/harness/harness.js.map +1 -1
  42. package/dist/harness/inbox.d.ts +59 -0
  43. package/dist/harness/inbox.d.ts.map +1 -0
  44. package/dist/harness/inbox.js +97 -0
  45. package/dist/harness/inbox.js.map +1 -0
  46. package/dist/harness/json.d.ts +10 -0
  47. package/dist/harness/json.d.ts.map +1 -0
  48. package/dist/harness/json.js +33 -0
  49. package/dist/harness/json.js.map +1 -0
  50. package/dist/harness/live.d.ts +66 -7
  51. package/dist/harness/live.d.ts.map +1 -1
  52. package/dist/harness/live.js +71 -7
  53. package/dist/harness/live.js.map +1 -1
  54. package/dist/harness/output.d.ts +62 -0
  55. package/dist/harness/output.d.ts.map +1 -0
  56. package/dist/harness/output.js +261 -0
  57. package/dist/harness/output.js.map +1 -0
  58. package/dist/harness/prompt.d.ts +9 -6
  59. package/dist/harness/prompt.d.ts.map +1 -1
  60. package/dist/harness/prompt.js +57 -14
  61. package/dist/harness/prompt.js.map +1 -1
  62. package/dist/harness/registry.d.ts +2 -3
  63. package/dist/harness/registry.d.ts.map +1 -1
  64. package/dist/harness/registry.js +69 -277
  65. package/dist/harness/registry.js.map +1 -1
  66. package/dist/harness/scheduler.d.ts +42 -12
  67. package/dist/harness/scheduler.d.ts.map +1 -1
  68. package/dist/harness/scheduler.js +649 -75
  69. package/dist/harness/scheduler.js.map +1 -1
  70. package/dist/harness/submissions.d.ts +14 -9
  71. package/dist/harness/submissions.d.ts.map +1 -1
  72. package/dist/harness/submissions.js +76 -34
  73. package/dist/harness/submissions.js.map +1 -1
  74. package/dist/harness/task-graph.d.ts +49 -0
  75. package/dist/harness/task-graph.d.ts.map +1 -0
  76. package/dist/harness/task-graph.js +163 -0
  77. package/dist/harness/task-graph.js.map +1 -0
  78. package/dist/harness/tool.d.ts +36 -0
  79. package/dist/harness/tool.d.ts.map +1 -0
  80. package/dist/harness/tool.js +415 -0
  81. package/dist/harness/tool.js.map +1 -0
  82. package/dist/harness/types.d.ts +330 -125
  83. package/dist/harness/types.d.ts.map +1 -1
  84. package/dist/harness/types.js.map +1 -1
  85. package/dist/harness/usage.d.ts +18 -0
  86. package/dist/harness/usage.d.ts.map +1 -0
  87. package/dist/harness/usage.js +57 -0
  88. package/dist/harness/usage.js.map +1 -0
  89. package/dist/harness/view.d.ts +43 -0
  90. package/dist/harness/view.d.ts.map +1 -0
  91. package/dist/harness/view.js +189 -0
  92. package/dist/harness/view.js.map +1 -0
  93. package/dist/index.d.ts +13 -5
  94. package/dist/index.d.ts.map +1 -1
  95. package/dist/index.js +8 -2
  96. package/dist/index.js.map +1 -1
  97. package/dist/session/observation.d.ts +18 -11
  98. package/dist/session/observation.d.ts.map +1 -1
  99. package/dist/session/observation.js +24 -13
  100. package/dist/session/observation.js.map +1 -1
  101. package/dist/session/session.d.ts +10 -1
  102. package/dist/session/session.d.ts.map +1 -1
  103. package/dist/session/session.js +23 -5
  104. package/dist/session/session.js.map +1 -1
  105. package/dist/session/transaction.d.ts +12 -3
  106. package/dist/session/transaction.d.ts.map +1 -1
  107. package/dist/session/transaction.js +90 -31
  108. package/dist/session/transaction.js.map +1 -1
  109. package/dist/storage/jsonl/storage.d.ts +22 -2
  110. package/dist/storage/jsonl/storage.d.ts.map +1 -1
  111. package/dist/storage/jsonl/storage.js +1 -1
  112. package/dist/storage/jsonl/storage.js.map +1 -1
  113. package/dist/storage/memory.js +1 -1
  114. package/dist/storage/memory.js.map +1 -1
  115. package/dist/storage/sqlite/database.d.ts +26 -19
  116. package/dist/storage/sqlite/database.d.ts.map +1 -1
  117. package/dist/storage/sqlite/database.js.map +1 -1
  118. package/dist/storage/sqlite/index.d.ts +1 -1
  119. package/dist/storage/sqlite/index.d.ts.map +1 -1
  120. package/dist/storage/sqlite/index.js.map +1 -1
  121. package/dist/storage/sqlite/migrations.js +7 -7
  122. package/dist/storage/sqlite/migrations.js.map +1 -1
  123. package/dist/storage/sqlite/node.d.ts +23 -7
  124. package/dist/storage/sqlite/node.d.ts.map +1 -1
  125. package/dist/storage/sqlite/node.js +129 -47
  126. package/dist/storage/sqlite/node.js.map +1 -1
  127. package/dist/storage/sqlite/storage.d.ts +12 -0
  128. package/dist/storage/sqlite/storage.d.ts.map +1 -1
  129. package/dist/storage/sqlite/storage.js +121 -129
  130. package/dist/storage/sqlite/storage.js.map +1 -1
  131. package/dist/testing/storage-benchmark.d.ts.map +1 -1
  132. package/dist/testing/storage-benchmark.js +0 -1
  133. package/dist/testing/storage-benchmark.js.map +1 -1
  134. package/dist/testing/storage-conformance.d.ts.map +1 -1
  135. package/dist/testing/storage-conformance.js +34 -2
  136. package/dist/testing/storage-conformance.js.map +1 -1
  137. package/dist/tools/bash.d.ts +28 -0
  138. package/dist/tools/bash.d.ts.map +1 -0
  139. package/dist/tools/bash.js +70 -0
  140. package/dist/tools/bash.js.map +1 -0
  141. package/dist/tools/edit-diff.d.ts +89 -0
  142. package/dist/tools/edit-diff.d.ts.map +1 -0
  143. package/dist/tools/edit-diff.js +386 -0
  144. package/dist/tools/edit-diff.js.map +1 -0
  145. package/dist/tools/edit.d.ts +18 -0
  146. package/dist/tools/edit.d.ts.map +1 -0
  147. package/dist/tools/edit.js +117 -0
  148. package/dist/tools/edit.js.map +1 -0
  149. package/dist/tools/env.d.ts +5 -0
  150. package/dist/tools/env.d.ts.map +1 -0
  151. package/dist/tools/env.js +7 -0
  152. package/dist/tools/env.js.map +1 -0
  153. package/dist/tools/file-mutation-queue.d.ts +9 -0
  154. package/dist/tools/file-mutation-queue.d.ts.map +1 -0
  155. package/dist/tools/file-mutation-queue.js +52 -0
  156. package/dist/tools/file-mutation-queue.js.map +1 -0
  157. package/dist/tools/image.d.ts +2 -0
  158. package/dist/tools/image.d.ts.map +1 -0
  159. package/dist/tools/image.js +92 -0
  160. package/dist/tools/image.js.map +1 -0
  161. package/dist/tools/index.d.ts +23 -0
  162. package/dist/tools/index.d.ts.map +1 -0
  163. package/dist/tools/index.js +15 -0
  164. package/dist/tools/index.js.map +1 -0
  165. package/dist/tools/path-utils.d.ts +5 -0
  166. package/dist/tools/path-utils.d.ts.map +1 -0
  167. package/dist/tools/path-utils.js +26 -0
  168. package/dist/tools/path-utils.js.map +1 -0
  169. package/dist/tools/read.d.ts +17 -0
  170. package/dist/tools/read.d.ts.map +1 -0
  171. package/dist/tools/read.js +101 -0
  172. package/dist/tools/read.js.map +1 -0
  173. package/dist/tools/write.d.ts +10 -0
  174. package/dist/tools/write.d.ts.map +1 -0
  175. package/dist/tools/write.js +31 -0
  176. package/dist/tools/write.js.map +1 -0
  177. package/dist/{env/utils/truncate.d.ts → truncate.d.ts} +1 -17
  178. package/dist/truncate.d.ts.map +1 -0
  179. package/dist/truncate.js +146 -0
  180. package/dist/truncate.js.map +1 -0
  181. package/dist/types.d.ts +97 -19
  182. package/dist/types.d.ts.map +1 -1
  183. package/dist/types.js.map +1 -1
  184. package/package.json +32 -14
  185. package/dist/env/utils/adaptive-publisher.d.ts +0 -24
  186. package/dist/env/utils/adaptive-publisher.d.ts.map +0 -1
  187. package/dist/env/utils/adaptive-publisher.js +0 -79
  188. package/dist/env/utils/adaptive-publisher.js.map +0 -1
  189. package/dist/env/utils/output-capture.d.ts +0 -31
  190. package/dist/env/utils/output-capture.d.ts.map +0 -1
  191. package/dist/env/utils/output-capture.js +0 -238
  192. package/dist/env/utils/output-capture.js.map +0 -1
  193. package/dist/env/utils/truncate.d.ts.map +0 -1
  194. package/dist/env/utils/truncate.js +0 -294
  195. package/dist/env/utils/truncate.js.map +0 -1
  196. package/dist/harness/config.d.ts +0 -20
  197. package/dist/harness/config.d.ts.map +0 -1
  198. package/dist/harness/config.js +0 -18
  199. package/dist/harness/config.js.map +0 -1
  200. package/docs/chord-delta-findings.md +0 -358
  201. package/docs/pico-v5-chord-usage.md +0 -373
  202. package/docs/pico-v5-handoff.md +0 -581
  203. package/docs/pico-v5.md +0 -3084
@@ -1 +1 @@
1
- {"version":3,"file":"submissions.js","sourceRoot":"","sources":["../../src/harness/submissions.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Context } from \"@earendil-works/chord\";\nimport { UserEntry } from \"../entries.ts\";\nimport { ConversationBusy } from \"../errors.ts\";\nimport type { SessionImpl } from \"../session/session.ts\";\nimport type { CommitPublication, ConversationId, Storage, SubmissionId, SubmissionRecord } from \"../types.ts\";\nimport { GenerationTask } from \"./generation.ts\";\nimport { LiveDoc } from \"./live.ts\";\nimport type { SettledSubmissionRecord, Submission, SubmissionDraft } from \"./types.ts\";\nimport { closedError, Waiters } from \"./util.ts\";\n\ntype AbortResult = \"aborted\" | \"already_placed\" | \"settled\";\n\n/** Admission, waits, and withdrawal of the durable submissions of one Harness. */\nexport class Submissions {\n\treadonly #session: SessionImpl;\n\treadonly #storage: Storage;\n\treadonly #now: () => number;\n\t/** Enable task scheduling; submitting or waiting asks for progress. */\n\treadonly #resume: () => void;\n\treadonly #waiters = new Waiters<SubmissionId, SettledSubmissionRecord>();\n\t#closed = false;\n\n\tconstructor(session: SessionImpl, storage: Storage, now: () => number, resume: () => void) {\n\t\tthis.#session = session;\n\t\tthis.#storage = storage;\n\t\tthis.#now = now;\n\t\tthis.#resume = resume;\n\t\tsession.subscribeCommits((publication) => this.#observe(publication));\n\t\tsession.subscribeClose(() => {\n\t\t\tthis.#closed = true;\n\t\t\tthis.#waiters.rejectAll(closedError());\n\t\t});\n\t}\n\n\t/**\n\t * Admit a submission in one commit. A known request ID returns its existing submission without writing. Until the\n\t * inbox exists, a busy conversation rejects with `ConversationBusy` and writes nothing. Idle input places a user\n\t * entry and starts a generation run; an idle write appends its entry and settles `done`.\n\t */\n\tasync submit(conversationId: ConversationId, draft: SubmissionDraft, context: Context): Promise<Submission> {\n\t\tthis.#resume();\n\t\tconst id = await this.#session.commitWith(async (tx) => {\n\t\t\tif (draft.requestId !== undefined) {\n\t\t\t\tconst existing = await tx.submissionByRequest(conversationId, draft.requestId);\n\t\t\t\tif (existing !== undefined) {\n\t\t\t\t\tif (existing.type !== draft.type) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t`Request ${draft.requestId} already identifies a submission of type ${existing.type}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn existing.id;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst live = await tx.doc(LiveDoc, conversationId);\n\t\t\tif (live.run !== undefined) throw new ConversationBusy(conversationId);\n\t\t\tconst requestId = draft.requestId === undefined ? {} : { requestId: draft.requestId };\n\t\t\tif (draft.type === \"write\") {\n\t\t\t\tconst entry = await tx.appendEntry(conversationId, draft.entry);\n\t\t\t\tconst write = { conversationId, ...requestId, type: \"write\", status: \"done\", entry: entry.id } as const;\n\t\t\t\treturn (await tx.createSubmission(write)).id;\n\t\t\t}\n\t\t\tconst message = { role: \"user\", content: draft.content, timestamp: this.#now() } as const;\n\t\t\tconst entry = await tx.appendEntry(UserEntry, conversationId, { model: [message] });\n\t\t\tconst input = { conversationId, ...requestId, type: \"input\", status: \"placed\", entry: entry.id } as const;\n\t\t\tconst { id } = await tx.createSubmission(input);\n\t\t\tlive.run = { taskId: await tx.createTask(GenerationTask, {}, { conversationId }), inputs: [id] };\n\t\t\treturn id;\n\t\t}, context);\n\t\treturn new SubmissionHandle(id, this);\n\t}\n\n\t/** Handle for an existing submission, or `undefined`. */\n\tasync get(id: SubmissionId, context: Context): Promise<Submission | undefined> {\n\t\tconst record = await this.#session.readOnLine(() => this.#storage.submission(id, context));\n\t\treturn record === undefined ? undefined : new SubmissionHandle(record.id, this);\n\t}\n\n\tasync status(id: SubmissionId, context: Context): Promise<SubmissionRecord> {\n\t\tconst record = await this.#session.readOnLine(() => this.#storage.submission(id, context));\n\t\tif (record === undefined) throw new Error(`Submission ${id} does not exist`);\n\t\treturn record;\n\t}\n\n\tasync wait(id: SubmissionId, context: Context): Promise<SettledSubmissionRecord> {\n\t\tthis.#resume();\n\t\t// Check and register on the line so no settling publication falls between them.\n\t\tconst found = await this.#session.readOnLine(async () => {\n\t\t\tconst record = await this.#storage.submission(id, context);\n\t\t\tif (record === undefined) throw new Error(`Submission ${id} does not exist`);\n\t\t\tif (isSettled(record)) return { promise: Promise.resolve(record) };\n\t\t\t// Close rejects registered waiters synchronously and may begin during the read.\n\t\t\tif (this.#closed) throw closedError();\n\t\t\treturn { promise: this.#waiters.add(id, context) };\n\t\t});\n\t\treturn found.promise;\n\t}\n\n\t/** Withdraw a queued submission; placed inputs and settled submissions are reported, not changed. */\n\tabort(id: SubmissionId, context: Context, conversationId?: ConversationId): Promise<AbortResult | \"not_found\"> {\n\t\treturn this.#session.commitWith(async (tx) => {\n\t\t\tconst record = await tx.submission(id);\n\t\t\tif (record === undefined || (conversationId !== undefined && record.conversationId !== conversationId)) {\n\t\t\t\treturn \"not_found\";\n\t\t\t}\n\t\t\tif (record.status === \"queued\") {\n\t\t\t\ttx.settleSubmission(id, { status: \"unanswered\", reason: \"aborted\" });\n\t\t\t\treturn \"aborted\";\n\t\t\t}\n\t\t\treturn record.status === \"placed\" ? \"already_placed\" : \"settled\";\n\t\t}, context);\n\t}\n\n\t#observe(publication: CommitPublication): void {\n\t\tfor (const change of publication.changes) {\n\t\t\tif (change.type !== \"submission\" || !isSettled(change.value)) continue;\n\t\t\tthis.#waiters.resolve(change.value.id, change.value);\n\t\t}\n\t}\n}\n\nclass SubmissionHandle implements Submission {\n\treadonly id: SubmissionId;\n\treadonly #submissions: Submissions;\n\n\tconstructor(id: SubmissionId, submissions: Submissions) {\n\t\tthis.id = id;\n\t\tthis.#submissions = submissions;\n\t}\n\n\tstatus(context: Context): Promise<SubmissionRecord> {\n\t\treturn this.#submissions.status(this.id, context);\n\t}\n\n\twait(context: Context): Promise<SettledSubmissionRecord> {\n\t\treturn this.#submissions.wait(this.id, context);\n\t}\n\n\tasync abort(context: Context): Promise<AbortResult> {\n\t\tconst result = await this.#submissions.abort(this.id, context);\n\t\tif (result === \"not_found\") throw new Error(`Submission ${this.id} does not exist`);\n\t\treturn result;\n\t}\n}\n\nfunction isSettled(record: SubmissionRecord): record is SettledSubmissionRecord {\n\treturn record.status === \"done\" || record.status === \"unanswered\";\n}\n"]}
1
+ {"version":3,"file":"submissions.js","sourceRoot":"","sources":["../../src/harness/submissions.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Context, copyJson, type JsonRepresentation } from \"@earendil-works/chord\";\nimport { UserEntry } from \"../entries.ts\";\nimport { ConversationBusy } from \"../errors.ts\";\nimport type { SessionImpl } from \"../session/session.ts\";\nimport type {\n\tCommitPublication,\n\tConversationId,\n\tJsonObject,\n\tStorage,\n\tSubmissionId,\n\tSubmissionRecord,\n\tTx,\n} from \"../types.ts\";\nimport { startRun } from \"./generation.ts\";\nimport { applyBoundary, InboxDoc, isStale, prepareBoundary, type QueueModes, removeInboxItem } from \"./inbox.ts\";\nimport { LiveDoc } from \"./live.ts\";\nimport type { SettledSubmissionRecord, Submission, SubmissionDraft, UserInput } from \"./types.ts\";\nimport { closedError, Waiters } from \"./util.ts\";\n\ntype AbortResult = \"aborted\" | \"already_placed\" | \"settled\";\n\n/** Admission, waits, and withdrawal of the durable submissions of one Harness. */\nexport class Submissions {\n\treadonly #session: SessionImpl;\n\treadonly #storage: Storage;\n\treadonly #now: () => number;\n\t/** Read at each admission, on the Session line. */\n\treadonly #queueModes: () => QueueModes;\n\t/** Enable task scheduling; submitting or waiting asks for progress. */\n\treadonly #resume: () => void;\n\treadonly #waiters = new Waiters<SubmissionId, SettledSubmissionRecord>();\n\t#closed = false;\n\n\tconstructor(\n\t\tsession: SessionImpl,\n\t\tstorage: Storage,\n\t\tnow: () => number,\n\t\tqueueModes: () => QueueModes,\n\t\tresume: () => void,\n\t) {\n\t\tthis.#session = session;\n\t\tthis.#storage = storage;\n\t\tthis.#now = now;\n\t\tthis.#queueModes = queueModes;\n\t\tthis.#resume = resume;\n\t\tsession.subscribeCommits((publication) => this.#observe(publication));\n\t\tsession.subscribeClose(() => {\n\t\t\tthis.#closed = true;\n\t\t\tthis.#waiters.rejectAll(closedError());\n\t\t});\n\t}\n\n\t/** Admit a submission in one commit; see `admitSubmission()`. */\n\tasync submit(conversationId: ConversationId, draft: SubmissionDraft, context: Context): Promise<Submission> {\n\t\tthis.#resume();\n\t\tconst id = await this.#session.commitWith(\n\t\t\t(tx) => admitSubmission(tx, conversationId, draft, this.#now(), this.#queueModes()),\n\t\t\tcontext,\n\t\t);\n\t\treturn new SubmissionHandle(id, this);\n\t}\n\n\t/** Handle for an existing submission, or `undefined`. */\n\tasync get(id: SubmissionId, context: Context): Promise<Submission | undefined> {\n\t\tconst record = await this.#session.readOnLine(() => this.#storage.submission(id, context));\n\t\treturn record === undefined ? undefined : new SubmissionHandle(record.id, this);\n\t}\n\n\tasync status(id: SubmissionId, context: Context): Promise<SubmissionRecord> {\n\t\tconst record = await this.#session.readOnLine(() => this.#storage.submission(id, context));\n\t\tif (record === undefined) throw new Error(`Submission ${id} does not exist`);\n\t\treturn record;\n\t}\n\n\tasync wait(id: SubmissionId, context: Context): Promise<SettledSubmissionRecord> {\n\t\tthis.#resume();\n\t\t// Check and register on the line so no settling publication falls between them.\n\t\tconst found = await this.#session.readOnLine(async () => {\n\t\t\tconst record = await this.#storage.submission(id, context);\n\t\t\tif (record === undefined) throw new Error(`Submission ${id} does not exist`);\n\t\t\tif (isSettled(record)) return { promise: Promise.resolve(record) };\n\t\t\t// Close rejects registered waiters synchronously and may begin during the read.\n\t\t\tif (this.#closed) throw closedError();\n\t\t\treturn { promise: this.#waiters.add(id, context) };\n\t\t});\n\t\treturn found.promise;\n\t}\n\n\t/** Withdraw a queued submission and remove its inbox item; placed inputs and settled submissions are reported. */\n\tabort(id: SubmissionId, context: Context, conversationId?: ConversationId): Promise<AbortResult | \"not_found\"> {\n\t\treturn this.#session.commitWith(async (tx) => {\n\t\t\tconst record = await tx.submission(id);\n\t\t\tif (record === undefined || (conversationId !== undefined && record.conversationId !== conversationId)) {\n\t\t\t\treturn \"not_found\";\n\t\t\t}\n\t\t\tif (record.status === \"queued\") {\n\t\t\t\ttx.settleSubmission(id, { status: \"unanswered\", reason: \"aborted\" });\n\t\t\t\tawait removeInboxItem(tx, record.conversationId, id);\n\t\t\t\treturn \"aborted\";\n\t\t\t}\n\t\t\treturn record.status === \"placed\" ? \"already_placed\" : \"settled\";\n\t\t}, context);\n\t}\n\n\t#observe(publication: CommitPublication): void {\n\t\tfor (const change of publication.changes) {\n\t\t\tif (change.type !== \"submission\" || !isSettled(change.value)) continue;\n\t\t\tthis.#waiters.resolve(change.value.id, change.value);\n\t\t}\n\t}\n}\n\nclass SubmissionHandle implements Submission {\n\treadonly id: SubmissionId;\n\treadonly #submissions: Submissions;\n\n\tconstructor(id: SubmissionId, submissions: Submissions) {\n\t\tthis.id = id;\n\t\tthis.#submissions = submissions;\n\t}\n\n\tstatus(context: Context): Promise<SubmissionRecord> {\n\t\treturn this.#submissions.status(this.id, context);\n\t}\n\n\twait(context: Context): Promise<SettledSubmissionRecord> {\n\t\treturn this.#submissions.wait(this.id, context);\n\t}\n\n\tasync abort(context: Context): Promise<AbortResult> {\n\t\tconst result = await this.#submissions.abort(this.id, context);\n\t\tif (result === \"not_found\") throw new Error(`Submission ${this.id} does not exist`);\n\t\treturn result;\n\t}\n}\n\nfunction isSettled(record: SubmissionRecord): record is SettledSubmissionRecord {\n\treturn record.status === \"done\" || record.status === \"unanswered\";\n}\n\n/**\n * Admit a submission inside a commit (spec §6); `Conversation.submit()` and conversation-owned compactions share it. A\n * known request ID returns its existing submission without writing. A busy conversation queues it in `pi.inbox`, or\n * rejects `whenBusy: \"reject\"` input with `ConversationBusy`. An idle conversation with queued items queues it behind\n * them and runs a final boundary. Otherwise idle input places a user entry and starts a run, and an idle write appends\n * its entry and settles `done`, or `stale` when its head reaches before the active range.\n */\nexport async function admitSubmission(\n\ttx: Tx,\n\tconversationId: ConversationId,\n\tdraft: SubmissionDraft,\n\tnow: number,\n\tqueueModes: QueueModes,\n): Promise<SubmissionId> {\n\tif (draft.requestId !== undefined) {\n\t\tconst existing = await tx.submissionByRequest(conversationId, draft.requestId);\n\t\tif (existing !== undefined) {\n\t\t\tif (existing.type !== draft.type) {\n\t\t\t\tthrow new Error(`Request ${draft.requestId} already identifies a submission of type ${existing.type}`);\n\t\t\t}\n\t\t\treturn existing.id;\n\t\t}\n\t}\n\tconst live = await tx.doc(LiveDoc, conversationId);\n\tconst busy = live.run !== undefined;\n\tif (busy && draft.type === \"input\" && draft.whenBusy === \"reject\") throw new ConversationBusy(conversationId);\n\tconst requestId = draft.requestId === undefined ? {} : { requestId: draft.requestId };\n\t// A boundary reads the table, so it is prepared before the first table write; a busy one needs none.\n\tconst boundary = busy ? undefined : await prepareBoundary(tx, conversationId, queueModes);\n\tif (boundary === undefined || boundary.inbox.items.length > 0) {\n\t\tconst { id } = await tx.createSubmission({\n\t\t\tconversationId,\n\t\t\t...requestId,\n\t\t\ttype: draft.type,\n\t\t\tstatus: \"queued\",\n\t\t});\n\t\t// Hosts may leave optional fields `undefined`; drafts take strict JSON.\n\t\tconst value = copyJson(draft.type === \"write\" ? draft.entry : draft.content, {\n\t\t\tomitUndefinedProperties: true,\n\t\t});\n\t\tconst items = (boundary?.inbox ?? (await tx.doc(InboxDoc, conversationId))).items;\n\t\tif (draft.type === \"write\") items.push({ id, mode: \"write\", entry: value as JsonObject });\n\t\telse {\n\t\t\tconst mode = draft.whenBusy === \"steer\" ? \"steer\" : \"followUp\";\n\t\t\titems.push({ id, mode, content: value as JsonRepresentation<UserInput> });\n\t\t}\n\t\tif (boundary === undefined) return id;\n\t\tconst { users } = await applyBoundary(tx, boundary, \"final\", now);\n\t\tif (users.length > 0) await startRun(tx, conversationId, live, users);\n\t\treturn id;\n\t}\n\tif (draft.type === \"write\") {\n\t\tif (isStale(boundary, draft.entry)) {\n\t\t\tconst stale = { status: \"unanswered\", reason: \"stale\" } as const;\n\t\t\treturn (await tx.createSubmission({ conversationId, ...requestId, type: \"write\", ...stale })).id;\n\t\t}\n\t\tconst entry = await tx.appendEntry(conversationId, draft.entry);\n\t\tconst write = { conversationId, ...requestId, type: \"write\", status: \"done\", entry: entry.id } as const;\n\t\treturn (await tx.createSubmission(write)).id;\n\t}\n\tconst message = { role: \"user\", content: draft.content, timestamp: now } as const;\n\tconst entry = await tx.appendEntry(UserEntry, conversationId, { model: [message] });\n\tconst input = { conversationId, ...requestId, type: \"input\", status: \"placed\", entry: entry.id } as const;\n\tconst { id } = await tx.createSubmission(input);\n\tawait startRun(tx, conversationId, live, [id]);\n\treturn id;\n}\n"]}
@@ -0,0 +1,49 @@
1
+ import { type AttachedReplicatedState, type Context, type JsonValue } from "@earendil-works/chord";
2
+ import type { SessionImpl } from "../session/session.ts";
3
+ import type { ConversationId, JoinPolicy, Storage, TaskId, TaskOutcome, WatchHandle } from "../types.ts";
4
+ /** A live task's durable status without its checkpoint and outcome payloads (spec §9.5). */
5
+ export type TaskGraphState = {
6
+ readonly status: "pending" | "running";
7
+ readonly phase: string;
8
+ } | {
9
+ readonly status: "waiting";
10
+ readonly phase: string;
11
+ readonly on: readonly TaskId[];
12
+ readonly policy: JoinPolicy;
13
+ }
14
+ /** Outcome held until its ordinary owned work drains. */
15
+ | {
16
+ readonly status: "completing";
17
+ readonly outcome: TaskOutcome<JsonValue>["status"];
18
+ };
19
+ export type TaskGraphNode = {
20
+ readonly id: TaskId;
21
+ readonly kind: string;
22
+ readonly conversationId: ConversationId;
23
+ /** Owner task; absent for a conversation-owned task. */
24
+ readonly owner?: TaskId;
25
+ readonly background: boolean;
26
+ readonly abortRequested: boolean;
27
+ readonly state: TaskGraphState;
28
+ /** Conversations this task owns, in ID order. */
29
+ readonly conversations: readonly ConversationId[];
30
+ };
31
+ /** Every live task of the Session (spec §9.5). */
32
+ export type TaskGraph = {
33
+ /** Every live task, keyed by its decimal ID. */
34
+ readonly tasks: Readonly<Record<string, TaskGraphNode>>;
35
+ };
36
+ export type TaskGraphWatch = WatchHandle<TaskGraph>;
37
+ /**
38
+ * The Harness's task graph mount: built on the Session line by its first observer and dropped with its last. It
39
+ * advances from the Session's commit publications, which are durable.
40
+ */
41
+ export declare class TaskGraphView {
42
+ #private;
43
+ constructor(session: SessionImpl, storage: Storage);
44
+ /** A disposable read-only Chord state of the graph. */
45
+ state(context: Context): Promise<AttachedReplicatedState<TaskGraph>>;
46
+ /** A serialized exact-frame watch of the graph; cancelling `context` stops it. */
47
+ watch(context: Context): Promise<TaskGraphWatch>;
48
+ }
49
+ //# sourceMappingURL=task-graph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-graph.d.ts","sourceRoot":"","sources":["../../src/harness/task-graph.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,uBAAuB,EAAE,KAAK,OAAO,EAAE,KAAK,SAAS,EAAmB,MAAM,uBAAuB,CAAC;AAIpH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAEX,cAAc,EACd,UAAU,EACV,OAAO,EACP,MAAM,EACN,WAAW,EAEX,WAAW,EACX,MAAM,aAAa,CAAC;AAGrB,4FAA4F;AAC5F,MAAM,MAAM,cAAc,GACvB;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAClE;IACA,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;CAC3B;AACH,yDAAyD;GACvD;IAAE,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAA;CAAE,CAAC;AAEzF,MAAM,MAAM,aAAa,GAAG;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC,wDAAwD;IACxD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,iDAAiD;IACjD,QAAQ,CAAC,aAAa,EAAE,SAAS,cAAc,EAAE,CAAC;CAClD,CAAC;AAEF,kDAAkD;AAClD,MAAM,MAAM,SAAS,GAAG;IACvB,gDAAgD;IAChD,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;CACxD,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;AASpD;;;GAGG;AACH,qBAAa,aAAa;;IAMzB,YAAY,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAWjD;IAED,uDAAuD;IACjD,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,uBAAuB,CAAC,SAAS,CAAC,CAAC,CAWzE;IAED,kFAAkF;IAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC,CAYrD;CAyCD"}
@@ -0,0 +1,163 @@
1
+ import { replicatedState } from "@earendil-works/chord";
2
+ import { withoutAbortSignal } from "@earendil-works/chord/context";
3
+ import { applyImmutable } from "@earendil-works/chord/delta";
4
+ import { CommittedStateSource, CommittedWatch } from "../session/observation.js";
5
+ import { closedError, scanAll } from "./util.js";
6
+ const LIVE_STATUSES = ["pending", "running", "waiting", "completing"];
7
+ const SCAN_PAGE_SIZE = 256;
8
+ /**
9
+ * The Harness's task graph mount: built on the Session line by its first observer and dropped with its last. It
10
+ * advances from the Session's commit publications, which are durable.
11
+ */
12
+ export class TaskGraphView {
13
+ #session;
14
+ #storage;
15
+ #mount;
16
+ #closed = false;
17
+ constructor(session, storage) {
18
+ this.#session = session;
19
+ this.#storage = storage;
20
+ session.subscribeCommits((publication, context) => {
21
+ if (this.#mount !== undefined)
22
+ advance(this.#mount, publication, context);
23
+ });
24
+ session.subscribeClose(() => {
25
+ this.#closed = true;
26
+ for (const observer of [...(this.#mount?.observers ?? [])])
27
+ observer.closeSession();
28
+ this.#mount = undefined;
29
+ });
30
+ }
31
+ /** A disposable read-only Chord state of the graph. */
32
+ async state(context) {
33
+ const { observer, detach } = await this.#attach((value, release) => new CommittedStateSource(value, release), context);
34
+ try {
35
+ return replicatedState(observer);
36
+ }
37
+ catch (error) {
38
+ detach();
39
+ throw error;
40
+ }
41
+ }
42
+ /** A serialized exact-frame watch of the graph; cancelling `context` stops it. */
43
+ async watch(context) {
44
+ const { observer } = await this.#attach((value, release) => new CommittedWatch(value, release), context);
45
+ const signal = context.abortSignal;
46
+ if (signal?.aborted) {
47
+ observer.cancel();
48
+ throw signal.reason;
49
+ }
50
+ if (signal !== undefined)
51
+ observer.observeCancellation(signal);
52
+ return observer;
53
+ }
54
+ /** Register an observer created from the current revision, atomically on the Session line. */
55
+ #attach(create, context) {
56
+ return this.#session.readOnLine(async () => {
57
+ const mount = this.#mount ?? { value: await this.#build(context), observers: new Set() };
58
+ const detach = () => {
59
+ mount.observers.delete(observer);
60
+ if (mount.observers.size === 0 && this.#mount === mount)
61
+ this.#mount = undefined;
62
+ };
63
+ const observer = create(mount.value, detach);
64
+ // Close or cancellation may begin while the mount builds; register nothing then.
65
+ if (this.#closed)
66
+ throw closedError();
67
+ context.abortSignal?.throwIfAborted();
68
+ this.#mount = mount;
69
+ mount.observers.add(observer);
70
+ return { observer, detach };
71
+ });
72
+ }
73
+ async #build(context) {
74
+ const tasks = {};
75
+ const records = [];
76
+ for (const status of LIVE_STATUSES) {
77
+ records.push(...(await scanAll((cursor) => this.#storage.scanTasks({ status }, SCAN_PAGE_SIZE, cursor, context))));
78
+ }
79
+ records.sort((a, b) => a.id - b.id);
80
+ for (const record of records) {
81
+ const owned = await scanAll((cursor) => this.#storage.scanConversations({ ownerTaskId: record.id }, SCAN_PAGE_SIZE, cursor, context));
82
+ const conversations = owned.map((conversation) => conversation.id).sort((a, b) => a - b);
83
+ tasks[String(record.id)] = nodeOf(record, conversations);
84
+ }
85
+ return { tasks };
86
+ }
87
+ }
88
+ /** Derive the mount's operations from one publication, apply them, and hand the revision to every observer. */
89
+ function advance(mount, publication, context) {
90
+ const ops = [];
91
+ // Nodes this publication set or deleted, over the mount's value.
92
+ const changed = new Map();
93
+ const node = (key) => changed.has(key) ? changed.get(key) : mount.value.tasks[key];
94
+ for (const change of publication.changes) {
95
+ if (change.type !== "task")
96
+ continue;
97
+ const record = change.value;
98
+ const key = String(record.id);
99
+ const previous = node(key);
100
+ if (record.state.status === "terminal") {
101
+ if (previous === undefined)
102
+ continue;
103
+ ops.push(["d", ["tasks", key]]);
104
+ changed.set(key, undefined);
105
+ continue;
106
+ }
107
+ const next = nodeOf(record, previous?.conversations ?? []);
108
+ if (previous !== undefined && JSON.stringify(next) === JSON.stringify(previous))
109
+ continue;
110
+ ops.push(["s", ["tasks", key], next]);
111
+ changed.set(key, next);
112
+ }
113
+ // After the tasks, so a conversation created with its owner task in one commit finds the owner's node. Change order
114
+ // within a publication is unspecified, so each owner's list is sorted again.
115
+ const created = new Map();
116
+ for (const change of publication.changes) {
117
+ if (change.type !== "conversation" || change.value.owner === undefined)
118
+ continue;
119
+ const key = String(change.value.owner.taskId);
120
+ if (node(key) !== undefined)
121
+ created.set(key, [...(created.get(key) ?? []), change.value.id]);
122
+ }
123
+ for (const [key, ids] of created) {
124
+ const conversations = [...node(key).conversations, ...ids].sort((a, b) => a - b);
125
+ ops.push(["s", ["tasks", key, "conversations"], conversations]);
126
+ }
127
+ if (ops.length === 0)
128
+ return;
129
+ mount.value = applyImmutable(mount.value, ops);
130
+ const frameContext = withoutAbortSignal(context);
131
+ for (const observer of [...mount.observers])
132
+ observer.advance(mount.value, ops, frameContext);
133
+ }
134
+ function nodeOf(record, conversations) {
135
+ return {
136
+ id: record.id,
137
+ kind: record.kind,
138
+ conversationId: record.conversationId,
139
+ ...(record.owner === undefined ? {} : { owner: record.owner }),
140
+ background: record.background,
141
+ abortRequested: record.abortRequested,
142
+ state: stateOf(record),
143
+ conversations,
144
+ };
145
+ }
146
+ function stateOf(record) {
147
+ const state = record.state;
148
+ switch (state.status) {
149
+ case "pending":
150
+ case "running":
151
+ return { status: state.status, phase: phaseOf(state.checkpoint) };
152
+ case "waiting":
153
+ return { status: "waiting", phase: phaseOf(state.checkpoint), on: [...state.on], policy: state.policy };
154
+ // Terminal records never reach here: they leave the graph.
155
+ case "completing":
156
+ case "terminal":
157
+ return { status: "completing", outcome: state.outcome.status };
158
+ }
159
+ }
160
+ function phaseOf(checkpoint) {
161
+ return checkpoint.phase;
162
+ }
163
+ //# sourceMappingURL=task-graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-graph.js","sourceRoot":"","sources":["../../src/harness/task-graph.ts"],"names":[],"mappings":"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","sourcesContent":["import { type AttachedReplicatedState, type Context, type JsonValue, replicatedState } from \"@earendil-works/chord\";\nimport { withoutAbortSignal } from \"@earendil-works/chord/context\";\nimport { applyImmutable, type Op } from \"@earendil-works/chord/delta\";\nimport { CommittedStateSource, CommittedWatch } from \"../session/observation.ts\";\nimport type { SessionImpl } from \"../session/session.ts\";\nimport type {\n\tCommitPublication,\n\tConversationId,\n\tJoinPolicy,\n\tStorage,\n\tTaskId,\n\tTaskOutcome,\n\tTaskRecord,\n\tWatchHandle,\n} from \"../types.ts\";\nimport { closedError, scanAll } from \"./util.ts\";\n\n/** A live task's durable status without its checkpoint and outcome payloads (spec §9.5). */\nexport type TaskGraphState =\n\t| { readonly status: \"pending\" | \"running\"; readonly phase: string }\n\t| {\n\t\t\treadonly status: \"waiting\";\n\t\t\treadonly phase: string;\n\t\t\treadonly on: readonly TaskId[];\n\t\t\treadonly policy: JoinPolicy;\n\t }\n\t/** Outcome held until its ordinary owned work drains. */\n\t| { readonly status: \"completing\"; readonly outcome: TaskOutcome<JsonValue>[\"status\"] };\n\nexport type TaskGraphNode = {\n\treadonly id: TaskId;\n\treadonly kind: string;\n\treadonly conversationId: ConversationId;\n\t/** Owner task; absent for a conversation-owned task. */\n\treadonly owner?: TaskId;\n\treadonly background: boolean;\n\treadonly abortRequested: boolean;\n\treadonly state: TaskGraphState;\n\t/** Conversations this task owns, in ID order. */\n\treadonly conversations: readonly ConversationId[];\n};\n\n/** Every live task of the Session (spec §9.5). */\nexport type TaskGraph = {\n\t/** Every live task, keyed by its decimal ID. */\n\treadonly tasks: Readonly<Record<string, TaskGraphNode>>;\n};\n\nexport type TaskGraphWatch = WatchHandle<TaskGraph>;\n\ntype AnyTaskRecord = TaskRecord<JsonValue, JsonValue, JsonValue>;\ntype Observer = CommittedStateSource<TaskGraph> | CommittedWatch<TaskGraph>;\ntype Mount = { value: TaskGraph; readonly observers: Set<Observer> };\n\nconst LIVE_STATUSES = [\"pending\", \"running\", \"waiting\", \"completing\"] as const;\nconst SCAN_PAGE_SIZE = 256;\n\n/**\n * The Harness's task graph mount: built on the Session line by its first observer and dropped with its last. It\n * advances from the Session's commit publications, which are durable.\n */\nexport class TaskGraphView {\n\treadonly #session: SessionImpl;\n\treadonly #storage: Storage;\n\t#mount: Mount | undefined;\n\t#closed = false;\n\n\tconstructor(session: SessionImpl, storage: Storage) {\n\t\tthis.#session = session;\n\t\tthis.#storage = storage;\n\t\tsession.subscribeCommits((publication, context) => {\n\t\t\tif (this.#mount !== undefined) advance(this.#mount, publication, context);\n\t\t});\n\t\tsession.subscribeClose(() => {\n\t\t\tthis.#closed = true;\n\t\t\tfor (const observer of [...(this.#mount?.observers ?? [])]) observer.closeSession();\n\t\t\tthis.#mount = undefined;\n\t\t});\n\t}\n\n\t/** A disposable read-only Chord state of the graph. */\n\tasync state(context: Context): Promise<AttachedReplicatedState<TaskGraph>> {\n\t\tconst { observer, detach } = await this.#attach(\n\t\t\t(value, release) => new CommittedStateSource<TaskGraph>(value, release),\n\t\t\tcontext,\n\t\t);\n\t\ttry {\n\t\t\treturn replicatedState(observer);\n\t\t} catch (error) {\n\t\t\tdetach();\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/** A serialized exact-frame watch of the graph; cancelling `context` stops it. */\n\tasync watch(context: Context): Promise<TaskGraphWatch> {\n\t\tconst { observer } = await this.#attach(\n\t\t\t(value, release) => new CommittedWatch<TaskGraph>(value, release),\n\t\t\tcontext,\n\t\t);\n\t\tconst signal = context.abortSignal;\n\t\tif (signal?.aborted) {\n\t\t\tobserver.cancel();\n\t\t\tthrow signal.reason;\n\t\t}\n\t\tif (signal !== undefined) observer.observeCancellation(signal);\n\t\treturn observer;\n\t}\n\n\t/** Register an observer created from the current revision, atomically on the Session line. */\n\t#attach<O extends Observer>(\n\t\tcreate: (value: TaskGraph, release: () => void) => O,\n\t\tcontext: Context,\n\t): Promise<{ observer: O; detach: () => void }> {\n\t\treturn this.#session.readOnLine(async () => {\n\t\t\tconst mount = this.#mount ?? { value: await this.#build(context), observers: new Set<Observer>() };\n\t\t\tconst detach = (): void => {\n\t\t\t\tmount.observers.delete(observer);\n\t\t\t\tif (mount.observers.size === 0 && this.#mount === mount) this.#mount = undefined;\n\t\t\t};\n\t\t\tconst observer = create(mount.value, detach);\n\t\t\t// Close or cancellation may begin while the mount builds; register nothing then.\n\t\t\tif (this.#closed) throw closedError();\n\t\t\tcontext.abortSignal?.throwIfAborted();\n\t\t\tthis.#mount = mount;\n\t\t\tmount.observers.add(observer);\n\t\t\treturn { observer, detach };\n\t\t});\n\t}\n\n\tasync #build(context: Context): Promise<TaskGraph> {\n\t\tconst tasks: Record<string, TaskGraphNode> = {};\n\t\tconst records: AnyTaskRecord[] = [];\n\t\tfor (const status of LIVE_STATUSES) {\n\t\t\trecords.push(\n\t\t\t\t...(await scanAll((cursor) => this.#storage.scanTasks({ status }, SCAN_PAGE_SIZE, cursor, context))),\n\t\t\t);\n\t\t}\n\t\trecords.sort((a, b) => a.id - b.id);\n\t\tfor (const record of records) {\n\t\t\tconst owned = await scanAll((cursor) =>\n\t\t\t\tthis.#storage.scanConversations({ ownerTaskId: record.id }, SCAN_PAGE_SIZE, cursor, context),\n\t\t\t);\n\t\t\tconst conversations = owned.map((conversation) => conversation.id).sort((a, b) => a - b);\n\t\t\ttasks[String(record.id)] = nodeOf(record, conversations);\n\t\t}\n\t\treturn { tasks };\n\t}\n}\n\n/** Derive the mount's operations from one publication, apply them, and hand the revision to every observer. */\nfunction advance(mount: Mount, publication: CommitPublication, context: Context): void {\n\tconst ops: Op[] = [];\n\t// Nodes this publication set or deleted, over the mount's value.\n\tconst changed = new Map<string, TaskGraphNode | undefined>();\n\tconst node = (key: string): TaskGraphNode | undefined =>\n\t\tchanged.has(key) ? changed.get(key) : mount.value.tasks[key];\n\tfor (const change of publication.changes) {\n\t\tif (change.type !== \"task\") continue;\n\t\tconst record = change.value;\n\t\tconst key = String(record.id);\n\t\tconst previous = node(key);\n\t\tif (record.state.status === \"terminal\") {\n\t\t\tif (previous === undefined) continue;\n\t\t\tops.push([\"d\", [\"tasks\", key]]);\n\t\t\tchanged.set(key, undefined);\n\t\t\tcontinue;\n\t\t}\n\t\tconst next = nodeOf(record, previous?.conversations ?? []);\n\t\tif (previous !== undefined && JSON.stringify(next) === JSON.stringify(previous)) continue;\n\t\tops.push([\"s\", [\"tasks\", key], next as unknown as JsonValue]);\n\t\tchanged.set(key, next);\n\t}\n\t// After the tasks, so a conversation created with its owner task in one commit finds the owner's node. Change order\n\t// within a publication is unspecified, so each owner's list is sorted again.\n\tconst created = new Map<string, ConversationId[]>();\n\tfor (const change of publication.changes) {\n\t\tif (change.type !== \"conversation\" || change.value.owner === undefined) continue;\n\t\tconst key = String(change.value.owner.taskId);\n\t\tif (node(key) !== undefined) created.set(key, [...(created.get(key) ?? []), change.value.id]);\n\t}\n\tfor (const [key, ids] of created) {\n\t\tconst conversations = [...node(key)!.conversations, ...ids].sort((a, b) => a - b);\n\t\tops.push([\"s\", [\"tasks\", key, \"conversations\"], conversations]);\n\t}\n\tif (ops.length === 0) return;\n\tmount.value = applyImmutable(mount.value, ops);\n\tconst frameContext = withoutAbortSignal(context);\n\tfor (const observer of [...mount.observers]) observer.advance(mount.value, ops, frameContext);\n}\n\nfunction nodeOf(record: AnyTaskRecord, conversations: readonly ConversationId[]): TaskGraphNode {\n\treturn {\n\t\tid: record.id,\n\t\tkind: record.kind,\n\t\tconversationId: record.conversationId,\n\t\t...(record.owner === undefined ? {} : { owner: record.owner }),\n\t\tbackground: record.background,\n\t\tabortRequested: record.abortRequested,\n\t\tstate: stateOf(record),\n\t\tconversations,\n\t};\n}\n\nfunction stateOf(record: AnyTaskRecord): TaskGraphState {\n\tconst state = record.state;\n\tswitch (state.status) {\n\t\tcase \"pending\":\n\t\tcase \"running\":\n\t\t\treturn { status: state.status, phase: phaseOf(state.checkpoint) };\n\t\tcase \"waiting\":\n\t\t\treturn { status: \"waiting\", phase: phaseOf(state.checkpoint), on: [...state.on], policy: state.policy };\n\t\t// Terminal records never reach here: they leave the graph.\n\t\tcase \"completing\":\n\t\tcase \"terminal\":\n\t\t\treturn { status: \"completing\", outcome: state.outcome.status };\n\t}\n}\n\nfunction phaseOf(checkpoint: JsonValue): string {\n\treturn (checkpoint as { readonly phase: string }).phase;\n}\n"]}
@@ -0,0 +1,36 @@
1
+ import type { ToolCall } from "@earendil-works/pi-ai";
2
+ import type { ConversationId, EntryId, JsonObject, Task, Tx, TypedEntry } from "../types.ts";
3
+ import type { ToolControl, ToolDiagnostic, ToolExecutionResult, ToolHooks } from "./types.ts";
4
+ export type ToolTaskInput = {
5
+ assistant: EntryId;
6
+ callId: string;
7
+ };
8
+ export type ToolTaskCheckpoint = {
9
+ phase: "call";
10
+ }
11
+ /** Durable intent: the final arguments and the replay policy recorded before execution. */
12
+ | {
13
+ phase: "execute";
14
+ arguments: JsonObject;
15
+ replay: "safe" | "unsafe";
16
+ };
17
+ export type ToolTaskResult = {
18
+ entryId: EntryId;
19
+ control?: ToolControl;
20
+ };
21
+ /**
22
+ * Built-in tool task: resolves the called tool among its phase agent's tools, validates, runs `beforeTool`, records intent,
23
+ * executes, runs `afterTool`, and appends the result, all in one `call` handler so nothing separates resolution from
24
+ * settlement. `execute` is reached only by recovery and applies the replay rule.
25
+ */
26
+ export declare const ToolTask: Task<ToolTaskInput, ToolTaskCheckpoint, ToolTaskResult, ToolHooks>;
27
+ /** An error result the Harness writes itself: no content and one `error` diagnostic with `code`. */
28
+ export declare function harnessError(code: string, message: string): ToolExecutionResult;
29
+ /**
30
+ * Append a `pi.tool-result` entry. The content ends with the rendered diagnostics, so the stored message is exactly
31
+ * what the model sees; `data` keeps the structured list. A result's usage is added to `pi.usage` in the same commit.
32
+ */
33
+ export declare function appendToolResult(tx: Tx, conversationId: ConversationId, call: ToolCall, result: ToolExecutionResult, timestamp: number): Promise<TypedEntry<{
34
+ diagnostics: ToolDiagnostic[];
35
+ }>>;
36
+ //# sourceMappingURL=tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/harness/tool.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAA6B,QAAQ,EAAqB,MAAM,uBAAuB,CAAC;AAKpG,OAAO,KAAK,EACX,cAAc,EACd,OAAO,EACP,UAAU,EACV,IAAI,EAIJ,EAAE,EACF,UAAU,EACV,MAAM,aAAa,CAAC;AAIrB,OAAO,KAAK,EACX,WAAW,EACX,cAAc,EAEd,mBAAmB,EACnB,SAAS,EAET,MAAM,YAAY,CAAC;AAGpB,MAAM,MAAM,aAAa,GAAG;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE,MAAM,MAAM,kBAAkB,GAC3B;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE;AACnB,2FAA2F;GACzF;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAA;CAAE,CAAC;AAE1E,MAAM,MAAM,cAAc,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,WAAW,CAAA;CAAE,CAAC;AAKzE;;;;GAIG;AACH,eAAO,MAAM,QAAQ,oEAoEnB,CAAC;AAsSH,oGAAoG;AACpG,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,mBAAmB,CAE/E;AAmBD;;;GAGG;AACH,wBAAsB,gBAAgB,CACrC,EAAE,EAAE,EAAE,EACN,cAAc,EAAE,cAAc,EAC9B,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,mBAAmB,EAC3B,SAAS,EAAE,MAAM,GACf,OAAO,CAAC,UAAU,CAAC;IAAE,WAAW,EAAE,cAAc,EAAE,CAAA;CAAE,CAAC,CAAC,CAgBxD"}