@xopcai/xopc 0.0.344 → 0.0.346

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 (205) hide show
  1. package/dist/browser-ext/dist/assets/{auth-BsvblhQz.js → auth-CFiOJ_rf.js} +1 -1
  2. package/dist/browser-ext/dist/background.js +1 -1
  3. package/dist/browser-ext/dist/sidepanel.html +1 -1
  4. package/dist/browser-ext/dist/sidepanel.js +1 -1
  5. package/dist/browser-ext/manifest.json +1 -1
  6. package/dist/extensions/telegram/xopc.extension.json +1 -1
  7. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DRFs0Jjv.js → agent-avatar-dicebear-M2vuj6W3.js} +1 -1
  8. package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-C9J-ILd0.js → agent-defaults-settings-panel-B_d0WGFm.js} +1 -1
  9. package/dist/gateway/static/root/assets/{agent-plugin-dialog-CGstiK5S.js → agent-plugin-dialog-egTQDEeV.js} +1 -1
  10. package/dist/gateway/static/root/assets/{agents-DS-CV-xB.js → agents-BbwmG8Kl.js} +6 -6
  11. package/dist/gateway/static/root/assets/{agents-admin-api-BTYHoqlW.js → agents-admin-api-Dlw9XxYa.js} +1 -1
  12. package/dist/gateway/static/root/assets/{app-management-settings-panel-znCRRKVF.js → app-management-settings-panel-IxWZDAeT.js} +1 -1
  13. package/dist/gateway/static/root/assets/{appearance-settings-DSUujN-S.js → appearance-settings-C56szwjn.js} +1 -1
  14. package/dist/gateway/static/root/assets/{apps-page-7uOjQp30.js → apps-page-Cqoc4xoi.js} +1 -1
  15. package/dist/gateway/static/root/assets/{archive-plugin-DV01jcWu.js → archive-plugin-Ce3TNO-R.js} +1 -1
  16. package/dist/gateway/static/root/assets/{automations-page-D_Ts5PDI.js → automations-page-4so9_Bya.js} +1 -1
  17. package/dist/gateway/static/root/assets/{automations-workspace-Dg7IuWeB.js → automations-workspace-CP3GH1iA.js} +1 -1
  18. package/dist/gateway/static/root/assets/{binary-plugins-CEoIySYJ.js → binary-plugins-l6tKp21u.js} +1 -1
  19. package/dist/gateway/static/root/assets/{block-editor-4bv_tjfg.js → block-editor-cj2RNjQs.js} +1 -1
  20. package/dist/gateway/static/root/assets/{browser-automation-inputs-UYRx7nE_.js → browser-automation-inputs-C9W2EklQ.js} +1 -1
  21. package/dist/gateway/static/root/assets/{browser-automations-page-EtXgro_V.js → browser-automations-page-CbTkFxIX.js} +1 -1
  22. package/dist/gateway/static/root/assets/{browser-settings-page-Bf45sjmd.js → browser-settings-page-KMfDs9dO.js} +1 -1
  23. package/dist/gateway/static/root/assets/{capabilities-B-2wxCUQ.js → capabilities-Co9ZxHHB.js} +1 -1
  24. package/dist/gateway/static/root/assets/{capabilities-page-YjIv97Sw.js → capabilities-page-cm2Q7EfF.js} +2 -2
  25. package/dist/gateway/static/root/assets/{capabilities-settings-panel-Ch2iNnfI.js → capabilities-settings-panel-CIe5qsxW.js} +1 -1
  26. package/dist/gateway/static/root/assets/{capability-header-actions-DJKC0sss.js → capability-header-actions-D2ASOs4Z.js} +1 -1
  27. package/dist/gateway/static/root/assets/{channels-BWZmepe_.js → channels-D-DnLz_c.js} +1 -1
  28. package/dist/gateway/static/root/assets/{chat-terminal-dock-DLBqdgS-.js → chat-terminal-dock-DaQrqzCz.js} +1 -1
  29. package/dist/gateway/static/root/assets/computer-settings-page-C-59NTyH.js +1 -0
  30. package/dist/gateway/static/root/assets/{connector-service-page-CYE4gX1g.js → connector-service-page-Cq7t7AJq.js} +1 -1
  31. package/dist/gateway/static/root/assets/{connectors-page-dJDZx96_.js → connectors-page-BH53KX8Y.js} +1 -1
  32. package/dist/gateway/static/root/assets/{date-picker-BM9HDlUj.js → date-picker-CcfRQKmj.js} +1 -1
  33. package/dist/gateway/static/root/assets/{dependency-picker-BybqITjG.js → dependency-picker-b9Tif8dg.js} +1 -1
  34. package/dist/gateway/static/root/assets/{desktop-pet-CYoJiTna.js → desktop-pet-BHe6Cb51.js} +1 -1
  35. package/dist/gateway/static/root/assets/{desktop-pet-settings-CXcTdFHs.js → desktop-pet-settings-wgA6yOo1.js} +1 -1
  36. package/dist/gateway/static/root/assets/{device-pairing-wizard-DnkRc3SQ.js → device-pairing-wizard-fv8c6u1o.js} +1 -1
  37. package/dist/gateway/static/root/assets/{directory-picker-path-field-BNC2UnEM.js → directory-picker-path-field-DM2YpM4N.js} +1 -1
  38. package/dist/gateway/static/root/assets/{extension-debug-page-CHU0dr2j.js → extension-debug-page-B-Y_Zk8L.js} +1 -1
  39. package/dist/gateway/static/root/assets/{extension-page-DXjPSQIh.js → extension-page-BC1m3MlB.js} +1 -1
  40. package/dist/gateway/static/root/assets/{extension-settings-page-DqFNPQsx.js → extension-settings-page-Cu3cfeJj.js} +1 -1
  41. package/dist/gateway/static/root/assets/{gateway-config-swr-DcE8n_ZS.js → gateway-config-swr-ukBQYwfH.js} +1 -1
  42. package/dist/gateway/static/root/assets/gateway-realtime-DvNfXjan.js +1 -0
  43. package/dist/gateway/static/root/assets/gateway-realtime-store-DGQMXjfI.js +1 -0
  44. package/dist/gateway/static/root/assets/{gateway-settings-BJVKTwIx.js → gateway-settings-pxmn3b8n.js} +1 -1
  45. package/dist/gateway/static/root/assets/{gateway-startup-retry-CCPlq9Lk.js → gateway-startup-retry-CVpOj205.js} +1 -1
  46. package/dist/gateway/static/root/assets/{home-page-B2imtrmi.js → home-page-DOsvv2rU.js} +1 -1
  47. package/dist/gateway/static/root/assets/{image-generation-api-D1Uh-05P.js → image-generation-api-zxx0qG9z.js} +1 -1
  48. package/dist/gateway/static/root/assets/{imports-page-CsypWC3J.js → imports-page-CWYDLeqJ.js} +1 -1
  49. package/dist/gateway/static/root/assets/index-DsIQD44S.js +106 -0
  50. package/dist/gateway/static/root/assets/index-y6kxoLV2.css +1 -0
  51. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-CSzm05SM.js → keyboard-shortcuts-settings-BEkTI6mv.js} +1 -1
  52. package/dist/gateway/static/root/assets/{local-app-workbench-page-BulzWHzC.js → local-app-workbench-page-aSXZL05r.js} +1 -1
  53. package/dist/gateway/static/root/assets/{local-apps-page-BQ2QlJNH.js → local-apps-page-BJThsekO.js} +1 -1
  54. package/dist/gateway/static/root/assets/{local-session-drafts-D9DeB55u.js → local-session-drafts-Dt_Yx7kq.js} +1 -1
  55. package/dist/gateway/static/root/assets/{locale-store-B0WmWiCo.js → locale-store-B008NR-f.js} +1 -1
  56. package/dist/gateway/static/root/assets/{logs-page-harzpOPJ.js → logs-page-WlqqTmpk.js} +1 -1
  57. package/dist/gateway/static/root/assets/{management-settings-BXKeyT_O.js → management-settings-j_npowOA.js} +1 -1
  58. package/dist/gateway/static/root/assets/{markdown-view-CSADmLmZ.js → markdown-view-BjDzimRP.js} +1 -1
  59. package/dist/gateway/static/root/assets/{media-plugins-CMe8YQ8l.js → media-plugins-DhYWGP6O.js} +1 -1
  60. package/dist/gateway/static/root/assets/messages-aVTaD9Mj.js +3 -0
  61. package/dist/gateway/static/root/assets/{note-detail-panel-DD9n9tnf.js → note-detail-panel-CYcNB2Pf.js} +3 -3
  62. package/dist/gateway/static/root/assets/{notes-page-B5NcvMau.js → notes-page-4D1-mt6Y.js} +1 -1
  63. package/dist/gateway/static/root/assets/{page-context-capture-button-BwFIuZqk.js → page-context-capture-button-BfmOqRGN.js} +1 -1
  64. package/dist/gateway/static/root/assets/{page-tabs-DH4JI3t_.js → page-tabs-aFGUXE53.js} +1 -1
  65. package/dist/gateway/static/root/assets/{preview-open-alternatives-D3Wsh5jh.js → preview-open-alternatives-BCEnqJTC.js} +1 -1
  66. package/dist/gateway/static/root/assets/{product-open-page-iigCUM2g.js → product-open-page-DHcx6kDT.js} +1 -1
  67. package/dist/gateway/static/root/assets/{project-detail-page-C19aDnSV.js → project-detail-page-ChKkovsq.js} +1 -1
  68. package/dist/gateway/static/root/assets/{projects-page-aWOL4_py.js → projects-page-Lt3HXMRm.js} +1 -1
  69. package/dist/gateway/static/root/assets/{registry-api-Bw0ZkSav.js → registry-api-EPj5O77m.js} +1 -1
  70. package/dist/gateway/static/root/assets/{remote-access-hub-CGLJFrLG.js → remote-access-hub-B94Vc-fj.js} +1 -1
  71. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-ArGdQMYT.js → runtime-tools-settings-panel-DNU19xEH.js} +1 -1
  72. package/dist/gateway/static/root/assets/{scenes-page-WB5cZttQ.js → scenes-page-BgzfnfOB.js} +1 -1
  73. package/dist/gateway/static/root/assets/{schema-form-Bzga2Tq0.js → schema-form-MKBLqh8C.js} +1 -1
  74. package/dist/gateway/static/root/assets/session-api-D5BlAIge.js +1 -0
  75. package/dist/gateway/static/root/assets/session-manager-DcFS0yfO.js +16 -0
  76. package/dist/gateway/static/root/assets/{sessions-page-DCs83Gg-.js → sessions-page-sYWhgEMH.js} +1 -1
  77. package/dist/gateway/static/root/assets/settings-advanced-gate-alf3atpI.js +1 -0
  78. package/dist/gateway/static/root/assets/{settings-form-section-DMchToFl.js → settings-form-section-C2gcfyxy.js} +1 -1
  79. package/dist/gateway/static/root/assets/{settings-page-Dh-S9_GO.js → settings-page-CYd6_yBb.js} +1 -1
  80. package/dist/gateway/static/root/assets/{setup-status-panel-kFPkdt3z.js → setup-status-panel-CUbH_YtB.js} +1 -1
  81. package/dist/gateway/static/root/assets/{share-preview-page-CrVC0BzQ.js → share-preview-page-Dxwq4fx1.js} +1 -1
  82. package/dist/gateway/static/root/assets/{shares-settings-ZesbsEGA.js → shares-settings-CqwHm0Mf.js} +1 -1
  83. package/dist/gateway/static/root/assets/{skill-api-Deb8HqtR.js → skill-api-C9k6G-tI.js} +1 -1
  84. package/dist/gateway/static/root/assets/skill-reload-api-D9bB-ANm.js +1 -0
  85. package/dist/gateway/static/root/assets/{skills-page-Bgs9jaCc.js → skills-page-CFiCgbAs.js} +1 -1
  86. package/dist/gateway/static/root/assets/{system-settings-panel-CwD47-_i.js → system-settings-panel-1tXKr0cJ.js} +1 -1
  87. package/dist/gateway/static/root/assets/task-detail-page-BBQ3sk4y.js +1 -0
  88. package/dist/gateway/static/root/assets/{tasks-QQJXsiER.js → tasks-BH8_WMUF.js} +1 -1
  89. package/dist/gateway/static/root/assets/{tunnel-api-DtL__Vgg.js → tunnel-api-COo0rSrc.js} +1 -1
  90. package/dist/gateway/static/root/assets/{usage-page-DZ01CsLl.js → usage-page-DHXG-2Rr.js} +1 -1
  91. package/dist/gateway/static/root/assets/{use-autosave-XBFnwLd0.js → use-autosave-CJfX4SWk.js} +1 -1
  92. package/dist/gateway/static/root/assets/{user-model-page-ByACaDBG.js → user-model-page-d-Gjs-EX.js} +1 -1
  93. package/dist/gateway/static/root/assets/{voice-api-key-field-NaIj9rQC.js → voice-api-key-field-D0gWz3iO.js} +1 -1
  94. package/dist/gateway/static/root/assets/{voice-config-api-st1q4lqP.js → voice-config-api-BnnUzr07.js} +1 -1
  95. package/dist/gateway/static/root/assets/{work-discovery-overlay-D418eqa5.js → work-discovery-overlay-CDAZKFVO.js} +1 -1
  96. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-CSXIidqw.js → workflow-run-setup-panel-Db0lk_9G.js} +1 -1
  97. package/dist/gateway/static/root/assets/{workflows-page-nGttfQ1r.js → workflows-page-Dj89Gagd.js} +1 -1
  98. package/dist/gateway/static/root/index.html +16 -16
  99. package/dist/package.js +1 -1
  100. package/dist/packages/endpoint-tools-protocol/src/index.js +2 -1
  101. package/dist/packages/gateway-contract/src/sessions.js +11 -0
  102. package/dist/packages/gateway-contract/src/tasks.js +1 -0
  103. package/dist/src/agent/memory/context-budget.d.ts +2 -0
  104. package/dist/src/agent/memory/context-budget.js +23 -2
  105. package/dist/src/agent/memory/context-recovery.js +2 -2
  106. package/dist/src/agent/service/direct-turn-helpers.js +2 -2
  107. package/dist/src/agent/service/process-direct-streaming.js +16 -2
  108. package/dist/src/agent/tasks/task-judge-service.d.ts +1 -0
  109. package/dist/src/agent/tasks/task-judge-service.js +55 -33
  110. package/dist/src/agent/tool-manuals/computer.d.ts +1 -1
  111. package/dist/src/agent/tool-manuals/computer.js +2 -2
  112. package/dist/src/agent/tool-manuals/xopc-use.d.ts +1 -1
  113. package/dist/src/agent/tool-manuals/xopc-use.js +28 -2
  114. package/dist/src/agent/tools/computer-use-tool.d.ts +0 -2
  115. package/dist/src/agent/tools/computer-use-tool.js +31 -19
  116. package/dist/src/agent/tools/factory.js +2 -3
  117. package/dist/src/agent/tools/xopc-use-tool.js +179 -8
  118. package/dist/src/capabilities/runtime/dispatcher.d.ts +2 -0
  119. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  120. package/dist/src/computer/broker.d.ts +6 -0
  121. package/dist/src/computer/broker.js +14 -0
  122. package/dist/src/computer/errors.js +2 -1
  123. package/dist/src/computer/model-adapter.js +3 -3
  124. package/dist/src/gateway/chat-stream/mapper.d.ts +3 -0
  125. package/dist/src/gateway/chat-stream/mapper.js +5 -1
  126. package/dist/src/gateway/chat-stream/protocol.d.ts +3 -0
  127. package/dist/src/gateway/hono/routes/session-input-handler.d.ts +2 -2
  128. package/dist/src/gateway/hono/routes/sessions.js +19 -2
  129. package/dist/src/gateway/hono/routes/tasks.js +93 -0
  130. package/dist/src/gateway/service/active-execution.js +1 -1
  131. package/dist/src/gateway/service/run-gateway-agent.js +5 -1
  132. package/dist/src/gateway/service/session-input-coordinator.d.ts +1 -1
  133. package/dist/src/gateway/service.d.ts +2 -1
  134. package/dist/src/gateway/service.js +70 -6
  135. package/dist/src/gateway/session-context-summary.js +17 -0
  136. package/dist/src/home-intelligence/host.js +2 -2
  137. package/dist/src/session/client-history.d.ts +7 -1
  138. package/dist/src/session/client-history.js +51 -1
  139. package/dist/src/session/store.js +10 -2
  140. package/dist/src/session/types.d.ts +1 -0
  141. package/dist/src/storage/sqlite/index.d.ts +1 -1
  142. package/dist/src/storage/sqlite/index.js +2 -2
  143. package/dist/src/storage/sqlite/migrations/224_task_origin_links.sql +8 -0
  144. package/dist/src/storage/sqlite/migrations/225_task_collaboration.sql +32 -0
  145. package/dist/src/storage/sqlite/migrations/226_task_main_updates.sql +9 -0
  146. package/dist/src/storage/sqlite/migrations/227_task_main_update_decisions.sql +8 -0
  147. package/dist/src/storage/sqlite/migrations/228_task_main_agent_links.sql +14 -0
  148. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  149. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  150. package/dist/src/storage/sqlite/schema.js +1 -1
  151. package/dist/src/storage/sqlite/session-input-repository.d.ts +9 -0
  152. package/dist/src/storage/sqlite/session-input-repository.js +28 -1
  153. package/dist/src/storage/sqlite/session-repository.js +11 -0
  154. package/dist/src/tasks/capabilities/write.js +2 -0
  155. package/dist/src/tasks/index.js +2 -2
  156. package/dist/src/tasks/task-application-service.js +19 -1
  157. package/dist/src/tasks/task-collaboration-delivery.d.ts +9 -0
  158. package/dist/src/tasks/task-collaboration-delivery.js +100 -0
  159. package/dist/src/tasks/task-collaboration-repository.d.ts +52 -0
  160. package/dist/src/tasks/task-collaboration-repository.js +151 -0
  161. package/dist/src/tasks/task-context-assembler.d.ts +2 -0
  162. package/dist/src/tasks/task-context-assembler.js +23 -1
  163. package/dist/src/tasks/task-main-agent-repository.d.ts +10 -0
  164. package/dist/src/tasks/task-main-agent-repository.js +30 -0
  165. package/dist/src/tasks/task-main-update-decision-service.d.ts +21 -0
  166. package/dist/src/tasks/task-main-update-decision-service.js +118 -0
  167. package/dist/src/tasks/task-main-update-delivery.d.ts +16 -0
  168. package/dist/src/tasks/task-main-update-delivery.js +64 -0
  169. package/dist/src/tasks/task-main-update-input.d.ts +20 -0
  170. package/dist/src/tasks/task-main-update-input.js +37 -0
  171. package/dist/src/tasks/task-orchestration-metrics.d.ts +17 -0
  172. package/dist/src/tasks/task-orchestration-metrics.js +61 -0
  173. package/dist/src/tasks/task-origin-repository.d.ts +14 -0
  174. package/dist/src/tasks/task-origin-repository.js +29 -0
  175. package/dist/src/tasks/task-run-dispatcher.d.ts +3 -0
  176. package/dist/src/tasks/task-run-dispatcher.js +65 -7
  177. package/dist/src/tasks/task-run-repository.d.ts +2 -0
  178. package/dist/src/tasks/task-run-repository.js +12 -1
  179. package/dist/src/tasks/task-sidebar-hierarchy.d.ts +14 -0
  180. package/dist/src/tasks/task-sidebar-hierarchy.js +49 -0
  181. package/dist/src/tui/chat-history.js +8 -0
  182. package/dist/src/tui/tui-session-snapshot.js +4 -3
  183. package/dist/src/tui/tui.js +1 -1
  184. package/dist/src/voice/realtime/agentBroker.d.ts +4 -0
  185. package/dist/src/voice/realtime/agentBroker.js +9 -3
  186. package/dist/src/voice/realtime/agentEngine.js +47 -13
  187. package/dist/src/voice/realtime/engine.d.ts +5 -0
  188. package/dist/src/voice/realtime/omniEngine.js +66 -12
  189. package/dist/src/voice/realtime/playback-echo.js +2 -0
  190. package/dist/src/voice/realtime/runtime.d.ts +6 -0
  191. package/dist/src/voice/realtime/runtime.js +12 -0
  192. package/dist/src/voice/realtime/turnPolicy.d.ts +1 -0
  193. package/dist/src/voice/realtime/turnPolicy.js +3 -0
  194. package/package.json +3 -3
  195. package/dist/gateway/static/root/assets/computer-settings-page-CciQtKpz.js +0 -1
  196. package/dist/gateway/static/root/assets/gateway-realtime-BeUJkjA3.js +0 -1
  197. package/dist/gateway/static/root/assets/gateway-realtime-store-C-8wwbt_.js +0 -1
  198. package/dist/gateway/static/root/assets/index-Ca6iqaCn.css +0 -1
  199. package/dist/gateway/static/root/assets/index-DqQgdJHd.js +0 -106
  200. package/dist/gateway/static/root/assets/messages-CTKYRqR-.js +0 -3
  201. package/dist/gateway/static/root/assets/session-api-BY3dAGBn.js +0 -1
  202. package/dist/gateway/static/root/assets/session-manager-D10sD8IN.js +0 -16
  203. package/dist/gateway/static/root/assets/settings-advanced-gate-yIwyFL-A.js +0 -1
  204. package/dist/gateway/static/root/assets/skill-reload-api-DvWOrc3C.js +0 -1
  205. package/dist/gateway/static/root/assets/task-detail-page-DFEM3Xbj.js +0 -1
@@ -2,6 +2,7 @@ import { init_transaction, runSqliteWriteTransaction } from "../../../storage/sq
2
2
  import { TaskCommandRequestSchema, TaskCreateRequestSchema, TaskHandoffRequestSchema } from "../../../../packages/gateway-contract/src/tasks.js";
3
3
  import { ProductReadContracts, TaskRunCancelOutputSchema, TaskRunFeedbackOutputSchema } from "../../../../packages/gateway-contract/src/capabilities.js";
4
4
  import { init_src } from "../../../../packages/gateway-contract/src/index.js";
5
+ import { hasGatewayScope, init_gateway_scopes } from "../../security/gateway-scopes.js";
5
6
  import { enqueueTaskChangedEvent, init_task_change_events } from "../../../tasks/task-change-events.js";
6
7
  import { TaskRepository, init_task_repository } from "../../../tasks/task-repository.js";
7
8
  import { TaskRunRepository, init_task_run_repository } from "../../../tasks/task-run-repository.js";
@@ -10,14 +11,17 @@ import "../../../capabilities/runtime/dispatcher.js";
10
11
  import { TaskConversationRepository } from "../../../tasks/task-conversation-repository.js";
11
12
  import { TaskContextMutationOutputSchema } from "../../../tasks/capabilities/relations.js";
12
13
  import { TaskDeleteOutputSchema } from "../../../tasks/capabilities/management.js";
14
+ import { TaskCollaborationRepository } from "../../../tasks/task-collaboration-repository.js";
13
15
  import { TaskMutationOutputSchema } from "../../../tasks/capabilities/write.js";
14
16
  import { createProductDispatcher } from "../../../capabilities/runtime/product.js";
15
17
  import { ProjectOperatingViewService } from "../../../tasks/project-operating-view-service.js";
16
18
  import { TaskHandoffService } from "../../../tasks/task-handoff-service.js";
19
+ import { getGatewayPrincipal } from "../../security/gateway-principal.js";
17
20
  import { submitSessionInput } from "./session-input-handler.js";
18
21
  import { patchChatModelConfig } from "./chat-model-config.js";
19
22
  import { capabilityHttpContext, capabilityHttpError } from "../../../capabilities/adapters/http.js";
20
23
  import { TaskConversationQueryService } from "../../service/task-conversation-query-service.js";
24
+ import { getTaskOrchestrationMetrics } from "../../../tasks/task-orchestration-metrics.js";
21
25
  import { randomUUID } from "node:crypto";
22
26
  //#region src/gateway/hono/routes/tasks.ts
23
27
  init_src();
@@ -25,6 +29,7 @@ init_transaction();
25
29
  init_task_change_events();
26
30
  init_task_repository();
27
31
  init_task_run_repository();
32
+ init_gateway_scopes();
28
33
  function registerTaskRoutes(authenticated, deps) {
29
34
  const capabilities = createProductDispatcher(() => deps.service.notesServiceInstance, {
30
35
  getConfig: () => deps.service.currentConfig,
@@ -47,6 +52,7 @@ function registerTaskRoutes(authenticated, deps) {
47
52
  const tasks = new TaskRepository();
48
53
  const runs = new TaskRunRepository();
49
54
  const conversations = new TaskConversationRepository();
55
+ const collaboration = new TaskCollaborationRepository();
50
56
  const conversationQuery = new TaskConversationQueryService(deps.service.sessions);
51
57
  const handoffs = new TaskHandoffService({
52
58
  sessionIndex: deps.service.sessionIndexInstance,
@@ -102,6 +108,21 @@ function registerTaskRoutes(authenticated, deps) {
102
108
  return capabilityHttpError(c, error);
103
109
  }
104
110
  });
111
+ authenticated.get("/api/tasks/orchestration-metrics", async (c) => {
112
+ if (!hasGatewayScope(getGatewayPrincipal(c).scopes, "tasks.read")) return c.json({
113
+ ok: false,
114
+ error: "Forbidden"
115
+ }, 403);
116
+ const since = c.req.query("since") === void 0 ? void 0 : Number(c.req.query("since"));
117
+ if (since !== void 0 && (!Number.isInteger(since) || since < 0)) return c.json({
118
+ ok: false,
119
+ error: "Invalid since timestamp"
120
+ }, 400);
121
+ return c.json({
122
+ ok: true,
123
+ metrics: getTaskOrchestrationMetrics(since)
124
+ });
125
+ });
105
126
  authenticated.get("/api/tasks/:id", async (c) => {
106
127
  try {
107
128
  return c.json(await capabilities.call("xopc.tasks.get", { id: c.req.param("id") }, capabilityHttpContext(c)));
@@ -109,6 +130,78 @@ function registerTaskRoutes(authenticated, deps) {
109
130
  return capabilityHttpError(c, error);
110
131
  }
111
132
  });
133
+ authenticated.get("/api/tasks/:id/collaboration", async (c) => {
134
+ if (!hasGatewayScope(getGatewayPrincipal(c).scopes, "tasks.read")) return c.json({
135
+ ok: false,
136
+ error: "Forbidden"
137
+ }, 403);
138
+ const taskId = c.req.param("id");
139
+ if (!tasks.get(taskId)) return c.json({
140
+ ok: false,
141
+ error: "Task not found"
142
+ }, 404);
143
+ const afterSequence = Number(c.req.query("afterSequence") ?? 0);
144
+ const beforeSequence = c.req.query("beforeSequence") === void 0 ? void 0 : Number(c.req.query("beforeSequence"));
145
+ const limit = Number(c.req.query("limit") ?? 50);
146
+ if (!Number.isInteger(afterSequence) || afterSequence < 0 || !Number.isInteger(limit) || limit < 1 || beforeSequence !== void 0 && (!Number.isInteger(beforeSequence) || beforeSequence < 1)) return c.json({
147
+ ok: false,
148
+ error: "Invalid cursor or limit"
149
+ }, 400);
150
+ return c.json({
151
+ ok: true,
152
+ items: c.req.query("recent") === "1" ? collaboration.recent(taskId, beforeSequence, limit) : collaboration.list(taskId, afterSequence, limit)
153
+ });
154
+ });
155
+ authenticated.post("/api/tasks/:id/collaboration", taskRateLimit, async (c) => {
156
+ const principal = getGatewayPrincipal(c);
157
+ if (!hasGatewayScope(principal.scopes, "tasks.write")) return c.json({
158
+ ok: false,
159
+ error: "Forbidden"
160
+ }, 403);
161
+ const body = await c.req.json().catch(() => null);
162
+ const kind = body?.kind;
163
+ const content = body?.body;
164
+ if (kind !== "instruction" && kind !== "question" && kind !== "answer" || typeof content !== "string" || !content.trim() || content.length > 8e3) return c.json({
165
+ ok: false,
166
+ error: "Invalid collaboration message"
167
+ }, 400);
168
+ const causationId = typeof body?.causationId === "string" ? body.causationId : void 0;
169
+ if (kind === "answer" && (!causationId || collaboration.get(causationId)?.taskId !== c.req.param("id") || collaboration.get(causationId)?.kind !== "question")) return c.json({
170
+ ok: false,
171
+ error: "Answer must reference a question on this Task"
172
+ }, 400);
173
+ try {
174
+ const task = tasks.get(c.req.param("id"));
175
+ if (!task) return c.json({
176
+ ok: false,
177
+ error: "Task not found"
178
+ }, 404);
179
+ if (task.phase === "closed") return c.json({
180
+ ok: false,
181
+ error: "Task is closed"
182
+ }, 409);
183
+ const entry = collaboration.append({
184
+ taskId: c.req.param("id"),
185
+ authorKind: "user",
186
+ authorId: principal.principalId,
187
+ kind,
188
+ body: content,
189
+ ...causationId ? { causationId } : {},
190
+ idempotencyKey: c.req.header("idempotency-key") ?? randomUUID(),
191
+ deliverToWorker: true
192
+ });
193
+ deps.service.dispatchTaskRuns();
194
+ return c.json({
195
+ ok: true,
196
+ entry
197
+ }, 201);
198
+ } catch (error) {
199
+ return c.json({
200
+ ok: false,
201
+ error: error instanceof Error ? error.message : String(error)
202
+ }, 409);
203
+ }
204
+ });
112
205
  authenticated.post("/api/tasks/:id/conversation", taskRateLimit, async (c) => {
113
206
  try {
114
207
  const result = await deps.service.ensureTaskConversation(c.req.param("id"));
@@ -1,7 +1,7 @@
1
1
  //#region src/gateway/service/active-execution.ts
2
2
  function describeActiveExecution(input) {
3
3
  const { origin } = input;
4
- const background = origin.type === "system" && (origin.source === "automation" || origin.source === "heartbeat" || origin.source === "internal");
4
+ const background = origin.type === "system" && (origin.source === "automation" || origin.source === "heartbeat" || origin.source === "internal" || origin.source === "task_update");
5
5
  const kind = input.kind ?? (origin.type === "system" && origin.source === "automation" ? "automation" : origin.type === "system" && origin.source === "workflow" ? "workflow" : input.taskRunId ? "task" : "chat");
6
6
  return {
7
7
  conversationId: input.conversationId,
@@ -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 { init_session_input_repository, listTaskUpdateTriggers } from "../../storage/sqlite/session-input-repository.js";
4
5
  import { init_clarification_wait_repository, isClarificationSuspended } from "../../storage/sqlite/clarification-wait-repository.js";
5
6
  import { updateInteractionStateFromMessage } from "../../storage/sqlite/interaction-state-repository.js";
6
7
  import { getConnectionResumeInput, init_connection_wait_repository, isConnectionSuspended } from "../../storage/sqlite/connection-wait-repository.js";
@@ -25,6 +26,7 @@ init_clarification_wait_repository();
25
26
  init_logger();
26
27
  init_session_key();
27
28
  init_sqlite();
29
+ init_session_input_repository();
28
30
  const log = createLogger("Gateway:Service");
29
31
  /**
30
32
  * @param runOptions.signal — When set (e.g. client disconnect), aborts in-flight generation and persists partial output.
@@ -85,7 +87,9 @@ async function* runGatewayAgent(deps, message, channel, chatId, origin, attachme
85
87
  const mapper = new ChatStreamMapper({
86
88
  runId,
87
89
  conversationId: streamConversationId,
88
- channel
90
+ channel,
91
+ startsNewBubble: origin.type === "system" && origin.source === "task_update",
92
+ ...origin.type === "system" && origin.source === "task_update" && webchatConversationId ? { taskTrigger: listTaskUpdateTriggers(webchatConversationId).get(runId) } : {}
89
93
  });
90
94
  let registeredActiveWebchatRun = false;
91
95
  const captureTaskEvent = (event) => {
@@ -61,7 +61,7 @@ export declare class SessionInputCoordinator {
61
61
  channel: string;
62
62
  } | {
63
63
  type: "system";
64
- source: "automation" | "cli" | "workflow" | "heartbeat" | "internal";
64
+ source: "automation" | "cli" | "workflow" | "heartbeat" | "internal" | "task_update";
65
65
  };
66
66
  }>;
67
67
  dispatchAcceptedInput(conversationId: string, inputId: string): Promise<void>;
@@ -126,6 +126,7 @@ export declare class GatewayService {
126
126
  private createTaskRunDispatcher;
127
127
  private createNotificationService;
128
128
  private readonly taskRunDispatch;
129
+ private readonly taskMainUpdateDispatch;
129
130
  dispatchTaskRuns(): void;
130
131
  ensureTaskConversation(taskId: string, options?: {
131
132
  runId?: string;
@@ -164,7 +165,7 @@ export declare class GatewayService {
164
165
  channel: string;
165
166
  } | {
166
167
  type: "system";
167
- source: "automation" | "cli" | "workflow" | "heartbeat" | "internal";
168
+ source: "automation" | "cli" | "workflow" | "heartbeat" | "internal" | "task_update";
168
169
  };
169
170
  }>;
170
171
  drainSessionInputs(conversationId: string): Promise<void>;
@@ -10,6 +10,7 @@ import { getSqliteDatabase, init_transaction } from "../storage/sqlite/transacti
10
10
  import { getBrowserTabBindingById, init_browser_tab_binding_repository } from "../storage/sqlite/browser-tab-binding-repository.js";
11
11
  import { findSessionInput, init_session_input_repository, insertSessionInput } from "../storage/sqlite/session-input-repository.js";
12
12
  import { TaskRepository } from "../tasks/task-repository.js";
13
+ import { TaskRunRepository, init_task_run_repository } from "../tasks/task-run-repository.js";
13
14
  import { init_changes, notifyUserContextChange } from "../user-context/changes.js";
14
15
  import { getSessionMetadata } from "../storage/sqlite/session-read-repository.js";
15
16
  import { init_session_repository, listSessionMetadata, patchSessionMetadata } from "../storage/sqlite/session-repository.js";
@@ -87,10 +88,6 @@ import { DiscussionSealer } from "../discussions/sealer.js";
87
88
  import "../discussions/index.js";
88
89
  import { EndpointToolRuntime } from "../endpoint-tools/runtime.js";
89
90
  import "../endpoint-tools/index.js";
90
- import { HomeCapabilityPreflightService } from "../home-intelligence/capability-preflight.js";
91
- import { HomeAdviceGenerator } from "../home-intelligence/generator.js";
92
- import { HomeIntelligenceHost } from "../home-intelligence/host.js";
93
- import { HomeSnapshotBuilder } from "../home-intelligence/snapshot.js";
94
91
  import { assertGatewayAuthConfigured, extractToken, resolveGatewayAuth, validateToken } from "./auth.js";
95
92
  import { prepareAutomationAgentSession } from "./automation-agent-session.js";
96
93
  import { stopTailscaleExposure } from "./tailscale-lifecycle.js";
@@ -146,8 +143,16 @@ import { reconcileMemoryMaintenanceAutomations } from "./memory-maintenance-auto
146
143
  import { GatewayReadiness } from "./startup-readiness.js";
147
144
  import { createGatewayStartupTrace } from "./startup-trace.js";
148
145
  import { GatewaySceneHost } from "./scenes/host.js";
146
+ import { TaskCollaborationDelivery } from "../tasks/task-collaboration-delivery.js";
147
+ import { TaskMainUpdateDelivery } from "../tasks/task-main-update-delivery.js";
148
+ import { TaskMainUpdateDecisionService } from "../tasks/task-main-update-decision-service.js";
149
+ import { selectTaskMainUpdateAttempt, submitAndConfirmTaskMainUpdate } from "../tasks/task-main-update-input.js";
149
150
  import { checkAppContextAccess, prepareAppContext } from "./service/app-context-access.js";
150
151
  import { applyAutomaticVoiceLanguage, inferProductLanguageFromEnvironment, initializeVoiceDefaults } from "../voice/language-profile.js";
152
+ import { HomeAdviceGenerator } from "../home-intelligence/generator.js";
153
+ import { HomeIntelligenceHost } from "../home-intelligence/host.js";
154
+ import { HomeSnapshotBuilder } from "../home-intelligence/snapshot.js";
155
+ import { HomeCapabilityPreflightService } from "../home-intelligence/capability-preflight.js";
151
156
  import crypto from "node:crypto";
152
157
  //#region src/gateway/service.ts
153
158
  init_session_repository();
@@ -163,6 +168,7 @@ init_logger();
163
168
  init_log_stream();
164
169
  init_paths();
165
170
  init_package_version();
171
+ init_task_run_repository();
166
172
  init_resolve_route();
167
173
  init_session_key();
168
174
  init_sqlite();
@@ -763,7 +769,7 @@ var GatewayService = class {
763
769
  this.ensureAgentService();
764
770
  return;
765
771
  }
766
- const clientMessageId = `task:${runId}`;
772
+ const clientMessageId = new TaskRunRepository().nextAgentInputClientMessageId(runId);
767
773
  const session = await this.sessionIndex.getSessionMetadata(conversationId);
768
774
  if (!session) throw new Error("Task session is unavailable");
769
775
  insertSessionInput({
@@ -804,6 +810,19 @@ var GatewayService = class {
804
810
  this.projects.flushCommittedEffects();
805
811
  this._workDiscovery?.dispatchProjectUnderstanding();
806
812
  this.dispatchTaskEvents();
813
+ await new TaskCollaborationDelivery().drain(async (input) => {
814
+ const state = this.agentRunner.inputs.snapshot(input.conversationId);
815
+ return (await this.agentRunner.submitSessionInput({
816
+ conversationId: input.conversationId,
817
+ clientMessageId: input.clientMessageId,
818
+ delivery: state.activeRunId ? "steer" : "next",
819
+ content: input.content,
820
+ origin: {
821
+ type: "system",
822
+ source: "workflow"
823
+ }
824
+ })).ok;
825
+ });
807
826
  this.createTaskRunDispatcher().dispatch();
808
827
  await this.createWorkflowRunService().dispatchTaskRuns();
809
828
  }, (err) => {
@@ -814,8 +833,53 @@ var GatewayService = class {
814
833
  phase: "task_run_dispatch"
815
834
  }, `Task dispatch failed: ${errorMessage}`);
816
835
  });
836
+ taskMainUpdateDispatch = createBackgroundTask(async () => {
837
+ await new TaskMainUpdateDelivery().drain({
838
+ isAvailable: (conversationId) => {
839
+ const state = this.agentRunner.inputs.snapshot(conversationId);
840
+ return !state.activeRunId && state.inputs.every((item) => item.status === "interrupted") && (!this.voiceRealtime.hasConversation(conversationId) || this.voiceRealtime.canOfferTaskUpdate(conversationId));
841
+ },
842
+ decide: (input) => new TaskMainUpdateDecisionService({
843
+ getModelRef: (conversationId) => this.ensureAgentService().getModelForSession(conversationId),
844
+ loadHistory: (conversationId) => this.sessionIndex.loadMessages(conversationId)
845
+ }).decide(input),
846
+ submitAndConfirm: (input) => {
847
+ if (this.voiceRealtime.hasConversation(input.conversationId)) {
848
+ const attempt = selectTaskMainUpdateAttempt(input.conversationId, input.clientMessageId, findSessionInput);
849
+ if (attempt.kind === "completed") return Promise.resolve(true);
850
+ if (attempt.kind !== "new" || !attempt.clientMessageId) return Promise.resolve(false);
851
+ return this.voiceRealtime.offerTaskUpdate({
852
+ ...input,
853
+ clientMessageId: attempt.clientMessageId
854
+ });
855
+ }
856
+ return submitAndConfirmTaskMainUpdate(input, {
857
+ findInput: findSessionInput,
858
+ submit: async (message) => {
859
+ return (await this.agentRunner.submitSessionInput({
860
+ ...message,
861
+ delivery: "next",
862
+ origin: {
863
+ type: "system",
864
+ source: "task_update"
865
+ }
866
+ })).ok;
867
+ },
868
+ waitForCompletion: (conversationId, clientMessageId) => this.agentRunner.inputs.waitForCompletion(conversationId, clientMessageId)
869
+ });
870
+ }
871
+ });
872
+ }, (err) => {
873
+ const errorMessage = err instanceof Error ? err.message : String(err);
874
+ log.error({
875
+ err,
876
+ errorMessage,
877
+ phase: "task_main_update_dispatch"
878
+ }, `Main Agent update dispatch failed: ${errorMessage}`);
879
+ });
817
880
  dispatchTaskRuns() {
818
881
  this.taskRunDispatch();
882
+ this.taskMainUpdateDispatch();
819
883
  }
820
884
  async ensureTaskConversation(taskId, options = {}) {
821
885
  const task = new TaskRepository().require(taskId);
@@ -1864,7 +1928,7 @@ var GatewayService = class {
1864
1928
  });
1865
1929
  }
1866
1930
  if (event.type.startsWith("task.")) this.emit(event.type, event.payload);
1867
- if (this.config.userContext.homeIntelligence.refreshOnContextChange && (event.type.startsWith("task.") || event.type.startsWith("project."))) {
1931
+ if (this.config.userContext.homeIntelligence.refreshOnContextChange && (event.type.startsWith("task.") && event.type !== "task.collaboration_entry_added" || event.type.startsWith("project."))) {
1868
1932
  const payload = event.payload;
1869
1933
  const objectId = event.type.startsWith("task.") ? payload.taskId : payload.projectId;
1870
1934
  const revision = payload.version ?? payload.revision ?? "unknown";
@@ -11,6 +11,8 @@ import { getExecutionEnvironmentForSession } from "../execution-environments/sub
11
11
  import { effectiveWorkspacePathForSession } from "../session/session-workspace.js";
12
12
  import { ProjectStore } from "../projects/project-store.js";
13
13
  import { runExec } from "../infra/exec.js";
14
+ import { TaskCollaborationRepository } from "../tasks/task-collaboration-repository.js";
15
+ import { TaskOriginRepository } from "../tasks/task-origin-repository.js";
14
16
  import { isSessionSourceBinding } from "../agent/source-context/types.js";
15
17
  import { realpath, stat } from "node:fs/promises";
16
18
  //#region src/gateway/session-context-summary.ts
@@ -106,6 +108,21 @@ async function getSessionContextSummary(config, conversationId, scopes) {
106
108
  phase: task.phase
107
109
  };
108
110
  else if (taskId) unavailable("work");
111
+ const delegated = new TaskOriginRepository().list(conversationId, 20);
112
+ const board = new TaskCollaborationRepository();
113
+ summary.work.delegatedTasks = delegated.items.map((item) => {
114
+ const latest = board.latest(item.id);
115
+ return {
116
+ ...item,
117
+ title: item.title.slice(0, 240),
118
+ ...latest ? { latestUpdate: {
119
+ kind: latest.kind,
120
+ body: latest.body.slice(0, 400),
121
+ createdAt: latest.createdAt
122
+ } } : {}
123
+ };
124
+ });
125
+ summary.work.delegatedTaskCount = delegated.total;
109
126
  } catch (err) {
110
127
  unavailable("work", err);
111
128
  }
@@ -1,10 +1,10 @@
1
1
  import { createLogger } from "../utils/logger/index.js";
2
2
  import { init_logger } from "../utils/logger.js";
3
+ import { HomeAdviceBudgetExceededError } from "./generator.js";
3
4
  import { homePatternKey } from "./strategy.js";
5
+ import { HomeAdvicePolicy } from "./policy.js";
4
6
  import { HomeIntelligenceRepository } from "./repository.js";
5
7
  import { HomeOpportunityApplicationService } from "./application-service.js";
6
- import { HomeAdvicePolicy } from "./policy.js";
7
- import { HomeAdviceBudgetExceededError } from "./generator.js";
8
8
  import { buildHomeOpportunityNotification } from "./notification.js";
9
9
  import { createHash } from "node:crypto";
10
10
  //#region src/home-intelligence/host.ts
@@ -1,12 +1,16 @@
1
1
  import { type TurnOutcome, type UserTurnDocument } from '@xopcai/gateway-contract';
2
2
  import type { Message } from './types.js';
3
+ import type { TaskUpdateTrigger } from '../storage/sqlite/session-input-repository.js';
3
4
  import type { TranscriptStoredRow } from './session-context-for-llm.js';
4
5
  /** Transcript row for TUI and HTTP clients (flattened from persisted session messages). */
5
6
  export interface ClientHistoryMessage {
6
7
  id?: string;
7
8
  turnId?: string;
8
- role: 'user' | 'assistant' | 'system';
9
+ /** A background Agent turn starts a new visible assistant bubble without a visible user row. */
10
+ startsNewBubble?: boolean;
11
+ role: 'user' | 'assistant' | 'system' | 'task';
9
12
  content: string;
13
+ taskTrigger?: TaskUpdateTrigger;
10
14
  displayIndex?: number;
11
15
  rawContent?: string | unknown[];
12
16
  /** Persisted inbound attachment metadata used by chat clients to reload media. */
@@ -81,4 +85,6 @@ export declare function transcriptRowsToClientHistory(rows: TranscriptStoredRow[
81
85
  startRowNumber?: number;
82
86
  endRowNumber?: number;
83
87
  rowNumberOffset?: number;
88
+ startsNewBubbleTurnIds?: ReadonlySet<string>;
89
+ taskUpdateTriggers?: ReadonlyMap<string, TaskUpdateTrigger>;
84
90
  }): ClientHistoryMessage[];
@@ -5,6 +5,24 @@ import { stripRuntimeContextFromUserMessage } from "./user-message-display.js";
5
5
  import { buildTranscriptOutline } from "./transcript-outline.js";
6
6
  //#region src/session/client-history.ts
7
7
  init_src();
8
+ function taskTriggerFromMetadata(metadata) {
9
+ if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) return void 0;
10
+ const value = metadata.taskTrigger;
11
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
12
+ const trigger = value;
13
+ if (typeof trigger.entryId !== "string" || typeof trigger.taskId !== "string" || typeof trigger.taskTitle !== "string" || !trigger.taskTitle.trim() || ![
14
+ "progress",
15
+ "question",
16
+ "result",
17
+ "failure"
18
+ ].includes(String(trigger.kind))) return void 0;
19
+ return {
20
+ entryId: trigger.entryId,
21
+ taskId: trigger.taskId,
22
+ taskTitle: trigger.taskTitle,
23
+ kind: trigger.kind
24
+ };
25
+ }
8
26
  function sourceContextDisplayMetadata(metadata) {
9
27
  if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) return void 0;
10
28
  const record = metadata;
@@ -143,9 +161,23 @@ function messagesToClientHistory(messages, opts) {
143
161
  const slice = opts?.limit !== void 0 && messages.length > opts.limit ? messages.slice(-opts.limit) : messages;
144
162
  const results = collectToolResults(slice);
145
163
  const out = [];
164
+ const hiddenTurnIds = new Set(slice.flatMap((message) => message.metadata?.hiddenFromClient === true && typeof message.turnId === "string" ? [message.turnId] : []));
165
+ const assistantTurnIds = new Set(slice.filter((message) => message.role === "assistant").map((message) => message.turnId).filter((turnId) => Boolean(turnId)));
146
166
  for (const m of slice) {
147
167
  if (m.role === "tool" || m.role === "toolResult") continue;
148
168
  if (m.role === "user" || m.role === "system") {
169
+ if (m.metadata?.hiddenFromClient === true) {
170
+ const turnId = m.turnId;
171
+ const trigger = turnId && assistantTurnIds.has(turnId) ? taskTriggerFromMetadata(m.metadata) : void 0;
172
+ if (trigger) out.push({
173
+ role: "task",
174
+ turnId,
175
+ content: "",
176
+ taskTrigger: trigger,
177
+ timestamp: parseTimestamp(m.timestamp)
178
+ });
179
+ continue;
180
+ }
149
181
  const text = flattenMessageContent(m.content);
150
182
  out.push({
151
183
  role: m.role,
@@ -163,6 +195,7 @@ function messagesToClientHistory(messages, opts) {
163
195
  out.push({
164
196
  role: "assistant",
165
197
  ...typeof m.turnId === "string" ? { turnId: m.turnId } : {},
198
+ ...typeof m.turnId === "string" && hiddenTurnIds.has(m.turnId) ? { startsNewBubble: true } : {},
166
199
  content: text,
167
200
  timestamp: parseTimestamp(m.timestamp),
168
201
  toolCalls
@@ -368,7 +401,9 @@ function transcriptRowsToClientHistory(rows, opts) {
368
401
  const startIndex = hasRowWindow ? Math.max(0, Math.trunc(opts?.startRowNumber ?? 1) - 1) : opts?.limit !== void 0 && rows.length > opts.limit ? rows.length - opts.limit : 0;
369
402
  const endIndex = hasRowWindow ? Math.max(startIndex, Math.min(rows.length, Math.trunc(opts?.endRowNumber ?? rows.length))) : rows.length;
370
403
  const slice = hasRowWindow ? rows.slice(startIndex, endIndex) : opts?.limit !== void 0 && rows.length > opts.limit ? rows.slice(-opts.limit) : rows;
371
- const results = collectHistoryToolResults(slice.map(asHistoryMessageRow).filter((row) => row !== null));
404
+ const messages = slice.map(asHistoryMessageRow).filter((row) => row !== null);
405
+ const results = collectHistoryToolResults(messages);
406
+ const assistantTurnIds = new Set(messages.filter((message) => message.role === "assistant").map((message) => message.turnId).filter((turnId) => Boolean(turnId)));
372
407
  const out = [];
373
408
  const reviewTraceToolById = /* @__PURE__ */ new Map();
374
409
  for (const [offset, row] of slice.entries()) {
@@ -472,6 +507,20 @@ function transcriptRowsToClientHistory(rows, opts) {
472
507
  if (!messageRow) continue;
473
508
  if (messageRow.role === "tool" || messageRow.role === "toolResult") continue;
474
509
  if (messageRow.role === "user" || messageRow.role === "system") {
510
+ if (messageRow.metadata?.hiddenFromClient === true) {
511
+ const trigger = messageRow.turnId && assistantTurnIds.has(messageRow.turnId) ? taskTriggerFromMetadata(messageRow.metadata) ?? opts?.taskUpdateTriggers?.get(messageRow.turnId) : void 0;
512
+ if (trigger) out.push({
513
+ id,
514
+ turnId: messageRow.turnId,
515
+ role: "task",
516
+ kind: "message",
517
+ content: "",
518
+ taskTrigger: trigger,
519
+ timestamp: parseTimestampValue(messageRow.timestamp),
520
+ ...displayIndex !== void 0 ? { displayIndex } : {}
521
+ });
522
+ continue;
523
+ }
475
524
  out.push({
476
525
  id,
477
526
  ...messageRow.turnId ? { turnId: messageRow.turnId } : {},
@@ -489,6 +538,7 @@ function transcriptRowsToClientHistory(rows, opts) {
489
538
  out.push({
490
539
  id,
491
540
  ...messageRow.turnId ? { turnId: messageRow.turnId } : {},
541
+ ...messageRow.turnId && opts?.startsNewBubbleTurnIds?.has(messageRow.turnId) ? { startsNewBubble: true } : {},
492
542
  role: "assistant",
493
543
  kind: "message",
494
544
  content: flattenMessageContent(messageRow.content ?? ""),
@@ -3,6 +3,7 @@ import { createLogger } from "../utils/logger/index.js";
3
3
  import { init_logger } from "../utils/logger.js";
4
4
  import { requireXopcDatabase } from "../storage/sqlite/connection.js";
5
5
  import { runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
6
+ import { listTaskUpdateRunIds, listTaskUpdateTriggers } from "../storage/sqlite/session-input-repository.js";
6
7
  import { buildSessionContextForLlm, buildSessionDisplayMessages, init_session_context_for_llm, isRuntimeOnlyTranscriptMessage, isTranscriptCompactionEntry, mergeLlmMessagesPreservingContextRows, transcriptRowsFromJsonArray } from "./session-context-for-llm.js";
7
8
  import "./types.js";
8
9
  import { estimateTokensFromMessages } from "../storage/sqlite/row-mappers.js";
@@ -192,7 +193,11 @@ var SessionStore = class {
192
193
  });
193
194
  const endIndex = hasBeforeCursor ? Math.min(page.total, Math.max(0, parsedBefore)) : Math.max(0, page.total - offset);
194
195
  const startIndex = Math.max(0, endIndex - page.rows.length);
195
- const history = transcriptRowsToClientHistory(page.rows, { rowNumberOffset: startIndex });
196
+ const history = transcriptRowsToClientHistory(page.rows, {
197
+ rowNumberOffset: startIndex,
198
+ startsNewBubbleTurnIds: listTaskUpdateRunIds(key),
199
+ taskUpdateTriggers: listTaskUpdateTriggers(key)
200
+ });
196
201
  const messages = options.compact ? compactHistory(history) : history;
197
202
  const session = {
198
203
  ...metadata,
@@ -632,7 +637,10 @@ var SessionStore = class {
632
637
  }
633
638
  async findInSession(key, query, limit) {
634
639
  if (!await this.getMetadata(key)) return null;
635
- return findSessionMessages(transcriptRowsToClientHistory(await this.loadTranscriptRows(key)), query, limit);
640
+ return findSessionMessages(transcriptRowsToClientHistory(await this.loadTranscriptRows(key), {
641
+ startsNewBubbleTurnIds: listTaskUpdateRunIds(key),
642
+ taskUpdateTriggers: listTaskUpdateTriggers(key)
643
+ }), query, limit);
636
644
  }
637
645
  recallSession(key, query, options) {
638
646
  requireXopcDatabase();
@@ -142,6 +142,7 @@ export interface SessionDetail extends SessionMetadata {
142
142
  }
143
143
  /** Session list query parameters */
144
144
  export interface SessionListQuery extends SessionDiscoveryQuery {
145
+ rootConversationsOnly?: boolean;
145
146
  status?: SessionStatus | SessionStatus[];
146
147
  /** Single `sourceChannel`, or comma-separated list (e.g. `telegram,weixin`). */
147
148
  channel?: string;
@@ -14,7 +14,7 @@ export { claimContextExtractionRun, finishContextExtractionRun, getContextExtrac
14
14
  export { createCollaborationRule, getCollaborationRule, listCollaborationRules, setCollaborationRuleStatus, type CollaborationRule, } from './collaboration-rule-repository.js';
15
15
  export { createContextEvidence, type ContextEvidence } from './context-evidence-repository.js';
16
16
  export { getUserPerson, getUserPeopleIndexState, listUserPeople, mergeUserPeople, replaceUserPeopleIndex, summarizeUserPeople, updateUserPerson, } from './user-people-repository.js';
17
- export { cancelQueuedSessionInput, claimNextSessionInput, findSessionInput, finishSessionInputRun, getSessionInputState, getSessionInputById, insertSessionInput, listActiveSessionInputExecutions, listActiveSessionInputRuns, mutateQueuedSessionInput, recoverSessionInputState, setSessionInputStatus, type SessionInput, type SessionInputDelivery, type SessionInputPayload, type SessionInputState, type SessionInputStatus, } from './session-input-repository.js';
17
+ export { cancelQueuedSessionInput, claimNextSessionInput, findSessionInput, finishSessionInputRun, getSessionInputState, getSessionInputById, insertSessionInput, listActiveSessionInputExecutions, listActiveSessionInputRuns, listTaskUpdateRunIds, listTaskUpdateTriggers, mutateQueuedSessionInput, recoverSessionInputState, setSessionInputStatus, type SessionInput, type SessionInputDelivery, type SessionInputPayload, type SessionInputState, type TaskUpdateTrigger, type SessionInputStatus, } from './session-input-repository.js';
18
18
  export { consumeClarificationApproval, consumeClarificationResume, createClarificationWait, getActiveClarification, getClarification, getClarificationResumeInput, getClarificationSnapshot, isClarificationSuspended, resolveClarification, supersedeActiveClarification, type CreateClarificationInput, type ResolveClarificationInput, type ResolveClarificationResult, } from './clarification-wait-repository.js';
19
19
  export { replaceLatestSessionTurnAndQueueInput, validateLatestSessionTurnTarget, type ReplaceLatestSessionTurnInput, type ReplaceLatestSessionTurnResult, } from './session-turn-replace-repository.js';
20
20
  export { acknowledgeHomeAttention, isHomeAttentionAcknowledged, type HomeAttentionSubjectKind, } from './home-attention-repository.js';
@@ -17,7 +17,7 @@ import { claimContextExtractionRun, finishContextExtractionRun, getContextExtrac
17
17
  import { createCollaborationRule, getCollaborationRule, init_collaboration_rule_repository, listCollaborationRules, setCollaborationRuleStatus } from "./collaboration-rule-repository.js";
18
18
  import { createContextEvidence, init_context_evidence_repository } from "./context-evidence-repository.js";
19
19
  import { getUserPeopleIndexState, getUserPerson, init_user_people_repository, listUserPeople, mergeUserPeople, replaceUserPeopleIndex, summarizeUserPeople, updateUserPerson } from "./user-people-repository.js";
20
- import { cancelQueuedSessionInput, claimNextSessionInput, findSessionInput, finishSessionInputRun, getSessionInputById, getSessionInputState, init_session_input_repository, insertSessionInput, listActiveSessionInputExecutions, listActiveSessionInputRuns, mutateQueuedSessionInput, recoverSessionInputState, setSessionInputStatus } from "./session-input-repository.js";
20
+ import { cancelQueuedSessionInput, claimNextSessionInput, findSessionInput, finishSessionInputRun, getSessionInputById, getSessionInputState, init_session_input_repository, insertSessionInput, listActiveSessionInputExecutions, listActiveSessionInputRuns, listTaskUpdateRunIds, listTaskUpdateTriggers, mutateQueuedSessionInput, recoverSessionInputState, setSessionInputStatus } from "./session-input-repository.js";
21
21
  import { consumeClarificationApproval, consumeClarificationResume, createClarificationWait, getActiveClarification, getClarification, getClarificationResumeInput, getClarificationSnapshot, init_clarification_wait_repository, isClarificationSuspended, resolveClarification, supersedeActiveClarification } from "./clarification-wait-repository.js";
22
22
  import { buildDefaultSessionMetadata, init_session_metadata } from "./session-metadata.js";
23
23
  import { buildGlobalSessionStats, classifyStoredRow, estimateTokensFromMessages, extractFtsContent, init_row_mappers, metadataToSessionInsert, sessionConfigRowToConfig, sessionRowToMetadata, transcriptEntryRowToStoredRow } from "./row-mappers.js";
@@ -87,4 +87,4 @@ var init_sqlite = __esmMin((() => {
87
87
  }));
88
88
  //#endregion
89
89
  init_sqlite();
90
- export { COMPOSER_INPUT_HISTORY_LIMIT, DatabaseSchemaMigrationGapError, DatabaseSchemaTooNewError, DatabaseSchemaTooOldError, SCHEMA_META_SCHEMA_VERSION_KEY, SidebarLayoutConflictError, XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_FILENAME, XOPC_DB_SCHEMA_VERSION, acknowledgeHomeAttention, appendCompactionBoundaryIfUnchanged, appendComposerInputHistory, appendConnectorExecutionAudit, appendMediaToAssistantTranscriptEntry, appendTranscriptEntry, applyPendingMigrations, authenticateDeviceAccessToken, bindEndpointPrincipal, buildDefaultSessionMetadata, buildGlobalSessionStats, buildRefreshProofMessage, cancelQueuedSessionInput, claimConnectorWebhookDelivery, claimContextExtractionRun, claimKnowledgeSourceItems, claimNextConnectorLearningJob, claimNextSessionInput, classifyStoredRow, clearComposerInputHistory, clearGatewayIdentityForTest, closeXopcDatabase, completeConnectorWebhookDelivery, completeKnowledgeSourceItemSynthesis, consumeClarificationApproval, consumeClarificationResume, consumeConnectorApproval, countKnowledgeSourceItems, createClarificationWait, createCollaborationRule, createConnectorApproval, createContextEvidence, createDevice, createDevicePairingSetup, createEndpointPrincipal, createObjectLinkRecord, decideConnectorApproval, deleteBrowserTabBinding, deleteBrowserTabBindingsByEndpoint, deleteBrowserTabBindingsByPrincipal, deleteConnectorConnection, deleteConnectorInstallation, deleteEndpointSessionBinding, deleteEndpointSessionBindingsByPrincipal, deleteKnowledgeSourceItems, deleteNoteAgentContextRecord, deleteNoteRecord, deleteObjectLinkRecord, deleteSessionConfig, deleteSessionRecord, discoverSqlMigrations, enqueueConnectorLearningJob, ensureSessionRecord, ensureXopcDatabaseSchema, estimateTokensFromMessages, extractFtsContent, findConversationIdByTranscriptId, findLatestAssistantTranscriptEntryId, findSessionInput, finishContextExtractionRun, finishEndpointToolInvocationAudit, finishKnowledgeSyncRun, finishSessionInputRun, getActiveClarification, getActivityEventRecord, getBrowserTabBinding, getBrowserTabBindingById, getCachedConnectorCatalogEntry, getClarification, getClarificationResumeInput, getClarificationSnapshot, getCollaborationRule, getConnectorAccount, getConnectorApproval, getConnectorConnection, getConnectorInstallation, getConnectorSyncPolicy, getConnectorSyncPolicyForConnection, getContextExtractionRun, getCurrentTranscriptId, getDevice, getEndpointPrincipal, getEndpointSessionBinding, getGlobalSessionStats, getInteractionState, getKnowledgeConsumerWatermark, getKnowledgeSourceCursor, getKnowledgeSourceItem, getNoteAgentContextRecord, getNoteRecord, getOrCreateGatewayIdentity, getSessionConfig, getSessionInputById, getSessionInputState, getSessionMetadata, getSessionTaskPlan, getSidebarLayout, getSqliteDatabase, getUserPeopleIndexState, getUserPerson, getUserTrustPolicy, getXopcDatabase, hasSessionConfig, incrementSessionStatsOnAppend, init_sqlite, insertSessionInput, inspectSchemaMigrationStatus, isClarificationSuspended, isDevicePairingSetupActive, isHomeAttentionAcknowledged, isXopcDatabaseOpen, issueDeviceTokenPair, listActiveSessionInputExecutions, listActiveSessionInputRuns, listActivityRecords, listCachedConnectorCatalogEntries, listCollaborationRules, listCompactionBoundaries, listComposerInputHistory, listConnectorAccounts, listConnectorActionMetadata, listConnectorApprovals, listConnectorConnections, listConnectorExecutionAudit, listConnectorInstallations, listConnectorLearningJobs, listConnectorSyncPolicies, listContextExtractionOutputs, listContextExtractionRuns, listDevices, listEndpointPrincipals, listEndpointToolInvocationAuditPage, listKnowledgeSourceChanges, listKnowledgeSourceItems, listKnowledgeSyncRuns, listNoteRecords, listObjectActivityRecords, listObjectLinkRecords, listProjectActivityRecords, listRegisteredMigrationTargets, listSessionMetadata, listSessionsByAgent, listUserPeople, loadCompactionSourceSnapshot, loadLlmMessagesForSession, loadTranscriptHistoryRowsForSession, loadTranscriptRows, loadTranscriptRowsForSession, mergeUserPeople, metadataToSessionInsert, mutateQueuedSessionInput, openXopcDatabase, paginateTranscriptMessages, patchSessionMetadata, pruneBoundedKnowledgeSourceItems, readSchemaVersion, readSchemaVersionForTest, reconcileConnectorAccount, recordActivityEvent, recoverSessionInputState, recoverStaleConnectorLearningJobs, refreshConnectorAccountCurrent, releaseConnectorWebhookDelivery, replaceConnectorCatalogEntries, replaceLatestSessionTurnAndQueueInput, replaceSidebarLayout, replaceTranscriptRows, replaceUserPeopleIndex, requireXopcDatabase, resetSessionRecord, resetXopcDatabaseSingletonForTest, resolveClarification, resolveMigrationsDir, resolveSessionAgentId, resolveXopcDatabasePath, restoreBeforeCompactionBoundary, revokeDevice, revokeEndpointPrincipal, rotateDeviceRefreshToken, runSqliteWriteTransaction, searchSessionTranscript, sessionConfigRowToConfig, sessionRowToMetadata, setBrowserTabBinding, setCollaborationRuleStatus, setConnectorLearningPaused, setEndpointSessionBinding, setInteractionState, setKnowledgeConsumerWatermark, setKnowledgeSourceCursor, setKnowledgeSourceItemSynthesisStatus, setSessionConfig, setSessionInputStatus, setSessionTaskPlan, setUserTrustPolicy, signGatewayPayload, sortBySidebarLayout, startEndpointToolInvocationAudit, startKnowledgeSyncRun, summarizeUserPeople, supersedeActiveClarification, touchEndpointPrincipal, transcriptEntryRowToStoredRow, updateConnectorLearningJob, updateInteractionStateFromMessage, updateSessionConfig, updateSessionStats, updateUserPerson, upsertConnectorActionMetadata, upsertConnectorCatalogEntry, upsertConnectorConnection, upsertConnectorInstallation, upsertConnectorSyncPolicy, upsertKnowledgeSourceItems, upsertNoteAgentContextRecord, upsertNoteRecord, validateLatestSessionTurnTarget };
90
+ export { COMPOSER_INPUT_HISTORY_LIMIT, DatabaseSchemaMigrationGapError, DatabaseSchemaTooNewError, DatabaseSchemaTooOldError, SCHEMA_META_SCHEMA_VERSION_KEY, SidebarLayoutConflictError, XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_FILENAME, XOPC_DB_SCHEMA_VERSION, acknowledgeHomeAttention, appendCompactionBoundaryIfUnchanged, appendComposerInputHistory, appendConnectorExecutionAudit, appendMediaToAssistantTranscriptEntry, appendTranscriptEntry, applyPendingMigrations, authenticateDeviceAccessToken, bindEndpointPrincipal, buildDefaultSessionMetadata, buildGlobalSessionStats, buildRefreshProofMessage, cancelQueuedSessionInput, claimConnectorWebhookDelivery, claimContextExtractionRun, claimKnowledgeSourceItems, claimNextConnectorLearningJob, claimNextSessionInput, classifyStoredRow, clearComposerInputHistory, clearGatewayIdentityForTest, closeXopcDatabase, completeConnectorWebhookDelivery, completeKnowledgeSourceItemSynthesis, consumeClarificationApproval, consumeClarificationResume, consumeConnectorApproval, countKnowledgeSourceItems, createClarificationWait, createCollaborationRule, createConnectorApproval, createContextEvidence, createDevice, createDevicePairingSetup, createEndpointPrincipal, createObjectLinkRecord, decideConnectorApproval, deleteBrowserTabBinding, deleteBrowserTabBindingsByEndpoint, deleteBrowserTabBindingsByPrincipal, deleteConnectorConnection, deleteConnectorInstallation, deleteEndpointSessionBinding, deleteEndpointSessionBindingsByPrincipal, deleteKnowledgeSourceItems, deleteNoteAgentContextRecord, deleteNoteRecord, deleteObjectLinkRecord, deleteSessionConfig, deleteSessionRecord, discoverSqlMigrations, enqueueConnectorLearningJob, ensureSessionRecord, ensureXopcDatabaseSchema, estimateTokensFromMessages, extractFtsContent, findConversationIdByTranscriptId, findLatestAssistantTranscriptEntryId, findSessionInput, finishContextExtractionRun, finishEndpointToolInvocationAudit, finishKnowledgeSyncRun, finishSessionInputRun, getActiveClarification, getActivityEventRecord, getBrowserTabBinding, getBrowserTabBindingById, getCachedConnectorCatalogEntry, getClarification, getClarificationResumeInput, getClarificationSnapshot, getCollaborationRule, getConnectorAccount, getConnectorApproval, getConnectorConnection, getConnectorInstallation, getConnectorSyncPolicy, getConnectorSyncPolicyForConnection, getContextExtractionRun, getCurrentTranscriptId, getDevice, getEndpointPrincipal, getEndpointSessionBinding, getGlobalSessionStats, getInteractionState, getKnowledgeConsumerWatermark, getKnowledgeSourceCursor, getKnowledgeSourceItem, getNoteAgentContextRecord, getNoteRecord, getOrCreateGatewayIdentity, getSessionConfig, getSessionInputById, getSessionInputState, getSessionMetadata, getSessionTaskPlan, getSidebarLayout, getSqliteDatabase, getUserPeopleIndexState, getUserPerson, getUserTrustPolicy, getXopcDatabase, hasSessionConfig, incrementSessionStatsOnAppend, init_sqlite, insertSessionInput, inspectSchemaMigrationStatus, isClarificationSuspended, isDevicePairingSetupActive, isHomeAttentionAcknowledged, isXopcDatabaseOpen, issueDeviceTokenPair, listActiveSessionInputExecutions, listActiveSessionInputRuns, listActivityRecords, listCachedConnectorCatalogEntries, listCollaborationRules, listCompactionBoundaries, listComposerInputHistory, listConnectorAccounts, listConnectorActionMetadata, listConnectorApprovals, listConnectorConnections, listConnectorExecutionAudit, listConnectorInstallations, listConnectorLearningJobs, listConnectorSyncPolicies, listContextExtractionOutputs, listContextExtractionRuns, listDevices, listEndpointPrincipals, listEndpointToolInvocationAuditPage, listKnowledgeSourceChanges, listKnowledgeSourceItems, listKnowledgeSyncRuns, listNoteRecords, listObjectActivityRecords, listObjectLinkRecords, listProjectActivityRecords, listRegisteredMigrationTargets, listSessionMetadata, listSessionsByAgent, listTaskUpdateRunIds, listTaskUpdateTriggers, listUserPeople, loadCompactionSourceSnapshot, loadLlmMessagesForSession, loadTranscriptHistoryRowsForSession, loadTranscriptRows, loadTranscriptRowsForSession, mergeUserPeople, metadataToSessionInsert, mutateQueuedSessionInput, openXopcDatabase, paginateTranscriptMessages, patchSessionMetadata, pruneBoundedKnowledgeSourceItems, readSchemaVersion, readSchemaVersionForTest, reconcileConnectorAccount, recordActivityEvent, recoverSessionInputState, recoverStaleConnectorLearningJobs, refreshConnectorAccountCurrent, releaseConnectorWebhookDelivery, replaceConnectorCatalogEntries, replaceLatestSessionTurnAndQueueInput, replaceSidebarLayout, replaceTranscriptRows, replaceUserPeopleIndex, requireXopcDatabase, resetSessionRecord, resetXopcDatabaseSingletonForTest, resolveClarification, resolveMigrationsDir, resolveSessionAgentId, resolveXopcDatabasePath, restoreBeforeCompactionBoundary, revokeDevice, revokeEndpointPrincipal, rotateDeviceRefreshToken, runSqliteWriteTransaction, searchSessionTranscript, sessionConfigRowToConfig, sessionRowToMetadata, setBrowserTabBinding, setCollaborationRuleStatus, setConnectorLearningPaused, setEndpointSessionBinding, setInteractionState, setKnowledgeConsumerWatermark, setKnowledgeSourceCursor, setKnowledgeSourceItemSynthesisStatus, setSessionConfig, setSessionInputStatus, setSessionTaskPlan, setUserTrustPolicy, signGatewayPayload, sortBySidebarLayout, startEndpointToolInvocationAudit, startKnowledgeSyncRun, summarizeUserPeople, supersedeActiveClarification, touchEndpointPrincipal, transcriptEntryRowToStoredRow, updateConnectorLearningJob, updateInteractionStateFromMessage, updateSessionConfig, updateSessionStats, updateUserPerson, upsertConnectorActionMetadata, upsertConnectorCatalogEntry, upsertConnectorConnection, upsertConnectorInstallation, upsertConnectorSyncPolicy, upsertKnowledgeSourceItems, upsertNoteAgentContextRecord, upsertNoteRecord, validateLatestSessionTurnTarget };
@@ -0,0 +1,8 @@
1
+ CREATE TABLE IF NOT EXISTS task_origin_links (
2
+ task_id TEXT PRIMARY KEY REFERENCES tasks(task_id) ON DELETE CASCADE,
3
+ conversation_id TEXT NOT NULL REFERENCES sessions(conversation_id) ON DELETE CASCADE,
4
+ created_at INTEGER NOT NULL
5
+ );
6
+
7
+ CREATE INDEX IF NOT EXISTS idx_task_origin_links_conversation
8
+ ON task_origin_links(conversation_id, created_at DESC);