@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.
- package/dist/{chunk-JCKR7NED.js → chunk-2DLMZDDB.js} +3 -3
- package/dist/{chunk-S2KANK3D.js → chunk-2WQTCETP.js} +2 -2
- package/dist/{chunk-PDPQV3DI.js → chunk-35ZAMQ3A.js} +4 -4
- package/dist/{chunk-2U7YFUMU.js → chunk-4RARO46V.js} +4 -4
- package/dist/{chunk-WLXPKUEQ.js → chunk-4TMCQZNB.js} +2 -2
- package/dist/{chunk-WLXPKUEQ.js.map → chunk-4TMCQZNB.js.map} +1 -1
- package/dist/{chunk-APSFRYOW.js → chunk-AERVDGON.js} +2 -2
- package/dist/{chunk-U5LXWLP7.js → chunk-BN4IHFWR.js} +2 -2
- package/dist/{chunk-7JL65PRH.js → chunk-D4XCP2ZE.js} +3 -3
- package/dist/{chunk-WZAKJJSR.js → chunk-DFTKUEF5.js} +2 -2
- package/dist/{chunk-44IZ4TT5.js → chunk-EAGSRHRT.js} +2 -2
- package/dist/{chunk-NVNYDL6N.js → chunk-EJZFQAKT.js} +2 -2
- package/dist/{chunk-WCW42MV2.js → chunk-GVN6B4YX.js} +3 -3
- package/dist/{chunk-EA3PJ2Y7.js → chunk-GZDRJBI2.js} +2 -2
- package/dist/{chunk-UUUY4SGW.js → chunk-HXDITEO6.js} +2 -2
- package/dist/{chunk-LX54AI3F.js → chunk-IDMKQWQG.js} +81 -14
- package/dist/chunk-IDMKQWQG.js.map +1 -0
- package/dist/{chunk-TQ5RX4HR.js → chunk-IOZMMARY.js} +2 -2
- package/dist/{chunk-6WEF6UCR.js → chunk-IS5TDLAJ.js} +2 -2
- package/dist/{chunk-BNKT5FXS.js → chunk-JG5MJI34.js} +2 -2
- package/dist/{chunk-CHJAXYH6.js → chunk-LBOFTF6A.js} +21 -21
- package/dist/{chunk-MF4VKKGF.js → chunk-LDXKXBYN.js} +2 -2
- package/dist/{chunk-VBPSPP4F.js → chunk-MWUFDBWQ.js} +2 -2
- package/dist/{chunk-HWRZZZT4.js → chunk-OE2LFOYB.js} +2 -2
- package/dist/{chunk-NR4KNQAT.js → chunk-QAZM5ELA.js} +2 -2
- package/dist/{chunk-MOCMOSGF.js → chunk-QW33U4EI.js} +4 -4
- package/dist/{chunk-AVJJABHB.js → chunk-STJTJDAV.js} +28 -13
- package/dist/chunk-STJTJDAV.js.map +1 -0
- package/dist/{chunk-PXL3VUK2.js → chunk-SX2P5ZUP.js} +2 -2
- package/dist/{chunk-RAPGIYHS.js → chunk-TBVIOQ5O.js} +2 -2
- package/dist/{chunk-ZXBAHHQI.js → chunk-TDT6J2X4.js} +2 -2
- package/dist/{chunk-CABQ652L.js → chunk-TLXVGE4R.js} +1 -1
- package/dist/chunk-TLXVGE4R.js.map +1 -0
- package/dist/{chunk-EPJZVTNY.js → chunk-U4KCWD3I.js} +2 -2
- package/dist/{chunk-TGFSIZAJ.js → chunk-WQC3YOER.js} +3 -3
- package/dist/{chunk-FWVBSH2M.js → chunk-X4VPV3A7.js} +2 -2
- package/dist/{chunk-JFVFAFHR.js → chunk-XEQZQTZR.js} +2 -2
- package/dist/{chunk-IPEYIERJ.js → chunk-XYHP2TFY.js} +2 -2
- package/dist/client.cjs +1 -1
- package/dist/client.cjs.map +1 -1
- package/dist/client.js +28 -28
- package/dist/core/client.cjs +1 -1
- package/dist/core/client.cjs.map +1 -1
- package/dist/core/client.js +4 -4
- package/dist/core/error.cjs +1 -1
- package/dist/core/error.cjs.map +1 -1
- package/dist/core/error.js +3 -3
- package/dist/core/index.cjs +1 -1
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.js +4 -4
- package/dist/edge.cjs +1 -1
- package/dist/edge.cjs.map +1 -1
- package/dist/edge.js +7 -7
- package/dist/git/client.cjs +1 -1
- package/dist/git/client.cjs.map +1 -1
- package/dist/git/client.js +5 -5
- package/dist/git/index.cjs +1 -1
- package/dist/git/index.cjs.map +1 -1
- package/dist/git/index.js +5 -5
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +28 -28
- package/dist/modelrouter/core.cjs +1 -1
- package/dist/modelrouter/core.cjs.map +1 -1
- package/dist/modelrouter/core.js +5 -5
- package/dist/modelrouter/index.cjs +1 -1
- package/dist/modelrouter/index.cjs.map +1 -1
- package/dist/modelrouter/index.js +5 -5
- package/dist/{otel-Dk8kdhmZ.d.ts → otel-CG0uqXjp.d.ts} +1 -1
- package/dist/subagents/anthropic.cjs +1 -1
- package/dist/subagents/anthropic.cjs.map +1 -1
- package/dist/subagents/anthropic.js +9 -9
- package/dist/subagents/vercel.cjs +1 -1
- package/dist/subagents/vercel.cjs.map +1 -1
- package/dist/subagents/vercel.js +9 -9
- package/dist/tools/browser/anthropic.cjs +1 -1
- package/dist/tools/browser/anthropic.cjs.map +1 -1
- package/dist/tools/browser/anthropic.js +7 -7
- package/dist/tools/browser/core.cjs +1 -1
- package/dist/tools/browser/core.cjs.map +1 -1
- package/dist/tools/browser/core.js +6 -6
- package/dist/tools/browser/index.cjs +1 -1
- package/dist/tools/browser/index.cjs.map +1 -1
- package/dist/tools/browser/index.js +9 -9
- package/dist/tools/browser/openai.cjs +1 -1
- package/dist/tools/browser/openai.cjs.map +1 -1
- package/dist/tools/browser/openai.js +7 -7
- package/dist/tools/browser/profiles/core.cjs +1 -1
- package/dist/tools/browser/profiles/core.cjs.map +1 -1
- package/dist/tools/browser/profiles/core.js +3 -3
- package/dist/tools/browser/profiles/index.cjs +1 -1
- package/dist/tools/browser/profiles/index.cjs.map +1 -1
- package/dist/tools/browser/profiles/index.js +3 -3
- package/dist/tools/browser/vercel.cjs +1 -1
- package/dist/tools/browser/vercel.cjs.map +1 -1
- package/dist/tools/browser/vercel.js +7 -7
- package/dist/tools/codebase_search/anthropic.cjs +1 -1
- package/dist/tools/codebase_search/anthropic.cjs.map +1 -1
- package/dist/tools/codebase_search/anthropic.js +6 -6
- package/dist/tools/codebase_search/core.cjs +1 -1
- package/dist/tools/codebase_search/core.cjs.map +1 -1
- package/dist/tools/codebase_search/core.js +5 -5
- package/dist/tools/codebase_search/index.cjs +1 -1
- package/dist/tools/codebase_search/index.cjs.map +1 -1
- package/dist/tools/codebase_search/index.js +8 -8
- package/dist/tools/codebase_search/openai.cjs +1 -1
- package/dist/tools/codebase_search/openai.cjs.map +1 -1
- package/dist/tools/codebase_search/openai.js +6 -6
- package/dist/tools/codebase_search/vercel.cjs +1 -1
- package/dist/tools/codebase_search/vercel.cjs.map +1 -1
- package/dist/tools/codebase_search/vercel.js +6 -6
- package/dist/tools/compact/core.cjs +1 -1
- package/dist/tools/compact/core.cjs.map +1 -1
- package/dist/tools/compact/core.js +5 -5
- package/dist/tools/compact/index.cjs +1 -1
- package/dist/tools/compact/index.cjs.map +1 -1
- package/dist/tools/compact/index.js +6 -6
- package/dist/tools/fastapply/anthropic.cjs +1 -1
- package/dist/tools/fastapply/anthropic.cjs.map +1 -1
- package/dist/tools/fastapply/anthropic.js +7 -7
- package/dist/tools/fastapply/apply.cjs +1 -1
- package/dist/tools/fastapply/apply.cjs.map +1 -1
- package/dist/tools/fastapply/apply.js +2 -2
- package/dist/tools/fastapply/core.cjs +1 -1
- package/dist/tools/fastapply/core.cjs.map +1 -1
- package/dist/tools/fastapply/core.js +6 -6
- package/dist/tools/fastapply/index.cjs +1 -1
- package/dist/tools/fastapply/index.cjs.map +1 -1
- package/dist/tools/fastapply/index.js +9 -9
- package/dist/tools/fastapply/openai.cjs +1 -1
- package/dist/tools/fastapply/openai.cjs.map +1 -1
- package/dist/tools/fastapply/openai.js +7 -7
- package/dist/tools/fastapply/vercel.cjs +1 -1
- package/dist/tools/fastapply/vercel.cjs.map +1 -1
- package/dist/tools/fastapply/vercel.js +7 -7
- package/dist/tools/index.cjs +1 -1
- package/dist/tools/index.cjs.map +1 -1
- package/dist/tools/index.js +9 -9
- package/dist/tools/reflex/core.cjs +1 -1
- package/dist/tools/reflex/core.cjs.map +1 -1
- package/dist/tools/reflex/core.js +5 -5
- package/dist/tools/reflex/index.cjs +1 -1
- package/dist/tools/reflex/index.cjs.map +1 -1
- package/dist/tools/reflex/index.js +5 -5
- package/dist/tools/utils/resilience.cjs +1 -1
- package/dist/tools/utils/resilience.cjs.map +1 -1
- package/dist/tools/utils/resilience.js +2 -2
- package/dist/tools/warp_grep/agent/runner.cjs +1 -1
- package/dist/tools/warp_grep/agent/runner.cjs.map +1 -1
- package/dist/tools/warp_grep/agent/runner.js +2 -2
- package/dist/tools/warp_grep/anthropic.cjs +1 -1
- package/dist/tools/warp_grep/anthropic.cjs.map +1 -1
- package/dist/tools/warp_grep/anthropic.js +9 -9
- package/dist/tools/warp_grep/client.cjs +1 -1
- package/dist/tools/warp_grep/client.cjs.map +1 -1
- package/dist/tools/warp_grep/client.js +8 -8
- package/dist/tools/warp_grep/gemini.cjs +1 -1
- package/dist/tools/warp_grep/gemini.cjs.map +1 -1
- package/dist/tools/warp_grep/gemini.js +8 -8
- package/dist/tools/warp_grep/index.cjs +1 -1
- package/dist/tools/warp_grep/index.cjs.map +1 -1
- package/dist/tools/warp_grep/index.js +8 -8
- package/dist/tools/warp_grep/openai.cjs +1 -1
- package/dist/tools/warp_grep/openai.cjs.map +1 -1
- package/dist/tools/warp_grep/openai.js +9 -9
- package/dist/tools/warp_grep/vercel.cjs +1 -1
- package/dist/tools/warp_grep/vercel.cjs.map +1 -1
- package/dist/tools/warp_grep/vercel.js +9 -9
- package/dist/tracing/core.cjs +100 -20
- package/dist/tracing/core.cjs.map +1 -1
- package/dist/tracing/core.d.ts +7 -2
- package/dist/tracing/core.js +3 -3
- package/dist/tracing/index.cjs +100 -20
- package/dist/tracing/index.cjs.map +1 -1
- package/dist/tracing/index.d.ts +1 -1
- package/dist/tracing/index.js +3 -3
- package/dist/tracing/interaction.cjs +81 -13
- package/dist/tracing/interaction.cjs.map +1 -1
- package/dist/tracing/interaction.d.ts +12 -2
- package/dist/tracing/interaction.js +6 -4
- package/dist/tracing/otel.cjs.map +1 -1
- package/dist/tracing/otel.d.ts +1 -1
- package/dist/tracing/otel.js +1 -1
- package/dist/version.cjs +1 -1
- package/dist/version.cjs.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-AVJJABHB.js.map +0 -1
- package/dist/chunk-CABQ652L.js.map +0 -1
- package/dist/chunk-LX54AI3F.js.map +0 -1
- /package/dist/{chunk-JCKR7NED.js.map → chunk-2DLMZDDB.js.map} +0 -0
- /package/dist/{chunk-S2KANK3D.js.map → chunk-2WQTCETP.js.map} +0 -0
- /package/dist/{chunk-PDPQV3DI.js.map → chunk-35ZAMQ3A.js.map} +0 -0
- /package/dist/{chunk-2U7YFUMU.js.map → chunk-4RARO46V.js.map} +0 -0
- /package/dist/{chunk-APSFRYOW.js.map → chunk-AERVDGON.js.map} +0 -0
- /package/dist/{chunk-U5LXWLP7.js.map → chunk-BN4IHFWR.js.map} +0 -0
- /package/dist/{chunk-7JL65PRH.js.map → chunk-D4XCP2ZE.js.map} +0 -0
- /package/dist/{chunk-WZAKJJSR.js.map → chunk-DFTKUEF5.js.map} +0 -0
- /package/dist/{chunk-44IZ4TT5.js.map → chunk-EAGSRHRT.js.map} +0 -0
- /package/dist/{chunk-NVNYDL6N.js.map → chunk-EJZFQAKT.js.map} +0 -0
- /package/dist/{chunk-WCW42MV2.js.map → chunk-GVN6B4YX.js.map} +0 -0
- /package/dist/{chunk-EA3PJ2Y7.js.map → chunk-GZDRJBI2.js.map} +0 -0
- /package/dist/{chunk-UUUY4SGW.js.map → chunk-HXDITEO6.js.map} +0 -0
- /package/dist/{chunk-TQ5RX4HR.js.map → chunk-IOZMMARY.js.map} +0 -0
- /package/dist/{chunk-6WEF6UCR.js.map → chunk-IS5TDLAJ.js.map} +0 -0
- /package/dist/{chunk-BNKT5FXS.js.map → chunk-JG5MJI34.js.map} +0 -0
- /package/dist/{chunk-CHJAXYH6.js.map → chunk-LBOFTF6A.js.map} +0 -0
- /package/dist/{chunk-MF4VKKGF.js.map → chunk-LDXKXBYN.js.map} +0 -0
- /package/dist/{chunk-VBPSPP4F.js.map → chunk-MWUFDBWQ.js.map} +0 -0
- /package/dist/{chunk-HWRZZZT4.js.map → chunk-OE2LFOYB.js.map} +0 -0
- /package/dist/{chunk-NR4KNQAT.js.map → chunk-QAZM5ELA.js.map} +0 -0
- /package/dist/{chunk-MOCMOSGF.js.map → chunk-QW33U4EI.js.map} +0 -0
- /package/dist/{chunk-PXL3VUK2.js.map → chunk-SX2P5ZUP.js.map} +0 -0
- /package/dist/{chunk-RAPGIYHS.js.map → chunk-TBVIOQ5O.js.map} +0 -0
- /package/dist/{chunk-ZXBAHHQI.js.map → chunk-TDT6J2X4.js.map} +0 -0
- /package/dist/{chunk-EPJZVTNY.js.map → chunk-U4KCWD3I.js.map} +0 -0
- /package/dist/{chunk-TGFSIZAJ.js.map → chunk-WQC3YOER.js.map} +0 -0
- /package/dist/{chunk-FWVBSH2M.js.map → chunk-X4VPV3A7.js.map} +0 -0
- /package/dist/{chunk-JFVFAFHR.js.map → chunk-XEQZQTZR.js.map} +0 -0
- /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-
|
|
8
|
+
} from "../../chunk-OE2LFOYB.js";
|
|
9
9
|
import "../../chunk-Q6QCHAMD.js";
|
|
10
10
|
import {
|
|
11
11
|
formatResult
|
|
12
|
-
} from "../../chunk-
|
|
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-
|
|
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-
|
|
21
|
-
import "../../chunk-
|
|
22
|
-
import "../../chunk-
|
|
20
|
+
import "../../chunk-TBVIOQ5O.js";
|
|
21
|
+
import "../../chunk-WQC3YOER.js";
|
|
22
|
+
import "../../chunk-4RARO46V.js";
|
|
23
23
|
import "../../chunk-F3NCFNUX.js";
|
|
24
|
-
import "../../chunk-
|
|
25
|
-
import "../../chunk-
|
|
26
|
-
import "../../chunk-
|
|
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 {
|
package/dist/tracing/core.cjs
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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}`, ...
|
|
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
|
-
/**
|
|
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
|
-
|
|
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
|
-
|
|
324
|
-
|
|
325
|
-
|
|
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
|
|
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"]}
|
package/dist/tracing/core.d.ts
CHANGED
|
@@ -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
|
-
/**
|
|
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
|
|
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>;
|
package/dist/tracing/core.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
MorphTracing,
|
|
3
3
|
morphTracing
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-STJTJDAV.js";
|
|
5
5
|
import "../chunk-PICGNBUE.js";
|
|
6
|
-
import "../chunk-
|
|
7
|
-
import "../chunk-
|
|
6
|
+
import "../chunk-IDMKQWQG.js";
|
|
7
|
+
import "../chunk-TLXVGE4R.js";
|
|
8
8
|
import "../chunk-PZ5AY32C.js";
|
|
9
9
|
export {
|
|
10
10
|
MorphTracing,
|
package/dist/tracing/index.cjs
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
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}`, ...
|
|
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
|
-
/**
|
|
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
|
-
|
|
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
|
-
|
|
334
|
-
|
|
335
|
-
|
|
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
|
|
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. */
|