@struct-ai/sdk 0.1.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 (228) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +168 -0
  3. package/dist/commonjs/content-capture.d.ts +10 -0
  4. package/dist/commonjs/content-capture.js +23 -0
  5. package/dist/commonjs/context.d.ts +30 -0
  6. package/dist/commonjs/context.js +94 -0
  7. package/dist/commonjs/core.d.ts +120 -0
  8. package/dist/commonjs/core.js +408 -0
  9. package/dist/commonjs/events.d.ts +12 -0
  10. package/dist/commonjs/events.js +103 -0
  11. package/dist/commonjs/index.d.ts +6 -0
  12. package/dist/commonjs/index.js +10 -0
  13. package/dist/commonjs/integrations/anthropic-content.d.ts +24 -0
  14. package/dist/commonjs/integrations/anthropic-content.js +178 -0
  15. package/dist/commonjs/integrations/anthropic.d.ts +34 -0
  16. package/dist/commonjs/integrations/anthropic.js +377 -0
  17. package/dist/commonjs/integrations/index.d.ts +5 -0
  18. package/dist/commonjs/integrations/index.js +47 -0
  19. package/dist/commonjs/integrations/langchain-callback.d.ts +134 -0
  20. package/dist/commonjs/integrations/langchain-callback.js +723 -0
  21. package/dist/commonjs/integrations/langchain-content.d.ts +35 -0
  22. package/dist/commonjs/integrations/langchain-content.js +307 -0
  23. package/dist/commonjs/integrations/langchain.d.ts +11 -0
  24. package/dist/commonjs/integrations/langchain.js +100 -0
  25. package/dist/commonjs/package.json +3 -0
  26. package/dist/commonjs/semconv.d.ts +54 -0
  27. package/dist/commonjs/semconv.js +74 -0
  28. package/dist/commonjs/truncation.d.ts +10 -0
  29. package/dist/commonjs/truncation.js +103 -0
  30. package/dist/esm/content-capture.d.ts +10 -0
  31. package/dist/esm/content-capture.js +17 -0
  32. package/dist/esm/context.d.ts +30 -0
  33. package/dist/esm/context.js +80 -0
  34. package/dist/esm/core.d.ts +120 -0
  35. package/dist/esm/core.js +403 -0
  36. package/dist/esm/events.d.ts +12 -0
  37. package/dist/esm/events.js +99 -0
  38. package/dist/esm/index.d.ts +6 -0
  39. package/dist/esm/index.js +5 -0
  40. package/dist/esm/integrations/anthropic-content.d.ts +24 -0
  41. package/dist/esm/integrations/anthropic-content.js +168 -0
  42. package/dist/esm/integrations/anthropic.d.ts +34 -0
  43. package/dist/esm/integrations/anthropic.js +370 -0
  44. package/dist/esm/integrations/index.d.ts +5 -0
  45. package/dist/esm/integrations/index.js +42 -0
  46. package/dist/esm/integrations/langchain-callback.d.ts +134 -0
  47. package/dist/esm/integrations/langchain-callback.js +719 -0
  48. package/dist/esm/integrations/langchain-content.d.ts +35 -0
  49. package/dist/esm/integrations/langchain-content.js +294 -0
  50. package/dist/esm/integrations/langchain.d.ts +11 -0
  51. package/dist/esm/integrations/langchain.js +95 -0
  52. package/dist/esm/package.json +3 -0
  53. package/dist/esm/semconv.d.ts +54 -0
  54. package/dist/esm/semconv.js +71 -0
  55. package/dist/esm/truncation.d.ts +10 -0
  56. package/dist/esm/truncation.js +96 -0
  57. package/dist/node_modules/@struct-ai/sdk/dist/commonjs/content-capture.d.ts +10 -0
  58. package/dist/node_modules/@struct-ai/sdk/dist/commonjs/context.d.ts +30 -0
  59. package/dist/node_modules/@struct-ai/sdk/dist/commonjs/core.d.ts +120 -0
  60. package/dist/node_modules/@struct-ai/sdk/dist/commonjs/events.d.ts +12 -0
  61. package/dist/node_modules/@struct-ai/sdk/dist/commonjs/index.d.ts +6 -0
  62. package/dist/node_modules/@struct-ai/sdk/dist/commonjs/integrations/anthropic-content.d.ts +24 -0
  63. package/dist/node_modules/@struct-ai/sdk/dist/commonjs/integrations/anthropic.d.ts +34 -0
  64. package/dist/node_modules/@struct-ai/sdk/dist/commonjs/integrations/index.d.ts +5 -0
  65. package/dist/node_modules/@struct-ai/sdk/dist/commonjs/integrations/langchain-callback.d.ts +134 -0
  66. package/dist/node_modules/@struct-ai/sdk/dist/commonjs/integrations/langchain-content.d.ts +35 -0
  67. package/dist/node_modules/@struct-ai/sdk/dist/commonjs/integrations/langchain.d.ts +11 -0
  68. package/dist/node_modules/@struct-ai/sdk/dist/commonjs/package.json +3 -0
  69. package/dist/node_modules/@struct-ai/sdk/dist/commonjs/semconv.d.ts +54 -0
  70. package/dist/node_modules/@struct-ai/sdk/dist/commonjs/truncation.d.ts +10 -0
  71. package/dist/node_modules/@struct-ai/sdk/dist/esm/content-capture.d.ts +10 -0
  72. package/dist/node_modules/@struct-ai/sdk/dist/esm/context.d.ts +30 -0
  73. package/dist/node_modules/@struct-ai/sdk/dist/esm/core.d.ts +120 -0
  74. package/dist/node_modules/@struct-ai/sdk/dist/esm/events.d.ts +12 -0
  75. package/dist/node_modules/@struct-ai/sdk/dist/esm/index.d.ts +6 -0
  76. package/dist/node_modules/@struct-ai/sdk/dist/esm/integrations/anthropic-content.d.ts +24 -0
  77. package/dist/node_modules/@struct-ai/sdk/dist/esm/integrations/anthropic.d.ts +34 -0
  78. package/dist/node_modules/@struct-ai/sdk/dist/esm/integrations/index.d.ts +5 -0
  79. package/dist/node_modules/@struct-ai/sdk/dist/esm/integrations/langchain-callback.d.ts +134 -0
  80. package/dist/node_modules/@struct-ai/sdk/dist/esm/integrations/langchain-content.d.ts +35 -0
  81. package/dist/node_modules/@struct-ai/sdk/dist/esm/integrations/langchain.d.ts +11 -0
  82. package/dist/node_modules/@struct-ai/sdk/dist/esm/package.json +3 -0
  83. package/dist/node_modules/@struct-ai/sdk/dist/esm/semconv.d.ts +54 -0
  84. package/dist/node_modules/@struct-ai/sdk/dist/esm/truncation.d.ts +10 -0
  85. package/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/dist/commonjs/package.json +3 -0
  86. package/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/dist/esm/package.json +3 -0
  87. package/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/package.json +100 -0
  88. package/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/node_modules/@anthropic-ai/sdk/package.json +103 -0
  89. package/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/anthropic/package.json +118 -0
  90. package/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/core/package.json +916 -0
  91. package/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/langgraph/package.json +188 -0
  92. package/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/node_modules/@opentelemetry/api/package.json +96 -0
  93. package/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/node_modules/@opentelemetry/api-logs/package.json +91 -0
  94. package/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/node_modules/@opentelemetry/core/package.json +96 -0
  95. package/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/node_modules/@opentelemetry/exporter-logs-otlp-proto/package.json +108 -0
  96. package/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/node_modules/@opentelemetry/exporter-trace-otlp-proto/package.json +105 -0
  97. package/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/node_modules/@opentelemetry/resources/package.json +100 -0
  98. package/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/node_modules/@opentelemetry/sdk-logs/package.json +109 -0
  99. package/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/node_modules/@opentelemetry/sdk-trace-base/package.json +100 -0
  100. package/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/node_modules/@opentelemetry/sdk-trace-node/package.json +76 -0
  101. package/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/package.json +140 -0
  102. package/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/node_modules/nock/package.json +89 -0
  103. package/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/node_modules/tshy/package.json +81 -0
  104. package/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/node_modules/typescript/package.json +120 -0
  105. package/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/node_modules/vitest/package.json +239 -0
  106. package/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/package.json +100 -0
  107. package/dist/node_modules/@struct-ai/sdk/node_modules/@anthropic-ai/sdk/core.d.ts +244 -0
  108. package/dist/node_modules/@struct-ai/sdk/node_modules/@anthropic-ai/sdk/error.d.ts +54 -0
  109. package/dist/node_modules/@struct-ai/sdk/node_modules/@anthropic-ai/sdk/index.d.ts +188 -0
  110. package/dist/node_modules/@struct-ai/sdk/node_modules/@anthropic-ai/sdk/package.json +103 -0
  111. package/dist/node_modules/@struct-ai/sdk/node_modules/@anthropic-ai/sdk/pagination.d.ts +26 -0
  112. package/dist/node_modules/@struct-ai/sdk/node_modules/@anthropic-ai/sdk/resource.d.ts +6 -0
  113. package/dist/node_modules/@struct-ai/sdk/node_modules/@anthropic-ai/sdk/streaming.d.ts +41 -0
  114. package/dist/node_modules/@struct-ai/sdk/node_modules/@anthropic-ai/sdk/uploads.d.ts +75 -0
  115. package/dist/node_modules/@struct-ai/sdk/node_modules/@anthropic-ai/sdk/version.d.ts +2 -0
  116. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/anthropic/experimental.d.ts +1 -0
  117. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/anthropic/index.d.ts +1 -0
  118. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/anthropic/package.json +118 -0
  119. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/core/agents.d.ts +1 -0
  120. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/core/caches.d.ts +1 -0
  121. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/core/chat_history.d.ts +1 -0
  122. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/core/context.d.ts +1 -0
  123. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/core/documents.d.ts +1 -0
  124. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/core/embeddings.d.ts +1 -0
  125. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/core/example_selectors.d.ts +1 -0
  126. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/core/index.d.ts +1 -0
  127. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/core/indexing.d.ts +1 -0
  128. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/core/load.d.ts +1 -0
  129. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/core/memory.d.ts +1 -0
  130. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/core/messages.d.ts +1 -0
  131. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/core/output_parsers.d.ts +1 -0
  132. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/core/outputs.d.ts +1 -0
  133. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/core/package.json +916 -0
  134. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/core/prompt_values.d.ts +1 -0
  135. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/core/prompts.d.ts +1 -0
  136. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/core/retrievers.d.ts +1 -0
  137. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/core/runnables.d.ts +1 -0
  138. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/core/singletons.d.ts +1 -0
  139. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/core/stores.d.ts +1 -0
  140. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/core/structured_query.d.ts +1 -0
  141. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/core/tools.d.ts +1 -0
  142. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/core/vectorstores.d.ts +1 -0
  143. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/langgraph/index.d.ts +1 -0
  144. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/langgraph/package.json +188 -0
  145. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/langgraph/prebuilt.d.ts +1 -0
  146. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/langgraph/pregel.d.ts +1 -0
  147. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/langgraph/remote.d.ts +1 -0
  148. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/langgraph/web.d.ts +1 -0
  149. package/dist/node_modules/@struct-ai/sdk/node_modules/@langchain/langgraph/zod.d.ts +1 -0
  150. package/dist/node_modules/@struct-ai/sdk/node_modules/@opentelemetry/api/package.json +96 -0
  151. package/dist/node_modules/@struct-ai/sdk/node_modules/@opentelemetry/api-logs/package.json +91 -0
  152. package/dist/node_modules/@struct-ai/sdk/node_modules/@opentelemetry/core/package.json +96 -0
  153. package/dist/node_modules/@struct-ai/sdk/node_modules/@opentelemetry/exporter-logs-otlp-proto/package.json +108 -0
  154. package/dist/node_modules/@struct-ai/sdk/node_modules/@opentelemetry/exporter-trace-otlp-proto/package.json +105 -0
  155. package/dist/node_modules/@struct-ai/sdk/node_modules/@opentelemetry/resources/package.json +100 -0
  156. package/dist/node_modules/@struct-ai/sdk/node_modules/@opentelemetry/sdk-logs/package.json +109 -0
  157. package/dist/node_modules/@struct-ai/sdk/node_modules/@opentelemetry/sdk-trace-base/package.json +100 -0
  158. package/dist/node_modules/@struct-ai/sdk/node_modules/@opentelemetry/sdk-trace-node/package.json +76 -0
  159. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/assert.d.ts +1062 -0
  160. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/async_hooks.d.ts +605 -0
  161. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/buffer.buffer.d.ts +471 -0
  162. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/buffer.d.ts +1936 -0
  163. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/child_process.d.ts +1475 -0
  164. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/cluster.d.ts +577 -0
  165. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/console.d.ts +452 -0
  166. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/constants.d.ts +21 -0
  167. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/crypto.d.ts +4590 -0
  168. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/dgram.d.ts +597 -0
  169. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/diagnostics_channel.d.ts +578 -0
  170. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/dns.d.ts +871 -0
  171. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/domain.d.ts +170 -0
  172. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/events.d.ts +977 -0
  173. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/fs.d.ts +4375 -0
  174. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/globals.d.ts +172 -0
  175. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/globals.typedarray.d.ts +38 -0
  176. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/http.d.ts +2049 -0
  177. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/http2.d.ts +2631 -0
  178. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/https.d.ts +578 -0
  179. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/index.d.ts +93 -0
  180. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/inspector.generated.d.ts +3966 -0
  181. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/module.d.ts +539 -0
  182. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/net.d.ts +1031 -0
  183. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/os.d.ts +506 -0
  184. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/package.json +140 -0
  185. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/path.d.ts +200 -0
  186. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/perf_hooks.d.ts +961 -0
  187. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/process.d.ts +1961 -0
  188. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/punycode.d.ts +117 -0
  189. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/querystring.d.ts +152 -0
  190. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/readline.d.ts +589 -0
  191. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/repl.d.ts +430 -0
  192. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/sea.d.ts +153 -0
  193. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/stream.d.ts +1698 -0
  194. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/string_decoder.d.ts +67 -0
  195. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/test.d.ts +1787 -0
  196. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/timers.d.ts +286 -0
  197. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/tls.d.ts +1259 -0
  198. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/trace_events.d.ts +197 -0
  199. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/tty.d.ts +208 -0
  200. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/url.d.ts +964 -0
  201. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/util.d.ts +2331 -0
  202. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/v8.d.ts +809 -0
  203. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/vm.d.ts +1001 -0
  204. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/wasi.d.ts +181 -0
  205. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/worker_threads.d.ts +715 -0
  206. package/dist/node_modules/@struct-ai/sdk/node_modules/@types/node/zlib.d.ts +598 -0
  207. package/dist/node_modules/@struct-ai/sdk/node_modules/nock/package.json +89 -0
  208. package/dist/node_modules/@struct-ai/sdk/node_modules/tshy/package.json +81 -0
  209. package/dist/node_modules/@struct-ai/sdk/node_modules/typescript/package.json +120 -0
  210. package/dist/node_modules/@struct-ai/sdk/node_modules/vitest/config.d.ts +3 -0
  211. package/dist/node_modules/@struct-ai/sdk/node_modules/vitest/coverage.d.ts +1 -0
  212. package/dist/node_modules/@struct-ai/sdk/node_modules/vitest/environments.d.ts +1 -0
  213. package/dist/node_modules/@struct-ai/sdk/node_modules/vitest/globals.d.ts +22 -0
  214. package/dist/node_modules/@struct-ai/sdk/node_modules/vitest/import-meta.d.ts +5 -0
  215. package/dist/node_modules/@struct-ai/sdk/node_modules/vitest/importMeta.d.ts +4 -0
  216. package/dist/node_modules/@struct-ai/sdk/node_modules/vitest/jsdom.d.ts +6 -0
  217. package/dist/node_modules/@struct-ai/sdk/node_modules/vitest/mocker.d.ts +1 -0
  218. package/dist/node_modules/@struct-ai/sdk/node_modules/vitest/node.d.ts +1 -0
  219. package/dist/node_modules/@struct-ai/sdk/node_modules/vitest/optional-runtime-types.d.ts +6 -0
  220. package/dist/node_modules/@struct-ai/sdk/node_modules/vitest/optional-types.d.ts +7 -0
  221. package/dist/node_modules/@struct-ai/sdk/node_modules/vitest/package.json +239 -0
  222. package/dist/node_modules/@struct-ai/sdk/node_modules/vitest/reporters.d.ts +1 -0
  223. package/dist/node_modules/@struct-ai/sdk/node_modules/vitest/runners.d.ts +1 -0
  224. package/dist/node_modules/@struct-ai/sdk/node_modules/vitest/snapshot.d.ts +1 -0
  225. package/dist/node_modules/@struct-ai/sdk/node_modules/vitest/suite.d.ts +1 -0
  226. package/dist/node_modules/@struct-ai/sdk/node_modules/vitest/worker.d.ts +1 -0
  227. package/dist/node_modules/@struct-ai/sdk/package.json +100 -0
  228. package/package.json +100 -0
@@ -0,0 +1,719 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { context as otelContext, SpanKind, SpanStatusCode, trace, } from "@opentelemetry/api";
3
+ import { getAgentSpan, getSessionId, popPendingToolCallId, pushPendingToolCalls, } from "../context.js";
4
+ import { safe } from "../core.js";
5
+ import { ERROR_TYPE, EVENT_NAMES, EVENT_NAME, GEN_AI, LANGCHAIN_FINISH_REASON_MAP, ROLE_TO_EVENT_NAME, STRUCT, } from "../semconv.js";
6
+ import { safeJsonStringify, truncateAndSerialize, truncateParts, } from "../truncation.js";
7
+ import { detectProvider, langchainMessageToRoleAndParts, langchainToInputMessages, langchainToOutputMessages, lastUserMessageParts, } from "./langchain-content.js";
8
+ /**
9
+ * LangChain CallbackHandler — creates OTel spans from LangChain callbacks.
10
+ *
11
+ * Parent-child linkage comes from `parentRunId` fields LangChain passes to us,
12
+ * NOT from OTel's async context. This survives LangGraph's internal task
13
+ * shuffling, which is why the callback API is the industry-standard integration
14
+ * point (LangSmith, OpenInference, Traceloop, Langfuse all use it).
15
+ *
16
+ * thread_id vs gen_ai.conversation.id
17
+ * -----------------------------------
18
+ * These are distinct concepts and Struct keeps them separate:
19
+ *
20
+ * - `config.configurable.thread_id` is LangGraph's checkpoint identifier,
21
+ * keying a conversation's state in the checkpointer. Multiple turns of
22
+ * the same conversation reuse one thread_id so history accumulates.
23
+ *
24
+ * - `gen_ai.conversation.id` is the OTel GenAI-spec conversation identifier
25
+ * and Struct's UI grouping unit — one value = one entry in the sessions
26
+ * list. For the top-level agent we auto-derive it from thread_id, so a
27
+ * stable thread_id across multi-turn chats collapses into one session.
28
+ *
29
+ * For SUBAGENTS (an agent invoked from inside another's tool body) we
30
+ * deliberately assign a DIFFERENT conversation.id — either from the subagent's
31
+ * own thread_id if supplied, or a fresh UUID. The resulting session is
32
+ * linked back to the outer agent's session via the
33
+ * `struct.agent.parent_session_id` span attribute (what powers "Spawned
34
+ * by" / subagent navigation in the UI). Without this split the subagent's
35
+ * spans would collapse into the outer session, burying delegation.
36
+ *
37
+ * LangChain quirk (handled automatically): when `agent.invoke(...)` runs
38
+ * nested inside a parent call, LangChain's config-merge inherits the
39
+ * parent's `metadata.thread_id` onto the child even if its config provided
40
+ * a different one. We detect that by comparing against the nearest agent
41
+ * ancestor's session; if they match, treat it as "inherited, not
42
+ * user-intended" and assign a fresh UUID to the subagent.
43
+ *
44
+ * End-user guidance:
45
+ * - Use thread_id per conversation; multi-turn chats reuse it.
46
+ * - For a subagent call, pass a DIFFERENT thread_id (or omit it and let
47
+ * LangGraph generate one). Each subagent then surfaces as its own
48
+ * session in the UI, linked back via parent_session_id.
49
+ */
50
+ export class StructCallbackHandler {
51
+ sdk;
52
+ tracer;
53
+ logger;
54
+ name = "struct";
55
+ lc_namespace = ["struct", "callbacks"];
56
+ lc_serializable = false;
57
+ awaitHandlers = false;
58
+ ignoreLLM = false;
59
+ ignoreChain = false;
60
+ ignoreAgent = false;
61
+ ignoreRetriever = false;
62
+ ignoreCustomEvent = true;
63
+ /**
64
+ * LangChain reads `raiseError` to decide whether a callback throw should
65
+ * abort the user's run. We keep this `false` because every callback method
66
+ * is wrapped in `safe()` and never throws — but a `true` here would tell
67
+ * LangChain to surface our (impossible) throws into the user's call.
68
+ * Locked by `test_handler_raiseError_is_false`.
69
+ */
70
+ raiseError = false;
71
+ runs = new Map();
72
+ internalLogger;
73
+ constructor(sdk, tracer, logger) {
74
+ this.sdk = sdk;
75
+ this.tracer = tracer;
76
+ this.logger = logger;
77
+ this.internalLogger = sdk.getInternalLogger();
78
+ }
79
+ // ─── Chain / Agent (Pregel, AgentExecutor, custom Runnables) ─────────────
80
+ handleChainStart = (chain, inputs, runId, parentRunId, _tags, metadata, runType, runName) => {
81
+ // Non-agent chain (RunnableSequence, ChannelWrite, Branch, internal
82
+ // LangGraph nodes): don't create a span, but record the runId so
83
+ // downstream children with parentRunId pointing here can still find
84
+ // their effective parent span.
85
+ if (!isAgentChain(chain, runType, runName)) {
86
+ // Skipped chains inherit session from parent (so chat/tool spans
87
+ // created under them stay tied to the enclosing agent's session).
88
+ const sessionId = this.resolveSessionId(parentRunId, metadata);
89
+ const { parentSpan } = this.resolveParent(parentRunId);
90
+ this.runs.set(runId, {
91
+ span: undefined,
92
+ effectiveParentSpan: parentSpan,
93
+ sessionId,
94
+ nearestAgentSessionId: this.inheritedAgentSessionId(parentRunId),
95
+ kind: "skipped-chain",
96
+ });
97
+ return;
98
+ }
99
+ const agentName = runName ??
100
+ extractClassName(chain) ??
101
+ (typeof inputs === "object" && inputs
102
+ ? inputs.name
103
+ : undefined) ??
104
+ "agent";
105
+ // Agent-start: each agent invocation gets its OWN gen_ai.conversation.id.
106
+ // Prefer config.configurable.thread_id, then a fresh UUID. Never inherit
107
+ // from the parent agent — subagents should appear as separate sessions
108
+ // in the UI, linked via ``struct.agent.parent_session_id``.
109
+ //
110
+ // Convention (documented publicly):
111
+ // * thread_id is a LangGraph checkpoint identifier. Multiple turns
112
+ // of one conversation reuse a thread_id → we group them into one
113
+ // session.
114
+ // * Subagents should be given a distinct thread_id (or none at all,
115
+ // letting LangGraph generate one). That way a subagent surfaces
116
+ // as its own entry in the sessions list.
117
+ //
118
+ // LangChain quirk (handled below): when an invoke runs nested inside
119
+ // a parent's call (e.g. the tool body invokes a subagent), LangChain
120
+ // inherits the parent's ``metadata.thread_id`` into the child run's
121
+ // metadata — even when the child config supplied its own. Treat that
122
+ // inheritance as "no thread_id" and assign a fresh UUID.
123
+ //
124
+ // For the struct.agent.parent_session_id attribute, we need the
125
+ // NEAREST agent ancestor's session — not just the immediate parent
126
+ // run, which might be a tool span. That's what
127
+ // ``inheritedAgentSessionId`` walks.
128
+ const parentAgentSessionId = this.inheritedAgentSessionId(parentRunId);
129
+ const sessionId = this.resolveAgentSessionId(metadata, parentAgentSessionId);
130
+ if (process.env.STRUCT_SDK_DEBUG === "1") {
131
+ // eslint-disable-next-line no-console
132
+ console.error("[struct-sdk] agent-start", agentName, "metadata.thread_id=", metadata?.thread_id, "parent.agent.session=", parentAgentSessionId, "→ resolved session=", sessionId);
133
+ }
134
+ const { parentSpan, parentSpanIsAgent } = this.resolveParent(parentRunId);
135
+ void parentSpanIsAgent;
136
+ const parentCtx = parentSpan
137
+ ? trace.setSpan(otelContext.active(), parentSpan)
138
+ : otelContext.active();
139
+ // Span creation can fail (custom tracer / broken context). Skip
140
+ // run-state insertion when it does — end/error callbacks already
141
+ // tolerate missing run state via the early `_runs.get(...) === undefined`
142
+ // short-circuit at the top of each method.
143
+ let span;
144
+ safe(() => {
145
+ span = this.tracer.startSpan(`invoke_agent ${agentName}`, { kind: SpanKind.INTERNAL }, parentCtx);
146
+ }, "langchain.handleChainStart.create_span", this.internalLogger);
147
+ if (span === undefined)
148
+ return;
149
+ const startedSpan = span;
150
+ safe(() => {
151
+ startedSpan.setAttribute(GEN_AI.OPERATION_NAME, "invoke_agent");
152
+ startedSpan.setAttribute(GEN_AI.PROVIDER_NAME, "langchain");
153
+ startedSpan.setAttribute(GEN_AI.AGENT_NAME, String(agentName));
154
+ // Do NOT set gen_ai.agent.id from sessionId — that conflates agent
155
+ // identity (spec: stable agent-definition id) with a per-invocation
156
+ // session. LangChain doesn't surface a stable agent-id to us, so we
157
+ // leave the attribute unset. Callers who use struct.agent() directly
158
+ // can pass their own agentId via the scope options.
159
+ startedSpan.setAttribute(GEN_AI.CONVERSATION_ID, sessionId);
160
+ // Link subagents back to the parent agent's session. Use the nearest
161
+ // agent ancestor (NOT the immediate parent run) — a subagent spawned
162
+ // from inside a tool has the tool as its immediate parent, but we want
163
+ // to point at the outer agent's session.
164
+ if (parentAgentSessionId && parentAgentSessionId !== sessionId) {
165
+ startedSpan.setAttribute(STRUCT.AGENT_PARENT_SESSION_ID, parentAgentSessionId);
166
+ }
167
+ // User prompt propagation — set gen_ai.input.messages on the agent
168
+ // span so the waterfall UI shows the question without drilling into
169
+ // chat spans.
170
+ if (this.sdk.emitSpanContent) {
171
+ const messages = extractChainInputMessages(inputs);
172
+ if (messages && messages.length > 0) {
173
+ startedSpan.setAttribute(GEN_AI.INPUT_MESSAGES, langchainToInputMessages(messages));
174
+ }
175
+ }
176
+ }, "langchain.handleChainStart.set_attrs", this.internalLogger);
177
+ this.runs.set(runId, {
178
+ span: startedSpan,
179
+ effectiveParentSpan: startedSpan,
180
+ sessionId,
181
+ // This agent IS itself the nearest agent ancestor for everything nested inside.
182
+ nearestAgentSessionId: sessionId,
183
+ kind: "chain",
184
+ });
185
+ };
186
+ handleChainEnd = (_outputs, runId) => {
187
+ const r = this.runs.get(runId);
188
+ this.runs.delete(runId);
189
+ if (!r || !r.span)
190
+ return;
191
+ const span = r.span;
192
+ safe(() => span.setStatus({ code: SpanStatusCode.OK }), "langchain.handleChainEnd.set_status", this.internalLogger);
193
+ safe(() => span.end(), "langchain.handleChainEnd.span_end", this.internalLogger);
194
+ };
195
+ handleChainError = (err, runId) => {
196
+ const r = this.runs.get(runId);
197
+ this.runs.delete(runId);
198
+ if (!r || !r.span)
199
+ return;
200
+ const span = r.span;
201
+ safe(() => recordError(span, err), "langchain.handleChainError.record_error", this.internalLogger);
202
+ safe(() => span.end(), "langchain.handleChainError.span_end", this.internalLogger);
203
+ };
204
+ // ─── LLM / Chat model ────────────────────────────────────────────────────
205
+ handleChatModelStart = (llm, messages, runId, parentRunId, extraParams, _tags, metadata, runName) => {
206
+ const provider = detectProviderFromSerialized(llm);
207
+ // Note: we emit a chat span from the callback handler even when a
208
+ // provider-direct SDK monkey-patch is also active. The two integration
209
+ // layers often run against different @anthropic-ai/sdk instances due to
210
+ // pnpm hoisting; skipping here would silently drop the only chat span.
211
+ // Duplicate-span de-dup is done server-side if ever needed.
212
+ const model = extractParam(extraParams, "model") ??
213
+ extractParam(extraParams?.invocation_params, "model") ??
214
+ extractParam(extraParams?.invocation_params, "modelName") ??
215
+ runName ??
216
+ "unknown";
217
+ const { parentSpan } = this.resolveParent(parentRunId);
218
+ const parentCtx = parentSpan
219
+ ? trace.setSpan(otelContext.active(), parentSpan)
220
+ : otelContext.active();
221
+ let span;
222
+ safe(() => {
223
+ span = this.tracer.startSpan(`chat ${model}`, { kind: SpanKind.CLIENT }, parentCtx);
224
+ }, "langchain.handleChatModelStart.create_span", this.internalLogger);
225
+ if (span === undefined)
226
+ return;
227
+ const startedSpan = span;
228
+ const sessionId = this.resolveSessionId(parentRunId, metadata);
229
+ safe(() => {
230
+ startedSpan.setAttribute(GEN_AI.OPERATION_NAME, "chat");
231
+ startedSpan.setAttribute(GEN_AI.PROVIDER_NAME, provider);
232
+ startedSpan.setAttribute(GEN_AI.REQUEST_MODEL, String(model));
233
+ startedSpan.setAttribute(GEN_AI.CONVERSATION_ID, sessionId);
234
+ setRequestAttrsFromInvocation(startedSpan, extraParams?.invocation_params);
235
+ const flat = messages.flat();
236
+ if (flat.length > 0) {
237
+ startedSpan.setAttribute(STRUCT.INPUT_MESSAGE_COUNT, flat.length);
238
+ if (this.sdk.emitEvents && this.logger) {
239
+ emitMessageEvents(this.logger, flat, provider, sessionId, startedSpan);
240
+ }
241
+ if (this.sdk.emitSpanContent) {
242
+ startedSpan.setAttribute(GEN_AI.INPUT_MESSAGES, langchainToInputMessages(flat));
243
+ }
244
+ // Propagate the most recent user message onto the nearest agent span.
245
+ const ancestorAgentSpan = this.resolveParent(parentRunId).parentSpan ?? getAgentSpan();
246
+ if (ancestorAgentSpan)
247
+ this.propagateUserPrompt(ancestorAgentSpan, flat);
248
+ }
249
+ }, "langchain.handleChatModelStart.set_attrs", this.internalLogger);
250
+ this.runs.set(runId, {
251
+ span: startedSpan,
252
+ effectiveParentSpan: startedSpan,
253
+ sessionId,
254
+ nearestAgentSessionId: this.inheritedAgentSessionId(parentRunId),
255
+ kind: "llm",
256
+ });
257
+ };
258
+ handleLLMStart = (llm, prompts, runId, parentRunId, extraParams, tags, metadata, runName) => {
259
+ // Treat completion-style LLMs as chat with a single user message.
260
+ const messages = prompts.map((p) => [
261
+ { _getType: () => "human", content: p },
262
+ ]);
263
+ this.handleChatModelStart(llm, messages, runId, parentRunId, extraParams, tags, metadata, runName);
264
+ };
265
+ handleLLMEnd = (output, runId) => {
266
+ const r = this.runs.get(runId);
267
+ this.runs.delete(runId);
268
+ if (!r || !r.span)
269
+ return;
270
+ const span = r.span;
271
+ const sessionId = r.sessionId;
272
+ safe(() => {
273
+ const gen = output.generations?.[0]?.[0];
274
+ const message = gen?.message;
275
+ if (!message)
276
+ return;
277
+ setLlmResponseAttrs(span, this.sdk, this.logger, message, span.attributes?.[GEN_AI.PROVIDER_NAME], sessionId);
278
+ }, "langchain.handleLLMEnd.set_response_attrs", this.internalLogger);
279
+ safe(() => {
280
+ const gen = output.generations?.[0]?.[0];
281
+ const message = gen?.message;
282
+ if (!message)
283
+ return;
284
+ // Bridge tool_calls into the pending queue so @struct.tool() can autofill.
285
+ const toolCalls = message.tool_calls;
286
+ if (!Array.isArray(toolCalls) || toolCalls.length === 0)
287
+ return;
288
+ const pairs = [];
289
+ for (const tc of toolCalls) {
290
+ if (tc && typeof tc === "object") {
291
+ const n = tc.name;
292
+ const id = tc.id;
293
+ if (typeof n === "string" && typeof id === "string" && n && id) {
294
+ pairs.push([n, id]);
295
+ }
296
+ }
297
+ }
298
+ if (pairs.length > 0)
299
+ pushPendingToolCalls(pairs);
300
+ }, "langchain.handleLLMEnd.record_pending_tool_calls", this.internalLogger);
301
+ safe(() => span.setStatus({ code: SpanStatusCode.OK }), "langchain.handleLLMEnd.set_status", this.internalLogger);
302
+ safe(() => span.end(), "langchain.handleLLMEnd.span_end", this.internalLogger);
303
+ };
304
+ handleLLMError = (err, runId) => {
305
+ const r = this.runs.get(runId);
306
+ this.runs.delete(runId);
307
+ if (!r || !r.span)
308
+ return;
309
+ const span = r.span;
310
+ safe(() => recordError(span, err), "langchain.handleLLMError.record_error", this.internalLogger);
311
+ safe(() => span.end(), "langchain.handleLLMError.span_end", this.internalLogger);
312
+ };
313
+ // ─── Tool ────────────────────────────────────────────────────────────────
314
+ handleToolStart = (tool, input, runId, parentRunId, _tags, metadata, runName) => {
315
+ const toolName = runName ??
316
+ (typeof tool === "object" && tool?.name) ??
317
+ extractClassName(tool) ??
318
+ "tool";
319
+ const { parentSpan } = this.resolveParent(parentRunId);
320
+ const parentCtx = parentSpan
321
+ ? trace.setSpan(otelContext.active(), parentSpan)
322
+ : otelContext.active();
323
+ let span;
324
+ safe(() => {
325
+ span = this.tracer.startSpan(`execute_tool ${toolName}`, { kind: SpanKind.INTERNAL }, parentCtx);
326
+ }, "langchain.handleToolStart.create_span", this.internalLogger);
327
+ if (span === undefined)
328
+ return;
329
+ const startedSpan = span;
330
+ const sessionId = this.resolveSessionId(parentRunId, metadata);
331
+ safe(() => {
332
+ startedSpan.setAttribute(GEN_AI.OPERATION_NAME, "execute_tool");
333
+ startedSpan.setAttribute(GEN_AI.PROVIDER_NAME, "langchain");
334
+ startedSpan.setAttribute(GEN_AI.TOOL_NAME, String(toolName));
335
+ // Tool call id from metadata (LangChain passes it there for ToolCall inputs)
336
+ // or fallback to the pending queue populated by the LLM's tool_calls.
337
+ const callId = metadata?.tool_call_id ??
338
+ extractToolCallIdFromInput(input) ??
339
+ popPendingToolCallId(String(toolName));
340
+ if (callId)
341
+ startedSpan.setAttribute(GEN_AI.TOOL_CALL_ID, callId);
342
+ startedSpan.setAttribute(GEN_AI.CONVERSATION_ID, sessionId);
343
+ if (this.sdk.captureContent && input !== undefined) {
344
+ startedSpan.setAttribute(GEN_AI.TOOL_CALL_ARGUMENTS, safeJsonStringify(input).slice(0, 8192));
345
+ }
346
+ }, "langchain.handleToolStart.set_attrs", this.internalLogger);
347
+ this.runs.set(runId, {
348
+ span: startedSpan,
349
+ effectiveParentSpan: startedSpan,
350
+ sessionId,
351
+ nearestAgentSessionId: this.inheritedAgentSessionId(parentRunId),
352
+ kind: "tool",
353
+ });
354
+ };
355
+ handleToolEnd = (output, runId) => {
356
+ const r = this.runs.get(runId);
357
+ this.runs.delete(runId);
358
+ if (!r || !r.span)
359
+ return;
360
+ const span = r.span;
361
+ safe(() => {
362
+ if (this.sdk.captureContent && output != null) {
363
+ span.setAttribute(GEN_AI.TOOL_CALL_RESULT, safeJsonStringify(output).slice(0, 8192));
364
+ }
365
+ }, "langchain.handleToolEnd.set_result", this.internalLogger);
366
+ safe(() => span.setStatus({ code: SpanStatusCode.OK }), "langchain.handleToolEnd.set_status", this.internalLogger);
367
+ safe(() => span.end(), "langchain.handleToolEnd.span_end", this.internalLogger);
368
+ };
369
+ handleToolError = (err, runId) => {
370
+ const r = this.runs.get(runId);
371
+ this.runs.delete(runId);
372
+ if (!r || !r.span)
373
+ return;
374
+ const span = r.span;
375
+ safe(() => recordError(span, err), "langchain.handleToolError.record_error", this.internalLogger);
376
+ safe(() => span.end(), "langchain.handleToolError.span_end", this.internalLogger);
377
+ };
378
+ // ─── Retriever ───────────────────────────────────────────────────────────
379
+ handleRetrieverStart = (retriever, query, runId, parentRunId, _tags, metadata, runName) => {
380
+ const name = runName ??
381
+ retriever?.name ??
382
+ extractClassName(retriever) ??
383
+ "retriever";
384
+ const { parentSpan } = this.resolveParent(parentRunId);
385
+ const parentCtx = parentSpan
386
+ ? trace.setSpan(otelContext.active(), parentSpan)
387
+ : otelContext.active();
388
+ let span;
389
+ safe(() => {
390
+ span = this.tracer.startSpan(`retrieval ${name}`, { kind: SpanKind.INTERNAL }, parentCtx);
391
+ }, "langchain.handleRetrieverStart.create_span", this.internalLogger);
392
+ if (span === undefined)
393
+ return;
394
+ const startedSpan = span;
395
+ const sessionId = this.resolveSessionId(parentRunId, metadata);
396
+ safe(() => {
397
+ startedSpan.setAttribute(GEN_AI.OPERATION_NAME, "retrieval");
398
+ startedSpan.setAttribute(GEN_AI.PROVIDER_NAME, "langchain");
399
+ startedSpan.setAttribute(GEN_AI.DATA_SOURCE_ID, String(name));
400
+ startedSpan.setAttribute(GEN_AI.CONVERSATION_ID, sessionId);
401
+ if (this.sdk.captureContent && typeof query === "string") {
402
+ startedSpan.setAttribute(GEN_AI.RETRIEVAL_QUERY_TEXT, query.slice(0, 4096));
403
+ }
404
+ }, "langchain.handleRetrieverStart.set_attrs", this.internalLogger);
405
+ this.runs.set(runId, {
406
+ span: startedSpan,
407
+ effectiveParentSpan: startedSpan,
408
+ sessionId,
409
+ nearestAgentSessionId: this.inheritedAgentSessionId(parentRunId),
410
+ kind: "retriever",
411
+ });
412
+ };
413
+ handleRetrieverEnd = (documents, runId) => {
414
+ const r = this.runs.get(runId);
415
+ this.runs.delete(runId);
416
+ if (!r || !r.span)
417
+ return;
418
+ const span = r.span;
419
+ safe(() => {
420
+ if (Array.isArray(documents)) {
421
+ span.setAttribute(GEN_AI.RETRIEVAL_DOCUMENTS, documents.length);
422
+ }
423
+ }, "langchain.handleRetrieverEnd.set_doc_count", this.internalLogger);
424
+ safe(() => span.setStatus({ code: SpanStatusCode.OK }), "langchain.handleRetrieverEnd.set_status", this.internalLogger);
425
+ safe(() => span.end(), "langchain.handleRetrieverEnd.span_end", this.internalLogger);
426
+ };
427
+ handleRetrieverError = (err, runId) => {
428
+ const r = this.runs.get(runId);
429
+ this.runs.delete(runId);
430
+ if (!r || !r.span)
431
+ return;
432
+ const span = r.span;
433
+ safe(() => recordError(span, err), "langchain.handleRetrieverError.record_error", this.internalLogger);
434
+ safe(() => span.end(), "langchain.handleRetrieverError.span_end", this.internalLogger);
435
+ };
436
+ // ─── Internals ───────────────────────────────────────────────────────────
437
+ resolveParent(parentRunId) {
438
+ if (parentRunId) {
439
+ const p = this.runs.get(parentRunId);
440
+ if (p) {
441
+ // Use the effective parent span, which correctly skips over
442
+ // filtered chains (RunnableSequence, ChannelWrite, ...).
443
+ return {
444
+ parentSpan: p.effectiveParentSpan,
445
+ parentSpanIsAgent: p.kind === "chain",
446
+ };
447
+ }
448
+ }
449
+ return { parentSpan: getAgentSpan(), parentSpanIsAgent: true };
450
+ }
451
+ /**
452
+ * Conversation-id resolution for chat/tool/retriever spans — INHERIT from
453
+ * the parent agent so everything rolls up under one gen_ai.conversation.id.
454
+ */
455
+ resolveSessionId(parentRunId, metadata) {
456
+ if (parentRunId) {
457
+ const p = this.runs.get(parentRunId);
458
+ if (p?.sessionId)
459
+ return p.sessionId;
460
+ }
461
+ const threadId = metadata?.thread_id;
462
+ if (typeof threadId === "string" && threadId.length > 0)
463
+ return threadId;
464
+ const ambient = getSessionId();
465
+ if (ambient)
466
+ return ambient;
467
+ return randomUUID();
468
+ }
469
+ /**
470
+ * Walk the run tree to find the nearest ``invoke_agent`` ancestor's
471
+ * gen_ai.conversation.id.
472
+ *
473
+ * The immediate ``parentRunId`` might be a tool, LLM, retriever, or a
474
+ * filtered RunnableSequence — none of which are agents themselves. We
475
+ * populate ``nearestAgentSessionId`` at each run's creation so any
476
+ * descendant can read it in O(1).
477
+ *
478
+ * Used to set ``struct.agent.parent_session_id`` on nested ``invoke_agent``
479
+ * spans (our UI's "Spawned by" / "Subagents" linkage).
480
+ */
481
+ inheritedAgentSessionId(parentRunId) {
482
+ if (!parentRunId)
483
+ return undefined;
484
+ return this.runs.get(parentRunId)?.nearestAgentSessionId;
485
+ }
486
+ /**
487
+ * Conversation-id resolution for AGENT spans — each agent invocation gets
488
+ * its own gen_ai.conversation.id. We deliberately do NOT inherit from the
489
+ * parent run, so subagents surface as separate entries in the sessions
490
+ * list. Parent linkage is preserved via `struct.agent.parent_session_id`.
491
+ *
492
+ * LangChain inherits `metadata.thread_id` from the parent invoke's config
493
+ * when a nested invoke runs inside it (even if the child config supplied
494
+ * its own). We detect that inheritance by comparing against the parent's
495
+ * resolved session and ignore the inherited value.
496
+ */
497
+ resolveAgentSessionId(metadata, parentSessionId) {
498
+ const threadId = metadata?.thread_id;
499
+ if (typeof threadId === "string" && threadId.length > 0) {
500
+ if (parentSessionId && threadId === parentSessionId) {
501
+ // Inherited from parent — treat as unset, assign fresh.
502
+ return randomUUID();
503
+ }
504
+ return threadId;
505
+ }
506
+ const ambient = getSessionId();
507
+ if (ambient)
508
+ return ambient;
509
+ return randomUUID();
510
+ }
511
+ propagateUserPrompt(parentSpan, messages) {
512
+ try {
513
+ const attrs = parentSpan
514
+ .attributes;
515
+ if (attrs && attrs[GEN_AI.INPUT_MESSAGES])
516
+ return;
517
+ const parts = lastUserMessageParts(messages);
518
+ if (!parts)
519
+ return;
520
+ parentSpan.setAttribute(GEN_AI.INPUT_MESSAGES, truncateAndSerialize([{ role: "user", parts }]));
521
+ }
522
+ catch {
523
+ /* never fail telemetry */
524
+ }
525
+ }
526
+ }
527
+ // ─── helpers ─────────────────────────────────────────────────────────────────
528
+ /**
529
+ * Only promote explicit agent classes to `invoke_agent`. LangGraph fires
530
+ * chain-start for every internal node (`ChannelWrite`, `Branch`, `prompt`,
531
+ * `tools`, `__start__`, etc.); those are plumbing, not user-meaningful
532
+ * agent invocations, so we drop them to avoid flooding the waterfall.
533
+ *
534
+ * Users of non-standard agent frameworks can opt in by setting
535
+ * `runType: "agent"` in the Runnable config.
536
+ */
537
+ const AGENT_CLASSES = new Set([
538
+ "AgentExecutor",
539
+ "CompiledStateGraph",
540
+ "CompiledGraph",
541
+ "Pregel",
542
+ "LangGraph",
543
+ ]);
544
+ function isAgentChain(chain, runType, _runName) {
545
+ if (runType === "agent")
546
+ return true;
547
+ const cls = extractClassName(chain);
548
+ return !!cls && AGENT_CLASSES.has(cls);
549
+ }
550
+ function extractClassName(obj) {
551
+ if (!obj)
552
+ return undefined;
553
+ if (Array.isArray(obj.id) && obj.id.length > 0) {
554
+ const last = obj.id[obj.id.length - 1];
555
+ if (typeof last === "string")
556
+ return last;
557
+ }
558
+ if (typeof obj.name === "string")
559
+ return obj.name;
560
+ return undefined;
561
+ }
562
+ function detectProviderFromSerialized(llm) {
563
+ const cls = extractClassName(llm) ?? "";
564
+ const fake = { constructor: { name: cls }, _llmType: undefined };
565
+ return detectProvider(fake);
566
+ }
567
+ function extractParam(obj, key) {
568
+ if (!obj || typeof obj !== "object")
569
+ return undefined;
570
+ const v = obj[key];
571
+ return typeof v === "string" && v.length > 0 ? v : undefined;
572
+ }
573
+ function setRequestAttrsFromInvocation(span, invocation) {
574
+ if (!invocation || typeof invocation !== "object")
575
+ return;
576
+ const m = invocation;
577
+ const mapping = [
578
+ ["temperature", GEN_AI.REQUEST_TEMPERATURE],
579
+ ["maxTokens", GEN_AI.REQUEST_MAX_TOKENS],
580
+ ["max_tokens", GEN_AI.REQUEST_MAX_TOKENS],
581
+ ["topP", GEN_AI.REQUEST_TOP_P],
582
+ ["top_p", GEN_AI.REQUEST_TOP_P],
583
+ ["topK", GEN_AI.REQUEST_TOP_K],
584
+ ["top_k", GEN_AI.REQUEST_TOP_K],
585
+ ["frequencyPenalty", GEN_AI.REQUEST_FREQUENCY_PENALTY],
586
+ ["presencePenalty", GEN_AI.REQUEST_PRESENCE_PENALTY],
587
+ ];
588
+ for (const [src, dst] of mapping) {
589
+ const v = m[src];
590
+ if (typeof v === "number")
591
+ span.setAttribute(dst, v);
592
+ }
593
+ const stop = m.stop ?? m.stopSequences ?? m.stop_sequences;
594
+ if (Array.isArray(stop) && stop.length > 0) {
595
+ span.setAttribute(GEN_AI.REQUEST_STOP_SEQUENCES, stop);
596
+ }
597
+ }
598
+ function setLlmResponseAttrs(span, sdk, logger, message, provider, sessionId) {
599
+ if (!message || typeof message !== "object")
600
+ return;
601
+ const m = message;
602
+ const usage = m.usage_metadata;
603
+ if (usage) {
604
+ if (typeof usage.input_tokens === "number")
605
+ span.setAttribute(GEN_AI.USAGE_INPUT_TOKENS, usage.input_tokens);
606
+ if (typeof usage.output_tokens === "number")
607
+ span.setAttribute(GEN_AI.USAGE_OUTPUT_TOKENS, usage.output_tokens);
608
+ const cr = usage.input_token_details?.cache_read;
609
+ const cc = usage.input_token_details?.cache_creation;
610
+ if (typeof cr === "number" && cr > 0)
611
+ span.setAttribute(GEN_AI.USAGE_CACHE_READ_INPUT_TOKENS, cr);
612
+ if (typeof cc === "number" && cc > 0)
613
+ span.setAttribute(GEN_AI.USAGE_CACHE_CREATION_INPUT_TOKENS, cc);
614
+ }
615
+ const respMeta = m.response_metadata ?? {};
616
+ const respModel = (typeof respMeta.model_name === "string" && respMeta.model_name) ||
617
+ (typeof respMeta.model === "string" && respMeta.model) ||
618
+ null;
619
+ if (respModel)
620
+ span.setAttribute(GEN_AI.RESPONSE_MODEL, respModel);
621
+ const finish = (typeof respMeta.finish_reason === "string" && respMeta.finish_reason) ||
622
+ (typeof respMeta.stop_reason === "string" && respMeta.stop_reason) ||
623
+ null;
624
+ if (finish) {
625
+ const mapped = LANGCHAIN_FINISH_REASON_MAP[finish] ?? finish;
626
+ span.setAttribute(GEN_AI.RESPONSE_FINISH_REASONS, [mapped]);
627
+ }
628
+ const respId = (typeof m.id === "string" && m.id) ||
629
+ (typeof respMeta.id === "string" && respMeta.id) ||
630
+ null;
631
+ if (respId)
632
+ span.setAttribute(GEN_AI.RESPONSE_ID, respId);
633
+ if (sdk.emitEvents && logger) {
634
+ emitChoiceEvent(logger, message, provider ?? "langchain", sessionId, span);
635
+ }
636
+ if (sdk.emitSpanContent) {
637
+ span.setAttribute(GEN_AI.OUTPUT_MESSAGES, langchainToOutputMessages(message));
638
+ }
639
+ }
640
+ // OTel logs convention for our emitted log events:
641
+ // - Body column = event tag string (human-readable signal)
642
+ // - LogAttributes["body"] = JSON-serialised structured payload
643
+ // Both emitMessageEvents and emitChoiceEvent bypass the central emitLogRecord
644
+ // helper in events.ts because they need to bind a specific span context (the
645
+ // callback handler creates spans directly and doesn't enter them with
646
+ // context.with). The flip is inlined at both sites.
647
+ function emitMessageEvents(logger, messages, provider, sessionId, span) {
648
+ // Bind the log record's context to the chat span so the exported LogRecord
649
+ // carries non-zero TraceId/SpanId. Using `otelContext.active()` here would
650
+ // only work if the caller had entered `context.with(spanCtx, ...)` first —
651
+ // the LangChain callback handler doesn't (it creates the span directly).
652
+ const logCtx = trace.setSpan(otelContext.active(), span);
653
+ for (let i = 0; i < messages.length; i++) {
654
+ const { role, parts } = langchainMessageToRoleAndParts(messages[i]);
655
+ const eventName = ROLE_TO_EVENT_NAME[role] ?? `gen_ai.${role}.message`;
656
+ const payload = safeJsonStringify({ role, parts: truncateParts(parts) });
657
+ logger.emit({
658
+ body: eventName,
659
+ context: logCtx,
660
+ attributes: {
661
+ [EVENT_NAME]: eventName,
662
+ body: payload,
663
+ [GEN_AI.SYSTEM]: provider,
664
+ [GEN_AI.MESSAGE_INDEX]: i,
665
+ [GEN_AI.CONVERSATION_ID]: sessionId,
666
+ },
667
+ });
668
+ }
669
+ }
670
+ function emitChoiceEvent(logger, message, provider, sessionId, span) {
671
+ const { parts } = langchainMessageToRoleAndParts(message);
672
+ const respMeta = (message && typeof message === "object"
673
+ ? message.response_metadata
674
+ : undefined) ?? {};
675
+ const finish = (typeof respMeta.finish_reason === "string" && respMeta.finish_reason) ||
676
+ (typeof respMeta.stop_reason === "string" && respMeta.stop_reason) ||
677
+ "stop";
678
+ const mapped = LANGCHAIN_FINISH_REASON_MAP[finish] ?? finish;
679
+ const payload = safeJsonStringify({
680
+ index: 0,
681
+ finish_reason: mapped,
682
+ message: { role: "assistant", parts: truncateParts(parts) },
683
+ });
684
+ logger.emit({
685
+ body: EVENT_NAMES.CHOICE,
686
+ context: trace.setSpan(otelContext.active(), span),
687
+ attributes: {
688
+ [EVENT_NAME]: EVENT_NAMES.CHOICE,
689
+ body: payload,
690
+ [GEN_AI.SYSTEM]: provider,
691
+ [GEN_AI.CONVERSATION_ID]: sessionId,
692
+ },
693
+ });
694
+ }
695
+ function extractChainInputMessages(inputs) {
696
+ if (!inputs || typeof inputs !== "object")
697
+ return undefined;
698
+ const msgs = inputs.messages;
699
+ if (Array.isArray(msgs))
700
+ return msgs;
701
+ return undefined;
702
+ }
703
+ function extractToolCallIdFromInput(input) {
704
+ if (input && typeof input === "object" && !Array.isArray(input)) {
705
+ const id = input.id;
706
+ if (typeof id === "string" && id.length > 0)
707
+ return id;
708
+ }
709
+ return undefined;
710
+ }
711
+ function recordError(span, err) {
712
+ const errorType = err instanceof Error ? err.constructor.name : typeof err;
713
+ const message = err instanceof Error ? err.message : String(err);
714
+ span.setAttribute(ERROR_TYPE, errorType);
715
+ span.setStatus({ code: SpanStatusCode.ERROR, message });
716
+ if (err instanceof Error)
717
+ span.recordException(err);
718
+ }
719
+ //# sourceMappingURL=langchain-callback.js.map