@morphllm/morphsdk 0.2.178 → 0.2.180

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (220) hide show
  1. package/dist/{chunk-JCKR7NED.js → chunk-2DLMZDDB.js} +3 -3
  2. package/dist/{chunk-S2KANK3D.js → chunk-2WQTCETP.js} +2 -2
  3. package/dist/{chunk-PDPQV3DI.js → chunk-35ZAMQ3A.js} +4 -4
  4. package/dist/{chunk-2U7YFUMU.js → chunk-4RARO46V.js} +4 -4
  5. package/dist/{chunk-WLXPKUEQ.js → chunk-4TMCQZNB.js} +2 -2
  6. package/dist/{chunk-WLXPKUEQ.js.map → chunk-4TMCQZNB.js.map} +1 -1
  7. package/dist/{chunk-APSFRYOW.js → chunk-AERVDGON.js} +2 -2
  8. package/dist/{chunk-U5LXWLP7.js → chunk-BN4IHFWR.js} +2 -2
  9. package/dist/{chunk-7JL65PRH.js → chunk-D4XCP2ZE.js} +3 -3
  10. package/dist/{chunk-WZAKJJSR.js → chunk-DFTKUEF5.js} +2 -2
  11. package/dist/{chunk-44IZ4TT5.js → chunk-EAGSRHRT.js} +2 -2
  12. package/dist/{chunk-NVNYDL6N.js → chunk-EJZFQAKT.js} +2 -2
  13. package/dist/{chunk-WCW42MV2.js → chunk-GVN6B4YX.js} +3 -3
  14. package/dist/{chunk-EA3PJ2Y7.js → chunk-GZDRJBI2.js} +2 -2
  15. package/dist/{chunk-UUUY4SGW.js → chunk-HXDITEO6.js} +2 -2
  16. package/dist/{chunk-LX54AI3F.js → chunk-IDMKQWQG.js} +81 -14
  17. package/dist/chunk-IDMKQWQG.js.map +1 -0
  18. package/dist/{chunk-TQ5RX4HR.js → chunk-IOZMMARY.js} +2 -2
  19. package/dist/{chunk-6WEF6UCR.js → chunk-IS5TDLAJ.js} +2 -2
  20. package/dist/{chunk-BNKT5FXS.js → chunk-JG5MJI34.js} +2 -2
  21. package/dist/{chunk-CHJAXYH6.js → chunk-LBOFTF6A.js} +21 -21
  22. package/dist/{chunk-MF4VKKGF.js → chunk-LDXKXBYN.js} +2 -2
  23. package/dist/{chunk-VBPSPP4F.js → chunk-MWUFDBWQ.js} +2 -2
  24. package/dist/{chunk-HWRZZZT4.js → chunk-OE2LFOYB.js} +2 -2
  25. package/dist/{chunk-NR4KNQAT.js → chunk-QAZM5ELA.js} +2 -2
  26. package/dist/{chunk-MOCMOSGF.js → chunk-QW33U4EI.js} +4 -4
  27. package/dist/{chunk-AVJJABHB.js → chunk-STJTJDAV.js} +28 -13
  28. package/dist/chunk-STJTJDAV.js.map +1 -0
  29. package/dist/{chunk-PXL3VUK2.js → chunk-SX2P5ZUP.js} +2 -2
  30. package/dist/{chunk-RAPGIYHS.js → chunk-TBVIOQ5O.js} +2 -2
  31. package/dist/{chunk-ZXBAHHQI.js → chunk-TDT6J2X4.js} +2 -2
  32. package/dist/{chunk-CABQ652L.js → chunk-TLXVGE4R.js} +1 -1
  33. package/dist/chunk-TLXVGE4R.js.map +1 -0
  34. package/dist/{chunk-EPJZVTNY.js → chunk-U4KCWD3I.js} +2 -2
  35. package/dist/{chunk-TGFSIZAJ.js → chunk-WQC3YOER.js} +3 -3
  36. package/dist/{chunk-FWVBSH2M.js → chunk-X4VPV3A7.js} +2 -2
  37. package/dist/{chunk-JFVFAFHR.js → chunk-XEQZQTZR.js} +2 -2
  38. package/dist/{chunk-IPEYIERJ.js → chunk-XYHP2TFY.js} +2 -2
  39. package/dist/client.cjs +1 -1
  40. package/dist/client.cjs.map +1 -1
  41. package/dist/client.js +28 -28
  42. package/dist/core/client.cjs +1 -1
  43. package/dist/core/client.cjs.map +1 -1
  44. package/dist/core/client.js +4 -4
  45. package/dist/core/error.cjs +1 -1
  46. package/dist/core/error.cjs.map +1 -1
  47. package/dist/core/error.js +3 -3
  48. package/dist/core/index.cjs +1 -1
  49. package/dist/core/index.cjs.map +1 -1
  50. package/dist/core/index.js +4 -4
  51. package/dist/edge.cjs +1 -1
  52. package/dist/edge.cjs.map +1 -1
  53. package/dist/edge.js +7 -7
  54. package/dist/git/client.cjs +1 -1
  55. package/dist/git/client.cjs.map +1 -1
  56. package/dist/git/client.js +5 -5
  57. package/dist/git/index.cjs +1 -1
  58. package/dist/git/index.cjs.map +1 -1
  59. package/dist/git/index.js +5 -5
  60. package/dist/index.cjs +1 -1
  61. package/dist/index.cjs.map +1 -1
  62. package/dist/index.js +28 -28
  63. package/dist/modelrouter/core.cjs +1 -1
  64. package/dist/modelrouter/core.cjs.map +1 -1
  65. package/dist/modelrouter/core.js +5 -5
  66. package/dist/modelrouter/index.cjs +1 -1
  67. package/dist/modelrouter/index.cjs.map +1 -1
  68. package/dist/modelrouter/index.js +5 -5
  69. package/dist/{otel-Dk8kdhmZ.d.ts → otel-CG0uqXjp.d.ts} +1 -1
  70. package/dist/subagents/anthropic.cjs +1 -1
  71. package/dist/subagents/anthropic.cjs.map +1 -1
  72. package/dist/subagents/anthropic.js +9 -9
  73. package/dist/subagents/vercel.cjs +1 -1
  74. package/dist/subagents/vercel.cjs.map +1 -1
  75. package/dist/subagents/vercel.js +9 -9
  76. package/dist/tools/browser/anthropic.cjs +1 -1
  77. package/dist/tools/browser/anthropic.cjs.map +1 -1
  78. package/dist/tools/browser/anthropic.js +7 -7
  79. package/dist/tools/browser/core.cjs +1 -1
  80. package/dist/tools/browser/core.cjs.map +1 -1
  81. package/dist/tools/browser/core.js +6 -6
  82. package/dist/tools/browser/index.cjs +1 -1
  83. package/dist/tools/browser/index.cjs.map +1 -1
  84. package/dist/tools/browser/index.js +9 -9
  85. package/dist/tools/browser/openai.cjs +1 -1
  86. package/dist/tools/browser/openai.cjs.map +1 -1
  87. package/dist/tools/browser/openai.js +7 -7
  88. package/dist/tools/browser/profiles/core.cjs +1 -1
  89. package/dist/tools/browser/profiles/core.cjs.map +1 -1
  90. package/dist/tools/browser/profiles/core.js +3 -3
  91. package/dist/tools/browser/profiles/index.cjs +1 -1
  92. package/dist/tools/browser/profiles/index.cjs.map +1 -1
  93. package/dist/tools/browser/profiles/index.js +3 -3
  94. package/dist/tools/browser/vercel.cjs +1 -1
  95. package/dist/tools/browser/vercel.cjs.map +1 -1
  96. package/dist/tools/browser/vercel.js +7 -7
  97. package/dist/tools/codebase_search/anthropic.cjs +1 -1
  98. package/dist/tools/codebase_search/anthropic.cjs.map +1 -1
  99. package/dist/tools/codebase_search/anthropic.js +6 -6
  100. package/dist/tools/codebase_search/core.cjs +1 -1
  101. package/dist/tools/codebase_search/core.cjs.map +1 -1
  102. package/dist/tools/codebase_search/core.js +5 -5
  103. package/dist/tools/codebase_search/index.cjs +1 -1
  104. package/dist/tools/codebase_search/index.cjs.map +1 -1
  105. package/dist/tools/codebase_search/index.js +8 -8
  106. package/dist/tools/codebase_search/openai.cjs +1 -1
  107. package/dist/tools/codebase_search/openai.cjs.map +1 -1
  108. package/dist/tools/codebase_search/openai.js +6 -6
  109. package/dist/tools/codebase_search/vercel.cjs +1 -1
  110. package/dist/tools/codebase_search/vercel.cjs.map +1 -1
  111. package/dist/tools/codebase_search/vercel.js +6 -6
  112. package/dist/tools/compact/core.cjs +1 -1
  113. package/dist/tools/compact/core.cjs.map +1 -1
  114. package/dist/tools/compact/core.js +5 -5
  115. package/dist/tools/compact/index.cjs +1 -1
  116. package/dist/tools/compact/index.cjs.map +1 -1
  117. package/dist/tools/compact/index.js +6 -6
  118. package/dist/tools/fastapply/anthropic.cjs +1 -1
  119. package/dist/tools/fastapply/anthropic.cjs.map +1 -1
  120. package/dist/tools/fastapply/anthropic.js +7 -7
  121. package/dist/tools/fastapply/apply.cjs +1 -1
  122. package/dist/tools/fastapply/apply.cjs.map +1 -1
  123. package/dist/tools/fastapply/apply.js +2 -2
  124. package/dist/tools/fastapply/core.cjs +1 -1
  125. package/dist/tools/fastapply/core.cjs.map +1 -1
  126. package/dist/tools/fastapply/core.js +6 -6
  127. package/dist/tools/fastapply/index.cjs +1 -1
  128. package/dist/tools/fastapply/index.cjs.map +1 -1
  129. package/dist/tools/fastapply/index.js +9 -9
  130. package/dist/tools/fastapply/openai.cjs +1 -1
  131. package/dist/tools/fastapply/openai.cjs.map +1 -1
  132. package/dist/tools/fastapply/openai.js +7 -7
  133. package/dist/tools/fastapply/vercel.cjs +1 -1
  134. package/dist/tools/fastapply/vercel.cjs.map +1 -1
  135. package/dist/tools/fastapply/vercel.js +7 -7
  136. package/dist/tools/index.cjs +1 -1
  137. package/dist/tools/index.cjs.map +1 -1
  138. package/dist/tools/index.js +9 -9
  139. package/dist/tools/reflex/core.cjs +1 -1
  140. package/dist/tools/reflex/core.cjs.map +1 -1
  141. package/dist/tools/reflex/core.js +5 -5
  142. package/dist/tools/reflex/index.cjs +1 -1
  143. package/dist/tools/reflex/index.cjs.map +1 -1
  144. package/dist/tools/reflex/index.js +5 -5
  145. package/dist/tools/utils/resilience.cjs +1 -1
  146. package/dist/tools/utils/resilience.cjs.map +1 -1
  147. package/dist/tools/utils/resilience.js +2 -2
  148. package/dist/tools/warp_grep/agent/runner.cjs +1 -1
  149. package/dist/tools/warp_grep/agent/runner.cjs.map +1 -1
  150. package/dist/tools/warp_grep/agent/runner.js +2 -2
  151. package/dist/tools/warp_grep/anthropic.cjs +1 -1
  152. package/dist/tools/warp_grep/anthropic.cjs.map +1 -1
  153. package/dist/tools/warp_grep/anthropic.js +9 -9
  154. package/dist/tools/warp_grep/client.cjs +1 -1
  155. package/dist/tools/warp_grep/client.cjs.map +1 -1
  156. package/dist/tools/warp_grep/client.js +8 -8
  157. package/dist/tools/warp_grep/gemini.cjs +1 -1
  158. package/dist/tools/warp_grep/gemini.cjs.map +1 -1
  159. package/dist/tools/warp_grep/gemini.js +8 -8
  160. package/dist/tools/warp_grep/index.cjs +1 -1
  161. package/dist/tools/warp_grep/index.cjs.map +1 -1
  162. package/dist/tools/warp_grep/index.js +8 -8
  163. package/dist/tools/warp_grep/openai.cjs +1 -1
  164. package/dist/tools/warp_grep/openai.cjs.map +1 -1
  165. package/dist/tools/warp_grep/openai.js +9 -9
  166. package/dist/tools/warp_grep/vercel.cjs +1 -1
  167. package/dist/tools/warp_grep/vercel.cjs.map +1 -1
  168. package/dist/tools/warp_grep/vercel.js +9 -9
  169. package/dist/tracing/core.cjs +100 -20
  170. package/dist/tracing/core.cjs.map +1 -1
  171. package/dist/tracing/core.d.ts +7 -2
  172. package/dist/tracing/core.js +3 -3
  173. package/dist/tracing/index.cjs +100 -20
  174. package/dist/tracing/index.cjs.map +1 -1
  175. package/dist/tracing/index.d.ts +1 -1
  176. package/dist/tracing/index.js +3 -3
  177. package/dist/tracing/interaction.cjs +81 -13
  178. package/dist/tracing/interaction.cjs.map +1 -1
  179. package/dist/tracing/interaction.d.ts +12 -2
  180. package/dist/tracing/interaction.js +6 -4
  181. package/dist/tracing/otel.cjs.map +1 -1
  182. package/dist/tracing/otel.d.ts +1 -1
  183. package/dist/tracing/otel.js +1 -1
  184. package/dist/version.cjs +1 -1
  185. package/dist/version.cjs.map +1 -1
  186. package/dist/version.js +1 -1
  187. package/package.json +1 -1
  188. package/dist/chunk-AVJJABHB.js.map +0 -1
  189. package/dist/chunk-CABQ652L.js.map +0 -1
  190. package/dist/chunk-LX54AI3F.js.map +0 -1
  191. /package/dist/{chunk-JCKR7NED.js.map → chunk-2DLMZDDB.js.map} +0 -0
  192. /package/dist/{chunk-S2KANK3D.js.map → chunk-2WQTCETP.js.map} +0 -0
  193. /package/dist/{chunk-PDPQV3DI.js.map → chunk-35ZAMQ3A.js.map} +0 -0
  194. /package/dist/{chunk-2U7YFUMU.js.map → chunk-4RARO46V.js.map} +0 -0
  195. /package/dist/{chunk-APSFRYOW.js.map → chunk-AERVDGON.js.map} +0 -0
  196. /package/dist/{chunk-U5LXWLP7.js.map → chunk-BN4IHFWR.js.map} +0 -0
  197. /package/dist/{chunk-7JL65PRH.js.map → chunk-D4XCP2ZE.js.map} +0 -0
  198. /package/dist/{chunk-WZAKJJSR.js.map → chunk-DFTKUEF5.js.map} +0 -0
  199. /package/dist/{chunk-44IZ4TT5.js.map → chunk-EAGSRHRT.js.map} +0 -0
  200. /package/dist/{chunk-NVNYDL6N.js.map → chunk-EJZFQAKT.js.map} +0 -0
  201. /package/dist/{chunk-WCW42MV2.js.map → chunk-GVN6B4YX.js.map} +0 -0
  202. /package/dist/{chunk-EA3PJ2Y7.js.map → chunk-GZDRJBI2.js.map} +0 -0
  203. /package/dist/{chunk-UUUY4SGW.js.map → chunk-HXDITEO6.js.map} +0 -0
  204. /package/dist/{chunk-TQ5RX4HR.js.map → chunk-IOZMMARY.js.map} +0 -0
  205. /package/dist/{chunk-6WEF6UCR.js.map → chunk-IS5TDLAJ.js.map} +0 -0
  206. /package/dist/{chunk-BNKT5FXS.js.map → chunk-JG5MJI34.js.map} +0 -0
  207. /package/dist/{chunk-CHJAXYH6.js.map → chunk-LBOFTF6A.js.map} +0 -0
  208. /package/dist/{chunk-MF4VKKGF.js.map → chunk-LDXKXBYN.js.map} +0 -0
  209. /package/dist/{chunk-VBPSPP4F.js.map → chunk-MWUFDBWQ.js.map} +0 -0
  210. /package/dist/{chunk-HWRZZZT4.js.map → chunk-OE2LFOYB.js.map} +0 -0
  211. /package/dist/{chunk-NR4KNQAT.js.map → chunk-QAZM5ELA.js.map} +0 -0
  212. /package/dist/{chunk-MOCMOSGF.js.map → chunk-QW33U4EI.js.map} +0 -0
  213. /package/dist/{chunk-PXL3VUK2.js.map → chunk-SX2P5ZUP.js.map} +0 -0
  214. /package/dist/{chunk-RAPGIYHS.js.map → chunk-TBVIOQ5O.js.map} +0 -0
  215. /package/dist/{chunk-ZXBAHHQI.js.map → chunk-TDT6J2X4.js.map} +0 -0
  216. /package/dist/{chunk-EPJZVTNY.js.map → chunk-U4KCWD3I.js.map} +0 -0
  217. /package/dist/{chunk-TGFSIZAJ.js.map → chunk-WQC3YOER.js.map} +0 -0
  218. /package/dist/{chunk-FWVBSH2M.js.map → chunk-X4VPV3A7.js.map} +0 -0
  219. /package/dist/{chunk-JFVFAFHR.js.map → chunk-XEQZQTZR.js.map} +0 -0
  220. /package/dist/{chunk-IPEYIERJ.js.map → chunk-XYHP2TFY.js.map} +0 -0
@@ -5,25 +5,25 @@ import {
5
5
  execute,
6
6
  vercel_default,
7
7
  warpGrepJsonSchema
8
- } from "../../chunk-HWRZZZT4.js";
8
+ } from "../../chunk-OE2LFOYB.js";
9
9
  import "../../chunk-Q6QCHAMD.js";
10
10
  import {
11
11
  formatResult
12
- } from "../../chunk-PDPQV3DI.js";
12
+ } from "../../chunk-35ZAMQ3A.js";
13
13
  import "../../chunk-GVGJIXV2.js";
14
14
  import "../../chunk-A4D2CIIT.js";
15
15
  import "../../chunk-63VHBANJ.js";
16
- import "../../chunk-VBPSPP4F.js";
16
+ import "../../chunk-MWUFDBWQ.js";
17
17
  import "../../chunk-IA5K2HTC.js";
18
18
  import "../../chunk-CCJK3HTG.js";
19
19
  import "../../chunk-FBRNUWEB.js";
20
- import "../../chunk-RAPGIYHS.js";
21
- import "../../chunk-TGFSIZAJ.js";
22
- import "../../chunk-2U7YFUMU.js";
20
+ import "../../chunk-TBVIOQ5O.js";
21
+ import "../../chunk-WQC3YOER.js";
22
+ import "../../chunk-4RARO46V.js";
23
23
  import "../../chunk-F3NCFNUX.js";
24
- import "../../chunk-FWVBSH2M.js";
25
- import "../../chunk-MF4VKKGF.js";
26
- import "../../chunk-WLXPKUEQ.js";
24
+ import "../../chunk-X4VPV3A7.js";
25
+ import "../../chunk-LDXKXBYN.js";
26
+ import "../../chunk-4TMCQZNB.js";
27
27
  import "../../chunk-LKFZBBTD.js";
28
28
  import "../../chunk-PZ5AY32C.js";
29
29
  export {
@@ -93,7 +93,7 @@ function associationProps(ctx, extra) {
93
93
  if (ctx.event) props.event_name = ctx.event;
94
94
  return props;
95
95
  }
96
- function createInteractionApi(initial, traceContent) {
96
+ function createInteractionApi(initial, traceContent, onClose) {
97
97
  const ctx = {
98
98
  ...initial,
99
99
  eventId: initial.eventId ?? uuid2()
@@ -101,6 +101,7 @@ function createInteractionApi(initial, traceContent) {
101
101
  const properties = { ...initial.properties ?? {} };
102
102
  let input = initial.input;
103
103
  let workflowSpan = null;
104
+ let finished = false;
104
105
  const withAssoc = (fn) => traceloop.withAssociationProperties(associationProps(ctx, properties), fn);
105
106
  const workflowName = () => ctx.event ?? "interaction";
106
107
  function ensureWorkflowSpan() {
@@ -120,6 +121,25 @@ function createInteractionApi(initial, traceContent) {
120
121
  return import_api.context.with(import_api.trace.setSpan(import_api.context.active(), span), fn);
121
122
  });
122
123
  }
124
+ function closeWorkflowSpan(apply) {
125
+ if (finished) return;
126
+ withAssoc(() => {
127
+ const span = ensureWorkflowSpan();
128
+ apply(span);
129
+ span.end();
130
+ });
131
+ workflowSpan = null;
132
+ finished = true;
133
+ onClose?.(ctx.eventId);
134
+ }
135
+ function failWorkflowSpan(err) {
136
+ const e = err instanceof Error ? err : new Error(String(err));
137
+ closeWorkflowSpan((span) => {
138
+ span.recordException(e);
139
+ span.setStatus({ code: import_api.SpanStatusCode.ERROR, message: e.message });
140
+ if (traceContent) span.setAttribute(ENTITY_OUTPUT, `ERROR: ${e.message}`);
141
+ });
142
+ }
123
143
  const toolName = (p) => typeof p === "string" ? p : p.name;
124
144
  function startToolSpan(params) {
125
145
  const name = toolName(params);
@@ -169,8 +189,13 @@ function createInteractionApi(initial, traceContent) {
169
189
  properties
170
190
  });
171
191
  },
172
- run(fn) {
173
- return Promise.resolve(withWorkflowContext(fn));
192
+ async run(fn) {
193
+ try {
194
+ return await Promise.resolve(withWorkflowContext(fn));
195
+ } catch (err) {
196
+ failWorkflowSpan(err);
197
+ throw err;
198
+ }
174
199
  },
175
200
  withSpan(params, fn) {
176
201
  const name = typeof params === "string" ? params : params.name;
@@ -192,14 +217,55 @@ function createInteractionApi(initial, traceContent) {
192
217
  async finish(opts) {
193
218
  const output = typeof opts === "string" ? opts : opts.output;
194
219
  if (typeof opts !== "string" && opts.properties) Object.assign(properties, opts.properties);
195
- await Promise.resolve(
196
- withAssoc(() => {
197
- const span = ensureWorkflowSpan();
198
- if (traceContent) span.setAttribute(ENTITY_OUTPUT, output);
199
- span.end();
200
- workflowSpan = null;
201
- })
202
- );
220
+ closeWorkflowSpan((span) => {
221
+ if (traceContent) span.setAttribute(ENTITY_OUTPUT, output);
222
+ });
223
+ }
224
+ };
225
+ }
226
+ function createNoopInteraction(initial) {
227
+ const ctx = {
228
+ ...initial,
229
+ eventId: initial.eventId ?? uuid2()
230
+ };
231
+ const properties = { ...initial.properties ?? {} };
232
+ const noopToolSpan = { setInput() {
233
+ }, setOutput() {
234
+ }, setError() {
235
+ }, end() {
236
+ } };
237
+ return {
238
+ getEventId: () => ctx.eventId,
239
+ setInput() {
240
+ },
241
+ setProperty(key, value) {
242
+ properties[key] = value;
243
+ },
244
+ setProperties(props) {
245
+ Object.assign(properties, props);
246
+ },
247
+ vercelAiSdkMetadata() {
248
+ return metadata({
249
+ userId: ctx.userId ?? "unknown",
250
+ convoId: ctx.convoId,
251
+ eventName: ctx.event,
252
+ eventId: ctx.eventId,
253
+ properties
254
+ });
255
+ },
256
+ async run(fn) {
257
+ return await fn();
258
+ },
259
+ async withSpan(_params, fn) {
260
+ return await fn();
261
+ },
262
+ async withTool(_params, fn) {
263
+ return await fn();
264
+ },
265
+ startToolSpan: () => noopToolSpan,
266
+ trackTool() {
267
+ },
268
+ async finish() {
203
269
  }
204
270
  };
205
271
  }
@@ -257,6 +323,7 @@ var MorphTracing = class {
257
323
  appName: config.appName ?? process.env.npm_package_name ?? "morph-app",
258
324
  disableBatching: config.disableBatching ?? !isProd,
259
325
  traceContent: config.traceContent ?? true,
326
+ headers: config.headers,
260
327
  debug
261
328
  };
262
329
  if (config.disabled) {
@@ -286,7 +353,7 @@ var MorphTracing = class {
286
353
  }
287
354
  const exporter = new import_exporter_trace_otlp_http.OTLPTraceExporter({
288
355
  url: `${baseUrl}/v1/traces`,
289
- headers: { Authorization: `Bearer ${apiKey}`, ...config.headers }
356
+ headers: { Authorization: `Bearer ${apiKey}`, ...this.cfg.headers }
290
357
  });
291
358
  traceloop2.initialize({
292
359
  baseUrl,
@@ -305,9 +372,18 @@ var MorphTracing = class {
305
372
  `initialized \u2192 ${baseUrl}/v1/traces (batching ${this.cfg.disableBatching ? "off" : "on"})`
306
373
  );
307
374
  }
308
- /** Begin a new traced interaction (a single user turn / agent run). */
375
+ /**
376
+ * Begin a new traced interaction (a single user turn / agent run). On a
377
+ * disabled instance this returns an inert no-op interaction — callbacks still
378
+ * run, but no spans are created or shipped.
379
+ */
309
380
  begin(ctx) {
310
- const interaction = createInteractionApi(ctx, this.cfg.traceContent);
381
+ if (!this.enabled) return createNoopInteraction(ctx);
382
+ const interaction = createInteractionApi(
383
+ ctx,
384
+ this.cfg.traceContent,
385
+ (eventId) => this.active.delete(eventId)
386
+ );
311
387
  this.active.set(interaction.getEventId(), interaction);
312
388
  return interaction;
313
389
  }
@@ -320,12 +396,11 @@ var MorphTracing = class {
320
396
  * spans/token usage, not a user-facing interaction.
321
397
  */
322
398
  tracer(globalProperties = {}) {
323
- return createInteractionApi(
324
- { userId: globalProperties.userId ?? "batch", properties: globalProperties },
325
- this.cfg.traceContent
326
- );
399
+ const ctx = { userId: globalProperties.userId ?? "batch", properties: globalProperties };
400
+ if (!this.enabled) return createNoopInteraction(ctx);
401
+ return createInteractionApi(ctx, this.cfg.traceContent);
327
402
  }
328
- /** Build Vercel AI SDK telemetry metadata (see `morphsdk/tracing/otel`). */
403
+ /** Build Vercel AI SDK telemetry metadata (see `@morphllm/morphsdk/tracing/otel`). */
329
404
  metadata(opts) {
330
405
  return metadata(opts);
331
406
  }
@@ -337,10 +412,15 @@ var MorphTracing = class {
337
412
  }
338
413
  /** Span processor for `useExternalOtel: true` integrations. */
339
414
  createSpanProcessor(options) {
415
+ const exporter = options?.exporter ?? new import_exporter_trace_otlp_http.OTLPTraceExporter({
416
+ url: `${this.cfg.baseUrl}/v1/traces`,
417
+ headers: { Authorization: `Bearer ${this.cfg.apiKey}`, ...this.cfg.headers }
418
+ });
340
419
  return traceloop2.createSpanProcessor({
341
420
  apiKey: this.cfg.apiKey,
342
421
  baseUrl: this.cfg.baseUrl,
343
- ...options
422
+ ...options,
423
+ exporter
344
424
  });
345
425
  }
346
426
  /** Flush any batched spans immediately. Safe to call when idle. */
@@ -1 +1 @@
1
- {"version":3,"sources":["../../tracing/core.ts","../../tracing/interaction.ts","../../tracing/otel.ts","../../tracing/signals.ts"],"sourcesContent":["/**\n * Morph Tracing — core initialization.\n *\n * Thin Morph layer over OpenLLMetry / Traceloop. `morphTracing()` initializes\n * Traceloop with a JSON OTLP exporter pointed at Morph's ingest endpoint\n * (`${baseUrl}/v1/traces`, `Authorization: Bearer <apiKey>`) and returns a\n * `MorphTracing` handle for interactions, tools, and signals.\n *\n * We deliberately override Traceloop's default protobuf exporter with the\n * JSON-over-HTTP exporter so the ingest service can parse plain OTLP/JSON.\n */\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';\nimport * as traceloop from '@traceloop/node-server-sdk';\n\nimport { createInteractionApi, type Interaction, type Tracer } from './interaction.js';\nimport { metadata as buildMetadata } from './otel.js';\nimport { shipSignal } from './signals.js';\nimport type {\n MetadataOptions,\n MorphTracingConfig,\n SignalEvent,\n TraceContext,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://api.morphllm.com';\n\nexport interface ResolvedConfig {\n apiKey: string;\n baseUrl: string;\n signalsEndpoint: string;\n appName: string;\n disableBatching: boolean;\n traceContent: boolean;\n debug: boolean;\n}\n\nfunction log(debug: boolean, ...args: unknown[]): void {\n if (debug) console.log('[morph-tracing]', ...args);\n}\n\n/**\n * Handle returned by {@link morphTracing}. Create interactions with `begin()`,\n * get a non-interactive `tracer()`, attach feedback with `trackSignal()`, and\n * flush/shutdown the exporter.\n */\nexport class MorphTracing {\n private readonly cfg: ResolvedConfig;\n private readonly active = new Map<string, Interaction>();\n readonly enabled: boolean;\n\n constructor(config: MorphTracingConfig = {}) {\n const debug = config.debug ?? process.env.MORPH_TRACING_DEBUG === '1';\n const apiKey = config.apiKey ?? process.env.MORPH_API_KEY ?? '';\n const baseUrlRaw =\n config.baseUrl ?? process.env.MORPH_TRACES_URL ?? DEFAULT_BASE_URL;\n const baseUrl = baseUrlRaw.replace(/\\/+$/, '');\n const isProd = process.env.NODE_ENV === 'production';\n\n this.cfg = {\n apiKey,\n baseUrl,\n signalsEndpoint: `${baseUrl}/v1/signals`,\n appName: config.appName ?? process.env.npm_package_name ?? 'morph-app',\n disableBatching: config.disableBatching ?? !isProd,\n traceContent: config.traceContent ?? true,\n debug,\n };\n\n if (config.disabled) {\n log(debug, 'disabled — no tracing initialized');\n this.enabled = false;\n return;\n }\n if (!apiKey) {\n console.warn(\n '[morph-tracing] No API key (set MORPH_API_KEY or pass { apiKey }). Tracing disabled.',\n );\n this.enabled = false;\n return;\n }\n\n this.enabled = true;\n if (config.useExternalOtel) {\n // Customer drives their own NodeSDK; just register config, no SDK start.\n traceloop.initialize({\n baseUrl,\n apiKey,\n appName: this.cfg.appName,\n tracingEnabled: false,\n traceContent: this.cfg.traceContent,\n silenceInitializationMessage: true,\n });\n log(debug, 'external OTEL mode — add createSpanProcessor() to your NodeSDK');\n return;\n }\n\n const exporter = new OTLPTraceExporter({\n url: `${baseUrl}/v1/traces`,\n headers: { Authorization: `Bearer ${apiKey}`, ...config.headers },\n });\n\n traceloop.initialize({\n baseUrl,\n apiKey,\n appName: this.cfg.appName,\n exporter,\n disableBatch: this.cfg.disableBatching,\n traceContent: this.cfg.traceContent,\n instrumentModules: config.instrumentModules as NonNullable<\n Parameters<typeof traceloop.initialize>[0]\n >['instrumentModules'],\n tracingEnabled: true,\n traceloopSyncEnabled: false,\n silenceInitializationMessage: !debug,\n });\n log(\n debug,\n `initialized → ${baseUrl}/v1/traces (batching ${this.cfg.disableBatching ? 'off' : 'on'})`,\n );\n }\n\n /** Begin a new traced interaction (a single user turn / agent run). */\n begin(ctx: TraceContext & { userId: string; event?: string }): Interaction {\n const interaction = createInteractionApi(ctx, this.cfg.traceContent);\n this.active.set(interaction.getEventId()!, interaction);\n return interaction;\n }\n\n /** Look up an in-flight interaction by its eventId. */\n getActiveInteraction(eventId: string): Interaction | undefined {\n return this.active.get(eventId);\n }\n\n /**\n * Non-interactive tracer for batch jobs where you only care about\n * spans/token usage, not a user-facing interaction.\n */\n tracer(globalProperties: Record<string, string> = {}): Tracer {\n return createInteractionApi(\n { userId: globalProperties.userId ?? 'batch', properties: globalProperties },\n this.cfg.traceContent,\n );\n }\n\n /** Build Vercel AI SDK telemetry metadata (see `morphsdk/tracing/otel`). */\n metadata(opts: MetadataOptions): Record<string, string> {\n return buildMetadata(opts);\n }\n\n /** Attach a feedback/quality signal to an interaction by eventId. */\n async trackSignal(signal: SignalEvent | SignalEvent[]): Promise<void> {\n if (!this.enabled) return;\n const signals = Array.isArray(signal) ? signal : [signal];\n await shipSignal(this.cfg.signalsEndpoint, this.cfg.apiKey, signals, this.cfg.debug);\n }\n\n /** Span processor for `useExternalOtel: true` integrations. */\n createSpanProcessor(\n options?: Parameters<typeof traceloop.createSpanProcessor>[0],\n ): ReturnType<typeof traceloop.createSpanProcessor> {\n return traceloop.createSpanProcessor({\n apiKey: this.cfg.apiKey,\n baseUrl: this.cfg.baseUrl,\n ...options,\n });\n }\n\n /** Flush any batched spans immediately. Safe to call when idle. */\n async forceFlush(): Promise<void> {\n if (!this.enabled) return;\n try {\n await traceloop.forceFlush();\n } catch (err) {\n log(this.cfg.debug, 'forceFlush error (ignored):', err);\n }\n }\n\n /** Flush and stop tracing. */\n async shutdown(): Promise<void> {\n await this.forceFlush();\n }\n}\n\n/** Initialize Morph Tracing and auto-instrument supported AI SDKs. */\nexport function morphTracing(config: MorphTracingConfig = {}): MorphTracing {\n return new MorphTracing(config);\n}\n","/**\n * Morph Tracing — interactions, tools, and manual spans.\n *\n * An `Interaction` is one user turn / agent run. It threads association\n * properties (user_id / convo_id / event_id) onto every span created inside it —\n * including the auto-instrumented LLM spans — so a whole conversation stitches\n * together in the Morph UI. Built on Traceloop's `withTask` / `withTool` and a\n * manual tracer for already-completed tool spans.\n */\nimport { context, SpanStatusCode, trace, type Span } from '@opentelemetry/api';\nimport * as traceloop from '@traceloop/node-server-sdk';\n\nimport { metadata as buildMetadata } from './otel.js';\nimport type {\n FinishOptions,\n SpanParams,\n ToolParams,\n ToolSpan,\n TrackToolParams,\n TraceContext,\n} from './types.js';\n\n// Traceloop semantic-convention attribute keys.\nconst ASSOC = 'traceloop.association.properties.';\nconst ENTITY_INPUT = 'traceloop.entity.input';\nconst ENTITY_OUTPUT = 'traceloop.entity.output';\nconst ENTITY_NAME = 'traceloop.entity.name';\nconst SPAN_KIND = 'traceloop.span.kind';\n\nfunction uuid(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\n if (c?.randomUUID) return c.randomUUID();\n return 'xxxxxxxxxxxx4xxxyxxx'.replace(/[xy]/g, (ch) => {\n const r = (Math.random() * 16) | 0;\n return (ch === 'x' ? r : (r & 0x3) | 0x8).toString(16);\n });\n}\n\nfunction asString(v: unknown): string {\n if (v == null) return '';\n return typeof v === 'string' ? v : JSON.stringify(v);\n}\n\nexport interface Interaction {\n getEventId(): string | undefined;\n setInput(input: string): void;\n setProperty(key: string, value: string): void;\n setProperties(props: Record<string, string>): void;\n /**\n * Run `fn` with this interaction's association properties active — required so\n * auto-instrumented OpenAI/Anthropic spans inherit user_id / convo_id / tags.\n */\n run<T>(fn: () => Promise<T> | T): Promise<T>;\n /** Run `fn` inside a traced task span; LLM calls within inherit attribution. */\n withSpan<T>(params: SpanParams | string, fn: () => Promise<T> | T): Promise<T>;\n /** Run `fn` inside a traced tool span. */\n withTool<T>(params: ToolParams | string, fn: () => Promise<T> | T): Promise<T>;\n /** Start a tool span you end manually. */\n startToolSpan(params: ToolParams | string): ToolSpan;\n /** Record an already-completed tool invocation. */\n trackTool(params: TrackToolParams): void;\n /** Metadata for the Vercel AI SDK `experimental_telemetry.metadata`. */\n vercelAiSdkMetadata(): Record<string, string>;\n /** End the interaction with its final output. */\n finish(opts: FinishOptions | string): Promise<void>;\n}\n\nexport type Tracer = Pick<Interaction, 'withSpan' | 'withTool' | 'startToolSpan' | 'trackTool'>;\n\n/** Build the association-property bag Traceloop propagates onto child spans. */\nfunction associationProps(\n ctx: TraceContext & { userId?: string },\n extra: Record<string, string>,\n): Record<string, string> {\n const props: Record<string, string> = { ...extra };\n if (ctx.userId) props.user_id = ctx.userId;\n if (ctx.convoId) props.convo_id = ctx.convoId;\n if (ctx.eventId) props.event_id = ctx.eventId;\n if (ctx.event) props.event_name = ctx.event;\n return props;\n}\n\nexport function createInteractionApi(\n initial: TraceContext & { userId?: string },\n traceContent: boolean,\n): Interaction {\n const ctx: TraceContext & { userId?: string } = {\n ...initial,\n eventId: initial.eventId ?? uuid(),\n };\n const properties: Record<string, string> = { ...(initial.properties ?? {}) };\n let input = initial.input;\n let workflowSpan: Span | null = null;\n\n const withAssoc = <T>(fn: () => Promise<T> | T): Promise<T> | T =>\n traceloop.withAssociationProperties(associationProps(ctx, properties), fn);\n\n const workflowName = () => ctx.event ?? 'interaction';\n\n /** Open the interaction workflow span once; stays active until finish(). */\n function ensureWorkflowSpan(): Span {\n if (workflowSpan) return workflowSpan;\n const span = traceloop.getTraceloopTracer().startSpan(workflowName());\n span.setAttribute(SPAN_KIND, 'workflow');\n for (const [k, v] of Object.entries(associationProps(ctx, properties))) {\n span.setAttribute(ASSOC + k, v);\n }\n if (traceContent && input) span.setAttribute(ENTITY_INPUT, input);\n workflowSpan = span;\n return span;\n }\n\n /** Run fn with association props and the workflow span as the active parent. */\n function withWorkflowContext<T>(fn: () => Promise<T> | T): Promise<T> | T {\n return withAssoc(() => {\n const span = ensureWorkflowSpan();\n return context.with(trace.setSpan(context.active(), span), fn);\n });\n }\n\n const toolName = (p: ToolParams | string) => (typeof p === 'string' ? p : p.name);\n\n function startToolSpan(params: ToolParams | string): ToolSpan {\n const name = toolName(params);\n const span: Span = traceloop.getTraceloopTracer().startSpan(name);\n span.setAttribute(SPAN_KIND, 'tool');\n span.setAttribute(ENTITY_NAME, name);\n for (const [k, v] of Object.entries(associationProps(ctx, properties))) {\n span.setAttribute(ASSOC + k, v);\n }\n if (typeof params !== 'string' && params.properties) {\n for (const [k, v] of Object.entries(params.properties)) span.setAttribute(k, v);\n }\n return {\n setInput(value: unknown) {\n if (traceContent) span.setAttribute(ENTITY_INPUT, asString(value));\n },\n setOutput(value: unknown) {\n if (traceContent) span.setAttribute(ENTITY_OUTPUT, asString(value));\n },\n setError(error: Error | string) {\n const e = typeof error === 'string' ? new Error(error) : error;\n span.recordException(e);\n span.setStatus({ code: SpanStatusCode.ERROR, message: e.message });\n },\n end() {\n span.end();\n },\n };\n }\n\n return {\n getEventId: () => ctx.eventId,\n setInput(value: string) {\n input = value;\n },\n setProperty(key: string, value: string) {\n properties[key] = value;\n },\n setProperties(props: Record<string, string>) {\n Object.assign(properties, props);\n },\n vercelAiSdkMetadata() {\n return buildMetadata({\n userId: ctx.userId ?? 'unknown',\n convoId: ctx.convoId,\n eventName: ctx.event,\n eventId: ctx.eventId,\n properties,\n });\n },\n run(fn) {\n return Promise.resolve(withWorkflowContext(fn));\n },\n withSpan(params, fn) {\n const name = typeof params === 'string' ? params : params.name;\n return Promise.resolve(withWorkflowContext(() => traceloop.withTask({ name }, fn)));\n },\n withTool(params, fn) {\n const name = toolName(params);\n const version = typeof params === 'string' ? undefined : params.version;\n return Promise.resolve(withWorkflowContext(() => traceloop.withTool({ name, version }, fn)));\n },\n startToolSpan,\n trackTool(params: TrackToolParams) {\n const span = startToolSpan({ name: params.name, properties: params.properties });\n if (params.input !== undefined) span.setInput(params.input);\n if (params.output !== undefined) span.setOutput(params.output);\n if (params.error) span.setError(params.error);\n span.end();\n },\n async finish(opts) {\n const output = typeof opts === 'string' ? opts : opts.output;\n if (typeof opts !== 'string' && opts.properties) Object.assign(properties, opts.properties);\n // End the workflow span opened by run()/withTool(); create one if finish() is called alone.\n await Promise.resolve(\n withAssoc(() => {\n const span = ensureWorkflowSpan();\n if (traceContent) span.setAttribute(ENTITY_OUTPUT, output);\n span.end();\n workflowSpan = null;\n }),\n );\n },\n };\n}\n","/**\n * Morph Tracing — Vercel AI SDK helper.\n *\n * The Vercel AI SDK emits its own OpenTelemetry spans when you pass\n * `experimental_telemetry`. There is nothing to monkey-patch; instead you tag\n * each call with `metadata()` so Morph can attribute the resulting spans to a\n * user/conversation/event.\n *\n * @example\n * ```ts\n * import { generateText } from \"ai\";\n * import { metadata } from \"morphsdk/tracing/otel\";\n *\n * const res = await generateText({\n * model: openai(\"gpt-4o\"),\n * prompt: \"Hello!\",\n * experimental_telemetry: {\n * isEnabled: true,\n * metadata: metadata({ userId: \"user-123\", convoId: \"convo-456\" }),\n * },\n * });\n * ```\n */\nimport type { MetadataOptions } from './types.js';\n\n/**\n * Reserved metadata keys Morph owns. Custom `properties` can't overwrite these,\n * so attribution (user_id / convo_id / event_id) stays intact.\n *\n * The AI SDK stores metadata as `ai.telemetry.metadata.<key>`; Traceloop's span\n * processor copies them to `traceloop.association.properties.<key>`, which is\n * what ClickHouse views read. Use snake_case names (user_id, convo_id, …).\n */\nconst RESERVED_KEYS = new Set(['user_id', 'convo_id', 'event_id', 'event_name']);\n\nfunction uuid(): string {\n // Node 18+ and modern runtimes expose globalThis.crypto.randomUUID.\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\n if (c?.randomUUID) return c.randomUUID();\n // Fallback: RFC4122-ish without crypto.\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (ch) => {\n const r = (Math.random() * 16) | 0;\n const v = ch === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\n/**\n * Build the metadata object for the Vercel AI SDK's\n * `experimental_telemetry.metadata`. The values are propagated to every span the\n * AI SDK creates for that call. Generate a fresh `eventId` per call for grouping.\n */\nexport function metadata(opts: MetadataOptions): Record<string, string> {\n const result: Record<string, string> = {\n user_id: opts.userId,\n event_id: opts.eventId ?? uuid(),\n };\n if (opts.convoId) result.convo_id = opts.convoId;\n if (opts.eventName) result.event_name = opts.eventName;\n if (opts.properties) {\n for (const [key, value] of Object.entries(opts.properties)) {\n if (!RESERVED_KEYS.has(key)) result[key] = value;\n }\n }\n return result;\n}\n\nexport default { metadata };\n","/**\n * Morph Tracing — feedback signals.\n *\n * Signals (👍/👎, free-text feedback, user edits) attach to an interaction by\n * `eventId` and ship directly over HTTP — they are low-volume and need no OTel\n * pipeline. Mirrors the request shape of `tools/fastapply/core.ts`.\n */\nimport type { SignalEvent } from './types.js';\n\nexport async function shipSignal(\n endpoint: string,\n apiKey: string,\n signals: SignalEvent[],\n debug = false,\n timeoutMs = 10_000,\n): Promise<void> {\n if (signals.length === 0) return;\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const res = await fetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({ signals }),\n signal: controller.signal,\n });\n if (!res.ok) {\n const body = await res.text().catch(() => '');\n // Signals are best-effort; never throw into the caller's hot path.\n console.warn(`[morph-tracing] signal POST failed (${res.status}): ${body}`);\n } else if (debug) {\n console.log(`[morph-tracing] shipped ${signals.length} signal(s)`);\n }\n } catch (err) {\n console.warn(\n '[morph-tracing] signal POST error:',\n err instanceof Error ? err.message : err,\n );\n } finally {\n clearTimeout(timer);\n }\n}\n"],"mappings":"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","names":["traceloop","uuid"]}
1
+ {"version":3,"sources":["../../tracing/core.ts","../../tracing/interaction.ts","../../tracing/otel.ts","../../tracing/signals.ts"],"sourcesContent":["/**\n * Morph Tracing — core initialization.\n *\n * Thin Morph layer over OpenLLMetry / Traceloop. `morphTracing()` initializes\n * Traceloop with a JSON OTLP exporter pointed at Morph's ingest endpoint\n * (`${baseUrl}/v1/traces`, `Authorization: Bearer <apiKey>`) and returns a\n * `MorphTracing` handle for interactions, tools, and signals.\n *\n * We deliberately override Traceloop's default protobuf exporter with the\n * JSON-over-HTTP exporter so the ingest service can parse plain OTLP/JSON.\n */\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';\nimport * as traceloop from '@traceloop/node-server-sdk';\n\nimport {\n createInteractionApi,\n createNoopInteraction,\n type Interaction,\n type Tracer,\n} from './interaction.js';\nimport { metadata as buildMetadata } from './otel.js';\nimport { shipSignal } from './signals.js';\nimport type {\n MetadataOptions,\n MorphTracingConfig,\n SignalEvent,\n TraceContext,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://api.morphllm.com';\n\nexport interface ResolvedConfig {\n apiKey: string;\n baseUrl: string;\n signalsEndpoint: string;\n appName: string;\n disableBatching: boolean;\n traceContent: boolean;\n headers?: Record<string, string>;\n debug: boolean;\n}\n\nfunction log(debug: boolean, ...args: unknown[]): void {\n if (debug) console.log('[morph-tracing]', ...args);\n}\n\n/**\n * Handle returned by {@link morphTracing}. Create interactions with `begin()`,\n * get a non-interactive `tracer()`, attach feedback with `trackSignal()`, and\n * flush/shutdown the exporter.\n */\nexport class MorphTracing {\n private readonly cfg: ResolvedConfig;\n private readonly active = new Map<string, Interaction>();\n readonly enabled: boolean;\n\n constructor(config: MorphTracingConfig = {}) {\n const debug = config.debug ?? process.env.MORPH_TRACING_DEBUG === '1';\n const apiKey = config.apiKey ?? process.env.MORPH_API_KEY ?? '';\n const baseUrlRaw =\n config.baseUrl ?? process.env.MORPH_TRACES_URL ?? DEFAULT_BASE_URL;\n const baseUrl = baseUrlRaw.replace(/\\/+$/, '');\n const isProd = process.env.NODE_ENV === 'production';\n\n this.cfg = {\n apiKey,\n baseUrl,\n signalsEndpoint: `${baseUrl}/v1/signals`,\n appName: config.appName ?? process.env.npm_package_name ?? 'morph-app',\n disableBatching: config.disableBatching ?? !isProd,\n traceContent: config.traceContent ?? true,\n headers: config.headers,\n debug,\n };\n\n if (config.disabled) {\n log(debug, 'disabled — no tracing initialized');\n this.enabled = false;\n return;\n }\n if (!apiKey) {\n console.warn(\n '[morph-tracing] No API key (set MORPH_API_KEY or pass { apiKey }). Tracing disabled.',\n );\n this.enabled = false;\n return;\n }\n\n this.enabled = true;\n if (config.useExternalOtel) {\n // Customer drives their own NodeSDK; just register config, no SDK start.\n traceloop.initialize({\n baseUrl,\n apiKey,\n appName: this.cfg.appName,\n tracingEnabled: false,\n traceContent: this.cfg.traceContent,\n silenceInitializationMessage: true,\n });\n log(debug, 'external OTEL mode — add createSpanProcessor() to your NodeSDK');\n return;\n }\n\n const exporter = new OTLPTraceExporter({\n url: `${baseUrl}/v1/traces`,\n headers: { Authorization: `Bearer ${apiKey}`, ...this.cfg.headers },\n });\n\n traceloop.initialize({\n baseUrl,\n apiKey,\n appName: this.cfg.appName,\n exporter,\n disableBatch: this.cfg.disableBatching,\n traceContent: this.cfg.traceContent,\n instrumentModules: config.instrumentModules as NonNullable<\n Parameters<typeof traceloop.initialize>[0]\n >['instrumentModules'],\n tracingEnabled: true,\n traceloopSyncEnabled: false,\n silenceInitializationMessage: !debug,\n });\n log(\n debug,\n `initialized → ${baseUrl}/v1/traces (batching ${this.cfg.disableBatching ? 'off' : 'on'})`,\n );\n }\n\n /**\n * Begin a new traced interaction (a single user turn / agent run). On a\n * disabled instance this returns an inert no-op interaction — callbacks still\n * run, but no spans are created or shipped.\n */\n begin(ctx: TraceContext & { userId: string; event?: string }): Interaction {\n if (!this.enabled) return createNoopInteraction(ctx);\n const interaction = createInteractionApi(ctx, this.cfg.traceContent, (eventId) =>\n this.active.delete(eventId),\n );\n this.active.set(interaction.getEventId()!, interaction);\n return interaction;\n }\n\n /** Look up an in-flight interaction by its eventId. */\n getActiveInteraction(eventId: string): Interaction | undefined {\n return this.active.get(eventId);\n }\n\n /**\n * Non-interactive tracer for batch jobs where you only care about\n * spans/token usage, not a user-facing interaction.\n */\n tracer(globalProperties: Record<string, string> = {}): Tracer {\n const ctx = { userId: globalProperties.userId ?? 'batch', properties: globalProperties };\n if (!this.enabled) return createNoopInteraction(ctx);\n return createInteractionApi(ctx, this.cfg.traceContent);\n }\n\n /** Build Vercel AI SDK telemetry metadata (see `@morphllm/morphsdk/tracing/otel`). */\n metadata(opts: MetadataOptions): Record<string, string> {\n return buildMetadata(opts);\n }\n\n /** Attach a feedback/quality signal to an interaction by eventId. */\n async trackSignal(signal: SignalEvent | SignalEvent[]): Promise<void> {\n if (!this.enabled) return;\n const signals = Array.isArray(signal) ? signal : [signal];\n await shipSignal(this.cfg.signalsEndpoint, this.cfg.apiKey, signals, this.cfg.debug);\n }\n\n /** Span processor for `useExternalOtel: true` integrations. */\n createSpanProcessor(\n options?: Parameters<typeof traceloop.createSpanProcessor>[0],\n ): ReturnType<typeof traceloop.createSpanProcessor> {\n // Traceloop's default exporter here is OTLP/protobuf, but Morph's ingest\n // parses OTLP/JSON only — supply the JSON exporter unless the caller\n // brings their own.\n const exporter =\n options?.exporter ??\n new OTLPTraceExporter({\n url: `${this.cfg.baseUrl}/v1/traces`,\n headers: { Authorization: `Bearer ${this.cfg.apiKey}`, ...this.cfg.headers },\n });\n return traceloop.createSpanProcessor({\n apiKey: this.cfg.apiKey,\n baseUrl: this.cfg.baseUrl,\n ...options,\n exporter,\n });\n }\n\n /** Flush any batched spans immediately. Safe to call when idle. */\n async forceFlush(): Promise<void> {\n if (!this.enabled) return;\n try {\n await traceloop.forceFlush();\n } catch (err) {\n log(this.cfg.debug, 'forceFlush error (ignored):', err);\n }\n }\n\n /** Flush and stop tracing. */\n async shutdown(): Promise<void> {\n await this.forceFlush();\n }\n}\n\n/** Initialize Morph Tracing and auto-instrument supported AI SDKs. */\nexport function morphTracing(config: MorphTracingConfig = {}): MorphTracing {\n return new MorphTracing(config);\n}\n","/**\n * Morph Tracing — interactions, tools, and manual spans.\n *\n * An `Interaction` is one user turn / agent run. It threads association\n * properties (user_id / convo_id / event_id) onto every span created inside it —\n * including the auto-instrumented LLM spans — so a whole conversation stitches\n * together in the Morph UI. Built on Traceloop's `withTask` / `withTool` and a\n * manual tracer for already-completed tool spans.\n */\nimport { context, SpanStatusCode, trace, type Span } from '@opentelemetry/api';\nimport * as traceloop from '@traceloop/node-server-sdk';\n\nimport { metadata as buildMetadata } from './otel.js';\nimport type {\n FinishOptions,\n SpanParams,\n ToolParams,\n ToolSpan,\n TrackToolParams,\n TraceContext,\n} from './types.js';\n\n// Traceloop semantic-convention attribute keys.\nconst ASSOC = 'traceloop.association.properties.';\nconst ENTITY_INPUT = 'traceloop.entity.input';\nconst ENTITY_OUTPUT = 'traceloop.entity.output';\nconst ENTITY_NAME = 'traceloop.entity.name';\nconst SPAN_KIND = 'traceloop.span.kind';\n\nfunction uuid(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\n if (c?.randomUUID) return c.randomUUID();\n return 'xxxxxxxxxxxx4xxxyxxx'.replace(/[xy]/g, (ch) => {\n const r = (Math.random() * 16) | 0;\n return (ch === 'x' ? r : (r & 0x3) | 0x8).toString(16);\n });\n}\n\nfunction asString(v: unknown): string {\n if (v == null) return '';\n return typeof v === 'string' ? v : JSON.stringify(v);\n}\n\nexport interface Interaction {\n getEventId(): string | undefined;\n setInput(input: string): void;\n setProperty(key: string, value: string): void;\n setProperties(props: Record<string, string>): void;\n /**\n * Run `fn` with this interaction's association properties active — required so\n * auto-instrumented OpenAI/Anthropic spans inherit user_id / convo_id / tags.\n */\n run<T>(fn: () => Promise<T> | T): Promise<T>;\n /** Run `fn` inside a traced task span; LLM calls within inherit attribution. */\n withSpan<T>(params: SpanParams | string, fn: () => Promise<T> | T): Promise<T>;\n /** Run `fn` inside a traced tool span. */\n withTool<T>(params: ToolParams | string, fn: () => Promise<T> | T): Promise<T>;\n /** Start a tool span you end manually. */\n startToolSpan(params: ToolParams | string): ToolSpan;\n /** Record an already-completed tool invocation. */\n trackTool(params: TrackToolParams): void;\n /** Metadata for the Vercel AI SDK `experimental_telemetry.metadata`. */\n vercelAiSdkMetadata(): Record<string, string>;\n /** End the interaction with its final output. */\n finish(opts: FinishOptions | string): Promise<void>;\n}\n\nexport type Tracer = Pick<Interaction, 'withSpan' | 'withTool' | 'startToolSpan' | 'trackTool'>;\n\n/** Build the association-property bag Traceloop propagates onto child spans. */\nfunction associationProps(\n ctx: TraceContext & { userId?: string },\n extra: Record<string, string>,\n): Record<string, string> {\n const props: Record<string, string> = { ...extra };\n if (ctx.userId) props.user_id = ctx.userId;\n if (ctx.convoId) props.convo_id = ctx.convoId;\n if (ctx.eventId) props.event_id = ctx.eventId;\n if (ctx.event) props.event_name = ctx.event;\n return props;\n}\n\nexport function createInteractionApi(\n initial: TraceContext & { userId?: string },\n traceContent: boolean,\n onClose?: (eventId: string) => void,\n): Interaction {\n const ctx: TraceContext & { userId?: string } = {\n ...initial,\n eventId: initial.eventId ?? uuid(),\n };\n const properties: Record<string, string> = { ...(initial.properties ?? {}) };\n let input = initial.input;\n let workflowSpan: Span | null = null;\n let finished = false;\n\n const withAssoc = <T>(fn: () => Promise<T> | T): Promise<T> | T =>\n traceloop.withAssociationProperties(associationProps(ctx, properties), fn);\n\n const workflowName = () => ctx.event ?? 'interaction';\n\n /** Open the interaction workflow span once; stays active until finish(). */\n function ensureWorkflowSpan(): Span {\n if (workflowSpan) return workflowSpan;\n const span = traceloop.getTraceloopTracer().startSpan(workflowName());\n span.setAttribute(SPAN_KIND, 'workflow');\n for (const [k, v] of Object.entries(associationProps(ctx, properties))) {\n span.setAttribute(ASSOC + k, v);\n }\n if (traceContent && input) span.setAttribute(ENTITY_INPUT, input);\n workflowSpan = span;\n return span;\n }\n\n /** Run fn with association props and the workflow span as the active parent. */\n function withWorkflowContext<T>(fn: () => Promise<T> | T): Promise<T> | T {\n return withAssoc(() => {\n const span = ensureWorkflowSpan();\n return context.with(trace.setSpan(context.active(), span), fn);\n });\n }\n\n /** Close the workflow span exactly once, applying final attributes. */\n function closeWorkflowSpan(apply: (span: Span) => void): void {\n if (finished) return;\n withAssoc(() => {\n const span = ensureWorkflowSpan();\n apply(span);\n span.end();\n });\n workflowSpan = null;\n finished = true;\n onClose?.(ctx.eventId!);\n }\n\n /** Record an exception + ERROR status on the workflow span, then close it. */\n function failWorkflowSpan(err: unknown): void {\n const e = err instanceof Error ? err : new Error(String(err));\n closeWorkflowSpan((span) => {\n span.recordException(e);\n span.setStatus({ code: SpanStatusCode.ERROR, message: e.message });\n if (traceContent) span.setAttribute(ENTITY_OUTPUT, `ERROR: ${e.message}`);\n });\n }\n\n const toolName = (p: ToolParams | string) => (typeof p === 'string' ? p : p.name);\n\n function startToolSpan(params: ToolParams | string): ToolSpan {\n const name = toolName(params);\n const span: Span = traceloop.getTraceloopTracer().startSpan(name);\n span.setAttribute(SPAN_KIND, 'tool');\n span.setAttribute(ENTITY_NAME, name);\n for (const [k, v] of Object.entries(associationProps(ctx, properties))) {\n span.setAttribute(ASSOC + k, v);\n }\n if (typeof params !== 'string' && params.properties) {\n for (const [k, v] of Object.entries(params.properties)) span.setAttribute(k, v);\n }\n return {\n setInput(value: unknown) {\n if (traceContent) span.setAttribute(ENTITY_INPUT, asString(value));\n },\n setOutput(value: unknown) {\n if (traceContent) span.setAttribute(ENTITY_OUTPUT, asString(value));\n },\n setError(error: Error | string) {\n const e = typeof error === 'string' ? new Error(error) : error;\n span.recordException(e);\n span.setStatus({ code: SpanStatusCode.ERROR, message: e.message });\n },\n end() {\n span.end();\n },\n };\n }\n\n return {\n getEventId: () => ctx.eventId,\n setInput(value: string) {\n input = value;\n },\n setProperty(key: string, value: string) {\n properties[key] = value;\n },\n setProperties(props: Record<string, string>) {\n Object.assign(properties, props);\n },\n vercelAiSdkMetadata() {\n return buildMetadata({\n userId: ctx.userId ?? 'unknown',\n convoId: ctx.convoId,\n eventName: ctx.event,\n eventId: ctx.eventId,\n properties,\n });\n },\n async run(fn) {\n try {\n return await Promise.resolve(withWorkflowContext(fn));\n } catch (err) {\n // Natively record the failure on the workflow span and ship it, so a\n // throwing interaction still lands in the trace as an errored span.\n failWorkflowSpan(err);\n throw err;\n }\n },\n withSpan(params, fn) {\n const name = typeof params === 'string' ? params : params.name;\n return Promise.resolve(withWorkflowContext(() => traceloop.withTask({ name }, fn)));\n },\n withTool(params, fn) {\n const name = toolName(params);\n const version = typeof params === 'string' ? undefined : params.version;\n return Promise.resolve(withWorkflowContext(() => traceloop.withTool({ name, version }, fn)));\n },\n startToolSpan,\n trackTool(params: TrackToolParams) {\n const span = startToolSpan({ name: params.name, properties: params.properties });\n if (params.input !== undefined) span.setInput(params.input);\n if (params.output !== undefined) span.setOutput(params.output);\n if (params.error) span.setError(params.error);\n span.end();\n },\n async finish(opts) {\n const output = typeof opts === 'string' ? opts : opts.output;\n if (typeof opts !== 'string' && opts.properties) Object.assign(properties, opts.properties);\n // No-op if run() already closed the span on error; otherwise end it now.\n // (Creates one if finish() is called alone, i.e. begin() → finish().)\n closeWorkflowSpan((span) => {\n if (traceContent) span.setAttribute(ENTITY_OUTPUT, output);\n });\n },\n };\n}\n\n/**\n * Inert Interaction for disabled instances. Preserves control flow — run() /\n * withTool() still execute their callback and rethrow errors — but never touches\n * the tracer. Required because the OTel provider is a process-wide singleton: a\n * disabled instance that created real spans would ship them through whichever\n * enabled instance registered the provider.\n */\nexport function createNoopInteraction(initial: TraceContext & { userId?: string }): Interaction {\n const ctx: TraceContext & { userId?: string } = {\n ...initial,\n eventId: initial.eventId ?? uuid(),\n };\n const properties: Record<string, string> = { ...(initial.properties ?? {}) };\n const noopToolSpan: ToolSpan = { setInput() {}, setOutput() {}, setError() {}, end() {} };\n\n return {\n getEventId: () => ctx.eventId,\n setInput() {},\n setProperty(key: string, value: string) {\n properties[key] = value;\n },\n setProperties(props: Record<string, string>) {\n Object.assign(properties, props);\n },\n vercelAiSdkMetadata() {\n return buildMetadata({\n userId: ctx.userId ?? 'unknown',\n convoId: ctx.convoId,\n eventName: ctx.event,\n eventId: ctx.eventId,\n properties,\n });\n },\n async run(fn) {\n return await fn();\n },\n async withSpan(_params, fn) {\n return await fn();\n },\n async withTool(_params, fn) {\n return await fn();\n },\n startToolSpan: () => noopToolSpan,\n trackTool() {},\n async finish() {},\n };\n}\n","/**\n * Morph Tracing — Vercel AI SDK helper.\n *\n * The Vercel AI SDK emits its own OpenTelemetry spans when you pass\n * `experimental_telemetry`. There is nothing to monkey-patch; instead you tag\n * each call with `metadata()` so Morph can attribute the resulting spans to a\n * user/conversation/event.\n *\n * @example\n * ```ts\n * import { generateText } from \"ai\";\n * import { metadata } from \"@morphllm/morphsdk/tracing/otel\";\n *\n * const res = await generateText({\n * model: openai(\"gpt-4o\"),\n * prompt: \"Hello!\",\n * experimental_telemetry: {\n * isEnabled: true,\n * metadata: metadata({ userId: \"user-123\", convoId: \"convo-456\" }),\n * },\n * });\n * ```\n */\nimport type { MetadataOptions } from './types.js';\n\n/**\n * Reserved metadata keys Morph owns. Custom `properties` can't overwrite these,\n * so attribution (user_id / convo_id / event_id) stays intact.\n *\n * The AI SDK stores metadata as `ai.telemetry.metadata.<key>`; Traceloop's span\n * processor copies them to `traceloop.association.properties.<key>`, which is\n * what ClickHouse views read. Use snake_case names (user_id, convo_id, …).\n */\nconst RESERVED_KEYS = new Set(['user_id', 'convo_id', 'event_id', 'event_name']);\n\nfunction uuid(): string {\n // Node 18+ and modern runtimes expose globalThis.crypto.randomUUID.\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\n if (c?.randomUUID) return c.randomUUID();\n // Fallback: RFC4122-ish without crypto.\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (ch) => {\n const r = (Math.random() * 16) | 0;\n const v = ch === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\n/**\n * Build the metadata object for the Vercel AI SDK's\n * `experimental_telemetry.metadata`. The values are propagated to every span the\n * AI SDK creates for that call. Generate a fresh `eventId` per call for grouping.\n */\nexport function metadata(opts: MetadataOptions): Record<string, string> {\n const result: Record<string, string> = {\n user_id: opts.userId,\n event_id: opts.eventId ?? uuid(),\n };\n if (opts.convoId) result.convo_id = opts.convoId;\n if (opts.eventName) result.event_name = opts.eventName;\n if (opts.properties) {\n for (const [key, value] of Object.entries(opts.properties)) {\n if (!RESERVED_KEYS.has(key)) result[key] = value;\n }\n }\n return result;\n}\n\nexport default { metadata };\n","/**\n * Morph Tracing — feedback signals.\n *\n * Signals (👍/👎, free-text feedback, user edits) attach to an interaction by\n * `eventId` and ship directly over HTTP — they are low-volume and need no OTel\n * pipeline. Mirrors the request shape of `tools/fastapply/core.ts`.\n */\nimport type { SignalEvent } from './types.js';\n\nexport async function shipSignal(\n endpoint: string,\n apiKey: string,\n signals: SignalEvent[],\n debug = false,\n timeoutMs = 10_000,\n): Promise<void> {\n if (signals.length === 0) return;\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const res = await fetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({ signals }),\n signal: controller.signal,\n });\n if (!res.ok) {\n const body = await res.text().catch(() => '');\n // Signals are best-effort; never throw into the caller's hot path.\n console.warn(`[morph-tracing] signal POST failed (${res.status}): ${body}`);\n } else if (debug) {\n console.log(`[morph-tracing] shipped ${signals.length} signal(s)`);\n }\n } catch (err) {\n console.warn(\n '[morph-tracing] signal POST error:',\n err instanceof Error ? err.message : err,\n );\n } finally {\n clearTimeout(timer);\n }\n}\n"],"mappings":"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","names":["traceloop","uuid"]}
@@ -9,6 +9,7 @@ interface ResolvedConfig {
9
9
  appName: string;
10
10
  disableBatching: boolean;
11
11
  traceContent: boolean;
12
+ headers?: Record<string, string>;
12
13
  debug: boolean;
13
14
  }
14
15
  /**
@@ -21,7 +22,11 @@ declare class MorphTracing {
21
22
  private readonly active;
22
23
  readonly enabled: boolean;
23
24
  constructor(config?: MorphTracingConfig);
24
- /** Begin a new traced interaction (a single user turn / agent run). */
25
+ /**
26
+ * Begin a new traced interaction (a single user turn / agent run). On a
27
+ * disabled instance this returns an inert no-op interaction — callbacks still
28
+ * run, but no spans are created or shipped.
29
+ */
25
30
  begin(ctx: TraceContext & {
26
31
  userId: string;
27
32
  event?: string;
@@ -33,7 +38,7 @@ declare class MorphTracing {
33
38
  * spans/token usage, not a user-facing interaction.
34
39
  */
35
40
  tracer(globalProperties?: Record<string, string>): Tracer;
36
- /** Build Vercel AI SDK telemetry metadata (see `morphsdk/tracing/otel`). */
41
+ /** Build Vercel AI SDK telemetry metadata (see `@morphllm/morphsdk/tracing/otel`). */
37
42
  metadata(opts: MetadataOptions): Record<string, string>;
38
43
  /** Attach a feedback/quality signal to an interaction by eventId. */
39
44
  trackSignal(signal: SignalEvent | SignalEvent[]): Promise<void>;
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  MorphTracing,
3
3
  morphTracing
4
- } from "../chunk-AVJJABHB.js";
4
+ } from "../chunk-STJTJDAV.js";
5
5
  import "../chunk-PICGNBUE.js";
6
- import "../chunk-LX54AI3F.js";
7
- import "../chunk-CABQ652L.js";
6
+ import "../chunk-IDMKQWQG.js";
7
+ import "../chunk-TLXVGE4R.js";
8
8
  import "../chunk-PZ5AY32C.js";
9
9
  export {
10
10
  MorphTracing,
@@ -103,7 +103,7 @@ function associationProps(ctx, extra) {
103
103
  if (ctx.event) props.event_name = ctx.event;
104
104
  return props;
105
105
  }
106
- function createInteractionApi(initial, traceContent) {
106
+ function createInteractionApi(initial, traceContent, onClose) {
107
107
  const ctx = {
108
108
  ...initial,
109
109
  eventId: initial.eventId ?? uuid2()
@@ -111,6 +111,7 @@ function createInteractionApi(initial, traceContent) {
111
111
  const properties = { ...initial.properties ?? {} };
112
112
  let input = initial.input;
113
113
  let workflowSpan = null;
114
+ let finished = false;
114
115
  const withAssoc = (fn) => traceloop.withAssociationProperties(associationProps(ctx, properties), fn);
115
116
  const workflowName = () => ctx.event ?? "interaction";
116
117
  function ensureWorkflowSpan() {
@@ -130,6 +131,25 @@ function createInteractionApi(initial, traceContent) {
130
131
  return import_api.context.with(import_api.trace.setSpan(import_api.context.active(), span), fn);
131
132
  });
132
133
  }
134
+ function closeWorkflowSpan(apply) {
135
+ if (finished) return;
136
+ withAssoc(() => {
137
+ const span = ensureWorkflowSpan();
138
+ apply(span);
139
+ span.end();
140
+ });
141
+ workflowSpan = null;
142
+ finished = true;
143
+ onClose?.(ctx.eventId);
144
+ }
145
+ function failWorkflowSpan(err) {
146
+ const e = err instanceof Error ? err : new Error(String(err));
147
+ closeWorkflowSpan((span) => {
148
+ span.recordException(e);
149
+ span.setStatus({ code: import_api.SpanStatusCode.ERROR, message: e.message });
150
+ if (traceContent) span.setAttribute(ENTITY_OUTPUT, `ERROR: ${e.message}`);
151
+ });
152
+ }
133
153
  const toolName = (p) => typeof p === "string" ? p : p.name;
134
154
  function startToolSpan(params) {
135
155
  const name = toolName(params);
@@ -179,8 +199,13 @@ function createInteractionApi(initial, traceContent) {
179
199
  properties
180
200
  });
181
201
  },
182
- run(fn) {
183
- return Promise.resolve(withWorkflowContext(fn));
202
+ async run(fn) {
203
+ try {
204
+ return await Promise.resolve(withWorkflowContext(fn));
205
+ } catch (err) {
206
+ failWorkflowSpan(err);
207
+ throw err;
208
+ }
184
209
  },
185
210
  withSpan(params, fn) {
186
211
  const name = typeof params === "string" ? params : params.name;
@@ -202,14 +227,55 @@ function createInteractionApi(initial, traceContent) {
202
227
  async finish(opts) {
203
228
  const output = typeof opts === "string" ? opts : opts.output;
204
229
  if (typeof opts !== "string" && opts.properties) Object.assign(properties, opts.properties);
205
- await Promise.resolve(
206
- withAssoc(() => {
207
- const span = ensureWorkflowSpan();
208
- if (traceContent) span.setAttribute(ENTITY_OUTPUT, output);
209
- span.end();
210
- workflowSpan = null;
211
- })
212
- );
230
+ closeWorkflowSpan((span) => {
231
+ if (traceContent) span.setAttribute(ENTITY_OUTPUT, output);
232
+ });
233
+ }
234
+ };
235
+ }
236
+ function createNoopInteraction(initial) {
237
+ const ctx = {
238
+ ...initial,
239
+ eventId: initial.eventId ?? uuid2()
240
+ };
241
+ const properties = { ...initial.properties ?? {} };
242
+ const noopToolSpan = { setInput() {
243
+ }, setOutput() {
244
+ }, setError() {
245
+ }, end() {
246
+ } };
247
+ return {
248
+ getEventId: () => ctx.eventId,
249
+ setInput() {
250
+ },
251
+ setProperty(key, value) {
252
+ properties[key] = value;
253
+ },
254
+ setProperties(props) {
255
+ Object.assign(properties, props);
256
+ },
257
+ vercelAiSdkMetadata() {
258
+ return metadata({
259
+ userId: ctx.userId ?? "unknown",
260
+ convoId: ctx.convoId,
261
+ eventName: ctx.event,
262
+ eventId: ctx.eventId,
263
+ properties
264
+ });
265
+ },
266
+ async run(fn) {
267
+ return await fn();
268
+ },
269
+ async withSpan(_params, fn) {
270
+ return await fn();
271
+ },
272
+ async withTool(_params, fn) {
273
+ return await fn();
274
+ },
275
+ startToolSpan: () => noopToolSpan,
276
+ trackTool() {
277
+ },
278
+ async finish() {
213
279
  }
214
280
  };
215
281
  }
@@ -267,6 +333,7 @@ var MorphTracing = class {
267
333
  appName: config.appName ?? process.env.npm_package_name ?? "morph-app",
268
334
  disableBatching: config.disableBatching ?? !isProd,
269
335
  traceContent: config.traceContent ?? true,
336
+ headers: config.headers,
270
337
  debug
271
338
  };
272
339
  if (config.disabled) {
@@ -296,7 +363,7 @@ var MorphTracing = class {
296
363
  }
297
364
  const exporter = new import_exporter_trace_otlp_http.OTLPTraceExporter({
298
365
  url: `${baseUrl}/v1/traces`,
299
- headers: { Authorization: `Bearer ${apiKey}`, ...config.headers }
366
+ headers: { Authorization: `Bearer ${apiKey}`, ...this.cfg.headers }
300
367
  });
301
368
  traceloop2.initialize({
302
369
  baseUrl,
@@ -315,9 +382,18 @@ var MorphTracing = class {
315
382
  `initialized \u2192 ${baseUrl}/v1/traces (batching ${this.cfg.disableBatching ? "off" : "on"})`
316
383
  );
317
384
  }
318
- /** Begin a new traced interaction (a single user turn / agent run). */
385
+ /**
386
+ * Begin a new traced interaction (a single user turn / agent run). On a
387
+ * disabled instance this returns an inert no-op interaction — callbacks still
388
+ * run, but no spans are created or shipped.
389
+ */
319
390
  begin(ctx) {
320
- const interaction = createInteractionApi(ctx, this.cfg.traceContent);
391
+ if (!this.enabled) return createNoopInteraction(ctx);
392
+ const interaction = createInteractionApi(
393
+ ctx,
394
+ this.cfg.traceContent,
395
+ (eventId) => this.active.delete(eventId)
396
+ );
321
397
  this.active.set(interaction.getEventId(), interaction);
322
398
  return interaction;
323
399
  }
@@ -330,12 +406,11 @@ var MorphTracing = class {
330
406
  * spans/token usage, not a user-facing interaction.
331
407
  */
332
408
  tracer(globalProperties = {}) {
333
- return createInteractionApi(
334
- { userId: globalProperties.userId ?? "batch", properties: globalProperties },
335
- this.cfg.traceContent
336
- );
409
+ const ctx = { userId: globalProperties.userId ?? "batch", properties: globalProperties };
410
+ if (!this.enabled) return createNoopInteraction(ctx);
411
+ return createInteractionApi(ctx, this.cfg.traceContent);
337
412
  }
338
- /** Build Vercel AI SDK telemetry metadata (see `morphsdk/tracing/otel`). */
413
+ /** Build Vercel AI SDK telemetry metadata (see `@morphllm/morphsdk/tracing/otel`). */
339
414
  metadata(opts) {
340
415
  return metadata(opts);
341
416
  }
@@ -347,10 +422,15 @@ var MorphTracing = class {
347
422
  }
348
423
  /** Span processor for `useExternalOtel: true` integrations. */
349
424
  createSpanProcessor(options) {
425
+ const exporter = options?.exporter ?? new import_exporter_trace_otlp_http.OTLPTraceExporter({
426
+ url: `${this.cfg.baseUrl}/v1/traces`,
427
+ headers: { Authorization: `Bearer ${this.cfg.apiKey}`, ...this.cfg.headers }
428
+ });
350
429
  return traceloop2.createSpanProcessor({
351
430
  apiKey: this.cfg.apiKey,
352
431
  baseUrl: this.cfg.baseUrl,
353
- ...options
432
+ ...options,
433
+ exporter
354
434
  });
355
435
  }
356
436
  /** Flush any batched spans immediately. Safe to call when idle. */