@astralyn/pi 1.4.8 → 1.4.10

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 (243) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/dist/bundle/chunks/{chunk-I2COK45I.js → chunk-6GTUUUCJ.js} +128 -128
  3. package/dist/bundle/chunks/{chunk-PU2IWWXV.js → chunk-DLVLAQEG.js} +1 -1
  4. package/dist/bundle/chunks/{chunk-MG5XDTXV.js → chunk-LPF7HQ3S.js} +1 -1
  5. package/dist/bundle/chunks/{chunk-FODCTZXW.js → chunk-MF3T3ETJ.js} +4 -4
  6. package/dist/bundle/chunks/{chunk-RO2VH6UZ.js → chunk-R267VV5T.js} +1 -1
  7. package/dist/bundle/chunks/{chunk-RLNMABLM.js → chunk-RVKT7OUB.js} +1 -1
  8. package/dist/bundle/chunks/{chunk-5VIOGR76.js → chunk-UCH27AVQ.js} +1 -1
  9. package/dist/bundle/chunks/{cli-MEL7SGJD.js → cli-MBFCFGI2.js} +1 -1
  10. package/dist/bundle/chunks/{execute-4CWRNHPO.js → execute-FQKRO4XJ.js} +1 -1
  11. package/dist/bundle/chunks/{runtime-R3X67XMR.js → runtime-3RPOJS5T.js} +1 -1
  12. package/dist/bundle/chunks/{virtual-modules-BBLD7YLS.js → virtual-modules-6IJ6V2CG.js} +1 -1
  13. package/dist/bundle/cli.js +1 -1
  14. package/dist/bundle/index.js +1 -1
  15. package/dist/bundle/rpc-entry.js +1 -1
  16. package/dist/core/agent-session.d.ts +34 -0
  17. package/dist/core/agent-session.d.ts.map +1 -1
  18. package/dist/core/agent-session.js +99 -2
  19. package/dist/core/agent-session.js.map +1 -1
  20. package/dist/core/isolated-session.d.ts +7 -2
  21. package/dist/core/isolated-session.d.ts.map +1 -1
  22. package/dist/core/isolated-session.js +7 -3
  23. package/dist/core/isolated-session.js.map +1 -1
  24. package/dist/core/session-manager.d.ts +17 -1
  25. package/dist/core/session-manager.d.ts.map +1 -1
  26. package/dist/core/session-manager.js +29 -0
  27. package/dist/core/session-manager.js.map +1 -1
  28. package/dist/core/tasks/delivery.d.ts +42 -7
  29. package/dist/core/tasks/delivery.d.ts.map +1 -1
  30. package/dist/core/tasks/delivery.js +129 -15
  31. package/dist/core/tasks/delivery.js.map +1 -1
  32. package/dist/core/tasks/execution.d.ts +27 -14
  33. package/dist/core/tasks/execution.d.ts.map +1 -1
  34. package/dist/core/tasks/execution.js +90 -86
  35. package/dist/core/tasks/execution.js.map +1 -1
  36. package/dist/core/tasks/limits.d.ts +13 -1
  37. package/dist/core/tasks/limits.d.ts.map +1 -1
  38. package/dist/core/tasks/limits.js +14 -1
  39. package/dist/core/tasks/limits.js.map +1 -1
  40. package/dist/core/tasks/output.d.ts +9 -1
  41. package/dist/core/tasks/output.d.ts.map +1 -1
  42. package/dist/core/tasks/output.js +23 -10
  43. package/dist/core/tasks/output.js.map +1 -1
  44. package/dist/core/tasks/presentation.d.ts +1 -1
  45. package/dist/core/tasks/presentation.d.ts.map +1 -1
  46. package/dist/core/tasks/presentation.js +6 -4
  47. package/dist/core/tasks/presentation.js.map +1 -1
  48. package/dist/core/tasks/record.d.ts +41 -29
  49. package/dist/core/tasks/record.d.ts.map +1 -1
  50. package/dist/core/tasks/record.js +82 -37
  51. package/dist/core/tasks/record.js.map +1 -1
  52. package/dist/core/tasks/reminder.js +2 -2
  53. package/dist/core/tasks/reminder.js.map +1 -1
  54. package/dist/core/tasks/runtime.d.ts +17 -14
  55. package/dist/core/tasks/runtime.d.ts.map +1 -1
  56. package/dist/core/tasks/runtime.js +68 -116
  57. package/dist/core/tasks/runtime.js.map +1 -1
  58. package/dist/core/tasks/scheduler.d.ts +3 -1
  59. package/dist/core/tasks/scheduler.d.ts.map +1 -1
  60. package/dist/core/tasks/scheduler.js +16 -12
  61. package/dist/core/tasks/scheduler.js.map +1 -1
  62. package/dist/core/tasks/session.d.ts +24 -3
  63. package/dist/core/tasks/session.d.ts.map +1 -1
  64. package/dist/core/tasks/session.js +73 -9
  65. package/dist/core/tasks/session.js.map +1 -1
  66. package/dist/core/tasks/store.d.ts +17 -4
  67. package/dist/core/tasks/store.d.ts.map +1 -1
  68. package/dist/core/tasks/store.js +45 -48
  69. package/dist/core/tasks/store.js.map +1 -1
  70. package/dist/core/tasks/types.d.ts +72 -29
  71. package/dist/core/tasks/types.d.ts.map +1 -1
  72. package/dist/core/tasks/types.js +7 -0
  73. package/dist/core/tasks/types.js.map +1 -1
  74. package/dist/core/tasks/wait.d.ts +19 -0
  75. package/dist/core/tasks/wait.d.ts.map +1 -0
  76. package/dist/core/tasks/wait.js +45 -0
  77. package/dist/core/tasks/wait.js.map +1 -0
  78. package/dist/core/tools/shell-execution.d.ts.map +1 -1
  79. package/dist/core/tools/shell-execution.js +2 -1
  80. package/dist/core/tools/shell-execution.js.map +1 -1
  81. package/dist/core/tools/shell-tool.d.ts.map +1 -1
  82. package/dist/core/tools/shell-tool.js +20 -13
  83. package/dist/core/tools/shell-tool.js.map +1 -1
  84. package/dist/extensions/agent/activity-lines.d.ts +10 -0
  85. package/dist/extensions/agent/activity-lines.d.ts.map +1 -0
  86. package/dist/extensions/agent/activity-lines.js +76 -0
  87. package/dist/extensions/agent/activity-lines.js.map +1 -0
  88. package/dist/extensions/agent/activity.d.ts +25 -4
  89. package/dist/extensions/agent/activity.d.ts.map +1 -1
  90. package/dist/extensions/agent/activity.js +76 -21
  91. package/dist/extensions/agent/activity.js.map +1 -1
  92. package/dist/extensions/agent/artifacts.d.ts +15 -0
  93. package/dist/extensions/agent/artifacts.d.ts.map +1 -0
  94. package/dist/extensions/agent/artifacts.js +44 -0
  95. package/dist/extensions/agent/artifacts.js.map +1 -0
  96. package/dist/extensions/agent/progress.d.ts +30 -4
  97. package/dist/extensions/agent/progress.d.ts.map +1 -1
  98. package/dist/extensions/agent/progress.js +84 -11
  99. package/dist/extensions/agent/progress.js.map +1 -1
  100. package/dist/extensions/agent/render.d.ts.map +1 -1
  101. package/dist/extensions/agent/render.js +8 -24
  102. package/dist/extensions/agent/render.js.map +1 -1
  103. package/dist/extensions/agent/report.d.ts +11 -3
  104. package/dist/extensions/agent/report.d.ts.map +1 -1
  105. package/dist/extensions/agent/report.js +32 -7
  106. package/dist/extensions/agent/report.js.map +1 -1
  107. package/dist/extensions/agent/tool.d.ts.map +1 -1
  108. package/dist/extensions/agent/tool.js +20 -5
  109. package/dist/extensions/agent/tool.js.map +1 -1
  110. package/dist/extensions/agent/types.d.ts +2 -0
  111. package/dist/extensions/agent/types.d.ts.map +1 -1
  112. package/dist/extensions/agent/types.js.map +1 -1
  113. package/dist/extensions/agent/worker.d.ts +7 -0
  114. package/dist/extensions/agent/worker.d.ts.map +1 -1
  115. package/dist/extensions/agent/worker.js +9 -3
  116. package/dist/extensions/agent/worker.js.map +1 -1
  117. package/dist/extensions/index.d.ts.map +1 -1
  118. package/dist/extensions/index.js +2 -0
  119. package/dist/extensions/index.js.map +1 -1
  120. package/dist/extensions/search/index.d.ts.map +1 -1
  121. package/dist/extensions/search/index.js +6 -7
  122. package/dist/extensions/search/index.js.map +1 -1
  123. package/dist/extensions/shell-paths/index.d.ts +8 -0
  124. package/dist/extensions/shell-paths/index.d.ts.map +1 -0
  125. package/dist/extensions/shell-paths/index.js +74 -0
  126. package/dist/extensions/shell-paths/index.js.map +1 -0
  127. package/dist/extensions/tasks/tool/actions.d.ts.map +1 -1
  128. package/dist/extensions/tasks/tool/actions.js +15 -11
  129. package/dist/extensions/tasks/tool/actions.js.map +1 -1
  130. package/dist/extensions/tasks/tool/schema.d.ts +1 -1
  131. package/dist/extensions/tasks/tool/schema.d.ts.map +1 -1
  132. package/dist/extensions/tasks/tool/schema.js +5 -5
  133. package/dist/extensions/tasks/tool/schema.js.map +1 -1
  134. package/dist/extensions/tasks/tool/types.d.ts +2 -0
  135. package/dist/extensions/tasks/tool/types.d.ts.map +1 -1
  136. package/dist/extensions/tasks/tool/types.js.map +1 -1
  137. package/dist/extensions/tasks/tool.d.ts.map +1 -1
  138. package/dist/extensions/tasks/tool.js +3 -2
  139. package/dist/extensions/tasks/tool.js.map +1 -1
  140. package/dist/extensions/tasks/ui/completion-render.d.ts.map +1 -1
  141. package/dist/extensions/tasks/ui/completion-render.js +2 -2
  142. package/dist/extensions/tasks/ui/completion-render.js.map +1 -1
  143. package/dist/extensions/tasks/ui/footer.d.ts +37 -0
  144. package/dist/extensions/tasks/ui/footer.d.ts.map +1 -0
  145. package/dist/extensions/tasks/ui/footer.js +129 -0
  146. package/dist/extensions/tasks/ui/footer.js.map +1 -0
  147. package/dist/extensions/tasks/ui/frame.d.ts +36 -0
  148. package/dist/extensions/tasks/ui/frame.d.ts.map +1 -0
  149. package/dist/extensions/tasks/ui/frame.js +33 -0
  150. package/dist/extensions/tasks/ui/frame.js.map +1 -0
  151. package/dist/extensions/tasks/ui/help.d.ts +6 -0
  152. package/dist/extensions/tasks/ui/help.d.ts.map +1 -0
  153. package/dist/extensions/tasks/ui/help.js +53 -0
  154. package/dist/extensions/tasks/ui/help.js.map +1 -0
  155. package/dist/extensions/tasks/ui/inspector.d.ts +4 -3
  156. package/dist/extensions/tasks/ui/inspector.d.ts.map +1 -1
  157. package/dist/extensions/tasks/ui/inspector.js +25 -6
  158. package/dist/extensions/tasks/ui/inspector.js.map +1 -1
  159. package/dist/extensions/tasks/ui/layout.d.ts +15 -18
  160. package/dist/extensions/tasks/ui/layout.d.ts.map +1 -1
  161. package/dist/extensions/tasks/ui/layout.js +162 -255
  162. package/dist/extensions/tasks/ui/layout.js.map +1 -1
  163. package/dist/extensions/tasks/ui/list.d.ts +3 -1
  164. package/dist/extensions/tasks/ui/list.d.ts.map +1 -1
  165. package/dist/extensions/tasks/ui/list.js +19 -14
  166. package/dist/extensions/tasks/ui/list.js.map +1 -1
  167. package/dist/extensions/tasks/ui/manager.d.ts +17 -5
  168. package/dist/extensions/tasks/ui/manager.d.ts.map +1 -1
  169. package/dist/extensions/tasks/ui/manager.js +147 -90
  170. package/dist/extensions/tasks/ui/manager.js.map +1 -1
  171. package/dist/extensions/tasks/ui/model.d.ts +32 -5
  172. package/dist/extensions/tasks/ui/model.d.ts.map +1 -1
  173. package/dist/extensions/tasks/ui/model.js +7 -7
  174. package/dist/extensions/tasks/ui/model.js.map +1 -1
  175. package/dist/extensions/tasks/ui/panes.d.ts +40 -0
  176. package/dist/extensions/tasks/ui/panes.d.ts.map +1 -0
  177. package/dist/extensions/tasks/ui/panes.js +144 -0
  178. package/dist/extensions/tasks/ui/panes.js.map +1 -0
  179. package/dist/extensions/tasks/ui/render.d.ts.map +1 -1
  180. package/dist/extensions/tasks/ui/render.js +11 -7
  181. package/dist/extensions/tasks/ui/render.js.map +1 -1
  182. package/dist/extensions/tasks/ui/viewport.d.ts +12 -4
  183. package/dist/extensions/tasks/ui/viewport.d.ts.map +1 -1
  184. package/dist/extensions/tasks/ui/viewport.js +23 -7
  185. package/dist/extensions/tasks/ui/viewport.js.map +1 -1
  186. package/dist/extensions/tasks/ui/views.d.ts +12 -6
  187. package/dist/extensions/tasks/ui/views.d.ts.map +1 -1
  188. package/dist/extensions/tasks/ui/views.js +39 -32
  189. package/dist/extensions/tasks/ui/views.js.map +1 -1
  190. package/dist/modes/interactive/chat-viewport.d.ts +5 -2
  191. package/dist/modes/interactive/chat-viewport.d.ts.map +1 -1
  192. package/dist/modes/interactive/chat-viewport.js +72 -12
  193. package/dist/modes/interactive/chat-viewport.js.map +1 -1
  194. package/dist/modes/interactive/components/session-selector.d.ts +11 -1
  195. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  196. package/dist/modes/interactive/components/session-selector.js +43 -17
  197. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  198. package/dist/modes/interactive/components/sticky-user-message.d.ts +23 -0
  199. package/dist/modes/interactive/components/sticky-user-message.d.ts.map +1 -0
  200. package/dist/modes/interactive/components/sticky-user-message.js +58 -0
  201. package/dist/modes/interactive/components/sticky-user-message.js.map +1 -0
  202. package/dist/modes/interactive/components/user-message.d.ts +9 -0
  203. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  204. package/dist/modes/interactive/components/user-message.js +51 -10
  205. package/dist/modes/interactive/components/user-message.js.map +1 -1
  206. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  207. package/dist/modes/interactive/interactive-mode.js +4 -1
  208. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  209. package/dist/modes/interactive/tool-view/chat.d.ts +3 -2
  210. package/dist/modes/interactive/tool-view/chat.d.ts.map +1 -1
  211. package/dist/modes/interactive/tool-view/chat.js +3 -3
  212. package/dist/modes/interactive/tool-view/chat.js.map +1 -1
  213. package/dist/modes/interactive/transcript-layout.d.ts +23 -0
  214. package/dist/modes/interactive/transcript-layout.d.ts.map +1 -0
  215. package/dist/modes/interactive/transcript-layout.js +29 -0
  216. package/dist/modes/interactive/transcript-layout.js.map +1 -0
  217. package/dist/modes/print-mode.d.ts.map +1 -1
  218. package/dist/modes/print-mode.js +37 -2
  219. package/dist/modes/print-mode.js.map +1 -1
  220. package/dist/modes/rpc/rpc-client.d.ts +11 -0
  221. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  222. package/dist/modes/rpc/rpc-client.js +48 -0
  223. package/dist/modes/rpc/rpc-client.js.map +1 -1
  224. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  225. package/dist/modes/rpc/rpc-mode.js +1 -0
  226. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  227. package/dist/modes/rpc/rpc-types.d.ts +2 -0
  228. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  229. package/dist/modes/rpc/rpc-types.js.map +1 -1
  230. package/docs/bundled/README.md +1 -0
  231. package/docs/bundled/extensions/agent.md +39 -7
  232. package/docs/bundled/extensions/shell-paths.md +17 -0
  233. package/docs/bundled/tasks.md +25 -21
  234. package/docs/docs.json +4 -0
  235. package/docs/extensions.md +14 -10
  236. package/docs/json.md +3 -0
  237. package/docs/rpc.md +14 -0
  238. package/docs/sdk.md +11 -1
  239. package/docs/session-format.md +10 -4
  240. package/docs/sessions.md +1 -1
  241. package/docs/usage.md +3 -1
  242. package/npm-shrinkwrap.json +2 -2
  243. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"output.js","sourceRoot":"","sources":["../../../src/core/tasks/output.ts"],"names":[],"mappings":"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","sourcesContent":["import { open } from \"node:fs/promises\";\nimport type { AgentToolResult } from \"@earendil-works/pi-agent-core\";\nimport { finiteLimit } from \"../../utils/number.ts\";\nimport type { TaskFact, TaskInput, TaskReadOptions, TaskText } from \"./types.ts\";\n\nexport const TASK_RESULT_BYTES = 48 * 1024;\nexport const TASK_DETAILS_BYTES = 120 * 1024;\nexport const TASK_READ_BYTES = 8 * 1024;\nexport const TASK_INPUT_BYTES = 24 * 1024;\n/** Task title budget, independent of notification wording and rendering. */\nexport const TASK_TITLE_BYTES = 1024;\nexport const TASK_LABEL_BYTES = 256;\nexport const TASK_FACTS = 16;\nexport const TASK_FACT_BYTES = 1024;\nexport const TASK_ERROR_BYTES = 4096;\nexport const TASK_PATH_BYTES = 8192;\n\n/** A bounded, printable message for any thrown value. */\nexport function errorText(error: unknown, fallback = \"Task execution failed (unprintable error)\"): string {\n\ttry {\n\t\treturn boundText(error instanceof Error ? error.message : String(error), TASK_ERROR_BYTES);\n\t} catch {\n\t\treturn fallback;\n\t}\n}\n\nexport function boundReadBytes(bytes: number | undefined): number {\n\treturn finiteLimit(bytes, TASK_READ_BYTES, TASK_RESULT_BYTES);\n}\n\n/** Both ends are codepoint aligned, including a head read ending inside a character. */\nfunction alignedSlice(buffer: Buffer, start: number, end: number): Buffer {\n\twhile (start < end && (buffer[start]! & 0xc0) === 0x80) start++;\n\tif (end < buffer.length) {\n\t\twhile (end > start && (buffer[end]! & 0xc0) === 0x80) end--;\n\t}\n\t// A concurrently written file can itself end in an incomplete UTF-8 sequence.\n\tlet lead = end - 1;\n\twhile (lead >= start && (buffer[lead]! & 0xc0) === 0x80) lead--;\n\tif (lead >= start) {\n\t\tconst byte = buffer[lead]!;\n\t\tconst width = byte >= 0xf0 ? 4 : byte >= 0xe0 ? 3 : byte >= 0xc0 ? 2 : 1;\n\t\tif (end - lead < width) end = lead;\n\t}\n\treturn buffer.subarray(start, end);\n}\n\nexport function boundText(text: string, bytes = TASK_RESULT_BYTES): string {\n\t// Avoid allocating a buffer proportional to an unbounded source.\n\tconst limit = finiteLimit(bytes, TASK_RESULT_BYTES, TASK_RESULT_BYTES);\n\tconst prefix = text.slice(0, limit + 1);\n\tconst buffer = Buffer.from(prefix);\n\treturn alignedSlice(buffer, 0, Math.min(limit, buffer.length)).toString(\"utf8\");\n}\n\nexport function boundTaskText(text: string, bytes = TASK_RESULT_BYTES): TaskText {\n\tconst bounded = boundText(text, bytes);\n\treturn { text: bounded, truncated: bounded !== text };\n}\n\nexport function boundInput(input: TaskInput): TaskInput {\n\tconst text = boundTaskText(input.text, TASK_INPUT_BYTES);\n\treturn {\n\t\tlabel: boundText(input.label, TASK_LABEL_BYTES),\n\t\ttext: text.text,\n\t\ttruncated: input.truncated || text.truncated,\n\t\t...(input.language ? { language: boundText(input.language, 64) } : {}),\n\t};\n}\n\nexport function boundFacts(facts: readonly TaskFact[]): TaskFact[] {\n\treturn facts\n\t\t.slice(0, TASK_FACTS)\n\t\t.map(([label, value]): TaskFact => [boundText(label, TASK_LABEL_BYTES), boundText(value, TASK_FACT_BYTES)]);\n}\n\n/** The end of a bounded text, codepoint aligned: a command's outcome is at its end. */\nexport function boundTail(text: string, bytes: number): { text: string; truncated: boolean } {\n\tconst buffer = Buffer.from(text);\n\tif (buffer.length <= bytes) return { text, truncated: false };\n\treturn { text: alignedSlice(buffer, buffer.length - bytes, buffer.length).toString(\"utf8\"), truncated: true };\n}\n\n/** The bounded model-readable text of a result; images and private details never enter task state. */\nexport function resultText(result: AgentToolResult<unknown>): TaskText {\n\tlet remaining = TASK_RESULT_BYTES;\n\tconst parts: string[] = [];\n\tlet truncated = false;\n\tfor (const block of result.content) {\n\t\tif (remaining <= 0) {\n\t\t\ttruncated = true;\n\t\t\tbreak;\n\t\t}\n\t\tconst source = block.type === \"text\" ? block.text : \"[Image omitted from task output]\";\n\t\tconst text = boundText(source, remaining);\n\t\tif (block.type !== \"text\" || text !== source) truncated = true;\n\t\tparts.push(text);\n\t\tremaining -= Math.max(1, Buffer.byteLength(text) + 1);\n\t}\n\treturn { text: boundText(parts.join(\"\\n\")), truncated };\n}\n\nexport interface OutputSlice {\n\ttext: string;\n\ttotalBytes: number;\n\ttruncated: boolean;\n\tfromByte: number;\n}\n\n/**\n * The byte window a read covers in an output of `size` bytes. `floor` is the first byte the\n * caller has not seen yet; anything before it never counts as truncated.\n */\nfunction readWindow(size: number, options: TaskReadOptions): { start: number; length: number; floor: number } {\n\tconst bytes = boundReadBytes(options.bytes);\n\tconst since = finiteLimit(options.sinceBytes, 0, Number.MAX_SAFE_INTEGER);\n\tconst floor = since > size ? 0 : since;\n\tconst start =\n\t\toptions.sinceBytes !== undefined\n\t\t\t? Math.max(floor, size - bytes)\n\t\t\t: options.mode === \"head\"\n\t\t\t\t? 0\n\t\t\t\t: Math.max(0, size - bytes);\n\treturn { start, length: Math.min(bytes, size - start), floor };\n}\n\nfunction outputSlice(size: number, floor: number, slice: Buffer, fromByte: number): OutputSlice {\n\treturn { text: slice.toString(\"utf8\"), totalBytes: size, truncated: slice.length < size - floor, fromByte };\n}\n\n/** Positioned, bounded reads only. The executor owns the path and its cleanup. */\nexport async function readOutputSlice(path: string, options: TaskReadOptions = {}): Promise<OutputSlice> {\n\tconst file = await open(path, \"r\");\n\ttry {\n\t\tconst { size } = await file.stat();\n\t\tconst { start, length, floor } = readWindow(size, options);\n\t\t// One extra byte lets alignment distinguish a complete last codepoint.\n\t\tconst buffer = Buffer.alloc(Math.min(length + 1, size - start));\n\t\tconst { bytesRead } = await file.read(buffer, 0, buffer.length, start);\n\t\tconst slice = alignedSlice(buffer.subarray(0, bytesRead), 0, Math.min(length, bytesRead));\n\t\treturn outputSlice(size, floor, slice, start + slice.byteOffset - buffer.byteOffset);\n\t} finally {\n\t\tawait file.close();\n\t}\n}\n\nexport function sliceText(text: string, options: TaskReadOptions = {}): OutputSlice {\n\tconst buffer = Buffer.from(text);\n\tconst { start, length, floor } = readWindow(buffer.length, options);\n\tconst slice = alignedSlice(buffer, start, start + length);\n\treturn outputSlice(buffer.length, floor, slice, slice.byteOffset - buffer.byteOffset);\n}\n"]}
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../../src/core/tasks/output.ts"],"names":[],"mappings":"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","sourcesContent":["import { open } from \"node:fs/promises\";\nimport type { AgentToolResult } from \"@earendil-works/pi-agent-core\";\nimport { finiteLimit } from \"../../utils/number.ts\";\nimport type { TaskFact, TaskInput, TaskRead, TaskReadOptions, TaskText } from \"./types.ts\";\n\nexport const TASK_RESULT_BYTES = 48 * 1024;\nexport const TASK_DETAILS_BYTES = 120 * 1024;\nexport const TASK_READ_BYTES = 8 * 1024;\nexport const TASK_INPUT_BYTES = 24 * 1024;\n/** Task title budget, independent of notification wording and rendering. */\nexport const TASK_TITLE_BYTES = 1024;\nexport const TASK_LABEL_BYTES = 256;\nexport const TASK_FACTS = 16;\nexport const TASK_FACT_BYTES = 1024;\nexport const TASK_ERROR_BYTES = 4096;\nexport const TASK_PATH_BYTES = 8192;\n\n/** A bounded, printable message for any thrown value. */\nexport function errorText(error: unknown, fallback = \"Task execution failed (unprintable error)\"): string {\n\ttry {\n\t\treturn boundText(error instanceof Error ? error.message : String(error), TASK_ERROR_BYTES);\n\t} catch {\n\t\treturn fallback;\n\t}\n}\n\nexport function boundReadBytes(bytes: number | undefined): number {\n\treturn finiteLimit(bytes, TASK_READ_BYTES, TASK_RESULT_BYTES);\n}\n\n/** Both ends are codepoint aligned, including a head read ending inside a character. */\nfunction alignedSlice(buffer: Buffer, start: number, end: number): Buffer {\n\twhile (start < end && (buffer[start]! & 0xc0) === 0x80) start++;\n\tif (end < buffer.length) {\n\t\twhile (end > start && (buffer[end]! & 0xc0) === 0x80) end--;\n\t}\n\t// A concurrently written file can itself end in an incomplete UTF-8 sequence.\n\tlet lead = end - 1;\n\twhile (lead >= start && (buffer[lead]! & 0xc0) === 0x80) lead--;\n\tif (lead >= start) {\n\t\tconst byte = buffer[lead]!;\n\t\tconst width = byte >= 0xf0 ? 4 : byte >= 0xe0 ? 3 : byte >= 0xc0 ? 2 : 1;\n\t\tif (end - lead < width) end = lead;\n\t}\n\treturn buffer.subarray(start, end);\n}\n\nexport function boundText(text: string, bytes = TASK_RESULT_BYTES): string {\n\t// Avoid allocating a buffer proportional to an unbounded source.\n\tconst limit = finiteLimit(bytes, TASK_RESULT_BYTES, TASK_RESULT_BYTES);\n\tconst prefix = text.slice(0, limit + 1);\n\tconst buffer = Buffer.from(prefix);\n\treturn alignedSlice(buffer, 0, Math.min(limit, buffer.length)).toString(\"utf8\");\n}\n\nexport function boundTaskText(text: string, bytes = TASK_RESULT_BYTES): TaskText {\n\tconst bounded = boundText(text, bytes);\n\treturn { text: bounded, truncated: bounded !== text };\n}\n\nexport function boundInput(input: TaskInput): TaskInput {\n\tconst text = boundTaskText(input.text, TASK_INPUT_BYTES);\n\treturn {\n\t\tlabel: boundText(input.label, TASK_LABEL_BYTES),\n\t\ttext: text.text,\n\t\ttruncated: input.truncated || text.truncated,\n\t\t...(input.language ? { language: boundText(input.language, 64) } : {}),\n\t};\n}\n\nexport function boundFacts(facts: readonly TaskFact[]): TaskFact[] {\n\treturn facts\n\t\t.slice(0, TASK_FACTS)\n\t\t.map(([label, value]): TaskFact => [boundText(label, TASK_LABEL_BYTES), boundText(value, TASK_FACT_BYTES)]);\n}\n\n/** The end of a bounded text, codepoint aligned: a command's outcome is at its end. */\nexport function boundTail(text: string, bytes: number): { text: string; truncated: boolean } {\n\tconst buffer = Buffer.from(text);\n\tif (buffer.length <= bytes) return { text, truncated: false };\n\treturn { text: alignedSlice(buffer, buffer.length - bytes, buffer.length).toString(\"utf8\"), truncated: true };\n}\n\n/** The bounded model-readable text of a result; images and private details never enter task state. */\nexport function resultText(result: AgentToolResult<unknown>): TaskText {\n\tlet remaining = TASK_RESULT_BYTES;\n\tconst parts: string[] = [];\n\tlet truncated = false;\n\tfor (const block of result.content) {\n\t\tif (remaining <= 0) {\n\t\t\ttruncated = true;\n\t\t\tbreak;\n\t\t}\n\t\tconst source = block.type === \"text\" ? block.text : \"[Image omitted from task output]\";\n\t\tconst text = boundText(source, remaining);\n\t\tif (block.type !== \"text\" || text !== source) truncated = true;\n\t\tparts.push(text);\n\t\tremaining -= Math.max(1, Buffer.byteLength(text) + 1);\n\t}\n\treturn { text: boundText(parts.join(\"\\n\")), truncated };\n}\n\nexport interface OutputSlice {\n\ttext: string;\n\ttotalBytes: number;\n\ttruncated: boolean;\n\tfromByte: number;\n\t/** Raw source-byte end, independent of UTF-8 decoding or replacement characters. */\n\tendByte: number;\n}\n\n/** Raw source-byte range; decoding invalid UTF-8 must never move the continuation offset. */\nexport function taskReadRange(slice: Pick<TaskRead, \"text\" | \"fromByte\" | \"endByte\">): { from: number; to: number } {\n\tconst from = slice.fromByte ?? 0;\n\treturn { from, to: slice.endByte ?? from + Buffer.byteLength(slice.text) };\n}\n\nexport function taskReadBytes(slice: Pick<TaskRead, \"text\" | \"fromByte\" | \"endByte\">): number {\n\tconst { from, to } = taskReadRange(slice);\n\treturn to - from;\n}\n\n/**\n * The byte window a read covers in an output of `size` bytes. `floor` is the first byte the\n * caller has not seen yet. A head read continues forward from it; a tail read keeps the newest\n * unread window. Anything before the floor never counts as truncated.\n */\nfunction readWindow(size: number, options: TaskReadOptions): { start: number; length: number; floor: number } {\n\tconst bytes = boundReadBytes(options.bytes);\n\tconst since = finiteLimit(options.sinceBytes, 0, Number.MAX_SAFE_INTEGER);\n\tconst floor = since > size ? 0 : since;\n\tconst start =\n\t\toptions.mode === \"head\" ? (options.sinceBytes !== undefined ? floor : 0) : Math.max(floor, size - bytes);\n\treturn { start, length: Math.min(bytes, size - start), floor };\n}\n\nfunction outputSlice(size: number, slice: Buffer, fromByte: number, earlierTruncated: boolean): OutputSlice {\n\tconst endByte = fromByte + slice.byteLength;\n\treturn {\n\t\ttext: slice.toString(\"utf8\"),\n\t\ttotalBytes: size,\n\t\ttruncated: earlierTruncated || endByte < size,\n\t\tfromByte,\n\t\tendByte,\n\t};\n}\n\n/** Positioned, bounded reads only. The executor owns the path and its cleanup. */\nexport async function readOutputSlice(path: string, options: TaskReadOptions = {}): Promise<OutputSlice> {\n\tconst file = await open(path, \"r\");\n\ttry {\n\t\tconst { size } = await file.stat();\n\t\tconst { start, length, floor } = readWindow(size, options);\n\t\t// One extra byte lets alignment distinguish a complete last codepoint.\n\t\tconst buffer = Buffer.alloc(Math.min(length + 1, size - start));\n\t\tconst { bytesRead } = await file.read(buffer, 0, buffer.length, start);\n\t\tconst slice = alignedSlice(buffer.subarray(0, bytesRead), 0, Math.min(length, bytesRead));\n\t\treturn outputSlice(\n\t\t\tsize,\n\t\t\tslice,\n\t\t\tstart + slice.byteOffset - buffer.byteOffset,\n\t\t\toptions.mode !== \"head\" && start > floor,\n\t\t);\n\t} finally {\n\t\tawait file.close();\n\t}\n}\n\nexport function sliceText(text: string, options: TaskReadOptions = {}): OutputSlice {\n\tconst buffer = Buffer.from(text);\n\tconst { start, length, floor } = readWindow(buffer.length, options);\n\tconst slice = alignedSlice(buffer, start, start + length);\n\treturn outputSlice(\n\t\tbuffer.length,\n\t\tslice,\n\t\tslice.byteOffset - buffer.byteOffset,\n\t\toptions.mode !== \"head\" && start > floor,\n\t);\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import type { CustomMessage } from "../messages.ts";
2
2
  import { TASK_SNAPSHOT_VERSION } from "./codec.ts";
3
- import type { TaskSnapshot } from "./types.ts";
3
+ import { type TaskSnapshot } from "./types.ts";
4
4
  export interface TaskCompletionDetails {
5
5
  version: typeof TASK_SNAPSHOT_VERSION;
6
6
  task: TaskSnapshot;
@@ -1 +1 @@
1
- {"version":3,"file":"presentation.d.ts","sourceRoot":"","sources":["../../../src/core/tasks/presentation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEnD,OAAO,KAAK,EAAE,YAAY,EAAwB,MAAM,YAAY,CAAC;AASrE,MAAM,WAAW,qBAAqB;IACrC,OAAO,EAAE,OAAO,qBAAqB,CAAC;IACtC,IAAI,EAAE,YAAY,CAAC;CACnB;AAyCD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAkB1D;AAOD,kHAAkH;AAClH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,YAAY,GAAG,qBAAqB,CAgB/E;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,YAAY,GAAG,aAAa,CAAC,qBAAqB,CAAC,CAS9F"}
1
+ {"version":3,"file":"presentation.d.ts","sourceRoot":"","sources":["../../../src/core/tasks/presentation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAGnD,OAAO,EAAmB,KAAK,YAAY,EAAkC,MAAM,YAAY,CAAC;AAShG,MAAM,WAAW,qBAAqB;IACrC,OAAO,EAAE,OAAO,qBAAqB,CAAC;IACtC,IAAI,EAAE,YAAY,CAAC;CACnB;AAyCD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAkB1D;AAOD,kHAAkH;AAClH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,YAAY,GAAG,qBAAqB,CAgB/E;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,YAAY,GAAG,aAAa,CAAC,qBAAqB,CAAC,CAS9F"}
@@ -1,6 +1,8 @@
1
1
  import { truncateHead, truncateTail } from "../tools/truncate.js";
2
2
  import { TASK_SNAPSHOT_VERSION } from "./codec.js";
3
+ import { defaultReadMode } from "./limits.js";
3
4
  import { boundTail, boundText, TASK_DETAILS_BYTES, TASK_RESULT_BYTES } from "./output.js";
5
+ import { TASKS_TOOL_NAME } from "./types.js";
4
6
  /** Automatic model turns get only a small readable log tail; reports arrive whole. */
5
7
  const MODEL_LOG_BYTES = 8 * 1024;
6
8
  const MODEL_LINES = 2000;
@@ -9,8 +11,8 @@ const REPLAY_OUTPUT_BYTES = [40 * 1024, 16 * 1024, 4 * 1024, 0];
9
11
  const REPLAY_INPUT_BYTES = 8 * 1024;
10
12
  const singleLine = (value) => value.replace(/\s+/gu, " ").trim();
11
13
  const bytes = (value) => Buffer.byteLength(value);
12
- const OMISSION = "\n[Saved output truncated; use tasks read for retained task details.]";
13
- const EARLIER_OMISSION = "[Earlier output truncated; use tasks read for retained task details.]\n";
14
+ const OMISSION = `\n[Saved output truncated; use ${TASKS_TOOL_NAME} read for retained task details.]`;
15
+ const EARLIER_OMISSION = `[Earlier output truncated; use ${TASKS_TOOL_NAME} read for retained task details.]\n`;
14
16
  /** A report keeps its beginning, where its summary is. */
15
17
  function modelHead(value, maxBytes, lines) {
16
18
  const result = truncateHead(value.text, {
@@ -58,7 +60,7 @@ export function projectForModel(task) {
58
60
  const budget = TASK_RESULT_BYTES - bytes(prefix) - bytes(suffix);
59
61
  const lines = MODEL_LINES - prefix.split("\n").length - (guidance ? 3 : 0);
60
62
  const output = task.result?.text ? task.result : { text: "No text result.", truncated: false };
61
- const body = task.output === "report"
63
+ const body = defaultReadMode(task) === "head"
62
64
  ? modelHead(output, budget, lines)
63
65
  : modelTail(output, Math.min(MODEL_LOG_BYTES, budget), lines);
64
66
  return prefix + body + suffix;
@@ -70,7 +72,7 @@ function clipped(value, maxBytes, keep) {
70
72
  /** A self-contained replay snapshot within the details budget; human-only display stays in the session record. */
71
73
  export function taskCompletionDetails(task) {
72
74
  const { display: _display, result, input, ...rest } = task;
73
- const keep = task.output === "report" ? "head" : "tail";
75
+ const keep = defaultReadMode(task);
74
76
  const replayInput = input && { ...input, ...clipped(input, REPLAY_INPUT_BYTES, "head") };
75
77
  for (const outputBytes of REPLAY_OUTPUT_BYTES) {
76
78
  const details = {
@@ -1 +1 @@
1
- {"version":3,"file":"presentation.js","sourceRoot":"","sources":["../../../src/core/tasks/presentation.ts"],"names":[],"mappings":"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","sourcesContent":["import type { CustomMessage } from \"../messages.ts\";\nimport { truncateHead, truncateTail } from \"../tools/truncate.ts\";\nimport { TASK_SNAPSHOT_VERSION } from \"./codec.ts\";\nimport { boundTail, boundText, TASK_DETAILS_BYTES, TASK_RESULT_BYTES } from \"./output.ts\";\nimport type { TaskSnapshot, TaskStatus, TaskText } from \"./types.ts\";\n\n/** Automatic model turns get only a small readable log tail; reports arrive whole. */\nconst MODEL_LOG_BYTES = 8 * 1024;\nconst MODEL_LINES = 2000;\n/** Replay copies of the output and input inside completion details. */\nconst REPLAY_OUTPUT_BYTES = [40 * 1024, 16 * 1024, 4 * 1024, 0] as const;\nconst REPLAY_INPUT_BYTES = 8 * 1024;\n\nexport interface TaskCompletionDetails {\n\tversion: typeof TASK_SNAPSHOT_VERSION;\n\ttask: TaskSnapshot;\n}\n\nconst singleLine = (value: string) => value.replace(/\\s+/gu, \" \").trim();\nconst bytes = (value: string) => Buffer.byteLength(value);\n\nconst OMISSION = \"\\n[Saved output truncated; use tasks read for retained task details.]\";\nconst EARLIER_OMISSION = \"[Earlier output truncated; use tasks read for retained task details.]\\n\";\n\n/** A report keeps its beginning, where its summary is. */\nfunction modelHead(value: TaskText, maxBytes: number, lines: number): string {\n\tconst result = truncateHead(value.text, {\n\t\tmaxBytes: Math.max(0, maxBytes - bytes(OMISSION)),\n\t\tmaxLines: Math.max(1, lines - 1),\n\t});\n\treturn result.content + (value.truncated || result.truncated ? OMISSION : \"\");\n}\n\n/** A log keeps its end, where the outcome is. */\nfunction modelTail(value: TaskText, maxBytes: number, lines: number): string {\n\tconst result = truncateTail(value.text, {\n\t\tmaxBytes: Math.max(0, maxBytes - bytes(EARLIER_OMISSION)),\n\t\tmaxLines: Math.max(1, lines - 1),\n\t});\n\treturn (value.truncated || result.truncated ? EARLIER_OMISSION : \"\") + result.content;\n}\n\n/** One bounded action hint per terminal outcome; completed work needs none. */\nfunction nextStepLine(status: TaskStatus): string {\n\tswitch (status) {\n\t\tcase \"cancelled\":\n\t\t\treturn \"Next step: the task was cancelled — do not restart it unless the user asks.\";\n\t\tcase \"timeout\":\n\t\t\treturn \"Next step: the task hit its timeout; inspect the partial output above, then rerun with a longer timeout or in smaller pieces if still needed.\";\n\t\tcase \"failed\":\n\t\tcase \"partial\":\n\t\t\treturn \"Next step: diagnose from the output above before retrying; rerun only what is still needed.\";\n\t\tdefault:\n\t\t\treturn \"\";\n\t}\n}\n\n/**\n * The model-facing text of a settled background task. A report reaches the model as its\n * foreground result would have; a log contributes only its tail to the automatic turn.\n */\nexport function projectForModel(task: TaskSnapshot): string {\n\tconst header = [\n\t\tboundText(`Background ${task.kind} ${task.id}: ${task.status} — ${singleLine(task.title)}`, 2048),\n\t\ttask.error ? `Error: ${singleLine(task.error)}` : \"\",\n\t\t...(task.facts ?? []).map(([label, value]) => `${label}: ${singleLine(value)}`),\n\t\ttask.outputPath ? `Output: ${singleLine(task.outputPath)}` : \"\",\n\t].filter(Boolean);\n\tconst prefix = `${header.join(\"\\n\")}\\n\\n`;\n\tconst guidance = nextStepLine(task.status);\n\tconst suffix = guidance ? `\\n\\n${guidance}` : \"\";\n\tconst budget = TASK_RESULT_BYTES - bytes(prefix) - bytes(suffix);\n\tconst lines = MODEL_LINES - prefix.split(\"\\n\").length - (guidance ? 3 : 0);\n\tconst output = task.result?.text ? task.result : { text: \"No text result.\", truncated: false };\n\tconst body =\n\t\ttask.output === \"report\"\n\t\t\t? modelHead(output, budget, lines)\n\t\t\t: modelTail(output, Math.min(MODEL_LOG_BYTES, budget), lines);\n\treturn prefix + body + suffix;\n}\n\nfunction clipped(value: TaskText, maxBytes: number, keep: \"head\" | \"tail\"): TaskText {\n\tconst text = keep === \"head\" ? boundText(value.text, maxBytes) : boundTail(value.text, maxBytes).text;\n\treturn { text, truncated: value.truncated || text !== value.text };\n}\n\n/** A self-contained replay snapshot within the details budget; human-only display stays in the session record. */\nexport function taskCompletionDetails(task: TaskSnapshot): TaskCompletionDetails {\n\tconst { display: _display, result, input, ...rest } = task;\n\tconst keep = task.output === \"report\" ? \"head\" : \"tail\";\n\tconst replayInput = input && { ...input, ...clipped(input, REPLAY_INPUT_BYTES, \"head\") };\n\tfor (const outputBytes of REPLAY_OUTPUT_BYTES) {\n\t\tconst details: TaskCompletionDetails = {\n\t\t\tversion: TASK_SNAPSHOT_VERSION,\n\t\t\ttask: {\n\t\t\t\t...rest,\n\t\t\t\t...(replayInput ? { input: replayInput } : {}),\n\t\t\t\t...(result && outputBytes > 0 ? { result: clipped(result, outputBytes, keep) } : {}),\n\t\t\t},\n\t\t};\n\t\tif (bytes(JSON.stringify(details)) <= TASK_DETAILS_BYTES) return details;\n\t}\n\treturn { version: TASK_SNAPSHOT_VERSION, task: rest };\n}\n\nexport function taskCompletionMessage(task: TaskSnapshot): CustomMessage<TaskCompletionDetails> {\n\treturn {\n\t\trole: \"custom\",\n\t\tcustomType: \"task-completion\",\n\t\tdisplay: true,\n\t\tcontent: projectForModel(task),\n\t\tdetails: taskCompletionDetails(task),\n\t\ttimestamp: Date.now(),\n\t};\n}\n"]}
1
+ {"version":3,"file":"presentation.js","sourceRoot":"","sources":["../../../src/core/tasks/presentation.ts"],"names":[],"mappings":"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","sourcesContent":["import type { CustomMessage } from \"../messages.ts\";\nimport { truncateHead, truncateTail } from \"../tools/truncate.ts\";\nimport { TASK_SNAPSHOT_VERSION } from \"./codec.ts\";\nimport { defaultReadMode } from \"./limits.ts\";\nimport { boundTail, boundText, TASK_DETAILS_BYTES, TASK_RESULT_BYTES } from \"./output.ts\";\nimport { TASKS_TOOL_NAME, type TaskSnapshot, type TaskStatus, type TaskText } from \"./types.ts\";\n\n/** Automatic model turns get only a small readable log tail; reports arrive whole. */\nconst MODEL_LOG_BYTES = 8 * 1024;\nconst MODEL_LINES = 2000;\n/** Replay copies of the output and input inside completion details. */\nconst REPLAY_OUTPUT_BYTES = [40 * 1024, 16 * 1024, 4 * 1024, 0] as const;\nconst REPLAY_INPUT_BYTES = 8 * 1024;\n\nexport interface TaskCompletionDetails {\n\tversion: typeof TASK_SNAPSHOT_VERSION;\n\ttask: TaskSnapshot;\n}\n\nconst singleLine = (value: string) => value.replace(/\\s+/gu, \" \").trim();\nconst bytes = (value: string) => Buffer.byteLength(value);\n\nconst OMISSION = `\\n[Saved output truncated; use ${TASKS_TOOL_NAME} read for retained task details.]`;\nconst EARLIER_OMISSION = `[Earlier output truncated; use ${TASKS_TOOL_NAME} read for retained task details.]\\n`;\n\n/** A report keeps its beginning, where its summary is. */\nfunction modelHead(value: TaskText, maxBytes: number, lines: number): string {\n\tconst result = truncateHead(value.text, {\n\t\tmaxBytes: Math.max(0, maxBytes - bytes(OMISSION)),\n\t\tmaxLines: Math.max(1, lines - 1),\n\t});\n\treturn result.content + (value.truncated || result.truncated ? OMISSION : \"\");\n}\n\n/** A log keeps its end, where the outcome is. */\nfunction modelTail(value: TaskText, maxBytes: number, lines: number): string {\n\tconst result = truncateTail(value.text, {\n\t\tmaxBytes: Math.max(0, maxBytes - bytes(EARLIER_OMISSION)),\n\t\tmaxLines: Math.max(1, lines - 1),\n\t});\n\treturn (value.truncated || result.truncated ? EARLIER_OMISSION : \"\") + result.content;\n}\n\n/** One bounded action hint per terminal outcome; completed work needs none. */\nfunction nextStepLine(status: TaskStatus): string {\n\tswitch (status) {\n\t\tcase \"cancelled\":\n\t\t\treturn \"Next step: the task was cancelled — do not restart it unless the user asks.\";\n\t\tcase \"timeout\":\n\t\t\treturn \"Next step: the task hit its timeout; inspect the partial output above, then rerun with a longer timeout or in smaller pieces if still needed.\";\n\t\tcase \"failed\":\n\t\tcase \"partial\":\n\t\t\treturn \"Next step: diagnose from the output above before retrying; rerun only what is still needed.\";\n\t\tdefault:\n\t\t\treturn \"\";\n\t}\n}\n\n/**\n * The model-facing text of a settled background task. A report reaches the model as its\n * foreground result would have; a log contributes only its tail to the automatic turn.\n */\nexport function projectForModel(task: TaskSnapshot): string {\n\tconst header = [\n\t\tboundText(`Background ${task.kind} ${task.id}: ${task.status} — ${singleLine(task.title)}`, 2048),\n\t\ttask.error ? `Error: ${singleLine(task.error)}` : \"\",\n\t\t...(task.facts ?? []).map(([label, value]) => `${label}: ${singleLine(value)}`),\n\t\ttask.outputPath ? `Output: ${singleLine(task.outputPath)}` : \"\",\n\t].filter(Boolean);\n\tconst prefix = `${header.join(\"\\n\")}\\n\\n`;\n\tconst guidance = nextStepLine(task.status);\n\tconst suffix = guidance ? `\\n\\n${guidance}` : \"\";\n\tconst budget = TASK_RESULT_BYTES - bytes(prefix) - bytes(suffix);\n\tconst lines = MODEL_LINES - prefix.split(\"\\n\").length - (guidance ? 3 : 0);\n\tconst output = task.result?.text ? task.result : { text: \"No text result.\", truncated: false };\n\tconst body =\n\t\tdefaultReadMode(task) === \"head\"\n\t\t\t? modelHead(output, budget, lines)\n\t\t\t: modelTail(output, Math.min(MODEL_LOG_BYTES, budget), lines);\n\treturn prefix + body + suffix;\n}\n\nfunction clipped(value: TaskText, maxBytes: number, keep: \"head\" | \"tail\"): TaskText {\n\tconst text = keep === \"head\" ? boundText(value.text, maxBytes) : boundTail(value.text, maxBytes).text;\n\treturn { text, truncated: value.truncated || text !== value.text };\n}\n\n/** A self-contained replay snapshot within the details budget; human-only display stays in the session record. */\nexport function taskCompletionDetails(task: TaskSnapshot): TaskCompletionDetails {\n\tconst { display: _display, result, input, ...rest } = task;\n\tconst keep = defaultReadMode(task);\n\tconst replayInput = input && { ...input, ...clipped(input, REPLAY_INPUT_BYTES, \"head\") };\n\tfor (const outputBytes of REPLAY_OUTPUT_BYTES) {\n\t\tconst details: TaskCompletionDetails = {\n\t\t\tversion: TASK_SNAPSHOT_VERSION,\n\t\t\ttask: {\n\t\t\t\t...rest,\n\t\t\t\t...(replayInput ? { input: replayInput } : {}),\n\t\t\t\t...(result && outputBytes > 0 ? { result: clipped(result, outputBytes, keep) } : {}),\n\t\t\t},\n\t\t};\n\t\tif (bytes(JSON.stringify(details)) <= TASK_DETAILS_BYTES) return details;\n\t}\n\treturn { version: TASK_SNAPSHOT_VERSION, task: rest };\n}\n\nexport function taskCompletionMessage(task: TaskSnapshot): CustomMessage<TaskCompletionDetails> {\n\treturn {\n\t\trole: \"custom\",\n\t\tcustomType: \"task-completion\",\n\t\tdisplay: true,\n\t\tcontent: projectForModel(task),\n\t\tdetails: taskCompletionDetails(task),\n\t\ttimestamp: Date.now(),\n\t};\n}\n"]}
@@ -1,45 +1,57 @@
1
- import type { TaskSnapshot } from "./types.ts";
1
+ import type { Theme } from "../../modes/interactive/theme/theme.ts";
2
+ import { type TaskPresenter, type TaskSnapshot } from "./types.ts";
3
+ export declare const EXPIRED_OUTPUT = "Output has expired: the managed log was released; showing the stored result.";
4
+ type OutputCleanup = () => void | Promise<void>;
2
5
  /**
3
- * none: running, or answered inline by its tool call; pending: a settled handoff
4
- * awaiting automatic delivery; claimed: handed to the host; delivered: acknowledged.
5
- */
6
- export type TaskDeliveryState = "none" | "pending" | "claimed" | "delivered";
7
- /**
8
- * The runtime's state for one task: its working snapshot, retention counters and delivery
9
- * state. The working snapshot changes only through `update()`, which also drops the frozen
10
- * copy that readers share, so a mutation can never leave a stale snapshot behind.
6
+ * The runtime's state for one task: its working snapshot, whether it is on the selected branch,
7
+ * the pins that keep it retained, and the managed output it owns. Whether a completion reached
8
+ * the model is a session concern held outside the runtime as a pin. Every lifecycle fact changes
9
+ * through a named method here; the working snapshot changes only through `update()`, which also
10
+ * drops the frozen copy that readers share, so a mutation can never leave a stale snapshot behind.
11
11
  */
12
12
  export declare class TaskRecord {
13
13
  /** Read-only view of the working copy; change it with update(). */
14
14
  readonly task: Readonly<TaskSnapshot>;
15
- settled: boolean;
16
- /** Whether the launch anchor is on the selected branch. */
17
- visible: boolean;
18
- pins: number;
19
- deliveryHolds: number;
20
- cleanup?: () => void | Promise<void>;
21
- readError?: string;
22
- readonly waiters: Set<() => void>;
15
+ /** Settles once the task is terminal and its final snapshot is stored. Never rejects. */
16
+ readonly settlement: Promise<void>;
23
17
  private readonly working;
24
18
  private frozen?;
25
- private state;
19
+ private resolveSettlement;
20
+ private onBranch;
21
+ private pins;
22
+ private cleanup?;
23
+ private expiredReason?;
24
+ private presenter?;
26
25
  constructor(task: TaskSnapshot);
27
26
  /** A terminal record rebuilt from persisted history: nothing is left to run or deliver. */
28
27
  static restored(task: TaskSnapshot, readError: string | undefined): TaskRecord;
28
+ /** Terminal: nothing is left to run. Derived from the status so it can never disagree with it. */
29
+ get settled(): boolean;
30
+ /** The executor's live Output renderer; held in memory for a running task only. */
31
+ setPresenter(presenter: TaskPresenter | undefined): void;
32
+ /** Live Output while running; `undefined` once settled, without a presenter, or if the presenter throws. */
33
+ present(width: number, theme: Theme): string[] | undefined;
34
+ /** Called once, after the terminal snapshot is final. */
35
+ settle(): void;
29
36
  update(mutate: (task: TaskSnapshot) => void): void;
30
37
  /** Readers share one frozen copy, so polling and status rendering never clone unchanged output. */
31
38
  snapshot(): TaskSnapshot;
32
- get delivery(): TaskDeliveryState;
33
- /** A settled handoff the host has not yet been told about. */
34
- queueDelivery(): void;
35
- /** The result was answered inline, or the host acknowledged its delivery. */
36
- acknowledge(): void;
37
- /** Only explicit result-delivery holds and active waits delay an automatic completion. */
38
- get deliverable(): boolean;
39
- claim(): boolean;
40
- /** Return a claimed record to pending after a failed delivery. */
41
- unclaim(): boolean;
42
- /** Delivered, unpinned and unwatched: bounded history that retention may evict. */
39
+ /** Whether the launch anchor is on the selected branch. */
40
+ get visible(): boolean;
41
+ setVisible(visible: boolean): void;
42
+ /** Keep the record, and its output, retained until the returned release runs. Idempotent. */
43
+ pin(): () => void;
44
+ /** Settled and unpinned: bounded history that retention may evict. */
43
45
  get inHistory(): boolean;
46
+ /** Why the output could not be read from a log: it expired, or was never kept. */
47
+ get readError(): string | undefined;
48
+ /** Register the one output file this task owns; `cleanup` deletes it when retention lets go. */
49
+ attachOutput(path: string, cleanup?: OutputCleanup): void;
50
+ /**
51
+ * Release the managed output once nothing retains it. Returns the owner's cleanup to run, if
52
+ * any; the snapshot keeps its final bounded text, so an expired file is never needed again.
53
+ */
54
+ expireOutput(): OutputCleanup | undefined;
44
55
  }
56
+ export {};
45
57
  //# sourceMappingURL=record.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../../src/core/tasks/record.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC;AAU7E;;;;GAIG;AACH,qBAAa,UAAU;IACtB,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC;IACtC,OAAO,UAAS;IAChB,2DAA2D;IAC3D,OAAO,UAAQ;IACf,IAAI,SAAK;IACT,aAAa,SAAK;IAClB,OAAO,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,OAAO,YAAiB,IAAI,EAAI;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,MAAM,CAAC,CAAe;IAC9B,OAAO,CAAC,KAAK,CAA6B;gBAE9B,IAAI,EAAE,YAAY;IAK9B,2FAA2F;IAC3F,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU;IAQ9E,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,GAAG,IAAI;IAQlD,mGAAmG;IACnG,QAAQ,IAAI,YAAY;IAKxB,IAAI,QAAQ,IAAI,iBAAiB,CAEhC;IAED,8DAA8D;IAC9D,aAAa,IAAI,IAAI;IAIrB,6EAA6E;IAC7E,WAAW,IAAI,IAAI;IAInB,0FAA0F;IAC1F,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED,KAAK,IAAI,OAAO;IAMhB,kEAAkE;IAClE,OAAO,IAAI,OAAO;IAMlB,mFAAmF;IACnF,IAAI,SAAS,IAAI,OAAO,CAEvB;CACD"}
1
+ {"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../../src/core/tasks/record.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wCAAwC,CAAC;AACpE,OAAO,EAAkB,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAEnF,eAAO,MAAM,cAAc,iFAAiF,CAAC;AAU7G,KAAK,aAAa,GAAG,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEhD;;;;;;GAMG;AACH,qBAAa,UAAU;IACtB,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC;IACtC,yFAAyF;IACzF,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,MAAM,CAAC,CAAe;IAC9B,OAAO,CAAC,iBAAiB,CAAc;IACvC,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,OAAO,CAAC,CAAgB;IAChC,OAAO,CAAC,aAAa,CAAC,CAAS;IAC/B,OAAO,CAAC,SAAS,CAAC,CAAgB;gBAEtB,IAAI,EAAE,YAAY;IAQ9B,2FAA2F;IAC3F,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU;IAO9E,kGAAkG;IAClG,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,mFAAmF;IACnF,YAAY,CAAC,SAAS,EAAE,aAAa,GAAG,SAAS,GAAG,IAAI;IAIxD,4GAA4G;IAC5G,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,MAAM,EAAE,GAAG,SAAS;IAW1D,yDAAyD;IACzD,MAAM,IAAI,IAAI;IAKd,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,GAAG,IAAI;IAQlD,mGAAmG;IACnG,QAAQ,IAAI,YAAY;IAKxB,2DAA2D;IAC3D,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAIlC,6FAA6F;IAC7F,GAAG,IAAI,MAAM,IAAI;IAUjB,sEAAsE;IACtE,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,kFAAkF;IAClF,IAAI,SAAS,IAAI,MAAM,GAAG,SAAS,CAElC;IAED,gGAAgG;IAChG,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,IAAI;IAQzD;;;OAGG;IACH,YAAY,IAAI,aAAa,GAAG,SAAS;CAUzC"}
@@ -1,3 +1,5 @@
1
+ import { isTaskTerminal } from "./types.js";
2
+ export const EXPIRED_OUTPUT = "Output has expired: the managed log was released; showing the stored result.";
1
3
  function freeze(value) {
2
4
  if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
3
5
  for (const child of Object.values(value))
@@ -7,30 +9,55 @@ function freeze(value) {
7
9
  return value;
8
10
  }
9
11
  /**
10
- * The runtime's state for one task: its working snapshot, retention counters and delivery
11
- * state. The working snapshot changes only through `update()`, which also drops the frozen
12
- * copy that readers share, so a mutation can never leave a stale snapshot behind.
12
+ * The runtime's state for one task: its working snapshot, whether it is on the selected branch,
13
+ * the pins that keep it retained, and the managed output it owns. Whether a completion reached
14
+ * the model is a session concern held outside the runtime as a pin. Every lifecycle fact changes
15
+ * through a named method here; the working snapshot changes only through `update()`, which also
16
+ * drops the frozen copy that readers share, so a mutation can never leave a stale snapshot behind.
13
17
  */
14
18
  export class TaskRecord {
15
19
  constructor(task) {
16
- this.settled = false;
17
- /** Whether the launch anchor is on the selected branch. */
18
- this.visible = true;
20
+ this.onBranch = true;
19
21
  this.pins = 0;
20
- this.deliveryHolds = 0;
21
- this.waiters = new Set();
22
- this.state = "none";
23
22
  this.working = task;
24
23
  this.task = task;
24
+ this.settlement = new Promise((resolve) => {
25
+ this.resolveSettlement = resolve;
26
+ });
25
27
  }
26
28
  /** A terminal record rebuilt from persisted history: nothing is left to run or deliver. */
27
29
  static restored(task, readError) {
28
30
  const record = new TaskRecord(task);
29
- record.settled = true;
30
- record.state = "delivered";
31
- record.readError = readError;
31
+ record.expiredReason = readError;
32
+ record.settle();
32
33
  return record;
33
34
  }
35
+ /** Terminal: nothing is left to run. Derived from the status so it can never disagree with it. */
36
+ get settled() {
37
+ return isTaskTerminal(this.working.status);
38
+ }
39
+ /** The executor's live Output renderer; held in memory for a running task only. */
40
+ setPresenter(presenter) {
41
+ this.presenter = presenter;
42
+ }
43
+ /** Live Output while running; `undefined` once settled, without a presenter, or if the presenter throws. */
44
+ present(width, theme) {
45
+ if (this.settled || !this.presenter)
46
+ return undefined;
47
+ try {
48
+ const lines = this.presenter(width, theme);
49
+ return Array.isArray(lines) ? lines : undefined;
50
+ }
51
+ catch {
52
+ // An executor bug must not break the panel; it falls back to the default view.
53
+ return undefined;
54
+ }
55
+ }
56
+ /** Called once, after the terminal snapshot is final. */
57
+ settle() {
58
+ this.presenter = undefined;
59
+ this.resolveSettlement();
60
+ }
34
61
  update(mutate) {
35
62
  try {
36
63
  mutate(this.working);
@@ -44,37 +71,55 @@ export class TaskRecord {
44
71
  this.frozen ??= freeze(structuredClone(this.working));
45
72
  return this.frozen;
46
73
  }
47
- get delivery() {
48
- return this.state;
74
+ /** Whether the launch anchor is on the selected branch. */
75
+ get visible() {
76
+ return this.onBranch;
49
77
  }
50
- /** A settled handoff the host has not yet been told about. */
51
- queueDelivery() {
52
- this.state = "pending";
78
+ setVisible(visible) {
79
+ this.onBranch = visible;
53
80
  }
54
- /** The result was answered inline, or the host acknowledged its delivery. */
55
- acknowledge() {
56
- this.state = "delivered";
81
+ /** Keep the record, and its output, retained until the returned release runs. Idempotent. */
82
+ pin() {
83
+ this.pins++;
84
+ let released = false;
85
+ return () => {
86
+ if (released)
87
+ return;
88
+ released = true;
89
+ this.pins--;
90
+ };
57
91
  }
58
- /** Only explicit result-delivery holds and active waits delay an automatic completion. */
59
- get deliverable() {
60
- return this.visible && this.state === "pending" && this.waiters.size === 0 && this.deliveryHolds === 0;
92
+ /** Settled and unpinned: bounded history that retention may evict. */
93
+ get inHistory() {
94
+ return this.settled && this.pins === 0;
61
95
  }
62
- claim() {
63
- if (!this.deliverable)
64
- return false;
65
- this.state = "claimed";
66
- return true;
96
+ /** Why the output could not be read from a log: it expired, or was never kept. */
97
+ get readError() {
98
+ return this.expiredReason;
67
99
  }
68
- /** Return a claimed record to pending after a failed delivery. */
69
- unclaim() {
70
- if (this.state !== "claimed")
71
- return false;
72
- this.state = "pending";
73
- return true;
100
+ /** Register the one output file this task owns; `cleanup` deletes it when retention lets go. */
101
+ attachOutput(path, cleanup) {
102
+ if (this.cleanup)
103
+ throw new Error("Managed output is already registered");
104
+ this.cleanup = cleanup;
105
+ this.update((task) => {
106
+ task.outputPath = path;
107
+ });
74
108
  }
75
- /** Delivered, unpinned and unwatched: bounded history that retention may evict. */
76
- get inHistory() {
77
- return this.settled && this.state === "delivered" && !this.pins && !this.waiters.size;
109
+ /**
110
+ * Release the managed output once nothing retains it. Returns the owner's cleanup to run, if
111
+ * any; the snapshot keeps its final bounded text, so an expired file is never needed again.
112
+ */
113
+ expireOutput() {
114
+ if (!this.settled || this.pins > 0 || !this.cleanup)
115
+ return undefined;
116
+ const cleanup = this.cleanup;
117
+ this.cleanup = undefined;
118
+ this.update((task) => {
119
+ task.outputPath = undefined;
120
+ });
121
+ this.expiredReason = EXPIRED_OUTPUT;
122
+ return cleanup;
78
123
  }
79
124
  }
80
125
  //# sourceMappingURL=record.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"record.js","sourceRoot":"","sources":["../../../src/core/tasks/record.ts"],"names":[],"mappings":"AAQA,SAAS,MAAM,CAAI,KAAQ;IAC1B,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5E,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC;YAAE,MAAM,CAAC,KAAK,CAAC,CAAC;QACxD,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,OAAO,UAAU;IAetB,YAAY,IAAkB;QAZ9B,YAAO,GAAG,KAAK,CAAC;QAChB,2DAA2D;QAC3D,YAAO,GAAG,IAAI,CAAC;QACf,SAAI,GAAG,CAAC,CAAC;QACT,kBAAa,GAAG,CAAC,CAAC;QAGT,YAAO,GAAG,IAAI,GAAG,EAAc,CAAC;QAGjC,UAAK,GAAsB,MAAM,CAAC;QAGzC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IAClB,CAAC;IAED,2FAA2F;IAC3F,MAAM,CAAC,QAAQ,CAAC,IAAkB,EAAE,SAA6B;QAChE,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;QACtB,MAAM,CAAC,KAAK,GAAG,WAAW,CAAC;QAC3B,MAAM,CAAC,SAAS,GAAG,SAAS,CAAC;QAC7B,OAAO,MAAM,CAAC;IACf,CAAC;IAED,MAAM,CAAC,MAAoC;QAC1C,IAAI,CAAC;YACJ,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACtB,CAAC;gBAAS,CAAC;YACV,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;QACzB,CAAC;IACF,CAAC;IAED,mGAAmG;IACnG,QAAQ;QACP,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QACtD,OAAO,IAAI,CAAC,MAAM,CAAC;IACpB,CAAC;IAED,IAAI,QAAQ;QACX,OAAO,IAAI,CAAC,KAAK,CAAC;IACnB,CAAC;IAED,8DAA8D;IAC9D,aAAa;QACZ,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;IACxB,CAAC;IAED,6EAA6E;IAC7E,WAAW;QACV,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC;IAC1B,CAAC;IAED,0FAA0F;IAC1F,IAAI,WAAW;QACd,OAAO,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,aAAa,KAAK,CAAC,CAAC;IACxG,CAAC;IAED,KAAK;QACJ,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,OAAO,KAAK,CAAC;QACpC,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;QACvB,OAAO,IAAI,CAAC;IACb,CAAC;IAED,kEAAkE;IAClE,OAAO;QACN,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;QAC3C,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;QACvB,OAAO,IAAI,CAAC;IACb,CAAC;IAED,mFAAmF;IACnF,IAAI,SAAS;QACZ,OAAO,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,KAAK,WAAW,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IACvF,CAAC;CACD","sourcesContent":["import type { TaskSnapshot } from \"./types.ts\";\n\n/**\n * none: running, or answered inline by its tool call; pending: a settled handoff\n * awaiting automatic delivery; claimed: handed to the host; delivered: acknowledged.\n */\nexport type TaskDeliveryState = \"none\" | \"pending\" | \"claimed\" | \"delivered\";\n\nfunction freeze<T>(value: T): T {\n\tif (value !== null && typeof value === \"object\" && !Object.isFrozen(value)) {\n\t\tfor (const child of Object.values(value)) freeze(child);\n\t\tObject.freeze(value);\n\t}\n\treturn value;\n}\n\n/**\n * The runtime's state for one task: its working snapshot, retention counters and delivery\n * state. The working snapshot changes only through `update()`, which also drops the frozen\n * copy that readers share, so a mutation can never leave a stale snapshot behind.\n */\nexport class TaskRecord {\n\t/** Read-only view of the working copy; change it with update(). */\n\treadonly task: Readonly<TaskSnapshot>;\n\tsettled = false;\n\t/** Whether the launch anchor is on the selected branch. */\n\tvisible = true;\n\tpins = 0;\n\tdeliveryHolds = 0;\n\tcleanup?: () => void | Promise<void>;\n\treadError?: string;\n\treadonly waiters = new Set<() => void>();\n\tprivate readonly working: TaskSnapshot;\n\tprivate frozen?: TaskSnapshot;\n\tprivate state: TaskDeliveryState = \"none\";\n\n\tconstructor(task: TaskSnapshot) {\n\t\tthis.working = task;\n\t\tthis.task = task;\n\t}\n\n\t/** A terminal record rebuilt from persisted history: nothing is left to run or deliver. */\n\tstatic restored(task: TaskSnapshot, readError: string | undefined): TaskRecord {\n\t\tconst record = new TaskRecord(task);\n\t\trecord.settled = true;\n\t\trecord.state = \"delivered\";\n\t\trecord.readError = readError;\n\t\treturn record;\n\t}\n\n\tupdate(mutate: (task: TaskSnapshot) => void): void {\n\t\ttry {\n\t\t\tmutate(this.working);\n\t\t} finally {\n\t\t\tthis.frozen = undefined;\n\t\t}\n\t}\n\n\t/** Readers share one frozen copy, so polling and status rendering never clone unchanged output. */\n\tsnapshot(): TaskSnapshot {\n\t\tthis.frozen ??= freeze(structuredClone(this.working));\n\t\treturn this.frozen;\n\t}\n\n\tget delivery(): TaskDeliveryState {\n\t\treturn this.state;\n\t}\n\n\t/** A settled handoff the host has not yet been told about. */\n\tqueueDelivery(): void {\n\t\tthis.state = \"pending\";\n\t}\n\n\t/** The result was answered inline, or the host acknowledged its delivery. */\n\tacknowledge(): void {\n\t\tthis.state = \"delivered\";\n\t}\n\n\t/** Only explicit result-delivery holds and active waits delay an automatic completion. */\n\tget deliverable(): boolean {\n\t\treturn this.visible && this.state === \"pending\" && this.waiters.size === 0 && this.deliveryHolds === 0;\n\t}\n\n\tclaim(): boolean {\n\t\tif (!this.deliverable) return false;\n\t\tthis.state = \"claimed\";\n\t\treturn true;\n\t}\n\n\t/** Return a claimed record to pending after a failed delivery. */\n\tunclaim(): boolean {\n\t\tif (this.state !== \"claimed\") return false;\n\t\tthis.state = \"pending\";\n\t\treturn true;\n\t}\n\n\t/** Delivered, unpinned and unwatched: bounded history that retention may evict. */\n\tget inHistory(): boolean {\n\t\treturn this.settled && this.state === \"delivered\" && !this.pins && !this.waiters.size;\n\t}\n}\n"]}
1
+ {"version":3,"file":"record.js","sourceRoot":"","sources":["../../../src/core/tasks/record.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { isTaskTerminal, type TaskPresenter, type TaskSnapshot } from \"./types.ts\";\n\nexport const EXPIRED_OUTPUT = \"Output has expired: the managed log was released; showing the stored result.\";\n\nfunction freeze<T>(value: T): T {\n\tif (value !== null && typeof value === \"object\" && !Object.isFrozen(value)) {\n\t\tfor (const child of Object.values(value)) freeze(child);\n\t\tObject.freeze(value);\n\t}\n\treturn value;\n}\n\ntype OutputCleanup = () => void | Promise<void>;\n\n/**\n * The runtime's state for one task: its working snapshot, whether it is on the selected branch,\n * the pins that keep it retained, and the managed output it owns. Whether a completion reached\n * the model is a session concern held outside the runtime as a pin. Every lifecycle fact changes\n * through a named method here; the working snapshot changes only through `update()`, which also\n * drops the frozen copy that readers share, so a mutation can never leave a stale snapshot behind.\n */\nexport class TaskRecord {\n\t/** Read-only view of the working copy; change it with update(). */\n\treadonly task: Readonly<TaskSnapshot>;\n\t/** Settles once the task is terminal and its final snapshot is stored. Never rejects. */\n\treadonly settlement: Promise<void>;\n\tprivate readonly working: TaskSnapshot;\n\tprivate frozen?: TaskSnapshot;\n\tprivate resolveSettlement!: () => void;\n\tprivate onBranch = true;\n\tprivate pins = 0;\n\tprivate cleanup?: OutputCleanup;\n\tprivate expiredReason?: string;\n\tprivate presenter?: TaskPresenter;\n\n\tconstructor(task: TaskSnapshot) {\n\t\tthis.working = task;\n\t\tthis.task = task;\n\t\tthis.settlement = new Promise<void>((resolve) => {\n\t\t\tthis.resolveSettlement = resolve;\n\t\t});\n\t}\n\n\t/** A terminal record rebuilt from persisted history: nothing is left to run or deliver. */\n\tstatic restored(task: TaskSnapshot, readError: string | undefined): TaskRecord {\n\t\tconst record = new TaskRecord(task);\n\t\trecord.expiredReason = readError;\n\t\trecord.settle();\n\t\treturn record;\n\t}\n\n\t/** Terminal: nothing is left to run. Derived from the status so it can never disagree with it. */\n\tget settled(): boolean {\n\t\treturn isTaskTerminal(this.working.status);\n\t}\n\n\t/** The executor's live Output renderer; held in memory for a running task only. */\n\tsetPresenter(presenter: TaskPresenter | undefined): void {\n\t\tthis.presenter = presenter;\n\t}\n\n\t/** Live Output while running; `undefined` once settled, without a presenter, or if the presenter throws. */\n\tpresent(width: number, theme: Theme): string[] | undefined {\n\t\tif (this.settled || !this.presenter) return undefined;\n\t\ttry {\n\t\t\tconst lines = this.presenter(width, theme);\n\t\t\treturn Array.isArray(lines) ? lines : undefined;\n\t\t} catch {\n\t\t\t// An executor bug must not break the panel; it falls back to the default view.\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\t/** Called once, after the terminal snapshot is final. */\n\tsettle(): void {\n\t\tthis.presenter = undefined;\n\t\tthis.resolveSettlement();\n\t}\n\n\tupdate(mutate: (task: TaskSnapshot) => void): void {\n\t\ttry {\n\t\t\tmutate(this.working);\n\t\t} finally {\n\t\t\tthis.frozen = undefined;\n\t\t}\n\t}\n\n\t/** Readers share one frozen copy, so polling and status rendering never clone unchanged output. */\n\tsnapshot(): TaskSnapshot {\n\t\tthis.frozen ??= freeze(structuredClone(this.working));\n\t\treturn this.frozen;\n\t}\n\n\t/** Whether the launch anchor is on the selected branch. */\n\tget visible(): boolean {\n\t\treturn this.onBranch;\n\t}\n\n\tsetVisible(visible: boolean): void {\n\t\tthis.onBranch = visible;\n\t}\n\n\t/** Keep the record, and its output, retained until the returned release runs. Idempotent. */\n\tpin(): () => void {\n\t\tthis.pins++;\n\t\tlet released = false;\n\t\treturn () => {\n\t\t\tif (released) return;\n\t\t\treleased = true;\n\t\t\tthis.pins--;\n\t\t};\n\t}\n\n\t/** Settled and unpinned: bounded history that retention may evict. */\n\tget inHistory(): boolean {\n\t\treturn this.settled && this.pins === 0;\n\t}\n\n\t/** Why the output could not be read from a log: it expired, or was never kept. */\n\tget readError(): string | undefined {\n\t\treturn this.expiredReason;\n\t}\n\n\t/** Register the one output file this task owns; `cleanup` deletes it when retention lets go. */\n\tattachOutput(path: string, cleanup?: OutputCleanup): void {\n\t\tif (this.cleanup) throw new Error(\"Managed output is already registered\");\n\t\tthis.cleanup = cleanup;\n\t\tthis.update((task) => {\n\t\t\ttask.outputPath = path;\n\t\t});\n\t}\n\n\t/**\n\t * Release the managed output once nothing retains it. Returns the owner's cleanup to run, if\n\t * any; the snapshot keeps its final bounded text, so an expired file is never needed again.\n\t */\n\texpireOutput(): OutputCleanup | undefined {\n\t\tif (!this.settled || this.pins > 0 || !this.cleanup) return undefined;\n\t\tconst cleanup = this.cleanup;\n\t\tthis.cleanup = undefined;\n\t\tthis.update((task) => {\n\t\t\ttask.outputPath = undefined;\n\t\t});\n\t\tthis.expiredReason = EXPIRED_OUTPUT;\n\t\treturn cleanup;\n\t}\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { boundText } from "./output.js";
2
- import { isTaskTerminal } from "./types.js";
2
+ import { isTaskTerminal, TASKS_TOOL_NAME } from "./types.js";
3
3
  function taskLine(task) {
4
4
  const title = boundText(task.title.replace(/\s+/gu, " ").trim(), 240);
5
5
  return boundText(`${task.id} ${task.kind} ${task.status} ${title}`, 1024);
@@ -32,7 +32,7 @@ export class TaskContextReminder {
32
32
  type: "text",
33
33
  text: [
34
34
  "Context was compacted. These background tasks are still active; do not start duplicates.",
35
- "Use tasks list/read/wait/kill to inspect or control them. Completion arrives automatically.",
35
+ `Use ${TASKS_TOOL_NAME} list/read/kill to inspect or stop them. Each completion wakes you automatically; do not wait for it.`,
36
36
  ...tasks.map(taskLine),
37
37
  ].join("\n"),
38
38
  },
@@ -1 +1 @@
1
- {"version":3,"file":"reminder.js","sourceRoot":"","sources":["../../../src/core/tasks/reminder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EAAE,cAAc,EAAqB,MAAM,YAAY,CAAC;AAE/D,SAAS,QAAQ,CAAC,IAAkB;IACnC,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC;IACtE,OAAO,SAAS,CAAC,GAAG,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,IAAI,KAAK,EAAE,EAAE,IAAI,CAAC,CAAC;AAC3E,CAAC;AAED;;;GAGG;AACH,MAAM,OAAO,mBAAmB;IAAhC;QACS,YAAO,GAAG,KAAK,CAAC;QAChB,cAAS,GAAG,KAAK,CAAC;IAwC3B,CAAC;IAtCA,SAAS;QACR,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IACxB,CAAC;IAED,OAAO,CAAC,OAAoB,EAAE,QAAwB;QACrD,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,QAAQ,CAAC;QACnC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QAC1G,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,IAAI,CAAC,KAAK,EAAE,CAAC;YACb,OAAO,QAAQ,CAAC;QACjB,CAAC;QACD,MAAM,QAAQ,GAAiB;YAC9B,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE;gBACR;oBACC,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE;wBACL,0FAA0F;wBAC1F,6FAA6F;wBAC7F,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC;qBACtB,CAAC,IAAI,CAAC,IAAI,CAAC;iBACZ;aACD;YACD,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACrB,CAAC;QACF,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,OAAO,CAAC,GAAG,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAChC,CAAC;IAED,kBAAkB;QACjB,IAAI,IAAI,CAAC,SAAS;YAAE,IAAI,CAAC,KAAK,EAAE,CAAC;IAClC,CAAC;IAED,KAAK;QACJ,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IACxB,CAAC;CACD","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport { boundText } from \"./output.ts\";\nimport type { TaskRuntime } from \"./runtime.ts\";\nimport { isTaskTerminal, type TaskSnapshot } from \"./types.ts\";\n\nfunction taskLine(task: TaskSnapshot): string {\n\tconst title = boundText(task.title.replace(/\\s+/gu, \" \").trim(), 240);\n\treturn boundText(`${task.id} ${task.kind} ${task.status} ${title}`, 1024);\n}\n\n/**\n * A one-shot, request-local reminder after compaction. It is never persisted and\n * creates no turn. Failed requests keep it eligible; an assistant response consumes it.\n */\nexport class TaskContextReminder {\n\tprivate pending = false;\n\tprivate projected = false;\n\n\tcompacted(): void {\n\t\tthis.pending = true;\n\t\tthis.projected = false;\n\t}\n\n\tproject(service: TaskRuntime, messages: AgentMessage[]): AgentMessage[] {\n\t\tif (!this.pending) return messages;\n\t\tconst tasks = service.list().filter((task) => task.mode === \"background\" && !isTaskTerminal(task.status));\n\t\tif (tasks.length === 0) {\n\t\t\tthis.reset();\n\t\t\treturn messages;\n\t\t}\n\t\tconst reminder: AgentMessage = {\n\t\t\trole: \"user\",\n\t\t\tcontent: [\n\t\t\t\t{\n\t\t\t\t\ttype: \"text\",\n\t\t\t\t\ttext: [\n\t\t\t\t\t\t\"Context was compacted. These background tasks are still active; do not start duplicates.\",\n\t\t\t\t\t\t\"Use tasks list/read/wait/kill to inspect or control them. Completion arrives automatically.\",\n\t\t\t\t\t\t...tasks.map(taskLine),\n\t\t\t\t\t].join(\"\\n\"),\n\t\t\t\t},\n\t\t\t],\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\t\tthis.projected = true;\n\t\treturn [...messages, reminder];\n\t}\n\n\tassistantCompleted(): void {\n\t\tif (this.projected) this.reset();\n\t}\n\n\treset(): void {\n\t\tthis.pending = false;\n\t\tthis.projected = false;\n\t}\n}\n"]}
1
+ {"version":3,"file":"reminder.js","sourceRoot":"","sources":["../../../src/core/tasks/reminder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EAAE,cAAc,EAAE,eAAe,EAAqB,MAAM,YAAY,CAAC;AAEhF,SAAS,QAAQ,CAAC,IAAkB;IACnC,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC;IACtE,OAAO,SAAS,CAAC,GAAG,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,IAAI,KAAK,EAAE,EAAE,IAAI,CAAC,CAAC;AAC3E,CAAC;AAED;;;GAGG;AACH,MAAM,OAAO,mBAAmB;IAAhC;QACS,YAAO,GAAG,KAAK,CAAC;QAChB,cAAS,GAAG,KAAK,CAAC;IAwC3B,CAAC;IAtCA,SAAS;QACR,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IACxB,CAAC;IAED,OAAO,CAAC,OAAoB,EAAE,QAAwB;QACrD,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,QAAQ,CAAC;QACnC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QAC1G,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,IAAI,CAAC,KAAK,EAAE,CAAC;YACb,OAAO,QAAQ,CAAC;QACjB,CAAC;QACD,MAAM,QAAQ,GAAiB;YAC9B,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE;gBACR;oBACC,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE;wBACL,0FAA0F;wBAC1F,OAAO,eAAe,uGAAuG;wBAC7H,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC;qBACtB,CAAC,IAAI,CAAC,IAAI,CAAC;iBACZ;aACD;YACD,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACrB,CAAC;QACF,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,OAAO,CAAC,GAAG,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAChC,CAAC;IAED,kBAAkB;QACjB,IAAI,IAAI,CAAC,SAAS;YAAE,IAAI,CAAC,KAAK,EAAE,CAAC;IAClC,CAAC;IAED,KAAK;QACJ,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IACxB,CAAC;CACD","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport { boundText } from \"./output.ts\";\nimport type { TaskRuntime } from \"./runtime.ts\";\nimport { isTaskTerminal, TASKS_TOOL_NAME, type TaskSnapshot } from \"./types.ts\";\n\nfunction taskLine(task: TaskSnapshot): string {\n\tconst title = boundText(task.title.replace(/\\s+/gu, \" \").trim(), 240);\n\treturn boundText(`${task.id} ${task.kind} ${task.status} ${title}`, 1024);\n}\n\n/**\n * A one-shot, request-local reminder after compaction. It is never persisted and\n * creates no turn. Failed requests keep it eligible; an assistant response consumes it.\n */\nexport class TaskContextReminder {\n\tprivate pending = false;\n\tprivate projected = false;\n\n\tcompacted(): void {\n\t\tthis.pending = true;\n\t\tthis.projected = false;\n\t}\n\n\tproject(service: TaskRuntime, messages: AgentMessage[]): AgentMessage[] {\n\t\tif (!this.pending) return messages;\n\t\tconst tasks = service.list().filter((task) => task.mode === \"background\" && !isTaskTerminal(task.status));\n\t\tif (tasks.length === 0) {\n\t\t\tthis.reset();\n\t\t\treturn messages;\n\t\t}\n\t\tconst reminder: AgentMessage = {\n\t\t\trole: \"user\",\n\t\t\tcontent: [\n\t\t\t\t{\n\t\t\t\t\ttype: \"text\",\n\t\t\t\t\ttext: [\n\t\t\t\t\t\t\"Context was compacted. These background tasks are still active; do not start duplicates.\",\n\t\t\t\t\t\t`Use ${TASKS_TOOL_NAME} list/read/kill to inspect or stop them. Each completion wakes you automatically; do not wait for it.`,\n\t\t\t\t\t\t...tasks.map(taskLine),\n\t\t\t\t\t].join(\"\\n\"),\n\t\t\t\t},\n\t\t\t],\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\t\tthis.projected = true;\n\t\treturn [...messages, reminder];\n\t}\n\n\tassistantCompleted(): void {\n\t\tif (this.projected) this.reset();\n\t}\n\n\treset(): void {\n\t\tthis.pending = false;\n\t\tthis.projected = false;\n\t}\n}\n"]}
@@ -1,7 +1,8 @@
1
1
  import type { AgentToolResult } from "@earendil-works/pi-agent-core";
2
- import { type TaskDeliveryLedger, type TaskExecution, type TaskRead, type TaskReadOptions, type TaskRuntimeOptions, type TaskSnapshot, type TasksContext, type TaskToolOutcome, type TaskWaitAnyOptions, type TaskWaitAnyResult, type TaskWaitOptions, type TaskWaitResult } from "./types.ts";
2
+ import type { Theme } from "../../modes/interactive/theme/theme.ts";
3
+ import { type TaskExecution, type TaskRead, type TaskReadOptions, type TaskRuntimeOptions, type TaskSnapshot, type TasksContext, type TaskToolOutcome, type TaskWaitAnyOptions, type TaskWaitAnyResult, type TaskWaitOptions, type TaskWaitResult } from "./types.ts";
3
4
  /** Session-local supervision. Executors own their processes, items and output files. */
4
- export declare class TaskRuntime implements TasksContext, TaskDeliveryLedger {
5
+ export declare class TaskRuntime implements TasksContext {
5
6
  private readonly store;
6
7
  private readonly executions;
7
8
  private readonly scheduler;
@@ -11,6 +12,7 @@ export declare class TaskRuntime implements TasksContext, TaskDeliveryLedger {
11
12
  private readonly maxHistory;
12
13
  private readonly maxRetained;
13
14
  private readonly options;
15
+ private readonly closing;
14
16
  private configuredEnabled;
15
17
  private _closed;
16
18
  constructor(options?: TaskRuntimeOptions);
@@ -26,8 +28,16 @@ export declare class TaskRuntime implements TasksContext, TaskDeliveryLedger {
26
28
  restoreHistory(records: readonly unknown[], toolResults?: ReadonlyMap<string, AgentToolResult<unknown>["content"]>): void;
27
29
  get enabled(): boolean;
28
30
  setEnabled(enabled: boolean): void;
29
- /** Foreground work is bounded by its caller; only background work, queued or running, holds a slot. */
31
+ /** Tell subscribers that something the runtime reads from its host changed, such as `canManageBackground`. */
32
+ refresh(): void;
33
+ /** Whether new work may move to or start in the background: enabled, and the host can manage it. */
34
+ private get admitsBackground();
35
+ /** Handed-off work that has not settled: the waitAny cohort and the statusline count. */
30
36
  private activeBackground;
37
+ /**
38
+ * Foreground work is bounded by its caller; only background work holds a slot, including work
39
+ * whose caller is still waiting for the executor to accept (a detaching task).
40
+ */
31
41
  private backgroundActive;
32
42
  private limitError;
33
43
  execute<T>(execution: TaskExecution<T>): Promise<TaskToolOutcome<T>>;
@@ -35,13 +45,14 @@ export declare class TaskRuntime implements TasksContext, TaskDeliveryLedger {
35
45
  detachForeground(): number;
36
46
  canDetach(id: string): boolean;
37
47
  detach(id: string): boolean;
48
+ /** Every placement changes before any listener hears about it. */
49
+ private detachAll;
38
50
  list(): TaskSnapshot[];
39
51
  private lookup;
40
52
  get(id: string): TaskSnapshot;
41
53
  read(id: string, options?: TaskReadOptions): Promise<TaskRead>;
54
+ presentOutput(id: string, width: number, theme: Theme): string[] | undefined;
42
55
  private resultText;
43
- /** One event-driven waiter can observe a whole waitAny cohort without per-task timers. */
44
- private waitForRecords;
45
56
  /**
46
57
  * One observation: hold delivery for the observed records, wait, read, then register the
47
58
  * receipt with the host, and only then release. Nothing the caller does between those steps
@@ -53,17 +64,9 @@ export declare class TaskRuntime implements TasksContext, TaskDeliveryLedger {
53
64
  kill(id: string): boolean;
54
65
  private cancel;
55
66
  subscribe(listener: () => void): () => void;
56
- /**
57
- * Retention protects snapshots and logs only. Delivery has its own explicit hold.
58
- */
67
+ /** Retention protects snapshots and logs only; completion delivery never waits on it. */
59
68
  retain(id: string): () => void;
60
69
  private pin;
61
- holdDelivery(id: string): () => void;
62
- private holdRecord;
63
- pendingNotifications(): TaskSnapshot[];
64
- claimNotification(id: string): boolean;
65
- markDelivered(id: string): void;
66
- releaseNotification(id: string): void;
67
70
  close(): void;
68
71
  shutdown(graceMs?: number): Promise<void>;
69
72
  /** Running tasks whose launch anchor is outside the branch made of `ancestors`. */
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/core/tasks/runtime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/core/tasks/runtime.ts"],"names":[],"mappings":"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"}