@sentry/core 10.47.0 → 10.49.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 (413) 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/fetch.js +36 -17
  8. package/build/cjs/fetch.js.map +1 -1
  9. package/build/cjs/index.js +53 -18
  10. package/build/cjs/index.js.map +1 -1
  11. package/build/cjs/integration.js +6 -0
  12. package/build/cjs/integration.js.map +1 -1
  13. package/build/cjs/integrations/conversationId.js +11 -0
  14. package/build/cjs/integrations/conversationId.js.map +1 -1
  15. package/build/cjs/integrations/express/index.js +243 -0
  16. package/build/cjs/integrations/express/index.js.map +1 -0
  17. package/build/cjs/integrations/express/patch-layer.js +257 -0
  18. package/build/cjs/integrations/express/patch-layer.js.map +1 -0
  19. package/build/cjs/integrations/express/request-layer-store.js +25 -0
  20. package/build/cjs/integrations/express/request-layer-store.js.map +1 -0
  21. package/build/cjs/integrations/express/set-sdk-processing-metadata.js +17 -0
  22. package/build/cjs/integrations/express/set-sdk-processing-metadata.js.map +1 -0
  23. package/build/cjs/integrations/express/types.js +17 -0
  24. package/build/cjs/integrations/express/types.js.map +1 -0
  25. package/build/cjs/integrations/express/utils.js +238 -0
  26. package/build/cjs/integrations/express/utils.js.map +1 -0
  27. package/build/cjs/integrations/mcp-server/correlation.js +5 -1
  28. package/build/cjs/integrations/mcp-server/correlation.js.map +1 -1
  29. package/build/cjs/integrations/mcp-server/handlers.js +18 -10
  30. package/build/cjs/integrations/mcp-server/handlers.js.map +1 -1
  31. package/build/cjs/integrations/mcp-server/index.js +2 -1
  32. package/build/cjs/integrations/mcp-server/index.js.map +1 -1
  33. package/build/cjs/integrations/mcp-server/transport.js +1 -1
  34. package/build/cjs/integrations/mcp-server/transport.js.map +1 -1
  35. package/build/cjs/integrations/mcp-server/validation.js +7 -5
  36. package/build/cjs/integrations/mcp-server/validation.js.map +1 -1
  37. package/build/cjs/integrations/requestdata.js.map +1 -1
  38. package/build/cjs/integrations/spanStreaming.js +48 -0
  39. package/build/cjs/integrations/spanStreaming.js.map +1 -0
  40. package/build/cjs/semanticAttributes.js +35 -3
  41. package/build/cjs/semanticAttributes.js.map +1 -1
  42. package/build/cjs/tracing/ai/gen-ai-attributes.js +3 -89
  43. package/build/cjs/tracing/ai/gen-ai-attributes.js.map +1 -1
  44. package/build/cjs/tracing/ai/utils.js +74 -0
  45. package/build/cjs/tracing/ai/utils.js.map +1 -1
  46. package/build/cjs/tracing/anthropic-ai/index.js +6 -17
  47. package/build/cjs/tracing/anthropic-ai/index.js.map +1 -1
  48. package/build/cjs/tracing/anthropic-ai/streaming.js +2 -100
  49. package/build/cjs/tracing/anthropic-ai/streaming.js.map +1 -1
  50. package/build/cjs/tracing/anthropic-ai/utils.js +4 -2
  51. package/build/cjs/tracing/anthropic-ai/utils.js.map +1 -1
  52. package/build/cjs/tracing/dynamicSamplingContext.js +2 -1
  53. package/build/cjs/tracing/dynamicSamplingContext.js.map +1 -1
  54. package/build/cjs/tracing/google-genai/constants.js +1 -6
  55. package/build/cjs/tracing/google-genai/constants.js.map +1 -1
  56. package/build/cjs/tracing/google-genai/index.js +40 -35
  57. package/build/cjs/tracing/google-genai/index.js.map +1 -1
  58. package/build/cjs/tracing/google-genai/streaming.js +2 -23
  59. package/build/cjs/tracing/google-genai/streaming.js.map +1 -1
  60. package/build/cjs/tracing/langchain/embeddings.js +132 -0
  61. package/build/cjs/tracing/langchain/embeddings.js.map +1 -0
  62. package/build/cjs/tracing/langchain/index.js +3 -0
  63. package/build/cjs/tracing/langchain/index.js.map +1 -1
  64. package/build/cjs/tracing/langchain/utils.js +12 -4
  65. package/build/cjs/tracing/langchain/utils.js.map +1 -1
  66. package/build/cjs/tracing/langgraph/index.js +4 -3
  67. package/build/cjs/tracing/langgraph/index.js.map +1 -1
  68. package/build/cjs/tracing/openai/index.js +14 -34
  69. package/build/cjs/tracing/openai/index.js.map +1 -1
  70. package/build/cjs/tracing/openai/streaming.js +3 -34
  71. package/build/cjs/tracing/openai/streaming.js.map +1 -1
  72. package/build/cjs/tracing/openai/utils.js +78 -204
  73. package/build/cjs/tracing/openai/utils.js.map +1 -1
  74. package/build/cjs/tracing/sentryNonRecordingSpan.js +7 -0
  75. package/build/cjs/tracing/sentryNonRecordingSpan.js.map +1 -1
  76. package/build/cjs/tracing/sentrySpan.js +39 -0
  77. package/build/cjs/tracing/sentrySpan.js.map +1 -1
  78. package/build/cjs/tracing/spans/beforeSendSpan.js +43 -0
  79. package/build/cjs/tracing/spans/beforeSendSpan.js.map +1 -0
  80. package/build/cjs/tracing/spans/captureSpan.js +126 -0
  81. package/build/cjs/tracing/spans/captureSpan.js.map +1 -0
  82. package/build/cjs/tracing/spans/envelope.js +38 -0
  83. package/build/cjs/tracing/spans/envelope.js.map +1 -0
  84. package/build/cjs/tracing/spans/estimateSize.js +41 -0
  85. package/build/cjs/tracing/spans/estimateSize.js.map +1 -0
  86. package/build/cjs/tracing/spans/hasSpanStreamingEnabled.js +11 -0
  87. package/build/cjs/tracing/spans/hasSpanStreamingEnabled.js.map +1 -0
  88. package/build/cjs/tracing/spans/spanBuffer.js +158 -0
  89. package/build/cjs/tracing/spans/spanBuffer.js.map +1 -0
  90. package/build/cjs/tracing/trace.js +83 -13
  91. package/build/cjs/tracing/trace.js.map +1 -1
  92. package/build/cjs/tracing/utils.js +3 -37
  93. package/build/cjs/tracing/utils.js.map +1 -1
  94. package/build/cjs/tracing/vercel-ai/constants.js +15 -23
  95. package/build/cjs/tracing/vercel-ai/constants.js.map +1 -1
  96. package/build/cjs/tracing/vercel-ai/index.js +32 -45
  97. package/build/cjs/tracing/vercel-ai/index.js.map +1 -1
  98. package/build/cjs/tracing/vercel-ai/utils.js +11 -42
  99. package/build/cjs/tracing/vercel-ai/utils.js.map +1 -1
  100. package/build/cjs/tracing/vercel-ai/vercel-ai-attributes.js +4 -1
  101. package/build/cjs/tracing/vercel-ai/vercel-ai-attributes.js.map +1 -1
  102. package/build/cjs/utils/browser.js +2 -3
  103. package/build/cjs/utils/browser.js.map +1 -1
  104. package/build/cjs/utils/featureFlags.js +6 -0
  105. package/build/cjs/utils/featureFlags.js.map +1 -1
  106. package/build/cjs/utils/object.js +33 -0
  107. package/build/cjs/utils/object.js.map +1 -1
  108. package/build/cjs/utils/spanUtils.js +116 -13
  109. package/build/cjs/utils/spanUtils.js.map +1 -1
  110. package/build/cjs/utils/stacktrace.js +3 -1
  111. package/build/cjs/utils/stacktrace.js.map +1 -1
  112. package/build/cjs/utils/string.js +3 -0
  113. package/build/cjs/utils/string.js.map +1 -1
  114. package/build/cjs/utils/version.js +1 -1
  115. package/build/cjs/utils/weakRef.js +62 -0
  116. package/build/cjs/utils/weakRef.js.map +1 -0
  117. package/build/esm/attributes.js +43 -1
  118. package/build/esm/attributes.js.map +1 -1
  119. package/build/esm/client.js +8 -1
  120. package/build/esm/client.js.map +1 -1
  121. package/build/esm/envelope.js +2 -1
  122. package/build/esm/envelope.js.map +1 -1
  123. package/build/esm/fetch.js +36 -17
  124. package/build/esm/fetch.js.map +1 -1
  125. package/build/esm/index.js +12 -3
  126. package/build/esm/index.js.map +1 -1
  127. package/build/esm/integration.js +6 -0
  128. package/build/esm/integration.js.map +1 -1
  129. package/build/esm/integrations/conversationId.js +11 -0
  130. package/build/esm/integrations/conversationId.js.map +1 -1
  131. package/build/esm/integrations/express/index.js +239 -0
  132. package/build/esm/integrations/express/index.js.map +1 -0
  133. package/build/esm/integrations/express/patch-layer.js +255 -0
  134. package/build/esm/integrations/express/patch-layer.js.map +1 -0
  135. package/build/esm/integrations/express/request-layer-store.js +22 -0
  136. package/build/esm/integrations/express/request-layer-store.js.map +1 -0
  137. package/build/esm/integrations/express/set-sdk-processing-metadata.js +15 -0
  138. package/build/esm/integrations/express/set-sdk-processing-metadata.js.map +1 -0
  139. package/build/esm/integrations/express/types.js +10 -0
  140. package/build/esm/integrations/express/types.js.map +1 -0
  141. package/build/esm/integrations/express/utils.js +225 -0
  142. package/build/esm/integrations/express/utils.js.map +1 -0
  143. package/build/esm/integrations/mcp-server/correlation.js +5 -1
  144. package/build/esm/integrations/mcp-server/correlation.js.map +1 -1
  145. package/build/esm/integrations/mcp-server/handlers.js +18 -10
  146. package/build/esm/integrations/mcp-server/handlers.js.map +1 -1
  147. package/build/esm/integrations/mcp-server/index.js +2 -1
  148. package/build/esm/integrations/mcp-server/index.js.map +1 -1
  149. package/build/esm/integrations/mcp-server/transport.js +1 -1
  150. package/build/esm/integrations/mcp-server/transport.js.map +1 -1
  151. package/build/esm/integrations/mcp-server/validation.js +7 -5
  152. package/build/esm/integrations/mcp-server/validation.js.map +1 -1
  153. package/build/esm/integrations/requestdata.js.map +1 -1
  154. package/build/esm/integrations/spanStreaming.js +46 -0
  155. package/build/esm/integrations/spanStreaming.js.map +1 -0
  156. package/build/esm/package.json +1 -1
  157. package/build/esm/semanticAttributes.js +26 -4
  158. package/build/esm/semanticAttributes.js.map +1 -1
  159. package/build/esm/tracing/ai/gen-ai-attributes.js +3 -76
  160. package/build/esm/tracing/ai/gen-ai-attributes.js.map +1 -1
  161. package/build/esm/tracing/ai/utils.js +73 -2
  162. package/build/esm/tracing/ai/utils.js.map +1 -1
  163. package/build/esm/tracing/anthropic-ai/index.js +8 -19
  164. package/build/esm/tracing/anthropic-ai/index.js.map +1 -1
  165. package/build/esm/tracing/anthropic-ai/streaming.js +3 -101
  166. package/build/esm/tracing/anthropic-ai/streaming.js.map +1 -1
  167. package/build/esm/tracing/anthropic-ai/utils.js +5 -3
  168. package/build/esm/tracing/anthropic-ai/utils.js.map +1 -1
  169. package/build/esm/tracing/dynamicSamplingContext.js +2 -1
  170. package/build/esm/tracing/dynamicSamplingContext.js.map +1 -1
  171. package/build/esm/tracing/google-genai/constants.js +2 -5
  172. package/build/esm/tracing/google-genai/constants.js.map +1 -1
  173. package/build/esm/tracing/google-genai/index.js +42 -37
  174. package/build/esm/tracing/google-genai/index.js.map +1 -1
  175. package/build/esm/tracing/google-genai/streaming.js +2 -23
  176. package/build/esm/tracing/google-genai/streaming.js.map +1 -1
  177. package/build/esm/tracing/langchain/embeddings.js +129 -0
  178. package/build/esm/tracing/langchain/embeddings.js.map +1 -0
  179. package/build/esm/tracing/langchain/index.js +4 -1
  180. package/build/esm/tracing/langchain/index.js.map +1 -1
  181. package/build/esm/tracing/langchain/utils.js +13 -5
  182. package/build/esm/tracing/langchain/utils.js.map +1 -1
  183. package/build/esm/tracing/langgraph/index.js +5 -4
  184. package/build/esm/tracing/langgraph/index.js.map +1 -1
  185. package/build/esm/tracing/openai/index.js +16 -36
  186. package/build/esm/tracing/openai/index.js.map +1 -1
  187. package/build/esm/tracing/openai/streaming.js +4 -35
  188. package/build/esm/tracing/openai/streaming.js.map +1 -1
  189. package/build/esm/tracing/openai/utils.js +79 -196
  190. package/build/esm/tracing/openai/utils.js.map +1 -1
  191. package/build/esm/tracing/sentryNonRecordingSpan.js +7 -0
  192. package/build/esm/tracing/sentryNonRecordingSpan.js.map +1 -1
  193. package/build/esm/tracing/sentrySpan.js +40 -1
  194. package/build/esm/tracing/sentrySpan.js.map +1 -1
  195. package/build/esm/tracing/spans/beforeSendSpan.js +40 -0
  196. package/build/esm/tracing/spans/beforeSendSpan.js.map +1 -0
  197. package/build/esm/tracing/spans/captureSpan.js +122 -0
  198. package/build/esm/tracing/spans/captureSpan.js.map +1 -0
  199. package/build/esm/tracing/spans/envelope.js +36 -0
  200. package/build/esm/tracing/spans/envelope.js.map +1 -0
  201. package/build/esm/tracing/spans/estimateSize.js +39 -0
  202. package/build/esm/tracing/spans/estimateSize.js.map +1 -0
  203. package/build/esm/tracing/spans/hasSpanStreamingEnabled.js +9 -0
  204. package/build/esm/tracing/spans/hasSpanStreamingEnabled.js.map +1 -0
  205. package/build/esm/tracing/spans/spanBuffer.js +156 -0
  206. package/build/esm/tracing/spans/spanBuffer.js.map +1 -0
  207. package/build/esm/tracing/trace.js +84 -14
  208. package/build/esm/tracing/trace.js.map +1 -1
  209. package/build/esm/tracing/utils.js +3 -37
  210. package/build/esm/tracing/utils.js.map +1 -1
  211. package/build/esm/tracing/vercel-ai/constants.js +15 -19
  212. package/build/esm/tracing/vercel-ai/constants.js.map +1 -1
  213. package/build/esm/tracing/vercel-ai/index.js +29 -42
  214. package/build/esm/tracing/vercel-ai/index.js.map +1 -1
  215. package/build/esm/tracing/vercel-ai/utils.js +14 -44
  216. package/build/esm/tracing/vercel-ai/utils.js.map +1 -1
  217. package/build/esm/tracing/vercel-ai/vercel-ai-attributes.js +4 -1
  218. package/build/esm/tracing/vercel-ai/vercel-ai-attributes.js.map +1 -1
  219. package/build/esm/utils/browser.js +2 -3
  220. package/build/esm/utils/browser.js.map +1 -1
  221. package/build/esm/utils/featureFlags.js +6 -0
  222. package/build/esm/utils/featureFlags.js.map +1 -1
  223. package/build/esm/utils/object.js +33 -1
  224. package/build/esm/utils/object.js.map +1 -1
  225. package/build/esm/utils/spanUtils.js +112 -14
  226. package/build/esm/utils/spanUtils.js.map +1 -1
  227. package/build/esm/utils/stacktrace.js +3 -1
  228. package/build/esm/utils/stacktrace.js.map +1 -1
  229. package/build/esm/utils/string.js +3 -0
  230. package/build/esm/utils/string.js.map +1 -1
  231. package/build/esm/utils/version.js +1 -1
  232. package/build/esm/utils/weakRef.js +59 -0
  233. package/build/esm/utils/weakRef.js.map +1 -0
  234. package/build/types/attributes.d.ts +5 -0
  235. package/build/types/attributes.d.ts.map +1 -1
  236. package/build/types/build-time-plugins/buildTimeOptionsBase.d.ts +13 -0
  237. package/build/types/build-time-plugins/buildTimeOptionsBase.d.ts.map +1 -1
  238. package/build/types/client.d.ts +35 -1
  239. package/build/types/client.d.ts.map +1 -1
  240. package/build/types/envelope.d.ts.map +1 -1
  241. package/build/types/fetch.d.ts +12 -8
  242. package/build/types/fetch.d.ts.map +1 -1
  243. package/build/types/index.d.ts +16 -5
  244. package/build/types/index.d.ts.map +1 -1
  245. package/build/types/integration.d.ts.map +1 -1
  246. package/build/types/integrations/conversationId.d.ts.map +1 -1
  247. package/build/types/integrations/express/index.d.ts +82 -0
  248. package/build/types/integrations/express/index.d.ts.map +1 -0
  249. package/build/types/integrations/express/patch-layer.d.ts +32 -0
  250. package/build/types/integrations/express/patch-layer.d.ts.map +1 -0
  251. package/build/types/integrations/express/request-layer-store.d.ts +32 -0
  252. package/build/types/integrations/express/request-layer-store.d.ts.map +1 -0
  253. package/build/types/integrations/express/set-sdk-processing-metadata.d.ts +35 -0
  254. package/build/types/integrations/express/set-sdk-processing-metadata.d.ts.map +1 -0
  255. package/build/types/integrations/express/types.d.ts +158 -0
  256. package/build/types/integrations/express/types.d.ts.map +1 -0
  257. package/build/types/integrations/express/utils.d.ts +93 -0
  258. package/build/types/integrations/express/utils.d.ts.map +1 -0
  259. package/build/types/integrations/mcp-server/correlation.d.ts +2 -1
  260. package/build/types/integrations/mcp-server/correlation.d.ts.map +1 -1
  261. package/build/types/integrations/mcp-server/handlers.d.ts +9 -4
  262. package/build/types/integrations/mcp-server/handlers.d.ts.map +1 -1
  263. package/build/types/integrations/mcp-server/index.d.ts +2 -1
  264. package/build/types/integrations/mcp-server/index.d.ts.map +1 -1
  265. package/build/types/integrations/mcp-server/types.d.ts +40 -7
  266. package/build/types/integrations/mcp-server/types.d.ts.map +1 -1
  267. package/build/types/integrations/mcp-server/validation.d.ts +4 -1
  268. package/build/types/integrations/mcp-server/validation.d.ts.map +1 -1
  269. package/build/types/integrations/requestdata.d.ts.map +1 -1
  270. package/build/types/integrations/spanStreaming.d.ts +2 -0
  271. package/build/types/integrations/spanStreaming.d.ts.map +1 -0
  272. package/build/types/semanticAttributes.d.ts +23 -3
  273. package/build/types/semanticAttributes.d.ts.map +1 -1
  274. package/build/types/tracing/ai/gen-ai-attributes.d.ts +4 -44
  275. package/build/types/tracing/ai/gen-ai-attributes.d.ts.map +1 -1
  276. package/build/types/tracing/ai/utils.d.ts +32 -2
  277. package/build/types/tracing/ai/utils.d.ts.map +1 -1
  278. package/build/types/tracing/anthropic-ai/index.d.ts.map +1 -1
  279. package/build/types/tracing/anthropic-ai/streaming.d.ts.map +1 -1
  280. package/build/types/tracing/anthropic-ai/types.d.ts +5 -0
  281. package/build/types/tracing/anthropic-ai/types.d.ts.map +1 -1
  282. package/build/types/tracing/anthropic-ai/utils.d.ts +1 -1
  283. package/build/types/tracing/anthropic-ai/utils.d.ts.map +1 -1
  284. package/build/types/tracing/dynamicSamplingContext.d.ts.map +1 -1
  285. package/build/types/tracing/google-genai/constants.d.ts +1 -3
  286. package/build/types/tracing/google-genai/constants.d.ts.map +1 -1
  287. package/build/types/tracing/google-genai/index.d.ts.map +1 -1
  288. package/build/types/tracing/google-genai/streaming.d.ts.map +1 -1
  289. package/build/types/tracing/google-genai/types.d.ts +5 -0
  290. package/build/types/tracing/google-genai/types.d.ts.map +1 -1
  291. package/build/types/tracing/index.d.ts +1 -0
  292. package/build/types/tracing/index.d.ts.map +1 -1
  293. package/build/types/tracing/langchain/embeddings.d.ts +27 -0
  294. package/build/types/tracing/langchain/embeddings.d.ts.map +1 -0
  295. package/build/types/tracing/langchain/index.d.ts +1 -0
  296. package/build/types/tracing/langchain/index.d.ts.map +1 -1
  297. package/build/types/tracing/langchain/types.d.ts +5 -0
  298. package/build/types/tracing/langchain/types.d.ts.map +1 -1
  299. package/build/types/tracing/langchain/utils.d.ts +2 -2
  300. package/build/types/tracing/langchain/utils.d.ts.map +1 -1
  301. package/build/types/tracing/langgraph/index.d.ts.map +1 -1
  302. package/build/types/tracing/langgraph/types.d.ts +5 -0
  303. package/build/types/tracing/langgraph/types.d.ts.map +1 -1
  304. package/build/types/tracing/openai/index.d.ts.map +1 -1
  305. package/build/types/tracing/openai/streaming.d.ts.map +1 -1
  306. package/build/types/tracing/openai/types.d.ts +5 -0
  307. package/build/types/tracing/openai/types.d.ts.map +1 -1
  308. package/build/types/tracing/openai/utils.d.ts +4 -49
  309. package/build/types/tracing/openai/utils.d.ts.map +1 -1
  310. package/build/types/tracing/sentryNonRecordingSpan.d.ts +12 -1
  311. package/build/types/tracing/sentryNonRecordingSpan.d.ts.map +1 -1
  312. package/build/types/tracing/sentrySpan.d.ts +10 -1
  313. package/build/types/tracing/sentrySpan.d.ts.map +1 -1
  314. package/build/types/tracing/spans/beforeSendSpan.d.ts +35 -0
  315. package/build/types/tracing/spans/beforeSendSpan.d.ts.map +1 -0
  316. package/build/types/tracing/spans/captureSpan.d.ts +26 -0
  317. package/build/types/tracing/spans/captureSpan.d.ts.map +1 -0
  318. package/build/types/tracing/spans/envelope.d.ts +8 -0
  319. package/build/types/tracing/spans/envelope.d.ts.map +1 -0
  320. package/build/types/tracing/spans/estimateSize.d.ts +12 -0
  321. package/build/types/tracing/spans/estimateSize.d.ts.map +1 -0
  322. package/build/types/tracing/spans/hasSpanStreamingEnabled.d.ts +6 -0
  323. package/build/types/tracing/spans/hasSpanStreamingEnabled.d.ts.map +1 -0
  324. package/build/types/tracing/spans/spanBuffer.d.ts +60 -0
  325. package/build/types/tracing/spans/spanBuffer.d.ts.map +1 -0
  326. package/build/types/tracing/trace.d.ts.map +1 -1
  327. package/build/types/tracing/utils.d.ts.map +1 -1
  328. package/build/types/tracing/vercel-ai/constants.d.ts +2 -5
  329. package/build/types/tracing/vercel-ai/constants.d.ts.map +1 -1
  330. package/build/types/tracing/vercel-ai/index.d.ts.map +1 -1
  331. package/build/types/tracing/vercel-ai/utils.d.ts +1 -5
  332. package/build/types/tracing/vercel-ai/utils.d.ts.map +1 -1
  333. package/build/types/tracing/vercel-ai/vercel-ai-attributes.d.ts +0 -480
  334. package/build/types/tracing/vercel-ai/vercel-ai-attributes.d.ts.map +1 -1
  335. package/build/types/types-hoist/envelope.d.ts +22 -2
  336. package/build/types/types-hoist/envelope.d.ts.map +1 -1
  337. package/build/types/types-hoist/integration.d.ts +8 -0
  338. package/build/types/types-hoist/integration.d.ts.map +1 -1
  339. package/build/types/types-hoist/link.d.ts +2 -2
  340. package/build/types/types-hoist/link.d.ts.map +1 -1
  341. package/build/types/types-hoist/options.d.ts +26 -2
  342. package/build/types/types-hoist/options.d.ts.map +1 -1
  343. package/build/types/types-hoist/span.d.ts +35 -0
  344. package/build/types/types-hoist/span.d.ts.map +1 -1
  345. package/build/types/types-hoist/view-hierarchy.d.ts +1 -0
  346. package/build/types/types-hoist/view-hierarchy.d.ts.map +1 -1
  347. package/build/types/utils/browser.d.ts +1 -1
  348. package/build/types/utils/browser.d.ts.map +1 -1
  349. package/build/types/utils/featureFlags.d.ts.map +1 -1
  350. package/build/types/utils/object.d.ts +10 -0
  351. package/build/types/utils/object.d.ts.map +1 -1
  352. package/build/types/utils/spanUtils.d.ts +27 -2
  353. package/build/types/utils/spanUtils.d.ts.map +1 -1
  354. package/build/types/utils/stacktrace.d.ts.map +1 -1
  355. package/build/types/utils/string.d.ts +2 -2
  356. package/build/types/utils/string.d.ts.map +1 -1
  357. package/build/types/utils/weakRef.d.ts +34 -0
  358. package/build/types/utils/weakRef.d.ts.map +1 -0
  359. package/build/types-ts3.8/attributes.d.ts +5 -0
  360. package/build/types-ts3.8/build-time-plugins/buildTimeOptionsBase.d.ts +13 -0
  361. package/build/types-ts3.8/client.d.ts +35 -1
  362. package/build/types-ts3.8/fetch.d.ts +14 -10
  363. package/build/types-ts3.8/index.d.ts +16 -5
  364. package/build/types-ts3.8/integrations/express/index.d.ts +82 -0
  365. package/build/types-ts3.8/integrations/express/patch-layer.d.ts +32 -0
  366. package/build/types-ts3.8/integrations/express/request-layer-store.d.ts +32 -0
  367. package/build/types-ts3.8/integrations/express/set-sdk-processing-metadata.d.ts +35 -0
  368. package/build/types-ts3.8/integrations/express/types.d.ts +158 -0
  369. package/build/types-ts3.8/integrations/express/utils.d.ts +96 -0
  370. package/build/types-ts3.8/integrations/mcp-server/correlation.d.ts +2 -1
  371. package/build/types-ts3.8/integrations/mcp-server/handlers.d.ts +9 -4
  372. package/build/types-ts3.8/integrations/mcp-server/index.d.ts +2 -1
  373. package/build/types-ts3.8/integrations/mcp-server/types.d.ts +40 -7
  374. package/build/types-ts3.8/integrations/mcp-server/validation.d.ts +4 -1
  375. package/build/types-ts3.8/integrations/spanStreaming.d.ts +2 -0
  376. package/build/types-ts3.8/semanticAttributes.d.ts +23 -3
  377. package/build/types-ts3.8/tracing/ai/gen-ai-attributes.d.ts +4 -44
  378. package/build/types-ts3.8/tracing/ai/utils.d.ts +32 -2
  379. package/build/types-ts3.8/tracing/anthropic-ai/types.d.ts +5 -0
  380. package/build/types-ts3.8/tracing/anthropic-ai/utils.d.ts +1 -1
  381. package/build/types-ts3.8/tracing/google-genai/constants.d.ts +1 -3
  382. package/build/types-ts3.8/tracing/google-genai/types.d.ts +5 -0
  383. package/build/types-ts3.8/tracing/index.d.ts +1 -0
  384. package/build/types-ts3.8/tracing/langchain/embeddings.d.ts +27 -0
  385. package/build/types-ts3.8/tracing/langchain/index.d.ts +1 -0
  386. package/build/types-ts3.8/tracing/langchain/types.d.ts +5 -0
  387. package/build/types-ts3.8/tracing/langchain/utils.d.ts +2 -2
  388. package/build/types-ts3.8/tracing/langgraph/types.d.ts +5 -0
  389. package/build/types-ts3.8/tracing/openai/types.d.ts +5 -0
  390. package/build/types-ts3.8/tracing/openai/utils.d.ts +4 -49
  391. package/build/types-ts3.8/tracing/sentryNonRecordingSpan.d.ts +12 -1
  392. package/build/types-ts3.8/tracing/sentrySpan.d.ts +10 -1
  393. package/build/types-ts3.8/tracing/spans/beforeSendSpan.d.ts +35 -0
  394. package/build/types-ts3.8/tracing/spans/captureSpan.d.ts +26 -0
  395. package/build/types-ts3.8/tracing/spans/envelope.d.ts +8 -0
  396. package/build/types-ts3.8/tracing/spans/estimateSize.d.ts +12 -0
  397. package/build/types-ts3.8/tracing/spans/hasSpanStreamingEnabled.d.ts +6 -0
  398. package/build/types-ts3.8/tracing/spans/spanBuffer.d.ts +60 -0
  399. package/build/types-ts3.8/tracing/vercel-ai/constants.d.ts +2 -5
  400. package/build/types-ts3.8/tracing/vercel-ai/utils.d.ts +1 -5
  401. package/build/types-ts3.8/tracing/vercel-ai/vercel-ai-attributes.d.ts +0 -480
  402. package/build/types-ts3.8/types-hoist/envelope.d.ts +22 -2
  403. package/build/types-ts3.8/types-hoist/integration.d.ts +8 -0
  404. package/build/types-ts3.8/types-hoist/link.d.ts +2 -2
  405. package/build/types-ts3.8/types-hoist/options.d.ts +26 -2
  406. package/build/types-ts3.8/types-hoist/span.d.ts +35 -0
  407. package/build/types-ts3.8/types-hoist/view-hierarchy.d.ts +1 -0
  408. package/build/types-ts3.8/utils/browser.d.ts +1 -1
  409. package/build/types-ts3.8/utils/object.d.ts +10 -0
  410. package/build/types-ts3.8/utils/spanUtils.d.ts +27 -2
  411. package/build/types-ts3.8/utils/string.d.ts +2 -2
  412. package/build/types-ts3.8/utils/weakRef.d.ts +34 -0
  413. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sources":["../../../../src/tracing/langchain/utils.ts"],"sourcesContent":["import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../../semanticAttributes';\nimport type { SpanAttributeValue } from '../../types-hoist/span';\nimport {\n GEN_AI_INPUT_MESSAGES_ATTRIBUTE,\n GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE,\n GEN_AI_OPERATION_NAME_ATTRIBUTE,\n GEN_AI_REQUEST_FREQUENCY_PENALTY_ATTRIBUTE,\n GEN_AI_REQUEST_MAX_TOKENS_ATTRIBUTE,\n GEN_AI_REQUEST_MODEL_ATTRIBUTE,\n GEN_AI_REQUEST_PRESENCE_PENALTY_ATTRIBUTE,\n GEN_AI_REQUEST_STREAM_ATTRIBUTE,\n GEN_AI_REQUEST_TEMPERATURE_ATTRIBUTE,\n GEN_AI_REQUEST_TOP_P_ATTRIBUTE,\n GEN_AI_RESPONSE_FINISH_REASONS_ATTRIBUTE,\n GEN_AI_RESPONSE_ID_ATTRIBUTE,\n GEN_AI_RESPONSE_MODEL_ATTRIBUTE,\n GEN_AI_RESPONSE_STOP_REASON_ATTRIBUTE,\n GEN_AI_RESPONSE_TEXT_ATTRIBUTE,\n GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE,\n GEN_AI_SYSTEM_ATTRIBUTE,\n GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE,\n GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS_ATTRIBUTE,\n GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS_ATTRIBUTE,\n GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE,\n GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE,\n GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE,\n} from '../ai/gen-ai-attributes';\nimport { isContentMedia, stripInlineMediaFromSingleMessage } from '../ai/mediaStripping';\nimport { truncateGenAiMessages } from '../ai/messageTruncation';\nimport { extractSystemInstructions } from '../ai/utils';\nimport { LANGCHAIN_ORIGIN, ROLE_MAP } from './constants';\nimport type { LangChainLLMResult, LangChainMessage, LangChainSerialized } from './types';\n\n/**\n * Assigns an attribute only when the value is neither `undefined` nor `null`.\n *\n * We keep this tiny helper because call sites are repetitive and easy to miswrite.\n * It also preserves falsy-but-valid values like `0` and `\"\"`.\n */\nconst setIfDefined = (target: Record<string, SpanAttributeValue>, key: string, value: unknown): void => {\n if (value != null) target[key] = value as SpanAttributeValue;\n};\n\n/**\n * Like `setIfDefined`, but converts the value with `Number()` and skips only when the\n * result is `NaN`. This ensures numeric 0 makes it through (unlike truthy checks).\n */\nconst setNumberIfDefined = (target: Record<string, SpanAttributeValue>, key: string, value: unknown): void => {\n const n = Number(value);\n if (!Number.isNaN(n)) target[key] = n;\n};\n\n/**\n * Converts a value to a string. Avoids double-quoted JSON strings where a plain\n * string is desired, but still handles objects/arrays safely.\n */\nfunction asString(v: unknown): string {\n if (typeof v === 'string') return v;\n try {\n return JSON.stringify(v);\n } catch {\n return String(v);\n }\n}\n\n/**\n * Converts message content to a string, stripping inline media (base64 images, audio, etc.)\n * from multimodal content before stringification so downstream media stripping can't miss it.\n *\n * @example\n * // String content passes through unchanged:\n * normalizeContent(\"Hello\") // => \"Hello\"\n *\n * // Multimodal array content — media is replaced with \"[Blob substitute]\" before JSON.stringify:\n * normalizeContent([\n * { type: \"text\", text: \"What color?\" },\n * { type: \"image_url\", image_url: { url: \"data:image/png;base64,iVBOR...\" } }\n * ])\n * // => '[{\"type\":\"text\",\"text\":\"What color?\"},{\"type\":\"image_url\",\"image_url\":{\"url\":\"[Blob substitute]\"}}]'\n *\n * // Without this, asString() would JSON.stringify the raw array and the base64 blob\n * // would end up in span attributes, since downstream stripping only works on objects.\n */\nfunction normalizeContent(v: unknown): string {\n if (Array.isArray(v)) {\n try {\n const stripped = v.map(part =>\n part && typeof part === 'object' && isContentMedia(part) ? stripInlineMediaFromSingleMessage(part) : part,\n );\n return JSON.stringify(stripped);\n } catch {\n return String(v);\n }\n }\n return asString(v);\n}\n\n/**\n * Normalizes a single role token to our canonical set.\n *\n * @param role Incoming role value (free-form, any casing)\n * @returns Canonical role: 'user' | 'assistant' | 'system' | 'function' | 'tool' | <passthrough>\n */\nfunction normalizeMessageRole(role: string): string {\n const normalized = role.toLowerCase();\n return ROLE_MAP[normalized] ?? normalized;\n}\n\n/**\n * Infers a role from a LangChain message constructor name.\n *\n * Checks for substrings like \"System\", \"Human\", \"AI\", etc.\n */\nfunction normalizeRoleNameFromCtor(name: string): string {\n if (name.includes('System')) return 'system';\n if (name.includes('Human')) return 'user';\n if (name.includes('AI') || name.includes('Assistant')) return 'assistant';\n if (name.includes('Function')) return 'function';\n if (name.includes('Tool')) return 'tool';\n return 'user';\n}\n\n/**\n * Returns invocation params from a LangChain `tags` object.\n *\n * LangChain often passes runtime parameters (model, temperature, etc.) via the\n * `tags.invocation_params` bag. If `tags` is an array (LangChain sometimes uses\n * string tags), we return `undefined`.\n *\n * @param tags LangChain tags (string[] or record)\n * @returns The `invocation_params` object, if present\n */\nexport function getInvocationParams(tags?: string[] | Record<string, unknown>): Record<string, unknown> | undefined {\n if (!tags || Array.isArray(tags)) return undefined;\n return tags.invocation_params as Record<string, unknown> | undefined;\n}\n\n/**\n * Normalizes a heterogeneous set of LangChain messages to `{ role, content }`.\n *\n * Why so many branches? LangChain messages can arrive in several shapes:\n * - Message classes with `_getType()` (most reliable)\n * - Classes with meaningful constructor names (e.g. `SystemMessage`)\n * - Plain objects with `type`, or `{ role, content }`\n * - Serialized format with `{ lc: 1, id: [...], kwargs: { content } }`\n * We preserve the prioritization to minimize behavioral drift.\n *\n * @param messages Mixed LangChain messages\n * @returns Array of normalized `{ role, content }`\n */\nexport function normalizeLangChainMessages(messages: LangChainMessage[]): Array<{ role: string; content: string }> {\n return messages.map(message => {\n // 1) Prefer _getType() when present\n const maybeGetType = (message as { _getType?: () => string })._getType;\n if (typeof maybeGetType === 'function') {\n const messageType = maybeGetType.call(message);\n return {\n role: normalizeMessageRole(messageType),\n content: normalizeContent(message.content),\n };\n }\n\n // 2) Serialized LangChain format (lc: 1) - check before constructor name\n // This is more reliable than constructor.name which can be lost during serialization\n if (message.lc === 1 && message.kwargs) {\n const id = message.id;\n const messageType = Array.isArray(id) && id.length > 0 ? id[id.length - 1] : '';\n const role = typeof messageType === 'string' ? normalizeRoleNameFromCtor(messageType) : 'user';\n\n return {\n role: normalizeMessageRole(role),\n content: normalizeContent(message.kwargs?.content),\n };\n }\n\n // 3) Then objects with `type`\n if (message.type) {\n const role = String(message.type).toLowerCase();\n return {\n role: normalizeMessageRole(role),\n content: normalizeContent(message.content),\n };\n }\n\n // 4) Then objects with `{ role, content }` - check before constructor name\n // Plain objects have constructor.name=\"Object\" which would incorrectly default to \"user\"\n if (message.role) {\n return {\n role: normalizeMessageRole(String(message.role)),\n content: normalizeContent(message.content),\n };\n }\n\n // 5) Then try constructor name (SystemMessage / HumanMessage / ...)\n // Only use this if we haven't matched a more specific case\n const ctor = (message as { constructor?: { name?: string } }).constructor?.name;\n if (ctor && ctor !== 'Object') {\n return {\n role: normalizeMessageRole(normalizeRoleNameFromCtor(ctor)),\n content: normalizeContent(message.content),\n };\n }\n\n // 6) Fallback: treat as user text\n return {\n role: 'user',\n content: normalizeContent(message.content),\n };\n });\n}\n\n/**\n * Extracts request attributes common to both LLM and ChatModel invocations.\n *\n * Source precedence:\n * 1) `invocationParams` (highest)\n * 2) `langSmithMetadata`\n *\n * Numeric values are set even when 0 (e.g. `temperature: 0`), but skipped if `NaN`.\n */\nfunction extractCommonRequestAttributes(\n serialized: LangChainSerialized,\n invocationParams?: Record<string, unknown>,\n langSmithMetadata?: Record<string, unknown>,\n): Record<string, SpanAttributeValue> {\n const attrs: Record<string, SpanAttributeValue> = {};\n\n // Get kwargs if available (from constructor type)\n const kwargs = 'kwargs' in serialized ? serialized.kwargs : undefined;\n\n const temperature = invocationParams?.temperature ?? langSmithMetadata?.ls_temperature ?? kwargs?.temperature;\n setNumberIfDefined(attrs, GEN_AI_REQUEST_TEMPERATURE_ATTRIBUTE, temperature);\n\n const maxTokens = invocationParams?.max_tokens ?? langSmithMetadata?.ls_max_tokens ?? kwargs?.max_tokens;\n setNumberIfDefined(attrs, GEN_AI_REQUEST_MAX_TOKENS_ATTRIBUTE, maxTokens);\n\n const topP = invocationParams?.top_p ?? kwargs?.top_p;\n setNumberIfDefined(attrs, GEN_AI_REQUEST_TOP_P_ATTRIBUTE, topP);\n\n const frequencyPenalty = invocationParams?.frequency_penalty;\n setNumberIfDefined(attrs, GEN_AI_REQUEST_FREQUENCY_PENALTY_ATTRIBUTE, frequencyPenalty);\n\n const presencePenalty = invocationParams?.presence_penalty;\n setNumberIfDefined(attrs, GEN_AI_REQUEST_PRESENCE_PENALTY_ATTRIBUTE, presencePenalty);\n\n // LangChain uses `stream`. We only set the attribute if the key actually exists\n // (some callbacks report `false` even on streamed requests, this stems from LangChain's callback handler).\n if (invocationParams && 'stream' in invocationParams) {\n setIfDefined(attrs, GEN_AI_REQUEST_STREAM_ATTRIBUTE, Boolean(invocationParams.stream));\n }\n\n return attrs;\n}\n\n/**\n * Small helper to assemble boilerplate attributes shared by both request extractors.\n * Always uses 'chat' as the operation type for all LLM and chat model operations.\n */\nfunction baseRequestAttributes(\n system: unknown,\n modelName: unknown,\n serialized: LangChainSerialized,\n invocationParams?: Record<string, unknown>,\n langSmithMetadata?: Record<string, unknown>,\n): Record<string, SpanAttributeValue> {\n return {\n [GEN_AI_SYSTEM_ATTRIBUTE]: asString(system ?? 'langchain'),\n [GEN_AI_OPERATION_NAME_ATTRIBUTE]: 'chat',\n [GEN_AI_REQUEST_MODEL_ATTRIBUTE]: asString(modelName),\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: LANGCHAIN_ORIGIN,\n ...extractCommonRequestAttributes(serialized, invocationParams, langSmithMetadata),\n };\n}\n\n/**\n * Extracts attributes for plain LLM invocations (string prompts).\n *\n * - Operation is tagged as `chat` following OpenTelemetry semantic conventions.\n * LangChain LLM operations are treated as chat operations.\n * - When `recordInputs` is true, string prompts are wrapped into `{role:\"user\"}`\n * messages to align with the chat schema used elsewhere.\n */\nexport function extractLLMRequestAttributes(\n llm: LangChainSerialized,\n prompts: string[],\n recordInputs: boolean,\n invocationParams?: Record<string, unknown>,\n langSmithMetadata?: Record<string, unknown>,\n): Record<string, SpanAttributeValue> {\n const system = langSmithMetadata?.ls_provider;\n const modelName = invocationParams?.model ?? langSmithMetadata?.ls_model_name ?? 'unknown';\n\n const attrs = baseRequestAttributes(system, modelName, llm, invocationParams, langSmithMetadata);\n\n if (recordInputs && Array.isArray(prompts) && prompts.length > 0) {\n setIfDefined(attrs, GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE, prompts.length);\n const messages = prompts.map(p => ({ role: 'user', content: p }));\n setIfDefined(attrs, GEN_AI_INPUT_MESSAGES_ATTRIBUTE, asString(messages));\n }\n\n return attrs;\n}\n\n/**\n * Extracts attributes for ChatModel invocations (array-of-arrays of messages).\n *\n * - Operation is tagged as `chat` following OpenTelemetry semantic conventions.\n * LangChain chat model operations are chat operations.\n * - We flatten LangChain's `LangChainMessage[][]` and normalize shapes into a\n * consistent `{ role, content }` array when `recordInputs` is true.\n * - Provider system value falls back to `serialized.id?.[2]`.\n */\nexport function extractChatModelRequestAttributes(\n llm: LangChainSerialized,\n langChainMessages: LangChainMessage[][],\n recordInputs: boolean,\n invocationParams?: Record<string, unknown>,\n langSmithMetadata?: Record<string, unknown>,\n): Record<string, SpanAttributeValue> {\n const system = langSmithMetadata?.ls_provider ?? llm.id?.[2];\n const modelName = invocationParams?.model ?? langSmithMetadata?.ls_model_name ?? 'unknown';\n\n const attrs = baseRequestAttributes(system, modelName, llm, invocationParams, langSmithMetadata);\n\n if (recordInputs && Array.isArray(langChainMessages) && langChainMessages.length > 0) {\n const normalized = normalizeLangChainMessages(langChainMessages.flat());\n\n const { systemInstructions, filteredMessages } = extractSystemInstructions(normalized);\n\n if (systemInstructions) {\n setIfDefined(attrs, GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE, systemInstructions);\n }\n\n const filteredLength = Array.isArray(filteredMessages) ? filteredMessages.length : 0;\n setIfDefined(attrs, GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE, filteredLength);\n\n const truncated = truncateGenAiMessages(filteredMessages as unknown[]);\n setIfDefined(attrs, GEN_AI_INPUT_MESSAGES_ATTRIBUTE, asString(truncated));\n }\n\n return attrs;\n}\n\n/**\n * Scans generations for Anthropic-style `tool_use` items and records them.\n *\n * LangChain represents some provider messages (e.g., Anthropic) with a `message.content`\n * array that may include objects `{ type: 'tool_use', ... }`. We collect and attach\n * them as a JSON array on `gen_ai.response.tool_calls` for downstream consumers.\n */\nfunction addToolCallsAttributes(generations: LangChainMessage[][], attrs: Record<string, SpanAttributeValue>): void {\n const toolCalls: unknown[] = [];\n const flatGenerations = generations.flat();\n\n for (const gen of flatGenerations) {\n const content = gen.message?.content;\n if (Array.isArray(content)) {\n for (const item of content) {\n const t = item as { type: string };\n if (t.type === 'tool_use') toolCalls.push(t);\n }\n }\n }\n\n if (toolCalls.length > 0) {\n setIfDefined(attrs, GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE, asString(toolCalls));\n }\n}\n\n/**\n * Adds token usage attributes, supporting both OpenAI (`tokenUsage`) and Anthropic (`usage`) formats.\n * - Preserve zero values (0 tokens) by avoiding truthy checks.\n * - Compute a total for Anthropic when not explicitly provided.\n * - Include cache token metrics when present.\n */\nfunction addTokenUsageAttributes(\n llmOutput: LangChainLLMResult['llmOutput'],\n attrs: Record<string, SpanAttributeValue>,\n): void {\n if (!llmOutput) return;\n\n const tokenUsage = llmOutput.tokenUsage as\n | { promptTokens?: number; completionTokens?: number; totalTokens?: number }\n | undefined;\n const anthropicUsage = llmOutput.usage as\n | {\n input_tokens?: number;\n output_tokens?: number;\n cache_creation_input_tokens?: number;\n cache_read_input_tokens?: number;\n }\n | undefined;\n\n if (tokenUsage) {\n setNumberIfDefined(attrs, GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE, tokenUsage.promptTokens);\n setNumberIfDefined(attrs, GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE, tokenUsage.completionTokens);\n setNumberIfDefined(attrs, GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE, tokenUsage.totalTokens);\n } else if (anthropicUsage) {\n setNumberIfDefined(attrs, GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE, anthropicUsage.input_tokens);\n setNumberIfDefined(attrs, GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE, anthropicUsage.output_tokens);\n\n // Compute total when not provided by the provider.\n const input = Number(anthropicUsage.input_tokens);\n const output = Number(anthropicUsage.output_tokens);\n const total = (Number.isNaN(input) ? 0 : input) + (Number.isNaN(output) ? 0 : output);\n if (total > 0) setNumberIfDefined(attrs, GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE, total);\n\n // Extra Anthropic cache metrics (present only when caching is enabled)\n if (anthropicUsage.cache_creation_input_tokens !== undefined)\n setNumberIfDefined(\n attrs,\n GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS_ATTRIBUTE,\n anthropicUsage.cache_creation_input_tokens,\n );\n if (anthropicUsage.cache_read_input_tokens !== undefined)\n setNumberIfDefined(attrs, GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS_ATTRIBUTE, anthropicUsage.cache_read_input_tokens);\n }\n}\n\n/**\n * Extracts response-related attributes based on a `LangChainLLMResult`.\n *\n * - Records finish reasons when present on generations (e.g., OpenAI)\n * - When `recordOutputs` is true, captures textual response content and any\n * tool calls.\n * - Also propagates model name (`model_name` or `model`), response `id`, and\n * `stop_reason` (for providers that use it).\n */\nexport function extractLlmResponseAttributes(\n llmResult: LangChainLLMResult,\n recordOutputs: boolean,\n): Record<string, SpanAttributeValue> | undefined {\n if (!llmResult) return;\n\n const attrs: Record<string, SpanAttributeValue> = {};\n\n if (Array.isArray(llmResult.generations)) {\n const finishReasons = llmResult.generations\n .flat()\n .map(g => {\n // v1 uses generationInfo.finish_reason\n if (g.generationInfo?.finish_reason) {\n return g.generationInfo.finish_reason;\n }\n // v0.3+ uses generation_info.finish_reason\n if (g.generation_info?.finish_reason) {\n return g.generation_info.finish_reason;\n }\n return null;\n })\n .filter((r): r is string => typeof r === 'string');\n\n if (finishReasons.length > 0) {\n setIfDefined(attrs, GEN_AI_RESPONSE_FINISH_REASONS_ATTRIBUTE, asString(finishReasons));\n }\n\n // Tool calls metadata (names, IDs) are not PII, so capture them regardless of recordOutputs\n addToolCallsAttributes(llmResult.generations as LangChainMessage[][], attrs);\n\n if (recordOutputs) {\n const texts = llmResult.generations\n .flat()\n .map(gen => gen.text ?? gen.message?.content)\n .filter(t => typeof t === 'string');\n\n if (texts.length > 0) {\n setIfDefined(attrs, GEN_AI_RESPONSE_TEXT_ATTRIBUTE, asString(texts));\n }\n }\n }\n\n addTokenUsageAttributes(llmResult.llmOutput, attrs);\n\n const llmOutput = llmResult.llmOutput;\n\n // Extract from v1 generations structure if available\n const firstGeneration = llmResult.generations?.[0]?.[0];\n const v1Message = firstGeneration?.message;\n\n // Provider model identifier: `model_name` (OpenAI-style) or `model` (others)\n // v1 stores this in message.response_metadata.model_name\n const modelName = llmOutput?.model_name ?? llmOutput?.model ?? v1Message?.response_metadata?.model_name;\n if (modelName) setIfDefined(attrs, GEN_AI_RESPONSE_MODEL_ATTRIBUTE, modelName);\n\n // Response ID: v1 stores this in message.id\n const responseId = llmOutput?.id ?? v1Message?.id;\n if (responseId) {\n setIfDefined(attrs, GEN_AI_RESPONSE_ID_ATTRIBUTE, responseId);\n }\n\n // Stop reason: v1 stores this in message.response_metadata.finish_reason\n const stopReason = llmOutput?.stop_reason ?? v1Message?.response_metadata?.finish_reason;\n if (stopReason) {\n setIfDefined(attrs, GEN_AI_RESPONSE_STOP_REASON_ATTRIBUTE, asString(stopReason));\n }\n\n return attrs;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","sources":["../../../../src/tracing/langchain/utils.ts"],"sourcesContent":["import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../../semanticAttributes';\nimport type { SpanAttributeValue } from '../../types-hoist/span';\nimport {\n GEN_AI_INPUT_MESSAGES_ATTRIBUTE,\n GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE,\n GEN_AI_OPERATION_NAME_ATTRIBUTE,\n GEN_AI_REQUEST_FREQUENCY_PENALTY_ATTRIBUTE,\n GEN_AI_REQUEST_MAX_TOKENS_ATTRIBUTE,\n GEN_AI_REQUEST_MODEL_ATTRIBUTE,\n GEN_AI_REQUEST_PRESENCE_PENALTY_ATTRIBUTE,\n GEN_AI_REQUEST_STREAM_ATTRIBUTE,\n GEN_AI_REQUEST_TEMPERATURE_ATTRIBUTE,\n GEN_AI_REQUEST_TOP_P_ATTRIBUTE,\n GEN_AI_RESPONSE_FINISH_REASONS_ATTRIBUTE,\n GEN_AI_RESPONSE_ID_ATTRIBUTE,\n GEN_AI_RESPONSE_MODEL_ATTRIBUTE,\n GEN_AI_RESPONSE_STOP_REASON_ATTRIBUTE,\n GEN_AI_RESPONSE_TEXT_ATTRIBUTE,\n GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE,\n GEN_AI_SYSTEM_ATTRIBUTE,\n GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE,\n GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS_ATTRIBUTE,\n GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS_ATTRIBUTE,\n GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE,\n GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE,\n GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE,\n} from '../ai/gen-ai-attributes';\nimport { isContentMedia, stripInlineMediaFromSingleMessage } from '../ai/mediaStripping';\nimport { extractSystemInstructions, getJsonString, getTruncatedJsonString } from '../ai/utils';\nimport { LANGCHAIN_ORIGIN, ROLE_MAP } from './constants';\nimport type { LangChainLLMResult, LangChainMessage, LangChainSerialized } from './types';\n\n/**\n * Assigns an attribute only when the value is neither `undefined` nor `null`.\n *\n * We keep this tiny helper because call sites are repetitive and easy to miswrite.\n * It also preserves falsy-but-valid values like `0` and `\"\"`.\n */\nconst setIfDefined = (target: Record<string, SpanAttributeValue>, key: string, value: unknown): void => {\n if (value != null) target[key] = value as SpanAttributeValue;\n};\n\n/**\n * Like `setIfDefined`, but converts the value with `Number()` and skips only when the\n * result is `NaN`. This ensures numeric 0 makes it through (unlike truthy checks).\n */\nconst setNumberIfDefined = (target: Record<string, SpanAttributeValue>, key: string, value: unknown): void => {\n const n = Number(value);\n if (!Number.isNaN(n)) target[key] = n;\n};\n\n/**\n * Converts a value to a string. Avoids double-quoted JSON strings where a plain\n * string is desired, but still handles objects/arrays safely.\n */\nfunction asString(v: unknown): string {\n if (typeof v === 'string') return v;\n try {\n return JSON.stringify(v);\n } catch {\n return String(v);\n }\n}\n\n/**\n * Converts message content to a string, stripping inline media (base64 images, audio, etc.)\n * from multimodal content before stringification so downstream media stripping can't miss it.\n *\n * @example\n * // String content passes through unchanged:\n * normalizeContent(\"Hello\") // => \"Hello\"\n *\n * // Multimodal array content — media is replaced with \"[Blob substitute]\" before JSON.stringify:\n * normalizeContent([\n * { type: \"text\", text: \"What color?\" },\n * { type: \"image_url\", image_url: { url: \"data:image/png;base64,iVBOR...\" } }\n * ])\n * // => '[{\"type\":\"text\",\"text\":\"What color?\"},{\"type\":\"image_url\",\"image_url\":{\"url\":\"[Blob substitute]\"}}]'\n *\n * // Without this, asString() would JSON.stringify the raw array and the base64 blob\n * // would end up in span attributes, since downstream stripping only works on objects.\n */\nfunction normalizeContent(v: unknown): string {\n if (Array.isArray(v)) {\n try {\n const stripped = v.map(part =>\n part && typeof part === 'object' && isContentMedia(part) ? stripInlineMediaFromSingleMessage(part) : part,\n );\n return JSON.stringify(stripped);\n } catch {\n return String(v);\n }\n }\n return asString(v);\n}\n\n/**\n * Normalizes a single role token to our canonical set.\n *\n * @param role Incoming role value (free-form, any casing)\n * @returns Canonical role: 'user' | 'assistant' | 'system' | 'function' | 'tool' | <passthrough>\n */\nfunction normalizeMessageRole(role: string): string {\n const normalized = role.toLowerCase();\n return ROLE_MAP[normalized] ?? normalized;\n}\n\n/**\n * Infers a role from a LangChain message constructor name.\n *\n * Checks for substrings like \"System\", \"Human\", \"AI\", etc.\n */\nfunction normalizeRoleNameFromCtor(name: string): string {\n if (name.includes('System')) return 'system';\n if (name.includes('Human')) return 'user';\n if (name.includes('AI') || name.includes('Assistant')) return 'assistant';\n if (name.includes('Function')) return 'function';\n if (name.includes('Tool')) return 'tool';\n return 'user';\n}\n\n/**\n * Returns invocation params from a LangChain `tags` object.\n *\n * LangChain often passes runtime parameters (model, temperature, etc.) via the\n * `tags.invocation_params` bag. If `tags` is an array (LangChain sometimes uses\n * string tags), we return `undefined`.\n *\n * @param tags LangChain tags (string[] or record)\n * @returns The `invocation_params` object, if present\n */\nexport function getInvocationParams(tags?: string[] | Record<string, unknown>): Record<string, unknown> | undefined {\n if (!tags || Array.isArray(tags)) return undefined;\n return tags.invocation_params as Record<string, unknown> | undefined;\n}\n\n/**\n * Normalizes a heterogeneous set of LangChain messages to `{ role, content }`.\n *\n * Why so many branches? LangChain messages can arrive in several shapes:\n * - Message classes with `_getType()` (most reliable)\n * - Classes with meaningful constructor names (e.g. `SystemMessage`)\n * - Plain objects with `type`, or `{ role, content }`\n * - Serialized format with `{ lc: 1, id: [...], kwargs: { content } }`\n * We preserve the prioritization to minimize behavioral drift.\n *\n * @param messages Mixed LangChain messages\n * @returns Array of normalized `{ role, content }`\n */\nexport function normalizeLangChainMessages(messages: LangChainMessage[]): Array<{ role: string; content: string }> {\n return messages.map(message => {\n // 1) Prefer _getType() when present\n const maybeGetType = (message as { _getType?: () => string })._getType;\n if (typeof maybeGetType === 'function') {\n const messageType = maybeGetType.call(message);\n return {\n role: normalizeMessageRole(messageType),\n content: normalizeContent(message.content),\n };\n }\n\n // 2) Serialized LangChain format (lc: 1) - check before constructor name\n // This is more reliable than constructor.name which can be lost during serialization\n if (message.lc === 1 && message.kwargs) {\n const id = message.id;\n const messageType = Array.isArray(id) && id.length > 0 ? id[id.length - 1] : '';\n const role = typeof messageType === 'string' ? normalizeRoleNameFromCtor(messageType) : 'user';\n\n return {\n role: normalizeMessageRole(role),\n content: normalizeContent(message.kwargs?.content),\n };\n }\n\n // 3) Then objects with `type`\n if (message.type) {\n const role = String(message.type).toLowerCase();\n return {\n role: normalizeMessageRole(role),\n content: normalizeContent(message.content),\n };\n }\n\n // 4) Then objects with `{ role, content }` - check before constructor name\n // Plain objects have constructor.name=\"Object\" which would incorrectly default to \"user\"\n if (message.role) {\n return {\n role: normalizeMessageRole(String(message.role)),\n content: normalizeContent(message.content),\n };\n }\n\n // 5) Then try constructor name (SystemMessage / HumanMessage / ...)\n // Only use this if we haven't matched a more specific case\n const ctor = (message as { constructor?: { name?: string } }).constructor?.name;\n if (ctor && ctor !== 'Object') {\n return {\n role: normalizeMessageRole(normalizeRoleNameFromCtor(ctor)),\n content: normalizeContent(message.content),\n };\n }\n\n // 6) Fallback: treat as user text\n return {\n role: 'user',\n content: normalizeContent(message.content),\n };\n });\n}\n\n/**\n * Extracts request attributes common to both LLM and ChatModel invocations.\n *\n * Source precedence:\n * 1) `invocationParams` (highest)\n * 2) `langSmithMetadata`\n *\n * Numeric values are set even when 0 (e.g. `temperature: 0`), but skipped if `NaN`.\n */\nfunction extractCommonRequestAttributes(\n serialized: LangChainSerialized,\n invocationParams?: Record<string, unknown>,\n langSmithMetadata?: Record<string, unknown>,\n): Record<string, SpanAttributeValue> {\n const attrs: Record<string, SpanAttributeValue> = {};\n\n // Get kwargs if available (from constructor type)\n const kwargs = 'kwargs' in serialized ? serialized.kwargs : undefined;\n\n const temperature = invocationParams?.temperature ?? langSmithMetadata?.ls_temperature ?? kwargs?.temperature;\n setNumberIfDefined(attrs, GEN_AI_REQUEST_TEMPERATURE_ATTRIBUTE, temperature);\n\n const maxTokens = invocationParams?.max_tokens ?? langSmithMetadata?.ls_max_tokens ?? kwargs?.max_tokens;\n setNumberIfDefined(attrs, GEN_AI_REQUEST_MAX_TOKENS_ATTRIBUTE, maxTokens);\n\n const topP = invocationParams?.top_p ?? kwargs?.top_p;\n setNumberIfDefined(attrs, GEN_AI_REQUEST_TOP_P_ATTRIBUTE, topP);\n\n const frequencyPenalty = invocationParams?.frequency_penalty;\n setNumberIfDefined(attrs, GEN_AI_REQUEST_FREQUENCY_PENALTY_ATTRIBUTE, frequencyPenalty);\n\n const presencePenalty = invocationParams?.presence_penalty;\n setNumberIfDefined(attrs, GEN_AI_REQUEST_PRESENCE_PENALTY_ATTRIBUTE, presencePenalty);\n\n // LangChain uses `stream`. We only set the attribute if the key actually exists\n // (some callbacks report `false` even on streamed requests, this stems from LangChain's callback handler).\n if (invocationParams && 'stream' in invocationParams) {\n setIfDefined(attrs, GEN_AI_REQUEST_STREAM_ATTRIBUTE, Boolean(invocationParams.stream));\n }\n\n return attrs;\n}\n\n/**\n * Small helper to assemble boilerplate attributes shared by both request extractors.\n * Always uses 'chat' as the operation type for all LLM and chat model operations.\n */\nfunction baseRequestAttributes(\n system: unknown,\n modelName: unknown,\n serialized: LangChainSerialized,\n invocationParams?: Record<string, unknown>,\n langSmithMetadata?: Record<string, unknown>,\n): Record<string, SpanAttributeValue> {\n return {\n [GEN_AI_SYSTEM_ATTRIBUTE]: asString(system ?? 'langchain'),\n [GEN_AI_OPERATION_NAME_ATTRIBUTE]: 'chat',\n [GEN_AI_REQUEST_MODEL_ATTRIBUTE]: asString(modelName),\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: LANGCHAIN_ORIGIN,\n ...extractCommonRequestAttributes(serialized, invocationParams, langSmithMetadata),\n };\n}\n\n/**\n * Extracts attributes for plain LLM invocations (string prompts).\n *\n * - Operation is tagged as `chat` following OpenTelemetry semantic conventions.\n * LangChain LLM operations are treated as chat operations.\n * - When `recordInputs` is true, string prompts are wrapped into `{role:\"user\"}`\n * messages to align with the chat schema used elsewhere.\n */\nexport function extractLLMRequestAttributes(\n llm: LangChainSerialized,\n prompts: string[],\n recordInputs: boolean,\n enableTruncation: boolean,\n invocationParams?: Record<string, unknown>,\n langSmithMetadata?: Record<string, unknown>,\n): Record<string, SpanAttributeValue> {\n const system = langSmithMetadata?.ls_provider;\n const modelName = invocationParams?.model ?? langSmithMetadata?.ls_model_name ?? 'unknown';\n\n const attrs = baseRequestAttributes(system, modelName, llm, invocationParams, langSmithMetadata);\n\n if (recordInputs && Array.isArray(prompts) && prompts.length > 0) {\n setIfDefined(attrs, GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE, prompts.length);\n const messages = prompts.map(p => ({ role: 'user', content: p }));\n setIfDefined(\n attrs,\n GEN_AI_INPUT_MESSAGES_ATTRIBUTE,\n enableTruncation ? getTruncatedJsonString(messages) : getJsonString(messages),\n );\n }\n\n return attrs;\n}\n\n/**\n * Extracts attributes for ChatModel invocations (array-of-arrays of messages).\n *\n * - Operation is tagged as `chat` following OpenTelemetry semantic conventions.\n * LangChain chat model operations are chat operations.\n * - We flatten LangChain's `LangChainMessage[][]` and normalize shapes into a\n * consistent `{ role, content }` array when `recordInputs` is true.\n * - Provider system value falls back to `serialized.id?.[2]`.\n */\nexport function extractChatModelRequestAttributes(\n llm: LangChainSerialized,\n langChainMessages: LangChainMessage[][],\n recordInputs: boolean,\n enableTruncation: boolean,\n invocationParams?: Record<string, unknown>,\n langSmithMetadata?: Record<string, unknown>,\n): Record<string, SpanAttributeValue> {\n const system = langSmithMetadata?.ls_provider ?? llm.id?.[2];\n const modelName = invocationParams?.model ?? langSmithMetadata?.ls_model_name ?? 'unknown';\n\n const attrs = baseRequestAttributes(system, modelName, llm, invocationParams, langSmithMetadata);\n\n if (recordInputs && Array.isArray(langChainMessages) && langChainMessages.length > 0) {\n const normalized = normalizeLangChainMessages(langChainMessages.flat());\n\n const { systemInstructions, filteredMessages } = extractSystemInstructions(normalized);\n\n if (systemInstructions) {\n setIfDefined(attrs, GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE, systemInstructions);\n }\n\n const filteredLength = Array.isArray(filteredMessages) ? filteredMessages.length : 0;\n setIfDefined(attrs, GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE, filteredLength);\n\n setIfDefined(\n attrs,\n GEN_AI_INPUT_MESSAGES_ATTRIBUTE,\n enableTruncation ? getTruncatedJsonString(filteredMessages) : getJsonString(filteredMessages),\n );\n }\n\n return attrs;\n}\n\n/**\n * Scans generations for Anthropic-style `tool_use` items and records them.\n *\n * LangChain represents some provider messages (e.g., Anthropic) with a `message.content`\n * array that may include objects `{ type: 'tool_use', ... }`. We collect and attach\n * them as a JSON array on `gen_ai.response.tool_calls` for downstream consumers.\n */\nfunction addToolCallsAttributes(generations: LangChainMessage[][], attrs: Record<string, SpanAttributeValue>): void {\n const toolCalls: unknown[] = [];\n const flatGenerations = generations.flat();\n\n for (const gen of flatGenerations) {\n const content = gen.message?.content;\n if (Array.isArray(content)) {\n for (const item of content) {\n const t = item as { type: string };\n if (t.type === 'tool_use') toolCalls.push(t);\n }\n }\n }\n\n if (toolCalls.length > 0) {\n setIfDefined(attrs, GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE, asString(toolCalls));\n }\n}\n\n/**\n * Adds token usage attributes, supporting both OpenAI (`tokenUsage`) and Anthropic (`usage`) formats.\n * - Preserve zero values (0 tokens) by avoiding truthy checks.\n * - Compute a total for Anthropic when not explicitly provided.\n * - Include cache token metrics when present.\n */\nfunction addTokenUsageAttributes(\n llmOutput: LangChainLLMResult['llmOutput'],\n attrs: Record<string, SpanAttributeValue>,\n): void {\n if (!llmOutput) return;\n\n const tokenUsage = llmOutput.tokenUsage as\n | { promptTokens?: number; completionTokens?: number; totalTokens?: number }\n | undefined;\n const anthropicUsage = llmOutput.usage as\n | {\n input_tokens?: number;\n output_tokens?: number;\n cache_creation_input_tokens?: number;\n cache_read_input_tokens?: number;\n }\n | undefined;\n\n if (tokenUsage) {\n setNumberIfDefined(attrs, GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE, tokenUsage.promptTokens);\n setNumberIfDefined(attrs, GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE, tokenUsage.completionTokens);\n setNumberIfDefined(attrs, GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE, tokenUsage.totalTokens);\n } else if (anthropicUsage) {\n setNumberIfDefined(attrs, GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE, anthropicUsage.input_tokens);\n setNumberIfDefined(attrs, GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE, anthropicUsage.output_tokens);\n\n // Compute total when not provided by the provider.\n const input = Number(anthropicUsage.input_tokens);\n const output = Number(anthropicUsage.output_tokens);\n const total = (Number.isNaN(input) ? 0 : input) + (Number.isNaN(output) ? 0 : output);\n if (total > 0) setNumberIfDefined(attrs, GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE, total);\n\n // Extra Anthropic cache metrics (present only when caching is enabled)\n if (anthropicUsage.cache_creation_input_tokens !== undefined)\n setNumberIfDefined(\n attrs,\n GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS_ATTRIBUTE,\n anthropicUsage.cache_creation_input_tokens,\n );\n if (anthropicUsage.cache_read_input_tokens !== undefined)\n setNumberIfDefined(attrs, GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS_ATTRIBUTE, anthropicUsage.cache_read_input_tokens);\n }\n}\n\n/**\n * Extracts response-related attributes based on a `LangChainLLMResult`.\n *\n * - Records finish reasons when present on generations (e.g., OpenAI)\n * - When `recordOutputs` is true, captures textual response content and any\n * tool calls.\n * - Also propagates model name (`model_name` or `model`), response `id`, and\n * `stop_reason` (for providers that use it).\n */\nexport function extractLlmResponseAttributes(\n llmResult: LangChainLLMResult,\n recordOutputs: boolean,\n): Record<string, SpanAttributeValue> | undefined {\n if (!llmResult) return;\n\n const attrs: Record<string, SpanAttributeValue> = {};\n\n if (Array.isArray(llmResult.generations)) {\n const finishReasons = llmResult.generations\n .flat()\n .map(g => {\n // v1 uses generationInfo.finish_reason\n if (g.generationInfo?.finish_reason) {\n return g.generationInfo.finish_reason;\n }\n // v0.3+ uses generation_info.finish_reason\n if (g.generation_info?.finish_reason) {\n return g.generation_info.finish_reason;\n }\n return null;\n })\n .filter((r): r is string => typeof r === 'string');\n\n if (finishReasons.length > 0) {\n setIfDefined(attrs, GEN_AI_RESPONSE_FINISH_REASONS_ATTRIBUTE, asString(finishReasons));\n }\n\n // Tool calls metadata (names, IDs) are not PII, so capture them regardless of recordOutputs\n addToolCallsAttributes(llmResult.generations as LangChainMessage[][], attrs);\n\n if (recordOutputs) {\n const texts = llmResult.generations\n .flat()\n .map(gen => gen.text ?? gen.message?.content)\n .filter(t => typeof t === 'string');\n\n if (texts.length > 0) {\n setIfDefined(attrs, GEN_AI_RESPONSE_TEXT_ATTRIBUTE, asString(texts));\n }\n }\n }\n\n addTokenUsageAttributes(llmResult.llmOutput, attrs);\n\n const llmOutput = llmResult.llmOutput;\n\n // Extract from v1 generations structure if available\n const firstGeneration = llmResult.generations?.[0]?.[0];\n const v1Message = firstGeneration?.message;\n\n // Provider model identifier: `model_name` (OpenAI-style) or `model` (others)\n // v1 stores this in message.response_metadata.model_name\n const modelName = llmOutput?.model_name ?? llmOutput?.model ?? v1Message?.response_metadata?.model_name;\n if (modelName) setIfDefined(attrs, GEN_AI_RESPONSE_MODEL_ATTRIBUTE, modelName);\n\n // Response ID: v1 stores this in message.id\n const responseId = llmOutput?.id ?? v1Message?.id;\n if (responseId) {\n setIfDefined(attrs, GEN_AI_RESPONSE_ID_ATTRIBUTE, responseId);\n }\n\n // Stop reason: v1 stores this in message.response_metadata.finish_reason\n const stopReason = llmOutput?.stop_reason ?? v1Message?.response_metadata?.finish_reason;\n if (stopReason) {\n setIfDefined(attrs, GEN_AI_RESPONSE_STOP_REASON_ATTRIBUTE, asString(stopReason));\n }\n\n return attrs;\n}\n"],"names":[],"mappings":"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"}
@@ -3,8 +3,7 @@ import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '
3
3
  import { SPAN_STATUS_ERROR } from '../spanstatus.js';
4
4
  import { startSpan } from '../trace.js';
5
5
  import { GEN_AI_AGENT_NAME_ATTRIBUTE, GEN_AI_OPERATION_NAME_ATTRIBUTE, GEN_AI_PIPELINE_NAME_ATTRIBUTE, GEN_AI_CONVERSATION_ID_ATTRIBUTE, GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE, GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE, GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE, GEN_AI_INPUT_MESSAGES_ATTRIBUTE, GEN_AI_INVOKE_AGENT_OPERATION_ATTRIBUTE } from '../ai/gen-ai-attributes.js';
6
- import { truncateGenAiMessages } from '../ai/messageTruncation.js';
7
- import { resolveAIRecordingOptions, extractSystemInstructions } from '../ai/utils.js';
6
+ import { resolveAIRecordingOptions, extractSystemInstructions, shouldEnableTruncation, getTruncatedJsonString, getJsonString } from '../ai/utils.js';
8
7
  import { normalizeLangChainMessages } from '../langchain/utils.js';
9
8
  import { LANGGRAPH_ORIGIN } from './constants.js';
10
9
  import { extractToolsFromCompiledGraph, setResponseAttributes } from './utils.js';
@@ -134,10 +133,12 @@ function instrumentCompiledGraphInvoke(
134
133
  span.setAttribute(GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE, systemInstructions);
135
134
  }
136
135
 
137
- const truncatedMessages = truncateGenAiMessages(filteredMessages );
136
+ const enableTruncation = shouldEnableTruncation(options.enableTruncation);
138
137
  const filteredLength = Array.isArray(filteredMessages) ? filteredMessages.length : 0;
139
138
  span.setAttributes({
140
- [GEN_AI_INPUT_MESSAGES_ATTRIBUTE]: JSON.stringify(truncatedMessages),
139
+ [GEN_AI_INPUT_MESSAGES_ATTRIBUTE]: enableTruncation
140
+ ? getTruncatedJsonString(filteredMessages)
141
+ : getJsonString(filteredMessages),
141
142
  [GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE]: filteredLength,
142
143
  });
143
144
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../src/tracing/langgraph/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 {\n GEN_AI_AGENT_NAME_ATTRIBUTE,\n GEN_AI_CONVERSATION_ID_ATTRIBUTE,\n GEN_AI_INPUT_MESSAGES_ATTRIBUTE,\n GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE,\n GEN_AI_INVOKE_AGENT_OPERATION_ATTRIBUTE,\n GEN_AI_OPERATION_NAME_ATTRIBUTE,\n GEN_AI_PIPELINE_NAME_ATTRIBUTE,\n GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE,\n GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE,\n} from '../ai/gen-ai-attributes';\nimport { truncateGenAiMessages } from '../ai/messageTruncation';\nimport { extractSystemInstructions, resolveAIRecordingOptions } from '../ai/utils';\nimport type { LangChainMessage } from '../langchain/types';\nimport { normalizeLangChainMessages } from '../langchain/utils';\nimport { startSpan } from '../trace';\nimport { LANGGRAPH_ORIGIN } from './constants';\nimport type { CompiledGraph, LangGraphOptions } from './types';\nimport { extractToolsFromCompiledGraph, setResponseAttributes } from './utils';\n\n/**\n * Instruments StateGraph's compile method to create spans for agent creation and invocation\n *\n * Wraps the compile() method to:\n * - Create a `gen_ai.create_agent` span when compile() is called\n * - Automatically wrap the invoke() method on the returned compiled graph with a `gen_ai.invoke_agent` span\n *\n */\nexport function instrumentStateGraphCompile(\n originalCompile: (...args: unknown[]) => CompiledGraph,\n options: LangGraphOptions,\n): (...args: unknown[]) => CompiledGraph {\n return new Proxy(originalCompile, {\n apply(target, thisArg, args: unknown[]): CompiledGraph {\n return startSpan(\n {\n op: 'gen_ai.create_agent',\n name: 'create_agent',\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: LANGGRAPH_ORIGIN,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'gen_ai.create_agent',\n [GEN_AI_OPERATION_NAME_ATTRIBUTE]: 'create_agent',\n },\n },\n span => {\n try {\n const compiledGraph = Reflect.apply(target, thisArg, args);\n const compileOptions = args.length > 0 ? (args[0] as Record<string, unknown>) : {};\n\n // Extract graph name\n if (compileOptions?.name && typeof compileOptions.name === 'string') {\n span.setAttribute(GEN_AI_AGENT_NAME_ATTRIBUTE, compileOptions.name);\n span.updateName(`create_agent ${compileOptions.name}`);\n }\n\n // Instrument agent invoke method on the compiled graph\n const originalInvoke = compiledGraph.invoke;\n if (originalInvoke && typeof originalInvoke === 'function') {\n compiledGraph.invoke = instrumentCompiledGraphInvoke(\n originalInvoke.bind(compiledGraph) as (...args: unknown[]) => Promise<unknown>,\n compiledGraph,\n compileOptions,\n options,\n ) as typeof originalInvoke;\n }\n\n return compiledGraph;\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.langgraph.error',\n },\n });\n throw error;\n }\n },\n );\n },\n }) as (...args: unknown[]) => CompiledGraph;\n}\n\n/**\n * Instruments CompiledGraph's invoke method to create spans for agent invocation\n *\n * Creates a `gen_ai.invoke_agent` span when invoke() is called\n */\nfunction instrumentCompiledGraphInvoke(\n originalInvoke: (...args: unknown[]) => Promise<unknown>,\n graphInstance: CompiledGraph,\n compileOptions: Record<string, unknown>,\n options: LangGraphOptions,\n): (...args: unknown[]) => Promise<unknown> {\n return new Proxy(originalInvoke, {\n apply(target, thisArg, args: unknown[]): Promise<unknown> {\n return startSpan(\n {\n op: 'gen_ai.invoke_agent',\n name: 'invoke_agent',\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: LANGGRAPH_ORIGIN,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: GEN_AI_INVOKE_AGENT_OPERATION_ATTRIBUTE,\n [GEN_AI_OPERATION_NAME_ATTRIBUTE]: 'invoke_agent',\n },\n },\n async span => {\n try {\n const graphName = compileOptions?.name;\n\n if (graphName && typeof graphName === 'string') {\n span.setAttribute(GEN_AI_PIPELINE_NAME_ATTRIBUTE, graphName);\n span.setAttribute(GEN_AI_AGENT_NAME_ATTRIBUTE, graphName);\n span.updateName(`invoke_agent ${graphName}`);\n }\n\n // Extract thread_id from the config (second argument)\n // LangGraph uses config.configurable.thread_id for conversation/session linking\n const config = args.length > 1 ? (args[1] as Record<string, unknown> | undefined) : undefined;\n const configurable = config?.configurable as Record<string, unknown> | undefined;\n const threadId = configurable?.thread_id;\n if (threadId && typeof threadId === 'string') {\n span.setAttribute(GEN_AI_CONVERSATION_ID_ATTRIBUTE, threadId);\n }\n\n // Extract available tools from the graph instance\n const tools = extractToolsFromCompiledGraph(graphInstance);\n if (tools) {\n span.setAttribute(GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE, JSON.stringify(tools));\n }\n\n // Parse input messages\n const recordInputs = options.recordInputs;\n const recordOutputs = options.recordOutputs;\n const inputMessages =\n args.length > 0 ? ((args[0] as { messages?: LangChainMessage[] } | null)?.messages ?? []) : [];\n\n if (inputMessages && recordInputs) {\n const normalizedMessages = normalizeLangChainMessages(inputMessages);\n const { systemInstructions, filteredMessages } = extractSystemInstructions(normalizedMessages);\n\n if (systemInstructions) {\n span.setAttribute(GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE, systemInstructions);\n }\n\n const truncatedMessages = truncateGenAiMessages(filteredMessages as unknown[]);\n const filteredLength = Array.isArray(filteredMessages) ? filteredMessages.length : 0;\n span.setAttributes({\n [GEN_AI_INPUT_MESSAGES_ATTRIBUTE]: JSON.stringify(truncatedMessages),\n [GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE]: filteredLength,\n });\n }\n\n // Call original invoke\n const result = await Reflect.apply(target, thisArg, args);\n\n // Set response attributes\n if (recordOutputs) {\n setResponseAttributes(span, inputMessages ?? null, result);\n }\n\n return result;\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.langgraph.error',\n },\n });\n throw error;\n }\n },\n );\n },\n }) as (...args: unknown[]) => Promise<unknown>;\n}\n\n/**\n * Directly instruments a StateGraph instance to add tracing spans\n *\n * This function can be used to manually instrument LangGraph StateGraph instances\n * in environments where automatic instrumentation is not available or desired.\n *\n * @param stateGraph - The StateGraph instance to instrument\n * @param options - Optional configuration for recording inputs/outputs\n *\n * @example\n * ```typescript\n * import { instrumentLangGraph } from '@sentry/cloudflare';\n * import { StateGraph } from '@langchain/langgraph';\n *\n * const graph = new StateGraph(MessagesAnnotation)\n * .addNode('agent', mockLlm)\n * .addEdge(START, 'agent')\n * .addEdge('agent', END);\n *\n * instrumentLangGraph(graph, { recordInputs: true, recordOutputs: true });\n * const compiled = graph.compile({ name: 'my_agent' });\n * ```\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function instrumentLangGraph<T extends { compile: (...args: any[]) => any }>(\n stateGraph: T,\n options?: LangGraphOptions,\n): T {\n stateGraph.compile = instrumentStateGraphCompile(stateGraph.compile, resolveAIRecordingOptions(options));\n\n return stateGraph;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../../../src/tracing/langgraph/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 {\n GEN_AI_AGENT_NAME_ATTRIBUTE,\n GEN_AI_CONVERSATION_ID_ATTRIBUTE,\n GEN_AI_INPUT_MESSAGES_ATTRIBUTE,\n GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE,\n GEN_AI_INVOKE_AGENT_OPERATION_ATTRIBUTE,\n GEN_AI_OPERATION_NAME_ATTRIBUTE,\n GEN_AI_PIPELINE_NAME_ATTRIBUTE,\n GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE,\n GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE,\n} from '../ai/gen-ai-attributes';\nimport {\n extractSystemInstructions,\n getJsonString,\n getTruncatedJsonString,\n resolveAIRecordingOptions,\n shouldEnableTruncation,\n} from '../ai/utils';\nimport type { LangChainMessage } from '../langchain/types';\nimport { normalizeLangChainMessages } from '../langchain/utils';\nimport { startSpan } from '../trace';\nimport { LANGGRAPH_ORIGIN } from './constants';\nimport type { CompiledGraph, LangGraphOptions } from './types';\nimport { extractToolsFromCompiledGraph, setResponseAttributes } from './utils';\n\n/**\n * Instruments StateGraph's compile method to create spans for agent creation and invocation\n *\n * Wraps the compile() method to:\n * - Create a `gen_ai.create_agent` span when compile() is called\n * - Automatically wrap the invoke() method on the returned compiled graph with a `gen_ai.invoke_agent` span\n *\n */\nexport function instrumentStateGraphCompile(\n originalCompile: (...args: unknown[]) => CompiledGraph,\n options: LangGraphOptions,\n): (...args: unknown[]) => CompiledGraph {\n return new Proxy(originalCompile, {\n apply(target, thisArg, args: unknown[]): CompiledGraph {\n return startSpan(\n {\n op: 'gen_ai.create_agent',\n name: 'create_agent',\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: LANGGRAPH_ORIGIN,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'gen_ai.create_agent',\n [GEN_AI_OPERATION_NAME_ATTRIBUTE]: 'create_agent',\n },\n },\n span => {\n try {\n const compiledGraph = Reflect.apply(target, thisArg, args);\n const compileOptions = args.length > 0 ? (args[0] as Record<string, unknown>) : {};\n\n // Extract graph name\n if (compileOptions?.name && typeof compileOptions.name === 'string') {\n span.setAttribute(GEN_AI_AGENT_NAME_ATTRIBUTE, compileOptions.name);\n span.updateName(`create_agent ${compileOptions.name}`);\n }\n\n // Instrument agent invoke method on the compiled graph\n const originalInvoke = compiledGraph.invoke;\n if (originalInvoke && typeof originalInvoke === 'function') {\n compiledGraph.invoke = instrumentCompiledGraphInvoke(\n originalInvoke.bind(compiledGraph) as (...args: unknown[]) => Promise<unknown>,\n compiledGraph,\n compileOptions,\n options,\n ) as typeof originalInvoke;\n }\n\n return compiledGraph;\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.langgraph.error',\n },\n });\n throw error;\n }\n },\n );\n },\n }) as (...args: unknown[]) => CompiledGraph;\n}\n\n/**\n * Instruments CompiledGraph's invoke method to create spans for agent invocation\n *\n * Creates a `gen_ai.invoke_agent` span when invoke() is called\n */\nfunction instrumentCompiledGraphInvoke(\n originalInvoke: (...args: unknown[]) => Promise<unknown>,\n graphInstance: CompiledGraph,\n compileOptions: Record<string, unknown>,\n options: LangGraphOptions,\n): (...args: unknown[]) => Promise<unknown> {\n return new Proxy(originalInvoke, {\n apply(target, thisArg, args: unknown[]): Promise<unknown> {\n return startSpan(\n {\n op: 'gen_ai.invoke_agent',\n name: 'invoke_agent',\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: LANGGRAPH_ORIGIN,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: GEN_AI_INVOKE_AGENT_OPERATION_ATTRIBUTE,\n [GEN_AI_OPERATION_NAME_ATTRIBUTE]: 'invoke_agent',\n },\n },\n async span => {\n try {\n const graphName = compileOptions?.name;\n\n if (graphName && typeof graphName === 'string') {\n span.setAttribute(GEN_AI_PIPELINE_NAME_ATTRIBUTE, graphName);\n span.setAttribute(GEN_AI_AGENT_NAME_ATTRIBUTE, graphName);\n span.updateName(`invoke_agent ${graphName}`);\n }\n\n // Extract thread_id from the config (second argument)\n // LangGraph uses config.configurable.thread_id for conversation/session linking\n const config = args.length > 1 ? (args[1] as Record<string, unknown> | undefined) : undefined;\n const configurable = config?.configurable as Record<string, unknown> | undefined;\n const threadId = configurable?.thread_id;\n if (threadId && typeof threadId === 'string') {\n span.setAttribute(GEN_AI_CONVERSATION_ID_ATTRIBUTE, threadId);\n }\n\n // Extract available tools from the graph instance\n const tools = extractToolsFromCompiledGraph(graphInstance);\n if (tools) {\n span.setAttribute(GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE, JSON.stringify(tools));\n }\n\n // Parse input messages\n const recordInputs = options.recordInputs;\n const recordOutputs = options.recordOutputs;\n const inputMessages =\n args.length > 0 ? ((args[0] as { messages?: LangChainMessage[] } | null)?.messages ?? []) : [];\n\n if (inputMessages && recordInputs) {\n const normalizedMessages = normalizeLangChainMessages(inputMessages);\n const { systemInstructions, filteredMessages } = extractSystemInstructions(normalizedMessages);\n\n if (systemInstructions) {\n span.setAttribute(GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE, systemInstructions);\n }\n\n const enableTruncation = shouldEnableTruncation(options.enableTruncation);\n const filteredLength = Array.isArray(filteredMessages) ? filteredMessages.length : 0;\n span.setAttributes({\n [GEN_AI_INPUT_MESSAGES_ATTRIBUTE]: enableTruncation\n ? getTruncatedJsonString(filteredMessages)\n : getJsonString(filteredMessages),\n [GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE]: filteredLength,\n });\n }\n\n // Call original invoke\n const result = await Reflect.apply(target, thisArg, args);\n\n // Set response attributes\n if (recordOutputs) {\n setResponseAttributes(span, inputMessages ?? null, result);\n }\n\n return result;\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.langgraph.error',\n },\n });\n throw error;\n }\n },\n );\n },\n }) as (...args: unknown[]) => Promise<unknown>;\n}\n\n/**\n * Directly instruments a StateGraph instance to add tracing spans\n *\n * This function can be used to manually instrument LangGraph StateGraph instances\n * in environments where automatic instrumentation is not available or desired.\n *\n * @param stateGraph - The StateGraph instance to instrument\n * @param options - Optional configuration for recording inputs/outputs\n *\n * @example\n * ```typescript\n * import { instrumentLangGraph } from '@sentry/cloudflare';\n * import { StateGraph } from '@langchain/langgraph';\n *\n * const graph = new StateGraph(MessagesAnnotation)\n * .addNode('agent', mockLlm)\n * .addEdge(START, 'agent')\n * .addEdge('agent', END);\n *\n * instrumentLangGraph(graph, { recordInputs: true, recordOutputs: true });\n * const compiled = graph.compile({ name: 'my_agent' });\n * ```\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function instrumentLangGraph<T extends { compile: (...args: any[]) => any }>(\n stateGraph: T,\n options?: LangGraphOptions,\n): T {\n stateGraph.compile = instrumentStateGraphCompile(stateGraph.compile, resolveAIRecordingOptions(options));\n\n return stateGraph;\n}\n"],"names":[],"mappings":";;;;;;;;;;AA4BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,2BAA2B;AAC3C,EAAE,eAAe;AACjB,EAAE,OAAO;AACT,EAAyC;AACzC,EAAE,OAAO,IAAI,KAAK,CAAC,eAAe,EAAE;AACpC,IAAI,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAA4B;AAC3D,MAAM,OAAO,SAAS;AACtB,QAAQ;AACR,UAAU,EAAE,EAAE,qBAAqB;AACnC,UAAU,IAAI,EAAE,cAAc;AAC9B,UAAU,UAAU,EAAE;AACtB,YAAY,CAAC,gCAAgC,GAAG,gBAAgB;AAChE,YAAY,CAAC,4BAA4B,GAAG,qBAAqB;AACjE,YAAY,CAAC,+BAA+B,GAAG,cAAc;AAC7D,WAAW;AACX,SAAS;AACT,QAAQ,QAAQ;AAChB,UAAU,IAAI;AACd,YAAY,MAAM,aAAA,GAAgB,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC;AACtE,YAAY,MAAM,cAAA,GAAiB,IAAI,CAAC,SAAS,CAAA,IAAK,IAAI,CAAC,CAAC,MAAgC,EAAE;;AAE9F;AACA,YAAY,IAAI,cAAc,EAAE,IAAA,IAAQ,OAAO,cAAc,CAAC,IAAA,KAAS,QAAQ,EAAE;AACjF,cAAc,IAAI,CAAC,YAAY,CAAC,2BAA2B,EAAE,cAAc,CAAC,IAAI,CAAC;AACjF,cAAc,IAAI,CAAC,UAAU,CAAC,CAAC,aAAa,EAAE,cAAc,CAAC,IAAI,CAAC,CAAA,CAAA;AACA,YAAA;;AAEA;AACA,YAAA,MAAA,cAAA,GAAA,aAAA,CAAA,MAAA;AACA,YAAA,IAAA,cAAA,IAAA,OAAA,cAAA,KAAA,UAAA,EAAA;AACA,cAAA,aAAA,CAAA,MAAA,GAAA,6BAAA;AACA,gBAAA,cAAA,CAAA,IAAA,CAAA,aAAA,CAAA;AACA,gBAAA,aAAA;AACA,gBAAA,cAAA;AACA,gBAAA,OAAA;AACA,eAAA;AACA,YAAA;;AAEA,YAAA,OAAA,aAAA;AACA,UAAA,CAAA,CAAA,OAAA,KAAA,EAAA;AACA,YAAA,IAAA,CAAA,SAAA,CAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,gBAAA,EAAA,CAAA;AACA,YAAA,gBAAA,CAAA,KAAA,EAAA;AACA,cAAA,SAAA,EAAA;AACA,gBAAA,OAAA,EAAA,KAAA;AACA,gBAAA,IAAA,EAAA,yBAAA;AACA,eAAA;AACA,aAAA,CAAA;AACA,YAAA,MAAA,KAAA;AACA,UAAA;AACA,QAAA,CAAA;AACA,OAAA;AACA,IAAA,CAAA;AACA,GAAA,CAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,SAAA,6BAAA;AACA,EAAA,cAAA;AACA,EAAA,aAAA;AACA,EAAA,cAAA;AACA,EAAA,OAAA;AACA,EAAA;AACA,EAAA,OAAA,IAAA,KAAA,CAAA,cAAA,EAAA;AACA,IAAA,KAAA,CAAA,MAAA,EAAA,OAAA,EAAA,IAAA,EAAA;AACA,MAAA,OAAA,SAAA;AACA,QAAA;AACA,UAAA,EAAA,EAAA,qBAAA;AACA,UAAA,IAAA,EAAA,cAAA;AACA,UAAA,UAAA,EAAA;AACA,YAAA,CAAA,gCAAA,GAAA,gBAAA;AACA,YAAA,CAAA,4BAAA,GAAA,uCAAA;AACA,YAAA,CAAA,+BAAA,GAAA,cAAA;AACA,WAAA;AACA,SAAA;AACA,QAAA,MAAA,IAAA,IAAA;AACA,UAAA,IAAA;AACA,YAAA,MAAA,SAAA,GAAA,cAAA,EAAA,IAAA;;AAEA,YAAA,IAAA,SAAA,IAAA,OAAA,SAAA,KAAA,QAAA,EAAA;AACA,cAAA,IAAA,CAAA,YAAA,CAAA,8BAAA,EAAA,SAAA,CAAA;AACA,cAAA,IAAA,CAAA,YAAA,CAAA,2BAAA,EAAA,SAAA,CAAA;AACA,cAAA,IAAA,CAAA,UAAA,CAAA,CAAA,aAAA,EAAA,SAAA,CAAA,CAAA,CAAA;AACA,YAAA;;AAEA;AACA;AACA,YAAA,MAAA,MAAA,GAAA,IAAA,CAAA,MAAA,GAAA,CAAA,IAAA,IAAA,CAAA,CAAA,CAAA,KAAA,SAAA;AACA,YAAA,MAAA,YAAA,GAAA,MAAA,EAAA,YAAA;AACA,YAAA,MAAA,QAAA,GAAA,YAAA,EAAA,SAAA;AACA,YAAA,IAAA,QAAA,IAAA,OAAA,QAAA,KAAA,QAAA,EAAA;AACA,cAAA,IAAA,CAAA,YAAA,CAAA,gCAAA,EAAA,QAAA,CAAA;AACA,YAAA;;AAEA;AACA,YAAA,MAAA,KAAA,GAAA,6BAAA,CAAA,aAAA,CAAA;AACA,YAAA,IAAA,KAAA,EAAA;AACA,cAAA,IAAA,CAAA,YAAA,CAAA,wCAAA,EAAA,IAAA,CAAA,SAAA,CAAA,KAAA,CAAA,CAAA;AACA,YAAA;;AAEA;AACA,YAAA,MAAA,YAAA,GAAA,OAAA,CAAA,YAAA;AACA,YAAA,MAAA,aAAA,GAAA,OAAA,CAAA,aAAA;AACA,YAAA,MAAA,aAAA;AACA,cAAA,IAAA,CAAA,MAAA,GAAA,CAAA,IAAA,CAAA,IAAA,CAAA,CAAA,CAAA,IAAA,QAAA,IAAA,EAAA,IAAA,EAAA;;AAEA,YAAA,IAAA,aAAA,IAAA,YAAA,EAAA;AACA,cAAA,MAAA,kBAAA,GAAA,0BAAA,CAAA,aAAA,CAAA;AACA,cAAA,MAAA,EAAA,kBAAA,EAAA,gBAAA,EAAA,GAAA,yBAAA,CAAA,kBAAA,CAAA;;AAEA,cAAA,IAAA,kBAAA,EAAA;AACA,gBAAA,IAAA,CAAA,YAAA,CAAA,oCAAA,EAAA,kBAAA,CAAA;AACA,cAAA;;AAEA,cAAA,MAAA,gBAAA,GAAA,sBAAA,CAAA,OAAA,CAAA,gBAAA,CAAA;AACA,cAAA,MAAA,cAAA,GAAA,KAAA,CAAA,OAAA,CAAA,gBAAA,CAAA,GAAA,gBAAA,CAAA,MAAA,GAAA,CAAA;AACA,cAAA,IAAA,CAAA,aAAA,CAAA;AACA,gBAAA,CAAA,+BAAA,GAAA;AACA,oBAAA,sBAAA,CAAA,gBAAA;AACA,oBAAA,aAAA,CAAA,gBAAA,CAAA;AACA,gBAAA,CAAA,+CAAA,GAAA,cAAA;AACA,eAAA,CAAA;AACA,YAAA;;AAEA;AACA,YAAA,MAAA,MAAA,GAAA,MAAA,OAAA,CAAA,KAAA,CAAA,MAAA,EAAA,OAAA,EAAA,IAAA,CAAA;;AAEA;AACA,YAAA,IAAA,aAAA,EAAA;AACA,cAAA,qBAAA,CAAA,IAAA,EAAA,aAAA,IAAA,IAAA,EAAA,MAAA,CAAA;AACA,YAAA;;AAEA,YAAA,OAAA,MAAA;AACA,UAAA,CAAA,CAAA,OAAA,KAAA,EAAA;AACA,YAAA,IAAA,CAAA,SAAA,CAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,gBAAA,EAAA,CAAA;AACA,YAAA,gBAAA,CAAA,KAAA,EAAA;AACA,cAAA,SAAA,EAAA;AACA,gBAAA,OAAA,EAAA,KAAA;AACA,gBAAA,IAAA,EAAA,yBAAA;AACA,eAAA;AACA,aAAA,CAAA;AACA,YAAA,MAAA,KAAA;AACA,UAAA;AACA,QAAA,CAAA;AACA,OAAA;AACA,IAAA,CAAA;AACA,GAAA,CAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAA,mBAAA;AACA,EAAA,UAAA;AACA,EAAA,OAAA;AACA,EAAA;AACA,EAAA,UAAA,CAAA,OAAA,GAAA,2BAAA,CAAA,UAAA,CAAA,OAAA,EAAA,yBAAA,CAAA,OAAA,CAAA,CAAA;;AAEA,EAAA,OAAA,UAAA;AACA;;;;"}
@@ -4,11 +4,11 @@ import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../../semanticAttributes.js';
4
4
  import { debug } from '../../utils/debug-logger.js';
5
5
  import { SPAN_STATUS_ERROR } from '../spanstatus.js';
6
6
  import { startSpanManual, startSpan } from '../trace.js';
7
- import { GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE, GEN_AI_REQUEST_MODEL_ATTRIBUTE, GEN_AI_EMBEDDINGS_INPUT_ATTRIBUTE, GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE, GEN_AI_INPUT_MESSAGES_ATTRIBUTE, GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE, GEN_AI_RESPONSE_TEXT_ATTRIBUTE, GEN_AI_OPERATION_NAME_ATTRIBUTE, GEN_AI_SYSTEM_ATTRIBUTE } from '../ai/gen-ai-attributes.js';
8
- import { resolveAIRecordingOptions, wrapPromiseWithMethods, buildMethodPath, extractSystemInstructions, getTruncatedJsonString } from '../ai/utils.js';
7
+ import { GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE, GEN_AI_REQUEST_MODEL_ATTRIBUTE, GEN_AI_EMBEDDINGS_INPUT_ATTRIBUTE, GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE, GEN_AI_INPUT_MESSAGES_ATTRIBUTE, GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE, GEN_AI_OPERATION_NAME_ATTRIBUTE, GEN_AI_SYSTEM_ATTRIBUTE } from '../ai/gen-ai-attributes.js';
8
+ import { resolveAIRecordingOptions, shouldEnableTruncation, wrapPromiseWithMethods, buildMethodPath, extractSystemInstructions, getTruncatedJsonString, getJsonString } from '../ai/utils.js';
9
9
  import { OPENAI_METHOD_REGISTRY } from './constants.js';
10
10
  import { instrumentStream } from './streaming.js';
11
- import { extractRequestParameters, isChatCompletionResponse, addChatCompletionAttributes, isResponsesApiResponse, addResponsesApiAttributes, isEmbeddingsResponse, addEmbeddingsAttributes, isConversationResponse, addConversationAttributes } from './utils.js';
11
+ import { addResponseAttributes, extractRequestParameters } from './utils.js';
12
12
 
13
13
  /**
14
14
  * Extract available tools from request parameters
@@ -59,35 +59,13 @@ function extractRequestAttributes(args, operationName) {
59
59
  return attributes;
60
60
  }
61
61
 
62
- /**
63
- * Add response attributes to spans
64
- * This supports Chat Completion, Responses API, Embeddings, and Conversations API responses
65
- */
66
- function addResponseAttributes(span, result, recordOutputs) {
67
- if (!result || typeof result !== 'object') return;
68
-
69
- const response = result ;
70
-
71
- if (isChatCompletionResponse(response)) {
72
- addChatCompletionAttributes(span, response, recordOutputs);
73
- if (recordOutputs && response.choices?.length) {
74
- const responseTexts = response.choices.map(choice => choice.message?.content || '');
75
- span.setAttributes({ [GEN_AI_RESPONSE_TEXT_ATTRIBUTE]: JSON.stringify(responseTexts) });
76
- }
77
- } else if (isResponsesApiResponse(response)) {
78
- addResponsesApiAttributes(span, response, recordOutputs);
79
- if (recordOutputs && response.output_text) {
80
- span.setAttributes({ [GEN_AI_RESPONSE_TEXT_ATTRIBUTE]: response.output_text });
81
- }
82
- } else if (isEmbeddingsResponse(response)) {
83
- addEmbeddingsAttributes(span, response);
84
- } else if (isConversationResponse(response)) {
85
- addConversationAttributes(span, response);
86
- }
87
- }
88
-
89
62
  // Extract and record AI request inputs, if present. This is intentionally separate from response attributes.
90
- function addRequestAttributes(span, params, operationName) {
63
+ function addRequestAttributes(
64
+ span,
65
+ params,
66
+ operationName,
67
+ enableTruncation,
68
+ ) {
91
69
  // Store embeddings input on a separate attribute and do not truncate it
92
70
  if (operationName === 'embeddings' && 'input' in params) {
93
71
  const input = params.input;
@@ -128,8 +106,10 @@ function addRequestAttributes(span, params, operationName) {
128
106
  span.setAttribute(GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE, systemInstructions);
129
107
  }
130
108
 
131
- const truncatedInput = getTruncatedJsonString(filteredMessages);
132
- span.setAttribute(GEN_AI_INPUT_MESSAGES_ATTRIBUTE, truncatedInput);
109
+ span.setAttribute(
110
+ GEN_AI_INPUT_MESSAGES_ATTRIBUTE,
111
+ enableTruncation ? getTruncatedJsonString(filteredMessages) : getJsonString(filteredMessages),
112
+ );
133
113
 
134
114
  if (Array.isArray(filteredMessages)) {
135
115
  span.setAttribute(GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE, filteredMessages.length);
@@ -151,7 +131,7 @@ function instrumentMethod(
151
131
  options,
152
132
  ) {
153
133
  return function instrumentedCall(...args) {
154
- const operationName = instrumentedMethod.operation;
134
+ const operationName = instrumentedMethod.operation || 'unknown';
155
135
  const requestAttributes = extractRequestAttributes(args, operationName);
156
136
  const model = (requestAttributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] ) || 'unknown';
157
137
 
@@ -171,7 +151,7 @@ function instrumentMethod(
171
151
  originalResult = originalMethod.apply(context, args);
172
152
 
173
153
  if (options.recordInputs && params) {
174
- addRequestAttributes(span, params, operationName);
154
+ addRequestAttributes(span, params, operationName, shouldEnableTruncation(options.enableTruncation));
175
155
  }
176
156
 
177
157
  // Return async processing
@@ -209,7 +189,7 @@ function instrumentMethod(
209
189
  originalResult = originalMethod.apply(context, args);
210
190
 
211
191
  if (options.recordInputs && params) {
212
- addRequestAttributes(span, params, operationName);
192
+ addRequestAttributes(span, params, operationName, shouldEnableTruncation(options.enableTruncation));
213
193
  }
214
194
 
215
195
  return originalResult.then(
@@ -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":[],"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 getJsonString,\n getTruncatedJsonString,\n resolveAIRecordingOptions,\n shouldEnableTruncation,\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(\n span: Span,\n params: Record<string, unknown>,\n operationName: string,\n enableTruncation: boolean,\n): 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 span.setAttribute(\n GEN_AI_INPUT_MESSAGES_ATTRIBUTE,\n enableTruncation ? getTruncatedJsonString(filteredMessages) : getJsonString(filteredMessages),\n );\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, shouldEnableTruncation(options.enableTruncation));\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, shouldEnableTruncation(options.enableTruncation));\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":[],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import { captureException } from '../../exports.js';
2
2
  import { SPAN_STATUS_ERROR } from '../spanstatus.js';
3
- import { GEN_AI_RESPONSE_STREAMING_ATTRIBUTE, GEN_AI_RESPONSE_FINISH_REASONS_ATTRIBUTE, GEN_AI_RESPONSE_TEXT_ATTRIBUTE, GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE } from '../ai/gen-ai-attributes.js';
3
+ import { endStreamSpan } from '../ai/utils.js';
4
4
  import { RESPONSE_EVENT_TYPES } from './constants.js';
5
- import { isChatCompletionChunk, isResponsesApiStreamEvent, setCommonResponseAttributes, setTokenUsageAttributes } from './utils.js';
5
+ import { isChatCompletionChunk, isResponsesApiStreamEvent } from './utils.js';
6
6
 
7
7
  /**
8
8
  * State object used to accumulate information from a stream of OpenAI events/chunks.
@@ -51,7 +51,6 @@ function processChatCompletionToolCalls(toolCalls, state) {
51
51
  function processChatCompletionChunk(chunk, state, recordOutputs) {
52
52
  state.responseId = chunk.id ?? state.responseId;
53
53
  state.responseModel = chunk.model ?? state.responseModel;
54
- state.responseTimestamp = chunk.created ?? state.responseTimestamp;
55
54
 
56
55
  if (chunk.usage) {
57
56
  // For stream responses, the input tokens remain constant across all events in the stream.
@@ -135,7 +134,6 @@ function processResponsesApiEvent(
135
134
  const { response } = event ;
136
135
  state.responseId = response.id ?? state.responseId;
137
136
  state.responseModel = response.model ?? state.responseModel;
138
- state.responseTimestamp = response.created_at ?? state.responseTimestamp;
139
137
 
140
138
  if (response.usage) {
141
139
  // For stream responses, the input tokens remain constant across all events in the stream.
@@ -179,7 +177,6 @@ async function* instrumentStream(
179
177
  finishReasons: [],
180
178
  responseId: '',
181
179
  responseModel: '',
182
- responseTimestamp: 0,
183
180
  promptTokens: undefined,
184
181
  completionTokens: undefined,
185
182
  totalTokens: undefined,
@@ -197,36 +194,8 @@ async function* instrumentStream(
197
194
  yield event;
198
195
  }
199
196
  } finally {
200
- setCommonResponseAttributes(span, state.responseId, state.responseModel, state.responseTimestamp);
201
- setTokenUsageAttributes(span, state.promptTokens, state.completionTokens, state.totalTokens);
202
-
203
- span.setAttributes({
204
- [GEN_AI_RESPONSE_STREAMING_ATTRIBUTE]: true,
205
- });
206
-
207
- if (state.finishReasons.length) {
208
- span.setAttributes({
209
- [GEN_AI_RESPONSE_FINISH_REASONS_ATTRIBUTE]: JSON.stringify(state.finishReasons),
210
- });
211
- }
212
-
213
- if (recordOutputs && state.responseTexts.length) {
214
- span.setAttributes({
215
- [GEN_AI_RESPONSE_TEXT_ATTRIBUTE]: state.responseTexts.join(''),
216
- });
217
- }
218
-
219
- // Set tool calls attribute if any were accumulated
220
- const chatCompletionToolCallsArray = Object.values(state.chatCompletionToolCalls);
221
- const allToolCalls = [...chatCompletionToolCallsArray, ...state.responsesApiToolCalls];
222
-
223
- if (allToolCalls.length > 0) {
224
- span.setAttributes({
225
- [GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE]: JSON.stringify(allToolCalls),
226
- });
227
- }
228
-
229
- span.end();
197
+ const allToolCalls = [...Object.values(state.chatCompletionToolCalls), ...state.responsesApiToolCalls];
198
+ endStreamSpan(span, { ...state, toolCalls: allToolCalls }, recordOutputs);
230
199
  }
231
200
  }
232
201
 
@@ -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":[],"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":[],"mappings":"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"}