@xopcai/xopc 0.0.362 → 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 (201) 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-_2aJ4ozN.js → activity-store-GvR2gZ0T.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CSIn4ghK.js → agent-avatar-dicebear-DkcXyPH0.js} +1 -1
  5. package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-DBNFaHYa.js → agent-defaults-settings-panel-B-l5AaYN.js} +1 -1
  6. package/dist/gateway/static/root/assets/{agent-plugin-dialog-DJkGbMVg.js → agent-plugin-dialog-BY6tPYOK.js} +1 -1
  7. package/dist/gateway/static/root/assets/{agents-CuQayYYr.js → agents-CdSEoeje.js} +3 -3
  8. package/dist/gateway/static/root/assets/{agents-admin-api-Dl0V7UQq.js → agents-admin-api-BkXb7VEZ.js} +1 -1
  9. package/dist/gateway/static/root/assets/{app-management-settings-panel-CSczq9QV.js → app-management-settings-panel-BtD53cfe.js} +1 -1
  10. package/dist/gateway/static/root/assets/{appearance-settings-W0vc1J1Q.js → appearance-settings-BAweWgX_.js} +1 -1
  11. package/dist/gateway/static/root/assets/{apps-page-esnvb3hh.js → apps-page-CS6-hrIB.js} +1 -1
  12. package/dist/gateway/static/root/assets/{archive-plugin-CBR91gHK.js → archive-plugin-CKe3qAaL.js} +1 -1
  13. package/dist/gateway/static/root/assets/{automations-page-B9RdzKUS.js → automations-page-CtE8r9Y2.js} +1 -1
  14. package/dist/gateway/static/root/assets/{automations-workspace-U9TEZd_t.js → automations-workspace-pnMgR4Da.js} +1 -1
  15. package/dist/gateway/static/root/assets/{binary-plugins-C9KIjPph.js → binary-plugins-J51oS7-D.js} +1 -1
  16. package/dist/gateway/static/root/assets/{block-editor-C0bammwh.js → block-editor-D5hf6WcP.js} +1 -1
  17. package/dist/gateway/static/root/assets/{browser-automation-inputs-D2E0co_S.js → browser-automation-inputs-5B3qAdmb.js} +1 -1
  18. package/dist/gateway/static/root/assets/{browser-automations-page-8kqdhAOz.js → browser-automations-page-PZDQlXH4.js} +1 -1
  19. package/dist/gateway/static/root/assets/{browser-settings-page-Dl4idi13.js → browser-settings-page-2YDV-ZWt.js} +1 -1
  20. package/dist/gateway/static/root/assets/{capabilities-Bfktn_7E.js → capabilities-BKu9BqPe.js} +1 -1
  21. package/dist/gateway/static/root/assets/{capabilities-BmMMlNmY.js → capabilities-CT_ZW9fT.js} +1 -1
  22. package/dist/gateway/static/root/assets/{capabilities-page-3ImhKPBx.js → capabilities-page-CB-iX3Fy.js} +2 -2
  23. package/dist/gateway/static/root/assets/{capabilities-settings-panel-4VDEB_ob.js → capabilities-settings-panel-BCTuWNaW.js} +1 -1
  24. package/dist/gateway/static/root/assets/{capability-header-actions-D1gxCGi8.js → capability-header-actions--aC5XB9E.js} +1 -1
  25. package/dist/gateway/static/root/assets/{channels-Drbr2JR-.js → channels-JnAQP1bt.js} +1 -1
  26. package/dist/gateway/static/root/assets/{chat-terminal-dock-CSkksCaa.js → chat-terminal-dock-BFZEpvzn.js} +1 -1
  27. package/dist/gateway/static/root/assets/{computer-settings-page-BIXpOJAk.js → computer-settings-page-Dc9ooEM-.js} +1 -1
  28. package/dist/gateway/static/root/assets/{connector-service-page-CTnlVEE1.js → connector-service-page-1_QB5D-t.js} +1 -1
  29. package/dist/gateway/static/root/assets/{connectors-page-BluT2l4d.js → connectors-page-Um_Jy5zh.js} +1 -1
  30. package/dist/gateway/static/root/assets/{date-picker-Bw-CydDe.js → date-picker-C9ZqTPui.js} +1 -1
  31. package/dist/gateway/static/root/assets/{dependency-picker-CgHzhtAc.js → dependency-picker-DBz0Pmyr.js} +1 -1
  32. package/dist/gateway/static/root/assets/{desktop-pet-YahEnyfd.js → desktop-pet-BLtp2MmX.js} +1 -1
  33. package/dist/gateway/static/root/assets/{desktop-pet-settings-47Z4bqJr.js → desktop-pet-settings-BNGbqwec.js} +1 -1
  34. package/dist/gateway/static/root/assets/{device-pairing-wizard-C3aPEEaM.js → device-pairing-wizard-7rdo-A7d.js} +1 -1
  35. package/dist/gateway/static/root/assets/{directory-picker-path-field-DH_ok92y.js → directory-picker-path-field-BnilGgwM.js} +1 -1
  36. package/dist/gateway/static/root/assets/{extension-debug-page-t1TiLQrR.js → extension-debug-page-BGyJpRv4.js} +1 -1
  37. package/dist/gateway/static/root/assets/{extension-page-BeV-7G1h.js → extension-page-DsrVktRN.js} +1 -1
  38. package/dist/gateway/static/root/assets/{extension-provider-CFCxzqna.js → extension-provider-F9JzOWZ3.js} +1 -1
  39. package/dist/gateway/static/root/assets/{extension-settings-page-DCODJHOu.js → extension-settings-page-jeb0ytRK.js} +1 -1
  40. package/dist/gateway/static/root/assets/{fallback-models-CJzvASNV.js → fallback-models-bZcxkEDz.js} +1 -1
  41. package/dist/gateway/static/root/assets/{gateway-config-swr-B3LfyXpc.js → gateway-config-swr-CoRoOG1l.js} +1 -1
  42. package/dist/gateway/static/root/assets/{gateway-realtime-CWxXXAe_.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-Q5NFzAJ_.js → gateway-settings-A9SzLsGp.js} +1 -1
  45. package/dist/gateway/static/root/assets/{gateway-startup-retry-BzQP02wp.js → gateway-startup-retry-FDS6S6qa.js} +1 -1
  46. package/dist/gateway/static/root/assets/{home-page-DndTkAw8.js → home-page-CnHzaH9K.js} +1 -1
  47. package/dist/gateway/static/root/assets/{image-generation-api-BO-Xs__S.js → image-generation-api-BPd76jW5.js} +1 -1
  48. package/dist/gateway/static/root/assets/{imports-page-Bb6Gm30L.js → imports-page-CzpsV6Vz.js} +1 -1
  49. package/dist/gateway/static/root/assets/{index-qOHWhsEK.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-D2u6sk5l.js → keyboard-shortcuts-settings-D90Dvlwo.js} +1 -1
  52. package/dist/gateway/static/root/assets/{local-app-workbench-page-CHeMfXrB.js → local-app-workbench-page-_9IKMkV8.js} +1 -1
  53. package/dist/gateway/static/root/assets/{local-apps-page-BanU1SLr.js → local-apps-page-D6gejARs.js} +1 -1
  54. package/dist/gateway/static/root/assets/{local-session-drafts-DLZQBcZY.js → local-session-drafts-gbemPamv.js} +1 -1
  55. package/dist/gateway/static/root/assets/{locale-store-BbwWB0ra.js → locale-store-DId6-v2R.js} +1 -1
  56. package/dist/gateway/static/root/assets/{logs-page-CQdHKCL0.js → logs-page--t8d-oLb.js} +1 -1
  57. package/dist/gateway/static/root/assets/{management-settings-D0V5kCx0.js → management-settings-DVDmXzTg.js} +1 -1
  58. package/dist/gateway/static/root/assets/{markdown-view-DIBLXsPm.js → markdown-view-DQZ51j9e.js} +1 -1
  59. package/dist/gateway/static/root/assets/{media-plugins-XPzvDZPz.js → media-plugins-XLewwq2q.js} +1 -1
  60. package/dist/gateway/static/root/assets/{messages-B4AhAW4B.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-CodeKI_W.js → note-detail-panel-DuZAEfU1.js} +3 -3
  63. package/dist/gateway/static/root/assets/{notes-api-CLn4r03Z.js → notes-api-Byt65v3r.js} +1 -1
  64. package/dist/gateway/static/root/assets/{notes-page-liRQoHbF.js → notes-page-CgWNESGp.js} +1 -1
  65. package/dist/gateway/static/root/assets/{oauth-api-D9zkd42J.js → oauth-api-BYsCbyGZ.js} +1 -1
  66. package/dist/gateway/static/root/assets/{page-context-capture-button-DO6DB9pi.js → page-context-capture-button-Z72eiQZn.js} +1 -1
  67. package/dist/gateway/static/root/assets/{personal-page-DdfdwOv5.js → personal-page-BtMatL9a.js} +1 -1
  68. package/dist/gateway/static/root/assets/{product-open-page-C9a3sm6Z.js → product-open-page-w5Hdf0hQ.js} +1 -1
  69. package/dist/gateway/static/root/assets/{project-detail-page-BVe5R-Nj.js → project-detail-page-CP6I3ZCV.js} +1 -1
  70. package/dist/gateway/static/root/assets/{projects-page-D_rCwi7w.js → projects-page-DYs6XrrK.js} +1 -1
  71. package/dist/gateway/static/root/assets/{registry-api-BFxQTbXQ.js → registry-api-7F2WNEZC.js} +1 -1
  72. package/dist/gateway/static/root/assets/{remote-access-hub-B3imt2du.js → remote-access-hub-DjYoYAEw.js} +1 -1
  73. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-C9WC8hJM.js → runtime-tools-settings-panel-Qar_DXLv.js} +1 -1
  74. package/dist/gateway/static/root/assets/{scenes-page-DL95V1UP.js → scenes-page-BSIcDCa-.js} +1 -1
  75. package/dist/gateway/static/root/assets/{schema-form-CDgGmgrq.js → schema-form-C_cJLGgF.js} +1 -1
  76. package/dist/gateway/static/root/assets/{send-session-input-tkAQXGBG.js → send-session-input-D1oc6BC6.js} +1 -1
  77. package/dist/gateway/static/root/assets/{session-api-9X7qep91.js → session-api-N3N37MrR.js} +1 -1
  78. package/dist/gateway/static/root/assets/{session-manager-Dy22bbJT.js → session-manager-CMGUwtbN.js} +1 -1
  79. package/dist/gateway/static/root/assets/{sessions-page-CeeKIVsM.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-xmUGYSOG.js → settings-page-F2vGXBw7.js} +1 -1
  82. package/dist/gateway/static/root/assets/{setup-status-panel-CmjT9Q4P.js → setup-status-panel-DJxbjUOg.js} +1 -1
  83. package/dist/gateway/static/root/assets/{share-link-dialog-DeOe9qfQ.js → share-link-dialog-TBBGJPfT.js} +1 -1
  84. package/dist/gateway/static/root/assets/{share-preview-page-Ck27gozJ.js → share-preview-page-DyRLPsPv.js} +1 -1
  85. package/dist/gateway/static/root/assets/{shares-api-D-GuMkPu.js → shares-api-DU0fHP2G.js} +1 -1
  86. package/dist/gateway/static/root/assets/{shares-settings-DpvM2OyO.js → shares-settings-CJa6FBpP.js} +1 -1
  87. package/dist/gateway/static/root/assets/{skill-api-BpD02td8.js → skill-api-C340XD9d.js} +1 -1
  88. package/dist/gateway/static/root/assets/{skill-reload-api-CezAwYxM.js → skill-reload-api-ClyFqHk7.js} +1 -1
  89. package/dist/gateway/static/root/assets/{skills-page-BCgbVI-P.js → skills-page-C4lF94m5.js} +1 -1
  90. package/dist/gateway/static/root/assets/{system-settings-panel-UODcpzsP.js → system-settings-panel-CmJUu3lb.js} +1 -1
  91. package/dist/gateway/static/root/assets/{task-detail-page-BbqQnNes.js → task-detail-page-De-Rr8W6.js} +1 -1
  92. package/dist/gateway/static/root/assets/{theme-store-6IK2Ik2J.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-Eey2aZIz.js → tunnel-api-Bl4nrCuE.js} +1 -1
  95. package/dist/gateway/static/root/assets/{usage-page-BrWj5mk3.js → usage-page-QZEAaa8n.js} +1 -1
  96. package/dist/gateway/static/root/assets/{use-autosave-B-3BJbnn.js → use-autosave-veoM0dHn.js} +1 -1
  97. package/dist/gateway/static/root/assets/{use-composer-attachments-ByAHuR8v.js → use-composer-attachments-DB0bBGzZ.js} +1 -1
  98. package/dist/gateway/static/root/assets/{use-file-preview-expanded-CXVwWJeP.js → use-file-preview-expanded-Bope6MW6.js} +2 -2
  99. package/dist/gateway/static/root/assets/{user-model-page-Cg-oM8nY.js → user-model-page-Crh2oNpZ.js} +1 -1
  100. package/dist/gateway/static/root/assets/{voice-api-key-field-BtffIKZD.js → voice-api-key-field-CwD6a3KQ.js} +1 -1
  101. package/dist/gateway/static/root/assets/{voice-config-api-BMm9dSKX.js → voice-config-api-Daexehmc.js} +1 -1
  102. package/dist/gateway/static/root/assets/{work-discovery-overlay-ByHhF_4r.js → work-discovery-overlay-9jnjEAaz.js} +1 -1
  103. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-DfNn5VTy.js → workflow-run-setup-panel-BAcPxdcT.js} +1 -1
  104. package/dist/gateway/static/root/assets/{workflows-page-B67D-7Wt.js → workflows-page-D8Zm-ooa.js} +1 -1
  105. package/dist/gateway/static/root/assets/{workspace-api-TAD7LYsc.js → workspace-api-Cs4sjV2A.js} +2 -2
  106. package/dist/gateway/static/root/index.html +28 -28
  107. package/dist/package.js +1 -1
  108. package/dist/src/agent/agent-manager.js +10 -6
  109. package/dist/src/agent/embedded/model-runtime.js +1 -1
  110. package/dist/src/agent/embedded/run-for-session.js +28 -3
  111. package/dist/src/agent/embedded/run-turn.js +18 -3
  112. package/dist/src/agent/image/tool-model-config.js +1 -1
  113. package/dist/src/agent/mcp/oauth/mcp-oauth-store.js +1 -1
  114. package/dist/src/agent/service.js +5 -3
  115. package/dist/src/agent/skills/hub-lock.js +1 -1
  116. package/dist/src/agent-catalog/migrations/legacy-config-cutover.js +1 -1
  117. package/dist/src/agent-catalog/repository.js +1 -1
  118. package/dist/src/auth/credentials.js +2 -2
  119. package/dist/src/auth/oauth-provider-lock.js +1 -1
  120. package/dist/src/auth/profiles/store.js +1 -1
  121. package/dist/src/auth/sync-provider-auth.js +1 -1
  122. package/dist/src/browser/providers/browser-ext-install.js +1 -1
  123. package/dist/src/chat-commands/agent-edit.js +1 -1
  124. package/dist/src/chat-commands/builtins/config.js +1 -1
  125. package/dist/src/cli/commands/agent.js +1 -1
  126. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  127. package/dist/src/cli/commands/doctor/checks/image-providers.js +1 -1
  128. package/dist/src/cli/commands/doctor/checks/provider-auth.js +3 -3
  129. package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
  130. package/dist/src/cli/commands/models.js +1 -1
  131. package/dist/src/cli/commands/onboard/model.js +3 -3
  132. package/dist/src/config/agent-profile.js +1 -1
  133. package/dist/src/config/index.js +4 -4
  134. package/dist/src/config/loader.js +2 -2
  135. package/dist/src/config/models-json.js +1 -1
  136. package/dist/src/config/reload.d.ts +1 -0
  137. package/dist/src/config/reload.js +4 -0
  138. package/dist/src/config/rules.js +5 -0
  139. package/dist/src/config/schema.d.ts +23 -0
  140. package/dist/src/config/schema.js +6 -3
  141. package/dist/src/extensions/activation-context.js +1 -1
  142. package/dist/src/extensions/lockfile.js +1 -1
  143. package/dist/src/gateway/file-path-classifier.js +1 -1
  144. package/dist/src/gateway/hono/lib/config-payload.js +2 -2
  145. package/dist/src/gateway/hono/routes/agents.js +1 -1
  146. package/dist/src/gateway/hono/routes/config-patch/misc.js +2 -2
  147. package/dist/src/gateway/hono/routes/connectors.js +1 -1
  148. package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
  149. package/dist/src/gateway/hono/routes/models.js +2 -2
  150. package/dist/src/gateway/hono/routes/observability.d.ts +3 -0
  151. package/dist/src/gateway/hono/routes/observability.js +106 -0
  152. package/dist/src/gateway/image-generation-setup.js +1 -1
  153. package/dist/src/gateway/lock.js +1 -1
  154. package/dist/src/gateway/security/gateway-scopes.js +1 -0
  155. package/dist/src/gateway/service/config-coordinator.d.ts +0 -25
  156. package/dist/src/gateway/service/config-coordinator.js +31 -0
  157. package/dist/src/gateway/service.js +5 -3
  158. package/dist/src/infra/update-restart.js +1 -1
  159. package/dist/src/observability/config.d.ts +40 -0
  160. package/dist/src/observability/config.js +31 -0
  161. package/dist/src/observability/langfuse.d.ts +31 -0
  162. package/dist/src/observability/langfuse.js +180 -0
  163. package/dist/src/observability/runtime.d.ts +57 -0
  164. package/dist/src/observability/runtime.js +404 -0
  165. package/dist/src/observability/sanitize.d.ts +3 -0
  166. package/dist/src/observability/sanitize.js +74 -0
  167. package/dist/src/observability/store.d.ts +20 -0
  168. package/dist/src/observability/store.js +128 -0
  169. package/dist/src/observability/storeWorker.d.ts +2 -0
  170. package/dist/src/observability/storeWorker.js +155 -0
  171. package/dist/src/observability/types.d.ts +21 -0
  172. package/dist/src/observability/types.js +1 -0
  173. package/dist/src/platform/index.js +1 -1
  174. package/dist/src/providers/auth-runtime/resolve-auth.js +1 -1
  175. package/dist/src/providers/index.js +3 -3
  176. package/dist/src/providers/model-call.js +19 -5
  177. package/dist/src/providers/model-catalog-persistence.js +1 -1
  178. package/dist/src/providers/model-registry.js +1 -1
  179. package/dist/src/providers/provider-disconnect-core.js +1 -1
  180. package/dist/src/providers/xopc-cloud-catalog-coordinator.js +1 -1
  181. package/dist/src/storage/sqlite/ai-usage-repository.d.ts +6 -0
  182. package/dist/src/storage/sqlite/ai-usage-repository.js +4 -2
  183. package/dist/src/storage/sqlite/migrations/233_observability_usage_links.sql +3 -0
  184. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  185. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  186. package/dist/src/storage/sqlite/schema.js +1 -1
  187. package/dist/src/tui/backends/embedded-backend.js +2 -2
  188. package/dist/src/tui/tui-commands.js +1 -1
  189. package/dist/src/tui/tui-startup-resources.js +1 -1
  190. package/dist/src/tui/tui.js +1 -1
  191. package/dist/src/usage/recorder.d.ts +4 -2
  192. package/dist/src/usage/recorder.js +54 -26
  193. package/dist/src/usage/types.d.ts +3 -0
  194. package/dist/src/utils/logger/context.d.ts +1 -1
  195. package/dist/src/utils/logger/context.js +4 -1
  196. package/dist/src/utils/logger/types.d.ts +3 -0
  197. package/package.json +6 -3
  198. package/dist/gateway/static/root/assets/gateway-realtime-store-DS4WzQyF.js +0 -1
  199. package/dist/gateway/static/root/assets/index-Byk2QKIS.css +0 -1
  200. package/dist/gateway/static/root/assets/models-hub-cache-DN5MnhL8.js +0 -1
  201. package/dist/gateway/static/root/assets/settings-advanced-gate-DuvJrDU2.js +0 -1
@@ -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;
@@ -0,0 +1,404 @@
1
+ import { init_context, runWithLogContext } from "../utils/logger/context.js";
2
+ import { createLogger } from "../utils/logger/index.js";
3
+ import { init_logger } from "../utils/logger.js";
4
+ import { CredentialResolver, init_credentials } from "../auth/credentials.js";
5
+ import { TracingConfigSchema, defaultTracingConfig, init_config } from "./config.js";
6
+ import { LangfuseTarget } from "./langfuse.js";
7
+ import { boundedJson, redactString } from "./sanitize.js";
8
+ import { LocalTraceStore } from "./store.js";
9
+ import { AsyncLocalStorage } from "node:async_hooks";
10
+ import { SpanStatusCode, context, createContextKey, trace } from "@opentelemetry/api";
11
+ import { AsyncLocalStorageContextManager } from "@opentelemetry/context-async-hooks";
12
+ import { BasicTracerProvider } from "@opentelemetry/sdk-trace-base";
13
+ //#region src/observability/runtime.ts
14
+ init_credentials();
15
+ init_logger();
16
+ init_context();
17
+ init_config();
18
+ const log = createLogger("Observability");
19
+ let lastStorageWarning = 0;
20
+ function storageWarning(message) {
21
+ if (Date.now() - lastStorageWarning < 6e4) return;
22
+ lastStorageWarning = Date.now();
23
+ log.warn({
24
+ errorMessage: message,
25
+ phase: "local_trace_write"
26
+ }, `Local trace recording unavailable: ${message}`);
27
+ }
28
+ const localEpochKey = createContextKey("xopc.trace.localEpoch");
29
+ const scopes = new AsyncLocalStorage();
30
+ let config = defaultTracingConfig();
31
+ let store;
32
+ let target;
33
+ let provider;
34
+ let revision = 0;
35
+ let active = 0;
36
+ let dropped = 0;
37
+ const pendingLocal = /* @__PURE__ */ new Set();
38
+ let pendingLocalBytes = 0;
39
+ let remoteState = "disabled";
40
+ let knownSecrets = [];
41
+ let configureVersion = 0;
42
+ let targetSignature = "";
43
+ const targets = /* @__PURE__ */ new WeakMap();
44
+ const localEpochs = /* @__PURE__ */ new WeakMap();
45
+ const captured = /* @__PURE__ */ new WeakMap();
46
+ function secretSafe(value) {
47
+ let result = redactString(value);
48
+ for (const secret of knownSecrets) if (secret.length >= 4) result = result.split(secret).join("[REDACTED]");
49
+ return result;
50
+ }
51
+ function record(span, ended = true) {
52
+ const attrs = {};
53
+ for (const [key, value] of Object.entries(span.attributes)) if ([
54
+ "string",
55
+ "number",
56
+ "boolean"
57
+ ].includes(typeof value)) attrs[key] = typeof value === "string" ? secretSafe(value) : value;
58
+ return {
59
+ traceId: span.spanContext().traceId,
60
+ spanId: span.spanContext().spanId,
61
+ parentSpanId: span.parentSpanContext?.spanId,
62
+ name: secretSafe(span.name),
63
+ type: String(attrs["langfuse.observation.type"] ?? "span"),
64
+ startedAt: Math.floor(span.startTime[0] * 1e3 + span.startTime[1] / 1e6),
65
+ ...ended ? { endedAt: Math.floor(span.endTime[0] * 1e3 + span.endTime[1] / 1e6) } : {},
66
+ status: ended ? String(attrs["xopc.status"] ?? (span.status.code === SpanStatusCode.ERROR ? "error" : "success")) : "running",
67
+ attributes: attrs
68
+ };
69
+ }
70
+ var TraceProcessor = class {
71
+ onStart(span, parentContext) {
72
+ const scope = scopes.getStore();
73
+ if (!(scope?.config ?? config).enabled) return;
74
+ captured.set(span, true);
75
+ if (scope?.target ?? target) targets.set(span, scope?.target ?? target);
76
+ if (!span.parentSpanContext || span.attributes["xopc.localRoot"] === true) {
77
+ const epoch = localStore().begin(record(span, false)).catch(() => {
78
+ storageWarning("Trace root could not be persisted");
79
+ return -1;
80
+ });
81
+ localEpochs.set(span, epoch);
82
+ if (scope) scope.epoch = epoch;
83
+ } else {
84
+ const epoch = scope?.epoch ?? parentContext.getValue(localEpochKey);
85
+ if (epoch) localEpochs.set(span, epoch);
86
+ }
87
+ }
88
+ onEnd(span) {
89
+ if (!captured.has(span)) return;
90
+ try {
91
+ const value = record(span);
92
+ const bytes = Buffer.byteLength(JSON.stringify(value));
93
+ if (pendingLocal.size < 2e3 && pendingLocalBytes + bytes <= 8 * 1048576) {
94
+ const destination = localStore();
95
+ pendingLocalBytes += bytes;
96
+ const pending = (localEpochs.get(span) ?? Promise.resolve(void 0)).then(async (epoch) => {
97
+ await destination.write(value, epoch);
98
+ if (destination.lastError) storageWarning(destination.lastError);
99
+ }).catch(() => {
100
+ dropped++;
101
+ }).finally(() => {
102
+ pendingLocal.delete(pending);
103
+ pendingLocalBytes -= bytes;
104
+ });
105
+ pendingLocal.add(pending);
106
+ } else dropped++;
107
+ targets.get(span)?.enqueue(value);
108
+ } catch {
109
+ dropped++;
110
+ }
111
+ }
112
+ async forceFlush() {
113
+ await Promise.allSettled([...pendingLocal]);
114
+ await Promise.allSettled([store?.flush(), target?.flush()]);
115
+ }
116
+ async shutdown() {
117
+ await this.forceFlush();
118
+ target?.close();
119
+ await store?.close();
120
+ }
121
+ };
122
+ function tracer() {
123
+ if (!provider) {
124
+ context.setGlobalContextManager(new AsyncLocalStorageContextManager().enable());
125
+ process.once("beforeExit", () => {
126
+ flushTracing();
127
+ });
128
+ provider = new BasicTracerProvider({
129
+ spanProcessors: [new TraceProcessor()],
130
+ spanLimits: {
131
+ attributeCountLimit: 64,
132
+ attributeValueLengthLimit: 65536,
133
+ eventCountLimit: 0
134
+ }
135
+ });
136
+ }
137
+ return provider.getTracer("xopc.observability");
138
+ }
139
+ function localStore() {
140
+ return store ??= new LocalTraceStore(config);
141
+ }
142
+ function tracingConfig() {
143
+ return structuredClone(config);
144
+ }
145
+ async function configureTracing(value) {
146
+ const version = ++configureVersion;
147
+ const next = TracingConfigSchema.parse(value ?? {});
148
+ config = next;
149
+ revision++;
150
+ if (store) await store.request("configure", config).catch(() => {});
151
+ remoteState = !next.enabled || !next.langfuse.enabled ? "disabled" : "missing_credentials";
152
+ if (remoteState === "disabled") {
153
+ target?.close();
154
+ target = void 0;
155
+ targetSignature = "";
156
+ return;
157
+ }
158
+ try {
159
+ const secretKey = process.env.LANGFUSE_SECRET_KEY || await new CredentialResolver().revealGatewayStoredApiKey("langfuse");
160
+ const publicKey = process.env.LANGFUSE_PUBLIC_KEY || await new CredentialResolver().revealGatewayStoredApiKey("langfuse-public");
161
+ if (version !== configureVersion) return;
162
+ if (secretKey && publicKey) {
163
+ const baseUrl = process.env.LANGFUSE_BASE_URL || next.langfuse.baseUrl;
164
+ const signature = JSON.stringify([
165
+ baseUrl,
166
+ publicKey,
167
+ secretKey
168
+ ]);
169
+ knownSecrets = [...new Set([
170
+ ...knownSecrets,
171
+ secretKey,
172
+ publicKey
173
+ ])].slice(-64);
174
+ if (!target || signature !== targetSignature) {
175
+ target?.close();
176
+ target = new LangfuseTarget(baseUrl, publicKey, secretKey);
177
+ targetSignature = signature;
178
+ }
179
+ remoteState = "ready";
180
+ } else {
181
+ target?.close();
182
+ target = void 0;
183
+ targetSignature = "";
184
+ }
185
+ } catch {
186
+ remoteState = "missing_credentials";
187
+ target?.close();
188
+ target = void 0;
189
+ targetSignature = "";
190
+ }
191
+ }
192
+ async function tracingStatus() {
193
+ return {
194
+ local: {
195
+ ...await localStore().request("status").catch(() => ({ unavailable: true })),
196
+ pending: pendingLocal.size,
197
+ pendingBytes: pendingLocalBytes,
198
+ queueDropped: localStore().dropped,
199
+ lastError: localStore().lastError
200
+ },
201
+ langfuse: target?.status() ?? {
202
+ state: remoteState,
203
+ pending: 0,
204
+ dropped: 0
205
+ },
206
+ active,
207
+ dropped
208
+ };
209
+ }
210
+ function traceIds() {
211
+ const current = trace.getSpan(context.active())?.spanContext();
212
+ return current ? {
213
+ traceId: current.traceId,
214
+ spanId: current.spanId
215
+ } : {};
216
+ }
217
+ function attrs(identity, type) {
218
+ const result = {
219
+ ...type === "agent" ? { "xopc.localRoot": true } : {},
220
+ "langfuse.observation.type": type,
221
+ "xopc.configRevision": revision
222
+ };
223
+ for (const [key, value] of Object.entries(identity)) if (value) {
224
+ result[`xopc.${key}`] = value;
225
+ result[`langfuse.trace.metadata.${key}`] = value;
226
+ }
227
+ if (scopes.getStore()?.name) result["langfuse.trace.name"] = scopes.getStore().name;
228
+ if (identity.conversationId) result["langfuse.session.id"] = identity.conversationId;
229
+ return result;
230
+ }
231
+ function startObservation(name, type, identity = {}) {
232
+ const scope = scopes.getStore();
233
+ if (!(scope?.config ?? config).enabled || scope && ++scope.count > 1e3) {
234
+ if (scope?.count > 1e3) scope.root?.setAttribute("xopc.partialReason", "span_quota");
235
+ dropped++;
236
+ return {
237
+ run: (fn) => fn(),
238
+ finish() {},
239
+ input() {},
240
+ update() {}
241
+ };
242
+ }
243
+ const standalone = !scope;
244
+ if (standalone && active >= 256) {
245
+ dropped++;
246
+ return {
247
+ run: (fn) => fn(),
248
+ finish() {},
249
+ input() {},
250
+ update() {}
251
+ };
252
+ }
253
+ if (standalone) active++;
254
+ const span = tracer().startSpan(name.slice(0, 120), { attributes: attrs({
255
+ ...scope?.identity,
256
+ ...identity
257
+ }, type) });
258
+ const spanContext = trace.setSpan(context.active(), span).setValue(localEpochKey, localEpochs.get(span) ?? context.active().getValue(localEpochKey));
259
+ let ended = false;
260
+ const put = (key, value) => {
261
+ const policy = scope?.config ?? config;
262
+ if (policy.capture === "metadata") return;
263
+ const json = secretSafe(boundedJson(value, policy.capture === "detailed" && (policy.detailedUntil ?? 0) > Date.now() ? 65536 : 8192));
264
+ if (scope && (scope.bytes += Buffer.byteLength(json)) > policy.local.maxTraceKiB * 1024) {
265
+ span.setAttribute("xopc.partialReason", "capture_quota");
266
+ return;
267
+ }
268
+ span.setAttribute(key, json);
269
+ };
270
+ return {
271
+ span,
272
+ run: (fn) => context.with(spanContext, () => runWithLogContext({
273
+ ...identity,
274
+ ...traceIds()
275
+ }, fn)),
276
+ input: (value) => put("langfuse.observation.input", value),
277
+ update: (values) => {
278
+ for (const [key, value] of Object.entries(values)) if (value !== void 0) span.setAttribute(key, typeof value === "string" ? secretSafe(value.slice(0, 1024)) : value);
279
+ },
280
+ finish(status = "success", output) {
281
+ if (ended) return;
282
+ ended = true;
283
+ if (standalone) active--;
284
+ if (output !== void 0) put("langfuse.observation.output", output);
285
+ span.setAttribute("xopc.status", status);
286
+ span.setStatus({ code: status === "error" ? SpanStatusCode.ERROR : SpanStatusCode.OK });
287
+ span.end();
288
+ }
289
+ };
290
+ }
291
+ async function traceRun(name, identity, fn, input) {
292
+ if (scopes.getStore() || !config.enabled) return fn();
293
+ if (active >= 256) {
294
+ dropped++;
295
+ return scopes.run({
296
+ config: {
297
+ ...config,
298
+ enabled: false
299
+ },
300
+ identity,
301
+ name,
302
+ count: 0,
303
+ bytes: 0
304
+ }, fn);
305
+ }
306
+ active++;
307
+ const scope = {
308
+ config: structuredClone(config),
309
+ target,
310
+ identity,
311
+ name,
312
+ count: 0,
313
+ bytes: 0
314
+ };
315
+ try {
316
+ return await scopes.run(scope, async () => {
317
+ const observation = startObservation(name, "agent", identity);
318
+ scope.root = observation.span;
319
+ observation.input(input);
320
+ try {
321
+ const result = await observation.run(fn);
322
+ observation.finish(result.stopReason ? "suspended" : result.ok === false ? result.errorMessage === "aborted" ? "cancelled" : "error" : "success", result.lastAssistantText ?? result.errorMessage);
323
+ return result;
324
+ } catch (error) {
325
+ observation.finish("error", error instanceof Error ? error.message : String(error));
326
+ throw error;
327
+ }
328
+ });
329
+ } finally {
330
+ active--;
331
+ }
332
+ }
333
+ const tracedExecutions = /* @__PURE__ */ new WeakSet();
334
+ function traceTools(tools) {
335
+ return tools.map((tool) => {
336
+ if (tracedExecutions.has(tool.execute)) return tool;
337
+ const execute = (...args) => {
338
+ const observation = startObservation(`tool.${tool.name}`, "tool");
339
+ observation.update({ "xopc.toolCallId": String(args[0]) });
340
+ observation.input(args[1]);
341
+ return observation.run(async () => {
342
+ try {
343
+ const result = await tool.execute(...args);
344
+ observation.finish(result?.isError || result?.details?.isError ? "error" : "success", result);
345
+ return result;
346
+ } catch (error) {
347
+ observation.finish(args[2]?.aborted ? "cancelled" : "error", error instanceof Error ? error.message : String(error));
348
+ throw error;
349
+ }
350
+ });
351
+ };
352
+ tracedExecutions.add(execute);
353
+ return {
354
+ ...tool,
355
+ execute
356
+ };
357
+ });
358
+ }
359
+ async function flushTracing() {
360
+ const timer = new Promise((resolve) => {
361
+ setTimeout(resolve, 3e3).unref();
362
+ });
363
+ await Promise.race([(async () => {
364
+ await Promise.allSettled([...pendingLocal]);
365
+ await Promise.allSettled([store?.flush(), target?.flush()]);
366
+ })(), timer]);
367
+ }
368
+ async function testLangfuse() {
369
+ if (!target) return false;
370
+ const result = await traceRun("diagnostic.langfuse", {}, async () => ({ ok: true }));
371
+ await target.flush();
372
+ return result.ok && !target.status().lastError;
373
+ }
374
+ async function closeTracing() {
375
+ await flushTracing();
376
+ target?.close();
377
+ target = void 0;
378
+ targetSignature = "";
379
+ await store?.close();
380
+ store = void 0;
381
+ }
382
+ async function traceOperation(name, fn, attributes = {}) {
383
+ const observation = startObservation(name, "span");
384
+ observation.update(attributes);
385
+ try {
386
+ const result = await observation.run(fn);
387
+ observation.finish();
388
+ return result;
389
+ } catch (error) {
390
+ observation.finish("error", error instanceof Error ? error.message : String(error));
391
+ throw error;
392
+ }
393
+ }
394
+ function setTraceIdentity(identity) {
395
+ const scope = scopes.getStore();
396
+ if (!scope) return;
397
+ scope.identity = {
398
+ ...scope.identity,
399
+ ...identity
400
+ };
401
+ scope.root?.setAttributes(attrs(scope.identity, "agent"));
402
+ }
403
+ //#endregion
404
+ export { closeTracing, configureTracing, flushTracing, localStore, setTraceIdentity, startObservation, testLangfuse, traceIds, traceOperation, traceRun, traceTools, tracingConfig, tracingStatus };
@@ -0,0 +1,3 @@
1
+ export declare function redactString(value: string): string;
2
+ /** Bounds traversal before serializing; never materializes an entire tool/file payload. */
3
+ export declare function boundedJson(value: unknown, maxBytes?: number): string;