@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,18 +1,20 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { finiteLimit } from "../../utils/number.js";
3
3
  import { Execution } from "./execution.js";
4
- import { boundWaitMs, TASKS_WAIT_DEFAULT_MS } from "./limits.js";
4
+ import { defaultReadMode, TASKS_WAIT_DEFAULT_MS } from "./limits.js";
5
5
  import { boundFacts, boundInput, boundText, errorText, readOutputSlice, sliceText, TASK_LABEL_BYTES, TASK_TITLE_BYTES, } from "./output.js";
6
6
  import { TaskRecord } from "./record.js";
7
7
  import { TaskScheduler } from "./scheduler.js";
8
8
  import { TaskStore } from "./store.js";
9
- import { TASK_BACKGROUND_REJECTION, TASK_KIND_PATTERN, TaskLookupError, } from "./types.js";
9
+ import { TASK_BACKGROUND_REJECTION, TASK_KIND_PATTERN, TASK_MANAGEMENT_REJECTION, TaskLookupError, } from "./types.js";
10
+ import { waitForFirst } from "./wait.js";
10
11
  /** Session-local supervision. Executors own their processes, items and output files. */
11
12
  export class TaskRuntime {
12
13
  constructor(options = {}) {
13
14
  this.executions = new Map();
14
15
  this.scheduler = new TaskScheduler();
15
16
  this.listeners = new Set();
17
+ this.closing = new AbortController();
16
18
  this._closed = false;
17
19
  this.options = options;
18
20
  this.configuredEnabled = options.enabled ?? false;
@@ -59,12 +61,24 @@ export class TaskRuntime {
59
61
  this.configuredEnabled = enabled;
60
62
  this.emit();
61
63
  }
62
- /** Foreground work is bounded by its caller; only background work, queued or running, holds a slot. */
64
+ /** Tell subscribers that something the runtime reads from its host changed, such as `canManageBackground`. */
65
+ refresh() {
66
+ this.emit();
67
+ }
68
+ /** Whether new work may move to or start in the background: enabled, and the host can manage it. */
69
+ get admitsBackground() {
70
+ return this.enabled && (this.options.canManageBackground?.() ?? true);
71
+ }
72
+ /** Handed-off work that has not settled: the waitAny cohort and the statusline count. */
63
73
  activeBackground() {
64
74
  return this.store.unsettled().filter((record) => record.task.mode === "background");
65
75
  }
76
+ /**
77
+ * Foreground work is bounded by its caller; only background work holds a slot, including work
78
+ * whose caller is still waiting for the executor to accept (a detaching task).
79
+ */
66
80
  backgroundActive() {
67
- return this.activeBackground().length;
81
+ return [...this.executions.values()].filter((execution) => execution.holdsBackgroundSlot).length;
68
82
  }
69
83
  limitError() {
70
84
  return new Error(`Background task limit reached (${this.maxBackground}); stop or wait for a background task, or run in the foreground.`);
@@ -78,10 +92,12 @@ export class TaskRuntime {
78
92
  if (execution.background) {
79
93
  if (!this.enabled)
80
94
  throw new Error("Background execution is not available in this host");
95
+ if (!this.admitsBackground)
96
+ throw new Error(TASK_MANAGEMENT_REJECTION);
81
97
  if (this.backgroundActive() >= this.maxBackground)
82
98
  throw this.limitError();
83
99
  if (this.store.retainedCount() >= this.maxRetained) {
84
- throw new Error("Task history retention limit reached; deliver pending notifications or release pinned or claimed records");
100
+ throw new Error("Task history retention limit reached; deliver pending notifications or release task pins and delivery leases");
85
101
  }
86
102
  }
87
103
  if (execution.signal?.aborted)
@@ -104,18 +120,18 @@ export class TaskRuntime {
104
120
  ...(execution.facts?.length ? { facts: boundFacts(execution.facts) } : {}),
105
121
  toolCallId: boundText(execution.toolCallId, 512),
106
122
  anchorId,
107
- mode: execution.background ? "background" : "foreground",
123
+ mode: "foreground",
108
124
  status: "queued",
109
125
  startedAt: Date.now(),
110
126
  };
111
127
  const record = new TaskRecord(task);
128
+ record.setPresenter(execution.present);
112
129
  const active = new Execution(this.host, record, execution);
113
130
  this.store.add(record);
114
131
  this.executions.set(task.id, active);
115
132
  this.scheduler.schedule(active);
116
133
  // Queued background work returns at once; started work hands off after its own accept().
117
- if (active.queued)
118
- active.handoff();
134
+ active.handOffIfQueued();
119
135
  this.emit();
120
136
  return active.caller;
121
137
  }
@@ -123,7 +139,7 @@ export class TaskRuntime {
123
139
  return this.executions.get(record.task.id)?.detachable ?? false;
124
140
  }
125
141
  detachForeground() {
126
- if (!this.enabled)
142
+ if (!this.admitsBackground)
127
143
  return 0;
128
144
  const eligible = [...this.executions.values()]
129
145
  .filter((execution) => execution.detachable)
@@ -133,30 +149,29 @@ export class TaskRuntime {
133
149
  const free = this.maxBackground - this.backgroundActive();
134
150
  if (free <= 0)
135
151
  throw this.limitError();
136
- const executions = eligible.slice(0, free);
137
- for (const execution of executions)
138
- execution.requestDetach();
139
- for (const execution of executions)
140
- execution.completeDetach();
141
- this.emit();
142
- return executions.length;
152
+ return this.detachAll(eligible.slice(0, free));
143
153
  }
144
154
  canDetach(id) {
145
155
  const record = this.lookup(id);
146
- return this.enabled && this.backgroundActive() < this.maxBackground && this.detachable(record);
156
+ return this.admitsBackground && this.backgroundActive() < this.maxBackground && this.detachable(record);
147
157
  }
148
158
  detach(id) {
149
159
  const record = this.lookup(id);
150
- if (!this.enabled || !this.detachable(record))
160
+ if (!this.admitsBackground || !this.detachable(record))
151
161
  return false;
152
162
  if (this.backgroundActive() >= this.maxBackground)
153
163
  throw this.limitError();
154
- const execution = this.executions.get(record.task.id);
155
- execution.requestDetach();
156
- execution.completeDetach();
157
- this.emit();
164
+ this.detachAll([this.executions.get(record.task.id)]);
158
165
  return true;
159
166
  }
167
+ /** Every placement changes before any listener hears about it. */
168
+ detachAll(executions) {
169
+ const notifications = executions.map((execution) => execution.detach());
170
+ for (const notify of notifications)
171
+ notify();
172
+ this.emit();
173
+ return executions.length;
174
+ }
160
175
  list() {
161
176
  return this.store.visible().map((record) => record.snapshot());
162
177
  }
@@ -178,65 +193,38 @@ export class TaskRuntime {
178
193
  const release = this.retain(record.task.id);
179
194
  try {
180
195
  const task = record.snapshot();
196
+ const window = { ...options, mode: options.mode ?? defaultReadMode(task) };
181
197
  if (task.outputPath) {
182
198
  try {
183
- return { task, ...(await readOutputSlice(task.outputPath, options)) };
199
+ return { task, ...(await readOutputSlice(task.outputPath, window)) };
184
200
  }
185
201
  catch (error) {
186
202
  return {
187
203
  task,
188
204
  readError: boundText(`Output could not be read: ${errorText(error)}`, 4096),
189
- ...sliceText(this.resultText(task), options),
205
+ ...sliceText(this.resultText(task), window),
190
206
  };
191
207
  }
192
208
  }
193
- return { task, readError: record.readError, ...sliceText(this.resultText(task), options) };
209
+ return { task, readError: record.readError, ...sliceText(this.resultText(task), window) };
194
210
  }
195
211
  finally {
196
212
  release();
197
213
  }
198
214
  }
215
+ presentOutput(id, width, theme) {
216
+ let record;
217
+ try {
218
+ record = this.lookup(id);
219
+ }
220
+ catch {
221
+ return undefined;
222
+ }
223
+ return record.present(width, theme);
224
+ }
199
225
  resultText(task) {
200
226
  return task.result?.text || task.error || "No output yet.";
201
227
  }
202
- /** One event-driven waiter can observe a whole waitAny cohort without per-task timers. */
203
- waitForRecords(records, timeoutMs, signal, interruptSignal) {
204
- if (records.some((record) => record.settled) || interruptSignal?.aborted)
205
- return Promise.resolve();
206
- return new Promise((resolve, reject) => {
207
- let finished = false;
208
- let timer;
209
- const complete = (aborted = false) => {
210
- if (finished)
211
- return;
212
- finished = true;
213
- if (timer !== undefined)
214
- clearTimeout(timer);
215
- signal?.removeEventListener("abort", abort);
216
- interruptSignal?.removeEventListener("abort", interrupt);
217
- for (const record of records)
218
- record.waiters.delete(wake);
219
- if (aborted)
220
- reject(signal?.reason ?? new Error("Wait aborted"));
221
- else
222
- resolve();
223
- this.store.trim();
224
- this.emit();
225
- };
226
- const wake = () => complete();
227
- const abort = () => complete(true);
228
- const interrupt = () => complete();
229
- for (const record of records)
230
- record.waiters.add(wake);
231
- signal?.addEventListener("abort", abort, { once: true });
232
- interruptSignal?.addEventListener("abort", interrupt, { once: true });
233
- timer = setTimeout(wake, boundWaitMs(timeoutMs));
234
- if (this.closed || interruptSignal?.aborted)
235
- wake();
236
- if (signal?.aborted)
237
- abort();
238
- });
239
- }
240
228
  /**
241
229
  * One observation: hold delivery for the observed records, wait, read, then register the
242
230
  * receipt with the host, and only then release. Nothing the caller does between those steps
@@ -246,11 +234,20 @@ export class TaskRuntime {
246
234
  /** Record to read when none settled; a cohort has none. */
247
235
  fallback) {
248
236
  const { signal } = options;
249
- const releases = records.map((record) => this.holdRecord(record));
237
+ // Retention pins the records; the host keeps them out of automatic delivery until released.
238
+ const releases = records.map((record) => this.pin(record));
239
+ releases.push(this.options.waits?.hold(records.map((record) => record.task.id)) ?? (() => { }));
250
240
  try {
251
241
  const start = Date.now();
252
242
  const interrupt = this.options.waits?.interruptSignal;
253
- await this.waitForRecords(records, options.timeoutMs ?? TASKS_WAIT_DEFAULT_MS, signal, interrupt);
243
+ await waitForFirst({
244
+ hasSettled: () => records.some((record) => record.settled),
245
+ subscribe: (listener) => this.subscribe(listener),
246
+ timeoutMs: options.timeoutMs ?? TASKS_WAIT_DEFAULT_MS,
247
+ signal,
248
+ interrupt,
249
+ closed: this.closing.signal,
250
+ });
254
251
  const waitedMs = Date.now() - start;
255
252
  const settled = records
256
253
  .filter((record) => record.settled)
@@ -315,62 +312,17 @@ export class TaskRuntime {
315
312
  this.listeners.delete(listener);
316
313
  };
317
314
  }
318
- /**
319
- * Retention protects snapshots and logs only. Delivery has its own explicit hold.
320
- */
315
+ /** Retention protects snapshots and logs only; completion delivery never waits on it. */
321
316
  retain(id) {
322
317
  return this.pin(this.lookup(id));
323
318
  }
324
319
  pin(record) {
325
- record.pins++;
326
- let released = false;
320
+ const release = record.pin();
327
321
  return () => {
328
- if (released)
329
- return;
330
- released = true;
331
- record.pins--;
322
+ release();
332
323
  this.store.trim();
333
- // Listeners decide whether delivery may proceed; TaskDelivery owns pausing.
334
- if (!this.closed && record.deliverable)
335
- this.emit();
336
324
  };
337
325
  }
338
- holdDelivery(id) {
339
- return this.holdRecord(this.lookup(id));
340
- }
341
- holdRecord(record) {
342
- const releasePin = this.pin(record);
343
- record.deliveryHolds++;
344
- let released = false;
345
- return () => {
346
- if (released)
347
- return;
348
- released = true;
349
- record.deliveryHolds--;
350
- releasePin();
351
- };
352
- }
353
- pendingNotifications() {
354
- if (this.closed)
355
- return [];
356
- return this.store.deliverable().map((record) => record.snapshot());
357
- }
358
- claimNotification(id) {
359
- return !this.closed && (this.store.get(id)?.claim() ?? false);
360
- }
361
- markDelivered(id) {
362
- const record = this.store.get(id);
363
- if (!record)
364
- return;
365
- record.acknowledge();
366
- this.store.trim();
367
- }
368
- releaseNotification(id) {
369
- if (!this.store.get(id)?.unclaim())
370
- return;
371
- this.store.trim();
372
- this.emit();
373
- }
374
326
  close() {
375
327
  if (this.closed)
376
328
  return;
@@ -379,9 +331,9 @@ export class TaskRuntime {
379
331
  for (const record of this.store.all()) {
380
332
  this.executions.get(record.task.id)?.releaseParent();
381
333
  this.cancel(record);
382
- for (const waiter of [...record.waiters])
383
- waiter();
384
334
  }
335
+ this.closing.abort();
336
+ this.options.onClosed?.();
385
337
  this.store.trim();
386
338
  }
387
339
  async shutdown(graceMs = 2000) {
@@ -402,7 +354,7 @@ export class TaskRuntime {
402
354
  async cancelOutsideBranch(ancestors) {
403
355
  const records = this.store.all();
404
356
  for (const record of records)
405
- record.visible = record.task.anchorId === null || ancestors.has(record.task.anchorId);
357
+ record.setVisible(record.task.anchorId === null || ancestors.has(record.task.anchorId));
406
358
  const outside = records.filter((record) => !record.visible);
407
359
  for (const record of outside)
408
360
  this.cancel(record);
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/core/tasks/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAsB,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EACN,UAAU,EACV,UAAU,EACV,SAAS,EACT,SAAS,EACT,eAAe,EACf,SAAS,EACT,gBAAgB,EAChB,gBAAgB,GAChB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EACN,yBAAyB,EACzB,iBAAiB,EAGjB,eAAe,GAYf,MAAM,YAAY,CAAC;AAEpB,wFAAwF;AACxF,MAAM,OAAO,WAAW;IAavB,YAAY,UAA8B,EAAE;QAX3B,eAAU,GAAG,IAAI,GAAG,EAA8B,CAAC;QACnD,cAAS,GAAG,IAAI,aAAa,EAAE,CAAC;QAChC,cAAS,GAAG,IAAI,GAAG,EAAc,CAAC;QAO3C,YAAO,GAAG,KAAK,CAAC;QAGvB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,iBAAiB,GAAG,OAAO,CAAC,OAAO,IAAI,KAAK,CAAC;QAClD,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QAC7E,IAAI,CAAC,UAAU,GAAG,WAAW,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;QAC5D,qFAAqF;QACrF,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,aAAa,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC;QAC3F,IAAI,CAAC,KAAK,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;QACzG,MAAM,OAAO,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG;YACX,IAAI,MAAM;gBACT,OAAO,OAAO,CAAC,MAAM,CAAC;YACvB,CAAC;YACD,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE;YACvB,MAAM,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC;YAC9D,QAAQ,EAAE,CAAC,SAAS,EAAE,EAAE;gBACvB,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAC1C,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBAClC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;gBAClB,IAAI,CAAC,IAAI,EAAE,CAAC;YACb,CAAC;SACD,CAAC;IACH,CAAC;IAED,IAAI,MAAM;QACT,OAAO,IAAI,CAAC,OAAO,CAAC;IACrB,CAAC;IAED,IAAI,OAAO;QACV,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;IAC7B,CAAC;IAED;;;;;;OAMG;IACH,cAAc,CACb,OAA2B,EAC3B,WAAsE;QAEtE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IACjD,CAAC;IAED,IAAI,OAAO;QACV,OAAO,IAAI,CAAC,iBAAiB,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,iBAAiB,KAAK,KAAK,CAAC;IAC3F,CAAC;IAED,UAAU,CAAC,OAAgB;QAC1B,IAAI,CAAC,iBAAiB,GAAG,OAAO,CAAC;QACjC,IAAI,CAAC,IAAI,EAAE,CAAC;IACb,CAAC;IAED,uGAAuG;IAC/F,gBAAgB;QACvB,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC;IACrF,CAAC;IAEO,gBAAgB;QACvB,OAAO,IAAI,CAAC,gBAAgB,EAAE,CAAC,MAAM,CAAC;IACvC,CAAC;IAEO,UAAU;QACjB,OAAO,IAAI,KAAK,CACf,kCAAkC,IAAI,CAAC,aAAa,kEAAkE,CACtH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAO,CAAI,SAA2B;QAC3C,mGAAmG;QACnG,IAAI,SAAS,CAAC,UAAU,IAAI,IAAI,CAAC,OAAO,CAAC,iBAAiB,KAAK,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QACjH,IAAI,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAC3D,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC;YAC1B,IAAI,CAAC,IAAI,CAAC,OAAO;gBAAE,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;YACzF,IAAI,IAAI,CAAC,gBAAgB,EAAE,IAAI,IAAI,CAAC,aAAa;gBAAE,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;YAC3E,IAAI,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;gBACpD,MAAM,IAAI,KAAK,CACd,0GAA0G,CAC1G,CAAC;YACH,CAAC;QACF,CAAC;QACD,IAAI,SAAS,CAAC,MAAM,EAAE,OAAO;YAAE,MAAM,SAAS,CAAC,MAAM,CAAC,MAAM,IAAI,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QAC/F,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;QACpF,MAAM,WAAW,GAAG,SAAS,CAAC,WAAW,CAAC;QAC1C,IAAI,WAAW,IAAI,CAAC,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,WAAW,CAAC,KAAK,GAAG,CAAC,CAAC;YACzG,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,IAAI,IAAI,CAAC;QACjD,IAAI,QAAQ,KAAK,IAAI,IAAI,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;QAChH,MAAM,IAAI,GAAiB;YAC1B,EAAE,EAAE,GAAG,SAAS,CAAC,IAAI,IAAI,UAAU,EAAE,EAAE;YACvC,IAAI,EAAE,SAAS,CAAC,IAAI;YACpB,KAAK,EAAE,SAAS,CAAC,SAAS,CAAC,KAAK,IAAI,SAAS,CAAC,IAAI,EAAE,gBAAgB,CAAC;YACrE,KAAK,EAAE,SAAS,CAAC,SAAS,CAAC,KAAK,EAAE,gBAAgB,CAAC;YACnD,MAAM,EAAE,SAAS,CAAC,MAAM,IAAI,KAAK;YACjC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClE,GAAG,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1E,UAAU,EAAE,SAAS,CAAC,SAAS,CAAC,UAAU,EAAE,GAAG,CAAC;YAChD,QAAQ;YACR,IAAI,EAAE,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY;YACxD,MAAM,EAAE,QAAQ;YAChB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACrB,CAAC;QACF,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;QAC3D,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACvB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,MAA4B,CAAC,CAAC;QAC3D,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAChC,yFAAyF;QACzF,IAAI,MAAM,CAAC,MAAM;YAAE,MAAM,CAAC,OAAO,EAAE,CAAC;QACpC,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,OAAO,MAAM,CAAC,MAAM,CAAC;IACtB,CAAC;IAEO,UAAU,CAAC,MAAkB;QACpC,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,UAAU,IAAI,KAAK,CAAC;IACjE,CAAC;IAED,gBAAgB;QACf,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,CAAC,CAAC;QAC5B,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;aAC5C,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC;aAC3C,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACpE,IAAI,CAAC,QAAQ,CAAC,MAAM;YAAE,OAAO,CAAC,CAAC;QAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC1D,IAAI,IAAI,IAAI,CAAC;YAAE,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QACvC,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QAC3C,KAAK,MAAM,SAAS,IAAI,UAAU;YAAE,SAAS,CAAC,aAAa,EAAE,CAAC;QAC9D,KAAK,MAAM,SAAS,IAAI,UAAU;YAAE,SAAS,CAAC,cAAc,EAAE,CAAC;QAC/D,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,OAAO,UAAU,CAAC,MAAM,CAAC;IAC1B,CAAC;IAED,SAAS,CAAC,EAAU;QACnB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,gBAAgB,EAAE,GAAG,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAChG,CAAC;IAED,MAAM,CAAC,EAAU;QAChB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC/B,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,OAAO,KAAK,CAAC;QAC5D,IAAI,IAAI,CAAC,gBAAgB,EAAE,IAAI,IAAI,CAAC,aAAa;YAAE,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QAC3E,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAE,CAAC;QACvD,SAAS,CAAC,aAAa,EAAE,CAAC;QAC1B,SAAS,CAAC,cAAc,EAAE,CAAC;QAC3B,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAI;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;IAChE,CAAC;IAEO,MAAM,CAAC,EAAU;QACxB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACjC,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;QACxB,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACrC,IAAI,CAAC,EAAE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjC,MAAM,IAAI,eAAe,CACxB,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,EAC5C,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAC1C,CAAC;QACH,CAAC;QACD,OAAO,OAAO,CAAC,CAAC,CAAE,CAAC;IACpB,CAAC;IAED,GAAG,CAAC,EAAU;QACb,OAAO,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAU,EAAE,UAA2B,EAAE;QACnD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC5C,IAAI,CAAC;YACJ,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;YAC/B,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBACrB,IAAI,CAAC;oBACJ,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,eAAe,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;gBACvE,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBAChB,OAAO;wBACN,IAAI;wBACJ,SAAS,EAAE,SAAS,CAAC,6BAA6B,SAAS,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC;wBAC3E,GAAG,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;qBAC5C,CAAC;gBACH,CAAC;YACF,CAAC;YACD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC;QAC5F,CAAC;gBAAS,CAAC;YACV,OAAO,EAAE,CAAC;QACX,CAAC;IACF,CAAC;IAEO,UAAU,CAAC,IAAkB;QACpC,OAAO,IAAI,CAAC,MAAM,EAAE,IAAI,IAAI,IAAI,CAAC,KAAK,IAAI,gBAAgB,CAAC;IAC5D,CAAC;IAED,0FAA0F;IAClF,cAAc,CACrB,OAA8B,EAC9B,SAAiB,EACjB,MAAoB,EACpB,eAA6B;QAE7B,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,eAAe,EAAE,OAAO;YAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QACnG,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC5C,IAAI,QAAQ,GAAG,KAAK,CAAC;YACrB,IAAI,KAAgD,CAAC;YACrD,MAAM,QAAQ,GAAG,CAAC,OAAO,GAAG,KAAK,EAAE,EAAE;gBACpC,IAAI,QAAQ;oBAAE,OAAO;gBACrB,QAAQ,GAAG,IAAI,CAAC;gBAChB,IAAI,KAAK,KAAK,SAAS;oBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;gBAC7C,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;gBAC5C,eAAe,EAAE,mBAAmB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;gBACzD,KAAK,MAAM,MAAM,IAAI,OAAO;oBAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAC1D,IAAI,OAAO;oBAAE,MAAM,CAAC,MAAM,EAAE,MAAM,IAAI,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC;;oBAC5D,OAAO,EAAE,CAAC;gBACf,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;gBAClB,IAAI,CAAC,IAAI,EAAE,CAAC;YACb,CAAC,CAAC;YACF,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;YAC9B,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACnC,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;YACnC,KAAK,MAAM,MAAM,IAAI,OAAO;gBAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACvD,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACzD,eAAe,EAAE,gBAAgB,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACtE,KAAK,GAAG,UAAU,CAAC,IAAI,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC;YACjD,IAAI,IAAI,CAAC,MAAM,IAAI,eAAe,EAAE,OAAO;gBAAE,IAAI,EAAE,CAAC;YACpD,IAAI,MAAM,EAAE,OAAO;gBAAE,KAAK,EAAE,CAAC;QAC9B,CAAC,CAAC,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,OAAO,CACpB,OAA8B,EAC9B,OAAwB;IACxB,2DAA2D;IAC3D,QAAqB;QAQrB,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;QAC3B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;QAClE,IAAI,CAAC;YACJ,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACzB,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,eAAe,CAAC;YACtD,MAAM,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,IAAI,qBAAqB,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;YAClG,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;YACpC,MAAM,OAAO,GAAG,OAAO;iBACrB,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC;iBAClC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACjF,MAAM,OAAO,GAAoB,OAAO;gBACvC,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,IAAI,CAAC,MAAM;oBACZ,CAAC,CAAC,QAAQ;oBACV,CAAC,CAAC,SAAS,EAAE,OAAO;wBACnB,CAAC,CAAC,aAAa;wBACf,CAAC,CAAC,WAAW,CAAC;YACjB,MAAM,OAAO,GAAG,OAAO;iBACrB,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;iBACrD,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;YACrC,MAAM,QAAQ,GAAG,OAAO,IAAI,QAAQ,CAAC;YACrC,MAAM,IAAI,GACT,OAAO,CAAC,IAAI,IAAI,QAAQ,IAAI,OAAO,KAAK,aAAa;gBACpD,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC;gBACjD,CAAC,CAAC,SAAS,CAAC;YACd,MAAM,EAAE,cAAc,EAAE,CAAC;YACzB,IAAI,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,KAAK,YAAY,IAAI,OAAO,CAAC,UAAU;gBACtE,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC/D,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACtD,CAAC;gBAAS,CAAC;YACV,KAAK,MAAM,OAAO,IAAI,QAAQ;gBAAE,OAAO,EAAE,CAAC;QAC3C,CAAC;IACF,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAU,EAAE,UAA2B,EAAE;QACnD,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO;YAAE,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC;QACtF,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC/B,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QAClF,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IAClF,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,UAA8B,EAAE;QAC7C,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO;YAAE,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC;QACtF,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC3E,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QACnF,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC3F,OAAO;YACN,OAAO;YACP,QAAQ;YACR,OAAO;YACP,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAChD,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACzB,CAAC;IACH,CAAC;IAED,IAAI,CAAC,EAAU;QACd,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IACrC,CAAC;IAEO,MAAM,CAAC,MAAkB;QAChC,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,KAAK,CAAC;IAC/D,CAAC;IAED,SAAS,CAAC,QAAoB;QAC7B,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO,GAAG,EAAE,GAAE,CAAC,CAAC;QACjC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,GAAG,EAAE;YACX,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC,CAAC;IACH,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,EAAU;QAChB,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAClC,CAAC;IAEO,GAAG,CAAC,MAAkB;QAC7B,MAAM,CAAC,IAAI,EAAE,CAAC;QACd,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,OAAO,GAAG,EAAE;YACX,IAAI,QAAQ;gBAAE,OAAO;YACrB,QAAQ,GAAG,IAAI,CAAC;YAChB,MAAM,CAAC,IAAI,EAAE,CAAC;YACd,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;YAClB,4EAA4E;YAC5E,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,WAAW;gBAAE,IAAI,CAAC,IAAI,EAAE,CAAC;QACrD,CAAC,CAAC;IACH,CAAC;IAED,YAAY,CAAC,EAAU;QACtB,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IACzC,CAAC;IAEO,UAAU,CAAC,MAAkB;QACpC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpC,MAAM,CAAC,aAAa,EAAE,CAAC;QACvB,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,OAAO,GAAG,EAAE;YACX,IAAI,QAAQ;gBAAE,OAAO;YACrB,QAAQ,GAAG,IAAI,CAAC;YAChB,MAAM,CAAC,aAAa,EAAE,CAAC;YACvB,UAAU,EAAE,CAAC;QACd,CAAC,CAAC;IACH,CAAC;IAED,oBAAoB;QACnB,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;IACpE,CAAC;IAED,iBAAiB,CAAC,EAAU;QAC3B,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,KAAK,CAAC,CAAC;IAC/D,CAAC;IAED,aAAa,CAAC,EAAU;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClC,IAAI,CAAC,MAAM;YAAE,OAAO;QACpB,MAAM,CAAC,WAAW,EAAE,CAAC;QACrB,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IACnB,CAAC;IAED,mBAAmB,CAAC,EAAU;QAC7B,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE;YAAE,OAAO;QAC3C,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAClB,IAAI,CAAC,IAAI,EAAE,CAAC;IACb,CAAC;IAED,KAAK;QACJ,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO;QACxB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QACvB,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,CAAC;YACvC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC;YACrD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACpB,KAAK,MAAM,MAAM,IAAI,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC;gBAAE,MAAM,EAAE,CAAC;QACpD,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,OAAO,GAAG,IAAI;QAC5B,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;IAC7C,CAAC;IAED,mFAAmF;IACnF,mBAAmB,CAAC,SAA8B;QACjD,OAAO,IAAI,CAAC,KAAK;aACf,SAAS,EAAE;aACX,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,KAAK,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;aACzF,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;IACtC,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,mBAAmB,CAAC,SAA8B;QACvD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;QACjC,KAAK,MAAM,MAAM,IAAI,OAAO;YAC3B,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,KAAK,IAAI,IAAI,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvF,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC5D,KAAK,MAAM,MAAM,IAAI,OAAO;YAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAClD,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAClB,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACjC,CAAC;IAEO,KAAK,CAAC,KAAK,CAAC,OAAqB,EAAE,OAAe;QACzD,IAAI,KAAgD,CAAC;QACrD,IAAI,CAAC;YACJ,MAAM,OAAO,CAAC,IAAI,CAAC;gBAClB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CACzF,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CACzB;gBACD,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;oBAC7B,KAAK,GAAG,UAAU,CAAC,OAAO,EAAE,WAAW,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;gBACjE,CAAC,CAAC;aACF,CAAC,CAAC;QACJ,CAAC;gBAAS,CAAC;YACV,IAAI,KAAK,KAAK,SAAS;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QAC9C,CAAC;IACF,CAAC;IAEO,IAAI;QACX,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO;QACxB,KAAK,MAAM,QAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YAC5C,IAAI,IAAI,CAAC,MAAM;gBAAE,MAAM;YACvB,IAAI,CAAC;gBACJ,QAAQ,EAAE,CAAC;YACZ,CAAC;YAAC,MAAM,CAAC;gBACR,iDAAiD;YAClD,CAAC;QACF,CAAC;IACF,CAAC;CACD","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type { AgentToolResult } from \"@earendil-works/pi-agent-core\";\nimport { finiteLimit } from \"../../utils/number.ts\";\nimport { Execution, type ExecutionHost } from \"./execution.ts\";\nimport { boundWaitMs, TASKS_WAIT_DEFAULT_MS } from \"./limits.ts\";\nimport {\n\tboundFacts,\n\tboundInput,\n\tboundText,\n\terrorText,\n\treadOutputSlice,\n\tsliceText,\n\tTASK_LABEL_BYTES,\n\tTASK_TITLE_BYTES,\n} from \"./output.ts\";\nimport { TaskRecord } from \"./record.ts\";\nimport { TaskScheduler } from \"./scheduler.ts\";\nimport { TaskStore } from \"./store.ts\";\nimport {\n\tTASK_BACKGROUND_REJECTION,\n\tTASK_KIND_PATTERN,\n\ttype TaskDeliveryLedger,\n\ttype TaskExecution,\n\tTaskLookupError,\n\ttype TaskRead,\n\ttype TaskReadOptions,\n\ttype TaskRuntimeOptions,\n\ttype TaskSnapshot,\n\ttype TasksContext,\n\ttype TaskToolOutcome,\n\ttype TaskWaitAnyOptions,\n\ttype TaskWaitAnyResult,\n\ttype TaskWaitOptions,\n\ttype TaskWaitOutcome,\n\ttype TaskWaitResult,\n} from \"./types.ts\";\n\n/** Session-local supervision. Executors own their processes, items and output files. */\nexport class TaskRuntime implements TasksContext, TaskDeliveryLedger {\n\tprivate readonly store: TaskStore;\n\tprivate readonly executions = new Map<string, Execution<unknown>>();\n\tprivate readonly scheduler = new TaskScheduler();\n\tprivate readonly listeners = new Set<() => void>();\n\tprivate readonly host: ExecutionHost;\n\tprivate readonly maxBackground: number;\n\tprivate readonly maxHistory: number;\n\tprivate readonly maxRetained: number;\n\tprivate readonly options: TaskRuntimeOptions;\n\tprivate configuredEnabled: boolean;\n\tprivate _closed = false;\n\n\tconstructor(options: TaskRuntimeOptions = {}) {\n\t\tthis.options = options;\n\t\tthis.configuredEnabled = options.enabled ?? false;\n\t\tthis.maxBackground = Math.max(1, finiteLimit(options.maxBackground, 8, 128));\n\t\tthis.maxHistory = finiteLimit(options.maxHistory, 32, 1024);\n\t\t// Separate foreground and background histories, plus the protected-record allowance.\n\t\tthis.maxRetained = this.maxBackground + 2 * Math.max(1, this.maxHistory) + this.maxHistory;\n\t\tthis.store = new TaskStore(this.maxHistory, this.maxRetained, () => this.closed, options.onCleanupError);\n\t\tconst runtime = this;\n\t\tthis.host = {\n\t\t\tget closed() {\n\t\t\t\treturn runtime.closed;\n\t\t\t},\n\t\t\temit: () => this.emit(),\n\t\t\tsettle: (task, usage) => this.options.onSettled?.(task, usage),\n\t\t\treleased: (execution) => {\n\t\t\t\tthis.executions.delete(execution.task.id);\n\t\t\t\tthis.scheduler.release(execution);\n\t\t\t\tthis.store.trim();\n\t\t\t\tthis.emit();\n\t\t\t},\n\t\t};\n\t}\n\n\tget closed(): boolean {\n\t\treturn this._closed;\n\t}\n\n\tget session(): TaskRuntimeOptions[\"session\"] {\n\t\treturn this.options.session;\n\t}\n\n\t/**\n\t * Rehydrate terminal snapshots only, newest endedAt in each history (later input wins\n\t * ties). Existing runtime records win ID collisions. No execution, accounting,\n\t * notification, or deletion ownership is restored. Foreground records take their output\n\t * from the branch's tool results. The host supplies the current branch; closed services\n\t * ignore restoration.\n\t */\n\trestoreHistory(\n\t\trecords: readonly unknown[],\n\t\ttoolResults?: ReadonlyMap<string, AgentToolResult<unknown>[\"content\"]>,\n\t): void {\n\t\tthis.store.restoreHistory(records, toolResults);\n\t}\n\n\tget enabled(): boolean {\n\t\treturn this.configuredEnabled && !this.closed && this.options.backgroundAllowed !== false;\n\t}\n\n\tsetEnabled(enabled: boolean): void {\n\t\tthis.configuredEnabled = enabled;\n\t\tthis.emit();\n\t}\n\n\t/** Foreground work is bounded by its caller; only background work, queued or running, holds a slot. */\n\tprivate activeBackground(): TaskRecord[] {\n\t\treturn this.store.unsettled().filter((record) => record.task.mode === \"background\");\n\t}\n\n\tprivate backgroundActive(): number {\n\t\treturn this.activeBackground().length;\n\t}\n\n\tprivate limitError(): Error {\n\t\treturn new Error(\n\t\t\t`Background task limit reached (${this.maxBackground}); stop or wait for a background task, or run in the foreground.`,\n\t\t);\n\t}\n\n\tasync execute<T>(execution: TaskExecution<T>): Promise<TaskToolOutcome<T>> {\n\t\t// Admission and registration happen synchronously, before invoking user code or awaiting anything.\n\t\tif (execution.background && this.options.backgroundAllowed === false) throw new Error(TASK_BACKGROUND_REJECTION);\n\t\tif (this.closed) throw new Error(\"Task service is closed\");\n\t\tif (execution.background) {\n\t\t\tif (!this.enabled) throw new Error(\"Background execution is not available in this host\");\n\t\t\tif (this.backgroundActive() >= this.maxBackground) throw this.limitError();\n\t\t\tif (this.store.retainedCount() >= this.maxRetained) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"Task history retention limit reached; deliver pending notifications or release pinned or claimed records\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (execution.signal?.aborted) throw execution.signal.reason ?? new Error(\"Execution aborted\");\n\t\tif (!TASK_KIND_PATTERN.test(execution.kind)) throw new Error(\"Invalid task source\");\n\t\tconst concurrency = execution.concurrency;\n\t\tif (concurrency && (!concurrency.key || !Number.isSafeInteger(concurrency.limit) || concurrency.limit < 1))\n\t\t\tthrow new Error(\"Invalid task concurrency\");\n\t\tconst anchorId = this.options.anchor?.() ?? null;\n\t\tif (anchorId !== null && Buffer.byteLength(anchorId) > 8192) throw new Error(\"Task branch anchor is too large\");\n\t\tconst task: TaskSnapshot = {\n\t\t\tid: `${execution.kind}-${randomUUID()}`,\n\t\t\tkind: execution.kind,\n\t\t\tlabel: boundText(execution.label ?? execution.kind, TASK_LABEL_BYTES),\n\t\t\ttitle: boundText(execution.title, TASK_TITLE_BYTES),\n\t\t\toutput: execution.output ?? \"log\",\n\t\t\t...(execution.input ? { input: boundInput(execution.input) } : {}),\n\t\t\t...(execution.facts?.length ? { facts: boundFacts(execution.facts) } : {}),\n\t\t\ttoolCallId: boundText(execution.toolCallId, 512),\n\t\t\tanchorId,\n\t\t\tmode: execution.background ? \"background\" : \"foreground\",\n\t\t\tstatus: \"queued\",\n\t\t\tstartedAt: Date.now(),\n\t\t};\n\t\tconst record = new TaskRecord(task);\n\t\tconst active = new Execution(this.host, record, execution);\n\t\tthis.store.add(record);\n\t\tthis.executions.set(task.id, active as Execution<unknown>);\n\t\tthis.scheduler.schedule(active);\n\t\t// Queued background work returns at once; started work hands off after its own accept().\n\t\tif (active.queued) active.handoff();\n\t\tthis.emit();\n\t\treturn active.caller;\n\t}\n\n\tprivate detachable(record: TaskRecord): boolean {\n\t\treturn this.executions.get(record.task.id)?.detachable ?? false;\n\t}\n\n\tdetachForeground(): number {\n\t\tif (!this.enabled) return 0;\n\t\tconst eligible = [...this.executions.values()]\n\t\t\t.filter((execution) => execution.detachable)\n\t\t\t.sort((left, right) => left.task.startedAt - right.task.startedAt);\n\t\tif (!eligible.length) return 0;\n\t\tconst free = this.maxBackground - this.backgroundActive();\n\t\tif (free <= 0) throw this.limitError();\n\t\tconst executions = eligible.slice(0, free);\n\t\tfor (const execution of executions) execution.requestDetach();\n\t\tfor (const execution of executions) execution.completeDetach();\n\t\tthis.emit();\n\t\treturn executions.length;\n\t}\n\n\tcanDetach(id: string): boolean {\n\t\tconst record = this.lookup(id);\n\t\treturn this.enabled && this.backgroundActive() < this.maxBackground && this.detachable(record);\n\t}\n\n\tdetach(id: string): boolean {\n\t\tconst record = this.lookup(id);\n\t\tif (!this.enabled || !this.detachable(record)) return false;\n\t\tif (this.backgroundActive() >= this.maxBackground) throw this.limitError();\n\t\tconst execution = this.executions.get(record.task.id)!;\n\t\texecution.requestDetach();\n\t\texecution.completeDetach();\n\t\tthis.emit();\n\t\treturn true;\n\t}\n\n\tlist(): TaskSnapshot[] {\n\t\treturn this.store.visible().map((record) => record.snapshot());\n\t}\n\n\tprivate lookup(id: string): TaskRecord {\n\t\tconst exact = this.store.get(id);\n\t\tif (exact) return exact;\n\t\tconst matches = this.store.match(id);\n\t\tif (!id || matches.length !== 1) {\n\t\t\tthrow new TaskLookupError(\n\t\t\t\tmatches.length > 1 ? \"ambiguous\" : \"unknown\",\n\t\t\t\tmatches.map((record) => record.snapshot()),\n\t\t\t);\n\t\t}\n\t\treturn matches[0]!;\n\t}\n\n\tget(id: string): TaskSnapshot {\n\t\treturn this.lookup(id).snapshot();\n\t}\n\n\tasync read(id: string, options: TaskReadOptions = {}): Promise<TaskRead> {\n\t\tconst record = this.lookup(id);\n\t\tconst release = this.retain(record.task.id);\n\t\ttry {\n\t\t\tconst task = record.snapshot();\n\t\t\tif (task.outputPath) {\n\t\t\t\ttry {\n\t\t\t\t\treturn { task, ...(await readOutputSlice(task.outputPath, options)) };\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttask,\n\t\t\t\t\t\treadError: boundText(`Output could not be read: ${errorText(error)}`, 4096),\n\t\t\t\t\t\t...sliceText(this.resultText(task), options),\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { task, readError: record.readError, ...sliceText(this.resultText(task), options) };\n\t\t} finally {\n\t\t\trelease();\n\t\t}\n\t}\n\n\tprivate resultText(task: TaskSnapshot): string {\n\t\treturn task.result?.text || task.error || \"No output yet.\";\n\t}\n\n\t/** One event-driven waiter can observe a whole waitAny cohort without per-task timers. */\n\tprivate waitForRecords(\n\t\trecords: readonly TaskRecord[],\n\t\ttimeoutMs: number,\n\t\tsignal?: AbortSignal,\n\t\tinterruptSignal?: AbortSignal,\n\t): Promise<void> {\n\t\tif (records.some((record) => record.settled) || interruptSignal?.aborted) return Promise.resolve();\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\tlet finished = false;\n\t\t\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\t\t\tconst complete = (aborted = false) => {\n\t\t\t\tif (finished) return;\n\t\t\t\tfinished = true;\n\t\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t\t\tsignal?.removeEventListener(\"abort\", abort);\n\t\t\t\tinterruptSignal?.removeEventListener(\"abort\", interrupt);\n\t\t\t\tfor (const record of records) record.waiters.delete(wake);\n\t\t\t\tif (aborted) reject(signal?.reason ?? new Error(\"Wait aborted\"));\n\t\t\t\telse resolve();\n\t\t\t\tthis.store.trim();\n\t\t\t\tthis.emit();\n\t\t\t};\n\t\t\tconst wake = () => complete();\n\t\t\tconst abort = () => complete(true);\n\t\t\tconst interrupt = () => complete();\n\t\t\tfor (const record of records) record.waiters.add(wake);\n\t\t\tsignal?.addEventListener(\"abort\", abort, { once: true });\n\t\t\tinterruptSignal?.addEventListener(\"abort\", interrupt, { once: true });\n\t\t\ttimer = setTimeout(wake, boundWaitMs(timeoutMs));\n\t\t\tif (this.closed || interruptSignal?.aborted) wake();\n\t\t\tif (signal?.aborted) abort();\n\t\t});\n\t}\n\n\t/**\n\t * One observation: hold delivery for the observed records, wait, read, then register the\n\t * receipt with the host, and only then release. Nothing the caller does between those steps\n\t * can leak a settled result into an automatic notification or lose it.\n\t */\n\tprivate async observe(\n\t\trecords: readonly TaskRecord[],\n\t\toptions: TaskWaitOptions,\n\t\t/** Record to read when none settled; a cohort has none. */\n\t\tfallback?: TaskRecord,\n\t): Promise<{\n\t\toutcome: TaskWaitOutcome;\n\t\twaitedMs: number;\n\t\tsettled?: TaskRecord;\n\t\trunning: TaskSnapshot[];\n\t\tread?: TaskRead;\n\t}> {\n\t\tconst { signal } = options;\n\t\tconst releases = records.map((record) => this.holdRecord(record));\n\t\ttry {\n\t\t\tconst start = Date.now();\n\t\t\tconst interrupt = this.options.waits?.interruptSignal;\n\t\t\tawait this.waitForRecords(records, options.timeoutMs ?? TASKS_WAIT_DEFAULT_MS, signal, interrupt);\n\t\t\tconst waitedMs = Date.now() - start;\n\t\t\tconst settled = records\n\t\t\t\t.filter((record) => record.settled)\n\t\t\t\t.sort((left, right) => (left.task.endedAt ?? 0) - (right.task.endedAt ?? 0))[0];\n\t\t\tconst outcome: TaskWaitOutcome = settled\n\t\t\t\t? \"settled\"\n\t\t\t\t: this.closed\n\t\t\t\t\t? \"closed\"\n\t\t\t\t\t: interrupt?.aborted\n\t\t\t\t\t\t? \"interrupted\"\n\t\t\t\t\t\t: \"timed_out\";\n\t\t\tconst running = records\n\t\t\t\t.filter((record) => record.visible && !record.settled)\n\t\t\t\t.map((record) => record.snapshot());\n\t\t\tconst observed = settled ?? fallback;\n\t\t\tconst read =\n\t\t\t\toptions.read && observed && outcome !== \"interrupted\"\n\t\t\t\t\t? await this.read(observed.task.id, options.read)\n\t\t\t\t\t: undefined;\n\t\t\tsignal?.throwIfAborted();\n\t\t\tif (settled && settled.task.mode === \"background\" && options.toolCallId)\n\t\t\t\tthis.options.waits?.bind(options.toolCallId, settled.task.id);\n\t\t\treturn { outcome, waitedMs, settled, running, read };\n\t\t} finally {\n\t\t\tfor (const release of releases) release();\n\t\t}\n\t}\n\n\tasync wait(id: string, options: TaskWaitOptions = {}): Promise<TaskWaitResult> {\n\t\tif (options.signal?.aborted) throw options.signal.reason ?? new Error(\"Wait aborted\");\n\t\tconst record = this.lookup(id);\n\t\tconst { outcome, waitedMs, read } = await this.observe([record], options, record);\n\t\treturn { outcome, waitedMs, task: record.snapshot(), ...(read ? { read } : {}) };\n\t}\n\n\tasync waitAny(options: TaskWaitAnyOptions = {}): Promise<TaskWaitAnyResult> {\n\t\tif (options.signal?.aborted) throw options.signal.reason ?? new Error(\"Wait aborted\");\n\t\tconst records = this.activeBackground().filter((record) => record.visible);\n\t\tif (records.length === 0) return { outcome: \"no_tasks\", waitedMs: 0, running: [] };\n\t\tconst { outcome, waitedMs, settled, running, read } = await this.observe(records, options);\n\t\treturn {\n\t\t\toutcome,\n\t\t\twaitedMs,\n\t\t\trunning,\n\t\t\t...(settled ? { task: settled.snapshot() } : {}),\n\t\t\t...(read ? { read } : {}),\n\t\t};\n\t}\n\n\tkill(id: string): boolean {\n\t\treturn this.cancel(this.lookup(id));\n\t}\n\n\tprivate cancel(record: TaskRecord): boolean {\n\t\treturn this.executions.get(record.task.id)?.cancel() ?? false;\n\t}\n\n\tsubscribe(listener: () => void): () => void {\n\t\tif (this.closed) return () => {};\n\t\tthis.listeners.add(listener);\n\t\treturn () => {\n\t\t\tthis.listeners.delete(listener);\n\t\t};\n\t}\n\n\t/**\n\t * Retention protects snapshots and logs only. Delivery has its own explicit hold.\n\t */\n\tretain(id: string): () => void {\n\t\treturn this.pin(this.lookup(id));\n\t}\n\n\tprivate pin(record: TaskRecord): () => void {\n\t\trecord.pins++;\n\t\tlet released = false;\n\t\treturn () => {\n\t\t\tif (released) return;\n\t\t\treleased = true;\n\t\t\trecord.pins--;\n\t\t\tthis.store.trim();\n\t\t\t// Listeners decide whether delivery may proceed; TaskDelivery owns pausing.\n\t\t\tif (!this.closed && record.deliverable) this.emit();\n\t\t};\n\t}\n\n\tholdDelivery(id: string): () => void {\n\t\treturn this.holdRecord(this.lookup(id));\n\t}\n\n\tprivate holdRecord(record: TaskRecord): () => void {\n\t\tconst releasePin = this.pin(record);\n\t\trecord.deliveryHolds++;\n\t\tlet released = false;\n\t\treturn () => {\n\t\t\tif (released) return;\n\t\t\treleased = true;\n\t\t\trecord.deliveryHolds--;\n\t\t\treleasePin();\n\t\t};\n\t}\n\n\tpendingNotifications(): TaskSnapshot[] {\n\t\tif (this.closed) return [];\n\t\treturn this.store.deliverable().map((record) => record.snapshot());\n\t}\n\n\tclaimNotification(id: string): boolean {\n\t\treturn !this.closed && (this.store.get(id)?.claim() ?? false);\n\t}\n\n\tmarkDelivered(id: string): void {\n\t\tconst record = this.store.get(id);\n\t\tif (!record) return;\n\t\trecord.acknowledge();\n\t\tthis.store.trim();\n\t}\n\n\treleaseNotification(id: string): void {\n\t\tif (!this.store.get(id)?.unclaim()) return;\n\t\tthis.store.trim();\n\t\tthis.emit();\n\t}\n\n\tclose(): void {\n\t\tif (this.closed) return;\n\t\tthis._closed = true;\n\t\tthis.listeners.clear();\n\t\tfor (const record of this.store.all()) {\n\t\t\tthis.executions.get(record.task.id)?.releaseParent();\n\t\t\tthis.cancel(record);\n\t\t\tfor (const waiter of [...record.waiters]) waiter();\n\t\t}\n\t\tthis.store.trim();\n\t}\n\n\tasync shutdown(graceMs = 2000): Promise<void> {\n\t\tthis.close();\n\t\tawait this.drain(this.store.all(), graceMs);\n\t}\n\n\t/** Running tasks whose launch anchor is outside the branch made of `ancestors`. */\n\tactiveOutsideBranch(ancestors: ReadonlySet<string>): TaskSnapshot[] {\n\t\treturn this.store\n\t\t\t.unsettled()\n\t\t\t.filter((record) => record.task.anchorId !== null && !ancestors.has(record.task.anchorId))\n\t\t\t.map((record) => record.snapshot());\n\t}\n\n\t/**\n\t * Hidden results stay pending: returning to their branch delivers them again.\n\t * Restored history is already delivered.\n\t */\n\tasync cancelOutsideBranch(ancestors: ReadonlySet<string>): Promise<void> {\n\t\tconst records = this.store.all();\n\t\tfor (const record of records)\n\t\t\trecord.visible = record.task.anchorId === null || ancestors.has(record.task.anchorId);\n\t\tconst outside = records.filter((record) => !record.visible);\n\t\tfor (const record of outside) this.cancel(record);\n\t\tthis.store.trim();\n\t\tthis.emit();\n\t\tawait this.drain(outside, 2000);\n\t}\n\n\tprivate async drain(records: TaskRecord[], graceMs: number): Promise<void> {\n\t\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\t\ttry {\n\t\t\tawait Promise.race([\n\t\t\t\tPromise.all(records.map((record) => this.executions.get(record.task.id)?.done)).then(() =>\n\t\t\t\t\tthis.store.cleanupsDone(),\n\t\t\t\t),\n\t\t\t\tnew Promise<void>((resolve) => {\n\t\t\t\t\ttimer = setTimeout(resolve, finiteLimit(graceMs, 2000, 60_000));\n\t\t\t\t}),\n\t\t\t]);\n\t\t} finally {\n\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t}\n\t}\n\n\tprivate emit(): void {\n\t\tif (this.closed) return;\n\t\tfor (const listener of [...this.listeners]) {\n\t\t\tif (this.closed) break;\n\t\t\ttry {\n\t\t\t\tlistener();\n\t\t\t} catch {\n\t\t\t\t/* Observers do not own execution or delivery. */\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/core/tasks/runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type { AgentToolResult } from \"@earendil-works/pi-agent-core\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { finiteLimit } from \"../../utils/number.ts\";\nimport { Execution, type ExecutionHost } from \"./execution.ts\";\nimport { defaultReadMode, TASKS_WAIT_DEFAULT_MS } from \"./limits.ts\";\nimport {\n\tboundFacts,\n\tboundInput,\n\tboundText,\n\terrorText,\n\treadOutputSlice,\n\tsliceText,\n\tTASK_LABEL_BYTES,\n\tTASK_TITLE_BYTES,\n} from \"./output.ts\";\nimport { TaskRecord } from \"./record.ts\";\nimport { TaskScheduler } from \"./scheduler.ts\";\nimport { TaskStore } from \"./store.ts\";\nimport {\n\tTASK_BACKGROUND_REJECTION,\n\tTASK_KIND_PATTERN,\n\tTASK_MANAGEMENT_REJECTION,\n\ttype TaskExecution,\n\tTaskLookupError,\n\ttype TaskRead,\n\ttype TaskReadOptions,\n\ttype TaskRuntimeOptions,\n\ttype TaskSnapshot,\n\ttype TasksContext,\n\ttype TaskToolOutcome,\n\ttype TaskWaitAnyOptions,\n\ttype TaskWaitAnyResult,\n\ttype TaskWaitOptions,\n\ttype TaskWaitOutcome,\n\ttype TaskWaitResult,\n} from \"./types.ts\";\nimport { waitForFirst } from \"./wait.ts\";\n\n/** Session-local supervision. Executors own their processes, items and output files. */\nexport class TaskRuntime implements TasksContext {\n\tprivate readonly store: TaskStore;\n\tprivate readonly executions = new Map<string, Execution<unknown>>();\n\tprivate readonly scheduler = new TaskScheduler();\n\tprivate readonly listeners = new Set<() => void>();\n\tprivate readonly host: ExecutionHost;\n\tprivate readonly maxBackground: number;\n\tprivate readonly maxHistory: number;\n\tprivate readonly maxRetained: number;\n\tprivate readonly options: TaskRuntimeOptions;\n\tprivate readonly closing = new AbortController();\n\tprivate configuredEnabled: boolean;\n\tprivate _closed = false;\n\n\tconstructor(options: TaskRuntimeOptions = {}) {\n\t\tthis.options = options;\n\t\tthis.configuredEnabled = options.enabled ?? false;\n\t\tthis.maxBackground = Math.max(1, finiteLimit(options.maxBackground, 8, 128));\n\t\tthis.maxHistory = finiteLimit(options.maxHistory, 32, 1024);\n\t\t// Separate foreground and background histories, plus the protected-record allowance.\n\t\tthis.maxRetained = this.maxBackground + 2 * Math.max(1, this.maxHistory) + this.maxHistory;\n\t\tthis.store = new TaskStore(this.maxHistory, this.maxRetained, () => this.closed, options.onCleanupError);\n\t\tconst runtime = this;\n\t\tthis.host = {\n\t\t\tget closed() {\n\t\t\t\treturn runtime.closed;\n\t\t\t},\n\t\t\temit: () => this.emit(),\n\t\t\tsettle: (task, usage) => this.options.onSettled?.(task, usage),\n\t\t\treleased: (execution) => {\n\t\t\t\tthis.executions.delete(execution.task.id);\n\t\t\t\tthis.scheduler.release(execution);\n\t\t\t\tthis.store.trim();\n\t\t\t\tthis.emit();\n\t\t\t},\n\t\t};\n\t}\n\n\tget closed(): boolean {\n\t\treturn this._closed;\n\t}\n\n\tget session(): TaskRuntimeOptions[\"session\"] {\n\t\treturn this.options.session;\n\t}\n\n\t/**\n\t * Rehydrate terminal snapshots only, newest endedAt in each history (later input wins\n\t * ties). Existing runtime records win ID collisions. No execution, accounting,\n\t * notification, or deletion ownership is restored. Foreground records take their output\n\t * from the branch's tool results. The host supplies the current branch; closed services\n\t * ignore restoration.\n\t */\n\trestoreHistory(\n\t\trecords: readonly unknown[],\n\t\ttoolResults?: ReadonlyMap<string, AgentToolResult<unknown>[\"content\"]>,\n\t): void {\n\t\tthis.store.restoreHistory(records, toolResults);\n\t}\n\n\tget enabled(): boolean {\n\t\treturn this.configuredEnabled && !this.closed && this.options.backgroundAllowed !== false;\n\t}\n\n\tsetEnabled(enabled: boolean): void {\n\t\tthis.configuredEnabled = enabled;\n\t\tthis.emit();\n\t}\n\n\t/** Tell subscribers that something the runtime reads from its host changed, such as `canManageBackground`. */\n\trefresh(): void {\n\t\tthis.emit();\n\t}\n\n\t/** Whether new work may move to or start in the background: enabled, and the host can manage it. */\n\tprivate get admitsBackground(): boolean {\n\t\treturn this.enabled && (this.options.canManageBackground?.() ?? true);\n\t}\n\n\t/** Handed-off work that has not settled: the waitAny cohort and the statusline count. */\n\tprivate activeBackground(): TaskRecord[] {\n\t\treturn this.store.unsettled().filter((record) => record.task.mode === \"background\");\n\t}\n\n\t/**\n\t * Foreground work is bounded by its caller; only background work holds a slot, including work\n\t * whose caller is still waiting for the executor to accept (a detaching task).\n\t */\n\tprivate backgroundActive(): number {\n\t\treturn [...this.executions.values()].filter((execution) => execution.holdsBackgroundSlot).length;\n\t}\n\n\tprivate limitError(): Error {\n\t\treturn new Error(\n\t\t\t`Background task limit reached (${this.maxBackground}); stop or wait for a background task, or run in the foreground.`,\n\t\t);\n\t}\n\n\tasync execute<T>(execution: TaskExecution<T>): Promise<TaskToolOutcome<T>> {\n\t\t// Admission and registration happen synchronously, before invoking user code or awaiting anything.\n\t\tif (execution.background && this.options.backgroundAllowed === false) throw new Error(TASK_BACKGROUND_REJECTION);\n\t\tif (this.closed) throw new Error(\"Task service is closed\");\n\t\tif (execution.background) {\n\t\t\tif (!this.enabled) throw new Error(\"Background execution is not available in this host\");\n\t\t\tif (!this.admitsBackground) throw new Error(TASK_MANAGEMENT_REJECTION);\n\t\t\tif (this.backgroundActive() >= this.maxBackground) throw this.limitError();\n\t\t\tif (this.store.retainedCount() >= this.maxRetained) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"Task history retention limit reached; deliver pending notifications or release task pins and delivery leases\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (execution.signal?.aborted) throw execution.signal.reason ?? new Error(\"Execution aborted\");\n\t\tif (!TASK_KIND_PATTERN.test(execution.kind)) throw new Error(\"Invalid task source\");\n\t\tconst concurrency = execution.concurrency;\n\t\tif (concurrency && (!concurrency.key || !Number.isSafeInteger(concurrency.limit) || concurrency.limit < 1))\n\t\t\tthrow new Error(\"Invalid task concurrency\");\n\t\tconst anchorId = this.options.anchor?.() ?? null;\n\t\tif (anchorId !== null && Buffer.byteLength(anchorId) > 8192) throw new Error(\"Task branch anchor is too large\");\n\t\tconst task: TaskSnapshot = {\n\t\t\tid: `${execution.kind}-${randomUUID()}`,\n\t\t\tkind: execution.kind,\n\t\t\tlabel: boundText(execution.label ?? execution.kind, TASK_LABEL_BYTES),\n\t\t\ttitle: boundText(execution.title, TASK_TITLE_BYTES),\n\t\t\toutput: execution.output ?? \"log\",\n\t\t\t...(execution.input ? { input: boundInput(execution.input) } : {}),\n\t\t\t...(execution.facts?.length ? { facts: boundFacts(execution.facts) } : {}),\n\t\t\ttoolCallId: boundText(execution.toolCallId, 512),\n\t\t\tanchorId,\n\t\t\tmode: \"foreground\",\n\t\t\tstatus: \"queued\",\n\t\t\tstartedAt: Date.now(),\n\t\t};\n\t\tconst record = new TaskRecord(task);\n\t\trecord.setPresenter(execution.present);\n\t\tconst active = new Execution(this.host, record, execution);\n\t\tthis.store.add(record);\n\t\tthis.executions.set(task.id, active as Execution<unknown>);\n\t\tthis.scheduler.schedule(active);\n\t\t// Queued background work returns at once; started work hands off after its own accept().\n\t\tactive.handOffIfQueued();\n\t\tthis.emit();\n\t\treturn active.caller;\n\t}\n\n\tprivate detachable(record: TaskRecord): boolean {\n\t\treturn this.executions.get(record.task.id)?.detachable ?? false;\n\t}\n\n\tdetachForeground(): number {\n\t\tif (!this.admitsBackground) return 0;\n\t\tconst eligible = [...this.executions.values()]\n\t\t\t.filter((execution) => execution.detachable)\n\t\t\t.sort((left, right) => left.task.startedAt - right.task.startedAt);\n\t\tif (!eligible.length) return 0;\n\t\tconst free = this.maxBackground - this.backgroundActive();\n\t\tif (free <= 0) throw this.limitError();\n\t\treturn this.detachAll(eligible.slice(0, free));\n\t}\n\n\tcanDetach(id: string): boolean {\n\t\tconst record = this.lookup(id);\n\t\treturn this.admitsBackground && this.backgroundActive() < this.maxBackground && this.detachable(record);\n\t}\n\n\tdetach(id: string): boolean {\n\t\tconst record = this.lookup(id);\n\t\tif (!this.admitsBackground || !this.detachable(record)) return false;\n\t\tif (this.backgroundActive() >= this.maxBackground) throw this.limitError();\n\t\tthis.detachAll([this.executions.get(record.task.id)!]);\n\t\treturn true;\n\t}\n\n\t/** Every placement changes before any listener hears about it. */\n\tprivate detachAll(executions: Execution<unknown>[]): number {\n\t\tconst notifications = executions.map((execution) => execution.detach());\n\t\tfor (const notify of notifications) notify();\n\t\tthis.emit();\n\t\treturn executions.length;\n\t}\n\n\tlist(): TaskSnapshot[] {\n\t\treturn this.store.visible().map((record) => record.snapshot());\n\t}\n\n\tprivate lookup(id: string): TaskRecord {\n\t\tconst exact = this.store.get(id);\n\t\tif (exact) return exact;\n\t\tconst matches = this.store.match(id);\n\t\tif (!id || matches.length !== 1) {\n\t\t\tthrow new TaskLookupError(\n\t\t\t\tmatches.length > 1 ? \"ambiguous\" : \"unknown\",\n\t\t\t\tmatches.map((record) => record.snapshot()),\n\t\t\t);\n\t\t}\n\t\treturn matches[0]!;\n\t}\n\n\tget(id: string): TaskSnapshot {\n\t\treturn this.lookup(id).snapshot();\n\t}\n\n\tasync read(id: string, options: TaskReadOptions = {}): Promise<TaskRead> {\n\t\tconst record = this.lookup(id);\n\t\tconst release = this.retain(record.task.id);\n\t\ttry {\n\t\t\tconst task = record.snapshot();\n\t\t\tconst window = { ...options, mode: options.mode ?? defaultReadMode(task) };\n\t\t\tif (task.outputPath) {\n\t\t\t\ttry {\n\t\t\t\t\treturn { task, ...(await readOutputSlice(task.outputPath, window)) };\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttask,\n\t\t\t\t\t\treadError: boundText(`Output could not be read: ${errorText(error)}`, 4096),\n\t\t\t\t\t\t...sliceText(this.resultText(task), window),\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { task, readError: record.readError, ...sliceText(this.resultText(task), window) };\n\t\t} finally {\n\t\t\trelease();\n\t\t}\n\t}\n\n\tpresentOutput(id: string, width: number, theme: Theme): string[] | undefined {\n\t\tlet record: TaskRecord;\n\t\ttry {\n\t\t\trecord = this.lookup(id);\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn record.present(width, theme);\n\t}\n\n\tprivate resultText(task: TaskSnapshot): string {\n\t\treturn task.result?.text || task.error || \"No output yet.\";\n\t}\n\n\t/**\n\t * One observation: hold delivery for the observed records, wait, read, then register the\n\t * receipt with the host, and only then release. Nothing the caller does between those steps\n\t * can leak a settled result into an automatic notification or lose it.\n\t */\n\tprivate async observe(\n\t\trecords: readonly TaskRecord[],\n\t\toptions: TaskWaitOptions,\n\t\t/** Record to read when none settled; a cohort has none. */\n\t\tfallback?: TaskRecord,\n\t): Promise<{\n\t\toutcome: TaskWaitOutcome;\n\t\twaitedMs: number;\n\t\tsettled?: TaskRecord;\n\t\trunning: TaskSnapshot[];\n\t\tread?: TaskRead;\n\t}> {\n\t\tconst { signal } = options;\n\t\t// Retention pins the records; the host keeps them out of automatic delivery until released.\n\t\tconst releases = records.map((record) => this.pin(record));\n\t\treleases.push(this.options.waits?.hold(records.map((record) => record.task.id)) ?? (() => {}));\n\t\ttry {\n\t\t\tconst start = Date.now();\n\t\t\tconst interrupt = this.options.waits?.interruptSignal;\n\t\t\tawait waitForFirst({\n\t\t\t\thasSettled: () => records.some((record) => record.settled),\n\t\t\t\tsubscribe: (listener) => this.subscribe(listener),\n\t\t\t\ttimeoutMs: options.timeoutMs ?? TASKS_WAIT_DEFAULT_MS,\n\t\t\t\tsignal,\n\t\t\t\tinterrupt,\n\t\t\t\tclosed: this.closing.signal,\n\t\t\t});\n\t\t\tconst waitedMs = Date.now() - start;\n\t\t\tconst settled = records\n\t\t\t\t.filter((record) => record.settled)\n\t\t\t\t.sort((left, right) => (left.task.endedAt ?? 0) - (right.task.endedAt ?? 0))[0];\n\t\t\tconst outcome: TaskWaitOutcome = settled\n\t\t\t\t? \"settled\"\n\t\t\t\t: this.closed\n\t\t\t\t\t? \"closed\"\n\t\t\t\t\t: interrupt?.aborted\n\t\t\t\t\t\t? \"interrupted\"\n\t\t\t\t\t\t: \"timed_out\";\n\t\t\tconst running = records\n\t\t\t\t.filter((record) => record.visible && !record.settled)\n\t\t\t\t.map((record) => record.snapshot());\n\t\t\tconst observed = settled ?? fallback;\n\t\t\tconst read =\n\t\t\t\toptions.read && observed && outcome !== \"interrupted\"\n\t\t\t\t\t? await this.read(observed.task.id, options.read)\n\t\t\t\t\t: undefined;\n\t\t\tsignal?.throwIfAborted();\n\t\t\tif (settled && settled.task.mode === \"background\" && options.toolCallId)\n\t\t\t\tthis.options.waits?.bind(options.toolCallId, settled.task.id);\n\t\t\treturn { outcome, waitedMs, settled, running, read };\n\t\t} finally {\n\t\t\tfor (const release of releases) release();\n\t\t}\n\t}\n\n\tasync wait(id: string, options: TaskWaitOptions = {}): Promise<TaskWaitResult> {\n\t\tif (options.signal?.aborted) throw options.signal.reason ?? new Error(\"Wait aborted\");\n\t\tconst record = this.lookup(id);\n\t\tconst { outcome, waitedMs, read } = await this.observe([record], options, record);\n\t\treturn { outcome, waitedMs, task: record.snapshot(), ...(read ? { read } : {}) };\n\t}\n\n\tasync waitAny(options: TaskWaitAnyOptions = {}): Promise<TaskWaitAnyResult> {\n\t\tif (options.signal?.aborted) throw options.signal.reason ?? new Error(\"Wait aborted\");\n\t\tconst records = this.activeBackground().filter((record) => record.visible);\n\t\tif (records.length === 0) return { outcome: \"no_tasks\", waitedMs: 0, running: [] };\n\t\tconst { outcome, waitedMs, settled, running, read } = await this.observe(records, options);\n\t\treturn {\n\t\t\toutcome,\n\t\t\twaitedMs,\n\t\t\trunning,\n\t\t\t...(settled ? { task: settled.snapshot() } : {}),\n\t\t\t...(read ? { read } : {}),\n\t\t};\n\t}\n\n\tkill(id: string): boolean {\n\t\treturn this.cancel(this.lookup(id));\n\t}\n\n\tprivate cancel(record: TaskRecord): boolean {\n\t\treturn this.executions.get(record.task.id)?.cancel() ?? false;\n\t}\n\n\tsubscribe(listener: () => void): () => void {\n\t\tif (this.closed) return () => {};\n\t\tthis.listeners.add(listener);\n\t\treturn () => {\n\t\t\tthis.listeners.delete(listener);\n\t\t};\n\t}\n\n\t/** Retention protects snapshots and logs only; completion delivery never waits on it. */\n\tretain(id: string): () => void {\n\t\treturn this.pin(this.lookup(id));\n\t}\n\n\tprivate pin(record: TaskRecord): () => void {\n\t\tconst release = record.pin();\n\t\treturn () => {\n\t\t\trelease();\n\t\t\tthis.store.trim();\n\t\t};\n\t}\n\n\tclose(): void {\n\t\tif (this.closed) return;\n\t\tthis._closed = true;\n\t\tthis.listeners.clear();\n\t\tfor (const record of this.store.all()) {\n\t\t\tthis.executions.get(record.task.id)?.releaseParent();\n\t\t\tthis.cancel(record);\n\t\t}\n\t\tthis.closing.abort();\n\t\tthis.options.onClosed?.();\n\t\tthis.store.trim();\n\t}\n\n\tasync shutdown(graceMs = 2000): Promise<void> {\n\t\tthis.close();\n\t\tawait this.drain(this.store.all(), graceMs);\n\t}\n\n\t/** Running tasks whose launch anchor is outside the branch made of `ancestors`. */\n\tactiveOutsideBranch(ancestors: ReadonlySet<string>): TaskSnapshot[] {\n\t\treturn this.store\n\t\t\t.unsettled()\n\t\t\t.filter((record) => record.task.anchorId !== null && !ancestors.has(record.task.anchorId))\n\t\t\t.map((record) => record.snapshot());\n\t}\n\n\t/**\n\t * Hidden results stay pending: returning to their branch delivers them again.\n\t * Restored history is already delivered.\n\t */\n\tasync cancelOutsideBranch(ancestors: ReadonlySet<string>): Promise<void> {\n\t\tconst records = this.store.all();\n\t\tfor (const record of records)\n\t\t\trecord.setVisible(record.task.anchorId === null || ancestors.has(record.task.anchorId));\n\t\tconst outside = records.filter((record) => !record.visible);\n\t\tfor (const record of outside) this.cancel(record);\n\t\tthis.store.trim();\n\t\tthis.emit();\n\t\tawait this.drain(outside, 2000);\n\t}\n\n\tprivate async drain(records: TaskRecord[], graceMs: number): Promise<void> {\n\t\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\t\ttry {\n\t\t\tawait Promise.race([\n\t\t\t\tPromise.all(records.map((record) => this.executions.get(record.task.id)?.done)).then(() =>\n\t\t\t\t\tthis.store.cleanupsDone(),\n\t\t\t\t),\n\t\t\t\tnew Promise<void>((resolve) => {\n\t\t\t\t\ttimer = setTimeout(resolve, finiteLimit(graceMs, 2000, 60_000));\n\t\t\t\t}),\n\t\t\t]);\n\t\t} finally {\n\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t}\n\t}\n\n\tprivate emit(): void {\n\t\tif (this.closed) return;\n\t\tfor (const listener of [...this.listeners]) {\n\t\t\tif (this.closed) break;\n\t\t\ttry {\n\t\t\t\tlistener();\n\t\t\t} catch {\n\t\t\t\t/* Observers do not own execution or delivery. */\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
@@ -1,5 +1,7 @@
1
- /** Per-key concurrency lanes. Executions without a concurrency key start immediately. */
1
+ /** Per-executor concurrency lanes. Executions without a concurrency key start immediately. */
2
2
  export interface Schedulable {
3
+ /** The executor kind, which namespaces its lane keys. */
4
+ readonly kind: string;
3
5
  readonly concurrency?: {
4
6
  key: string;
5
7
  limit: number;
@@ -1 +1 @@
1
- {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../../src/core/tasks/scheduler.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,WAAW,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,KAAK,IAAI,IAAI,CAAC;CACd;AAOD,qBAAa,aAAa;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA2B;IAEjD,QAAQ,CAAC,SAAS,EAAE,WAAW,GAAG,IAAI;IAetC,2FAA2F;IAC3F,OAAO,CAAC,SAAS,EAAE,WAAW,GAAG,IAAI;IAUrC,OAAO,CAAC,IAAI;CASZ"}
1
+ {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../../src/core/tasks/scheduler.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,MAAM,WAAW,WAAW;IAC3B,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,KAAK,IAAI,IAAI,CAAC;CACd;AAYD,qBAAa,aAAa;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA2B;IAEjD,QAAQ,CAAC,SAAS,EAAE,WAAW,GAAG,IAAI;IAetC,2FAA2F;IAC3F,OAAO,CAAC,SAAS,EAAE,WAAW,GAAG,IAAI;IAUrC,OAAO,CAAC,IAAI;CASZ"}
@@ -1,42 +1,46 @@
1
+ /** A lane belongs to one executor kind, so two executors can never collide on a chosen key. */
2
+ function laneId(execution) {
3
+ return execution.concurrency ? `${execution.kind}:${execution.concurrency.key}` : undefined;
4
+ }
1
5
  export class TaskScheduler {
2
6
  constructor() {
3
7
  this.lanes = new Map();
4
8
  }
5
9
  schedule(execution) {
6
- const concurrency = execution.concurrency;
7
- if (!concurrency) {
10
+ const id = laneId(execution);
11
+ if (id === undefined) {
8
12
  execution.start();
9
13
  return;
10
14
  }
11
- let lane = this.lanes.get(concurrency.key);
15
+ let lane = this.lanes.get(id);
12
16
  if (!lane) {
13
17
  lane = { running: new Set(), waiting: [] };
14
- this.lanes.set(concurrency.key, lane);
18
+ this.lanes.set(id, lane);
15
19
  }
16
20
  lane.waiting.push(execution);
17
- this.pump(concurrency.key, lane);
21
+ this.pump(id, lane);
18
22
  }
19
23
  /** A settled execution frees its slot or leaves the queue; the next waiting one starts. */
20
24
  release(execution) {
21
- const key = execution.concurrency?.key;
22
- const lane = key === undefined ? undefined : this.lanes.get(key);
23
- if (!lane || key === undefined)
25
+ const id = laneId(execution);
26
+ const lane = id === undefined ? undefined : this.lanes.get(id);
27
+ if (!lane || id === undefined)
24
28
  return;
25
29
  lane.running.delete(execution);
26
30
  const index = lane.waiting.indexOf(execution);
27
31
  if (index >= 0)
28
32
  lane.waiting.splice(index, 1);
29
- this.pump(key, lane);
33
+ this.pump(id, lane);
30
34
  }
31
- pump(key, lane) {
35
+ pump(id, lane) {
32
36
  // Starting can settle synchronously and re-enter release(); the loop rereads lane state.
33
37
  while (lane.waiting.length > 0 && lane.running.size < lane.waiting[0].concurrency.limit) {
34
38
  const next = lane.waiting.shift();
35
39
  lane.running.add(next);
36
40
  next.start();
37
41
  }
38
- if (lane.running.size === 0 && lane.waiting.length === 0 && this.lanes.get(key) === lane)
39
- this.lanes.delete(key);
42
+ if (lane.running.size === 0 && lane.waiting.length === 0 && this.lanes.get(id) === lane)
43
+ this.lanes.delete(id);
40
44
  }
41
45
  }
42
46
  //# sourceMappingURL=scheduler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../../src/core/tasks/scheduler.ts"],"names":[],"mappings":"AAWA,MAAM,OAAO,aAAa;IAA1B;QACkB,UAAK,GAAG,IAAI,GAAG,EAAgB,CAAC;IAqClD,CAAC;IAnCA,QAAQ,CAAC,SAAsB;QAC9B,MAAM,WAAW,GAAG,SAAS,CAAC,WAAW,CAAC;QAC1C,IAAI,CAAC,WAAW,EAAE,CAAC;YAClB,SAAS,CAAC,KAAK,EAAE,CAAC;YAClB,OAAO;QACR,CAAC;QACD,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAC3C,IAAI,CAAC,IAAI,EAAE,CAAC;YACX,IAAI,GAAG,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;YAC3C,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACvC,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC7B,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAClC,CAAC;IAED,2FAA2F;IAC3F,OAAO,CAAC,SAAsB;QAC7B,MAAM,GAAG,GAAG,SAAS,CAAC,WAAW,EAAE,GAAG,CAAC;QACvC,MAAM,IAAI,GAAG,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACjE,IAAI,CAAC,IAAI,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO;QACvC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC9C,IAAI,KAAK,IAAI,CAAC;YAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAC9C,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACtB,CAAC;IAEO,IAAI,CAAC,GAAW,EAAE,IAAU;QACnC,yFAAyF;QACzF,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC,WAAY,CAAC,KAAK,EAAE,CAAC;YAC3F,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAG,CAAC;YACnC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACvB,IAAI,CAAC,KAAK,EAAE,CAAC;QACd,CAAC;QACD,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI;YAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAClH,CAAC;CACD","sourcesContent":["/** Per-key concurrency lanes. Executions without a concurrency key start immediately. */\nexport interface Schedulable {\n\treadonly concurrency?: { key: string; limit: number };\n\tstart(): void;\n}\n\ninterface Lane {\n\trunning: Set<Schedulable>;\n\twaiting: Schedulable[];\n}\n\nexport class TaskScheduler {\n\tprivate readonly lanes = new Map<string, Lane>();\n\n\tschedule(execution: Schedulable): void {\n\t\tconst concurrency = execution.concurrency;\n\t\tif (!concurrency) {\n\t\t\texecution.start();\n\t\t\treturn;\n\t\t}\n\t\tlet lane = this.lanes.get(concurrency.key);\n\t\tif (!lane) {\n\t\t\tlane = { running: new Set(), waiting: [] };\n\t\t\tthis.lanes.set(concurrency.key, lane);\n\t\t}\n\t\tlane.waiting.push(execution);\n\t\tthis.pump(concurrency.key, lane);\n\t}\n\n\t/** A settled execution frees its slot or leaves the queue; the next waiting one starts. */\n\trelease(execution: Schedulable): void {\n\t\tconst key = execution.concurrency?.key;\n\t\tconst lane = key === undefined ? undefined : this.lanes.get(key);\n\t\tif (!lane || key === undefined) return;\n\t\tlane.running.delete(execution);\n\t\tconst index = lane.waiting.indexOf(execution);\n\t\tif (index >= 0) lane.waiting.splice(index, 1);\n\t\tthis.pump(key, lane);\n\t}\n\n\tprivate pump(key: string, lane: Lane): void {\n\t\t// Starting can settle synchronously and re-enter release(); the loop rereads lane state.\n\t\twhile (lane.waiting.length > 0 && lane.running.size < lane.waiting[0]!.concurrency!.limit) {\n\t\t\tconst next = lane.waiting.shift()!;\n\t\t\tlane.running.add(next);\n\t\t\tnext.start();\n\t\t}\n\t\tif (lane.running.size === 0 && lane.waiting.length === 0 && this.lanes.get(key) === lane) this.lanes.delete(key);\n\t}\n}\n"]}
1
+ {"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../../src/core/tasks/scheduler.ts"],"names":[],"mappings":"AAaA,+FAA+F;AAC/F,SAAS,MAAM,CAAC,SAAsB;IACrC,OAAO,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,IAAI,IAAI,SAAS,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7F,CAAC;AAED,MAAM,OAAO,aAAa;IAA1B;QACkB,UAAK,GAAG,IAAI,GAAG,EAAgB,CAAC;IAqClD,CAAC;IAnCA,QAAQ,CAAC,SAAsB;QAC9B,MAAM,EAAE,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;QAC7B,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;YACtB,SAAS,CAAC,KAAK,EAAE,CAAC;YAClB,OAAO;QACR,CAAC;QACD,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,EAAE,CAAC;YACX,IAAI,GAAG,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;YAC3C,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAC1B,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC7B,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IACrB,CAAC;IAED,2FAA2F;IAC3F,OAAO,CAAC,SAAsB;QAC7B,MAAM,EAAE,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;QAC7B,MAAM,IAAI,GAAG,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC/D,IAAI,CAAC,IAAI,IAAI,EAAE,KAAK,SAAS;YAAE,OAAO;QACtC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC9C,IAAI,KAAK,IAAI,CAAC;YAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAC9C,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IACrB,CAAC;IAEO,IAAI,CAAC,EAAU,EAAE,IAAU;QAClC,yFAAyF;QACzF,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC,WAAY,CAAC,KAAK,EAAE,CAAC;YAC3F,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAG,CAAC;YACnC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACvB,IAAI,CAAC,KAAK,EAAE,CAAC;QACd,CAAC;QACD,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,IAAI;YAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAChH,CAAC;CACD","sourcesContent":["/** Per-executor concurrency lanes. Executions without a concurrency key start immediately. */\nexport interface Schedulable {\n\t/** The executor kind, which namespaces its lane keys. */\n\treadonly kind: string;\n\treadonly concurrency?: { key: string; limit: number };\n\tstart(): void;\n}\n\ninterface Lane {\n\trunning: Set<Schedulable>;\n\twaiting: Schedulable[];\n}\n\n/** A lane belongs to one executor kind, so two executors can never collide on a chosen key. */\nfunction laneId(execution: Schedulable): string | undefined {\n\treturn execution.concurrency ? `${execution.kind}:${execution.concurrency.key}` : undefined;\n}\n\nexport class TaskScheduler {\n\tprivate readonly lanes = new Map<string, Lane>();\n\n\tschedule(execution: Schedulable): void {\n\t\tconst id = laneId(execution);\n\t\tif (id === undefined) {\n\t\t\texecution.start();\n\t\t\treturn;\n\t\t}\n\t\tlet lane = this.lanes.get(id);\n\t\tif (!lane) {\n\t\t\tlane = { running: new Set(), waiting: [] };\n\t\t\tthis.lanes.set(id, lane);\n\t\t}\n\t\tlane.waiting.push(execution);\n\t\tthis.pump(id, lane);\n\t}\n\n\t/** A settled execution frees its slot or leaves the queue; the next waiting one starts. */\n\trelease(execution: Schedulable): void {\n\t\tconst id = laneId(execution);\n\t\tconst lane = id === undefined ? undefined : this.lanes.get(id);\n\t\tif (!lane || id === undefined) return;\n\t\tlane.running.delete(execution);\n\t\tconst index = lane.waiting.indexOf(execution);\n\t\tif (index >= 0) lane.waiting.splice(index, 1);\n\t\tthis.pump(id, lane);\n\t}\n\n\tprivate pump(id: string, lane: Lane): void {\n\t\t// Starting can settle synchronously and re-enter release(); the loop rereads lane state.\n\t\twhile (lane.waiting.length > 0 && lane.running.size < lane.waiting[0]!.concurrency!.limit) {\n\t\t\tconst next = lane.waiting.shift()!;\n\t\t\tlane.running.add(next);\n\t\t\tnext.start();\n\t\t}\n\t\tif (lane.running.size === 0 && lane.waiting.length === 0 && this.lanes.get(id) === lane) this.lanes.delete(id);\n\t}\n}\n"]}