@xopcai/xopc 0.0.221 → 0.0.223

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 (232) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/{activity-store-NItGQmvR.js → activity-store--GBciH10.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-B8SBTGg3.js → agent-avatar-dicebear-C93T3FLD.js} +1 -1
  5. package/dist/gateway/static/root/assets/agents-Ba4XF0Im.js +68 -0
  6. package/dist/gateway/static/root/assets/{api-53ZXsuyr.js → api-HoIz_ija.js} +1 -1
  7. package/dist/gateway/static/root/assets/{app-management-settings-panel-BtmPXaqu.js → app-management-settings-panel-Bhl8Xluk.js} +1 -1
  8. package/dist/gateway/static/root/assets/{appearance-settings-t7HoJyNN.js → appearance-settings-CywEN-kG.js} +1 -1
  9. package/dist/gateway/static/root/assets/apps-page-BZY09nuJ.js +1 -0
  10. package/dist/gateway/static/root/assets/{archive-plugin-D8o8CP9Y.js → archive-plugin-CteCVsBP.js} +1 -1
  11. package/dist/gateway/static/root/assets/{attachment-load-CsLXzas8.js → attachment-load-CbNE_EPd.js} +1 -1
  12. package/dist/gateway/static/root/assets/{automations-page-D-zgoAKz.js → automations-page-Bcqk6tOx.js} +1 -1
  13. package/dist/gateway/static/root/assets/automations-workspace-DtI6vsMf.js +6 -0
  14. package/dist/gateway/static/root/assets/{binary-plugins-B-MjP_22.js → binary-plugins-M_i3WS5M.js} +1 -1
  15. package/dist/gateway/static/root/assets/block-editor-eg9LEH2o.js +184 -0
  16. package/dist/gateway/static/root/assets/browser-settings-page-kKwbvzjj.js +8 -0
  17. package/dist/gateway/static/root/assets/{browser-workflow-inputs-Bi6RSSpD.js → browser-workflow-inputs-1UZ0vnIy.js} +1 -1
  18. package/dist/gateway/static/root/assets/{browser-workflows-page-EEFHUm1i.js → browser-workflows-page-D8ATQqZ5.js} +2 -2
  19. package/dist/gateway/static/root/assets/capabilities-settings-panel-CZRcis8B.js +7 -0
  20. package/dist/gateway/static/root/assets/{capability-presets-api-pC2fno7r.js → capability-presets-api-yNqTIuyd.js} +1 -1
  21. package/dist/gateway/static/root/assets/capability-presets-settings-panel-CgdRkwnk.js +3 -0
  22. package/dist/gateway/static/root/assets/{channel-recipient-api-B5Szgu_z.js → channel-recipient-api-krezGsKc.js} +1 -1
  23. package/dist/gateway/static/root/assets/channels-settings-DETCY0Ku.js +1 -0
  24. package/dist/gateway/static/root/assets/channels-status-swr-DMxB7slL.js +1 -0
  25. package/dist/gateway/static/root/assets/{chat-terminal-dock-DT-OFl4r.js → chat-terminal-dock-DQ5bB4Su.js} +2 -2
  26. package/dist/gateway/static/root/assets/connectors-page-D9D92u28.js +2 -0
  27. package/dist/gateway/static/root/assets/{cron-expression-MZ_AJqrm.js → cron-expression-CEwPkdhh.js} +1 -1
  28. package/dist/gateway/static/root/assets/{date-picker-Bv9hZLuD.js → date-picker-DDAxTir8.js} +1 -1
  29. package/dist/gateway/static/root/assets/{dependency-picker-D-6oO_Vk.js → dependency-picker-CYVoSZwI.js} +1 -1
  30. package/dist/gateway/static/root/assets/{desktop-pet-CiI5caKj.js → desktop-pet-CrNKfW_c.js} +1 -1
  31. package/dist/gateway/static/root/assets/{desktop-pet-settings-DhkSOy4K.js → desktop-pet-settings-C06PaB46.js} +1 -1
  32. package/dist/gateway/static/root/assets/{directory-picker-path-field-C4s4Pz8I.js → directory-picker-path-field--D7laeLF.js} +1 -1
  33. package/dist/gateway/static/root/assets/dist-DaxPZj9e.js +1 -0
  34. package/dist/gateway/static/root/assets/{dist-DY4Af0fY.js → dist-J_ySZvz0.js} +1 -1
  35. package/dist/gateway/static/root/assets/{extension-debug-page-DE7J1-6W.js → extension-debug-page-Dn4Px9KQ.js} +1 -1
  36. package/dist/gateway/static/root/assets/{extension-page-DSnACD7E.js → extension-page-DzLf3fMQ.js} +1 -1
  37. package/dist/gateway/static/root/assets/{extension-settings-page-Dk7k2Pok.js → extension-settings-page-DIchwtvB.js} +1 -1
  38. package/dist/gateway/static/root/assets/floating-ui.dom-B7uQOZZW.js +1 -0
  39. package/dist/gateway/static/root/assets/{gateway-config-api-IOA1OlHx.js → gateway-config-api-SmTGLhqK.js} +1 -1
  40. package/dist/gateway/static/root/assets/{gateway-config-swr-BzTbnu4O.js → gateway-config-swr-yUxMMVjK.js} +1 -1
  41. package/dist/gateway/static/root/assets/{gateway-settings-FX7QsgSQ.js → gateway-settings-yCDkOYzA.js} +1 -1
  42. package/dist/gateway/static/root/assets/{gateway-startup-retry-B2zpkNvi.js → gateway-startup-retry-9mrsL84j.js} +1 -1
  43. package/dist/gateway/static/root/assets/heartbeat-settings-CquIULHX.js +1 -0
  44. package/dist/gateway/static/root/assets/home-page-COSGBh4c.js +1 -0
  45. package/dist/gateway/static/root/assets/{image-generation-api-BXRjz-iY.js → image-generation-api-CgFAGDi8.js} +1 -1
  46. package/dist/gateway/static/root/assets/index-5XkDWH_Q.css +2 -0
  47. package/dist/gateway/static/root/assets/index-wnDPGRTi.js +74 -0
  48. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BjYiM4xq.js → keyboard-shortcuts-settings-DI2To7yl.js} +1 -1
  49. package/dist/gateway/static/root/assets/local-app-workbench-page-CAF5SZXv.js +2 -0
  50. package/dist/gateway/static/root/assets/{local-apps-page-7DHvwSgA.js → local-apps-page-CSEJsQ1F.js} +1 -1
  51. package/dist/gateway/static/root/assets/{locale-store-iKjqemWG.js → locale-store-CPylQjH9.js} +1 -1
  52. package/dist/gateway/static/root/assets/logs-page-D1KFPHL1.js +2 -0
  53. package/dist/gateway/static/root/assets/{management-settings-BSxppo9Z.js → management-settings-CgyaIyuk.js} +1 -1
  54. package/dist/gateway/static/root/assets/{markdown-split-D4oDjZtl.js → markdown-split-paG9qap9.js} +1 -1
  55. package/dist/gateway/static/root/assets/markdown-view-CUsob4Pz.js +69 -0
  56. package/dist/gateway/static/root/assets/{media-plugins-BPNTGROA.js → media-plugins-0Q-c_QIy.js} +1 -1
  57. package/dist/gateway/static/root/assets/messages-B82nsi9k.js +3 -0
  58. package/dist/gateway/static/root/assets/notes-api-CfKZYrBC.js +1 -0
  59. package/dist/gateway/static/root/assets/{notes-page-DU5tKPTq.js → notes-page-Bvb-ycX_.js} +1 -1
  60. package/dist/gateway/static/root/assets/notes-workbench-DelxGBof.js +4 -0
  61. package/dist/gateway/static/root/assets/oauth-authorization-window-Cdolr2wE.js +1 -0
  62. package/dist/gateway/static/root/assets/{popover-select-BzdnTy3h.js → popover-select-CccGri5Y.js} +1 -1
  63. package/dist/gateway/static/root/assets/{product-open-page-CPoQvD6P.js → product-open-page-DrvBwAns.js} +1 -1
  64. package/dist/gateway/static/root/assets/project-detail-page-C2EnYXEQ.js +1 -0
  65. package/dist/gateway/static/root/assets/projects-page-BiMPU6Oa.js +1 -0
  66. package/dist/gateway/static/root/assets/{registry-api-Cx3JxXSL.js → registry-api-B_5D8epF.js} +1 -1
  67. package/dist/gateway/static/root/assets/remote-access-hub-CpbNivVs.js +1 -0
  68. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-xqnWcvIv.js → runtime-tools-settings-panel-DKjdN4Lr.js} +1 -1
  69. package/dist/gateway/static/root/assets/{schema-form-CuIDPYu6.js → schema-form-DskqaNqC.js} +1 -1
  70. package/dist/gateway/static/root/assets/sessions-page-BxKtzsKI.js +1 -0
  71. package/dist/gateway/static/root/assets/settings-advanced-gate-BfBKMMUx.js +1 -0
  72. package/dist/gateway/static/root/assets/{settings-form-section-DkAv9ncE.js → settings-form-section-CZlMvHA9.js} +1 -1
  73. package/dist/gateway/static/root/assets/{settings-loading-skeleton-BJUQiEKb.js → settings-loading-skeleton-DS6lcAg9.js} +1 -1
  74. package/dist/gateway/static/root/assets/{settings-page-KHRbLwmw.js → settings-page-oE5J9tsV.js} +1 -1
  75. package/dist/gateway/static/root/assets/{setup-status-panel-C8jd20Db.js → setup-status-panel-C7oFCIqD.js} +1 -1
  76. package/dist/gateway/static/root/assets/share-preview-page-CPFAj8NE.js +2 -0
  77. package/dist/gateway/static/root/assets/shares-settings-B46DWZK4.js +1 -0
  78. package/dist/gateway/static/root/assets/skill-reload-api-CyKolUZ-.js +1 -0
  79. package/dist/gateway/static/root/assets/{skills-page-CKhR9J81.js → skills-page-Bh4gFi8e.js} +1 -1
  80. package/dist/gateway/static/root/assets/{skills-page.utils-AYX-e5sD.js → skills-page.utils-BQaUWP9z.js} +1 -1
  81. package/dist/gateway/static/root/assets/{system-settings-panel-IIF-K9ML.js → system-settings-panel-COAZoh_O.js} +1 -1
  82. package/dist/gateway/static/root/assets/task-detail-page-CXkhprf-.js +1 -0
  83. package/dist/gateway/static/root/assets/{theme-store-BOD2D0dJ.js → theme-store-BN-32Fz5.js} +1 -1
  84. package/dist/gateway/static/root/assets/{use-autosave-DcktF1j1.js → use-autosave-BAkToU15.js} +1 -1
  85. package/dist/gateway/static/root/assets/user-context-page-Br5wgARM.js +1 -0
  86. package/dist/gateway/static/root/assets/{voice-api-key-field-BMkNTHHE.js → voice-api-key-field-CC4z9-ux.js} +1 -1
  87. package/dist/gateway/static/root/assets/{work-discovery-overlay-DVoiXekA.js → work-discovery-overlay-dLVUYSSE.js} +1 -1
  88. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-Cw4LQjuM.js → workflow-run-setup-panel-BYU5-0KF.js} +2 -2
  89. package/dist/gateway/static/root/assets/workflows-page-CJ24a1HM.js +5 -0
  90. package/dist/gateway/static/root/index.html +15 -14
  91. package/dist/package.js +1 -1
  92. package/dist/src/agent/agent-instance-gateway.d.ts +3 -0
  93. package/dist/src/agent/agent-manager.d.ts +3 -0
  94. package/dist/src/agent/agent-manager.js +34 -28
  95. package/dist/src/agent/embedded/index.d.ts +1 -1
  96. package/dist/src/agent/embedded/index.js +2 -2
  97. package/dist/src/agent/embedded/model-runtime.js +1 -1
  98. package/dist/src/agent/embedded/run-for-session.js +102 -63
  99. package/dist/src/agent/embedded/run-turn.js +56 -28
  100. package/dist/src/agent/embedded/runs.d.ts +16 -29
  101. package/dist/src/agent/embedded/runs.js +44 -65
  102. package/dist/src/agent/embedded/types.d.ts +4 -0
  103. package/dist/src/agent/image/tool-model-config.js +1 -1
  104. package/dist/src/agent/ipc/inbox.js +1 -1
  105. package/dist/src/agent/memory/create-memory-manager.js +1 -1
  106. package/dist/src/agent/orchestration/agent-run-supervisor.d.ts +28 -0
  107. package/dist/src/agent/orchestration/agent-run-supervisor.js +49 -0
  108. package/dist/src/agent/orchestration/agent-turn-policy.d.ts +18 -0
  109. package/dist/src/agent/orchestration/agent-turn-policy.js +36 -0
  110. package/dist/src/agent/orchestration/llm-turn-retry.d.ts +5 -0
  111. package/dist/src/agent/orchestration/llm-turn-retry.js +34 -4
  112. package/dist/src/agent/orchestration/run-agent-turn-with-timeout.d.ts +10 -1
  113. package/dist/src/agent/orchestration/run-agent-turn-with-timeout.js +25 -4
  114. package/dist/src/agent/service/async-queue.d.ts +16 -3
  115. package/dist/src/agent/service/async-queue.js +29 -11
  116. package/dist/src/agent/service/process-direct-streaming.js +27 -4
  117. package/dist/src/agent/service.js +3 -2
  118. package/dist/src/agent/session/session-inspector.js +1 -1
  119. package/dist/src/agent/skills/hub-lock.js +1 -1
  120. package/dist/src/agent/tasks/task-judge-service.js +3 -3
  121. package/dist/src/agent/tools/exec-command.d.ts +2 -0
  122. package/dist/src/agent/tools/exec-command.js +70 -7
  123. package/dist/src/agent-runtime/index.js +1 -1
  124. package/dist/src/agent-runtime/runtime-profile.js +1 -1
  125. package/dist/src/ai-assist/text-assist.js +1 -1
  126. package/dist/src/auth/credentials.js +2 -2
  127. package/dist/src/auth/oauth/index.js +3 -3
  128. package/dist/src/auth/oauth/registry.d.ts +2 -0
  129. package/dist/src/auth/oauth/registry.js +20 -12
  130. package/dist/src/auth/oauth/xopc-cloud.d.ts +1 -0
  131. package/dist/src/auth/oauth/xopc-cloud.js +32 -16
  132. package/dist/src/auth/profiles/store.js +1 -1
  133. package/dist/src/auth/sync-provider-auth.js +2 -2
  134. package/dist/src/browser/providers/browser-ext-install.js +1 -1
  135. package/dist/src/channels/attachments/voice-stt-webchat.js +20 -3
  136. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  137. package/dist/src/cli/commands/models.js +1 -1
  138. package/dist/src/cli/commands/tunnel.js +4 -5
  139. package/dist/src/config/index.js +4 -4
  140. package/dist/src/config/loader.js +1 -1
  141. package/dist/src/config/models-json.js +1 -1
  142. package/dist/src/config/schema.d.ts +18 -0
  143. package/dist/src/config/schema.js +19 -1
  144. package/dist/src/connectors/learning-coordinator.js +3 -19
  145. package/dist/src/extensions/lockfile.js +1 -1
  146. package/dist/src/gateway/agents-admin.js +1 -1
  147. package/dist/src/gateway/file-path-classifier.js +1 -1
  148. package/dist/src/gateway/hono/app.js +2 -1
  149. package/dist/src/gateway/hono/lib/config-payload.js +1 -1
  150. package/dist/src/gateway/hono/oauth-async.d.ts +1 -0
  151. package/dist/src/gateway/hono/oauth-async.js +11 -4
  152. package/dist/src/gateway/hono/routes/config.js +10 -0
  153. package/dist/src/gateway/hono/routes/host-fs.js +40 -1
  154. package/dist/src/gateway/hono/routes/media.js +33 -1
  155. package/dist/src/gateway/hono/routes/models.js +1 -1
  156. package/dist/src/gateway/hono/routes/notes.js +162 -7
  157. package/dist/src/gateway/hono/routes/shares.js +141 -6
  158. package/dist/src/gateway/hono/routes/tunnel.js +47 -10
  159. package/dist/src/gateway/hono/routes/voice.d.ts +2 -6
  160. package/dist/src/gateway/hono/routes/voice.js +28 -5
  161. package/dist/src/gateway/service/config-coordinator.js +1 -1
  162. package/dist/src/gateway/service.js +3 -3
  163. package/dist/src/notes/service.d.ts +6 -2
  164. package/dist/src/notes/service.js +36 -4
  165. package/dist/src/providers/auth-runtime/resolve-auth.js +1 -1
  166. package/dist/src/providers/index.js +3 -3
  167. package/dist/src/providers/model-registry.js +1 -1
  168. package/dist/src/providers/register-runtime-providers.js +1 -1
  169. package/dist/src/share/note-share-service.d.ts +67 -0
  170. package/dist/src/share/note-share-service.js +283 -0
  171. package/dist/src/share/share-config.js +32 -3
  172. package/dist/src/share/share-landing.d.ts +5 -1
  173. package/dist/src/share/share-landing.js +28 -1
  174. package/dist/src/share/share-store.d.ts +34 -5
  175. package/dist/src/share/share-store.js +125 -19
  176. package/dist/src/share/share-thumbnail.js +4 -2
  177. package/dist/src/share/share-types.d.ts +52 -14
  178. package/dist/src/share/share-types.js +9 -0
  179. package/dist/src/share/share-zip.d.ts +2 -2
  180. package/dist/src/tui/tui-startup-resources.js +1 -1
  181. package/dist/src/tui/tui.js +1 -1
  182. package/dist/src/tunnel/env.d.ts +12 -6
  183. package/dist/src/tunnel/env.js +34 -26
  184. package/dist/src/tunnel/gateway-lifecycle.js +2 -13
  185. package/dist/src/tunnel/index.d.ts +1 -1
  186. package/dist/src/tunnel/index.js +2 -2
  187. package/dist/src/tunnel/tunnel-audit.d.ts +1 -1
  188. package/dist/src/tunnel/tunnel-config.d.ts +1 -1
  189. package/dist/src/tunnel/tunnel-config.js +9 -4
  190. package/dist/src/tunnel/tunnel-service.d.ts +1 -1
  191. package/dist/src/tunnel/tunnel-service.js +3 -0
  192. package/dist/src/tunnel/well-known.d.ts +1 -1
  193. package/dist/src/tunnel/well-known.js +1 -1
  194. package/dist/src/tunnel/xopc-cloud-registration.d.ts +9 -0
  195. package/dist/src/tunnel/xopc-cloud-registration.js +42 -0
  196. package/dist/src/voice/audio/normalize.d.ts +7 -0
  197. package/dist/src/voice/audio/normalize.js +30 -4
  198. package/dist/src/voice/local/runtime-worker.js +26 -6
  199. package/dist/src/workflows/service/workflow-run-service.js +1 -1
  200. package/package.json +8 -14
  201. package/dist/gateway/static/root/assets/agents-Brs2-m6t.js +0 -68
  202. package/dist/gateway/static/root/assets/apps-page-DJ_Dsb1j.js +0 -1
  203. package/dist/gateway/static/root/assets/automations-workspace-DehLRXfd.js +0 -6
  204. package/dist/gateway/static/root/assets/block-editor-i4CfDqLG.js +0 -184
  205. package/dist/gateway/static/root/assets/browser-settings-page-C3QIO4Ti.js +0 -8
  206. package/dist/gateway/static/root/assets/capabilities-settings-panel-BHhUp7FW.js +0 -7
  207. package/dist/gateway/static/root/assets/capability-presets-settings-panel-DoClNVLz.js +0 -3
  208. package/dist/gateway/static/root/assets/channels-settings-Je-9a5ZC.js +0 -1
  209. package/dist/gateway/static/root/assets/channels-status-swr-ByRbxC6z.js +0 -1
  210. package/dist/gateway/static/root/assets/connectors-page-D8z9Trw4.js +0 -2
  211. package/dist/gateway/static/root/assets/dist-C230izr8.js +0 -1
  212. package/dist/gateway/static/root/assets/heartbeat-settings-D5CGVyci.js +0 -1
  213. package/dist/gateway/static/root/assets/home-page-DzfZFZx5.js +0 -1
  214. package/dist/gateway/static/root/assets/index-Dcj5KJRg.css +0 -2
  215. package/dist/gateway/static/root/assets/index-EvA8c7fo.js +0 -74
  216. package/dist/gateway/static/root/assets/local-app-workbench-page-hPyTaVYU.js +0 -2
  217. package/dist/gateway/static/root/assets/logs-page-DW0xMKWP.js +0 -2
  218. package/dist/gateway/static/root/assets/markdown-view-DYkxMtJA.js +0 -69
  219. package/dist/gateway/static/root/assets/messages-kx5W39dO.js +0 -3
  220. package/dist/gateway/static/root/assets/notes-api-DJizatxh.js +0 -1
  221. package/dist/gateway/static/root/assets/notes-workbench-D669d98r.js +0 -4
  222. package/dist/gateway/static/root/assets/project-detail-page-CpsQ9PTA.js +0 -1
  223. package/dist/gateway/static/root/assets/projects-page-CitO1LMc.js +0 -1
  224. package/dist/gateway/static/root/assets/remote-access-hub-C9-bL4V6.js +0 -1
  225. package/dist/gateway/static/root/assets/sessions-page-CPSARi4y.js +0 -1
  226. package/dist/gateway/static/root/assets/settings-advanced-gate-BxT80Fmr.js +0 -1
  227. package/dist/gateway/static/root/assets/share-preview-page-WCVtJ3sX.js +0 -2
  228. package/dist/gateway/static/root/assets/shares-settings-DrQ_cOXh.js +0 -1
  229. package/dist/gateway/static/root/assets/skill-reload-api-C_4cG30x.js +0 -1
  230. package/dist/gateway/static/root/assets/task-detail-page-CYjsecEr.js +0 -1
  231. package/dist/gateway/static/root/assets/user-context-page-Cy1D2hkt.js +0 -1
  232. package/dist/gateway/static/root/assets/workflows-page-DKKH1_Yt.js +0 -5
@@ -1,91 +1,70 @@
1
- import { createLogger } from "../../utils/logger/index.js";
2
- import { init_logger } from "../../utils/logger.js";
3
1
  //#region src/agent/embedded/runs.ts
4
- init_logger();
5
- const log = createLogger("EmbeddedRunRegistry");
6
- /**
7
- * Tracks in-flight embedded agent turns so we can abort/steer them by sessionKey or runId.
8
- *
9
- * The previous implementation used two module-level Maps; this class is the supported
10
- * single-instance state, while {@link defaultEmbeddedRunRegistry} preserves the previous
11
- * free-function API for callers that have not yet been moved to dependency injection.
12
- */
2
+ var EmbeddedRunConflictError = class extends Error {
3
+ constructor(sessionKey, activeRunId) {
4
+ super(`Session '${sessionKey}' already has active embedded run '${activeRunId}'`);
5
+ this.sessionKey = sessionKey;
6
+ this.activeRunId = activeRunId;
7
+ this.name = "EmbeddedRunConflictError";
8
+ }
9
+ };
10
+ /** Owns one process-local execution lease per session while leaving steer/abort on the control plane. */
13
11
  var EmbeddedRunRegistry = class {
14
12
  bySessionKey = /* @__PURE__ */ new Map();
15
- byRunId = /* @__PURE__ */ new Map();
16
- /**
17
- * Register a new in-flight run. If a run is already registered for the same
18
- * sessionKey we drop the stale handle (the new run takes ownership). The caller
19
- * is responsible for aborting the previous run before re-registering if needed —
20
- * we warn loudly so this does not happen silently.
21
- */
22
- register(handle) {
23
- const previous = this.bySessionKey.get(handle.sessionKey);
24
- if (previous && previous !== handle) {
25
- log.warn({
26
- sessionKey: handle.sessionKey,
27
- previousRunId: previous.runId,
28
- newRunId: handle.runId
29
- }, "Replacing already-registered embedded run for sessionKey (caller did not unregister first)");
30
- this.byRunId.delete(previous.runId);
31
- }
32
- this.bySessionKey.set(handle.sessionKey, handle);
33
- this.byRunId.set(handle.runId, handle);
34
- }
35
- unregister(handle) {
36
- if (this.bySessionKey.get(handle.sessionKey) === handle) this.bySessionKey.delete(handle.sessionKey);
37
- this.byRunId.delete(handle.runId);
13
+ acquire(identity) {
14
+ const active = this.bySessionKey.get(identity.sessionKey);
15
+ if (active) throw new EmbeddedRunConflictError(identity.sessionKey, active.runId);
16
+ const entry = {
17
+ ...identity,
18
+ abortController: new AbortController()
19
+ };
20
+ this.bySessionKey.set(identity.sessionKey, entry);
21
+ return {
22
+ signal: entry.abortController.signal,
23
+ attach: async (session, abort) => {
24
+ entry.handle = {
25
+ ...identity,
26
+ session,
27
+ abort
28
+ };
29
+ if (entry.abortController.signal.aborted) await abort();
30
+ },
31
+ release: () => {
32
+ if (this.bySessionKey.get(identity.sessionKey) === entry) this.bySessionKey.delete(identity.sessionKey);
33
+ }
34
+ };
38
35
  }
39
36
  getBySessionKey(sessionKey) {
40
- return this.bySessionKey.get(sessionKey);
41
- }
42
- getByRunId(runId) {
43
- return this.byRunId.get(runId);
37
+ return this.bySessionKey.get(sessionKey)?.handle;
44
38
  }
45
39
  async abortBySessionKey(sessionKey) {
46
- const handle = this.bySessionKey.get(sessionKey);
47
- if (!handle) return false;
48
- await handle.abort();
40
+ const entry = this.bySessionKey.get(sessionKey);
41
+ if (!entry) return false;
42
+ entry.abortController.abort(/* @__PURE__ */ new Error("Embedded run aborted"));
43
+ if (entry.handle) await entry.handle.abort();
49
44
  return true;
50
45
  }
51
46
  async steerBySessionKey(sessionKey, text) {
52
- const handle = this.bySessionKey.get(sessionKey);
47
+ const handle = this.getBySessionKey(sessionKey);
53
48
  if (!handle) return false;
54
49
  await handle.session.steer(text);
55
50
  return true;
56
51
  }
57
- /** Test-only helper to drop all registrations without touching live sessions. */
58
- resetForTest() {
59
- this.bySessionKey.clear();
60
- this.byRunId.clear();
61
- }
62
52
  size() {
63
53
  return this.bySessionKey.size;
64
54
  }
65
55
  };
66
- /**
67
- * Process-wide default registry. Prefer constructing a dedicated `EmbeddedRunRegistry`
68
- * and injecting it; the module-level singleton stays so the existing free functions
69
- * keep working until every caller has been migrated.
70
- */
71
- const defaultEmbeddedRunRegistry = new EmbeddedRunRegistry();
72
- function registerEmbeddedRun(handle) {
73
- defaultEmbeddedRunRegistry.register(handle);
74
- }
75
- function unregisterEmbeddedRun(handle) {
76
- defaultEmbeddedRunRegistry.unregister(handle);
56
+ const embeddedRunRegistry = new EmbeddedRunRegistry();
57
+ function acquireEmbeddedRunLease(identity) {
58
+ return embeddedRunRegistry.acquire(identity);
77
59
  }
78
60
  function getEmbeddedRunBySessionKey(sessionKey) {
79
- return defaultEmbeddedRunRegistry.getBySessionKey(sessionKey);
80
- }
81
- function getEmbeddedRunByRunId(runId) {
82
- return defaultEmbeddedRunRegistry.getByRunId(runId);
61
+ return embeddedRunRegistry.getBySessionKey(sessionKey);
83
62
  }
84
63
  function abortEmbeddedRun(sessionKey) {
85
- return defaultEmbeddedRunRegistry.abortBySessionKey(sessionKey);
64
+ return embeddedRunRegistry.abortBySessionKey(sessionKey);
86
65
  }
87
66
  function queueEmbeddedSteer(sessionKey, text) {
88
- return defaultEmbeddedRunRegistry.steerBySessionKey(sessionKey, text);
67
+ return embeddedRunRegistry.steerBySessionKey(sessionKey, text);
89
68
  }
90
69
  //#endregion
91
- export { EmbeddedRunRegistry, abortEmbeddedRun, defaultEmbeddedRunRegistry, getEmbeddedRunByRunId, getEmbeddedRunBySessionKey, queueEmbeddedSteer, registerEmbeddedRun, unregisterEmbeddedRun };
70
+ export { EmbeddedRunConflictError, EmbeddedRunRegistry, abortEmbeddedRun, acquireEmbeddedRunLease, getEmbeddedRunBySessionKey, queueEmbeddedSteer };
@@ -2,6 +2,7 @@ import type { AgentMessage, AgentToolResult, ThinkingLevel } from '@earendil-wor
2
2
  import type { AssistantMessageEvent, Model, Api, ImageContent } from '@earendil-works/pi-ai';
3
3
  import type { SessionStore } from '../../session/store.js';
4
4
  import type { EmbeddedTranscriptRuntime } from './transcript-runtime.js';
5
+ import type { AgentTurnPolicy } from '../orchestration/agent-turn-policy.js';
5
6
  export type EmbeddedStreamEvent = {
6
7
  type: 'agent_start';
7
8
  runId?: string;
@@ -97,6 +98,7 @@ export type RunXopcEmbeddedTurnParams = {
97
98
  sessionStore?: SessionStore;
98
99
  transcriptRuntime?: EmbeddedTranscriptRuntime;
99
100
  timeoutMs: number;
101
+ turnPolicy?: AgentTurnPolicy;
100
102
  abortSignal?: AbortSignal;
101
103
  onEvent?: (event: EmbeddedStreamEvent) => void;
102
104
  images?: ImageContent[];
@@ -105,6 +107,8 @@ export type RunXopcEmbeddedTurnParams = {
105
107
  };
106
108
  export type RunXopcEmbeddedTurnResult = {
107
109
  ok: boolean;
110
+ /** False for harness failures that must not trigger another model attempt. */
111
+ retryable?: boolean;
108
112
  errorMessage?: string;
109
113
  lastAssistantText?: string;
110
114
  };
@@ -1,7 +1,7 @@
1
1
  import { getAgentDefaultImageModelConfig, getAgentDefaultModelRef, init_schema, parseModelRef } from "../../config/schema.js";
2
2
  import { init_agent_scope, resolveDefaultAgentId } from "../agent-scope.js";
3
- import { getDefaultModelSync, getModelsByProvider, init_providers, isProviderConfiguredSync, resolveModel } from "../../providers/index.js";
4
3
  import { resolveEffectiveAgentManifestForAgent } from "../../config/agent-profile.js";
4
+ import { getDefaultModelSync, getModelsByProvider, init_providers, isProviderConfiguredSync, resolveModel } from "../../providers/index.js";
5
5
  import { resolveAgentModelFallbackValues, resolveAgentModelPrimaryValue } from "../../config/model-input.js";
6
6
  import { buildCapabilityPlansForConfig } from "../../capabilities/readiness/from-config.js";
7
7
  import "../../capabilities/readiness/index.js";
@@ -1,7 +1,7 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
- import { init_write_file_atomic, writeTextAtomic } from "../../infra/write-file-atomic.js";
4
3
  import { init_paths, resolveAgentDir } from "../../config/paths.js";
4
+ import { init_write_file_atomic, writeTextAtomic } from "../../infra/write-file-atomic.js";
5
5
  import { join } from "path";
6
6
  import { existsSync, watch } from "fs";
7
7
  import { mkdir, readFile, readdir, rename } from "fs/promises";
@@ -1,8 +1,8 @@
1
- import { buildMemoryRuntime } from "../../agent-runtime/memory-runtime.js";
2
1
  import { isMemorySubsystemEnabled } from "./memory-config.js";
3
2
  import { BuiltinMemoryProvider } from "./builtin-provider.js";
4
3
  import { MemoryManager } from "./manager.js";
5
4
  import { loadMemoryPluginProviders } from "./plugin-discovery.js";
5
+ import { buildMemoryRuntime } from "../../agent-runtime/memory-runtime.js";
6
6
  //#region src/agent/memory/create-memory-manager.ts
7
7
  function createMemoryManagerFromConfig(config) {
8
8
  const routing = resolveMemoryManagerOptions(config);
@@ -0,0 +1,28 @@
1
+ export type ModelAttemptPlan = {
2
+ ok: true;
3
+ timeoutMs: number;
4
+ remainingMs: number;
5
+ } | {
6
+ ok: false;
7
+ reason: string;
8
+ };
9
+ export interface AgentRunSupervisorOptions {
10
+ timeoutMs: number;
11
+ deadlineAtMs?: number;
12
+ parentSignal?: AbortSignal;
13
+ minimumFallbackMs?: number;
14
+ }
15
+ /** Minimal run-level coordination: root cancellation and per-attempt deadline planning. */
16
+ export declare class AgentRunSupervisor {
17
+ readonly deadlineAtMs: number;
18
+ readonly signal: AbortSignal;
19
+ private readonly controller;
20
+ private readonly timeout;
21
+ private readonly forwardParentAbort;
22
+ private readonly timeoutMs;
23
+ private readonly minimumFallbackMs;
24
+ private readonly parentSignal?;
25
+ constructor(options: AgentRunSupervisorOptions);
26
+ planModelAttempt(isFallback: boolean): ModelAttemptPlan;
27
+ dispose(): void;
28
+ }
@@ -0,0 +1,49 @@
1
+ //#region src/agent/orchestration/agent-run-supervisor.ts
2
+ /** Minimal run-level coordination: root cancellation and per-attempt deadline planning. */
3
+ var AgentRunSupervisor = class {
4
+ deadlineAtMs;
5
+ signal;
6
+ controller = new AbortController();
7
+ timeout;
8
+ forwardParentAbort;
9
+ timeoutMs;
10
+ minimumFallbackMs;
11
+ parentSignal;
12
+ constructor(options) {
13
+ this.timeoutMs = options.timeoutMs;
14
+ this.minimumFallbackMs = options.minimumFallbackMs ?? 5e3;
15
+ this.deadlineAtMs = options.deadlineAtMs ?? Date.now() + options.timeoutMs;
16
+ this.parentSignal = options.parentSignal;
17
+ this.signal = this.controller.signal;
18
+ this.forwardParentAbort = () => this.controller.abort(this.parentSignal?.reason);
19
+ if (this.parentSignal?.aborted) this.forwardParentAbort();
20
+ else this.parentSignal?.addEventListener("abort", this.forwardParentAbort, { once: true });
21
+ this.timeout = setTimeout(() => this.controller.abort(/* @__PURE__ */ new Error("Agent run deadline expired")), Math.max(0, this.deadlineAtMs - Date.now()));
22
+ }
23
+ planModelAttempt(isFallback) {
24
+ if (this.signal.aborted) return {
25
+ ok: false,
26
+ reason: "Agent run aborted"
27
+ };
28
+ const remainingMs = this.deadlineAtMs - Date.now();
29
+ if (remainingMs <= 0) return {
30
+ ok: false,
31
+ reason: "Agent run deadline expired before the next model attempt"
32
+ };
33
+ if (isFallback && remainingMs < this.minimumFallbackMs) return {
34
+ ok: false,
35
+ reason: "Agent run deadline left too little time for a fallback model attempt"
36
+ };
37
+ return {
38
+ ok: true,
39
+ remainingMs,
40
+ timeoutMs: Math.max(1, Math.min(this.timeoutMs, remainingMs))
41
+ };
42
+ }
43
+ dispose() {
44
+ clearTimeout(this.timeout);
45
+ this.parentSignal?.removeEventListener("abort", this.forwardParentAbort);
46
+ }
47
+ };
48
+ //#endregion
49
+ export { AgentRunSupervisor };
@@ -0,0 +1,18 @@
1
+ import type { AfterToolCallContext, BeforeToolCallContext, BeforeToolCallResult, ShouldStopAfterTurnContext } from '@earendil-works/pi-agent-core';
2
+ export interface AgentTurnPolicy {
3
+ reset(): void;
4
+ beforeToolCall(context: BeforeToolCallContext, signal?: AbortSignal): Promise<BeforeToolCallResult | undefined>;
5
+ afterToolCall(context: AfterToolCallContext): Promise<undefined>;
6
+ shouldStopAfterTurn(context: ShouldStopAfterTurnContext): boolean;
7
+ }
8
+ export interface AgentTurnPolicyOptions {
9
+ maxTurns?: number;
10
+ maxToolFailures?: number;
11
+ resolveToolLimit?: (toolName: string, args: unknown) => {
12
+ id: string;
13
+ maxCalls: number;
14
+ } | undefined;
15
+ authorizeToolCall?: (context: BeforeToolCallContext, signal?: AbortSignal) => Promise<BeforeToolCallResult | undefined>;
16
+ }
17
+ /** One user-visible run policy. A fresh instance is created for every embedded run. */
18
+ export declare function createAgentTurnPolicy(options: AgentTurnPolicyOptions): AgentTurnPolicy;
@@ -0,0 +1,36 @@
1
+ //#region src/agent/orchestration/agent-turn-policy.ts
2
+ function assistantMessageCount(messages) {
3
+ return messages.filter((message) => message.role === "assistant").length;
4
+ }
5
+ /** One user-visible run policy. A fresh instance is created for every embedded run. */
6
+ function createAgentTurnPolicy(options) {
7
+ const toolCalls = /* @__PURE__ */ new Map();
8
+ let toolFailures = 0;
9
+ return {
10
+ reset() {
11
+ toolCalls.clear();
12
+ toolFailures = 0;
13
+ },
14
+ async beforeToolCall(context, signal) {
15
+ const limit = options.resolveToolLimit?.(context.toolCall.name, context.args);
16
+ if (limit) {
17
+ const count = (toolCalls.get(limit.id) ?? 0) + 1;
18
+ toolCalls.set(limit.id, count);
19
+ if (count > limit.maxCalls) return {
20
+ block: true,
21
+ terminate: true,
22
+ reason: `${limit.id} exceeded its per-turn call limit.`
23
+ };
24
+ }
25
+ return options.authorizeToolCall?.(context, signal);
26
+ },
27
+ async afterToolCall(context) {
28
+ if (context.isError) toolFailures += 1;
29
+ },
30
+ shouldStopAfterTurn(context) {
31
+ return Boolean(options.maxTurns && assistantMessageCount(context.newMessages) >= options.maxTurns || options.maxToolFailures && toolFailures >= options.maxToolFailures);
32
+ }
33
+ };
34
+ }
35
+ //#endregion
36
+ export { createAgentTurnPolicy };
@@ -6,6 +6,8 @@
6
6
  */
7
7
  import type { Agent, AgentMessage } from '@earendil-works/pi-agent-core';
8
8
  export declare function isTransientLlmErrorMessage(message: string): boolean;
9
+ export type LlmFailureKind = 'transient_network' | 'context_overflow' | 'aborted' | 'permanent';
10
+ export declare function classifyLlmFailure(message: string): LlmFailureKind;
9
11
  export declare function getLastAssistantMessage(messages: AgentMessage[]): AgentMessage | undefined;
10
12
  /** Raw provider/LLM error from the last failed assistant message, if any. */
11
13
  export declare function getAssistantTurnErrorMessage(agent: Agent): string | undefined;
@@ -20,6 +22,9 @@ export declare function stripTrailingErrorAssistantMessages(messages: AgentMessa
20
22
  export interface RetryTransientTurnOptions {
21
23
  /** Extra turns after a failed assistant message (default 2). */
22
24
  maxContinues?: number;
25
+ /** Initial deterministic backoff. Each later retry doubles it. */
26
+ baseDelayMs?: number;
27
+ signal?: AbortSignal;
23
28
  sessionKey: string;
24
29
  log: {
25
30
  warn: (obj: Record<string, unknown>, msg: string) => void;
@@ -1,3 +1,4 @@
1
+ import { isContextOverflowError } from "./context-overflow.js";
1
2
  //#region src/agent/orchestration/llm-turn-retry.ts
2
3
  const TRANSIENT_LLM_ERROR_SUBSTRINGS = [
3
4
  "fetch failed",
@@ -16,6 +17,13 @@ function isTransientLlmErrorMessage(message) {
16
17
  const lower = message.toLowerCase();
17
18
  return TRANSIENT_LLM_ERROR_SUBSTRINGS.some((s) => lower.includes(s));
18
19
  }
20
+ function classifyLlmFailure(message) {
21
+ const normalized = message.trim().toLowerCase();
22
+ if (normalized === "aborted" || normalized.includes("aborterror")) return "aborted";
23
+ if (isContextOverflowError(message)) return "context_overflow";
24
+ if (isTransientLlmErrorMessage(message)) return "transient_network";
25
+ return "permanent";
26
+ }
19
27
  function getLastAssistantMessage(messages) {
20
28
  for (let i = messages.length - 1; i >= 0; i--) if (messages[i].role === "assistant") return messages[i];
21
29
  }
@@ -56,32 +64,54 @@ function stripTrailingErrorAssistantMessages(messages) {
56
64
  }
57
65
  return out;
58
66
  }
67
+ async function waitForRetryDelay(delayMs, signal) {
68
+ signal?.throwIfAborted();
69
+ if (delayMs <= 0) return;
70
+ await new Promise((resolve, reject) => {
71
+ const onAbort = () => {
72
+ clearTimeout(timer);
73
+ reject(signal?.reason ?? new DOMException("Aborted", "AbortError"));
74
+ };
75
+ const timer = setTimeout(() => {
76
+ signal?.removeEventListener("abort", onAbort);
77
+ resolve();
78
+ }, delayMs);
79
+ signal?.addEventListener("abort", onAbort, { once: true });
80
+ });
81
+ }
59
82
  /**
60
83
  * After waitForIdle(), call this to optionally re-run the last user turn when the
61
84
  * assistant message only contains a transient provider/network error.
62
85
  */
63
86
  async function maybeRetryTurnAfterTransientLlmFailure(agent, options) {
64
87
  const maxContinues = options.maxContinues ?? 2;
88
+ const baseDelayMs = Math.max(0, options.baseDelayMs ?? 300);
65
89
  let continues = 0;
66
90
  while (continues < maxContinues) {
67
91
  const last = getLastAssistantMessage(agent.state.messages);
68
92
  if (!last) return;
69
93
  if (last.stopReason !== "error") return;
70
94
  const errMsg = String(last.errorMessage || "");
71
- if (!isTransientLlmErrorMessage(errMsg)) {
95
+ const failureKind = classifyLlmFailure(errMsg);
96
+ if (failureKind !== "transient_network") {
72
97
  options.log.warn({
73
98
  sessionKey: options.sessionKey,
74
- errorMessage: errMsg
99
+ errorMessage: errMsg,
100
+ failureKind
75
101
  }, "Assistant turn ended with error (not retrying as transient)");
76
102
  return;
77
103
  }
78
104
  continues += 1;
105
+ const retryDelayMs = baseDelayMs * 2 ** (continues - 1);
79
106
  options.log.warn({
80
107
  sessionKey: options.sessionKey,
81
108
  errorMessage: errMsg,
109
+ failureKind,
82
110
  continueAttempt: continues,
83
- maxContinues
111
+ maxContinues,
112
+ retryDelayMs
84
113
  }, "LLM request failed with a transient network error; retrying the same turn. If this persists, check outbound HTTPS to the provider API and HTTP(S)_PROXY.");
114
+ await waitForRetryDelay(retryDelayMs, options.signal);
85
115
  const trimmed = stripTrailingErrorAssistantMessages(agent.state.messages);
86
116
  agent.state.messages = trimmed;
87
117
  await agent.continue();
@@ -89,4 +119,4 @@ async function maybeRetryTurnAfterTransientLlmFailure(agent, options) {
89
119
  }
90
120
  }
91
121
  //#endregion
92
- export { getAssistantTurnErrorMessage, getLastAssistantMessage, isAssistantTurnAborted, isAssistantTurnFailed, isTransientLlmErrorMessage, maybeRetryTurnAfterTransientLlmFailure, stripTrailingErrorAssistantMessages };
122
+ export { classifyLlmFailure, getAssistantTurnErrorMessage, getLastAssistantMessage, isAssistantTurnAborted, isAssistantTurnFailed, isTransientLlmErrorMessage, maybeRetryTurnAfterTransientLlmFailure, stripTrailingErrorAssistantMessages };
@@ -10,6 +10,15 @@ export declare const MIN_AGENT_TURN_TIMEOUT_MS = 60000;
10
10
  export declare const MAX_AGENT_TURN_TIMEOUT_MS: number;
11
11
  /** Default per-turn timeout (30 minutes). */
12
12
  export declare const DEFAULT_AGENT_TURN_TIMEOUT_MS: number;
13
+ export declare const DEFAULT_AGENT_ABORT_GRACE_MS = 5000;
14
+ export declare class AgentTurnUnsettledError extends Error {
15
+ readonly timeoutMs: number;
16
+ readonly abortGraceMs: number;
17
+ constructor(timeoutMs: number, abortGraceMs: number);
18
+ }
19
+ export declare function isAgentTurnUnsettledError(err: unknown): err is AgentTurnUnsettledError;
13
20
  export declare function resolveAgentTurnTimeoutMs(config?: Config, sessionKey?: string): number;
14
21
  export declare function isAgentTurnTimeoutError(err: unknown): boolean;
15
- export declare function runAgentTurnWithTimeout(agent: Agent, runTurn: () => Promise<void>, timeoutMs: number): Promise<void>;
22
+ export declare function runAgentTurnWithTimeout(agent: Agent, runTurn: () => Promise<void>, timeoutMs: number, options?: {
23
+ abortGraceMs?: number;
24
+ }): Promise<void>;
@@ -6,6 +6,18 @@ const MIN_AGENT_TURN_TIMEOUT_MS = 6e4;
6
6
  const MAX_AGENT_TURN_TIMEOUT_MS = 14400 * 1e3;
7
7
  /** Default per-turn timeout (30 minutes). */
8
8
  const DEFAULT_AGENT_TURN_TIMEOUT_MS = 1800 * 1e3;
9
+ const DEFAULT_AGENT_ABORT_GRACE_MS = 5e3;
10
+ var AgentTurnUnsettledError = class extends Error {
11
+ constructor(timeoutMs, abortGraceMs) {
12
+ super(`Agent turn timed out after ${timeoutMs / 1e3}s and did not settle within ${abortGraceMs / 1e3}s`);
13
+ this.timeoutMs = timeoutMs;
14
+ this.abortGraceMs = abortGraceMs;
15
+ this.name = "AgentTurnUnsettledError";
16
+ }
17
+ };
18
+ function isAgentTurnUnsettledError(err) {
19
+ return err instanceof AgentTurnUnsettledError;
20
+ }
9
21
  function resolveAgentTurnTimeoutMs(config, sessionKey) {
10
22
  if (!config) return DEFAULT_AGENT_TURN_TIMEOUT_MS;
11
23
  const configured = resolveEffectiveAgentManifestForSession(config, sessionKey).runtime?.timeoutMs;
@@ -15,22 +27,31 @@ function resolveAgentTurnTimeoutMs(config, sessionKey) {
15
27
  function isAgentTurnTimeoutError(err) {
16
28
  return err instanceof Error && err.message.startsWith("Agent turn timed out after");
17
29
  }
18
- async function runAgentTurnWithTimeout(agent, runTurn, timeoutMs) {
30
+ async function runAgentTurnWithTimeout(agent, runTurn, timeoutMs, options = {}) {
19
31
  let timeoutId;
20
32
  const timeoutPromise = new Promise((_, reject) => {
21
33
  timeoutId = setTimeout(() => reject(/* @__PURE__ */ new Error(`Agent turn timed out after ${timeoutMs / 1e3}s`)), timeoutMs);
22
34
  });
35
+ const runTurnPromise = Promise.resolve().then(runTurn);
23
36
  try {
24
- await Promise.race([runTurn().finally(() => {
37
+ await Promise.race([runTurnPromise.finally(() => {
25
38
  if (timeoutId !== void 0) clearTimeout(timeoutId);
26
39
  }), timeoutPromise]);
27
40
  } catch (err) {
28
41
  if (isAgentTurnTimeoutError(err)) {
29
42
  agent.abort();
30
- await agent.waitForIdle();
43
+ const abortGraceMs = options.abortGraceMs ?? 5e3;
44
+ let graceTimer;
45
+ try {
46
+ await Promise.race([Promise.allSettled([runTurnPromise, agent.waitForIdle()]), new Promise((_, reject) => {
47
+ graceTimer = setTimeout(() => reject(new AgentTurnUnsettledError(timeoutMs, abortGraceMs)), abortGraceMs);
48
+ })]);
49
+ } finally {
50
+ if (graceTimer !== void 0) clearTimeout(graceTimer);
51
+ }
31
52
  }
32
53
  throw err;
33
54
  }
34
55
  }
35
56
  //#endregion
36
- export { DEFAULT_AGENT_TURN_TIMEOUT_MS, MAX_AGENT_TURN_TIMEOUT_MS, MIN_AGENT_TURN_TIMEOUT_MS, isAgentTurnTimeoutError, resolveAgentTurnTimeoutMs, runAgentTurnWithTimeout };
57
+ export { AgentTurnUnsettledError, DEFAULT_AGENT_ABORT_GRACE_MS, DEFAULT_AGENT_TURN_TIMEOUT_MS, MAX_AGENT_TURN_TIMEOUT_MS, MIN_AGENT_TURN_TIMEOUT_MS, isAgentTurnTimeoutError, isAgentTurnUnsettledError, resolveAgentTurnTimeoutMs, runAgentTurnWithTimeout };
@@ -3,15 +3,28 @@
3
3
  *
4
4
  * Replaces the ad-hoc `eventQueue + resolveWaiting` single-slot pattern that
5
5
  * the streaming direct turn used to manage run events. The previous pattern was
6
- * lossy if two pushes landed before the single waiter resumed; this queue keeps
7
- * the buffer growing until consumed, and closes cleanly so the iterator drains.
6
+ * lossy if two pushes landed before the single waiter resumed; this queue buffers
7
+ * until consumed, supports an explicit bound, and drains cleanly on close.
8
8
  */
9
+ export interface AsyncQueueOptions<T> {
10
+ /** Maximum buffer size. Lossy events are evicted; critical-only overflow fails fast. */
11
+ maxBuffered?: number;
12
+ isDroppable?: (value: T) => boolean;
13
+ }
14
+ export declare class AsyncQueueOverflowError extends Error {
15
+ readonly maxBuffered: number;
16
+ constructor(maxBuffered: number);
17
+ }
9
18
  export declare class AsyncQueue<T> implements AsyncIterable<T> {
19
+ private readonly options;
10
20
  private readonly buffer;
11
21
  private readonly waiters;
12
22
  private closed;
23
+ private dropped;
24
+ constructor(options?: AsyncQueueOptions<T>);
13
25
  /** Push a value to the queue. No-op when the queue is closed. */
14
- push(value: T): void;
26
+ push(value: T): boolean;
27
+ get droppedCount(): number;
15
28
  /** Close the queue. Pending iterators drain any buffered values and then complete. */
16
29
  close(): void;
17
30
  /** True if the queue is closed and the internal buffer is drained. */
@@ -1,25 +1,43 @@
1
1
  //#region src/agent/service/async-queue.ts
2
- /**
3
- * Async FIFO queue with `for await` support.
4
- *
5
- * Replaces the ad-hoc `eventQueue + resolveWaiting` single-slot pattern that
6
- * the streaming direct turn used to manage run events. The previous pattern was
7
- * lossy if two pushes landed before the single waiter resumed; this queue keeps
8
- * the buffer growing until consumed, and closes cleanly so the iterator drains.
9
- */
2
+ var AsyncQueueOverflowError = class extends Error {
3
+ constructor(maxBuffered) {
4
+ super(`Async queue exceeded its ${maxBuffered}-event buffer`);
5
+ this.maxBuffered = maxBuffered;
6
+ this.name = "AsyncQueueOverflowError";
7
+ }
8
+ };
10
9
  var AsyncQueue = class {
11
10
  buffer = [];
12
11
  waiters = [];
13
12
  closed = false;
13
+ dropped = 0;
14
+ constructor(options = {}) {
15
+ this.options = options;
16
+ }
14
17
  /** Push a value to the queue. No-op when the queue is closed. */
15
18
  push(value) {
16
- if (this.closed) return;
19
+ if (this.closed) return false;
17
20
  const waiter = this.waiters.shift();
18
21
  if (waiter) {
19
22
  waiter(value);
20
- return;
23
+ return true;
24
+ }
25
+ const maxBuffered = this.options.maxBuffered;
26
+ if (maxBuffered && this.buffer.length >= maxBuffered) {
27
+ const droppableIndex = this.options.isDroppable ? this.buffer.findIndex(this.options.isDroppable) : -1;
28
+ if (droppableIndex >= 0) {
29
+ this.buffer.splice(droppableIndex, 1);
30
+ this.dropped += 1;
31
+ } else if (this.options.isDroppable?.(value)) {
32
+ this.dropped += 1;
33
+ return false;
34
+ } else throw new AsyncQueueOverflowError(maxBuffered);
21
35
  }
22
36
  this.buffer.push(value);
37
+ return true;
38
+ }
39
+ get droppedCount() {
40
+ return this.dropped;
23
41
  }
24
42
  /** Close the queue. Pending iterators drain any buffered values and then complete. */
25
43
  close() {
@@ -48,4 +66,4 @@ var AsyncQueue = class {
48
66
  };
49
67
  const CLOSE_SENTINEL = Symbol("AsyncQueue.close");
50
68
  //#endregion
51
- export { AsyncQueue };
69
+ export { AsyncQueue, AsyncQueueOverflowError };