@astralyn/pi 1.4.9 → 1.4.11

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 (230) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/dist/bundle/chunks/{chunk-BAGHIP5J.js → chunk-NUQMVNKQ.js} +3 -3
  3. package/dist/bundle/chunks/{chunk-3PKXUKTB.js → chunk-PUU43PDV.js} +121 -136
  4. package/dist/bundle/chunks/{chunk-F66AY3WR.js → chunk-TH3QDDPD.js} +1 -1
  5. package/dist/bundle/chunks/{execute-P22VMM2H.js → execute-VLAIP26K.js} +1 -1
  6. package/dist/bundle/chunks/{virtual-modules-VKMBQTR2.js → virtual-modules-63XNTSVN.js} +1 -1
  7. package/dist/bundle/cli.js +1 -1
  8. package/dist/bundle/index.js +1 -1
  9. package/dist/bundle/rpc-entry.js +1 -1
  10. package/dist/core/agent-session.d.ts +34 -0
  11. package/dist/core/agent-session.d.ts.map +1 -1
  12. package/dist/core/agent-session.js +99 -5
  13. package/dist/core/agent-session.js.map +1 -1
  14. package/dist/core/extensions/index.d.ts +1 -1
  15. package/dist/core/extensions/index.d.ts.map +1 -1
  16. package/dist/core/extensions/index.js.map +1 -1
  17. package/dist/core/extensions/loader.d.ts.map +1 -1
  18. package/dist/core/extensions/loader.js +14 -7
  19. package/dist/core/extensions/loader.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 +31 -12
  29. package/dist/core/tasks/delivery.d.ts.map +1 -1
  30. package/dist/core/tasks/delivery.js +97 -36
  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 +7 -11
  37. package/dist/core/tasks/limits.d.ts.map +1 -1
  38. package/dist/core/tasks/limits.js +8 -16
  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 +15 -23
  55. package/dist/core/tasks/runtime.d.ts.map +1 -1
  56. package/dist/core/tasks/runtime.js +50 -178
  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 -6
  63. package/dist/core/tasks/session.d.ts.map +1 -1
  64. package/dist/core/tasks/session.js +70 -22
  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 +64 -93
  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/tools/shell-execution.d.ts.map +1 -1
  75. package/dist/core/tools/shell-execution.js +2 -1
  76. package/dist/core/tools/shell-execution.js.map +1 -1
  77. package/dist/core/tools/shell-tool.d.ts.map +1 -1
  78. package/dist/core/tools/shell-tool.js +20 -13
  79. package/dist/core/tools/shell-tool.js.map +1 -1
  80. package/dist/extensions/agent/activity-lines.d.ts +10 -0
  81. package/dist/extensions/agent/activity-lines.d.ts.map +1 -0
  82. package/dist/extensions/agent/activity-lines.js +76 -0
  83. package/dist/extensions/agent/activity-lines.js.map +1 -0
  84. package/dist/extensions/agent/activity.d.ts +25 -4
  85. package/dist/extensions/agent/activity.d.ts.map +1 -1
  86. package/dist/extensions/agent/activity.js +76 -21
  87. package/dist/extensions/agent/activity.js.map +1 -1
  88. package/dist/extensions/agent/artifacts.d.ts +15 -0
  89. package/dist/extensions/agent/artifacts.d.ts.map +1 -0
  90. package/dist/extensions/agent/artifacts.js +44 -0
  91. package/dist/extensions/agent/artifacts.js.map +1 -0
  92. package/dist/extensions/agent/progress.d.ts +30 -4
  93. package/dist/extensions/agent/progress.d.ts.map +1 -1
  94. package/dist/extensions/agent/progress.js +84 -11
  95. package/dist/extensions/agent/progress.js.map +1 -1
  96. package/dist/extensions/agent/render.d.ts.map +1 -1
  97. package/dist/extensions/agent/render.js +8 -24
  98. package/dist/extensions/agent/render.js.map +1 -1
  99. package/dist/extensions/agent/report.d.ts +11 -3
  100. package/dist/extensions/agent/report.d.ts.map +1 -1
  101. package/dist/extensions/agent/report.js +32 -7
  102. package/dist/extensions/agent/report.js.map +1 -1
  103. package/dist/extensions/agent/tool.d.ts.map +1 -1
  104. package/dist/extensions/agent/tool.js +20 -5
  105. package/dist/extensions/agent/tool.js.map +1 -1
  106. package/dist/extensions/agent/types.d.ts +2 -0
  107. package/dist/extensions/agent/types.d.ts.map +1 -1
  108. package/dist/extensions/agent/types.js.map +1 -1
  109. package/dist/extensions/agent/worker.d.ts +7 -0
  110. package/dist/extensions/agent/worker.d.ts.map +1 -1
  111. package/dist/extensions/agent/worker.js +9 -3
  112. package/dist/extensions/agent/worker.js.map +1 -1
  113. package/dist/extensions/cached-compaction/summary.d.ts +1 -1
  114. package/dist/extensions/cached-compaction/summary.d.ts.map +1 -1
  115. package/dist/extensions/cached-compaction/summary.js +13 -16
  116. package/dist/extensions/cached-compaction/summary.js.map +1 -1
  117. package/dist/extensions/search/index.d.ts.map +1 -1
  118. package/dist/extensions/search/index.js +6 -7
  119. package/dist/extensions/search/index.js.map +1 -1
  120. package/dist/extensions/tasks/tool/actions.d.ts +1 -2
  121. package/dist/extensions/tasks/tool/actions.d.ts.map +1 -1
  122. package/dist/extensions/tasks/tool/actions.js +12 -80
  123. package/dist/extensions/tasks/tool/actions.js.map +1 -1
  124. package/dist/extensions/tasks/tool/constants.d.ts +1 -3
  125. package/dist/extensions/tasks/tool/constants.d.ts.map +1 -1
  126. package/dist/extensions/tasks/tool/constants.js +1 -3
  127. package/dist/extensions/tasks/tool/constants.js.map +1 -1
  128. package/dist/extensions/tasks/tool/schema.d.ts +2 -3
  129. package/dist/extensions/tasks/tool/schema.d.ts.map +1 -1
  130. package/dist/extensions/tasks/tool/schema.js +10 -18
  131. package/dist/extensions/tasks/tool/schema.js.map +1 -1
  132. package/dist/extensions/tasks/tool/types.d.ts +1 -17
  133. package/dist/extensions/tasks/tool/types.d.ts.map +1 -1
  134. package/dist/extensions/tasks/tool/types.js.map +1 -1
  135. package/dist/extensions/tasks/tool.d.ts +1 -2
  136. package/dist/extensions/tasks/tool.d.ts.map +1 -1
  137. package/dist/extensions/tasks/tool.js +5 -6
  138. package/dist/extensions/tasks/tool.js.map +1 -1
  139. package/dist/extensions/tasks/ui/completion-render.d.ts.map +1 -1
  140. package/dist/extensions/tasks/ui/completion-render.js +2 -2
  141. package/dist/extensions/tasks/ui/completion-render.js.map +1 -1
  142. package/dist/extensions/tasks/ui/footer.d.ts +37 -0
  143. package/dist/extensions/tasks/ui/footer.d.ts.map +1 -0
  144. package/dist/extensions/tasks/ui/footer.js +129 -0
  145. package/dist/extensions/tasks/ui/footer.js.map +1 -0
  146. package/dist/extensions/tasks/ui/frame.d.ts +36 -0
  147. package/dist/extensions/tasks/ui/frame.d.ts.map +1 -0
  148. package/dist/extensions/tasks/ui/frame.js +33 -0
  149. package/dist/extensions/tasks/ui/frame.js.map +1 -0
  150. package/dist/extensions/tasks/ui/help.d.ts +6 -0
  151. package/dist/extensions/tasks/ui/help.d.ts.map +1 -0
  152. package/dist/extensions/tasks/ui/help.js +53 -0
  153. package/dist/extensions/tasks/ui/help.js.map +1 -0
  154. package/dist/extensions/tasks/ui/inspector.d.ts +4 -3
  155. package/dist/extensions/tasks/ui/inspector.d.ts.map +1 -1
  156. package/dist/extensions/tasks/ui/inspector.js +25 -6
  157. package/dist/extensions/tasks/ui/inspector.js.map +1 -1
  158. package/dist/extensions/tasks/ui/layout.d.ts +15 -18
  159. package/dist/extensions/tasks/ui/layout.d.ts.map +1 -1
  160. package/dist/extensions/tasks/ui/layout.js +162 -255
  161. package/dist/extensions/tasks/ui/layout.js.map +1 -1
  162. package/dist/extensions/tasks/ui/list.d.ts +3 -1
  163. package/dist/extensions/tasks/ui/list.d.ts.map +1 -1
  164. package/dist/extensions/tasks/ui/list.js +19 -14
  165. package/dist/extensions/tasks/ui/list.js.map +1 -1
  166. package/dist/extensions/tasks/ui/manager.d.ts +17 -5
  167. package/dist/extensions/tasks/ui/manager.d.ts.map +1 -1
  168. package/dist/extensions/tasks/ui/manager.js +147 -90
  169. package/dist/extensions/tasks/ui/manager.js.map +1 -1
  170. package/dist/extensions/tasks/ui/model.d.ts +32 -5
  171. package/dist/extensions/tasks/ui/model.d.ts.map +1 -1
  172. package/dist/extensions/tasks/ui/model.js +7 -7
  173. package/dist/extensions/tasks/ui/model.js.map +1 -1
  174. package/dist/extensions/tasks/ui/panes.d.ts +40 -0
  175. package/dist/extensions/tasks/ui/panes.d.ts.map +1 -0
  176. package/dist/extensions/tasks/ui/panes.js +144 -0
  177. package/dist/extensions/tasks/ui/panes.js.map +1 -0
  178. package/dist/extensions/tasks/ui/render.d.ts +2 -16
  179. package/dist/extensions/tasks/ui/render.d.ts.map +1 -1
  180. package/dist/extensions/tasks/ui/render.js +13 -85
  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/index.d.ts +1 -1
  191. package/dist/index.d.ts.map +1 -1
  192. package/dist/index.js.map +1 -1
  193. package/dist/modes/interactive/components/session-selector.d.ts +11 -1
  194. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  195. package/dist/modes/interactive/components/session-selector.js +43 -17
  196. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  197. package/dist/modes/print-mode.d.ts.map +1 -1
  198. package/dist/modes/print-mode.js +38 -2
  199. package/dist/modes/print-mode.js.map +1 -1
  200. package/dist/modes/rpc/rpc-client.d.ts +11 -0
  201. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  202. package/dist/modes/rpc/rpc-client.js +48 -0
  203. package/dist/modes/rpc/rpc-client.js.map +1 -1
  204. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  205. package/dist/modes/rpc/rpc-mode.js +2 -0
  206. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  207. package/dist/modes/rpc/rpc-types.d.ts +2 -0
  208. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  209. package/dist/modes/rpc/rpc-types.js.map +1 -1
  210. package/docs/bundled/extensions/agent.md +39 -7
  211. package/docs/bundled/extensions/statusline.md +1 -1
  212. package/docs/bundled/tasks.md +28 -37
  213. package/docs/bundled/tool-presentation.md +1 -1
  214. package/docs/extensions.md +15 -13
  215. package/docs/json.md +3 -0
  216. package/docs/models-configuration.md +1 -1
  217. package/docs/models.md +7 -85
  218. package/docs/rpc.md +14 -0
  219. package/docs/sdk.md +12 -2
  220. package/docs/session-format.md +11 -5
  221. package/docs/sessions.md +1 -1
  222. package/docs/usage.md +2 -0
  223. package/package.json +3 -4
  224. package/dist/modes/interactive/tool-view/tool-execution.d.ts +0 -14
  225. package/dist/modes/interactive/tool-view/tool-execution.d.ts.map +0 -1
  226. package/dist/modes/interactive/tool-view/tool-execution.js +0 -13
  227. package/dist/modes/interactive/tool-view/tool-execution.js.map +0 -1
  228. package/docs/images/doom-extension.png +0 -0
  229. package/docs/images/exy.png +0 -0
  230. package/npm-shrinkwrap.json +0 -4207
@@ -1,15 +1,19 @@
1
1
  import type { AgentMessage } from "@earendil-works/pi-agent-core";
2
2
  import type { CustomMessage } from "../messages.ts";
3
- import type { TaskDeliveryLedger } from "./types.ts";
3
+ import type { TaskSnapshot, TasksContext } from "./types.ts";
4
+ /** All the delivery policy needs from a runtime: its public, session-independent surface. */
5
+ export type TaskDeliveryService = Pick<TasksContext, "enabled" | "closed" | "list" | "retain">;
4
6
  export interface TaskDeliveryOptions {
5
- service(): TaskDeliveryLedger;
7
+ service(): TaskDeliveryService;
6
8
  canDeliver(): boolean;
7
9
  deliver(message: CustomMessage, waitForPersistence: () => Promise<void>): Promise<void>;
8
10
  warn(event: string, message: string): void;
9
11
  }
10
12
  /**
11
- * Sole owner of delivery policy: pausing, failure tracking, the in-flight completion and wait
12
- * receipts. The runtime only answers per-record questions through TaskDeliveryLedger.
13
+ * Sole owner of "has this completion reached the model": the pending queue, claims, the in-flight
14
+ * completion, failures and pauses. An undelivered completion is
15
+ * a retention lease on its task, so the runtime keeps the record and its output exactly as long
16
+ * as delivery needs them, and a bare runtime carries no delivery concept at all.
13
17
  */
14
18
  export declare class TaskDelivery {
15
19
  private readonly options;
@@ -17,14 +21,36 @@ export declare class TaskDelivery {
17
21
  private pauses;
18
22
  private timer?;
19
23
  private delivery?;
24
+ /** Settlement order. */
25
+ private readonly completions;
20
26
  private readonly failures;
21
- private readonly waits;
27
+ private readonly listeners;
22
28
  constructor(options: TaskDeliveryOptions);
23
29
  private get service();
24
30
  private warn;
31
+ /** Called whenever what `hasDeliverableWork()` reads may have changed. */
32
+ subscribe(listener: () => void): () => void;
33
+ private changed;
34
+ /**
35
+ * Whether a completion is in flight or will be delivered without further input: queued on the
36
+ * current runtime, visible on the branch and not failed. A failed delivery only retries on the
37
+ * next input, so it does not count.
38
+ */
39
+ hasDeliverableWork(): boolean;
25
40
  /** Nestable across asynchronous preflight and service replacement. */
26
41
  pause(): () => void;
27
42
  retry(): void;
43
+ /** A handed-off task settled on `service`; it awaits automatic delivery under a retention lease. */
44
+ enqueue(service: TaskDeliveryService, taskId: string): void;
45
+ /** The model has the result (or the host consumed it): stop waiting to deliver and release the lease. */
46
+ acknowledge(taskId: string): void;
47
+ /** Release every lease held for a runtime that closed or was replaced, so its output cleanup can run. */
48
+ discard(service: TaskDeliveryService): void;
49
+ /**
50
+ * Completions that would be delivered next, oldest launch first: on the visible branch and not
51
+ * claimed. Failed deliveries stay listed until the next retry.
52
+ */
53
+ pending(): TaskSnapshot[];
28
54
  schedule(): void;
29
55
  private canDeliver;
30
56
  private drain;
@@ -35,13 +61,6 @@ export declare class TaskDelivery {
35
61
  queueCleared(): void;
36
62
  /** Acknowledge only successful appends, using identity even when metadata was rewritten. */
37
63
  messagePersisted(message: AgentMessage): void;
38
- /**
39
- * A wait observed a settled background task. The runtime still holds it; take over that hold
40
- * until the wait's tool result is persisted, then acknowledge it instead of notifying.
41
- */
42
- bindWait(service: TaskDeliveryLedger, toolCallId: string, taskId: string): void;
43
- private acknowledgeWait;
44
- private releaseWaits;
45
64
  dispose(): void;
46
65
  }
47
66
  //# sourceMappingURL=delivery.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"delivery.d.ts","sourceRoot":"","sources":["../../../src/core/tasks/delivery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,MAAM,WAAW,mBAAmB;IACnC,OAAO,IAAI,kBAAkB,CAAC;IAC9B,UAAU,IAAI,OAAO,CAAC;IACtB,OAAO,CAAC,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxF,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3C;AAUD;;;GAGG;AACH,qBAAa,YAAY;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,KAAK,CAAC,CAAgC;IAC9C,OAAO,CAAC,QAAQ,CAAC,CAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuF;gBACjG,OAAO,EAAE,mBAAmB;IAGxC,OAAO,KAAK,OAAO,GAElB;IACD,OAAO,CAAC,IAAI;IAGZ,sEAAsE;IACtE,KAAK,IAAI,MAAM,IAAI;IAWnB,KAAK,IAAI,IAAI;IAKb,QAAQ,IAAI,IAAI;IAWhB,OAAO,CAAC,UAAU;YAMJ,KAAK;IAiDnB,mFAAmF;IACnF,cAAc,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAK3C,gFAAgF;IAChF,UAAU,IAAI,IAAI;IAQlB,YAAY,IAAI,IAAI;IAIpB,4FAA4F;IAC5F,gBAAgB,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAU7C;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAK/E,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,YAAY;IAKpB,OAAO,IAAI,IAAI;CAOf"}
1
+ {"version":3,"file":"delivery.d.ts","sourceRoot":"","sources":["../../../src/core/tasks/delivery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE7D,6FAA6F;AAC7F,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,YAAY,EAAE,SAAS,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC,CAAC;AAE/F,MAAM,WAAW,mBAAmB;IACnC,OAAO,IAAI,mBAAmB,CAAC;IAC/B,UAAU,IAAI,OAAO,CAAC;IACtB,OAAO,CAAC,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxF,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3C;AAmBD;;;;;GAKG;AACH,qBAAa,YAAY;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,KAAK,CAAC,CAAgC;IAC9C,OAAO,CAAC,QAAQ,CAAC,CAAW;IAC5B,wBAAwB;IACxB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAiC;IAC7D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyB;gBACvC,OAAO,EAAE,mBAAmB;IAGxC,OAAO,KAAK,OAAO,GAElB;IACD,OAAO,CAAC,IAAI;IAGZ,0EAA0E;IAC1E,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAO3C,OAAO,CAAC,OAAO;IAUf;;;;OAIG;IACH,kBAAkB,IAAI,OAAO;IAY7B,sEAAsE;IACtE,KAAK,IAAI,MAAM,IAAI;IAWnB,KAAK,IAAI,IAAI;IAMb,oGAAoG;IACpG,OAAO,CAAC,OAAO,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAO3D,yGAAyG;IACzG,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAQjC,yGAAyG;IACzG,OAAO,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI;IAS3C;;;OAGG;IACH,OAAO,IAAI,YAAY,EAAE;IASzB,QAAQ,IAAI,IAAI;IAWhB,OAAO,CAAC,UAAU;YAMJ,KAAK;IAiDnB,mFAAmF;IACnF,cAAc,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAK3C,gFAAgF;IAChF,UAAU,IAAI,IAAI;IAOlB,YAAY,IAAI,IAAI;IAIpB,4FAA4F;IAC5F,gBAAgB,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAS7C,OAAO,IAAI,IAAI;CAUf"}
@@ -1,14 +1,18 @@
1
1
  import { taskCompletionMessage } from "./presentation.js";
2
2
  /**
3
- * Sole owner of delivery policy: pausing, failure tracking, the in-flight completion and wait
4
- * receipts. The runtime only answers per-record questions through TaskDeliveryLedger.
3
+ * Sole owner of "has this completion reached the model": the pending queue, claims, the in-flight
4
+ * completion, failures and pauses. An undelivered completion is
5
+ * a retention lease on its task, so the runtime keeps the record and its output exactly as long
6
+ * as delivery needs them, and a bare runtime carries no delivery concept at all.
5
7
  */
6
8
  export class TaskDelivery {
7
9
  constructor(options) {
8
10
  this.disposed = false;
9
11
  this.pauses = 0;
12
+ /** Settlement order. */
13
+ this.completions = new Map();
10
14
  this.failures = new Set();
11
- this.waits = new Map();
15
+ this.listeners = new Set();
12
16
  this.options = options;
13
17
  }
14
18
  get service() {
@@ -17,6 +21,43 @@ export class TaskDelivery {
17
21
  warn(event, message) {
18
22
  this.options.warn(event, message);
19
23
  }
24
+ /** Called whenever what `hasDeliverableWork()` reads may have changed. */
25
+ subscribe(listener) {
26
+ this.listeners.add(listener);
27
+ return () => {
28
+ this.listeners.delete(listener);
29
+ };
30
+ }
31
+ changed() {
32
+ for (const listener of [...this.listeners]) {
33
+ try {
34
+ listener();
35
+ }
36
+ catch {
37
+ // Observers cannot interrupt delivery.
38
+ }
39
+ }
40
+ }
41
+ /**
42
+ * Whether a completion is in flight or will be delivered without further input: queued on the
43
+ * current runtime, visible on the branch and not failed. A failed delivery only retries on the
44
+ * next input, so it does not count.
45
+ */
46
+ hasDeliverableWork() {
47
+ if (this.disposed)
48
+ return false;
49
+ const service = this.service;
50
+ if (service.closed)
51
+ return false;
52
+ if (this.delivery)
53
+ return true;
54
+ if (!service.enabled || this.completions.size === 0)
55
+ return false;
56
+ return service.list().some((task) => {
57
+ const completion = this.completions.get(task.id);
58
+ return completion?.service === service && !this.failures.has(task.id);
59
+ });
60
+ }
20
61
  /** Nestable across asynchronous preflight and service replacement. */
21
62
  pause() {
22
63
  this.pauses++;
@@ -32,6 +73,47 @@ export class TaskDelivery {
32
73
  retry() {
33
74
  this.failures.clear();
34
75
  this.schedule();
76
+ this.changed();
77
+ }
78
+ /** A handed-off task settled on `service`; it awaits automatic delivery under a retention lease. */
79
+ enqueue(service, taskId) {
80
+ if (this.disposed || service.closed || this.completions.has(taskId))
81
+ return;
82
+ this.completions.set(taskId, { service, release: service.retain(taskId), claimed: false });
83
+ this.schedule();
84
+ this.changed();
85
+ }
86
+ /** The model has the result (or the host consumed it): stop waiting to deliver and release the lease. */
87
+ acknowledge(taskId) {
88
+ const completion = this.completions.get(taskId);
89
+ if (!completion)
90
+ return;
91
+ this.completions.delete(taskId);
92
+ completion.release();
93
+ this.changed();
94
+ }
95
+ /** Release every lease held for a runtime that closed or was replaced, so its output cleanup can run. */
96
+ discard(service) {
97
+ for (const [id, completion] of [...this.completions]) {
98
+ if (completion.service !== service)
99
+ continue;
100
+ this.completions.delete(id);
101
+ completion.release();
102
+ }
103
+ this.changed();
104
+ }
105
+ /**
106
+ * Completions that would be delivered next, oldest launch first: on the visible branch and not
107
+ * claimed. Failed deliveries stay listed until the next retry.
108
+ */
109
+ pending() {
110
+ const service = this.service;
111
+ if (service.closed)
112
+ return [];
113
+ return service.list().filter((task) => {
114
+ const completion = this.completions.get(task.id);
115
+ return completion?.service === service && !completion.claimed;
116
+ });
35
117
  }
36
118
  schedule() {
37
119
  if (this.disposed || this.timer || this.delivery)
@@ -55,17 +137,16 @@ export class TaskDelivery {
55
137
  if (!retained.has(id))
56
138
  this.failures.delete(id);
57
139
  }
58
- const task = service.pendingNotifications().find((task) => !this.failures.has(task.id));
140
+ const task = this.pending().find((task) => !this.failures.has(task.id));
59
141
  if (!task)
60
142
  return;
143
+ const completion = this.completions.get(task.id);
61
144
  const message = taskCompletionMessage(task);
62
- if (!service.claimNotification(task.id))
63
- return;
145
+ completion.claimed = true;
64
146
  // Exactly one completion may be in flight, whether queued for steering or running its
65
147
  // own turn; there is no separate claim registry.
66
148
  const delivery = {
67
149
  id: task.id,
68
- service,
69
150
  message,
70
151
  phase: "pending",
71
152
  };
@@ -84,16 +165,16 @@ export class TaskDelivery {
84
165
  }
85
166
  finally {
86
167
  if (delivery.phase !== "persisted") {
87
- service.releaseNotification(task.id);
168
+ completion.claimed = false;
88
169
  if (service === this.service)
89
170
  this.failures.add(task.id);
90
171
  const reason = deliveryError instanceof Error ? `: ${deliveryError.message}` : "";
91
172
  this.warn("task_delivery", `Background completion delivery failed for ${task.id}${reason}; it will retry on the next input.`);
92
173
  }
93
174
  this.delivery = undefined;
94
- const current = this.service;
95
- if (this.canDeliver(current) && current.pendingNotifications().some((task) => !this.failures.has(task.id)))
175
+ if (this.canDeliver(this.service) && this.pending().some((task) => !this.failures.has(task.id)))
96
176
  this.schedule();
177
+ this.changed();
97
178
  }
98
179
  }
99
180
  /** Record dequeueing before message hooks can fail or rewrite the notification. */
@@ -104,7 +185,6 @@ export class TaskDelivery {
104
185
  }
105
186
  /** A queued message that was never emitted remains claimed for the next run. */
106
187
  agentEnded() {
107
- this.releaseWaits();
108
188
  const delivery = this.delivery;
109
189
  if (delivery?.phase === "started") {
110
190
  delivery.queued?.reject(new Error("the completion message was not persisted"));
@@ -118,40 +198,21 @@ export class TaskDelivery {
118
198
  const delivery = this.delivery;
119
199
  if (delivery?.message === message && delivery.phase !== "persisted") {
120
200
  delivery.phase = "persisted";
121
- delivery.service.markDelivered(delivery.id);
201
+ this.acknowledge(delivery.id);
122
202
  delivery.queued?.resolve();
123
203
  }
124
- if (message.role === "toolResult")
125
- this.acknowledgeWait(message.toolCallId);
126
- }
127
- /**
128
- * A wait observed a settled background task. The runtime still holds it; take over that hold
129
- * until the wait's tool result is persisted, then acknowledge it instead of notifying.
130
- */
131
- bindWait(service, toolCallId, taskId) {
132
- this.waits.get(toolCallId)?.release();
133
- this.waits.set(toolCallId, { service, taskId, release: service.holdDelivery(taskId) });
134
- }
135
- acknowledgeWait(toolCallId) {
136
- const receipt = this.waits.get(toolCallId);
137
- if (!receipt)
138
- return;
139
- this.waits.delete(toolCallId);
140
- receipt.service.markDelivered(receipt.taskId);
141
- receipt.release();
142
- }
143
- releaseWaits() {
144
- for (const receipt of this.waits.values())
145
- receipt.release();
146
- this.waits.clear();
147
204
  }
148
205
  dispose() {
149
206
  this.disposed = true;
150
- this.releaseWaits();
207
+ for (const completion of this.completions.values())
208
+ completion.release();
209
+ this.completions.clear();
151
210
  this.delivery?.queued?.reject(new Error("the session was disposed"));
152
211
  if (this.timer)
153
212
  clearTimeout(this.timer);
154
213
  this.timer = undefined;
214
+ this.changed();
215
+ this.listeners.clear();
155
216
  }
156
217
  }
157
218
  //# sourceMappingURL=delivery.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"delivery.js","sourceRoot":"","sources":["../../../src/core/tasks/delivery.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport type { CustomMessage } from \"../messages.ts\";\nimport { taskCompletionMessage } from \"./presentation.ts\";\nimport type { TaskDeliveryLedger } from \"./types.ts\";\n\nexport interface TaskDeliveryOptions {\n\tservice(): TaskDeliveryLedger;\n\tcanDeliver(): boolean;\n\tdeliver(message: CustomMessage, waitForPersistence: () => Promise<void>): Promise<void>;\n\twarn(event: string, message: string): void;\n}\ninterface Delivery {\n\tid: string;\n\tservice: TaskDeliveryLedger;\n\t/** Agent-core preserves message identity; extension rewrites mutate it in place. */\n\tmessage: CustomMessage;\n\tphase: \"pending\" | \"started\" | \"persisted\";\n\tqueued?: { resolve(): void; reject(reason: Error): void };\n}\n\n/**\n * Sole owner of delivery policy: pausing, failure tracking, the in-flight completion and wait\n * receipts. The runtime only answers per-record questions through TaskDeliveryLedger.\n */\nexport class TaskDelivery {\n\tprivate readonly options: TaskDeliveryOptions;\n\tprivate disposed = false;\n\tprivate pauses = 0;\n\tprivate timer?: ReturnType<typeof setTimeout>;\n\tprivate delivery?: Delivery;\n\tprivate readonly failures = new Set<string>();\n\tprivate readonly waits = new Map<string, { service: TaskDeliveryLedger; taskId: string; release(): void }>();\n\tconstructor(options: TaskDeliveryOptions) {\n\t\tthis.options = options;\n\t}\n\tprivate get service(): TaskDeliveryLedger {\n\t\treturn this.options.service();\n\t}\n\tprivate warn(event: string, message: string): void {\n\t\tthis.options.warn(event, message);\n\t}\n\t/** Nestable across asynchronous preflight and service replacement. */\n\tpause(): () => void {\n\t\tthis.pauses++;\n\t\tlet released = false;\n\t\treturn () => {\n\t\t\tif (released) return;\n\t\t\treleased = true;\n\t\t\tthis.pauses--;\n\t\t\tthis.schedule();\n\t\t};\n\t}\n\n\tretry(): void {\n\t\tthis.failures.clear();\n\t\tthis.schedule();\n\t}\n\n\tschedule(): void {\n\t\tif (this.disposed || this.timer || this.delivery) return;\n\t\tthis.timer = setTimeout(() => {\n\t\t\tthis.timer = undefined;\n\t\t\tvoid this.drain().catch(() =>\n\t\t\t\tthis.warn(\"task_delivery\", \"Background notification drain failed; delivery was not confirmed.\"),\n\t\t\t);\n\t\t}, 0);\n\t\tthis.timer.unref?.();\n\t}\n\n\tprivate canDeliver(service: TaskDeliveryLedger): boolean {\n\t\treturn (\n\t\t\t!this.disposed && service === this.service && service.enabled && this.pauses === 0 && this.options.canDeliver()\n\t\t);\n\t}\n\n\tprivate async drain(): Promise<void> {\n\t\tconst service = this.service;\n\t\tif (this.delivery || !this.canDeliver(service)) return;\n\t\tif (this.failures.size) {\n\t\t\tconst retained = new Set(service.list().map((task) => task.id));\n\t\t\tfor (const id of this.failures) if (!retained.has(id)) this.failures.delete(id);\n\t\t}\n\t\tconst task = service.pendingNotifications().find((task) => !this.failures.has(task.id));\n\t\tif (!task) return;\n\t\tconst message = taskCompletionMessage(task);\n\t\tif (!service.claimNotification(task.id)) return;\n\t\t// Exactly one completion may be in flight, whether queued for steering or running its\n\t\t// own turn; there is no separate claim registry.\n\t\tconst delivery: Delivery = {\n\t\t\tid: task.id,\n\t\t\tservice,\n\t\t\tmessage,\n\t\t\tphase: \"pending\",\n\t\t};\n\t\tthis.delivery = delivery;\n\t\tlet deliveryError: unknown;\n\t\ttry {\n\t\t\tawait this.options.deliver(\n\t\t\t\tdelivery.message,\n\t\t\t\t() =>\n\t\t\t\t\tnew Promise<void>((resolve, reject) => {\n\t\t\t\t\t\tif (delivery.phase === \"persisted\") resolve();\n\t\t\t\t\t\telse delivery.queued = { resolve, reject };\n\t\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tdeliveryError = error;\n\t\t} finally {\n\t\t\tif (delivery.phase !== \"persisted\") {\n\t\t\t\tservice.releaseNotification(task.id);\n\t\t\t\tif (service === this.service) this.failures.add(task.id);\n\t\t\t\tconst reason = deliveryError instanceof Error ? `: ${deliveryError.message}` : \"\";\n\t\t\t\tthis.warn(\n\t\t\t\t\t\"task_delivery\",\n\t\t\t\t\t`Background completion delivery failed for ${task.id}${reason}; it will retry on the next input.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.delivery = undefined;\n\t\t\tconst current = this.service;\n\t\t\tif (this.canDeliver(current) && current.pendingNotifications().some((task) => !this.failures.has(task.id)))\n\t\t\t\tthis.schedule();\n\t\t}\n\t}\n\n\t/** Record dequeueing before message hooks can fail or rewrite the notification. */\n\tmessageStarted(message: AgentMessage): void {\n\t\tconst delivery = this.delivery;\n\t\tif (delivery?.message === message && delivery.phase === \"pending\") delivery.phase = \"started\";\n\t}\n\n\t/** A queued message that was never emitted remains claimed for the next run. */\n\tagentEnded(): void {\n\t\tthis.releaseWaits();\n\t\tconst delivery = this.delivery;\n\t\tif (delivery?.phase === \"started\") {\n\t\t\tdelivery.queued?.reject(new Error(\"the completion message was not persisted\"));\n\t\t}\n\t}\n\n\tqueueCleared(): void {\n\t\tthis.delivery?.queued?.reject(new Error(\"the completion message was dequeued before delivery\"));\n\t}\n\n\t/** Acknowledge only successful appends, using identity even when metadata was rewritten. */\n\tmessagePersisted(message: AgentMessage): void {\n\t\tconst delivery = this.delivery;\n\t\tif (delivery?.message === message && delivery.phase !== \"persisted\") {\n\t\t\tdelivery.phase = \"persisted\";\n\t\t\tdelivery.service.markDelivered(delivery.id);\n\t\t\tdelivery.queued?.resolve();\n\t\t}\n\t\tif (message.role === \"toolResult\") this.acknowledgeWait(message.toolCallId);\n\t}\n\n\t/**\n\t * A wait observed a settled background task. The runtime still holds it; take over that hold\n\t * until the wait's tool result is persisted, then acknowledge it instead of notifying.\n\t */\n\tbindWait(service: TaskDeliveryLedger, toolCallId: string, taskId: string): void {\n\t\tthis.waits.get(toolCallId)?.release();\n\t\tthis.waits.set(toolCallId, { service, taskId, release: service.holdDelivery(taskId) });\n\t}\n\n\tprivate acknowledgeWait(toolCallId: string): void {\n\t\tconst receipt = this.waits.get(toolCallId);\n\t\tif (!receipt) return;\n\t\tthis.waits.delete(toolCallId);\n\t\treceipt.service.markDelivered(receipt.taskId);\n\t\treceipt.release();\n\t}\n\n\tprivate releaseWaits(): void {\n\t\tfor (const receipt of this.waits.values()) receipt.release();\n\t\tthis.waits.clear();\n\t}\n\n\tdispose(): void {\n\t\tthis.disposed = true;\n\t\tthis.releaseWaits();\n\t\tthis.delivery?.queued?.reject(new Error(\"the session was disposed\"));\n\t\tif (this.timer) clearTimeout(this.timer);\n\t\tthis.timer = undefined;\n\t}\n}\n"]}
1
+ {"version":3,"file":"delivery.js","sourceRoot":"","sources":["../../../src/core/tasks/delivery.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport type { CustomMessage } from \"../messages.ts\";\nimport { taskCompletionMessage } from \"./presentation.ts\";\nimport type { TaskSnapshot, TasksContext } from \"./types.ts\";\n\n/** All the delivery policy needs from a runtime: its public, session-independent surface. */\nexport type TaskDeliveryService = Pick<TasksContext, \"enabled\" | \"closed\" | \"list\" | \"retain\">;\n\nexport interface TaskDeliveryOptions {\n\tservice(): TaskDeliveryService;\n\tcanDeliver(): boolean;\n\tdeliver(message: CustomMessage, waitForPersistence: () => Promise<void>): Promise<void>;\n\twarn(event: string, message: string): void;\n}\n\n/** A settled handoff the model has not yet seen, kept retained by a lease until it has. */\ninterface Completion {\n\tservice: TaskDeliveryService;\n\t/** The retention lease: the record and its output stay available until delivery or acknowledgement. */\n\trelease(): void;\n\t/** Handed to the host and awaiting persistence. */\n\tclaimed: boolean;\n}\n\ninterface Delivery {\n\tid: string;\n\t/** Agent-core preserves message identity; extension rewrites mutate it in place. */\n\tmessage: CustomMessage;\n\tphase: \"pending\" | \"started\" | \"persisted\";\n\tqueued?: { resolve(): void; reject(reason: Error): void };\n}\n\n/**\n * Sole owner of \"has this completion reached the model\": the pending queue, claims, the in-flight\n * completion, failures and pauses. An undelivered completion is\n * a retention lease on its task, so the runtime keeps the record and its output exactly as long\n * as delivery needs them, and a bare runtime carries no delivery concept at all.\n */\nexport class TaskDelivery {\n\tprivate readonly options: TaskDeliveryOptions;\n\tprivate disposed = false;\n\tprivate pauses = 0;\n\tprivate timer?: ReturnType<typeof setTimeout>;\n\tprivate delivery?: Delivery;\n\t/** Settlement order. */\n\tprivate readonly completions = new Map<string, Completion>();\n\tprivate readonly failures = new Set<string>();\n\tprivate readonly listeners = new Set<() => void>();\n\tconstructor(options: TaskDeliveryOptions) {\n\t\tthis.options = options;\n\t}\n\tprivate get service(): TaskDeliveryService {\n\t\treturn this.options.service();\n\t}\n\tprivate warn(event: string, message: string): void {\n\t\tthis.options.warn(event, message);\n\t}\n\t/** Called whenever what `hasDeliverableWork()` reads may have changed. */\n\tsubscribe(listener: () => void): () => void {\n\t\tthis.listeners.add(listener);\n\t\treturn () => {\n\t\t\tthis.listeners.delete(listener);\n\t\t};\n\t}\n\n\tprivate changed(): void {\n\t\tfor (const listener of [...this.listeners]) {\n\t\t\ttry {\n\t\t\t\tlistener();\n\t\t\t} catch {\n\t\t\t\t// Observers cannot interrupt delivery.\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Whether a completion is in flight or will be delivered without further input: queued on the\n\t * current runtime, visible on the branch and not failed. A failed delivery only retries on the\n\t * next input, so it does not count.\n\t */\n\thasDeliverableWork(): boolean {\n\t\tif (this.disposed) return false;\n\t\tconst service = this.service;\n\t\tif (service.closed) return false;\n\t\tif (this.delivery) return true;\n\t\tif (!service.enabled || this.completions.size === 0) return false;\n\t\treturn service.list().some((task) => {\n\t\t\tconst completion = this.completions.get(task.id);\n\t\t\treturn completion?.service === service && !this.failures.has(task.id);\n\t\t});\n\t}\n\n\t/** Nestable across asynchronous preflight and service replacement. */\n\tpause(): () => void {\n\t\tthis.pauses++;\n\t\tlet released = false;\n\t\treturn () => {\n\t\t\tif (released) return;\n\t\t\treleased = true;\n\t\t\tthis.pauses--;\n\t\t\tthis.schedule();\n\t\t};\n\t}\n\n\tretry(): void {\n\t\tthis.failures.clear();\n\t\tthis.schedule();\n\t\tthis.changed();\n\t}\n\n\t/** A handed-off task settled on `service`; it awaits automatic delivery under a retention lease. */\n\tenqueue(service: TaskDeliveryService, taskId: string): void {\n\t\tif (this.disposed || service.closed || this.completions.has(taskId)) return;\n\t\tthis.completions.set(taskId, { service, release: service.retain(taskId), claimed: false });\n\t\tthis.schedule();\n\t\tthis.changed();\n\t}\n\n\t/** The model has the result (or the host consumed it): stop waiting to deliver and release the lease. */\n\tacknowledge(taskId: string): void {\n\t\tconst completion = this.completions.get(taskId);\n\t\tif (!completion) return;\n\t\tthis.completions.delete(taskId);\n\t\tcompletion.release();\n\t\tthis.changed();\n\t}\n\n\t/** Release every lease held for a runtime that closed or was replaced, so its output cleanup can run. */\n\tdiscard(service: TaskDeliveryService): void {\n\t\tfor (const [id, completion] of [...this.completions]) {\n\t\t\tif (completion.service !== service) continue;\n\t\t\tthis.completions.delete(id);\n\t\t\tcompletion.release();\n\t\t}\n\t\tthis.changed();\n\t}\n\n\t/**\n\t * Completions that would be delivered next, oldest launch first: on the visible branch and not\n\t * claimed. Failed deliveries stay listed until the next retry.\n\t */\n\tpending(): TaskSnapshot[] {\n\t\tconst service = this.service;\n\t\tif (service.closed) return [];\n\t\treturn service.list().filter((task) => {\n\t\t\tconst completion = this.completions.get(task.id);\n\t\t\treturn completion?.service === service && !completion.claimed;\n\t\t});\n\t}\n\n\tschedule(): void {\n\t\tif (this.disposed || this.timer || this.delivery) return;\n\t\tthis.timer = setTimeout(() => {\n\t\t\tthis.timer = undefined;\n\t\t\tvoid this.drain().catch(() =>\n\t\t\t\tthis.warn(\"task_delivery\", \"Background notification drain failed; delivery was not confirmed.\"),\n\t\t\t);\n\t\t}, 0);\n\t\tthis.timer.unref?.();\n\t}\n\n\tprivate canDeliver(service: TaskDeliveryService): boolean {\n\t\treturn (\n\t\t\t!this.disposed && service === this.service && service.enabled && this.pauses === 0 && this.options.canDeliver()\n\t\t);\n\t}\n\n\tprivate async drain(): Promise<void> {\n\t\tconst service = this.service;\n\t\tif (this.delivery || !this.canDeliver(service)) return;\n\t\tif (this.failures.size) {\n\t\t\tconst retained = new Set(service.list().map((task) => task.id));\n\t\t\tfor (const id of this.failures) if (!retained.has(id)) this.failures.delete(id);\n\t\t}\n\t\tconst task = this.pending().find((task) => !this.failures.has(task.id));\n\t\tif (!task) return;\n\t\tconst completion = this.completions.get(task.id)!;\n\t\tconst message = taskCompletionMessage(task);\n\t\tcompletion.claimed = true;\n\t\t// Exactly one completion may be in flight, whether queued for steering or running its\n\t\t// own turn; there is no separate claim registry.\n\t\tconst delivery: Delivery = {\n\t\t\tid: task.id,\n\t\t\tmessage,\n\t\t\tphase: \"pending\",\n\t\t};\n\t\tthis.delivery = delivery;\n\t\tlet deliveryError: unknown;\n\t\ttry {\n\t\t\tawait this.options.deliver(\n\t\t\t\tdelivery.message,\n\t\t\t\t() =>\n\t\t\t\t\tnew Promise<void>((resolve, reject) => {\n\t\t\t\t\t\tif (delivery.phase === \"persisted\") resolve();\n\t\t\t\t\t\telse delivery.queued = { resolve, reject };\n\t\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tdeliveryError = error;\n\t\t} finally {\n\t\t\tif (delivery.phase !== \"persisted\") {\n\t\t\t\tcompletion.claimed = false;\n\t\t\t\tif (service === this.service) this.failures.add(task.id);\n\t\t\t\tconst reason = deliveryError instanceof Error ? `: ${deliveryError.message}` : \"\";\n\t\t\t\tthis.warn(\n\t\t\t\t\t\"task_delivery\",\n\t\t\t\t\t`Background completion delivery failed for ${task.id}${reason}; it will retry on the next input.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.delivery = undefined;\n\t\t\tif (this.canDeliver(this.service) && this.pending().some((task) => !this.failures.has(task.id)))\n\t\t\t\tthis.schedule();\n\t\t\tthis.changed();\n\t\t}\n\t}\n\n\t/** Record dequeueing before message hooks can fail or rewrite the notification. */\n\tmessageStarted(message: AgentMessage): void {\n\t\tconst delivery = this.delivery;\n\t\tif (delivery?.message === message && delivery.phase === \"pending\") delivery.phase = \"started\";\n\t}\n\n\t/** A queued message that was never emitted remains claimed for the next run. */\n\tagentEnded(): void {\n\t\tconst delivery = this.delivery;\n\t\tif (delivery?.phase === \"started\") {\n\t\t\tdelivery.queued?.reject(new Error(\"the completion message was not persisted\"));\n\t\t}\n\t}\n\n\tqueueCleared(): void {\n\t\tthis.delivery?.queued?.reject(new Error(\"the completion message was dequeued before delivery\"));\n\t}\n\n\t/** Acknowledge only successful appends, using identity even when metadata was rewritten. */\n\tmessagePersisted(message: AgentMessage): void {\n\t\tconst delivery = this.delivery;\n\t\tif (delivery?.message === message && delivery.phase !== \"persisted\") {\n\t\t\tdelivery.phase = \"persisted\";\n\t\t\tthis.acknowledge(delivery.id);\n\t\t\tdelivery.queued?.resolve();\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tthis.disposed = true;\n\t\tfor (const completion of this.completions.values()) completion.release();\n\t\tthis.completions.clear();\n\t\tthis.delivery?.queued?.reject(new Error(\"the session was disposed\"));\n\t\tif (this.timer) clearTimeout(this.timer);\n\t\tthis.timer = undefined;\n\t\tthis.changed();\n\t\tthis.listeners.clear();\n\t}\n}\n"]}
@@ -14,10 +14,13 @@ export interface ExecutionHost {
14
14
  * One live task: its caller, controller, parent link and executor callbacks.
15
15
  *
16
16
  * A caller may be handed off to the background whenever no executor preflight is in
17
- * progress: before `run` starts (queued) or after the executor calls `accept()`.
17
+ * progress: before `run` starts (queued) or after the executor calls `accept()`. A release
18
+ * requested during preflight waits for `accept()`; if the run settles first, the caller is
19
+ * answered inline and the task never becomes background.
18
20
  */
19
21
  export declare class Execution<T> {
20
22
  readonly record: TaskRecord;
23
+ readonly kind: string;
21
24
  readonly concurrency?: {
22
25
  key: string;
23
26
  limit: number;
@@ -31,39 +34,49 @@ export declare class Execution<T> {
31
34
  private readonly modeListeners;
32
35
  private resolveCaller;
33
36
  private rejectCaller;
34
- private resolveDone;
35
37
  private onUpdate?;
36
38
  private releaseParentSignal;
37
39
  private usage?;
38
- private started;
39
- private accepted;
40
- private handedOff;
41
- private detachRequested;
40
+ private phase;
41
+ private placement;
42
+ private readonly reason;
42
43
  /** The executor's `run` promise once started. */
43
44
  private running?;
44
45
  constructor(host: ExecutionHost, record: TaskRecord, execution: TaskExecution<T>);
45
46
  get task(): Readonly<TaskSnapshot>;
46
47
  get aborted(): boolean;
47
- /** Executor preflight never races a handoff; queued work has not begun any. */
48
- private get handoffAllowed();
49
48
  /** Waiting for a concurrency slot: registered, but `run` has not started. */
50
49
  get queued(): boolean;
50
+ /** Holds a background slot: handed off, or asked to be and waiting for the executor to accept. */
51
+ get holdsBackgroundSlot(): boolean;
51
52
  get detachable(): boolean;
52
53
  /** Stop forwarding to the launching tool call: parent cancellation and progress no longer reach it. */
53
54
  releaseParent(): void;
54
55
  start(): void;
55
- handoff(): void;
56
- requestDetach(): void;
57
- completeDetach(): void;
56
+ /** Queued background work returns at once; started work is released at its own `accept()`. */
57
+ handOffIfQueued(): void;
58
+ /**
59
+ * Ask to move the caller to the background. The placement changes now; the returned
60
+ * notification is for the caller of a batch to run after every placement has changed, so no
61
+ * listener ever observes a half-moved set.
62
+ */
63
+ detach(): () => void;
58
64
  cancel(): boolean;
59
65
  private onModeChange;
60
66
  private accept;
61
67
  /**
62
- * Hand off unless `run` has already settled. A reaction on an already settled promise is
63
- * queued at once, ahead of the pending-check below whatever the promise's chain depth, so
64
- * the outcome never depends on how `start()` chains its own handlers.
68
+ * Hand off unless `run` has already settled. This observes the `run` promise's own settlement,
69
+ * not the phase `finish()` sets: a reaction on an already settled promise is queued at once,
70
+ * ahead of the pending-check below whatever the promise's chain depth, so the outcome never
71
+ * depends on how many hops `start()` chains before `finish()`.
65
72
  */
66
73
  private handoffIfRunning;
74
+ /**
75
+ * Release the caller with a background outcome if it asked to leave and the executor's
76
+ * preflight is over. The task is background exactly from here on.
77
+ */
78
+ private handoff;
79
+ private announceBackground;
67
80
  private publish;
68
81
  private attachOutput;
69
82
  private finish;
@@ -1 +1 @@
1
- {"version":3,"file":"execution.d.ts","sourceRoot":"","sources":["../../../src/core/tasks/execution.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,8BAA8B,CAAC;AAU1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAEX,WAAW,EACX,aAAa,EAGb,YAAY,EAGZ,eAAe,EAEf,MAAM,YAAY,CAAC;AAEpB,0FAA0F;AAC1F,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,IAAI,IAAI,IAAI,CAAC;IACb,0EAA0E;IAC1E,MAAM,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,KAAK,GAAG,SAAS,GAAG,IAAI,CAAC;IAC3D,mFAAmF;IACnF,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;CAC9C;AAeD;;;;;GAKG;AACH,qBAAa,SAAS,CAAC,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IACjC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;IACrC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA0B;IAC9C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAyB;IACpD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAuC;IACrE,OAAO,CAAC,aAAa,CAAyC;IAC9D,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,QAAQ,CAAC,CAAuC;IACxD,OAAO,CAAC,mBAAmB,CAAwB;IACnD,OAAO,CAAC,KAAK,CAAC,CAAQ;IACtB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,eAAe,CAAU;IACjC,iDAAiD;IACjD,OAAO,CAAC,OAAO,CAAC,CAA6B;gBAEjC,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC;IAuChF,IAAI,IAAI,IAAI,QAAQ,CAAC,YAAY,CAAC,CAEjC;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,+EAA+E;IAC/E,OAAO,KAAK,cAAc,GAEzB;IAED,6EAA6E;IAC7E,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,uGAAuG;IACvG,aAAa,IAAI,IAAI;IAMrB,KAAK,IAAI,IAAI;IAsBb,OAAO,IAAI,IAAI;IAoBf,aAAa,IAAI,IAAI;IAQrB,cAAc,IAAI,IAAI;IAWtB,MAAM,IAAI,OAAO;IAWjB,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,MAAM;IAUd;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,OAAO;IAiBf,OAAO,CAAC,YAAY;IAepB,OAAO,CAAC,MAAM;CAoDd"}
1
+ {"version":3,"file":"execution.d.ts","sourceRoot":"","sources":["../../../src/core/tasks/execution.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,8BAA8B,CAAC;AAU1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAEX,WAAW,EACX,aAAa,EAGb,YAAY,EAGZ,eAAe,EAEf,MAAM,YAAY,CAAC;AAEpB,0FAA0F;AAC1F,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,IAAI,IAAI,IAAI,CAAC;IACb,0EAA0E;IAC1E,MAAM,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,KAAK,GAAG,SAAS,GAAG,IAAI,CAAC;IAC3D,mFAAmF;IACnF,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;CAC9C;AAyBD;;;;;;;GAOG;AACH,qBAAa,SAAS,CAAC,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,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,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IACjC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;IACrC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA0B;IAC9C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAyB;IACpD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAuC;IACrE,OAAO,CAAC,aAAa,CAAyC;IAC9D,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,QAAQ,CAAC,CAAuC;IACxD,OAAO,CAAC,mBAAmB,CAAwB;IACnD,OAAO,CAAC,KAAK,CAAC,CAAQ;IACtB,OAAO,CAAC,KAAK,CAAmB;IAChC,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2B;IAClD,iDAAiD;IACjD,OAAO,CAAC,OAAO,CAAC,CAA6B;gBAEjC,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC;IAwChF,IAAI,IAAI,IAAI,QAAQ,CAAC,YAAY,CAAC,CAEjC;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,6EAA6E;IAC7E,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,kGAAkG;IAClG,IAAI,mBAAmB,IAAI,OAAO,CAEjC;IAED,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,uGAAuG;IACvG,aAAa,IAAI,IAAI;IAMrB,KAAK,IAAI,IAAI;IAsBb,8FAA8F;IAC9F,eAAe,IAAI,IAAI;IAIvB;;;;OAIG;IACH,MAAM,IAAI,MAAM,IAAI;IAQpB,MAAM,IAAI,OAAO;IAWjB,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,MAAM;IAUd;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;IAWxB;;;OAGG;IACH,OAAO,CAAC,OAAO;IAkBf,OAAO,CAAC,kBAAkB;IAW1B,OAAO,CAAC,OAAO;IAiBf,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,MAAM;CAmDd"}