@xopcai/xopc 0.0.252 → 0.0.254

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 (220) hide show
  1. package/dist/browser-ext/dist/background.js +59 -13
  2. package/dist/browser-ext/dist/content.js +0 -5
  3. package/dist/browser-ext/manifest.json +2 -1
  4. package/dist/extensions/telegram/src/inbound-processor.js +2 -2
  5. package/dist/extensions/telegram/src/plugin.js +3 -2
  6. package/dist/extensions/telegram/xopc.extension.json +1 -1
  7. package/dist/gateway/static/root/assets/{activity-store-w3eq3YpP.js → activity-store-Ci5Rxmi_.js} +1 -1
  8. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-k039rbUz.js → agent-avatar-dicebear-D82jpmFL.js} +1 -1
  9. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-vul32IsP.js +1 -0
  10. package/dist/gateway/static/root/assets/{agents-Bmth_bSQ.js → agents-p3kWyz1T.js} +1 -1
  11. package/dist/gateway/static/root/assets/{api-2joIfbrH.js → api-CXIzQJ2Z.js} +1 -1
  12. package/dist/gateway/static/root/assets/{app-management-settings-panel-ByJ4kiD0.js → app-management-settings-panel-mhxcQpkQ.js} +1 -1
  13. package/dist/gateway/static/root/assets/{appearance-settings-BK2Jga-B.js → appearance-settings-BIMwACUF.js} +1 -1
  14. package/dist/gateway/static/root/assets/apps-page-CJFJKNwS.js +1 -0
  15. package/dist/gateway/static/root/assets/{archive-plugin-DMDKtYpi.js → archive-plugin-C63Xp_sU.js} +1 -1
  16. package/dist/gateway/static/root/assets/{attachment-load-B764Ql3Z.js → attachment-load-D12KYOav.js} +1 -1
  17. package/dist/gateway/static/root/assets/{automations-page-D-sO8CZe.js → automations-page-DXj0o5CY.js} +1 -1
  18. package/dist/gateway/static/root/assets/automations-workspace-B2wxcpgq.js +6 -0
  19. package/dist/gateway/static/root/assets/{binary-plugins-fxtzYRpv.js → binary-plugins-Bcv8hun6.js} +1 -1
  20. package/dist/gateway/static/root/assets/{block-editor-Bcjtvckh.js → block-editor-C61LqK_-.js} +50 -50
  21. package/dist/gateway/static/root/assets/{browser-automation-inputs-BSmnusjD.js → browser-automation-inputs-CAclu735.js} +1 -1
  22. package/dist/gateway/static/root/assets/{browser-automations-page-DC_OQIBk.js → browser-automations-page-BITfKX8L.js} +2 -2
  23. package/dist/gateway/static/root/assets/browser-settings-page-BMjY8cyv.js +8 -0
  24. package/dist/gateway/static/root/assets/capabilities-settings-panel-wB3Vgmp3.js +7 -0
  25. package/dist/gateway/static/root/assets/channels-settings-U5ffzu4r.js +1 -0
  26. package/dist/gateway/static/root/assets/{channels-status-swr-BuWjIG_a.js → channels-status-swr-Cmbx0E8O.js} +1 -1
  27. package/dist/gateway/static/root/assets/{chat-terminal-dock-5SevEo_I.js → chat-terminal-dock-CNBgHN9U.js} +1 -1
  28. package/dist/gateway/static/root/assets/connectors-page-BGaF--m5.js +2 -0
  29. package/dist/gateway/static/root/assets/{cron-expression-DtsfalBM.js → cron-expression-DCTN4QAG.js} +1 -1
  30. package/dist/gateway/static/root/assets/{date-picker-tDEQV5TP.js → date-picker-BuEyUxZn.js} +1 -1
  31. package/dist/gateway/static/root/assets/{dependency-picker-HhNwg0Y2.js → dependency-picker-l6IXzk0C.js} +1 -1
  32. package/dist/gateway/static/root/assets/{desktop-pet-acU4Li-C.js → desktop-pet-cGn_20DO.js} +1 -1
  33. package/dist/gateway/static/root/assets/{desktop-pet-settings-R84AR0Pe.js → desktop-pet-settings-DIfccDKS.js} +1 -1
  34. package/dist/gateway/static/root/assets/{extension-debug-page-CrLlRkSN.js → extension-debug-page-CTS5RP_D.js} +1 -1
  35. package/dist/gateway/static/root/assets/{extension-page-BH5lmZXE.js → extension-page-Dg9YssYH.js} +1 -1
  36. package/dist/gateway/static/root/assets/{extension-settings-page-BscjNAd1.js → extension-settings-page-CWZYL8Fi.js} +1 -1
  37. package/dist/gateway/static/root/assets/{gateway-config-swr-9HidFZUd.js → gateway-config-swr-Chsr5wGH.js} +1 -1
  38. package/dist/gateway/static/root/assets/gateway-settings-vHI_Que8.js +1 -0
  39. package/dist/gateway/static/root/assets/{gateway-startup-retry-DRCPXONr.js → gateway-startup-retry-C9ynH6VV.js} +1 -1
  40. package/dist/gateway/static/root/assets/{heartbeat-settings-K5Zhl2rx.js → heartbeat-settings-WUhSfvob.js} +1 -1
  41. package/dist/gateway/static/root/assets/home-page-CYjlMzPx.js +1 -0
  42. package/dist/gateway/static/root/assets/{image-generation-api-CR6Kle8H.js → image-generation-api-D_TsVe7h.js} +1 -1
  43. package/dist/gateway/static/root/assets/index-BBlJYVxR.js +74 -0
  44. package/dist/gateway/static/root/assets/index-_I0dD2LN.css +2 -0
  45. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-B1QR49-7.js → keyboard-shortcuts-settings-DGBf6YfD.js} +1 -1
  46. package/dist/gateway/static/root/assets/local-app-workbench-page-CLlIl83V.js +2 -0
  47. package/dist/gateway/static/root/assets/{local-apps-page-C74It-T8.js → local-apps-page-DGWP_xsQ.js} +1 -1
  48. package/dist/gateway/static/root/assets/{locale-store-BfZGZKSs.js → locale-store-B2v8mNJw.js} +1 -1
  49. package/dist/gateway/static/root/assets/logs-page-DuhCigiB.js +2 -0
  50. package/dist/gateway/static/root/assets/{management-settings-1kNnYL97.js → management-settings-DUAZ-dtt.js} +1 -1
  51. package/dist/gateway/static/root/assets/markdown-view-DBWu9d_n.js +201 -0
  52. package/dist/gateway/static/root/assets/{media-plugins-B5c0AoS1.js → media-plugins-CsUjcIBy.js} +1 -1
  53. package/dist/gateway/static/root/assets/messages-ChSTFZR5.js +3 -0
  54. package/dist/gateway/static/root/assets/{mobile-pairing-wizard-CsIZqK51.js → mobile-pairing-wizard-Dxu8twiQ.js} +1 -1
  55. package/dist/gateway/static/root/assets/note-detail-panel-DMdbaTZp.js +5 -0
  56. package/dist/gateway/static/root/assets/notes-page-xe_vX0nM.js +8 -0
  57. package/dist/gateway/static/root/assets/{page-tabs-CqJN6Ljz.js → page-tabs-YeJKwV-7.js} +1 -1
  58. package/dist/gateway/static/root/assets/{preview-open-alternatives-DqRIGxf4.js → preview-open-alternatives-BfJ3jMDG.js} +1 -1
  59. package/dist/gateway/static/root/assets/{product-open-page-DE2nPE_K.js → product-open-page-B7NRGPox.js} +1 -1
  60. package/dist/gateway/static/root/assets/project-detail-page-hG7ELibZ.js +1 -0
  61. package/dist/gateway/static/root/assets/projects-page-C5G2ET4w.js +1 -0
  62. package/dist/gateway/static/root/assets/{registry-api-Bpy8XX-5.js → registry-api-B9OZUdwC.js} +1 -1
  63. package/dist/gateway/static/root/assets/{remote-access-hub-Dnd73xWt.js → remote-access-hub-DTO-faxH.js} +1 -1
  64. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-Bb4b74-P.js → runtime-tools-settings-panel-uJ8Br3ZL.js} +1 -1
  65. package/dist/gateway/static/root/assets/{schema-form-DoPU5j3J.js → schema-form-CXwn6up5.js} +1 -1
  66. package/dist/gateway/static/root/assets/sessions-page-CwzsUCgP.js +1 -0
  67. package/dist/gateway/static/root/assets/settings-advanced-gate-Djc3EdoO.js +1 -0
  68. package/dist/gateway/static/root/assets/{settings-form-section-Ci-9WajJ.js → settings-form-section-YVNYsR0U.js} +1 -1
  69. package/dist/gateway/static/root/assets/{settings-page-CL_2F95D.js → settings-page-cHqrIdVR.js} +1 -1
  70. package/dist/gateway/static/root/assets/setup-status-panel-MUAMcZLD.js +1 -0
  71. package/dist/gateway/static/root/assets/{share-preview-page-XUA3oKQX.js → share-preview-page-DnjSDQru.js} +1 -1
  72. package/dist/gateway/static/root/assets/shares-settings-C7A0aywX.js +1 -0
  73. package/dist/gateway/static/root/assets/skill-reload-api-D1xSGJAQ.js +1 -0
  74. package/dist/gateway/static/root/assets/{skills-page-sXXAZDc9.js → skills-page-DkrGEdiY.js} +1 -1
  75. package/dist/gateway/static/root/assets/{skills-page.utils-DD79Bl1I.js → skills-page.utils-CqZbiZuK.js} +1 -1
  76. package/dist/gateway/static/root/assets/{system-settings-panel-BEH64qBV.js → system-settings-panel-Dmw0RfxZ.js} +1 -1
  77. package/dist/gateway/static/root/assets/task-detail-page-BvZSCLUH.js +1 -0
  78. package/dist/gateway/static/root/assets/{theme-store-CISSxU1c.js → theme-store-CubltMKm.js} +1 -1
  79. package/dist/gateway/static/root/assets/{tunnel-api-DrKDhnJm.js → tunnel-api-CiieC6HP.js} +1 -1
  80. package/dist/gateway/static/root/assets/{use-autosave-CPYePL-Q.js → use-autosave-XQ3SuyB9.js} +1 -1
  81. package/dist/gateway/static/root/assets/user-model-page-BKJC7tyW.js +2 -0
  82. package/dist/gateway/static/root/assets/{voice-api-key-field-DKqzrCXx.js → voice-api-key-field-D4QzVgdt.js} +1 -1
  83. package/dist/gateway/static/root/assets/{voice-config-api-e9xWjwBX.js → voice-config-api-B1ZbyVmF.js} +1 -1
  84. package/dist/gateway/static/root/assets/{work-discovery-overlay-kTQug6bq.js → work-discovery-overlay-D5Tf8GRZ.js} +1 -1
  85. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-m9SKj_GT.js → workflow-run-setup-panel-BW9p8Maz.js} +2 -2
  86. package/dist/gateway/static/root/assets/workflows-page-DuqRodIc.js +5 -0
  87. package/dist/gateway/static/root/index.html +10 -10
  88. package/dist/package.js +1 -1
  89. package/dist/packages/realtime-protocol/src/voice.js +6 -1
  90. package/dist/src/agent/agent-manager.js +24 -7
  91. package/dist/src/agent/background-review/run-background-review.js +1 -1
  92. package/dist/src/agent/embedded/execution-context.d.ts +2 -1
  93. package/dist/src/agent/embedded/execution-context.js +10 -4
  94. package/dist/src/agent/embedded/index.d.ts +1 -1
  95. package/dist/src/agent/embedded/index.js +2 -2
  96. package/dist/src/agent/embedded/model-runtime.js +1 -1
  97. package/dist/src/agent/embedded/run-for-session.js +5 -4
  98. package/dist/src/agent/embedded/run-turn.js +22 -3
  99. package/dist/src/agent/embedded/types.d.ts +1 -1
  100. package/dist/src/agent/image/tool-model-config.js +1 -1
  101. package/dist/src/agent/mcp/oauth/mcp-oauth-store.js +1 -1
  102. package/dist/src/agent/service/direct-turn-helpers.js +6 -3
  103. package/dist/src/agent/service/process-direct-streaming.js +6 -3
  104. package/dist/src/agent/service.d.ts +2 -0
  105. package/dist/src/agent/service.js +23 -9
  106. package/dist/src/agent/session/session-inspector.js +1 -1
  107. package/dist/src/agent/skills/hub-lock.js +1 -1
  108. package/dist/src/agent/tasks/task-judge-service.js +3 -3
  109. package/dist/src/agent/tools/browser/tool/browser-use-tool.js +17 -2
  110. package/dist/src/agent/tools/browser/tool/schemas.d.ts +85 -1
  111. package/dist/src/agent/tools/browser/tool/schemas.js +212 -5
  112. package/dist/src/agent/tools/clarify-tool.d.ts +17 -3
  113. package/dist/src/agent/tools/clarify-tool.js +27 -32
  114. package/dist/src/agent/tools/cli-clarify.js +23 -8
  115. package/dist/src/agent/tools/factory.js +14 -4
  116. package/dist/src/ai-assist/text-assist.js +1 -1
  117. package/dist/src/auth/credentials.js +2 -2
  118. package/dist/src/auth/oauth/xopc-cloud.js +1 -1
  119. package/dist/src/auth/profiles/store.js +1 -1
  120. package/dist/src/auth/sync-provider-auth.js +2 -2
  121. package/dist/src/automations/domain/validation.d.ts +4 -4
  122. package/dist/src/automations/draft/automation-draft-validator.d.ts +1 -1
  123. package/dist/src/browser/drivers/extension-driver.d.ts +4 -4
  124. package/dist/src/browser/drivers/extension-driver.js +20 -8
  125. package/dist/src/browser/drivers/playwright-driver.js +1 -1
  126. package/dist/src/browser/providers/browser-ext-install.d.ts +3 -0
  127. package/dist/src/browser/providers/browser-ext-install.js +19 -4
  128. package/dist/src/browser/providers/extension.d.ts +14 -1
  129. package/dist/src/browser/providers/extension.js +89 -11
  130. package/dist/src/browser/providers/playwright-install.js +8 -12
  131. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  132. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  133. package/dist/src/cli/commands/models.js +1 -1
  134. package/dist/src/config/index.js +4 -4
  135. package/dist/src/config/loader.js +2 -2
  136. package/dist/src/config/models-json.js +1 -1
  137. package/dist/src/extensions/lockfile.js +1 -1
  138. package/dist/src/gateway/agents-admin.js +1 -1
  139. package/dist/src/gateway/chat-stream/mapper.js +5 -1
  140. package/dist/src/gateway/chat-stream/protocol.d.ts +5 -1
  141. package/dist/src/gateway/clarify-runtime.d.ts +7 -5
  142. package/dist/src/gateway/clarify-runtime.js +8 -11
  143. package/dist/src/gateway/ephemeral-clarification-waiter.d.ts +17 -0
  144. package/dist/src/gateway/ephemeral-clarification-waiter.js +46 -0
  145. package/dist/src/gateway/file-path-classifier.js +1 -1
  146. package/dist/src/gateway/heartbeat/service.js +1 -1
  147. package/dist/src/gateway/hono/lib/config-payload.js +1 -1
  148. package/dist/src/gateway/hono/routes/agent-stream.js +44 -18
  149. package/dist/src/gateway/hono/routes/browser.js +149 -27
  150. package/dist/src/gateway/hono/routes/lazy-bundles.js +1 -1
  151. package/dist/src/gateway/hono/routes/models.js +1 -1
  152. package/dist/src/gateway/hono/routes/session-input-handler.d.ts +10 -2
  153. package/dist/src/gateway/hono/routes/side-chats.js +24 -4
  154. package/dist/src/gateway/security/gateway-scopes.js +1 -1
  155. package/dist/src/gateway/service/agent-runner.d.ts +25 -36
  156. package/dist/src/gateway/service/agent-runner.js +103 -32
  157. package/dist/src/gateway/service/config-coordinator.js +1 -1
  158. package/dist/src/gateway/service/run-gateway-agent.js +5 -2
  159. package/dist/src/gateway/service/session-input-coordinator.js +4 -1
  160. package/dist/src/gateway/service/sessions-api.js +1 -1
  161. package/dist/src/gateway/service.d.ts +4 -2
  162. package/dist/src/gateway/service.js +36 -20
  163. package/dist/src/gateway/side-chat/manager.d.ts +2 -1
  164. package/dist/src/gateway/side-chat/manager.js +5 -4
  165. package/dist/src/gateway/side-chat/run-service.d.ts +5 -1
  166. package/dist/src/gateway/side-chat/run-service.js +24 -23
  167. package/dist/src/gateway/side-chat/types.d.ts +3 -1
  168. package/dist/src/heartbeat/index.js +1 -1
  169. package/dist/src/providers/auth-runtime/resolve-auth.js +1 -1
  170. package/dist/src/providers/index.js +2 -2
  171. package/dist/src/providers/model-registry.js +1 -1
  172. package/dist/src/providers/model-thinking.js +57 -20
  173. package/dist/src/providers/register-runtime-providers.js +1 -1
  174. package/dist/src/storage/sqlite/clarification-wait-repository.d.ts +41 -0
  175. package/dist/src/storage/sqlite/clarification-wait-repository.js +418 -0
  176. package/dist/src/storage/sqlite/index.d.ts +2 -1
  177. package/dist/src/storage/sqlite/index.js +2 -1
  178. package/dist/src/storage/sqlite/migrations/154_session_clarification_waits.sql +60 -0
  179. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  180. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  181. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  182. package/dist/src/storage/sqlite/schema.js +1 -1
  183. package/dist/src/storage/sqlite/session-input-repository.d.ts +11 -6
  184. package/dist/src/tui/tui-startup-resources.js +1 -1
  185. package/dist/src/tui/tui.js +1 -1
  186. package/dist/src/voice/realtime/agentEngine.js +7 -2
  187. package/dist/src/voice/realtime/runtime.types.d.ts +5 -0
  188. package/dist/src/work-discovery/service.js +1 -1
  189. package/dist/src/workflows/service/workflow-run-service.js +1 -1
  190. package/package.json +3 -3
  191. package/skills/creative/hatch-pet/SKILL.md +1 -1
  192. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-D4J4oq8p.js +0 -1
  193. package/dist/gateway/static/root/assets/apps-page-B3ky7cWU.js +0 -1
  194. package/dist/gateway/static/root/assets/automations-workspace-Ds5-_-9z.js +0 -6
  195. package/dist/gateway/static/root/assets/browser-settings-page-C1FojyG6.js +0 -3
  196. package/dist/gateway/static/root/assets/capabilities-settings-panel-Bs59UCut.js +0 -7
  197. package/dist/gateway/static/root/assets/channels-settings-CM9vNmoo.js +0 -1
  198. package/dist/gateway/static/root/assets/connectors-page-BPZ44D-V.js +0 -2
  199. package/dist/gateway/static/root/assets/gateway-settings-BxLcW6ij.js +0 -1
  200. package/dist/gateway/static/root/assets/home-page-CZAg9RBv.js +0 -1
  201. package/dist/gateway/static/root/assets/index-D4Ykja-U.js +0 -72
  202. package/dist/gateway/static/root/assets/index-zIJ3AXgR.css +0 -2
  203. package/dist/gateway/static/root/assets/local-app-workbench-page-wicoV-ti.js +0 -2
  204. package/dist/gateway/static/root/assets/logs-page-xX-7S49A.js +0 -2
  205. package/dist/gateway/static/root/assets/markdown-view-DjiwT28p.js +0 -201
  206. package/dist/gateway/static/root/assets/messages-DaIwVWar.js +0 -3
  207. package/dist/gateway/static/root/assets/note-detail-panel-CfWxopl4.js +0 -5
  208. package/dist/gateway/static/root/assets/notes-page-CYN-LCHJ.js +0 -8
  209. package/dist/gateway/static/root/assets/project-detail-page-B5G3LzDq.js +0 -1
  210. package/dist/gateway/static/root/assets/projects-page-CuVK2mKu.js +0 -1
  211. package/dist/gateway/static/root/assets/sessions-page-XL4LyKZe.js +0 -1
  212. package/dist/gateway/static/root/assets/settings-advanced-gate-0ForzDSS.js +0 -1
  213. package/dist/gateway/static/root/assets/setup-status-panel-DVws6XZc.js +0 -1
  214. package/dist/gateway/static/root/assets/shares-settings-BwDvcacF.js +0 -1
  215. package/dist/gateway/static/root/assets/skill-reload-api-BJjrATqE.js +0 -1
  216. package/dist/gateway/static/root/assets/task-detail-page-0jxMi75O.js +0 -1
  217. package/dist/gateway/static/root/assets/user-model-page-B6zLDfDl.js +0 -2
  218. package/dist/gateway/static/root/assets/workflows-page-Bcd1XqP7.js +0 -5
  219. package/dist/src/gateway/clarify-bridge.d.ts +0 -46
  220. package/dist/src/gateway/clarify-bridge.js +0 -111
@@ -1,15 +1,20 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
3
  import { listActiveSessionInputRuns } from "../../storage/sqlite/session-input-repository.js";
4
+ import { createClarificationWait, getClarification, getClarificationSnapshot, resolveClarification, supersedeActiveClarification } from "../../storage/sqlite/clarification-wait-repository.js";
4
5
  import { onConnectionWaitChanged } from "../../storage/sqlite/connection-wait-repository.js";
5
6
  import "../../storage/sqlite/index.js";
6
- import { ClarifyBridge } from "../clarify-bridge.js";
7
+ import { EphemeralClarificationWaiter } from "../ephemeral-clarification-waiter.js";
7
8
  import { runGatewayAgent } from "./run-gateway-agent.js";
8
9
  import { fitSourceContextsToBudget } from "../../agent/source-context/budget.js";
9
10
  import { SessionInputCoordinator } from "./session-input-coordinator.js";
10
11
  import crypto from "node:crypto";
11
12
  //#region src/gateway/service/agent-runner.ts
12
13
  init_logger();
14
+ /**
15
+ * Owns gateway agent runs, durable clarification coordination, and the
16
+ * lifecycle-bound clarification waiter used by ephemeral side chats.
17
+ */
13
18
  const log = createLogger("Gateway:AgentRunner");
14
19
  const MAX_TURN_CONTEXTS = 5;
15
20
  var GatewayAgentRunner = class {
@@ -18,11 +23,10 @@ var GatewayAgentRunner = class {
18
23
  runAbortControllers = /* @__PURE__ */ new Map();
19
24
  runCompletions = /* @__PURE__ */ new Map();
20
25
  resolveRunCompletions = /* @__PURE__ */ new Map();
21
- clarifyBridge = new ClarifyBridge();
26
+ ephemeralClarifications = new EphemeralClarificationWaiter();
22
27
  /** Maps webchat session key → active `runId` for `clarify` tool routing. */
23
28
  activeWebchatRunBySession = /* @__PURE__ */ new Map();
24
29
  externalStreamBySession = /* @__PURE__ */ new Map();
25
- externalClarificationTimeouts = /* @__PURE__ */ new Map();
26
30
  externalClarificationResponses = /* @__PURE__ */ new Map();
27
31
  inputs;
28
32
  unsubscribeConnectionWait;
@@ -104,30 +108,24 @@ var GatewayAgentRunner = class {
104
108
  runId
105
109
  }));
106
110
  }
107
- getClarifyBridge() {
108
- return this.clarifyBridge;
109
- }
110
- /** Called from `GatewayService.stop()` so the bridge gets cleaned up. */
111
- disposeClarifyBridge() {
112
- this.clarifyBridge.dispose();
111
+ disposeClarifications() {
112
+ this.ephemeralClarifications.dispose();
113
113
  this.unsubscribeConnectionWait();
114
114
  }
115
115
  registerExternalWebchatRun(sessionKey, runId, publish, options) {
116
116
  this.activeWebchatRunBySession.set(sessionKey, runId);
117
117
  this.externalStreamBySession.set(sessionKey, publish);
118
- if (options?.clarificationTimeoutMs !== void 0) this.externalClarificationTimeouts.set(sessionKey, options.clarificationTimeoutMs);
119
118
  if (options?.beforeClarificationResponse) this.externalClarificationResponses.set(sessionKey, options.beforeClarificationResponse);
120
119
  }
121
120
  unregisterExternalWebchatRun(sessionKey, runId) {
122
121
  if (this.activeWebchatRunBySession.get(sessionKey) === runId) {
123
122
  this.activeWebchatRunBySession.delete(sessionKey);
124
123
  this.externalStreamBySession.delete(sessionKey);
125
- this.externalClarificationTimeouts.delete(sessionKey);
126
124
  this.externalClarificationResponses.delete(sessionKey);
127
125
  }
128
126
  }
129
127
  cancelClarificationForRun(runId) {
130
- this.clarifyBridge.cancelForRun(runId);
128
+ this.ephemeralClarifications.cancelForRun(runId);
131
129
  }
132
130
  async *runAgent(message, channel, chatId, origin, attachments, thinking, runOptions) {
133
131
  const trackedRunId = runOptions?.runId;
@@ -185,7 +183,7 @@ var GatewayAgentRunner = class {
185
183
  }
186
184
  /** Abort an in-flight webchat agent run. */
187
185
  async abortAgentRun(runId) {
188
- this.clarifyBridge.cancelForRun(runId);
186
+ this.ephemeralClarifications.cancelForRun(runId);
189
187
  const keysToMark = [];
190
188
  for (const [sk, id] of this.activeWebchatRunBySession) if (id === runId) keysToMark.push(sk);
191
189
  const c = this.runAbortControllers.get(runId);
@@ -194,10 +192,13 @@ var GatewayAgentRunner = class {
194
192
  idle: true
195
193
  };
196
194
  const completion = this.runCompletions.get(runId);
197
- for (const sk of keysToMark) this.opts.sessionIndex.appendTranscriptContextEntry(sk, {
198
- text: "Webchat agent run aborted",
199
- data: { runId }
200
- }).catch(() => {});
195
+ for (const sk of keysToMark) {
196
+ if ((getClarificationSnapshot(sk)?.clarification)?.originRunId === runId) supersedeActiveClarification(sk);
197
+ this.opts.sessionIndex.appendTranscriptContextEntry(sk, {
198
+ text: "Webchat agent run aborted",
199
+ data: { runId }
200
+ }).catch(() => {});
201
+ }
201
202
  c.abort();
202
203
  const { abortEmbeddedRun } = await import("../../agent/embedded/runs.js");
203
204
  await Promise.all(keysToMark.map((sessionKey) => abortEmbeddedRun(sessionKey).catch(() => false)));
@@ -207,9 +208,45 @@ var GatewayAgentRunner = class {
207
208
  idle: true
208
209
  };
209
210
  }
210
- /** Deliver a user's answer to a pending `clarify` tool call. */
211
- submitClarifyResponse(requestId, answer) {
212
- return this.clarifyBridge.handleResponse(requestId, answer);
211
+ answerEphemeralClarification(requestId, answer) {
212
+ return this.ephemeralClarifications.answer(requestId, answer);
213
+ }
214
+ getClarificationState(sessionKey) {
215
+ return getClarificationSnapshot(sessionKey);
216
+ }
217
+ resolveClarificationResponse(input) {
218
+ const result = resolveClarification(input);
219
+ if (result.ok) {
220
+ this.opts.emit("clarification.updated", result.clarification);
221
+ if (result.queued) this.inputs.drain(result.clarification.sessionKey);
222
+ }
223
+ return result;
224
+ }
225
+ getClarificationById(id) {
226
+ return getClarification(id);
227
+ }
228
+ answerClarificationChoice(requestId, choiceIndex, idempotencyKey) {
229
+ const wait = getClarification(requestId);
230
+ const answer = wait?.status === "open" ? wait.choices?.[choiceIndex] : void 0;
231
+ if (!answer) return false;
232
+ return this.resolveClarificationResponse({
233
+ id: wait.id,
234
+ expectedVersion: wait.version,
235
+ idempotencyKey,
236
+ action: "answer",
237
+ answer
238
+ }).ok;
239
+ }
240
+ answerClarificationText(sessionKey, answer, idempotencyKey) {
241
+ const wait = getClarificationSnapshot(sessionKey)?.clarification;
242
+ if (!wait || wait.status !== "open" || !answer.trim()) return false;
243
+ return this.resolveClarificationResponse({
244
+ id: wait.id,
245
+ expectedVersion: wait.version,
246
+ idempotencyKey,
247
+ action: "answer",
248
+ answer
249
+ }).ok;
213
250
  }
214
251
  /** Same execution path as scheduled continuation, but lets callers observe failures. */
215
252
  async runScheduledWebchatTurn(sessionKey, userTurn) {
@@ -243,8 +280,8 @@ var GatewayAgentRunner = class {
243
280
  }
244
281
  }
245
282
  /**
246
- * Resolve clarify-bridge config for `sessionKey`: who delivers the question
247
- * (webchat stream, Telegram message, or both), then start the bridge request.
283
+ * Persist normal clarification waits and use the lifecycle-bound waiter only
284
+ * for caller-owned ephemeral sessions.
248
285
  * Rejects when neither path is available (e.g. CLI without webchat or TG).
249
286
  *
250
287
  * `publishStreamFor(runId)` is the bridge into AgentService's
@@ -253,33 +290,67 @@ var GatewayAgentRunner = class {
253
290
  */
254
291
  async requestClarification(opts) {
255
292
  const { sessionKey, request, publishStreamFor } = opts;
256
- const runId = this.activeWebchatRunBySession.get(sessionKey);
293
+ const runId = this.activeWebchatRunBySession.get(sessionKey) ?? opts.runId;
257
294
  const publishStream = this.externalStreamBySession.get(sessionKey) ?? (runId ? publishStreamFor(runId) : void 0);
258
295
  const deliver = ((await this.opts.sessionIndex.getSessionMetadata(sessionKey).catch(() => null))?.routing)?.source === "telegram" ? async (ctx) => {
259
296
  await this.deliverTelegramClarify(ctx);
260
297
  } : void 0;
261
- if (!runId && !deliver) return Promise.reject(/* @__PURE__ */ new Error("Clarify is not available for this session (use webchat, Telegram, or CLI)"));
262
- return this.clarifyBridge.startRequest({
263
- timeoutMs: this.externalClarificationTimeouts.get(sessionKey),
298
+ const persistedSession = getClarificationSnapshot(sessionKey);
299
+ if (!persistedSession && this.externalStreamBySession.has(sessionKey)) return this.ephemeralClarifications.start({
264
300
  beforeResponse: this.externalClarificationResponses.get(sessionKey),
265
- sessionKey,
266
301
  runId,
267
- publishStream,
268
- request,
269
- deliver
302
+ publish: publishStream,
303
+ request
304
+ }).then((answer) => ({
305
+ status: "answered",
306
+ answer
307
+ }));
308
+ if (!persistedSession) return Promise.reject(/* @__PURE__ */ new Error("Clarify requires a persisted session."));
309
+ const wait = createClarificationWait({
310
+ sessionKey,
311
+ runId: opts.runId,
312
+ toolCallId: opts.toolCallId,
313
+ kind: request.kind === "approval" ? "approval" : "input",
314
+ question: request.question,
315
+ choices: request.choices,
316
+ suggestedAnswer: request.suggestedAnswer,
317
+ approvalKey: request.approvalKey
318
+ });
319
+ const event = {
320
+ type: "clarify_request",
321
+ requestId: wait.id,
322
+ kind: wait.kind,
323
+ question: wait.question,
324
+ choices: wait.choices,
325
+ suggestedAnswer: wait.suggestedAnswer,
326
+ expiresAt: wait.expiresAt,
327
+ createdAt: wait.createdAt,
328
+ version: wait.version
329
+ };
330
+ if (this.activeWebchatRunBySession.has(sessionKey)) publishStream?.(event);
331
+ if (deliver) await deliver({
332
+ sessionKey,
333
+ requestId: wait.id,
334
+ request
270
335
  });
336
+ return {
337
+ status: "waiting",
338
+ waitId: wait.id,
339
+ expiresAt: wait.expiresAt
340
+ };
271
341
  }
272
342
  async deliverTelegramClarify(ctx) {
273
343
  const routing = (await this.opts.sessionIndex.getSessionMetadata(ctx.sessionKey).catch(() => null))?.routing;
274
344
  if (!routing || routing.source !== "telegram") return;
275
345
  let body = ctx.request.question;
276
- if (ctx.request.default) body += `\n\nDefault if unsure: ${ctx.request.default}`;
346
+ if (ctx.request.suggestedAnswer) body += `\n\nSuggested answer (never selected automatically): ${ctx.request.suggestedAnswer}`;
347
+ body += ctx.request.kind === "approval" ? "\n\nFor safety, this approval expires after 10 minutes." : "\n\nThis question remains available until you answer or cancel the task.";
277
348
  const choices = ctx.request.choices;
278
349
  const buttonRows = choices && choices.length >= 2 ? choices.map((c, i) => [{
279
350
  text: c.length > 64 ? `${c.slice(0, 61)}…` : c,
280
351
  callback_data: `clarify:${ctx.requestId}:${i}`
281
352
  }]) : void 0;
282
- if (!buttonRows) body += "\n\nReply with your answer in this chat.";
353
+ body += buttonRows ? "\n\nReply with your answer, or tap an option below." : "\n\nReply with your answer.";
283
354
  await this.opts.getChannelManager().send({
284
355
  channel: "telegram",
285
356
  chat_id: routing.peerId,
@@ -1,7 +1,7 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
- import { loadConfig, saveConfig } from "../../config/loader.js";
4
3
  import { getModelRegistry } from "../../providers/model-registry.js";
4
+ import { loadConfig, saveConfig } from "../../config/loader.js";
5
5
  import { init_providers } from "../../providers/index.js";
6
6
  import { disposeAllSessionMcpRuntimes } from "../../agent/mcp/bundle-mcp-runtime.js";
7
7
  import { reloadImageGenerationProviders } from "../../agent/image/generation/provider-registry.js";
@@ -1,6 +1,7 @@
1
1
  import { inboundCorrelationMetadataFromAsyncLogContext, updateAsyncLogContext } from "../../utils/logger/context.js";
2
2
  import { createLogger } from "../../utils/logger/index.js";
3
3
  import { init_logger } from "../../utils/logger.js";
4
+ import { isClarificationSuspended } from "../../storage/sqlite/clarification-wait-repository.js";
4
5
  import { updateInteractionStateFromMessage } from "../../storage/sqlite/interaction-state-repository.js";
5
6
  import { getConnectionResumeInput, isConnectionSuspended } from "../../storage/sqlite/connection-wait-repository.js";
6
7
  import "../../storage/sqlite/index.js";
@@ -144,9 +145,11 @@ async function* runGatewayAgent(deps, message, channel, chatId, origin, attachme
144
145
  for await (const event of eventStream) yield* mapper.map(event);
145
146
  })();
146
147
  for await (const event of coalesceThinkingDeltas(mappedEvents)) yield* emitAndYield([event]);
147
- const suspended = isConnectionSuspended(sessionKey, runId);
148
+ const connectionSuspended = isConnectionSuspended(sessionKey, runId);
149
+ const clarificationSuspended = isClarificationSuspended(sessionKey, runId);
150
+ const suspended = connectionSuspended || clarificationSuspended;
148
151
  const endStatus = mergedSignal.aborted ? "cancelled" : suspended ? "suspended" : "success";
149
- const endSummary = mergedSignal.aborted ? "Interrupted" : suspended ? "Waiting for connection" : "Message processed successfully";
152
+ const endSummary = mergedSignal.aborted ? "Interrupted" : connectionSuspended ? "Waiting for connection" : clarificationSuspended ? "Waiting for user input" : "Message processed successfully";
150
153
  taskRunStatus = mergedSignal.aborted ? "cancelled" : "succeeded";
151
154
  terminalStatus = endStatus;
152
155
  taskRunSummary = endSummary;
@@ -1,6 +1,7 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
3
  import { SessionInstanceChangedError, cancelQueuedSessionInput, claimNextSessionInput, findSessionInput, finishSessionInputRun, getSessionInputById, getSessionInputState, insertSessionInput, mutateQueuedSessionInput, recoverSessionInputState, setSessionInputStatus } from "../../storage/sqlite/session-input-repository.js";
4
+ import { consumeClarificationResume, supersedeActiveClarification } from "../../storage/sqlite/clarification-wait-repository.js";
4
5
  import { replaceLatestSessionTurnAndQueueInput, validateLatestSessionTurnTarget } from "../../storage/sqlite/session-turn-replace-repository.js";
5
6
  import { cancelConnectionObjective, consumeConnectionResume, invalidateConnectionResumeIntent, publishConnectionWait } from "../../storage/sqlite/connection-wait-repository.js";
6
7
  import "../../storage/sqlite/index.js";
@@ -113,6 +114,7 @@ var SessionInputCoordinator = class {
113
114
  if (result.ok === false) return result;
114
115
  if (!result.idempotent) {
115
116
  cancelConnectionObjective(sessionKey);
117
+ supersedeActiveClarification(sessionKey);
116
118
  const replacement = {
117
119
  role: "user",
118
120
  content,
@@ -187,6 +189,7 @@ var SessionInputCoordinator = class {
187
189
  targetRunId: canSteer ? runtime.activeRunId : void 0
188
190
  });
189
191
  invalidateConnectionResumeIntent(sessionKey);
192
+ supersedeActiveClarification(sessionKey);
190
193
  if (canSteer) {
191
194
  if (!await this.deps.steer(sessionKey, content)) {
192
195
  setSessionInputStatus(row.id, "queued", {
@@ -221,7 +224,7 @@ var SessionInputCoordinator = class {
221
224
  const runId = crypto.randomUUID();
222
225
  const input = claimNextSessionInput(sessionKey, runId);
223
226
  if (!input) return;
224
- if (this.deps.beforeExecute && !await this.deps.beforeExecute(input) || !consumeConnectionResume(input)) {
227
+ if (this.deps.beforeExecute && !await this.deps.beforeExecute(input) || !consumeConnectionResume(input) || !consumeClarificationResume(input)) {
225
228
  finishSessionInputRun(sessionKey, runId, "cancelled");
226
229
  this.publish(sessionKey);
227
230
  continue;
@@ -4,8 +4,8 @@ import { retireSessionMcpRuntimeForSessionKey } from "../../agent/mcp/bundle-mcp
4
4
  import "../../agent/mcp/bundle-mcp-tools.js";
5
5
  import { buildSessionTimeline } from "../../session/transcript-outline.js";
6
6
  import { transcriptRowsToClientHistory } from "../../session/client-history.js";
7
- import { withModelConfigLock } from "../../session/model-config-lock.js";
8
7
  import { collectMediaUrisFromValues, deleteMediaUris } from "../../media/session-references.js";
8
+ import { withModelConfigLock } from "../../session/model-config-lock.js";
9
9
  import { getDistinctSessionChatIds } from "./session-chat-ids.js";
10
10
  import { performSessionReset } from "../session-reset-service.js";
11
11
  import { randomUUID } from "node:crypto";
@@ -81,7 +81,7 @@ export declare class GatewayService {
81
81
  private stopRealtimeLogBridge;
82
82
  /**
83
83
  * Webchat agent invocation surface (`runAgent`, `abortAgentRun`, `steer*`,
84
- * `submitClarifyResponse`, clarify-bridge dispatch). Owns the
84
+ * clarification dispatch). Owns the
85
85
  * `activeWebchatRunBySession` + `runAbortControllers` maps.
86
86
  */
87
87
  readonly agentRunner: GatewayAgentRunner;
@@ -168,7 +168,9 @@ export declare class GatewayService {
168
168
  idle: boolean;
169
169
  }>;
170
170
  getActiveWebchatRunId(sessionKey: string): string | undefined;
171
- submitClarifyResponse(requestId: string, answer: string): boolean;
171
+ answerEphemeralClarification(requestId: string, answer: string): boolean;
172
+ getClarificationState(sessionKey: string): import("@xopcai/gateway-contract/src/clarifications.js").ClarificationWaitSnapshot;
173
+ resolveClarificationResponse(input: Parameters<GatewayAgentRunner['resolveClarificationResponse']>[0]): import("../storage/sqlite/clarification-wait-repository.js").ResolveClarificationResult;
172
174
  private initializeExtensionLoader;
173
175
  private registerExtensionChannelPlugins;
174
176
  /**
@@ -12,16 +12,16 @@ import { getSessionConfig } from "../storage/sqlite/config-repository.js";
12
12
  import "../storage/sqlite/index.js";
13
13
  import { getAgentDefaultModelRef, init_schema } from "../config/schema.js";
14
14
  import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agent/agent-scope.js";
15
- import { buildSessionKey, init_session_key, sanitizeSegment } from "../routing/session-key.js";
16
- import { getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
17
- import { resolveEffectiveAgentProfileForSession } from "../config/agent-profile.js";
18
15
  import { init_paths, resolveConfigPath, resolveExtensionsDir } from "../config/paths.js";
16
+ import { prewarmModelRegistry } from "../providers/model-registry.js";
19
17
  import { areExtensionsGloballyDisabled } from "../extensions/discover-extensions.js";
20
18
  import { buildExtensionMetadataSnapshot } from "../extensions/extension-metadata-snapshot.js";
21
19
  import { buildChannelCatalogForConfig, buildChannelCatalogFromSnapshot, init_channel_catalog_service } from "../channels/catalog/channel-catalog-service.js";
22
20
  import { loadConfig, saveConfig } from "../config/loader.js";
23
- import { prewarmModelRegistry } from "../providers/model-registry.js";
21
+ import { buildSessionKey, init_session_key, sanitizeSegment } from "../routing/session-key.js";
22
+ import { getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
24
23
  import { init_providers, providers_exports } from "../providers/index.js";
24
+ import { resolveEffectiveAgentProfileForSession } from "../config/agent-profile.js";
25
25
  import { TaskRepository } from "../tasks/task-repository.js";
26
26
  import { TaskConversationRepository } from "../tasks/task-conversation-repository.js";
27
27
  import { getEmbeddedExecutionSession } from "../agent/embedded/execution-context.js";
@@ -50,10 +50,16 @@ import "../infra/bus/index.js";
50
50
  import { AgentService } from "../agent/service.js";
51
51
  import { ensureStarterAgentsInitialized } from "../agent/starter-agents.js";
52
52
  import { setPairingBroadcastSink } from "../channels/pairing/pairing-events.js";
53
- import { registerClarifyBridge } from "./clarify-runtime.js";
53
+ import { registerClarificationChannelRuntime } from "./clarify-runtime.js";
54
54
  import { ChannelManager } from "../channels/manager.js";
55
55
  import { getWorkspacePath } from "../config/workspace-path-helpers.js";
56
56
  import "../config/index.js";
57
+ import { DiscussionService } from "../discussions/service.js";
58
+ import { DiscussionOrganizer } from "../discussions/organizer.js";
59
+ import { DiscussionLiveWorker } from "../discussions/live-worker.js";
60
+ import { DiscussionOrganizerWorker } from "../discussions/organizer-worker.js";
61
+ import { DiscussionSealer } from "../discussions/sealer.js";
62
+ import "../discussions/index.js";
57
63
  import { ManagedComposioEventPoller } from "../connectors/composio-managed-events.js";
58
64
  import { startConnectedKnowledgeCoordinator } from "../knowledge/coordinator.js";
59
65
  import "../knowledge/index.js";
@@ -61,12 +67,6 @@ import { ConnectionRecoveryService } from "../connectors/connection-recovery-ser
61
67
  import { startConnectorLearningCoordinator } from "../connectors/learning-coordinator.js";
62
68
  import { ConnectedSourceChangePublisher } from "../connectors/source-change-publisher.js";
63
69
  import { startConnectorSupervisor } from "../connectors/supervisor.js";
64
- import { DiscussionService } from "../discussions/service.js";
65
- import { DiscussionOrganizer } from "../discussions/organizer.js";
66
- import { DiscussionLiveWorker } from "../discussions/live-worker.js";
67
- import { DiscussionOrganizerWorker } from "../discussions/organizer-worker.js";
68
- import { DiscussionSealer } from "../discussions/sealer.js";
69
- import "../discussions/index.js";
70
70
  import { EndpointToolRuntime } from "../endpoint-tools/runtime.js";
71
71
  import "../endpoint-tools/index.js";
72
72
  import { assertGatewayAuthConfigured, extractToken, resolveGatewayAuth, validateToken } from "./auth.js";
@@ -97,6 +97,7 @@ import { assertGatewayRuntimeConfig } from "./runtime-config.js";
97
97
  import { auditGatewayConfig } from "./security/audit.js";
98
98
  import { getXopcCloudCatalogCoordinator } from "../providers/xopc-cloud-catalog-coordinator.js";
99
99
  import { ModelCatalogSyncService } from "../providers/model-catalog-sync-service.js";
100
+ import { collectMediaUrisFromMessages, deleteMediaUris } from "../media/session-references.js";
100
101
  import { runBootstrapMigrationsSync } from "../migrations/runner.js";
101
102
  import { NotificationService } from "../notifications/service.js";
102
103
  import { LocalAppService } from "../local-apps/service.js";
@@ -268,7 +269,7 @@ var GatewayService = class {
268
269
  stopRealtimeLogBridge = null;
269
270
  /**
270
271
  * Webchat agent invocation surface (`runAgent`, `abortAgentRun`, `steer*`,
271
- * `submitClarifyResponse`, clarify-bridge dispatch). Owns the
272
+ * clarification dispatch). Owns the
272
273
  * `activeWebchatRunBySession` + `runAbortControllers` maps.
273
274
  */
274
275
  agentRunner;
@@ -465,8 +466,12 @@ var GatewayService = class {
465
466
  getParentMetadata: (sessionKey) => this.sessionIndex.getSessionMetadata(sessionKey),
466
467
  loadParentMessages: (sessionKey) => this.sessionIndex.getStore().load(sessionKey),
467
468
  getDefaultModelRef: (sessionKey) => this.ensureAgentService().getModelForSession(sessionKey),
469
+ getDefaultThinkingLevel: (sessionKey) => this.ensureAgentService().getThinkingLevelForSession(sessionKey),
468
470
  getWorkspacePath: (metadata) => metadata.cwd || this.currentWorkspacePath,
469
- onBeforeDispose: (sideChatId, clientInstanceId) => sideChatRuns?.cancelRun(sideChatId, clientInstanceId).then(() => void 0),
471
+ onBeforeDispose: async (sideChatId, clientInstanceId, messages) => {
472
+ await sideChatRuns?.cancelRun(sideChatId, clientInstanceId);
473
+ await deleteMediaUris(collectMediaUrisFromMessages(messages));
474
+ },
470
475
  onExpired: (sideChatId, clientInstanceId, reason) => {
471
476
  const topic = `side-chat:${clientInstanceId}:${sideChatId}`;
472
477
  this.realtime.broker.publish(topic, "expired", { reason });
@@ -572,10 +577,12 @@ var GatewayService = class {
572
577
  }
573
578
  return null;
574
579
  },
575
- gatewayClarify: { requestClarification: (sessionKey, request) => {
576
- const executionSessionKey = getEmbeddedExecutionSession() ?? sessionKey;
580
+ gatewayClarify: { requestClarification: (context, request) => {
581
+ const executionSessionKey = getEmbeddedExecutionSession() ?? context.sessionKey;
577
582
  return this.agentRunner.requestClarification({
578
583
  sessionKey: executionSessionKey,
584
+ runId: context.runId,
585
+ toolCallId: context.toolCallId,
579
586
  request,
580
587
  publishStreamFor: (_runId) => (event) => {
581
588
  this._agentService.turnDispatcher.enqueueWebchatStreamEvent(executionSessionKey, event);
@@ -776,8 +783,14 @@ var GatewayService = class {
776
783
  getActiveWebchatRunId(sessionKey) {
777
784
  return this.agentRunner.getActiveRunId(sessionKey);
778
785
  }
779
- submitClarifyResponse(requestId, answer) {
780
- return this.agentRunner.submitClarifyResponse(requestId, answer);
786
+ answerEphemeralClarification(requestId, answer) {
787
+ return this.agentRunner.answerEphemeralClarification(requestId, answer);
788
+ }
789
+ getClarificationState(sessionKey) {
790
+ return this.agentRunner.getClarificationState(sessionKey);
791
+ }
792
+ resolveClarificationResponse(input) {
793
+ return this.agentRunner.resolveClarificationResponse(input);
781
794
  }
782
795
  initializeExtensionLoader() {
783
796
  try {
@@ -925,7 +938,10 @@ var GatewayService = class {
925
938
  errorMessage: readiness.error.message
926
939
  }, `Initial XOPC Cloud catalog refresh failed: ${readiness.error.message}`);
927
940
  }
928
- registerClarifyBridge(this.agentRunner.getClarifyBridge());
941
+ registerClarificationChannelRuntime({
942
+ answerChoice: (requestId, choiceIndex, idempotencyKey) => this.agentRunner.answerClarificationChoice(requestId, choiceIndex, idempotencyKey),
943
+ answerText: (sessionKey, text, idempotencyKey) => this.agentRunner.answerClarificationText(sessionKey, text, idempotencyKey)
944
+ });
929
945
  this.ensureAgentService();
930
946
  this.agentRunner.recoverSessionInputs();
931
947
  this.connectionRecovery.start();
@@ -1242,9 +1258,9 @@ var GatewayService = class {
1242
1258
  }
1243
1259
  this.browserExtensionProvider = null;
1244
1260
  this.browserExtensionBindKey = null;
1245
- registerClarifyBridge(null);
1261
+ registerClarificationChannelRuntime(null);
1246
1262
  this.connectionRecovery.stop();
1247
- this.agentRunner.disposeClarifyBridge();
1263
+ this.agentRunner.disposeClarifications();
1248
1264
  await disposeAllSessionMcpRuntimes().catch((err) => {
1249
1265
  log.warn({ err }, "MCP runtime shutdown failed");
1250
1266
  });
@@ -11,13 +11,14 @@ export interface EphemeralSideChatManagerOptions {
11
11
  getParentMetadata: (sessionKey: string) => Promise<SessionMetadata | null>;
12
12
  loadParentMessages: (sessionKey: string) => Promise<AgentMessage[]>;
13
13
  getDefaultModelRef: (sessionKey: string) => string;
14
+ getDefaultThinkingLevel?: (sessionKey: string) => ThinkingLevel;
14
15
  getWorkspacePath: (metadata: SessionMetadata) => string;
15
16
  idleTtlMs?: number;
16
17
  maxPerClient?: number;
17
18
  maxTotal?: number;
18
19
  now?: () => number;
19
20
  startSweepTimer?: boolean;
20
- onBeforeDispose?: (sideChatId: string, clientInstanceId: string) => void | Promise<void>;
21
+ onBeforeDispose?: (sideChatId: string, clientInstanceId: string, messages: AgentMessage[]) => void | Promise<void>;
21
22
  onExpired?: (sideChatId: string, clientInstanceId: string, reason: 'idle' | 'waiting') => void;
22
23
  }
23
24
  export declare class EphemeralSideChatManager {
@@ -90,7 +90,7 @@ var EphemeralSideChatManager = class {
90
90
  runtime.captureBaseline();
91
91
  const config = {
92
92
  modelRef: normalizeOptionalString(input.config?.modelRef) || this.options.getDefaultModelRef(parentSessionKey),
93
- thinkingLevel: input.config?.thinkingLevel
93
+ thinkingLevel: input.config?.thinkingLevel ?? this.options.getDefaultThinkingLevel?.(parentSessionKey) ?? "medium"
94
94
  };
95
95
  const entry = {
96
96
  id,
@@ -169,10 +169,11 @@ var EphemeralSideChatManager = class {
169
169
  }
170
170
  if (entry.clientInstanceId !== clientInstanceId) return false;
171
171
  entry.status = "closing";
172
+ const messages = entry.runtime.loadConversationMessages();
172
173
  this.entries.delete(id);
173
174
  const cleanup = (async () => {
174
175
  try {
175
- await this.runBeforeDispose(id, clientInstanceId);
176
+ await this.runBeforeDispose(id, clientInstanceId, messages);
176
177
  await evictEmbeddedSessionRunner(entry.runtime.runtimeId, "side_chat_dispose");
177
178
  return true;
178
179
  } finally {
@@ -255,9 +256,9 @@ var EphemeralSideChatManager = class {
255
256
  entry.lastActiveAt = new Date(now).toISOString();
256
257
  entry.expiresAt = entry.status === "running" ? null : new Date(now + this.idleTtlMs).toISOString();
257
258
  }
258
- async runBeforeDispose(id, clientInstanceId) {
259
+ async runBeforeDispose(id, clientInstanceId, messages) {
259
260
  try {
260
- await this.options.onBeforeDispose?.(id, clientInstanceId);
261
+ await this.options.onBeforeDispose?.(id, clientInstanceId, messages);
261
262
  } catch (err) {
262
263
  log.warn({
263
264
  err,
@@ -1,6 +1,7 @@
1
1
  import type { AgentService } from '../../agent/service.js';
2
2
  import type { GatewayAgentRunner } from '../service/agent-runner.js';
3
3
  import { type EphemeralSideChatManager } from './manager.js';
4
+ import type { UserTurnAttachment } from '../user-turn-input.js';
4
5
  export interface SideChatRunServiceOptions {
5
6
  manager: EphemeralSideChatManager;
6
7
  getAgentService: () => AgentService;
@@ -12,7 +13,10 @@ export declare class SideChatRunService {
12
13
  private readonly options;
13
14
  private readonly activeBySideChat;
14
15
  constructor(options: SideChatRunServiceOptions);
15
- submit(sideChatId: string, clientInstanceId: string, content: string): {
16
+ submit(sideChatId: string, clientInstanceId: string, input: {
17
+ content: string;
18
+ attachments?: UserTurnAttachment[];
19
+ }): {
16
20
  runId: string;
17
21
  };
18
22
  abort(sideChatId: string, clientInstanceId: string, runId?: string): Promise<boolean>;
@@ -12,9 +12,9 @@ var SideChatRunService = class {
12
12
  constructor(options) {
13
13
  this.options = options;
14
14
  }
15
- submit(sideChatId, clientInstanceId, content) {
16
- const text = content.trim();
17
- if (!text) throw new SideChatError("content is required", "INVALID_REQUEST");
15
+ submit(sideChatId, clientInstanceId, input) {
16
+ const text = input.content.trim();
17
+ if (!text && !input.attachments?.length) throw new SideChatError("content or attachments are required", "INVALID_REQUEST");
18
18
  const sideChat = this.options.manager.get(sideChatId, clientInstanceId);
19
19
  if (this.activeBySideChat.has(sideChatId)) throw new SideChatError("A side chat run is already active", "CONFLICT");
20
20
  const run = {
@@ -26,7 +26,10 @@ var SideChatRunService = class {
26
26
  };
27
27
  this.activeBySideChat.set(sideChatId, run);
28
28
  this.options.manager.setStatus(sideChatId, clientInstanceId, "running", run.runId);
29
- this.execute(run, text, sideChat.config).catch((err) => {
29
+ this.execute(run, {
30
+ content: text,
31
+ attachments: input.attachments
32
+ }, sideChat.config).catch((err) => {
30
33
  log.error({
31
34
  err,
32
35
  sideChatId,
@@ -55,11 +58,11 @@ var SideChatRunService = class {
55
58
  }
56
59
  submitClarification(sideChatId, clientInstanceId, requestId, answer) {
57
60
  if (this.options.manager.get(sideChatId, clientInstanceId).clarification?.requestId !== requestId) return false;
58
- const handled = this.options.agentRunner.submitClarifyResponse(requestId, answer);
61
+ const handled = this.options.agentRunner.answerEphemeralClarification(requestId, answer);
59
62
  if (handled) this.options.manager.setStatus(sideChatId, clientInstanceId, "running");
60
63
  return handled;
61
64
  }
62
- async execute(run, content, config) {
65
+ async execute(run, input, config) {
63
66
  const topic = `run:${run.runId}`;
64
67
  const mapper = new ChatStreamMapper({
65
68
  runId: run.runId,
@@ -73,8 +76,10 @@ var SideChatRunService = class {
73
76
  if (run.abortController.signal.aborted) return;
74
77
  if (event.type === "clarify_request") this.options.manager.waitForInput(run.sideChatId, run.clientInstanceId, {
75
78
  requestId: String(event.requestId),
79
+ kind: event.kind === "approval" ? "approval" : "input",
76
80
  question: String(event.question),
77
- choices: Array.isArray(event.choices) ? event.choices.filter((choice) => typeof choice === "string") : void 0
81
+ choices: Array.isArray(event.choices) ? event.choices.filter((choice) => typeof choice === "string") : void 0,
82
+ suggestedAnswer: typeof event.suggestedAnswer === "string" ? event.suggestedAnswer : void 0
78
83
  }, event.kind === "approval" ? "waiting-approval" : "waiting-input");
79
84
  for (const mapped of mapper.map(event)) publish(mapped);
80
85
  };
@@ -82,28 +87,24 @@ var SideChatRunService = class {
82
87
  for (const event of mapper.start()) publish(event);
83
88
  publishMapped({
84
89
  type: "user_message",
85
- message: {
86
- role: "user",
87
- content,
88
- timestamp: Date.now()
89
- }
90
+ content: input.content,
91
+ media: input.attachments?.map(({ data: _data, ...attachment }) => attachment),
92
+ timestamp: Date.now()
90
93
  });
91
- this.options.agentRunner.registerExternalWebchatRun(run.executionSessionKey, run.runId, (event) => publishMapped(event), {
92
- clarificationTimeoutMs: null,
93
- beforeClarificationResponse: () => {
94
- try {
95
- this.options.manager.setStatus(run.sideChatId, run.clientInstanceId, "running");
96
- return true;
97
- } catch {
98
- return false;
99
- }
94
+ this.options.agentRunner.registerExternalWebchatRun(run.executionSessionKey, run.runId, (event) => publishMapped(event), { beforeClarificationResponse: () => {
95
+ try {
96
+ this.options.manager.setStatus(run.sideChatId, run.clientInstanceId, "running");
97
+ return true;
98
+ } catch {
99
+ return false;
100
100
  }
101
- });
101
+ } });
102
102
  const result = await this.options.getAgentService().runEphemeralTurn({
103
103
  executionSessionKey: run.executionSessionKey,
104
104
  parentSessionKey: this.options.manager.get(run.sideChatId, run.clientInstanceId).parentSessionKey,
105
105
  runId: run.runId,
106
- content,
106
+ content: input.content,
107
+ attachments: input.attachments,
107
108
  modelRef: config.modelRef,
108
109
  thinkingLevel: config.thinkingLevel,
109
110
  transcriptRuntime: this.options.manager.getRuntime(run.sideChatId, run.clientInstanceId),
@@ -39,7 +39,7 @@ export interface SideChatContextSnapshot {
39
39
  }
40
40
  export interface SideChatConfig {
41
41
  modelRef: string;
42
- thinkingLevel?: ThinkingLevel;
42
+ thinkingLevel: ThinkingLevel;
43
43
  }
44
44
  export interface SideChatView {
45
45
  id: string;
@@ -54,8 +54,10 @@ export interface SideChatView {
54
54
  runId?: string;
55
55
  clarification?: {
56
56
  requestId: string;
57
+ kind: 'input' | 'approval';
57
58
  question: string;
58
59
  choices?: string[];
60
+ suggestedAnswer?: string;
59
61
  };
60
62
  messageCount: number;
61
63
  context: SideChatContextSnapshot;