@sentry/core 10.47.0 → 10.48.0

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 (316) hide show
  1. package/build/cjs/attributes.js +43 -0
  2. package/build/cjs/attributes.js.map +1 -1
  3. package/build/cjs/client.js +13 -6
  4. package/build/cjs/client.js.map +1 -1
  5. package/build/cjs/envelope.js +4 -3
  6. package/build/cjs/envelope.js.map +1 -1
  7. package/build/cjs/index.js +44 -13
  8. package/build/cjs/index.js.map +1 -1
  9. package/build/cjs/integration.js +6 -0
  10. package/build/cjs/integration.js.map +1 -1
  11. package/build/cjs/integrations/express/index.js +206 -0
  12. package/build/cjs/integrations/express/index.js.map +1 -0
  13. package/build/cjs/integrations/express/patch-layer.js +251 -0
  14. package/build/cjs/integrations/express/patch-layer.js.map +1 -0
  15. package/build/cjs/integrations/express/request-layer-store.js +25 -0
  16. package/build/cjs/integrations/express/request-layer-store.js.map +1 -0
  17. package/build/cjs/integrations/express/set-sdk-processing-metadata.js +17 -0
  18. package/build/cjs/integrations/express/set-sdk-processing-metadata.js.map +1 -0
  19. package/build/cjs/integrations/express/types.js +17 -0
  20. package/build/cjs/integrations/express/types.js.map +1 -0
  21. package/build/cjs/integrations/express/utils.js +238 -0
  22. package/build/cjs/integrations/express/utils.js.map +1 -0
  23. package/build/cjs/integrations/mcp-server/correlation.js +5 -1
  24. package/build/cjs/integrations/mcp-server/correlation.js.map +1 -1
  25. package/build/cjs/integrations/mcp-server/handlers.js +18 -10
  26. package/build/cjs/integrations/mcp-server/handlers.js.map +1 -1
  27. package/build/cjs/integrations/mcp-server/index.js +2 -1
  28. package/build/cjs/integrations/mcp-server/index.js.map +1 -1
  29. package/build/cjs/integrations/mcp-server/transport.js +1 -1
  30. package/build/cjs/integrations/mcp-server/transport.js.map +1 -1
  31. package/build/cjs/integrations/mcp-server/validation.js +7 -5
  32. package/build/cjs/integrations/mcp-server/validation.js.map +1 -1
  33. package/build/cjs/integrations/spanStreaming.js +48 -0
  34. package/build/cjs/integrations/spanStreaming.js.map +1 -0
  35. package/build/cjs/semanticAttributes.js +35 -3
  36. package/build/cjs/semanticAttributes.js.map +1 -1
  37. package/build/cjs/tracing/ai/gen-ai-attributes.js +9 -65
  38. package/build/cjs/tracing/ai/gen-ai-attributes.js.map +1 -1
  39. package/build/cjs/tracing/ai/utils.js +50 -0
  40. package/build/cjs/tracing/ai/utils.js.map +1 -1
  41. package/build/cjs/tracing/anthropic-ai/index.js +1 -12
  42. package/build/cjs/tracing/anthropic-ai/index.js.map +1 -1
  43. package/build/cjs/tracing/anthropic-ai/streaming.js +2 -100
  44. package/build/cjs/tracing/anthropic-ai/streaming.js.map +1 -1
  45. package/build/cjs/tracing/dynamicSamplingContext.js +2 -1
  46. package/build/cjs/tracing/dynamicSamplingContext.js.map +1 -1
  47. package/build/cjs/tracing/google-genai/constants.js +1 -6
  48. package/build/cjs/tracing/google-genai/constants.js.map +1 -1
  49. package/build/cjs/tracing/google-genai/index.js +24 -30
  50. package/build/cjs/tracing/google-genai/index.js.map +1 -1
  51. package/build/cjs/tracing/google-genai/streaming.js +2 -23
  52. package/build/cjs/tracing/google-genai/streaming.js.map +1 -1
  53. package/build/cjs/tracing/langchain/embeddings.js +132 -0
  54. package/build/cjs/tracing/langchain/embeddings.js.map +1 -0
  55. package/build/cjs/tracing/langchain/index.js.map +1 -1
  56. package/build/cjs/tracing/openai/index.js +2 -29
  57. package/build/cjs/tracing/openai/index.js.map +1 -1
  58. package/build/cjs/tracing/openai/streaming.js +3 -34
  59. package/build/cjs/tracing/openai/streaming.js.map +1 -1
  60. package/build/cjs/tracing/openai/utils.js +78 -204
  61. package/build/cjs/tracing/openai/utils.js.map +1 -1
  62. package/build/cjs/tracing/sentryNonRecordingSpan.js +7 -0
  63. package/build/cjs/tracing/sentryNonRecordingSpan.js.map +1 -1
  64. package/build/cjs/tracing/sentrySpan.js +39 -0
  65. package/build/cjs/tracing/sentrySpan.js.map +1 -1
  66. package/build/cjs/tracing/spans/beforeSendSpan.js +43 -0
  67. package/build/cjs/tracing/spans/beforeSendSpan.js.map +1 -0
  68. package/build/cjs/tracing/spans/captureSpan.js +126 -0
  69. package/build/cjs/tracing/spans/captureSpan.js.map +1 -0
  70. package/build/cjs/tracing/spans/envelope.js +38 -0
  71. package/build/cjs/tracing/spans/envelope.js.map +1 -0
  72. package/build/cjs/tracing/spans/estimateSize.js +41 -0
  73. package/build/cjs/tracing/spans/estimateSize.js.map +1 -0
  74. package/build/cjs/tracing/spans/hasSpanStreamingEnabled.js +11 -0
  75. package/build/cjs/tracing/spans/hasSpanStreamingEnabled.js.map +1 -0
  76. package/build/cjs/tracing/spans/spanBuffer.js +158 -0
  77. package/build/cjs/tracing/spans/spanBuffer.js.map +1 -0
  78. package/build/cjs/tracing/trace.js +83 -13
  79. package/build/cjs/tracing/trace.js.map +1 -1
  80. package/build/cjs/tracing/vercel-ai/utils.js +1 -4
  81. package/build/cjs/tracing/vercel-ai/utils.js.map +1 -1
  82. package/build/cjs/utils/featureFlags.js +6 -0
  83. package/build/cjs/utils/featureFlags.js.map +1 -1
  84. package/build/cjs/utils/object.js +33 -0
  85. package/build/cjs/utils/object.js.map +1 -1
  86. package/build/cjs/utils/spanUtils.js +116 -13
  87. package/build/cjs/utils/spanUtils.js.map +1 -1
  88. package/build/cjs/utils/stacktrace.js +3 -1
  89. package/build/cjs/utils/stacktrace.js.map +1 -1
  90. package/build/cjs/utils/string.js +3 -0
  91. package/build/cjs/utils/string.js.map +1 -1
  92. package/build/cjs/utils/version.js +1 -1
  93. package/build/esm/attributes.js +43 -1
  94. package/build/esm/attributes.js.map +1 -1
  95. package/build/esm/client.js +8 -1
  96. package/build/esm/client.js.map +1 -1
  97. package/build/esm/envelope.js +2 -1
  98. package/build/esm/envelope.js.map +1 -1
  99. package/build/esm/index.js +10 -2
  100. package/build/esm/index.js.map +1 -1
  101. package/build/esm/integration.js +6 -0
  102. package/build/esm/integration.js.map +1 -1
  103. package/build/esm/integrations/express/index.js +202 -0
  104. package/build/esm/integrations/express/index.js.map +1 -0
  105. package/build/esm/integrations/express/patch-layer.js +249 -0
  106. package/build/esm/integrations/express/patch-layer.js.map +1 -0
  107. package/build/esm/integrations/express/request-layer-store.js +22 -0
  108. package/build/esm/integrations/express/request-layer-store.js.map +1 -0
  109. package/build/esm/integrations/express/set-sdk-processing-metadata.js +15 -0
  110. package/build/esm/integrations/express/set-sdk-processing-metadata.js.map +1 -0
  111. package/build/esm/integrations/express/types.js +10 -0
  112. package/build/esm/integrations/express/types.js.map +1 -0
  113. package/build/esm/integrations/express/utils.js +225 -0
  114. package/build/esm/integrations/express/utils.js.map +1 -0
  115. package/build/esm/integrations/mcp-server/correlation.js +5 -1
  116. package/build/esm/integrations/mcp-server/correlation.js.map +1 -1
  117. package/build/esm/integrations/mcp-server/handlers.js +18 -10
  118. package/build/esm/integrations/mcp-server/handlers.js.map +1 -1
  119. package/build/esm/integrations/mcp-server/index.js +2 -1
  120. package/build/esm/integrations/mcp-server/index.js.map +1 -1
  121. package/build/esm/integrations/mcp-server/transport.js +1 -1
  122. package/build/esm/integrations/mcp-server/transport.js.map +1 -1
  123. package/build/esm/integrations/mcp-server/validation.js +7 -5
  124. package/build/esm/integrations/mcp-server/validation.js.map +1 -1
  125. package/build/esm/integrations/spanStreaming.js +46 -0
  126. package/build/esm/integrations/spanStreaming.js.map +1 -0
  127. package/build/esm/package.json +1 -1
  128. package/build/esm/semanticAttributes.js +26 -4
  129. package/build/esm/semanticAttributes.js.map +1 -1
  130. package/build/esm/tracing/ai/gen-ai-attributes.js +8 -56
  131. package/build/esm/tracing/ai/gen-ai-attributes.js.map +1 -1
  132. package/build/esm/tracing/ai/utils.js +51 -2
  133. package/build/esm/tracing/ai/utils.js.map +1 -1
  134. package/build/esm/tracing/anthropic-ai/index.js +2 -13
  135. package/build/esm/tracing/anthropic-ai/index.js.map +1 -1
  136. package/build/esm/tracing/anthropic-ai/streaming.js +3 -101
  137. package/build/esm/tracing/anthropic-ai/streaming.js.map +1 -1
  138. package/build/esm/tracing/dynamicSamplingContext.js +2 -1
  139. package/build/esm/tracing/dynamicSamplingContext.js.map +1 -1
  140. package/build/esm/tracing/google-genai/constants.js +2 -5
  141. package/build/esm/tracing/google-genai/constants.js.map +1 -1
  142. package/build/esm/tracing/google-genai/index.js +25 -31
  143. package/build/esm/tracing/google-genai/index.js.map +1 -1
  144. package/build/esm/tracing/google-genai/streaming.js +2 -23
  145. package/build/esm/tracing/google-genai/streaming.js.map +1 -1
  146. package/build/esm/tracing/langchain/embeddings.js +129 -0
  147. package/build/esm/tracing/langchain/embeddings.js.map +1 -0
  148. package/build/esm/tracing/langchain/index.js.map +1 -1
  149. package/build/esm/tracing/openai/index.js +3 -30
  150. package/build/esm/tracing/openai/index.js.map +1 -1
  151. package/build/esm/tracing/openai/streaming.js +4 -35
  152. package/build/esm/tracing/openai/streaming.js.map +1 -1
  153. package/build/esm/tracing/openai/utils.js +79 -196
  154. package/build/esm/tracing/openai/utils.js.map +1 -1
  155. package/build/esm/tracing/sentryNonRecordingSpan.js +7 -0
  156. package/build/esm/tracing/sentryNonRecordingSpan.js.map +1 -1
  157. package/build/esm/tracing/sentrySpan.js +40 -1
  158. package/build/esm/tracing/sentrySpan.js.map +1 -1
  159. package/build/esm/tracing/spans/beforeSendSpan.js +40 -0
  160. package/build/esm/tracing/spans/beforeSendSpan.js.map +1 -0
  161. package/build/esm/tracing/spans/captureSpan.js +122 -0
  162. package/build/esm/tracing/spans/captureSpan.js.map +1 -0
  163. package/build/esm/tracing/spans/envelope.js +36 -0
  164. package/build/esm/tracing/spans/envelope.js.map +1 -0
  165. package/build/esm/tracing/spans/estimateSize.js +39 -0
  166. package/build/esm/tracing/spans/estimateSize.js.map +1 -0
  167. package/build/esm/tracing/spans/hasSpanStreamingEnabled.js +9 -0
  168. package/build/esm/tracing/spans/hasSpanStreamingEnabled.js.map +1 -0
  169. package/build/esm/tracing/spans/spanBuffer.js +156 -0
  170. package/build/esm/tracing/spans/spanBuffer.js.map +1 -0
  171. package/build/esm/tracing/trace.js +84 -14
  172. package/build/esm/tracing/trace.js.map +1 -1
  173. package/build/esm/tracing/vercel-ai/utils.js +2 -5
  174. package/build/esm/tracing/vercel-ai/utils.js.map +1 -1
  175. package/build/esm/utils/featureFlags.js +6 -0
  176. package/build/esm/utils/featureFlags.js.map +1 -1
  177. package/build/esm/utils/object.js +33 -1
  178. package/build/esm/utils/object.js.map +1 -1
  179. package/build/esm/utils/spanUtils.js +112 -14
  180. package/build/esm/utils/spanUtils.js.map +1 -1
  181. package/build/esm/utils/stacktrace.js +3 -1
  182. package/build/esm/utils/stacktrace.js.map +1 -1
  183. package/build/esm/utils/string.js +3 -0
  184. package/build/esm/utils/string.js.map +1 -1
  185. package/build/esm/utils/version.js +1 -1
  186. package/build/types/attributes.d.ts +5 -0
  187. package/build/types/attributes.d.ts.map +1 -1
  188. package/build/types/client.d.ts +35 -1
  189. package/build/types/client.d.ts.map +1 -1
  190. package/build/types/envelope.d.ts.map +1 -1
  191. package/build/types/index.d.ts +12 -4
  192. package/build/types/index.d.ts.map +1 -1
  193. package/build/types/integration.d.ts.map +1 -1
  194. package/build/types/integrations/express/index.d.ts +75 -0
  195. package/build/types/integrations/express/index.d.ts.map +1 -0
  196. package/build/types/integrations/express/patch-layer.d.ts +32 -0
  197. package/build/types/integrations/express/patch-layer.d.ts.map +1 -0
  198. package/build/types/integrations/express/request-layer-store.d.ts +32 -0
  199. package/build/types/integrations/express/request-layer-store.d.ts.map +1 -0
  200. package/build/types/integrations/express/set-sdk-processing-metadata.d.ts +35 -0
  201. package/build/types/integrations/express/set-sdk-processing-metadata.d.ts.map +1 -0
  202. package/build/types/integrations/express/types.d.ts +154 -0
  203. package/build/types/integrations/express/types.d.ts.map +1 -0
  204. package/build/types/integrations/express/utils.d.ts +93 -0
  205. package/build/types/integrations/express/utils.d.ts.map +1 -0
  206. package/build/types/integrations/mcp-server/correlation.d.ts +2 -1
  207. package/build/types/integrations/mcp-server/correlation.d.ts.map +1 -1
  208. package/build/types/integrations/mcp-server/handlers.d.ts +9 -4
  209. package/build/types/integrations/mcp-server/handlers.d.ts.map +1 -1
  210. package/build/types/integrations/mcp-server/index.d.ts +2 -1
  211. package/build/types/integrations/mcp-server/index.d.ts.map +1 -1
  212. package/build/types/integrations/mcp-server/types.d.ts +40 -7
  213. package/build/types/integrations/mcp-server/types.d.ts.map +1 -1
  214. package/build/types/integrations/mcp-server/validation.d.ts +4 -1
  215. package/build/types/integrations/mcp-server/validation.d.ts.map +1 -1
  216. package/build/types/integrations/spanStreaming.d.ts +2 -0
  217. package/build/types/integrations/spanStreaming.d.ts.map +1 -0
  218. package/build/types/semanticAttributes.d.ts +23 -3
  219. package/build/types/semanticAttributes.d.ts.map +1 -1
  220. package/build/types/tracing/ai/gen-ai-attributes.d.ts +6 -38
  221. package/build/types/tracing/ai/gen-ai-attributes.d.ts.map +1 -1
  222. package/build/types/tracing/ai/utils.d.ts +21 -2
  223. package/build/types/tracing/ai/utils.d.ts.map +1 -1
  224. package/build/types/tracing/anthropic-ai/index.d.ts.map +1 -1
  225. package/build/types/tracing/anthropic-ai/streaming.d.ts.map +1 -1
  226. package/build/types/tracing/dynamicSamplingContext.d.ts.map +1 -1
  227. package/build/types/tracing/google-genai/constants.d.ts +1 -3
  228. package/build/types/tracing/google-genai/constants.d.ts.map +1 -1
  229. package/build/types/tracing/google-genai/index.d.ts.map +1 -1
  230. package/build/types/tracing/google-genai/streaming.d.ts.map +1 -1
  231. package/build/types/tracing/index.d.ts +1 -0
  232. package/build/types/tracing/index.d.ts.map +1 -1
  233. package/build/types/tracing/langchain/embeddings.d.ts +27 -0
  234. package/build/types/tracing/langchain/embeddings.d.ts.map +1 -0
  235. package/build/types/tracing/langchain/index.d.ts +1 -0
  236. package/build/types/tracing/langchain/index.d.ts.map +1 -1
  237. package/build/types/tracing/openai/index.d.ts.map +1 -1
  238. package/build/types/tracing/openai/streaming.d.ts.map +1 -1
  239. package/build/types/tracing/openai/utils.d.ts +4 -49
  240. package/build/types/tracing/openai/utils.d.ts.map +1 -1
  241. package/build/types/tracing/sentryNonRecordingSpan.d.ts +12 -1
  242. package/build/types/tracing/sentryNonRecordingSpan.d.ts.map +1 -1
  243. package/build/types/tracing/sentrySpan.d.ts +10 -1
  244. package/build/types/tracing/sentrySpan.d.ts.map +1 -1
  245. package/build/types/tracing/spans/beforeSendSpan.d.ts +35 -0
  246. package/build/types/tracing/spans/beforeSendSpan.d.ts.map +1 -0
  247. package/build/types/tracing/spans/captureSpan.d.ts +26 -0
  248. package/build/types/tracing/spans/captureSpan.d.ts.map +1 -0
  249. package/build/types/tracing/spans/envelope.d.ts +8 -0
  250. package/build/types/tracing/spans/envelope.d.ts.map +1 -0
  251. package/build/types/tracing/spans/estimateSize.d.ts +12 -0
  252. package/build/types/tracing/spans/estimateSize.d.ts.map +1 -0
  253. package/build/types/tracing/spans/hasSpanStreamingEnabled.d.ts +6 -0
  254. package/build/types/tracing/spans/hasSpanStreamingEnabled.d.ts.map +1 -0
  255. package/build/types/tracing/spans/spanBuffer.d.ts +60 -0
  256. package/build/types/tracing/spans/spanBuffer.d.ts.map +1 -0
  257. package/build/types/tracing/trace.d.ts.map +1 -1
  258. package/build/types/tracing/vercel-ai/utils.d.ts.map +1 -1
  259. package/build/types/types-hoist/envelope.d.ts +22 -2
  260. package/build/types/types-hoist/envelope.d.ts.map +1 -1
  261. package/build/types/types-hoist/integration.d.ts +8 -0
  262. package/build/types/types-hoist/integration.d.ts.map +1 -1
  263. package/build/types/types-hoist/link.d.ts +2 -2
  264. package/build/types/types-hoist/link.d.ts.map +1 -1
  265. package/build/types/types-hoist/options.d.ts +26 -2
  266. package/build/types/types-hoist/options.d.ts.map +1 -1
  267. package/build/types/types-hoist/span.d.ts +35 -0
  268. package/build/types/types-hoist/span.d.ts.map +1 -1
  269. package/build/types/utils/featureFlags.d.ts.map +1 -1
  270. package/build/types/utils/object.d.ts +10 -0
  271. package/build/types/utils/object.d.ts.map +1 -1
  272. package/build/types/utils/spanUtils.d.ts +27 -2
  273. package/build/types/utils/spanUtils.d.ts.map +1 -1
  274. package/build/types/utils/stacktrace.d.ts.map +1 -1
  275. package/build/types/utils/string.d.ts +2 -2
  276. package/build/types/utils/string.d.ts.map +1 -1
  277. package/build/types-ts3.8/attributes.d.ts +5 -0
  278. package/build/types-ts3.8/client.d.ts +35 -1
  279. package/build/types-ts3.8/index.d.ts +12 -4
  280. package/build/types-ts3.8/integrations/express/index.d.ts +75 -0
  281. package/build/types-ts3.8/integrations/express/patch-layer.d.ts +32 -0
  282. package/build/types-ts3.8/integrations/express/request-layer-store.d.ts +32 -0
  283. package/build/types-ts3.8/integrations/express/set-sdk-processing-metadata.d.ts +35 -0
  284. package/build/types-ts3.8/integrations/express/types.d.ts +154 -0
  285. package/build/types-ts3.8/integrations/express/utils.d.ts +96 -0
  286. package/build/types-ts3.8/integrations/mcp-server/correlation.d.ts +2 -1
  287. package/build/types-ts3.8/integrations/mcp-server/handlers.d.ts +9 -4
  288. package/build/types-ts3.8/integrations/mcp-server/index.d.ts +2 -1
  289. package/build/types-ts3.8/integrations/mcp-server/types.d.ts +40 -7
  290. package/build/types-ts3.8/integrations/mcp-server/validation.d.ts +4 -1
  291. package/build/types-ts3.8/integrations/spanStreaming.d.ts +2 -0
  292. package/build/types-ts3.8/semanticAttributes.d.ts +23 -3
  293. package/build/types-ts3.8/tracing/ai/gen-ai-attributes.d.ts +6 -38
  294. package/build/types-ts3.8/tracing/ai/utils.d.ts +21 -2
  295. package/build/types-ts3.8/tracing/google-genai/constants.d.ts +1 -3
  296. package/build/types-ts3.8/tracing/index.d.ts +1 -0
  297. package/build/types-ts3.8/tracing/langchain/embeddings.d.ts +27 -0
  298. package/build/types-ts3.8/tracing/langchain/index.d.ts +1 -0
  299. package/build/types-ts3.8/tracing/openai/utils.d.ts +4 -49
  300. package/build/types-ts3.8/tracing/sentryNonRecordingSpan.d.ts +12 -1
  301. package/build/types-ts3.8/tracing/sentrySpan.d.ts +10 -1
  302. package/build/types-ts3.8/tracing/spans/beforeSendSpan.d.ts +35 -0
  303. package/build/types-ts3.8/tracing/spans/captureSpan.d.ts +26 -0
  304. package/build/types-ts3.8/tracing/spans/envelope.d.ts +8 -0
  305. package/build/types-ts3.8/tracing/spans/estimateSize.d.ts +12 -0
  306. package/build/types-ts3.8/tracing/spans/hasSpanStreamingEnabled.d.ts +6 -0
  307. package/build/types-ts3.8/tracing/spans/spanBuffer.d.ts +60 -0
  308. package/build/types-ts3.8/types-hoist/envelope.d.ts +22 -2
  309. package/build/types-ts3.8/types-hoist/integration.d.ts +8 -0
  310. package/build/types-ts3.8/types-hoist/link.d.ts +2 -2
  311. package/build/types-ts3.8/types-hoist/options.d.ts +26 -2
  312. package/build/types-ts3.8/types-hoist/span.d.ts +35 -0
  313. package/build/types-ts3.8/utils/object.d.ts +10 -0
  314. package/build/types-ts3.8/utils/spanUtils.d.ts +27 -2
  315. package/build/types-ts3.8/utils/string.d.ts +2 -2
  316. package/package.json +1 -1
@@ -0,0 +1,132 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ const _exports = require('../../exports.js');
4
+ const semanticAttributes = require('../../semanticAttributes.js');
5
+ const trace = require('../trace.js');
6
+ const genAiAttributes = require('../ai/gen-ai-attributes.js');
7
+ const utils = require('../ai/utils.js');
8
+ const constants = require('./constants.js');
9
+
10
+ /**
11
+ * Infers the AI provider system name from the embedding class instance.
12
+ */
13
+ function inferSystemFromInstance(instance) {
14
+ const name = (instance.constructor )?.name ?? '';
15
+ if (name.includes('OpenAI')) return 'openai';
16
+ if (name.includes('Google')) return 'google_genai';
17
+ if (name.includes('Mistral')) return 'mistralai';
18
+ if (name.includes('Vertex')) return 'google_vertexai';
19
+ if (name.includes('Bedrock')) return 'aws_bedrock';
20
+ if (name.includes('Ollama')) return 'ollama';
21
+ if (name.includes('Cloudflare')) return 'cloudflare';
22
+ if (name.includes('Cohere')) return 'cohere';
23
+ return 'langchain';
24
+ }
25
+
26
+ /**
27
+ * Extracts span attributes from a LangChain embedding class instance.
28
+ */
29
+ function extractEmbeddingAttributes(instance) {
30
+ const embeddingsInstance = (instance ?? {}) ;
31
+
32
+ const attributes = {
33
+ [semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: constants.LANGCHAIN_ORIGIN,
34
+ [semanticAttributes.SEMANTIC_ATTRIBUTE_SENTRY_OP]: genAiAttributes.GEN_AI_EMBEDDINGS_OPERATION_ATTRIBUTE,
35
+ [genAiAttributes.GEN_AI_OPERATION_NAME_ATTRIBUTE]: 'embeddings',
36
+ [genAiAttributes.GEN_AI_REQUEST_MODEL_ATTRIBUTE]: embeddingsInstance.model ?? 'unknown',
37
+ };
38
+
39
+ attributes[genAiAttributes.GEN_AI_SYSTEM_ATTRIBUTE] = inferSystemFromInstance(embeddingsInstance);
40
+ if ('dimensions' in embeddingsInstance) {
41
+ attributes[genAiAttributes.GEN_AI_REQUEST_DIMENSIONS_ATTRIBUTE] = embeddingsInstance.dimensions;
42
+ }
43
+ if ('encodingFormat' in embeddingsInstance) {
44
+ attributes[genAiAttributes.GEN_AI_REQUEST_ENCODING_FORMAT_ATTRIBUTE] = embeddingsInstance.encodingFormat;
45
+ }
46
+
47
+ return attributes;
48
+ }
49
+
50
+ /**
51
+ * Wraps a LangChain embedding method (embedQuery or embedDocuments) to create Sentry spans.
52
+ *
53
+ * Used internally by the Node.js auto-instrumentation to patch embedding class prototypes.
54
+ */
55
+ function instrumentEmbeddingMethod(
56
+ originalMethod,
57
+ options = {},
58
+ ) {
59
+ const { recordInputs } = utils.resolveAIRecordingOptions(options);
60
+
61
+ return new Proxy(originalMethod, {
62
+ apply(target, thisArg, args) {
63
+ const attributes = extractEmbeddingAttributes(thisArg);
64
+ const modelName = attributes[genAiAttributes.GEN_AI_REQUEST_MODEL_ATTRIBUTE] || 'unknown';
65
+
66
+ if (recordInputs) {
67
+ const input = args[0];
68
+ if (input != null) {
69
+ attributes[genAiAttributes.GEN_AI_EMBEDDINGS_INPUT_ATTRIBUTE] = typeof input === 'string' ? input : JSON.stringify(input);
70
+ }
71
+ }
72
+
73
+ return trace.startSpan(
74
+ {
75
+ name: `embeddings ${modelName}`,
76
+ op: genAiAttributes.GEN_AI_EMBEDDINGS_OPERATION_ATTRIBUTE,
77
+ attributes: attributes ,
78
+ },
79
+ () => {
80
+ return Reflect.apply(target, thisArg, args).then(undefined, error => {
81
+ _exports.captureException(error, {
82
+ mechanism: { handled: false, type: 'auto.ai.langchain' },
83
+ });
84
+ throw error;
85
+ });
86
+ },
87
+ );
88
+ },
89
+ }) ;
90
+ }
91
+
92
+ /**
93
+ * Wraps a LangChain embeddings instance to create Sentry spans for `embedQuery` and `embedDocuments` calls.
94
+ *
95
+ * Use this in non-Node runtimes (Cloudflare, browser, etc.) where auto-instrumentation is not available.
96
+ *
97
+ * @example
98
+ * ```javascript
99
+ * import * as Sentry from '@sentry/cloudflare';
100
+ * import { OpenAIEmbeddings } from '@langchain/openai';
101
+ *
102
+ * const embeddings = Sentry.instrumentLangChainEmbeddings(
103
+ * new OpenAIEmbeddings({ model: 'text-embedding-3-small' })
104
+ * );
105
+ *
106
+ * await embeddings.embedQuery('Hello world');
107
+ * await embeddings.embedDocuments(['doc1', 'doc2']);
108
+ * ```
109
+ */
110
+ function instrumentLangChainEmbeddings(instance, options) {
111
+ const embeddingsInstance = instance ;
112
+
113
+ if (typeof embeddingsInstance.embedQuery === 'function') {
114
+ embeddingsInstance.embedQuery = instrumentEmbeddingMethod(
115
+ embeddingsInstance.embedQuery ,
116
+ options,
117
+ );
118
+ }
119
+
120
+ if (typeof embeddingsInstance.embedDocuments === 'function') {
121
+ embeddingsInstance.embedDocuments = instrumentEmbeddingMethod(
122
+ embeddingsInstance.embedDocuments ,
123
+ options,
124
+ );
125
+ }
126
+
127
+ return instance;
128
+ }
129
+
130
+ exports.instrumentEmbeddingMethod = instrumentEmbeddingMethod;
131
+ exports.instrumentLangChainEmbeddings = instrumentLangChainEmbeddings;
132
+ //# sourceMappingURL=embeddings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embeddings.js","sources":["../../../../src/tracing/langchain/embeddings.ts"],"sourcesContent":["import { captureException } from '../../exports';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../../semanticAttributes';\nimport { startSpan } from '../../tracing/trace';\nimport type { SpanAttributeValue } from '../../types-hoist/span';\nimport {\n GEN_AI_EMBEDDINGS_OPERATION_ATTRIBUTE,\n GEN_AI_EMBEDDINGS_INPUT_ATTRIBUTE,\n GEN_AI_OPERATION_NAME_ATTRIBUTE,\n GEN_AI_REQUEST_DIMENSIONS_ATTRIBUTE,\n GEN_AI_REQUEST_ENCODING_FORMAT_ATTRIBUTE,\n GEN_AI_REQUEST_MODEL_ATTRIBUTE,\n GEN_AI_SYSTEM_ATTRIBUTE,\n} from '../ai/gen-ai-attributes';\nimport { resolveAIRecordingOptions } from '../ai/utils';\nimport { LANGCHAIN_ORIGIN } from './constants';\nimport type { LangChainOptions } from './types';\n\n/**\n * Infers the AI provider system name from the embedding class instance.\n */\nfunction inferSystemFromInstance(instance: Record<string, unknown>): string {\n const name = (instance.constructor as { name?: string })?.name ?? '';\n if (name.includes('OpenAI')) return 'openai';\n if (name.includes('Google')) return 'google_genai';\n if (name.includes('Mistral')) return 'mistralai';\n if (name.includes('Vertex')) return 'google_vertexai';\n if (name.includes('Bedrock')) return 'aws_bedrock';\n if (name.includes('Ollama')) return 'ollama';\n if (name.includes('Cloudflare')) return 'cloudflare';\n if (name.includes('Cohere')) return 'cohere';\n return 'langchain';\n}\n\n/**\n * Extracts span attributes from a LangChain embedding class instance.\n */\nfunction extractEmbeddingAttributes(instance: unknown): Record<string, unknown> {\n const embeddingsInstance = (instance ?? {}) as Record<string, unknown>;\n\n const attributes: Record<string, unknown> = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: LANGCHAIN_ORIGIN,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: GEN_AI_EMBEDDINGS_OPERATION_ATTRIBUTE,\n [GEN_AI_OPERATION_NAME_ATTRIBUTE]: 'embeddings',\n [GEN_AI_REQUEST_MODEL_ATTRIBUTE]: embeddingsInstance.model ?? 'unknown',\n };\n\n attributes[GEN_AI_SYSTEM_ATTRIBUTE] = inferSystemFromInstance(embeddingsInstance);\n if ('dimensions' in embeddingsInstance) {\n attributes[GEN_AI_REQUEST_DIMENSIONS_ATTRIBUTE] = embeddingsInstance.dimensions;\n }\n if ('encodingFormat' in embeddingsInstance) {\n attributes[GEN_AI_REQUEST_ENCODING_FORMAT_ATTRIBUTE] = embeddingsInstance.encodingFormat;\n }\n\n return attributes;\n}\n\n/**\n * Wraps a LangChain embedding method (embedQuery or embedDocuments) to create Sentry spans.\n *\n * Used internally by the Node.js auto-instrumentation to patch embedding class prototypes.\n */\nexport function instrumentEmbeddingMethod(\n originalMethod: (...args: unknown[]) => Promise<unknown>,\n options: LangChainOptions = {},\n): (...args: unknown[]) => Promise<unknown> {\n const { recordInputs } = resolveAIRecordingOptions(options);\n\n return new Proxy(originalMethod, {\n apply(target, thisArg, args: unknown[]): Promise<unknown> {\n const attributes = extractEmbeddingAttributes(thisArg);\n const modelName = attributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] || 'unknown';\n\n if (recordInputs) {\n const input = args[0];\n if (input != null) {\n attributes[GEN_AI_EMBEDDINGS_INPUT_ATTRIBUTE] = typeof input === 'string' ? input : JSON.stringify(input);\n }\n }\n\n return startSpan(\n {\n name: `embeddings ${modelName}`,\n op: GEN_AI_EMBEDDINGS_OPERATION_ATTRIBUTE,\n attributes: attributes as Record<string, SpanAttributeValue>,\n },\n () => {\n return Reflect.apply(target, thisArg, args).then(undefined, error => {\n captureException(error, {\n mechanism: { handled: false, type: 'auto.ai.langchain' },\n });\n throw error;\n });\n },\n );\n },\n }) as (...args: unknown[]) => Promise<unknown>;\n}\n\n/**\n * Wraps a LangChain embeddings instance to create Sentry spans for `embedQuery` and `embedDocuments` calls.\n *\n * Use this in non-Node runtimes (Cloudflare, browser, etc.) where auto-instrumentation is not available.\n *\n * @example\n * ```javascript\n * import * as Sentry from '@sentry/cloudflare';\n * import { OpenAIEmbeddings } from '@langchain/openai';\n *\n * const embeddings = Sentry.instrumentLangChainEmbeddings(\n * new OpenAIEmbeddings({ model: 'text-embedding-3-small' })\n * );\n *\n * await embeddings.embedQuery('Hello world');\n * await embeddings.embedDocuments(['doc1', 'doc2']);\n * ```\n */\nexport function instrumentLangChainEmbeddings<T extends object>(instance: T, options?: LangChainOptions): T {\n const embeddingsInstance = instance as Record<string, unknown>;\n\n if (typeof embeddingsInstance.embedQuery === 'function') {\n embeddingsInstance.embedQuery = instrumentEmbeddingMethod(\n embeddingsInstance.embedQuery as (...args: unknown[]) => Promise<unknown>,\n options,\n );\n }\n\n if (typeof embeddingsInstance.embedDocuments === 'function') {\n embeddingsInstance.embedDocuments = instrumentEmbeddingMethod(\n embeddingsInstance.embedDocuments as (...args: unknown[]) => Promise<unknown>,\n options,\n );\n }\n\n return instance;\n}\n"],"names":["SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","LANGCHAIN_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_OP","GEN_AI_EMBEDDINGS_OPERATION_ATTRIBUTE","GEN_AI_OPERATION_NAME_ATTRIBUTE","GEN_AI_REQUEST_MODEL_ATTRIBUTE","GEN_AI_SYSTEM_ATTRIBUTE","GEN_AI_REQUEST_DIMENSIONS_ATTRIBUTE","GEN_AI_REQUEST_ENCODING_FORMAT_ATTRIBUTE","resolveAIRecordingOptions","GEN_AI_EMBEDDINGS_INPUT_ATTRIBUTE","startSpan","captureException"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../src/tracing/langchain/index.ts"],"sourcesContent":["import { captureException } from '../../exports';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../../semanticAttributes';\nimport { SPAN_STATUS_ERROR } from '../../tracing';\nimport { startSpanManual } from '../../tracing/trace';\nimport type { Span, SpanAttributeValue } from '../../types-hoist/span';\nimport {\n GEN_AI_OPERATION_NAME_ATTRIBUTE,\n GEN_AI_REQUEST_MODEL_ATTRIBUTE,\n GEN_AI_TOOL_INPUT_ATTRIBUTE,\n GEN_AI_TOOL_NAME_ATTRIBUTE,\n GEN_AI_TOOL_OUTPUT_ATTRIBUTE,\n} from '../ai/gen-ai-attributes';\nimport { resolveAIRecordingOptions } from '../ai/utils';\nimport { LANGCHAIN_ORIGIN } from './constants';\nimport type {\n LangChainCallbackHandler,\n LangChainLLMResult,\n LangChainMessage,\n LangChainOptions,\n LangChainSerialized,\n} from './types';\nimport {\n extractChatModelRequestAttributes,\n extractLLMRequestAttributes,\n extractLlmResponseAttributes,\n getInvocationParams,\n} from './utils';\n\n/**\n * Creates a Sentry callback handler for LangChain\n * Returns a plain object that LangChain will call via duck-typing\n *\n * This is a stateful handler that tracks spans across multiple LangChain executions.\n */\nexport function createLangChainCallbackHandler(options: LangChainOptions = {}): LangChainCallbackHandler {\n const { recordInputs, recordOutputs } = resolveAIRecordingOptions(options);\n\n // Internal state - single instance tracks all spans\n const spanMap = new Map<string, Span>();\n\n /**\n * Exit a span and clean up\n */\n const exitSpan = (runId: string): void => {\n const span = spanMap.get(runId);\n if (span?.isRecording()) {\n span.end();\n spanMap.delete(runId);\n }\n };\n\n /**\n * Handler for LLM Start\n * This handler will be called by LangChain's callback handler when an LLM event is detected.\n */\n const handler: LangChainCallbackHandler = {\n // Required LangChain BaseCallbackHandler properties\n lc_serializable: false,\n lc_namespace: ['langchain_core', 'callbacks', 'sentry'],\n lc_secrets: undefined,\n lc_attributes: undefined,\n lc_aliases: undefined,\n lc_serializable_keys: undefined,\n lc_id: ['langchain_core', 'callbacks', 'sentry'],\n lc_kwargs: {},\n name: 'SentryCallbackHandler',\n\n // BaseCallbackHandlerInput boolean flags\n ignoreLLM: false,\n ignoreChain: false,\n ignoreAgent: false,\n ignoreRetriever: false,\n ignoreCustomEvent: false,\n raiseError: false,\n awaitHandlers: true,\n\n handleLLMStart(\n llm: unknown,\n prompts: string[],\n runId: string,\n _parentRunId?: string,\n _extraParams?: Record<string, unknown>,\n tags?: string[],\n metadata?: Record<string, unknown>,\n _runName?: string,\n ) {\n const invocationParams = getInvocationParams(tags);\n const attributes = extractLLMRequestAttributes(\n llm as LangChainSerialized,\n prompts,\n recordInputs,\n invocationParams,\n metadata,\n );\n const modelName = attributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE];\n const operationName = attributes[GEN_AI_OPERATION_NAME_ATTRIBUTE];\n\n startSpanManual(\n {\n name: `${operationName} ${modelName}`,\n op: 'gen_ai.chat',\n attributes: {\n ...attributes,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'gen_ai.chat',\n },\n },\n span => {\n spanMap.set(runId, span);\n return span;\n },\n );\n },\n\n // Chat Model Start Handler\n handleChatModelStart(\n llm: unknown,\n messages: unknown,\n runId: string,\n _parentRunId?: string,\n _extraParams?: Record<string, unknown>,\n tags?: string[],\n metadata?: Record<string, unknown>,\n _runName?: string,\n ) {\n const invocationParams = getInvocationParams(tags);\n const attributes = extractChatModelRequestAttributes(\n llm as LangChainSerialized,\n messages as LangChainMessage[][],\n recordInputs,\n invocationParams,\n metadata,\n );\n const modelName = attributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE];\n const operationName = attributes[GEN_AI_OPERATION_NAME_ATTRIBUTE];\n\n startSpanManual(\n {\n name: `${operationName} ${modelName}`,\n op: 'gen_ai.chat',\n attributes: {\n ...attributes,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'gen_ai.chat',\n },\n },\n span => {\n spanMap.set(runId, span);\n return span;\n },\n );\n },\n\n // LLM End Handler - note: handleLLMEnd with capital LLM (used by both LLMs and chat models!)\n handleLLMEnd(\n output: unknown,\n runId: string,\n _parentRunId?: string,\n _tags?: string[],\n _extraParams?: Record<string, unknown>,\n ) {\n const span = spanMap.get(runId);\n if (span?.isRecording()) {\n const attributes = extractLlmResponseAttributes(output as LangChainLLMResult, recordOutputs);\n if (attributes) {\n span.setAttributes(attributes);\n }\n exitSpan(runId);\n }\n },\n\n // LLM Error Handler - note: handleLLMError with capital LLM\n handleLLMError(error: Error, runId: string) {\n const span = spanMap.get(runId);\n if (span?.isRecording()) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n exitSpan(runId);\n }\n\n captureException(error, {\n mechanism: {\n handled: false,\n type: `${LANGCHAIN_ORIGIN}.llm_error_handler`,\n },\n });\n },\n\n // Chain Start Handler\n handleChainStart(\n chain: { name?: string },\n inputs: Record<string, unknown>,\n runId: string,\n _parentRunId?: string,\n _tags?: string[],\n _metadata?: Record<string, unknown>,\n _runType?: string,\n runName?: string,\n ) {\n const chainName = runName || chain.name || 'unknown_chain';\n const attributes: Record<string, SpanAttributeValue> = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ai.langchain',\n 'langchain.chain.name': chainName,\n };\n\n // Add inputs if recordInputs is enabled\n if (recordInputs) {\n attributes['langchain.chain.inputs'] = JSON.stringify(inputs);\n }\n\n startSpanManual(\n {\n name: `chain ${chainName}`,\n op: 'gen_ai.invoke_agent',\n attributes: {\n ...attributes,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'gen_ai.invoke_agent',\n },\n },\n span => {\n spanMap.set(runId, span);\n return span;\n },\n );\n },\n\n // Chain End Handler\n handleChainEnd(outputs: unknown, runId: string) {\n const span = spanMap.get(runId);\n if (span?.isRecording()) {\n // Add outputs if recordOutputs is enabled\n if (recordOutputs) {\n span.setAttributes({\n 'langchain.chain.outputs': JSON.stringify(outputs),\n });\n }\n exitSpan(runId);\n }\n },\n\n // Chain Error Handler\n handleChainError(error: Error, runId: string) {\n const span = spanMap.get(runId);\n if (span?.isRecording()) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n exitSpan(runId);\n }\n\n captureException(error, {\n mechanism: {\n handled: false,\n type: `${LANGCHAIN_ORIGIN}.chain_error_handler`,\n },\n });\n },\n\n // Tool Start Handler\n handleToolStart(tool: { name?: string }, input: string, runId: string, _parentRunId?: string) {\n const toolName = tool.name || 'unknown_tool';\n const attributes: Record<string, SpanAttributeValue> = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: LANGCHAIN_ORIGIN,\n [GEN_AI_TOOL_NAME_ATTRIBUTE]: toolName,\n };\n\n // Add input if recordInputs is enabled\n if (recordInputs) {\n attributes[GEN_AI_TOOL_INPUT_ATTRIBUTE] = input;\n }\n\n startSpanManual(\n {\n name: `execute_tool ${toolName}`,\n op: 'gen_ai.execute_tool',\n attributes: {\n ...attributes,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'gen_ai.execute_tool',\n },\n },\n span => {\n spanMap.set(runId, span);\n return span;\n },\n );\n },\n\n // Tool End Handler\n handleToolEnd(output: unknown, runId: string) {\n const span = spanMap.get(runId);\n if (span?.isRecording()) {\n // Add output if recordOutputs is enabled\n if (recordOutputs) {\n span.setAttributes({\n [GEN_AI_TOOL_OUTPUT_ATTRIBUTE]: JSON.stringify(output),\n });\n }\n exitSpan(runId);\n }\n },\n\n // Tool Error Handler\n handleToolError(error: Error, runId: string) {\n const span = spanMap.get(runId);\n if (span?.isRecording()) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n exitSpan(runId);\n }\n\n captureException(error, {\n mechanism: {\n handled: false,\n type: `${LANGCHAIN_ORIGIN}.tool_error_handler`,\n },\n });\n },\n\n // LangChain BaseCallbackHandler required methods\n copy() {\n return handler;\n },\n\n toJSON() {\n return {\n lc: 1,\n type: 'not_implemented',\n id: handler.lc_id,\n };\n },\n\n toJSONNotImplemented() {\n return {\n lc: 1,\n type: 'not_implemented',\n id: handler.lc_id,\n };\n },\n };\n\n return handler;\n}\n"],"names":["resolveAIRecordingOptions","getInvocationParams","extractLLMRequestAttributes","GEN_AI_REQUEST_MODEL_ATTRIBUTE","GEN_AI_OPERATION_NAME_ATTRIBUTE","startSpanManual","SEMANTIC_ATTRIBUTE_SENTRY_OP","extractChatModelRequestAttributes","extractLlmResponseAttributes","SPAN_STATUS_ERROR","captureException","LANGCHAIN_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","GEN_AI_TOOL_NAME_ATTRIBUTE","GEN_AI_TOOL_INPUT_ATTRIBUTE","GEN_AI_TOOL_OUTPUT_ATTRIBUTE"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../../../src/tracing/langchain/index.ts"],"sourcesContent":["import { captureException } from '../../exports';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../../semanticAttributes';\nimport { SPAN_STATUS_ERROR } from '../../tracing';\nimport { startSpanManual } from '../../tracing/trace';\nimport type { Span, SpanAttributeValue } from '../../types-hoist/span';\nimport {\n GEN_AI_OPERATION_NAME_ATTRIBUTE,\n GEN_AI_REQUEST_MODEL_ATTRIBUTE,\n GEN_AI_TOOL_INPUT_ATTRIBUTE,\n GEN_AI_TOOL_NAME_ATTRIBUTE,\n GEN_AI_TOOL_OUTPUT_ATTRIBUTE,\n} from '../ai/gen-ai-attributes';\nimport { resolveAIRecordingOptions } from '../ai/utils';\nimport { LANGCHAIN_ORIGIN } from './constants';\nimport type {\n LangChainCallbackHandler,\n LangChainLLMResult,\n LangChainMessage,\n LangChainOptions,\n LangChainSerialized,\n} from './types';\nimport {\n extractChatModelRequestAttributes,\n extractLLMRequestAttributes,\n extractLlmResponseAttributes,\n getInvocationParams,\n} from './utils';\n\n/**\n * Creates a Sentry callback handler for LangChain\n * Returns a plain object that LangChain will call via duck-typing\n *\n * This is a stateful handler that tracks spans across multiple LangChain executions.\n */\nexport function createLangChainCallbackHandler(options: LangChainOptions = {}): LangChainCallbackHandler {\n const { recordInputs, recordOutputs } = resolveAIRecordingOptions(options);\n\n // Internal state - single instance tracks all spans\n const spanMap = new Map<string, Span>();\n\n /**\n * Exit a span and clean up\n */\n const exitSpan = (runId: string): void => {\n const span = spanMap.get(runId);\n if (span?.isRecording()) {\n span.end();\n spanMap.delete(runId);\n }\n };\n\n /**\n * Handler for LLM Start\n * This handler will be called by LangChain's callback handler when an LLM event is detected.\n */\n const handler: LangChainCallbackHandler = {\n // Required LangChain BaseCallbackHandler properties\n lc_serializable: false,\n lc_namespace: ['langchain_core', 'callbacks', 'sentry'],\n lc_secrets: undefined,\n lc_attributes: undefined,\n lc_aliases: undefined,\n lc_serializable_keys: undefined,\n lc_id: ['langchain_core', 'callbacks', 'sentry'],\n lc_kwargs: {},\n name: 'SentryCallbackHandler',\n\n // BaseCallbackHandlerInput boolean flags\n ignoreLLM: false,\n ignoreChain: false,\n ignoreAgent: false,\n ignoreRetriever: false,\n ignoreCustomEvent: false,\n raiseError: false,\n awaitHandlers: true,\n\n handleLLMStart(\n llm: unknown,\n prompts: string[],\n runId: string,\n _parentRunId?: string,\n _extraParams?: Record<string, unknown>,\n tags?: string[],\n metadata?: Record<string, unknown>,\n _runName?: string,\n ) {\n const invocationParams = getInvocationParams(tags);\n const attributes = extractLLMRequestAttributes(\n llm as LangChainSerialized,\n prompts,\n recordInputs,\n invocationParams,\n metadata,\n );\n const modelName = attributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE];\n const operationName = attributes[GEN_AI_OPERATION_NAME_ATTRIBUTE];\n\n startSpanManual(\n {\n name: `${operationName} ${modelName}`,\n op: 'gen_ai.chat',\n attributes: {\n ...attributes,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'gen_ai.chat',\n },\n },\n span => {\n spanMap.set(runId, span);\n return span;\n },\n );\n },\n\n // Chat Model Start Handler\n handleChatModelStart(\n llm: unknown,\n messages: unknown,\n runId: string,\n _parentRunId?: string,\n _extraParams?: Record<string, unknown>,\n tags?: string[],\n metadata?: Record<string, unknown>,\n _runName?: string,\n ) {\n const invocationParams = getInvocationParams(tags);\n const attributes = extractChatModelRequestAttributes(\n llm as LangChainSerialized,\n messages as LangChainMessage[][],\n recordInputs,\n invocationParams,\n metadata,\n );\n const modelName = attributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE];\n const operationName = attributes[GEN_AI_OPERATION_NAME_ATTRIBUTE];\n\n startSpanManual(\n {\n name: `${operationName} ${modelName}`,\n op: 'gen_ai.chat',\n attributes: {\n ...attributes,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'gen_ai.chat',\n },\n },\n span => {\n spanMap.set(runId, span);\n return span;\n },\n );\n },\n\n // LLM End Handler - note: handleLLMEnd with capital LLM (used by both LLMs and chat models!)\n handleLLMEnd(\n output: unknown,\n runId: string,\n _parentRunId?: string,\n _tags?: string[],\n _extraParams?: Record<string, unknown>,\n ) {\n const span = spanMap.get(runId);\n if (span?.isRecording()) {\n const attributes = extractLlmResponseAttributes(output as LangChainLLMResult, recordOutputs);\n if (attributes) {\n span.setAttributes(attributes);\n }\n exitSpan(runId);\n }\n },\n\n // LLM Error Handler - note: handleLLMError with capital LLM\n handleLLMError(error: Error, runId: string) {\n const span = spanMap.get(runId);\n if (span?.isRecording()) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n exitSpan(runId);\n }\n\n captureException(error, {\n mechanism: {\n handled: false,\n type: `${LANGCHAIN_ORIGIN}.llm_error_handler`,\n },\n });\n },\n\n // Chain Start Handler\n handleChainStart(\n chain: { name?: string },\n inputs: Record<string, unknown>,\n runId: string,\n _parentRunId?: string,\n _tags?: string[],\n _metadata?: Record<string, unknown>,\n _runType?: string,\n runName?: string,\n ) {\n const chainName = runName || chain.name || 'unknown_chain';\n const attributes: Record<string, SpanAttributeValue> = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ai.langchain',\n 'langchain.chain.name': chainName,\n };\n\n // Add inputs if recordInputs is enabled\n if (recordInputs) {\n attributes['langchain.chain.inputs'] = JSON.stringify(inputs);\n }\n\n startSpanManual(\n {\n name: `chain ${chainName}`,\n op: 'gen_ai.invoke_agent',\n attributes: {\n ...attributes,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'gen_ai.invoke_agent',\n },\n },\n span => {\n spanMap.set(runId, span);\n return span;\n },\n );\n },\n\n // Chain End Handler\n handleChainEnd(outputs: unknown, runId: string) {\n const span = spanMap.get(runId);\n if (span?.isRecording()) {\n // Add outputs if recordOutputs is enabled\n if (recordOutputs) {\n span.setAttributes({\n 'langchain.chain.outputs': JSON.stringify(outputs),\n });\n }\n exitSpan(runId);\n }\n },\n\n // Chain Error Handler\n handleChainError(error: Error, runId: string) {\n const span = spanMap.get(runId);\n if (span?.isRecording()) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n exitSpan(runId);\n }\n\n captureException(error, {\n mechanism: {\n handled: false,\n type: `${LANGCHAIN_ORIGIN}.chain_error_handler`,\n },\n });\n },\n\n // Tool Start Handler\n handleToolStart(tool: { name?: string }, input: string, runId: string, _parentRunId?: string) {\n const toolName = tool.name || 'unknown_tool';\n const attributes: Record<string, SpanAttributeValue> = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: LANGCHAIN_ORIGIN,\n [GEN_AI_TOOL_NAME_ATTRIBUTE]: toolName,\n };\n\n // Add input if recordInputs is enabled\n if (recordInputs) {\n attributes[GEN_AI_TOOL_INPUT_ATTRIBUTE] = input;\n }\n\n startSpanManual(\n {\n name: `execute_tool ${toolName}`,\n op: 'gen_ai.execute_tool',\n attributes: {\n ...attributes,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'gen_ai.execute_tool',\n },\n },\n span => {\n spanMap.set(runId, span);\n return span;\n },\n );\n },\n\n // Tool End Handler\n handleToolEnd(output: unknown, runId: string) {\n const span = spanMap.get(runId);\n if (span?.isRecording()) {\n // Add output if recordOutputs is enabled\n if (recordOutputs) {\n span.setAttributes({\n [GEN_AI_TOOL_OUTPUT_ATTRIBUTE]: JSON.stringify(output),\n });\n }\n exitSpan(runId);\n }\n },\n\n // Tool Error Handler\n handleToolError(error: Error, runId: string) {\n const span = spanMap.get(runId);\n if (span?.isRecording()) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n exitSpan(runId);\n }\n\n captureException(error, {\n mechanism: {\n handled: false,\n type: `${LANGCHAIN_ORIGIN}.tool_error_handler`,\n },\n });\n },\n\n // LangChain BaseCallbackHandler required methods\n copy() {\n return handler;\n },\n\n toJSON() {\n return {\n lc: 1,\n type: 'not_implemented',\n id: handler.lc_id,\n };\n },\n\n toJSONNotImplemented() {\n return {\n lc: 1,\n type: 'not_implemented',\n id: handler.lc_id,\n };\n },\n };\n\n return handler;\n}\n\nexport { instrumentLangChainEmbeddings } from './embeddings';\n"],"names":["resolveAIRecordingOptions","getInvocationParams","extractLLMRequestAttributes","GEN_AI_REQUEST_MODEL_ATTRIBUTE","GEN_AI_OPERATION_NAME_ATTRIBUTE","startSpanManual","SEMANTIC_ATTRIBUTE_SENTRY_OP","extractChatModelRequestAttributes","extractLlmResponseAttributes","SPAN_STATUS_ERROR","captureException","LANGCHAIN_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","GEN_AI_TOOL_NAME_ATTRIBUTE","GEN_AI_TOOL_INPUT_ATTRIBUTE","GEN_AI_TOOL_OUTPUT_ATTRIBUTE"],"mappings":"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"}
@@ -61,33 +61,6 @@ function extractRequestAttributes(args, operationName) {
61
61
  return attributes;
62
62
  }
63
63
 
64
- /**
65
- * Add response attributes to spans
66
- * This supports Chat Completion, Responses API, Embeddings, and Conversations API responses
67
- */
68
- function addResponseAttributes(span, result, recordOutputs) {
69
- if (!result || typeof result !== 'object') return;
70
-
71
- const response = result ;
72
-
73
- if (utils$1.isChatCompletionResponse(response)) {
74
- utils$1.addChatCompletionAttributes(span, response, recordOutputs);
75
- if (recordOutputs && response.choices?.length) {
76
- const responseTexts = response.choices.map(choice => choice.message?.content || '');
77
- span.setAttributes({ [genAiAttributes.GEN_AI_RESPONSE_TEXT_ATTRIBUTE]: JSON.stringify(responseTexts) });
78
- }
79
- } else if (utils$1.isResponsesApiResponse(response)) {
80
- utils$1.addResponsesApiAttributes(span, response, recordOutputs);
81
- if (recordOutputs && response.output_text) {
82
- span.setAttributes({ [genAiAttributes.GEN_AI_RESPONSE_TEXT_ATTRIBUTE]: response.output_text });
83
- }
84
- } else if (utils$1.isEmbeddingsResponse(response)) {
85
- utils$1.addEmbeddingsAttributes(span, response);
86
- } else if (utils$1.isConversationResponse(response)) {
87
- utils$1.addConversationAttributes(span, response);
88
- }
89
- }
90
-
91
64
  // Extract and record AI request inputs, if present. This is intentionally separate from response attributes.
92
65
  function addRequestAttributes(span, params, operationName) {
93
66
  // Store embeddings input on a separate attribute and do not truncate it
@@ -153,7 +126,7 @@ function instrumentMethod(
153
126
  options,
154
127
  ) {
155
128
  return function instrumentedCall(...args) {
156
- const operationName = instrumentedMethod.operation;
129
+ const operationName = instrumentedMethod.operation || 'unknown';
157
130
  const requestAttributes = extractRequestAttributes(args, operationName);
158
131
  const model = (requestAttributes[genAiAttributes.GEN_AI_REQUEST_MODEL_ATTRIBUTE] ) || 'unknown';
159
132
 
@@ -216,7 +189,7 @@ function instrumentMethod(
216
189
 
217
190
  return originalResult.then(
218
191
  result => {
219
- addResponseAttributes(span, result, options.recordOutputs);
192
+ utils$1.addResponseAttributes(span, result, options.recordOutputs);
220
193
  return result;
221
194
  },
222
195
  error => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../src/tracing/openai/index.ts"],"sourcesContent":["import { DEBUG_BUILD } from '../../debug-build';\nimport { captureException } from '../../exports';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../../semanticAttributes';\nimport { SPAN_STATUS_ERROR } from '../../tracing';\nimport { startSpan, startSpanManual } from '../../tracing/trace';\nimport type { Span, SpanAttributeValue } from '../../types-hoist/span';\nimport { debug } from '../../utils/debug-logger';\nimport {\n GEN_AI_EMBEDDINGS_INPUT_ATTRIBUTE,\n GEN_AI_INPUT_MESSAGES_ATTRIBUTE,\n GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE,\n GEN_AI_OPERATION_NAME_ATTRIBUTE,\n GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE,\n GEN_AI_REQUEST_MODEL_ATTRIBUTE,\n GEN_AI_RESPONSE_TEXT_ATTRIBUTE,\n GEN_AI_SYSTEM_ATTRIBUTE,\n GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE,\n} from '../ai/gen-ai-attributes';\nimport type { InstrumentedMethodEntry } from '../ai/utils';\nimport {\n buildMethodPath,\n extractSystemInstructions,\n getTruncatedJsonString,\n resolveAIRecordingOptions,\n wrapPromiseWithMethods,\n} from '../ai/utils';\nimport { OPENAI_METHOD_REGISTRY } from './constants';\nimport { instrumentStream } from './streaming';\nimport type { ChatCompletionChunk, OpenAiOptions, OpenAiResponse, OpenAIStream, ResponseStreamingEvent } from './types';\nimport {\n addChatCompletionAttributes,\n addConversationAttributes,\n addEmbeddingsAttributes,\n addResponsesApiAttributes,\n extractRequestParameters,\n isChatCompletionResponse,\n isConversationResponse,\n isEmbeddingsResponse,\n isResponsesApiResponse,\n} from './utils';\n\n/**\n * Extract available tools from request parameters\n */\nfunction extractAvailableTools(params: Record<string, unknown>): string | undefined {\n const tools = Array.isArray(params.tools) ? params.tools : [];\n const hasWebSearchOptions = params.web_search_options && typeof params.web_search_options === 'object';\n const webSearchOptions = hasWebSearchOptions\n ? [{ type: 'web_search_options', ...(params.web_search_options as Record<string, unknown>) }]\n : [];\n\n const availableTools = [...tools, ...webSearchOptions];\n if (availableTools.length === 0) {\n return undefined;\n }\n\n try {\n return JSON.stringify(availableTools);\n } catch (error) {\n DEBUG_BUILD && debug.error('Failed to serialize OpenAI tools:', error);\n return undefined;\n }\n}\n\n/**\n * Extract request attributes from method arguments\n */\nfunction extractRequestAttributes(args: unknown[], operationName: string): Record<string, unknown> {\n const attributes: Record<string, unknown> = {\n [GEN_AI_SYSTEM_ATTRIBUTE]: 'openai',\n [GEN_AI_OPERATION_NAME_ATTRIBUTE]: operationName,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ai.openai',\n };\n\n if (args.length > 0 && typeof args[0] === 'object' && args[0] !== null) {\n const params = args[0] as Record<string, unknown>;\n\n const availableTools = extractAvailableTools(params);\n if (availableTools) {\n attributes[GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE] = availableTools;\n }\n\n Object.assign(attributes, extractRequestParameters(params));\n } else {\n attributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] = 'unknown';\n }\n\n return attributes;\n}\n\n/**\n * Add response attributes to spans\n * This supports Chat Completion, Responses API, Embeddings, and Conversations API responses\n */\nfunction addResponseAttributes(span: Span, result: unknown, recordOutputs?: boolean): void {\n if (!result || typeof result !== 'object') return;\n\n const response = result as OpenAiResponse;\n\n if (isChatCompletionResponse(response)) {\n addChatCompletionAttributes(span, response, recordOutputs);\n if (recordOutputs && response.choices?.length) {\n const responseTexts = response.choices.map(choice => choice.message?.content || '');\n span.setAttributes({ [GEN_AI_RESPONSE_TEXT_ATTRIBUTE]: JSON.stringify(responseTexts) });\n }\n } else if (isResponsesApiResponse(response)) {\n addResponsesApiAttributes(span, response, recordOutputs);\n if (recordOutputs && response.output_text) {\n span.setAttributes({ [GEN_AI_RESPONSE_TEXT_ATTRIBUTE]: response.output_text });\n }\n } else if (isEmbeddingsResponse(response)) {\n addEmbeddingsAttributes(span, response);\n } else if (isConversationResponse(response)) {\n addConversationAttributes(span, response);\n }\n}\n\n// Extract and record AI request inputs, if present. This is intentionally separate from response attributes.\nfunction addRequestAttributes(span: Span, params: Record<string, unknown>, operationName: string): void {\n // Store embeddings input on a separate attribute and do not truncate it\n if (operationName === 'embeddings' && 'input' in params) {\n const input = params.input;\n\n // No input provided\n if (input == null) {\n return;\n }\n\n // Empty input string\n if (typeof input === 'string' && input.length === 0) {\n return;\n }\n\n // Empty array input\n if (Array.isArray(input) && input.length === 0) {\n return;\n }\n\n // Store strings as-is, arrays/objects as JSON\n span.setAttribute(GEN_AI_EMBEDDINGS_INPUT_ATTRIBUTE, typeof input === 'string' ? input : JSON.stringify(input));\n return;\n }\n\n const src = 'input' in params ? params.input : 'messages' in params ? params.messages : undefined;\n\n if (!src) {\n return;\n }\n\n if (Array.isArray(src) && src.length === 0) {\n return;\n }\n\n const { systemInstructions, filteredMessages } = extractSystemInstructions(src);\n\n if (systemInstructions) {\n span.setAttribute(GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE, systemInstructions);\n }\n\n const truncatedInput = getTruncatedJsonString(filteredMessages);\n span.setAttribute(GEN_AI_INPUT_MESSAGES_ATTRIBUTE, truncatedInput);\n\n if (Array.isArray(filteredMessages)) {\n span.setAttribute(GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE, filteredMessages.length);\n } else {\n span.setAttribute(GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE, 1);\n }\n}\n\n/**\n * Instrument a method with Sentry spans\n * Following Sentry AI Agents Manual Instrumentation conventions\n * @see https://docs.sentry.io/platforms/javascript/guides/node/tracing/instrumentation/ai-agents-module/#manual-instrumentation\n */\nfunction instrumentMethod<T extends unknown[], R>(\n originalMethod: (...args: T) => Promise<R>,\n methodPath: string,\n instrumentedMethod: InstrumentedMethodEntry,\n context: unknown,\n options: OpenAiOptions,\n): (...args: T) => Promise<R> {\n return function instrumentedCall(...args: T): Promise<R> {\n const operationName = instrumentedMethod.operation;\n const requestAttributes = extractRequestAttributes(args, operationName);\n const model = (requestAttributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] as string) || 'unknown';\n\n const params = args[0] as Record<string, unknown> | undefined;\n const isStreamRequested = params && typeof params === 'object' && params.stream === true;\n\n const spanConfig = {\n name: `${operationName} ${model}`,\n op: `gen_ai.${operationName}`,\n attributes: requestAttributes as Record<string, SpanAttributeValue>,\n };\n\n if (isStreamRequested) {\n let originalResult!: Promise<R>;\n\n const instrumentedPromise = startSpanManual(spanConfig, (span: Span) => {\n originalResult = originalMethod.apply(context, args);\n\n if (options.recordInputs && params) {\n addRequestAttributes(span, params, operationName);\n }\n\n // Return async processing\n return (async () => {\n try {\n const result = await originalResult;\n return instrumentStream(\n result as OpenAIStream<ChatCompletionChunk | ResponseStreamingEvent>,\n span,\n options.recordOutputs ?? false,\n ) as unknown as R;\n } catch (error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureException(error, {\n mechanism: {\n handled: false,\n type: 'auto.ai.openai.stream',\n data: { function: methodPath },\n },\n });\n span.end();\n throw error;\n }\n })();\n });\n\n return wrapPromiseWithMethods(originalResult, instrumentedPromise, 'auto.ai.openai');\n }\n\n // Non-streaming\n let originalResult!: Promise<R>;\n\n const instrumentedPromise = startSpan(spanConfig, (span: Span) => {\n // Call synchronously to capture the promise\n originalResult = originalMethod.apply(context, args);\n\n if (options.recordInputs && params) {\n addRequestAttributes(span, params, operationName);\n }\n\n return originalResult.then(\n result => {\n addResponseAttributes(span, result, options.recordOutputs);\n return result;\n },\n error => {\n captureException(error, {\n mechanism: {\n handled: false,\n type: 'auto.ai.openai',\n data: { function: methodPath },\n },\n });\n throw error;\n },\n );\n });\n\n return wrapPromiseWithMethods(originalResult, instrumentedPromise, 'auto.ai.openai');\n };\n}\n\n/**\n * Create a deep proxy for OpenAI client instrumentation\n */\nfunction createDeepProxy<T extends object>(target: T, currentPath = '', options: OpenAiOptions): T {\n return new Proxy(target, {\n get(obj: object, prop: string): unknown {\n const value = (obj as Record<string, unknown>)[prop];\n const methodPath = buildMethodPath(currentPath, String(prop));\n\n const instrumentedMethod = OPENAI_METHOD_REGISTRY[methodPath as keyof typeof OPENAI_METHOD_REGISTRY];\n if (typeof value === 'function' && instrumentedMethod) {\n return instrumentMethod(\n value as (...args: unknown[]) => Promise<unknown>,\n methodPath,\n instrumentedMethod,\n obj,\n options,\n );\n }\n\n if (typeof value === 'function') {\n // Bind non-instrumented functions to preserve the original `this` context,\n // which is required for accessing private class fields (e.g. #baseURL) in OpenAI SDK v5.\n return value.bind(obj);\n }\n\n if (value && typeof value === 'object') {\n return createDeepProxy(value, methodPath, options);\n }\n\n return value;\n },\n }) as T;\n}\n\n/**\n * Instrument an OpenAI client with Sentry tracing\n * Can be used across Node.js, Cloudflare Workers, and Vercel Edge\n */\nexport function instrumentOpenAiClient<T extends object>(client: T, options?: OpenAiOptions): T {\n return createDeepProxy(client, '', resolveAIRecordingOptions(options));\n}\n"],"names":["DEBUG_BUILD","debug","GEN_AI_SYSTEM_ATTRIBUTE","GEN_AI_OPERATION_NAME_ATTRIBUTE","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE","extractRequestParameters","GEN_AI_REQUEST_MODEL_ATTRIBUTE","isChatCompletionResponse","addChatCompletionAttributes","GEN_AI_RESPONSE_TEXT_ATTRIBUTE","isResponsesApiResponse","addResponsesApiAttributes","isEmbeddingsResponse","addEmbeddingsAttributes","isConversationResponse","addConversationAttributes","GEN_AI_EMBEDDINGS_INPUT_ATTRIBUTE","extractSystemInstructions","GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE","getTruncatedJsonString","GEN_AI_INPUT_MESSAGES_ATTRIBUTE","GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE","startSpanManual","instrumentStream","SPAN_STATUS_ERROR","captureException","wrapPromiseWithMethods","startSpan","buildMethodPath","OPENAI_METHOD_REGISTRY","resolveAIRecordingOptions"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../../../src/tracing/openai/index.ts"],"sourcesContent":["import { DEBUG_BUILD } from '../../debug-build';\nimport { captureException } from '../../exports';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../../semanticAttributes';\nimport { SPAN_STATUS_ERROR } from '../../tracing';\nimport { startSpan, startSpanManual } from '../../tracing/trace';\nimport type { Span, SpanAttributeValue } from '../../types-hoist/span';\nimport { debug } from '../../utils/debug-logger';\nimport {\n GEN_AI_EMBEDDINGS_INPUT_ATTRIBUTE,\n GEN_AI_INPUT_MESSAGES_ATTRIBUTE,\n GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE,\n GEN_AI_OPERATION_NAME_ATTRIBUTE,\n GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE,\n GEN_AI_REQUEST_MODEL_ATTRIBUTE,\n GEN_AI_SYSTEM_ATTRIBUTE,\n GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE,\n} from '../ai/gen-ai-attributes';\nimport type { InstrumentedMethodEntry } from '../ai/utils';\nimport {\n buildMethodPath,\n extractSystemInstructions,\n getTruncatedJsonString,\n resolveAIRecordingOptions,\n wrapPromiseWithMethods,\n} from '../ai/utils';\nimport { OPENAI_METHOD_REGISTRY } from './constants';\nimport { instrumentStream } from './streaming';\nimport type { ChatCompletionChunk, OpenAiOptions, OpenAIStream, ResponseStreamingEvent } from './types';\nimport { addResponseAttributes, extractRequestParameters } from './utils';\n\n/**\n * Extract available tools from request parameters\n */\nfunction extractAvailableTools(params: Record<string, unknown>): string | undefined {\n const tools = Array.isArray(params.tools) ? params.tools : [];\n const hasWebSearchOptions = params.web_search_options && typeof params.web_search_options === 'object';\n const webSearchOptions = hasWebSearchOptions\n ? [{ type: 'web_search_options', ...(params.web_search_options as Record<string, unknown>) }]\n : [];\n\n const availableTools = [...tools, ...webSearchOptions];\n if (availableTools.length === 0) {\n return undefined;\n }\n\n try {\n return JSON.stringify(availableTools);\n } catch (error) {\n DEBUG_BUILD && debug.error('Failed to serialize OpenAI tools:', error);\n return undefined;\n }\n}\n\n/**\n * Extract request attributes from method arguments\n */\nfunction extractRequestAttributes(args: unknown[], operationName: string): Record<string, unknown> {\n const attributes: Record<string, unknown> = {\n [GEN_AI_SYSTEM_ATTRIBUTE]: 'openai',\n [GEN_AI_OPERATION_NAME_ATTRIBUTE]: operationName,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ai.openai',\n };\n\n if (args.length > 0 && typeof args[0] === 'object' && args[0] !== null) {\n const params = args[0] as Record<string, unknown>;\n\n const availableTools = extractAvailableTools(params);\n if (availableTools) {\n attributes[GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE] = availableTools;\n }\n\n Object.assign(attributes, extractRequestParameters(params));\n } else {\n attributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] = 'unknown';\n }\n\n return attributes;\n}\n\n// Extract and record AI request inputs, if present. This is intentionally separate from response attributes.\nfunction addRequestAttributes(span: Span, params: Record<string, unknown>, operationName: string): void {\n // Store embeddings input on a separate attribute and do not truncate it\n if (operationName === 'embeddings' && 'input' in params) {\n const input = params.input;\n\n // No input provided\n if (input == null) {\n return;\n }\n\n // Empty input string\n if (typeof input === 'string' && input.length === 0) {\n return;\n }\n\n // Empty array input\n if (Array.isArray(input) && input.length === 0) {\n return;\n }\n\n // Store strings as-is, arrays/objects as JSON\n span.setAttribute(GEN_AI_EMBEDDINGS_INPUT_ATTRIBUTE, typeof input === 'string' ? input : JSON.stringify(input));\n return;\n }\n\n const src = 'input' in params ? params.input : 'messages' in params ? params.messages : undefined;\n\n if (!src) {\n return;\n }\n\n if (Array.isArray(src) && src.length === 0) {\n return;\n }\n\n const { systemInstructions, filteredMessages } = extractSystemInstructions(src);\n\n if (systemInstructions) {\n span.setAttribute(GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE, systemInstructions);\n }\n\n const truncatedInput = getTruncatedJsonString(filteredMessages);\n span.setAttribute(GEN_AI_INPUT_MESSAGES_ATTRIBUTE, truncatedInput);\n\n if (Array.isArray(filteredMessages)) {\n span.setAttribute(GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE, filteredMessages.length);\n } else {\n span.setAttribute(GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE, 1);\n }\n}\n\n/**\n * Instrument a method with Sentry spans\n * Following Sentry AI Agents Manual Instrumentation conventions\n * @see https://docs.sentry.io/platforms/javascript/guides/node/tracing/instrumentation/ai-agents-module/#manual-instrumentation\n */\nfunction instrumentMethod<T extends unknown[], R>(\n originalMethod: (...args: T) => Promise<R>,\n methodPath: string,\n instrumentedMethod: InstrumentedMethodEntry,\n context: unknown,\n options: OpenAiOptions,\n): (...args: T) => Promise<R> {\n return function instrumentedCall(...args: T): Promise<R> {\n const operationName = instrumentedMethod.operation || 'unknown';\n const requestAttributes = extractRequestAttributes(args, operationName);\n const model = (requestAttributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] as string) || 'unknown';\n\n const params = args[0] as Record<string, unknown> | undefined;\n const isStreamRequested = params && typeof params === 'object' && params.stream === true;\n\n const spanConfig = {\n name: `${operationName} ${model}`,\n op: `gen_ai.${operationName}`,\n attributes: requestAttributes as Record<string, SpanAttributeValue>,\n };\n\n if (isStreamRequested) {\n let originalResult!: Promise<R>;\n\n const instrumentedPromise = startSpanManual(spanConfig, (span: Span) => {\n originalResult = originalMethod.apply(context, args);\n\n if (options.recordInputs && params) {\n addRequestAttributes(span, params, operationName);\n }\n\n // Return async processing\n return (async () => {\n try {\n const result = await originalResult;\n return instrumentStream(\n result as OpenAIStream<ChatCompletionChunk | ResponseStreamingEvent>,\n span,\n options.recordOutputs ?? false,\n ) as unknown as R;\n } catch (error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureException(error, {\n mechanism: {\n handled: false,\n type: 'auto.ai.openai.stream',\n data: { function: methodPath },\n },\n });\n span.end();\n throw error;\n }\n })();\n });\n\n return wrapPromiseWithMethods(originalResult, instrumentedPromise, 'auto.ai.openai');\n }\n\n // Non-streaming\n let originalResult!: Promise<R>;\n\n const instrumentedPromise = startSpan(spanConfig, (span: Span) => {\n // Call synchronously to capture the promise\n originalResult = originalMethod.apply(context, args);\n\n if (options.recordInputs && params) {\n addRequestAttributes(span, params, operationName);\n }\n\n return originalResult.then(\n result => {\n addResponseAttributes(span, result, options.recordOutputs);\n return result;\n },\n error => {\n captureException(error, {\n mechanism: {\n handled: false,\n type: 'auto.ai.openai',\n data: { function: methodPath },\n },\n });\n throw error;\n },\n );\n });\n\n return wrapPromiseWithMethods(originalResult, instrumentedPromise, 'auto.ai.openai');\n };\n}\n\n/**\n * Create a deep proxy for OpenAI client instrumentation\n */\nfunction createDeepProxy<T extends object>(target: T, currentPath = '', options: OpenAiOptions): T {\n return new Proxy(target, {\n get(obj: object, prop: string): unknown {\n const value = (obj as Record<string, unknown>)[prop];\n const methodPath = buildMethodPath(currentPath, String(prop));\n\n const instrumentedMethod = OPENAI_METHOD_REGISTRY[methodPath as keyof typeof OPENAI_METHOD_REGISTRY];\n if (typeof value === 'function' && instrumentedMethod) {\n return instrumentMethod(\n value as (...args: unknown[]) => Promise<unknown>,\n methodPath,\n instrumentedMethod,\n obj,\n options,\n );\n }\n\n if (typeof value === 'function') {\n // Bind non-instrumented functions to preserve the original `this` context,\n // which is required for accessing private class fields (e.g. #baseURL) in OpenAI SDK v5.\n return value.bind(obj);\n }\n\n if (value && typeof value === 'object') {\n return createDeepProxy(value, methodPath, options);\n }\n\n return value;\n },\n }) as T;\n}\n\n/**\n * Instrument an OpenAI client with Sentry tracing\n * Can be used across Node.js, Cloudflare Workers, and Vercel Edge\n */\nexport function instrumentOpenAiClient<T extends object>(client: T, options?: OpenAiOptions): T {\n return createDeepProxy(client, '', resolveAIRecordingOptions(options));\n}\n"],"names":["DEBUG_BUILD","debug","GEN_AI_SYSTEM_ATTRIBUTE","GEN_AI_OPERATION_NAME_ATTRIBUTE","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE","extractRequestParameters","GEN_AI_REQUEST_MODEL_ATTRIBUTE","GEN_AI_EMBEDDINGS_INPUT_ATTRIBUTE","extractSystemInstructions","GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE","getTruncatedJsonString","GEN_AI_INPUT_MESSAGES_ATTRIBUTE","GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE","startSpanManual","instrumentStream","SPAN_STATUS_ERROR","captureException","wrapPromiseWithMethods","startSpan","addResponseAttributes","buildMethodPath","OPENAI_METHOD_REGISTRY","resolveAIRecordingOptions"],"mappings":";;;;;;;;;;;;;;AA8BA;AACA;AACA;AACA,SAAS,qBAAqB,CAAC,MAAM,EAA+C;AACpF,EAAE,MAAM,KAAA,GAAQ,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,KAAA,GAAQ,EAAE;AAC/D,EAAE,MAAM,mBAAA,GAAsB,MAAM,CAAC,kBAAA,IAAsB,OAAO,MAAM,CAAC,kBAAA,KAAuB,QAAQ;AACxG,EAAE,MAAM,mBAAmB;AAC3B,MAAM,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,IAAI,MAAM,CAAC,kBAAA,IAAgD;AAChG,MAAM,EAAE;;AAER,EAAE,MAAM,iBAAiB,CAAC,GAAG,KAAK,EAAE,GAAG,gBAAgB,CAAC;AACxD,EAAE,IAAI,cAAc,CAAC,MAAA,KAAW,CAAC,EAAE;AACnC,IAAI,OAAO,SAAS;AACpB,EAAE;;AAEF,EAAE,IAAI;AACN,IAAI,OAAO,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC;AACzC,EAAE,CAAA,CAAE,OAAO,KAAK,EAAE;AAClB,IAAIA,sBAAA,IAAeC,iBAAK,CAAC,KAAK,CAAC,mCAAmC,EAAE,KAAK,CAAC;AAC1E,IAAI,OAAO,SAAS;AACpB,EAAE;AACF;;AAEA;AACA;AACA;AACA,SAAS,wBAAwB,CAAC,IAAI,EAAa,aAAa,EAAmC;AACnG,EAAE,MAAM,UAAU,GAA4B;AAC9C,IAAI,CAACC,uCAAuB,GAAG,QAAQ;AACvC,IAAI,CAACC,+CAA+B,GAAG,aAAa;AACpD,IAAI,CAACC,mDAAgC,GAAG,gBAAgB;AACxD,GAAG;;AAEH,EAAE,IAAI,IAAI,CAAC,SAAS,CAAA,IAAK,OAAO,IAAI,CAAC,CAAC,CAAA,KAAM,YAAY,IAAI,CAAC,CAAC,CAAA,KAAM,IAAI,EAAE;AAC1E,IAAI,MAAM,MAAA,GAAS,IAAI,CAAC,CAAC,CAAA;;AAEzB,IAAI,MAAM,cAAA,GAAiB,qBAAqB,CAAC,MAAM,CAAC;AACxD,IAAI,IAAI,cAAc,EAAE;AACxB,MAAM,UAAU,CAACC,wDAAwC,CAAA,GAAI,cAAc;AAC3E,IAAI;;AAEJ,IAAI,MAAM,CAAC,MAAM,CAAC,UAAU,EAAEC,gCAAwB,CAAC,MAAM,CAAC,CAAC;AAC/D,EAAE,OAAO;AACT,IAAI,UAAU,CAACC,8CAA8B,CAAA,GAAI,SAAS;AAC1D,EAAE;;AAEF,EAAE,OAAO,UAAU;AACnB;;AAEA;AACA,SAAS,oBAAoB,CAAC,IAAI,EAAQ,MAAM,EAA2B,aAAa,EAAgB;AACxG;AACA,EAAE,IAAI,aAAA,KAAkB,gBAAgB,OAAA,IAAW,MAAM,EAAE;AAC3D,IAAI,MAAM,KAAA,GAAQ,MAAM,CAAC,KAAK;;AAE9B;AACA,IAAI,IAAI,KAAA,IAAS,IAAI,EAAE;AACvB,MAAM;AACN,IAAI;;AAEJ;AACA,IAAI,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAK,CAAC,MAAA,KAAW,CAAC,EAAE;AACzD,MAAM;AACN,IAAI;;AAEJ;AACA,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAA,IAAK,KAAK,CAAC,MAAA,KAAW,CAAC,EAAE;AACpD,MAAM;AACN,IAAI;;AAEJ;AACA,IAAI,IAAI,CAAC,YAAY,CAACC,iDAAiC,EAAE,OAAO,KAAA,KAAU,WAAW,KAAA,GAAQ,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AACnH,IAAI;AACJ,EAAE;;AAEF,EAAE,MAAM,GAAA,GAAM,WAAW,MAAA,GAAS,MAAM,CAAC,QAAQ,UAAA,IAAc,MAAA,GAAS,MAAM,CAAC,QAAA,GAAW,SAAS;;AAEnG,EAAE,IAAI,CAAC,GAAG,EAAE;AACZ,IAAI;AACJ,EAAE;;AAEF,EAAE,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAA,IAAK,GAAG,CAAC,MAAA,KAAW,CAAC,EAAE;AAC9C,IAAI;AACJ,EAAE;;AAEF,EAAE,MAAM,EAAE,kBAAkB,EAAE,gBAAA,KAAqBC,+BAAyB,CAAC,GAAG,CAAC;;AAEjF,EAAE,IAAI,kBAAkB,EAAE;AAC1B,IAAI,IAAI,CAAC,YAAY,CAACC,oDAAoC,EAAE,kBAAkB,CAAC;AAC/E,EAAE;;AAEF,EAAE,MAAM,cAAA,GAAiBC,4BAAsB,CAAC,gBAAgB,CAAC;AACjE,EAAE,IAAI,CAAC,YAAY,CAACC,+CAA+B,EAAE,cAAc,CAAC;;AAEpE,EAAE,IAAI,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE;AACvC,IAAI,IAAI,CAAC,YAAY,CAACC,+DAA+C,EAAE,gBAAgB,CAAC,MAAM,CAAC;AAC/F,EAAE,OAAO;AACT,IAAI,IAAI,CAAC,YAAY,CAACA,+DAA+C,EAAE,CAAC,CAAC;AACzE,EAAE;AACF;;AAEA;AACA;AACA;AACA;AACA;AACA,SAAS,gBAAgB;AACzB,EAAE,cAAc;AAChB,EAAE,UAAU;AACZ,EAAE,kBAAkB;AACpB,EAAE,OAAO;AACT,EAAE,OAAO;AACT,EAA8B;AAC9B,EAAE,OAAO,SAAS,gBAAgB,CAAC,GAAG,IAAI,EAAiB;AAC3D,IAAI,MAAM,aAAA,GAAgB,kBAAkB,CAAC,SAAA,IAAa,SAAS;AACnE,IAAI,MAAM,oBAAoB,wBAAwB,CAAC,IAAI,EAAE,aAAa,CAAC;AAC3E,IAAI,MAAM,KAAA,GAAQ,CAAC,iBAAiB,CAACN,8CAA8B,CAAA,MAAgB,SAAS;;AAE5F,IAAI,MAAM,MAAA,GAAS,IAAI,CAAC,CAAC,CAAA;AACzB,IAAI,MAAM,iBAAA,GAAoB,MAAA,IAAU,OAAO,MAAA,KAAW,QAAA,IAAY,MAAM,CAAC,MAAA,KAAW,IAAI;;AAE5F,IAAI,MAAM,aAAa;AACvB,MAAM,IAAI,EAAE,CAAC,EAAA,aAAA,CAAA,CAAA,EAAA,KAAA,CAAA,CAAA;AACA,MAAA,EAAA,EAAA,CAAA,OAAA,EAAA,aAAA,CAAA,CAAA;AACA,MAAA,UAAA,EAAA,iBAAA;AACA,KAAA;;AAEA,IAAA,IAAA,iBAAA,EAAA;AACA,MAAA,IAAA,cAAA;;AAEA,MAAA,MAAA,mBAAA,GAAAO,qBAAA,CAAA,UAAA,EAAA,CAAA,IAAA,KAAA;AACA,QAAA,cAAA,GAAA,cAAA,CAAA,KAAA,CAAA,OAAA,EAAA,IAAA,CAAA;;AAEA,QAAA,IAAA,OAAA,CAAA,YAAA,IAAA,MAAA,EAAA;AACA,UAAA,oBAAA,CAAA,IAAA,EAAA,MAAA,EAAA,aAAA,CAAA;AACA,QAAA;;AAEA;AACA,QAAA,OAAA,CAAA,YAAA;AACA,UAAA,IAAA;AACA,YAAA,MAAA,MAAA,GAAA,MAAA,cAAA;AACA,YAAA,OAAAC,0BAAA;AACA,cAAA,MAAA;AACA,cAAA,IAAA;AACA,cAAA,OAAA,CAAA,aAAA,IAAA,KAAA;AACA,aAAA;AACA,UAAA,CAAA,CAAA,OAAA,KAAA,EAAA;AACA,YAAA,IAAA,CAAA,SAAA,CAAA,EAAA,IAAA,EAAAC,4BAAA,EAAA,OAAA,EAAA,gBAAA,EAAA,CAAA;AACA,YAAAC,yBAAA,CAAA,KAAA,EAAA;AACA,cAAA,SAAA,EAAA;AACA,gBAAA,OAAA,EAAA,KAAA;AACA,gBAAA,IAAA,EAAA,uBAAA;AACA,gBAAA,IAAA,EAAA,EAAA,QAAA,EAAA,UAAA,EAAA;AACA,eAAA;AACA,aAAA,CAAA;AACA,YAAA,IAAA,CAAA,GAAA,EAAA;AACA,YAAA,MAAA,KAAA;AACA,UAAA;AACA,QAAA,CAAA,GAAA;AACA,MAAA,CAAA,CAAA;;AAEA,MAAA,OAAAC,4BAAA,CAAA,cAAA,EAAA,mBAAA,EAAA,gBAAA,CAAA;AACA,IAAA;;AAEA;AACA,IAAA,IAAA,cAAA;;AAEA,IAAA,MAAA,mBAAA,GAAAC,eAAA,CAAA,UAAA,EAAA,CAAA,IAAA,KAAA;AACA;AACA,MAAA,cAAA,GAAA,cAAA,CAAA,KAAA,CAAA,OAAA,EAAA,IAAA,CAAA;;AAEA,MAAA,IAAA,OAAA,CAAA,YAAA,IAAA,MAAA,EAAA;AACA,QAAA,oBAAA,CAAA,IAAA,EAAA,MAAA,EAAA,aAAA,CAAA;AACA,MAAA;;AAEA,MAAA,OAAA,cAAA,CAAA,IAAA;AACA,QAAA,MAAA,IAAA;AACA,UAAAC,6BAAA,CAAA,IAAA,EAAA,MAAA,EAAA,OAAA,CAAA,aAAA,CAAA;AACA,UAAA,OAAA,MAAA;AACA,QAAA,CAAA;AACA,QAAA,KAAA,IAAA;AACA,UAAAH,yBAAA,CAAA,KAAA,EAAA;AACA,YAAA,SAAA,EAAA;AACA,cAAA,OAAA,EAAA,KAAA;AACA,cAAA,IAAA,EAAA,gBAAA;AACA,cAAA,IAAA,EAAA,EAAA,QAAA,EAAA,UAAA,EAAA;AACA,aAAA;AACA,WAAA,CAAA;AACA,UAAA,MAAA,KAAA;AACA,QAAA,CAAA;AACA,OAAA;AACA,IAAA,CAAA,CAAA;;AAEA,IAAA,OAAAC,4BAAA,CAAA,cAAA,EAAA,mBAAA,EAAA,gBAAA,CAAA;AACA,EAAA,CAAA;AACA;;AAEA;AACA;AACA;AACA,SAAA,eAAA,CAAA,MAAA,EAAA,WAAA,GAAA,EAAA,EAAA,OAAA,EAAA;AACA,EAAA,OAAA,IAAA,KAAA,CAAA,MAAA,EAAA;AACA,IAAA,GAAA,CAAA,GAAA,EAAA,IAAA,EAAA;AACA,MAAA,MAAA,KAAA,GAAA,CAAA,GAAA,GAAA,IAAA,CAAA;AACA,MAAA,MAAA,UAAA,GAAAG,qBAAA,CAAA,WAAA,EAAA,MAAA,CAAA,IAAA,CAAA,CAAA;;AAEA,MAAA,MAAA,kBAAA,GAAAC,gCAAA,CAAA,UAAA,EAAA;AACA,MAAA,IAAA,OAAA,KAAA,KAAA,UAAA,IAAA,kBAAA,EAAA;AACA,QAAA,OAAA,gBAAA;AACA,UAAA,KAAA;AACA,UAAA,UAAA;AACA,UAAA,kBAAA;AACA,UAAA,GAAA;AACA,UAAA,OAAA;AACA,SAAA;AACA,MAAA;;AAEA,MAAA,IAAA,OAAA,KAAA,KAAA,UAAA,EAAA;AACA;AACA;AACA,QAAA,OAAA,KAAA,CAAA,IAAA,CAAA,GAAA,CAAA;AACA,MAAA;;AAEA,MAAA,IAAA,KAAA,IAAA,OAAA,KAAA,KAAA,QAAA,EAAA;AACA,QAAA,OAAA,eAAA,CAAA,KAAA,EAAA,UAAA,EAAA,OAAA,CAAA;AACA,MAAA;;AAEA,MAAA,OAAA,KAAA;AACA,IAAA,CAAA;AACA,GAAA,CAAA;AACA;;AAEA;AACA;AACA;AACA;AACA,SAAA,sBAAA,CAAA,MAAA,EAAA,OAAA,EAAA;AACA,EAAA,OAAA,eAAA,CAAA,MAAA,EAAA,EAAA,EAAAC,+BAAA,CAAA,OAAA,CAAA,CAAA;AACA;;;;"}
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
 
3
3
  const _exports = require('../../exports.js');
4
4
  const spanstatus = require('../spanstatus.js');
5
- const genAiAttributes = require('../ai/gen-ai-attributes.js');
5
+ const utils$1 = require('../ai/utils.js');
6
6
  const constants = require('./constants.js');
7
7
  const utils = require('./utils.js');
8
8
 
@@ -53,7 +53,6 @@ function processChatCompletionToolCalls(toolCalls, state) {
53
53
  function processChatCompletionChunk(chunk, state, recordOutputs) {
54
54
  state.responseId = chunk.id ?? state.responseId;
55
55
  state.responseModel = chunk.model ?? state.responseModel;
56
- state.responseTimestamp = chunk.created ?? state.responseTimestamp;
57
56
 
58
57
  if (chunk.usage) {
59
58
  // For stream responses, the input tokens remain constant across all events in the stream.
@@ -137,7 +136,6 @@ function processResponsesApiEvent(
137
136
  const { response } = event ;
138
137
  state.responseId = response.id ?? state.responseId;
139
138
  state.responseModel = response.model ?? state.responseModel;
140
- state.responseTimestamp = response.created_at ?? state.responseTimestamp;
141
139
 
142
140
  if (response.usage) {
143
141
  // For stream responses, the input tokens remain constant across all events in the stream.
@@ -181,7 +179,6 @@ async function* instrumentStream(
181
179
  finishReasons: [],
182
180
  responseId: '',
183
181
  responseModel: '',
184
- responseTimestamp: 0,
185
182
  promptTokens: undefined,
186
183
  completionTokens: undefined,
187
184
  totalTokens: undefined,
@@ -199,36 +196,8 @@ async function* instrumentStream(
199
196
  yield event;
200
197
  }
201
198
  } finally {
202
- utils.setCommonResponseAttributes(span, state.responseId, state.responseModel, state.responseTimestamp);
203
- utils.setTokenUsageAttributes(span, state.promptTokens, state.completionTokens, state.totalTokens);
204
-
205
- span.setAttributes({
206
- [genAiAttributes.GEN_AI_RESPONSE_STREAMING_ATTRIBUTE]: true,
207
- });
208
-
209
- if (state.finishReasons.length) {
210
- span.setAttributes({
211
- [genAiAttributes.GEN_AI_RESPONSE_FINISH_REASONS_ATTRIBUTE]: JSON.stringify(state.finishReasons),
212
- });
213
- }
214
-
215
- if (recordOutputs && state.responseTexts.length) {
216
- span.setAttributes({
217
- [genAiAttributes.GEN_AI_RESPONSE_TEXT_ATTRIBUTE]: state.responseTexts.join(''),
218
- });
219
- }
220
-
221
- // Set tool calls attribute if any were accumulated
222
- const chatCompletionToolCallsArray = Object.values(state.chatCompletionToolCalls);
223
- const allToolCalls = [...chatCompletionToolCallsArray, ...state.responsesApiToolCalls];
224
-
225
- if (allToolCalls.length > 0) {
226
- span.setAttributes({
227
- [genAiAttributes.GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE]: JSON.stringify(allToolCalls),
228
- });
229
- }
230
-
231
- span.end();
199
+ const allToolCalls = [...Object.values(state.chatCompletionToolCalls), ...state.responsesApiToolCalls];
200
+ utils$1.endStreamSpan(span, { ...state, toolCalls: allToolCalls }, recordOutputs);
232
201
  }
233
202
  }
234
203
 
@@ -1 +1 @@
1
- {"version":3,"file":"streaming.js","sources":["../../../../src/tracing/openai/streaming.ts"],"sourcesContent":["import { captureException } from '../../exports';\nimport { SPAN_STATUS_ERROR } from '../../tracing';\nimport type { Span } from '../../types-hoist/span';\nimport {\n GEN_AI_RESPONSE_FINISH_REASONS_ATTRIBUTE,\n GEN_AI_RESPONSE_STREAMING_ATTRIBUTE,\n GEN_AI_RESPONSE_TEXT_ATTRIBUTE,\n GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE,\n} from '../ai/gen-ai-attributes';\nimport { RESPONSE_EVENT_TYPES } from './constants';\nimport type {\n ChatCompletionChunk,\n ChatCompletionToolCall,\n OpenAIResponseObject,\n ResponseFunctionCall,\n ResponseStreamingEvent,\n} from './types';\nimport {\n isChatCompletionChunk,\n isResponsesApiStreamEvent,\n setCommonResponseAttributes,\n setTokenUsageAttributes,\n} from './utils';\n\n/**\n * State object used to accumulate information from a stream of OpenAI events/chunks.\n */\ninterface StreamingState {\n /** Types of events encountered in the stream. */\n eventTypes: string[];\n /** Collected response text fragments (for output recording). */\n responseTexts: string[];\n /** Reasons for finishing the response, as reported by the API. */\n finishReasons: string[];\n /** The response ID. */\n responseId: string;\n /** The model name. */\n responseModel: string;\n /** The timestamp of the response. */\n responseTimestamp: number;\n /** Number of prompt/input tokens used. */\n promptTokens: number | undefined;\n /** Number of completion/output tokens used. */\n completionTokens: number | undefined;\n /** Total number of tokens used (prompt + completion). */\n totalTokens: number | undefined;\n /**\n * Accumulated tool calls from Chat Completion streaming, indexed by tool call index.\n * @see https://platform.openai.com/docs/guides/function-calling?api-mode=chat#streaming\n */\n chatCompletionToolCalls: Record<number, ChatCompletionToolCall>;\n /**\n * Accumulated function calls from Responses API streaming.\n * @see https://platform.openai.com/docs/guides/function-calling?api-mode=responses#streaming\n */\n responsesApiToolCalls: Array<ResponseFunctionCall | unknown>;\n}\n\n/**\n * Processes tool calls from a chat completion chunk delta.\n * Follows the pattern: accumulate by index, then convert to array at the end.\n *\n * @param toolCalls - Array of tool calls from the delta.\n * @param state - The current streaming state to update.\n *\n * @see https://platform.openai.com/docs/guides/function-calling#streaming\n */\nfunction processChatCompletionToolCalls(toolCalls: ChatCompletionToolCall[], state: StreamingState): void {\n for (const toolCall of toolCalls) {\n const index = toolCall.index;\n if (index === undefined || !toolCall.function) continue;\n\n // Initialize tool call if this is the first chunk for this index\n if (!(index in state.chatCompletionToolCalls)) {\n state.chatCompletionToolCalls[index] = {\n ...toolCall,\n function: {\n name: toolCall.function.name,\n arguments: toolCall.function.arguments || '',\n },\n };\n } else {\n // Accumulate function arguments from subsequent chunks\n const existingToolCall = state.chatCompletionToolCalls[index];\n if (toolCall.function.arguments && existingToolCall?.function) {\n existingToolCall.function.arguments += toolCall.function.arguments;\n }\n }\n }\n}\n\n/**\n * Processes a single OpenAI ChatCompletionChunk event, updating the streaming state.\n *\n * @param chunk - The ChatCompletionChunk event to process.\n * @param state - The current streaming state to update.\n * @param recordOutputs - Whether to record output text fragments.\n */\nfunction processChatCompletionChunk(chunk: ChatCompletionChunk, state: StreamingState, recordOutputs: boolean): void {\n state.responseId = chunk.id ?? state.responseId;\n state.responseModel = chunk.model ?? state.responseModel;\n state.responseTimestamp = chunk.created ?? state.responseTimestamp;\n\n if (chunk.usage) {\n // For stream responses, the input tokens remain constant across all events in the stream.\n // Output tokens, however, are only finalized in the last event.\n // Since we can't guarantee that the last event will include usage data or even be a typed event,\n // we update the output token values on every event that includes them.\n // This ensures that output token usage is always set, even if the final event lacks it.\n state.promptTokens = chunk.usage.prompt_tokens;\n state.completionTokens = chunk.usage.completion_tokens;\n state.totalTokens = chunk.usage.total_tokens;\n }\n\n for (const choice of chunk.choices ?? []) {\n if (recordOutputs) {\n if (choice.delta?.content) {\n state.responseTexts.push(choice.delta.content);\n }\n\n // Handle tool calls from delta\n if (choice.delta?.tool_calls) {\n processChatCompletionToolCalls(choice.delta.tool_calls, state);\n }\n }\n if (choice.finish_reason) {\n state.finishReasons.push(choice.finish_reason);\n }\n }\n}\n\n/**\n * Processes a single OpenAI Responses API streaming event, updating the streaming state and span.\n *\n * @param streamEvent - The event to process (may be an error or unknown object).\n * @param state - The current streaming state to update.\n * @param recordOutputs - Whether to record output text fragments.\n * @param span - The span to update with error status if needed.\n */\nfunction processResponsesApiEvent(\n streamEvent: ResponseStreamingEvent | unknown | Error,\n state: StreamingState,\n recordOutputs: boolean,\n span: Span,\n): void {\n if (!(streamEvent && typeof streamEvent === 'object')) {\n state.eventTypes.push('unknown:non-object');\n return;\n }\n if (streamEvent instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureException(streamEvent, {\n mechanism: {\n handled: false,\n type: 'auto.ai.openai.stream-response',\n },\n });\n return;\n }\n\n if (!('type' in streamEvent)) return;\n const event = streamEvent as ResponseStreamingEvent;\n\n if (!RESPONSE_EVENT_TYPES.includes(event.type)) {\n state.eventTypes.push(event.type);\n return;\n }\n\n // Handle output text delta\n if (recordOutputs) {\n // Handle tool call events for Responses API\n if (event.type === 'response.output_item.done' && 'item' in event) {\n state.responsesApiToolCalls.push(event.item);\n }\n\n if (event.type === 'response.output_text.delta' && 'delta' in event && event.delta) {\n state.responseTexts.push(event.delta);\n return;\n }\n }\n\n if ('response' in event) {\n const { response } = event as { response: OpenAIResponseObject };\n state.responseId = response.id ?? state.responseId;\n state.responseModel = response.model ?? state.responseModel;\n state.responseTimestamp = response.created_at ?? state.responseTimestamp;\n\n if (response.usage) {\n // For stream responses, the input tokens remain constant across all events in the stream.\n // Output tokens, however, are only finalized in the last event.\n // Since we can't guarantee that the last event will include usage data or even be a typed event,\n // we update the output token values on every event that includes them.\n // This ensures that output token usage is always set, even if the final event lacks it.\n state.promptTokens = response.usage.input_tokens;\n state.completionTokens = response.usage.output_tokens;\n state.totalTokens = response.usage.total_tokens;\n }\n\n if (response.status) {\n state.finishReasons.push(response.status);\n }\n\n if (recordOutputs && response.output_text) {\n state.responseTexts.push(response.output_text);\n }\n }\n}\n\n/**\n * Instruments a stream of OpenAI events, updating the provided span with relevant attributes and\n * optionally recording output text. This function yields each event from the input stream as it is processed.\n *\n * @template T - The type of events in the stream.\n * @param stream - The async iterable stream of events to instrument.\n * @param span - The span to add attributes to and to finish at the end of the stream.\n * @param recordOutputs - Whether to record output text fragments in the span.\n * @returns An async generator yielding each event from the input stream.\n */\nexport async function* instrumentStream<T>(\n stream: AsyncIterable<T>,\n span: Span,\n recordOutputs: boolean,\n): AsyncGenerator<T, void, unknown> {\n const state: StreamingState = {\n eventTypes: [],\n responseTexts: [],\n finishReasons: [],\n responseId: '',\n responseModel: '',\n responseTimestamp: 0,\n promptTokens: undefined,\n completionTokens: undefined,\n totalTokens: undefined,\n chatCompletionToolCalls: {},\n responsesApiToolCalls: [],\n };\n\n try {\n for await (const event of stream) {\n if (isChatCompletionChunk(event)) {\n processChatCompletionChunk(event as ChatCompletionChunk, state, recordOutputs);\n } else if (isResponsesApiStreamEvent(event)) {\n processResponsesApiEvent(event as ResponseStreamingEvent, state, recordOutputs, span);\n }\n yield event;\n }\n } finally {\n setCommonResponseAttributes(span, state.responseId, state.responseModel, state.responseTimestamp);\n setTokenUsageAttributes(span, state.promptTokens, state.completionTokens, state.totalTokens);\n\n span.setAttributes({\n [GEN_AI_RESPONSE_STREAMING_ATTRIBUTE]: true,\n });\n\n if (state.finishReasons.length) {\n span.setAttributes({\n [GEN_AI_RESPONSE_FINISH_REASONS_ATTRIBUTE]: JSON.stringify(state.finishReasons),\n });\n }\n\n if (recordOutputs && state.responseTexts.length) {\n span.setAttributes({\n [GEN_AI_RESPONSE_TEXT_ATTRIBUTE]: state.responseTexts.join(''),\n });\n }\n\n // Set tool calls attribute if any were accumulated\n const chatCompletionToolCallsArray = Object.values(state.chatCompletionToolCalls);\n const allToolCalls = [...chatCompletionToolCallsArray, ...state.responsesApiToolCalls];\n\n if (allToolCalls.length > 0) {\n span.setAttributes({\n [GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE]: JSON.stringify(allToolCalls),\n });\n }\n\n span.end();\n }\n}\n"],"names":["SPAN_STATUS_ERROR","captureException","RESPONSE_EVENT_TYPES","isChatCompletionChunk","isResponsesApiStreamEvent","setCommonResponseAttributes","setTokenUsageAttributes","GEN_AI_RESPONSE_STREAMING_ATTRIBUTE","GEN_AI_RESPONSE_FINISH_REASONS_ATTRIBUTE","GEN_AI_RESPONSE_TEXT_ATTRIBUTE","GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE"],"mappings":"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"}
1
+ {"version":3,"file":"streaming.js","sources":["../../../../src/tracing/openai/streaming.ts"],"sourcesContent":["import { captureException } from '../../exports';\nimport { SPAN_STATUS_ERROR } from '../../tracing';\nimport type { Span } from '../../types-hoist/span';\nimport { endStreamSpan } from '../ai/utils';\nimport { RESPONSE_EVENT_TYPES } from './constants';\nimport type {\n ChatCompletionChunk,\n ChatCompletionToolCall,\n OpenAIResponseObject,\n ResponseFunctionCall,\n ResponseStreamingEvent,\n} from './types';\nimport { isChatCompletionChunk, isResponsesApiStreamEvent } from './utils';\n\n/**\n * State object used to accumulate information from a stream of OpenAI events/chunks.\n */\ninterface StreamingState {\n /** Types of events encountered in the stream. */\n eventTypes: string[];\n /** Collected response text fragments (for output recording). */\n responseTexts: string[];\n /** Reasons for finishing the response, as reported by the API. */\n finishReasons: string[];\n /** The response ID. */\n responseId: string;\n /** The model name. */\n responseModel: string;\n /** Number of prompt/input tokens used. */\n promptTokens: number | undefined;\n /** Number of completion/output tokens used. */\n completionTokens: number | undefined;\n /** Total number of tokens used (prompt + completion). */\n totalTokens: number | undefined;\n /**\n * Accumulated tool calls from Chat Completion streaming, indexed by tool call index.\n * @see https://platform.openai.com/docs/guides/function-calling?api-mode=chat#streaming\n */\n chatCompletionToolCalls: Record<number, ChatCompletionToolCall>;\n /**\n * Accumulated function calls from Responses API streaming.\n * @see https://platform.openai.com/docs/guides/function-calling?api-mode=responses#streaming\n */\n responsesApiToolCalls: Array<ResponseFunctionCall | unknown>;\n}\n\n/**\n * Processes tool calls from a chat completion chunk delta.\n * Follows the pattern: accumulate by index, then convert to array at the end.\n *\n * @param toolCalls - Array of tool calls from the delta.\n * @param state - The current streaming state to update.\n *\n * @see https://platform.openai.com/docs/guides/function-calling#streaming\n */\nfunction processChatCompletionToolCalls(toolCalls: ChatCompletionToolCall[], state: StreamingState): void {\n for (const toolCall of toolCalls) {\n const index = toolCall.index;\n if (index === undefined || !toolCall.function) continue;\n\n // Initialize tool call if this is the first chunk for this index\n if (!(index in state.chatCompletionToolCalls)) {\n state.chatCompletionToolCalls[index] = {\n ...toolCall,\n function: {\n name: toolCall.function.name,\n arguments: toolCall.function.arguments || '',\n },\n };\n } else {\n // Accumulate function arguments from subsequent chunks\n const existingToolCall = state.chatCompletionToolCalls[index];\n if (toolCall.function.arguments && existingToolCall?.function) {\n existingToolCall.function.arguments += toolCall.function.arguments;\n }\n }\n }\n}\n\n/**\n * Processes a single OpenAI ChatCompletionChunk event, updating the streaming state.\n *\n * @param chunk - The ChatCompletionChunk event to process.\n * @param state - The current streaming state to update.\n * @param recordOutputs - Whether to record output text fragments.\n */\nfunction processChatCompletionChunk(chunk: ChatCompletionChunk, state: StreamingState, recordOutputs: boolean): void {\n state.responseId = chunk.id ?? state.responseId;\n state.responseModel = chunk.model ?? state.responseModel;\n\n if (chunk.usage) {\n // For stream responses, the input tokens remain constant across all events in the stream.\n // Output tokens, however, are only finalized in the last event.\n // Since we can't guarantee that the last event will include usage data or even be a typed event,\n // we update the output token values on every event that includes them.\n // This ensures that output token usage is always set, even if the final event lacks it.\n state.promptTokens = chunk.usage.prompt_tokens;\n state.completionTokens = chunk.usage.completion_tokens;\n state.totalTokens = chunk.usage.total_tokens;\n }\n\n for (const choice of chunk.choices ?? []) {\n if (recordOutputs) {\n if (choice.delta?.content) {\n state.responseTexts.push(choice.delta.content);\n }\n\n // Handle tool calls from delta\n if (choice.delta?.tool_calls) {\n processChatCompletionToolCalls(choice.delta.tool_calls, state);\n }\n }\n if (choice.finish_reason) {\n state.finishReasons.push(choice.finish_reason);\n }\n }\n}\n\n/**\n * Processes a single OpenAI Responses API streaming event, updating the streaming state and span.\n *\n * @param streamEvent - The event to process (may be an error or unknown object).\n * @param state - The current streaming state to update.\n * @param recordOutputs - Whether to record output text fragments.\n * @param span - The span to update with error status if needed.\n */\nfunction processResponsesApiEvent(\n streamEvent: ResponseStreamingEvent | unknown | Error,\n state: StreamingState,\n recordOutputs: boolean,\n span: Span,\n): void {\n if (!(streamEvent && typeof streamEvent === 'object')) {\n state.eventTypes.push('unknown:non-object');\n return;\n }\n if (streamEvent instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureException(streamEvent, {\n mechanism: {\n handled: false,\n type: 'auto.ai.openai.stream-response',\n },\n });\n return;\n }\n\n if (!('type' in streamEvent)) return;\n const event = streamEvent as ResponseStreamingEvent;\n\n if (!RESPONSE_EVENT_TYPES.includes(event.type)) {\n state.eventTypes.push(event.type);\n return;\n }\n\n // Handle output text delta\n if (recordOutputs) {\n // Handle tool call events for Responses API\n if (event.type === 'response.output_item.done' && 'item' in event) {\n state.responsesApiToolCalls.push(event.item);\n }\n\n if (event.type === 'response.output_text.delta' && 'delta' in event && event.delta) {\n state.responseTexts.push(event.delta);\n return;\n }\n }\n\n if ('response' in event) {\n const { response } = event as { response: OpenAIResponseObject };\n state.responseId = response.id ?? state.responseId;\n state.responseModel = response.model ?? state.responseModel;\n\n if (response.usage) {\n // For stream responses, the input tokens remain constant across all events in the stream.\n // Output tokens, however, are only finalized in the last event.\n // Since we can't guarantee that the last event will include usage data or even be a typed event,\n // we update the output token values on every event that includes them.\n // This ensures that output token usage is always set, even if the final event lacks it.\n state.promptTokens = response.usage.input_tokens;\n state.completionTokens = response.usage.output_tokens;\n state.totalTokens = response.usage.total_tokens;\n }\n\n if (response.status) {\n state.finishReasons.push(response.status);\n }\n\n if (recordOutputs && response.output_text) {\n state.responseTexts.push(response.output_text);\n }\n }\n}\n\n/**\n * Instruments a stream of OpenAI events, updating the provided span with relevant attributes and\n * optionally recording output text. This function yields each event from the input stream as it is processed.\n *\n * @template T - The type of events in the stream.\n * @param stream - The async iterable stream of events to instrument.\n * @param span - The span to add attributes to and to finish at the end of the stream.\n * @param recordOutputs - Whether to record output text fragments in the span.\n * @returns An async generator yielding each event from the input stream.\n */\nexport async function* instrumentStream<T>(\n stream: AsyncIterable<T>,\n span: Span,\n recordOutputs: boolean,\n): AsyncGenerator<T, void, unknown> {\n const state: StreamingState = {\n eventTypes: [],\n responseTexts: [],\n finishReasons: [],\n responseId: '',\n responseModel: '',\n promptTokens: undefined,\n completionTokens: undefined,\n totalTokens: undefined,\n chatCompletionToolCalls: {},\n responsesApiToolCalls: [],\n };\n\n try {\n for await (const event of stream) {\n if (isChatCompletionChunk(event)) {\n processChatCompletionChunk(event as ChatCompletionChunk, state, recordOutputs);\n } else if (isResponsesApiStreamEvent(event)) {\n processResponsesApiEvent(event as ResponseStreamingEvent, state, recordOutputs, span);\n }\n yield event;\n }\n } finally {\n const allToolCalls = [...Object.values(state.chatCompletionToolCalls), ...state.responsesApiToolCalls];\n endStreamSpan(span, { ...state, toolCalls: allToolCalls }, recordOutputs);\n }\n}\n"],"names":["SPAN_STATUS_ERROR","captureException","RESPONSE_EVENT_TYPES","isChatCompletionChunk","isResponsesApiStreamEvent","endStreamSpan"],"mappings":"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"}