@xopcai/xopc 0.0.361 → 0.0.363

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (220) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/{activity-store-tpFInIoh.js → activity-store-GvR2gZ0T.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DUhFW_Go.js → agent-avatar-dicebear-DkcXyPH0.js} +1 -1
  5. package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-BNILmgey.js → agent-defaults-settings-panel-B-l5AaYN.js} +1 -1
  6. package/dist/gateway/static/root/assets/{agent-plugin-dialog-CnWci4JJ.js → agent-plugin-dialog-BY6tPYOK.js} +1 -1
  7. package/dist/gateway/static/root/assets/{agents-CKS5LUUs.js → agents-CdSEoeje.js} +3 -3
  8. package/dist/gateway/static/root/assets/{agents-admin-api-CiAjB2iQ.js → agents-admin-api-BkXb7VEZ.js} +1 -1
  9. package/dist/gateway/static/root/assets/{app-management-settings-panel-DEig00YU.js → app-management-settings-panel-BtD53cfe.js} +1 -1
  10. package/dist/gateway/static/root/assets/{appearance-settings-CccnRRrL.js → appearance-settings-BAweWgX_.js} +1 -1
  11. package/dist/gateway/static/root/assets/{apps-page-CkT6UNZW.js → apps-page-CS6-hrIB.js} +1 -1
  12. package/dist/gateway/static/root/assets/{archive-plugin-CIlmZBe5.js → archive-plugin-CKe3qAaL.js} +1 -1
  13. package/dist/gateway/static/root/assets/{automations-page-8kZugDcf.js → automations-page-CtE8r9Y2.js} +1 -1
  14. package/dist/gateway/static/root/assets/{automations-workspace-3V54ShL0.js → automations-workspace-pnMgR4Da.js} +1 -1
  15. package/dist/gateway/static/root/assets/{binary-plugins-BuQiee_b.js → binary-plugins-J51oS7-D.js} +1 -1
  16. package/dist/gateway/static/root/assets/{block-editor-BFFRbsKX.js → block-editor-D5hf6WcP.js} +1 -1
  17. package/dist/gateway/static/root/assets/{browser-automation-inputs-CWujpdCx.js → browser-automation-inputs-5B3qAdmb.js} +1 -1
  18. package/dist/gateway/static/root/assets/{browser-automations-page-HVXiBKXE.js → browser-automations-page-PZDQlXH4.js} +1 -1
  19. package/dist/gateway/static/root/assets/{browser-settings-page-DpxAXNvM.js → browser-settings-page-2YDV-ZWt.js} +1 -1
  20. package/dist/gateway/static/root/assets/{capabilities-CngwB2JU.js → capabilities-BKu9BqPe.js} +1 -1
  21. package/dist/gateway/static/root/assets/{capabilities-RMlKKfGF.js → capabilities-CT_ZW9fT.js} +1 -1
  22. package/dist/gateway/static/root/assets/{capabilities-page-BBi4ef3u.js → capabilities-page-CB-iX3Fy.js} +2 -2
  23. package/dist/gateway/static/root/assets/{capabilities-settings-panel-IxszGl-Q.js → capabilities-settings-panel-BCTuWNaW.js} +1 -1
  24. package/dist/gateway/static/root/assets/{capability-header-actions-BLOIJvIZ.js → capability-header-actions--aC5XB9E.js} +1 -1
  25. package/dist/gateway/static/root/assets/{channels-Ced5nFBc.js → channels-JnAQP1bt.js} +1 -1
  26. package/dist/gateway/static/root/assets/{chat-terminal-dock-BskUzDCS.js → chat-terminal-dock-BFZEpvzn.js} +1 -1
  27. package/dist/gateway/static/root/assets/{computer-settings-page-De-pjlvn.js → computer-settings-page-Dc9ooEM-.js} +1 -1
  28. package/dist/gateway/static/root/assets/{connector-service-page-Qc1mVfp9.js → connector-service-page-1_QB5D-t.js} +1 -1
  29. package/dist/gateway/static/root/assets/{connectors-page-CPqeY1x5.js → connectors-page-Um_Jy5zh.js} +1 -1
  30. package/dist/gateway/static/root/assets/{date-picker-7ppMIGfQ.js → date-picker-C9ZqTPui.js} +1 -1
  31. package/dist/gateway/static/root/assets/dependency-picker-DBz0Pmyr.js +1 -0
  32. package/dist/gateway/static/root/assets/{desktop-pet-GKEfqHDF.js → desktop-pet-BLtp2MmX.js} +1 -1
  33. package/dist/gateway/static/root/assets/{desktop-pet-settings-qoFZBKe9.js → desktop-pet-settings-BNGbqwec.js} +1 -1
  34. package/dist/gateway/static/root/assets/{device-pairing-wizard-D8sTDd5s.js → device-pairing-wizard-7rdo-A7d.js} +1 -1
  35. package/dist/gateway/static/root/assets/{directory-picker-path-field-BC87CZa2.js → directory-picker-path-field-BnilGgwM.js} +1 -1
  36. package/dist/gateway/static/root/assets/{extension-debug-page-VxCq29jC.js → extension-debug-page-BGyJpRv4.js} +1 -1
  37. package/dist/gateway/static/root/assets/{extension-page-DypBVBTt.js → extension-page-DsrVktRN.js} +1 -1
  38. package/dist/gateway/static/root/assets/{extension-provider-wlvxPese.js → extension-provider-F9JzOWZ3.js} +1 -1
  39. package/dist/gateway/static/root/assets/{extension-settings-page-DzzkBN9y.js → extension-settings-page-jeb0ytRK.js} +1 -1
  40. package/dist/gateway/static/root/assets/{fallback-models-s4qTRcPJ.js → fallback-models-bZcxkEDz.js} +1 -1
  41. package/dist/gateway/static/root/assets/{gateway-config-swr-ZM72jovc.js → gateway-config-swr-CoRoOG1l.js} +1 -1
  42. package/dist/gateway/static/root/assets/{gateway-realtime-B-hrykag.js → gateway-realtime-D0ygm6bc.js} +1 -1
  43. package/dist/gateway/static/root/assets/gateway-realtime-store-DBvCRclh.js +1 -0
  44. package/dist/gateway/static/root/assets/{gateway-settings--M7ZH_37.js → gateway-settings-A9SzLsGp.js} +1 -1
  45. package/dist/gateway/static/root/assets/{gateway-startup-retry-DjWuTj8B.js → gateway-startup-retry-FDS6S6qa.js} +1 -1
  46. package/dist/gateway/static/root/assets/{home-page-KFs5suD1.js → home-page-CnHzaH9K.js} +1 -1
  47. package/dist/gateway/static/root/assets/{image-generation-api-C9cwrqCr.js → image-generation-api-BPd76jW5.js} +1 -1
  48. package/dist/gateway/static/root/assets/{imports-page-BKy0ImXk.js → imports-page-CzpsV6Vz.js} +1 -1
  49. package/dist/gateway/static/root/assets/{index-C0JT9Ja4.js → index-BYNmHn-z.js} +7 -7
  50. package/dist/gateway/static/root/assets/index-CbJNcWAn.css +1 -0
  51. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-CexiL-Ey.js → keyboard-shortcuts-settings-D90Dvlwo.js} +1 -1
  52. package/dist/gateway/static/root/assets/{local-app-workbench-page-CcU1OLWQ.js → local-app-workbench-page-_9IKMkV8.js} +1 -1
  53. package/dist/gateway/static/root/assets/{local-apps-page-BcLijQx4.js → local-apps-page-D6gejARs.js} +1 -1
  54. package/dist/gateway/static/root/assets/{local-session-drafts-C7QjBMNp.js → local-session-drafts-gbemPamv.js} +1 -1
  55. package/dist/gateway/static/root/assets/{locale-store-5sV3dDRG.js → locale-store-DId6-v2R.js} +1 -1
  56. package/dist/gateway/static/root/assets/{logs-page-48nrZNQe.js → logs-page--t8d-oLb.js} +1 -1
  57. package/dist/gateway/static/root/assets/{management-settings-B_gzl_Vh.js → management-settings-DVDmXzTg.js} +1 -1
  58. package/dist/gateway/static/root/assets/{markdown-view-V0f5NW7D.js → markdown-view-DQZ51j9e.js} +1 -1
  59. package/dist/gateway/static/root/assets/{media-plugins-_obxSZmT.js → media-plugins-XLewwq2q.js} +1 -1
  60. package/dist/gateway/static/root/assets/{messages-CaURu8bb.js → messages-BHvpZNe9.js} +2 -2
  61. package/dist/gateway/static/root/assets/models-hub-cache-B9SKjidc.js +1 -0
  62. package/dist/gateway/static/root/assets/{note-detail-panel-B9AeX98W.js → note-detail-panel-DuZAEfU1.js} +3 -3
  63. package/dist/gateway/static/root/assets/{notes-api-CBnMq6Nc.js → notes-api-Byt65v3r.js} +1 -1
  64. package/dist/gateway/static/root/assets/{notes-page-CKTTfxw-.js → notes-page-CgWNESGp.js} +1 -1
  65. package/dist/gateway/static/root/assets/{oauth-api-Bu2RoLF2.js → oauth-api-BYsCbyGZ.js} +1 -1
  66. package/dist/gateway/static/root/assets/{page-context-capture-button-BsxBAWD_.js → page-context-capture-button-Z72eiQZn.js} +1 -1
  67. package/dist/gateway/static/root/assets/{personal-page-Cfl1FR3i.js → personal-page-BtMatL9a.js} +1 -1
  68. package/dist/gateway/static/root/assets/{product-open-page-D1ARqS3r.js → product-open-page-w5Hdf0hQ.js} +1 -1
  69. package/dist/gateway/static/root/assets/{project-detail-page-Cro1OE8P.js → project-detail-page-CP6I3ZCV.js} +1 -1
  70. package/dist/gateway/static/root/assets/{projects-page-CdEmmBCz.js → projects-page-DYs6XrrK.js} +1 -1
  71. package/dist/gateway/static/root/assets/{registry-api-j1rNFkP2.js → registry-api-7F2WNEZC.js} +1 -1
  72. package/dist/gateway/static/root/assets/{remote-access-hub-C9_ea_4p.js → remote-access-hub-DjYoYAEw.js} +1 -1
  73. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-DtmQbC72.js → runtime-tools-settings-panel-Qar_DXLv.js} +1 -1
  74. package/dist/gateway/static/root/assets/{scenes-page-DeFdMf2q.js → scenes-page-BSIcDCa-.js} +1 -1
  75. package/dist/gateway/static/root/assets/{schema-form-ByEHHW6n.js → schema-form-C_cJLGgF.js} +1 -1
  76. package/dist/gateway/static/root/assets/{send-session-input-CO_vUCb8.js → send-session-input-D1oc6BC6.js} +1 -1
  77. package/dist/gateway/static/root/assets/{session-api-CYPGi01d.js → session-api-N3N37MrR.js} +1 -1
  78. package/dist/gateway/static/root/assets/{session-manager-BdJThQQ6.js → session-manager-CMGUwtbN.js} +2 -2
  79. package/dist/gateway/static/root/assets/{sessions-page-CV0JlaXS.js → sessions-page-BBV5Z24a.js} +1 -1
  80. package/dist/gateway/static/root/assets/settings-advanced-gate-DRc9IDJf.js +1 -0
  81. package/dist/gateway/static/root/assets/{settings-page-CHKsZFAN.js → settings-page-F2vGXBw7.js} +1 -1
  82. package/dist/gateway/static/root/assets/{setup-status-panel-CC58OVOe.js → setup-status-panel-DJxbjUOg.js} +1 -1
  83. package/dist/gateway/static/root/assets/{share-link-dialog-ZOdnHkmb.js → share-link-dialog-TBBGJPfT.js} +1 -1
  84. package/dist/gateway/static/root/assets/{share-preview-page-BPDWUuH_.js → share-preview-page-DyRLPsPv.js} +1 -1
  85. package/dist/gateway/static/root/assets/{shares-api-T5gR8yqz.js → shares-api-DU0fHP2G.js} +1 -1
  86. package/dist/gateway/static/root/assets/{shares-settings-DaXvdH8c.js → shares-settings-CJa6FBpP.js} +1 -1
  87. package/dist/gateway/static/root/assets/{skill-api-CHCLMcfO.js → skill-api-C340XD9d.js} +1 -1
  88. package/dist/gateway/static/root/assets/{skill-reload-api-C-RoiUJi.js → skill-reload-api-ClyFqHk7.js} +1 -1
  89. package/dist/gateway/static/root/assets/{skills-page-a9UQQnqn.js → skills-page-C4lF94m5.js} +1 -1
  90. package/dist/gateway/static/root/assets/{system-settings-panel-Dho_dlBS.js → system-settings-panel-CmJUu3lb.js} +1 -1
  91. package/dist/gateway/static/root/assets/task-detail-page-De-Rr8W6.js +2 -0
  92. package/dist/gateway/static/root/assets/{theme-store-CEl74p7l.js → theme-store-OhcbFEUR.js} +1 -1
  93. package/dist/gateway/static/root/assets/tracing-settings-page-DoBJ0TYY.js +1 -0
  94. package/dist/gateway/static/root/assets/{tunnel-api-BDqCyf8G.js → tunnel-api-Bl4nrCuE.js} +1 -1
  95. package/dist/gateway/static/root/assets/{usage-page-DKwKfszc.js → usage-page-QZEAaa8n.js} +1 -1
  96. package/dist/gateway/static/root/assets/{use-autosave-D09eZTLp.js → use-autosave-veoM0dHn.js} +1 -1
  97. package/dist/gateway/static/root/assets/{use-composer-attachments-CkvJM8Km.js → use-composer-attachments-DB0bBGzZ.js} +1 -1
  98. package/dist/gateway/static/root/assets/{use-file-preview-expanded-J3HnG8OH.js → use-file-preview-expanded-Bope6MW6.js} +2 -2
  99. package/dist/gateway/static/root/assets/{user-model-page-BsgADrGL.js → user-model-page-Crh2oNpZ.js} +1 -1
  100. package/dist/gateway/static/root/assets/{voice-api-key-field-DH-to9Rd.js → voice-api-key-field-CwD6a3KQ.js} +1 -1
  101. package/dist/gateway/static/root/assets/{voice-config-api-CmCfVy3H.js → voice-config-api-Daexehmc.js} +1 -1
  102. package/dist/gateway/static/root/assets/{work-discovery-overlay-x1vZDBhu.js → work-discovery-overlay-9jnjEAaz.js} +1 -1
  103. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-DGatvmK1.js → workflow-run-setup-panel-BAcPxdcT.js} +1 -1
  104. package/dist/gateway/static/root/assets/{workflows-page-DgNy6mBQ.js → workflows-page-D8Zm-ooa.js} +1 -1
  105. package/dist/gateway/static/root/assets/{workspace-api-DzPw92Kx.js → workspace-api-Cs4sjV2A.js} +2 -2
  106. package/dist/gateway/static/root/connector-icons/README.md +5 -2
  107. package/dist/gateway/static/root/connector-icons/SOURCES.md +15 -1
  108. package/dist/gateway/static/root/connector-icons/amap.ico +0 -0
  109. package/dist/gateway/static/root/connector-icons/antv-chart.png +0 -0
  110. package/dist/gateway/static/root/connector-icons/bailian.png +0 -0
  111. package/dist/gateway/static/root/connector-icons/dida365.png +0 -0
  112. package/dist/gateway/static/root/connector-icons/flomo.png +0 -0
  113. package/dist/gateway/static/root/connector-icons/gmail.svg +1 -3
  114. package/dist/gateway/static/root/connector-icons/jira.svg +3 -14
  115. package/dist/gateway/static/root/connector-icons/railway-12306.jpg +0 -0
  116. package/dist/gateway/static/root/connector-icons/railway-query.svg +1 -0
  117. package/dist/gateway/static/root/connector-icons/tencent-docs.ico +0 -0
  118. package/dist/gateway/static/root/connector-icons/yuque.png +0 -0
  119. package/dist/gateway/static/root/index.html +28 -28
  120. package/dist/package.js +1 -1
  121. package/dist/packages/gateway-contract/src/task-result-delivery.js +2 -2
  122. package/dist/src/agent/agent-manager.js +10 -6
  123. package/dist/src/agent/embedded/model-runtime.js +1 -1
  124. package/dist/src/agent/embedded/run-for-session.js +28 -3
  125. package/dist/src/agent/embedded/run-turn.js +18 -3
  126. package/dist/src/agent/image/tool-model-config.js +1 -1
  127. package/dist/src/agent/mcp/oauth/mcp-oauth-store.js +1 -1
  128. package/dist/src/agent/service.js +5 -3
  129. package/dist/src/agent/skills/hub-lock.js +1 -1
  130. package/dist/src/agent/tasks/task-judge-service.js +1 -1
  131. package/dist/src/agent-catalog/migrations/legacy-config-cutover.js +1 -1
  132. package/dist/src/agent-catalog/repository.js +1 -1
  133. package/dist/src/auth/credentials.js +2 -2
  134. package/dist/src/auth/oauth-provider-lock.js +1 -1
  135. package/dist/src/auth/profiles/store.js +1 -1
  136. package/dist/src/auth/sync-provider-auth.js +1 -1
  137. package/dist/src/browser/providers/browser-ext-install.js +1 -1
  138. package/dist/src/chat-commands/agent-edit.js +1 -1
  139. package/dist/src/chat-commands/builtins/config.js +1 -1
  140. package/dist/src/cli/commands/agent.js +1 -1
  141. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  142. package/dist/src/cli/commands/doctor/checks/image-providers.js +1 -1
  143. package/dist/src/cli/commands/doctor/checks/provider-auth.js +3 -3
  144. package/dist/src/cli/commands/models.js +1 -1
  145. package/dist/src/cli/commands/onboard/model.js +3 -3
  146. package/dist/src/config/agent-profile.js +1 -1
  147. package/dist/src/config/index.js +4 -4
  148. package/dist/src/config/loader.js +2 -2
  149. package/dist/src/config/models-json.js +1 -1
  150. package/dist/src/config/reload.d.ts +1 -0
  151. package/dist/src/config/reload.js +4 -0
  152. package/dist/src/config/rules.js +5 -0
  153. package/dist/src/config/schema.d.ts +23 -0
  154. package/dist/src/config/schema.js +6 -3
  155. package/dist/src/connectors/china-catalog.js +572 -0
  156. package/dist/src/connectors/cli/authorization.js +3 -2
  157. package/dist/src/connectors/cli/installer.js +3 -1
  158. package/dist/src/extensions/activation-context.js +1 -1
  159. package/dist/src/extensions/lockfile.js +1 -1
  160. package/dist/src/gateway/file-path-classifier.js +1 -1
  161. package/dist/src/gateway/hono/lib/config-payload.js +2 -2
  162. package/dist/src/gateway/hono/routes/agents.js +1 -1
  163. package/dist/src/gateway/hono/routes/config-patch/misc.js +2 -2
  164. package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
  165. package/dist/src/gateway/hono/routes/models.js +2 -2
  166. package/dist/src/gateway/hono/routes/observability.d.ts +3 -0
  167. package/dist/src/gateway/hono/routes/observability.js +106 -0
  168. package/dist/src/gateway/image-generation-setup.js +1 -1
  169. package/dist/src/gateway/lock.js +1 -1
  170. package/dist/src/gateway/security/gateway-scopes.js +1 -0
  171. package/dist/src/gateway/service/config-coordinator.d.ts +0 -25
  172. package/dist/src/gateway/service/config-coordinator.js +31 -0
  173. package/dist/src/gateway/service.js +5 -3
  174. package/dist/src/gateway/side-chat/manager.js +3 -2
  175. package/dist/src/observability/config.d.ts +40 -0
  176. package/dist/src/observability/config.js +31 -0
  177. package/dist/src/observability/langfuse.d.ts +31 -0
  178. package/dist/src/observability/langfuse.js +180 -0
  179. package/dist/src/observability/runtime.d.ts +57 -0
  180. package/dist/src/observability/runtime.js +404 -0
  181. package/dist/src/observability/sanitize.d.ts +3 -0
  182. package/dist/src/observability/sanitize.js +74 -0
  183. package/dist/src/observability/store.d.ts +20 -0
  184. package/dist/src/observability/store.js +128 -0
  185. package/dist/src/observability/storeWorker.d.ts +2 -0
  186. package/dist/src/observability/storeWorker.js +155 -0
  187. package/dist/src/observability/types.d.ts +21 -0
  188. package/dist/src/observability/types.js +1 -0
  189. package/dist/src/platform/index.js +1 -1
  190. package/dist/src/providers/auth-runtime/resolve-auth.js +1 -1
  191. package/dist/src/providers/index.js +3 -3
  192. package/dist/src/providers/model-call.js +19 -5
  193. package/dist/src/providers/model-catalog-persistence.js +1 -1
  194. package/dist/src/providers/model-registry.js +1 -1
  195. package/dist/src/providers/provider-disconnect-core.js +1 -1
  196. package/dist/src/providers/xopc-cloud-catalog-coordinator.js +1 -1
  197. package/dist/src/storage/sqlite/ai-usage-repository.d.ts +6 -0
  198. package/dist/src/storage/sqlite/ai-usage-repository.js +4 -2
  199. package/dist/src/storage/sqlite/migrations/233_observability_usage_links.sql +3 -0
  200. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  201. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  202. package/dist/src/storage/sqlite/schema.js +1 -1
  203. package/dist/src/tasks/task-result-delivery-repository.js +4 -5
  204. package/dist/src/tui/backends/embedded-backend.js +2 -2
  205. package/dist/src/tui/tui-commands.js +1 -1
  206. package/dist/src/tui/tui-startup-resources.js +1 -1
  207. package/dist/src/tui/tui.js +1 -1
  208. package/dist/src/usage/recorder.d.ts +4 -2
  209. package/dist/src/usage/recorder.js +54 -26
  210. package/dist/src/usage/types.d.ts +3 -0
  211. package/dist/src/utils/logger/context.d.ts +1 -1
  212. package/dist/src/utils/logger/context.js +4 -1
  213. package/dist/src/utils/logger/types.d.ts +3 -0
  214. package/package.json +5 -2
  215. package/dist/gateway/static/root/assets/dependency-picker-DfYC22si.js +0 -1
  216. package/dist/gateway/static/root/assets/gateway-realtime-store-B6B1fw_K.js +0 -1
  217. package/dist/gateway/static/root/assets/index-B7AHDHSO.css +0 -1
  218. package/dist/gateway/static/root/assets/models-hub-cache-Cs3E5pEA.js +0 -1
  219. package/dist/gateway/static/root/assets/settings-advanced-gate-D9sW0hKa.js +0 -1
  220. package/dist/gateway/static/root/assets/task-detail-page-B5JyH4z7.js +0 -1
@@ -297,6 +297,14 @@ const AUTHENTICATED_LAZY_ROUTE_BUNDLES = [
297
297
  return { register: registerLogsRoutes };
298
298
  }
299
299
  },
300
+ {
301
+ id: "observability",
302
+ match: (path) => startsWithAny(path, ["/api/observability"]),
303
+ load: async () => {
304
+ const { registerObservabilityRoutes } = await import("./observability.js");
305
+ return { register: registerObservabilityRoutes };
306
+ }
307
+ },
300
308
  {
301
309
  id: "usage",
302
310
  match: (path) => startsWithAny(path, ["/api/usage"]),
@@ -1,11 +1,11 @@
1
- import { resolveEffectiveAgentConfigForAgent } from "../../../config/agent-profile.js";
2
1
  import { resolveModelsJsonPath } from "../../../config/paths.js";
2
+ import { CredentialResolver, init_credentials } from "../../../auth/credentials.js";
3
+ import { resolveEffectiveAgentConfigForAgent } from "../../../config/agent-profile.js";
3
4
  import { init_resolve_config_value, testApiKeyResolution } from "../../../config/resolve-config-value.js";
4
5
  import { computerModelProfile, init_model_policy, isDedicatedComputerModel } from "../../../computer/model-policy.js";
5
6
  import { init_models_json, loadModelsJson, saveModelsJson, validateModelsConfig } from "../../../config/models-json.js";
6
7
  import { getModelCatalogStore, init_model_catalog_store } from "../../../providers/model-catalog-store.js";
7
8
  import { getModelRegistry } from "../../../providers/model-registry.js";
8
- import { CredentialResolver, init_credentials } from "../../../auth/credentials.js";
9
9
  import "../../../providers/constants.js";
10
10
  import { getProviderRegistry, init_plugin_registry } from "../../../providers/plugin-registry.js";
11
11
  import { PROVIDER_META, getAllModels, getAllProviders, getAvailableModels, getProviderAuthState, init_providers, isProviderConfigured, isProviderConfiguredSync } from "../../../providers/index.js";
@@ -0,0 +1,3 @@
1
+ import { Hono } from 'hono';
2
+ import type { AuthenticatedRouteDeps } from './deps.js';
3
+ export declare function registerObservabilityRoutes(authenticated: Hono, { service, strictRateLimitMiddleware }: AuthenticatedRouteDeps): void;
@@ -0,0 +1,106 @@
1
+ import { CredentialResolver, init_credentials } from "../../../auth/credentials.js";
2
+ import { TracingConfigSchema, init_config } from "../../../observability/config.js";
3
+ import { configureTracing, localStore, testLangfuse, tracingConfig, tracingStatus } from "../../../observability/runtime.js";
4
+ import { z } from "zod";
5
+ import { Hono } from "hono";
6
+ //#region src/gateway/hono/routes/observability.ts
7
+ init_credentials();
8
+ init_config();
9
+ const traceIdSchema = z.string().regex(/^[0-9a-f]{32}$/);
10
+ const querySchema = z.object({
11
+ limit: z.coerce.number().int().min(1).max(100).optional(),
12
+ cursor: z.string().regex(/^\d{1,16}:[0-9a-f]{32}$/).optional(),
13
+ from: z.coerce.number().int().nonnegative().optional(),
14
+ to: z.coerce.number().int().positive().optional(),
15
+ status: z.enum([
16
+ "running",
17
+ "success",
18
+ "error",
19
+ "cancelled",
20
+ "suspended",
21
+ "interrupted"
22
+ ]).optional(),
23
+ conversationId: z.string().max(200).optional(),
24
+ runId: z.string().max(200).optional(),
25
+ agentId: z.string().max(200).optional()
26
+ });
27
+ function registerObservabilityRoutes(authenticated, { service, strictRateLimitMiddleware }) {
28
+ const app = new Hono();
29
+ app.onError((error, c) => {
30
+ if (error instanceof z.ZodError || error instanceof SyntaxError) return c.json({ error: "Invalid tracing request" }, 400);
31
+ return c.json({ error: "Tracing service unavailable" }, 503);
32
+ });
33
+ app.get("/tracing/settings", async (c) => {
34
+ const resolver = new CredentialResolver();
35
+ const secret = process.env.LANGFUSE_SECRET_KEY || await resolver.revealGatewayStoredApiKey("langfuse");
36
+ const pub = process.env.LANGFUSE_PUBLIC_KEY || await resolver.revealGatewayStoredApiKey("langfuse-public");
37
+ return c.json({
38
+ config: tracingConfig(),
39
+ credentials: {
40
+ publicKeyConfigured: Boolean(pub),
41
+ secretKeyConfigured: Boolean(secret),
42
+ publicKeySource: process.env.LANGFUSE_PUBLIC_KEY ? "environment" : pub ? "stored" : "none",
43
+ secretKeySource: process.env.LANGFUSE_SECRET_KEY ? "environment" : secret ? "stored" : "none",
44
+ baseUrlSource: process.env.LANGFUSE_BASE_URL ? "environment" : "config"
45
+ }
46
+ });
47
+ });
48
+ app.patch("/tracing/settings", strictRateLimitMiddleware, async (c) => {
49
+ const parsed = TracingConfigSchema.parse(await c.req.json());
50
+ if (parsed.capture === "detailed") parsed.detailedUntil = Date.now() + 1800 * 1e3;
51
+ else delete parsed.detailedUntil;
52
+ const next = {
53
+ ...service.currentConfig,
54
+ observability: { tracing: parsed }
55
+ };
56
+ if (!(await service.saveConfig(next)).saved) return c.json({ error: "Could not save tracing configuration" }, 500);
57
+ await configureTracing(parsed);
58
+ return c.json({
59
+ ok: true,
60
+ config: parsed
61
+ });
62
+ });
63
+ app.put("/tracing/langfuse/credentials", strictRateLimitMiddleware, async (c) => {
64
+ const body = z.object({
65
+ publicKey: z.string().trim().min(1).max(512).optional(),
66
+ secretKey: z.string().trim().min(1).max(512).optional()
67
+ }).strict().parse(await c.req.json());
68
+ const resolver = new CredentialResolver();
69
+ if (body.publicKey) await resolver.saveApiKey("langfuse-public", body.publicKey, { profileName: "default" });
70
+ if (body.secretKey) await resolver.saveApiKey("langfuse", body.secretKey, { profileName: "default" });
71
+ await configureTracing(service.currentConfig.observability?.tracing);
72
+ return c.json({ ok: true });
73
+ });
74
+ app.delete("/tracing/langfuse/credentials", strictRateLimitMiddleware, async (c) => {
75
+ const resolver = new CredentialResolver();
76
+ await resolver.deleteProviderCredential("langfuse");
77
+ await resolver.deleteProviderCredential("langfuse-public");
78
+ await configureTracing(service.currentConfig.observability?.tracing);
79
+ return c.json({ ok: true });
80
+ });
81
+ app.post("/tracing/langfuse/test", strictRateLimitMiddleware, async (c) => c.json({ ok: await testLangfuse() }));
82
+ app.get("/tracing/status", async (c) => c.json(await tracingStatus()));
83
+ app.get("/traces", async (c) => c.json(await localStore().request("list", querySchema.parse(c.req.query()))));
84
+ app.post("/traces/prune", strictRateLimitMiddleware, async (c) => {
85
+ await localStore().request("prune");
86
+ return c.json({ ok: true });
87
+ });
88
+ app.delete("/traces", strictRateLimitMiddleware, async (c) => {
89
+ await localStore().clear();
90
+ return c.json({ ok: true });
91
+ });
92
+ app.get("/traces/:traceId/export", async (c) => {
93
+ const id = traceIdSchema.parse(c.req.param("traceId"));
94
+ const data = await localStore().request("detail", id);
95
+ if (!data) return c.json({ error: "Trace not found" }, 404);
96
+ c.header("Content-Disposition", `attachment; filename="trace-${id}.json"`);
97
+ return c.json(data);
98
+ });
99
+ app.get("/traces/:traceId", async (c) => {
100
+ const data = await localStore().request("detail", traceIdSchema.parse(c.req.param("traceId")));
101
+ return data ? c.json(data) : c.json({ error: "Trace not found" }, 404);
102
+ });
103
+ authenticated.route("/api/observability", app);
104
+ }
105
+ //#endregion
106
+ export { registerObservabilityRoutes };
@@ -1,7 +1,7 @@
1
1
  import { normalizeAgentId } from "../agent-catalog/id.js";
2
2
  import { AgentCatalogRepository, init_repository } from "../agent-catalog/repository.js";
3
- import { ConfigSchema, init_schema } from "../config/schema.js";
4
3
  import { init_agent_scope } from "../agent/agent-scope.js";
4
+ import { ConfigSchema, init_schema } from "../config/schema.js";
5
5
  import { resolveEffectiveAgentConfigForAgent } from "../config/agent-profile.js";
6
6
  import { fetchWithTimeoutGuarded } from "../media-shared/http/provider-http.js";
7
7
  import "../media-shared/http/index.js";
@@ -1,8 +1,8 @@
1
1
  import path from "node:path";
2
2
  import fs from "node:fs";
3
3
  import { createHash } from "node:crypto";
4
- import net from "node:net";
5
4
  import fs$1 from "node:fs/promises";
5
+ import net from "node:net";
6
6
  import { homedir } from "os";
7
7
  //#region src/gateway/lock.ts
8
8
  /**
@@ -24,6 +24,7 @@ function requiredGatewayScope(method, path) {
24
24
  if (method === "GET" && path === "/api/connectors/approvals") return "sessions.read";
25
25
  if (method === "POST" && path === "/api/connectors/approvals/respond") return "sessions.write";
26
26
  if (path === "/api/agent" || path.startsWith("/api/agent/")) return "agents.run";
27
+ if (path === "/api/observability" || path.startsWith("/api/observability/")) return "gateway.admin";
27
28
  if (path.startsWith("/api/usage")) return "gateway.admin";
28
29
  if (path.startsWith("/api/agents") || path.startsWith("/api/models")) return methodScope(method, "agents.read", "gateway.admin");
29
30
  if (path.startsWith("/api/sessions") || path.startsWith("/api/side-chats")) return methodScope(method, "sessions.read", "sessions.write");
@@ -1,28 +1,3 @@
1
- /**
2
- * GatewayConfigCoordinator — owns config persistence, hot-reload, and the
3
- * per-section reload handlers.
4
- *
5
- * Was 350 lines of `GatewayService` covering nine concerns:
6
- * - manual `reloadConfig()` (CLI/UI trigger)
7
- * - `saveConfig()` / `updateConfig()` (PATCH /api/config)
8
- * - `setExtensionActivationTarget` (extension lifecycle)
9
- * - `afterWeixinCredentialsPersisted` / `afterFeishuCredentialsPersisted`
10
- * (QR-login follow-ups that bypass the watcher)
11
- * - `ConfigHotReloader` (fs.watch → debounced per-section dispatch)
12
- * - Section reload handlers (models / agents / channels /
13
- * tools / mcp / extensions)
14
- * - `scheduleChannelPluginsAfterPersist` (coalesces rapid saves so
15
- * Telegram/Weixin do not stop/start repeatedly)
16
- *
17
- * Pulled out so the gateway composition root stays focused on lifecycle, and
18
- * each handler is reachable from one place when adding a new config section.
19
- *
20
- * **Config state ownership.** `GatewayService.config` is still the single
21
- * source of truth — this coordinator reads it via `getConfig()` and writes it
22
- * back via `setConfig()` after every reload / persist. We pass through rather
23
- * than holding our own copy so other coordinators (sessions, marketplace,
24
- * agent runner) see the latest config the moment a reload commits.
25
- */
26
1
  import type { Config } from '../../config/schema.js';
27
2
  import type { AgentService } from '../../agent/service.js';
28
3
  import type { ChannelManager } from '../../channels/manager.js';
@@ -1,5 +1,6 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
+ import { configureTracing } from "../../observability/runtime.js";
3
4
  import { getModelRegistry } from "../../providers/model-registry.js";
4
5
  import { init_providers } from "../../providers/index.js";
5
6
  import { disposeAllSessionMcpRuntimes } from "../../agent/mcp/bundle-mcp-runtime.js";
@@ -11,6 +12,31 @@ import "../../config/index.js";
11
12
  import { computeExtensionActivationPatch } from "../../extensions/bundled-extension-activation.js";
12
13
  import { sanitizeTunnelConfig } from "../../tunnel/tunnel-config.js";
13
14
  //#region src/gateway/service/config-coordinator.ts
15
+ /**
16
+ * GatewayConfigCoordinator — owns config persistence, hot-reload, and the
17
+ * per-section reload handlers.
18
+ *
19
+ * Was 350 lines of `GatewayService` covering nine concerns:
20
+ * - manual `reloadConfig()` (CLI/UI trigger)
21
+ * - `saveConfig()` / `updateConfig()` (PATCH /api/config)
22
+ * - `setExtensionActivationTarget` (extension lifecycle)
23
+ * - `afterWeixinCredentialsPersisted` / `afterFeishuCredentialsPersisted`
24
+ * (QR-login follow-ups that bypass the watcher)
25
+ * - `ConfigHotReloader` (fs.watch → debounced per-section dispatch)
26
+ * - Section reload handlers (models / agents / channels /
27
+ * tools / mcp / extensions)
28
+ * - `scheduleChannelPluginsAfterPersist` (coalesces rapid saves so
29
+ * Telegram/Weixin do not stop/start repeatedly)
30
+ *
31
+ * Pulled out so the gateway composition root stays focused on lifecycle, and
32
+ * each handler is reachable from one place when adding a new config section.
33
+ *
34
+ * **Config state ownership.** `GatewayService.config` is still the single
35
+ * source of truth — this coordinator reads it via `getConfig()` and writes it
36
+ * back via `setConfig()` after every reload / persist. We pass through rather
37
+ * than holding our own copy so other coordinators (sessions, marketplace,
38
+ * agent runner) see the latest config the moment a reload commits.
39
+ */
14
40
  init_providers();
15
41
  init_logger();
16
42
  const log = createLogger("GatewayConfigCoordinator");
@@ -26,6 +52,10 @@ var GatewayConfigCoordinator = class {
26
52
  startHotReloader() {
27
53
  if (this.configReloader) return;
28
54
  this.configReloader = new ConfigHotReloader(this.opts.configPath, this.opts.getConfig(), {
55
+ onTracingReload: async (next) => {
56
+ this.opts.setConfig(next);
57
+ await configureTracing(next.observability?.tracing);
58
+ },
29
59
  onModelsReload: (newConfig) => this.handleModelsReload(newConfig),
30
60
  onChannelsReload: (newConfig) => this.handleChannelsReload(newConfig),
31
61
  onCronReload: (newConfig) => this.handleAutomationReload(newConfig),
@@ -316,6 +346,7 @@ var GatewayConfigCoordinator = class {
316
346
  await saveConfig(configToWrite, this.opts.configPath);
317
347
  const reloaded = loadConfig(this.opts.configPath);
318
348
  this.opts.setConfig(reloaded);
349
+ await configureTracing(reloaded.observability?.tracing);
319
350
  if (sanitizeTunnelConfig(reloaded)) await saveConfig(reloaded, this.opts.configPath);
320
351
  this.opts.getAgentService().applyRuntimeConfiguration(reloaded);
321
352
  await this.opts.reconcileMemoryMaintenanceAutomations().catch((err) => {
@@ -17,14 +17,15 @@ import { init_session_repository, listSessionMetadata, patchSessionMetadata } fr
17
17
  import { getSessionConfig, init_config_repository } from "../storage/sqlite/config-repository.js";
18
18
  import { init_sqlite } from "../storage/sqlite/index.js";
19
19
  import { normalizeAgentId } from "../agent-catalog/id.js";
20
+ import { init_agent_scope, listAgentEntries, resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agent/agent-scope.js";
21
+ import { init_paths, resolveConfigPath, resolveExtensionsDir } from "../config/paths.js";
22
+ import { flushTracing } from "../observability/runtime.js";
20
23
  import { init_config, resolveKnowledgeReadPolicy } from "../user-context/config.js";
21
24
  import { getAgentDefaultModelRef, init_schema } from "../config/schema.js";
22
- import { init_agent_scope, listAgentEntries, resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agent/agent-scope.js";
23
25
  import { init_agent_session_key, resolveAgentMainConversationId } from "../routing/agent-session-key.js";
24
26
  import { init_session_key, resolveConversationId, sanitizeSegment } from "../routing/session-key.js";
25
27
  import { getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
26
28
  import { resolveEffectiveAgentProfileForSession } from "../config/agent-profile.js";
27
- import { init_paths, resolveConfigPath, resolveExtensionsDir } from "../config/paths.js";
28
29
  import { prewarmModelRegistry } from "../providers/model-registry.js";
29
30
  import { init_providers, providers_exports } from "../providers/index.js";
30
31
  import { AI_USAGE_RETENTION_MS, markStaleAiUsageEventsUnknown, pruneAiUsageEvents } from "../storage/sqlite/ai-usage-repository.js";
@@ -1513,6 +1514,7 @@ var GatewayService = class {
1513
1514
  }
1514
1515
  }
1515
1516
  async stop() {
1517
+ await flushTracing();
1516
1518
  if (!this.running) return;
1517
1519
  this.stopping = true;
1518
1520
  this.taskRunDispatcher?.stop();
@@ -1563,7 +1565,7 @@ var GatewayService = class {
1563
1565
  await disposeAllSessionMcpRuntimes().catch((err) => {
1564
1566
  log.warn({ err }, "MCP runtime shutdown failed");
1565
1567
  });
1566
- this._agentService?.stop();
1568
+ await this._agentService?.stop();
1567
1569
  this.running = false;
1568
1570
  this.bus.shutdown();
1569
1571
  this.lastDeferredChannelConnectIds = [];
@@ -6,7 +6,8 @@ import { createSideChatContextSnapshot, formatSideChatSelections, validateSideCh
6
6
  import { randomUUID } from "node:crypto";
7
7
  //#region src/gateway/side-chat/manager.ts
8
8
  init_logger();
9
- const DEFAULT_IDLE_TTL_MS = 1800 * 1e3;
9
+ const DEFAULT_IDLE_TTL_MS = 360 * 60 * 1e3;
10
+ const EXPIRED_RECORD_RETENTION_MS = 1800 * 1e3;
10
11
  const DEFAULT_MAX_PER_CLIENT = 5;
11
12
  const DEFAULT_MAX_TOTAL = 50;
12
13
  const MAX_EXPIRED_RECORDS = 500;
@@ -260,7 +261,7 @@ var EphemeralSideChatManager = class {
260
261
  this.expired.set(entry.id, {
261
262
  clientInstanceId: entry.clientInstanceId,
262
263
  reason,
263
- removeAt: this.now() + DEFAULT_IDLE_TTL_MS
264
+ removeAt: this.now() + EXPIRED_RECORD_RETENTION_MS
264
265
  });
265
266
  this.pruneExpiredRecords(this.now());
266
267
  const cleanup = this.disposeEntry(entry.id, entry.clientInstanceId);
@@ -0,0 +1,40 @@
1
+ import { z } from 'zod';
2
+ export declare const TracingConfigSchema: z.ZodObject<{
3
+ enabled: z.ZodDefault<z.ZodBoolean>;
4
+ capture: z.ZodDefault<z.ZodEnum<{
5
+ metadata: "metadata";
6
+ redacted: "redacted";
7
+ detailed: "detailed";
8
+ }>>;
9
+ detailedUntil: z.ZodOptional<z.ZodNumber>;
10
+ local: z.ZodPrefault<z.ZodObject<{
11
+ retentionDays: z.ZodDefault<z.ZodNumber>;
12
+ maxStoreMiB: z.ZodDefault<z.ZodNumber>;
13
+ maxTraces: z.ZodDefault<z.ZodNumber>;
14
+ maxSpans: z.ZodDefault<z.ZodNumber>;
15
+ maxTraceKiB: z.ZodDefault<z.ZodNumber>;
16
+ maxWriteMiBPerMinute: z.ZodDefault<z.ZodNumber>;
17
+ }, z.core.$strip>>;
18
+ langfuse: z.ZodPrefault<z.ZodObject<{
19
+ enabled: z.ZodDefault<z.ZodBoolean>;
20
+ baseUrl: z.ZodDefault<z.ZodString>;
21
+ }, z.core.$strip>>;
22
+ }, z.core.$strict>;
23
+ export type TracingConfig = z.infer<typeof TracingConfigSchema>;
24
+ export declare const defaultTracingConfig: () => {
25
+ enabled: boolean;
26
+ capture: "metadata" | "redacted" | "detailed";
27
+ local: {
28
+ retentionDays: number;
29
+ maxStoreMiB: number;
30
+ maxTraces: number;
31
+ maxSpans: number;
32
+ maxTraceKiB: number;
33
+ maxWriteMiBPerMinute: number;
34
+ };
35
+ langfuse: {
36
+ enabled: boolean;
37
+ baseUrl: string;
38
+ };
39
+ detailedUntil?: number;
40
+ };
@@ -0,0 +1,31 @@
1
+ import { __esmMin } from "../../_virtual/_rolldown/runtime.js";
2
+ import { z } from "zod";
3
+ //#region src/observability/config.ts
4
+ var TracingConfigSchema, defaultTracingConfig;
5
+ var init_config = __esmMin((() => {
6
+ TracingConfigSchema = z.object({
7
+ enabled: z.boolean().default(true),
8
+ capture: z.enum([
9
+ "metadata",
10
+ "redacted",
11
+ "detailed"
12
+ ]).default("redacted"),
13
+ detailedUntil: z.number().int().nonnegative().optional(),
14
+ local: z.object({
15
+ retentionDays: z.number().int().min(1).max(90).default(7),
16
+ maxStoreMiB: z.number().int().min(16).max(4096).default(256),
17
+ maxTraces: z.number().int().min(10).max(1e5).default(1e4),
18
+ maxSpans: z.number().int().min(100).max(1e6).default(1e5),
19
+ maxTraceKiB: z.number().int().min(16).max(4096).default(1024),
20
+ maxWriteMiBPerMinute: z.number().int().min(1).max(100).default(2)
21
+ }).prefault({}),
22
+ langfuse: z.object({
23
+ enabled: z.boolean().default(false),
24
+ baseUrl: z.string().url().max(2048).refine((value) => ["http:", "https:"].includes(new URL(value).protocol), "HTTP(S) URL required").default("https://cloud.langfuse.com")
25
+ }).prefault({})
26
+ }).strict();
27
+ defaultTracingConfig = () => TracingConfigSchema.parse({});
28
+ }));
29
+ //#endregion
30
+ init_config();
31
+ export { TracingConfigSchema, defaultTracingConfig, init_config };
@@ -0,0 +1,31 @@
1
+ import type { TraceRecord } from './types.js';
2
+ /** Bounded OTLP/HTTP JSON exporter. No hidden SDK queue or durable replay. */
3
+ export declare class LangfuseTarget {
4
+ private baseUrl;
5
+ private publicKey;
6
+ private secretKey;
7
+ private queue;
8
+ private bytes;
9
+ private timer?;
10
+ private sending?;
11
+ private controller?;
12
+ private closed;
13
+ private lastWarning;
14
+ dropped: number;
15
+ lastSuccess?: number;
16
+ lastFailure?: number;
17
+ lastError?: string;
18
+ constructor(baseUrl: string, publicKey: string, secretKey: string);
19
+ status(): {
20
+ state: string;
21
+ pending: number;
22
+ dropped: number;
23
+ lastSuccess: number;
24
+ lastFailure: number;
25
+ lastError: string;
26
+ };
27
+ enqueue(record: TraceRecord): void;
28
+ flush(): Promise<void>;
29
+ private send;
30
+ close(): void;
31
+ }
@@ -0,0 +1,180 @@
1
+ import { createLogger } from "../utils/logger/index.js";
2
+ import { init_logger } from "../utils/logger.js";
3
+ //#region src/observability/langfuse.ts
4
+ init_logger();
5
+ const log = createLogger("Observability:Langfuse");
6
+ function otlp(record) {
7
+ const attributes = Object.entries(record.attributes).map(([key, value]) => ({
8
+ key,
9
+ value: typeof value === "number" ? { doubleValue: value } : typeof value === "boolean" ? { boolValue: value } : { stringValue: value }
10
+ }));
11
+ return {
12
+ traceId: record.traceId,
13
+ spanId: record.spanId,
14
+ parentSpanId: record.parentSpanId,
15
+ name: record.name,
16
+ kind: 1,
17
+ startTimeUnixNano: String(BigInt(Math.floor(record.startedAt * 1e3)) * 1000n),
18
+ endTimeUnixNano: String(BigInt(Math.floor((record.endedAt ?? record.startedAt) * 1e3)) * 1000n),
19
+ attributes,
20
+ status: { code: record.status === "error" ? 2 : 1 }
21
+ };
22
+ }
23
+ /** Bounded OTLP/HTTP JSON exporter. No hidden SDK queue or durable replay. */
24
+ var LangfuseTarget = class {
25
+ queue = [];
26
+ bytes = 0;
27
+ timer;
28
+ sending;
29
+ controller;
30
+ closed = false;
31
+ lastWarning = 0;
32
+ dropped = 0;
33
+ lastSuccess;
34
+ lastFailure;
35
+ lastError;
36
+ constructor(baseUrl, publicKey, secretKey) {
37
+ this.baseUrl = baseUrl;
38
+ this.publicKey = publicKey;
39
+ this.secretKey = secretKey;
40
+ }
41
+ status() {
42
+ return {
43
+ state: this.lastError ? "degraded" : "ready",
44
+ pending: this.queue.length,
45
+ dropped: this.dropped,
46
+ lastSuccess: this.lastSuccess,
47
+ lastFailure: this.lastFailure,
48
+ lastError: this.lastError
49
+ };
50
+ }
51
+ enqueue(record) {
52
+ if (this.closed) return;
53
+ const bytes = Buffer.byteLength(JSON.stringify(record));
54
+ if (this.queue.length >= 2e3 || this.bytes + bytes > 8 * 1048576) {
55
+ this.dropped++;
56
+ this.lastError = "Export queue full";
57
+ return;
58
+ }
59
+ this.queue.push({
60
+ record,
61
+ bytes
62
+ });
63
+ this.bytes += bytes;
64
+ if (this.queue.length >= 100) this.flush();
65
+ else if (!this.timer) {
66
+ this.timer = setTimeout(() => {
67
+ this.timer = void 0;
68
+ this.flush();
69
+ }, 5e3);
70
+ this.timer.unref();
71
+ }
72
+ }
73
+ async flush() {
74
+ if (this.sending) {
75
+ await this.sending;
76
+ if (this.queue.length && !this.closed) await this.flush();
77
+ return;
78
+ }
79
+ if (this.timer) {
80
+ clearTimeout(this.timer);
81
+ this.timer = void 0;
82
+ }
83
+ if (this.closed || !this.queue.length) return;
84
+ const batch = this.queue.splice(0, 100);
85
+ this.bytes -= batch.reduce((n, row) => n + row.bytes, 0);
86
+ this.sending = this.send(batch.map((row) => row.record)).finally(() => {
87
+ this.sending = void 0;
88
+ });
89
+ await this.sending;
90
+ if (this.queue.length && !this.closed && !this.timer) {
91
+ this.timer = setTimeout(() => {
92
+ this.timer = void 0;
93
+ this.flush();
94
+ }, 5e3);
95
+ this.timer.unref();
96
+ }
97
+ }
98
+ async send(records) {
99
+ for (let attempt = 0; attempt < 3 && !this.closed; attempt++) {
100
+ this.controller = new AbortController();
101
+ const timeout = setTimeout(() => this.controller?.abort(), 5e3);
102
+ try {
103
+ const response = await fetch(this.baseUrl.replace(/\/$/, "") + "/api/public/otel/v1/traces", {
104
+ method: "POST",
105
+ redirect: "error",
106
+ signal: this.controller.signal,
107
+ headers: {
108
+ "Content-Type": "application/json",
109
+ Authorization: `Basic ${Buffer.from(`${this.publicKey}:${this.secretKey}`).toString("base64")}`,
110
+ "x-langfuse-ingestion-version": "4"
111
+ },
112
+ body: JSON.stringify({ resourceSpans: [{
113
+ resource: { attributes: [{
114
+ key: "service.name",
115
+ value: { stringValue: "xopc" }
116
+ }] },
117
+ scopeSpans: [{
118
+ scope: { name: "xopc.observability" },
119
+ spans: records.map(otlp)
120
+ }]
121
+ }] })
122
+ });
123
+ if (!response.ok) {
124
+ await response.body?.cancel();
125
+ throw new Error(`Langfuse returned HTTP ${response.status}`);
126
+ }
127
+ if (response.body) {
128
+ const reader = response.body.getReader();
129
+ const chunks = [];
130
+ let size = 0;
131
+ try {
132
+ while (true) {
133
+ const chunk = await reader.read();
134
+ if (chunk.done) break;
135
+ size += chunk.value.length;
136
+ if (size > 16384) {
137
+ await reader.cancel();
138
+ throw new Error("Oversized ingestion response");
139
+ }
140
+ chunks.push(chunk.value);
141
+ }
142
+ const text = Buffer.concat(chunks).toString("utf8");
143
+ if (text && Number(JSON.parse(text).partialSuccess?.rejectedSpans ?? 0) > 0) throw new Error("Ingestion rejected spans");
144
+ } finally {
145
+ reader.releaseLock();
146
+ }
147
+ }
148
+ this.lastSuccess = Date.now();
149
+ this.lastError = void 0;
150
+ return;
151
+ } catch (error) {
152
+ this.lastFailure = Date.now();
153
+ if (Date.now() - this.lastWarning > 6e4) {
154
+ this.lastWarning = Date.now();
155
+ log.warn({
156
+ phase: "langfuse_export",
157
+ attempt: attempt + 1
158
+ }, "Langfuse trace export failed; local recording continues");
159
+ }
160
+ this.lastError = error instanceof Error && /^Langfuse returned HTTP \d+$/.test(error.message) ? error.message : "Langfuse export failed";
161
+ } finally {
162
+ clearTimeout(timeout);
163
+ }
164
+ if (attempt < 2 && !this.closed) await new Promise((resolve) => {
165
+ setTimeout(resolve, 250 * 2 ** attempt).unref();
166
+ });
167
+ }
168
+ this.dropped += records.length;
169
+ }
170
+ close() {
171
+ this.closed = true;
172
+ this.controller?.abort();
173
+ if (this.timer) clearTimeout(this.timer);
174
+ this.dropped += this.queue.length;
175
+ this.queue = [];
176
+ this.bytes = 0;
177
+ }
178
+ };
179
+ //#endregion
180
+ export { LangfuseTarget };
@@ -0,0 +1,57 @@
1
+ import { type Span, type Attributes } from '@opentelemetry/api';
2
+ import { type TracingConfig } from './config.js';
3
+ import { LocalTraceStore } from './store.js';
4
+ import type { TraceRecord } from './types.js';
5
+ export type TraceIdentity = {
6
+ conversationId?: string;
7
+ runId?: string;
8
+ agentId?: string;
9
+ transcriptId?: string;
10
+ };
11
+ export declare function localStore(): LocalTraceStore;
12
+ export declare function tracingConfig(): TracingConfig;
13
+ export declare function configureTracing(value?: unknown): Promise<void>;
14
+ export declare function tracingStatus(): Promise<{
15
+ local: any;
16
+ langfuse: {
17
+ state: string;
18
+ pending: number;
19
+ dropped: number;
20
+ lastSuccess: number;
21
+ lastFailure: number;
22
+ lastError: string;
23
+ } | {
24
+ state: string;
25
+ pending: number;
26
+ dropped: number;
27
+ };
28
+ active: number;
29
+ dropped: number;
30
+ }>;
31
+ export declare function traceIds(): {
32
+ traceId?: string;
33
+ spanId?: string;
34
+ };
35
+ export type Observation = {
36
+ span?: Span;
37
+ run: <T>(fn: () => T) => T;
38
+ finish: (status?: string, output?: unknown) => void;
39
+ input: (value: unknown) => void;
40
+ update: (values: Attributes) => void;
41
+ };
42
+ export declare function startObservation(name: string, type: TraceRecord['type'], identity?: TraceIdentity): Observation;
43
+ export declare function traceRun<T extends {
44
+ ok?: boolean;
45
+ stopReason?: string;
46
+ errorMessage?: string;
47
+ lastAssistantText?: string;
48
+ }>(name: string, identity: TraceIdentity, fn: () => Promise<T>, input?: unknown): Promise<T>;
49
+ export declare function traceTools<T extends {
50
+ name: string;
51
+ execute: (...args: any[]) => any;
52
+ }>(tools: T[]): T[];
53
+ export declare function flushTracing(): Promise<void>;
54
+ export declare function testLangfuse(): Promise<boolean>;
55
+ export declare function closeTracing(): Promise<void>;
56
+ export declare function traceOperation<T>(name: string, fn: () => Promise<T>, attributes?: Attributes): Promise<T>;
57
+ export declare function setTraceIdentity(identity: TraceIdentity): void;