@xopcai/xopc 0.0.232 → 0.0.234

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 (227) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/{activity-store-VXCWz43N.js → activity-store-BzswYHcj.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-BXRaZYW8.js → agent-avatar-dicebear-CztNAQyE.js} +1 -1
  5. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-BHeLVAW5.js +1 -0
  6. package/dist/gateway/static/root/assets/agents-B8c0U7Ze.js +1 -0
  7. package/dist/gateway/static/root/assets/{api-wGPgL8xY.js → api-7zOtMbaE.js} +1 -1
  8. package/dist/gateway/static/root/assets/{app-management-settings-panel-BJfClfPx.js → app-management-settings-panel-BxBMAdWc.js} +1 -1
  9. package/dist/gateway/static/root/assets/{appearance-settings-C_R0vUAu.js → appearance-settings-DVAxCOPL.js} +1 -1
  10. package/dist/gateway/static/root/assets/{apps-page-CBow8pBI.js → apps-page-BtzXxSYK.js} +1 -1
  11. package/dist/gateway/static/root/assets/{archive-plugin-DnFHkSHE.js → archive-plugin-DawToDU8.js} +1 -1
  12. package/dist/gateway/static/root/assets/{attachment-load-DZrEwytM.js → attachment-load-BpCKsdiO.js} +1 -1
  13. package/dist/gateway/static/root/assets/attachment-preview-renderer-BDTD8YUe.js +12 -0
  14. package/dist/gateway/static/root/assets/{automations-page-DpkKajui.js → automations-page-a6_hTplT.js} +1 -1
  15. package/dist/gateway/static/root/assets/automations-workspace-C7ZwZl04.js +6 -0
  16. package/dist/gateway/static/root/assets/{binary-plugins-Ckc_Csue.js → binary-plugins-OqUf-uET.js} +2 -2
  17. package/dist/gateway/static/root/assets/{block-editor-DAC6w-iV.js → block-editor-9OAYqVKF.js} +3 -3
  18. package/dist/gateway/static/root/assets/browser-settings-page-CEHhbDj0.js +8 -0
  19. package/dist/gateway/static/root/assets/{browser-workflow-inputs-BGd7R8GO.js → browser-workflow-inputs-4ooVX-Tx.js} +1 -1
  20. package/dist/gateway/static/root/assets/{browser-workflows-page-DUfj7ntM.js → browser-workflows-page-CUgwXXsi.js} +2 -2
  21. package/dist/gateway/static/root/assets/{capabilities-settings-panel-97gkGeSV.js → capabilities-settings-panel-CAbI9beX.js} +5 -5
  22. package/dist/gateway/static/root/assets/channels-settings-BksDnAyv.js +1 -0
  23. package/dist/gateway/static/root/assets/{channels-status-swr-CfboECLt.js → channels-status-swr-BDJvMnA_.js} +1 -1
  24. package/dist/gateway/static/root/assets/{chat-terminal-dock-CA9fndbZ.js → chat-terminal-dock-DB9zi_dy.js} +2 -2
  25. package/dist/gateway/static/root/assets/connectors-page-CnY8lcGJ.js +2 -0
  26. package/dist/gateway/static/root/assets/{cron-expression-CqPu7HYJ.js → cron-expression-a9Jyianb.js} +1 -1
  27. package/dist/gateway/static/root/assets/{date-picker-C8dJsCgk.js → date-picker-B_l2CHWO.js} +1 -1
  28. package/dist/gateway/static/root/assets/{dependency-picker-Iz2wYimy.js → dependency-picker-DjcEIzVJ.js} +1 -1
  29. package/dist/gateway/static/root/assets/{desktop-pet-C3h40FmG.js → desktop-pet-ZCBsj8Je.js} +1 -1
  30. package/dist/gateway/static/root/assets/{desktop-pet-settings-YfeVVzLe.js → desktop-pet-settings-DJJf0EvL.js} +1 -1
  31. package/dist/gateway/static/root/assets/{extension-debug-page-CChgztz_.js → extension-debug-page-CMXbAkx-.js} +1 -1
  32. package/dist/gateway/static/root/assets/{extension-page-DF6ct6_y.js → extension-page-WWePedpo.js} +1 -1
  33. package/dist/gateway/static/root/assets/{extension-settings-page-jgBsjn0F.js → extension-settings-page-DjIhNJVI.js} +1 -1
  34. package/dist/gateway/static/root/assets/{gateway-config-api-CVajuIGL.js → gateway-config-api-BNj6srhV.js} +1 -1
  35. package/dist/gateway/static/root/assets/{gateway-config-swr-BGQn8duh.js → gateway-config-swr-R702lNJR.js} +1 -1
  36. package/dist/gateway/static/root/assets/{gateway-settings-BbssNGid.js → gateway-settings-DvlFDxhZ.js} +1 -1
  37. package/dist/gateway/static/root/assets/{gateway-startup-retry-D2Rnh9fX.js → gateway-startup-retry-2rVSUvyw.js} +1 -1
  38. package/dist/gateway/static/root/assets/heartbeat-settings-Dlahslof.js +1 -0
  39. package/dist/gateway/static/root/assets/home-page-DJhUd30b.js +1 -0
  40. package/dist/gateway/static/root/assets/{image-generation-api-D7W2p5_8.js → image-generation-api-B28USRCK.js} +1 -1
  41. package/dist/gateway/static/root/assets/index-BTUuTnc9.css +2 -0
  42. package/dist/gateway/static/root/assets/index-CXGQihfj.js +70 -0
  43. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BvHYyNus.js → keyboard-shortcuts-settings-d12AAEaC.js} +1 -1
  44. package/dist/gateway/static/root/assets/local-app-workbench-page-DUP0UiFY.js +2 -0
  45. package/dist/gateway/static/root/assets/{local-apps-page-Cb8t2wWM.js → local-apps-page-_z2o0cD1.js} +1 -1
  46. package/dist/gateway/static/root/assets/{locale-store-DLwVxS3V.js → locale-store-8k4mvYGL.js} +1 -1
  47. package/dist/gateway/static/root/assets/logs-page-CPUaLcGH.js +2 -0
  48. package/dist/gateway/static/root/assets/{management-settings-B8Jie4-J.js → management-settings-eTBfNgXU.js} +1 -1
  49. package/dist/gateway/static/root/assets/{markdown-split-BD1r4o2i.js → markdown-split-7rTfQCN_.js} +1 -1
  50. package/dist/gateway/static/root/assets/markdown-view-D02mJdoU.js +201 -0
  51. package/dist/gateway/static/root/assets/{media-plugins-BCev8fkW.js → media-plugins-BIfKo5Ow.js} +1 -1
  52. package/dist/gateway/static/root/assets/messages-CoovNoMn.js +3 -0
  53. package/dist/gateway/static/root/assets/{mobile-device-api-DACoHhhk.js → mobile-device-api-CvjVB_TB.js} +1 -1
  54. package/dist/gateway/static/root/assets/models-hub-cache-CYr6LzvY.js +1 -0
  55. package/dist/gateway/static/root/assets/{notes-api-DEdNKw0I.js → notes-api-p2Pncp2B.js} +1 -1
  56. package/dist/gateway/static/root/assets/{notes-page-BBTLjJwa.js → notes-page-dOvbZBOQ.js} +1 -1
  57. package/dist/gateway/static/root/assets/notes-workbench-DQMUpDc9.js +4 -0
  58. package/dist/gateway/static/root/assets/{oauth-api-BNCO2YK5.js → oauth-api-DpLONwfK.js} +1 -1
  59. package/dist/gateway/static/root/assets/{product-open-page-fEBbRekH.js → product-open-page-CgZhadZQ.js} +1 -1
  60. package/dist/gateway/static/root/assets/project-detail-page-D1HidxgT.js +1 -0
  61. package/dist/gateway/static/root/assets/projects-page-CxwNbbud.js +1 -0
  62. package/dist/gateway/static/root/assets/{registry-api-Cvr4Qm7N.js → registry-api-B7b0LJgI.js} +1 -1
  63. package/dist/gateway/static/root/assets/remote-access-hub-CK59rSc_.js +1 -0
  64. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-BT5B74IH.js → runtime-tools-settings-panel-D3PS55Yg.js} +2 -2
  65. package/dist/gateway/static/root/assets/{schema-form-C4tB34S5.js → schema-form-H-aeWTzM.js} +1 -1
  66. package/dist/gateway/static/root/assets/sessions-page-C2tP7363.js +1 -0
  67. package/dist/gateway/static/root/assets/settings-advanced-gate-DlYBA2N-.js +1 -0
  68. package/dist/gateway/static/root/assets/{settings-form-section-D1oXhkgI.js → settings-form-section-B9oF8Rhw.js} +1 -1
  69. package/dist/gateway/static/root/assets/{settings-loading-skeleton-CldfX6FJ.js → settings-loading-skeleton-CazDM3n5.js} +1 -1
  70. package/dist/gateway/static/root/assets/{settings-page-c3LJnbvE.js → settings-page-C6pmQNzY.js} +1 -1
  71. package/dist/gateway/static/root/assets/setup-status-panel-Cn2E0G2o.js +1 -0
  72. package/dist/gateway/static/root/assets/{share-preview-page-DptCK_mk.js → share-preview-page-XgxvE8cx.js} +1 -1
  73. package/dist/gateway/static/root/assets/shares-settings-Czph0_fM.js +1 -0
  74. package/dist/gateway/static/root/assets/skill-reload-api-DDq_QEqd.js +1 -0
  75. package/dist/gateway/static/root/assets/{skills-page-OHBeBtSg.js → skills-page-CfNV6kgb.js} +1 -1
  76. package/dist/gateway/static/root/assets/{skills-page.utils-B9WZbOLC.js → skills-page.utils-DgxGb7v7.js} +1 -1
  77. package/dist/gateway/static/root/assets/{system-settings-panel-Dj_DpOGw.js → system-settings-panel-B4W--Ukh.js} +1 -1
  78. package/dist/gateway/static/root/assets/task-detail-page-UY5kNWoR.js +1 -0
  79. package/dist/gateway/static/root/assets/{theme-store-Cpd3Gd5R.js → theme-store-CpcBI73Q.js} +1 -1
  80. package/dist/gateway/static/root/assets/{use-autosave-DCl5Yq7N.js → use-autosave-DR7YWBzR.js} +1 -1
  81. package/dist/gateway/static/root/assets/user-context-page-DnUL8kJU.js +1 -0
  82. package/dist/gateway/static/root/assets/{voice-api-key-field-BB_ZQV8F.js → voice-api-key-field-BZhqoxBR.js} +1 -1
  83. package/dist/gateway/static/root/assets/{voice-config-api-BNiYmpl5.js → voice-config-api-ynE-vY6I.js} +1 -1
  84. package/dist/gateway/static/root/assets/{work-discovery-overlay-BrIdtdum.js → work-discovery-overlay-CouKiK45.js} +1 -1
  85. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-hKh-uCLo.js → workflow-run-setup-panel-CUqAESrr.js} +2 -2
  86. package/dist/gateway/static/root/assets/workflows-page-B8dJRjMJ.js +5 -0
  87. package/dist/gateway/static/root/index.html +13 -13
  88. package/dist/package.js +1 -1
  89. package/dist/packages/endpoint-tools-protocol/src/index.js +162 -2
  90. package/dist/packages/gateway-contract/src/product-delivery.js +6 -2
  91. package/dist/packages/gateway-contract/src/turn-outcome.js +77 -1
  92. package/dist/src/agent/agent-manager.js +4 -4
  93. package/dist/src/agent/background-review/run-background-review.js +1 -1
  94. package/dist/src/agent/capabilities/definitions.d.ts +1 -1
  95. package/dist/src/agent/capabilities/definitions.js +2 -1
  96. package/dist/src/agent/embedded/model-runtime.js +1 -1
  97. package/dist/src/agent/embedded/run-for-session.js +57 -8
  98. package/dist/src/agent/embedded/types.d.ts +5 -0
  99. package/dist/src/agent/external-tools/endpoint-provider.js +5 -1
  100. package/dist/src/agent/image/tool-model-config.js +1 -1
  101. package/dist/src/agent/ipc/inbox.js +1 -1
  102. package/dist/src/agent/mcp/oauth/mcp-oauth-store.js +1 -1
  103. package/dist/src/agent/prompt/sections/tooling.js +5 -0
  104. package/dist/src/agent/service.js +2 -2
  105. package/dist/src/agent/session/session-inspector.js +1 -1
  106. package/dist/src/agent/skills/hub-lock.js +1 -1
  107. package/dist/src/agent/tasks/task-judge-service.js +3 -3
  108. package/dist/src/agent/tools/create-share-tool.js +2 -1
  109. package/dist/src/agent/tools/exec-command.d.ts +2 -0
  110. package/dist/src/agent/tools/exec-command.js +24 -7
  111. package/dist/src/agent/tools/factory.js +2 -0
  112. package/dist/src/agent/tools/index.d.ts +1 -0
  113. package/dist/src/agent/tools/index.js +2 -1
  114. package/dist/src/agent/tools/publish-artifacts.d.ts +8 -0
  115. package/dist/src/agent/tools/publish-artifacts.js +95 -0
  116. package/dist/src/agent/tools/send-media.js +2 -1
  117. package/dist/src/ai-assist/text-assist.js +1 -1
  118. package/dist/src/auth/credentials.js +2 -2
  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/browser/providers/browser-ext-install.js +1 -1
  122. package/dist/src/cli/command-catalog.js +4 -0
  123. package/dist/src/cli/command-loaders.js +1 -0
  124. package/dist/src/cli/command-manifest.js +4 -0
  125. package/dist/src/cli/commands/auth.js +1 -1
  126. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  127. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  128. package/dist/src/cli/commands/models.js +1 -1
  129. package/dist/src/cli/commands/onboard/model.js +1 -1
  130. package/dist/src/cli/commands/providers.js +1 -1
  131. package/dist/src/cli/commands/support.d.ts +1 -0
  132. package/dist/src/cli/commands/support.js +51 -0
  133. package/dist/src/config/index.js +4 -4
  134. package/dist/src/config/loader.js +1 -1
  135. package/dist/src/config/models-json.js +1 -1
  136. package/dist/src/endpoint-tools/binding-service.d.ts +22 -0
  137. package/dist/src/endpoint-tools/binding-service.js +45 -0
  138. package/dist/src/endpoint-tools/index.d.ts +1 -0
  139. package/dist/src/endpoint-tools/index.js +2 -1
  140. package/dist/src/endpoint-tools/invocation-service.d.ts +1 -0
  141. package/dist/src/endpoint-tools/invocation-service.js +8 -0
  142. package/dist/src/endpoint-tools/policy.d.ts +4 -1
  143. package/dist/src/endpoint-tools/policy.js +68 -5
  144. package/dist/src/endpoint-tools/registry.js +1 -1
  145. package/dist/src/endpoint-tools/runtime.d.ts +2 -0
  146. package/dist/src/endpoint-tools/runtime.js +8 -0
  147. package/dist/src/extensions/lockfile.js +1 -1
  148. package/dist/src/files/file-service.js +14 -5
  149. package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
  150. package/dist/src/gateway/agents-admin.js +1 -1
  151. package/dist/src/gateway/chat-stream/mapper.js +5 -0
  152. package/dist/src/gateway/hono/lib/config-payload.js +1 -1
  153. package/dist/src/gateway/hono/middleware/auth.js +3 -2
  154. package/dist/src/gateway/hono/routes/endpoint-tools.js +68 -1
  155. package/dist/src/gateway/hono/routes/files.js +7 -0
  156. package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
  157. package/dist/src/gateway/hono/routes/media.js +46 -2
  158. package/dist/src/gateway/hono/routes/models.js +1 -1
  159. package/dist/src/gateway/hono/routes/support.d.ts +3 -0
  160. package/dist/src/gateway/hono/routes/support.js +28 -0
  161. package/dist/src/gateway/hono/routes/you.js +24 -0
  162. package/dist/src/gateway/service/config-coordinator.js +1 -1
  163. package/dist/src/gateway/service/run-gateway-agent.js +0 -35
  164. package/dist/src/gateway/service.js +3 -3
  165. package/dist/src/media/store.js +9 -0
  166. package/dist/src/providers/auth-runtime/resolve-auth.js +1 -1
  167. package/dist/src/providers/index.js +2 -2
  168. package/dist/src/providers/model-registry.js +1 -1
  169. package/dist/src/providers/register-runtime-providers.js +1 -1
  170. package/dist/src/session/store.js +4 -2
  171. package/dist/src/session/turn-outcome-projector.d.ts +9 -0
  172. package/dist/src/session/turn-outcome-projector.js +209 -0
  173. package/dist/src/share/hosted-session-share.js +1 -1
  174. package/dist/src/storage/sqlite/endpoint-session-binding-repository.d.ts +8 -0
  175. package/dist/src/storage/sqlite/endpoint-session-binding-repository.js +32 -0
  176. package/dist/src/storage/sqlite/index.d.ts +1 -0
  177. package/dist/src/storage/sqlite/index.js +2 -1
  178. package/dist/src/storage/sqlite/migrations/139_turn_outcome_artifact_backfill.sql +231 -0
  179. package/dist/src/storage/sqlite/migrations/140_endpoint_session_bindings.sql +8 -0
  180. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  181. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  182. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  183. package/dist/src/storage/sqlite/schema.js +1 -1
  184. package/dist/src/support/build-support-investigation-prompt.d.ts +2 -0
  185. package/dist/src/support/build-support-investigation-prompt.js +29 -0
  186. package/dist/src/support/collect-support-report.d.ts +16 -0
  187. package/dist/src/support/collect-support-report.js +216 -0
  188. package/dist/src/support/redact-support-report.d.ts +16 -0
  189. package/dist/src/support/redact-support-report.js +89 -0
  190. package/dist/src/support/types.d.ts +76 -0
  191. package/dist/src/support/types.js +18 -0
  192. package/dist/src/tui/tui-startup-resources.js +1 -1
  193. package/dist/src/tui/tui.js +1 -1
  194. package/dist/src/user-context/user-avatar.d.ts +17 -0
  195. package/dist/src/user-context/user-avatar.js +116 -0
  196. package/dist/src/workflows/service/workflow-run-service.js +1 -1
  197. package/package.json +2 -2
  198. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-dR7HMaRX.js +0 -1
  199. package/dist/gateway/static/root/assets/agents-Bileycwe.js +0 -1
  200. package/dist/gateway/static/root/assets/attachment-preview-renderer-Cmo-5BP5.js +0 -11
  201. package/dist/gateway/static/root/assets/automations-workspace-BBntVWgv.js +0 -6
  202. package/dist/gateway/static/root/assets/browser-settings-page-DrsMd-Po.js +0 -8
  203. package/dist/gateway/static/root/assets/channels-settings-CuBsz8UI.js +0 -1
  204. package/dist/gateway/static/root/assets/connectors-page-SuL7td7Z.js +0 -2
  205. package/dist/gateway/static/root/assets/heartbeat-settings-CJtXu8iD.js +0 -1
  206. package/dist/gateway/static/root/assets/home-page-Be1o1AXQ.js +0 -1
  207. package/dist/gateway/static/root/assets/index-B2OJSXX9.js +0 -70
  208. package/dist/gateway/static/root/assets/index-rHjAElxG.css +0 -2
  209. package/dist/gateway/static/root/assets/local-app-workbench-page-COfelgk7.js +0 -2
  210. package/dist/gateway/static/root/assets/logs-page-DA8oDjeB.js +0 -2
  211. package/dist/gateway/static/root/assets/markdown-view-B-BHEcNd.js +0 -201
  212. package/dist/gateway/static/root/assets/messages-Dp1OxSKt.js +0 -3
  213. package/dist/gateway/static/root/assets/models-hub-cache-C8zjqmIv.js +0 -1
  214. package/dist/gateway/static/root/assets/notes-workbench-DICgUGPv.js +0 -4
  215. package/dist/gateway/static/root/assets/project-detail-page-CqdkznYJ.js +0 -1
  216. package/dist/gateway/static/root/assets/projects-page-dHDXpMCg.js +0 -1
  217. package/dist/gateway/static/root/assets/remote-access-hub-2feZudJw.js +0 -1
  218. package/dist/gateway/static/root/assets/sessions-page-CO2JCFdy.js +0 -1
  219. package/dist/gateway/static/root/assets/settings-advanced-gate-DxMVaqdn.js +0 -1
  220. package/dist/gateway/static/root/assets/setup-status-panel-DZNHb6A5.js +0 -1
  221. package/dist/gateway/static/root/assets/shares-settings-DakZ2AGN.js +0 -1
  222. package/dist/gateway/static/root/assets/skill-reload-api-BOiNkWJC.js +0 -1
  223. package/dist/gateway/static/root/assets/task-detail-page-D5Nbe3C8.js +0 -1
  224. package/dist/gateway/static/root/assets/user-context-page-CAPSUK8B.js +0 -1
  225. package/dist/gateway/static/root/assets/workflows-page-ahDvypGO.js +0 -5
  226. package/dist/src/gateway/chat-stream/turn-outcome-collector.d.ts +0 -16
  227. package/dist/src/gateway/chat-stream/turn-outcome-collector.js +0 -111
@@ -0,0 +1,45 @@
1
+ //#region src/endpoint-tools/binding-service.ts
2
+ function memoryStore() {
3
+ const bindings = /* @__PURE__ */ new Map();
4
+ return {
5
+ get: (sessionKey) => bindings.get(sessionKey),
6
+ set: (binding) => {
7
+ bindings.set(binding.sessionKey, binding);
8
+ return binding;
9
+ },
10
+ delete: (sessionKey) => bindings.delete(sessionKey)
11
+ };
12
+ }
13
+ var EndpointBindingService = class {
14
+ constructor(registry, store = memoryStore()) {
15
+ this.registry = registry;
16
+ this.store = store;
17
+ }
18
+ bind(sessionKey, endpointId, now = Date.now()) {
19
+ const normalizedSessionKey = this.normalizeSessionKey(sessionKey);
20
+ if (!this.registry.get(endpointId)) throw new Error("Endpoint is offline");
21
+ const binding = {
22
+ sessionKey: normalizedSessionKey,
23
+ endpointId,
24
+ boundAt: now
25
+ };
26
+ return this.store.set(binding);
27
+ }
28
+ get(sessionKey) {
29
+ return this.store.get(this.normalizeSessionKey(sessionKey));
30
+ }
31
+ resolve(sessionKey) {
32
+ const binding = this.get(sessionKey);
33
+ return binding ? this.registry.get(binding.endpointId) : void 0;
34
+ }
35
+ unbind(sessionKey) {
36
+ return this.store.delete(this.normalizeSessionKey(sessionKey));
37
+ }
38
+ normalizeSessionKey(sessionKey) {
39
+ const normalized = sessionKey.trim();
40
+ if (!normalized || normalized.length > 500) throw new TypeError("Invalid session key");
41
+ return normalized;
42
+ }
43
+ };
44
+ //#endregion
45
+ export { EndpointBindingService };
@@ -1,4 +1,5 @@
1
1
  export { EndpointToolRuntime } from './runtime.js';
2
+ export { EndpointBindingService, type EndpointSessionBinding, type EndpointSessionBindingStore, } from './binding-service.js';
2
3
  export { EndpointInvocationService, EndpointToolExecutionError, type EndpointInvocationAuditSink, type EndpointInvocationResult, } from './invocation-service.js';
3
4
  export { EndpointToolPolicy, EndpointToolPolicyError } from './policy.js';
4
5
  export { EndpointRegistry, endpointToolRevision, type EndpointConnectionSnapshot, type RegisteredEndpointTool, } from './registry.js';
@@ -1,6 +1,7 @@
1
+ import { EndpointBindingService } from "./binding-service.js";
1
2
  import { EndpointToolPolicy, EndpointToolPolicyError } from "./policy.js";
2
3
  import { EndpointInvocationService, EndpointToolExecutionError } from "./invocation-service.js";
3
4
  import { EndpointRegistry, endpointToolRevision } from "./registry.js";
4
5
  import { ENDPOINT_UPLOAD_MAX_BYTES, EndpointUploadError, EndpointUploadService } from "./upload-service.js";
5
6
  import { EndpointToolRuntime } from "./runtime.js";
6
- export { ENDPOINT_UPLOAD_MAX_BYTES, EndpointInvocationService, EndpointRegistry, EndpointToolExecutionError, EndpointToolPolicy, EndpointToolPolicyError, EndpointToolRuntime, EndpointUploadError, EndpointUploadService, endpointToolRevision };
7
+ export { ENDPOINT_UPLOAD_MAX_BYTES, EndpointBindingService, EndpointInvocationService, EndpointRegistry, EndpointToolExecutionError, EndpointToolPolicy, EndpointToolPolicyError, EndpointToolRuntime, EndpointUploadError, EndpointUploadService, endpointToolRevision };
@@ -43,6 +43,7 @@ export declare class EndpointInvocationService {
43
43
  private readonly options;
44
44
  private readonly pending;
45
45
  private readonly policy;
46
+ private readonly ajv;
46
47
  constructor(registry: EndpointRegistry, options?: EndpointInvocationServiceOptions);
47
48
  invoke(params: {
48
49
  endpointId: string;
@@ -1,6 +1,7 @@
1
1
  import { ENDPOINT_INVOCATION_RECEIPT_TIMEOUT_MS, canonicalJson } from "../../packages/endpoint-tools-protocol/src/index.js";
2
2
  import { EndpointToolPolicy, EndpointToolPolicyError } from "./policy.js";
3
3
  import crypto from "node:crypto";
4
+ import Ajv2020 from "ajv/dist/2020.js";
4
5
  //#region src/endpoint-tools/invocation-service.ts
5
6
  var EndpointToolExecutionError = class extends Error {
6
7
  constructor(code, message) {
@@ -12,6 +13,10 @@ var EndpointToolExecutionError = class extends Error {
12
13
  var EndpointInvocationService = class {
13
14
  pending = /* @__PURE__ */ new Map();
14
15
  policy;
16
+ ajv = new Ajv2020({
17
+ allErrors: true,
18
+ strict: true
19
+ });
15
20
  constructor(registry, options = {}) {
16
21
  this.registry = registry;
17
22
  this.options = options;
@@ -58,6 +63,7 @@ var EndpointInvocationService = class {
58
63
  id: invocationId,
59
64
  endpointId: params.endpointId,
60
65
  toolName: params.toolName,
66
+ descriptor: tool.descriptor,
61
67
  state: "sent",
62
68
  receiptTimer: setTimeout(() => {
63
69
  this.fail(invocationId, this.error("TOOL_TIMEOUT", "Endpoint did not receive the invocation"));
@@ -111,6 +117,8 @@ var EndpointInvocationService = class {
111
117
  case "tool.result":
112
118
  if (pending.state !== "running") return;
113
119
  try {
120
+ const validate = this.ajv.compile(pending.descriptor.outputSchema);
121
+ if (!validate(message.payload.content)) throw new Error(`Endpoint result does not match its contract: ${this.ajv.errorsText(validate.errors)}`);
114
122
  this.options.uploads?.validateAndClose(invocationId, message.payload.content);
115
123
  } catch (error) {
116
124
  this.fail(invocationId, this.error("PROTOCOL_ERROR", error instanceof Error ? error.message : String(error)));
@@ -1,10 +1,13 @@
1
- import type { EndpointAvailability, EndpointKind, EndpointToolDescriptor } from '@xopcai/endpoint-tools-protocol';
1
+ import { type EndpointAvailability, type EndpointKind, type EndpointToolDescriptor } from '@xopcai/endpoint-tools-protocol';
2
2
  export interface EndpointToolPolicyDecision {
3
3
  confirmationRequired: boolean;
4
4
  }
5
5
  export declare class EndpointToolPolicyError extends Error {
6
6
  }
7
7
  export declare class EndpointToolPolicy {
8
+ private readonly ajv;
8
9
  validateDescriptor(kind: EndpointKind, descriptor: EndpointToolDescriptor): void;
9
10
  evaluate(descriptor: EndpointToolDescriptor, availability: EndpointAvailability): EndpointToolPolicyDecision;
11
+ private validatePolicyFields;
12
+ private assertFields;
10
13
  }
@@ -1,17 +1,80 @@
1
+ import { ENDPOINT_CONTACT_LIST_OUTPUT_SCHEMA, ENDPOINT_CONTACT_OUTPUT_SCHEMA, ENDPOINT_FILE_OUTPUT_SCHEMA, ENDPOINT_TEXT_OUTPUT_SCHEMA, canonicalJson } from "../../packages/endpoint-tools-protocol/src/index.js";
2
+ import Ajv2020 from "ajv/dist/2020.js";
1
3
  //#region src/endpoint-tools/policy.ts
2
4
  var EndpointToolPolicyError = class extends Error {};
5
+ function contract(policyId, outputSchema, resultKinds, permissions) {
6
+ return {
7
+ policyId,
8
+ outputSchema,
9
+ resultKinds,
10
+ permissions
11
+ };
12
+ }
13
+ const POLICY_BY_TOOL = {
14
+ "web.file.pick": contract("personal.foreground-read", ENDPOINT_FILE_OUTPUT_SCHEMA, ["file"], ["file-read"]),
15
+ "web.file.download": contract("user.foreground-write", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["file-download"]),
16
+ "web.page.get_selection": contract("public.foreground-read", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], []),
17
+ "web.clipboard.write": contract("user.foreground-write", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["clipboard-write"]),
18
+ "web.page.navigate": contract("user.foreground-write", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["navigation"]),
19
+ "desktop.file.pick": contract("personal.foreground-read", ENDPOINT_FILE_OUTPUT_SCHEMA, ["file"], ["file-read"]),
20
+ "desktop.file.save": contract("user.foreground-write", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["file-write"]),
21
+ "desktop.notification.show": contract("user.foreground-write", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["notifications"]),
22
+ "desktop.clipboard.read": contract("personal.foreground-read", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["clipboard-read"]),
23
+ "desktop.clipboard.write": contract("user.foreground-write", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["clipboard-write"]),
24
+ "desktop.app.open_external": contract("user.foreground-write", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["open-external-url"]),
25
+ "mobile.contacts.pick": contract("personal.foreground-read", ENDPOINT_CONTACT_OUTPUT_SCHEMA, ["json"], ["contacts-read-selected"]),
26
+ "mobile.contacts.search": contract("personal.foreground-read", ENDPOINT_CONTACT_LIST_OUTPUT_SCHEMA, ["json"], ["contacts-read"]),
27
+ "mobile.contacts.get": contract("personal.foreground-read", ENDPOINT_CONTACT_OUTPUT_SCHEMA, ["json"], ["contacts-read"]),
28
+ "mobile.file.pick": contract("personal.foreground-read", ENDPOINT_FILE_OUTPUT_SCHEMA, ["file"], ["file-read"]),
29
+ "mobile.file.share": contract("user.foreground-write", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["file-share"]),
30
+ "mobile.notification.show": contract("user.foreground-write", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["notifications"]),
31
+ "mobile.device.get_info": contract("public.background-read", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], []),
32
+ "mobile.clipboard.write": contract("user.foreground-write", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["clipboard-write"]),
33
+ "mobile.app.open_url": contract("user.foreground-write", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["open-external-url"])
34
+ };
3
35
  var EndpointToolPolicy = class {
36
+ ajv = new Ajv2020({
37
+ allErrors: true,
38
+ strict: true
39
+ });
4
40
  validateDescriptor(kind, descriptor) {
5
41
  if (!descriptor.name.startsWith(`${kind}.`)) throw new EndpointToolPolicyError(`Tool ${descriptor.name} does not belong to ${kind}`);
6
- if (descriptor.effect !== "read") {
7
- if (descriptor.confirmation !== "always") throw new EndpointToolPolicyError(`Mutating tool ${descriptor.name} must always require confirmation`);
8
- if (!descriptor.requiresForeground) throw new EndpointToolPolicyError(`Mutating tool ${descriptor.name} must require foreground`);
9
- if (descriptor.requiredPermissions.length === 0) throw new EndpointToolPolicyError(`Mutating tool ${descriptor.name} must declare a permission`);
42
+ const contract = POLICY_BY_TOOL[descriptor.name];
43
+ if (!contract) throw new EndpointToolPolicyError(`Tool ${descriptor.name} has no trusted server policy`);
44
+ if (descriptor.policyId !== contract.policyId) throw new EndpointToolPolicyError(`Tool ${descriptor.name} does not match its trusted server policy`);
45
+ if (canonicalJson(descriptor.outputSchema) !== canonicalJson(contract.outputSchema) || canonicalJson(descriptor.resultKinds) !== canonicalJson(contract.resultKinds) || canonicalJson([...descriptor.requiredPermissions].sort()) !== canonicalJson([...contract.permissions].sort())) throw new EndpointToolPolicyError(`Tool ${descriptor.name} does not match its trusted server contract`);
46
+ this.validatePolicyFields(descriptor);
47
+ try {
48
+ this.ajv.compile(descriptor.outputSchema);
49
+ } catch (error) {
50
+ throw new EndpointToolPolicyError(`Tool ${descriptor.name} has an invalid output schema: ${error instanceof Error ? error.message : String(error)}`);
10
51
  }
11
52
  }
12
53
  evaluate(descriptor, availability) {
13
54
  if (descriptor.requiresForeground && availability !== "foreground") throw new EndpointToolPolicyError("Endpoint is not in the foreground");
14
- return { confirmationRequired: descriptor.confirmation === "always" || descriptor.effect !== "read" };
55
+ return { confirmationRequired: descriptor.confirmation === "always" };
56
+ }
57
+ validatePolicyFields(descriptor) {
58
+ switch (descriptor.policyId) {
59
+ case "public.background-read":
60
+ this.assertFields(descriptor, "read", "never", false, "public");
61
+ return;
62
+ case "public.foreground-read":
63
+ this.assertFields(descriptor, "read", "never", true, "public");
64
+ return;
65
+ case "personal.foreground-read":
66
+ this.assertFields(descriptor, "read", "always", true, "personal");
67
+ if (descriptor.requiredPermissions.length === 0) throw new EndpointToolPolicyError(`Personal tool ${descriptor.name} must declare a permission`);
68
+ return;
69
+ case "user.foreground-write":
70
+ if (descriptor.effect === "read") throw new EndpointToolPolicyError(`Mutating tool ${descriptor.name} cannot declare a read effect`);
71
+ if (descriptor.confirmation !== "always" || !descriptor.requiresForeground || descriptor.sensitivity !== "personal" || descriptor.requiredPermissions.length === 0) throw new EndpointToolPolicyError(`Mutating tool ${descriptor.name} violates its trusted policy`);
72
+ return;
73
+ default: throw new EndpointToolPolicyError(`Unknown endpoint policy: ${descriptor.policyId}`);
74
+ }
75
+ }
76
+ assertFields(descriptor, effect, confirmation, requiresForeground, sensitivity) {
77
+ if (descriptor.effect !== effect || descriptor.confirmation !== confirmation || descriptor.requiresForeground !== requiresForeground || descriptor.sensitivity !== sensitivity) throw new EndpointToolPolicyError(`Tool ${descriptor.name} violates its trusted policy`);
15
78
  }
16
79
  };
17
80
  //#endregion
@@ -93,7 +93,7 @@ var EndpointRegistry = class {
93
93
  const connection = this.connectionByEndpointId.get(endpointId);
94
94
  if (!connection || connection.transport.readyState !== 1) throw new Error(`Endpoint is offline: ${endpointId}`);
95
95
  const message = {
96
- protocolVersion: 1,
96
+ protocolVersion: 2,
97
97
  messageId: crypto.randomUUID(),
98
98
  type,
99
99
  sentAt: Date.now(),
@@ -1,5 +1,6 @@
1
1
  import { type ClientEndpointMessage, type EndpointHelloPayload } from '@xopcai/endpoint-tools-protocol';
2
2
  import { type EndpointAuthenticatorDeps } from './auth.js';
3
+ import { EndpointBindingService } from './binding-service.js';
3
4
  import { EndpointInvocationService, type EndpointInvocationAuditSink } from './invocation-service.js';
4
5
  import { EndpointRegistry, type EndpointRegistration, type EndpointTransport } from './registry.js';
5
6
  import { EndpointUploadService } from './upload-service.js';
@@ -7,6 +8,7 @@ export declare class EndpointToolRuntime {
7
8
  readonly registry: EndpointRegistry;
8
9
  readonly invocations: EndpointInvocationService;
9
10
  readonly uploads: EndpointUploadService;
11
+ readonly bindings: EndpointBindingService;
10
12
  private readonly authenticator;
11
13
  private closed;
12
14
  constructor(options?: {
@@ -1,11 +1,13 @@
1
1
  import { resolveStateDir } from "../config/paths-state.js";
2
2
  import { createLogger } from "../utils/logger/index.js";
3
3
  import { init_logger } from "../utils/logger.js";
4
+ import { deleteEndpointSessionBinding, getEndpointSessionBinding, setEndpointSessionBinding } from "../storage/sqlite/endpoint-session-binding-repository.js";
4
5
  import { bindEndpointPrincipal, getEndpointPrincipal, touchEndpointPrincipal } from "../storage/sqlite/endpoint-principal-repository.js";
5
6
  import { finishEndpointToolInvocationAudit, startEndpointToolInvocationAudit } from "../storage/sqlite/endpoint-tool-invocation-repository.js";
6
7
  import "../storage/sqlite/index.js";
7
8
  import { init_paths } from "../config/paths.js";
8
9
  import { EndpointAuthenticator } from "./auth.js";
10
+ import { EndpointBindingService } from "./binding-service.js";
9
11
  import { EndpointToolPolicy } from "./policy.js";
10
12
  import { EndpointInvocationService } from "./invocation-service.js";
11
13
  import { EndpointRegistry } from "./registry.js";
@@ -20,11 +22,17 @@ var EndpointToolRuntime = class {
20
22
  registry;
21
23
  invocations;
22
24
  uploads;
25
+ bindings;
23
26
  authenticator;
24
27
  closed = false;
25
28
  constructor(options = {}) {
26
29
  const policy = new EndpointToolPolicy();
27
30
  this.registry = new EndpointRegistry(policy);
31
+ this.bindings = new EndpointBindingService(this.registry, {
32
+ get: getEndpointSessionBinding,
33
+ set: setEndpointSessionBinding,
34
+ delete: deleteEndpointSessionBinding
35
+ });
28
36
  this.authenticator = new EndpointAuthenticator(options.auth ?? {
29
37
  getPrincipal: getEndpointPrincipal,
30
38
  bindEndpoint: bindEndpointPrincipal,
@@ -1,7 +1,7 @@
1
1
  import { createLogger } from "../utils/logger/index.js";
2
2
  import { init_logger } from "../utils/logger.js";
3
- import { init_paths, resolveExtensionsDir, resolveExtensionsLockPath } from "../config/paths.js";
4
3
  import { init_write_file_atomic, writeTextAtomic } from "../infra/write-file-atomic.js";
4
+ import { init_paths, resolveExtensionsDir, resolveExtensionsLockPath } from "../config/paths.js";
5
5
  import { dirname, join } from "path";
6
6
  import { existsSync } from "fs";
7
7
  import { mkdir, readFile } from "fs/promises";
@@ -26,6 +26,7 @@ const TEXT_EXTENSIONS = new Set([
26
26
  "svg",
27
27
  "ts",
28
28
  "tsx",
29
+ "tsv",
29
30
  "txt",
30
31
  "xml",
31
32
  "yaml",
@@ -50,10 +51,18 @@ const MIME_TYPES = {
50
51
  ts: "text/typescript",
51
52
  tsx: "text/typescript",
52
53
  csv: "text/csv",
54
+ tsv: "text/tab-separated-values",
53
55
  xml: "application/xml",
54
56
  yaml: "application/yaml",
55
57
  yml: "application/yaml",
56
58
  pdf: "application/pdf",
59
+ doc: "application/msword",
60
+ docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
61
+ xls: "application/vnd.ms-excel",
62
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
63
+ ppt: "application/vnd.ms-powerpoint",
64
+ pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
65
+ zip: "application/zip",
57
66
  mp3: "audio/mpeg",
58
67
  wav: "audio/wav",
59
68
  ogg: "audio/ogg",
@@ -106,13 +115,13 @@ async function resolveFilePath(root, path, mustExist = true) {
106
115
  const canonicalRoot = await realpath(root).catch(() => {
107
116
  throw new FileServiceError(404, "File space is unavailable");
108
117
  });
109
- const candidate = resolve(canonicalRoot, normalizeRelativePath(path));
110
- if (!isWithin(canonicalRoot, candidate)) throw new FileServiceError(400, "Invalid file path");
118
+ const candidate = isAbsolute(path) ? resolve(path) : resolve(canonicalRoot, normalizeRelativePath(path));
111
119
  if (!mustExist) {
112
- if (!isWithin(canonicalRoot, await realpath(dirname(candidate)).catch(() => {
120
+ const parent = await realpath(dirname(candidate)).catch(() => {
113
121
  throw new FileServiceError(404, "Parent directory not found");
114
- }))) throw new FileServiceError(400, "Invalid file path");
115
- return candidate;
122
+ });
123
+ if (!isWithin(canonicalRoot, parent)) throw new FileServiceError(400, "Invalid file path");
124
+ return resolve(parent, basename(candidate));
116
125
  }
117
126
  const canonicalTarget = await realpath(candidate).catch(() => {
118
127
  throw new FileServiceError(404, "File not found");
@@ -247,4 +247,4 @@ export declare const GATEWAY_BUILTIN_TOOLS: readonly [{
247
247
  readonly zh: "使用已验证的参数执行选定的外部工具。";
248
248
  };
249
249
  }];
250
- export declare const GATEWAY_BUILTIN_TOOL_IDS: ("automation" | "workflow" | "find" | "todo" | "image" | "clarify" | "dreaming" | "memory_search" | "memory_get" | "web_search" | "web_fetch" | "browser_use" | "grep" | "session_search" | "read_file" | "list_dir" | "write_file" | "apply_patch" | "exec_command" | "update_plan" | "xopc_tool_search" | "xopc_tool_describe" | "xopc_tool_execute" | "web_extract" | "image_generate" | "skills_list" | "skill_view" | "skill_manage" | "skills_marketplace_search" | "send_message" | "send_media" | "read_media" | "create_share" | "session_status" | "tool_manual" | "delegate_task" | "skill_install" | "text_to_speech" | "execute_code" | "create_desktop_pet")[];
250
+ export declare const GATEWAY_BUILTIN_TOOL_IDS: ("automation" | "workflow" | "find" | "todo" | "image" | "clarify" | "dreaming" | "memory_search" | "memory_get" | "web_search" | "web_fetch" | "browser_use" | "grep" | "session_search" | "read_file" | "list_dir" | "write_file" | "apply_patch" | "exec_command" | "update_plan" | "web_extract" | "image_generate" | "skills_list" | "skill_view" | "skill_manage" | "skills_marketplace_search" | "xopc_tool_search" | "xopc_tool_describe" | "xopc_tool_execute" | "send_message" | "send_media" | "read_media" | "create_share" | "session_status" | "tool_manual" | "delegate_task" | "skill_install" | "text_to_speech" | "execute_code" | "create_desktop_pet")[];
@@ -1,6 +1,6 @@
1
1
  import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveAgentDir, resolveAgentProfileDir, resolveAgentWorkspaceDir, resolveDefaultAgentId, resolveUserPath, validateAgentIdForNewAgent } from "../agent/agent-scope.js";
2
- import { resolveEffectiveAgentProfile } from "../config/agent-profile.js";
3
2
  import { WORKSPACE_FILES, init_paths } from "../config/paths.js";
3
+ import { resolveEffectiveAgentProfile } from "../config/agent-profile.js";
4
4
  import { AGENT_PROFILE_MARKDOWN_SYSTEM_FILES, REQUIRED_AGENT_PROFILE_MARKDOWN_FILE_SET } from "../agent/context/workspace.js";
5
5
  import { isPathUnderWorkspace, resolveWorkspaceSafePath } from "./workspace-editor-path.js";
6
6
  import { seedAgentProfileMarkdownFiles } from "../agent/context/workspace-seed.js";
@@ -1,3 +1,4 @@
1
+ import { parseTurnOutcome } from "../../../packages/gateway-contract/src/turn-outcome.js";
1
2
  import { resolveToolActivity } from "../../../packages/gateway-contract/src/tool-activity.js";
2
3
  import { createPetFeedback } from "./pet-feedback.js";
3
4
  //#region src/gateway/chat-stream/mapper.ts
@@ -126,6 +127,10 @@ var ChatStreamMapper = class {
126
127
  kind
127
128
  }] : [];
128
129
  }) : [] })];
130
+ case "turn_outcome": {
131
+ const outcome = parseTurnOutcome(event.outcome);
132
+ return outcome ? [this.make("turn_outcome", outcome)] : [];
133
+ }
129
134
  case "error": return [this.make("error", {
130
135
  code: "AGENT_RUN_ERROR",
131
136
  message: String(event.content ?? event.message ?? "Unknown error"),
@@ -1,9 +1,9 @@
1
1
  import { ContextCompactionPolicySchema, UserContextDreamingSchema, UserContextPrivacySchema, init_config } from "../../../user-context/config.js";
2
2
  import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveDefaultAgentId } from "../../../agent/agent-scope.js";
3
3
  import { resolveModelsJsonPath } from "../../../config/paths.js";
4
- import { buildChannelCatalogForConfig, buildChannelCatalogFromSnapshot, getChannelSetupStatus, init_channel_catalog_service } from "../../../channels/catalog/channel-catalog-service.js";
5
4
  import { init_models_json, loadModelsJson } from "../../../config/models-json.js";
6
5
  import { CredentialResolver, init_credentials } from "../../../auth/credentials.js";
6
+ import { buildChannelCatalogForConfig, buildChannelCatalogFromSnapshot, getChannelSetupStatus, init_channel_catalog_service } from "../../../channels/catalog/channel-catalog-service.js";
7
7
  import { getProviderRegistry, init_plugin_registry } from "../../../providers/plugin-registry.js";
8
8
  import { getAllProviders, init_providers, isProviderConfigured } from "../../../providers/index.js";
9
9
  import { normalizeConfiguredMcpServers } from "../../../config/mcp-config-normalize.js";
@@ -31,7 +31,7 @@ function extractTokenFromHeader(authHeader) {
31
31
  }
32
32
  /**
33
33
  * SECURITY: query-string tokens leak into server logs, Referer headers, and
34
- * browser history. We accept them only for agent avatar `<img>` loads, where an
34
+ * browser history. We accept them only for avatar `<img>` loads, where an
35
35
  * Authorization header cannot be set. Realtime WebSocket authentication uses a
36
36
  * one-time ticket acquired over authenticated HTTP.
37
37
  */
@@ -39,9 +39,10 @@ function extractTokenFromQuery(url) {
39
39
  return new URL(url).searchParams.get("token");
40
40
  }
41
41
  const AGENT_AVATAR_GET_PATH = /^\/api\/agents\/[^/]+\/avatar$/;
42
+ const USER_AVATAR_GET_PATH = "/api/you/avatar";
42
43
  /** Exported for gateway security tests. */
43
44
  function isQueryTokenAllowedPath(path, method) {
44
- if (method === "GET" && AGENT_AVATAR_GET_PATH.test(path)) return true;
45
+ if (method === "GET" && (AGENT_AVATAR_GET_PATH.test(path) || path === USER_AVATAR_GET_PATH)) return true;
45
46
  return false;
46
47
  }
47
48
  function resolveRemoteAddress(c) {
@@ -1,4 +1,4 @@
1
- import { endpointPrincipalRegistrationSchema } from "../../../../packages/endpoint-tools-protocol/src/index.js";
1
+ import { endpointPrincipalRegistrationSchema, endpointSessionBindingRequestSchema } from "../../../../packages/endpoint-tools-protocol/src/index.js";
2
2
  import { createEndpointPrincipal, getEndpointPrincipal, listEndpointPrincipals, revokeEndpointPrincipal } from "../../../storage/sqlite/endpoint-principal-repository.js";
3
3
  import { listEndpointToolInvocationAudits } from "../../../storage/sqlite/endpoint-tool-invocation-repository.js";
4
4
  import "../../../storage/sqlite/index.js";
@@ -130,6 +130,73 @@ function registerEndpointToolRoutes(authenticated, deps) {
130
130
  payload: listEndpointToolInvocationAudits(Number.isFinite(limit) ? limit : 100)
131
131
  });
132
132
  });
133
+ authenticated.get("/api/endpoint-tools/bindings/:sessionKey", (c) => {
134
+ try {
135
+ const binding = deps.service.endpointTools.bindings.get(c.req.param("sessionKey"));
136
+ return binding ? c.json({
137
+ ok: true,
138
+ payload: binding
139
+ }) : c.json({
140
+ ok: false,
141
+ error: {
142
+ code: "NOT_FOUND",
143
+ message: "Endpoint binding not found"
144
+ }
145
+ }, 404);
146
+ } catch {
147
+ return c.json({
148
+ ok: false,
149
+ error: {
150
+ code: "BAD_REQUEST",
151
+ message: "Invalid session key"
152
+ }
153
+ }, 400);
154
+ }
155
+ });
156
+ authenticated.put("/api/endpoint-tools/bindings/:sessionKey", async (c) => {
157
+ const parsed = endpointSessionBindingRequestSchema.safeParse(await c.req.json().catch(() => null));
158
+ if (!parsed.success) return c.json({
159
+ ok: false,
160
+ error: {
161
+ code: "BAD_REQUEST",
162
+ message: "Invalid endpoint binding"
163
+ }
164
+ }, 400);
165
+ try {
166
+ const binding = deps.service.endpointTools.bindings.bind(c.req.param("sessionKey"), parsed.data.endpointId);
167
+ return c.json({
168
+ ok: true,
169
+ payload: binding
170
+ });
171
+ } catch (error) {
172
+ const message = error instanceof Error ? error.message : String(error);
173
+ const status = message === "Endpoint is offline" ? 409 : 400;
174
+ return c.json({
175
+ ok: false,
176
+ error: {
177
+ code: "BINDING_FAILED",
178
+ message
179
+ }
180
+ }, status);
181
+ }
182
+ });
183
+ authenticated.delete("/api/endpoint-tools/bindings/:sessionKey", (c) => {
184
+ try {
185
+ const removed = deps.service.endpointTools.bindings.unbind(c.req.param("sessionKey"));
186
+ return c.json({
187
+ ok: true,
188
+ payload: { removed }
189
+ });
190
+ } catch {
191
+ return c.json({
192
+ ok: false,
193
+ error: {
194
+ code: "BAD_REQUEST",
195
+ message: "Invalid session key"
196
+ }
197
+ }, 400);
198
+ }
199
+ });
133
200
  authenticated.post("/api/endpoint-tools/invocations/:invocationId/files", async (c) => {
134
201
  const invocationId = c.req.param("invocationId");
135
202
  const endpointId = c.req.header("x-endpoint-id") ?? "";
@@ -119,6 +119,13 @@ function registerFilesRoutes(authenticated, deps) {
119
119
  return errorResponse(c, error);
120
120
  }
121
121
  });
122
+ authenticated.get("/api/files/:id/host-path", async (c) => {
123
+ try {
124
+ return c.json({ absolutePath: (await files.resource(c.req.param("id"))).absolutePath });
125
+ } catch (error) {
126
+ return errorResponse(c, error);
127
+ }
128
+ });
122
129
  authenticated.get("/api/files/:id/content", async (c) => {
123
130
  try {
124
131
  const { resource, absolutePath } = await files.resource(c.req.param("id"));
@@ -100,6 +100,14 @@ const AUTHENTICATED_LAZY_ROUTE_BUNDLES = [
100
100
  } };
101
101
  }
102
102
  },
103
+ {
104
+ id: "support",
105
+ match: (path) => startsWithAny(path, ["/api/support"]),
106
+ load: async () => {
107
+ const { registerSupportRoutes } = await import("./support.js");
108
+ return { register: registerSupportRoutes };
109
+ }
110
+ },
103
111
  {
104
112
  id: "image-generation",
105
113
  match: (path) => startsWithAny(path, ["/api/image-generation"]) || /^\/api\/agents\/[^/]+\/image-generation(?:\/setup)?$/.test(path),
@@ -9,6 +9,26 @@ import { messagesReferenceMediaUri } from "../../../media/session-references.js"
9
9
  import { createGatewayRouteLogger } from "../lib/route-logger.js";
10
10
  //#region src/gateway/hono/routes/media.ts
11
11
  const log = createGatewayRouteLogger("Media");
12
+ function parseByteRange(header, size) {
13
+ if (!header) return null;
14
+ const match = /^bytes=(\d*)-(\d*)$/i.exec(header.trim());
15
+ if (!match || !match[1] && !match[2] || size <= 0) return "invalid";
16
+ if (!match[1]) {
17
+ const suffixLength = Number(match[2]);
18
+ if (!Number.isSafeInteger(suffixLength) || suffixLength <= 0) return "invalid";
19
+ return {
20
+ start: Math.max(0, size - suffixLength),
21
+ end: size - 1
22
+ };
23
+ }
24
+ const start = Number(match[1]);
25
+ const requestedEnd = match[2] ? Number(match[2]) : size - 1;
26
+ if (!Number.isSafeInteger(start) || !Number.isSafeInteger(requestedEnd) || start < 0 || start >= size || requestedEnd < start) return "invalid";
27
+ return {
28
+ start,
29
+ end: Math.min(requestedEnd, size - 1)
30
+ };
31
+ }
12
32
  function registerMediaRoutes(authenticated, deps) {
13
33
  const tasks = new TaskRepository();
14
34
  authenticated.post("/api/media", deps.strictRateLimitMiddleware, async (c) => {
@@ -64,9 +84,33 @@ function registerMediaRoutes(authenticated, deps) {
64
84
  }, 404);
65
85
  const { buffer, path } = await readMediaReference(parsed.uri);
66
86
  const contentType = mimeTypeFromMediaPath(path);
87
+ const range = parseByteRange(c.req.header("Range"), buffer.byteLength);
88
+ const commonHeaders = {
89
+ "Accept-Ranges": "bytes",
90
+ "Cache-Control": "private, max-age=3600",
91
+ "Content-Type": contentType
92
+ };
93
+ if (range === "invalid") return new Response(null, {
94
+ status: 416,
95
+ headers: {
96
+ ...commonHeaders,
97
+ "Content-Range": `bytes */${buffer.byteLength}`
98
+ }
99
+ });
100
+ if (range) {
101
+ const body = buffer.subarray(range.start, range.end + 1);
102
+ return new Response(body, {
103
+ status: 206,
104
+ headers: {
105
+ ...commonHeaders,
106
+ "Content-Length": String(body.byteLength),
107
+ "Content-Range": `bytes ${range.start}-${range.end}/${buffer.byteLength}`
108
+ }
109
+ });
110
+ }
67
111
  return new Response(buffer, { headers: {
68
- "Content-Type": contentType,
69
- "Cache-Control": "private, max-age=3600"
112
+ ...commonHeaders,
113
+ "Content-Length": String(buffer.byteLength)
70
114
  } });
71
115
  } catch (err) {
72
116
  const em = err instanceof Error ? err.message : String(err);
@@ -1,5 +1,5 @@
1
- import { resolveModelsJsonPath } from "../../../config/paths.js";
2
1
  import { init_resolve_config_value, testApiKeyResolution } from "../../../config/resolve-config-value.js";
2
+ import { resolveModelsJsonPath } from "../../../config/paths.js";
3
3
  import { init_models_json, loadModelsJson, saveModelsJson, validateModelsConfig } from "../../../config/models-json.js";
4
4
  import { getModelCatalogStore, init_model_catalog_store } from "../../../providers/model-catalog-store.js";
5
5
  import { getModelRegistry } from "../../../providers/model-registry.js";
@@ -0,0 +1,3 @@
1
+ import type { Hono } from 'hono';
2
+ import type { AuthenticatedRouteDeps } from './deps.js';
3
+ export declare function registerSupportRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void;
@@ -0,0 +1,28 @@
1
+ import { buildSupportInvestigationPrompt } from "../../../support/build-support-investigation-prompt.js";
2
+ import { collectSupportReport } from "../../../support/collect-support-report.js";
3
+ import { SupportReportInputSchema } from "../../../support/types.js";
4
+ //#region src/gateway/hono/routes/support.ts
5
+ function registerSupportRoutes(authenticated, deps) {
6
+ authenticated.post("/api/support/report", deps.strictRateLimitMiddleware, async (c) => {
7
+ const parsed = SupportReportInputSchema.safeParse(await c.req.json().catch(() => null));
8
+ if (!parsed.success) return c.json({
9
+ ok: false,
10
+ error: "Invalid support report input"
11
+ }, 400);
12
+ const health = deps.service.getHealth();
13
+ const channels = Object.fromEntries(deps.service.getChannelsStatus().map((channel) => [channel.name, !channel.enabled ? "disabled" : channel.connected ? "connected" : "disconnected"]));
14
+ const report = await collectSupportReport(parsed.data, { runtime: {
15
+ gatewayStatus: health.status,
16
+ gatewayVersion: health.version,
17
+ gatewayUptimeMs: health.uptime,
18
+ channels
19
+ } });
20
+ return c.json({
21
+ ok: true,
22
+ report,
23
+ investigationPrompt: buildSupportInvestigationPrompt(report)
24
+ });
25
+ });
26
+ }
27
+ //#endregion
28
+ export { registerSupportRoutes };